14a5d661aSToomas Soome /* $NetBSD: nfs.c,v 1.2 1998/01/24 12:43:09 drochner Exp $ */ 24a5d661aSToomas Soome 34a5d661aSToomas Soome /*- 44a5d661aSToomas Soome * Copyright (c) 1993 John Brezak 54a5d661aSToomas Soome * All rights reserved. 64a5d661aSToomas Soome * 74a5d661aSToomas Soome * Redistribution and use in source and binary forms, with or without 84a5d661aSToomas Soome * modification, are permitted provided that the following conditions 94a5d661aSToomas Soome * are met: 104a5d661aSToomas Soome * 1. Redistributions of source code must retain the above copyright 114a5d661aSToomas Soome * notice, this list of conditions and the following disclaimer. 124a5d661aSToomas Soome * 2. Redistributions in binary form must reproduce the above copyright 134a5d661aSToomas Soome * notice, this list of conditions and the following disclaimer in the 144a5d661aSToomas Soome * documentation and/or other materials provided with the distribution. 154a5d661aSToomas Soome * 3. The name of the author may not be used to endorse or promote products 164a5d661aSToomas Soome * derived from this software without specific prior written permission. 174a5d661aSToomas Soome * 184a5d661aSToomas Soome * THIS SOFTWARE IS PROVIDED BY THE AUTHOR `AS IS'' AND ANY EXPRESS OR 194a5d661aSToomas Soome * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 204a5d661aSToomas Soome * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 214a5d661aSToomas Soome * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, 224a5d661aSToomas Soome * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 234a5d661aSToomas Soome * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 244a5d661aSToomas Soome * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 254a5d661aSToomas Soome * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 264a5d661aSToomas Soome * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 274a5d661aSToomas Soome * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 284a5d661aSToomas Soome * POSSIBILITY OF SUCH DAMAGE. 294a5d661aSToomas Soome */ 304a5d661aSToomas Soome 314a5d661aSToomas Soome #include <sys/cdefs.h> 324a5d661aSToomas Soome 334a5d661aSToomas Soome #include <sys/param.h> 344a5d661aSToomas Soome #include <sys/time.h> 354a5d661aSToomas Soome #include <sys/socket.h> 364a5d661aSToomas Soome #include <sys/stat.h> 374a5d661aSToomas Soome #include <string.h> 38dd8e2f72SToomas Soome #include <stddef.h> 394a5d661aSToomas Soome 404a5d661aSToomas Soome #include <netinet/in.h> 414a5d661aSToomas Soome #include <netinet/in_systm.h> 424a5d661aSToomas Soome 434a5d661aSToomas Soome #include "rpcv2.h" 444a5d661aSToomas Soome #include "nfsv2.h" 454a5d661aSToomas Soome 464a5d661aSToomas Soome #include "stand.h" 474a5d661aSToomas Soome #include "net.h" 484a5d661aSToomas Soome #include "netif.h" 494a5d661aSToomas Soome #include "rpc.h" 504a5d661aSToomas Soome 514a5d661aSToomas Soome #define NFS_DEBUGxx 524a5d661aSToomas Soome 53dd8e2f72SToomas Soome #define NFSREAD_MIN_SIZE 1024 54*cd017266SToomas Soome #define NFSREAD_MAX_SIZE 16384 554a5d661aSToomas Soome 564a5d661aSToomas Soome /* NFSv3 definitions */ 574a5d661aSToomas Soome #define NFS_V3MAXFHSIZE 64 584a5d661aSToomas Soome #define NFS_VER3 3 594a5d661aSToomas Soome #define RPCMNT_VER3 3 604a5d661aSToomas Soome #define NFSPROCV3_LOOKUP 3 614a5d661aSToomas Soome #define NFSPROCV3_READLINK 5 624a5d661aSToomas Soome #define NFSPROCV3_READ 6 634a5d661aSToomas Soome #define NFSPROCV3_READDIR 16 644a5d661aSToomas Soome 654a5d661aSToomas Soome typedef struct { 664a5d661aSToomas Soome uint32_t val[2]; 674a5d661aSToomas Soome } n_quad; 684a5d661aSToomas Soome 694a5d661aSToomas Soome struct nfsv3_time { 704a5d661aSToomas Soome uint32_t nfs_sec; 714a5d661aSToomas Soome uint32_t nfs_nsec; 724a5d661aSToomas Soome }; 734a5d661aSToomas Soome 744a5d661aSToomas Soome struct nfsv3_fattrs { 754a5d661aSToomas Soome uint32_t fa_type; 764a5d661aSToomas Soome uint32_t fa_mode; 774a5d661aSToomas Soome uint32_t fa_nlink; 784a5d661aSToomas Soome uint32_t fa_uid; 794a5d661aSToomas Soome uint32_t fa_gid; 804a5d661aSToomas Soome n_quad fa_size; 814a5d661aSToomas Soome n_quad fa_used; 824a5d661aSToomas Soome n_quad fa_rdev; 834a5d661aSToomas Soome n_quad fa_fsid; 844a5d661aSToomas Soome n_quad fa_fileid; 854a5d661aSToomas Soome struct nfsv3_time fa_atime; 864a5d661aSToomas Soome struct nfsv3_time fa_mtime; 874a5d661aSToomas Soome struct nfsv3_time fa_ctime; 884a5d661aSToomas Soome }; 894a5d661aSToomas Soome 904a5d661aSToomas Soome /* 914a5d661aSToomas Soome * For NFSv3, the file handle is variable in size, so most fixed sized 924a5d661aSToomas Soome * structures for arguments won't work. For most cases, a structure 934a5d661aSToomas Soome * that starts with any fixed size section is followed by an array 944a5d661aSToomas Soome * that covers the maximum size required. 954a5d661aSToomas Soome */ 964a5d661aSToomas Soome struct nfsv3_readdir_repl { 974a5d661aSToomas Soome uint32_t errno; 984a5d661aSToomas Soome uint32_t ok; 994a5d661aSToomas Soome struct nfsv3_fattrs fa; 1004a5d661aSToomas Soome uint32_t cookiev0; 1014a5d661aSToomas Soome uint32_t cookiev1; 1024a5d661aSToomas Soome }; 1034a5d661aSToomas Soome 1044a5d661aSToomas Soome struct nfsv3_readdir_entry { 1054a5d661aSToomas Soome uint32_t follows; 1064a5d661aSToomas Soome uint32_t fid0; 1074a5d661aSToomas Soome uint32_t fid1; 1084a5d661aSToomas Soome uint32_t len; 1094a5d661aSToomas Soome uint32_t nameplus[0]; 1104a5d661aSToomas Soome }; 1114a5d661aSToomas Soome 1124a5d661aSToomas Soome struct nfs_iodesc { 1134a5d661aSToomas Soome struct iodesc *iodesc; 1144a5d661aSToomas Soome off_t off; 1154a5d661aSToomas Soome uint32_t fhsize; 1164a5d661aSToomas Soome u_char fh[NFS_V3MAXFHSIZE]; 1174a5d661aSToomas Soome struct nfsv3_fattrs fa; /* all in network order */ 1184a5d661aSToomas Soome uint64_t cookie; 1194a5d661aSToomas Soome }; 1204a5d661aSToomas Soome 1214a5d661aSToomas Soome /* 1224a5d661aSToomas Soome * XXX interactions with tftp? See nfswrapper.c for a confusing 1234a5d661aSToomas Soome * issue. 1244a5d661aSToomas Soome */ 1254a5d661aSToomas Soome int nfs_open(const char *path, struct open_file *f); 1264a5d661aSToomas Soome static int nfs_close(struct open_file *f); 1274a5d661aSToomas Soome static int nfs_read(struct open_file *f, void *buf, size_t size, size_t *resid); 1284a5d661aSToomas Soome static int nfs_write(struct open_file *f, void *buf, size_t size, size_t *resid); 1294a5d661aSToomas Soome static off_t nfs_seek(struct open_file *f, off_t offset, int where); 1304a5d661aSToomas Soome static int nfs_stat(struct open_file *f, struct stat *sb); 1314a5d661aSToomas Soome static int nfs_readdir(struct open_file *f, struct dirent *d); 1324a5d661aSToomas Soome 1334a5d661aSToomas Soome struct nfs_iodesc nfs_root_node; 1344a5d661aSToomas Soome 1354a5d661aSToomas Soome struct fs_ops nfs_fsops = { 1364a5d661aSToomas Soome "nfs", 1374a5d661aSToomas Soome nfs_open, 1384a5d661aSToomas Soome nfs_close, 1394a5d661aSToomas Soome nfs_read, 1404a5d661aSToomas Soome nfs_write, 1414a5d661aSToomas Soome nfs_seek, 1424a5d661aSToomas Soome nfs_stat, 1434a5d661aSToomas Soome nfs_readdir 1444a5d661aSToomas Soome }; 1454a5d661aSToomas Soome 146dd8e2f72SToomas Soome static int nfs_read_size = NFSREAD_MIN_SIZE; 147dd8e2f72SToomas Soome 148dd8e2f72SToomas Soome /* 149dd8e2f72SToomas Soome * Improve boot performance over NFS 150dd8e2f72SToomas Soome */ 151dd8e2f72SToomas Soome static void 152dd8e2f72SToomas Soome set_nfs_read_size(void) 153dd8e2f72SToomas Soome { 154dd8e2f72SToomas Soome char *env, *end; 155dd8e2f72SToomas Soome char buf[10]; 156dd8e2f72SToomas Soome 157dd8e2f72SToomas Soome if ((env = getenv("nfs.read_size")) != NULL) { 158dd8e2f72SToomas Soome errno = 0; 159dd8e2f72SToomas Soome nfs_read_size = strtol(env, &end, 0); 160dd8e2f72SToomas Soome if (errno != 0 || *env == '\0' || *end != '\0') { 161dd8e2f72SToomas Soome printf("%s: bad value: \"%s\", defaulting to %d\n", 162dd8e2f72SToomas Soome "nfs.read_size", env, NFSREAD_MIN_SIZE); 163dd8e2f72SToomas Soome nfs_read_size = NFSREAD_MIN_SIZE; 164dd8e2f72SToomas Soome } 165dd8e2f72SToomas Soome } 166dd8e2f72SToomas Soome if (nfs_read_size < NFSREAD_MIN_SIZE) { 167dd8e2f72SToomas Soome printf("%s: bad value: \"%d\", defaulting to %d\n", 168dd8e2f72SToomas Soome "nfs.read_size", nfs_read_size, NFSREAD_MIN_SIZE); 169dd8e2f72SToomas Soome nfs_read_size = NFSREAD_MIN_SIZE; 170dd8e2f72SToomas Soome } 171dd8e2f72SToomas Soome if (nfs_read_size > NFSREAD_MAX_SIZE) { 172dd8e2f72SToomas Soome printf("%s: bad value: \"%d\", defaulting to %d\n", 173dd8e2f72SToomas Soome "nfs.read_size", nfs_read_size, NFSREAD_MIN_SIZE); 174dd8e2f72SToomas Soome nfs_read_size = NFSREAD_MAX_SIZE; 175dd8e2f72SToomas Soome } 176dd8e2f72SToomas Soome snprintf(buf, sizeof (buf), "%d", nfs_read_size); 177dd8e2f72SToomas Soome setenv("nfs.read_size", buf, 1); 178dd8e2f72SToomas Soome } 179dd8e2f72SToomas Soome 1804a5d661aSToomas Soome /* 1814a5d661aSToomas Soome * Fetch the root file handle (call mount daemon) 1824a5d661aSToomas Soome * Return zero or error number. 1834a5d661aSToomas Soome */ 1844a5d661aSToomas Soome int 1854a5d661aSToomas Soome nfs_getrootfh(struct iodesc *d, char *path, uint32_t *fhlenp, u_char *fhp) 1864a5d661aSToomas Soome { 1877b2a1233SToomas Soome void *pkt = NULL; 1884a5d661aSToomas Soome int len; 1894a5d661aSToomas Soome struct args { 1904a5d661aSToomas Soome uint32_t len; 1914a5d661aSToomas Soome char path[FNAME_SIZE]; 1924a5d661aSToomas Soome } *args; 1934a5d661aSToomas Soome struct repl { 1944a5d661aSToomas Soome uint32_t errno; 1954a5d661aSToomas Soome uint32_t fhsize; 1964a5d661aSToomas Soome u_char fh[NFS_V3MAXFHSIZE]; 1974a5d661aSToomas Soome uint32_t authcnt; 1984a5d661aSToomas Soome uint32_t auth[7]; 1994a5d661aSToomas Soome } *repl; 2004a5d661aSToomas Soome struct { 2014a5d661aSToomas Soome uint32_t h[RPC_HEADER_WORDS]; 2024a5d661aSToomas Soome struct args d; 2034a5d661aSToomas Soome } sdata; 2044a5d661aSToomas Soome size_t cc; 2054a5d661aSToomas Soome 2064a5d661aSToomas Soome #ifdef NFS_DEBUG 2074a5d661aSToomas Soome if (debug) 2084a5d661aSToomas Soome printf("nfs_getrootfh: %s\n", path); 2094a5d661aSToomas Soome #endif 2104a5d661aSToomas Soome 2114a5d661aSToomas Soome args = &sdata.d; 2124a5d661aSToomas Soome 2134a5d661aSToomas Soome bzero(args, sizeof(*args)); 2144a5d661aSToomas Soome len = strlen(path); 2154a5d661aSToomas Soome if (len > sizeof(args->path)) 2164a5d661aSToomas Soome len = sizeof(args->path); 2174a5d661aSToomas Soome args->len = htonl(len); 2184a5d661aSToomas Soome bcopy(path, args->path, len); 2194a5d661aSToomas Soome len = sizeof(uint32_t) + roundup(len, sizeof(uint32_t)); 2204a5d661aSToomas Soome 2214a5d661aSToomas Soome cc = rpc_call(d, RPCPROG_MNT, RPCMNT_VER3, RPCMNT_MOUNT, 2227b2a1233SToomas Soome args, len, (void **)&repl, &pkt); 2237b2a1233SToomas Soome if (cc == -1) { 2247b2a1233SToomas Soome free(pkt); 2254a5d661aSToomas Soome /* errno was set by rpc_call */ 2264a5d661aSToomas Soome return (errno); 2277b2a1233SToomas Soome } 2287b2a1233SToomas Soome if (cc < 2 * sizeof (uint32_t)) { 2297b2a1233SToomas Soome free(pkt); 2304a5d661aSToomas Soome return (EBADRPC); 2317b2a1233SToomas Soome } 2327b2a1233SToomas Soome if (repl->errno != 0) { 2337b2a1233SToomas Soome free(pkt); 2344a5d661aSToomas Soome return (ntohl(repl->errno)); 2357b2a1233SToomas Soome } 2364a5d661aSToomas Soome *fhlenp = ntohl(repl->fhsize); 2374a5d661aSToomas Soome bcopy(repl->fh, fhp, *fhlenp); 238dd8e2f72SToomas Soome 239dd8e2f72SToomas Soome set_nfs_read_size(); 2407b2a1233SToomas Soome free(pkt); 2414a5d661aSToomas Soome return (0); 2424a5d661aSToomas Soome } 2434a5d661aSToomas Soome 2444a5d661aSToomas Soome /* 2454a5d661aSToomas Soome * Lookup a file. Store handle and attributes. 2464a5d661aSToomas Soome * Return zero or error number. 2474a5d661aSToomas Soome */ 2484a5d661aSToomas Soome int 2494a5d661aSToomas Soome nfs_lookupfh(struct nfs_iodesc *d, const char *name, struct nfs_iodesc *newfd) 2504a5d661aSToomas Soome { 2517b2a1233SToomas Soome void *pkt = NULL; 2524a5d661aSToomas Soome int len, rlen, pos; 2534a5d661aSToomas Soome struct args { 2544a5d661aSToomas Soome uint32_t fhsize; 2554a5d661aSToomas Soome uint32_t fhplusname[1 + 2564a5d661aSToomas Soome (NFS_V3MAXFHSIZE + FNAME_SIZE) / sizeof(uint32_t)]; 2574a5d661aSToomas Soome } *args; 2584a5d661aSToomas Soome struct repl { 2594a5d661aSToomas Soome uint32_t errno; 2604a5d661aSToomas Soome uint32_t fhsize; 2614a5d661aSToomas Soome uint32_t fhplusattr[(NFS_V3MAXFHSIZE + 2624a5d661aSToomas Soome 2 * (sizeof(uint32_t) + 2634a5d661aSToomas Soome sizeof(struct nfsv3_fattrs))) / sizeof(uint32_t)]; 2644a5d661aSToomas Soome } *repl; 2654a5d661aSToomas Soome struct { 2664a5d661aSToomas Soome uint32_t h[RPC_HEADER_WORDS]; 2674a5d661aSToomas Soome struct args d; 2684a5d661aSToomas Soome } sdata; 2694a5d661aSToomas Soome ssize_t cc; 2704a5d661aSToomas Soome 2714a5d661aSToomas Soome #ifdef NFS_DEBUG 2724a5d661aSToomas Soome if (debug) 2734a5d661aSToomas Soome printf("lookupfh: called\n"); 2744a5d661aSToomas Soome #endif 2754a5d661aSToomas Soome 2764a5d661aSToomas Soome args = &sdata.d; 2774a5d661aSToomas Soome 2784a5d661aSToomas Soome bzero(args, sizeof(*args)); 2794a5d661aSToomas Soome args->fhsize = htonl(d->fhsize); 2804a5d661aSToomas Soome bcopy(d->fh, args->fhplusname, d->fhsize); 2814a5d661aSToomas Soome len = strlen(name); 2824a5d661aSToomas Soome if (len > FNAME_SIZE) 2834a5d661aSToomas Soome len = FNAME_SIZE; 2844a5d661aSToomas Soome pos = roundup(d->fhsize, sizeof(uint32_t)) / sizeof(uint32_t); 2854a5d661aSToomas Soome args->fhplusname[pos++] = htonl(len); 2864a5d661aSToomas Soome bcopy(name, &args->fhplusname[pos], len); 2874a5d661aSToomas Soome len = sizeof(uint32_t) + pos * sizeof(uint32_t) + 2884a5d661aSToomas Soome roundup(len, sizeof(uint32_t)); 2894a5d661aSToomas Soome 2904a5d661aSToomas Soome cc = rpc_call(d->iodesc, NFS_PROG, NFS_VER3, NFSPROCV3_LOOKUP, 2917b2a1233SToomas Soome args, len, (void **)&repl, &pkt); 2927b2a1233SToomas Soome if (cc == -1) { 2937b2a1233SToomas Soome free(pkt); 2944a5d661aSToomas Soome return (errno); /* XXX - from rpc_call */ 2957b2a1233SToomas Soome } 2967b2a1233SToomas Soome if (cc < 2 * sizeof(uint32_t)) { 2977b2a1233SToomas Soome free(pkt); 2984a5d661aSToomas Soome return (EIO); 2997b2a1233SToomas Soome } 3007b2a1233SToomas Soome if (repl->errno != 0) { 3017b2a1233SToomas Soome free(pkt); 3024a5d661aSToomas Soome /* saerrno.h now matches NFS error numbers. */ 3034a5d661aSToomas Soome return (ntohl(repl->errno)); 3047b2a1233SToomas Soome } 3054a5d661aSToomas Soome newfd->fhsize = ntohl(repl->fhsize); 3064a5d661aSToomas Soome bcopy(repl->fhplusattr, &newfd->fh, newfd->fhsize); 3074a5d661aSToomas Soome pos = roundup(newfd->fhsize, sizeof(uint32_t)) / sizeof(uint32_t); 3087b2a1233SToomas Soome if (repl->fhplusattr[pos++] == 0) { 3097b2a1233SToomas Soome free(pkt); 3104a5d661aSToomas Soome return (EIO); 3117b2a1233SToomas Soome } 3124a5d661aSToomas Soome bcopy(&repl->fhplusattr[pos], &newfd->fa, sizeof(newfd->fa)); 3137b2a1233SToomas Soome free(pkt); 3144a5d661aSToomas Soome return (0); 3154a5d661aSToomas Soome } 3164a5d661aSToomas Soome 3174a5d661aSToomas Soome /* 3184a5d661aSToomas Soome * Get the destination of a symbolic link. 3194a5d661aSToomas Soome */ 3204a5d661aSToomas Soome int 3214a5d661aSToomas Soome nfs_readlink(struct nfs_iodesc *d, char *buf) 3224a5d661aSToomas Soome { 3237b2a1233SToomas Soome void *pkt = NULL; 3244a5d661aSToomas Soome struct args { 3254a5d661aSToomas Soome uint32_t fhsize; 3264a5d661aSToomas Soome u_char fh[NFS_V3MAXFHSIZE]; 3274a5d661aSToomas Soome } *args; 3284a5d661aSToomas Soome struct repl { 3294a5d661aSToomas Soome uint32_t errno; 3304a5d661aSToomas Soome uint32_t ok; 3314a5d661aSToomas Soome struct nfsv3_fattrs fa; 3324a5d661aSToomas Soome uint32_t len; 3334a5d661aSToomas Soome u_char path[NFS_MAXPATHLEN]; 3344a5d661aSToomas Soome } *repl; 3354a5d661aSToomas Soome struct { 3364a5d661aSToomas Soome uint32_t h[RPC_HEADER_WORDS]; 3374a5d661aSToomas Soome struct args d; 3384a5d661aSToomas Soome } sdata; 3394a5d661aSToomas Soome ssize_t cc; 3407b2a1233SToomas Soome int rc = 0; 3414a5d661aSToomas Soome 3424a5d661aSToomas Soome #ifdef NFS_DEBUG 3434a5d661aSToomas Soome if (debug) 3444a5d661aSToomas Soome printf("readlink: called\n"); 3454a5d661aSToomas Soome #endif 3464a5d661aSToomas Soome 3474a5d661aSToomas Soome args = &sdata.d; 3484a5d661aSToomas Soome 3494a5d661aSToomas Soome bzero(args, sizeof(*args)); 3504a5d661aSToomas Soome args->fhsize = htonl(d->fhsize); 3514a5d661aSToomas Soome bcopy(d->fh, args->fh, d->fhsize); 3524a5d661aSToomas Soome cc = rpc_call(d->iodesc, NFS_PROG, NFS_VER3, NFSPROCV3_READLINK, 3534a5d661aSToomas Soome args, sizeof(uint32_t) + roundup(d->fhsize, sizeof(uint32_t)), 3547b2a1233SToomas Soome (void **)&repl, &pkt); 3554a5d661aSToomas Soome if (cc == -1) 3564a5d661aSToomas Soome return (errno); 3574a5d661aSToomas Soome 3587b2a1233SToomas Soome if (cc < 2 * sizeof(uint32_t)) { 3597b2a1233SToomas Soome rc = EIO; 3607b2a1233SToomas Soome goto done; 3617b2a1233SToomas Soome } 3624a5d661aSToomas Soome 3637b2a1233SToomas Soome if (repl->errno != 0) { 3647b2a1233SToomas Soome rc = ntohl(repl->errno); 3657b2a1233SToomas Soome goto done; 3667b2a1233SToomas Soome } 3674a5d661aSToomas Soome 3687b2a1233SToomas Soome if (repl->ok == 0) { 3697b2a1233SToomas Soome rc = EIO; 3707b2a1233SToomas Soome goto done; 3717b2a1233SToomas Soome } 3724a5d661aSToomas Soome 3734a5d661aSToomas Soome repl->len = ntohl(repl->len); 3747b2a1233SToomas Soome if (repl->len > NFS_MAXPATHLEN) { 3757b2a1233SToomas Soome rc = ENAMETOOLONG; 3767b2a1233SToomas Soome goto done; 3777b2a1233SToomas Soome } 3784a5d661aSToomas Soome 3794a5d661aSToomas Soome bcopy(repl->path, buf, repl->len); 3804a5d661aSToomas Soome buf[repl->len] = 0; 3817b2a1233SToomas Soome done: 3827b2a1233SToomas Soome free(pkt); 3837b2a1233SToomas Soome return (rc); 3844a5d661aSToomas Soome } 3854a5d661aSToomas Soome 3864a5d661aSToomas Soome /* 3874a5d661aSToomas Soome * Read data from a file. 3884a5d661aSToomas Soome * Return transfer count or -1 (and set errno) 3894a5d661aSToomas Soome */ 3904a5d661aSToomas Soome ssize_t 3914a5d661aSToomas Soome nfs_readdata(struct nfs_iodesc *d, off_t off, void *addr, size_t len) 3924a5d661aSToomas Soome { 3937b2a1233SToomas Soome void *pkt = NULL; 3944a5d661aSToomas Soome struct args { 3954a5d661aSToomas Soome uint32_t fhsize; 3964a5d661aSToomas Soome uint32_t fhoffcnt[NFS_V3MAXFHSIZE / sizeof(uint32_t) + 3]; 3974a5d661aSToomas Soome } *args; 3984a5d661aSToomas Soome struct repl { 3994a5d661aSToomas Soome uint32_t errno; 4004a5d661aSToomas Soome uint32_t ok; 4014a5d661aSToomas Soome struct nfsv3_fattrs fa; 4024a5d661aSToomas Soome uint32_t count; 4034a5d661aSToomas Soome uint32_t eof; 4044a5d661aSToomas Soome uint32_t len; 405dd8e2f72SToomas Soome u_char data[NFSREAD_MAX_SIZE]; 4064a5d661aSToomas Soome } *repl; 4074a5d661aSToomas Soome struct { 4084a5d661aSToomas Soome uint32_t h[RPC_HEADER_WORDS]; 4094a5d661aSToomas Soome struct args d; 4104a5d661aSToomas Soome } sdata; 4114a5d661aSToomas Soome size_t cc; 4124a5d661aSToomas Soome long x; 4134a5d661aSToomas Soome int hlen, rlen, pos; 4144a5d661aSToomas Soome 4154a5d661aSToomas Soome args = &sdata.d; 4164a5d661aSToomas Soome 4174a5d661aSToomas Soome bzero(args, sizeof(*args)); 4184a5d661aSToomas Soome args->fhsize = htonl(d->fhsize); 4194a5d661aSToomas Soome bcopy(d->fh, args->fhoffcnt, d->fhsize); 4204a5d661aSToomas Soome pos = roundup(d->fhsize, sizeof(uint32_t)) / sizeof(uint32_t); 4214a5d661aSToomas Soome args->fhoffcnt[pos++] = 0; 4224a5d661aSToomas Soome args->fhoffcnt[pos++] = htonl((uint32_t)off); 423dd8e2f72SToomas Soome if (len > nfs_read_size) 424dd8e2f72SToomas Soome len = nfs_read_size; 4254a5d661aSToomas Soome args->fhoffcnt[pos] = htonl((uint32_t)len); 426dd8e2f72SToomas Soome hlen = offsetof(struct repl, data[0]); 4274a5d661aSToomas Soome 4284a5d661aSToomas Soome cc = rpc_call(d->iodesc, NFS_PROG, NFS_VER3, NFSPROCV3_READ, 4294a5d661aSToomas Soome args, 4 * sizeof(uint32_t) + roundup(d->fhsize, sizeof(uint32_t)), 4307b2a1233SToomas Soome (void **)&repl, &pkt); 4317b2a1233SToomas Soome if (cc == -1) { 4324a5d661aSToomas Soome /* errno was already set by rpc_call */ 4334a5d661aSToomas Soome return (-1); 4347b2a1233SToomas Soome } 4354a5d661aSToomas Soome if (cc < hlen) { 4364a5d661aSToomas Soome errno = EBADRPC; 4377b2a1233SToomas Soome free(pkt); 4384a5d661aSToomas Soome return (-1); 4394a5d661aSToomas Soome } 4404a5d661aSToomas Soome if (repl->errno != 0) { 4414a5d661aSToomas Soome errno = ntohl(repl->errno); 4427b2a1233SToomas Soome free(pkt); 4434a5d661aSToomas Soome return (-1); 4444a5d661aSToomas Soome } 4454a5d661aSToomas Soome rlen = cc - hlen; 4464a5d661aSToomas Soome x = ntohl(repl->count); 4474a5d661aSToomas Soome if (rlen < x) { 4484a5d661aSToomas Soome printf("nfsread: short packet, %d < %ld\n", rlen, x); 4494a5d661aSToomas Soome errno = EBADRPC; 4507b2a1233SToomas Soome free(pkt); 4514a5d661aSToomas Soome return (-1); 4524a5d661aSToomas Soome } 4534a5d661aSToomas Soome bcopy(repl->data, addr, x); 4547b2a1233SToomas Soome free(pkt); 4554a5d661aSToomas Soome return (x); 4564a5d661aSToomas Soome } 4574a5d661aSToomas Soome 4584a5d661aSToomas Soome /* 4594a5d661aSToomas Soome * Open a file. 4604a5d661aSToomas Soome * return zero or error number 4614a5d661aSToomas Soome */ 4624a5d661aSToomas Soome int 4634a5d661aSToomas Soome nfs_open(const char *upath, struct open_file *f) 4644a5d661aSToomas Soome { 4654a5d661aSToomas Soome struct iodesc *desc; 4664a5d661aSToomas Soome struct nfs_iodesc *currfd; 4674a5d661aSToomas Soome char buf[2 * NFS_V3MAXFHSIZE + 3]; 4684a5d661aSToomas Soome u_char *fh; 4694a5d661aSToomas Soome char *cp; 4704a5d661aSToomas Soome int i; 4714a5d661aSToomas Soome struct nfs_iodesc *newfd; 4724a5d661aSToomas Soome struct nfsv3_fattrs *fa; 4734a5d661aSToomas Soome char *ncp; 4744a5d661aSToomas Soome int c; 4754a5d661aSToomas Soome char namebuf[NFS_MAXPATHLEN + 1]; 4764a5d661aSToomas Soome char linkbuf[NFS_MAXPATHLEN + 1]; 4774a5d661aSToomas Soome int nlinks = 0; 4784a5d661aSToomas Soome int error; 4794a5d661aSToomas Soome char *path; 4804a5d661aSToomas Soome 48118609d04SToomas Soome if (netproto != NET_NFS) 48218609d04SToomas Soome return (EINVAL); 48318609d04SToomas Soome 4844a5d661aSToomas Soome #ifdef NFS_DEBUG 4854a5d661aSToomas Soome if (debug) 4864a5d661aSToomas Soome printf("nfs_open: %s (rootpath=%s)\n", upath, rootpath); 4874a5d661aSToomas Soome #endif 4884a5d661aSToomas Soome if (!rootpath[0]) { 4894a5d661aSToomas Soome printf("no rootpath, no nfs\n"); 4904a5d661aSToomas Soome return (ENXIO); 4914a5d661aSToomas Soome } 4924a5d661aSToomas Soome 4937b2a1233SToomas Soome if (f->f_dev->dv_type != DEVT_NET) 4944a5d661aSToomas Soome return (EINVAL); 4954a5d661aSToomas Soome 4964a5d661aSToomas Soome if (!(desc = socktodesc(*(int *)(f->f_devdata)))) 4974a5d661aSToomas Soome return (EINVAL); 4984a5d661aSToomas Soome 4994a5d661aSToomas Soome /* Bind to a reserved port. */ 5004a5d661aSToomas Soome desc->myport = htons(--rpc_port); 5014a5d661aSToomas Soome desc->destip = rootip; 5024a5d661aSToomas Soome if ((error = nfs_getrootfh(desc, rootpath, &nfs_root_node.fhsize, 5034a5d661aSToomas Soome nfs_root_node.fh))) 5044a5d661aSToomas Soome return (error); 5054a5d661aSToomas Soome nfs_root_node.fa.fa_type = htonl(NFDIR); 5064a5d661aSToomas Soome nfs_root_node.fa.fa_mode = htonl(0755); 5074a5d661aSToomas Soome nfs_root_node.fa.fa_nlink = htonl(2); 5084a5d661aSToomas Soome nfs_root_node.iodesc = desc; 5094a5d661aSToomas Soome 5104a5d661aSToomas Soome fh = &nfs_root_node.fh[0]; 5114a5d661aSToomas Soome buf[0] = 'X'; 5124a5d661aSToomas Soome cp = &buf[1]; 5134a5d661aSToomas Soome for (i = 0; i < nfs_root_node.fhsize; i++, cp += 2) 5144a5d661aSToomas Soome sprintf(cp, "%02x", fh[i]); 5154a5d661aSToomas Soome sprintf(cp, "X"); 5164a5d661aSToomas Soome setenv("boot.nfsroot.server", inet_ntoa(rootip), 1); 5174a5d661aSToomas Soome setenv("boot.nfsroot.path", rootpath, 1); 5184a5d661aSToomas Soome setenv("boot.nfsroot.nfshandle", buf, 1); 5194a5d661aSToomas Soome sprintf(buf, "%d", nfs_root_node.fhsize); 5204a5d661aSToomas Soome setenv("boot.nfsroot.nfshandlelen", buf, 1); 5214a5d661aSToomas Soome 5224a5d661aSToomas Soome /* Allocate file system specific data structure */ 5234a5d661aSToomas Soome currfd = malloc(sizeof(*newfd)); 5244a5d661aSToomas Soome if (currfd == NULL) { 5254a5d661aSToomas Soome error = ENOMEM; 5264a5d661aSToomas Soome goto out; 5274a5d661aSToomas Soome } 5284a5d661aSToomas Soome bcopy(&nfs_root_node, currfd, sizeof(*currfd)); 529830d404aSToomas Soome newfd = NULL; 5304a5d661aSToomas Soome 5314a5d661aSToomas Soome cp = path = strdup(upath); 5324a5d661aSToomas Soome if (path == NULL) { 5334a5d661aSToomas Soome error = ENOMEM; 5344a5d661aSToomas Soome goto out; 5354a5d661aSToomas Soome } 5364a5d661aSToomas Soome while (*cp) { 5374a5d661aSToomas Soome /* 5384a5d661aSToomas Soome * Remove extra separators 5394a5d661aSToomas Soome */ 5404a5d661aSToomas Soome while (*cp == '/') 5414a5d661aSToomas Soome cp++; 5424a5d661aSToomas Soome 5434a5d661aSToomas Soome if (*cp == '\0') 5444a5d661aSToomas Soome break; 5454a5d661aSToomas Soome /* 5464a5d661aSToomas Soome * Check that current node is a directory. 5474a5d661aSToomas Soome */ 5484a5d661aSToomas Soome if (currfd->fa.fa_type != htonl(NFDIR)) { 5494a5d661aSToomas Soome error = ENOTDIR; 5504a5d661aSToomas Soome goto out; 5514a5d661aSToomas Soome } 5524a5d661aSToomas Soome 5534a5d661aSToomas Soome /* allocate file system specific data structure */ 5544a5d661aSToomas Soome newfd = malloc(sizeof(*newfd)); 5554a5d661aSToomas Soome if (newfd == NULL) { 5564a5d661aSToomas Soome error = ENOMEM; 5574a5d661aSToomas Soome goto out; 5584a5d661aSToomas Soome } 5594a5d661aSToomas Soome newfd->iodesc = currfd->iodesc; 5604a5d661aSToomas Soome 5614a5d661aSToomas Soome /* 5624a5d661aSToomas Soome * Get next component of path name. 5634a5d661aSToomas Soome */ 5644a5d661aSToomas Soome { 5654a5d661aSToomas Soome int len = 0; 5664a5d661aSToomas Soome 5674a5d661aSToomas Soome ncp = cp; 5684a5d661aSToomas Soome while ((c = *cp) != '\0' && c != '/') { 5694a5d661aSToomas Soome if (++len > NFS_MAXNAMLEN) { 5704a5d661aSToomas Soome error = ENOENT; 5714a5d661aSToomas Soome goto out; 5724a5d661aSToomas Soome } 5734a5d661aSToomas Soome cp++; 5744a5d661aSToomas Soome } 5754a5d661aSToomas Soome *cp = '\0'; 5764a5d661aSToomas Soome } 5774a5d661aSToomas Soome 5784a5d661aSToomas Soome /* lookup a file handle */ 5794a5d661aSToomas Soome error = nfs_lookupfh(currfd, ncp, newfd); 5804a5d661aSToomas Soome *cp = c; 5814a5d661aSToomas Soome if (error) 5824a5d661aSToomas Soome goto out; 5834a5d661aSToomas Soome 5844a5d661aSToomas Soome /* 5854a5d661aSToomas Soome * Check for symbolic link 5864a5d661aSToomas Soome */ 5874a5d661aSToomas Soome if (newfd->fa.fa_type == htonl(NFLNK)) { 5884a5d661aSToomas Soome int link_len, len; 5894a5d661aSToomas Soome 5904a5d661aSToomas Soome error = nfs_readlink(newfd, linkbuf); 5914a5d661aSToomas Soome if (error) 5924a5d661aSToomas Soome goto out; 5934a5d661aSToomas Soome 5944a5d661aSToomas Soome link_len = strlen(linkbuf); 5954a5d661aSToomas Soome len = strlen(cp); 5964a5d661aSToomas Soome 5974a5d661aSToomas Soome if (link_len + len > MAXPATHLEN 5984a5d661aSToomas Soome || ++nlinks > MAXSYMLINKS) { 5994a5d661aSToomas Soome error = ENOENT; 6004a5d661aSToomas Soome goto out; 6014a5d661aSToomas Soome } 6024a5d661aSToomas Soome 6034a5d661aSToomas Soome bcopy(cp, &namebuf[link_len], len + 1); 6044a5d661aSToomas Soome bcopy(linkbuf, namebuf, link_len); 6054a5d661aSToomas Soome 6064a5d661aSToomas Soome /* 6074a5d661aSToomas Soome * If absolute pathname, restart at root. 6084a5d661aSToomas Soome * If relative pathname, restart at parent directory. 6094a5d661aSToomas Soome */ 6104a5d661aSToomas Soome cp = namebuf; 6114a5d661aSToomas Soome if (*cp == '/') 6124a5d661aSToomas Soome bcopy(&nfs_root_node, currfd, sizeof(*currfd)); 6134a5d661aSToomas Soome 6144a5d661aSToomas Soome free(newfd); 615830d404aSToomas Soome newfd = NULL; 6164a5d661aSToomas Soome 6174a5d661aSToomas Soome continue; 6184a5d661aSToomas Soome } 6194a5d661aSToomas Soome 6204a5d661aSToomas Soome free(currfd); 6214a5d661aSToomas Soome currfd = newfd; 622830d404aSToomas Soome newfd = NULL; 6234a5d661aSToomas Soome } 6244a5d661aSToomas Soome 6254a5d661aSToomas Soome error = 0; 6264a5d661aSToomas Soome 6274a5d661aSToomas Soome out: 6284a5d661aSToomas Soome free(newfd); 6294a5d661aSToomas Soome free(path); 6304a5d661aSToomas Soome if (!error) { 6314a5d661aSToomas Soome currfd->off = 0; 6324a5d661aSToomas Soome currfd->cookie = 0; 6334a5d661aSToomas Soome f->f_fsdata = (void *)currfd; 6344a5d661aSToomas Soome return (0); 6354a5d661aSToomas Soome } 6364a5d661aSToomas Soome 6374a5d661aSToomas Soome #ifdef NFS_DEBUG 6384a5d661aSToomas Soome if (debug) 6394a5d661aSToomas Soome printf("nfs_open: %s lookupfh failed: %s\n", 6404a5d661aSToomas Soome path, strerror(error)); 6414a5d661aSToomas Soome #endif 6424a5d661aSToomas Soome free(currfd); 6434a5d661aSToomas Soome 6444a5d661aSToomas Soome return (error); 6454a5d661aSToomas Soome } 6464a5d661aSToomas Soome 6474a5d661aSToomas Soome int 6484a5d661aSToomas Soome nfs_close(struct open_file *f) 6494a5d661aSToomas Soome { 6504a5d661aSToomas Soome struct nfs_iodesc *fp = (struct nfs_iodesc *)f->f_fsdata; 6514a5d661aSToomas Soome 6524a5d661aSToomas Soome #ifdef NFS_DEBUG 6534a5d661aSToomas Soome if (debug) 6544a5d661aSToomas Soome printf("nfs_close: fp=0x%lx\n", (u_long)fp); 6554a5d661aSToomas Soome #endif 6564a5d661aSToomas Soome 6574a5d661aSToomas Soome free(fp); 6587b2a1233SToomas Soome f->f_fsdata = NULL; 6594a5d661aSToomas Soome 6604a5d661aSToomas Soome return (0); 6614a5d661aSToomas Soome } 6624a5d661aSToomas Soome 6634a5d661aSToomas Soome /* 6644a5d661aSToomas Soome * read a portion of a file 6654a5d661aSToomas Soome */ 6664a5d661aSToomas Soome int 6674a5d661aSToomas Soome nfs_read(struct open_file *f, void *buf, size_t size, size_t *resid) 6684a5d661aSToomas Soome { 6694a5d661aSToomas Soome struct nfs_iodesc *fp = (struct nfs_iodesc *)f->f_fsdata; 6704a5d661aSToomas Soome ssize_t cc; 6714a5d661aSToomas Soome char *addr = buf; 6724a5d661aSToomas Soome 6734a5d661aSToomas Soome #ifdef NFS_DEBUG 6744a5d661aSToomas Soome if (debug) 6754a5d661aSToomas Soome printf("nfs_read: size=%lu off=%d\n", (u_long)size, 6764a5d661aSToomas Soome (int)fp->off); 6774a5d661aSToomas Soome #endif 6784a5d661aSToomas Soome while ((int)size > 0) { 6794a5d661aSToomas Soome twiddle(16); 6804a5d661aSToomas Soome cc = nfs_readdata(fp, fp->off, (void *)addr, size); 6814a5d661aSToomas Soome /* XXX maybe should retry on certain errors */ 6824a5d661aSToomas Soome if (cc == -1) { 6834a5d661aSToomas Soome #ifdef NFS_DEBUG 6844a5d661aSToomas Soome if (debug) 6854a5d661aSToomas Soome printf("nfs_read: read: %s", strerror(errno)); 6864a5d661aSToomas Soome #endif 6874a5d661aSToomas Soome return (errno); /* XXX - from nfs_readdata */ 6884a5d661aSToomas Soome } 6894a5d661aSToomas Soome if (cc == 0) { 6904a5d661aSToomas Soome #ifdef NFS_DEBUG 6914a5d661aSToomas Soome if (debug) 6924a5d661aSToomas Soome printf("nfs_read: hit EOF unexpectantly"); 6934a5d661aSToomas Soome #endif 6944a5d661aSToomas Soome goto ret; 6954a5d661aSToomas Soome } 6964a5d661aSToomas Soome fp->off += cc; 6974a5d661aSToomas Soome addr += cc; 6984a5d661aSToomas Soome size -= cc; 6994a5d661aSToomas Soome } 7004a5d661aSToomas Soome ret: 7014a5d661aSToomas Soome if (resid) 7024a5d661aSToomas Soome *resid = size; 7034a5d661aSToomas Soome 7044a5d661aSToomas Soome return (0); 7054a5d661aSToomas Soome } 7064a5d661aSToomas Soome 7074a5d661aSToomas Soome /* 7084a5d661aSToomas Soome * Not implemented. 7094a5d661aSToomas Soome */ 7104a5d661aSToomas Soome int 7114a5d661aSToomas Soome nfs_write(struct open_file *f, void *buf, size_t size, size_t *resid) 7124a5d661aSToomas Soome { 7134a5d661aSToomas Soome return (EROFS); 7144a5d661aSToomas Soome } 7154a5d661aSToomas Soome 7164a5d661aSToomas Soome off_t 7174a5d661aSToomas Soome nfs_seek(struct open_file *f, off_t offset, int where) 7184a5d661aSToomas Soome { 7194a5d661aSToomas Soome struct nfs_iodesc *d = (struct nfs_iodesc *)f->f_fsdata; 7204a5d661aSToomas Soome uint32_t size = ntohl(d->fa.fa_size.val[1]); 7214a5d661aSToomas Soome 7224a5d661aSToomas Soome switch (where) { 7234a5d661aSToomas Soome case SEEK_SET: 7244a5d661aSToomas Soome d->off = offset; 7254a5d661aSToomas Soome break; 7264a5d661aSToomas Soome case SEEK_CUR: 7274a5d661aSToomas Soome d->off += offset; 7284a5d661aSToomas Soome break; 7294a5d661aSToomas Soome case SEEK_END: 7304a5d661aSToomas Soome d->off = size - offset; 7314a5d661aSToomas Soome break; 7324a5d661aSToomas Soome default: 7334a5d661aSToomas Soome errno = EINVAL; 7344a5d661aSToomas Soome return (-1); 7354a5d661aSToomas Soome } 7364a5d661aSToomas Soome 7374a5d661aSToomas Soome return (d->off); 7384a5d661aSToomas Soome } 7394a5d661aSToomas Soome 7404a5d661aSToomas Soome /* NFNON=0, NFREG=1, NFDIR=2, NFBLK=3, NFCHR=4, NFLNK=5, NFSOCK=6, NFFIFO=7 */ 7414a5d661aSToomas Soome int nfs_stat_types[9] = { 7424a5d661aSToomas Soome 0, S_IFREG, S_IFDIR, S_IFBLK, S_IFCHR, S_IFLNK, S_IFSOCK, S_IFIFO, 0 }; 7434a5d661aSToomas Soome 7444a5d661aSToomas Soome int 7454a5d661aSToomas Soome nfs_stat(struct open_file *f, struct stat *sb) 7464a5d661aSToomas Soome { 7474a5d661aSToomas Soome struct nfs_iodesc *fp = (struct nfs_iodesc *)f->f_fsdata; 7484a5d661aSToomas Soome uint32_t ftype, mode; 7494a5d661aSToomas Soome 7504a5d661aSToomas Soome ftype = ntohl(fp->fa.fa_type); 7514a5d661aSToomas Soome mode = ntohl(fp->fa.fa_mode); 7524a5d661aSToomas Soome mode |= nfs_stat_types[ftype & 7]; 7534a5d661aSToomas Soome 7544a5d661aSToomas Soome sb->st_mode = mode; 7554a5d661aSToomas Soome sb->st_nlink = ntohl(fp->fa.fa_nlink); 7564a5d661aSToomas Soome sb->st_uid = ntohl(fp->fa.fa_uid); 7574a5d661aSToomas Soome sb->st_gid = ntohl(fp->fa.fa_gid); 7584a5d661aSToomas Soome sb->st_size = ntohl(fp->fa.fa_size.val[1]); 7594a5d661aSToomas Soome 7604a5d661aSToomas Soome return (0); 7614a5d661aSToomas Soome } 7624a5d661aSToomas Soome 7634a5d661aSToomas Soome static int 7644a5d661aSToomas Soome nfs_readdir(struct open_file *f, struct dirent *d) 7654a5d661aSToomas Soome { 7664a5d661aSToomas Soome struct nfs_iodesc *fp = (struct nfs_iodesc *)f->f_fsdata; 7674a5d661aSToomas Soome struct nfsv3_readdir_repl *repl; 7684a5d661aSToomas Soome struct nfsv3_readdir_entry *rent; 7697b2a1233SToomas Soome static void *pkt = NULL; 7704a5d661aSToomas Soome static char *buf; 7714a5d661aSToomas Soome static struct nfs_iodesc *pfp = NULL; 7724a5d661aSToomas Soome static uint64_t cookie = 0; 7734a5d661aSToomas Soome size_t cc; 7747b2a1233SToomas Soome int pos, rc; 7754a5d661aSToomas Soome 7764a5d661aSToomas Soome struct args { 7774a5d661aSToomas Soome uint32_t fhsize; 7784a5d661aSToomas Soome uint32_t fhpluscookie[5 + NFS_V3MAXFHSIZE]; 7794a5d661aSToomas Soome } *args; 7804a5d661aSToomas Soome struct { 7814a5d661aSToomas Soome uint32_t h[RPC_HEADER_WORDS]; 7824a5d661aSToomas Soome struct args d; 7834a5d661aSToomas Soome } sdata; 7844a5d661aSToomas Soome 7854a5d661aSToomas Soome if (fp != pfp || fp->off != cookie) { 7864a5d661aSToomas Soome pfp = NULL; 7874a5d661aSToomas Soome refill: 7887b2a1233SToomas Soome free(pkt); 7897b2a1233SToomas Soome pkt = NULL; 7904a5d661aSToomas Soome args = &sdata.d; 7914a5d661aSToomas Soome bzero(args, sizeof(*args)); 7924a5d661aSToomas Soome 7934a5d661aSToomas Soome args->fhsize = htonl(fp->fhsize); 7944a5d661aSToomas Soome bcopy(fp->fh, args->fhpluscookie, fp->fhsize); 7954a5d661aSToomas Soome pos = roundup(fp->fhsize, sizeof(uint32_t)) / sizeof(uint32_t); 7964a5d661aSToomas Soome args->fhpluscookie[pos++] = htonl(fp->off >> 32); 7974a5d661aSToomas Soome args->fhpluscookie[pos++] = htonl(fp->off); 7984a5d661aSToomas Soome args->fhpluscookie[pos++] = htonl(fp->cookie >> 32); 7994a5d661aSToomas Soome args->fhpluscookie[pos++] = htonl(fp->cookie); 8004a5d661aSToomas Soome args->fhpluscookie[pos] = htonl(NFS_READDIRSIZE); 8014a5d661aSToomas Soome 8024a5d661aSToomas Soome cc = rpc_call(fp->iodesc, NFS_PROG, NFS_VER3, NFSPROCV3_READDIR, 8034a5d661aSToomas Soome args, 6 * sizeof(uint32_t) + 8044a5d661aSToomas Soome roundup(fp->fhsize, sizeof(uint32_t)), 8057b2a1233SToomas Soome (void **)&buf, &pkt); 8067b2a1233SToomas Soome if (cc == -1) { 8077b2a1233SToomas Soome rc = errno; 8087b2a1233SToomas Soome goto err; 8097b2a1233SToomas Soome } 8104a5d661aSToomas Soome repl = (struct nfsv3_readdir_repl *)buf; 8117b2a1233SToomas Soome if (repl->errno != 0) { 8127b2a1233SToomas Soome rc = ntohl(repl->errno); 8137b2a1233SToomas Soome goto err; 8147b2a1233SToomas Soome } 8154a5d661aSToomas Soome pfp = fp; 8164a5d661aSToomas Soome cookie = fp->off; 8174a5d661aSToomas Soome fp->cookie = ((uint64_t)ntohl(repl->cookiev0) << 32) | 8184a5d661aSToomas Soome ntohl(repl->cookiev1); 8194a5d661aSToomas Soome buf += sizeof (struct nfsv3_readdir_repl); 8204a5d661aSToomas Soome } 8214a5d661aSToomas Soome rent = (struct nfsv3_readdir_entry *)buf; 8224a5d661aSToomas Soome 8234a5d661aSToomas Soome if (rent->follows == 0) { 8244a5d661aSToomas Soome /* fid0 is actually eof */ 8254a5d661aSToomas Soome if (rent->fid0 != 0) { 8267b2a1233SToomas Soome rc = ENOENT; 8277b2a1233SToomas Soome goto err; 8284a5d661aSToomas Soome } 8294a5d661aSToomas Soome goto refill; 8304a5d661aSToomas Soome } 8314a5d661aSToomas Soome 8324a5d661aSToomas Soome d->d_namlen = ntohl(rent->len); 8334a5d661aSToomas Soome bcopy(rent->nameplus, d->d_name, d->d_namlen); 8344a5d661aSToomas Soome d->d_name[d->d_namlen] = '\0'; 8354a5d661aSToomas Soome 8364a5d661aSToomas Soome pos = roundup(d->d_namlen, sizeof(uint32_t)) / sizeof(uint32_t); 8374a5d661aSToomas Soome fp->off = cookie = ((uint64_t)ntohl(rent->nameplus[pos]) << 32) | 8384a5d661aSToomas Soome ntohl(rent->nameplus[pos + 1]); 8394a5d661aSToomas Soome pos += 2; 8404a5d661aSToomas Soome buf = (u_char *)&rent->nameplus[pos]; 8414a5d661aSToomas Soome return (0); 8427b2a1233SToomas Soome 8437b2a1233SToomas Soome err: 8447b2a1233SToomas Soome free(pkt); 8457b2a1233SToomas Soome pkt = NULL; 8467b2a1233SToomas Soome pfp = NULL; 8477b2a1233SToomas Soome cookie = 0; 8487b2a1233SToomas Soome return (rc); 8494a5d661aSToomas Soome } 850