dosfs.c 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916
  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. }
  284. /*
  285. * fill in a directory entry for a new file
  286. */
  287. static int
  288. mkdentry(Xfs *xf, Dosptr *ndp, char *name, char *sname, int longtype, int nattr, long start, long length)
  289. {
  290. Dosdir *nd;
  291. /*
  292. * fill in the entry
  293. */
  294. ndp->p = getsect(xf, ndp->addr);
  295. if(ndp->p == nil
  296. || longtype!=Short && putlongname(xf, ndp, name, sname) < 0){
  297. errno = Eio;
  298. return -1;
  299. }
  300. ndp->d = (Dosdir *)&ndp->p->iobuf[ndp->offset];
  301. nd = ndp->d;
  302. memset(nd, 0, DOSDIRSIZE);
  303. if(longtype!=Short)
  304. name = sname;
  305. putname(name, nd);
  306. nd->attr = nattr;
  307. puttime(nd, 0);
  308. putstart(xf, nd, start);
  309. nd->length[0] = length;
  310. nd->length[1] = length>>8;
  311. nd->length[2] = length>>16;
  312. nd->length[3] = length>>24;
  313. ndp->p->flags |= BMOD;
  314. return 0;
  315. }
  316. void
  317. rcreate(void)
  318. {
  319. Dosbpb *bp;
  320. Xfile *f;
  321. Dosptr *pdp, *ndp;
  322. Iosect *xp;
  323. Dosdir *pd, *xd;
  324. char sname[13];
  325. long start;
  326. int longtype, attr, omode, nattr;
  327. f = xfile(req->fid, Asis);
  328. if(!f || (f->flags&Omodes) || getfile(f)<0){
  329. errno = Eio;
  330. return;
  331. }
  332. pdp = f->ptr;
  333. pd = pdp->d;
  334. /*
  335. * perm check
  336. */
  337. if(isroot(pdp->addr) && pd != nil)
  338. panic("root pd != nil");
  339. attr = pd ? pd->attr : DDIR;
  340. if(!(attr & DDIR) || (attr & DRONLY)){
  341. badperm:
  342. putfile(f);
  343. errno = Eperm;
  344. return;
  345. }
  346. omode = 0;
  347. if(req->mode & ORCLOSE)
  348. omode |= Orclose;
  349. switch(req->mode & 7){
  350. case OREAD:
  351. case OEXEC:
  352. omode |= Oread;
  353. break;
  354. case ORDWR:
  355. omode |= Oread;
  356. /* fall through */
  357. case OWRITE:
  358. omode |= Owrite;
  359. if(req->perm & DMDIR)
  360. goto badperm;
  361. break;
  362. default:
  363. goto badperm;
  364. }
  365. /*
  366. * check the name, find the slot for the dentry,
  367. * and find a good alias for a long name
  368. */
  369. ndp = malloc(sizeof(Dosptr));
  370. if(ndp == nil){
  371. putfile(f);
  372. errno = Enomem;
  373. return;
  374. }
  375. longtype = mk8dot3name(f, ndp, req->name, sname);
  376. chat("rcreate %s longtype %d...\n", req->name, longtype);
  377. if(longtype == Invalid){
  378. free(ndp);
  379. goto badperm;
  380. }
  381. /*
  382. * allocate first cluster, if making directory
  383. */
  384. start = 0;
  385. bp = nil;
  386. if(req->perm & DMDIR){
  387. bp = f->xf->ptr;
  388. mlock(bp);
  389. start = falloc(f->xf);
  390. unmlock(bp);
  391. if(start <= 0){
  392. free(ndp);
  393. putfile(f);
  394. errno = Eio;
  395. return;
  396. }
  397. }
  398. /*
  399. * make the entry
  400. */
  401. nattr = 0;
  402. if((req->perm & 0222) == 0)
  403. nattr |= DRONLY;
  404. if(req->perm & DMDIR)
  405. nattr |= DDIR;
  406. if(mkdentry(f->xf, ndp, req->name, sname, longtype, nattr, start, 0) < 0){
  407. if(ndp->p != nil)
  408. putsect(ndp->p);
  409. free(ndp);
  410. if(start > 0)
  411. ffree(f->xf, start);
  412. putfile(f);
  413. return;
  414. }
  415. if(pd != nil){
  416. puttime(pd, 0);
  417. pdp->p->flags |= BMOD;
  418. }
  419. /*
  420. * fix up the fid
  421. */
  422. f->ptr = ndp;
  423. f->qid.type = QTFILE;
  424. f->qid.path = QIDPATH(ndp);
  425. //ZZZ set type for excl, append?
  426. if(req->perm & DMDIR){
  427. f->qid.type = QTDIR;
  428. xp = getsect(f->xf, clust2sect(bp, start));
  429. if(xp == nil){
  430. errno = Eio;
  431. goto badio;
  432. }
  433. xd = (Dosdir *)&xp->iobuf[0];
  434. memmove(xd, ndp->d, DOSDIRSIZE);
  435. memset(xd->name, ' ', sizeof xd->name+sizeof xd->ext);
  436. xd->name[0] = '.';
  437. xd = (Dosdir *)&xp->iobuf[DOSDIRSIZE];
  438. if(pd)
  439. memmove(xd, pd, DOSDIRSIZE);
  440. else{
  441. memset(xd, 0, DOSDIRSIZE);
  442. puttime(xd, 0);
  443. xd->attr = DDIR;
  444. }
  445. memset(xd->name, ' ', sizeof xd->name+sizeof xd->ext);
  446. xd->name[0] = '.';
  447. xd->name[1] = '.';
  448. xp->flags |= BMOD;
  449. putsect(xp);
  450. }
  451. f->flags |= omode;
  452. rep->qid = f->qid;
  453. rep->iounit = 0;
  454. badio:
  455. putfile(f);
  456. putsect(pdp->p);
  457. free(pdp);
  458. }
  459. void
  460. rread(void)
  461. {
  462. Xfile *f;
  463. int r;
  464. if (!(f=xfile(req->fid, Asis)) || !(f->flags&Oread))
  465. goto error;
  466. if(req->count > sizeof repdata)
  467. req->count = sizeof repdata;
  468. if(f->qid.type & QTDIR){
  469. if(getfile(f) < 0)
  470. goto error;
  471. r = readdir(f, repdata, req->offset, req->count);
  472. }else{
  473. if(getfile(f) < 0)
  474. goto error;
  475. r = readfile(f, repdata, req->offset, req->count);
  476. }
  477. putfile(f);
  478. if(r < 0){
  479. error:
  480. errno = Eio;
  481. }else{
  482. rep->count = r;
  483. rep->data = (char*)repdata;
  484. }
  485. }
  486. void
  487. rwrite(void)
  488. {
  489. Xfile *f;
  490. int r;
  491. if (!(f=xfile(req->fid, Asis)) || !(f->flags&Owrite))
  492. goto error;
  493. if(getfile(f) < 0)
  494. goto error;
  495. r = writefile(f, req->data, req->offset, req->count);
  496. putfile(f);
  497. if(r < 0){
  498. error:
  499. errno = Eio;
  500. }else{
  501. rep->count = r;
  502. }
  503. }
  504. void
  505. rclunk(void)
  506. {
  507. xfile(req->fid, Clunk);
  508. sync();
  509. }
  510. /*
  511. * wipe out a dos directory entry
  512. */
  513. static void
  514. doremove(Xfs *xf, Dosptr *dp)
  515. {
  516. Iosect *p;
  517. int prevdo;
  518. dp->p->iobuf[dp->offset] = DOSEMPTY;
  519. dp->p->flags |= BMOD;
  520. for(prevdo = dp->offset-DOSDIRSIZE; prevdo >= 0; prevdo -= DOSDIRSIZE){
  521. if(dp->p->iobuf[prevdo+11] != 0xf)
  522. break;
  523. dp->p->iobuf[prevdo] = DOSEMPTY;
  524. }
  525. if(prevdo < 0 && dp->prevaddr != -1){
  526. p = getsect(xf, dp->prevaddr);
  527. for(prevdo = ((Dosbpb*)xf->ptr)->sectsize-DOSDIRSIZE; prevdo >= 0; prevdo -= DOSDIRSIZE){
  528. if(p->iobuf[prevdo+11] != 0xf)
  529. break;
  530. p->iobuf[prevdo] = DOSEMPTY;
  531. p->flags |= BMOD;
  532. }
  533. putsect(p);
  534. }
  535. }
  536. void
  537. rremove(void)
  538. {
  539. Xfile *f;
  540. Dosptr *dp;
  541. Iosect *parp;
  542. Dosdir *pard;
  543. f = xfile(req->fid, Asis);
  544. parp = nil;
  545. if(f == nil){
  546. errno = Eio;
  547. goto out;
  548. }
  549. dp = f->ptr;
  550. if(isroot(dp->addr)){
  551. errno = Eperm;
  552. goto out;
  553. }
  554. /*
  555. * can't remove if parent is read only,
  556. * it's a non-empty directory,
  557. * or it's a read only file in the root directory
  558. */
  559. parp = getsect(f->xf, dp->paddr);
  560. if(parp == nil
  561. || getfile(f) < 0){
  562. errno = Eio;
  563. goto out;
  564. }
  565. pard = (Dosdir *)&parp->iobuf[dp->poffset];
  566. if(!isroot(dp->paddr) && (pard->attr & DRONLY)
  567. || (dp->d->attr & DDIR) && emptydir(f) < 0
  568. || isroot(dp->paddr) && (dp->d->attr&DRONLY)){
  569. errno = Eperm;
  570. goto out;
  571. }
  572. if(truncfile(f, 0) < 0){
  573. errno = Eio;
  574. goto out;
  575. }
  576. doremove(f->xf, f->ptr);
  577. if(!isroot(dp->paddr)){
  578. puttime(pard, 0);
  579. parp->flags |= BMOD;
  580. }
  581. out:
  582. if(parp != nil)
  583. putsect(parp);
  584. if(f != nil)
  585. putfile(f);
  586. xfile(req->fid, Clunk);
  587. sync();
  588. }
  589. static void
  590. dostat(Xfile *f, Dir *d)
  591. {
  592. Dosptr *dp;
  593. Iosect *p;
  594. char *name, namebuf[DOSNAMELEN];
  595. int islong, sum, prevdo;
  596. dp = f->ptr;
  597. if(isroot(dp->addr)){
  598. memset(d, 0, sizeof(Dir));
  599. d->name = "/";
  600. d->qid.type = QTDIR;
  601. d->qid.path = f->xf->rootqid.path;
  602. d->mode = DMDIR|0777;
  603. d->uid = "bill";
  604. d->muid = "bill";
  605. d->gid = "trog";
  606. }else{
  607. /*
  608. * assemble any long file name
  609. */
  610. sum = aliassum(dp->d);
  611. islong = 0;
  612. name = namebuf;
  613. for(prevdo = dp->offset-DOSDIRSIZE; prevdo >= 0; prevdo -= DOSDIRSIZE){
  614. if(dp->p->iobuf[prevdo+11] != 0xf)
  615. break;
  616. name = getnamesect(namebuf, name, &dp->p->iobuf[prevdo], &islong, &sum, -1);
  617. }
  618. if(prevdo < 0 && dp->prevaddr != -1){
  619. p = getsect(f->xf, dp->prevaddr);
  620. for(prevdo = ((Dosbpb*)f->xf->ptr)->sectsize-DOSDIRSIZE; prevdo >= 0; prevdo -= DOSDIRSIZE){
  621. if(p->iobuf[prevdo+11] != 0xf)
  622. break;
  623. name = getnamesect(namebuf, name, &p->iobuf[prevdo], &islong, &sum, -1);
  624. }
  625. putsect(p);
  626. }
  627. getdir(f->xf, d, dp->d, dp->addr, dp->offset);
  628. if(islong && sum == -1 && nameok(namebuf))
  629. strcpy(d->name, namebuf);
  630. }
  631. }
  632. void
  633. rstat(void)
  634. {
  635. Dir dir;
  636. Xfile *f;
  637. f = xfile(req->fid, Asis);
  638. if(!f || getfile(f) < 0){
  639. errno = Eio;
  640. return;
  641. }
  642. dir.name = repdata;
  643. dostat(f, &dir);
  644. rep->nstat = convD2M(&dir, statbuf, sizeof statbuf);
  645. rep->stat = statbuf;
  646. putfile(f);
  647. }
  648. void
  649. rwstat(void)
  650. {
  651. Dir dir, wdir;
  652. Xfile *f, pf;
  653. Dosptr *dp, ndp, pdp;
  654. Iosect *parp;
  655. Dosdir *pard, *d, od;
  656. char sname[13];
  657. ulong oaddr, ooffset;
  658. long start, length;
  659. int i, longtype, changes, attr;
  660. f = xfile(req->fid, Asis);
  661. if(!f || getfile(f) < 0){
  662. errno = Eio;
  663. return;
  664. }
  665. dp = f->ptr;
  666. if(isroot(dp->addr)){
  667. errno = Eperm;
  668. goto out;
  669. }
  670. changes = 0;
  671. dir.name = repdata;
  672. dostat(f, &dir);
  673. if(convM2D(req->stat, req->nstat, &wdir, (char*)statbuf) != req->nstat){
  674. errno = Ebadstat;
  675. goto out;
  676. }
  677. /*
  678. * To change length, must have write permission on file.
  679. * we only allow truncates for now.
  680. */
  681. if(wdir.length!=~0 && wdir.length!=dir.length){
  682. if(wdir.length > dir.length || !dir.mode & 0222){
  683. errno = Eperm;
  684. goto out;
  685. }
  686. }
  687. /*
  688. * no chown or chgrp
  689. */
  690. if(wdir.uid[0] != '\0' && strcmp(dir.uid, wdir.uid) != 0
  691. || wdir.gid[0] != '\0' && strcmp(dir.gid, wdir.gid) != 0){
  692. errno = Eperm;
  693. goto out;
  694. }
  695. /*
  696. * mode/mtime allowed
  697. */
  698. if(wdir.mtime != ~0 && dir.mtime != wdir.mtime)
  699. changes = 1;
  700. /*
  701. * Setting DMAPPEND (make system file contiguous)
  702. * requires setting DMEXCL (system file).
  703. */
  704. if(wdir.mode != ~0){
  705. if((wdir.mode & 7) != ((wdir.mode >> 3) & 7)
  706. || (wdir.mode & 7) != ((wdir.mode >> 6) & 7)){
  707. errno = Eperm;
  708. goto out;
  709. }
  710. if((dir.mode^wdir.mode) & (DMEXCL|DMAPPEND|0777))
  711. changes = 1;
  712. if((dir.mode^wdir.mode) & DMAPPEND) {
  713. if((wdir.mode & (DMEXCL|DMAPPEND)) == DMAPPEND) {
  714. errno = Eperm;
  715. goto out;
  716. }
  717. if((wdir.mode & DMAPPEND) && makecontig(f, 0) < 0) {
  718. errno = Econtig;
  719. goto out;
  720. }
  721. }
  722. }
  723. /*
  724. * to rename:
  725. * 1) make up a fake clone
  726. * 2) walk to parent
  727. * 3) remove the old entry
  728. * 4) create entry with new name
  729. * 5) write correct mode/mtime info
  730. * we need to remove the old entry before creating the new one
  731. * to avoid a lock loop.
  732. */
  733. if(wdir.name[0] != '\0' && strcmp(dir.name, wdir.name) != 0){
  734. if(utflen(wdir.name) >= DOSNAMELEN){
  735. errno = Etoolong;
  736. goto out;
  737. }
  738. /*
  739. * grab parent directory of file to be changed and check for write perm
  740. * rename also disallowed for read-only files in root directory
  741. */
  742. parp = getsect(f->xf, dp->paddr);
  743. if(parp == nil){
  744. errno = Eio;
  745. goto out;
  746. }
  747. pard = (Dosdir *)&parp->iobuf[dp->poffset];
  748. if(!isroot(dp->paddr) && (pard->attr & DRONLY)
  749. || isroot(dp->paddr) && (dp->d->attr&DRONLY)){
  750. putsect(parp);
  751. errno = Eperm;
  752. goto out;
  753. }
  754. /*
  755. * retrieve info from old entry
  756. */
  757. oaddr = dp->addr;
  758. ooffset = dp->offset;
  759. d = dp->d;
  760. od = *d;
  761. start = getstart(f->xf, d);
  762. length = GLONG(d->length);
  763. attr = d->attr;
  764. /*
  765. * temporarily release file to allow other directory ops:
  766. * walk to parent, validate new name
  767. * then remove old entry
  768. */
  769. putfile(f);
  770. pf = *f;
  771. memset(&pdp, 0, sizeof(Dosptr));
  772. pdp.prevaddr = -1;
  773. pdp.naddr = -1;
  774. pdp.addr = dp->paddr;
  775. pdp.offset = dp->poffset;
  776. pdp.p = parp;
  777. if(!isroot(pdp.addr))
  778. pdp.d = (Dosdir *)&parp->iobuf[pdp.offset];
  779. pf.ptr = &pdp;
  780. longtype = mk8dot3name(&pf, &ndp, wdir.name, sname);
  781. if(longtype==Invalid){
  782. putsect(parp);
  783. errno = Eperm;
  784. return;
  785. }
  786. if(getfile(f) < 0){
  787. putsect(parp);
  788. errno = Eio;
  789. return;
  790. }
  791. doremove(f->xf, dp);
  792. putfile(f);
  793. /*
  794. * search for dir entry again, since we may be able to use the old slot,
  795. * and we need to set up the naddr field if a long name spans the block.
  796. * create new entry.
  797. */
  798. if(searchdir(&pf, wdir.name, dp, 1, longtype) < 0
  799. || mkdentry(pf.xf, dp, wdir.name, sname, longtype, attr, start, length) < 0){
  800. putsect(parp);
  801. errno = Eio;
  802. goto out;
  803. }
  804. /*
  805. * copy invisible fields
  806. */
  807. d = dp->d;
  808. for(i = 0; i < 2; i++)
  809. d->ctime[i] = od.ctime[i];
  810. for(i = 0; i < nelem(od.cdate); i++)
  811. d->cdate[i] = od.cdate[i];
  812. for(i = 0; i < nelem(od.adate); i++)
  813. d->adate[i] = od.adate[i];
  814. putsect(parp);
  815. /*
  816. * relocate up other fids to the same file, if it moved
  817. */
  818. f->qid.path = QIDPATH(dp);
  819. if(oaddr != dp->addr || ooffset != dp->offset)
  820. dosptrreloc(f, dp, oaddr, ooffset);
  821. /*
  822. * copy fields that are not supposed to change
  823. */
  824. if(wdir.mtime == ~0)
  825. wdir.mtime = dir.mtime;
  826. if(wdir.mode == ~0)
  827. wdir.mode = dir.mode;
  828. changes = 1;
  829. }
  830. /*
  831. * do the actual truncate
  832. */
  833. if(wdir.length != ~0 && wdir.length != dir.length && truncfile(f, wdir.length) < 0)
  834. errno = Eio;
  835. if(changes){
  836. putdir(dp->d, &wdir);
  837. dp->p->flags |= BMOD;
  838. }
  839. out:
  840. putfile(f);
  841. sync();
  842. }