9p2.c 35 KB

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