1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 /* 22 * Copyright 2007 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 #pragma ident "%Z%%M% %I% %E% SMI" 27 28 #include <sys/param.h> 29 #include <sys/types.h> 30 #include <sys/systm.h> 31 #include <sys/cred.h> 32 #include <sys/buf.h> 33 #include <sys/vfs.h> 34 #include <sys/vnode.h> 35 #include <sys/uio.h> 36 #include <sys/errno.h> 37 #include <sys/sysmacros.h> 38 #include <sys/statvfs.h> 39 #include <sys/kmem.h> 40 #include <sys/dirent.h> 41 #include <rpc/types.h> 42 #include <rpc/auth.h> 43 #include <rpc/rpcsec_gss.h> 44 #include <rpc/svc.h> 45 #include <sys/strsubr.h> 46 #include <sys/strsun.h> 47 #include <sys/sdt.h> 48 49 #include <nfs/nfs.h> 50 #include <nfs/export.h> 51 #include <nfs/nfs4.h> 52 53 54 /* 55 * RFS4_MINLEN_ENTRY4: XDR-encoded size of smallest possible dirent. 56 * This is used to return NFS4ERR_TOOSMALL when clients specify 57 * maxcount that isn't large enough to hold the smallest possible 58 * XDR encoded dirent. 59 * 60 * sizeof cookie (8 bytes) + 61 * sizeof name_len (4 bytes) + 62 * sizeof smallest (padded) name (4 bytes) + 63 * sizeof bitmap4_len (12 bytes) + NOTE: we always encode len=2 bm4 64 * sizeof attrlist4_len (4 bytes) + 65 * sizeof next boolean (4 bytes) 66 * 67 * RFS4_MINLEN_RDDIR4: XDR-encoded size of READDIR op reply containing 68 * the smallest possible entry4 (assumes no attrs requested). 69 * sizeof nfsstat4 (4 bytes) + 70 * sizeof verifier4 (8 bytes) + 71 * sizeof entsecond_to_ry4list bool (4 bytes) + 72 * sizeof entry4 (36 bytes) + 73 * sizeof eof bool (4 bytes) 74 * 75 * RFS4_MINLEN_RDDIR_BUF: minimum length of buffer server will provide to 76 * VOP_READDIR. Its value is the size of the maximum possible dirent 77 * for solaris. The DIRENT64_RECLEN macro returns the size of dirent 78 * required for a given name length. MAXNAMELEN is the maximum 79 * filename length allowed in Solaris. The first two DIRENT64_RECLEN() 80 * macros are to allow for . and .. entries -- just a minor tweak to try 81 * and guarantee that buffer we give to VOP_READDIR will be large enough 82 * to hold ., .., and the largest possible solaris dirent64. 83 */ 84 #define RFS4_MINLEN_ENTRY4 36 85 #define RFS4_MINLEN_RDDIR4 (4 + NFS4_VERIFIER_SIZE + 4 + RFS4_MINLEN_ENTRY4 + 4) 86 #define RFS4_MINLEN_RDDIR_BUF \ 87 (DIRENT64_RECLEN(1) + DIRENT64_RECLEN(2) + DIRENT64_RECLEN(MAXNAMELEN)) 88 89 90 #ifdef nextdp 91 #undef nextdp 92 #endif 93 #define nextdp(dp) ((struct dirent64 *)((char *)(dp) + (dp)->d_reclen)) 94 95 verifier4 Readdir4verf = 0x0; 96 97 static nfs_ftype4 vt_to_nf4[] = { 98 0, NF4REG, NF4DIR, NF4BLK, NF4CHR, NF4LNK, NF4FIFO, 0, 0, NF4SOCK, 0 99 }; 100 101 102 int 103 nfs4_readdir_getvp(vnode_t *dvp, char *d_name, vnode_t **vpp, 104 struct exportinfo **exi, struct svc_req *req, 105 struct compound_state *cs, int expseudo) 106 { 107 int error; 108 int ismntpt; 109 fid_t fid; 110 vnode_t *vp, *pre_tvp; 111 nfsstat4 status; 112 struct exportinfo *newexi, *saveexi; 113 cred_t *scr; 114 115 *vpp = vp = NULL; 116 117 if (error = VOP_LOOKUP(dvp, d_name, &vp, NULL, 0, NULL, cs->cr, 118 NULL, NULL, NULL)) 119 return (error); 120 121 /* Is this object mounted upon? */ 122 ismntpt = vn_ismntpt(vp); 123 /* 124 * Nothing more to do if object is not a mount point or 125 * a possible LOFS shadow of an LOFS mount (which won't 126 * have v_vfsmountedhere set) 127 */ 128 if (ismntpt == 0 && dvp->v_vfsp == vp->v_vfsp && expseudo == 0) { 129 *vpp = vp; 130 return (0); 131 } 132 133 if (ismntpt) { 134 /* 135 * Something is mounted here. Traverse and manage the 136 * namespace 137 */ 138 pre_tvp = vp; 139 VN_HOLD(pre_tvp); 140 141 if ((error = traverse(&vp)) != 0) { 142 VN_RELE(pre_tvp); 143 return (error); 144 } 145 } 146 147 bzero(&fid, sizeof (fid)); 148 fid.fid_len = MAXFIDSZ; 149 150 /* 151 * If VOP_FID not supported by underlying fs (mntfs, procfs, 152 * etc.), then return attrs for stub instead of VROOT object. 153 * If it fails for any other reason, then return the error. 154 */ 155 if (error = VOP_FID(vp, &fid, NULL)) { 156 if (ismntpt == 0) { 157 VN_RELE(vp); 158 return (error); 159 } 160 161 if (error != ENOSYS && error != ENOTSUP) { 162 VN_RELE(vp); 163 VN_RELE(pre_tvp); 164 return (error); 165 } 166 /* go back to vnode that is "under" mount */ 167 VN_RELE(vp); 168 *vpp = pre_tvp; 169 return (0); 170 } 171 172 newexi = checkexport4(&vp->v_vfsp->vfs_fsid, &fid, vp); 173 if (newexi == NULL) { 174 if (ismntpt == 0) { 175 *vpp = vp; 176 } else { 177 VN_RELE(vp); 178 *vpp = pre_tvp; 179 } 180 return (0); 181 } 182 183 if (ismntpt) 184 VN_RELE(pre_tvp); 185 186 /* Save the exi and present the new one to checkauth4() */ 187 saveexi = cs->exi; 188 cs->exi = newexi; 189 190 /* Get the right cred like lookup does */ 191 scr = cs->cr; 192 cs->cr = crdup(cs->basecr); 193 194 status = call_checkauth4(cs, req); 195 196 crfree(cs->cr); 197 cs->cr = scr; 198 cs->exi = saveexi; 199 200 /* Reset what call_checkauth4() may have set */ 201 *cs->statusp = NFS4_OK; 202 203 if (status != NFS4_OK) { 204 VN_RELE(vp); 205 if (status == NFS4ERR_DELAY) 206 status = NFS4ERR_ACCESS; 207 return (status); 208 } 209 *vpp = vp; 210 *exi = newexi; 211 212 return (0); 213 } 214 215 /* This is the set of pathconf data for vfs */ 216 typedef struct { 217 uint64_t maxfilesize; 218 uint32_t maxlink; 219 uint32_t maxname; 220 } rfs4_pc_encode_t; 221 222 223 static int 224 rfs4_get_pc_encode(vnode_t *vp, rfs4_pc_encode_t *pce, bitmap4 ar, cred_t *cr) 225 { 226 int error; 227 ulong_t pc_val; 228 229 pce->maxfilesize = 0; 230 pce->maxlink = 0; 231 pce->maxname = 0; 232 233 if (ar & FATTR4_MAXFILESIZE_MASK) { 234 /* Maximum File Size */ 235 if (error = VOP_PATHCONF(vp, _PC_FILESIZEBITS, &pc_val, cr, 236 NULL)) 237 return (error); 238 239 if (pc_val >= (sizeof (uint64_t) * 8)) 240 pce->maxfilesize = UINT64_MAX; 241 else 242 pce->maxfilesize = ((1LL << pc_val) - 1); 243 } 244 245 if (ar & FATTR4_MAXLINK_MASK) { 246 /* Maximum Link Count */ 247 if (error = VOP_PATHCONF(vp, _PC_LINK_MAX, &pc_val, cr, NULL)) 248 return (error); 249 250 pce->maxlink = pc_val; 251 } 252 253 if (ar & FATTR4_MAXNAME_MASK) { 254 /* Maximum Name Length */ 255 if (error = VOP_PATHCONF(vp, _PC_NAME_MAX, &pc_val, cr, NULL)) 256 return (error); 257 258 pce->maxname = pc_val; 259 } 260 261 return (0); 262 } 263 264 /* This is the set of statvfs data that is ready for encoding */ 265 typedef struct { 266 uint64_t space_avail; 267 uint64_t space_free; 268 uint64_t space_total; 269 u_longlong_t fa; 270 u_longlong_t ff; 271 u_longlong_t ft; 272 } rfs4_sb_encode_t; 273 274 static int 275 rfs4_get_sb_encode(vfs_t *vfsp, rfs4_sb_encode_t *psbe) 276 { 277 int error; 278 struct statvfs64 sb; 279 280 /* Grab the per filesystem info */ 281 if (error = VFS_STATVFS(vfsp, &sb)) { 282 return (error); 283 } 284 285 /* Calculate space available */ 286 if (sb.f_bavail != (fsblkcnt64_t)-1) { 287 psbe->space_avail = 288 (fattr4_space_avail) sb.f_frsize * 289 (fattr4_space_avail) sb.f_bavail; 290 } else { 291 psbe->space_avail = 292 (fattr4_space_avail) sb.f_bavail; 293 } 294 295 /* Calculate space free */ 296 if (sb.f_bfree != (fsblkcnt64_t)-1) { 297 psbe->space_free = 298 (fattr4_space_free) sb.f_frsize * 299 (fattr4_space_free) sb.f_bfree; 300 } else { 301 psbe->space_free = 302 (fattr4_space_free) sb.f_bfree; 303 } 304 305 /* Calculate space total */ 306 if (sb.f_blocks != (fsblkcnt64_t)-1) { 307 psbe->space_total = 308 (fattr4_space_total) sb.f_frsize * 309 (fattr4_space_total) sb.f_blocks; 310 } else { 311 psbe->space_total = 312 (fattr4_space_total) sb.f_blocks; 313 } 314 315 /* For use later on attr encode */ 316 psbe->fa = sb.f_favail; 317 psbe->ff = sb.f_ffree; 318 psbe->ft = sb.f_files; 319 320 return (0); 321 } 322 323 /* 324 * Macros to handle if we have don't have enough space for the requested 325 * attributes and this is the first entry and the 326 * requested attributes are more than the minimal useful 327 * set, reset the attributes to the minimal set and 328 * retry the encoding. If the client has asked for both 329 * mounted_on_fileid and fileid, prefer mounted_on_fileid. 330 */ 331 #define MINIMAL_RD_ATTRS \ 332 (FATTR4_MOUNTED_ON_FILEID_MASK| \ 333 FATTR4_FILEID_MASK| \ 334 FATTR4_RDATTR_ERROR_MASK) 335 336 #define MINIMIZE_ATTR_MASK(m) { \ 337 if ((m) & FATTR4_MOUNTED_ON_FILEID_MASK) \ 338 (m) &= FATTR4_RDATTR_ERROR_MASK|FATTR4_MOUNTED_ON_FILEID_MASK;\ 339 else \ 340 (m) &= FATTR4_RDATTR_ERROR_MASK|FATTR4_FILEID_MASK; \ 341 } 342 343 #define IS_MIN_ATTR_MASK(m) (((m) & ~MINIMAL_RD_ATTRS) == 0) 344 /* 345 * If readdir only needs to return FILEID, we can take it from the 346 * dirent struct and save doing the lookup. 347 */ 348 /* ARGSUSED */ 349 void 350 rfs4_op_readdir(nfs_argop4 *argop, nfs_resop4 *resop, 351 struct svc_req *req, struct compound_state *cs) 352 { 353 READDIR4args *args = &argop->nfs_argop4_u.opreaddir; 354 READDIR4res *resp = &resop->nfs_resop4_u.opreaddir; 355 struct exportinfo *newexi = NULL; 356 int error; 357 mblk_t *mp; 358 uint_t mpcount; 359 int alloc_err = 0; 360 vnode_t *dvp = cs->vp; 361 vnode_t *vp; 362 vattr_t va; 363 struct dirent64 *dp; 364 rfs4_sb_encode_t dsbe, sbe; 365 int vfs_different; 366 int rddir_data_len, rddir_result_size; 367 caddr_t rddir_data; 368 offset_t rddir_next_offset; 369 int dircount; 370 int no_space; 371 int iseofdir; 372 uint_t eof; 373 struct iovec iov; 374 struct uio uio; 375 int tsize; 376 int check_visible; 377 int expseudo = 0; 378 379 uint32_t *ptr, *ptr_redzone; 380 uint32_t *beginning_ptr; 381 uint32_t *lastentry_ptr; 382 uint32_t *attrmask_ptr; 383 uint32_t *attr_offset_ptr; 384 uint32_t attr_length; 385 uint32_t rndup; 386 uint32_t namelen; 387 uint32_t rddirattr_error = 0; 388 int nents; 389 bitmap4 ar = args->attr_request & NFS4_SRV_RDDIR_SUPPORTED_ATTRS; 390 bitmap4 ae; 391 rfs4_pc_encode_t dpce, pce; 392 ulong_t pc_val; 393 uint64_t maxread; 394 uint64_t maxwrite; 395 uint_t true = TRUE; 396 uint_t false = FALSE; 397 uid_t lastuid; 398 gid_t lastgid; 399 int lu_set, lg_set; 400 utf8string owner, group; 401 int owner_error, group_error; 402 403 lu_set = lg_set = 0; 404 owner.utf8string_len = group.utf8string_len = 0; 405 owner.utf8string_val = group.utf8string_val = NULL; 406 407 resp->mblk = NULL; 408 409 /* Maximum read and write size */ 410 maxread = maxwrite = rfs4_tsize(req); 411 412 if (dvp == NULL) { 413 *cs->statusp = resp->status = NFS4ERR_NOFILEHANDLE; 414 return; 415 } 416 417 /* 418 * If there is an unshared filesystem mounted on this vnode, 419 * do not allow readdir in this directory. 420 */ 421 if (vn_ismntpt(dvp)) { 422 *cs->statusp = resp->status = NFS4ERR_ACCESS; 423 return; 424 } 425 426 if (dvp->v_type != VDIR) { 427 *cs->statusp = resp->status = NFS4ERR_NOTDIR; 428 return; 429 } 430 431 if (args->maxcount <= RFS4_MINLEN_RDDIR4) { 432 *cs->statusp = resp->status = NFS4ERR_TOOSMALL; 433 return; 434 } 435 436 /* 437 * If write-only attrs are requested, then fail the readdir op 438 */ 439 if (args->attr_request & 440 (FATTR4_TIME_MODIFY_SET_MASK | FATTR4_TIME_ACCESS_SET_MASK)) { 441 *cs->statusp = resp->status = NFS4ERR_INVAL; 442 return; 443 } 444 445 error = VOP_ACCESS(dvp, VREAD, 0, cs->cr, NULL); 446 if (error) { 447 *cs->statusp = resp->status = puterrno4(error); 448 return; 449 } 450 451 if (args->cookieverf != Readdir4verf) { 452 *cs->statusp = resp->status = NFS4ERR_NOT_SAME; 453 return; 454 } 455 456 /* Is there pseudo-fs work that is needed for this readdir? */ 457 check_visible = PSEUDO(cs->exi) || 458 ! is_exported_sec(cs->nfsflavor, cs->exi) || 459 cs->access & CS_ACCESS_LIMITED; 460 461 /* Check the requested attributes and only do the work if needed */ 462 463 if (ar & (FATTR4_MAXFILESIZE_MASK | 464 FATTR4_MAXLINK_MASK | 465 FATTR4_MAXNAME_MASK)) { 466 if (error = rfs4_get_pc_encode(cs->vp, &dpce, ar, cs->cr)) { 467 *cs->statusp = resp->status = puterrno4(error); 468 return; 469 } 470 pce = dpce; 471 } 472 473 /* If there is statvfs data requested, pick it up once */ 474 if (ar & 475 (FATTR4_FILES_AVAIL_MASK | 476 FATTR4_FILES_FREE_MASK | 477 FATTR4_FILES_TOTAL_MASK | 478 FATTR4_FILES_AVAIL_MASK | 479 FATTR4_FILES_FREE_MASK | 480 FATTR4_FILES_TOTAL_MASK)) { 481 if (error = rfs4_get_sb_encode(dvp->v_vfsp, &dsbe)) { 482 *cs->statusp = resp->status = puterrno4(error); 483 return; 484 } 485 sbe = dsbe; 486 } 487 488 /* 489 * Max transfer size of the server is the absolute limite. 490 * If the client has decided to max out with something really 491 * tiny, then return toosmall. Otherwise, move forward and 492 * see if a single entry can be encoded. 493 */ 494 tsize = rfs4_tsize(req); 495 if (args->maxcount > tsize) 496 args->maxcount = tsize; 497 else if (args->maxcount < RFS4_MINLEN_RDDIR_BUF) { 498 if (args->maxcount < RFS4_MINLEN_ENTRY4) { 499 *cs->statusp = resp->status = NFS4ERR_TOOSMALL; 500 return; 501 } 502 } 503 504 /* 505 * How large should the mblk be for outgoing encoding. 506 */ 507 if (args->maxcount < MAXBSIZE) 508 mpcount = MAXBSIZE; 509 else 510 mpcount = args->maxcount; 511 512 /* 513 * mp will contain the data to be sent out in the readdir reply. 514 * It will be freed after the reply has been sent. 515 * Let's roundup the data to a BYTES_PER_XDR_UNIX multiple, 516 * so that the call to xdrmblk_putmblk() never fails. 517 */ 518 mp = allocb(RNDUP(mpcount), BPRI_MED); 519 520 if (mp == NULL) { 521 /* 522 * The allocation of the client's requested size has 523 * failed. It may be that the size is too large for 524 * current system utilization; step down to a "common" 525 * size and wait for the allocation to occur. 526 */ 527 if (mpcount > MAXBSIZE) 528 args->maxcount = mpcount = MAXBSIZE; 529 mp = allocb_wait(RNDUP(mpcount), BPRI_MED, 530 STR_NOSIG, &alloc_err); 531 } 532 533 ASSERT(mp != NULL); 534 ASSERT(alloc_err == 0); 535 536 resp->mblk = mp; 537 538 ptr = beginning_ptr = (uint32_t *)mp->b_datap->db_base; 539 540 /* 541 * The "redzone" at the end of the encoding buffer is used 542 * to deal with xdr encoding length. Instead of checking 543 * each encoding of an attribute value before it is done, 544 * make the assumption that it will fit into the buffer and 545 * check occasionally. 546 * 547 * The largest block of attributes that are encoded without 548 * checking the redzone is 18 * BYTES_PER_XDR_UNIT (72 bytes) 549 * "round" to 128 as the redzone size. 550 */ 551 if (args->maxcount < (mpcount - 128)) 552 ptr_redzone = 553 (uint32_t *)(((char *)ptr) + RNDUP(args->maxcount)); 554 else 555 ptr_redzone = 556 (uint32_t *)((((char *)ptr) + RNDUP(mpcount)) - 128); 557 558 /* 559 * Set the dircount; this will be used as the size for the 560 * readdir of the underlying filesystem. First make sure 561 * that it is large enough to do a reasonable readdir (client 562 * may have short changed us - it is an advisory number); 563 * then make sure that it isn't too large. 564 * After all of that, if maxcount is "small" then just use 565 * that for the dircount number. 566 */ 567 dircount = (args->dircount < MAXBSIZE) ? MAXBSIZE : args->dircount; 568 dircount = (dircount > tsize) ? tsize : dircount; 569 if (dircount > args->maxcount) 570 dircount = args->maxcount; 571 if (args->maxcount <= MAXBSIZE) { 572 if (args->maxcount < RFS4_MINLEN_RDDIR_BUF) 573 dircount = RFS4_MINLEN_RDDIR_BUF; 574 else 575 dircount = args->maxcount; 576 } 577 578 /* number of entries fully encoded in outgoing buffer */ 579 nents = 0; 580 581 /* ENCODE READDIR4res.cookieverf */ 582 IXDR_PUT_HYPER(ptr, Readdir4verf); 583 584 rddir_data_len = dircount; 585 rddir_data = kmem_alloc(rddir_data_len, KM_NOSLEEP); 586 if (rddir_data == NULL) { 587 /* The allocation failed; downsize and wait for it this time */ 588 if (rddir_data_len > MAXBSIZE) 589 rddir_data_len = dircount = MAXBSIZE; 590 rddir_data = kmem_alloc(rddir_data_len, KM_SLEEP); 591 } 592 593 rddir_next_offset = (offset_t)args->cookie; 594 595 readagain: 596 597 no_space = FALSE; 598 iseofdir = FALSE; 599 600 vp = NULL; 601 602 /* Move on to reading the directory contents */ 603 iov.iov_base = rddir_data; 604 iov.iov_len = rddir_data_len; 605 uio.uio_iov = &iov; 606 uio.uio_iovcnt = 1; 607 uio.uio_segflg = UIO_SYSSPACE; 608 uio.uio_extflg = UIO_COPY_CACHED; 609 uio.uio_loffset = rddir_next_offset; 610 uio.uio_resid = rddir_data_len; 611 612 (void) VOP_RWLOCK(dvp, V_WRITELOCK_FALSE, NULL); 613 614 error = VOP_READDIR(dvp, &uio, cs->cr, &iseofdir, NULL, 0); 615 616 VOP_RWUNLOCK(dvp, V_WRITELOCK_FALSE, NULL); 617 618 if (error) { 619 kmem_free((caddr_t)rddir_data, rddir_data_len); 620 freeb(resp->mblk); 621 resp->mblk = NULL; 622 resp->data_len = 0; 623 *cs->statusp = resp->status = puterrno4(error); 624 return; 625 } 626 627 628 rddir_result_size = rddir_data_len - uio.uio_resid; 629 630 /* Reading at the end of the directory */ 631 if (iseofdir && (rddir_result_size == 0)) { 632 /* encode the BOOLEAN marking no further entries */ 633 IXDR_PUT_U_INT32(ptr, false); 634 /* encode the BOOLEAN signifying end of directory */ 635 IXDR_PUT_U_INT32(ptr, true); 636 resp->data_len = (char *)ptr - (char *)beginning_ptr; 637 resp->mblk->b_wptr += resp->data_len; 638 kmem_free((caddr_t)rddir_data, rddir_data_len); 639 *cs->statusp = resp->status = NFS4_OK; 640 return; 641 } 642 643 lastentry_ptr = ptr; 644 no_space = 0; 645 for (dp = (struct dirent64 *)rddir_data; 646 !no_space && rddir_result_size > 0; dp = nextdp(dp)) { 647 648 /* reset expseudo */ 649 expseudo = 0; 650 651 if (vp) { 652 VN_RELE(vp); 653 vp = NULL; 654 } 655 656 if (newexi) 657 newexi = NULL; 658 659 rddir_result_size -= dp->d_reclen; 660 661 /* skip "." and ".." entries */ 662 if (dp->d_ino == 0 || NFS_IS_DOTNAME(dp->d_name)) { 663 rddir_next_offset = dp->d_off; 664 continue; 665 } 666 667 if (check_visible && 668 !nfs_visible_inode(cs->exi, dp->d_ino, &expseudo)) { 669 rddir_next_offset = dp->d_off; 670 continue; 671 } 672 673 /* 674 * Only if the client requested attributes... 675 * If the VOP_LOOKUP fails ENOENT, then skip this entry 676 * for the readdir response. If there was another error, 677 * then set the rddirattr_error and the error will be 678 * encoded later in the "attributes" section. 679 */ 680 ae = ar; 681 if (ar != 0) { 682 error = nfs4_readdir_getvp(dvp, dp->d_name, 683 &vp, &newexi, req, cs, 684 expseudo); 685 if (error == ENOENT) { 686 rddir_next_offset = dp->d_off; 687 continue; 688 } 689 690 rddirattr_error = error; 691 692 /* 693 * The vp obtained from above may be from a 694 * different filesystem mount and the vfs-like 695 * attributes should be obtained from that 696 * different vfs; only do this if appropriate. 697 */ 698 if (vp && 699 (vfs_different = (dvp->v_vfsp != vp->v_vfsp))) { 700 if (ar & (FATTR4_FILES_AVAIL_MASK | 701 FATTR4_FILES_FREE_MASK | 702 FATTR4_FILES_TOTAL_MASK | 703 FATTR4_FILES_AVAIL_MASK | 704 FATTR4_FILES_FREE_MASK | 705 FATTR4_FILES_TOTAL_MASK)) { 706 if (error = 707 rfs4_get_sb_encode(dvp->v_vfsp, &sbe)) { 708 /* Remove attrs from encode */ 709 ae &= ~(FATTR4_FILES_AVAIL_MASK | 710 FATTR4_FILES_FREE_MASK | 711 FATTR4_FILES_TOTAL_MASK | 712 FATTR4_FILES_AVAIL_MASK | 713 FATTR4_FILES_FREE_MASK | 714 FATTR4_FILES_TOTAL_MASK); 715 rddirattr_error = error; 716 } 717 } 718 if (ar & (FATTR4_MAXFILESIZE_MASK | 719 FATTR4_MAXLINK_MASK | 720 FATTR4_MAXNAME_MASK)) { 721 if (error = 722 rfs4_get_pc_encode(cs->vp, 723 &pce, ar, cs->cr)) { 724 ar &= ~(FATTR4_MAXFILESIZE_MASK | 725 FATTR4_MAXLINK_MASK | 726 FATTR4_MAXNAME_MASK); 727 rddirattr_error = error; 728 } 729 } 730 } 731 } 732 733 reencode_attrs: 734 /* encode the BOOLEAN for the existence of the next entry */ 735 IXDR_PUT_U_INT32(ptr, true); 736 /* encode the COOKIE for the entry */ 737 IXDR_PUT_U_HYPER(ptr, dp->d_off); 738 739 /* Calculate the dirent name length */ 740 namelen = strlen(dp->d_name); 741 742 rndup = RNDUP(namelen) / BYTES_PER_XDR_UNIT; 743 744 /* room for LENGTH + string ? */ 745 if ((ptr + (1 + rndup)) > ptr_redzone) { 746 no_space = TRUE; 747 continue; 748 } 749 750 /* encode the LENGTH of the name */ 751 IXDR_PUT_U_INT32(ptr, namelen); 752 /* encode the RNDUP FILL first */ 753 ptr[rndup - 1] = 0; 754 /* encode the NAME of the entry */ 755 bcopy(dp->d_name, (char *)ptr, namelen); 756 /* now bump the ptr after... */ 757 ptr += rndup; 758 759 /* 760 * Keep checking on the dircount to see if we have 761 * reached the limit; from the RFC, dircount is to be 762 * the XDR encoded limit of the cookie plus name. 763 * So the count is the name, XDR_UNIT of length for 764 * that name and 2 * XDR_UNIT bytes of cookie; 765 * However, use the regular DIRENT64 to match most 766 * client's APIs. 767 */ 768 dircount -= DIRENT64_RECLEN(namelen); 769 if (nents != 0 && dircount < 0) { 770 no_space = TRUE; 771 continue; 772 } 773 774 /* 775 * Attributes requested? 776 * Gather up the attribute info and the previous VOP_LOOKUP() 777 * succeeded; if an error occurs on the VOP_GETATTR() then 778 * return just the error (again if it is requested). 779 * Note that the previous VOP_LOOKUP() could have failed 780 * itself which leaves this code without anything for 781 * a VOP_GETATTR(). 782 * Also note that the readdir_attr_error is left in the 783 * encoding mask if requested and so is the mounted_on_fileid. 784 */ 785 if (ae != 0) { 786 if (!vp) { 787 ae = ar & (FATTR4_RDATTR_ERROR_MASK | 788 FATTR4_MOUNTED_ON_FILEID_MASK); 789 } else { 790 va.va_mask = AT_ALL; 791 rddirattr_error = 792 VOP_GETATTR(vp, &va, 0, cs->cr, NULL); 793 if (rddirattr_error) 794 ae = ar & (FATTR4_RDATTR_ERROR_MASK | 795 FATTR4_MOUNTED_ON_FILEID_MASK); 796 } 797 } 798 799 /* START OF ATTRIBUTE ENCODING */ 800 801 /* encode the LENGTH of the BITMAP4 array */ 802 IXDR_PUT_U_INT32(ptr, 2); 803 /* encode the BITMAP4 */ 804 attrmask_ptr = ptr; 805 IXDR_PUT_HYPER(ptr, ae); 806 attr_offset_ptr = ptr; 807 /* encode the default LENGTH of the attributes for entry */ 808 IXDR_PUT_U_INT32(ptr, 0); 809 810 if (ptr > ptr_redzone) { 811 no_space = TRUE; 812 continue; 813 } 814 815 /* Check if any of the first 32 attributes are being encoded */ 816 if (ae & 0xffffffff00000000) { 817 /* 818 * Redzone check is done at the end of this section. 819 * This particular section will encode a maximum of 820 * 18 * BYTES_PER_XDR_UNIT of data 821 */ 822 if (ae & 823 (FATTR4_SUPPORTED_ATTRS_MASK | 824 FATTR4_TYPE_MASK | 825 FATTR4_FH_EXPIRE_TYPE_MASK | 826 FATTR4_CHANGE_MASK | 827 FATTR4_SIZE_MASK | 828 FATTR4_LINK_SUPPORT_MASK | 829 FATTR4_SYMLINK_SUPPORT_MASK | 830 FATTR4_NAMED_ATTR_MASK | 831 FATTR4_FSID_MASK | 832 FATTR4_UNIQUE_HANDLES_MASK | 833 FATTR4_LEASE_TIME_MASK | 834 FATTR4_RDATTR_ERROR_MASK)) { 835 836 if (ae & FATTR4_SUPPORTED_ATTRS_MASK) { 837 IXDR_PUT_INT32(ptr, 2); 838 IXDR_PUT_HYPER(ptr, 839 rfs4_supported_attrs); 840 } 841 if (ae & FATTR4_TYPE_MASK) { 842 uint_t ftype = vt_to_nf4[va.va_type]; 843 if (dvp->v_flag & V_XATTRDIR) { 844 if (va.va_type == VDIR) 845 ftype = NF4ATTRDIR; 846 else 847 ftype = NF4NAMEDATTR; 848 } 849 IXDR_PUT_U_INT32(ptr, ftype); 850 } 851 if (ae & FATTR4_FH_EXPIRE_TYPE_MASK) { 852 uint_t expire_type = FH4_PERSISTENT; 853 IXDR_PUT_U_INT32(ptr, expire_type); 854 } 855 if (ae & FATTR4_CHANGE_MASK) { 856 u_longlong_t change; 857 NFS4_SET_FATTR4_CHANGE(change, 858 va.va_ctime); 859 IXDR_PUT_HYPER(ptr, change); 860 } 861 if (ae & FATTR4_SIZE_MASK) { 862 u_longlong_t size = va.va_size; 863 IXDR_PUT_HYPER(ptr, size); 864 } 865 if (ae & FATTR4_LINK_SUPPORT_MASK) { 866 IXDR_PUT_U_INT32(ptr, true); 867 } 868 if (ae & FATTR4_SYMLINK_SUPPORT_MASK) { 869 IXDR_PUT_U_INT32(ptr, true); 870 } 871 if (ae & FATTR4_NAMED_ATTR_MASK) { 872 uint_t isit; 873 pc_val = FALSE; 874 875 if (!(vp->v_vfsp->vfs_flag & 876 VFS_XATTR)) { 877 isit = FALSE; 878 } else { 879 (void) VOP_PATHCONF(vp, 880 _PC_XATTR_EXISTS, 881 &pc_val, cs->cr, NULL); 882 } 883 isit = (pc_val ? TRUE : FALSE); 884 IXDR_PUT_U_INT32(ptr, isit); 885 } 886 if (ae & FATTR4_FSID_MASK) { 887 u_longlong_t major, minor; 888 struct exportinfo *exi; 889 890 exi = newexi ? newexi : cs->exi; 891 if (exi->exi_volatile_dev) { 892 int *pmaj = (int *)&major; 893 894 pmaj[0] = exi->exi_fsid.val[0]; 895 pmaj[1] = exi->exi_fsid.val[1]; 896 minor = 0; 897 } else { 898 major = getmajor(va.va_fsid); 899 minor = getminor(va.va_fsid); 900 } 901 IXDR_PUT_HYPER(ptr, major); 902 IXDR_PUT_HYPER(ptr, minor); 903 } 904 if (ae & FATTR4_UNIQUE_HANDLES_MASK) { 905 IXDR_PUT_U_INT32(ptr, false); 906 } 907 if (ae & FATTR4_LEASE_TIME_MASK) { 908 uint_t lt = rfs4_lease_time; 909 IXDR_PUT_U_INT32(ptr, lt); 910 } 911 if (ae & FATTR4_RDATTR_ERROR_MASK) { 912 rddirattr_error = 913 (rddirattr_error == 0 ? 914 0 : puterrno4(rddirattr_error)); 915 IXDR_PUT_U_INT32(ptr, rddirattr_error); 916 } 917 918 /* Check the redzone boundary */ 919 if (ptr > ptr_redzone) { 920 if (nents || IS_MIN_ATTR_MASK(ar)) { 921 no_space = TRUE; 922 continue; 923 } 924 MINIMIZE_ATTR_MASK(ar); 925 ae = ar; 926 ptr = lastentry_ptr; 927 goto reencode_attrs; 928 } 929 } 930 /* 931 * Redzone check is done at the end of this section. 932 * This particular section will encode a maximum of 933 * 4 * BYTES_PER_XDR_UNIT of data. 934 * NOTE: that if ACLs are supported that the 935 * redzone calculations will need to change. 936 */ 937 if (ae & 938 (FATTR4_ACL_MASK | 939 FATTR4_ACLSUPPORT_MASK | 940 FATTR4_ARCHIVE_MASK | 941 FATTR4_CANSETTIME_MASK | 942 FATTR4_CASE_INSENSITIVE_MASK | 943 FATTR4_CASE_PRESERVING_MASK | 944 FATTR4_CHOWN_RESTRICTED_MASK)) { 945 946 if (ae & FATTR4_ACL_MASK) { 947 ASSERT(0); 948 } 949 if (ae & FATTR4_ACLSUPPORT_MASK) { 950 ASSERT(0); 951 } 952 if (ae & FATTR4_ARCHIVE_MASK) { 953 ASSERT(0); 954 } 955 if (ae & FATTR4_CANSETTIME_MASK) { 956 IXDR_PUT_U_INT32(ptr, true); 957 } 958 if (ae & FATTR4_CASE_INSENSITIVE_MASK) { 959 IXDR_PUT_U_INT32(ptr, false); 960 } 961 if (ae & FATTR4_CASE_PRESERVING_MASK) { 962 IXDR_PUT_U_INT32(ptr, true); 963 } 964 if (ae & FATTR4_CHOWN_RESTRICTED_MASK) { 965 uint_t isit; 966 pc_val = FALSE; 967 (void) VOP_PATHCONF(vp, 968 _PC_CHOWN_RESTRICTED, 969 &pc_val, cs->cr, NULL); 970 isit = (pc_val ? TRUE : FALSE); 971 IXDR_PUT_U_INT32(ptr, isit); 972 } 973 /* Check the redzone boundary */ 974 if (ptr > ptr_redzone) { 975 if (nents || IS_MIN_ATTR_MASK(ar)) { 976 no_space = TRUE; 977 continue; 978 } 979 MINIMIZE_ATTR_MASK(ar); 980 ae = ar; 981 ptr = lastentry_ptr; 982 goto reencode_attrs; 983 } 984 } 985 /* 986 * Redzone check is done before the filehandle 987 * is encoded. 988 */ 989 if (ae & 990 (FATTR4_FILEHANDLE_MASK | 991 FATTR4_FILEID_MASK)) { 992 993 if (ae & FATTR4_FILEHANDLE_MASK) { 994 struct { 995 uint_t len; 996 char *val; 997 char fh[NFS_FH4_LEN]; 998 } fh; 999 fh.len = 0; 1000 fh.val = fh.fh; 1001 (void) makefh4((nfs_fh4 *)&fh, vp, 1002 (newexi ? newexi : cs->exi)); 1003 1004 if (!xdr_inline_encode_nfs_fh4( 1005 &ptr, ptr_redzone, 1006 (nfs_fh4_fmt_t *)fh.val)) { 1007 if (nents || 1008 IS_MIN_ATTR_MASK(ar)) { 1009 no_space = TRUE; 1010 continue; 1011 } 1012 MINIMIZE_ATTR_MASK(ar); 1013 ae = ar; 1014 ptr = lastentry_ptr; 1015 goto reencode_attrs; 1016 } 1017 } 1018 if (ae & FATTR4_FILEID_MASK) { 1019 IXDR_PUT_HYPER(ptr, va.va_nodeid); 1020 } 1021 /* Check the redzone boundary */ 1022 if (ptr > ptr_redzone) { 1023 if (nents || IS_MIN_ATTR_MASK(ar)) { 1024 no_space = TRUE; 1025 continue; 1026 } 1027 MINIMIZE_ATTR_MASK(ar); 1028 ae = ar; 1029 ptr = lastentry_ptr; 1030 goto reencode_attrs; 1031 } 1032 } 1033 /* 1034 * Redzone check is done at the end of this section. 1035 * This particular section will encode a maximum of 1036 * 15 * BYTES_PER_XDR_UNIT of data. 1037 */ 1038 if (ae & 1039 (FATTR4_FILES_AVAIL_MASK | 1040 FATTR4_FILES_FREE_MASK | 1041 FATTR4_FILES_TOTAL_MASK | 1042 FATTR4_FS_LOCATIONS_MASK | 1043 FATTR4_HIDDEN_MASK | 1044 FATTR4_HOMOGENEOUS_MASK | 1045 FATTR4_MAXFILESIZE_MASK | 1046 FATTR4_MAXLINK_MASK | 1047 FATTR4_MAXNAME_MASK | 1048 FATTR4_MAXREAD_MASK | 1049 FATTR4_MAXWRITE_MASK)) { 1050 1051 if (ae & FATTR4_FILES_AVAIL_MASK) { 1052 IXDR_PUT_HYPER(ptr, sbe.fa); 1053 } 1054 if (ae & FATTR4_FILES_FREE_MASK) { 1055 IXDR_PUT_HYPER(ptr, sbe.ff); 1056 } 1057 if (ae & FATTR4_FILES_TOTAL_MASK) { 1058 IXDR_PUT_HYPER(ptr, sbe.ft); 1059 } 1060 if (ae & FATTR4_FS_LOCATIONS_MASK) { 1061 ASSERT(0); 1062 } 1063 if (ae & FATTR4_HIDDEN_MASK) { 1064 ASSERT(0); 1065 } 1066 if (ae & FATTR4_HOMOGENEOUS_MASK) { 1067 IXDR_PUT_U_INT32(ptr, true); 1068 } 1069 if (ae & FATTR4_MAXFILESIZE_MASK) { 1070 IXDR_PUT_HYPER(ptr, pce.maxfilesize); 1071 } 1072 if (ae & FATTR4_MAXLINK_MASK) { 1073 IXDR_PUT_U_INT32(ptr, pce.maxlink); 1074 } 1075 if (ae & FATTR4_MAXNAME_MASK) { 1076 IXDR_PUT_U_INT32(ptr, pce.maxname); 1077 } 1078 if (ae & FATTR4_MAXREAD_MASK) { 1079 IXDR_PUT_HYPER(ptr, maxread); 1080 } 1081 if (ae & FATTR4_MAXWRITE_MASK) { 1082 IXDR_PUT_HYPER(ptr, maxwrite); 1083 } 1084 /* Check the redzone boundary */ 1085 if (ptr > ptr_redzone) { 1086 if (nents || IS_MIN_ATTR_MASK(ar)) { 1087 no_space = TRUE; 1088 continue; 1089 } 1090 MINIMIZE_ATTR_MASK(ar); 1091 ae = ar; 1092 ptr = lastentry_ptr; 1093 goto reencode_attrs; 1094 } 1095 } 1096 } 1097 if (ae & 0x00000000ffffffff) { 1098 /* 1099 * Redzone check is done at the end of this section. 1100 * This particular section will encode a maximum of 1101 * 3 * BYTES_PER_XDR_UNIT of data. 1102 */ 1103 if (ae & 1104 (FATTR4_MIMETYPE_MASK | 1105 FATTR4_MODE_MASK | 1106 FATTR4_NO_TRUNC_MASK | 1107 FATTR4_NUMLINKS_MASK)) { 1108 1109 if (ae & FATTR4_MIMETYPE_MASK) { 1110 ASSERT(0); 1111 } 1112 if (ae & FATTR4_MODE_MASK) { 1113 uint_t m = va.va_mode; 1114 IXDR_PUT_U_INT32(ptr, m); 1115 } 1116 if (ae & FATTR4_NO_TRUNC_MASK) { 1117 IXDR_PUT_U_INT32(ptr, true); 1118 } 1119 if (ae & FATTR4_NUMLINKS_MASK) { 1120 IXDR_PUT_U_INT32(ptr, va.va_nlink); 1121 } 1122 /* Check the redzone boundary */ 1123 if (ptr > ptr_redzone) { 1124 if (nents || IS_MIN_ATTR_MASK(ar)) { 1125 no_space = TRUE; 1126 continue; 1127 } 1128 MINIMIZE_ATTR_MASK(ar); 1129 ae = ar; 1130 ptr = lastentry_ptr; 1131 goto reencode_attrs; 1132 } 1133 } 1134 /* 1135 * Redzone check is done before the encoding of the 1136 * owner string since the length is indeterminate. 1137 */ 1138 if (ae & FATTR4_OWNER_MASK) { 1139 if (!lu_set) { 1140 owner_error = nfs_idmap_uid_str(va.va_uid, 1141 &owner, TRUE); 1142 if (!owner_error) { 1143 lu_set = TRUE; 1144 lastuid = va.va_uid; 1145 } 1146 } else { 1147 if (va.va_uid != lastuid) { 1148 if (owner.utf8string_len != 0) { 1149 kmem_free(owner.utf8string_val, 1150 owner.utf8string_len); 1151 owner.utf8string_len = 0; 1152 owner.utf8string_val = NULL; 1153 } 1154 owner_error = nfs_idmap_uid_str( 1155 va.va_uid, 1156 &owner, TRUE); 1157 if (!owner_error) { 1158 lastuid = va.va_uid; 1159 } else { 1160 lu_set = FALSE; 1161 } 1162 } 1163 } 1164 if (!owner_error) { 1165 if ((ptr + 1166 (owner.utf8string_len / 1167 BYTES_PER_XDR_UNIT) 1168 + 2) > ptr_redzone) { 1169 if (nents || 1170 IS_MIN_ATTR_MASK(ar)) { 1171 no_space = TRUE; 1172 continue; 1173 } 1174 MINIMIZE_ATTR_MASK(ar); 1175 ae = ar; 1176 ptr = lastentry_ptr; 1177 goto reencode_attrs; 1178 } 1179 /* encode the LENGTH of owner string */ 1180 IXDR_PUT_U_INT32(ptr, 1181 owner.utf8string_len); 1182 /* encode the RNDUP FILL first */ 1183 rndup = RNDUP(owner.utf8string_len) / 1184 BYTES_PER_XDR_UNIT; 1185 ptr[rndup - 1] = 0; 1186 /* encode the OWNER */ 1187 bcopy(owner.utf8string_val, ptr, 1188 owner.utf8string_len); 1189 ptr += rndup; 1190 } 1191 } 1192 /* 1193 * Redzone check is done before the encoding of the 1194 * group string since the length is indeterminate. 1195 */ 1196 if (ae & FATTR4_OWNER_GROUP_MASK) { 1197 if (!lg_set) { 1198 group_error = 1199 nfs_idmap_gid_str(va.va_gid, 1200 &group, TRUE); 1201 if (!group_error) { 1202 lg_set = TRUE; 1203 lastgid = va.va_gid; 1204 } 1205 } else { 1206 if (va.va_gid != lastgid) { 1207 if (group.utf8string_len != 0) { 1208 kmem_free(group.utf8string_val, 1209 group.utf8string_len); 1210 group.utf8string_len = 0; 1211 group.utf8string_val = NULL; 1212 } 1213 group_error = 1214 nfs_idmap_gid_str(va.va_gid, 1215 &group, TRUE); 1216 if (!group_error) 1217 lastgid = va.va_gid; 1218 else 1219 lg_set = FALSE; 1220 } 1221 } 1222 if (!group_error) { 1223 if ((ptr + 1224 (group.utf8string_len / 1225 BYTES_PER_XDR_UNIT) 1226 + 2) > ptr_redzone) { 1227 if (nents || 1228 IS_MIN_ATTR_MASK(ar)) { 1229 no_space = TRUE; 1230 continue; 1231 } 1232 MINIMIZE_ATTR_MASK(ar); 1233 ae = ar; 1234 ptr = lastentry_ptr; 1235 goto reencode_attrs; 1236 } 1237 /* encode the LENGTH of owner string */ 1238 IXDR_PUT_U_INT32(ptr, 1239 group.utf8string_len); 1240 /* encode the RNDUP FILL first */ 1241 rndup = RNDUP(group.utf8string_len) / 1242 BYTES_PER_XDR_UNIT; 1243 ptr[rndup - 1] = 0; 1244 /* encode the OWNER */ 1245 bcopy(group.utf8string_val, ptr, 1246 group.utf8string_len); 1247 ptr += rndup; 1248 } 1249 } 1250 if (ae & 1251 (FATTR4_QUOTA_AVAIL_HARD_MASK | 1252 FATTR4_QUOTA_AVAIL_SOFT_MASK | 1253 FATTR4_QUOTA_USED_MASK)) { 1254 if (ae & FATTR4_QUOTA_AVAIL_HARD_MASK) { 1255 ASSERT(0); 1256 } 1257 if (ae & FATTR4_QUOTA_AVAIL_SOFT_MASK) { 1258 ASSERT(0); 1259 } 1260 if (ae & FATTR4_QUOTA_USED_MASK) { 1261 ASSERT(0); 1262 } 1263 } 1264 /* 1265 * Redzone check is done at the end of this section. 1266 * This particular section will encode a maximum of 1267 * 10 * BYTES_PER_XDR_UNIT of data. 1268 */ 1269 if (ae & 1270 (FATTR4_RAWDEV_MASK | 1271 FATTR4_SPACE_AVAIL_MASK | 1272 FATTR4_SPACE_FREE_MASK | 1273 FATTR4_SPACE_TOTAL_MASK | 1274 FATTR4_SPACE_USED_MASK | 1275 FATTR4_SYSTEM_MASK)) { 1276 1277 if (ae & FATTR4_RAWDEV_MASK) { 1278 fattr4_rawdev rd; 1279 rd.specdata1 = 1280 (uint32)getmajor(va.va_rdev); 1281 rd.specdata2 = 1282 (uint32)getminor(va.va_rdev); 1283 IXDR_PUT_U_INT32(ptr, rd.specdata1); 1284 IXDR_PUT_U_INT32(ptr, rd.specdata2); 1285 } 1286 if (ae & FATTR4_SPACE_AVAIL_MASK) { 1287 IXDR_PUT_HYPER(ptr, sbe.space_avail); 1288 } 1289 if (ae & FATTR4_SPACE_FREE_MASK) { 1290 IXDR_PUT_HYPER(ptr, sbe.space_free); 1291 } 1292 if (ae & FATTR4_SPACE_TOTAL_MASK) { 1293 IXDR_PUT_HYPER(ptr, sbe.space_total); 1294 } 1295 if (ae & FATTR4_SPACE_USED_MASK) { 1296 u_longlong_t su; 1297 su = (fattr4_space_used) DEV_BSIZE * 1298 (fattr4_space_used) va.va_nblocks; 1299 IXDR_PUT_HYPER(ptr, su); 1300 } 1301 if (ae & FATTR4_SYSTEM_MASK) { 1302 ASSERT(0); 1303 } 1304 /* Check the redzone boundary */ 1305 if (ptr > ptr_redzone) { 1306 if (nents || IS_MIN_ATTR_MASK(ar)) { 1307 no_space = TRUE; 1308 continue; 1309 } 1310 MINIMIZE_ATTR_MASK(ar); 1311 ae = ar; 1312 ptr = lastentry_ptr; 1313 goto reencode_attrs; 1314 } 1315 } 1316 /* 1317 * Redzone check is done at the end of this section. 1318 * This particular section will encode a maximum of 1319 * 14 * BYTES_PER_XDR_UNIT of data. 1320 */ 1321 if (ae & 1322 (FATTR4_TIME_ACCESS_MASK | 1323 FATTR4_TIME_ACCESS_SET_MASK | 1324 FATTR4_TIME_BACKUP_MASK | 1325 FATTR4_TIME_CREATE_MASK | 1326 FATTR4_TIME_DELTA_MASK | 1327 FATTR4_TIME_METADATA_MASK | 1328 FATTR4_TIME_MODIFY_MASK | 1329 FATTR4_TIME_MODIFY_SET_MASK | 1330 FATTR4_MOUNTED_ON_FILEID_MASK)) { 1331 1332 if (ae & FATTR4_TIME_ACCESS_MASK) { 1333 u_longlong_t sec = 1334 (u_longlong_t)va.va_atime.tv_sec; 1335 uint_t nsec = 1336 (uint_t)va.va_atime.tv_nsec; 1337 IXDR_PUT_HYPER(ptr, sec); 1338 IXDR_PUT_INT32(ptr, nsec); 1339 } 1340 if (ae & FATTR4_TIME_ACCESS_SET_MASK) { 1341 ASSERT(0); 1342 } 1343 if (ae & FATTR4_TIME_BACKUP_MASK) { 1344 ASSERT(0); 1345 } 1346 if (ae & FATTR4_TIME_CREATE_MASK) { 1347 ASSERT(0); 1348 } 1349 if (ae & FATTR4_TIME_DELTA_MASK) { 1350 u_longlong_t sec = 0; 1351 uint_t nsec = 1000; 1352 IXDR_PUT_HYPER(ptr, sec); 1353 IXDR_PUT_INT32(ptr, nsec); 1354 } 1355 if (ae & FATTR4_TIME_METADATA_MASK) { 1356 u_longlong_t sec = 1357 (u_longlong_t)va.va_ctime.tv_sec; 1358 uint_t nsec = 1359 (uint_t)va.va_ctime.tv_nsec; 1360 IXDR_PUT_HYPER(ptr, sec); 1361 IXDR_PUT_INT32(ptr, nsec); 1362 } 1363 if (ae & FATTR4_TIME_MODIFY_MASK) { 1364 u_longlong_t sec = 1365 (u_longlong_t)va.va_mtime.tv_sec; 1366 uint_t nsec = 1367 (uint_t)va.va_mtime.tv_nsec; 1368 IXDR_PUT_HYPER(ptr, sec); 1369 IXDR_PUT_INT32(ptr, nsec); 1370 } 1371 if (ae & FATTR4_TIME_MODIFY_SET_MASK) { 1372 ASSERT(0); 1373 } 1374 if (ae & FATTR4_MOUNTED_ON_FILEID_MASK) { 1375 IXDR_PUT_HYPER(ptr, dp->d_ino); 1376 } 1377 /* Check the redzone boundary */ 1378 if (ptr > ptr_redzone) { 1379 if (nents || IS_MIN_ATTR_MASK(ar)) { 1380 no_space = TRUE; 1381 continue; 1382 } 1383 MINIMIZE_ATTR_MASK(ar); 1384 ae = ar; 1385 ptr = lastentry_ptr; 1386 goto reencode_attrs; 1387 } 1388 } 1389 } 1390 1391 /* Reset to directory's vfs info when encoding complete */ 1392 if (vfs_different) { 1393 dsbe = sbe; 1394 dpce = pce; 1395 vfs_different = 0; 1396 } 1397 1398 /* "go back" and encode the attributes' length */ 1399 attr_length = 1400 (char *)ptr - 1401 (char *)attr_offset_ptr - 1402 BYTES_PER_XDR_UNIT; 1403 IXDR_PUT_U_INT32(attr_offset_ptr, attr_length); 1404 1405 /* 1406 * If there was trouble obtaining a mapping for either 1407 * the owner or group attributes, then remove them from 1408 * bitmap4 for this entry and reset the bitmap value 1409 * in the data stream. 1410 */ 1411 if (owner_error || group_error) { 1412 if (owner_error) 1413 ae &= ~FATTR4_OWNER_MASK; 1414 if (group_error) 1415 ae &= ~FATTR4_OWNER_GROUP_MASK; 1416 IXDR_PUT_HYPER(attrmask_ptr, ae); 1417 } 1418 1419 /* END OF ATTRIBUTE ENCODING */ 1420 1421 lastentry_ptr = ptr; 1422 nents++; 1423 rddir_next_offset = dp->d_off; 1424 } 1425 1426 /* 1427 * Check for the case that another VOP_READDIR() has to be done. 1428 * - no space encoding error 1429 * - no entry successfully encoded 1430 * - still more directory to read 1431 */ 1432 if (!no_space && nents == 0 && !iseofdir) 1433 goto readagain; 1434 1435 *cs->statusp = resp->status = NFS4_OK; 1436 1437 /* 1438 * If no_space is set then we terminated prematurely, 1439 * rewind to the last entry and this can never be EOF. 1440 */ 1441 if (no_space) { 1442 ptr = lastentry_ptr; 1443 eof = FALSE; /* ended encoded prematurely */ 1444 } else { 1445 eof = (iseofdir ? TRUE : FALSE); 1446 } 1447 1448 /* 1449 * If we have entries, always return them, otherwise only error 1450 * if we ran out of space. 1451 */ 1452 if (nents || !no_space) { 1453 ASSERT(ptr != NULL); 1454 /* encode the BOOLEAN marking no further entries */ 1455 IXDR_PUT_U_INT32(ptr, false); 1456 /* encode the BOOLEAN signifying end of directory */ 1457 IXDR_PUT_U_INT32(ptr, eof); 1458 1459 resp->data_len = (char *)ptr - (char *)beginning_ptr; 1460 resp->mblk->b_wptr += resp->data_len; 1461 } else { 1462 freeb(mp); 1463 resp->mblk = NULL; 1464 resp->data_len = 0; 1465 *cs->statusp = resp->status = NFS4ERR_TOOSMALL; 1466 } 1467 1468 kmem_free((caddr_t)rddir_data, rddir_data_len); 1469 if (vp) 1470 VN_RELE(vp); 1471 if (owner.utf8string_len != 0) 1472 kmem_free(owner.utf8string_val, owner.utf8string_len); 1473 if (group.utf8string_len != 0) 1474 kmem_free(group.utf8string_val, group.utf8string_len); 1475 } 1476