9p2.c 34 KB

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