1 /* $NetBSD: nfs.c,v 1.6 1995/02/20 11:04:12 mycroft Exp $ */ 2 3 /*- 4 * Copyright (c) 1993 John Brezak 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 3. The name of the author may not be used to endorse or promote products 16 * derived from this software without specific prior written permission. 17 * 18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR `AS IS'' AND ANY EXPRESS OR 19 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 20 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 21 * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, 22 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 23 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 24 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 25 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 26 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 27 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 28 * POSSIBILITY OF SUCH DAMAGE. 29 */ 30 31 #include <sys/param.h> 32 #include <sys/time.h> 33 #include <sys/socket.h> 34 #include <sys/stat.h> 35 #include <string.h> 36 37 #include <netinet/in.h> 38 #include <netinet/in_systm.h> 39 40 #include <nfs/rpcv2.h> 41 #include <nfs/nfsv2.h> 42 #include <nfs/xdr_subs.h> 43 44 #include "stand.h" 45 #include "net.h" 46 #include "netif.h" 47 #include "nfs.h" 48 #include "rpc.h" 49 50 struct nfs_call_data { 51 u_char fh[NFS_FHSIZE]; 52 u_long off; 53 u_long len; 54 u_long xxx; /* XXX what's this for? */ 55 }; 56 57 /* Data part of nfs rpc reply (also the largest thing we receive) */ 58 struct nfs_reply_data { 59 u_long errno; 60 struct nfsv2_fattr fa; 61 u_long count; 62 u_char data[1200]; 63 }; 64 #define NFSREAD_SIZE sizeof(((struct nfs_reply_data *)0)->data) 65 66 struct nfs_iodesc { 67 off_t off; 68 size_t size; 69 u_char *fh; 70 struct iodesc *iodesc; 71 }; 72 73 /* Fetch (mount) file handle */ 74 static int 75 getmountfh(d, path, fhp) 76 register struct iodesc *d; 77 char *path; 78 u_char *fhp; 79 { 80 register int len; 81 struct { 82 u_long len; 83 char path[FNAME_SIZE]; 84 } wbuf; 85 struct { 86 u_long errno; 87 u_char fh[NFS_FHSIZE]; 88 } rbuf; 89 size_t cc; 90 91 #ifdef NFS_DEBUG 92 if (debug) 93 printf("getmountfh: called\n"); 94 #endif 95 96 bzero(&wbuf, sizeof(wbuf)); 97 len = strlen(path); 98 if (len > sizeof(wbuf.path)) 99 len = sizeof(wbuf.path); 100 bcopy(path, wbuf.path, len); 101 wbuf.len = htonl(len); 102 len = sizeof(wbuf) - sizeof(wbuf.path) + roundup(len, sizeof(long)); 103 104 if ((cc = callrpc(d, RPCPROG_MNT, RPCMNT_VER1, RPCMNT_MOUNT, 105 &wbuf, len, &rbuf, sizeof(rbuf))) == -1) 106 return (-1); 107 if (cc < sizeof(rbuf.errno)) 108 panic("getmountfh: callrpc small read"); 109 if (rbuf.errno) { 110 errno = ntohl(rbuf.errno); 111 return (-1); 112 } 113 bcopy(rbuf.fh, fhp, sizeof(rbuf.fh)); 114 return (0); 115 } 116 117 /* Fetch file timestamp and size */ 118 static int 119 getnfsinfo(d, tp, sp, fp, mp, up, gp) 120 register struct nfs_iodesc *d; 121 register time_t *tp; 122 u_long *sp, *fp; 123 mode_t *mp; 124 uid_t *up; 125 gid_t *gp; 126 { 127 register int rlen; 128 register u_long t; 129 struct { 130 u_long errno; 131 struct nfsv2_fattr fa; 132 } rbuf; 133 size_t cc; 134 135 #ifdef NFS_DEBUG 136 if (debug) 137 printf("getnfsinfo: called\n"); 138 #endif 139 rlen = sizeof(rbuf); 140 #if NFSX_FATTR(1) > NFSX_FATTR(0) 141 /* nqnfs makes this more painful than it needs to be */ 142 rlen -= NFSX_FATTR(1) - NFSX_FATTR(0); 143 #endif 144 if ((cc = callrpc(d->iodesc, NFS_PROG, NFS_VER2, NFSPROC_GETATTR, 145 d->fh, NFS_FHSIZE, &rbuf, rlen)) == -1) 146 return (-1); 147 if (cc < sizeof(rbuf.errno)) 148 panic("getnfsinfo: callrpc small read"); 149 if (rbuf.errno) { 150 errno = ntohl(rbuf.errno); 151 return (-1); 152 } 153 if (tp) { 154 *tp = ntohl(rbuf.fa.fa_nfsmtime.nfs_sec); 155 t = ntohl(rbuf.fa.fa_nfsatime.nfs_sec); 156 if (*tp < t) 157 *tp = t; 158 } 159 if (sp) 160 *sp = ntohl(rbuf.fa.fa_nfssize); 161 if (fp) 162 *fp = ntohl(rbuf.fa.fa_type); 163 if (mp) 164 *mp = ntohl(rbuf.fa.fa_mode); 165 if (up) 166 *up = ntohl(rbuf.fa.fa_uid); 167 if (gp) 168 *gp = ntohl(rbuf.fa.fa_gid); 169 return(0); 170 } 171 172 /* Lookup a file. Optionally return timestamp and size */ 173 static int 174 lookupfh(d, name, fhp, tp, sp, fp) 175 struct nfs_iodesc *d; 176 char *name; 177 u_char *fhp; 178 time_t *tp; 179 u_long *sp, *fp; 180 { 181 register int len, rlen; 182 struct { 183 u_char fh[NFS_FHSIZE]; 184 u_long len; 185 char name[FNAME_SIZE]; 186 } wbuf; 187 struct { 188 u_long errno; 189 u_char fh[NFS_FHSIZE]; 190 struct nfsv2_fattr fa; 191 } rbuf; 192 size_t cc; 193 194 #ifdef NFS_DEBUG 195 if (debug) 196 printf("lookupfh: called\n"); 197 #endif 198 199 bzero(&wbuf, sizeof(wbuf)); 200 bcopy(d->fh, wbuf.fh, sizeof(wbuf.fh)); 201 len = strlen(name); 202 if (len > sizeof(wbuf.name)) 203 len = sizeof(wbuf.name); 204 bcopy(name, wbuf.name, len); 205 wbuf.len = htonl(len); 206 len = sizeof(wbuf) - sizeof(wbuf.name) + roundup(len, sizeof(long)); 207 208 rlen = sizeof(rbuf); 209 #ifdef NFSX_FATTR 210 #if NFSX_FATTR(1) > NFSX_FATTR(0) 211 /* nqnfs makes this more painful than it needs to be */ 212 rlen -= NFSX_FATTR(1) - NFSX_FATTR(0); 213 #endif 214 #endif 215 216 if ((cc = callrpc(d->iodesc, NFS_PROG, NFS_VER2, NFSPROC_LOOKUP, 217 &wbuf, len, &rbuf, rlen)) == -1) 218 return (-1); 219 if (cc < sizeof(rbuf.errno)) 220 panic("lookupfh: callrpc small read"); 221 if (rbuf.errno) { 222 errno = ntohl(rbuf.errno); 223 return (-1); 224 } 225 bcopy(rbuf.fh, fhp, sizeof(rbuf.fh)); 226 if (tp) 227 *tp = ntohl(rbuf.fa.fa_nfsctime.nfs_sec); 228 if (sp) 229 *sp = ntohl(rbuf.fa.fa_nfssize); 230 if (fp) 231 *fp = ntohl(rbuf.fa.fa_type); 232 return (0); 233 } 234 235 /* Read data from a file */ 236 static size_t 237 readdata(d, off, addr, len) 238 register struct nfs_iodesc *d; 239 register off_t off; 240 register void *addr; 241 register size_t len; 242 { 243 size_t cc; 244 struct nfs_call_data wbuf; 245 struct nfs_reply_data rbuf; 246 247 bcopy(d->fh, wbuf.fh, NFS_FHSIZE); 248 wbuf.off = txdr_unsigned(off); 249 if (len > NFSREAD_SIZE) 250 len = NFSREAD_SIZE; 251 wbuf.len = txdr_unsigned(len); 252 wbuf.xxx = txdr_unsigned(0); 253 254 cc = callrpc(d->iodesc, NFS_PROG, NFS_VER2, NFSPROC_READ, 255 &wbuf, sizeof(wbuf), 256 &rbuf, sizeof(rbuf) - NFSREAD_SIZE + len); 257 if (cc == -1 || cc < sizeof(rbuf) - NFSREAD_SIZE) 258 return (-1); 259 260 cc -= sizeof(rbuf) - NFSREAD_SIZE; 261 bcopy(rbuf.data, addr, cc); 262 return (cc); 263 } 264 265 static struct iodesc *mountfs; 266 static u_char mountfh[NFS_FHSIZE]; 267 static time_t mounttime; 268 269 /* 270 * nfs_mount - mount this nfs filesystem to a host 271 */ 272 int 273 nfs_mount(sock, ip, path) 274 int sock; 275 n_long ip; 276 char *path; 277 { 278 struct iodesc *desc; 279 struct nfs_iodesc *fp; 280 u_long ftype; 281 282 if (!(desc = socktodesc(sock))) { 283 errno = EINVAL; 284 return(-1); 285 } 286 bcopy(&desc->myea[4], &desc->myport, 2); 287 desc->destip = ip; 288 getmountfh(desc, path, mountfh); 289 290 fp = alloc(sizeof(struct nfs_iodesc)); 291 fp->iodesc = desc; 292 fp->fh = mountfh; 293 fp->off = 0; 294 if (getnfsinfo(fp, &mounttime, NULL, &ftype, NULL, NULL, NULL) < 0) { 295 free(fp, sizeof(struct nfs_iodesc)); 296 return(-1); 297 } 298 299 if (ftype != NFDIR) { 300 free(fp, sizeof(struct nfs_iodesc)); 301 errno = EINVAL; 302 printf("nfs_mount: bad mount ftype %d", ftype); 303 return(-1); 304 } 305 #ifdef NFS_DEBUG 306 if (debug) 307 printf("nfs_mount: got fh for %s, mtime=%d, ftype=%d\n", 308 path, mounttime, ftype); 309 #endif 310 mountfs = desc; 311 free(fp, sizeof(struct nfs_iodesc)); 312 313 return(0); 314 } 315 316 /* 317 * Open a file. 318 */ 319 int 320 nfs_open(path, f) 321 char *path; 322 struct open_file *f; 323 { 324 register struct nfs_iodesc *fp; 325 u_char *imagefh; 326 u_long size, ftype; 327 int rc = 0; 328 329 #ifdef NFS_DEBUG 330 if (debug) 331 printf("nfs_open: %s\n", path); 332 #endif 333 if (!mountfs) { 334 errno = EIO; 335 printf("nfs_open: must mount first.\n"); 336 return(-1); 337 } 338 339 /* allocate file system specific data structure */ 340 fp = alloc(sizeof(struct nfs_iodesc)); 341 fp->iodesc = mountfs; 342 fp->fh = mountfh; 343 fp->off = 0; 344 345 f->f_fsdata = (void *)fp; 346 imagefh = alloc(NFS_FHSIZE); 347 bzero(imagefh, NFS_FHSIZE); 348 349 /* lookup a file handle */ 350 rc = lookupfh(fp, path, imagefh, NULL, &size, &ftype); 351 if (rc < 0) { 352 #ifdef NFS_DEBUG 353 if (debug) 354 printf("nfs_open: %s lookupfh failed: %s\n", path, strerror(errno)); 355 #endif 356 f->f_fsdata = (void *)0; 357 free(fp, sizeof(struct nfs_iodesc)); 358 free(imagefh, NFS_FHSIZE); 359 return(rc); 360 } 361 fp->fh = imagefh; 362 363 #ifdef NFS_DEBUG 364 if (debug) 365 printf("nfs_open: %s success, size=%d ftype=%d\n", 366 path, size, ftype); 367 #endif 368 fp->size = size; 369 370 return(rc); 371 } 372 373 int 374 nfs_close(f) 375 struct open_file *f; 376 { 377 register struct nfs_iodesc *fp = (struct nfs_iodesc *)f->f_fsdata; 378 379 #ifdef NFS_DEBUG 380 if (debug) 381 printf("nfs_close: called\n"); 382 #endif 383 f->f_fsdata = (void *)0; 384 if (fp == (struct nfs_iodesc *)0) 385 return (0); 386 387 free(fp->fh, NFS_FHSIZE); 388 free(fp, sizeof(struct nfs_iodesc)); 389 390 return (0); 391 } 392 393 /* 394 * read a portion of a file 395 */ 396 int 397 nfs_read(f, addr, size, resid) 398 struct open_file *f; 399 char *addr; 400 u_int size; 401 u_int *resid; /* out */ 402 { 403 register struct nfs_iodesc *fp = (struct nfs_iodesc *)f->f_fsdata; 404 register size_t cc; 405 406 #ifdef NFS_DEBUG 407 if (debug) 408 printf("nfs_read: size=%d off=%d\n", size, (int)fp->off); 409 #endif 410 while (size > 0) { 411 cc = readdata(fp->iodesc, fp->off, (void *)addr, size); 412 /* XXX maybe should retry on certain errors */ 413 if (cc == -1) { 414 #ifdef NFS_DEBUG 415 if (debug) 416 printf("nfs_read: read: %s", strerror(errno)); 417 #endif 418 return (-1); 419 } 420 if (cc == 0) { 421 if (debug) 422 printf("nfs_read: hit EOF unexpectantly"); 423 goto ret; 424 } 425 fp->off += cc; 426 addr += cc; 427 size -= cc; 428 } 429 ret: 430 if (resid) 431 *resid = size; 432 433 return (0); 434 } 435 436 /* 437 * Not implemented. 438 */ 439 int 440 nfs_write(f, start, size, resid) 441 struct open_file *f; 442 char *start; 443 u_int size; 444 u_int *resid; /* out */ 445 { 446 errno = EROFS; 447 448 return (-1); 449 } 450 451 off_t 452 nfs_seek(f, offset, where) 453 struct open_file *f; 454 off_t offset; 455 int where; 456 { 457 register struct nfs_iodesc *fp = (struct nfs_iodesc *)f->f_fsdata; 458 459 switch (where) { 460 case SEEK_SET: 461 fp->off = offset; 462 break; 463 case SEEK_CUR: 464 fp->off += offset; 465 break; 466 case SEEK_END: 467 fp->off = fp->size - offset; 468 break; 469 default: 470 return (-1); 471 } 472 return (fp->off); 473 } 474 475 int 476 nfs_stat(f, sb) 477 struct open_file *f; 478 struct stat *sb; 479 { 480 register struct nfs_iodesc *fp = (struct nfs_iodesc *)f->f_fsdata; 481 mode_t mode = 0; 482 u_long ftype = 0; 483 484 #ifdef NFS_DEBUG 485 if (debug) 486 printf("nfs_stat: called\n"); 487 #endif 488 489 if (getnfsinfo(fp, &mounttime, &sb->st_size, &ftype, &mode, &sb->st_uid, &sb->st_gid) < 0) 490 return(-1); 491 492 /* create a mode */ 493 switch (ftype) { 494 case NFNON: 495 sb->st_mode = 0; 496 break; 497 case NFREG: 498 sb->st_mode = S_IFREG; 499 break; 500 case NFDIR: 501 sb->st_mode = S_IFDIR; 502 break; 503 case NFBLK: 504 sb->st_mode = S_IFBLK; 505 break; 506 case NFCHR: 507 sb->st_mode = S_IFCHR; 508 break; 509 case NFLNK: 510 sb->st_mode = S_IFLNK; 511 break; 512 } 513 sb->st_mode |= mode; 514 515 return (0); 516 } 517