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 2008 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 #include <sys/types.h> 27 #include <sys/stat.h> 28 #include <sys/uio.h> 29 #include <sys/statvfs.h> 30 #include <sys/vnode.h> 31 #include <sys/thread.h> 32 #include <sys/pathname.h> 33 #include <sys/cred.h> 34 #include <sys/extdirent.h> 35 #include <sys/nbmlock.h> 36 #include <sys/share.h> 37 #include <sys/fcntl.h> 38 #include <nfs/lm.h> 39 40 #include <smbsrv/smb_vops.h> 41 #include <smbsrv/string.h> 42 43 #include <smbsrv/smbtrans.h> 44 #include <smbsrv/smb_fsops.h> 45 #include <smbsrv/smb_kproto.h> 46 #include <smbsrv/smb_incl.h> 47 48 void 49 smb_vop_setup_xvattr(smb_attr_t *smb_attr, xvattr_t *xvattr); 50 51 static int 52 smb_vop_readdir_readpage(vnode_t *, void *, uint32_t, int *, cred_t *); 53 54 static int 55 smb_vop_readdir_entry(vnode_t *, uint32_t *, char *, int *, 56 ino64_t *, vnode_t **, char *, int, cred_t *, char *, int); 57 58 static int 59 smb_vop_getdents_entries(smb_node_t *, uint32_t *, int32_t *, char *, uint32_t, 60 smb_request_t *, cred_t *, char *, int *, int, char *); 61 62 extern int 63 smb_gather_dents_info(char *args, ino_t fileid, int namelen, 64 char *name, uint32_t cookie, int32_t *countp, 65 smb_attr_t *attr, struct smb_node *snode, 66 char *shortname, char *name83); 67 68 static void 69 smb_sa_to_va_mask(uint_t sa_mask, uint_t *va_maskp); 70 71 static 72 callb_cpr_t *smb_lock_frlock_callback(flk_cb_when_t, void *); 73 74 extern sysid_t lm_alloc_sysidt(); 75 76 #define SMB_AT_MAX 16 77 static uint_t smb_attrmap[SMB_AT_MAX] = { 78 0, 79 AT_TYPE, 80 AT_MODE, 81 AT_UID, 82 AT_GID, 83 AT_FSID, 84 AT_NODEID, 85 AT_NLINK, 86 AT_SIZE, 87 AT_ATIME, 88 AT_MTIME, 89 AT_CTIME, 90 AT_RDEV, 91 AT_BLKSIZE, 92 AT_NBLOCKS, 93 AT_SEQ 94 }; 95 96 static boolean_t smb_vop_initialized = B_FALSE; 97 caller_context_t smb_ct; 98 99 /* 100 * smb_vop_init 101 * 102 * This function is not multi-thread safe. The caller must make sure only one 103 * thread makes the call. 104 */ 105 int 106 smb_vop_init(void) 107 { 108 if (smb_vop_initialized) 109 return (0); 110 /* 111 * The caller_context will be used primarily for range locking. 112 * Since the CIFS server is mapping its locks to POSIX locks, 113 * only one pid is used for operations originating from the 114 * CIFS server (to represent CIFS in the VOP_FRLOCK routines). 115 */ 116 smb_ct.cc_sysid = lm_alloc_sysidt(); 117 if (smb_ct.cc_sysid == LM_NOSYSID) 118 return (ENOMEM); 119 120 smb_ct.cc_caller_id = fs_new_caller_id(); 121 smb_ct.cc_pid = IGN_PID; 122 smb_ct.cc_flags = 0; 123 124 smb_vop_initialized = B_TRUE; 125 return (0); 126 } 127 128 /* 129 * smb_vop_fini 130 * 131 * This function is not multi-thread safe. The caller must make sure only one 132 * thread makes the call. 133 */ 134 void 135 smb_vop_fini(void) 136 { 137 if (!smb_vop_initialized) 138 return; 139 140 lm_free_sysidt(smb_ct.cc_sysid); 141 smb_ct.cc_pid = IGN_PID; 142 smb_ct.cc_sysid = LM_NOSYSID; 143 smb_vop_initialized = B_FALSE; 144 } 145 146 /* 147 * The smb_ct will be used primarily for range locking. 148 * Since the CIFS server is mapping its locks to POSIX locks, 149 * only one pid is used for operations originating from the 150 * CIFS server (to represent CIFS in the VOP_FRLOCK routines). 151 */ 152 153 int 154 smb_vop_open(vnode_t **vpp, int mode, cred_t *cred) 155 { 156 return (VOP_OPEN(vpp, mode, cred, &smb_ct)); 157 } 158 159 void 160 smb_vop_close(vnode_t *vp, int mode, cred_t *cred) 161 { 162 (void) VOP_CLOSE(vp, mode, 1, (offset_t)0, cred, &smb_ct); 163 } 164 165 int 166 smb_vop_other_opens(vnode_t *vp, int mode) 167 { 168 return (((mode & FWRITE) && vn_has_other_opens(vp, V_WRITE)) || 169 (((mode & FWRITE) == 0) && vn_is_opened(vp, V_WRITE)) || 170 ((mode & FREAD) && vn_has_other_opens(vp, V_READ)) || 171 (((mode & FREAD) == 0) && vn_is_opened(vp, V_READ)) || 172 vn_is_mapped(vp, V_RDORWR)); 173 } 174 175 /* 176 * The smb_vop_* functions have minimal knowledge of CIFS semantics and 177 * serve as an interface to the VFS layer. 178 * 179 * Only smb_fsop_* layer functions should call smb_vop_* layer functions. 180 * (Higher-level CIFS service code should never skip the smb_fsop_* layer 181 * to call smb_vop_* layer functions directly.) 182 */ 183 184 /* 185 * XXX - Extended attributes support in the file system assumed. 186 * This is needed for full NT Streams functionality. 187 */ 188 189 int 190 smb_vop_read(vnode_t *vp, uio_t *uiop, cred_t *cr) 191 { 192 int error; 193 194 (void) VOP_RWLOCK(vp, V_WRITELOCK_FALSE, &smb_ct); 195 error = VOP_READ(vp, uiop, 0, cr, &smb_ct); 196 VOP_RWUNLOCK(vp, V_WRITELOCK_FALSE, &smb_ct); 197 return (error); 198 } 199 200 int 201 smb_vop_write(vnode_t *vp, uio_t *uiop, int ioflag, uint32_t *lcount, 202 cred_t *cr) 203 { 204 int error; 205 206 *lcount = uiop->uio_resid; 207 208 uiop->uio_llimit = MAXOFFSET_T; 209 210 (void) VOP_RWLOCK(vp, V_WRITELOCK_TRUE, &smb_ct); 211 error = VOP_WRITE(vp, uiop, ioflag, cr, &smb_ct); 212 VOP_RWUNLOCK(vp, V_WRITELOCK_TRUE, &smb_ct); 213 214 *lcount -= uiop->uio_resid; 215 216 return (error); 217 } 218 219 /* 220 * smb_vop_getattr() 221 * 222 * smb_fsop_getattr()/smb_vop_getattr() should always be called from the CIFS 223 * service (instead of calling VOP_GETATTR directly) to retrieve attributes 224 * due to special processing needed for streams files. 225 * 226 * All attributes are retrieved. 227 * 228 * A named stream's attributes (as far as CIFS is concerned) are those of the 229 * unnamed (i.e. data) stream (minus the size attribute), and the size of the 230 * named stream. Though the file system may store attributes other than size 231 * with the named stream, these should not be used by CIFS for any purpose. 232 * 233 * When vp denotes a named stream, then unnamed_vp should be passed in (denoting 234 * the corresponding unnamed stream). 235 */ 236 237 int 238 smb_vop_getattr(vnode_t *vp, vnode_t *unnamed_vp, smb_attr_t *ret_attr, 239 int flags, cred_t *cr) 240 { 241 int error; 242 vnode_t *use_vp; 243 smb_attr_t tmp_attr; 244 xvattr_t tmp_xvattr; 245 xoptattr_t *xoap = NULL; 246 247 if (unnamed_vp) 248 use_vp = unnamed_vp; 249 else 250 use_vp = vp; 251 252 if (vfs_has_feature(use_vp->v_vfsp, VFSFT_XVATTR)) { 253 xva_init(&tmp_xvattr); 254 xoap = xva_getxoptattr(&tmp_xvattr); 255 256 ASSERT(xoap); 257 258 smb_sa_to_va_mask(ret_attr->sa_mask, 259 &tmp_xvattr.xva_vattr.va_mask); 260 261 XVA_SET_REQ(&tmp_xvattr, XAT_READONLY); 262 XVA_SET_REQ(&tmp_xvattr, XAT_HIDDEN); 263 XVA_SET_REQ(&tmp_xvattr, XAT_SYSTEM); 264 XVA_SET_REQ(&tmp_xvattr, XAT_ARCHIVE); 265 XVA_SET_REQ(&tmp_xvattr, XAT_CREATETIME); 266 267 if ((error = VOP_GETATTR(use_vp, &tmp_xvattr.xva_vattr, flags, 268 cr, &smb_ct)) != 0) 269 return (error); 270 271 ret_attr->sa_vattr = tmp_xvattr.xva_vattr; 272 273 /* 274 * Copy special attributes to ret_attr parameter 275 */ 276 277 ret_attr->sa_dosattr = 0; 278 279 ASSERT(tmp_xvattr.xva_vattr.va_mask & AT_XVATTR); 280 281 xoap = xva_getxoptattr(&tmp_xvattr); 282 ASSERT(xoap); 283 284 if (XVA_ISSET_RTN(&tmp_xvattr, XAT_READONLY)) { 285 if (xoap->xoa_readonly) 286 ret_attr->sa_dosattr |= FILE_ATTRIBUTE_READONLY; 287 } 288 289 if (XVA_ISSET_RTN(&tmp_xvattr, XAT_HIDDEN)) { 290 if (xoap->xoa_hidden) 291 ret_attr->sa_dosattr |= FILE_ATTRIBUTE_HIDDEN; 292 } 293 294 if (XVA_ISSET_RTN(&tmp_xvattr, XAT_SYSTEM)) { 295 if (xoap->xoa_system) 296 ret_attr->sa_dosattr |= FILE_ATTRIBUTE_SYSTEM; 297 } 298 299 if (XVA_ISSET_RTN(&tmp_xvattr, XAT_ARCHIVE)) { 300 if (xoap->xoa_archive) 301 ret_attr->sa_dosattr |= FILE_ATTRIBUTE_ARCHIVE; 302 } 303 304 ret_attr->sa_crtime = xoap->xoa_createtime; 305 306 if (unnamed_vp && (ret_attr->sa_mask & SMB_AT_SIZE)) { 307 /* 308 * Retrieve stream size attribute into temporary 309 * structure, in case the underlying file system 310 * returns attributes other than the size (we do not 311 * want to have ret_attr's other fields get 312 * overwritten). 313 * 314 * Note that vp is used here, and not use_vp. 315 * Also, only AT_SIZE is needed. 316 */ 317 318 tmp_xvattr.xva_vattr.va_mask = AT_SIZE; 319 320 if ((error = VOP_GETATTR(vp, &tmp_xvattr.xva_vattr, 321 flags, cr, &smb_ct)) != 0) 322 return (error); 323 324 ret_attr->sa_vattr.va_size = 325 tmp_xvattr.xva_vattr.va_size; 326 327 } 328 329 if (ret_attr->sa_vattr.va_type == VDIR) { 330 ret_attr->sa_dosattr |= FILE_ATTRIBUTE_DIRECTORY; 331 } 332 333 return (error); 334 } 335 336 /* 337 * Support for file systems without VFSFT_XVATTR 338 */ 339 340 smb_sa_to_va_mask(ret_attr->sa_mask, 341 &ret_attr->sa_vattr.va_mask); 342 343 error = VOP_GETATTR(use_vp, &ret_attr->sa_vattr, flags, cr, &smb_ct); 344 345 if (error != 0) 346 return (error); 347 348 /* 349 * "Fake" DOS attributes and create time, filesystem doesn't support 350 * them. 351 */ 352 353 ret_attr->sa_dosattr = 0; 354 ret_attr->sa_crtime = ret_attr->sa_vattr.va_mtime; 355 356 if (unnamed_vp && (ret_attr->sa_mask & SMB_AT_SIZE)) { 357 /* 358 * Retrieve stream size attribute into temporary structure, 359 * in case the underlying file system returns attributes 360 * other than the size (we do not want to have ret_attr's 361 * other fields get overwritten). 362 * 363 * Note that vp is used here, and not use_vp. 364 * Also, only AT_SIZE is needed. 365 */ 366 367 tmp_attr.sa_vattr.va_mask = AT_SIZE; 368 error = VOP_GETATTR(vp, &tmp_attr.sa_vattr, flags, cr, &smb_ct); 369 370 if (error != 0) 371 return (error); 372 373 374 ret_attr->sa_vattr.va_size = tmp_attr.sa_vattr.va_size; 375 } 376 377 if (ret_attr->sa_vattr.va_type == VDIR) { 378 ret_attr->sa_dosattr |= FILE_ATTRIBUTE_DIRECTORY; 379 } 380 381 return (error); 382 } 383 384 /* 385 * smb_vop_setattr() 386 * 387 * smb_fsop_setattr()/smb_vop_setattr() should always be used instead of 388 * VOP_SETATTR() when calling from the CIFS service, due to special processing 389 * for streams files. 390 * 391 * Streams have a size but otherwise do not have separate attributes from 392 * the (unnamed stream) file, i.e., the security and ownership of the file 393 * applies to the stream. In contrast, extended attribute files, which are 394 * used to implement streams, are independent objects with their own 395 * attributes. 396 * 397 * For compatibility with streams, we set the size on the extended attribute 398 * file and apply other attributes to the (unnamed stream) file. The one 399 * exception is that the UID and GID can be set on the stream by passing a 400 * NULL unnamed_vp, which allows callers to synchronize stream ownership 401 * with the (unnamed stream) file. 402 */ 403 404 int 405 smb_vop_setattr(vnode_t *vp, vnode_t *unnamed_vp, smb_attr_t *set_attr, 406 int flags, cred_t *cr, boolean_t no_xvattr) 407 { 408 int error = 0; 409 int at_size = 0; 410 vnode_t *use_vp; 411 xvattr_t xvattr; 412 vattr_t *vap; 413 414 if (unnamed_vp) { 415 use_vp = unnamed_vp; 416 if (set_attr->sa_mask & SMB_AT_SIZE) { 417 at_size = 1; 418 set_attr->sa_mask &= ~SMB_AT_SIZE; 419 } 420 } else { 421 use_vp = vp; 422 } 423 424 /* 425 * The caller should not be setting sa_vattr.va_mask, 426 * but rather sa_mask. 427 */ 428 429 set_attr->sa_vattr.va_mask = 0; 430 431 if ((no_xvattr == B_FALSE) && 432 vfs_has_feature(use_vp->v_vfsp, VFSFT_XVATTR)) { 433 smb_vop_setup_xvattr(set_attr, &xvattr); 434 vap = &xvattr.xva_vattr; 435 } else { 436 smb_sa_to_va_mask(set_attr->sa_mask, 437 &set_attr->sa_vattr.va_mask); 438 vap = &set_attr->sa_vattr; 439 } 440 441 if ((error = VOP_SETATTR(use_vp, vap, flags, cr, &smb_ct)) != 0) 442 return (error); 443 444 /* 445 * If the size of the stream needs to be set, set it on 446 * the stream file directly. (All other indicated attributes 447 * are set on the stream's unnamed stream, except under the 448 * exception described in the function header.) 449 */ 450 451 if (at_size) { 452 /* 453 * set_attr->sa_vattr.va_size already contains the 454 * size as set by the caller 455 * 456 * Note that vp is used here, and not use_vp. 457 * Also, only AT_SIZE is needed. 458 */ 459 460 set_attr->sa_vattr.va_mask = AT_SIZE; 461 error = VOP_SETATTR(vp, &set_attr->sa_vattr, flags, cr, 462 &smb_ct); 463 } 464 465 return (error); 466 } 467 468 /* 469 * smb_vop_access 470 * 471 * This is a wrapper round VOP_ACCESS. VOP_ACCESS checks the given mode 472 * against file's ACL or Unix permissions. CIFS on the other hand needs to 473 * know if the requested operation can succeed for the given object, this 474 * requires more checks in case of DELETE bit since permissions on the parent 475 * directory are important as well. Based on Windows rules if parent's ACL 476 * grant FILE_DELETE_CHILD a file can be delete regardless of the file's 477 * permissions. 478 */ 479 int 480 smb_vop_access(vnode_t *vp, int mode, int flags, vnode_t *dir_vp, cred_t *cr) 481 { 482 int error = 0; 483 484 if (mode == 0) 485 return (0); 486 487 if ((flags == V_ACE_MASK) && (mode & ACE_DELETE)) { 488 if (dir_vp) { 489 error = VOP_ACCESS(dir_vp, ACE_DELETE_CHILD, flags, 490 cr, NULL); 491 492 if (error == 0) 493 mode &= ~ACE_DELETE; 494 } 495 } 496 497 if (mode) { 498 error = VOP_ACCESS(vp, mode, flags, cr, NULL); 499 } 500 501 return (error); 502 } 503 504 /* 505 * smb_vop_lookup 506 * 507 * dvp: directory vnode (in) 508 * name: name of file to be looked up (in) 509 * vpp: looked-up vnode (out) 510 * od_name: on-disk name of file (out). 511 * This parameter is optional. If a pointer is passed in, it 512 * must be allocated with MAXNAMELEN bytes 513 * rootvp: vnode of the tree root (in) 514 * This parameter is always passed in non-NULL except at the time 515 * of share set up. 516 */ 517 518 int 519 smb_vop_lookup( 520 vnode_t *dvp, 521 char *name, 522 vnode_t **vpp, 523 char *od_name, 524 int flags, 525 vnode_t *rootvp, 526 cred_t *cr) 527 { 528 int error = 0; 529 int option_flags = 0; 530 pathname_t rpn; 531 532 if (*name == '\0') 533 return (EINVAL); 534 535 ASSERT(vpp); 536 *vpp = NULL; 537 538 if ((name[0] == '.') && (name[1] == '.') && (name[2] == 0)) { 539 if (rootvp && (dvp == rootvp)) { 540 VN_HOLD(dvp); 541 *vpp = dvp; 542 return (0); 543 } 544 545 if (dvp->v_flag & VROOT) { 546 vfs_t *vfsp; 547 vnode_t *cvp = dvp; 548 549 /* 550 * Set dvp and check for races with forced unmount 551 * (see lookuppnvp()) 552 */ 553 554 vfsp = cvp->v_vfsp; 555 vfs_rlock_wait(vfsp); 556 if (((dvp = cvp->v_vfsp->vfs_vnodecovered) == NULL) || 557 (cvp->v_vfsp->vfs_flag & VFS_UNMOUNTED)) { 558 vfs_unlock(vfsp); 559 return (EIO); 560 } 561 vfs_unlock(vfsp); 562 } 563 } 564 565 566 567 if (flags & SMB_IGNORE_CASE) 568 option_flags = FIGNORECASE; 569 570 pn_alloc(&rpn); 571 572 error = VOP_LOOKUP(dvp, name, vpp, NULL, option_flags, NULL, cr, 573 &smb_ct, NULL, &rpn); 574 575 if ((error == 0) && od_name) { 576 bzero(od_name, MAXNAMELEN); 577 if (option_flags == FIGNORECASE) 578 (void) strlcpy(od_name, rpn.pn_buf, MAXNAMELEN); 579 else 580 (void) strlcpy(od_name, name, MAXNAMELEN); 581 } 582 583 pn_free(&rpn); 584 return (error); 585 } 586 587 int 588 smb_vop_create(vnode_t *dvp, char *name, smb_attr_t *attr, vnode_t **vpp, 589 int flags, cred_t *cr, vsecattr_t *vsap) 590 { 591 int error; 592 int option_flags = 0; 593 xvattr_t xvattr; 594 vattr_t *vap; 595 596 if (flags & SMB_IGNORE_CASE) 597 option_flags = FIGNORECASE; 598 599 attr->sa_vattr.va_mask = 0; 600 601 if (vfs_has_feature(dvp->v_vfsp, VFSFT_XVATTR)) { 602 smb_vop_setup_xvattr(attr, &xvattr); 603 vap = &xvattr.xva_vattr; 604 } else { 605 smb_sa_to_va_mask(attr->sa_mask, &attr->sa_vattr.va_mask); 606 vap = &attr->sa_vattr; 607 } 608 609 error = VOP_CREATE(dvp, name, vap, EXCL, attr->sa_vattr.va_mode, 610 vpp, cr, option_flags, &smb_ct, vsap); 611 612 return (error); 613 } 614 615 int 616 smb_vop_remove(vnode_t *dvp, char *name, int flags, cred_t *cr) 617 { 618 int error; 619 int option_flags = 0; 620 621 if (flags & SMB_IGNORE_CASE) 622 option_flags = FIGNORECASE; 623 624 error = VOP_REMOVE(dvp, name, cr, &smb_ct, option_flags); 625 626 return (error); 627 } 628 629 /* 630 * smb_vop_rename() 631 * 632 * The rename is for files in the same tree (identical TID) only. 633 */ 634 635 int 636 smb_vop_rename(vnode_t *from_dvp, char *from_name, vnode_t *to_dvp, 637 char *to_name, int flags, cred_t *cr) 638 { 639 int error; 640 int option_flags = 0; 641 642 643 if (flags & SMB_IGNORE_CASE) 644 option_flags = FIGNORECASE; 645 646 error = VOP_RENAME(from_dvp, from_name, to_dvp, to_name, cr, 647 &smb_ct, option_flags); 648 649 return (error); 650 } 651 652 int 653 smb_vop_mkdir(vnode_t *dvp, char *name, smb_attr_t *attr, vnode_t **vpp, 654 int flags, cred_t *cr, vsecattr_t *vsap) 655 { 656 int error; 657 int option_flags = 0; 658 xvattr_t xvattr; 659 vattr_t *vap; 660 661 if (flags & SMB_IGNORE_CASE) 662 option_flags = FIGNORECASE; 663 664 attr->sa_vattr.va_mask = 0; 665 666 if (vfs_has_feature(dvp->v_vfsp, VFSFT_XVATTR)) { 667 smb_vop_setup_xvattr(attr, &xvattr); 668 vap = &xvattr.xva_vattr; 669 } else { 670 smb_sa_to_va_mask(attr->sa_mask, &attr->sa_vattr.va_mask); 671 vap = &attr->sa_vattr; 672 } 673 674 error = VOP_MKDIR(dvp, name, vap, vpp, cr, &smb_ct, 675 option_flags, vsap); 676 677 return (error); 678 } 679 680 /* 681 * smb_vop_rmdir() 682 * 683 * Only simple rmdir supported, consistent with NT semantics 684 * (can only remove an empty directory). 685 * 686 */ 687 688 int 689 smb_vop_rmdir(vnode_t *dvp, char *name, int flags, cred_t *cr) 690 { 691 int error; 692 int option_flags = 0; 693 694 if (flags & SMB_IGNORE_CASE) 695 option_flags = FIGNORECASE; 696 697 /* 698 * Comments adapted from rfs_rmdir(). 699 * 700 * VOP_RMDIR now takes a new third argument (the current 701 * directory of the process). That's because rmdir 702 * wants to return EINVAL if one tries to remove ".". 703 * Of course, SMB servers do not know what their 704 * clients' current directories are. We fake it by 705 * supplying a vnode known to exist and illegal to 706 * remove. 707 */ 708 709 error = VOP_RMDIR(dvp, name, rootdir, cr, &smb_ct, option_flags); 710 return (error); 711 } 712 713 int 714 smb_vop_commit(vnode_t *vp, cred_t *cr) 715 { 716 return (VOP_FSYNC(vp, 1, cr, &smb_ct)); 717 } 718 719 void 720 smb_vop_setup_xvattr(smb_attr_t *smb_attr, xvattr_t *xvattr) 721 { 722 xoptattr_t *xoap = NULL; 723 uint_t xva_mask; 724 725 /* 726 * Initialize xvattr, including bzero 727 */ 728 xva_init(xvattr); 729 xoap = xva_getxoptattr(xvattr); 730 731 ASSERT(xoap); 732 733 /* 734 * Copy caller-specified classic attributes to xvattr. 735 * First save xvattr's mask (set in xva_init()), which 736 * contains AT_XVATTR. This is |'d in later if needed. 737 */ 738 739 xva_mask = xvattr->xva_vattr.va_mask; 740 xvattr->xva_vattr = smb_attr->sa_vattr; 741 742 smb_sa_to_va_mask(smb_attr->sa_mask, &xvattr->xva_vattr.va_mask); 743 744 /* 745 * Do not set ctime (only the file system can do it) 746 */ 747 748 xvattr->xva_vattr.va_mask &= ~AT_CTIME; 749 750 if (smb_attr->sa_mask & SMB_AT_DOSATTR) { 751 752 /* 753 * "|" in the original xva_mask, which contains 754 * AT_XVATTR 755 */ 756 757 xvattr->xva_vattr.va_mask |= xva_mask; 758 759 XVA_SET_REQ(xvattr, XAT_ARCHIVE); 760 XVA_SET_REQ(xvattr, XAT_SYSTEM); 761 XVA_SET_REQ(xvattr, XAT_READONLY); 762 XVA_SET_REQ(xvattr, XAT_HIDDEN); 763 764 /* 765 * smb_attr->sa_dosattr: If a given bit is not set, 766 * that indicates that the corresponding field needs 767 * to be updated with a "0" value. This is done 768 * implicitly as the xoap->xoa_* fields were bzero'd. 769 */ 770 771 if (smb_attr->sa_dosattr & FILE_ATTRIBUTE_ARCHIVE) 772 xoap->xoa_archive = 1; 773 774 if (smb_attr->sa_dosattr & FILE_ATTRIBUTE_SYSTEM) 775 xoap->xoa_system = 1; 776 777 if (smb_attr->sa_dosattr & FILE_ATTRIBUTE_READONLY) 778 xoap->xoa_readonly = 1; 779 780 if (smb_attr->sa_dosattr & FILE_ATTRIBUTE_HIDDEN) 781 xoap->xoa_hidden = 1; 782 } 783 784 if (smb_attr->sa_mask & SMB_AT_CRTIME) { 785 /* 786 * "|" in the original xva_mask, which contains 787 * AT_XVATTR 788 */ 789 790 xvattr->xva_vattr.va_mask |= xva_mask; 791 XVA_SET_REQ(xvattr, XAT_CREATETIME); 792 xoap->xoa_createtime = smb_attr->sa_crtime; 793 } 794 } 795 796 797 /* 798 * smb_vop_readdir() 799 * 800 * Upon return, the "name" field will contain either the on-disk name or, if 801 * it needs mangling or has a case-insensitive collision, the mangled 802 * "shortname." 803 * 804 * vpp is an optional parameter. If non-NULL, it will contain a pointer to 805 * the vnode for the name that is looked up (the vnode will be returned held). 806 * 807 * od_name is an optional parameter (NULL can be passed if the on-disk name 808 * is not needed by the caller). 809 */ 810 811 int 812 smb_vop_readdir(vnode_t *dvp, uint32_t *cookiep, char *name, int *namelen, 813 ino64_t *inop, vnode_t **vpp, char *od_name, int flags, cred_t *cr) 814 { 815 int num_bytes; 816 int error = 0; 817 char *dirbuf = NULL; 818 819 ASSERT(dvp); 820 ASSERT(cookiep); 821 ASSERT(name); 822 ASSERT(namelen); 823 ASSERT(inop); 824 ASSERT(cr); 825 826 if (dvp->v_type != VDIR) { 827 *namelen = 0; 828 return (ENOTDIR); 829 } 830 831 if (vpp) 832 *vpp = NULL; 833 834 dirbuf = kmem_zalloc(SMB_MINLEN_RDDIR_BUF, KM_SLEEP); 835 num_bytes = SMB_MINLEN_RDDIR_BUF; 836 837 /* 838 * The goal is to retrieve the first valid entry from *cookiep 839 * forward. smb_vop_readdir_readpage() collects an 840 * SMB_MINLEN_RDDIR_BUF-size "page" of directory entry information. 841 * smb_vop_readdir_entry() attempts to find the first valid entry 842 * in that page. 843 */ 844 845 while ((error = smb_vop_readdir_readpage(dvp, dirbuf, *cookiep, 846 &num_bytes, cr)) == 0) { 847 848 if (num_bytes <= 0) 849 break; 850 851 name[0] = '\0'; 852 853 error = smb_vop_readdir_entry(dvp, cookiep, name, namelen, 854 inop, vpp, od_name, flags, cr, dirbuf, num_bytes); 855 856 if (error) 857 break; 858 859 if (*name) 860 break; 861 862 bzero(dirbuf, SMB_MINLEN_RDDIR_BUF); 863 num_bytes = SMB_MINLEN_RDDIR_BUF; 864 } 865 866 867 if (error) { 868 kmem_free(dirbuf, SMB_MINLEN_RDDIR_BUF); 869 *namelen = 0; 870 return (error); 871 } 872 873 if (num_bytes == 0) { /* EOF */ 874 kmem_free(dirbuf, SMB_MINLEN_RDDIR_BUF); 875 *cookiep = SMB_EOF; 876 *namelen = 0; 877 return (0); 878 } 879 880 kmem_free(dirbuf, SMB_MINLEN_RDDIR_BUF); 881 return (0); 882 } 883 884 /* 885 * smb_vop_readdir_readpage() 886 * 887 * Collects an SMB_MINLEN_RDDIR_BUF "page" of directory entries. (The 888 * directory entries are returned in an fs-independent format by the 889 * underlying file system. That is, the "page" of information returned is 890 * not literally stored on-disk in the format returned.) 891 * 892 * Much of the following is borrowed from getdents64() 893 * 894 * MAXGETDENTS_SIZE is defined in getdents.c 895 */ 896 897 #define MAXGETDENTS_SIZE (64 * 1024) 898 899 static int 900 smb_vop_readdir_readpage(vnode_t *vp, void *buf, uint32_t offset, int *count, 901 cred_t *cr) 902 { 903 int error = 0; 904 int rdirent_flags = 0; 905 int sink; 906 struct uio auio; 907 struct iovec aiov; 908 909 if (vp->v_type != VDIR) 910 return (ENOTDIR); 911 912 if (vfs_has_feature(vp->v_vfsp, VFSFT_DIRENTFLAGS)) { 913 /* 914 * Setting V_RDDIR_ENTFLAGS will cause the buffer to 915 * be filled with edirent_t structures (instead of 916 * dirent64_t structures). 917 */ 918 rdirent_flags = V_RDDIR_ENTFLAGS; 919 920 if (*count < sizeof (edirent_t)) 921 return (EINVAL); 922 } else { 923 if (*count < sizeof (dirent64_t)) 924 return (EINVAL); 925 } 926 927 if (*count > MAXGETDENTS_SIZE) 928 *count = MAXGETDENTS_SIZE; 929 930 aiov.iov_base = buf; 931 aiov.iov_len = *count; 932 auio.uio_iov = &aiov; 933 auio.uio_iovcnt = 1; 934 auio.uio_loffset = (uint64_t)offset; 935 auio.uio_segflg = UIO_SYSSPACE; 936 auio.uio_resid = *count; 937 auio.uio_fmode = 0; 938 939 (void) VOP_RWLOCK(vp, V_WRITELOCK_FALSE, &smb_ct); 940 error = VOP_READDIR(vp, &auio, cr, &sink, &smb_ct, rdirent_flags); 941 VOP_RWUNLOCK(vp, V_WRITELOCK_FALSE, &smb_ct); 942 943 if (error) { 944 if (error == ENOENT) { 945 /* Fake EOF if offset is bad due to dropping of lock */ 946 *count = 0; 947 return (0); 948 } else { 949 return (error); 950 } 951 } 952 953 /* 954 * Windows cannot handle an offset > SMB_EOF. 955 * Pretend we are at EOF. 956 */ 957 958 if (auio.uio_loffset > SMB_EOF) { 959 *count = 0; 960 return (0); 961 } 962 963 *count = *count - auio.uio_resid; 964 return (0); 965 } 966 967 /* 968 * smb_vop_readdir_entry() 969 * 970 * This function retrieves the first valid entry from the 971 * SMB_MINLEN_RDDIR_BUF-sized buffer returned by smb_vop_readdir_readpage() 972 * to smb_vop_readdir(). 973 * 974 * Both dirent64_t and edirent_t structures need to be handled. The former is 975 * needed for file systems that do not support VFSFT_DIRENTFLAGS. The latter 976 * is required for proper handling of case collisions on file systems that 977 * support case-insensitivity. edirent_t structures are also used for 978 * case-sensitive file systems if VFSFT_DIRENTFLAGS is supported. 979 */ 980 981 static int 982 smb_vop_readdir_entry( 983 vnode_t *dvp, 984 uint32_t *cookiep, 985 char *name, 986 int *namelen, 987 ino64_t *inop, 988 vnode_t **vpp, 989 char *od_name, 990 int flags, 991 cred_t *cr, 992 char *dirbuf, 993 int num_bytes) 994 { 995 uint32_t next_cookie; 996 int ebufsize; 997 int error = 0; 998 int len; 999 int rc; 1000 char shortname[SMB_SHORTNAMELEN]; 1001 char name83[SMB_SHORTNAMELEN]; 1002 char *ebuf = NULL; 1003 edirent_t *edp; 1004 dirent64_t *dp = NULL; 1005 vnode_t *vp = NULL; 1006 1007 ASSERT(dirbuf); 1008 1009 /* 1010 * Use edirent_t structure for both 1011 */ 1012 if (vfs_has_feature(dvp->v_vfsp, VFSFT_DIRENTFLAGS)) { 1013 /*LINTED E_BAD_PTR_CAST_ALIGN*/ 1014 edp = (edirent_t *)dirbuf; 1015 } else { 1016 /*LINTED E_BAD_PTR_CAST_ALIGN*/ 1017 dp = (dirent64_t *)dirbuf; 1018 ebufsize = EDIRENT_RECLEN(MAXNAMELEN); 1019 ebuf = kmem_zalloc(ebufsize, KM_SLEEP); 1020 /*LINTED E_BAD_PTR_CAST_ALIGN*/ 1021 edp = (edirent_t *)ebuf; 1022 } 1023 1024 while (edp) { 1025 if (dp) 1026 DP_TO_EDP(dp, edp); 1027 1028 next_cookie = (uint32_t)edp->ed_off; 1029 if (edp->ed_ino == 0) { 1030 *cookiep = next_cookie; 1031 1032 if (dp) { 1033 /*LINTED E_BAD_PTR_CAST_ALIGN*/ 1034 DP_ADVANCE(dp, dirbuf, num_bytes); 1035 if (dp == NULL) 1036 edp = NULL; 1037 } else { 1038 /*LINTED E_BAD_PTR_CAST_ALIGN*/ 1039 EDP_ADVANCE(edp, dirbuf, num_bytes); 1040 } 1041 continue; 1042 } 1043 1044 len = strlen(edp->ed_name); 1045 1046 if (*namelen < len) { 1047 *namelen = 0; 1048 1049 if (ebuf) 1050 kmem_free(ebuf, ebufsize); 1051 1052 return (EOVERFLOW); 1053 } 1054 1055 /* 1056 * Do not pass SMB_IGNORE_CASE to smb_vop_lookup 1057 */ 1058 1059 error = smb_vop_lookup(dvp, edp->ed_name, vpp ? vpp : &vp, 1060 od_name, 0, NULL, cr); 1061 1062 if (error) { 1063 if (error == ENOENT) { 1064 *cookiep = (uint32_t)next_cookie; 1065 1066 if (dp) { 1067 /*LINTED E_BAD_PTR_CAST_ALIGN*/ 1068 DP_ADVANCE(dp, dirbuf, num_bytes); 1069 if (dp == NULL) 1070 edp = NULL; 1071 } else { 1072 /*LINTED E_BAD_PTR_CAST_ALIGN*/ 1073 EDP_ADVANCE(edp, dirbuf, num_bytes); 1074 } 1075 continue; 1076 } 1077 1078 1079 *namelen = 0; 1080 1081 if (ebuf) 1082 kmem_free(ebuf, ebufsize); 1083 1084 return (error); 1085 } 1086 1087 if ((flags & SMB_IGNORE_CASE) && ED_CASE_CONFLICTS(edp)) { 1088 rc = smb_mangle_name(edp->ed_ino, edp->ed_name, 1089 shortname, name83, 1); 1090 1091 if (rc == 1) { /* success */ 1092 (void) strlcpy(name, shortname, *namelen + 1); 1093 *namelen = strlen(shortname); 1094 } else { 1095 (void) strlcpy(name, edp->ed_name, 1096 *namelen + 1); 1097 name[*namelen] = '\0'; 1098 } 1099 1100 } else { 1101 (void) strlcpy(name, edp->ed_name, *namelen + 1); 1102 *namelen = len; 1103 } 1104 1105 if (vpp == NULL) 1106 VN_RELE(vp); 1107 1108 if (inop) 1109 *inop = edp->ed_ino; 1110 1111 *cookiep = (uint32_t)next_cookie; 1112 break; 1113 } 1114 1115 if (ebuf) 1116 kmem_free(ebuf, ebufsize); 1117 1118 return (error); 1119 } 1120 1121 /* 1122 * smb_sa_to_va_mask 1123 * 1124 * Set va_mask by running through the SMB_AT_* #define's and 1125 * setting those bits that correspond to the SMB_AT_* bits 1126 * set in sa_mask. 1127 */ 1128 1129 void 1130 smb_sa_to_va_mask(uint_t sa_mask, uint_t *va_maskp) 1131 { 1132 int i; 1133 uint_t smask; 1134 1135 smask = (sa_mask); 1136 for (i = SMB_AT_TYPE; (i < SMB_AT_MAX) && (smask != 0); ++i) { 1137 if (smask & 1) 1138 *(va_maskp) |= smb_attrmap[i]; 1139 1140 smask >>= 1; 1141 } 1142 } 1143 1144 /* 1145 * smb_vop_getdents() 1146 * 1147 * Upon success, the smb_node corresponding to each entry returned will 1148 * have a reference taken on it. These will be released in 1149 * smb_trans2_find_get_dents(). 1150 * 1151 * If an error is returned from this routine, a list of already processed 1152 * entries will be returned. The smb_nodes corresponding to these entries 1153 * will be referenced, and will be released in smb_trans2_find_get_dents(). 1154 * 1155 * The returned dp->d_name field will contain either the on-disk name or, if 1156 * it needs mangling or has a case-insensitive collision, the mangled 1157 * "shortname." In this case, the on-disk name can be retrieved from the 1158 * smb_node's od_name (the smb_node is passed to smb_gather_dents_info()). 1159 */ 1160 1161 int /*ARGSUSED*/ 1162 smb_vop_getdents( 1163 smb_node_t *dir_snode, 1164 uint32_t *cookiep, 1165 uint64_t *verifierp, 1166 int32_t *dircountp, 1167 char *arg, 1168 char *pattern, 1169 uint32_t flags, 1170 smb_request_t *sr, 1171 cred_t *cr) 1172 { 1173 int error = 0; 1174 int maxentries; 1175 int num_bytes; 1176 int resid; 1177 char *dirbuf = NULL; 1178 vnode_t *dvp; 1179 /*LINTED E_BAD_PTR_CAST_ALIGN*/ 1180 smb_dent_info_hdr_t *ihdr = (smb_dent_info_hdr_t *)arg; 1181 1182 dvp = dir_snode->vp; 1183 1184 resid = ihdr->uio.uio_resid; 1185 maxentries = resid / SMB_MAX_DENT_INFO_SIZE; 1186 1187 bzero(ihdr->iov->iov_base, resid); 1188 1189 dirbuf = kmem_alloc(SMB_MINLEN_RDDIR_BUF, KM_SLEEP); 1190 1191 while (maxentries) { 1192 1193 bzero(dirbuf, SMB_MINLEN_RDDIR_BUF); 1194 1195 num_bytes = SMB_MINLEN_RDDIR_BUF; 1196 error = smb_vop_readdir_readpage(dvp, dirbuf, *cookiep, 1197 &num_bytes, cr); 1198 1199 if (error || (num_bytes <= 0)) 1200 break; 1201 1202 error = smb_vop_getdents_entries(dir_snode, cookiep, dircountp, 1203 arg, flags, sr, cr, dirbuf, &maxentries, num_bytes, 1204 pattern); 1205 1206 if (error) 1207 goto out; 1208 } 1209 1210 if (num_bytes < 0) { 1211 error = -1; 1212 } else if (num_bytes == 0) { 1213 *cookiep = SMB_EOF; 1214 error = 0; 1215 } else { 1216 error = 0; 1217 } 1218 1219 out: 1220 if (dirbuf) 1221 kmem_free(dirbuf, SMB_MINLEN_RDDIR_BUF); 1222 1223 return (error); 1224 } 1225 1226 /* 1227 * smb_vop_getdents_entries() 1228 * 1229 * This function retrieves names from the SMB_MINLEN_RDDIR_BUF-sized buffer 1230 * returned by smb_vop_readdir_readpage() to smb_vop_getdents(). 1231 * 1232 * Both dirent64_t and edirent_t structures need to be handled. The former is 1233 * needed for file systems that do not support VFSFT_DIRENTFLAGS. The latter 1234 * is required for properly handling case collisions on file systems that 1235 * support case-insensitivity. edirent_t is also used on case-sensitive 1236 * file systems where VFSFT_DIRENTFLAGS is available. 1237 */ 1238 1239 static int 1240 smb_vop_getdents_entries( 1241 smb_node_t *dir_snode, 1242 uint32_t *cookiep, 1243 int32_t *dircountp, 1244 char *arg, 1245 uint32_t flags, 1246 smb_request_t *sr, 1247 cred_t *cr, 1248 char *dirbuf, 1249 int *maxentries, 1250 int num_bytes, 1251 char *pattern) 1252 { 1253 uint32_t next_cookie; 1254 int ebufsize; 1255 char *tmp_name; 1256 int error; 1257 int rc; 1258 char shortname[SMB_SHORTNAMELEN]; 1259 char name83[SMB_SHORTNAMELEN]; 1260 char *ebuf = NULL; 1261 dirent64_t *dp = NULL; 1262 edirent_t *edp; 1263 smb_node_t *ret_snode; 1264 smb_attr_t ret_attr; 1265 vnode_t *dvp; 1266 vnode_t *fvp; 1267 1268 ASSERT(dirbuf); 1269 1270 dvp = dir_snode->vp; 1271 1272 if (vfs_has_feature(dvp->v_vfsp, VFSFT_DIRENTFLAGS)) { 1273 /*LINTED E_BAD_PTR_CAST_ALIGN*/ 1274 edp = (edirent_t *)dirbuf; 1275 } else { 1276 /*LINTED E_BAD_PTR_CAST_ALIGN*/ 1277 dp = (dirent64_t *)dirbuf; 1278 ebufsize = EDIRENT_RECLEN(MAXNAMELEN); 1279 ebuf = kmem_zalloc(ebufsize, KM_SLEEP); 1280 /*LINTED E_BAD_PTR_CAST_ALIGN*/ 1281 edp = (edirent_t *)ebuf; 1282 } 1283 1284 while (edp) { 1285 if (dp) 1286 DP_TO_EDP(dp, edp); 1287 1288 if (*maxentries == 0) 1289 break; 1290 1291 next_cookie = (uint32_t)edp->ed_off; 1292 1293 if (edp->ed_ino == 0) { 1294 *cookiep = next_cookie; 1295 if (dp) { 1296 /*LINTED E_BAD_PTR_CAST_ALIGN*/ 1297 DP_ADVANCE(dp, dirbuf, num_bytes); 1298 if (dp == NULL) 1299 edp = NULL; 1300 } else { 1301 /*LINTED E_BAD_PTR_CAST_ALIGN*/ 1302 EDP_ADVANCE(edp, dirbuf, num_bytes); 1303 } 1304 continue; 1305 } 1306 1307 error = smb_vop_lookup(dvp, edp->ed_name, &fvp, 1308 NULL, 0, NULL, cr); 1309 1310 if (error) { 1311 if (error == ENOENT) { 1312 *cookiep = next_cookie; 1313 if (dp) { 1314 /*LINTED E_BAD_PTR_CAST_ALIGN*/ 1315 DP_ADVANCE(dp, dirbuf, 1316 num_bytes); 1317 if (dp == NULL) 1318 edp = NULL; 1319 } else { 1320 /*LINTED E_BAD_PTR_CAST_ALIGN*/ 1321 EDP_ADVANCE(edp, dirbuf, 1322 num_bytes); 1323 } 1324 continue; 1325 } 1326 if (ebuf) 1327 kmem_free(ebuf, ebufsize); 1328 1329 return (error); 1330 } 1331 1332 ret_snode = smb_node_lookup(sr, NULL, cr, fvp, 1333 edp->ed_name, dir_snode, NULL, &ret_attr); 1334 1335 if (ret_snode == NULL) { 1336 VN_RELE(fvp); 1337 1338 if (ebuf) 1339 kmem_free(ebuf, ebufsize); 1340 1341 return (ENOMEM); 1342 } 1343 1344 if (smb_match_name(edp->ed_ino, edp->ed_name, shortname, 1345 name83, pattern, (flags & SMB_IGNORE_CASE))) { 1346 1347 tmp_name = edp->ed_name; 1348 1349 if ((flags & SMB_IGNORE_CASE) && 1350 ED_CASE_CONFLICTS(edp)) { 1351 rc = smb_mangle_name(edp->ed_ino, edp->ed_name, 1352 shortname, name83, 1); 1353 if (rc == 1) 1354 tmp_name = shortname; 1355 } else { 1356 rc = smb_mangle_name(edp->ed_ino, edp->ed_name, 1357 shortname, name83, 0); 1358 } 1359 1360 if (rc != 1) { 1361 (void) strlcpy(shortname, edp->ed_name, 1362 SMB_SHORTNAMELEN); 1363 (void) strlcpy(name83, edp->ed_name, 1364 SMB_SHORTNAMELEN); 1365 shortname[SMB_SHORTNAMELEN - 1] = '\0'; 1366 name83[SMB_SHORTNAMELEN - 1] = '\0'; 1367 } 1368 1369 error = smb_gather_dents_info(arg, edp->ed_ino, 1370 strlen(tmp_name), tmp_name, next_cookie, dircountp, 1371 &ret_attr, ret_snode, shortname, name83); 1372 1373 if (error > 0) { 1374 if (ebuf) 1375 kmem_free(ebuf, ebufsize); 1376 return (error); 1377 } 1378 1379 /* 1380 * Treat errors from smb_gather_dents_info() that are 1381 * < 0 the same as EOF. 1382 */ 1383 if (error < 0) { 1384 if (ebuf) 1385 kmem_free(ebuf, ebufsize); 1386 *maxentries = 0; 1387 return (0); 1388 } 1389 (*maxentries)--; 1390 } else { 1391 smb_node_release(ret_snode); 1392 } 1393 1394 *cookiep = next_cookie; 1395 1396 if (dp) { 1397 /*LINTED E_BAD_PTR_CAST_ALIGN*/ 1398 DP_ADVANCE(dp, dirbuf, num_bytes); 1399 if (dp == NULL) 1400 edp = NULL; 1401 } else { 1402 /*LINTED E_BAD_PTR_CAST_ALIGN*/ 1403 EDP_ADVANCE(edp, dirbuf, num_bytes); 1404 } 1405 } 1406 1407 if (ebuf) 1408 kmem_free(ebuf, ebufsize); 1409 1410 return (0); 1411 } 1412 1413 /* 1414 * smb_vop_stream_lookup() 1415 * 1416 * The name returned in od_name is the on-disk name of the stream with the 1417 * SMB_STREAM_PREFIX stripped off. od_name should be allocated to MAXNAMELEN 1418 * by the caller. 1419 */ 1420 1421 int 1422 smb_vop_stream_lookup( 1423 vnode_t *fvp, 1424 char *stream_name, 1425 vnode_t **vpp, 1426 char *od_name, 1427 vnode_t **xattrdirvpp, 1428 int flags, 1429 vnode_t *rootvp, 1430 cred_t *cr) 1431 { 1432 char *solaris_stream_name; 1433 char *name; 1434 int error; 1435 1436 if ((error = smb_vop_lookup_xattrdir(fvp, xattrdirvpp, 1437 LOOKUP_XATTR | CREATE_XATTR_DIR, cr)) != 0) 1438 return (error); 1439 1440 /* 1441 * Prepend SMB_STREAM_PREFIX to stream name 1442 */ 1443 1444 solaris_stream_name = kmem_alloc(MAXNAMELEN, KM_SLEEP); 1445 (void) sprintf(solaris_stream_name, "%s%s", SMB_STREAM_PREFIX, 1446 stream_name); 1447 1448 /* 1449 * "name" will hold the on-disk name returned from smb_vop_lookup 1450 * for the stream, including the SMB_STREAM_PREFIX. 1451 */ 1452 1453 name = kmem_zalloc(MAXNAMELEN, KM_SLEEP); 1454 1455 if ((error = smb_vop_lookup(*xattrdirvpp, solaris_stream_name, vpp, 1456 name, flags, rootvp, cr)) != 0) { 1457 VN_RELE(*xattrdirvpp); 1458 } else { 1459 (void) strlcpy(od_name, &(name[SMB_STREAM_PREFIX_LEN]), 1460 MAXNAMELEN); 1461 } 1462 1463 kmem_free(solaris_stream_name, MAXNAMELEN); 1464 kmem_free(name, MAXNAMELEN); 1465 1466 return (error); 1467 } 1468 1469 int 1470 smb_vop_stream_create(vnode_t *fvp, char *stream_name, smb_attr_t *attr, 1471 vnode_t **vpp, vnode_t **xattrdirvpp, int flags, cred_t *cr) 1472 { 1473 char *solaris_stream_name; 1474 int error; 1475 1476 if ((error = smb_vop_lookup_xattrdir(fvp, xattrdirvpp, 1477 LOOKUP_XATTR | CREATE_XATTR_DIR, cr)) != 0) 1478 return (error); 1479 1480 /* 1481 * Prepend SMB_STREAM_PREFIX to stream name 1482 */ 1483 1484 solaris_stream_name = kmem_alloc(MAXNAMELEN, KM_SLEEP); 1485 (void) sprintf(solaris_stream_name, "%s%s", SMB_STREAM_PREFIX, 1486 stream_name); 1487 1488 if ((error = smb_vop_create(*xattrdirvpp, solaris_stream_name, attr, 1489 vpp, flags, cr, NULL)) != 0) 1490 VN_RELE(*xattrdirvpp); 1491 1492 kmem_free(solaris_stream_name, MAXNAMELEN); 1493 1494 return (error); 1495 } 1496 1497 int 1498 smb_vop_stream_remove(vnode_t *vp, char *stream_name, int flags, cred_t *cr) 1499 { 1500 char *solaris_stream_name; 1501 vnode_t *xattrdirvp; 1502 int error; 1503 1504 error = smb_vop_lookup_xattrdir(vp, &xattrdirvp, LOOKUP_XATTR, cr); 1505 if (error != 0) 1506 return (error); 1507 1508 /* 1509 * Prepend SMB_STREAM_PREFIX to stream name 1510 */ 1511 1512 solaris_stream_name = kmem_alloc(MAXNAMELEN, KM_SLEEP); 1513 (void) sprintf(solaris_stream_name, "%s%s", SMB_STREAM_PREFIX, 1514 stream_name); 1515 1516 /* XXX might have to use kcred */ 1517 error = smb_vop_remove(xattrdirvp, solaris_stream_name, flags, cr); 1518 1519 kmem_free(solaris_stream_name, MAXNAMELEN); 1520 1521 return (error); 1522 } 1523 1524 /* 1525 * smb_vop_stream_readdir() 1526 * 1527 * Note: stream_info.size is not filled in in this routine. 1528 * It needs to be filled in by the caller due to the parameters for getattr. 1529 * 1530 * stream_info.name is set to the on-disk stream name with the SMB_STREAM_PREFIX 1531 * removed. 1532 */ 1533 1534 int 1535 smb_vop_stream_readdir(vnode_t *fvp, uint32_t *cookiep, 1536 struct fs_stream_info *stream_info, vnode_t **vpp, vnode_t **xattrdirvpp, 1537 int flags, cred_t *cr) 1538 { 1539 int nsize; 1540 int error = 0; 1541 ino64_t ino; 1542 char *tmp_name; 1543 vnode_t *xattrdirvp; 1544 vnode_t *vp; 1545 1546 if ((error = smb_vop_lookup_xattrdir(fvp, &xattrdirvp, LOOKUP_XATTR, 1547 cr)) != 0) 1548 return (error); 1549 1550 bzero(stream_info->name, sizeof (stream_info->name)); 1551 stream_info->size = 0; 1552 1553 tmp_name = kmem_zalloc(MAXNAMELEN, KM_SLEEP); 1554 1555 for (;;) { 1556 nsize = MAXNAMELEN-1; 1557 error = smb_vop_readdir(xattrdirvp, cookiep, tmp_name, &nsize, 1558 &ino, &vp, NULL, flags, cr); 1559 1560 if (error || (*cookiep == SMB_EOF)) 1561 break; 1562 1563 if (strncmp(tmp_name, SMB_STREAM_PREFIX, 1564 SMB_STREAM_PREFIX_LEN)) { 1565 VN_RELE(vp); 1566 continue; 1567 } 1568 1569 tmp_name[nsize] = '\0'; 1570 (void) strlcpy(stream_info->name, 1571 &(tmp_name[SMB_STREAM_PREFIX_LEN]), 1572 sizeof (stream_info->name)); 1573 1574 nsize -= SMB_STREAM_PREFIX_LEN; 1575 break; 1576 } 1577 1578 if ((error == 0) && nsize) { 1579 if (vpp) 1580 *vpp = vp; 1581 else 1582 VN_RELE(vp); 1583 1584 if (xattrdirvpp) 1585 *xattrdirvpp = xattrdirvp; 1586 else 1587 VN_RELE(xattrdirvp); 1588 1589 } else { 1590 VN_RELE(xattrdirvp); 1591 } 1592 1593 kmem_free(tmp_name, MAXNAMELEN); 1594 1595 return (error); 1596 } 1597 1598 int 1599 smb_vop_lookup_xattrdir(vnode_t *fvp, vnode_t **xattrdirvpp, int flags, 1600 cred_t *cr) 1601 { 1602 int error; 1603 1604 error = VOP_LOOKUP(fvp, "", xattrdirvpp, NULL, flags, NULL, cr, 1605 &smb_ct, NULL, NULL); 1606 return (error); 1607 } 1608 1609 /* 1610 * smb_vop_traverse_check() 1611 * 1612 * This function checks to see if the passed-in vnode has a file system 1613 * mounted on it. If it does, the mount point is "traversed" and the 1614 * vnode for the root of the file system is returned. 1615 */ 1616 1617 int 1618 smb_vop_traverse_check(vnode_t **vpp) 1619 { 1620 int error; 1621 1622 if (vn_mountedvfs(*vpp) == 0) 1623 return (0); 1624 1625 /* 1626 * traverse() may return a different held vnode, even in the error case. 1627 * If it returns a different vnode, it will have released the original. 1628 */ 1629 1630 error = traverse(vpp); 1631 1632 return (error); 1633 } 1634 1635 int /*ARGSUSED*/ 1636 smb_vop_statfs(vnode_t *vp, struct statvfs64 *statp, cred_t *cr) 1637 { 1638 int error; 1639 1640 error = VFS_STATVFS(vp->v_vfsp, statp); 1641 1642 return (error); 1643 } 1644 1645 /* 1646 * smb_vop_acl_read 1647 * 1648 * Reads the ACL of the specified file into 'aclp'. 1649 * acl_type is the type of ACL which the filesystem supports. 1650 * 1651 * Caller has to free the allocated memory for aclp by calling 1652 * acl_free(). 1653 */ 1654 int 1655 smb_vop_acl_read(vnode_t *vp, acl_t **aclp, int flags, acl_type_t acl_type, 1656 cred_t *cr) 1657 { 1658 int error; 1659 vsecattr_t vsecattr; 1660 1661 ASSERT(vp); 1662 ASSERT(aclp); 1663 1664 *aclp = NULL; 1665 bzero(&vsecattr, sizeof (vsecattr_t)); 1666 1667 switch (acl_type) { 1668 case ACLENT_T: 1669 vsecattr.vsa_mask = VSA_ACL | VSA_ACLCNT | VSA_DFACL | 1670 VSA_DFACLCNT; 1671 break; 1672 1673 case ACE_T: 1674 vsecattr.vsa_mask = VSA_ACE | VSA_ACECNT | VSA_ACE_ACLFLAGS; 1675 break; 1676 1677 default: 1678 return (EINVAL); 1679 } 1680 1681 if (error = VOP_GETSECATTR(vp, &vsecattr, flags, cr, &smb_ct)) 1682 return (error); 1683 1684 *aclp = smb_fsacl_from_vsa(&vsecattr, acl_type); 1685 if (vp->v_type == VDIR) 1686 (*aclp)->acl_flags |= ACL_IS_DIR; 1687 1688 return (0); 1689 } 1690 1691 /* 1692 * smb_vop_acl_write 1693 * 1694 * Writes the given ACL in aclp for the specified file. 1695 */ 1696 int 1697 smb_vop_acl_write(vnode_t *vp, acl_t *aclp, int flags, cred_t *cr) 1698 { 1699 int error; 1700 vsecattr_t vsecattr; 1701 int aclbsize; 1702 1703 ASSERT(vp); 1704 ASSERT(aclp); 1705 1706 error = smb_fsacl_to_vsa(aclp, &vsecattr, &aclbsize); 1707 1708 if (error == 0) { 1709 (void) VOP_RWLOCK(vp, V_WRITELOCK_TRUE, &smb_ct); 1710 error = VOP_SETSECATTR(vp, &vsecattr, flags, cr, &smb_ct); 1711 VOP_RWUNLOCK(vp, V_WRITELOCK_TRUE, &smb_ct); 1712 } 1713 1714 if (aclbsize && vsecattr.vsa_aclentp) 1715 kmem_free(vsecattr.vsa_aclentp, aclbsize); 1716 1717 return (error); 1718 } 1719 1720 /* 1721 * smb_vop_acl_type 1722 * 1723 * Determines the ACL type for the given vnode. 1724 * ACLENT_T is a Posix ACL and ACE_T is a ZFS ACL. 1725 */ 1726 acl_type_t 1727 smb_vop_acl_type(vnode_t *vp) 1728 { 1729 int error; 1730 ulong_t whichacl; 1731 1732 error = VOP_PATHCONF(vp, _PC_ACL_ENABLED, &whichacl, kcred, NULL); 1733 if (error != 0) { 1734 /* 1735 * If we got an error, then the filesystem 1736 * likely does not understand the _PC_ACL_ENABLED 1737 * pathconf. In this case, we fall back to trying 1738 * POSIX-draft (aka UFS-style) ACLs. 1739 */ 1740 whichacl = _ACL_ACLENT_ENABLED; 1741 } 1742 1743 if (!(whichacl & (_ACL_ACE_ENABLED | _ACL_ACLENT_ENABLED))) { 1744 /* 1745 * If the file system supports neither ACE nor 1746 * ACLENT ACLs we will fall back to UFS-style ACLs 1747 * like we did above if there was an error upon 1748 * calling VOP_PATHCONF. 1749 * 1750 * ACE and ACLENT type ACLs are the only interfaces 1751 * supported thus far. If any other bits are set on 1752 * 'whichacl' upon return from VOP_PATHCONF, we will 1753 * ignore them. 1754 */ 1755 whichacl = _ACL_ACLENT_ENABLED; 1756 } 1757 1758 if (whichacl == _ACL_ACLENT_ENABLED) 1759 return (ACLENT_T); 1760 1761 return (ACE_T); 1762 } 1763 1764 static int zfs_perms[] = { 1765 ACE_READ_DATA, ACE_WRITE_DATA, ACE_APPEND_DATA, ACE_READ_NAMED_ATTRS, 1766 ACE_WRITE_NAMED_ATTRS, ACE_EXECUTE, ACE_DELETE_CHILD, 1767 ACE_READ_ATTRIBUTES, ACE_WRITE_ATTRIBUTES, ACE_DELETE, ACE_READ_ACL, 1768 ACE_WRITE_ACL, ACE_WRITE_OWNER, ACE_SYNCHRONIZE 1769 }; 1770 1771 static int unix_perms[] = { VREAD, VWRITE, VEXEC }; 1772 /* 1773 * smb_vop_eaccess 1774 * 1775 * Returns the effective permission of the given credential for the 1776 * specified object. 1777 * 1778 * This is just a workaround. We need VFS/FS support for this. 1779 */ 1780 void 1781 smb_vop_eaccess(vnode_t *vp, int *mode, int flags, vnode_t *dir_vp, cred_t *cr) 1782 { 1783 int error, i; 1784 int pnum; 1785 1786 *mode = 0; 1787 1788 if (flags == V_ACE_MASK) { 1789 pnum = sizeof (zfs_perms) / sizeof (int); 1790 1791 for (i = 0; i < pnum; i++) { 1792 error = smb_vop_access(vp, zfs_perms[i], flags, 1793 dir_vp, cr); 1794 if (error == 0) 1795 *mode |= zfs_perms[i]; 1796 } 1797 } else { 1798 pnum = sizeof (unix_perms) / sizeof (int); 1799 1800 for (i = 0; i < pnum; i++) { 1801 error = smb_vop_access(vp, unix_perms[i], flags, 1802 dir_vp, cr); 1803 if (error == 0) 1804 *mode |= unix_perms[i]; 1805 } 1806 } 1807 } 1808 1809 /* 1810 * smb_vop_shrlock() 1811 * 1812 * See comments for smb_fsop_shrlock() 1813 */ 1814 1815 int 1816 smb_vop_shrlock(vnode_t *vp, uint32_t uniq_fid, uint32_t desired_access, 1817 uint32_t share_access, cred_t *cr) 1818 { 1819 struct shrlock shr; 1820 struct shr_locowner shr_own; 1821 short new_access = 0; 1822 short deny = 0; 1823 int flag = 0; 1824 int cmd; 1825 1826 cmd = (nbl_need_check(vp)) ? F_SHARE_NBMAND : F_SHARE; 1827 1828 /* 1829 * Check if this is a metadata access 1830 */ 1831 1832 if ((desired_access & FILE_DATA_ALL) == 0) { 1833 new_access |= F_MDACC; 1834 } else { 1835 if (desired_access & (ACE_READ_DATA | ACE_EXECUTE)) { 1836 new_access |= F_RDACC; 1837 flag |= FREAD; 1838 } 1839 1840 if (desired_access & (ACE_WRITE_DATA | ACE_APPEND_DATA | 1841 ACE_ADD_FILE)) { 1842 new_access |= F_WRACC; 1843 flag |= FWRITE; 1844 } 1845 1846 if (SMB_DENY_READ(share_access)) { 1847 deny |= F_RDDNY; 1848 } 1849 1850 if (SMB_DENY_WRITE(share_access)) { 1851 deny |= F_WRDNY; 1852 } 1853 1854 if (cmd == F_SHARE_NBMAND) { 1855 if (desired_access & ACE_DELETE) 1856 new_access |= F_RMACC; 1857 1858 if (SMB_DENY_DELETE(share_access)) { 1859 deny |= F_RMDNY; 1860 } 1861 } 1862 } 1863 1864 shr.s_access = new_access; 1865 shr.s_deny = deny; 1866 shr.s_sysid = smb_ct.cc_sysid; 1867 shr.s_pid = uniq_fid; 1868 shr.s_own_len = sizeof (shr_own); 1869 shr.s_owner = (caddr_t)&shr_own; 1870 shr_own.sl_id = shr.s_sysid; 1871 shr_own.sl_pid = shr.s_pid; 1872 1873 return (VOP_SHRLOCK(vp, cmd, &shr, flag, cr, NULL)); 1874 } 1875 1876 int 1877 smb_vop_unshrlock(vnode_t *vp, uint32_t uniq_fid, cred_t *cr) 1878 { 1879 struct shrlock shr; 1880 struct shr_locowner shr_own; 1881 1882 /* 1883 * For s_access and s_deny, we do not need to pass in the original 1884 * values. 1885 */ 1886 1887 shr.s_access = 0; 1888 shr.s_deny = 0; 1889 shr.s_sysid = smb_ct.cc_sysid; 1890 shr.s_pid = uniq_fid; 1891 shr.s_own_len = sizeof (shr_own); 1892 shr.s_owner = (caddr_t)&shr_own; 1893 shr_own.sl_id = shr.s_sysid; 1894 shr_own.sl_pid = shr.s_pid; 1895 1896 return (VOP_SHRLOCK(vp, F_UNSHARE, &shr, 0, cr, NULL)); 1897 } 1898 1899 int 1900 smb_vop_frlock(vnode_t *vp, cred_t *cr, int flag, flock64_t *bf) 1901 { 1902 int cmd = nbl_need_check(vp) ? F_SETLK_NBMAND : F_SETLK; 1903 flk_callback_t flk_cb; 1904 1905 flk_init_callback(&flk_cb, smb_lock_frlock_callback, NULL); 1906 1907 return (VOP_FRLOCK(vp, cmd, bf, flag, 0, &flk_cb, cr, &smb_ct)); 1908 } 1909 1910 static callb_cpr_t * 1911 /* ARGSUSED */ 1912 smb_lock_frlock_callback(flk_cb_when_t when, void *error) 1913 { 1914 return (0); 1915 } 1916