dosfs.c 17 KB

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