1*7c478bd9Sstevel@tonic-gate /* 2*7c478bd9Sstevel@tonic-gate * CDDL HEADER START 3*7c478bd9Sstevel@tonic-gate * 4*7c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the 5*7c478bd9Sstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only 6*7c478bd9Sstevel@tonic-gate * (the "License"). You may not use this file except in compliance 7*7c478bd9Sstevel@tonic-gate * with the License. 8*7c478bd9Sstevel@tonic-gate * 9*7c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10*7c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 11*7c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions 12*7c478bd9Sstevel@tonic-gate * and limitations under the License. 13*7c478bd9Sstevel@tonic-gate * 14*7c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 15*7c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16*7c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 17*7c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 18*7c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 19*7c478bd9Sstevel@tonic-gate * 20*7c478bd9Sstevel@tonic-gate * CDDL HEADER END 21*7c478bd9Sstevel@tonic-gate */ 22*7c478bd9Sstevel@tonic-gate /* 23*7c478bd9Sstevel@tonic-gate * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 24*7c478bd9Sstevel@tonic-gate * Use is subject to license terms. 25*7c478bd9Sstevel@tonic-gate * 26*7c478bd9Sstevel@tonic-gate * Stuff relating to NFSv4 directory reading ... 27*7c478bd9Sstevel@tonic-gate */ 28*7c478bd9Sstevel@tonic-gate 29*7c478bd9Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 30*7c478bd9Sstevel@tonic-gate 31*7c478bd9Sstevel@tonic-gate #include <rpc/types.h> 32*7c478bd9Sstevel@tonic-gate #include <rpc/auth.h> 33*7c478bd9Sstevel@tonic-gate #include <rpc/xdr.h> 34*7c478bd9Sstevel@tonic-gate #include "clnt.h" 35*7c478bd9Sstevel@tonic-gate #include <rpc/rpc_msg.h> 36*7c478bd9Sstevel@tonic-gate #include <sys/t_lock.h> 37*7c478bd9Sstevel@tonic-gate #include "nfs_inet.h" 38*7c478bd9Sstevel@tonic-gate #include <rpc/rpc.h> 39*7c478bd9Sstevel@tonic-gate #include "brpc.h" 40*7c478bd9Sstevel@tonic-gate #include <rpcsvc/nfs_prot.h> 41*7c478bd9Sstevel@tonic-gate #include <sys/types.h> 42*7c478bd9Sstevel@tonic-gate #include <sys/stat.h> 43*7c478bd9Sstevel@tonic-gate #include <sys/bootvfs.h> 44*7c478bd9Sstevel@tonic-gate #include <sys/sysmacros.h> 45*7c478bd9Sstevel@tonic-gate #include "socket_inet.h" 46*7c478bd9Sstevel@tonic-gate #include <sys/salib.h> 47*7c478bd9Sstevel@tonic-gate #include <sys/bootdebug.h> 48*7c478bd9Sstevel@tonic-gate 49*7c478bd9Sstevel@tonic-gate #define MAXDENTS 16 50*7c478bd9Sstevel@tonic-gate #define MINSIZ 20 51*7c478bd9Sstevel@tonic-gate 52*7c478bd9Sstevel@tonic-gate /* 53*7c478bd9Sstevel@tonic-gate * Boot needs to be cleaned up to use either dirent32 or dirent64, 54*7c478bd9Sstevel@tonic-gate * in the meantime use dirent_t and always round to 8 bytes 55*7c478bd9Sstevel@tonic-gate */ 56*7c478bd9Sstevel@tonic-gate #define BDIRENT_RECLEN(namelen) \ 57*7c478bd9Sstevel@tonic-gate ((offsetof(dirent_t, d_name[0]) + 1 + (namelen) + 7) & ~ 7) 58*7c478bd9Sstevel@tonic-gate 59*7c478bd9Sstevel@tonic-gate #define dprintf if (boothowto & RB_DEBUG) printf 60*7c478bd9Sstevel@tonic-gate 61*7c478bd9Sstevel@tonic-gate /* 62*7c478bd9Sstevel@tonic-gate * Get directory entries: 63*7c478bd9Sstevel@tonic-gate * 64*7c478bd9Sstevel@tonic-gate * Uses the nfs "READDIR" operation to read directory entries 65*7c478bd9Sstevel@tonic-gate * into a local buffer. These are then translated into file 66*7c478bd9Sstevel@tonic-gate * system independent "dirent" structs and returned in the 67*7c478bd9Sstevel@tonic-gate * caller's buffer. Returns the number of entries converted 68*7c478bd9Sstevel@tonic-gate * (-1 if there's an error). 69*7c478bd9Sstevel@tonic-gate * 70*7c478bd9Sstevel@tonic-gate * Although the xdr functions can allocate memory, we have 71*7c478bd9Sstevel@tonic-gate * a limited heap so we allocate our own space, 72*7c478bd9Sstevel@tonic-gate * assuming the worst case of 256 byte names. 73*7c478bd9Sstevel@tonic-gate * This is a space hog in our local buffer, so we want 74*7c478bd9Sstevel@tonic-gate * the number of buffers to be small. To make sure we don't 75*7c478bd9Sstevel@tonic-gate * get more names than we can handle, we tell the rpc 76*7c478bd9Sstevel@tonic-gate * routine that we only have space for MAXDENT names if 77*7c478bd9Sstevel@tonic-gate * they are all the minimum size. This keeps the return 78*7c478bd9Sstevel@tonic-gate * packet unfragmented, but may result in lots of reads 79*7c478bd9Sstevel@tonic-gate * to process a large directory. Since this is standalone 80*7c478bd9Sstevel@tonic-gate * we don't worry about speed. With MAXDENTs at 16, the 81*7c478bd9Sstevel@tonic-gate * local buffer is 4k. 82*7c478bd9Sstevel@tonic-gate */ 83*7c478bd9Sstevel@tonic-gate 84*7c478bd9Sstevel@tonic-gate int 85*7c478bd9Sstevel@tonic-gate nfs4getdents(struct nfs_file *nfp, struct dirent *dep, unsigned size) 86*7c478bd9Sstevel@tonic-gate { 87*7c478bd9Sstevel@tonic-gate int cnt = 0; 88*7c478bd9Sstevel@tonic-gate b_entry4_t *ep; 89*7c478bd9Sstevel@tonic-gate readdir4arg_t readdir_args; 90*7c478bd9Sstevel@tonic-gate readdir4res_t readdir_res; 91*7c478bd9Sstevel@tonic-gate attr4_bitmap1_t bitmap1; 92*7c478bd9Sstevel@tonic-gate enum clnt_stat status; 93*7c478bd9Sstevel@tonic-gate struct { 94*7c478bd9Sstevel@tonic-gate b_entry4_t etlist[MAXDENTS]; 95*7c478bd9Sstevel@tonic-gate char names[MAXDENTS][NFS_MAXNAMLEN+1]; 96*7c478bd9Sstevel@tonic-gate } rdbuf; 97*7c478bd9Sstevel@tonic-gate int j; 98*7c478bd9Sstevel@tonic-gate struct timeval zero_timeout = {0, 0}; /* default */ 99*7c478bd9Sstevel@tonic-gate utf8string str; 100*7c478bd9Sstevel@tonic-gate char tagname[] = "inetboot readdir"; 101*7c478bd9Sstevel@tonic-gate 102*7c478bd9Sstevel@tonic-gate bzero((caddr_t)&readdir_res, sizeof (readdir4res_t)); 103*7c478bd9Sstevel@tonic-gate bzero((caddr_t)&readdir_args, sizeof (readdir4arg_t)); 104*7c478bd9Sstevel@tonic-gate bzero((caddr_t)rdbuf.etlist, sizeof (rdbuf.etlist)); 105*7c478bd9Sstevel@tonic-gate 106*7c478bd9Sstevel@tonic-gate str.utf8string_len = sizeof (tagname) - 1; 107*7c478bd9Sstevel@tonic-gate str.utf8string_val = tagname; 108*7c478bd9Sstevel@tonic-gate 109*7c478bd9Sstevel@tonic-gate if (nfp->fh.fh4.len > 0) 110*7c478bd9Sstevel@tonic-gate compound_init(&readdir_args.rd_arg, &str, 0, 2, &nfp->fh.fh4); 111*7c478bd9Sstevel@tonic-gate else 112*7c478bd9Sstevel@tonic-gate compound_init(&readdir_args.rd_arg, &str, 0, 2, NULL); 113*7c478bd9Sstevel@tonic-gate 114*7c478bd9Sstevel@tonic-gate readdir_args.rd_opreaddir = OP_READDIR; 115*7c478bd9Sstevel@tonic-gate readdir_args.rd_cookie = nfp->cookie.cookie4; 116*7c478bd9Sstevel@tonic-gate 117*7c478bd9Sstevel@tonic-gate while (!readdir_res.rd_eof) { 118*7c478bd9Sstevel@tonic-gate /* 119*7c478bd9Sstevel@tonic-gate * Keep issuing nfs calls until EOF is reached on 120*7c478bd9Sstevel@tonic-gate * the directory or the user buffer is filled. 121*7c478bd9Sstevel@tonic-gate */ 122*7c478bd9Sstevel@tonic-gate for (j = 0; j < MAXDENTS; j++) { 123*7c478bd9Sstevel@tonic-gate /* 124*7c478bd9Sstevel@tonic-gate * Link our buffers together for the benefit of 125*7c478bd9Sstevel@tonic-gate * XDR. We do this each time we issue the rpc call 126*7c478bd9Sstevel@tonic-gate * JIC the xdr decode 127*7c478bd9Sstevel@tonic-gate * routines screw up the linkage! 128*7c478bd9Sstevel@tonic-gate */ 129*7c478bd9Sstevel@tonic-gate rdbuf.etlist[j].b_name.utf8string_len = NFS_MAXNAMLEN; 130*7c478bd9Sstevel@tonic-gate rdbuf.etlist[j].b_name.utf8string_val = 131*7c478bd9Sstevel@tonic-gate rdbuf.names[(MAXDENTS-1) - j]; 132*7c478bd9Sstevel@tonic-gate rdbuf.etlist[j].b_nextentry = 133*7c478bd9Sstevel@tonic-gate (j < (MAXDENTS-1)) ? &rdbuf.etlist[j+1] : 0; 134*7c478bd9Sstevel@tonic-gate } 135*7c478bd9Sstevel@tonic-gate 136*7c478bd9Sstevel@tonic-gate readdir_res.rd_entries = rdbuf.etlist; 137*7c478bd9Sstevel@tonic-gate /* 138*7c478bd9Sstevel@tonic-gate * Cannot give the whole buffer unless every name is 139*7c478bd9Sstevel@tonic-gate * 256 bytes! Assume the worst case of all 1 byte names. 140*7c478bd9Sstevel@tonic-gate * This results in MINSIZ bytes/name in the xdr stream. 141*7c478bd9Sstevel@tonic-gate */ 142*7c478bd9Sstevel@tonic-gate readdir_args.rd_dircount = MAXDENTS * MINSIZ; 143*7c478bd9Sstevel@tonic-gate readdir_args.rd_maxcount = sizeof (readdir4res_t) + 144*7c478bd9Sstevel@tonic-gate (MAXDENTS * MINSIZ); 145*7c478bd9Sstevel@tonic-gate bzero((caddr_t)rdbuf.names, sizeof (rdbuf.names)); 146*7c478bd9Sstevel@tonic-gate 147*7c478bd9Sstevel@tonic-gate /* 148*7c478bd9Sstevel@tonic-gate * Set the attr bitmap, so we get the fileid back. 149*7c478bd9Sstevel@tonic-gate */ 150*7c478bd9Sstevel@tonic-gate bitmap1.word = 0; 151*7c478bd9Sstevel@tonic-gate bitmap1.bm_fattr4_fileid = 1; 152*7c478bd9Sstevel@tonic-gate readdir_args.rd_attr_req.b_bitmap_len = 1; 153*7c478bd9Sstevel@tonic-gate readdir_args.rd_attr_req.b_bitmap_val[0] = bitmap1.word; 154*7c478bd9Sstevel@tonic-gate 155*7c478bd9Sstevel@tonic-gate status = CLNT_CALL(root_CLIENT, NFSPROC4_COMPOUND, 156*7c478bd9Sstevel@tonic-gate xdr_readdir4_args, (caddr_t)&readdir_args, 157*7c478bd9Sstevel@tonic-gate xdr_readdir4_res, (caddr_t)&readdir_res, zero_timeout); 158*7c478bd9Sstevel@tonic-gate 159*7c478bd9Sstevel@tonic-gate if (status != RPC_SUCCESS) { 160*7c478bd9Sstevel@tonic-gate dprintf("nfs4_getdents: RPC error\n"); 161*7c478bd9Sstevel@tonic-gate return (-1); 162*7c478bd9Sstevel@tonic-gate } 163*7c478bd9Sstevel@tonic-gate if (readdir_res.rd_status != NFS4_OK) { 164*7c478bd9Sstevel@tonic-gate /* 165*7c478bd9Sstevel@tonic-gate * The most common failure here would be trying to 166*7c478bd9Sstevel@tonic-gate * issue a getdents call on a non-directory! 167*7c478bd9Sstevel@tonic-gate */ 168*7c478bd9Sstevel@tonic-gate 169*7c478bd9Sstevel@tonic-gate nfs4_error(readdir_res.rd_status); 170*7c478bd9Sstevel@tonic-gate return (-1); 171*7c478bd9Sstevel@tonic-gate } 172*7c478bd9Sstevel@tonic-gate 173*7c478bd9Sstevel@tonic-gate /* 174*7c478bd9Sstevel@tonic-gate * If we are reading from the beginning of the 175*7c478bd9Sstevel@tonic-gate * directory we will need to create the "." and ".." 176*7c478bd9Sstevel@tonic-gate * since we won't be getting them from the server. To obtain 177*7c478bd9Sstevel@tonic-gate * the fileid's just issue a couple otw lookups to get the 178*7c478bd9Sstevel@tonic-gate * info we need. 179*7c478bd9Sstevel@tonic-gate */ 180*7c478bd9Sstevel@tonic-gate if (readdir_args.rd_cookie == 0 && 181*7c478bd9Sstevel@tonic-gate rdbuf.etlist[0].b_cookie > 2) { 182*7c478bd9Sstevel@tonic-gate int n; 183*7c478bd9Sstevel@tonic-gate int error; 184*7c478bd9Sstevel@tonic-gate uint64_t fileid; 185*7c478bd9Sstevel@tonic-gate struct vattr va; 186*7c478bd9Sstevel@tonic-gate 187*7c478bd9Sstevel@tonic-gate /* 188*7c478bd9Sstevel@tonic-gate * Do a getattr for the '.' 189*7c478bd9Sstevel@tonic-gate */ 190*7c478bd9Sstevel@tonic-gate error = nfs4getattr(nfp, &va); 191*7c478bd9Sstevel@tonic-gate if (error) 192*7c478bd9Sstevel@tonic-gate return (-1); 193*7c478bd9Sstevel@tonic-gate 194*7c478bd9Sstevel@tonic-gate dep->d_name[0] = '.'; 195*7c478bd9Sstevel@tonic-gate dep->d_name[1] = '\0'; 196*7c478bd9Sstevel@tonic-gate dep->d_ino = va.va_nodeid; 197*7c478bd9Sstevel@tonic-gate dep->d_off = 1; 198*7c478bd9Sstevel@tonic-gate n = BDIRENT_RECLEN(1); 199*7c478bd9Sstevel@tonic-gate dep->d_reclen = n; 200*7c478bd9Sstevel@tonic-gate dep = (struct dirent *)((char *)dep + n); 201*7c478bd9Sstevel@tonic-gate 202*7c478bd9Sstevel@tonic-gate /* 203*7c478bd9Sstevel@tonic-gate * Do a lookupp for the '..' 204*7c478bd9Sstevel@tonic-gate */ 205*7c478bd9Sstevel@tonic-gate (void) nfs4lookupp(nfp, &error, &fileid); 206*7c478bd9Sstevel@tonic-gate if (error) 207*7c478bd9Sstevel@tonic-gate return (-1); 208*7c478bd9Sstevel@tonic-gate 209*7c478bd9Sstevel@tonic-gate dep->d_name[0] = '.'; 210*7c478bd9Sstevel@tonic-gate dep->d_name[1] = '.'; 211*7c478bd9Sstevel@tonic-gate dep->d_name[2] = '\0'; 212*7c478bd9Sstevel@tonic-gate dep->d_ino = fileid; 213*7c478bd9Sstevel@tonic-gate dep->d_off = 2; 214*7c478bd9Sstevel@tonic-gate n = BDIRENT_RECLEN(2); 215*7c478bd9Sstevel@tonic-gate dep->d_reclen = n; 216*7c478bd9Sstevel@tonic-gate dep = (struct dirent *)((char *)dep + n); 217*7c478bd9Sstevel@tonic-gate } 218*7c478bd9Sstevel@tonic-gate 219*7c478bd9Sstevel@tonic-gate for (ep = rdbuf.etlist; ep; ep = ep->b_nextentry) { 220*7c478bd9Sstevel@tonic-gate /* 221*7c478bd9Sstevel@tonic-gate * Step thru all entries returned by NFS, converting 222*7c478bd9Sstevel@tonic-gate * to the cannonical form and copying out to the 223*7c478bd9Sstevel@tonic-gate * user's buffer. 224*7c478bd9Sstevel@tonic-gate */ 225*7c478bd9Sstevel@tonic-gate int n; 226*7c478bd9Sstevel@tonic-gate int namlen; 227*7c478bd9Sstevel@tonic-gate 228*7c478bd9Sstevel@tonic-gate /* 229*7c478bd9Sstevel@tonic-gate * catch the case user called at EOF 230*7c478bd9Sstevel@tonic-gate */ 231*7c478bd9Sstevel@tonic-gate if ((namlen = ep->b_name.utf8string_len) == 0) 232*7c478bd9Sstevel@tonic-gate return (cnt); 233*7c478bd9Sstevel@tonic-gate 234*7c478bd9Sstevel@tonic-gate n = BDIRENT_RECLEN(namlen); 235*7c478bd9Sstevel@tonic-gate 236*7c478bd9Sstevel@tonic-gate if (n > size) 237*7c478bd9Sstevel@tonic-gate return (cnt); 238*7c478bd9Sstevel@tonic-gate size -= n; 239*7c478bd9Sstevel@tonic-gate 240*7c478bd9Sstevel@tonic-gate bcopy(ep->b_name.utf8string_val, dep->d_name, namlen); 241*7c478bd9Sstevel@tonic-gate dep->d_name[namlen] = '\0'; 242*7c478bd9Sstevel@tonic-gate dep->d_ino = ep->b_fileid; 243*7c478bd9Sstevel@tonic-gate dep->d_off = (off_t)ep->b_cookie; 244*7c478bd9Sstevel@tonic-gate dep->d_reclen = (ushort_t)n; 245*7c478bd9Sstevel@tonic-gate 246*7c478bd9Sstevel@tonic-gate dep = (struct dirent *)((char *)dep + n); 247*7c478bd9Sstevel@tonic-gate readdir_args.rd_cookie = ep->b_cookie; 248*7c478bd9Sstevel@tonic-gate nfp->cookie.cookie4 = ep->b_cookie; 249*7c478bd9Sstevel@tonic-gate cnt++; 250*7c478bd9Sstevel@tonic-gate } 251*7c478bd9Sstevel@tonic-gate } 252*7c478bd9Sstevel@tonic-gate 253*7c478bd9Sstevel@tonic-gate return (cnt); 254*7c478bd9Sstevel@tonic-gate } 255