Home | History | Annotate | Line # | Download | only in libsa
nfs.c revision 1.5
      1 /*	$NetBSD: nfs.c,v 1.5 1995/02/19 23:51:39 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 
     43 #include "stand.h"
     44 #include "net.h"
     45 #include "netif.h"
     46 #include "nfs.h"
     47 #include "rpc.h"
     48 
     49 struct nfs_call_data {
     50 	u_char	fh[NFS_FHSIZE];
     51 	u_long	off;
     52 	u_long	len;
     53 	u_long	xxx;			/* XXX what's this for? */
     54 };
     55 
     56 /* Data part of nfs rpc reply (also the largest thing we receive) */
     57 struct nfs_reply_data {
     58 	u_long	errno;
     59 	struct	nfsv2_fattr fa;
     60 	u_long	count;
     61 	u_char	data[1200];
     62 };
     63 #define NFSREAD_SIZE sizeof(((struct nfs_reply_data *)0)->data)
     64 
     65 /* max number of nfs reads pending */
     66 #define NFS_COUNT 10
     67 
     68 static struct nfsstate {
     69 	u_long	off;
     70 	u_long	len;
     71 	int	done;
     72 	void	*addr;
     73 	u_long	xid;
     74 } nfsstate[NFS_COUNT];
     75 
     76 static u_long nfscc;
     77 
     78 struct nfs_iodesc {
     79 	off_t	off;
     80 	size_t	size;
     81 	u_char	*fh;
     82 	struct	iodesc	*iodesc;
     83 };
     84 
     85 /* Fetch (mount) file handle */
     86 static int
     87 getmountfh(d, path, fhp)
     88 	register struct iodesc *d;
     89 	char *path;
     90 	u_char *fhp;
     91 {
     92 	register int len;
     93 	struct {
     94 		u_long	len;
     95 		char	path[FNAME_SIZE];
     96 	} sdata;
     97 	struct {
     98 		u_long	errno;
     99 		u_char	fh[NFS_FHSIZE];
    100 	} rdata;
    101 	int cc;
    102 
    103 #ifdef NFS_DEBUG
    104 	if (debug)
    105 	    printf("getmountfh: called\n");
    106 #endif
    107 	bzero(&sdata, sizeof(sdata));
    108 	len = strlen(path);
    109 	if (len > sizeof(sdata.path))
    110 		len = sizeof(sdata.path);
    111 	bcopy(path, sdata.path, len);
    112 	sdata.len = htonl(len);
    113 	len = sizeof(sdata) - sizeof(sdata.path) + roundup(len, sizeof(long));
    114 
    115 	if ((cc = callrpc(d, RPCPROG_MNT, RPCMNT_VER1, RPCMNT_MOUNT,
    116 	    &sdata, len, &rdata, sizeof(rdata))) < 0)
    117 		    return(-1);
    118 	if (cc < sizeof(rdata.errno))
    119 		panic("getmountfh: callrpc small read");
    120 	if (rdata.errno) {
    121 		errno = ntohl(rdata.errno);
    122 		return(-1);
    123 	}
    124 	bcopy(rdata.fh, fhp, sizeof(rdata.fh));
    125 	return(0);
    126 }
    127 
    128 /* Fetch file timestamp and size */
    129 static int
    130 getnfsinfo(d, tp, sp, fp, mp, up, gp)
    131 	register struct nfs_iodesc *d;
    132 	register time_t *tp;
    133 	u_long *sp, *fp;
    134 	mode_t *mp;
    135 	uid_t *up;
    136 	gid_t *gp;
    137 {
    138 	register int rlen;
    139 	register u_long t;
    140 	struct {
    141 		u_long	errno;
    142 		struct	nfsv2_fattr fa;
    143 	} rdata;
    144 	int cc;
    145 
    146 #ifdef NFS_DEBUG
    147  	if (debug)
    148  	    printf("getnfsinfo: called\n");
    149 #endif
    150 	rlen = sizeof(rdata);
    151 #ifdef NFSX_FATTR
    152 #if NFSX_FATTR(1) > NFSX_FATTR(0)
    153 	/* nqnfs makes this more painful than it needs to be */
    154 	rlen -= NFSX_FATTR(1) - NFSX_FATTR(0);
    155 #endif
    156 #endif
    157 	if ((cc = callrpc(d->iodesc, NFS_PROG, NFS_VER2, NFSPROC_GETATTR,
    158 		          d->fh, NFS_FHSIZE, &rdata, rlen)) < 0)
    159 		return(-1);
    160 	if (cc < sizeof(rdata.errno))
    161 		panic("getnfsinfo: callrpc small read");
    162 	if (rdata.errno) {
    163 		errno = ntohl(rdata.errno);
    164 		return(-1);
    165 	}
    166 	if (tp) {
    167 		*tp = ntohl(rdata.fa.fa_nfsmtime.nfs_sec);
    168 		t = ntohl(rdata.fa.fa_nfsatime.nfs_sec);
    169 		if (*tp < t)
    170 			*tp = t;
    171 	}
    172 	if (sp)
    173 		*sp = ntohl(rdata.fa.fa_nfssize);
    174 	if (fp)
    175 		*fp = ntohl(rdata.fa.fa_type);
    176 	if (mp)
    177 		*mp = ntohl(rdata.fa.fa_mode);
    178 	if (up)
    179 		*up = ntohl(rdata.fa.fa_uid);
    180 	if (gp)
    181 		*gp = ntohl(rdata.fa.fa_gid);
    182 	return(0);
    183 }
    184 
    185 /* Lookup a file. Optionally return timestamp and size */
    186 static int
    187 lookupfh(d, name, fhp, tp, sp, fp)
    188 	struct nfs_iodesc *d;
    189 	char *name;
    190 	u_char *fhp;
    191 	time_t *tp;
    192 	u_long *sp, *fp;
    193 {
    194 	register int len, rlen;
    195 	struct {
    196 		u_char	fh[NFS_FHSIZE];
    197 		u_long	len;
    198 		char	name[FNAME_SIZE];
    199 	} sdata;
    200 	struct {
    201 		u_long	errno;
    202 		u_char	fh[NFS_FHSIZE];
    203 		struct	nfsv2_fattr fa;
    204 	} rdata;
    205 	int cc;
    206 
    207 #ifdef NFS_DEBUG
    208 	if (debug)
    209 	    printf("lookupfh: called\n");
    210 #endif
    211 
    212 	bzero(&sdata, sizeof(sdata));
    213 	bcopy(d->fh, sdata.fh, sizeof(sdata.fh));
    214 	len = strlen(name);
    215 	if (len > sizeof(sdata.name))
    216 		len = sizeof(sdata.name);
    217 	bcopy(name, sdata.name, len);
    218 	sdata.len = htonl(len);
    219 	len = sizeof(sdata) - sizeof(sdata.name) + roundup(len, sizeof(long));
    220 
    221 	rlen = sizeof(rdata);
    222 #if 0
    223 #ifdef NFSX_FATTR
    224 #if NFSX_FATTR(1) > NFSX_FATTR(0)
    225 	/* nqnfs makes this more painful than it needs to be */
    226 	rlen -= NFSX_FATTR(1) - NFSX_FATTR(0);
    227 #endif
    228 #endif
    229 #endif
    230 	if ((cc = callrpc(d->iodesc, NFS_PROG, NFS_VER2, NFSPROC_LOOKUP,
    231 	    &sdata, len, &rdata, rlen)) < 0)
    232 		return (-1);
    233 	if (cc < sizeof(rdata.errno))
    234 		panic("lookupfh: callrpc small read");
    235 	if (rdata.errno) {
    236 		errno = ntohl(rdata.errno);
    237 		return(-1);
    238 	}
    239 	bcopy(rdata.fh, fhp, sizeof(rdata.fh));
    240 	if (tp)
    241 		*tp = ntohl(rdata.fa.fa_nfsctime.nfs_sec);
    242 	if (sp)
    243 		*sp = ntohl(rdata.fa.fa_nfssize);
    244 	if (fp)
    245 		*fp = ntohl(rdata.fa.fa_type);
    246 	return (0);
    247 }
    248 
    249 static int
    250 sendreaddata(d, pkt, len)
    251 	register struct nfs_iodesc *d;
    252 	register void *pkt;
    253 	register int len;
    254 {
    255 	register int i;
    256 	register u_long cc;
    257 	register struct rpc_call *rpc;
    258 	register struct nfs_call_data *nfs;
    259 	register struct nfsstate *ns;
    260 
    261 #ifdef NFS_DEBUG
    262 	if (debug)
    263 	    printf("sendreaddata: called\n");
    264 #endif
    265 
    266 	if (len != sizeof(*rpc) + sizeof(*nfs))
    267 		panic("sendreaddata: bad buffer (%d != %d)",
    268 		    len, sizeof(*rpc) + sizeof(*nfs));
    269 	rpc = pkt;
    270 	nfs = (struct nfs_call_data *)(rpc + 1);
    271 	for (i = 0, ns = nfsstate; i < NFS_COUNT; ++i, ++ns) {
    272 		if (ns->done)
    273 			continue;
    274 
    275 		rpc->rp_xid = ns->xid;
    276 		nfs->off = htonl(ns->off);
    277 		nfs->len = htonl(ns->len);
    278 		cc = sendudp(d->iodesc, rpc, len);
    279 
    280 		if (cc != len)
    281 			panic("sendreaddata: short write (%d != %d)", cc, len);
    282 	}
    283 	/* XXX we may have actually sent a lot more bytes... */
    284 
    285 	return (len);
    286 }
    287 
    288 /* Returns char count if done else -1 (and errno == 0) */
    289 static int
    290 recvreaddata(d, pkt, len)
    291 	register struct nfs_iodesc *d;
    292 	register void *pkt;
    293 	int len;
    294 {
    295 	register int i;
    296 	register struct rpc_reply *rpc;
    297 	register struct nfs_reply_data *nfs;
    298 	register struct nfsstate *ns;
    299 
    300 #ifdef NFS_DEBUG
    301 	if (debug)
    302 	    printf("recvreaddata: called\n");
    303 #endif
    304 	rpc = (struct rpc_reply *)checkudp(d->iodesc, pkt, &len);
    305 	if (rpc == NULL || len < sizeof(*rpc)) {
    306 		errno = 0;
    307 		return (-1);
    308 	}
    309 	len -= sizeof(*rpc);
    310 
    311 	NTOHL(rpc->rp_direction);
    312 	NTOHL(rpc->rp_stat);
    313 
    314 	if (rpc->rp_direction != REPLY || rpc->rp_stat != MSG_ACCEPTED) {
    315 		errno = 0;
    316 		return (-1);
    317 	}
    318 
    319 	for (i = 0, ns = nfsstate; i < NFS_COUNT; ++i, ++ns)
    320 		if (rpc->rp_xid == ns->xid)
    321 			break;
    322 	if (i >= NFS_COUNT) {
    323 		errno = 0;
    324 		return (-1);
    325 	}
    326 
    327 	if (ns->done) {
    328 		errno = 0;
    329 		return (-1);
    330 	}
    331 #ifdef NFS_DEBUG
    332 	if (debug)
    333 	    printf("recvreaddata: ns=%x\n", (u_int)ns);
    334 #endif
    335 	nfs = (struct nfs_reply_data *)(rpc + 1);
    336 	if (len < sizeof(nfs->errno))
    337 		panic("recvreaddata: bad read %d", len);
    338 	if (nfs->errno) {
    339 		errno = ntohl(nfs->errno);
    340 		return (-1);
    341 	}
    342 	if (len < sizeof(*nfs) - sizeof(nfs->data))
    343 		panic("recvreaddata: less than nfs sized %d", len);
    344 	len -= sizeof(*nfs) - sizeof(nfs->data);
    345 
    346 	if (len < nfs->count)
    347 		panic("recvreaddata: short read (%d < %d)", len, nfs->count);
    348 	len = nfs->count;
    349 	if (len > ns->len)
    350 		panic("recvreaddata: huge read (%d > %d)", len, ns->len);
    351 
    352 
    353 #ifdef NFS_DEBUG
    354 	if (debug)
    355 	    printf("recvreaddata: read %d bytes.\n", len);
    356 #endif
    357 	bcopy(nfs->data, ns->addr, len);
    358 	ns->done = 1;
    359 	nfscc += len;
    360 
    361 	if (len < ns->len) {
    362 		/* If first packet assume no more data to read */
    363 		if (i == 0)
    364 			return (0);
    365 
    366 		/* Short read, assume we are at EOF */
    367 		++i;
    368 		++ns;
    369 		while (i < NFS_COUNT) {
    370 			ns->done = 1;
    371 			++i;
    372 			++ns;
    373 		}
    374 	}
    375 
    376 	for (i = 0, ns = nfsstate; i < NFS_COUNT; ++i, ++ns)
    377 		if (!ns->done) {
    378 			errno = 0;
    379 			return (-1);
    380 		}
    381 
    382 	/* Return data count (thus indicating success) */
    383 	return (nfscc);
    384 }
    385 
    386 /* Read data from a file */
    387 static int
    388 readdata(d, off, addr, len)
    389 	register struct nfs_iodesc *d;
    390 	register off_t off;
    391 	register void *addr;
    392 	register u_long len;
    393 {
    394 	register int i, cc;
    395 	register struct rpc_call *rpc;
    396 	register struct nfsstate *ns;
    397 	struct {
    398 		u_char	header[HEADER_SIZE];
    399 		struct	rpc_call rpc;
    400 		struct	nfs_call_data nfs;
    401 	} sdata;
    402 	struct {
    403 		u_char	header[HEADER_SIZE];
    404 		struct	rpc_call rpc;
    405 		struct	nfs_reply_data nfs;
    406 	} rdata;
    407 
    408 #ifdef NFS_DEBUG
    409 	if (debug)
    410 	    printf("readdata: addr=%x, off=%d len=%d\n", (u_int)addr, (u_int)off, len);
    411 #endif
    412 	if (len == 0)
    413 		return (0);
    414 	d->iodesc->destport = getport(d->iodesc, NFS_PROG, NFS_VER2);
    415 
    416 	bzero(&sdata, sizeof(sdata));
    417 
    418 	for (i = 0, ns = nfsstate; i < NFS_COUNT; ++i, ++ns) {
    419 		if (len <= 0) {
    420 			ns->done = 1;
    421 			continue;
    422 		}
    423 		ns->done = 0;
    424 
    425 		ns->xid = d->iodesc->xid;
    426 		++d->iodesc->xid;
    427 
    428 		ns->off = (u_int)off;
    429 		ns->len = len;
    430 		if (ns->len > NFSREAD_SIZE)
    431 			ns->len = NFSREAD_SIZE;
    432 #ifdef notdef
    433 /* XXX to align or not align? It doesn't seem to speed things up... */
    434 		if ((ns->off % NFSREAD_SIZE) != 0)
    435 			ns->len -= off % NFSREAD_SIZE;
    436 #endif
    437 
    438 		off += ns->len;
    439 		len -= ns->len;
    440 
    441 		ns->addr = addr;
    442 		addr += NFSREAD_SIZE;
    443 	}
    444 
    445 	rpc = &sdata.rpc;
    446 	rpc->rp_rpcvers = htonl(RPC_MSG_VERSION);
    447 	rpc->rp_prog = htonl(NFS_PROG);
    448 	rpc->rp_vers = htonl(NFS_VER2);
    449 	rpc->rp_proc = htonl(NFSPROC_READ);
    450 	bcopy(d->fh, sdata.nfs.fh, sizeof(sdata.nfs.fh));
    451 
    452 	nfscc = 0;
    453 	cc = sendrecv(d->iodesc,
    454 		      sendreaddata, &sdata.rpc,
    455 		      sizeof(struct rpc_call) + sizeof(struct nfs_call_data),
    456 		      recvreaddata,
    457 			((u_char *)&rdata.rpc) - HEADER_SIZE, HEADER_SIZE +
    458 			  sizeof(struct rpc_call) + sizeof(struct nfs_reply_data));
    459 	return (cc);
    460 }
    461 
    462 static struct iodesc *mountfs;
    463 static u_char mountfh[NFS_FHSIZE];
    464 static time_t mounttime;
    465 
    466 /*
    467  * nfs_mount - mount this nfs filesystem to a host
    468  */
    469 int
    470 nfs_mount(sock, ip, path)
    471 	int sock;
    472 	n_long ip;
    473 	char *path;
    474 {
    475 	struct iodesc *desc;
    476 	struct nfs_iodesc *fp;
    477 	u_long ftype;
    478 
    479 	if (!(desc = socktodesc(sock))) {
    480 		errno = EINVAL;
    481 		return(-1);
    482 	}
    483 	bcopy(&desc->myea[4], &desc->myport, 2);
    484 	desc->destip = ip;
    485 	getmountfh(desc, path, mountfh);
    486 
    487 	fp = alloc(sizeof(struct nfs_iodesc));
    488 	fp->iodesc = desc;
    489 	fp->fh = mountfh;
    490 	fp->off = 0;
    491 	if (getnfsinfo(fp, &mounttime, NULL, &ftype, NULL, NULL, NULL) < 0) {
    492 		free(fp, sizeof(struct nfs_iodesc));
    493 		return(-1);
    494 	}
    495 
    496 	if (ftype != NFDIR) {
    497 		free(fp, sizeof(struct nfs_iodesc));
    498 	    	errno = EINVAL;
    499 		printf("nfs_mount: bad mount ftype %d", ftype);
    500 		return(-1);
    501 	}
    502 #ifdef NFS_DEBUG
    503 	if (debug)
    504 		printf("nfs_mount: got fh for %s, mtime=%d, ftype=%d\n",
    505 			path, mounttime, ftype);
    506 #endif
    507 	mountfs = desc;
    508 	free(fp, sizeof(struct nfs_iodesc));
    509 
    510 	return(0);
    511 }
    512 
    513 /*
    514  * Open a file.
    515  */
    516 int
    517 nfs_open(path, f)
    518 	char *path;
    519 	struct open_file *f;
    520 {
    521 	register struct nfs_iodesc *fp;
    522 	u_char *imagefh;
    523 	u_long size, ftype;
    524 	int rc = 0;
    525 
    526 #ifdef NFS_DEBUG
    527  	if (debug)
    528  	    printf("nfs_open: %s\n", path);
    529 #endif
    530 	if (!mountfs) {
    531 		errno = EIO;
    532 		printf("nfs_open: must mount first.\n");
    533 		return(-1);
    534 	}
    535 
    536 	/* allocate file system specific data structure */
    537 	fp = alloc(sizeof(struct nfs_iodesc));
    538 	fp->iodesc = mountfs;
    539 	fp->fh = mountfh;
    540 	fp->off = 0;
    541 
    542 	f->f_fsdata = (void *)fp;
    543 	imagefh = alloc(NFS_FHSIZE);
    544 	bzero(imagefh, NFS_FHSIZE);
    545 
    546 	/* lookup a file handle */
    547 	rc = lookupfh(fp, path, imagefh, NULL, &size, &ftype);
    548 	if (rc < 0) {
    549 #ifdef NFS_DEBUG
    550 		if (debug)
    551 			printf("nfs_open: %s lookupfh failed: %s\n", path, strerror(errno));
    552 #endif
    553 		f->f_fsdata = (void *)0;
    554 		free(fp, sizeof(struct nfs_iodesc));
    555 		free(imagefh, NFS_FHSIZE);
    556 		return(rc);
    557 	}
    558 	fp->fh = imagefh;
    559 
    560 #ifdef NFS_DEBUG
    561 	if (debug)
    562 		printf("nfs_open: %s success, size=%d ftype=%d\n",
    563 			path, size, ftype);
    564 #endif
    565 	fp->size = size;
    566 
    567 	return(rc);
    568 }
    569 
    570 int
    571 nfs_close(f)
    572 	struct open_file *f;
    573 {
    574 	register struct nfs_iodesc *fp = (struct nfs_iodesc *)f->f_fsdata;
    575 
    576 #ifdef NFS_DEBUG
    577 	if (debug)
    578 		printf("nfs_close: called\n");
    579 #endif
    580 	f->f_fsdata = (void *)0;
    581 	if (fp == (struct nfs_iodesc *)0)
    582 		return (0);
    583 
    584 	free(fp->fh, NFS_FHSIZE);
    585 	free(fp, sizeof(struct nfs_iodesc));
    586 
    587 	return (0);
    588 }
    589 
    590 /*
    591  * read a portion of a file
    592  */
    593 int
    594 nfs_read(f, addr, size, resid)
    595 	struct open_file *f;
    596 	char *addr;
    597 	u_int size;
    598 	u_int *resid;	/* out */
    599 {
    600 	register struct nfs_iodesc *fp = (struct nfs_iodesc *)f->f_fsdata;
    601 	register int cc;
    602 
    603 #ifdef NFS_DEBUG
    604 	if (debug)
    605 		printf("nfs_read: size=%d off=%d\n", size, (int)fp->off);
    606 #endif
    607 	while (size > 0) {
    608 		cc = readdata(fp->iodesc, fp->off, (void *)addr, size);
    609 		if (cc <= 0) {
    610 			/* XXX maybe should retry on certain errors */
    611 			if (cc < 0) {
    612 #ifdef NFS_DEBUG
    613 				if (debug)
    614 					printf("nfs_read: read: %s",
    615 						strerror(errno));
    616 #endif
    617 				return (-1);
    618 			}
    619 			if (debug)
    620 				printf("nfs_read: hit EOF unexpectantly");
    621 			goto ret;
    622 		}
    623 		fp->off += cc;
    624 		addr += cc;
    625 		size -= cc;
    626 	}
    627 ret:
    628 	if (resid)
    629 		*resid = size;
    630 
    631 	return (0);
    632 }
    633 
    634 /*
    635  * Not implemented.
    636  */
    637 int
    638 nfs_write(f, start, size, resid)
    639 	struct open_file *f;
    640 	char *start;
    641 	u_int size;
    642 	u_int *resid;	/* out */
    643 {
    644 	errno = EROFS;
    645 
    646 	return (-1);
    647 }
    648 
    649 off_t
    650 nfs_seek(f, offset, where)
    651 	struct open_file *f;
    652 	off_t offset;
    653 	int where;
    654 {
    655 	register struct nfs_iodesc *fp = (struct nfs_iodesc *)f->f_fsdata;
    656 
    657 	switch (where) {
    658 	case SEEK_SET:
    659 		fp->off = offset;
    660 		break;
    661 	case SEEK_CUR:
    662 		fp->off += offset;
    663 		break;
    664 	case SEEK_END:
    665 		fp->off = fp->size - offset;
    666 		break;
    667 	default:
    668 		return (-1);
    669 	}
    670 	return (fp->off);
    671 }
    672 
    673 int
    674 nfs_stat(f, sb)
    675 	struct open_file *f;
    676 	struct stat *sb;
    677 {
    678 	register struct nfs_iodesc *fp = (struct nfs_iodesc *)f->f_fsdata;
    679 	mode_t mode = 0;
    680 	u_long ftype = 0;
    681 
    682 #ifdef NFS_DEBUG
    683  	if (debug)
    684  	    printf("nfs_stat: called\n");
    685 #endif
    686 	if (getnfsinfo(fp, &mounttime, &sb->st_size, &ftype, &mode, &sb->st_uid, &sb->st_gid) < 0)
    687 		return(-1);
    688 
    689 	/* create a mode */
    690 	switch (ftype) {
    691 	case NFNON:
    692 		sb->st_mode = 0;
    693 		break;
    694 	case NFREG:
    695 		sb->st_mode = S_IFREG;
    696 		break;
    697 	case NFDIR:
    698 		sb->st_mode = S_IFDIR;
    699 		break;
    700 	case NFBLK:
    701 		sb->st_mode = S_IFBLK;
    702 		break;
    703 	case NFCHR:
    704 		sb->st_mode = S_IFCHR;
    705 		break;
    706 	case NFLNK:
    707 		sb->st_mode = S_IFLNK;
    708 		break;
    709 	}
    710 	sb->st_mode |= mode;
    711 
    712 	return (0);
    713 }
    714