1 /*- 2 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD 3 * 4 * Copyright (c) 2000-2001 Boris Popov 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26 * SUCH DAMAGE. 27 * 28 * $FreeBSD$ 29 */ 30 #include <sys/param.h> 31 #include <sys/systm.h> 32 #include <sys/namei.h> 33 #include <sys/kernel.h> 34 #include <sys/proc.h> 35 #include <sys/bio.h> 36 #include <sys/buf.h> 37 #include <sys/fcntl.h> 38 #include <sys/mount.h> 39 #include <sys/unistd.h> 40 #include <sys/vnode.h> 41 #include <sys/limits.h> 42 #include <sys/lockf.h> 43 #include <sys/stat.h> 44 45 #include <vm/vm.h> 46 #include <vm/vm_extern.h> 47 48 #include <netsmb/smb.h> 49 #include <netsmb/smb_conn.h> 50 #include <netsmb/smb_subr.h> 51 52 #include <fs/smbfs/smbfs.h> 53 #include <fs/smbfs/smbfs_node.h> 54 #include <fs/smbfs/smbfs_subr.h> 55 56 /* 57 * Prototypes for SMBFS vnode operations 58 */ 59 static vop_create_t smbfs_create; 60 static vop_mknod_t smbfs_mknod; 61 static vop_open_t smbfs_open; 62 static vop_close_t smbfs_close; 63 static vop_access_t smbfs_access; 64 static vop_getattr_t smbfs_getattr; 65 static vop_setattr_t smbfs_setattr; 66 static vop_read_t smbfs_read; 67 static vop_write_t smbfs_write; 68 static vop_fsync_t smbfs_fsync; 69 static vop_remove_t smbfs_remove; 70 static vop_link_t smbfs_link; 71 static vop_lookup_t smbfs_lookup; 72 static vop_rename_t smbfs_rename; 73 static vop_mkdir_t smbfs_mkdir; 74 static vop_rmdir_t smbfs_rmdir; 75 static vop_symlink_t smbfs_symlink; 76 static vop_readdir_t smbfs_readdir; 77 static vop_strategy_t smbfs_strategy; 78 static vop_print_t smbfs_print; 79 static vop_pathconf_t smbfs_pathconf; 80 static vop_advlock_t smbfs_advlock; 81 static vop_getextattr_t smbfs_getextattr; 82 83 struct vop_vector smbfs_vnodeops = { 84 .vop_default = &default_vnodeops, 85 86 .vop_access = smbfs_access, 87 .vop_advlock = smbfs_advlock, 88 .vop_close = smbfs_close, 89 .vop_create = smbfs_create, 90 .vop_fsync = smbfs_fsync, 91 .vop_getattr = smbfs_getattr, 92 .vop_getextattr = smbfs_getextattr, 93 .vop_getpages = smbfs_getpages, 94 .vop_inactive = smbfs_inactive, 95 .vop_ioctl = smbfs_ioctl, 96 .vop_link = smbfs_link, 97 .vop_lookup = smbfs_lookup, 98 .vop_mkdir = smbfs_mkdir, 99 .vop_mknod = smbfs_mknod, 100 .vop_open = smbfs_open, 101 .vop_pathconf = smbfs_pathconf, 102 .vop_print = smbfs_print, 103 .vop_putpages = smbfs_putpages, 104 .vop_read = smbfs_read, 105 .vop_readdir = smbfs_readdir, 106 .vop_reclaim = smbfs_reclaim, 107 .vop_remove = smbfs_remove, 108 .vop_rename = smbfs_rename, 109 .vop_rmdir = smbfs_rmdir, 110 .vop_setattr = smbfs_setattr, 111 /* .vop_setextattr = smbfs_setextattr,*/ 112 .vop_strategy = smbfs_strategy, 113 .vop_symlink = smbfs_symlink, 114 .vop_write = smbfs_write, 115 }; 116 VFS_VOP_VECTOR_REGISTER(smbfs_vnodeops); 117 118 static int 119 smbfs_access(struct vop_access_args *ap) 120 { 121 struct vnode *vp = ap->a_vp; 122 accmode_t accmode = ap->a_accmode; 123 mode_t mpmode; 124 struct smbmount *smp = VTOSMBFS(vp); 125 126 SMBVDEBUG("\n"); 127 if ((accmode & VWRITE) && (vp->v_mount->mnt_flag & MNT_RDONLY)) { 128 switch (vp->v_type) { 129 case VREG: case VDIR: case VLNK: 130 return EROFS; 131 default: 132 break; 133 } 134 } 135 mpmode = vp->v_type == VREG ? smp->sm_file_mode : smp->sm_dir_mode; 136 return (vaccess(vp->v_type, mpmode, smp->sm_uid, 137 smp->sm_gid, ap->a_accmode, ap->a_cred)); 138 } 139 140 /* ARGSUSED */ 141 static int 142 smbfs_open(struct vop_open_args *ap) 143 { 144 struct vnode *vp = ap->a_vp; 145 struct smbnode *np = VTOSMB(vp); 146 struct smb_cred *scred; 147 struct vattr vattr; 148 int mode = ap->a_mode; 149 int error, accmode; 150 151 SMBVDEBUG("%s,%d\n", np->n_name, (np->n_flag & NOPEN) != 0); 152 if (vp->v_type != VREG && vp->v_type != VDIR) { 153 SMBFSERR("open eacces vtype=%d\n", vp->v_type); 154 return EACCES; 155 } 156 if (vp->v_type == VDIR) { 157 np->n_flag |= NOPEN; 158 return 0; 159 } 160 if (np->n_flag & NMODIFIED) { 161 if ((error = smbfs_vinvalbuf(vp, ap->a_td)) == EINTR) 162 return error; 163 smbfs_attr_cacheremove(vp); 164 error = VOP_GETATTR(vp, &vattr, ap->a_cred); 165 if (error) 166 return error; 167 np->n_mtime.tv_sec = vattr.va_mtime.tv_sec; 168 } else { 169 error = VOP_GETATTR(vp, &vattr, ap->a_cred); 170 if (error) 171 return error; 172 if (np->n_mtime.tv_sec != vattr.va_mtime.tv_sec) { 173 error = smbfs_vinvalbuf(vp, ap->a_td); 174 if (error == EINTR) 175 return error; 176 np->n_mtime.tv_sec = vattr.va_mtime.tv_sec; 177 } 178 } 179 if ((np->n_flag & NOPEN) != 0) 180 return 0; 181 /* 182 * Use DENYNONE to give unixy semantics of permitting 183 * everything not forbidden by permissions. Ie denial 184 * is up to server with clients/openers needing to use 185 * advisory locks for further control. 186 */ 187 accmode = SMB_SM_DENYNONE|SMB_AM_OPENREAD; 188 if ((vp->v_mount->mnt_flag & MNT_RDONLY) == 0) 189 accmode = SMB_SM_DENYNONE|SMB_AM_OPENRW; 190 scred = smbfs_malloc_scred(); 191 smb_makescred(scred, ap->a_td, ap->a_cred); 192 error = smbfs_smb_open(np, accmode, scred); 193 if (error) { 194 if (mode & FWRITE) 195 return EACCES; 196 else if ((vp->v_mount->mnt_flag & MNT_RDONLY) == 0) { 197 accmode = SMB_SM_DENYNONE|SMB_AM_OPENREAD; 198 error = smbfs_smb_open(np, accmode, scred); 199 } 200 } 201 if (error == 0) { 202 np->n_flag |= NOPEN; 203 vnode_create_vobject(ap->a_vp, vattr.va_size, ap->a_td); 204 } 205 smbfs_attr_cacheremove(vp); 206 smbfs_free_scred(scred); 207 return error; 208 } 209 210 static int 211 smbfs_close(struct vop_close_args *ap) 212 { 213 struct vnode *vp = ap->a_vp; 214 struct thread *td = ap->a_td; 215 struct smbnode *np = VTOSMB(vp); 216 struct smb_cred *scred; 217 218 if (vp->v_type == VDIR && (np->n_flag & NOPEN) != 0 && 219 np->n_dirseq != NULL) { 220 scred = smbfs_malloc_scred(); 221 smb_makescred(scred, td, ap->a_cred); 222 smbfs_findclose(np->n_dirseq, scred); 223 smbfs_free_scred(scred); 224 np->n_dirseq = NULL; 225 } 226 return 0; 227 } 228 229 /* 230 * smbfs_getattr call from vfs. 231 */ 232 static int 233 smbfs_getattr(struct vop_getattr_args *ap) 234 { 235 struct vnode *vp = ap->a_vp; 236 struct smbnode *np = VTOSMB(vp); 237 struct vattr *va=ap->a_vap; 238 struct smbfattr fattr; 239 struct smb_cred *scred; 240 u_quad_t oldsize; 241 int error; 242 243 SMBVDEBUG("%lx: '%s' %d\n", (long)vp, np->n_name, (vp->v_vflag & VV_ROOT) != 0); 244 error = smbfs_attr_cachelookup(vp, va); 245 if (!error) 246 return 0; 247 SMBVDEBUG("not in the cache\n"); 248 scred = smbfs_malloc_scred(); 249 smb_makescred(scred, curthread, ap->a_cred); 250 oldsize = np->n_size; 251 error = smbfs_smb_lookup(np, NULL, 0, &fattr, scred); 252 if (error) { 253 SMBVDEBUG("error %d\n", error); 254 smbfs_free_scred(scred); 255 return error; 256 } 257 smbfs_attr_cacheenter(vp, &fattr); 258 smbfs_attr_cachelookup(vp, va); 259 if (np->n_flag & NOPEN) 260 np->n_size = oldsize; 261 smbfs_free_scred(scred); 262 return 0; 263 } 264 265 static int 266 smbfs_setattr(struct vop_setattr_args *ap) 267 { 268 struct vnode *vp = ap->a_vp; 269 struct smbnode *np = VTOSMB(vp); 270 struct vattr *vap = ap->a_vap; 271 struct timespec *mtime, *atime; 272 struct smb_cred *scred; 273 struct smb_share *ssp = np->n_mount->sm_share; 274 struct smb_vc *vcp = SSTOVC(ssp); 275 struct thread *td = curthread; 276 u_quad_t tsize = 0; 277 int isreadonly, doclose, error = 0; 278 int old_n_dosattr; 279 280 SMBVDEBUG("\n"); 281 isreadonly = (vp->v_mount->mnt_flag & MNT_RDONLY); 282 /* 283 * Disallow write attempts if the filesystem is mounted read-only. 284 */ 285 if ((vap->va_uid != (uid_t)VNOVAL || vap->va_gid != (gid_t)VNOVAL || 286 vap->va_atime.tv_sec != VNOVAL || vap->va_mtime.tv_sec != VNOVAL || 287 vap->va_mode != (mode_t)VNOVAL || vap->va_flags != VNOVAL) && 288 isreadonly) 289 return EROFS; 290 291 /* 292 * We only support setting four flags. Don't allow setting others. 293 * 294 * We map UF_READONLY to SMB_FA_RDONLY, unlike the MacOS X version 295 * of this code, which maps both UF_IMMUTABLE AND SF_IMMUTABLE to 296 * SMB_FA_RDONLY. The immutable flags have different semantics 297 * than readonly, which is the reason for the difference. 298 */ 299 if (vap->va_flags != VNOVAL) { 300 if (vap->va_flags & ~(UF_HIDDEN|UF_SYSTEM|UF_ARCHIVE| 301 UF_READONLY)) 302 return EINVAL; 303 } 304 305 scred = smbfs_malloc_scred(); 306 smb_makescred(scred, td, ap->a_cred); 307 if (vap->va_size != VNOVAL) { 308 switch (vp->v_type) { 309 case VDIR: 310 error = EISDIR; 311 goto out; 312 case VREG: 313 break; 314 default: 315 error = EINVAL; 316 goto out; 317 } 318 if (isreadonly) { 319 error = EROFS; 320 goto out; 321 } 322 doclose = 0; 323 vnode_pager_setsize(vp, (u_long)vap->va_size); 324 tsize = np->n_size; 325 np->n_size = vap->va_size; 326 if ((np->n_flag & NOPEN) == 0) { 327 error = smbfs_smb_open(np, 328 SMB_SM_DENYNONE|SMB_AM_OPENRW, 329 scred); 330 if (error == 0) 331 doclose = 1; 332 } 333 if (error == 0) 334 error = smbfs_smb_setfsize(np, 335 (int64_t)vap->va_size, scred); 336 if (doclose) 337 smbfs_smb_close(ssp, np->n_fid, NULL, scred); 338 if (error) { 339 np->n_size = tsize; 340 vnode_pager_setsize(vp, (u_long)tsize); 341 goto out; 342 } 343 } 344 if ((vap->va_flags != VNOVAL) || (vap->va_mode != (mode_t)VNOVAL)) { 345 old_n_dosattr = np->n_dosattr; 346 347 if (vap->va_mode != (mode_t)VNOVAL) { 348 if (vap->va_mode & S_IWUSR) 349 np->n_dosattr &= ~SMB_FA_RDONLY; 350 else 351 np->n_dosattr |= SMB_FA_RDONLY; 352 } 353 354 if (vap->va_flags != VNOVAL) { 355 if (vap->va_flags & UF_HIDDEN) 356 np->n_dosattr |= SMB_FA_HIDDEN; 357 else 358 np->n_dosattr &= ~SMB_FA_HIDDEN; 359 360 if (vap->va_flags & UF_SYSTEM) 361 np->n_dosattr |= SMB_FA_SYSTEM; 362 else 363 np->n_dosattr &= ~SMB_FA_SYSTEM; 364 365 if (vap->va_flags & UF_ARCHIVE) 366 np->n_dosattr |= SMB_FA_ARCHIVE; 367 else 368 np->n_dosattr &= ~SMB_FA_ARCHIVE; 369 370 /* 371 * We only support setting the immutable / readonly 372 * bit for regular files. According to comments in 373 * the MacOS X version of this code, supporting the 374 * readonly bit on directories doesn't do the same 375 * thing in Windows as in Unix. 376 */ 377 if (vp->v_type == VREG) { 378 if (vap->va_flags & UF_READONLY) 379 np->n_dosattr |= SMB_FA_RDONLY; 380 else 381 np->n_dosattr &= ~SMB_FA_RDONLY; 382 } 383 } 384 385 if (np->n_dosattr != old_n_dosattr) { 386 error = smbfs_smb_setpattr(np, np->n_dosattr, NULL, scred); 387 if (error) 388 goto out; 389 } 390 } 391 mtime = atime = NULL; 392 if (vap->va_mtime.tv_sec != VNOVAL) 393 mtime = &vap->va_mtime; 394 if (vap->va_atime.tv_sec != VNOVAL) 395 atime = &vap->va_atime; 396 if (mtime != atime) { 397 if (vap->va_vaflags & VA_UTIMES_NULL) { 398 error = VOP_ACCESS(vp, VADMIN, ap->a_cred, td); 399 if (error) 400 error = VOP_ACCESS(vp, VWRITE, ap->a_cred, td); 401 } else 402 error = VOP_ACCESS(vp, VADMIN, ap->a_cred, td); 403 #if 0 404 if (mtime == NULL) 405 mtime = &np->n_mtime; 406 if (atime == NULL) 407 atime = &np->n_atime; 408 #endif 409 /* 410 * If file is opened, then we can use handle based calls. 411 * If not, use path based ones. 412 */ 413 if ((np->n_flag & NOPEN) == 0) { 414 if (vcp->vc_flags & SMBV_WIN95) { 415 error = VOP_OPEN(vp, FWRITE, ap->a_cred, td, 416 NULL); 417 if (!error) { 418 /* error = smbfs_smb_setfattrNT(np, 0, 419 mtime, atime, scred); 420 VOP_GETATTR(vp, &vattr, ap->a_cred); */ 421 if (mtime) 422 np->n_mtime = *mtime; 423 VOP_CLOSE(vp, FWRITE, ap->a_cred, td); 424 } 425 } else if ((vcp->vc_sopt.sv_caps & SMB_CAP_NT_SMBS)) { 426 error = smbfs_smb_setptime2(np, mtime, atime, 0, scred); 427 /* error = smbfs_smb_setpattrNT(np, 0, mtime, atime, scred);*/ 428 } else if (SMB_DIALECT(vcp) >= SMB_DIALECT_LANMAN2_0) { 429 error = smbfs_smb_setptime2(np, mtime, atime, 0, scred); 430 } else { 431 error = smbfs_smb_setpattr(np, 0, mtime, scred); 432 } 433 } else { 434 if (vcp->vc_sopt.sv_caps & SMB_CAP_NT_SMBS) { 435 error = smbfs_smb_setfattrNT(np, 0, mtime, atime, scred); 436 } else if (SMB_DIALECT(vcp) >= SMB_DIALECT_LANMAN1_0) { 437 error = smbfs_smb_setftime(np, mtime, atime, scred); 438 } else { 439 /* 440 * I have no idea how to handle this for core 441 * level servers. The possible solution is to 442 * update mtime after file is closed. 443 */ 444 SMBERROR("can't update times on an opened file\n"); 445 } 446 } 447 } 448 /* 449 * Invalidate attribute cache in case if server doesn't set 450 * required attributes. 451 */ 452 smbfs_attr_cacheremove(vp); /* invalidate cache */ 453 VOP_GETATTR(vp, vap, ap->a_cred); 454 np->n_mtime.tv_sec = vap->va_mtime.tv_sec; 455 out: 456 smbfs_free_scred(scred); 457 return error; 458 } 459 /* 460 * smbfs_read call. 461 */ 462 static int 463 smbfs_read(struct vop_read_args *ap) 464 { 465 struct vnode *vp = ap->a_vp; 466 struct uio *uio = ap->a_uio; 467 468 SMBVDEBUG("\n"); 469 if (vp->v_type != VREG && vp->v_type != VDIR) 470 return EPERM; 471 return smbfs_readvnode(vp, uio, ap->a_cred); 472 } 473 474 static int 475 smbfs_write(struct vop_write_args *ap) 476 { 477 struct vnode *vp = ap->a_vp; 478 struct uio *uio = ap->a_uio; 479 480 SMBVDEBUG("%d,ofs=%jd,sz=%zd\n",vp->v_type, (intmax_t)uio->uio_offset, 481 uio->uio_resid); 482 if (vp->v_type != VREG) 483 return (EPERM); 484 return smbfs_writevnode(vp, uio, ap->a_cred,ap->a_ioflag); 485 } 486 /* 487 * smbfs_create call 488 * Create a regular file. On entry the directory to contain the file being 489 * created is locked. We must release before we return. We must also free 490 * the pathname buffer pointed at by cnp->cn_pnbuf, always on error. 491 */ 492 static int 493 smbfs_create(struct vop_create_args *ap) 494 { 495 struct vnode *dvp = ap->a_dvp; 496 struct vattr *vap = ap->a_vap; 497 struct vnode **vpp=ap->a_vpp; 498 struct componentname *cnp = ap->a_cnp; 499 struct smbnode *dnp = VTOSMB(dvp); 500 struct vnode *vp; 501 struct vattr vattr; 502 struct smbfattr fattr; 503 struct smb_cred *scred; 504 char *name = cnp->cn_nameptr; 505 int nmlen = cnp->cn_namelen; 506 int error; 507 508 SMBVDEBUG("\n"); 509 *vpp = NULL; 510 if (vap->va_type != VREG) 511 return EOPNOTSUPP; 512 if ((error = VOP_GETATTR(dvp, &vattr, cnp->cn_cred))) 513 return error; 514 scred = smbfs_malloc_scred(); 515 smb_makescred(scred, curthread, cnp->cn_cred); 516 517 error = smbfs_smb_create(dnp, name, nmlen, scred); 518 if (error) 519 goto out; 520 error = smbfs_smb_lookup(dnp, name, nmlen, &fattr, scred); 521 if (error) 522 goto out; 523 error = smbfs_nget(VTOVFS(dvp), dvp, name, nmlen, &fattr, &vp); 524 if (error) 525 goto out; 526 *vpp = vp; 527 if (cnp->cn_flags & MAKEENTRY) 528 cache_enter(dvp, vp, cnp); 529 out: 530 smbfs_free_scred(scred); 531 return error; 532 } 533 534 static int 535 smbfs_remove(struct vop_remove_args *ap) 536 { 537 struct vnode *vp = ap->a_vp; 538 /* struct vnode *dvp = ap->a_dvp;*/ 539 struct componentname *cnp = ap->a_cnp; 540 struct smbnode *np = VTOSMB(vp); 541 struct smb_cred *scred; 542 int error; 543 544 if (vp->v_type == VDIR || (np->n_flag & NOPEN) != 0 || vrefcnt(vp) != 1) 545 return EPERM; 546 scred = smbfs_malloc_scred(); 547 smb_makescred(scred, curthread, cnp->cn_cred); 548 error = smbfs_smb_delete(np, scred); 549 if (error == 0) 550 np->n_flag |= NGONE; 551 cache_purge(vp); 552 smbfs_free_scred(scred); 553 return error; 554 } 555 556 /* 557 * smbfs_file rename call 558 */ 559 static int 560 smbfs_rename(struct vop_rename_args *ap) 561 { 562 struct vnode *fvp = ap->a_fvp; 563 struct vnode *tvp = ap->a_tvp; 564 struct vnode *fdvp = ap->a_fdvp; 565 struct vnode *tdvp = ap->a_tdvp; 566 struct componentname *tcnp = ap->a_tcnp; 567 /* struct componentname *fcnp = ap->a_fcnp;*/ 568 struct smb_cred *scred; 569 #ifdef notnow 570 u_int16_t flags = 6; 571 #endif 572 int error=0; 573 574 scred = NULL; 575 /* Check for cross-device rename */ 576 if ((fvp->v_mount != tdvp->v_mount) || 577 (tvp && (fvp->v_mount != tvp->v_mount))) { 578 error = EXDEV; 579 goto out; 580 } 581 582 if (tvp && vrefcnt(tvp) > 1) { 583 error = EBUSY; 584 goto out; 585 } 586 #ifdef notnow 587 flags = 0x10; /* verify all writes */ 588 #endif 589 if (fvp->v_type == VDIR) { 590 #ifdef notnow 591 flags |= 2; 592 #endif 593 } else if (fvp->v_type == VREG) { 594 #ifdef notnow 595 flags |= 1; 596 #endif 597 } else { 598 return EINVAL; 599 } 600 scred = smbfs_malloc_scred(); 601 smb_makescred(scred, curthread, tcnp->cn_cred); 602 /* 603 * It seems that Samba doesn't implement SMB_COM_MOVE call... 604 */ 605 #ifdef notnow 606 if (SMB_DIALECT(SSTOCN(smp->sm_share)) >= SMB_DIALECT_LANMAN1_0) { 607 error = smbfs_smb_move(VTOSMB(fvp), VTOSMB(tdvp), 608 tcnp->cn_nameptr, tcnp->cn_namelen, flags, scred); 609 } else 610 #endif 611 { 612 /* 613 * We have to do the work atomicaly 614 */ 615 if (tvp && tvp != fvp) { 616 error = smbfs_smb_delete(VTOSMB(tvp), scred); 617 if (error) 618 goto out_cacherem; 619 VTOSMB(fvp)->n_flag |= NGONE; 620 } 621 error = smbfs_smb_rename(VTOSMB(fvp), VTOSMB(tdvp), 622 tcnp->cn_nameptr, tcnp->cn_namelen, scred); 623 } 624 625 if (fvp->v_type == VDIR) { 626 if (tvp != NULL && tvp->v_type == VDIR) 627 cache_purge(tdvp); 628 cache_purge(fdvp); 629 } 630 631 out_cacherem: 632 smbfs_attr_cacheremove(fdvp); 633 smbfs_attr_cacheremove(tdvp); 634 out: 635 smbfs_free_scred(scred); 636 if (tdvp == tvp) 637 vrele(tdvp); 638 else 639 vput(tdvp); 640 if (tvp) 641 vput(tvp); 642 vrele(fdvp); 643 vrele(fvp); 644 #ifdef possible_mistake 645 vgone(fvp); 646 if (tvp) 647 vgone(tvp); 648 #endif 649 return error; 650 } 651 652 /* 653 * somtime it will come true... 654 */ 655 static int 656 smbfs_link(struct vop_link_args *ap) 657 { 658 return EOPNOTSUPP; 659 } 660 661 /* 662 * smbfs_symlink link create call. 663 * Sometime it will be functional... 664 */ 665 static int 666 smbfs_symlink(struct vop_symlink_args *ap) 667 { 668 return EOPNOTSUPP; 669 } 670 671 static int 672 smbfs_mknod(struct vop_mknod_args *ap) 673 { 674 return EOPNOTSUPP; 675 } 676 677 static int 678 smbfs_mkdir(struct vop_mkdir_args *ap) 679 { 680 struct vnode *dvp = ap->a_dvp; 681 /* struct vattr *vap = ap->a_vap;*/ 682 struct vnode *vp; 683 struct componentname *cnp = ap->a_cnp; 684 struct smbnode *dnp = VTOSMB(dvp); 685 struct vattr vattr; 686 struct smb_cred *scred; 687 struct smbfattr fattr; 688 char *name = cnp->cn_nameptr; 689 int len = cnp->cn_namelen; 690 int error; 691 692 if ((error = VOP_GETATTR(dvp, &vattr, cnp->cn_cred))) { 693 return error; 694 } 695 if ((name[0] == '.') && ((len == 1) || ((len == 2) && (name[1] == '.')))) 696 return EEXIST; 697 scred = smbfs_malloc_scred(); 698 smb_makescred(scred, curthread, cnp->cn_cred); 699 error = smbfs_smb_mkdir(dnp, name, len, scred); 700 if (error) 701 goto out; 702 error = smbfs_smb_lookup(dnp, name, len, &fattr, scred); 703 if (error) 704 goto out; 705 error = smbfs_nget(VTOVFS(dvp), dvp, name, len, &fattr, &vp); 706 if (error) 707 goto out; 708 *ap->a_vpp = vp; 709 out: 710 smbfs_free_scred(scred); 711 return error; 712 } 713 714 /* 715 * smbfs_remove directory call 716 */ 717 static int 718 smbfs_rmdir(struct vop_rmdir_args *ap) 719 { 720 struct vnode *vp = ap->a_vp; 721 struct vnode *dvp = ap->a_dvp; 722 struct componentname *cnp = ap->a_cnp; 723 /* struct smbmount *smp = VTOSMBFS(vp);*/ 724 struct smbnode *dnp = VTOSMB(dvp); 725 struct smbnode *np = VTOSMB(vp); 726 struct smb_cred *scred; 727 int error; 728 729 if (dvp == vp) 730 return EINVAL; 731 732 scred = smbfs_malloc_scred(); 733 smb_makescred(scred, curthread, cnp->cn_cred); 734 error = smbfs_smb_rmdir(np, scred); 735 if (error == 0) 736 np->n_flag |= NGONE; 737 dnp->n_flag |= NMODIFIED; 738 smbfs_attr_cacheremove(dvp); 739 /* cache_purge(dvp);*/ 740 cache_purge(vp); 741 smbfs_free_scred(scred); 742 return error; 743 } 744 745 /* 746 * smbfs_readdir call 747 */ 748 static int 749 smbfs_readdir(struct vop_readdir_args *ap) 750 { 751 struct vnode *vp = ap->a_vp; 752 struct uio *uio = ap->a_uio; 753 int error; 754 755 if (vp->v_type != VDIR) 756 return (EPERM); 757 #ifdef notnow 758 if (ap->a_ncookies) { 759 printf("smbfs_readdir: no support for cookies now..."); 760 return (EOPNOTSUPP); 761 } 762 #endif 763 error = smbfs_readvnode(vp, uio, ap->a_cred); 764 return error; 765 } 766 767 /* ARGSUSED */ 768 static int 769 smbfs_fsync(struct vop_fsync_args *ap) 770 { 771 /* return (smb_flush(ap->a_vp, ap->a_cred, ap->a_waitfor, ap->a_td, 1));*/ 772 return (0); 773 } 774 775 static 776 int smbfs_print(struct vop_print_args *ap) 777 { 778 struct vnode *vp = ap->a_vp; 779 struct smbnode *np = VTOSMB(vp); 780 781 if (np == NULL) { 782 printf("no smbnode data\n"); 783 return (0); 784 } 785 printf("\tname = %s, parent = %p, open = %d\n", np->n_name, 786 np->n_parent ? np->n_parent : NULL, (np->n_flag & NOPEN) != 0); 787 return (0); 788 } 789 790 static int 791 smbfs_pathconf(struct vop_pathconf_args *ap) 792 { 793 struct smbmount *smp = VFSTOSMBFS(VTOVFS(ap->a_vp)); 794 struct smb_vc *vcp = SSTOVC(smp->sm_share); 795 long *retval = ap->a_retval; 796 int error = 0; 797 798 switch (ap->a_name) { 799 case _PC_FILESIZEBITS: 800 if (vcp->vc_sopt.sv_caps & (SMB_CAP_LARGE_READX | 801 SMB_CAP_LARGE_WRITEX)) 802 *retval = 64; 803 else 804 *retval = 32; 805 break; 806 case _PC_NAME_MAX: 807 *retval = (vcp->vc_hflags2 & SMB_FLAGS2_KNOWS_LONG_NAMES) ? 255 : 12; 808 break; 809 case _PC_PATH_MAX: 810 *retval = 800; /* XXX: a correct one ? */ 811 break; 812 case _PC_NO_TRUNC: 813 *retval = 1; 814 break; 815 default: 816 error = vop_stdpathconf(ap); 817 } 818 return error; 819 } 820 821 static int 822 smbfs_strategy(struct vop_strategy_args *ap) 823 { 824 struct buf *bp=ap->a_bp; 825 struct ucred *cr; 826 struct thread *td; 827 828 SMBVDEBUG("\n"); 829 if (bp->b_flags & B_ASYNC) 830 td = (struct thread *)0; 831 else 832 td = curthread; /* XXX */ 833 if (bp->b_iocmd == BIO_READ) 834 cr = bp->b_rcred; 835 else 836 cr = bp->b_wcred; 837 838 if ((bp->b_flags & B_ASYNC) == 0 ) 839 (void)smbfs_doio(ap->a_vp, bp, cr, td); 840 return (0); 841 } 842 843 int 844 smbfs_ioctl(struct vop_ioctl_args *ap) 845 { 846 return ENOTTY; 847 } 848 849 static char smbfs_atl[] = "rhsvda"; 850 static int 851 smbfs_getextattr(struct vop_getextattr_args *ap) 852 /* { 853 IN struct vnode *a_vp; 854 IN char *a_name; 855 INOUT struct uio *a_uio; 856 IN struct ucred *a_cred; 857 IN struct thread *a_td; 858 }; 859 */ 860 { 861 struct vnode *vp = ap->a_vp; 862 struct thread *td = ap->a_td; 863 struct ucred *cred = ap->a_cred; 864 struct uio *uio = ap->a_uio; 865 const char *name = ap->a_name; 866 struct smbnode *np = VTOSMB(vp); 867 struct vattr vattr; 868 char buf[10]; 869 int i, attr, error; 870 871 error = VOP_ACCESS(vp, VREAD, cred, td); 872 if (error) 873 return error; 874 error = VOP_GETATTR(vp, &vattr, cred); 875 if (error) 876 return error; 877 if (strcmp(name, "dosattr") == 0) { 878 attr = np->n_dosattr; 879 for (i = 0; i < 6; i++, attr >>= 1) 880 buf[i] = (attr & 1) ? smbfs_atl[i] : '-'; 881 buf[i] = 0; 882 error = uiomove(buf, i, uio); 883 } else 884 error = EINVAL; 885 return error; 886 } 887 888 /* 889 * Since we expected to support F_GETLK (and SMB protocol has no such function), 890 * it is necessary to use lf_advlock(). It would be nice if this function had 891 * a callback mechanism because it will help to improve a level of consistency. 892 */ 893 int 894 smbfs_advlock(struct vop_advlock_args *ap) 895 { 896 struct vnode *vp = ap->a_vp; 897 struct smbnode *np = VTOSMB(vp); 898 struct flock *fl = ap->a_fl; 899 caddr_t id = (caddr_t)1 /* ap->a_id */; 900 /* int flags = ap->a_flags;*/ 901 struct thread *td = curthread; 902 struct smb_cred *scred; 903 u_quad_t size; 904 off_t start, end, oadd; 905 int error, lkop; 906 907 if (vp->v_type == VDIR) { 908 /* 909 * SMB protocol have no support for directory locking. 910 * Although locks can be processed on local machine, I don't 911 * think that this is a good idea, because some programs 912 * can work wrong assuming directory is locked. So, we just 913 * return 'operation not supported 914 */ 915 return EOPNOTSUPP; 916 } 917 size = np->n_size; 918 switch (fl->l_whence) { 919 case SEEK_SET: 920 case SEEK_CUR: 921 start = fl->l_start; 922 break; 923 924 case SEEK_END: 925 if (size > OFF_MAX || 926 (fl->l_start > 0 && size > OFF_MAX - fl->l_start)) 927 return EOVERFLOW; 928 start = size + fl->l_start; 929 break; 930 931 default: 932 return EINVAL; 933 } 934 if (start < 0) 935 return EINVAL; 936 if (fl->l_len < 0) { 937 if (start == 0) 938 return EINVAL; 939 end = start - 1; 940 start += fl->l_len; 941 if (start < 0) 942 return EINVAL; 943 } else if (fl->l_len == 0) 944 end = -1; 945 else { 946 oadd = fl->l_len - 1; 947 if (oadd > OFF_MAX - start) 948 return EOVERFLOW; 949 end = start + oadd; 950 } 951 scred = smbfs_malloc_scred(); 952 smb_makescred(scred, td, td->td_ucred); 953 switch (ap->a_op) { 954 case F_SETLK: 955 switch (fl->l_type) { 956 case F_WRLCK: 957 lkop = SMB_LOCK_EXCL; 958 break; 959 case F_RDLCK: 960 lkop = SMB_LOCK_SHARED; 961 break; 962 case F_UNLCK: 963 lkop = SMB_LOCK_RELEASE; 964 break; 965 default: 966 smbfs_free_scred(scred); 967 return EINVAL; 968 } 969 error = lf_advlock(ap, &vp->v_lockf, size); 970 if (error) 971 break; 972 lkop = SMB_LOCK_EXCL; 973 error = smbfs_smb_lock(np, lkop, id, start, end, scred); 974 if (error) { 975 int oldtype = fl->l_type; 976 fl->l_type = F_UNLCK; 977 ap->a_op = F_UNLCK; 978 lf_advlock(ap, &vp->v_lockf, size); 979 fl->l_type = oldtype; 980 } 981 break; 982 case F_UNLCK: 983 lf_advlock(ap, &vp->v_lockf, size); 984 error = smbfs_smb_lock(np, SMB_LOCK_RELEASE, id, start, end, scred); 985 break; 986 case F_GETLK: 987 error = lf_advlock(ap, &vp->v_lockf, size); 988 break; 989 default: 990 smbfs_free_scred(scred); 991 return EINVAL; 992 } 993 smbfs_free_scred(scred); 994 return error; 995 } 996 997 static int 998 smbfs_pathcheck(struct smbmount *smp, const char *name, int nmlen, int nameiop) 999 { 1000 static const char *badchars = "*/:<>?"; 1001 static const char *badchars83 = " +|,[]=;"; 1002 const char *cp; 1003 int i, error; 1004 1005 /* 1006 * Backslash characters, being a path delimiter, are prohibited 1007 * within a path component even for LOOKUP operations. 1008 */ 1009 if (strchr(name, '\\') != NULL) 1010 return ENOENT; 1011 1012 if (nameiop == LOOKUP) 1013 return 0; 1014 error = ENOENT; 1015 if (SMB_DIALECT(SSTOVC(smp->sm_share)) < SMB_DIALECT_LANMAN2_0) { 1016 /* 1017 * Name should conform 8.3 format 1018 */ 1019 if (nmlen > 12) 1020 return ENAMETOOLONG; 1021 cp = strchr(name, '.'); 1022 if (cp == NULL) 1023 return error; 1024 if (cp == name || (cp - name) > 8) 1025 return error; 1026 cp = strchr(cp + 1, '.'); 1027 if (cp != NULL) 1028 return error; 1029 for (cp = name, i = 0; i < nmlen; i++, cp++) 1030 if (strchr(badchars83, *cp) != NULL) 1031 return error; 1032 } 1033 for (cp = name, i = 0; i < nmlen; i++, cp++) 1034 if (strchr(badchars, *cp) != NULL) 1035 return error; 1036 return 0; 1037 } 1038 1039 /* 1040 * Things go even weird without fixed inode numbers... 1041 */ 1042 int 1043 smbfs_lookup(struct vop_lookup_args *ap) 1044 { 1045 struct componentname *cnp = ap->a_cnp; 1046 struct thread *td = curthread; 1047 struct vnode *dvp = ap->a_dvp; 1048 struct vnode **vpp = ap->a_vpp; 1049 struct vnode *vp; 1050 struct smbmount *smp; 1051 struct mount *mp = dvp->v_mount; 1052 struct smbnode *dnp; 1053 struct smbfattr fattr, *fap; 1054 struct smb_cred *scred; 1055 char *name = cnp->cn_nameptr; 1056 int flags = cnp->cn_flags; 1057 int nameiop = cnp->cn_nameiop; 1058 int nmlen = cnp->cn_namelen; 1059 int error, islastcn, isdot; 1060 int killit; 1061 1062 SMBVDEBUG("\n"); 1063 if (dvp->v_type != VDIR) 1064 return ENOTDIR; 1065 if ((flags & ISDOTDOT) && (dvp->v_vflag & VV_ROOT)) { 1066 SMBFSERR("invalid '..'\n"); 1067 return EIO; 1068 } 1069 islastcn = flags & ISLASTCN; 1070 if (islastcn && (mp->mnt_flag & MNT_RDONLY) && (nameiop != LOOKUP)) 1071 return EROFS; 1072 error = vn_dir_check_exec(dvp, cnp); 1073 if (error != 0) 1074 return error; 1075 smp = VFSTOSMBFS(mp); 1076 dnp = VTOSMB(dvp); 1077 isdot = (nmlen == 1 && name[0] == '.'); 1078 1079 error = smbfs_pathcheck(smp, cnp->cn_nameptr, cnp->cn_namelen, nameiop); 1080 1081 if (error) 1082 return ENOENT; 1083 1084 error = cache_lookup(dvp, vpp, cnp, NULL, NULL); 1085 SMBVDEBUG("cache_lookup returned %d\n", error); 1086 if (error > 0) 1087 return error; 1088 if (error) { /* name was found */ 1089 struct vattr vattr; 1090 1091 killit = 0; 1092 vp = *vpp; 1093 error = VOP_GETATTR(vp, &vattr, cnp->cn_cred); 1094 /* 1095 * If the file type on the server is inconsistent 1096 * with what it was when we created the vnode, 1097 * kill the bogus vnode now and fall through to 1098 * the code below to create a new one with the 1099 * right type. 1100 */ 1101 if (error == 0 && 1102 ((vp->v_type == VDIR && 1103 (VTOSMB(vp)->n_dosattr & SMB_FA_DIR) == 0) || 1104 (vp->v_type == VREG && 1105 (VTOSMB(vp)->n_dosattr & SMB_FA_DIR) != 0))) 1106 killit = 1; 1107 else if (error == 0 1108 /* && vattr.va_ctime.tv_sec == VTOSMB(vp)->n_ctime*/) { 1109 SMBVDEBUG("use cached vnode\n"); 1110 return (0); 1111 } 1112 cache_purge(vp); 1113 /* 1114 * XXX This is not quite right, if '.' is 1115 * inconsistent, we really need to start the lookup 1116 * all over again. Hopefully there is some other 1117 * guarantee that prevents this case from happening. 1118 */ 1119 if (killit && vp != dvp) 1120 vgone(vp); 1121 if (vp != dvp) 1122 vput(vp); 1123 else 1124 vrele(vp); 1125 *vpp = NULLVP; 1126 } 1127 /* 1128 * entry is not in the cache or has been expired 1129 */ 1130 error = 0; 1131 *vpp = NULLVP; 1132 scred = smbfs_malloc_scred(); 1133 smb_makescred(scred, td, cnp->cn_cred); 1134 fap = &fattr; 1135 if (flags & ISDOTDOT) { 1136 /* 1137 * In the DOTDOT case, don't go over-the-wire 1138 * in order to request attributes. We already 1139 * know it's a directory and subsequent call to 1140 * smbfs_getattr() will restore consistency. 1141 * 1142 */ 1143 SMBVDEBUG("smbfs_smb_lookup: dotdot\n"); 1144 } else if (isdot) { 1145 error = smbfs_smb_lookup(dnp, NULL, 0, fap, scred); 1146 SMBVDEBUG("result of smbfs_smb_lookup: %d\n", error); 1147 } 1148 else { 1149 error = smbfs_smb_lookup(dnp, name, nmlen, fap, scred); 1150 SMBVDEBUG("result of smbfs_smb_lookup: %d\n", error); 1151 } 1152 if (error && error != ENOENT) 1153 goto out; 1154 if (error) { /* entry not found */ 1155 /* 1156 * Handle RENAME or CREATE case... 1157 */ 1158 if ((nameiop == CREATE || nameiop == RENAME) && islastcn) { 1159 error = VOP_ACCESS(dvp, VWRITE, cnp->cn_cred, td); 1160 if (error) 1161 goto out; 1162 error = EJUSTRETURN; 1163 goto out; 1164 } 1165 error = ENOENT; 1166 goto out; 1167 }/* else { 1168 SMBVDEBUG("Found entry %s with id=%d\n", fap->entryName, fap->dirEntNum); 1169 }*/ 1170 /* 1171 * handle DELETE case ... 1172 */ 1173 if (nameiop == DELETE && islastcn) { /* delete last component */ 1174 error = VOP_ACCESS(dvp, VWRITE, cnp->cn_cred, td); 1175 if (error) 1176 goto out; 1177 if (isdot) { 1178 VREF(dvp); 1179 *vpp = dvp; 1180 goto out; 1181 } 1182 error = smbfs_nget(mp, dvp, name, nmlen, fap, &vp); 1183 if (error) 1184 goto out; 1185 *vpp = vp; 1186 goto out; 1187 } 1188 if (nameiop == RENAME && islastcn) { 1189 error = VOP_ACCESS(dvp, VWRITE, cnp->cn_cred, td); 1190 if (error) 1191 goto out; 1192 if (isdot) { 1193 error = EISDIR; 1194 goto out; 1195 } 1196 error = smbfs_nget(mp, dvp, name, nmlen, fap, &vp); 1197 if (error) 1198 goto out; 1199 *vpp = vp; 1200 goto out; 1201 } 1202 if (flags & ISDOTDOT) { 1203 mp = dvp->v_mount; 1204 error = vfs_busy(mp, MBF_NOWAIT); 1205 if (error != 0) { 1206 vfs_ref(mp); 1207 VOP_UNLOCK(dvp); 1208 error = vfs_busy(mp, 0); 1209 vn_lock(dvp, LK_EXCLUSIVE | LK_RETRY); 1210 vfs_rel(mp); 1211 if (error) { 1212 error = ENOENT; 1213 goto out; 1214 } 1215 if (VN_IS_DOOMED(dvp)) { 1216 vfs_unbusy(mp); 1217 error = ENOENT; 1218 goto out; 1219 } 1220 } 1221 VOP_UNLOCK(dvp); 1222 error = smbfs_nget(mp, dvp, name, nmlen, NULL, &vp); 1223 vfs_unbusy(mp); 1224 vn_lock(dvp, LK_EXCLUSIVE | LK_RETRY); 1225 if (VN_IS_DOOMED(dvp)) { 1226 if (error == 0) 1227 vput(vp); 1228 error = ENOENT; 1229 } 1230 if (error) 1231 goto out; 1232 *vpp = vp; 1233 } else if (isdot) { 1234 vref(dvp); 1235 *vpp = dvp; 1236 } else { 1237 error = smbfs_nget(mp, dvp, name, nmlen, fap, &vp); 1238 if (error) 1239 goto out; 1240 *vpp = vp; 1241 SMBVDEBUG("lookup: getnewvp!\n"); 1242 } 1243 if ((cnp->cn_flags & MAKEENTRY)/* && !islastcn*/) { 1244 /* VTOSMB(*vpp)->n_ctime = VTOSMB(*vpp)->n_vattr.va_ctime.tv_sec;*/ 1245 cache_enter(dvp, *vpp, cnp); 1246 } 1247 out: 1248 smbfs_free_scred(scred); 1249 return (error); 1250 } 1251