nfsserver.c 15 KB

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