9p2.c 35 KB

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