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