nfsserver.c 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652
  1. #include "all.h"
  2. /*
  3. * Cf. /lib/rfc/rfc1094
  4. */
  5. static int nfsnull(int, Rpccall*, Rpccall*);
  6. static int nfsgetattr(int, Rpccall*, Rpccall*);
  7. static int nfssetattr(int, Rpccall*, Rpccall*);
  8. static int nfsroot(int, Rpccall*, Rpccall*);
  9. static int nfslookup(int, Rpccall*, Rpccall*);
  10. static int nfsreadlink(int, Rpccall*, Rpccall*);
  11. static int nfsread(int, Rpccall*, Rpccall*);
  12. static int nfswritecache(int, Rpccall*, Rpccall*);
  13. static int nfswrite(int, Rpccall*, Rpccall*);
  14. static int nfscreate(int, Rpccall*, Rpccall*);
  15. static int nfsremove(int, Rpccall*, Rpccall*);
  16. static int nfsrename(int, Rpccall*, Rpccall*);
  17. static int nfslink(int, Rpccall*, Rpccall*);
  18. static int nfssymlink(int, Rpccall*, Rpccall*);
  19. static int nfsmkdir(int, Rpccall*, Rpccall*);
  20. static int nfsrmdir(int, Rpccall*, Rpccall*);
  21. static int nfsreaddir(int, Rpccall*, Rpccall*);
  22. static int nfsstatfs(int, Rpccall*, Rpccall*);
  23. Procmap nfsproc[] = {
  24. 0, nfsnull, /* void */
  25. 1, nfsgetattr, /* Fhandle */
  26. 2, nfssetattr, /* Fhandle, Sattr */
  27. 3, nfsroot, /* void */
  28. 4, nfslookup, /* Fhandle, String */
  29. 5, nfsreadlink, /* Fhandle */
  30. 6, nfsread, /* Fhandle, long, long, long */
  31. 7, nfswritecache,/* void */
  32. 8, nfswrite, /* Fhandle, long, long, long, String */
  33. 9, nfscreate, /* Fhandle, String, Sattr */
  34. 10, nfsremove, /* Fhandle, String */
  35. 11, nfsrename, /* Fhandle, String, Fhandle, String */
  36. 12, nfslink, /* Fhandle, Fhandle, String */
  37. 13, nfssymlink, /* Fhandle, String, String, Sattr */
  38. 14, nfsmkdir, /* Fhandle, String, Sattr */
  39. 15, nfsrmdir, /* Fhandle, String */
  40. 16, nfsreaddir, /* Fhandle, long, long */
  41. 17, nfsstatfs, /* Fhandle */
  42. 0, 0
  43. };
  44. void nfsinit(int, char**);
  45. extern void mntinit(int, char**);
  46. extern Procmap mntproc[];
  47. Progmap progmap[] = {
  48. 100005, 1, mntinit, mntproc,
  49. 100003, 2, nfsinit, nfsproc,
  50. 0, 0, 0,
  51. };
  52. int myport = 2049;
  53. long nfstime;
  54. int conftime;
  55. void
  56. main(int argc, char *argv[])
  57. {
  58. server(argc, argv, myport, progmap);
  59. }
  60. static void
  61. doalarm(void)
  62. {
  63. nfstime = time(0);
  64. mnttimer(nfstime);
  65. if(conftime+5*60 < nfstime){
  66. conftime = nfstime;
  67. readunixidmaps(config);
  68. }
  69. }
  70. void
  71. nfsinit(int argc, char **argv)
  72. {
  73. USED(argc, argv);
  74. clog("nfs file server init\n");
  75. rpcalarm = doalarm;
  76. nfstime = time(0);
  77. }
  78. static int
  79. nfsnull(int n, Rpccall *cmd, Rpccall *reply)
  80. {
  81. USED(n, reply);
  82. chat("nfsnull...");
  83. showauth(&cmd->cred);
  84. chat("OK\n");
  85. return 0;
  86. }
  87. static int
  88. nfsgetattr(int n, Rpccall *cmd, Rpccall *reply)
  89. {
  90. Xfid *xf;
  91. Dir dir;
  92. uchar *dataptr = reply->results;
  93. chat("getattr...");
  94. if(n != FHSIZE)
  95. return garbage(reply, "bad count");
  96. xf = rpc2xfid(cmd, &dir);
  97. if(xf == 0)
  98. return error(reply, NFSERR_STALE);
  99. chat("%s...", xf->xp->name);
  100. PLONG(NFS_OK);
  101. dataptr += dir2fattr(cmd->up, &dir, dataptr);
  102. chat("OK\n");
  103. return dataptr - (uchar *)reply->results;
  104. }
  105. static int
  106. nfssetattr(int n, Rpccall *cmd, Rpccall *reply)
  107. {
  108. Xfid *xf;
  109. Dir dir, nd;
  110. Sattr sattr;
  111. int r;
  112. uchar *argptr = cmd->args;
  113. uchar *dataptr = reply->results;
  114. chat("setattr...");
  115. if(n <= FHSIZE)
  116. return garbage(reply, "count too small");
  117. xf = rpc2xfid(cmd, &dir);
  118. argptr += FHSIZE;
  119. argptr += convM2sattr(argptr, &sattr);
  120. if(argptr != &((uchar *)cmd->args)[n])
  121. return garbage(reply, "bad count");
  122. chat("mode=0%lo,u=%ld,g=%ld,size=%ld,atime=%ld,mtime=%ld...",
  123. sattr.mode, sattr.uid, sattr.gid, sattr.size,
  124. sattr.atime, sattr.mtime);
  125. if(xf == 0)
  126. return error(reply, NFSERR_STALE);
  127. if(sattr.uid != NOATTR || sattr.gid != NOATTR)
  128. return error(reply, NFSERR_PERM);
  129. if(sattr.size == 0){
  130. if(xf->xp->s != xf->xp->parent->s){
  131. if(xfauthremove(xf, cmd->user) < 0)
  132. return error(reply, NFSERR_PERM);
  133. }else if(dir.length && xfopen(xf, Trunc|Oread|Owrite) < 0)
  134. return error(reply, NFSERR_PERM);
  135. }else if(sattr.size != NOATTR)
  136. return error(reply, NFSERR_PERM);
  137. r = 0;
  138. nulldir(&nd);
  139. if(sattr.mode != NOATTR)
  140. ++r, nd.mode = (dir.mode & ~0777) | (sattr.mode & 0777);
  141. if(sattr.atime != NOATTR)
  142. ++r, nd.atime = sattr.atime;
  143. if(sattr.mtime != NOATTR)
  144. ++r, nd.mtime = sattr.mtime;
  145. chat("sattr.mode=%luo dir.mode=%luo nd.mode=%luo...", sattr.mode, dir.mode, nd.mode);
  146. if(r){
  147. r = xfwstat(xf, &nd);
  148. if(r < 0)
  149. return error(reply, NFSERR_PERM);
  150. }
  151. if(xfstat(xf, &dir) < 0)
  152. return error(reply, NFSERR_STALE);
  153. PLONG(NFS_OK);
  154. dataptr += dir2fattr(cmd->up, &dir, dataptr);
  155. chat("OK\n");
  156. return dataptr - (uchar *)reply->results;
  157. }
  158. static int
  159. nfsroot(int n, Rpccall *cmd, Rpccall *reply)
  160. {
  161. USED(n, reply);
  162. chat("nfsroot...");
  163. showauth(&cmd->cred);
  164. chat("OK\n");
  165. return 0;
  166. }
  167. static int
  168. nfslookup(int n, Rpccall *cmd, Rpccall *reply)
  169. {
  170. Xfile *xp;
  171. Xfid *xf, *newxf;
  172. String elem;
  173. Dir dir;
  174. uchar *argptr = cmd->args;
  175. uchar *dataptr = reply->results;
  176. chat("lookup...");
  177. if(n <= FHSIZE)
  178. return garbage(reply, "count too small");
  179. xf = rpc2xfid(cmd, 0);
  180. argptr += FHSIZE;
  181. argptr += string2S(argptr, &elem);
  182. if(argptr != &((uchar *)cmd->args)[n])
  183. return garbage(reply, "bad count");
  184. if(xf == 0)
  185. return error(reply, NFSERR_STALE);
  186. xp = xf->xp;
  187. if(!(xp->qid.type & QTDIR))
  188. return error(reply, NFSERR_NOTDIR);
  189. chat("%s -> \"%.*s\"...", xp->name, utfnlen(elem.s, elem.n), elem.s);
  190. if(xp->s->noauth == 0 && xp->parent == xp && elem.s[0] == '#')
  191. newxf = xfauth(xp, &elem);
  192. else
  193. newxf = xfwalkcr(Twalk, xf, &elem, 0);
  194. if(newxf == 0)
  195. return error(reply, NFSERR_NOENT);
  196. if(xfstat(newxf, &dir) < 0)
  197. return error(reply, NFSERR_IO);
  198. PLONG(NFS_OK);
  199. dataptr += xp2fhandle(newxf->xp, dataptr);
  200. dataptr += dir2fattr(cmd->up, &dir, dataptr);
  201. chat("OK\n");
  202. return dataptr - (uchar *)reply->results;
  203. }
  204. static int
  205. nfsreadlink(int n, Rpccall *cmd, Rpccall *reply)
  206. {
  207. USED(n, reply);
  208. chat("readlink...");
  209. showauth(&cmd->cred);
  210. return error(reply, NFSERR_NOENT);
  211. }
  212. static int
  213. nfsread(int n, Rpccall *cmd, Rpccall *reply)
  214. {
  215. Session *s;
  216. Xfid *xf;
  217. Dir dir;
  218. int offset, count;
  219. uchar *argptr = cmd->args;
  220. uchar *dataptr = reply->results;
  221. uchar *readptr = dataptr + 4 + 17*4 + 4;
  222. chat("read...");
  223. if(n != FHSIZE+12)
  224. return garbage(reply, "bad count");
  225. xf = rpc2xfid(cmd, 0);
  226. argptr += FHSIZE;
  227. offset = GLONG();
  228. count = GLONG();
  229. if(xf == 0)
  230. return error(reply, NFSERR_STALE);
  231. chat("%s %d %d...", xf->xp->name, offset, count);
  232. if(xf->xp->s != xf->xp->parent->s){
  233. count = xfauthread(xf, offset, readptr, count);
  234. }else{
  235. if(xfopen(xf, Oread) < 0)
  236. return error(reply, NFSERR_PERM);
  237. if(count > 8192)
  238. count = 8192;
  239. s = xf->xp->s;
  240. setfid(s, xf->opfid);
  241. xf->opfid->tstale = nfstime + 60;
  242. s->f.offset = offset;
  243. s->f.count = count;
  244. if(xmesg(s, Tread) < 0)
  245. return error(reply, NFSERR_IO);
  246. count = s->f.count;
  247. memmove(readptr, s->f.data, count);
  248. }
  249. if(xfstat(xf, &dir) < 0)
  250. return error(reply, NFSERR_IO);
  251. PLONG(NFS_OK);
  252. dataptr += dir2fattr(cmd->up, &dir, dataptr);
  253. PLONG(count);
  254. dataptr += ROUNDUP(count);
  255. chat("%d OK\n", count);
  256. return dataptr - (uchar *)reply->results;
  257. }
  258. static int
  259. nfswritecache(int n, Rpccall *cmd, Rpccall *reply)
  260. {
  261. USED(n, reply);
  262. chat("writecache...");
  263. showauth(&cmd->cred);
  264. chat("OK\n");
  265. return 0;
  266. }
  267. static int
  268. nfswrite(int n, Rpccall *cmd, Rpccall *reply)
  269. {
  270. Session *s;
  271. Xfid *xf;
  272. Dir dir;
  273. int offset, count;
  274. uchar *argptr = cmd->args;
  275. uchar *dataptr = reply->results;
  276. chat("write...");
  277. if(n < FHSIZE+16)
  278. return garbage(reply, "count too small");
  279. xf = rpc2xfid(cmd, 0);
  280. argptr += FHSIZE + 4;
  281. offset = GLONG();
  282. argptr += 4;
  283. count = GLONG();
  284. if(xf == 0)
  285. return error(reply, NFSERR_STALE);
  286. chat("%s %d %d...", xf->xp->name, offset, count);
  287. if(xf->xp->s != xf->xp->parent->s){
  288. if(xfauthwrite(xf, offset, argptr, count) < 0)
  289. return error(reply, NFSERR_IO);
  290. }else{
  291. if(xfopen(xf, Owrite) < 0)
  292. return error(reply, NFSERR_PERM);
  293. s = xf->xp->s;
  294. setfid(s, xf->opfid);
  295. xf->opfid->tstale = nfstime + 60;
  296. s->f.offset = offset;
  297. s->f.count = count;
  298. s->f.data = (char *)argptr;
  299. if(xmesg(s, Twrite) < 0)
  300. return error(reply, NFSERR_IO);
  301. }
  302. if(xfstat(xf, &dir) < 0)
  303. return error(reply, NFSERR_IO);
  304. PLONG(NFS_OK);
  305. dataptr += dir2fattr(cmd->up, &dir, dataptr);
  306. chat("OK\n");
  307. return dataptr - (uchar *)reply->results;
  308. }
  309. static int
  310. creat(int n, Rpccall *cmd, Rpccall *reply, int chdir)
  311. {
  312. Xfid *xf, *newxf;
  313. Xfile *xp;
  314. String elem;
  315. Dir dir; Sattr sattr;
  316. uchar *argptr = cmd->args;
  317. uchar *dataptr = reply->results;
  318. int trunced;
  319. if(n <= FHSIZE)
  320. return garbage(reply, "count too small");
  321. xf = rpc2xfid(cmd, 0);
  322. argptr += FHSIZE;
  323. argptr += string2S(argptr, &elem);
  324. argptr += convM2sattr(argptr, &sattr);
  325. if(argptr != &((uchar *)cmd->args)[n])
  326. return garbage(reply, "bad count");
  327. if(xf == 0)
  328. return error(reply, NFSERR_STALE);
  329. xp = xf->xp;
  330. if(!(xp->qid.type & QTDIR))
  331. return error(reply, NFSERR_NOTDIR);
  332. chat("%s/%.*s...", xp->name, utfnlen(elem.s, elem.n), elem.s);
  333. trunced = 0;
  334. if(xp->parent == xp && elem.s[0] == '#'){
  335. newxf = xfauth(xp, &elem);
  336. if(newxf == 0)
  337. return error(reply, NFSERR_PERM);
  338. if(xfauthremove(newxf, cmd->user) < 0)
  339. return error(reply, NFSERR_PERM);
  340. trunced = 1;
  341. }else
  342. newxf = xfwalkcr(Twalk, xf, &elem, 0);
  343. if(newxf == 0){
  344. newxf = xfwalkcr(Tcreate, xf, &elem, chdir|(sattr.mode&0777));
  345. if(newxf)
  346. trunced = 1;
  347. else
  348. newxf = xfwalkcr(Twalk, xf, &elem, 0);
  349. }
  350. if(newxf == 0)
  351. return error(reply, NFSERR_PERM);
  352. if(!trunced && chdir)
  353. return error(reply, NFSERR_EXIST);
  354. if(!trunced && xfopen(newxf, Trunc|Oread|Owrite) < 0)
  355. return error(reply, NFSERR_PERM);
  356. if(xfstat(newxf, &dir) < 0)
  357. return error(reply, NFSERR_IO);
  358. PLONG(NFS_OK);
  359. dataptr += xp2fhandle(newxf->xp, dataptr);
  360. dataptr += dir2fattr(cmd->up, &dir, dataptr);
  361. chat("OK\n");
  362. return dataptr - (uchar *)reply->results;
  363. }
  364. static int
  365. nfscreate(int n, Rpccall *cmd, Rpccall *reply)
  366. {
  367. chat("create...");
  368. return creat(n, cmd, reply, 0);
  369. }
  370. static int
  371. remov(int n, Rpccall *cmd, Rpccall *reply)
  372. {
  373. Session *s;
  374. Xfile *xp;
  375. Xfid *xf, *newxf;
  376. String elem;
  377. Fid *nfid;
  378. uchar *argptr = cmd->args;
  379. uchar *dataptr = reply->results;
  380. if(n <= FHSIZE)
  381. return garbage(reply, "count too small");
  382. xf = rpc2xfid(cmd, 0);
  383. argptr += FHSIZE;
  384. argptr += string2S(argptr, &elem);
  385. if(argptr != &((uchar *)cmd->args)[n])
  386. return garbage(reply, "bad count");
  387. if(xf == 0)
  388. return error(reply, NFSERR_STALE);
  389. xp = xf->xp;
  390. if(!(xp->qid.type & QTDIR))
  391. return error(reply, NFSERR_NOTDIR);
  392. chat("%s/%.*s...", xp->name, utfnlen(elem.s, elem.n), elem.s);
  393. if(xp->s->noauth == 0 && xp->parent == xp && elem.s[0] == '#')
  394. return error(reply, NFSERR_PERM);
  395. newxf = xfwalkcr(Twalk, xf, &elem, 0);
  396. if(newxf == 0)
  397. return error(reply, NFSERR_NOENT);
  398. s = xp->s;
  399. nfid = newfid(s);
  400. setfid(s, newxf->urfid);
  401. s->f.newfid = nfid - s->fids;
  402. s->f.nwname = 0;
  403. if(xmesg(s, Twalk) < 0){
  404. putfid(s, nfid);
  405. return error(reply, NFSERR_IO);
  406. }
  407. s->f.fid = nfid - s->fids;
  408. if(xmesg(s, Tremove) < 0){
  409. putfid(s, nfid);
  410. return error(reply, NFSERR_PERM);
  411. }
  412. putfid(s, nfid);
  413. xpclear(newxf->xp);
  414. PLONG(NFS_OK);
  415. chat("OK\n");
  416. return dataptr - (uchar *)reply->results;
  417. }
  418. static int
  419. nfsremove(int n, Rpccall *cmd, Rpccall *reply)
  420. {
  421. chat("remove...");
  422. return remov(n, cmd, reply);
  423. }
  424. static int
  425. nfsrename(int n, Rpccall *cmd, Rpccall *reply)
  426. {
  427. Xfid *xf, *newxf;
  428. Xfile *xp;
  429. uchar *fromdir, *todir;
  430. String fromelem, toelem;
  431. Dir dir;
  432. uchar *argptr = cmd->args;
  433. uchar *dataptr = reply->results;
  434. chat("rename...");
  435. if(n <= FHSIZE)
  436. return garbage(reply, "count too small");
  437. xf = rpc2xfid(cmd, 0);
  438. fromdir = argptr;
  439. argptr += FHSIZE;
  440. argptr += string2S(argptr, &fromelem);
  441. todir = argptr;
  442. argptr += FHSIZE;
  443. argptr += string2S(argptr, &toelem);
  444. if(argptr != &((uchar *)cmd->args)[n])
  445. return garbage(reply, "bad count");
  446. if(xf == 0)
  447. return error(reply, NFSERR_STALE);
  448. xp = xf->xp;
  449. if(!(xp->qid.type & QTDIR))
  450. return error(reply, NFSERR_NOTDIR);
  451. if(memcmp(fromdir, todir, FHSIZE) != 0)
  452. return error(reply, NFSERR_NXIO);
  453. newxf = xfwalkcr(Twalk, xf, &fromelem, 0);
  454. if(newxf == 0)
  455. return error(reply, NFSERR_NOENT);
  456. if(xfstat(newxf, &dir) < 0)
  457. return error(reply, NFSERR_IO);
  458. if(xp->parent == xp && toelem.s[0] == '#')
  459. return error(reply, NFSERR_PERM);
  460. nulldir(&dir);
  461. dir.name = toelem.s;
  462. if(xfwstat(newxf, &dir) < 0)
  463. return error(reply, NFSERR_PERM);
  464. PLONG(NFS_OK);
  465. chat("OK\n");
  466. return dataptr - (uchar *)reply->results;
  467. }
  468. static int
  469. nfslink(int n, Rpccall *cmd, Rpccall *reply)
  470. {
  471. USED(n, reply);
  472. chat("link...");
  473. showauth(&cmd->cred);
  474. return error(reply, NFSERR_NOENT);
  475. }
  476. static int
  477. nfssymlink(int n, Rpccall *cmd, Rpccall *reply)
  478. {
  479. USED(n, reply);
  480. chat("symlink...");
  481. showauth(&cmd->cred);
  482. return error(reply, NFSERR_NOENT);
  483. }
  484. static int
  485. nfsmkdir(int n, Rpccall *cmd, Rpccall *reply)
  486. {
  487. chat("mkdir...");
  488. return creat(n, cmd, reply, DMDIR);
  489. }
  490. static int
  491. nfsrmdir(int n, Rpccall *cmd, Rpccall *reply)
  492. {
  493. chat("rmdir...");
  494. return remov(n, cmd, reply);
  495. }
  496. static int
  497. nfsreaddir(int n, Rpccall *cmd, Rpccall *reply)
  498. {
  499. Session *s;
  500. Xfid *xf;
  501. Dir dir;
  502. char *rdata;
  503. int k, offset, count, sfcount, entries, dsize;
  504. uchar *argptr = cmd->args;
  505. uchar *dataptr = reply->results;
  506. chat("readdir...");
  507. if(n != FHSIZE+8)
  508. return garbage(reply, "bad count");
  509. xf = rpc2xfid(cmd, 0);
  510. argptr += FHSIZE;
  511. offset = GLONG();
  512. count = GLONG();
  513. if(xf == 0)
  514. return error(reply, NFSERR_STALE);
  515. chat("%s (%ld) %d %d...", xf->xp->name, xf->offset, offset, count);
  516. s = xf->xp->s;
  517. if((xf->mode & Open) && xf->offset > offset)
  518. xfclose(xf);
  519. if(xfopen(xf, Oread) < 0)
  520. return error(reply, NFSERR_PERM);
  521. while(xf->offset < offset){ /* if we reopened, xf->offset will be zero */
  522. sfcount = offset - xf->offset;
  523. if(sfcount > messagesize-IOHDRSZ)
  524. sfcount = messagesize-IOHDRSZ;
  525. setfid(s, xf->opfid);
  526. s->f.offset = xf->offset;
  527. s->f.count = sfcount;
  528. if(xmesg(s, Tread) < 0){
  529. xfclose(xf);
  530. return error(reply, NFSERR_IO);
  531. }
  532. if(s->f.count <= BIT16SZ)
  533. break;
  534. xf->offset += s->f.count;
  535. }
  536. if(count > messagesize-IOHDRSZ)
  537. count = messagesize-IOHDRSZ;
  538. PLONG(NFS_OK);
  539. entries = 0;
  540. while(count > 16){ /* at least 16 bytes required; we don't know size of name */
  541. chat("top of loop\n");
  542. setfid(s, xf->opfid);
  543. s->f.offset = xf->offset;
  544. s->f.count = count; /* as good a guess as any */
  545. if(xmesg(s, Tread) < 0){
  546. xfclose(xf);
  547. return error(reply, NFSERR_IO);
  548. }
  549. sfcount = s->f.count;
  550. if(sfcount <= BIT16SZ)
  551. break;
  552. xf->offset += sfcount;
  553. chat("count %d data 0x%p\n", s->f.count, s->f.data);
  554. rdata = s->f.data;
  555. /* now have a buffer of Plan 9 directories; unpack into NFS thingies */
  556. while(sfcount >= 0){
  557. dsize = convM2D((uchar*)rdata, sfcount, &dir, (char*)s->statbuf);
  558. if(dsize <= BIT16SZ){
  559. count = 0; /* force break from outer loop */
  560. break;
  561. }
  562. offset += dsize;
  563. k = strlen(dir.name);
  564. if(count < 16+ROUNDUP(k)){
  565. count = 0; /* force break from outer loop */
  566. break;
  567. }
  568. PLONG(TRUE);
  569. PLONG(dir.qid.path);
  570. PLONG(k);
  571. PPTR(dir.name, k);
  572. PLONG(offset);
  573. count -= 16+ROUNDUP(k);
  574. rdata += dsize;
  575. sfcount -= dsize;
  576. }
  577. }
  578. PLONG(FALSE);
  579. if(s->f.count <= 0){
  580. xfclose(xf);
  581. chat("eof...");
  582. PLONG(TRUE);
  583. }else
  584. PLONG(FALSE);
  585. chat("%d OK\n", entries);
  586. return dataptr - (uchar *)reply->results;
  587. }
  588. static int
  589. nfsstatfs(int n, Rpccall *cmd, Rpccall *reply)
  590. {
  591. uchar *dataptr = reply->results;
  592. enum {
  593. Xfersize = 2048,
  594. Maxlong = (long)((1ULL<<31) - 1),
  595. Maxfreeblks = Maxlong / Xfersize,
  596. };
  597. chat("statfs...");
  598. showauth(&cmd->cred);
  599. if(n != FHSIZE)
  600. return garbage(reply, "bad count");
  601. PLONG(NFS_OK);
  602. PLONG(4096); /* tsize (fs block size) */
  603. PLONG(Xfersize); /* bsize (optimal transfer size) */
  604. PLONG(Maxfreeblks); /* blocks in fs */
  605. PLONG(Maxfreeblks); /* bfree to root*/
  606. PLONG(Maxfreeblks); /* bavail (free to mortals) */
  607. chat("OK\n");
  608. /*conftime = 0;
  609. readunixidmaps(config);*/
  610. return dataptr - (uchar *)reply->results;
  611. }