dosfs.c 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927
  1. /*
  2. * This file is part of the UCB release of Plan 9. It is subject to the license
  3. * terms in the LICENSE file found in the top-level directory of this
  4. * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No
  5. * part of the UCB release of Plan 9, including this file, may be copied,
  6. * modified, propagated, or distributed except according to the terms contained
  7. * in the LICENSE file.
  8. */
  9. #include <u.h>
  10. #include <libc.h>
  11. #include <auth.h>
  12. #include <fcall.h>
  13. #include "iotrack.h"
  14. #include "dat.h"
  15. #include "dosfs.h"
  16. #include "fns.h"
  17. void
  18. rversion(void)
  19. {
  20. if(req->msize > Maxiosize)
  21. rep->msize = Maxiosize;
  22. else
  23. rep->msize = req->msize;
  24. rep->version = "9P2000";
  25. }
  26. void
  27. rauth(void)
  28. {
  29. errno = Enoauth;
  30. }
  31. void
  32. rflush(void)
  33. {
  34. }
  35. void
  36. rattach(void)
  37. {
  38. Xfs *xf;
  39. Xfile *root;
  40. Dosptr *dp;
  41. root = xfile(req->fid, Clean);
  42. if(!root){
  43. errno = Enomem;
  44. goto error;
  45. }
  46. root->xf = xf = getxfs(req->uname, req->aname);
  47. if(!xf)
  48. goto error;
  49. if(xf->fmt == 0 && dosfs(xf) < 0){
  50. errno = Eformat;
  51. goto error;
  52. }
  53. root->qid.type = QTDIR;
  54. root->qid.path = 0;
  55. root->qid.vers = 0;
  56. root->xf->rootqid = root->qid;
  57. dp = malloc(sizeof(Dosptr));
  58. if(dp == nil){
  59. errno = Enomem;
  60. goto error;
  61. }
  62. root->ptr = dp;
  63. rootfile(root);
  64. rep->qid = root->qid;
  65. return;
  66. error:
  67. if(root)
  68. xfile(req->fid, Clunk);
  69. }
  70. Xfile*
  71. doclone(Xfile *of, int newfid)
  72. {
  73. Xfile *nf, *next;
  74. Dosptr *dp;
  75. nf = xfile(newfid, Clean);
  76. if(!nf){
  77. errno = Enomem;
  78. return nil;
  79. }
  80. dp = malloc(sizeof(Dosptr));
  81. if(dp == nil){
  82. errno = Enomem;
  83. return nil;
  84. }
  85. next = nf->next;
  86. *nf = *of;
  87. nf->next = next;
  88. nf->fid = req->newfid;
  89. nf->ptr = dp;
  90. refxfs(nf->xf, 1);
  91. memmove(dp, of->ptr, sizeof(Dosptr));
  92. dp->p = nil;
  93. dp->d = nil;
  94. return nf;
  95. }
  96. void
  97. rwalk(void)
  98. {
  99. Xfile *f, *nf;
  100. Dosptr dp[1], savedp[1];
  101. int r, longtype;
  102. Qid saveqid;
  103. rep->nwqid = 0;
  104. nf = nil;
  105. f = xfile(req->fid, Asis);
  106. if(f == nil){
  107. chat("\tno xfile\n");
  108. goto error2;
  109. }
  110. if(req->fid != req->newfid){
  111. nf = doclone(f, req->newfid);
  112. if(nf == nil){
  113. chat("\tclone failed\n");
  114. goto error2;
  115. }
  116. f = nf;
  117. }
  118. saveqid = f->qid;
  119. memmove(savedp, f->ptr, sizeof(Dosptr));
  120. for(; rep->nwqid < req->nwname && rep->nwqid < MAXWELEM; rep->nwqid++){
  121. chat("\twalking %s\n", req->wname[rep->nwqid]);
  122. if(!(f->qid.type & QTDIR)){
  123. chat("\tnot dir: type=%#x\n", f->qid.type);
  124. goto error;
  125. }
  126. if(strcmp(req->wname[rep->nwqid], ".") == 0){
  127. ;
  128. }else if(strcmp(req->wname[rep->nwqid], "..") == 0){
  129. if(f->qid.path != f->xf->rootqid.path){
  130. r = walkup(f, dp);
  131. if(r < 0)
  132. goto error;
  133. memmove(f->ptr, dp, sizeof(Dosptr));
  134. if(isroot(dp->addr))
  135. f->qid.path = f->xf->rootqid.path;
  136. else
  137. f->qid.path = QIDPATH(dp);
  138. }
  139. }else{
  140. fixname(req->wname[rep->nwqid]);
  141. longtype = classifyname(req->wname[rep->nwqid]);
  142. if(longtype==Invalid || getfile(f) < 0)
  143. goto error;
  144. /*
  145. * always do a search for the long name,
  146. * because it could be filed as such
  147. */
  148. r = searchdir(f, req->wname[rep->nwqid], dp, 0, longtype);
  149. putfile(f);
  150. if(r < 0)
  151. goto error;
  152. memmove(f->ptr, dp, sizeof(Dosptr));
  153. f->qid.path = QIDPATH(dp);
  154. f->qid.type = QTFILE;
  155. if(isroot(dp->addr))
  156. f->qid.path = f->xf->rootqid.path;
  157. else if(dp->d->attr & DDIR)
  158. f->qid.type = QTDIR;
  159. else if(dp->d->attr & DSYSTEM){
  160. f->qid.type |= QTEXCL;
  161. if(iscontig(f->xf, dp->d))
  162. f->qid.type |= QTAPPEND;
  163. }
  164. //ZZZ maybe use other bits than qtexcl & qtapppend
  165. putfile(f);
  166. }
  167. rep->wqid[rep->nwqid] = f->qid;
  168. }
  169. return;
  170. error:
  171. f->qid = saveqid;
  172. memmove(f->ptr, savedp, sizeof(Dosptr));
  173. if(nf != nil)
  174. xfile(req->newfid, Clunk);
  175. error2:
  176. if(!errno && !rep->nwqid)
  177. errno = Enonexist;
  178. }
  179. void
  180. ropen(void)
  181. {
  182. Xfile *f;
  183. Iosect *p;
  184. Dosptr *dp;
  185. int attr, omode;
  186. f = xfile(req->fid, Asis);
  187. if(!f || (f->flags&Omodes)){
  188. errno = Eio;
  189. return;
  190. }
  191. dp = f->ptr;
  192. omode = 0;
  193. if(!isroot(dp->paddr) && (req->mode & ORCLOSE)){
  194. /*
  195. * check on parent directory of file to be deleted
  196. */
  197. p = getsect(f->xf, dp->paddr);
  198. if(p == nil){
  199. errno = Eio;
  200. return;
  201. }
  202. attr = ((Dosdir *)&p->iobuf[dp->poffset])->attr;
  203. putsect(p);
  204. if(attr & DRONLY){
  205. errno = Eperm;
  206. return;
  207. }
  208. omode |= Orclose;
  209. }else if(req->mode & ORCLOSE)
  210. omode |= Orclose;
  211. if(getfile(f) < 0){
  212. errno = Enonexist;
  213. return;
  214. }
  215. if(!isroot(dp->addr))
  216. attr = dp->d->attr;
  217. else
  218. attr = DDIR;
  219. switch(req->mode & 7){
  220. case OREAD:
  221. case OEXEC:
  222. omode |= Oread;
  223. break;
  224. case ORDWR:
  225. omode |= Oread;
  226. /* fall through */
  227. case OWRITE:
  228. omode |= Owrite;
  229. if(attr & DRONLY){
  230. errno = Eperm;
  231. goto out;
  232. }
  233. break;
  234. default:
  235. errno = Eio;
  236. goto out;
  237. }
  238. if(req->mode & OTRUNC){
  239. if(attr & DDIR || attr & DRONLY){
  240. errno = Eperm;
  241. goto out;
  242. }
  243. if(truncfile(f, 0) < 0){
  244. errno = Eio;
  245. goto out;
  246. }
  247. }
  248. f->flags |= omode;
  249. rep->qid = f->qid;
  250. rep->iounit = 0;
  251. out:
  252. putfile(f);
  253. }
  254. static int
  255. mk8dot3name(Xfile *f, Dosptr *ndp, char *name, char *sname)
  256. {
  257. Dosptr tmpdp;
  258. int i, longtype;
  259. if(strcmp(name, ".") == 0 || strcmp(name, "..") == 0)
  260. return Invalid;
  261. /*
  262. * always do a search for the long name,
  263. * because it could be filed as such
  264. */
  265. fixname(name);
  266. longtype = classifyname(name);
  267. if(longtype==Invalid || searchdir(f, name, ndp, 1, longtype) < 0)
  268. return Invalid;
  269. if(longtype==Short)
  270. return Short;
  271. if(longtype==ShortLower){
  272. /*
  273. * alias is the upper-case version, which we
  274. * already know does not exist.
  275. */
  276. strcpy(sname, name);
  277. for(i=0; sname[i]; i++)
  278. if('a' <= sname[i] && sname[i] <= 'z')
  279. sname[i] += 'A'-'a';
  280. return ShortLower;
  281. }
  282. /*
  283. * find alias for the long name
  284. */
  285. for(i=1;; i++){
  286. mkalias(name, sname, i);
  287. if(searchdir(f, sname, &tmpdp, 0, 0) < 0)
  288. return Long;
  289. putsect(tmpdp.p);
  290. }
  291. }
  292. /*
  293. * fill in a directory entry for a new file
  294. */
  295. static int
  296. mkdentry(Xfs *xf, Dosptr *ndp, char *name, char *sname, int longtype,
  297. int nattr,
  298. int32_t start, int32_t length)
  299. {
  300. Dosdir *nd;
  301. /*
  302. * fill in the entry
  303. */
  304. ndp->p = getsect(xf, ndp->addr);
  305. if(ndp->p == nil
  306. || longtype!=Short && putlongname(xf, ndp, name, sname) < 0){
  307. errno = Eio;
  308. return -1;
  309. }
  310. ndp->d = (Dosdir *)&ndp->p->iobuf[ndp->offset];
  311. nd = ndp->d;
  312. memset(nd, 0, DOSDIRSIZE);
  313. if(longtype!=Short)
  314. name = sname;
  315. putname(name, nd);
  316. nd->attr = nattr;
  317. puttime(nd, 0);
  318. putstart(xf, nd, start);
  319. nd->length[0] = length;
  320. nd->length[1] = length>>8;
  321. nd->length[2] = length>>16;
  322. nd->length[3] = length>>24;
  323. ndp->p->flags |= BMOD;
  324. return 0;
  325. }
  326. void
  327. rcreate(void)
  328. {
  329. Dosbpb *bp;
  330. Xfile *f;
  331. Dosptr *pdp, *ndp;
  332. Iosect *xp;
  333. Dosdir *pd, *xd;
  334. char sname[13];
  335. int32_t start;
  336. int longtype, attr, omode, nattr;
  337. f = xfile(req->fid, Asis);
  338. if(!f || (f->flags&Omodes) || getfile(f)<0){
  339. errno = Eio;
  340. return;
  341. }
  342. pdp = f->ptr;
  343. pd = pdp->d;
  344. /*
  345. * perm check
  346. */
  347. if(isroot(pdp->addr) && pd != nil)
  348. panic("root pd != nil");
  349. attr = pd ? pd->attr : DDIR;
  350. if(!(attr & DDIR) || (attr & DRONLY)){
  351. badperm:
  352. putfile(f);
  353. errno = Eperm;
  354. return;
  355. }
  356. omode = 0;
  357. if(req->mode & ORCLOSE)
  358. omode |= Orclose;
  359. switch(req->mode & 7){
  360. case OREAD:
  361. case OEXEC:
  362. omode |= Oread;
  363. break;
  364. case ORDWR:
  365. omode |= Oread;
  366. /* fall through */
  367. case OWRITE:
  368. omode |= Owrite;
  369. if(req->perm & DMDIR)
  370. goto badperm;
  371. break;
  372. default:
  373. goto badperm;
  374. }
  375. /*
  376. * check the name, find the slot for the dentry,
  377. * and find a good alias for a long name
  378. */
  379. ndp = malloc(sizeof(Dosptr));
  380. if(ndp == nil){
  381. putfile(f);
  382. errno = Enomem;
  383. return;
  384. }
  385. longtype = mk8dot3name(f, ndp, req->name, sname);
  386. chat("rcreate %s longtype %d...\n", req->name, longtype);
  387. if(longtype == Invalid){
  388. free(ndp);
  389. goto badperm;
  390. }
  391. /*
  392. * allocate first cluster, if making directory
  393. */
  394. start = 0;
  395. bp = nil;
  396. if(req->perm & DMDIR){
  397. bp = f->xf->ptr;
  398. mlock(bp);
  399. start = falloc(f->xf);
  400. unmlock(bp);
  401. if(start <= 0){
  402. free(ndp);
  403. putfile(f);
  404. errno = Eio;
  405. return;
  406. }
  407. }
  408. /*
  409. * make the entry
  410. */
  411. nattr = 0;
  412. if((req->perm & 0222) == 0)
  413. nattr |= DRONLY;
  414. if(req->perm & DMDIR)
  415. nattr |= DDIR;
  416. if(mkdentry(f->xf, ndp, req->name, sname, longtype, nattr, start, 0) < 0){
  417. if(ndp->p != nil)
  418. putsect(ndp->p);
  419. free(ndp);
  420. if(start > 0)
  421. ffree(f->xf, start);
  422. putfile(f);
  423. return;
  424. }
  425. if(pd != nil){
  426. puttime(pd, 0);
  427. pdp->p->flags |= BMOD;
  428. }
  429. /*
  430. * fix up the fid
  431. */
  432. f->ptr = ndp;
  433. f->qid.type = QTFILE;
  434. f->qid.path = QIDPATH(ndp);
  435. //ZZZ set type for excl, append?
  436. if(req->perm & DMDIR){
  437. f->qid.type = QTDIR;
  438. xp = getsect(f->xf, clust2sect(bp, start));
  439. if(xp == nil){
  440. errno = Eio;
  441. goto badio;
  442. }
  443. xd = (Dosdir *)&xp->iobuf[0];
  444. memmove(xd, ndp->d, DOSDIRSIZE);
  445. memset(xd->name, ' ', sizeof xd->name+sizeof xd->ext);
  446. xd->name[0] = '.';
  447. xd = (Dosdir *)&xp->iobuf[DOSDIRSIZE];
  448. if(pd)
  449. memmove(xd, pd, DOSDIRSIZE);
  450. else{
  451. memset(xd, 0, DOSDIRSIZE);
  452. puttime(xd, 0);
  453. xd->attr = DDIR;
  454. }
  455. memset(xd->name, ' ', sizeof xd->name+sizeof xd->ext);
  456. xd->name[0] = '.';
  457. xd->name[1] = '.';
  458. xp->flags |= BMOD;
  459. putsect(xp);
  460. }
  461. f->flags |= omode;
  462. rep->qid = f->qid;
  463. rep->iounit = 0;
  464. badio:
  465. putfile(f);
  466. putsect(pdp->p);
  467. free(pdp);
  468. }
  469. void
  470. rread(void)
  471. {
  472. Xfile *f;
  473. int r;
  474. if (!(f=xfile(req->fid, Asis)) || !(f->flags&Oread))
  475. goto error;
  476. if(req->count > sizeof repdata)
  477. req->count = sizeof repdata;
  478. if(f->qid.type & QTDIR){
  479. if(getfile(f) < 0)
  480. goto error;
  481. r = readdir(f, repdata, req->offset, req->count);
  482. }else{
  483. if(getfile(f) < 0)
  484. goto error;
  485. r = readfile(f, repdata, req->offset, req->count);
  486. }
  487. putfile(f);
  488. if(r < 0){
  489. error:
  490. errno = Eio;
  491. }else{
  492. rep->count = r;
  493. rep->data = (char*)repdata;
  494. }
  495. }
  496. void
  497. rwrite(void)
  498. {
  499. Xfile *f;
  500. int r;
  501. if (!(f=xfile(req->fid, Asis)) || !(f->flags&Owrite))
  502. goto error;
  503. if(getfile(f) < 0)
  504. goto error;
  505. r = writefile(f, req->data, req->offset, req->count);
  506. putfile(f);
  507. if(r < 0){
  508. error:
  509. errno = Eio;
  510. }else{
  511. rep->count = r;
  512. }
  513. }
  514. void
  515. rclunk(void)
  516. {
  517. xfile(req->fid, Clunk);
  518. sync();
  519. }
  520. /*
  521. * wipe out a dos directory entry
  522. */
  523. static void
  524. doremove(Xfs *xf, Dosptr *dp)
  525. {
  526. Iosect *p;
  527. int prevdo;
  528. dp->p->iobuf[dp->offset] = DOSEMPTY;
  529. dp->p->flags |= BMOD;
  530. for(prevdo = dp->offset-DOSDIRSIZE; prevdo >= 0; prevdo -= DOSDIRSIZE){
  531. if(dp->p->iobuf[prevdo+11] != 0xf)
  532. break;
  533. dp->p->iobuf[prevdo] = DOSEMPTY;
  534. }
  535. if(prevdo < 0 && dp->prevaddr != -1){
  536. p = getsect(xf, dp->prevaddr);
  537. for(prevdo = ((Dosbpb*)xf->ptr)->sectsize-DOSDIRSIZE; prevdo >= 0; prevdo -= DOSDIRSIZE){
  538. if(p->iobuf[prevdo+11] != 0xf)
  539. break;
  540. p->iobuf[prevdo] = DOSEMPTY;
  541. p->flags |= BMOD;
  542. }
  543. putsect(p);
  544. }
  545. }
  546. void
  547. rremove(void)
  548. {
  549. Xfile *f;
  550. Dosptr *dp;
  551. Iosect *parp;
  552. Dosdir *pard;
  553. f = xfile(req->fid, Asis);
  554. parp = nil;
  555. if(f == nil){
  556. errno = Eio;
  557. goto out;
  558. }
  559. dp = f->ptr;
  560. if(isroot(dp->addr)){
  561. errno = Eperm;
  562. goto out;
  563. }
  564. /*
  565. * can't remove if parent is read only,
  566. * it's a non-empty directory,
  567. * or it's a read only file in the root directory
  568. */
  569. parp = getsect(f->xf, dp->paddr);
  570. if(parp == nil
  571. || getfile(f) < 0){
  572. errno = Eio;
  573. goto out;
  574. }
  575. pard = (Dosdir *)&parp->iobuf[dp->poffset];
  576. if(!isroot(dp->paddr) && (pard->attr & DRONLY)
  577. || (dp->d->attr & DDIR) && emptydir(f) < 0
  578. || isroot(dp->paddr) && (dp->d->attr&DRONLY)){
  579. errno = Eperm;
  580. goto out;
  581. }
  582. if(truncfile(f, 0) < 0){
  583. errno = Eio;
  584. goto out;
  585. }
  586. doremove(f->xf, f->ptr);
  587. if(!isroot(dp->paddr)){
  588. puttime(pard, 0);
  589. parp->flags |= BMOD;
  590. }
  591. out:
  592. if(parp != nil)
  593. putsect(parp);
  594. if(f != nil)
  595. putfile(f);
  596. xfile(req->fid, Clunk);
  597. sync();
  598. }
  599. static void
  600. dostat(Xfile *f, Dir *d)
  601. {
  602. Dosptr *dp;
  603. Iosect *p;
  604. char *name, namebuf[DOSNAMELEN];
  605. int islong, sum, prevdo;
  606. dp = f->ptr;
  607. if(isroot(dp->addr)){
  608. memset(d, 0, sizeof(Dir));
  609. d->name = "/";
  610. d->qid.type = QTDIR;
  611. d->qid.path = f->xf->rootqid.path;
  612. d->mode = DMDIR|0777;
  613. d->uid = "bill";
  614. d->muid = "bill";
  615. d->gid = "trog";
  616. }else{
  617. /*
  618. * assemble any long file name
  619. */
  620. sum = aliassum(dp->d);
  621. islong = 0;
  622. name = namebuf;
  623. for(prevdo = dp->offset-DOSDIRSIZE; prevdo >= 0; prevdo -= DOSDIRSIZE){
  624. if(dp->p->iobuf[prevdo+11] != 0xf)
  625. break;
  626. name = getnamesect(namebuf, name, &dp->p->iobuf[prevdo], &islong, &sum, -1);
  627. }
  628. if(prevdo < 0 && dp->prevaddr != -1){
  629. p = getsect(f->xf, dp->prevaddr);
  630. for(prevdo = ((Dosbpb*)f->xf->ptr)->sectsize-DOSDIRSIZE; prevdo >= 0; prevdo -= DOSDIRSIZE){
  631. if(p->iobuf[prevdo+11] != 0xf)
  632. break;
  633. name = getnamesect(namebuf, name, &p->iobuf[prevdo], &islong, &sum, -1);
  634. }
  635. putsect(p);
  636. }
  637. getdir(f->xf, d, dp->d, dp->addr, dp->offset);
  638. if(islong && sum == -1 && nameok(namebuf))
  639. strcpy(d->name, namebuf);
  640. }
  641. }
  642. void
  643. rstat(void)
  644. {
  645. Dir dir;
  646. Xfile *f;
  647. f = xfile(req->fid, Asis);
  648. if(!f || getfile(f) < 0){
  649. errno = Eio;
  650. return;
  651. }
  652. dir.name = repdata;
  653. dostat(f, &dir);
  654. rep->nstat = convD2M(&dir, statbuf, sizeof statbuf);
  655. rep->stat = statbuf;
  656. putfile(f);
  657. }
  658. void
  659. rwstat(void)
  660. {
  661. Dir dir, wdir;
  662. Xfile *f, pf;
  663. Dosptr *dp, ndp, pdp;
  664. Iosect *parp;
  665. Dosdir *pard, *d, od;
  666. char sname[13];
  667. uint32_t oaddr, ooffset;
  668. int32_t start, length;
  669. int i, longtype, changes, attr;
  670. f = xfile(req->fid, Asis);
  671. if(!f || getfile(f) < 0){
  672. errno = Eio;
  673. return;
  674. }
  675. dp = f->ptr;
  676. if(isroot(dp->addr)){
  677. errno = Eperm;
  678. goto out;
  679. }
  680. changes = 0;
  681. dir.name = repdata;
  682. dostat(f, &dir);
  683. if(convM2D(req->stat, req->nstat, &wdir, (char*)statbuf) != req->nstat){
  684. errno = Ebadstat;
  685. goto out;
  686. }
  687. /*
  688. * To change length, must have write permission on file.
  689. * we only allow truncates for now.
  690. */
  691. if(wdir.length!=~0 && wdir.length!=dir.length){
  692. if(wdir.length > dir.length || !dir.mode & 0222){
  693. errno = Eperm;
  694. goto out;
  695. }
  696. }
  697. /*
  698. * no chown or chgrp
  699. */
  700. if(wdir.uid[0] != '\0' && strcmp(dir.uid, wdir.uid) != 0
  701. || wdir.gid[0] != '\0' && strcmp(dir.gid, wdir.gid) != 0){
  702. errno = Eperm;
  703. goto out;
  704. }
  705. /*
  706. * mode/mtime allowed
  707. */
  708. if(wdir.mtime != ~0 && dir.mtime != wdir.mtime)
  709. changes = 1;
  710. /*
  711. * Setting DMAPPEND (make system file contiguous)
  712. * requires setting DMEXCL (system file).
  713. */
  714. if(wdir.mode != ~0){
  715. if((wdir.mode & 7) != ((wdir.mode >> 3) & 7)
  716. || (wdir.mode & 7) != ((wdir.mode >> 6) & 7)){
  717. errno = Eperm;
  718. goto out;
  719. }
  720. if((dir.mode^wdir.mode) & (DMEXCL|DMAPPEND|0777))
  721. changes = 1;
  722. if((dir.mode^wdir.mode) & DMAPPEND) {
  723. if((wdir.mode & (DMEXCL|DMAPPEND)) == DMAPPEND) {
  724. errno = Eperm;
  725. goto out;
  726. }
  727. if((wdir.mode & DMAPPEND) && makecontig(f, 0) < 0) {
  728. errno = Econtig;
  729. goto out;
  730. }
  731. }
  732. }
  733. /*
  734. * to rename:
  735. * 1) make up a fake clone
  736. * 2) walk to parent
  737. * 3) remove the old entry
  738. * 4) create entry with new name
  739. * 5) write correct mode/mtime info
  740. * we need to remove the old entry before creating the new one
  741. * to avoid a lock loop.
  742. */
  743. if(wdir.name[0] != '\0' && strcmp(dir.name, wdir.name) != 0){
  744. if(utflen(wdir.name) >= DOSNAMELEN){
  745. errno = Etoolong;
  746. goto out;
  747. }
  748. /*
  749. * grab parent directory of file to be changed and check for write perm
  750. * rename also disallowed for read-only files in root directory
  751. */
  752. parp = getsect(f->xf, dp->paddr);
  753. if(parp == nil){
  754. errno = Eio;
  755. goto out;
  756. }
  757. pard = (Dosdir *)&parp->iobuf[dp->poffset];
  758. if(!isroot(dp->paddr) && (pard->attr & DRONLY)
  759. || isroot(dp->paddr) && (dp->d->attr&DRONLY)){
  760. putsect(parp);
  761. errno = Eperm;
  762. goto out;
  763. }
  764. /*
  765. * retrieve info from old entry
  766. */
  767. oaddr = dp->addr;
  768. ooffset = dp->offset;
  769. d = dp->d;
  770. od = *d;
  771. start = getstart(f->xf, d);
  772. length = GLONG(d->length);
  773. attr = d->attr;
  774. /*
  775. * temporarily release file to allow other directory ops:
  776. * walk to parent, validate new name
  777. * then remove old entry
  778. */
  779. putfile(f);
  780. pf = *f;
  781. memset(&pdp, 0, sizeof(Dosptr));
  782. pdp.prevaddr = -1;
  783. pdp.naddr = -1;
  784. pdp.addr = dp->paddr;
  785. pdp.offset = dp->poffset;
  786. pdp.p = parp;
  787. if(!isroot(pdp.addr))
  788. pdp.d = (Dosdir *)&parp->iobuf[pdp.offset];
  789. pf.ptr = &pdp;
  790. longtype = mk8dot3name(&pf, &ndp, wdir.name, sname);
  791. if(longtype==Invalid){
  792. putsect(parp);
  793. errno = Eperm;
  794. return;
  795. }
  796. if(getfile(f) < 0){
  797. putsect(parp);
  798. errno = Eio;
  799. return;
  800. }
  801. doremove(f->xf, dp);
  802. putfile(f);
  803. /*
  804. * search for dir entry again, since we may be able to use the old slot,
  805. * and we need to set up the naddr field if a long name spans the block.
  806. * create new entry.
  807. */
  808. if(searchdir(&pf, wdir.name, dp, 1, longtype) < 0
  809. || mkdentry(pf.xf, dp, wdir.name, sname, longtype, attr, start, length) < 0){
  810. putsect(parp);
  811. errno = Eio;
  812. goto out;
  813. }
  814. /*
  815. * copy invisible fields
  816. */
  817. d = dp->d;
  818. for(i = 0; i < 2; i++)
  819. d->ctime[i] = od.ctime[i];
  820. for(i = 0; i < nelem(od.cdate); i++)
  821. d->cdate[i] = od.cdate[i];
  822. for(i = 0; i < nelem(od.adate); i++)
  823. d->adate[i] = od.adate[i];
  824. putsect(parp);
  825. /*
  826. * relocate up other fids to the same file, if it moved
  827. */
  828. f->qid.path = QIDPATH(dp);
  829. if(oaddr != dp->addr || ooffset != dp->offset)
  830. dosptrreloc(f, dp, oaddr, ooffset);
  831. /*
  832. * copy fields that are not supposed to change
  833. */
  834. if(wdir.mtime == ~0)
  835. wdir.mtime = dir.mtime;
  836. if(wdir.mode == ~0)
  837. wdir.mode = dir.mode;
  838. changes = 1;
  839. }
  840. /*
  841. * do the actual truncate
  842. */
  843. if(wdir.length != ~0 && wdir.length != dir.length && truncfile(f, wdir.length) < 0)
  844. errno = Eio;
  845. if(changes){
  846. putdir(dp->d, &wdir);
  847. dp->p->flags |= BMOD;
  848. }
  849. out:
  850. putfile(f);
  851. sync();
  852. }