9p.c 21 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121
  1. #include "stdinc.h"
  2. #include "9.h"
  3. enum {
  4. OMODE = 0x7, /* Topen/Tcreate mode */
  5. };
  6. enum {
  7. PermX = 1,
  8. PermW = 2,
  9. PermR = 4,
  10. };
  11. static char EPermission[] = "permission denied";
  12. static int
  13. permFile(File* file, Fid* fid, int perm)
  14. {
  15. char *u;
  16. DirEntry de;
  17. if(!fileGetDir(file, &de))
  18. return 0;
  19. /*
  20. * User none only gets other permissions.
  21. */
  22. if(strcmp(fid->uname, unamenone) != 0){
  23. /*
  24. * There is only one uid<->uname mapping
  25. * and it's already cached in the Fid, but
  26. * it might have changed during the lifetime
  27. * if this Fid.
  28. */
  29. if((u = unameByUid(de.uid)) != nil){
  30. if(strcmp(fid->uname, u) == 0 && ((perm<<6) & de.mode)){
  31. vtMemFree(u);
  32. deCleanup(&de);
  33. return 1;
  34. }
  35. vtMemFree(u);
  36. }
  37. if(groupMember(de.gid, fid->uname) && ((perm<<3) & de.mode)){
  38. deCleanup(&de);
  39. return 1;
  40. }
  41. }
  42. if(perm & de.mode){
  43. if(perm == PermX && (de.mode & ModeDir)){
  44. deCleanup(&de);
  45. return 1;
  46. }
  47. if(!groupMember(uidnoworld, fid->uname)){
  48. deCleanup(&de);
  49. return 1;
  50. }
  51. }
  52. if(fsysNoPermCheck(fid->fsys) || fid->con->noperm){
  53. deCleanup(&de);
  54. return 1;
  55. }
  56. vtSetError(EPermission);
  57. deCleanup(&de);
  58. return 0;
  59. }
  60. static int
  61. permFid(Fid* fid, int p)
  62. {
  63. return permFile(fid->file, fid, p);
  64. }
  65. static int
  66. permParent(Fid* fid, int p)
  67. {
  68. int r;
  69. File *parent;
  70. parent = fileGetParent(fid->file);
  71. r = permFile(parent, fid, p);
  72. fileDecRef(parent);
  73. return r;
  74. }
  75. int
  76. validFileName(char* name)
  77. {
  78. char *p;
  79. if(name == nil || name[0] == '\0'){
  80. vtSetError("no file name");
  81. return 0;
  82. }
  83. if(name[0] == '.'){
  84. if(name[1] == '\0' || (name[1] == '.' && name[2] == '\0')){
  85. vtSetError(". and .. illegal as file name");
  86. return 0;
  87. }
  88. }
  89. for(p = name; *p != '\0'; p++){
  90. if((*p & 0xFF) < 040){
  91. vtSetError("bad character in file name");
  92. return 0;
  93. }
  94. }
  95. return 1;
  96. }
  97. static int
  98. rTwstat(Msg* m)
  99. {
  100. Dir dir;
  101. Fid *fid;
  102. ulong mode, oldmode;
  103. DirEntry de;
  104. char *gid, *strs, *uid;
  105. int gl, op, retval, tsync;
  106. if((fid = fidGet(m->con, m->t.fid, FidFWlock)) == nil)
  107. return 0;
  108. gid = uid = nil;
  109. retval = 0;
  110. if(strcmp(fid->uname, unamenone) == 0 || (fid->qid.type & QTAUTH)){
  111. vtSetError(EPermission);
  112. goto error0;
  113. }
  114. if(fileIsRoFs(fid->file) || !groupWriteMember(fid->uname)){
  115. vtSetError("read-only filesystem");
  116. goto error0;
  117. }
  118. if(!fileGetDir(fid->file, &de))
  119. goto error0;
  120. strs = vtMemAlloc(m->t.nstat);
  121. if(convM2D(m->t.stat, m->t.nstat, &dir, strs) == 0){
  122. vtSetError("wstat -- protocol botch");
  123. goto error;
  124. }
  125. /*
  126. * Run through each of the (sub-)fields in the provided Dir
  127. * checking for validity and whether it's a default:
  128. * .type, .dev and .atime are completely ignored and not checked;
  129. * .qid.path, .qid.vers and .muid are checked for validity but
  130. * any attempt to change them is an error.
  131. * .qid.type/.mode, .mtime, .name, .length, .uid and .gid can
  132. * possibly be changed.
  133. *
  134. * 'Op' flags there are changed fields, i.e. it's not a no-op.
  135. * 'Tsync' flags all fields are defaulted.
  136. */
  137. tsync = 1;
  138. if(dir.qid.path != ~0){
  139. if(dir.qid.path != de.qid){
  140. vtSetError("wstat -- attempt to change qid.path");
  141. goto error;
  142. }
  143. tsync = 0;
  144. }
  145. if(dir.qid.vers != ~0){
  146. if(dir.qid.vers != de.mcount){
  147. vtSetError("wstat -- attempt to change qid.vers");
  148. goto error;
  149. }
  150. tsync = 0;
  151. }
  152. if(dir.muid != nil && *dir.muid != '\0'){
  153. if((uid = uidByUname(dir.muid)) == nil){
  154. vtSetError("wstat -- unknown muid");
  155. goto error;
  156. }
  157. if(strcmp(uid, de.mid) != 0){
  158. vtSetError("wstat -- attempt to change muid");
  159. goto error;
  160. }
  161. vtMemFree(uid);
  162. uid = nil;
  163. tsync = 0;
  164. }
  165. /*
  166. * Check .qid.type and .mode agree if neither is defaulted.
  167. */
  168. if(dir.qid.type != (uchar)~0 && dir.mode != ~0){
  169. if(dir.qid.type != ((dir.mode>>24) & 0xFF)){
  170. vtSetError("wstat -- qid.type/mode mismatch");
  171. goto error;
  172. }
  173. }
  174. op = 0;
  175. oldmode = de.mode;
  176. if(dir.qid.type != (uchar)~0 || dir.mode != ~0){
  177. /*
  178. * .qid.type or .mode isn't defaulted, check for unknown bits.
  179. */
  180. if(dir.mode == ~0)
  181. dir.mode = (dir.qid.type<<24)|(de.mode & 0777);
  182. if(dir.mode & ~(DMDIR|DMAPPEND|DMEXCL|DMTMP|0777)){
  183. vtSetError("wstat -- unknown bits in qid.type/mode");
  184. goto error;
  185. }
  186. /*
  187. * Synthesise a mode to check against the current settings.
  188. */
  189. mode = dir.mode & 0777;
  190. if(dir.mode & DMEXCL)
  191. mode |= ModeExclusive;
  192. if(dir.mode & DMAPPEND)
  193. mode |= ModeAppend;
  194. if(dir.mode & DMDIR)
  195. mode |= ModeDir;
  196. if(dir.mode & DMTMP)
  197. mode |= ModeTemporary;
  198. if((de.mode^mode) & ModeDir){
  199. vtSetError("wstat -- attempt to change directory bit");
  200. goto error;
  201. }
  202. if((de.mode & (ModeAppend|ModeExclusive|ModeTemporary|0777)) != mode){
  203. de.mode &= ~(ModeAppend|ModeExclusive|ModeTemporary|0777);
  204. de.mode |= mode;
  205. op = 1;
  206. }
  207. tsync = 0;
  208. }
  209. if(dir.mtime != ~0){
  210. if(dir.mtime != de.mtime){
  211. de.mtime = dir.mtime;
  212. op = 1;
  213. }
  214. tsync = 0;
  215. }
  216. if(dir.length != ~0){
  217. if(dir.length != de.size){
  218. /*
  219. * Cannot change length on append-only files.
  220. * If we're changing the append bit, it's okay.
  221. */
  222. if(de.mode & oldmode & ModeAppend){
  223. vtSetError("wstat -- attempt to change length of append-only file");
  224. goto error;
  225. }
  226. if(de.mode & ModeDir){
  227. vtSetError("wstat -- attempt to change length of directory");
  228. goto error;
  229. }
  230. de.size = dir.length;
  231. op = 1;
  232. }
  233. tsync = 0;
  234. }
  235. /*
  236. * Check for permission to change .mode, .mtime or .length,
  237. * must be owner or leader of either group, for which test gid
  238. * is needed; permission checks on gid will be done later.
  239. */
  240. if(dir.gid != nil && *dir.gid != '\0'){
  241. if((gid = uidByUname(dir.gid)) == nil){
  242. vtSetError("wstat -- unknown gid");
  243. goto error;
  244. }
  245. tsync = 0;
  246. }
  247. else
  248. gid = vtStrDup(de.gid);
  249. /*
  250. * 'Gl' counts whether neither, one or both groups are led.
  251. */
  252. gl = groupLeader(gid, fid->uname) != 0;
  253. gl += groupLeader(de.gid, fid->uname) != 0;
  254. if(op && !(fsysWstatAllow(fid->fsys) || m->con->wstatallow)){
  255. if(strcmp(fid->uid, de.uid) != 0 && !gl){
  256. vtSetError("wstat -- not owner or group leader");
  257. goto error;
  258. }
  259. }
  260. /*
  261. * Check for permission to change group, must be
  262. * either owner and in new group or leader of both groups.
  263. * If gid is nil here then
  264. */
  265. if(strcmp(gid, de.gid) != 0){
  266. if(!(fsysWstatAllow(fid->fsys) || m->con->wstatallow)
  267. && !(strcmp(fid->uid, de.uid) == 0 && groupMember(gid, fid->uname))
  268. && !(gl == 2)){
  269. vtSetError("wstat -- not owner and not group leaders");
  270. goto error;
  271. }
  272. vtMemFree(de.gid);
  273. de.gid = gid;
  274. gid = nil;
  275. op = 1;
  276. tsync = 0;
  277. }
  278. /*
  279. * Rename.
  280. * Check .name is valid and different to the current.
  281. * If so, check write permission in parent.
  282. */
  283. if(dir.name != nil && *dir.name != '\0'){
  284. if(!validFileName(dir.name))
  285. goto error;
  286. if(strcmp(dir.name, de.elem) != 0){
  287. if(!permParent(fid, PermW))
  288. goto error;
  289. vtMemFree(de.elem);
  290. de.elem = vtStrDup(dir.name);
  291. op = 1;
  292. }
  293. tsync = 0;
  294. }
  295. /*
  296. * Check for permission to change owner - must be god.
  297. */
  298. if(dir.uid != nil && *dir.uid != '\0'){
  299. if((uid = uidByUname(dir.uid)) == nil){
  300. vtSetError("wstat -- unknown uid");
  301. goto error;
  302. }
  303. if(strcmp(uid, de.uid) != 0){
  304. if(!(fsysWstatAllow(fid->fsys) || m->con->wstatallow)){
  305. vtSetError("wstat -- not owner");
  306. goto error;
  307. }
  308. if(strcmp(uid, uidnoworld) == 0){
  309. vtSetError(EPermission);
  310. goto error;
  311. }
  312. vtMemFree(de.uid);
  313. de.uid = uid;
  314. uid = nil;
  315. op = 1;
  316. }
  317. tsync = 0;
  318. }
  319. if(op)
  320. retval = fileSetDir(fid->file, &de, fid->uid);
  321. else
  322. retval = 1;
  323. if(tsync){
  324. /*
  325. * All values were defaulted,
  326. * make the state of the file exactly what it
  327. * claims to be before returning...
  328. */
  329. USED(tsync);
  330. }
  331. error:
  332. deCleanup(&de);
  333. vtMemFree(strs);
  334. if(gid != nil)
  335. vtMemFree(gid);
  336. if(uid != nil)
  337. vtMemFree(uid);
  338. error0:
  339. fidPut(fid);
  340. return retval;
  341. };
  342. static int
  343. rTstat(Msg* m)
  344. {
  345. Dir dir;
  346. Fid *fid;
  347. DirEntry de;
  348. if((fid = fidGet(m->con, m->t.fid, 0)) == nil)
  349. return 0;
  350. if(fid->qid.type & QTAUTH){
  351. memset(&dir, 0, sizeof(Dir));
  352. dir.qid = fid->qid;
  353. dir.mode = DMAUTH;
  354. dir.atime = time(0L);
  355. dir.mtime = dir.atime;
  356. dir.length = 0;
  357. dir.name = "#¿";
  358. dir.uid = fid->uname;
  359. dir.gid = fid->uname;
  360. dir.muid = fid->uname;
  361. if((m->r.nstat = convD2M(&dir, m->data, m->con->msize)) == 0){
  362. vtSetError("stat QTAUTH botch");
  363. fidPut(fid);
  364. return 0;
  365. }
  366. m->r.stat = m->data;
  367. fidPut(fid);
  368. return 1;
  369. }
  370. if(!fileGetDir(fid->file, &de)){
  371. fidPut(fid);
  372. return 0;
  373. }
  374. fidPut(fid);
  375. /*
  376. * TODO: optimise this copy (in convS2M) away somehow.
  377. * This pettifoggery with m->data will do for the moment.
  378. */
  379. m->r.nstat = dirDe2M(&de, m->data, m->con->msize);
  380. m->r.stat = m->data;
  381. deCleanup(&de);
  382. return 1;
  383. }
  384. static int
  385. _rTclunk(Fid* fid, int remove)
  386. {
  387. int rok;
  388. if(fid->excl)
  389. exclFree(fid);
  390. rok = 1;
  391. if(remove && !(fid->qid.type & QTAUTH)){
  392. if((rok = permParent(fid, PermW)) != 0)
  393. rok = fileRemove(fid->file, fid->uid);
  394. }
  395. fidClunk(fid);
  396. return rok;
  397. }
  398. static int
  399. rTremove(Msg* m)
  400. {
  401. Fid *fid;
  402. if((fid = fidGet(m->con, m->t.fid, FidFWlock)) == nil)
  403. return 0;
  404. return _rTclunk(fid, 1);
  405. }
  406. static int
  407. rTclunk(Msg* m)
  408. {
  409. Fid *fid;
  410. if((fid = fidGet(m->con, m->t.fid, FidFWlock)) == nil)
  411. return 0;
  412. _rTclunk(fid, (fid->open & FidORclose));
  413. return 1;
  414. }
  415. static int
  416. rTwrite(Msg* m)
  417. {
  418. Fid *fid;
  419. int count, n;
  420. if((fid = fidGet(m->con, m->t.fid, 0)) == nil)
  421. return 0;
  422. if(!(fid->open & FidOWrite)){
  423. vtSetError("fid not open for write");
  424. goto error;
  425. }
  426. count = m->t.count;
  427. if(count < 0 || count > m->con->msize-IOHDRSZ){
  428. vtSetError("write count too big");
  429. goto error;
  430. }
  431. if(m->t.offset < 0){
  432. vtSetError("write offset negative");
  433. goto error;
  434. }
  435. if(fid->excl != nil && !exclUpdate(fid))
  436. goto error;
  437. if(fid->qid.type & QTDIR){
  438. vtSetError("is a directory");
  439. goto error;
  440. }
  441. else if(fid->qid.type & QTAUTH)
  442. n = authWrite(fid, m->t.data, count);
  443. else
  444. n = fileWrite(fid->file, m->t.data, count, m->t.offset, fid->uid);
  445. if(n < 0)
  446. goto error;
  447. m->r.count = n;
  448. fidPut(fid);
  449. return 1;
  450. error:
  451. fidPut(fid);
  452. return 0;
  453. }
  454. static int
  455. rTread(Msg* m)
  456. {
  457. Fid *fid;
  458. uchar *data;
  459. int count, n;
  460. if((fid = fidGet(m->con, m->t.fid, 0)) == nil)
  461. return 0;
  462. if(!(fid->open & FidORead)){
  463. vtSetError("fid not open for read");
  464. goto error;
  465. }
  466. count = m->t.count;
  467. if(count < 0 || count > m->con->msize-IOHDRSZ){
  468. vtSetError("read count too big");
  469. goto error;
  470. }
  471. if(m->t.offset < 0){
  472. vtSetError("read offset negative");
  473. goto error;
  474. }
  475. if(fid->excl != nil && !exclUpdate(fid))
  476. goto error;
  477. /*
  478. * TODO: optimise this copy (in convS2M) away somehow.
  479. * This pettifoggery with m->data will do for the moment.
  480. */
  481. data = m->data+IOHDRSZ;
  482. if(fid->qid.type & QTDIR)
  483. n = dirRead(fid, data, count, m->t.offset);
  484. else if(fid->qid.type & QTAUTH)
  485. n = authRead(fid, data, count);
  486. else
  487. n = fileRead(fid->file, data, count, m->t.offset);
  488. if(n < 0)
  489. goto error;
  490. m->r.count = n;
  491. m->r.data = (char*)data;
  492. fidPut(fid);
  493. return 1;
  494. error:
  495. fidPut(fid);
  496. return 0;
  497. }
  498. static int
  499. rTcreate(Msg* m)
  500. {
  501. Fid *fid;
  502. File *file;
  503. ulong mode;
  504. int omode, open, perm;
  505. if((fid = fidGet(m->con, m->t.fid, FidFWlock)) == nil)
  506. return 0;
  507. if(fid->open){
  508. vtSetError("fid open for I/O");
  509. goto error;
  510. }
  511. if(fileIsRoFs(fid->file) || !groupWriteMember(fid->uname)){
  512. vtSetError("read-only filesystem");
  513. goto error;
  514. }
  515. if(!fileIsDir(fid->file)){
  516. vtSetError("not a directory");
  517. goto error;
  518. }
  519. if(!permFid(fid, PermW))
  520. goto error;
  521. if(!validFileName(m->t.name))
  522. goto error;
  523. if(strcmp(fid->uid, uidnoworld) == 0){
  524. vtSetError(EPermission);
  525. goto error;
  526. }
  527. omode = m->t.mode & OMODE;
  528. open = 0;
  529. if(omode == OREAD || omode == ORDWR || omode == OEXEC)
  530. open |= FidORead;
  531. if(omode == OWRITE || omode == ORDWR)
  532. open |= FidOWrite;
  533. if((open & (FidOWrite|FidORead)) == 0){
  534. vtSetError("unknown mode");
  535. goto error;
  536. }
  537. if(m->t.perm & DMDIR){
  538. if((m->t.mode & (ORCLOSE|OTRUNC)) || (open & FidOWrite)){
  539. vtSetError("illegal mode");
  540. goto error;
  541. }
  542. if(m->t.perm & DMAPPEND){
  543. vtSetError("illegal perm");
  544. goto error;
  545. }
  546. }
  547. mode = fileGetMode(fid->file);
  548. perm = m->t.perm;
  549. if(m->t.perm & DMDIR)
  550. perm &= ~0777|(mode & 0777);
  551. else
  552. perm &= ~0666|(mode & 0666);
  553. mode = perm & 0777;
  554. if(m->t.perm & DMDIR)
  555. mode |= ModeDir;
  556. if(m->t.perm & DMAPPEND)
  557. mode |= ModeAppend;
  558. if(m->t.perm & DMEXCL)
  559. mode |= ModeExclusive;
  560. if(m->t.perm & DMTMP)
  561. mode |= ModeTemporary;
  562. if((file = fileCreate(fid->file, m->t.name, mode, fid->uid)) == nil){
  563. fidPut(fid);
  564. return 0;
  565. }
  566. fileDecRef(fid->file);
  567. fid->qid.vers = fileGetMcount(file);
  568. fid->qid.path = fileGetId(file);
  569. fid->file = file;
  570. mode = fileGetMode(fid->file);
  571. if(mode & ModeDir)
  572. fid->qid.type = QTDIR;
  573. else
  574. fid->qid.type = QTFILE;
  575. if(mode & ModeAppend)
  576. fid->qid.type |= QTAPPEND;
  577. if(mode & ModeExclusive){
  578. fid->qid.type |= QTEXCL;
  579. assert(exclAlloc(fid) != 0);
  580. }
  581. if(m->t.mode & ORCLOSE)
  582. open |= FidORclose;
  583. fid->open = open;
  584. m->r.qid = fid->qid;
  585. m->r.iounit = m->con->msize-IOHDRSZ;
  586. fidPut(fid);
  587. return 1;
  588. error:
  589. fidPut(fid);
  590. return 0;
  591. }
  592. static int
  593. rTopen(Msg* m)
  594. {
  595. Fid *fid;
  596. int isdir, mode, omode, open, rofs;
  597. if((fid = fidGet(m->con, m->t.fid, FidFWlock)) == nil)
  598. return 0;
  599. if(fid->open){
  600. vtSetError("fid open for I/O");
  601. goto error;
  602. }
  603. isdir = fileIsDir(fid->file);
  604. open = 0;
  605. rofs = fileIsRoFs(fid->file) || !groupWriteMember(fid->uname);
  606. if(m->t.mode & ORCLOSE){
  607. if(isdir){
  608. vtSetError("is a directory");
  609. goto error;
  610. }
  611. if(rofs){
  612. vtSetError("read-only filesystem");
  613. goto error;
  614. }
  615. if(!permParent(fid, PermW))
  616. goto error;
  617. open |= FidORclose;
  618. }
  619. omode = m->t.mode & OMODE;
  620. if(omode == OREAD || omode == ORDWR){
  621. if(!permFid(fid, PermR))
  622. goto error;
  623. open |= FidORead;
  624. }
  625. if(omode == OWRITE || omode == ORDWR || (m->t.mode & OTRUNC)){
  626. if(isdir){
  627. vtSetError("is a directory");
  628. goto error;
  629. }
  630. if(rofs){
  631. vtSetError("read-only filesystem");
  632. goto error;
  633. }
  634. if(!permFid(fid, PermW))
  635. goto error;
  636. open |= FidOWrite;
  637. }
  638. if(omode == OEXEC){
  639. if(isdir){
  640. vtSetError("is a directory");
  641. goto error;
  642. }
  643. if(!permFid(fid, PermX))
  644. goto error;
  645. open |= FidORead;
  646. }
  647. if((open & (FidOWrite|FidORead)) == 0){
  648. vtSetError("unknown mode");
  649. goto error;
  650. }
  651. mode = fileGetMode(fid->file);
  652. if((mode & ModeExclusive) && exclAlloc(fid) == 0)
  653. goto error;
  654. /*
  655. * Everything checks out, try to commit any changes.
  656. */
  657. if((m->t.mode & OTRUNC) && !(mode & ModeAppend)){
  658. if(!fileTruncate(fid->file, fid->uid))
  659. goto error;
  660. fid->qid.vers = fileGetMcount(fid->file);
  661. }
  662. if(isdir && fid->db != nil){
  663. dirBufFree(fid->db);
  664. fid->db = nil;
  665. }
  666. m->r.qid = fid->qid;
  667. m->r.iounit = m->con->msize-IOHDRSZ;
  668. fid->open = open;
  669. fidPut(fid);
  670. return 1;
  671. error:
  672. if(fid->excl != nil)
  673. exclFree(fid);
  674. fidPut(fid);
  675. return 0;
  676. }
  677. static int
  678. rTwalk(Msg* m)
  679. {
  680. Qid qid;
  681. Fcall *r, *t;
  682. int nwname, wlock;
  683. File *file, *nfile;
  684. Fid *fid, *ofid, *nfid;
  685. t = &m->t;
  686. if(t->fid == t->newfid)
  687. wlock = FidFWlock;
  688. else
  689. wlock = 0;
  690. /*
  691. * The file identified by t->fid must be valid in the
  692. * current session and must not have been opened for I/O
  693. * by an open or create message.
  694. */
  695. if((ofid = fidGet(m->con, t->fid, wlock)) == nil)
  696. return 0;
  697. if(ofid->open){
  698. vtSetError("file open for I/O");
  699. fidPut(ofid);
  700. return 0;
  701. }
  702. /*
  703. * If newfid is not the same as fid, allocate a new file;
  704. * a side effect is checking newfid is not already in use (error);
  705. * if there are no names to walk this will be equivalent to a
  706. * simple 'clone' operation.
  707. * It's a no-op if newfid is the same as fid and t->nwname is 0.
  708. */
  709. nfid = nil;
  710. if(t->fid != t->newfid){
  711. nfid = fidGet(m->con, t->newfid, FidFWlock|FidFCreate);
  712. if(nfid == nil){
  713. vtSetError("fid in use");
  714. fidPut(ofid);
  715. return 0;
  716. }
  717. nfid->open = ofid->open & ~FidORclose;
  718. nfid->file = fileIncRef(ofid->file);
  719. nfid->qid = ofid->qid;
  720. nfid->uid = vtStrDup(ofid->uid);
  721. nfid->uname = vtStrDup(ofid->uname);
  722. nfid->fsys = fsysIncRef(ofid->fsys);
  723. fid = nfid;
  724. }
  725. else
  726. fid = ofid;
  727. r = &m->r;
  728. r->nwqid = 0;
  729. if(t->nwname == 0){
  730. if(nfid != nil)
  731. fidPut(nfid);
  732. fidPut(ofid);
  733. return 1;
  734. }
  735. file = fid->file;
  736. fileIncRef(file);
  737. qid = fid->qid;
  738. for(nwname = 0; nwname < t->nwname; nwname++){
  739. /*
  740. * Walked elements must represent a directory and
  741. * the implied user must have permission to search
  742. * the directory. Walking .. is always allowed, so that
  743. * you can't walk into a directory and then not be able
  744. * to walk out of it.
  745. */
  746. if(!(qid.type & QTDIR)){
  747. vtSetError("not a directory");
  748. break;
  749. }
  750. if(!permFile(file, fid, PermX) && strcmp(t->wname[nwname], "..") != 0)
  751. break;
  752. if((nfile = fileWalk(file, t->wname[nwname])) == nil)
  753. break;
  754. fileDecRef(file);
  755. file = nfile;
  756. qid.type = QTFILE;
  757. if(fileIsDir(file))
  758. qid.type = QTDIR;
  759. qid.vers = fileGetMcount(file);
  760. qid.path = fileGetId(file);
  761. r->wqid[r->nwqid++] = qid;
  762. }
  763. if(nwname == t->nwname){
  764. /*
  765. * Walked all elements. Update the target fid
  766. * from the temporary qid used during the walk,
  767. * and tidy up.
  768. */
  769. fid->qid = r->wqid[r->nwqid-1];
  770. fileDecRef(fid->file);
  771. fid->file = file;
  772. if(nfid != nil)
  773. fidPut(nfid);
  774. fidPut(ofid);
  775. return 1;
  776. }
  777. /*
  778. * Didn't walk all elements, 'clunk' nfid if it exists
  779. * and leave fid untouched.
  780. * It's not an error if some of the elements were walked OK.
  781. */
  782. fileDecRef(file);
  783. if(nfid != nil)
  784. fidClunk(nfid);
  785. fidPut(ofid);
  786. if(nwname == 0)
  787. return 0;
  788. return 1;
  789. }
  790. static int
  791. rTflush(Msg* m)
  792. {
  793. if(m->t.oldtag != NOTAG)
  794. msgFlush(m);
  795. return 1;
  796. }
  797. static void
  798. parseAname(char *aname, char **fsname, char **path)
  799. {
  800. char *s;
  801. if(aname && aname[0])
  802. s = vtStrDup(aname);
  803. else
  804. s = vtStrDup("main/active");
  805. *fsname = s;
  806. if((*path = strchr(s, '/')) != nil)
  807. *(*path)++ = '\0';
  808. else
  809. *path = "";
  810. }
  811. static int
  812. rTattach(Msg* m)
  813. {
  814. Fid *fid;
  815. Fsys *fsys;
  816. char *fsname, *path;
  817. if((fid = fidGet(m->con, m->t.fid, FidFWlock|FidFCreate)) == nil)
  818. return 0;
  819. parseAname(m->t.aname, &fsname, &path);
  820. if((fsys = fsysGet(fsname)) == nil){
  821. fidClunk(fid);
  822. vtMemFree(fsname);
  823. return 0;
  824. }
  825. fid->fsys = fsys;
  826. if(m->t.uname[0] != '\0')
  827. fid->uname = vtStrDup(m->t.uname);
  828. else
  829. fid->uname = vtStrDup(unamenone);
  830. if(fsysNoAuthCheck(fsys) || m->con->noauth){
  831. if((fid->uid = uidByUname(fid->uname)) == nil)
  832. fid->uid = vtStrDup(unamenone);
  833. }
  834. else if(!authCheck(&m->t, fid, fsys)){
  835. fidClunk(fid);
  836. vtMemFree(fsname);
  837. vtSetError("authentication failed");
  838. return 0;
  839. }
  840. fsysFsRlock(fsys);
  841. if((fid->file = fsysGetRoot(fsys, path)) == nil){
  842. fsysFsRUnlock(fsys);
  843. fidClunk(fid);
  844. vtMemFree(fsname);
  845. return 0;
  846. }
  847. fsysFsRUnlock(fsys);
  848. vtMemFree(fsname);
  849. fid->qid = (Qid){fileGetId(fid->file), 0, QTDIR};
  850. m->r.qid = fid->qid;
  851. fidPut(fid);
  852. return 1;
  853. }
  854. static int
  855. rTauth(Msg* m)
  856. {
  857. int afd;
  858. Con *con;
  859. Fid *afid;
  860. Fsys *fsys;
  861. char *fsname, *path;
  862. parseAname(m->t.aname, &fsname, &path);
  863. if((fsys = fsysGet(fsname)) == nil){
  864. vtMemFree(fsname);
  865. return 0;
  866. }
  867. vtMemFree(fsname);
  868. if(fsysNoAuthCheck(fsys) || m->con->noauth){
  869. m->con->aok = 1;
  870. vtSetError("authentication disabled");
  871. fsysPut(fsys);
  872. return 0;
  873. }
  874. if(strcmp(m->t.uname, unamenone) == 0){
  875. vtSetError("user 'none' requires no authentication");
  876. fsysPut(fsys);
  877. return 0;
  878. }
  879. con = m->con;
  880. if((afid = fidGet(con, m->t.afid, FidFWlock|FidFCreate)) == nil){
  881. fsysPut(fsys);
  882. return 0;
  883. }
  884. afid->fsys = fsys;
  885. if((afd = open("/mnt/factotum/rpc", ORDWR)) < 0){
  886. vtSetError("can't open \"/mnt/factotum/rpc\"");
  887. fidClunk(afid);
  888. return 0;
  889. }
  890. if((afid->rpc = auth_allocrpc(afd)) == nil){
  891. close(afd);
  892. vtSetError("can't auth_allocrpc");
  893. fidClunk(afid);
  894. return 0;
  895. }
  896. if(auth_rpc(afid->rpc, "start", "proto=p9any role=server", 23) != ARok){
  897. vtSetError("can't auth_rpc");
  898. fidClunk(afid);
  899. return 0;
  900. }
  901. afid->open = FidOWrite|FidORead;
  902. afid->qid.type = QTAUTH;
  903. afid->qid.path = m->t.afid;
  904. afid->uname = vtStrDup(m->t.uname);
  905. m->r.qid = afid->qid;
  906. fidPut(afid);
  907. return 1;
  908. }
  909. static int
  910. rTversion(Msg* m)
  911. {
  912. int v;
  913. Con *con;
  914. Fcall *r, *t;
  915. t = &m->t;
  916. r = &m->r;
  917. con = m->con;
  918. vtLock(con->lock);
  919. if(con->state != ConInit){
  920. vtUnlock(con->lock);
  921. vtSetError("Tversion: down");
  922. return 0;
  923. }
  924. con->state = ConNew;
  925. /*
  926. * Release the karma of past lives and suffering.
  927. * Should this be done before or after checking the
  928. * validity of the Tversion?
  929. */
  930. fidClunkAll(con);
  931. if(t->tag != NOTAG){
  932. vtUnlock(con->lock);
  933. vtSetError("Tversion: invalid tag");
  934. return 0;
  935. }
  936. if(t->msize < 256){
  937. vtUnlock(con->lock);
  938. vtSetError("Tversion: message size too small");
  939. return 0;
  940. }
  941. if(t->msize < con->msize)
  942. r->msize = t->msize;
  943. else
  944. r->msize = con->msize;
  945. r->version = "unknown";
  946. if(t->version[0] == '9' && t->version[1] == 'P'){
  947. /*
  948. * Currently, the only defined version
  949. * is "9P2000"; ignore any later versions.
  950. */
  951. v = strtol(&t->version[2], 0, 10);
  952. if(v >= 2000){
  953. r->version = VERSION9P;
  954. con->msize = r->msize;
  955. con->state = ConUp;
  956. }
  957. else if(strcmp(t->version, "9PEoF") == 0){
  958. r->version = "9PEoF";
  959. con->msize = r->msize;
  960. con->state = ConMoribund;
  961. /*
  962. * Don't want to attempt to write this
  963. * message as the connection may be already
  964. * closed.
  965. */
  966. m->state = MsgF;
  967. }
  968. }
  969. vtUnlock(con->lock);
  970. return 1;
  971. }
  972. int (*rFcall[Tmax])(Msg*) = {
  973. [Tversion] = rTversion,
  974. [Tauth] = rTauth,
  975. [Tattach] = rTattach,
  976. [Tflush] = rTflush,
  977. [Twalk] = rTwalk,
  978. [Topen] = rTopen,
  979. [Tcreate] = rTcreate,
  980. [Tread] = rTread,
  981. [Twrite] = rTwrite,
  982. [Tclunk] = rTclunk,
  983. [Tremove] = rTremove,
  984. [Tstat] = rTstat,
  985. [Twstat] = rTwstat,
  986. };