9p2.c 35 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870
  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 "all.h"
  10. #include <fcall.h>
  11. enum { MSIZE = MAXDAT+MAXMSG };
  12. static int
  13. mkmode9p1(uint32_t mode9p2)
  14. {
  15. int mode;
  16. /*
  17. * Assume this is for an allocated entry.
  18. */
  19. mode = DALLOC|(mode9p2 & 0777);
  20. if(mode9p2 & DMEXCL)
  21. mode |= DLOCK;
  22. if(mode9p2 & DMAPPEND)
  23. mode |= DAPND;
  24. if(mode9p2 & DMDIR)
  25. mode |= DDIR;
  26. return mode;
  27. }
  28. void
  29. mkqid9p1(Qid9p1* qid9p1, Qid* qid)
  30. {
  31. if(qid->path & 0xFFFFFFFF00000000LL)
  32. panic("mkqid9p1: path %lluX", (Wideoff)qid->path);
  33. qid9p1->path = qid->path & 0xFFFFFFFF;
  34. if(qid->type & QTDIR)
  35. qid9p1->path |= QPDIR;
  36. qid9p1->version = qid->vers;
  37. }
  38. static int
  39. mktype9p2(int mode9p1)
  40. {
  41. int type;
  42. type = 0;
  43. if(mode9p1 & DLOCK)
  44. type |= QTEXCL;
  45. if(mode9p1 & DAPND)
  46. type |= QTAPPEND;
  47. if(mode9p1 & DDIR)
  48. type |= QTDIR;
  49. return type;
  50. }
  51. static uint32_t
  52. mkmode9p2(int mode9p1)
  53. {
  54. uint32_t mode;
  55. mode = mode9p1 & 0777;
  56. if(mode9p1 & DLOCK)
  57. mode |= DMEXCL;
  58. if(mode9p1 & DAPND)
  59. mode |= DMAPPEND;
  60. if(mode9p1 & DDIR)
  61. mode |= DMDIR;
  62. return mode;
  63. }
  64. void
  65. mkqid9p2(Qid* qid, Qid9p1* qid9p1, int mode9p1)
  66. {
  67. qid->path = (uint32_t)(qid9p1->path & ~QPDIR);
  68. qid->vers = qid9p1->version;
  69. qid->type = mktype9p2(mode9p1);
  70. }
  71. static int
  72. mkdir9p2(Dir* dir, Dentry* dentry, void* strs)
  73. {
  74. char *op, *p;
  75. memset(dir, 0, sizeof(Dir));
  76. mkqid(&dir->qid, dentry, 1);
  77. dir->mode = mkmode9p2(dentry->mode);
  78. dir->atime = dentry->atime;
  79. dir->mtime = dentry->mtime;
  80. dir->length = dentry->size;
  81. op = p = strs;
  82. dir->name = p;
  83. p += sprint(p, "%s", dentry->name)+1;
  84. dir->uid = p;
  85. uidtostr(p, dentry->uid, 1);
  86. p += strlen(p)+1;
  87. dir->gid = p;
  88. uidtostr(p, dentry->gid, 1);
  89. p += strlen(p)+1;
  90. dir->muid = p;
  91. uidtostr(p, dentry->muid, 1);
  92. p += strlen(p)+1;
  93. return p-op;
  94. }
  95. static int
  96. checkname9p2(char* name)
  97. {
  98. char *p;
  99. /*
  100. * Return error or 0 if OK.
  101. */
  102. if(name == nil || *name == 0)
  103. return Ename;
  104. for(p = name; *p != 0; p++){
  105. if(p-name >= NAMELEN-1)
  106. return Etoolong;
  107. if((*p & 0xFF) <= 040)
  108. return Ename;
  109. }
  110. if(strcmp(name, ".") == 0 || strcmp(name, "..") == 0)
  111. return Edot;
  112. return 0;
  113. }
  114. static int
  115. version(Chan* chan, Fcall* f, Fcall* r)
  116. {
  117. if(chan->protocol != nil)
  118. return Eversion;
  119. if(f->msize < MSIZE)
  120. r->msize = f->msize;
  121. else
  122. r->msize = MSIZE;
  123. /*
  124. * Should check the '.' stuff here.
  125. */
  126. if(strcmp(f->version, VERSION9P) == 0){
  127. r->version = VERSION9P;
  128. chan->protocol = serve9p2;
  129. chan->msize = r->msize;
  130. } else
  131. r->version = "unknown";
  132. fileinit(chan);
  133. return 0;
  134. }
  135. struct {
  136. Lock;
  137. ulong hi;
  138. } authpath;
  139. static int
  140. auth(Chan* chan, Fcall* f, Fcall* r)
  141. {
  142. char *aname;
  143. File *file;
  144. Filsys *fs;
  145. int error;
  146. if(cons.flags & authdisableflag)
  147. return Eauthdisabled;
  148. error = 0;
  149. aname = f->aname;
  150. if(strcmp(f->uname, "none") == 0)
  151. return Eauthnone;
  152. if(!aname[0]) /* default */
  153. aname = "main";
  154. file = filep(chan, f->afid, 1);
  155. if(file == nil){
  156. error = Efidinuse;
  157. goto out;
  158. }
  159. fs = fsstr(aname);
  160. if(fs == nil){
  161. error = Ebadspc;
  162. goto out;
  163. }
  164. lock(&authpath);
  165. file->qid.path = authpath.hi++;
  166. unlock(&authpath);
  167. file->qid.type = QTAUTH;
  168. file->qid.vers = 0;
  169. file->fs = fs;
  170. file->open = FREAD+FWRITE;
  171. freewp(file->wpath);
  172. file->wpath = 0;
  173. file->auth = authnew(f->uname, f->aname);
  174. if(file->auth == nil){
  175. error = Eauthfile;
  176. goto out;
  177. }
  178. r->aqid = file->qid;
  179. out:
  180. if((cons.flags & attachflag) && error)
  181. print("9p2: auth %s %T SUCK EGGS --- %s\n",
  182. f->uname, time(nil), errstr9p[error]);
  183. if(file != nil){
  184. qunlock(file);
  185. if(error)
  186. freefp(file);
  187. }
  188. return error;
  189. }
  190. int
  191. authorize(Chan* chan, Fcall* f)
  192. {
  193. File* af;
  194. int db, uid = -1;
  195. db = cons.flags & authdebugflag;
  196. if(strcmp(f->uname, "none") == 0){
  197. uid = strtouid(f->uname);
  198. if(db)
  199. print("permission granted to none: uid %s = %d\n",
  200. f->uname, uid);
  201. return uid;
  202. }
  203. if(cons.flags & authdisableflag){
  204. uid = strtouid(f->uname);
  205. if(db)
  206. print("permission granted by authdisable uid %s = %d\n",
  207. f->uname, uid);
  208. return uid;
  209. }
  210. af = filep(chan, f->afid, 0);
  211. if(af == nil){
  212. if(db)
  213. print("authorize: af == nil\n");
  214. return -1;
  215. }
  216. if(af->auth == nil){
  217. if(db)
  218. print("authorize: af->auth == nil\n");
  219. goto out;
  220. }
  221. if(strcmp(f->uname, authuname(af->auth)) != 0){
  222. if(db)
  223. print("authorize: strcmp(f->uname, authuname(af->auth)) != 0\n");
  224. goto out;
  225. }
  226. if(strcmp(f->aname, authaname(af->auth)) != 0){
  227. if(db)
  228. print("authorize: strcmp(f->aname, authaname(af->auth)) != 0\n");
  229. goto out;
  230. }
  231. uid = authuid(af->auth);
  232. if(db)
  233. print("authorize: uid is %d\n", uid);
  234. out:
  235. qunlock(af);
  236. return uid;
  237. }
  238. static int
  239. attach(Chan* chan, Fcall* f, Fcall* r)
  240. {
  241. char *aname;
  242. Iobuf *p;
  243. Dentry *d;
  244. File *file;
  245. Filsys *fs;
  246. Off raddr;
  247. int error, u;
  248. aname = f->aname;
  249. if(!aname[0]) /* default */
  250. aname = "main";
  251. p = nil;
  252. error = 0;
  253. file = filep(chan, f->fid, 1);
  254. if(file == nil){
  255. error = Efidinuse;
  256. goto out;
  257. }
  258. u = -1;
  259. if(chan != cons.chan){
  260. if(noattach && strcmp(f->uname, "none")) {
  261. error = Enoattach;
  262. goto out;
  263. }
  264. u = authorize(chan, f);
  265. if(u < 0){
  266. error = Ebadu;
  267. goto out;
  268. }
  269. }
  270. file->uid = u;
  271. fs = fsstr(aname);
  272. if(fs == nil){
  273. error = Ebadspc;
  274. goto out;
  275. }
  276. raddr = getraddr(fs->dev);
  277. p = getbuf(fs->dev, raddr, Brd);
  278. if(p == nil || checktag(p, Tdir, QPROOT)){
  279. error = Ealloc;
  280. goto out;
  281. }
  282. d = getdir(p, 0);
  283. if(d == nil || !(d->mode & DALLOC)){
  284. error = Ealloc;
  285. goto out;
  286. }
  287. if (iaccess(file, d, DEXEC) ||
  288. file->uid == 0 && fs->dev->type == Devro) {
  289. /*
  290. * 'none' not allowed on dump
  291. */
  292. error = Eaccess;
  293. goto out;
  294. }
  295. accessdir(p, d, FREAD, file->uid);
  296. mkqid(&file->qid, d, 1);
  297. file->fs = fs;
  298. file->addr = raddr;
  299. file->slot = 0;
  300. file->open = 0;
  301. freewp(file->wpath);
  302. file->wpath = 0;
  303. r->qid = file->qid;
  304. strncpy(chan->whoname, f->uname, sizeof(chan->whoname));
  305. chan->whotime = time(nil);
  306. if(cons.flags & attachflag)
  307. print("9p2: attach %s %T to \"%s\" C%d\n",
  308. chan->whoname, chan->whotime, fs->name, chan->chan);
  309. out:
  310. if((cons.flags & attachflag) && error)
  311. print("9p2: attach %s %T SUCK EGGS --- %s\n",
  312. f->uname, time(nil), errstr9p[error]);
  313. if(p != nil)
  314. putbuf(p);
  315. if(file != nil){
  316. qunlock(file);
  317. if(error)
  318. freefp(file);
  319. }
  320. return error;
  321. }
  322. static int
  323. flush(Chan* chan, Fcall*, Fcall*)
  324. {
  325. runlock(&chan->reflock);
  326. wlock(&chan->reflock);
  327. wunlock(&chan->reflock);
  328. rlock(&chan->reflock);
  329. return 0;
  330. }
  331. static void
  332. clone(File* nfile, File* file)
  333. {
  334. Wpath *wpath;
  335. nfile->qid = file->qid;
  336. lock(&wpathlock);
  337. nfile->wpath = file->wpath;
  338. for(wpath = nfile->wpath; wpath != nil; wpath = wpath->up)
  339. wpath->refs++;
  340. unlock(&wpathlock);
  341. nfile->fs = file->fs;
  342. nfile->addr = file->addr;
  343. nfile->slot = file->slot;
  344. nfile->uid = file->uid;
  345. nfile->open = file->open & ~FREMOV;
  346. }
  347. static int
  348. walkname(File* file, char* wname, Qid* wqid)
  349. {
  350. Wpath *w;
  351. Iobuf *p, *p1;
  352. Dentry *d, *d1;
  353. int error, slot;
  354. Off addr, qpath;
  355. p = p1 = nil;
  356. /*
  357. * File must not have been opened for I/O by an open
  358. * or create message and must represent a directory.
  359. */
  360. if(file->open != 0){
  361. error = Emode;
  362. goto out;
  363. }
  364. p = getbuf(file->fs->dev, file->addr, Brd);
  365. if(p == nil || checktag(p, Tdir, QPNONE)){
  366. error = Edir1;
  367. goto out;
  368. }
  369. d = getdir(p, file->slot);
  370. if(d == nil || !(d->mode & DALLOC)){
  371. error = Ealloc;
  372. goto out;
  373. }
  374. if(!(d->mode & DDIR)){
  375. error = Edir1;
  376. goto out;
  377. }
  378. if(error = mkqidcmp(&file->qid, d))
  379. goto out;
  380. /*
  381. * For walked elements the implied user must
  382. * have permission to search the directory.
  383. */
  384. if(file->cp != cons.chan && iaccess(file, d, DEXEC)){
  385. error = Eaccess;
  386. goto out;
  387. }
  388. accessdir(p, d, FREAD, file->uid);
  389. if(strcmp(wname, ".") == 0){
  390. setdot:
  391. if(wqid != nil)
  392. *wqid = file->qid;
  393. goto out;
  394. }
  395. if(strcmp(wname, "..") == 0){
  396. if(file->wpath == 0)
  397. goto setdot;
  398. putbuf(p);
  399. p = nil;
  400. addr = file->wpath->addr;
  401. slot = file->wpath->slot;
  402. p1 = getbuf(file->fs->dev, addr, Brd);
  403. if(p1 == nil || checktag(p1, Tdir, QPNONE)){
  404. error = Edir1;
  405. goto out;
  406. }
  407. d1 = getdir(p1, slot);
  408. if(d == nil || !(d1->mode & DALLOC)){
  409. error = Ephase;
  410. goto out;
  411. }
  412. lock(&wpathlock);
  413. file->wpath->refs--;
  414. file->wpath = file->wpath->up;
  415. unlock(&wpathlock);
  416. goto found;
  417. }
  418. for(addr = 0; ; addr++){
  419. if(p == nil){
  420. p = getbuf(file->fs->dev, file->addr, Brd);
  421. if(p == nil || checktag(p, Tdir, QPNONE)){
  422. error = Ealloc;
  423. goto out;
  424. }
  425. d = getdir(p, file->slot);
  426. if(d == nil || !(d->mode & DALLOC)){
  427. error = Ealloc;
  428. goto out;
  429. }
  430. }
  431. qpath = d->qid.path;
  432. p1 = dnodebuf1(p, d, addr, 0, file->uid);
  433. p = nil;
  434. if(p1 == nil || checktag(p1, Tdir, qpath)){
  435. error = Eentry;
  436. goto out;
  437. }
  438. for(slot = 0; slot < DIRPERBUF; slot++){
  439. d1 = getdir(p1, slot);
  440. if (!(d1->mode & DALLOC) ||
  441. strncmp(wname, d1->name, NAMELEN) != 0)
  442. continue;
  443. /*
  444. * update walk path
  445. */
  446. if((w = newwp()) == nil){
  447. error = Ewalk;
  448. goto out;
  449. }
  450. w->addr = file->addr;
  451. w->slot = file->slot;
  452. w->up = file->wpath;
  453. file->wpath = w;
  454. slot += DIRPERBUF*addr;
  455. goto found;
  456. }
  457. putbuf(p1);
  458. p1 = nil;
  459. }
  460. found:
  461. file->addr = p1->addr;
  462. mkqid(&file->qid, d1, 1);
  463. putbuf(p1);
  464. p1 = nil;
  465. file->slot = slot;
  466. if(wqid != nil)
  467. *wqid = file->qid;
  468. out:
  469. if(p1 != nil)
  470. putbuf(p1);
  471. if(p != nil)
  472. putbuf(p);
  473. return error;
  474. }
  475. static int
  476. walk(Chan* chan, Fcall* f, Fcall* r)
  477. {
  478. int error, nwname;
  479. File *file, *nfile, tfile;
  480. /*
  481. * The file identified by f->fid must be valid in the
  482. * current session and must not have been opened for I/O
  483. * by an open or create message.
  484. */
  485. if((file = filep(chan, f->fid, 0)) == nil)
  486. return Efid;
  487. if(file->open != 0){
  488. qunlock(file);
  489. return Emode;
  490. }
  491. /*
  492. * If newfid is not the same as fid, allocate a new file;
  493. * a side effect is checking newfid is not already in use (error);
  494. * if there are no names to walk this will be equivalent to a
  495. * simple 'clone' operation.
  496. * Otherwise, fid and newfid are the same and if there are names
  497. * to walk make a copy of 'file' to be used during the walk as
  498. * 'file' must only be updated on success.
  499. * Finally, it's a no-op if newfid is the same as fid and f->nwname
  500. * is 0.
  501. */
  502. r->nwqid = 0;
  503. if(f->newfid != f->fid){
  504. if((nfile = filep(chan, f->newfid, 1)) == nil){
  505. qunlock(file);
  506. return Efidinuse;
  507. }
  508. } else if(f->nwname != 0){
  509. nfile = &tfile;
  510. memset(nfile, 0, sizeof(File));
  511. nfile->cp = chan;
  512. nfile->fid = ~0;
  513. } else {
  514. qunlock(file);
  515. return 0;
  516. }
  517. clone(nfile, file);
  518. /*
  519. * Should check name is not too long.
  520. */
  521. error = 0;
  522. for(nwname = 0; nwname < f->nwname; nwname++){
  523. error = walkname(nfile, f->wname[nwname], &r->wqid[r->nwqid]);
  524. if(error != 0 || ++r->nwqid >= MAXDAT/sizeof(Qid))
  525. break;
  526. }
  527. if(f->nwname == 0){
  528. /*
  529. * Newfid must be different to fid (see above)
  530. * so this is a simple 'clone' operation - there's
  531. * nothing to do except unlock unless there's
  532. * an error.
  533. */
  534. if(error){
  535. freewp(nfile->wpath);
  536. qunlock(nfile);
  537. freefp(nfile);
  538. } else
  539. qunlock(nfile);
  540. } else if(r->nwqid < f->nwname){
  541. /*
  542. * Didn't walk all elements, 'clunk' nfile
  543. * and leave 'file' alone.
  544. * Clear error if some of the elements were
  545. * walked OK.
  546. */
  547. freewp(nfile->wpath);
  548. if(nfile != &tfile){
  549. qunlock(nfile);
  550. freefp(nfile);
  551. }
  552. if(r->nwqid != 0)
  553. error = 0;
  554. } else {
  555. /*
  556. * Walked all elements. If newfid is the same
  557. * as fid must update 'file' from the temporary
  558. * copy used during the walk.
  559. * Otherwise just unlock (when using tfile there's
  560. * no need to unlock as it's a local).
  561. */
  562. if(nfile == &tfile){
  563. file->qid = nfile->qid;
  564. freewp(file->wpath);
  565. file->wpath = nfile->wpath;
  566. file->addr = nfile->addr;
  567. file->slot = nfile->slot;
  568. } else
  569. qunlock(nfile);
  570. }
  571. qunlock(file);
  572. return error;
  573. }
  574. static int
  575. fs_open(Chan* chan, Fcall* f, Fcall* r)
  576. {
  577. Iobuf *p;
  578. Dentry *d;
  579. File *file;
  580. Tlock *t;
  581. Qid qid;
  582. int error, ro, fmod, wok;
  583. wok = 0;
  584. p = nil;
  585. if(chan == cons.chan || writeallow)
  586. wok = 1;
  587. if((file = filep(chan, f->fid, 0)) == nil){
  588. error = Efid;
  589. goto out;
  590. }
  591. if(file->open != 0){
  592. error = Emode;
  593. goto out;
  594. }
  595. /*
  596. * if remove on close, check access here
  597. */
  598. ro = file->fs->dev->type == Devro;
  599. if(f->mode & ORCLOSE){
  600. if(ro){
  601. error = Eronly;
  602. goto out;
  603. }
  604. /*
  605. * check on parent directory of file to be deleted
  606. */
  607. if(file->wpath == 0 || file->wpath->addr == file->addr){
  608. error = Ephase;
  609. goto out;
  610. }
  611. p = getbuf(file->fs->dev, file->wpath->addr, Brd);
  612. if(p == nil || checktag(p, Tdir, QPNONE)){
  613. error = Ephase;
  614. goto out;
  615. }
  616. d = getdir(p, file->wpath->slot);
  617. if(d == nil || !(d->mode & DALLOC)){
  618. error = Ephase;
  619. goto out;
  620. }
  621. if(iaccess(file, d, DWRITE)){
  622. error = Eaccess;
  623. goto out;
  624. }
  625. putbuf(p);
  626. }
  627. p = getbuf(file->fs->dev, file->addr, Brd);
  628. if(p == nil || checktag(p, Tdir, QPNONE)){
  629. error = Ealloc;
  630. goto out;
  631. }
  632. d = getdir(p, file->slot);
  633. if(d == nil || !(d->mode & DALLOC)){
  634. error = Ealloc;
  635. goto out;
  636. }
  637. if(error = mkqidcmp(&file->qid, d))
  638. goto out;
  639. mkqid(&qid, d, 1);
  640. switch(f->mode & 7){
  641. case OREAD:
  642. if(iaccess(file, d, DREAD) && !wok)
  643. goto badaccess;
  644. fmod = FREAD;
  645. break;
  646. case OWRITE:
  647. if((d->mode & DDIR) || (iaccess(file, d, DWRITE) && !wok))
  648. goto badaccess;
  649. if(ro){
  650. error = Eronly;
  651. goto out;
  652. }
  653. fmod = FWRITE;
  654. break;
  655. case ORDWR:
  656. if((d->mode & DDIR)
  657. || (iaccess(file, d, DREAD) && !wok)
  658. || (iaccess(file, d, DWRITE) && !wok))
  659. goto badaccess;
  660. if(ro){
  661. error = Eronly;
  662. goto out;
  663. }
  664. fmod = FREAD+FWRITE;
  665. break;
  666. case OEXEC:
  667. if((d->mode & DDIR) || (iaccess(file, d, DEXEC) && !wok))
  668. goto badaccess;
  669. fmod = FREAD;
  670. break;
  671. default:
  672. error = Emode;
  673. goto out;
  674. }
  675. if(f->mode & OTRUNC){
  676. if((d->mode & DDIR) || (iaccess(file, d, DWRITE) && !wok))
  677. goto badaccess;
  678. if(ro){
  679. error = Eronly;
  680. goto out;
  681. }
  682. }
  683. t = 0;
  684. if(d->mode & DLOCK){
  685. if((t = tlocked(p, d)) == nil){
  686. error = Elocked;
  687. goto out;
  688. }
  689. }
  690. if(f->mode & ORCLOSE)
  691. fmod |= FREMOV;
  692. file->open = fmod;
  693. if((f->mode & OTRUNC) && !(d->mode & DAPND)){
  694. dtrunc(p, d, file->uid);
  695. qid.vers = d->qid.version;
  696. }
  697. r->qid = qid;
  698. file->tlock = t;
  699. if(t != nil)
  700. t->file = file;
  701. file->lastra = 1;
  702. goto out;
  703. badaccess:
  704. error = Eaccess;
  705. file->open = 0;
  706. out:
  707. if(p != nil)
  708. putbuf(p);
  709. if(file != nil)
  710. qunlock(file);
  711. r->iounit = chan->msize-IOHDRSZ;
  712. return error;
  713. }
  714. static int
  715. fs_create(Chan* chan, Fcall* f, Fcall* r)
  716. {
  717. Iobuf *p, *p1;
  718. Dentry *d, *d1;
  719. File *file;
  720. int error, slot, slot1, fmod, wok;
  721. Off addr, addr1, path;
  722. Tlock *t;
  723. Wpath *w;
  724. wok = 0;
  725. p = nil;
  726. if(chan == cons.chan || writeallow)
  727. wok = 1;
  728. if((file = filep(chan, f->fid, 0)) == nil){
  729. error = Efid;
  730. goto out;
  731. }
  732. if(file->fs->dev->type == Devro){
  733. error = Eronly;
  734. goto out;
  735. }
  736. if(file->qid.type & QTAUTH){
  737. error = Emode;
  738. goto out;
  739. }
  740. p = getbuf(file->fs->dev, file->addr, Brd);
  741. if(p == nil || checktag(p, Tdir, QPNONE)){
  742. error = Ealloc;
  743. goto out;
  744. }
  745. d = getdir(p, file->slot);
  746. if(d == nil || !(d->mode & DALLOC)){
  747. error = Ealloc;
  748. goto out;
  749. }
  750. if(error = mkqidcmp(&file->qid, d))
  751. goto out;
  752. if(!(d->mode & DDIR)){
  753. error = Edir2;
  754. goto out;
  755. }
  756. if(iaccess(file, d, DWRITE) && !wok) {
  757. error = Eaccess;
  758. goto out;
  759. }
  760. accessdir(p, d, FREAD, file->uid);
  761. /*
  762. * Check the name is valid (and will fit in an old
  763. * directory entry for the moment).
  764. */
  765. if(error = checkname9p2(f->name))
  766. goto out;
  767. addr1 = 0;
  768. slot1 = 0; /* set */
  769. for(addr = 0; ; addr++){
  770. if((p1 = dnodebuf(p, d, addr, 0, file->uid)) == nil){
  771. if(addr1 != 0)
  772. break;
  773. p1 = dnodebuf(p, d, addr, Tdir, file->uid);
  774. }
  775. if(p1 == nil){
  776. error = Efull;
  777. goto out;
  778. }
  779. if(checktag(p1, Tdir, d->qid.path)){
  780. putbuf(p1);
  781. goto phase;
  782. }
  783. for(slot = 0; slot < DIRPERBUF; slot++){
  784. d1 = getdir(p1, slot);
  785. if(!(d1->mode & DALLOC)){
  786. if(addr1 == 0){
  787. addr1 = p1->addr;
  788. slot1 = slot + addr*DIRPERBUF;
  789. }
  790. continue;
  791. }
  792. if(strncmp(f->name, d1->name, sizeof(d1->name)) == 0){
  793. putbuf(p1);
  794. error = Eexist;
  795. goto out;
  796. }
  797. }
  798. putbuf(p1);
  799. }
  800. switch(f->mode & 7){
  801. case OEXEC:
  802. case OREAD: /* seems only useful to make directories */
  803. fmod = FREAD;
  804. break;
  805. case OWRITE:
  806. fmod = FWRITE;
  807. break;
  808. case ORDWR:
  809. fmod = FREAD+FWRITE;
  810. break;
  811. default:
  812. error = Emode;
  813. goto out;
  814. }
  815. if(f->perm & PDIR)
  816. if((f->mode & OTRUNC) || (f->perm & PAPND) || (fmod & FWRITE))
  817. goto badaccess;
  818. /*
  819. * do it
  820. */
  821. path = qidpathgen(file->fs->dev);
  822. if((p1 = getbuf(file->fs->dev, addr1, Brd|Bimm|Bmod)) == nil)
  823. goto phase;
  824. d1 = getdir(p1, slot1);
  825. if(d1 == nil || checktag(p1, Tdir, d->qid.path)) {
  826. putbuf(p1);
  827. goto phase;
  828. }
  829. if(d1->mode & DALLOC){
  830. putbuf(p1);
  831. goto phase;
  832. }
  833. strncpy(d1->name, f->name, sizeof(d1->name));
  834. if(chan == cons.chan){
  835. d1->uid = cons.uid;
  836. d1->gid = cons.gid;
  837. } else {
  838. d1->uid = file->uid;
  839. d1->gid = d->gid;
  840. f->perm &= d->mode | ~0666;
  841. if(f->perm & PDIR)
  842. f->perm &= d->mode | ~0777;
  843. }
  844. d1->qid.path = path;
  845. d1->qid.version = 0;
  846. d1->mode = DALLOC | (f->perm & 0777);
  847. if(f->perm & PDIR) {
  848. d1->mode |= DDIR;
  849. d1->qid.path |= QPDIR;
  850. }
  851. if(f->perm & PAPND)
  852. d1->mode |= DAPND;
  853. t = nil;
  854. if(f->perm & PLOCK){
  855. d1->mode |= DLOCK;
  856. t = tlocked(p1, d1);
  857. /* if nil, out of tlock structures */
  858. }
  859. accessdir(p1, d1, FWRITE, file->uid);
  860. mkqid(&r->qid, d1, 0);
  861. putbuf(p1);
  862. accessdir(p, d, FWRITE, file->uid);
  863. /*
  864. * do a walk to new directory entry
  865. */
  866. if((w = newwp()) == nil){
  867. error = Ewalk;
  868. goto out;
  869. }
  870. w->addr = file->addr;
  871. w->slot = file->slot;
  872. w->up = file->wpath;
  873. file->wpath = w;
  874. file->qid = r->qid;
  875. file->tlock = t;
  876. if(t != nil)
  877. t->file = file;
  878. file->lastra = 1;
  879. if(f->mode & ORCLOSE)
  880. fmod |= FREMOV;
  881. file->open = fmod;
  882. file->addr = addr1;
  883. file->slot = slot1;
  884. goto out;
  885. badaccess:
  886. error = Eaccess;
  887. goto out;
  888. phase:
  889. error = Ephase;
  890. out:
  891. if(p != nil)
  892. putbuf(p);
  893. if(file != nil)
  894. qunlock(file);
  895. r->iounit = chan->msize-IOHDRSZ;
  896. return error;
  897. }
  898. static int
  899. fs_read(Chan* chan, Fcall* f, Fcall* r, uint8_t* data)
  900. {
  901. Iobuf *p, *p1;
  902. File *file;
  903. Dentry *d, *d1;
  904. Tlock *t;
  905. Off addr, offset, start;
  906. Timet tim;
  907. int error, iounit, nread, count, n, o, slot;
  908. Msgbuf *dmb;
  909. Dir dir;
  910. p = nil;
  911. error = 0;
  912. count = f->count;
  913. offset = f->offset;
  914. nread = 0;
  915. if((file = filep(chan, f->fid, 0)) == nil){
  916. error = Efid;
  917. goto out;
  918. }
  919. if(!(file->open & FREAD)){
  920. error = Eopen;
  921. goto out;
  922. }
  923. iounit = chan->msize-IOHDRSZ;
  924. if(count < 0 || count > iounit){
  925. error = Ecount;
  926. goto out;
  927. }
  928. if(offset < 0){
  929. error = Eoffset;
  930. goto out;
  931. }
  932. if(file->qid.type & QTAUTH){
  933. nread = authread(file, (uint8_t*)data, count);
  934. if(nread < 0)
  935. error = Eauth2;
  936. goto out;
  937. }
  938. p = getbuf(file->fs->dev, file->addr, Brd);
  939. if(p == nil || checktag(p, Tdir, QPNONE)){
  940. error = Ealloc;
  941. goto out;
  942. }
  943. d = getdir(p, file->slot);
  944. if(d == nil || !(d->mode & DALLOC)){
  945. error = Ealloc;
  946. goto out;
  947. }
  948. if(error = mkqidcmp(&file->qid, d))
  949. goto out;
  950. if(t = file->tlock){
  951. tim = toytime();
  952. if(t->time < tim || t->file != file){
  953. error = Ebroken;
  954. goto out;
  955. }
  956. /* renew the lock */
  957. t->time = tim + TLOCK;
  958. }
  959. accessdir(p, d, FREAD, file->uid);
  960. if(d->mode & DDIR)
  961. goto dread;
  962. if(offset+count > d->size)
  963. count = d->size - offset;
  964. while(count > 0){
  965. if(p == nil){
  966. p = getbuf(file->fs->dev, file->addr, Brd);
  967. if(p == nil || checktag(p, Tdir, QPNONE)){
  968. error = Ealloc;
  969. goto out;
  970. }
  971. d = getdir(p, file->slot);
  972. if(d == nil || !(d->mode & DALLOC)){
  973. error = Ealloc;
  974. goto out;
  975. }
  976. }
  977. addr = offset / BUFSIZE;
  978. file->lastra = dbufread(p, d, addr, file->lastra, file->uid);
  979. o = offset % BUFSIZE;
  980. n = BUFSIZE - o;
  981. if(n > count)
  982. n = count;
  983. p1 = dnodebuf1(p, d, addr, 0, file->uid);
  984. p = nil;
  985. if(p1 != nil){
  986. if(checktag(p1, Tfile, QPNONE)){
  987. error = Ephase;
  988. putbuf(p1);
  989. goto out;
  990. }
  991. memmove(data+nread, p1->iobuf+o, n);
  992. putbuf(p1);
  993. } else
  994. memset(data+nread, 0, n);
  995. count -= n;
  996. nread += n;
  997. offset += n;
  998. }
  999. goto out;
  1000. dread:
  1001. /*
  1002. * Pick up where we left off last time if nothing has changed,
  1003. * otherwise must scan from the beginning.
  1004. */
  1005. if(offset == file->doffset /*&& file->qid.vers == file->dvers*/){
  1006. addr = file->dslot/DIRPERBUF;
  1007. slot = file->dslot%DIRPERBUF;
  1008. start = offset;
  1009. } else {
  1010. addr = 0;
  1011. slot = 0;
  1012. start = 0;
  1013. }
  1014. dmb = mballoc(iounit, chan, Mbreply1);
  1015. for (;;) {
  1016. if(p == nil){
  1017. /*
  1018. * This is just a check to ensure the entry hasn't
  1019. * gone away during the read of each directory block.
  1020. */
  1021. p = getbuf(file->fs->dev, file->addr, Brd);
  1022. if(p == nil || checktag(p, Tdir, QPNONE)){
  1023. error = Ealloc;
  1024. goto out1;
  1025. }
  1026. d = getdir(p, file->slot);
  1027. if(d == nil || !(d->mode & DALLOC)){
  1028. error = Ealloc;
  1029. goto out1;
  1030. }
  1031. }
  1032. p1 = dnodebuf1(p, d, addr, 0, file->uid);
  1033. p = nil;
  1034. if(p1 == nil)
  1035. goto out1;
  1036. if(checktag(p1, Tdir, QPNONE)){
  1037. error = Ephase;
  1038. putbuf(p1);
  1039. goto out1;
  1040. }
  1041. for(; slot < DIRPERBUF; slot++){
  1042. d1 = getdir(p1, slot);
  1043. if(!(d1->mode & DALLOC))
  1044. continue;
  1045. mkdir9p2(&dir, d1, dmb->data);
  1046. n = convD2M(&dir, data+nread, iounit - nread);
  1047. if(n <= BIT16SZ){
  1048. putbuf(p1);
  1049. goto out1;
  1050. }
  1051. start += n;
  1052. if(start < offset)
  1053. continue;
  1054. if(count < n){
  1055. putbuf(p1);
  1056. goto out1;
  1057. }
  1058. count -= n;
  1059. nread += n;
  1060. offset += n;
  1061. }
  1062. putbuf(p1);
  1063. slot = 0;
  1064. addr++;
  1065. }
  1066. out1:
  1067. mbfree(dmb);
  1068. if(error == 0){
  1069. file->doffset = offset;
  1070. file->dvers = file->qid.vers;
  1071. file->dslot = slot+DIRPERBUF*addr;
  1072. }
  1073. out:
  1074. /*
  1075. * Do we need this any more?
  1076. count = f->count - nread;
  1077. if(count > 0)
  1078. memset(data+nread, 0, count);
  1079. */
  1080. if(p != nil)
  1081. putbuf(p);
  1082. if(file != nil)
  1083. qunlock(file);
  1084. r->count = nread;
  1085. r->data = (char*)data;
  1086. return error;
  1087. }
  1088. static int
  1089. fs_write(Chan* chan, Fcall* f, Fcall* r)
  1090. {
  1091. Iobuf *p, *p1;
  1092. Dentry *d;
  1093. File *file;
  1094. Tlock *t;
  1095. Off offset, addr, qpath;
  1096. Timet tim;
  1097. int count, error, nwrite, o, n;
  1098. error = 0;
  1099. offset = f->offset;
  1100. count = f->count;
  1101. nwrite = 0;
  1102. p = nil;
  1103. if((file = filep(chan, f->fid, 0)) == nil){
  1104. error = Efid;
  1105. goto out;
  1106. }
  1107. if(!(file->open & FWRITE)){
  1108. error = Eopen;
  1109. goto out;
  1110. }
  1111. if(count < 0 || count > chan->msize-IOHDRSZ){
  1112. error = Ecount;
  1113. goto out;
  1114. }
  1115. if(offset < 0) {
  1116. error = Eoffset;
  1117. goto out;
  1118. }
  1119. if(file->qid.type & QTAUTH){
  1120. nwrite = authwrite(file, (uint8_t*)f->data, count);
  1121. if(nwrite < 0)
  1122. error = Eauth2;
  1123. goto out;
  1124. } else if(file->fs->dev->type == Devro){
  1125. error = Eronly;
  1126. goto out;
  1127. }
  1128. if ((p = getbuf(file->fs->dev, file->addr, Brd|Bmod)) == nil ||
  1129. (d = getdir(p, file->slot)) == nil || !(d->mode & DALLOC)) {
  1130. error = Ealloc;
  1131. goto out;
  1132. }
  1133. if(error = mkqidcmp(&file->qid, d))
  1134. goto out;
  1135. if(t = file->tlock) {
  1136. tim = toytime();
  1137. if(t->time < tim || t->file != file){
  1138. error = Ebroken;
  1139. goto out;
  1140. }
  1141. /* renew the lock */
  1142. t->time = tim + TLOCK;
  1143. }
  1144. accessdir(p, d, FWRITE, file->uid);
  1145. if(d->mode & DAPND)
  1146. offset = d->size;
  1147. if(offset+count > d->size)
  1148. d->size = offset+count;
  1149. while(count > 0){
  1150. if(p == nil){
  1151. p = getbuf(file->fs->dev, file->addr, Brd|Bmod);
  1152. if(p == nil){
  1153. error = Ealloc;
  1154. goto out;
  1155. }
  1156. d = getdir(p, file->slot);
  1157. if(d == nil || !(d->mode & DALLOC)){
  1158. error = Ealloc;
  1159. goto out;
  1160. }
  1161. }
  1162. addr = offset / BUFSIZE;
  1163. o = offset % BUFSIZE;
  1164. n = BUFSIZE - o;
  1165. if(n > count)
  1166. n = count;
  1167. qpath = d->qid.path;
  1168. p1 = dnodebuf1(p, d, addr, Tfile, file->uid);
  1169. p = nil;
  1170. if(p1 == nil) {
  1171. error = Efull;
  1172. goto out;
  1173. }
  1174. if(checktag(p1, Tfile, qpath)){
  1175. putbuf(p1);
  1176. error = Ephase;
  1177. goto out;
  1178. }
  1179. memmove(p1->iobuf+o, f->data+nwrite, n);
  1180. p1->flags |= Bmod;
  1181. putbuf(p1);
  1182. count -= n;
  1183. nwrite += n;
  1184. offset += n;
  1185. }
  1186. out:
  1187. if(p != nil)
  1188. putbuf(p);
  1189. if(file != nil)
  1190. qunlock(file);
  1191. r->count = nwrite;
  1192. return error;
  1193. }
  1194. static int
  1195. _clunk(File* file, int remove, int wok)
  1196. {
  1197. Tlock *t;
  1198. int error;
  1199. error = 0;
  1200. if(t = file->tlock){
  1201. if(t->file == file)
  1202. t->time = 0; /* free the lock */
  1203. file->tlock = 0;
  1204. }
  1205. if(remove && (file->qid.type & QTAUTH) == 0)
  1206. error = doremove(file, wok);
  1207. file->open = 0;
  1208. freewp(file->wpath);
  1209. authfree(file->auth);
  1210. freefp(file);
  1211. qunlock(file);
  1212. return error;
  1213. }
  1214. static int
  1215. clunk(Chan* chan, Fcall* f, Fcall*)
  1216. {
  1217. File *file;
  1218. if((file = filep(chan, f->fid, 0)) == nil)
  1219. return Efid;
  1220. _clunk(file, file->open & FREMOV, 0);
  1221. return 0;
  1222. }
  1223. static int
  1224. fs_remove(Chan* chan, Fcall* f, Fcall*)
  1225. {
  1226. File *file;
  1227. if((file = filep(chan, f->fid, 0)) == nil)
  1228. return Efid;
  1229. return _clunk(file, 1, chan == cons.chan);
  1230. }
  1231. static int
  1232. fs_stat(Chan* chan, Fcall* f, Fcall* r, uint8_t* data)
  1233. {
  1234. Dir dir;
  1235. Iobuf *p;
  1236. Dentry *d, dentry;
  1237. File *file;
  1238. int error, len;
  1239. error = 0;
  1240. p = nil;
  1241. if((file = filep(chan, f->fid, 0)) == nil)
  1242. return Efid;
  1243. if(file->qid.type & QTAUTH){
  1244. memset(&dentry, 0, sizeof dentry);
  1245. d = &dentry;
  1246. mkqid9p1(&d->qid, &file->qid);
  1247. strcpy(d->name, "#¿");
  1248. d->uid = authuid(file->auth);
  1249. d->gid = d->uid;
  1250. d->muid = d->uid;
  1251. d->atime = time(nil);
  1252. d->mtime = d->atime;
  1253. d->size = 0;
  1254. } else {
  1255. p = getbuf(file->fs->dev, file->addr, Brd);
  1256. if(p == nil || checktag(p, Tdir, QPNONE)){
  1257. error = Edir1;
  1258. goto out;
  1259. }
  1260. d = getdir(p, file->slot);
  1261. if(d == nil || !(d->mode & DALLOC)){
  1262. error = Ealloc;
  1263. goto out;
  1264. }
  1265. if(error = mkqidcmp(&file->qid, d))
  1266. goto out;
  1267. if(d->qid.path == QPROOT) /* stat of root gives time */
  1268. d->atime = time(nil);
  1269. }
  1270. len = mkdir9p2(&dir, d, data);
  1271. data += len;
  1272. if((r->nstat = convD2M(&dir, data, chan->msize - len)) == 0)
  1273. error = Eedge;
  1274. r->stat = data;
  1275. out:
  1276. if(p != nil)
  1277. putbuf(p);
  1278. if(file != nil)
  1279. qunlock(file);
  1280. return error;
  1281. }
  1282. static int
  1283. fs_wstat(Chan* chan, Fcall* f, Fcall*, char* strs)
  1284. {
  1285. Iobuf *p, *p1;
  1286. Dentry *d, *d1;
  1287. File *file;
  1288. int error, err, gid, gl, muid, op, slot, tsync, uid;
  1289. int32_t addr;
  1290. Dir dir;
  1291. if(convM2D(f->stat, f->nstat, &dir, strs) == 0)
  1292. return Econvert;
  1293. /*
  1294. * Get the file.
  1295. * If user 'none' (uid == 0), can't do anything;
  1296. * if filesystem is read-only, can't change anything.
  1297. */
  1298. if((file = filep(chan, f->fid, 0)) == nil)
  1299. return Efid;
  1300. p = p1 = nil;
  1301. if(file->uid == 0){
  1302. error = Eaccess;
  1303. goto out;
  1304. }
  1305. if(file->fs->dev->type == Devro){
  1306. error = Eronly;
  1307. goto out;
  1308. }
  1309. if(file->qid.type & QTAUTH){
  1310. error = Emode;
  1311. goto out;
  1312. }
  1313. /*
  1314. * Get the current entry and check it is still valid.
  1315. */
  1316. p = getbuf(file->fs->dev, file->addr, Brd);
  1317. if(p == nil || checktag(p, Tdir, QPNONE)){
  1318. error = Ealloc;
  1319. goto out;
  1320. }
  1321. d = getdir(p, file->slot);
  1322. if(d == nil || !(d->mode & DALLOC)){
  1323. error = Ealloc;
  1324. goto out;
  1325. }
  1326. if(error = mkqidcmp(&file->qid, d))
  1327. goto out;
  1328. /*
  1329. * Run through each of the (sub-)fields in the provided Dir
  1330. * checking for validity and whether it's a default:
  1331. * .type, .dev and .atime are completely ignored and not checked;
  1332. * .qid.path, .qid.vers and .muid are checked for validity but
  1333. * any attempt to change them is an error.
  1334. * .qid.type/.mode, .mtime, .name, .length, .uid and .gid can
  1335. * possibly be changed (and .muid iff wstatallow).
  1336. *
  1337. * 'Op' flags there are changed fields, i.e. it's not a no-op.
  1338. * 'Tsync' flags all fields are defaulted.
  1339. *
  1340. * Wstatallow and writeallow are set to allow changes during the
  1341. * fileserver bootstrap phase.
  1342. */
  1343. tsync = 1;
  1344. if(dir.qid.path != ~0){
  1345. if(dir.qid.path != file->qid.path){
  1346. error = Ewstatp;
  1347. goto out;
  1348. }
  1349. tsync = 0;
  1350. }
  1351. if(dir.qid.vers != ~0){
  1352. if(dir.qid.vers != file->qid.vers){
  1353. error = Ewstatv;
  1354. goto out;
  1355. }
  1356. tsync = 0;
  1357. }
  1358. /*
  1359. * .qid.type and .mode have some bits in common. Only .mode
  1360. * is currently needed for comparisons with the old mode but
  1361. * if there are changes to the bits also encoded in .qid.type
  1362. * then file->qid must be updated appropriately later.
  1363. */
  1364. if(dir.qid.type == (uint8_t)~0){
  1365. if(dir.mode == ~0)
  1366. dir.qid.type = mktype9p2(d->mode);
  1367. else
  1368. dir.qid.type = dir.mode>>24;
  1369. } else
  1370. tsync = 0;
  1371. if(dir.mode == ~0)
  1372. dir.mode = mkmode9p2(d->mode);
  1373. else
  1374. tsync = 0;
  1375. /*
  1376. * Check dir.qid.type and dir.mode agree, check for any unknown
  1377. * type/mode bits, check for an attempt to change the directory bit.
  1378. */
  1379. if(dir.qid.type != ((dir.mode>>24) & 0xFF)){
  1380. error = Ewstatq;
  1381. goto out;
  1382. }
  1383. if(dir.mode & ~(DMDIR|DMAPPEND|DMEXCL|0777)){
  1384. error = Ewstatb;
  1385. goto out;
  1386. }
  1387. op = dir.mode^mkmode9p2(d->mode);
  1388. if(op & DMDIR){
  1389. error = Ewstatd;
  1390. goto out;
  1391. }
  1392. if(dir.mtime != ~0){
  1393. if(dir.mtime != d->mtime)
  1394. op = 1;
  1395. tsync = 0;
  1396. } else
  1397. dir.mtime = d->mtime;
  1398. if(dir.length == ~(Off)0)
  1399. dir.length = d->size;
  1400. else {
  1401. if (dir.length < 0) {
  1402. error = Ewstatl;
  1403. goto out;
  1404. } else if(dir.length != d->size)
  1405. op = 1;
  1406. tsync = 0;
  1407. }
  1408. /*
  1409. * Check for permission to change .mode, .mtime or .length,
  1410. * must be owner or leader of either group, for which test gid
  1411. * is needed; permission checks on gid will be done later.
  1412. * 'Gl' counts whether neither, one or both groups are led.
  1413. */
  1414. if(dir.gid != nil && *dir.gid != '\0'){
  1415. gid = strtouid(dir.gid);
  1416. tsync = 0;
  1417. } else
  1418. gid = d->gid;
  1419. gl = leadgroup(file->uid, gid) != 0;
  1420. gl += leadgroup(file->uid, d->gid) != 0;
  1421. if(op && !wstatallow && d->uid != file->uid && !gl){
  1422. error = Ewstato;
  1423. goto out;
  1424. }
  1425. /*
  1426. * Rename.
  1427. * Check .name is valid and different to the current.
  1428. */
  1429. if(dir.name != nil && *dir.name != '\0'){
  1430. if(error = checkname9p2(dir.name))
  1431. goto out;
  1432. if(strncmp(dir.name, d->name, NAMELEN))
  1433. op = 1;
  1434. else
  1435. dir.name = d->name;
  1436. tsync = 0;
  1437. } else
  1438. dir.name = d->name;
  1439. /*
  1440. * If the name is really to be changed check it's unique
  1441. * and there is write permission in the parent.
  1442. */
  1443. if(dir.name != d->name){
  1444. /*
  1445. * First get parent.
  1446. * Must drop current entry to prevent
  1447. * deadlock when searching that new name
  1448. * already exists below.
  1449. */
  1450. putbuf(p);
  1451. p = nil;
  1452. if(file->wpath == nil){
  1453. error = Ephase;
  1454. goto out;
  1455. }
  1456. p1 = getbuf(file->fs->dev, file->wpath->addr, Brd);
  1457. if(p1 == nil || checktag(p1, Tdir, QPNONE)){
  1458. error = Ephase;
  1459. goto out;
  1460. }
  1461. d1 = getdir(p1, file->wpath->slot);
  1462. if(d1 == nil || !(d1->mode & DALLOC)){
  1463. error = Ephase;
  1464. goto out;
  1465. }
  1466. /*
  1467. * Check entries in parent for new name.
  1468. */
  1469. for(addr = 0; ; addr++){
  1470. if((p = dnodebuf(p1, d1, addr, 0, file->uid)) == nil)
  1471. break;
  1472. if(checktag(p, Tdir, d1->qid.path)){
  1473. putbuf(p);
  1474. continue;
  1475. }
  1476. for(slot = 0; slot < DIRPERBUF; slot++){
  1477. d = getdir(p, slot);
  1478. if(!(d->mode & DALLOC) ||
  1479. strncmp(dir.name, d->name, sizeof d->name))
  1480. continue;
  1481. error = Eexist;
  1482. goto out;
  1483. }
  1484. putbuf(p);
  1485. }
  1486. /*
  1487. * Reacquire entry and check it's still OK.
  1488. */
  1489. p = getbuf(file->fs->dev, file->addr, Brd);
  1490. if(p == nil || checktag(p, Tdir, QPNONE)){
  1491. error = Ephase;
  1492. goto out;
  1493. }
  1494. d = getdir(p, file->slot);
  1495. if(d == nil || !(d->mode & DALLOC)){
  1496. error = Ephase;
  1497. goto out;
  1498. }
  1499. /*
  1500. * Check write permission in the parent.
  1501. */
  1502. if(!wstatallow && !writeallow && iaccess(file, d1, DWRITE)){
  1503. error = Eaccess;
  1504. goto out;
  1505. }
  1506. }
  1507. /*
  1508. * Check for permission to change owner - must be god.
  1509. */
  1510. if(dir.uid != nil && *dir.uid != '\0'){
  1511. uid = strtouid(dir.uid);
  1512. if(uid != d->uid){
  1513. if(!wstatallow){
  1514. error = Ewstatu;
  1515. goto out;
  1516. }
  1517. op = 1;
  1518. }
  1519. tsync = 0;
  1520. } else
  1521. uid = d->uid;
  1522. if(dir.muid != nil && *dir.muid != '\0'){
  1523. muid = strtouid(dir.muid);
  1524. if(muid != d->muid){
  1525. if(!wstatallow){
  1526. error = Ewstatm;
  1527. goto out;
  1528. }
  1529. op = 1;
  1530. }
  1531. tsync = 0;
  1532. } else
  1533. muid = d->muid;
  1534. /*
  1535. * Check for permission to change group, must be
  1536. * either owner and in new group or leader of both groups.
  1537. */
  1538. if(gid != d->gid){
  1539. if(!(wstatallow || writeallow)
  1540. && !(d->uid == file->uid && ingroup(file->uid, gid))
  1541. && !(gl == 2)){
  1542. error = Ewstatg;
  1543. goto out;
  1544. }
  1545. op = 1;
  1546. }
  1547. /*
  1548. * Checks all done, update if necessary.
  1549. */
  1550. if(op){
  1551. d->mode = mkmode9p1(dir.mode);
  1552. file->qid.type = mktype9p2(d->mode);
  1553. d->mtime = dir.mtime;
  1554. if (dir.length < d->size) {
  1555. err = dtrunclen(p, d, dir.length, uid);
  1556. if (error == 0)
  1557. error = err;
  1558. }
  1559. d->size = dir.length;
  1560. if(dir.name != d->name)
  1561. strncpy(d->name, dir.name, sizeof(d->name));
  1562. d->uid = uid;
  1563. d->gid = gid;
  1564. d->muid = muid;
  1565. }
  1566. if(!tsync)
  1567. accessdir(p, d, FREAD, file->uid);
  1568. out:
  1569. if(p != nil)
  1570. putbuf(p);
  1571. if(p1 != nil)
  1572. putbuf(p1);
  1573. qunlock(file);
  1574. return error;
  1575. }
  1576. int
  1577. serve9p2(Msgbuf* mb)
  1578. {
  1579. Chan *chan;
  1580. Fcall f, r;
  1581. Msgbuf *data, *rmb;
  1582. char ename[64];
  1583. int error, n, type;
  1584. static int once;
  1585. if(once == 0){
  1586. fmtinstall('F', fcallfmt);
  1587. once = 1;
  1588. }
  1589. /*
  1590. * 0 return means i don't understand this message,
  1591. * 1 return means i dealt with it, including error
  1592. * replies.
  1593. */
  1594. if(convM2S(mb->data, mb->count, &f) != mb->count)
  1595. {
  1596. print("didn't like %d byte message\n", mb->count);
  1597. return 0;
  1598. }
  1599. type = f.type;
  1600. if(type < Tversion || type >= Tmax || (type & 1) || type == Terror)
  1601. return 0;
  1602. chan = mb->chan;
  1603. if(CHAT(chan))
  1604. print("9p2: f %F\n", &f);
  1605. r.type = type+1;
  1606. r.tag = f.tag;
  1607. error = 0;
  1608. data = nil;
  1609. switch(type){
  1610. default:
  1611. r.type = Rerror;
  1612. snprint(ename, sizeof(ename), "unknown message: %F", &f);
  1613. r.ename = ename;
  1614. break;
  1615. case Tversion:
  1616. error = version(chan, &f, &r);
  1617. break;
  1618. case Tauth:
  1619. error = auth(chan, &f, &r);
  1620. break;
  1621. case Tattach:
  1622. error = attach(chan, &f, &r);
  1623. break;
  1624. case Tflush:
  1625. error = flush(chan, &f, &r);
  1626. break;
  1627. case Twalk:
  1628. error = walk(chan, &f, &r);
  1629. break;
  1630. case Topen:
  1631. error = fs_open(chan, &f, &r);
  1632. break;
  1633. case Tcreate:
  1634. error = fs_create(chan, &f, &r);
  1635. break;
  1636. case Tread:
  1637. data = mballoc(chan->msize, chan, Mbreply1);
  1638. error = fs_read(chan, &f, &r, data->data);
  1639. break;
  1640. case Twrite:
  1641. error = fs_write(chan, &f, &r);
  1642. break;
  1643. case Tclunk:
  1644. error = clunk(chan, &f, &r);
  1645. break;
  1646. case Tremove:
  1647. error = fs_remove(chan, &f, &r);
  1648. break;
  1649. case Tstat:
  1650. data = mballoc(chan->msize, chan, Mbreply1);
  1651. error = fs_stat(chan, &f, &r, data->data);
  1652. break;
  1653. case Twstat:
  1654. data = mballoc(chan->msize, chan, Mbreply1);
  1655. error = fs_wstat(chan, &f, &r, (char*)data->data);
  1656. break;
  1657. }
  1658. if(error != 0){
  1659. r.type = Rerror;
  1660. if(error >= MAXERR){
  1661. snprint(ename, sizeof(ename), "error %d", error);
  1662. r.ename = ename;
  1663. } else
  1664. r.ename = errstr9p[error];
  1665. }
  1666. if(CHAT(chan))
  1667. print("9p2: r %F\n", &r);
  1668. rmb = mballoc(chan->msize, chan, Mbreply2);
  1669. n = convS2M(&r, rmb->data, chan->msize);
  1670. if(data != nil)
  1671. mbfree(data);
  1672. if(n == 0){
  1673. type = r.type;
  1674. r.type = Rerror;
  1675. /*
  1676. * If a Tversion has not been seen on the chan then
  1677. * chan->msize will be 0. In that case craft a special
  1678. * Rerror message. It's fortunate that the mballoc above
  1679. * for rmb will have returned a Msgbuf of MAXMSG size
  1680. * when given a request with count of 0...
  1681. */
  1682. if(chan->msize == 0){
  1683. r.ename = "Tversion not seen";
  1684. n = convS2M(&r, rmb->data, MAXMSG);
  1685. } else {
  1686. snprint(ename, sizeof(ename), "9p2: convS2M: type %d",
  1687. type);
  1688. r.ename = ename;
  1689. n = convS2M(&r, rmb->data, chan->msize);
  1690. }
  1691. print("%s\n", r.ename);
  1692. if(n == 0){
  1693. /*
  1694. * What to do here, the failure notification failed?
  1695. */
  1696. mbfree(rmb);
  1697. return 1;
  1698. }
  1699. }
  1700. rmb->count = n;
  1701. rmb->param = mb->param;
  1702. /* done 9P processing, write reply to network */
  1703. fs_send(chan->reply, rmb);
  1704. return 1;
  1705. }