1 /* $NetBSD: smbfs_vnops.c,v 1.73 2009/07/04 07:36:46 cegger Exp $ */
4 * Copyright (c) 2003 The NetBSD Foundation, Inc.
7 * This code is derived from software contributed to The NetBSD Foundation
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 * POSSIBILITY OF SUCH DAMAGE.
33 * Copyright (c) 2000-2001 Boris Popov
34 * All rights reserved.
36 * Redistribution and use in source and binary forms, with or without
37 * modification, are permitted provided that the following conditions
39 * 1. Redistributions of source code must retain the above copyright
40 * notice, this list of conditions and the following disclaimer.
41 * 2. Redistributions in binary form must reproduce the above copyright
42 * notice, this list of conditions and the following disclaimer in the
43 * documentation and/or other materials provided with the distribution.
44 * 3. All advertising materials mentioning features or use of this software
45 * must display the following acknowledgement:
46 * This product includes software developed by Boris Popov.
47 * 4. Neither the name of the author nor the names of any co-contributors
48 * may be used to endorse or promote products derived from this software
49 * without specific prior written permission.
51 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
52 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
53 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
54 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
55 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
56 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
57 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
58 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
59 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
60 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
63 * FreeBSD: src/sys/fs/smbfs/smbfs_vnops.c,v 1.15 2001/12/20 15:56:45 bp Exp
66 #include <sys/cdefs.h>
67 __KERNEL_RCSID(0, "$NetBSD: smbfs_vnops.c,v 1.73 2009/07/04 07:36:46 cegger Exp $");
69 #include <sys/param.h>
70 #include <sys/systm.h>
71 #include <sys/namei.h>
72 #include <sys/kernel.h>
75 #include <sys/fcntl.h>
76 #include <sys/mount.h>
77 #include <sys/unistd.h>
78 #include <sys/vnode.h>
79 #include <sys/lockf.h>
80 #include <sys/kauth.h>
82 #include <machine/limits.h>
85 #include <uvm/uvm_extern.h>
87 #include <netsmb/smb.h>
88 #include <netsmb/smb_conn.h>
89 #include <netsmb/smb_subr.h>
91 #include <fs/smbfs/smbfs.h>
92 #include <fs/smbfs/smbfs_node.h>
93 #include <fs/smbfs/smbfs_subr.h>
95 #include <miscfs/genfs/genfs.h>
98 * Prototypes for SMBFS vnode operations
100 int smbfs_create(void *);
101 int smbfs_open(void *);
102 int smbfs_close(void *);
103 int smbfs_access(void *);
104 int smbfs_getattr(void *);
105 int smbfs_setattr(void *);
106 int smbfs_read(void *);
107 int smbfs_write(void *);
108 int smbfs_fsync(void *);
109 int smbfs_remove(void *);
110 int smbfs_link(void *);
111 int smbfs_lookup(void *);
112 int smbfs_rename(void *);
113 int smbfs_mkdir(void *);
114 int smbfs_rmdir(void *);
115 int smbfs_symlink(void *);
116 int smbfs_readdir(void *);
117 int smbfs_strategy(void *);
118 int smbfs_print(void *);
119 int smbfs_pathconf(void *ap
);
120 int smbfs_advlock(void *);
122 int (**smbfs_vnodeop_p
)(void *);
123 static struct vnodeopv_entry_desc smbfs_vnodeop_entries
[] = {
124 { &vop_default_desc
, vn_default_error
},
125 { &vop_access_desc
, smbfs_access
},
126 { &vop_advlock_desc
, smbfs_advlock
},
127 { &vop_close_desc
, smbfs_close
},
128 { &vop_create_desc
, smbfs_create
},
129 { &vop_fsync_desc
, smbfs_fsync
},
130 { &vop_getattr_desc
, smbfs_getattr
},
131 { &vop_getpages_desc
, genfs_compat_getpages
},
132 { &vop_inactive_desc
, smbfs_inactive
},
133 { &vop_ioctl_desc
, genfs_enoioctl
},
134 { &vop_islocked_desc
, genfs_islocked
},
135 { &vop_link_desc
, smbfs_link
},
136 { &vop_lock_desc
, genfs_lock
},
137 { &vop_lookup_desc
, smbfs_lookup
},
138 { &vop_mkdir_desc
, smbfs_mkdir
},
139 { &vop_mknod_desc
, genfs_eopnotsupp
},
140 { &vop_open_desc
, smbfs_open
},
141 { &vop_pathconf_desc
, smbfs_pathconf
},
142 { &vop_print_desc
, smbfs_print
},
143 { &vop_putpages_desc
, genfs_putpages
},
144 { &vop_read_desc
, smbfs_read
},
145 { &vop_readdir_desc
, smbfs_readdir
},
146 { &vop_reclaim_desc
, smbfs_reclaim
},
147 { &vop_remove_desc
, smbfs_remove
},
148 { &vop_rename_desc
, smbfs_rename
},
149 { &vop_rmdir_desc
, smbfs_rmdir
},
150 { &vop_setattr_desc
, smbfs_setattr
},
151 { &vop_strategy_desc
, smbfs_strategy
},
152 { &vop_symlink_desc
, smbfs_symlink
},
153 { &vop_unlock_desc
, genfs_unlock
},
154 { &vop_write_desc
, smbfs_write
},
155 { &vop_mmap_desc
, genfs_mmap
}, /* mmap */
156 { &vop_seek_desc
, genfs_seek
}, /* seek */
157 { &vop_kqfilter_desc
, smbfs_kqfilter
}, /* kqfilter */
160 const struct vnodeopv_desc smbfs_vnodeop_opv_desc
=
161 { &smbfs_vnodeop_p
, smbfs_vnodeop_entries
};
164 smbfs_check_possible(struct vnode
*vp
, struct smbnode
*np
, mode_t mode
)
168 * Disallow write attempts on read-only file systems;
169 * unless the file is a socket, fifo, or a block or
170 * character device resident on the file system.
173 switch (vp
->v_type
) {
177 if (vp
->v_mount
->mnt_flag
& MNT_RDONLY
)
188 smbfs_check_permitted(struct vnode
*vp
, struct smbnode
*np
, mode_t mode
,
191 struct smbmount
*smp
= VTOSMBFS(vp
);
193 return genfs_can_access(vp
->v_type
,
194 (vp
->v_type
== VDIR
) ? smp
->sm_args
.dir_mode
: smp
->sm_args
.file_mode
,
195 smp
->sm_args
.uid
, smp
->sm_args
.gid
, mode
, cred
);
199 smbfs_access(void *v
)
201 struct vop_access_args
/* {
206 struct vnode
*vp
= ap
->a_vp
;
207 struct smbnode
*np
= VTOSMB(vp
);
208 u_int acc_mode
= ap
->a_mode
;
210 #ifdef SMB_VNODE_DEBUG
211 struct smbmount
*smp
= VTOSMBFS(vp
);
214 SMBVDEBUG("file '%.*s', node mode=%o, acc mode=%x\n",
215 (int) np
->n_nmlen
, np
->n_name
,
216 (vp
->v_type
== VDIR
) ? smp
->sm_args
.dir_mode
: smp
->sm_args
.file_mode
,
219 error
= smbfs_check_possible(vp
, np
, acc_mode
);
223 error
= smbfs_check_permitted(vp
, np
, acc_mode
, ap
->a_cred
);
232 struct vop_open_args
/* {
237 struct lwp
*l
= curlwp
;
238 struct vnode
*vp
= ap
->a_vp
;
239 struct smbnode
*np
= VTOSMB(vp
);
240 struct smb_cred scred
;
242 u_int32_t sv_caps
= SMB_CAPS(SSTOVC(np
->n_mount
->sm_share
));
245 SMBVDEBUG("%.*s,%d\n", (int) np
->n_nmlen
, np
->n_name
,
246 (np
->n_flag
& NOPEN
) != 0);
247 if (vp
->v_type
!= VREG
&& vp
->v_type
!= VDIR
) {
248 SMBFSERR("open eacces vtype=%d\n", vp
->v_type
);
251 if (vp
->v_type
== VDIR
) {
253 if ((sv_caps
& SMB_CAP_NT_SMBS
) == 0)
255 goto do_open
; /* skip 'modified' check */
258 if (np
->n_flag
& NMODIFIED
) {
259 if ((error
= smbfs_vinvalbuf(vp
, V_SAVE
, ap
->a_cred
, l
, 1)) == EINTR
)
261 smbfs_attr_cacheremove(vp
);
262 error
= VOP_GETATTR(vp
, &vattr
, ap
->a_cred
);
265 np
->n_mtime
.tv_sec
= vattr
.va_mtime
.tv_sec
;
267 error
= VOP_GETATTR(vp
, &vattr
, ap
->a_cred
);
270 if (np
->n_mtime
.tv_sec
!= vattr
.va_mtime
.tv_sec
) {
271 error
= smbfs_vinvalbuf(vp
, V_SAVE
, ap
->a_cred
, l
, 1);
274 np
->n_mtime
.tv_sec
= vattr
.va_mtime
.tv_sec
;
279 if ((np
->n_flag
& NOPEN
) != 0)
282 smb_makescred(&scred
, l
, ap
->a_cred
);
283 if (vp
->v_type
== VDIR
)
284 error
= smbfs_smb_ntcreatex(np
,
285 SMB_SM_DENYNONE
|SMB_AM_OPENREAD
, &scred
);
288 * Use DENYNONE to give unixy semantics of permitting
289 * everything not forbidden by permissions. Ie denial
290 * is up to server with clients/openers needing to use
291 * advisory locks for further control.
293 accmode
= SMB_SM_DENYNONE
|SMB_AM_OPENREAD
;
294 if ((vp
->v_mount
->mnt_flag
& MNT_RDONLY
) == 0)
295 accmode
= SMB_SM_DENYNONE
|SMB_AM_OPENRW
;
296 error
= smbfs_smb_open(np
, accmode
, &scred
);
298 if (ap
->a_mode
& FWRITE
)
301 error
= smbfs_smb_open(np
,
302 SMB_SM_DENYNONE
|SMB_AM_OPENREAD
, &scred
);
307 smbfs_attr_cacheremove(vp
);
317 struct vop_close_args
/* {
318 struct vnodeop_desc *a_desc;
324 struct lwp
*l
= curlwp
;
325 struct vnode
*vp
= ap
->a_vp
;
326 struct smbnode
*np
= VTOSMB(vp
);
328 /* Flush all file data */
329 error
= smbfs_vinvalbuf(vp
, V_SAVE
, ap
->a_cred
, l
, 1);
334 * We must close the directory lookup context now, so that
335 * later directory changes would be properly detected.
336 * Ideally, the lookup routines should handle such case, and
337 * the context would be removed only in smbfs_inactive().
339 if (vp
->v_type
== VDIR
&& (np
->n_flag
& NOPEN
) != 0 &&
340 np
->n_dirseq
!= NULL
) {
341 struct smb_cred scred
;
343 smb_makescred(&scred
, l
, ap
->a_cred
);
344 smbfs_findclose(np
->n_dirseq
, &scred
);
352 * smbfs_getattr call from vfs.
355 smbfs_getattr(void *v
)
357 struct vop_getattr_args
/* {
362 struct vnode
*vp
= ap
->a_vp
;
363 struct smbnode
*np
= VTOSMB(vp
);
364 struct vattr
*va
=ap
->a_vap
;
365 struct smbfattr fattr
;
366 struct smb_cred scred
;
370 SMBVDEBUG("%p: '%.*s' isroot %d\n", vp
,
371 (int) np
->n_nmlen
, np
->n_name
, (vp
->v_vflag
& VV_ROOT
) != 0);
373 if ((error
= smbfs_attr_cachelookup(vp
, va
)) == 0)
376 SMBVDEBUG0("not in the cache\n");
377 smb_makescred(&scred
, curlwp
, ap
->a_cred
);
378 oldsize
= np
->n_size
;
379 error
= smbfs_smb_lookup(np
, NULL
, 0, &fattr
, &scred
);
381 SMBVDEBUG("error %d\n", error
);
384 smbfs_attr_cacheenter(vp
, &fattr
);
385 smbfs_attr_cachelookup(vp
, va
);
386 if ((np
->n_flag
& NOPEN
) != 0)
387 np
->n_size
= oldsize
;
392 smbfs_setattr(void *v
)
394 struct vop_setattr_args
/* {
399 struct lwp
*l
= curlwp
;
400 struct vnode
*vp
= ap
->a_vp
;
401 struct smbnode
*np
= VTOSMB(vp
);
402 struct vattr
*vap
= ap
->a_vap
;
403 struct timespec
*mtime
, *atime
;
404 struct smb_cred scred
;
405 struct smb_share
*ssp
= np
->n_mount
->sm_share
;
406 struct smb_vc
*vcp
= SSTOVC(ssp
);
408 int isreadonly
, doclose
, error
= 0;
411 if (vap
->va_flags
!= VNOVAL
)
413 isreadonly
= (vp
->v_mount
->mnt_flag
& MNT_RDONLY
);
415 * Disallow write attempts if the filesystem is mounted read-only.
417 if ((vap
->va_uid
!= (uid_t
)VNOVAL
|| vap
->va_gid
!= (gid_t
)VNOVAL
||
418 vap
->va_atime
.tv_sec
!= VNOVAL
|| vap
->va_mtime
.tv_sec
!= VNOVAL
||
419 vap
->va_mode
!= (mode_t
)VNOVAL
) && isreadonly
)
421 smb_makescred(&scred
, l
, ap
->a_cred
);
422 if (vap
->va_size
!= VNOVAL
) {
423 switch (vp
->v_type
) {
435 np
->n_size
= vap
->va_size
;
436 uvm_vnp_setsize(vp
, vap
->va_size
);
437 if ((np
->n_flag
& NOPEN
) == 0) {
438 error
= smbfs_smb_open(np
,
439 SMB_SM_DENYNONE
|SMB_AM_OPENRW
, &scred
);
444 error
= smbfs_smb_setfsize(np
, vap
->va_size
, &scred
);
446 smbfs_smb_close(ssp
, np
->n_fid
, NULL
, &scred
);
449 uvm_vnp_setsize(vp
, tsize
);
453 mtime
= atime
= NULL
;
454 if (vap
->va_mtime
.tv_sec
!= VNOVAL
)
455 mtime
= &vap
->va_mtime
;
456 if (vap
->va_atime
.tv_sec
!= VNOVAL
)
457 atime
= &vap
->va_atime
;
458 if (mtime
!= atime
) {
459 error
= genfs_can_chtimes(ap
->a_vp
, vap
->va_vaflags
,
460 VTOSMBFS(vp
)->sm_args
.uid
, ap
->a_cred
);
466 mtime
= &np
->n_mtime
;
468 atime
= &np
->n_atime
;
471 * If file is opened, then we can use handle based calls.
472 * If not, use path based ones.
474 if ((np
->n_flag
& NOPEN
) == 0) {
475 if (vcp
->vc_flags
& SMBV_WIN95
) {
476 error
= VOP_OPEN(vp
, FWRITE
, ap
->a_cred
);
478 /* error = smbfs_smb_setfattrNT(np, 0, mtime, atime, &scred);
479 VOP_GETATTR(vp, &vattr, ap->a_cred);*/
481 np
->n_mtime
= *mtime
;
482 VOP_CLOSE(vp
, FWRITE
, ap
->a_cred
);
484 } else if (SMB_CAPS(vcp
) & SMB_CAP_NT_SMBS
) {
485 error
= smbfs_smb_setptime2(np
, mtime
, atime
, 0, &scred
);
486 /* error = smbfs_smb_setpattrNT(np, 0, mtime, atime, &scred);*/
487 } else if (SMB_DIALECT(vcp
) >= SMB_DIALECT_LANMAN2_0
) {
488 error
= smbfs_smb_setptime2(np
, mtime
, atime
, 0, &scred
);
490 error
= smbfs_smb_setpattr(np
, 0, mtime
, &scred
);
493 if (SMB_CAPS(vcp
) & SMB_CAP_NT_SMBS
) {
494 error
= smbfs_smb_setfattrNT(np
, 0, mtime
, atime
, &scred
);
495 } else if (SMB_DIALECT(vcp
) >= SMB_DIALECT_LANMAN1_0
) {
496 error
= smbfs_smb_setftime(np
, mtime
, atime
, &scred
);
499 * XXX I have no idea how to handle this for core
500 * level servers. The possible solution is to
501 * update mtime after file is closed.
507 * Invalidate attribute cache in case if server doesn't set
508 * required attributes.
510 smbfs_attr_cacheremove(vp
); /* invalidate cache */
511 VOP_GETATTR(vp
, vap
, ap
->a_cred
);
512 np
->n_mtime
.tv_sec
= vap
->va_mtime
.tv_sec
;
513 VN_KNOTE(vp
, NOTE_ATTRIB
);
522 struct vop_read_args
/* {
528 struct vnode
*vp
= ap
->a_vp
;
530 if (vp
->v_type
!= VREG
&& vp
->v_type
!= VDIR
)
533 return smbfs_readvnode(vp
, ap
->a_uio
, ap
->a_cred
);
539 struct vop_write_args
/* {
545 struct vnode
*vp
= ap
->a_vp
;
546 struct uio
*uio
= ap
->a_uio
;
548 SMBVDEBUG("%d,ofs=%lld,sz=%zu\n",vp
->v_type
,
549 (long long int)uio
->uio_offset
, uio
->uio_resid
);
550 if (vp
->v_type
!= VREG
)
552 return smbfs_writevnode(vp
, uio
, ap
->a_cred
, ap
->a_ioflag
);
556 * Create a regular file. On entry the directory to contain the file being
557 * created is locked. We must release before we return. We must also free
558 * the pathname buffer pointed at by cnp->cn_pnbuf, always on error, or
559 * only if the SAVESTART bit in cn_flags is clear on success.
562 smbfs_create(void *v
)
564 struct vop_create_args
/* {
566 struct vnode **a_vpp;
567 struct componentname *a_cnp;
570 struct vnode
*dvp
= ap
->a_dvp
;
571 struct vattr
*vap
= ap
->a_vap
;
572 struct componentname
*cnp
= ap
->a_cnp
;
573 struct smbnode
*dnp
= VTOSMB(dvp
);
574 struct smbfattr fattr
;
575 struct smb_cred scred
;
576 const char *name
= cnp
->cn_nameptr
;
577 int nmlen
= cnp
->cn_namelen
;
581 if (vap
->va_type
!= VREG
)
584 smb_makescred(&scred
, curlwp
, cnp
->cn_cred
);
585 error
= smbfs_smb_create(dnp
, name
, nmlen
, &scred
);
589 error
= smbfs_smb_lookup(dnp
, name
, nmlen
, &fattr
, &scred
);
592 error
= smbfs_nget(VTOVFS(dvp
), dvp
, name
, nmlen
, &fattr
, ap
->a_vpp
);
597 if (cnp
->cn_flags
& MAKEENTRY
)
598 cache_enter(dvp
, *ap
->a_vpp
, cnp
);
601 if (error
|| ((cnp
->cn_flags
& SAVESTART
) == 0))
602 PNBUF_PUT(cnp
->cn_pnbuf
);
603 VN_KNOTE(dvp
, NOTE_WRITE
);
611 smbfs_remove(void *v
)
613 struct vop_remove_args
/* {
614 struct vnodeop_desc *a_desc;
615 struct vnode * a_dvp;
617 struct componentname * a_cnp;
619 struct vnode
*vp
= ap
->a_vp
;
620 struct vnode
*dvp
= ap
->a_dvp
;
621 struct componentname
*cnp
= ap
->a_cnp
;
622 struct smbnode
*np
= VTOSMB(vp
);
623 struct smb_cred scred
;
626 if (vp
->v_type
== VDIR
|| (np
->n_flag
& NOPEN
) != 0
627 || vp
->v_usecount
!= 1) {
628 /* XXX Eventually should do something along NFS sillyrename */
631 smb_makescred(&scred
, curlwp
, cnp
->cn_cred
);
632 error
= smbfs_smb_delete(np
, &scred
);
635 VN_KNOTE(ap
->a_vp
, NOTE_DELETE
);
636 VN_KNOTE(ap
->a_dvp
, NOTE_WRITE
);
646 * smbfs_file rename call
649 smbfs_rename(void *v
)
651 struct vop_rename_args
/* {
652 struct vnode *a_fdvp;
654 struct componentname *a_fcnp;
655 struct vnode *a_tdvp;
657 struct componentname *a_tcnp;
659 struct vnode
*fvp
= ap
->a_fvp
;
660 struct vnode
*tvp
= ap
->a_tvp
;
661 struct vnode
*fdvp
= ap
->a_fdvp
;
662 struct vnode
*tdvp
= ap
->a_tdvp
;
663 struct componentname
*tcnp
= ap
->a_tcnp
;
664 /* struct componentname *fcnp = ap->a_fcnp;*/
665 struct smb_cred scred
;
671 /* Check for cross-device rename */
672 if ((fvp
->v_mount
!= tdvp
->v_mount
) ||
673 (tvp
&& (fvp
->v_mount
!= tvp
->v_mount
))) {
678 if (tvp
&& tvp
->v_usecount
> 1) {
683 flags
= 0x10; /* verify all writes */
684 if (fvp
->v_type
== VDIR
) {
686 } else if (fvp
->v_type
== VREG
) {
693 smb_makescred(&scred
, curlwp
, tcnp
->cn_cred
);
695 * It seems that Samba doesn't implement SMB_COM_MOVE call...
698 if (SMB_DIALECT(SSTOCN(smp
->sm_share
)) >= SMB_DIALECT_LANMAN1_0
) {
699 error
= smbfs_smb_move(VTOSMB(fvp
), VTOSMB(tdvp
),
700 tcnp
->cn_nameptr
, tcnp
->cn_namelen
, flags
, &scred
);
705 * We have to do the work atomicaly
707 if (tvp
&& tvp
!= fvp
) {
708 error
= smbfs_smb_delete(VTOSMB(tvp
), &scred
);
711 VN_KNOTE(tdvp
, NOTE_WRITE
);
712 VN_KNOTE(tvp
, NOTE_DELETE
);
715 error
= smbfs_smb_rename(VTOSMB(fvp
), VTOSMB(tdvp
),
716 tcnp
->cn_nameptr
, tcnp
->cn_namelen
, &scred
);
717 VN_KNOTE(fdvp
, NOTE_WRITE
);
718 VN_KNOTE(fvp
, NOTE_RENAME
);
721 if (fvp
->v_type
== VDIR
) {
722 if (tvp
!= NULL
&& tvp
->v_type
== VDIR
)
727 smbfs_attr_cacheremove(fdvp
);
728 smbfs_attr_cacheremove(tdvp
);
746 * somtime it will come true...
751 return genfs_eopnotsupp(v
);
755 * smbfs_symlink link create call.
756 * Sometime it will be functional...
759 smbfs_symlink(void *v
)
761 return genfs_eopnotsupp(v
);
767 struct vop_mkdir_args
/* {
769 struct vnode **a_vpp;
770 struct componentname *a_cnp;
773 struct vnode
*dvp
= ap
->a_dvp
;
774 /* struct vattr *vap = ap->a_vap;*/
776 struct componentname
*cnp
= ap
->a_cnp
;
777 struct smbnode
*dnp
= VTOSMB(dvp
);
778 struct smb_cred scred
;
779 struct smbfattr fattr
;
780 const char *name
= cnp
->cn_nameptr
;
781 int len
= cnp
->cn_namelen
;
784 if ((name
[0] == '.') && ((len
== 1) || ((len
== 2) && (name
[1] == '.')))){
789 smb_makescred(&scred
, curlwp
, cnp
->cn_cred
);
790 error
= smbfs_smb_mkdir(dnp
, name
, len
, &scred
);
793 error
= smbfs_smb_lookup(dnp
, name
, len
, &fattr
, &scred
);
796 error
= smbfs_nget(VTOVFS(dvp
), dvp
, name
, len
, &fattr
, &vp
);
802 if (error
|| ((cnp
->cn_flags
& SAVESTART
) == 0))
803 PNBUF_PUT(cnp
->cn_pnbuf
);
804 VN_KNOTE(dvp
, NOTE_WRITE
| NOTE_LINK
);
811 * smbfs_remove directory call
816 struct vop_rmdir_args
/* {
819 struct componentname *a_cnp;
821 struct vnode
*vp
= ap
->a_vp
;
822 struct vnode
*dvp
= ap
->a_dvp
;
823 struct componentname
*cnp
= ap
->a_cnp
;
824 /* struct smbmount *smp = VTOSMBFS(vp);*/
825 struct smbnode
*dnp
= VTOSMB(dvp
);
826 struct smbnode
*np
= VTOSMB(vp
);
827 struct smb_cred scred
;
836 smb_makescred(&scred
, curlwp
, cnp
->cn_cred
);
837 error
= smbfs_smb_rmdir(np
, &scred
);
838 dnp
->n_flag
|= NMODIFIED
;
839 smbfs_attr_cacheremove(dvp
);
840 VN_KNOTE(dvp
, NOTE_WRITE
| NOTE_LINK
);
841 VN_KNOTE(vp
, NOTE_DELETE
);
854 smbfs_readdir(void *v
)
856 struct vop_readdir_args
/* {
864 struct vnode
*vp
= ap
->a_vp
;
866 if (vp
->v_type
!= VDIR
)
869 if (ap
->a_ncookies
) {
870 printf("smbfs_readdir: no support for cookies now...");
874 return (smbfs_readvnode(vp
, ap
->a_uio
, ap
->a_cred
));
881 /*return (smb_flush(ap->a_vp, ap->a_cred, ap->a_waitfor, ap->a_l, 1));*/
888 struct vop_print_args
/* {
891 struct vnode
*vp
= ap
->a_vp
;
892 struct smbnode
*np
= VTOSMB(vp
);
894 printf("tag VT_SMBFS, name = %.*s, parent = %p, open = %d\n",
895 (int)np
->n_nmlen
, np
->n_name
,
896 np
->n_parent
? np
->n_parent
: NULL
,
897 (np
->n_flag
& NOPEN
) != 0);
902 smbfs_pathconf(void *v
)
904 struct vop_pathconf_args
/* {
907 register_t *a_retval;
909 register_t
*retval
= ap
->a_retval
;
912 switch (ap
->a_name
) {
923 *retval
= ap
->a_vp
->v_mount
->mnt_stat
.f_namemax
;
926 *retval
= 800; /* XXX: a correct one ? */
937 smbfs_strategy(void *v
)
939 struct vop_strategy_args
/* {
943 struct buf
*bp
= ap
->a_bp
;
949 if ((bp
->b_flags
& (B_PHYS
|B_ASYNC
)) == (B_PHYS
|B_ASYNC
))
950 panic("smbfs physio/async");
951 if (bp
->b_flags
& B_ASYNC
) {
955 l
= curlwp
; /* XXX */
959 if ((bp
->b_flags
& B_ASYNC
) == 0)
960 error
= smbfs_doio(bp
, cr
, l
);
966 static char smbfs_atl
[] = "rhsvda";
968 smbfs_getextattr(struct vop_getextattr_args
*ap
)
970 IN struct vnode *a_vp;
972 INOUT struct uio *a_uio;
973 IN kauth_cred_t a_cred;
977 struct vnode
*vp
= ap
->a_vp
;
978 struct lwp
*l
= ap
->a_l
;
979 kauth_cred_t cred
= ap
->a_cred
;
980 struct uio
*uio
= ap
->a_uio
;
981 const char *name
= ap
->a_name
;
982 struct smbnode
*np
= VTOSMB(vp
);
987 error
= VOP_ACCESS(vp
, VREAD
, cred
, td
);
990 error
= VOP_GETATTR(vp
, &vattr
, cred
, td
);
993 if (strcmp(name
, "dosattr") == 0) {
994 attr
= np
->n_dosattr
;
995 for (i
= 0; i
< 6; i
++, attr
>>= 1)
996 buf
[i
] = (attr
& 1) ? smbfs_atl
[i
] : '-';
998 error
= uiomove(buf
, i
, uio
);
1004 #endif /* !__NetBSD__ */
1007 * Since we expected to support F_GETLK (and SMB protocol has no such function),
1008 * it is necessary to use lf_advlock(). It would be nice if this function had
1009 * a callback mechanism because it will help to improve a level of consistency.
1012 smbfs_advlock(void *v
)
1014 struct vop_advlock_args
/* {
1021 struct vnode
*vp
= ap
->a_vp
;
1022 struct smbnode
*np
= VTOSMB(vp
);
1023 struct flock
*fl
= ap
->a_fl
;
1024 struct lwp
*l
= curlwp
;
1025 struct smb_cred scred
;
1027 off_t start
, end
, oadd
;
1030 if (vp
->v_type
== VDIR
) {
1032 * SMB protocol have no support for directory locking.
1033 * Although locks can be processed on local machine, I don't
1034 * think that this is a good idea, because some programs
1035 * can work wrong assuming directory is locked. So, we just
1036 * return 'operation not supported'.
1041 switch (fl
->l_whence
) {
1045 start
= fl
->l_start
;
1050 if (size
> OFF_MAX
||
1051 (fl
->l_start
> 0 && size
> OFF_MAX
- fl
->l_start
))
1054 start
= size
+ fl
->l_start
;
1062 if (fl
->l_len
< 0) {
1069 } else if (fl
->l_len
== 0)
1072 oadd
= fl
->l_len
- 1;
1074 if (oadd
> OFF_MAX
- start
)
1079 smb_makescred(&scred
, l
, l
? l
->l_cred
: NULL
);
1082 switch (fl
->l_type
) {
1084 lkop
= SMB_LOCK_EXCL
;
1087 lkop
= SMB_LOCK_SHARED
;
1090 lkop
= SMB_LOCK_RELEASE
;
1095 error
= lf_advlock(ap
, &np
->n_lockf
, size
);
1099 * The ID we use for smb_lock is passed as PID to SMB
1100 * server. It MUST agree with PID as setup in basic
1101 * SMB header in later write requests, otherwise SMB server
1102 * returns EDEADLK. See also smb_rq_new() on SMB header setup.
1104 error
= smbfs_smb_lock(np
, lkop
,(void *)1, start
, end
, &scred
);
1107 lf_advlock(ap
, &np
->n_lockf
, size
);
1111 lf_advlock(ap
, &np
->n_lockf
, size
);
1112 error
= smbfs_smb_lock(np
, SMB_LOCK_RELEASE
, ap
->a_id
, start
, end
, &scred
);
1115 error
= lf_advlock(ap
, &np
->n_lockf
, size
);
1125 smbfs_pathcheck(struct smbmount
*smp
, const char *name
, int nmlen
)
1127 static const char * const badchars
= "*/\\:<>;?";
1128 static const char * const badchars83
= " +|,[]=";
1132 if (SMB_DIALECT(SSTOVC(smp
->sm_share
)) < SMB_DIALECT_LANMAN2_0
) {
1134 * Name should conform 8.3 format
1137 return (ENAMETOOLONG
);
1139 if ((cp
= memchr(name
, '.', nmlen
)) == NULL
1140 || cp
== name
|| (cp
- name
) > 8
1141 || (cp
= memchr(cp
+ 1, '.', nmlen
- (cp
- name
))) != NULL
)
1144 for (cp
= name
, i
= 0; i
< nmlen
; i
++, cp
++)
1145 if (strchr(badchars83
, *cp
) != NULL
)
1149 for (cp
= name
, i
= 0; i
< nmlen
; i
++, cp
++)
1150 if (strchr(badchars
, *cp
) != NULL
)
1161 * Things go even weird without fixed inode numbers...
1164 smbfs_lookup(void *v
)
1166 struct vop_lookup_args
/* {
1167 struct vnode *a_dvp;
1168 struct vnode **a_vpp;
1169 struct componentname *a_cnp;
1171 struct componentname
*cnp
= ap
->a_cnp
;
1172 struct vnode
*dvp
= ap
->a_dvp
;
1173 struct vnode
**vpp
= ap
->a_vpp
;
1174 struct mount
*mp
= dvp
->v_mount
;
1175 struct smbnode
*dnp
;
1176 struct smbfattr fattr
;
1177 struct smb_cred scred
;
1178 const char *name
= cnp
->cn_nameptr
;
1179 int flags
= cnp
->cn_flags
;
1180 int nameiop
= cnp
->cn_nameiop
;
1181 int nmlen
= cnp
->cn_namelen
;
1182 int error
, islastcn
, isdot
;
1185 * Check accessiblity of directory.
1187 error
= VOP_ACCESS(dvp
, VEXEC
, cnp
->cn_cred
);
1191 if ((cnp
->cn_flags
& ISLASTCN
) &&
1192 (dvp
->v_mount
->mnt_flag
& MNT_RDONLY
) &&
1193 (cnp
->cn_nameiop
== DELETE
|| cnp
->cn_nameiop
== RENAME
))
1196 SMBVDEBUG("%d '%.*s' in '%.*s'\n", nameiop
, nmlen
, name
,
1197 (int) VTOSMB(dvp
)->n_nmlen
, VTOSMB(dvp
)->n_name
);
1199 islastcn
= flags
& ISLASTCN
;
1202 * Before tediously performing a linear scan of the directory,
1203 * check the name cache to see if the directory/name pair
1204 * we are looking for is known already.
1205 * If the directory/name pair is found in the name cache,
1206 * we have to ensure the directory has not changed from
1207 * the time the cache entry has been created. If it has,
1208 * the cache entry has to be ignored.
1210 if ((error
= cache_lookup(dvp
, vpp
, cnp
)) >= 0) {
1212 struct vnode
*newvp
;
1215 if (error
&& error
!= ENOENT
) {
1220 err2
= VOP_ACCESS(dvp
, VEXEC
, cnp
->cn_cred
);
1232 if (error
== ENOENT
) {
1233 if (!VOP_GETATTR(dvp
, &vattr
, cnp
->cn_cred
)
1234 && vattr
.va_mtime
.tv_sec
== VTOSMB(dvp
)->n_nctime
)
1237 VTOSMB(dvp
)->n_nctime
= 0;
1242 if (!VOP_GETATTR(newvp
, &vattr
, cnp
->cn_cred
)
1243 && vattr
.va_ctime
.tv_sec
== VTOSMB(newvp
)->n_ctime
)
1245 /* nfsstats.lookupcache_hits++; */
1246 if (cnp
->cn_nameiop
!= LOOKUP
&& islastcn
)
1247 cnp
->cn_flags
|= SAVENAME
;
1262 /* ensure the name is sane */
1263 if (nameiop
!= LOOKUP
) {
1264 error
= smbfs_pathcheck(VFSTOSMBFS(mp
), cnp
->cn_nameptr
,
1271 isdot
= (nmlen
== 1 && name
[0] == '.');
1274 * entry is not in the cache or has been expired
1276 smb_makescred(&scred
, curlwp
, cnp
->cn_cred
);
1277 if (flags
& ISDOTDOT
)
1278 error
= smbfs_smb_lookup(VTOSMB(dnp
->n_parent
), NULL
, 0,
1281 error
= smbfs_smb_lookup(dnp
, name
, nmlen
, &fattr
, &scred
);
1286 if (error
!= ENOENT
)
1290 * Handle RENAME or CREATE case...
1292 if ((nameiop
== CREATE
|| nameiop
== RENAME
) && islastcn
) {
1294 * Access for write is interpreted as allowing
1295 * creation of files in the directory.
1297 error
= VOP_ACCESS(dvp
, VWRITE
, cnp
->cn_cred
);
1301 cnp
->cn_flags
|= SAVENAME
;
1302 return (EJUSTRETURN
);
1306 * Insert name into cache (as non-existent) if appropriate.
1308 if ((cnp
->cn_flags
& MAKEENTRY
) && nameiop
!= CREATE
)
1309 cache_enter(dvp
, *vpp
, cnp
);
1316 /* Handle RENAME case... */
1317 if (nameiop
== RENAME
&& islastcn
) {
1318 error
= VOP_ACCESS(dvp
, VWRITE
, cnp
->cn_cred
);
1324 if (flags
& ISDOTDOT
)
1326 error
= smbfs_nget(mp
, dvp
, name
, nmlen
, &fattr
, vpp
);
1327 if (flags
& ISDOTDOT
)
1328 vn_lock(dvp
, LK_EXCLUSIVE
| LK_RETRY
);
1331 cnp
->cn_flags
|= SAVENAME
;
1342 } else if (flags
& ISDOTDOT
) {
1348 error
= smbfs_nget(mp
, dvp
, name
, nmlen
, NULL
, vpp
);
1349 vn_lock(dvp
, LK_EXCLUSIVE
| LK_RETRY
);
1357 error
= smbfs_nget(mp
, dvp
, name
, nmlen
, &fattr
, vpp
);
1362 if (cnp
->cn_nameiop
!= LOOKUP
&& (flags
& ISLASTCN
))
1363 cnp
->cn_flags
|= SAVENAME
;
1365 if ((cnp
->cn_flags
& MAKEENTRY
)) {
1366 KASSERT(error
== 0);
1367 if (cnp
->cn_nameiop
!= DELETE
|| !islastcn
) {
1368 VTOSMB(*vpp
)->n_ctime
= VTOSMB(*vpp
)->n_mtime
.tv_sec
;
1369 cache_enter(dvp
, *vpp
, cnp
);
1371 } else if (error
== ENOENT
&& cnp
->cn_nameiop
!= CREATE
) {
1372 VTOSMB(*vpp
)->n_nctime
= VTOSMB(*vpp
)->n_mtime
.tv_sec
;
1373 cache_enter(dvp
, *vpp
, cnp
);