1ca987d46SWarner Losh /* $NetBSD: nfs.c,v 1.2 1998/01/24 12:43:09 drochner Exp $ */ 2ca987d46SWarner Losh 3ca987d46SWarner Losh /*- 4ca987d46SWarner Losh * Copyright (c) 1993 John Brezak 5ca987d46SWarner Losh * All rights reserved. 6ca987d46SWarner Losh * 7ca987d46SWarner Losh * Redistribution and use in source and binary forms, with or without 8ca987d46SWarner Losh * modification, are permitted provided that the following conditions 9ca987d46SWarner Losh * are met: 10ca987d46SWarner Losh * 1. Redistributions of source code must retain the above copyright 11ca987d46SWarner Losh * notice, this list of conditions and the following disclaimer. 12ca987d46SWarner Losh * 2. Redistributions in binary form must reproduce the above copyright 13ca987d46SWarner Losh * notice, this list of conditions and the following disclaimer in the 14ca987d46SWarner Losh * documentation and/or other materials provided with the distribution. 15ca987d46SWarner Losh * 3. The name of the author may not be used to endorse or promote products 16ca987d46SWarner Losh * derived from this software without specific prior written permission. 17ca987d46SWarner Losh * 18ca987d46SWarner Losh * THIS SOFTWARE IS PROVIDED BY THE AUTHOR `AS IS'' AND ANY EXPRESS OR 19ca987d46SWarner Losh * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 20ca987d46SWarner Losh * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 21ca987d46SWarner Losh * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, 22ca987d46SWarner Losh * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 23ca987d46SWarner Losh * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 24ca987d46SWarner Losh * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 25ca987d46SWarner Losh * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 26ca987d46SWarner Losh * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 27ca987d46SWarner Losh * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 28ca987d46SWarner Losh * POSSIBILITY OF SUCH DAMAGE. 29ca987d46SWarner Losh */ 30ca987d46SWarner Losh 31ca987d46SWarner Losh #include <sys/cdefs.h> 32ca987d46SWarner Losh __FBSDID("$FreeBSD$"); 33ca987d46SWarner Losh 34ca987d46SWarner Losh #include <sys/param.h> 35ca987d46SWarner Losh #include <sys/time.h> 36ca987d46SWarner Losh #include <sys/socket.h> 37ca987d46SWarner Losh #include <sys/stat.h> 38ca987d46SWarner Losh #include <string.h> 39ca987d46SWarner Losh #include <stddef.h> 40ca987d46SWarner Losh 41ca987d46SWarner Losh #include <netinet/in.h> 42ca987d46SWarner Losh #include <netinet/in_systm.h> 43ca987d46SWarner Losh 44ca987d46SWarner Losh #include "rpcv2.h" 45ca987d46SWarner Losh #include "nfsv2.h" 46ca987d46SWarner Losh 47ca987d46SWarner Losh #include "stand.h" 48ca987d46SWarner Losh #include "net.h" 49ca987d46SWarner Losh #include "netif.h" 50ca987d46SWarner Losh #include "rpc.h" 51ca987d46SWarner Losh 52ca987d46SWarner Losh #define NFS_DEBUGxx 53ca987d46SWarner Losh 54ca987d46SWarner Losh #define NFSREAD_MIN_SIZE 1024 55ca987d46SWarner Losh #define NFSREAD_MAX_SIZE 16384 56ca987d46SWarner Losh 57ca987d46SWarner Losh /* NFSv3 definitions */ 58ca987d46SWarner Losh #define NFS_V3MAXFHSIZE 64 59ca987d46SWarner Losh #define NFS_VER3 3 60ca987d46SWarner Losh #define RPCMNT_VER3 3 61ca987d46SWarner Losh #define NFSPROCV3_LOOKUP 3 62ca987d46SWarner Losh #define NFSPROCV3_READLINK 5 63ca987d46SWarner Losh #define NFSPROCV3_READ 6 64ca987d46SWarner Losh #define NFSPROCV3_READDIR 16 65ca987d46SWarner Losh 66ca987d46SWarner Losh typedef struct { 67ca987d46SWarner Losh uint32_t val[2]; 68ca987d46SWarner Losh } n_quad; 69ca987d46SWarner Losh 70ca987d46SWarner Losh struct nfsv3_time { 71ca987d46SWarner Losh uint32_t nfs_sec; 72ca987d46SWarner Losh uint32_t nfs_nsec; 73ca987d46SWarner Losh }; 74ca987d46SWarner Losh 75ca987d46SWarner Losh struct nfsv3_fattrs { 76ca987d46SWarner Losh uint32_t fa_type; 77ca987d46SWarner Losh uint32_t fa_mode; 78ca987d46SWarner Losh uint32_t fa_nlink; 79ca987d46SWarner Losh uint32_t fa_uid; 80ca987d46SWarner Losh uint32_t fa_gid; 81ca987d46SWarner Losh n_quad fa_size; 82ca987d46SWarner Losh n_quad fa_used; 83ca987d46SWarner Losh n_quad fa_rdev; 84ca987d46SWarner Losh n_quad fa_fsid; 85ca987d46SWarner Losh n_quad fa_fileid; 86ca987d46SWarner Losh struct nfsv3_time fa_atime; 87ca987d46SWarner Losh struct nfsv3_time fa_mtime; 88ca987d46SWarner Losh struct nfsv3_time fa_ctime; 89ca987d46SWarner Losh }; 90ca987d46SWarner Losh 91ca987d46SWarner Losh /* 92ca987d46SWarner Losh * For NFSv3, the file handle is variable in size, so most fixed sized 93ca987d46SWarner Losh * structures for arguments won't work. For most cases, a structure 94ca987d46SWarner Losh * that starts with any fixed size section is followed by an array 95ca987d46SWarner Losh * that covers the maximum size required. 96ca987d46SWarner Losh */ 97ca987d46SWarner Losh struct nfsv3_readdir_repl { 98ca987d46SWarner Losh uint32_t errno; 99ca987d46SWarner Losh uint32_t ok; 100ca987d46SWarner Losh struct nfsv3_fattrs fa; 101ca987d46SWarner Losh uint32_t cookiev0; 102ca987d46SWarner Losh uint32_t cookiev1; 103ca987d46SWarner Losh }; 104ca987d46SWarner Losh 105ca987d46SWarner Losh struct nfsv3_readdir_entry { 106ca987d46SWarner Losh uint32_t follows; 107ca987d46SWarner Losh uint32_t fid0; 108ca987d46SWarner Losh uint32_t fid1; 109ca987d46SWarner Losh uint32_t len; 110ca987d46SWarner Losh uint32_t nameplus[0]; 111ca987d46SWarner Losh }; 112ca987d46SWarner Losh 113ca987d46SWarner Losh struct nfs_iodesc { 114ca987d46SWarner Losh struct iodesc *iodesc; 115ca987d46SWarner Losh off_t off; 116ca987d46SWarner Losh uint32_t fhsize; 117ca987d46SWarner Losh u_char fh[NFS_V3MAXFHSIZE]; 118ca987d46SWarner Losh struct nfsv3_fattrs fa; /* all in network order */ 119ca987d46SWarner Losh uint64_t cookie; 120ca987d46SWarner Losh }; 121ca987d46SWarner Losh 122ca987d46SWarner Losh /* 123ca987d46SWarner Losh * XXX interactions with tftp? See nfswrapper.c for a confusing 124ca987d46SWarner Losh * issue. 125ca987d46SWarner Losh */ 126ca987d46SWarner Losh int nfs_open(const char *path, struct open_file *f); 127ca987d46SWarner Losh static int nfs_close(struct open_file *f); 128ca987d46SWarner Losh static int nfs_read(struct open_file *f, void *buf, size_t size, size_t *resid); 129ca987d46SWarner Losh static off_t nfs_seek(struct open_file *f, off_t offset, int where); 130ca987d46SWarner Losh static int nfs_stat(struct open_file *f, struct stat *sb); 131ca987d46SWarner Losh static int nfs_readdir(struct open_file *f, struct dirent *d); 132ca987d46SWarner Losh 133ca987d46SWarner Losh struct nfs_iodesc nfs_root_node; 134ca987d46SWarner Losh 135ca987d46SWarner Losh struct fs_ops nfs_fsops = { 136ca987d46SWarner Losh "nfs", 137ca987d46SWarner Losh nfs_open, 138ca987d46SWarner Losh nfs_close, 139ca987d46SWarner Losh nfs_read, 1402e7e6fbcSConrad Meyer null_write, 141ca987d46SWarner Losh nfs_seek, 142ca987d46SWarner Losh nfs_stat, 143ca987d46SWarner Losh nfs_readdir 144ca987d46SWarner Losh }; 145ca987d46SWarner Losh 146ca987d46SWarner Losh static int nfs_read_size = NFSREAD_MIN_SIZE; 147ca987d46SWarner Losh 148ca987d46SWarner Losh /* 149ca987d46SWarner Losh * Improve boot performance over NFS 150ca987d46SWarner Losh */ 151ca987d46SWarner Losh static void 152ca987d46SWarner Losh set_nfs_read_size(void) 153ca987d46SWarner Losh { 154ca987d46SWarner Losh char *env, *end; 155ca987d46SWarner Losh char buf[10]; 156ca987d46SWarner Losh 157ca987d46SWarner Losh if ((env = getenv("nfs.read_size")) != NULL) { 158ca987d46SWarner Losh errno = 0; 159ca987d46SWarner Losh nfs_read_size = (int)strtol(env, &end, 0); 160ca987d46SWarner Losh if (errno != 0 || *env == '\0' || *end != '\0') { 161ca987d46SWarner Losh printf("%s: bad value: \"%s\", defaulting to %d\n", 162ca987d46SWarner Losh "nfs.read_size", env, NFSREAD_MIN_SIZE); 163ca987d46SWarner Losh nfs_read_size = NFSREAD_MIN_SIZE; 164ca987d46SWarner Losh } 165ca987d46SWarner Losh } 166ca987d46SWarner Losh if (nfs_read_size < NFSREAD_MIN_SIZE) { 167ca987d46SWarner Losh printf("%s: bad value: \"%d\", defaulting to %d\n", 168ca987d46SWarner Losh "nfs.read_size", nfs_read_size, NFSREAD_MIN_SIZE); 169ca987d46SWarner Losh nfs_read_size = NFSREAD_MIN_SIZE; 170ca987d46SWarner Losh } 171ca987d46SWarner Losh if (nfs_read_size > NFSREAD_MAX_SIZE) { 172ca987d46SWarner Losh printf("%s: bad value: \"%d\", defaulting to %d\n", 173ca987d46SWarner Losh "nfs.read_size", nfs_read_size, NFSREAD_MIN_SIZE); 174ca987d46SWarner Losh nfs_read_size = NFSREAD_MAX_SIZE; 175ca987d46SWarner Losh } 176ca987d46SWarner Losh snprintf(buf, sizeof (buf), "%d", nfs_read_size); 177ca987d46SWarner Losh setenv("nfs.read_size", buf, 1); 178ca987d46SWarner Losh } 179ca987d46SWarner Losh 180ca987d46SWarner Losh /* 181ca987d46SWarner Losh * Fetch the root file handle (call mount daemon) 182ca987d46SWarner Losh * Return zero or error number. 183ca987d46SWarner Losh */ 184ca987d46SWarner Losh int 185ca987d46SWarner Losh nfs_getrootfh(struct iodesc *d, char *path, uint32_t *fhlenp, u_char *fhp) 186ca987d46SWarner Losh { 187ca987d46SWarner Losh void *pkt = NULL; 188ca987d46SWarner Losh int len; 189ca987d46SWarner Losh struct args { 190ca987d46SWarner Losh uint32_t len; 191ca987d46SWarner Losh char path[FNAME_SIZE]; 192ca987d46SWarner Losh } *args; 193ca987d46SWarner Losh struct repl { 194ca987d46SWarner Losh uint32_t errno; 195ca987d46SWarner Losh uint32_t fhsize; 196ca987d46SWarner Losh u_char fh[NFS_V3MAXFHSIZE]; 197ca987d46SWarner Losh uint32_t authcnt; 198ca987d46SWarner Losh uint32_t auth[7]; 199ca987d46SWarner Losh } *repl; 200ca987d46SWarner Losh struct { 201ca987d46SWarner Losh uint32_t h[RPC_HEADER_WORDS]; 202ca987d46SWarner Losh struct args d; 203ca987d46SWarner Losh } sdata; 204ca987d46SWarner Losh size_t cc; 205ca987d46SWarner Losh 206ca987d46SWarner Losh #ifdef NFS_DEBUG 207ca987d46SWarner Losh if (debug) 208ca987d46SWarner Losh printf("nfs_getrootfh: %s\n", path); 209ca987d46SWarner Losh #endif 210ca987d46SWarner Losh 211ca987d46SWarner Losh args = &sdata.d; 212ca987d46SWarner Losh 213ca987d46SWarner Losh bzero(args, sizeof(*args)); 214ca987d46SWarner Losh len = strlen(path); 215ca987d46SWarner Losh if (len > sizeof(args->path)) 216ca987d46SWarner Losh len = sizeof(args->path); 217ca987d46SWarner Losh args->len = htonl(len); 218ca987d46SWarner Losh bcopy(path, args->path, len); 219ca987d46SWarner Losh len = sizeof(uint32_t) + roundup(len, sizeof(uint32_t)); 220ca987d46SWarner Losh 221ca987d46SWarner Losh cc = rpc_call(d, RPCPROG_MNT, RPCMNT_VER3, RPCMNT_MOUNT, 222ca987d46SWarner Losh args, len, (void **)&repl, &pkt); 223ca987d46SWarner Losh if (cc == -1) { 224ca987d46SWarner Losh free(pkt); 225ca987d46SWarner Losh /* errno was set by rpc_call */ 226ca987d46SWarner Losh return (errno); 227ca987d46SWarner Losh } 228ca987d46SWarner Losh if (cc < 2 * sizeof (uint32_t)) { 229ca987d46SWarner Losh free(pkt); 230ca987d46SWarner Losh return (EBADRPC); 231ca987d46SWarner Losh } 232ca987d46SWarner Losh if (repl->errno != 0) { 233ca987d46SWarner Losh free(pkt); 234ca987d46SWarner Losh return (ntohl(repl->errno)); 235ca987d46SWarner Losh } 236ca987d46SWarner Losh *fhlenp = ntohl(repl->fhsize); 237ca987d46SWarner Losh bcopy(repl->fh, fhp, *fhlenp); 238ca987d46SWarner Losh 239ca987d46SWarner Losh set_nfs_read_size(); 240ca987d46SWarner Losh free(pkt); 241ca987d46SWarner Losh return (0); 242ca987d46SWarner Losh } 243ca987d46SWarner Losh 244ca987d46SWarner Losh /* 245ca987d46SWarner Losh * Lookup a file. Store handle and attributes. 246ca987d46SWarner Losh * Return zero or error number. 247ca987d46SWarner Losh */ 248ca987d46SWarner Losh int 249ca987d46SWarner Losh nfs_lookupfh(struct nfs_iodesc *d, const char *name, struct nfs_iodesc *newfd) 250ca987d46SWarner Losh { 251ca987d46SWarner Losh void *pkt = NULL; 252*46c0e42bSWarner Losh int len, pos; 253ca987d46SWarner Losh struct args { 254ca987d46SWarner Losh uint32_t fhsize; 255ca987d46SWarner Losh uint32_t fhplusname[1 + 256ca987d46SWarner Losh (NFS_V3MAXFHSIZE + FNAME_SIZE) / sizeof(uint32_t)]; 257ca987d46SWarner Losh } *args; 258ca987d46SWarner Losh struct repl { 259ca987d46SWarner Losh uint32_t errno; 260ca987d46SWarner Losh uint32_t fhsize; 261ca987d46SWarner Losh uint32_t fhplusattr[(NFS_V3MAXFHSIZE + 262ca987d46SWarner Losh 2 * (sizeof(uint32_t) + 263ca987d46SWarner Losh sizeof(struct nfsv3_fattrs))) / sizeof(uint32_t)]; 264ca987d46SWarner Losh } *repl; 265ca987d46SWarner Losh struct { 266ca987d46SWarner Losh uint32_t h[RPC_HEADER_WORDS]; 267ca987d46SWarner Losh struct args d; 268ca987d46SWarner Losh } sdata; 269ca987d46SWarner Losh ssize_t cc; 270ca987d46SWarner Losh 271ca987d46SWarner Losh #ifdef NFS_DEBUG 272ca987d46SWarner Losh if (debug) 273ca987d46SWarner Losh printf("lookupfh: called\n"); 274ca987d46SWarner Losh #endif 275ca987d46SWarner Losh 276ca987d46SWarner Losh args = &sdata.d; 277ca987d46SWarner Losh 278ca987d46SWarner Losh bzero(args, sizeof(*args)); 279ca987d46SWarner Losh args->fhsize = htonl(d->fhsize); 280ca987d46SWarner Losh bcopy(d->fh, args->fhplusname, d->fhsize); 281ca987d46SWarner Losh len = strlen(name); 282ca987d46SWarner Losh if (len > FNAME_SIZE) 283ca987d46SWarner Losh len = FNAME_SIZE; 284ca987d46SWarner Losh pos = roundup(d->fhsize, sizeof(uint32_t)) / sizeof(uint32_t); 285ca987d46SWarner Losh args->fhplusname[pos++] = htonl(len); 286ca987d46SWarner Losh bcopy(name, &args->fhplusname[pos], len); 287ca987d46SWarner Losh len = sizeof(uint32_t) + pos * sizeof(uint32_t) + 288ca987d46SWarner Losh roundup(len, sizeof(uint32_t)); 289ca987d46SWarner Losh 290ca987d46SWarner Losh cc = rpc_call(d->iodesc, NFS_PROG, NFS_VER3, NFSPROCV3_LOOKUP, 291ca987d46SWarner Losh args, len, (void **)&repl, &pkt); 292ca987d46SWarner Losh if (cc == -1) { 293ca987d46SWarner Losh free(pkt); 294ca987d46SWarner Losh return (errno); /* XXX - from rpc_call */ 295ca987d46SWarner Losh } 296ca987d46SWarner Losh if (cc < 2 * sizeof(uint32_t)) { 297ca987d46SWarner Losh free(pkt); 298ca987d46SWarner Losh return (EIO); 299ca987d46SWarner Losh } 300ca987d46SWarner Losh if (repl->errno != 0) { 301ca987d46SWarner Losh free(pkt); 302ca987d46SWarner Losh /* saerrno.h now matches NFS error numbers. */ 303ca987d46SWarner Losh return (ntohl(repl->errno)); 304ca987d46SWarner Losh } 305ca987d46SWarner Losh newfd->fhsize = ntohl(repl->fhsize); 306ca987d46SWarner Losh bcopy(repl->fhplusattr, &newfd->fh, newfd->fhsize); 307ca987d46SWarner Losh pos = roundup(newfd->fhsize, sizeof(uint32_t)) / sizeof(uint32_t); 308ca987d46SWarner Losh if (repl->fhplusattr[pos++] == 0) { 309ca987d46SWarner Losh free(pkt); 310ca987d46SWarner Losh return (EIO); 311ca987d46SWarner Losh } 312ca987d46SWarner Losh bcopy(&repl->fhplusattr[pos], &newfd->fa, sizeof(newfd->fa)); 313ca987d46SWarner Losh free(pkt); 314ca987d46SWarner Losh return (0); 315ca987d46SWarner Losh } 316ca987d46SWarner Losh 317ca987d46SWarner Losh #ifndef NFS_NOSYMLINK 318ca987d46SWarner Losh /* 319ca987d46SWarner Losh * Get the destination of a symbolic link. 320ca987d46SWarner Losh */ 321ca987d46SWarner Losh int 322ca987d46SWarner Losh nfs_readlink(struct nfs_iodesc *d, char *buf) 323ca987d46SWarner Losh { 324ca987d46SWarner Losh void *pkt = NULL; 325ca987d46SWarner Losh struct args { 326ca987d46SWarner Losh uint32_t fhsize; 327ca987d46SWarner Losh u_char fh[NFS_V3MAXFHSIZE]; 328ca987d46SWarner Losh } *args; 329ca987d46SWarner Losh struct repl { 330ca987d46SWarner Losh uint32_t errno; 331ca987d46SWarner Losh uint32_t ok; 332ca987d46SWarner Losh struct nfsv3_fattrs fa; 333ca987d46SWarner Losh uint32_t len; 334ca987d46SWarner Losh u_char path[NFS_MAXPATHLEN]; 335ca987d46SWarner Losh } *repl; 336ca987d46SWarner Losh struct { 337ca987d46SWarner Losh uint32_t h[RPC_HEADER_WORDS]; 338ca987d46SWarner Losh struct args d; 339ca987d46SWarner Losh } sdata; 340ca987d46SWarner Losh ssize_t cc; 341ca987d46SWarner Losh int rc = 0; 342ca987d46SWarner Losh 343ca987d46SWarner Losh #ifdef NFS_DEBUG 344ca987d46SWarner Losh if (debug) 345ca987d46SWarner Losh printf("readlink: called\n"); 346ca987d46SWarner Losh #endif 347ca987d46SWarner Losh 348ca987d46SWarner Losh args = &sdata.d; 349ca987d46SWarner Losh 350ca987d46SWarner Losh bzero(args, sizeof(*args)); 351ca987d46SWarner Losh args->fhsize = htonl(d->fhsize); 352ca987d46SWarner Losh bcopy(d->fh, args->fh, d->fhsize); 353ca987d46SWarner Losh cc = rpc_call(d->iodesc, NFS_PROG, NFS_VER3, NFSPROCV3_READLINK, 354ca987d46SWarner Losh args, sizeof(uint32_t) + roundup(d->fhsize, sizeof(uint32_t)), 355ca987d46SWarner Losh (void **)&repl, &pkt); 356ca987d46SWarner Losh if (cc == -1) 357ca987d46SWarner Losh return (errno); 358ca987d46SWarner Losh 359ca987d46SWarner Losh if (cc < 2 * sizeof(uint32_t)) { 360ca987d46SWarner Losh rc = EIO; 361ca987d46SWarner Losh goto done; 362ca987d46SWarner Losh } 363ca987d46SWarner Losh 364ca987d46SWarner Losh if (repl->errno != 0) { 365ca987d46SWarner Losh rc = ntohl(repl->errno); 366ca987d46SWarner Losh goto done; 367ca987d46SWarner Losh } 368ca987d46SWarner Losh 369ca987d46SWarner Losh if (repl->ok == 0) { 370ca987d46SWarner Losh rc = EIO; 371ca987d46SWarner Losh goto done; 372ca987d46SWarner Losh } 373ca987d46SWarner Losh 374ca987d46SWarner Losh repl->len = ntohl(repl->len); 375ca987d46SWarner Losh if (repl->len > NFS_MAXPATHLEN) { 376ca987d46SWarner Losh rc = ENAMETOOLONG; 377ca987d46SWarner Losh goto done; 378ca987d46SWarner Losh } 379ca987d46SWarner Losh 380ca987d46SWarner Losh bcopy(repl->path, buf, repl->len); 381ca987d46SWarner Losh buf[repl->len] = 0; 382ca987d46SWarner Losh done: 383ca987d46SWarner Losh free(pkt); 384ca987d46SWarner Losh return (rc); 385ca987d46SWarner Losh } 386ca987d46SWarner Losh #endif 387ca987d46SWarner Losh 388ca987d46SWarner Losh /* 389ca987d46SWarner Losh * Read data from a file. 390ca987d46SWarner Losh * Return transfer count or -1 (and set errno) 391ca987d46SWarner Losh */ 392ca987d46SWarner Losh ssize_t 393ca987d46SWarner Losh nfs_readdata(struct nfs_iodesc *d, off_t off, void *addr, size_t len) 394ca987d46SWarner Losh { 395ca987d46SWarner Losh void *pkt = NULL; 396ca987d46SWarner Losh struct args { 397ca987d46SWarner Losh uint32_t fhsize; 398ca987d46SWarner Losh uint32_t fhoffcnt[NFS_V3MAXFHSIZE / sizeof(uint32_t) + 3]; 399ca987d46SWarner Losh } *args; 400ca987d46SWarner Losh struct repl { 401ca987d46SWarner Losh uint32_t errno; 402ca987d46SWarner Losh uint32_t ok; 403ca987d46SWarner Losh struct nfsv3_fattrs fa; 404ca987d46SWarner Losh uint32_t count; 405ca987d46SWarner Losh uint32_t eof; 406ca987d46SWarner Losh uint32_t len; 407ca987d46SWarner Losh u_char data[NFSREAD_MAX_SIZE]; 408ca987d46SWarner Losh } *repl; 409ca987d46SWarner Losh struct { 410ca987d46SWarner Losh uint32_t h[RPC_HEADER_WORDS]; 411ca987d46SWarner Losh struct args d; 412ca987d46SWarner Losh } sdata; 413ca987d46SWarner Losh size_t cc; 414ca987d46SWarner Losh long x; 415ca987d46SWarner Losh int hlen, rlen, pos; 416ca987d46SWarner Losh 417ca987d46SWarner Losh args = &sdata.d; 418ca987d46SWarner Losh 419ca987d46SWarner Losh bzero(args, sizeof(*args)); 420ca987d46SWarner Losh args->fhsize = htonl(d->fhsize); 421ca987d46SWarner Losh bcopy(d->fh, args->fhoffcnt, d->fhsize); 422ca987d46SWarner Losh pos = roundup(d->fhsize, sizeof(uint32_t)) / sizeof(uint32_t); 423ca987d46SWarner Losh args->fhoffcnt[pos++] = 0; 424ca987d46SWarner Losh args->fhoffcnt[pos++] = htonl((uint32_t)off); 425ca987d46SWarner Losh if (len > nfs_read_size) 426ca987d46SWarner Losh len = nfs_read_size; 427ca987d46SWarner Losh args->fhoffcnt[pos] = htonl((uint32_t)len); 428ca987d46SWarner Losh hlen = offsetof(struct repl, data[0]); 429ca987d46SWarner Losh 430ca987d46SWarner Losh cc = rpc_call(d->iodesc, NFS_PROG, NFS_VER3, NFSPROCV3_READ, 431ca987d46SWarner Losh args, 4 * sizeof(uint32_t) + roundup(d->fhsize, sizeof(uint32_t)), 432ca987d46SWarner Losh (void **)&repl, &pkt); 433ca987d46SWarner Losh if (cc == -1) { 434ca987d46SWarner Losh /* errno was already set by rpc_call */ 435ca987d46SWarner Losh return (-1); 436ca987d46SWarner Losh } 437ca987d46SWarner Losh if (cc < hlen) { 438ca987d46SWarner Losh errno = EBADRPC; 439ca987d46SWarner Losh free(pkt); 440ca987d46SWarner Losh return (-1); 441ca987d46SWarner Losh } 442ca987d46SWarner Losh if (repl->errno != 0) { 443ca987d46SWarner Losh errno = ntohl(repl->errno); 444ca987d46SWarner Losh free(pkt); 445ca987d46SWarner Losh return (-1); 446ca987d46SWarner Losh } 447ca987d46SWarner Losh rlen = cc - hlen; 448ca987d46SWarner Losh x = ntohl(repl->count); 449ca987d46SWarner Losh if (rlen < x) { 450ca987d46SWarner Losh printf("nfsread: short packet, %d < %ld\n", rlen, x); 451ca987d46SWarner Losh errno = EBADRPC; 452ca987d46SWarner Losh free(pkt); 453ca987d46SWarner Losh return (-1); 454ca987d46SWarner Losh } 455ca987d46SWarner Losh bcopy(repl->data, addr, x); 456ca987d46SWarner Losh free(pkt); 457ca987d46SWarner Losh return (x); 458ca987d46SWarner Losh } 459ca987d46SWarner Losh 460ca987d46SWarner Losh /* 461ca987d46SWarner Losh * Open a file. 462ca987d46SWarner Losh * return zero or error number 463ca987d46SWarner Losh */ 464ca987d46SWarner Losh int 465ca987d46SWarner Losh nfs_open(const char *upath, struct open_file *f) 466ca987d46SWarner Losh { 467ca987d46SWarner Losh struct iodesc *desc; 468*46c0e42bSWarner Losh struct nfs_iodesc *currfd = NULL; 469ca987d46SWarner Losh char buf[2 * NFS_V3MAXFHSIZE + 3]; 470ca987d46SWarner Losh u_char *fh; 471ca987d46SWarner Losh char *cp; 472ca987d46SWarner Losh int i; 473ca987d46SWarner Losh #ifndef NFS_NOSYMLINK 474*46c0e42bSWarner Losh struct nfs_iodesc *newfd = NULL; 475ca987d46SWarner Losh char *ncp; 476ca987d46SWarner Losh int c; 477ca987d46SWarner Losh char namebuf[NFS_MAXPATHLEN + 1]; 478ca987d46SWarner Losh char linkbuf[NFS_MAXPATHLEN + 1]; 479ca987d46SWarner Losh int nlinks = 0; 480ca987d46SWarner Losh #endif 481ca987d46SWarner Losh int error; 482*46c0e42bSWarner Losh char *path = NULL; 483ca987d46SWarner Losh 484ca987d46SWarner Losh if (netproto != NET_NFS) 485ca987d46SWarner Losh return (EINVAL); 486ca987d46SWarner Losh 487ca987d46SWarner Losh #ifdef NFS_DEBUG 488ca987d46SWarner Losh if (debug) 489ca987d46SWarner Losh printf("nfs_open: %s (rootpath=%s)\n", upath, rootpath); 490ca987d46SWarner Losh #endif 491ca987d46SWarner Losh if (!rootpath[0]) { 492ca987d46SWarner Losh printf("no rootpath, no nfs\n"); 493ca987d46SWarner Losh return (ENXIO); 494ca987d46SWarner Losh } 495ca987d46SWarner Losh 496ca987d46SWarner Losh if (f->f_dev->dv_type != DEVT_NET) 497ca987d46SWarner Losh return (EINVAL); 498ca987d46SWarner Losh 499ca987d46SWarner Losh if (!(desc = socktodesc(*(int *)(f->f_devdata)))) 500ca987d46SWarner Losh return (EINVAL); 501ca987d46SWarner Losh 502ca987d46SWarner Losh /* Bind to a reserved port. */ 503ca987d46SWarner Losh desc->myport = htons(--rpc_port); 504ca987d46SWarner Losh desc->destip = rootip; 505ca987d46SWarner Losh if ((error = nfs_getrootfh(desc, rootpath, &nfs_root_node.fhsize, 506ca987d46SWarner Losh nfs_root_node.fh))) 507ca987d46SWarner Losh return (error); 508ca987d46SWarner Losh nfs_root_node.fa.fa_type = htonl(NFDIR); 509ca987d46SWarner Losh nfs_root_node.fa.fa_mode = htonl(0755); 510ca987d46SWarner Losh nfs_root_node.fa.fa_nlink = htonl(2); 511ca987d46SWarner Losh nfs_root_node.iodesc = desc; 512ca987d46SWarner Losh 513ca987d46SWarner Losh fh = &nfs_root_node.fh[0]; 514ca987d46SWarner Losh buf[0] = 'X'; 515ca987d46SWarner Losh cp = &buf[1]; 516ca987d46SWarner Losh for (i = 0; i < nfs_root_node.fhsize; i++, cp += 2) 517ca987d46SWarner Losh sprintf(cp, "%02x", fh[i]); 518ca987d46SWarner Losh sprintf(cp, "X"); 519ca987d46SWarner Losh setenv("boot.nfsroot.server", inet_ntoa(rootip), 1); 520ca987d46SWarner Losh setenv("boot.nfsroot.path", rootpath, 1); 521ca987d46SWarner Losh setenv("boot.nfsroot.nfshandle", buf, 1); 522ca987d46SWarner Losh sprintf(buf, "%d", nfs_root_node.fhsize); 523ca987d46SWarner Losh setenv("boot.nfsroot.nfshandlelen", buf, 1); 524ca987d46SWarner Losh 525ca987d46SWarner Losh /* Allocate file system specific data structure */ 526ca987d46SWarner Losh currfd = malloc(sizeof(*newfd)); 527ca987d46SWarner Losh if (currfd == NULL) { 528ca987d46SWarner Losh error = ENOMEM; 529ca987d46SWarner Losh goto out; 530ca987d46SWarner Losh } 531ca987d46SWarner Losh #ifndef NFS_NOSYMLINK 532ca987d46SWarner Losh bcopy(&nfs_root_node, currfd, sizeof(*currfd)); 533ca987d46SWarner Losh newfd = NULL; 534ca987d46SWarner Losh 535ca987d46SWarner Losh cp = path = strdup(upath); 536ca987d46SWarner Losh if (path == NULL) { 537ca987d46SWarner Losh error = ENOMEM; 538ca987d46SWarner Losh goto out; 539ca987d46SWarner Losh } 540ca987d46SWarner Losh while (*cp) { 541ca987d46SWarner Losh /* 542ca987d46SWarner Losh * Remove extra separators 543ca987d46SWarner Losh */ 544ca987d46SWarner Losh while (*cp == '/') 545ca987d46SWarner Losh cp++; 546ca987d46SWarner Losh 547ca987d46SWarner Losh if (*cp == '\0') 548ca987d46SWarner Losh break; 549ca987d46SWarner Losh /* 550ca987d46SWarner Losh * Check that current node is a directory. 551ca987d46SWarner Losh */ 552ca987d46SWarner Losh if (currfd->fa.fa_type != htonl(NFDIR)) { 553ca987d46SWarner Losh error = ENOTDIR; 554ca987d46SWarner Losh goto out; 555ca987d46SWarner Losh } 556ca987d46SWarner Losh 557ca987d46SWarner Losh /* allocate file system specific data structure */ 558ca987d46SWarner Losh newfd = malloc(sizeof(*newfd)); 559ca987d46SWarner Losh if (newfd == NULL) { 560ca987d46SWarner Losh error = ENOMEM; 561ca987d46SWarner Losh goto out; 562ca987d46SWarner Losh } 563ca987d46SWarner Losh newfd->iodesc = currfd->iodesc; 564ca987d46SWarner Losh 565ca987d46SWarner Losh /* 566ca987d46SWarner Losh * Get next component of path name. 567ca987d46SWarner Losh */ 568ca987d46SWarner Losh { 569ca987d46SWarner Losh int len = 0; 570ca987d46SWarner Losh 571ca987d46SWarner Losh ncp = cp; 572ca987d46SWarner Losh while ((c = *cp) != '\0' && c != '/') { 573ca987d46SWarner Losh if (++len > NFS_MAXNAMLEN) { 574ca987d46SWarner Losh error = ENOENT; 575ca987d46SWarner Losh goto out; 576ca987d46SWarner Losh } 577ca987d46SWarner Losh cp++; 578ca987d46SWarner Losh } 579ca987d46SWarner Losh *cp = '\0'; 580ca987d46SWarner Losh } 581ca987d46SWarner Losh 582ca987d46SWarner Losh /* lookup a file handle */ 583ca987d46SWarner Losh error = nfs_lookupfh(currfd, ncp, newfd); 584ca987d46SWarner Losh *cp = c; 585ca987d46SWarner Losh if (error) 586ca987d46SWarner Losh goto out; 587ca987d46SWarner Losh 588ca987d46SWarner Losh /* 589ca987d46SWarner Losh * Check for symbolic link 590ca987d46SWarner Losh */ 591ca987d46SWarner Losh if (newfd->fa.fa_type == htonl(NFLNK)) { 592ca987d46SWarner Losh int link_len, len; 593ca987d46SWarner Losh 594ca987d46SWarner Losh error = nfs_readlink(newfd, linkbuf); 595ca987d46SWarner Losh if (error) 596ca987d46SWarner Losh goto out; 597ca987d46SWarner Losh 598ca987d46SWarner Losh link_len = strlen(linkbuf); 599ca987d46SWarner Losh len = strlen(cp); 600ca987d46SWarner Losh 601ca987d46SWarner Losh if (link_len + len > MAXPATHLEN 602ca987d46SWarner Losh || ++nlinks > MAXSYMLINKS) { 603ca987d46SWarner Losh error = ENOENT; 604ca987d46SWarner Losh goto out; 605ca987d46SWarner Losh } 606ca987d46SWarner Losh 607ca987d46SWarner Losh bcopy(cp, &namebuf[link_len], len + 1); 608ca987d46SWarner Losh bcopy(linkbuf, namebuf, link_len); 609ca987d46SWarner Losh 610ca987d46SWarner Losh /* 611ca987d46SWarner Losh * If absolute pathname, restart at root. 612ca987d46SWarner Losh * If relative pathname, restart at parent directory. 613ca987d46SWarner Losh */ 614ca987d46SWarner Losh cp = namebuf; 615ca987d46SWarner Losh if (*cp == '/') 616ca987d46SWarner Losh bcopy(&nfs_root_node, currfd, sizeof(*currfd)); 617ca987d46SWarner Losh 618ca987d46SWarner Losh free(newfd); 619ca987d46SWarner Losh newfd = NULL; 620ca987d46SWarner Losh 621ca987d46SWarner Losh continue; 622ca987d46SWarner Losh } 623ca987d46SWarner Losh 624ca987d46SWarner Losh free(currfd); 625ca987d46SWarner Losh currfd = newfd; 626ca987d46SWarner Losh newfd = NULL; 627ca987d46SWarner Losh } 628ca987d46SWarner Losh 629ca987d46SWarner Losh error = 0; 630ca987d46SWarner Losh 631ca987d46SWarner Losh out: 632ca987d46SWarner Losh free(newfd); 633ca987d46SWarner Losh free(path); 634ca987d46SWarner Losh #else 635ca987d46SWarner Losh currfd->iodesc = desc; 636ca987d46SWarner Losh 637ca987d46SWarner Losh error = nfs_lookupfh(&nfs_root_node, upath, currfd); 638ca987d46SWarner Losh #endif 639ca987d46SWarner Losh if (!error) { 640ca987d46SWarner Losh currfd->off = 0; 641ca987d46SWarner Losh currfd->cookie = 0; 642ca987d46SWarner Losh f->f_fsdata = (void *)currfd; 643ca987d46SWarner Losh return (0); 644ca987d46SWarner Losh } 645ca987d46SWarner Losh 646ca987d46SWarner Losh #ifdef NFS_DEBUG 647ca987d46SWarner Losh if (debug) 648ca987d46SWarner Losh printf("nfs_open: %s lookupfh failed: %s\n", 649ca987d46SWarner Losh path, strerror(error)); 650ca987d46SWarner Losh #endif 651ca987d46SWarner Losh free(currfd); 652ca987d46SWarner Losh 653ca987d46SWarner Losh return (error); 654ca987d46SWarner Losh } 655ca987d46SWarner Losh 656ca987d46SWarner Losh int 657ca987d46SWarner Losh nfs_close(struct open_file *f) 658ca987d46SWarner Losh { 659ca987d46SWarner Losh struct nfs_iodesc *fp = (struct nfs_iodesc *)f->f_fsdata; 660ca987d46SWarner Losh 661ca987d46SWarner Losh #ifdef NFS_DEBUG 662ca987d46SWarner Losh if (debug) 663ca987d46SWarner Losh printf("nfs_close: fp=0x%lx\n", (u_long)fp); 664ca987d46SWarner Losh #endif 665ca987d46SWarner Losh 666ca987d46SWarner Losh free(fp); 667ca987d46SWarner Losh f->f_fsdata = NULL; 668ca987d46SWarner Losh 669ca987d46SWarner Losh return (0); 670ca987d46SWarner Losh } 671ca987d46SWarner Losh 672ca987d46SWarner Losh /* 673ca987d46SWarner Losh * read a portion of a file 674ca987d46SWarner Losh */ 675ca987d46SWarner Losh int 676ca987d46SWarner Losh nfs_read(struct open_file *f, void *buf, size_t size, size_t *resid) 677ca987d46SWarner Losh { 678ca987d46SWarner Losh struct nfs_iodesc *fp = (struct nfs_iodesc *)f->f_fsdata; 679ca987d46SWarner Losh ssize_t cc; 680ca987d46SWarner Losh char *addr = buf; 681ca987d46SWarner Losh 682ca987d46SWarner Losh #ifdef NFS_DEBUG 683ca987d46SWarner Losh if (debug) 684ca987d46SWarner Losh printf("nfs_read: size=%lu off=%d\n", (u_long)size, 685ca987d46SWarner Losh (int)fp->off); 686ca987d46SWarner Losh #endif 687ca987d46SWarner Losh while ((int)size > 0) { 688ca987d46SWarner Losh twiddle(16); 689ca987d46SWarner Losh cc = nfs_readdata(fp, fp->off, (void *)addr, size); 690ca987d46SWarner Losh /* XXX maybe should retry on certain errors */ 691ca987d46SWarner Losh if (cc == -1) { 692ca987d46SWarner Losh #ifdef NFS_DEBUG 693ca987d46SWarner Losh if (debug) 694ca987d46SWarner Losh printf("nfs_read: read: %s", strerror(errno)); 695ca987d46SWarner Losh #endif 696ca987d46SWarner Losh return (errno); /* XXX - from nfs_readdata */ 697ca987d46SWarner Losh } 698ca987d46SWarner Losh if (cc == 0) { 699ca987d46SWarner Losh #ifdef NFS_DEBUG 700ca987d46SWarner Losh if (debug) 701ca987d46SWarner Losh printf("nfs_read: hit EOF unexpectantly"); 702ca987d46SWarner Losh #endif 703ca987d46SWarner Losh goto ret; 704ca987d46SWarner Losh } 705ca987d46SWarner Losh fp->off += cc; 706ca987d46SWarner Losh addr += cc; 707ca987d46SWarner Losh size -= cc; 708ca987d46SWarner Losh } 709ca987d46SWarner Losh ret: 710ca987d46SWarner Losh if (resid) 711ca987d46SWarner Losh *resid = size; 712ca987d46SWarner Losh 713ca987d46SWarner Losh return (0); 714ca987d46SWarner Losh } 715ca987d46SWarner Losh 716ca987d46SWarner Losh off_t 717ca987d46SWarner Losh nfs_seek(struct open_file *f, off_t offset, int where) 718ca987d46SWarner Losh { 719ca987d46SWarner Losh struct nfs_iodesc *d = (struct nfs_iodesc *)f->f_fsdata; 720ca987d46SWarner Losh uint32_t size = ntohl(d->fa.fa_size.val[1]); 721ca987d46SWarner Losh 722ca987d46SWarner Losh switch (where) { 723ca987d46SWarner Losh case SEEK_SET: 724ca987d46SWarner Losh d->off = offset; 725ca987d46SWarner Losh break; 726ca987d46SWarner Losh case SEEK_CUR: 727ca987d46SWarner Losh d->off += offset; 728ca987d46SWarner Losh break; 729ca987d46SWarner Losh case SEEK_END: 730ca987d46SWarner Losh d->off = size - offset; 731ca987d46SWarner Losh break; 732ca987d46SWarner Losh default: 733ca987d46SWarner Losh errno = EINVAL; 734ca987d46SWarner Losh return (-1); 735ca987d46SWarner Losh } 736ca987d46SWarner Losh 737ca987d46SWarner Losh return (d->off); 738ca987d46SWarner Losh } 739ca987d46SWarner Losh 740ca987d46SWarner Losh /* NFNON=0, NFREG=1, NFDIR=2, NFBLK=3, NFCHR=4, NFLNK=5, NFSOCK=6, NFFIFO=7 */ 741ca987d46SWarner Losh int nfs_stat_types[9] = { 742ca987d46SWarner Losh 0, S_IFREG, S_IFDIR, S_IFBLK, S_IFCHR, S_IFLNK, S_IFSOCK, S_IFIFO, 0 }; 743ca987d46SWarner Losh 744ca987d46SWarner Losh int 745ca987d46SWarner Losh nfs_stat(struct open_file *f, struct stat *sb) 746ca987d46SWarner Losh { 747ca987d46SWarner Losh struct nfs_iodesc *fp = (struct nfs_iodesc *)f->f_fsdata; 748ca987d46SWarner Losh uint32_t ftype, mode; 749ca987d46SWarner Losh 750ca987d46SWarner Losh ftype = ntohl(fp->fa.fa_type); 751ca987d46SWarner Losh mode = ntohl(fp->fa.fa_mode); 752ca987d46SWarner Losh mode |= nfs_stat_types[ftype & 7]; 753ca987d46SWarner Losh 754ca987d46SWarner Losh sb->st_mode = mode; 755ca987d46SWarner Losh sb->st_nlink = ntohl(fp->fa.fa_nlink); 756ca987d46SWarner Losh sb->st_uid = ntohl(fp->fa.fa_uid); 757ca987d46SWarner Losh sb->st_gid = ntohl(fp->fa.fa_gid); 758ca987d46SWarner Losh sb->st_size = ntohl(fp->fa.fa_size.val[1]); 759ca987d46SWarner Losh 760ca987d46SWarner Losh return (0); 761ca987d46SWarner Losh } 762ca987d46SWarner Losh 763ca987d46SWarner Losh static int 764ca987d46SWarner Losh nfs_readdir(struct open_file *f, struct dirent *d) 765ca987d46SWarner Losh { 766ca987d46SWarner Losh struct nfs_iodesc *fp = (struct nfs_iodesc *)f->f_fsdata; 767ca987d46SWarner Losh struct nfsv3_readdir_repl *repl; 768ca987d46SWarner Losh struct nfsv3_readdir_entry *rent; 769ca987d46SWarner Losh static void *pkt = NULL; 770ca987d46SWarner Losh static char *buf; 771ca987d46SWarner Losh static struct nfs_iodesc *pfp = NULL; 772ca987d46SWarner Losh static uint64_t cookie = 0; 773ca987d46SWarner Losh size_t cc; 774ca987d46SWarner Losh int pos, rc; 775ca987d46SWarner Losh 776ca987d46SWarner Losh struct args { 777ca987d46SWarner Losh uint32_t fhsize; 778ca987d46SWarner Losh uint32_t fhpluscookie[5 + NFS_V3MAXFHSIZE]; 779ca987d46SWarner Losh } *args; 780ca987d46SWarner Losh struct { 781ca987d46SWarner Losh uint32_t h[RPC_HEADER_WORDS]; 782ca987d46SWarner Losh struct args d; 783ca987d46SWarner Losh } sdata; 784ca987d46SWarner Losh 785ca987d46SWarner Losh if (fp != pfp || fp->off != cookie) { 786ca987d46SWarner Losh pfp = NULL; 787ca987d46SWarner Losh refill: 788ca987d46SWarner Losh free(pkt); 789ca987d46SWarner Losh pkt = NULL; 790ca987d46SWarner Losh args = &sdata.d; 791ca987d46SWarner Losh bzero(args, sizeof(*args)); 792ca987d46SWarner Losh 793ca987d46SWarner Losh args->fhsize = htonl(fp->fhsize); 794ca987d46SWarner Losh bcopy(fp->fh, args->fhpluscookie, fp->fhsize); 795ca987d46SWarner Losh pos = roundup(fp->fhsize, sizeof(uint32_t)) / sizeof(uint32_t); 796ca987d46SWarner Losh args->fhpluscookie[pos++] = htonl(fp->off >> 32); 797ca987d46SWarner Losh args->fhpluscookie[pos++] = htonl(fp->off); 798ca987d46SWarner Losh args->fhpluscookie[pos++] = htonl(fp->cookie >> 32); 799ca987d46SWarner Losh args->fhpluscookie[pos++] = htonl(fp->cookie); 800ca987d46SWarner Losh args->fhpluscookie[pos] = htonl(NFS_READDIRSIZE); 801ca987d46SWarner Losh 802ca987d46SWarner Losh cc = rpc_call(fp->iodesc, NFS_PROG, NFS_VER3, NFSPROCV3_READDIR, 803ca987d46SWarner Losh args, 6 * sizeof(uint32_t) + 804ca987d46SWarner Losh roundup(fp->fhsize, sizeof(uint32_t)), 805ca987d46SWarner Losh (void **)&buf, &pkt); 806ca987d46SWarner Losh if (cc == -1) { 807ca987d46SWarner Losh rc = errno; 808ca987d46SWarner Losh goto err; 809ca987d46SWarner Losh } 810ca987d46SWarner Losh repl = (struct nfsv3_readdir_repl *)buf; 811ca987d46SWarner Losh if (repl->errno != 0) { 812ca987d46SWarner Losh rc = ntohl(repl->errno); 813ca987d46SWarner Losh goto err; 814ca987d46SWarner Losh } 815ca987d46SWarner Losh pfp = fp; 816ca987d46SWarner Losh cookie = fp->off; 817ca987d46SWarner Losh fp->cookie = ((uint64_t)ntohl(repl->cookiev0) << 32) | 818ca987d46SWarner Losh ntohl(repl->cookiev1); 819ca987d46SWarner Losh buf += sizeof (struct nfsv3_readdir_repl); 820ca987d46SWarner Losh } 821ca987d46SWarner Losh rent = (struct nfsv3_readdir_entry *)buf; 822ca987d46SWarner Losh 823ca987d46SWarner Losh if (rent->follows == 0) { 824ca987d46SWarner Losh /* fid0 is actually eof */ 825ca987d46SWarner Losh if (rent->fid0 != 0) { 826ca987d46SWarner Losh rc = ENOENT; 827ca987d46SWarner Losh goto err; 828ca987d46SWarner Losh } 829ca987d46SWarner Losh goto refill; 830ca987d46SWarner Losh } 831ca987d46SWarner Losh 832ca987d46SWarner Losh d->d_namlen = ntohl(rent->len); 833ca987d46SWarner Losh bcopy(rent->nameplus, d->d_name, d->d_namlen); 834ca987d46SWarner Losh d->d_name[d->d_namlen] = '\0'; 835ca987d46SWarner Losh 836ca987d46SWarner Losh pos = roundup(d->d_namlen, sizeof(uint32_t)) / sizeof(uint32_t); 837ca987d46SWarner Losh fp->off = cookie = ((uint64_t)ntohl(rent->nameplus[pos]) << 32) | 838ca987d46SWarner Losh ntohl(rent->nameplus[pos + 1]); 839ca987d46SWarner Losh pos += 2; 840ca987d46SWarner Losh buf = (u_char *)&rent->nameplus[pos]; 841ca987d46SWarner Losh return (0); 842ca987d46SWarner Losh 843ca987d46SWarner Losh err: 844ca987d46SWarner Losh free(pkt); 845ca987d46SWarner Losh pkt = NULL; 846ca987d46SWarner Losh pfp = NULL; 847ca987d46SWarner Losh cookie = 0; 848ca987d46SWarner Losh return (rc); 849ca987d46SWarner Losh } 850