1 /* $NetBSD: smbfs_vnops.c,v 1.42 2004/03/22 16:40:48 jdolecek Exp $ */
2
3 /*-
4 * Copyright (c) 2003 The NetBSD Foundation, Inc.
5 * All rights reserved.
6 *
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Jaromir Dolecek.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
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.
18 * 3. All advertising materials mentioning features or use of this software
19 * must display the following acknowledgement:
20 * This product includes software developed by the NetBSD
21 * Foundation, Inc. and its contributors.
22 * 4. Neither the name of The NetBSD Foundation nor the names of its
23 * contributors may be used to endorse or promote products derived
24 * from this software without specific prior written permission.
25 *
26 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
27 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
28 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
29 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
30 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
31 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
32 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
33 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
34 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
35 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
36 * POSSIBILITY OF SUCH DAMAGE.
37 */
38
39 /*
40 * Copyright (c) 2000-2001 Boris Popov
41 * All rights reserved.
42 *
43 * Redistribution and use in source and binary forms, with or without
44 * modification, are permitted provided that the following conditions
45 * are met:
46 * 1. Redistributions of source code must retain the above copyright
47 * notice, this list of conditions and the following disclaimer.
48 * 2. Redistributions in binary form must reproduce the above copyright
49 * notice, this list of conditions and the following disclaimer in the
50 * documentation and/or other materials provided with the distribution.
51 * 3. All advertising materials mentioning features or use of this software
52 * must display the following acknowledgement:
53 * This product includes software developed by Boris Popov.
54 * 4. Neither the name of the author nor the names of any co-contributors
55 * may be used to endorse or promote products derived from this software
56 * without specific prior written permission.
57 *
58 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
59 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
60 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
61 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
62 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
63 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
64 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
65 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
66 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
67 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
68 * SUCH DAMAGE.
69 *
70 * FreeBSD: src/sys/fs/smbfs/smbfs_vnops.c,v 1.15 2001/12/20 15:56:45 bp Exp
71 */
72
73 #include <sys/cdefs.h>
74 __KERNEL_RCSID(0, "$NetBSD: smbfs_vnops.c,v 1.42 2004/03/22 16:40:48 jdolecek Exp $");
75
76 #include <sys/param.h>
77 #include <sys/systm.h>
78 #include <sys/namei.h>
79 #include <sys/kernel.h>
80 #include <sys/proc.h>
81 #include <sys/buf.h>
82 #include <sys/fcntl.h>
83 #include <sys/mount.h>
84 #include <sys/unistd.h>
85 #include <sys/vnode.h>
86 #include <sys/lockf.h>
87
88 #include <machine/limits.h>
89
90 #include <uvm/uvm.h>
91 #include <uvm/uvm_extern.h>
92
93 #include <netsmb/smb.h>
94 #include <netsmb/smb_conn.h>
95 #include <netsmb/smb_subr.h>
96
97 #include <fs/smbfs/smbfs.h>
98 #include <fs/smbfs/smbfs_node.h>
99 #include <fs/smbfs/smbfs_subr.h>
100
101 #include <miscfs/genfs/genfs.h>
102
103 /*
104 * Prototypes for SMBFS vnode operations
105 */
106 int smbfs_create(void *);
107 int smbfs_open(void *);
108 int smbfs_close(void *);
109 int smbfs_access(void *);
110 int smbfs_getattr(void *);
111 int smbfs_setattr(void *);
112 int smbfs_read(void *);
113 int smbfs_write(void *);
114 int smbfs_fsync(void *);
115 int smbfs_remove(void *);
116 int smbfs_link(void *);
117 int smbfs_lookup(void *);
118 int smbfs_rename(void *);
119 int smbfs_mkdir(void *);
120 int smbfs_rmdir(void *);
121 int smbfs_symlink(void *);
122 int smbfs_readdir(void *);
123 int smbfs_strategy(void *);
124 int smbfs_print(void *);
125 int smbfs_pathconf(void *ap);
126 int smbfs_advlock(void *);
127
128 int (**smbfs_vnodeop_p) __P((void *));
129 static struct vnodeopv_entry_desc smbfs_vnodeop_entries[] = {
130 { &vop_default_desc, vn_default_error },
131 { &vop_access_desc, smbfs_access },
132 { &vop_advlock_desc, smbfs_advlock },
133 { &vop_close_desc, smbfs_close },
134 { &vop_create_desc, smbfs_create },
135 { &vop_fsync_desc, smbfs_fsync },
136 { &vop_getattr_desc, smbfs_getattr },
137 { &vop_getpages_desc, genfs_compat_getpages },
138 { &vop_inactive_desc, smbfs_inactive },
139 { &vop_ioctl_desc, genfs_enoioctl },
140 { &vop_islocked_desc, genfs_islocked },
141 { &vop_link_desc, smbfs_link },
142 { &vop_lock_desc, genfs_lock },
143 { &vop_lookup_desc, smbfs_lookup },
144 { &vop_mkdir_desc, smbfs_mkdir },
145 { &vop_mknod_desc, genfs_eopnotsupp },
146 { &vop_open_desc, smbfs_open },
147 { &vop_pathconf_desc, smbfs_pathconf },
148 { &vop_print_desc, smbfs_print },
149 { &vop_putpages_desc, genfs_putpages },
150 { &vop_read_desc, smbfs_read },
151 { &vop_readdir_desc, smbfs_readdir },
152 { &vop_reclaim_desc, smbfs_reclaim },
153 { &vop_remove_desc, smbfs_remove },
154 { &vop_rename_desc, smbfs_rename },
155 { &vop_rmdir_desc, smbfs_rmdir },
156 { &vop_setattr_desc, smbfs_setattr },
157 { &vop_strategy_desc, smbfs_strategy },
158 { &vop_symlink_desc, smbfs_symlink },
159 { &vop_unlock_desc, genfs_unlock },
160 { &vop_write_desc, smbfs_write },
161 { &vop_mmap_desc, genfs_mmap }, /* mmap */
162 { &vop_seek_desc, genfs_seek }, /* seek */
163 { &vop_kqfilter_desc, smbfs_kqfilter}, /* kqfilter */
164 { NULL, NULL }
165 };
166 const struct vnodeopv_desc smbfs_vnodeop_opv_desc =
167 { &smbfs_vnodeop_p, smbfs_vnodeop_entries };
168
169 int
170 smbfs_access(v)
171 void *v;
172 {
173 struct vop_access_args /* {
174 struct vnode *a_vp;
175 int a_mode;
176 struct ucred *a_cred;
177 struct proc *a_p;
178 } */ *ap = v;
179 struct vnode *vp = ap->a_vp;
180 #ifdef SMB_VNODE_DEBUG
181 struct smbnode *np = VTOSMB(vp);
182 #endif
183 u_int acc_mode = ap->a_mode;
184 struct smbmount *smp = VTOSMBFS(vp);
185
186 SMBVDEBUG("file '%.*s', node mode=%o, acc mode=%x\n",
187 (int) np->n_nmlen, np->n_name,
188 (vp->v_type == VDIR) ? smp->sm_args.dir_mode : smp->sm_args.file_mode,
189 acc_mode);
190
191 /*
192 * Disallow write attempts on read-only file systems;
193 * unless the file is a socket, fifo, or a block or
194 * character device resident on the file system.
195 */
196 if (acc_mode & VWRITE) {
197 switch (vp->v_type) {
198 case VREG:
199 case VDIR:
200 case VLNK:
201 if (vp->v_mount->mnt_flag & MNT_RDONLY)
202 return EROFS;
203 default:
204 break;
205 }
206 }
207
208 return (vaccess(vp->v_type,
209 (vp->v_type == VDIR) ? smp->sm_args.dir_mode : smp->sm_args.file_mode,
210 smp->sm_args.uid, smp->sm_args.gid,
211 acc_mode, ap->a_cred));
212 }
213
214 /* ARGSUSED */
215 int
216 smbfs_open(v)
217 void *v;
218 {
219 struct vop_open_args /* {
220 struct vnode *a_vp;
221 int a_mode;
222 struct ucred *a_cred;
223 struct proc *a_p;
224 } */ *ap = v;
225 struct vnode *vp = ap->a_vp;
226 struct smbnode *np = VTOSMB(vp);
227 struct smb_cred scred;
228 struct vattr vattr;
229 u_int32_t sv_caps = SMB_CAPS(SSTOVC(np->n_mount->sm_share));
230 int error, accmode;
231
232 SMBVDEBUG("%.*s,%d\n", (int) np->n_nmlen, np->n_name,
233 (np->n_flag & NOPEN) != 0);
234 if (vp->v_type != VREG && vp->v_type != VDIR) {
235 SMBFSERR("open eacces vtype=%d\n", vp->v_type);
236 return EACCES;
237 }
238 if (vp->v_type == VDIR) {
239 if ((sv_caps & SMB_CAP_NT_SMBS) == 0) {
240 np->n_flag |= NOPEN;
241 return 0;
242 }
243
244 goto do_open; /* skip 'modified' check */
245 }
246
247 if (np->n_flag & NMODIFIED) {
248 if ((error = smbfs_vinvalbuf(vp, V_SAVE, ap->a_cred, ap->a_p, 1)) == EINTR)
249 return error;
250 smbfs_attr_cacheremove(vp);
251 error = VOP_GETATTR(vp, &vattr, ap->a_cred, ap->a_p);
252 if (error)
253 return error;
254 np->n_mtime.tv_sec = vattr.va_mtime.tv_sec;
255 } else {
256 error = VOP_GETATTR(vp, &vattr, ap->a_cred, ap->a_p);
257 if (error)
258 return error;
259 if (np->n_mtime.tv_sec != vattr.va_mtime.tv_sec) {
260 error = smbfs_vinvalbuf(vp, V_SAVE, ap->a_cred, ap->a_p, 1);
261 if (error == EINTR)
262 return error;
263 np->n_mtime.tv_sec = vattr.va_mtime.tv_sec;
264 }
265 }
266
267 do_open:
268 if ((np->n_flag & NOPEN) != 0)
269 return 0;
270
271 smb_makescred(&scred, ap->a_p, ap->a_cred);
272 if (vp->v_type == VDIR)
273 error = smbfs_smb_ntcreatex(np, SMB_AM_OPENREAD, &scred);
274 else {
275 accmode = SMB_AM_OPENREAD;
276 if ((vp->v_mount->mnt_flag & MNT_RDONLY) == 0)
277 accmode = SMB_AM_OPENRW;
278 error = smbfs_smb_open(np, accmode, &scred);
279 if (error) {
280 if (ap->a_mode & FWRITE)
281 return EACCES;
282
283 error = smbfs_smb_open(np, SMB_AM_OPENREAD, &scred);
284 }
285 }
286 if (!error)
287 np->n_flag |= NOPEN;
288 smbfs_attr_cacheremove(vp);
289 return error;
290 }
291
292 /*
293 * Close called.
294 */
295 int
296 smbfs_close(v)
297 void *v;
298 {
299 struct vop_close_args /* {
300 struct vnodeop_desc *a_desc;
301 struct vnode *a_vp;
302 int a_fflag;
303 struct ucred *a_cred;
304 struct proc *a_p;
305 } */ *ap = v;
306 int error;
307 struct vnode *vp = ap->a_vp;
308 struct smbnode *np = VTOSMB(vp);
309
310 /* Flush all file data */
311 error = smbfs_vinvalbuf(vp, V_SAVE, ap->a_cred, ap->a_p, 1);
312 if (error)
313 return (error);
314
315 /*
316 * We must close the directory lookup context now, so that
317 * later directory changes would be properly detected.
318 * Ideally, the lookup routines should handle such case, and
319 * the context would be removed only in smbfs_inactive().
320 */
321 if (vp->v_type == VDIR && (np->n_flag & NOPEN) != 0 &&
322 np->n_dirseq != NULL) {
323 struct smb_cred scred;
324
325 smb_makescred(&scred, ap->a_p, ap->a_cred);
326 smbfs_findclose(np->n_dirseq, &scred);
327 np->n_dirseq = NULL;
328 }
329
330 return (0);
331 }
332
333 /*
334 * smbfs_getattr call from vfs.
335 */
336 int
337 smbfs_getattr(v)
338 void *v;
339 {
340 struct vop_getattr_args /* {
341 struct vnode *a_vp;
342 struct vattr *a_vap;
343 struct ucred *a_cred;
344 struct proc *p;
345 } */ *ap = v;
346 struct vnode *vp = ap->a_vp;
347 struct smbnode *np = VTOSMB(vp);
348 struct vattr *va=ap->a_vap;
349 struct smbfattr fattr;
350 struct smb_cred scred;
351 u_quad_t oldsize;
352 int error;
353
354 SMBVDEBUG("%p: '%.*s' isroot %d\n", vp,
355 (int) np->n_nmlen, np->n_name, (vp->v_flag & VROOT) != 0);
356
357 if ((error = smbfs_attr_cachelookup(vp, va)) == 0)
358 return (0);
359
360 SMBVDEBUG("not in the cache\n");
361 smb_makescred(&scred, ap->a_p, ap->a_cred);
362 oldsize = np->n_size;
363 error = smbfs_smb_lookup(np, NULL, 0, &fattr, &scred);
364 if (error) {
365 SMBVDEBUG("error %d\n", error);
366 return error;
367 }
368 smbfs_attr_cacheenter(vp, &fattr);
369 smbfs_attr_cachelookup(vp, va);
370 if ((np->n_flag & NOPEN) != 0)
371 np->n_size = oldsize;
372 return 0;
373 }
374
375 int
376 smbfs_setattr(v)
377 void *v;
378 {
379 struct vop_setattr_args /* {
380 struct vnode *a_vp;
381 struct vattr *a_vap;
382 struct ucred *a_cred;
383 struct proc *p;
384 } */ *ap = v;
385 struct vnode *vp = ap->a_vp;
386 struct smbnode *np = VTOSMB(vp);
387 struct vattr *vap = ap->a_vap;
388 struct timespec *mtime, *atime;
389 struct smb_cred scred;
390 struct smb_share *ssp = np->n_mount->sm_share;
391 struct smb_vc *vcp = SSTOVC(ssp);
392 u_quad_t tsize = 0;
393 int isreadonly, doclose, error = 0;
394
395 SMBVDEBUG("\n");
396 if (vap->va_flags != VNOVAL)
397 return EOPNOTSUPP;
398 isreadonly = (vp->v_mount->mnt_flag & MNT_RDONLY);
399 /*
400 * Disallow write attempts if the filesystem is mounted read-only.
401 */
402 if ((vap->va_uid != (uid_t)VNOVAL || vap->va_gid != (gid_t)VNOVAL ||
403 vap->va_atime.tv_sec != VNOVAL || vap->va_mtime.tv_sec != VNOVAL ||
404 vap->va_mode != (mode_t)VNOVAL) && isreadonly)
405 return EROFS;
406 smb_makescred(&scred, ap->a_p, ap->a_cred);
407 if (vap->va_size != VNOVAL) {
408 switch (vp->v_type) {
409 case VDIR:
410 return EISDIR;
411 case VREG:
412 break;
413 default:
414 return EINVAL;
415 };
416 if (isreadonly)
417 return EROFS;
418 doclose = 0;
419 tsize = np->n_size;
420 np->n_size = vap->va_size;
421 uvm_vnp_setsize(vp, vap->va_size);
422 if ((np->n_flag & NOPEN) == 0) {
423 error = smbfs_smb_open(np, SMB_AM_OPENRW, &scred);
424 if (error == 0)
425 doclose = 1;
426 }
427 if (error == 0)
428 error = smbfs_smb_setfsize(np, vap->va_size, &scred);
429 if (doclose)
430 smbfs_smb_close(ssp, np->n_fid, NULL, &scred);
431 if (error) {
432 np->n_size = tsize;
433 uvm_vnp_setsize(vp, tsize);
434 return (error);
435 }
436 }
437 mtime = atime = NULL;
438 if (vap->va_mtime.tv_sec != VNOVAL)
439 mtime = &vap->va_mtime;
440 if (vap->va_atime.tv_sec != VNOVAL)
441 atime = &vap->va_atime;
442 if (mtime != atime) {
443 if (ap->a_cred->cr_uid != VTOSMBFS(vp)->sm_args.uid &&
444 (error = suser(ap->a_cred, &ap->a_p->p_acflag)) &&
445 ((vap->va_vaflags & VA_UTIMES_NULL) == 0 ||
446 (error = VOP_ACCESS(ap->a_vp, VWRITE, ap->a_cred, ap->a_p))))
447 return (error);
448
449 #if 0
450 if (mtime == NULL)
451 mtime = &np->n_mtime;
452 if (atime == NULL)
453 atime = &np->n_atime;
454 #endif
455 /*
456 * If file is opened, then we can use handle based calls.
457 * If not, use path based ones.
458 */
459 if ((np->n_flag & NOPEN) == 0) {
460 if (vcp->vc_flags & SMBV_WIN95) {
461 error = VOP_OPEN(vp, FWRITE, ap->a_cred, ap->a_p);
462 if (!error) {
463 /* error = smbfs_smb_setfattrNT(np, 0, mtime, atime, &scred);
464 VOP_GETATTR(vp, &vattr, ap->a_cred, ap->a_p);*/
465 if (mtime)
466 np->n_mtime = *mtime;
467 VOP_CLOSE(vp, FWRITE, ap->a_cred, ap->a_p);
468 }
469 } else if (SMB_CAPS(vcp) & SMB_CAP_NT_SMBS) {
470 error = smbfs_smb_setptime2(np, mtime, atime, 0, &scred);
471 /* error = smbfs_smb_setpattrNT(np, 0, mtime, atime, &scred);*/
472 } else if (SMB_DIALECT(vcp) >= SMB_DIALECT_LANMAN2_0) {
473 error = smbfs_smb_setptime2(np, mtime, atime, 0, &scred);
474 } else {
475 error = smbfs_smb_setpattr(np, 0, mtime, &scred);
476 }
477 } else {
478 if (SMB_CAPS(vcp) & SMB_CAP_NT_SMBS) {
479 error = smbfs_smb_setfattrNT(np, 0, mtime, atime, &scred);
480 } else if (SMB_DIALECT(vcp) >= SMB_DIALECT_LANMAN1_0) {
481 error = smbfs_smb_setftime(np, mtime, atime, &scred);
482 } else {
483 /*
484 * XXX I have no idea how to handle this for core
485 * level servers. The possible solution is to
486 * update mtime after file is closed.
487 */
488 }
489 }
490 }
491 /*
492 * Invalidate attribute cache in case if server doesn't set
493 * required attributes.
494 */
495 smbfs_attr_cacheremove(vp); /* invalidate cache */
496 VOP_GETATTR(vp, vap, ap->a_cred, ap->a_p);
497 np->n_mtime.tv_sec = vap->va_mtime.tv_sec;
498 VN_KNOTE(vp, NOTE_ATTRIB);
499 return error;
500 }
501 /*
502 * smbfs_read call.
503 */
504 int
505 smbfs_read(v)
506 void *v;
507 {
508 struct vop_read_args /* {
509 struct vnode *a_vp;
510 struct uio *a_uio;
511 int a_ioflag;
512 struct ucred *a_cred;
513 } */ *ap = v;
514 struct vnode *vp = ap->a_vp;
515
516 if (vp->v_type != VREG && vp->v_type != VDIR)
517 return EPERM;
518
519 return smbfs_readvnode(vp, ap->a_uio, ap->a_cred);
520 }
521
522 int
523 smbfs_write(v)
524 void *v;
525 {
526 struct vop_write_args /* {
527 struct vnode *a_vp;
528 struct uio *a_uio;
529 int a_ioflag;
530 struct ucred *a_cred;
531 } */ *ap = v;
532 struct vnode *vp = ap->a_vp;
533 struct uio *uio = ap->a_uio;
534
535 SMBVDEBUG("%d,ofs=%lld,sz=%u\n",vp->v_type, (long long int)uio->uio_offset, uio->uio_resid);
536 if (vp->v_type != VREG)
537 return (EPERM);
538 return smbfs_writevnode(vp, uio, ap->a_cred, ap->a_ioflag);
539 }
540 /*
541 * smbfs_create call
542 * Create a regular file. On entry the directory to contain the file being
543 * created is locked. We must release before we return. We must also free
544 * the pathname buffer pointed at by cnp->cn_pnbuf, always on error, or
545 * only if the SAVESTART bit in cn_flags is clear on success.
546 */
547 int
548 smbfs_create(v)
549 void *v;
550 {
551 struct vop_create_args /* {
552 struct vnode *a_dvp;
553 struct vnode **a_vpp;
554 struct componentname *a_cnp;
555 struct vattr *a_vap;
556 } */ *ap = v;
557 struct vnode *dvp = ap->a_dvp;
558 struct vattr *vap = ap->a_vap;
559 struct componentname *cnp = ap->a_cnp;
560 struct smbnode *dnp = VTOSMB(dvp);
561 struct smbfattr fattr;
562 struct smb_cred scred;
563 const char *name = cnp->cn_nameptr;
564 int nmlen = cnp->cn_namelen;
565 int error = EINVAL;
566
567
568 if (vap->va_type != VREG)
569 goto out;
570
571 smb_makescred(&scred, cnp->cn_proc, cnp->cn_cred);
572 error = smbfs_smb_create(dnp, name, nmlen, &scred);
573 if (error)
574 goto out;
575
576 error = smbfs_smb_lookup(dnp, name, nmlen, &fattr, &scred);
577 if (error)
578 goto out;
579 error = smbfs_nget(VTOVFS(dvp), dvp, name, nmlen, &fattr, ap->a_vpp);
580 if (error)
581 goto out;
582
583 /* No error */
584 if (cnp->cn_flags & MAKEENTRY)
585 cache_enter(dvp, *ap->a_vpp, cnp);
586
587 out:
588 if (error || ((cnp->cn_flags & SAVESTART) == 0))
589 PNBUF_PUT(cnp->cn_pnbuf);
590 VN_KNOTE(dvp, NOTE_WRITE);
591 vput(dvp);
592 return (error);
593
594
595 }
596
597 int
598 smbfs_remove(v)
599 void *v;
600 {
601 struct vop_remove_args /* {
602 struct vnodeop_desc *a_desc;
603 struct vnode * a_dvp;
604 struct vnode * a_vp;
605 struct componentname * a_cnp;
606 } */ *ap = v;
607 struct vnode *vp = ap->a_vp;
608 struct vnode *dvp = ap->a_dvp;
609 struct componentname *cnp = ap->a_cnp;
610 struct smbnode *np = VTOSMB(vp);
611 struct smb_cred scred;
612 int error;
613
614 if (vp->v_type == VDIR || (np->n_flag & NOPEN) != 0
615 || vp->v_usecount != 1) {
616 /* XXX Eventually should do something along NFS sillyrename */
617 error = EPERM;
618 } else {
619 smb_makescred(&scred, cnp->cn_proc, cnp->cn_cred);
620 error = smbfs_smb_delete(np, &scred);
621 }
622
623 VN_KNOTE(ap->a_vp, NOTE_DELETE);
624 VN_KNOTE(ap->a_dvp, NOTE_WRITE);
625 if (dvp == vp)
626 vrele(vp);
627 else
628 vput(vp);
629 vput(dvp);
630 return (error);
631 }
632
633 /*
634 * smbfs_file rename call
635 */
636 int
637 smbfs_rename(v)
638 void *v;
639 {
640 struct vop_rename_args /* {
641 struct vnode *a_fdvp;
642 struct vnode *a_fvp;
643 struct componentname *a_fcnp;
644 struct vnode *a_tdvp;
645 struct vnode *a_tvp;
646 struct componentname *a_tcnp;
647 } */ *ap = v;
648 struct vnode *fvp = ap->a_fvp;
649 struct vnode *tvp = ap->a_tvp;
650 struct vnode *fdvp = ap->a_fdvp;
651 struct vnode *tdvp = ap->a_tdvp;
652 struct componentname *tcnp = ap->a_tcnp;
653 /* struct componentname *fcnp = ap->a_fcnp;*/
654 struct smb_cred scred;
655 #ifdef notyet
656 u_int16_t flags = 6;
657 #endif
658 int error=0;
659
660 /* Check for cross-device rename */
661 if ((fvp->v_mount != tdvp->v_mount) ||
662 (tvp && (fvp->v_mount != tvp->v_mount))) {
663 error = EXDEV;
664 goto out;
665 }
666
667 if (tvp && tvp->v_usecount > 1) {
668 error = EBUSY;
669 goto out;
670 }
671 #ifdef notnow
672 flags = 0x10; /* verify all writes */
673 if (fvp->v_type == VDIR) {
674 flags |= 2;
675 } else if (fvp->v_type == VREG) {
676 flags |= 1;
677 } else {
678 error = EINVAL;
679 goto out;
680 }
681 #endif
682 smb_makescred(&scred, tcnp->cn_proc, tcnp->cn_cred);
683 /*
684 * It seems that Samba doesn't implement SMB_COM_MOVE call...
685 */
686 #ifdef notnow
687 if (SMB_DIALECT(SSTOCN(smp->sm_share)) >= SMB_DIALECT_LANMAN1_0) {
688 error = smbfs_smb_move(VTOSMB(fvp), VTOSMB(tdvp),
689 tcnp->cn_nameptr, tcnp->cn_namelen, flags, &scred);
690 } else
691 #endif
692 {
693 /*
694 * We have to do the work atomicaly
695 */
696 if (tvp && tvp != fvp) {
697 error = smbfs_smb_delete(VTOSMB(tvp), &scred);
698 if (error)
699 goto out;
700 VN_KNOTE(tdvp, NOTE_WRITE);
701 VN_KNOTE(tvp, NOTE_DELETE);
702 cache_purge(tvp);
703 }
704 error = smbfs_smb_rename(VTOSMB(fvp), VTOSMB(tdvp),
705 tcnp->cn_nameptr, tcnp->cn_namelen, &scred);
706 VN_KNOTE(fdvp, NOTE_WRITE);
707 VN_KNOTE(fvp, NOTE_RENAME);
708 }
709
710 if (fvp->v_type == VDIR) {
711 if (tvp != NULL && tvp->v_type == VDIR)
712 cache_purge(tdvp);
713 cache_purge(fdvp);
714 }
715
716 smbfs_attr_cacheremove(fdvp);
717 smbfs_attr_cacheremove(tdvp);
718
719 out:
720
721 if (tdvp == tvp)
722 vrele(tdvp);
723 else
724 vput(tdvp);
725 if (tvp)
726 vput(tvp);
727
728 vrele(fdvp);
729 vrele(fvp);
730
731 return (error);
732 }
733
734 /*
735 * somtime it will come true...
736 */
737 int
738 smbfs_link(v)
739 void *v;
740 {
741 return genfs_eopnotsupp(v);
742 }
743
744 /*
745 * smbfs_symlink link create call.
746 * Sometime it will be functional...
747 */
748 int
749 smbfs_symlink(v)
750 void *v;
751 {
752 return genfs_eopnotsupp(v);
753 }
754
755 int
756 smbfs_mkdir(v)
757 void *v;
758 {
759 struct vop_mkdir_args /* {
760 struct vnode *a_dvp;
761 struct vnode **a_vpp;
762 struct componentname *a_cnp;
763 struct vattr *a_vap;
764 } */ *ap = v;
765 struct vnode *dvp = ap->a_dvp;
766 /* struct vattr *vap = ap->a_vap;*/
767 struct vnode *vp;
768 struct componentname *cnp = ap->a_cnp;
769 struct smbnode *dnp = VTOSMB(dvp);
770 struct smb_cred scred;
771 struct smbfattr fattr;
772 const char *name = cnp->cn_nameptr;
773 int len = cnp->cn_namelen;
774 int error;
775
776 if ((name[0] == '.') && ((len == 1) || ((len == 2) && (name[1] == '.')))){
777 error = EEXIST;
778 goto out;
779 }
780
781 smb_makescred(&scred, cnp->cn_proc, cnp->cn_cred);
782 error = smbfs_smb_mkdir(dnp, name, len, &scred);
783 if (error)
784 goto out;
785 error = smbfs_smb_lookup(dnp, name, len, &fattr, &scred);
786 if (error)
787 goto out;
788 error = smbfs_nget(VTOVFS(dvp), dvp, name, len, &fattr, &vp);
789 if (error)
790 goto out;
791 *ap->a_vpp = vp;
792
793 out:
794 if (error || ((cnp->cn_flags & SAVESTART) == 0))
795 PNBUF_PUT(cnp->cn_pnbuf);
796 VN_KNOTE(dvp, NOTE_WRITE | NOTE_LINK);
797 vput(dvp);
798
799 return (error);
800 }
801
802 /*
803 * smbfs_remove directory call
804 */
805 int
806 smbfs_rmdir(v)
807 void *v;
808 {
809 struct vop_rmdir_args /* {
810 struct vnode *a_dvp;
811 struct vnode *a_vp;
812 struct componentname *a_cnp;
813 } */ *ap = v;
814 struct vnode *vp = ap->a_vp;
815 struct vnode *dvp = ap->a_dvp;
816 struct componentname *cnp = ap->a_cnp;
817 /* struct smbmount *smp = VTOSMBFS(vp);*/
818 struct smbnode *dnp = VTOSMB(dvp);
819 struct smbnode *np = VTOSMB(vp);
820 struct smb_cred scred;
821 int error;
822
823 if (dvp == vp) {
824 vrele(dvp);
825 vput(dvp);
826 return (EINVAL);
827 }
828
829 smb_makescred(&scred, cnp->cn_proc, cnp->cn_cred);
830 error = smbfs_smb_rmdir(np, &scred);
831 dnp->n_flag |= NMODIFIED;
832 smbfs_attr_cacheremove(dvp);
833 VN_KNOTE(dvp, NOTE_WRITE | NOTE_LINK);
834 VN_KNOTE(vp, NOTE_DELETE);
835 cache_purge(dvp);
836 cache_purge(vp);
837 vput(vp);
838 vput(dvp);
839
840 return (error);
841 }
842
843 /*
844 * smbfs_readdir call
845 */
846 int
847 smbfs_readdir(v)
848 void *v;
849 {
850 struct vop_readdir_args /* {
851 struct vnode *a_vp;
852 struct uio *a_uio;
853 struct ucred *a_cred;
854 int *a_eofflag;
855 u_long *a_cookies;
856 int a_ncookies;
857 } */ *ap = v;
858 struct vnode *vp = ap->a_vp;
859
860 if (vp->v_type != VDIR)
861 return (EPERM);
862 #ifdef notnow
863 if (ap->a_ncookies) {
864 printf("smbfs_readdir: no support for cookies now...");
865 return (EOPNOTSUPP);
866 }
867 #endif
868 return (smbfs_readvnode(vp, ap->a_uio, ap->a_cred));
869 }
870
871 /* ARGSUSED */
872 int
873 smbfs_fsync(v)
874 void *v;
875 {
876 /*return (smb_flush(ap->a_vp, ap->a_cred, ap->a_waitfor, ap->a_p, 1));*/
877 return (0);
878 }
879
880 int
881 smbfs_print(v)
882 void *v;
883 {
884 struct vop_print_args /* {
885 struct vnode *a_vp;
886 } */ *ap = v;
887 struct vnode *vp = ap->a_vp;
888 struct smbnode *np = VTOSMB(vp);
889
890 printf("tag VT_SMBFS, name = %.*s, parent = %p, open = %d\n",
891 (int)np->n_nmlen, np->n_name,
892 np->n_parent ? SMBTOV(np->n_parent) : NULL,
893 (np->n_flag & NOPEN) != 0);
894 printf(" ");
895 lockmgr_printinfo(vp->v_vnlock);
896 printf("\n");
897 return (0);
898 }
899
900 int
901 smbfs_pathconf(v)
902 void *v;
903 {
904 struct vop_pathconf_args /* {
905 struct vnode *vp;
906 int a_name;
907 register_t *a_retval;
908 } */ *ap = v;
909 struct smbmount *smp = VFSTOSMBFS(VTOVFS(ap->a_vp));
910 struct smb_vc *vcp = SSTOVC(smp->sm_share);
911 register_t *retval = ap->a_retval;
912 int error = 0;
913
914 switch (ap->a_name) {
915 case _PC_PIPE_BUF:
916 *retval = PIPE_BUF;
917 break;
918 case _PC_SYNC_IO:
919 *retval = 1;
920 break;
921 case _PC_LINK_MAX:
922 *retval = 0;
923 break;
924 case _PC_NAME_MAX:
925 *retval = (vcp->vc_hflags2 & SMB_FLAGS2_KNOWS_LONG_NAMES) ? 255 : 12;
926 break;
927 case _PC_PATH_MAX:
928 *retval = 800; /* XXX: a correct one ? */
929 break;
930 default:
931 error = EINVAL;
932 break;
933 }
934
935 return (error);
936 }
937
938 int
939 smbfs_strategy(v)
940 void *v;
941 {
942 struct vop_strategy_args /* {
943 struct vnode *a_vp;
944 struct buf *a_bp;
945 } */ *ap = v;
946 struct buf *bp = ap->a_bp;
947 struct ucred *cr;
948 struct proc *p;
949 int error = 0;
950
951 SMBVDEBUG("\n");
952 if ((bp->b_flags & (B_PHYS|B_ASYNC)) == (B_PHYS|B_ASYNC))
953 panic("smbfs physio/async");
954 if (bp->b_flags & B_ASYNC)
955 p = NULL;
956 else
957 p = curproc; /* XXX */
958
959 cr = p->p_ucred; /* XXX */
960
961 if ((bp->b_flags & B_ASYNC) == 0)
962 error = smbfs_doio(bp, cr, p);
963
964 return (error);
965 }
966
967 #ifndef __NetBSD__
968 static char smbfs_atl[] = "rhsvda";
969 static int
970 smbfs_getextattr(struct vop_getextattr_args *ap)
971 /* {
972 IN struct vnode *a_vp;
973 IN char *a_name;
974 INOUT struct uio *a_uio;
975 IN struct ucred *a_cred;
976 IN struct proc *p;
977 };
978 */
979 {
980 struct vnode *vp = ap->a_vp;
981 struct proc *p = ap->a_p;
982 struct ucred *cred = ap->a_cred;
983 struct uio *uio = ap->a_uio;
984 const char *name = ap->a_name;
985 struct smbnode *np = VTOSMB(vp);
986 struct vattr vattr;
987 char buf[10];
988 int i, attr, error;
989
990 error = VOP_ACCESS(vp, VREAD, cred, td);
991 if (error)
992 return error;
993 error = VOP_GETATTR(vp, &vattr, cred, td);
994 if (error)
995 return error;
996 if (strcmp(name, "dosattr") == 0) {
997 attr = np->n_dosattr;
998 for (i = 0; i < 6; i++, attr >>= 1)
999 buf[i] = (attr & 1) ? smbfs_atl[i] : '-';
1000 buf[i] = 0;
1001 error = uiomove(buf, i, uio);
1002
1003 } else
1004 error = EINVAL;
1005 return error;
1006 }
1007 #endif /* !__NetBSD__ */
1008
1009 /*
1010 * Since we expected to support F_GETLK (and SMB protocol has no such function),
1011 * it is necessary to use lf_advlock(). It would be nice if this function had
1012 * a callback mechanism because it will help to improve a level of consistency.
1013 */
1014 int
1015 smbfs_advlock(v)
1016 void *v;
1017 {
1018 struct vop_advlock_args /* {
1019 struct vnode *a_vp;
1020 caddr_t a_id;
1021 int a_op;
1022 struct flock *a_fl;
1023 int a_flags;
1024 } */ *ap = v;
1025 struct vnode *vp = ap->a_vp;
1026 struct smbnode *np = VTOSMB(vp);
1027 struct flock *fl = ap->a_fl;
1028 struct proc *p = curproc;
1029 struct smb_cred scred;
1030 u_quad_t size;
1031 off_t start, end, oadd;
1032 int error, lkop;
1033
1034 if (vp->v_type == VDIR) {
1035 /*
1036 * SMB protocol have no support for directory locking.
1037 * Although locks can be processed on local machine, I don't
1038 * think that this is a good idea, because some programs
1039 * can work wrong assuming directory is locked. So, we just
1040 * return 'operation not supported'.
1041 */
1042 return EOPNOTSUPP;
1043 }
1044 size = np->n_size;
1045 switch (fl->l_whence) {
1046
1047 case SEEK_SET:
1048 case SEEK_CUR:
1049 start = fl->l_start;
1050 break;
1051
1052 case SEEK_END:
1053 #ifndef __NetBSD__
1054 if (size > OFF_MAX ||
1055 (fl->l_start > 0 && size > OFF_MAX - fl->l_start))
1056 return EOVERFLOW;
1057 #endif
1058 start = size + fl->l_start;
1059 break;
1060
1061 default:
1062 return EINVAL;
1063 }
1064 if (start < 0)
1065 return EINVAL;
1066 if (fl->l_len < 0) {
1067 if (start == 0)
1068 return EINVAL;
1069 end = start - 1;
1070 start += fl->l_len;
1071 if (start < 0)
1072 return EINVAL;
1073 } else if (fl->l_len == 0)
1074 end = -1;
1075 else {
1076 oadd = fl->l_len - 1;
1077 #ifndef __NetBSD__
1078 if (oadd > OFF_MAX - start)
1079 return EOVERFLOW;
1080 #endif
1081 end = start + oadd;
1082 }
1083 smb_makescred(&scred, p, p ? p->p_ucred : NULL);
1084 switch (ap->a_op) {
1085 case F_SETLK:
1086 switch (fl->l_type) {
1087 case F_WRLCK:
1088 lkop = SMB_LOCK_EXCL;
1089 break;
1090 case F_RDLCK:
1091 lkop = SMB_LOCK_SHARED;
1092 break;
1093 case F_UNLCK:
1094 lkop = SMB_LOCK_RELEASE;
1095 break;
1096 default:
1097 return EINVAL;
1098 }
1099 error = lf_advlock(ap, &np->n_lockf, size);
1100 if (error)
1101 break;
1102 /*
1103 * The ID we use for smb_lock is passed as PID to SMB
1104 * server. It MUST agree with PID as setup in basic
1105 * SMB header in later write requests, otherwise SMB server
1106 * returns EDEADLK. See also smb_rq_new() on SMB header setup.
1107 */
1108 error = smbfs_smb_lock(np, lkop,(caddr_t)1, start, end, &scred);
1109 if (error) {
1110 ap->a_op = F_UNLCK;
1111 lf_advlock(ap, &np->n_lockf, size);
1112 }
1113 break;
1114 case F_UNLCK:
1115 lf_advlock(ap, &np->n_lockf, size);
1116 error = smbfs_smb_lock(np, SMB_LOCK_RELEASE, ap->a_id, start, end, &scred);
1117 break;
1118 case F_GETLK:
1119 error = lf_advlock(ap, &np->n_lockf, size);
1120 break;
1121 default:
1122 return EINVAL;
1123 }
1124
1125 return error;
1126 }
1127
1128 static int
1129 smbfs_pathcheck(struct smbmount *smp, const char *name, int nmlen)
1130 {
1131 static const char * const badchars = "*/\\:<>;?";
1132 static const char * const badchars83 = " +|,[]=";
1133 const char *cp;
1134 int i;
1135
1136 if (SMB_DIALECT(SSTOVC(smp->sm_share)) < SMB_DIALECT_LANMAN2_0) {
1137 /*
1138 * Name should conform 8.3 format
1139 */
1140 if (nmlen > 12)
1141 return (ENAMETOOLONG);
1142
1143 if ((cp = memchr(name, '.', nmlen)) == NULL
1144 || cp == name || (cp - name) > 8
1145 || (cp = memchr(cp + 1, '.', nmlen - (cp - name))) != NULL)
1146 goto bad;
1147
1148 for (cp = name, i = 0; i < nmlen; i++, cp++)
1149 if (strchr(badchars83, *cp) != NULL)
1150 goto bad;
1151 }
1152
1153 for (cp = name, i = 0; i < nmlen; i++, cp++)
1154 if (strchr(badchars, *cp) != NULL)
1155 goto bad;
1156
1157 /* name is fine */
1158 return (0);
1159
1160 bad:
1161 return (ENOENT);
1162 }
1163
1164 /*
1165 * Things go even weird without fixed inode numbers...
1166 */
1167 int
1168 smbfs_lookup(v)
1169 void *v;
1170 {
1171 struct vop_lookup_args /* {
1172 struct vnode *a_dvp;
1173 struct vnode **a_vpp;
1174 struct componentname *a_cnp;
1175 } */ *ap = v;
1176 struct componentname *cnp = ap->a_cnp;
1177 struct vnode *dvp = ap->a_dvp;
1178 struct vnode **vpp = ap->a_vpp;
1179 struct mount *mp = dvp->v_mount;
1180 struct smbnode *dnp;
1181 struct smbfattr fattr;
1182 struct smb_cred scred;
1183 const char *name = cnp->cn_nameptr;
1184 int flags = cnp->cn_flags;
1185 int nameiop = cnp->cn_nameiop;
1186 int nmlen = cnp->cn_namelen;
1187 int lockparent, wantparent, error, islastcn, isdot;
1188
1189 /*
1190 * Check accessiblity of directory.
1191 */
1192 error = VOP_ACCESS(dvp, VEXEC, cnp->cn_cred, cnp->cn_proc);
1193 if (error)
1194 return (error);
1195
1196 if ((cnp->cn_flags & ISLASTCN) &&
1197 (dvp->v_mount->mnt_flag & MNT_RDONLY) &&
1198 (cnp->cn_nameiop == DELETE || cnp->cn_nameiop == RENAME))
1199 return (EROFS);
1200
1201 SMBVDEBUG("%d '%.*s' in '%.*s'\n", nameiop, nmlen, name,
1202 (int) VTOSMB(dvp)->n_nmlen, VTOSMB(dvp)->n_name);
1203
1204 islastcn = flags & ISLASTCN;
1205 lockparent = flags & LOCKPARENT;
1206
1207 /*
1208 * Before tediously performing a linear scan of the directory,
1209 * check the name cache to see if the directory/name pair
1210 * we are looking for is known already.
1211 * If the directory/name pair is found in the name cache,
1212 * we have to ensure the directory has not changed from
1213 * the time the cache entry has been created. If it has,
1214 * the cache entry has to be ignored.
1215 */
1216 if ((error = cache_lookup(dvp, vpp, cnp)) >= 0) {
1217 struct vattr vattr;
1218 struct vnode *newvp;
1219 int err2;
1220
1221 if (error && error != ENOENT) {
1222 *vpp = NULLVP;
1223 return error;
1224 }
1225
1226 if (cnp->cn_flags & PDIRUNLOCK) {
1227 err2 = vn_lock(dvp, LK_EXCLUSIVE | LK_RETRY);
1228 if (err2 != 0) {
1229 *vpp = NULLVP;
1230 return err2;
1231 }
1232 cnp->cn_flags &= ~PDIRUNLOCK;
1233 }
1234
1235 err2 = VOP_ACCESS(dvp, VEXEC, cnp->cn_cred, cnp->cn_proc);
1236 if (err2 != 0) {
1237 if (error == 0) {
1238 if (*vpp != dvp)
1239 vput(*vpp);
1240 else
1241 vrele(*vpp);
1242 }
1243 *vpp = NULLVP;
1244 return err2;
1245 }
1246
1247 if (error == ENOENT) {
1248 if (!VOP_GETATTR(dvp, &vattr, cnp->cn_cred,
1249 cnp->cn_proc) && vattr.va_mtime.tv_sec ==
1250 VTOSMB(dvp)->n_nctime)
1251 return ENOENT;
1252 cache_purge(dvp);
1253 VTOSMB(dvp)->n_nctime = 0;
1254 goto dolookup;
1255 }
1256
1257 newvp = *vpp;
1258 if (!VOP_GETATTR(newvp, &vattr, cnp->cn_cred, cnp->cn_proc)
1259 && vattr.va_ctime.tv_sec == VTOSMB(newvp)->n_ctime)
1260 {
1261 /* nfsstats.lookupcache_hits++; */
1262 if (cnp->cn_nameiop != LOOKUP && islastcn)
1263 cnp->cn_flags |= SAVENAME;
1264
1265 if ((!lockparent || !islastcn) &&
1266 newvp != dvp) {
1267 VOP_UNLOCK(dvp, 0);
1268 cnp->cn_flags |= PDIRUNLOCK;
1269 }
1270
1271 return (0);
1272 }
1273
1274 cache_purge(newvp);
1275 if (newvp != dvp)
1276 vput(newvp);
1277 else
1278 vrele(newvp);
1279 *vpp = NULLVP;
1280 }
1281
1282 dolookup:
1283
1284 /* ensure the name is sane */
1285 if (nameiop != LOOKUP) {
1286 error = smbfs_pathcheck(VFSTOSMBFS(mp), cnp->cn_nameptr,
1287 cnp->cn_namelen);
1288 if (error)
1289 return (error);
1290 }
1291
1292 wantparent = flags & (LOCKPARENT|WANTPARENT);
1293 dnp = VTOSMB(dvp);
1294 isdot = (nmlen == 1 && name[0] == '.');
1295
1296 /*
1297 * entry is not in the cache or has been expired
1298 */
1299 smb_makescred(&scred, cnp->cn_proc, cnp->cn_cred);
1300 if (flags & ISDOTDOT)
1301 error = smbfs_smb_lookup(dnp->n_parent, NULL, 0, &fattr, &scred);
1302 else
1303 error = smbfs_smb_lookup(dnp, name, nmlen, &fattr, &scred);
1304
1305 if (error) {
1306 /* Not found */
1307
1308 if (error != ENOENT)
1309 return (error);
1310
1311 /*
1312 * Handle RENAME or CREATE case...
1313 */
1314 if ((nameiop == CREATE || nameiop == RENAME) && islastcn) {
1315 /*
1316 * Access for write is interpreted as allowing
1317 * creation of files in the directory.
1318 */
1319 error = VOP_ACCESS(dvp, VWRITE, cnp->cn_cred, cnp->cn_proc);
1320 if (error)
1321 return (error);
1322
1323 cnp->cn_flags |= SAVENAME;
1324 if (!lockparent) {
1325 VOP_UNLOCK(dvp, 0);
1326 cnp->cn_flags |= PDIRUNLOCK;
1327 }
1328 return (EJUSTRETURN);
1329 }
1330
1331 /*
1332 * Insert name into cache (as non-existent) if appropriate.
1333 */
1334 if ((cnp->cn_flags & MAKEENTRY) && nameiop != CREATE)
1335 cache_enter(dvp, *vpp, cnp);
1336
1337 return (ENOENT);
1338 }
1339
1340 /* Found */
1341
1342 /* Handle RENAME case... */
1343 if (nameiop == RENAME && islastcn && wantparent) {
1344 error = VOP_ACCESS(dvp, VWRITE, cnp->cn_cred, cnp->cn_proc);
1345 if (error)
1346 return (error);
1347
1348 if (isdot)
1349 return (EISDIR);
1350 if (flags & ISDOTDOT)
1351 VOP_UNLOCK(dvp, 0);
1352 error = smbfs_nget(mp, dvp, name, nmlen, &fattr, vpp);
1353 if (flags & ISDOTDOT)
1354 vn_lock(dvp, LK_EXCLUSIVE | LK_RETRY);
1355 if (error)
1356 return (error);
1357 cnp->cn_flags |= SAVENAME;
1358 if (!lockparent) {
1359 VOP_UNLOCK(dvp, 0);
1360 cnp->cn_flags |= PDIRUNLOCK;
1361 }
1362 return (0);
1363 }
1364
1365 if (isdot) {
1366 /*
1367 * "." lookup
1368 */
1369 VREF(dvp);
1370 *vpp = dvp;
1371 } else if (flags & ISDOTDOT) {
1372 /*
1373 * ".." lookup
1374 */
1375 VOP_UNLOCK(dvp, 0);
1376 cnp->cn_flags |= PDIRUNLOCK;
1377
1378 error = smbfs_nget(mp, dvp, name, nmlen, NULL, vpp);
1379 if (error) {
1380 if (vn_lock(dvp, LK_EXCLUSIVE | LK_RETRY) == 0)
1381 cnp->cn_flags &= ~PDIRUNLOCK;
1382 return error;
1383 }
1384
1385 if (lockparent && islastcn) {
1386 if ((error = vn_lock(dvp, LK_EXCLUSIVE))) {
1387 vput(*vpp);
1388 *vpp = NULLVP;
1389 return error;
1390 }
1391 cnp->cn_flags &= ~PDIRUNLOCK;
1392 }
1393 } else {
1394 /*
1395 * Other lookups.
1396 */
1397 error = smbfs_nget(mp, dvp, name, nmlen, &fattr, vpp);
1398 if (error)
1399 return error;
1400 if (!lockparent || !islastcn) {
1401 VOP_UNLOCK(dvp, 0);
1402 cnp->cn_flags |= PDIRUNLOCK;
1403 }
1404 }
1405
1406 if (cnp->cn_nameiop != LOOKUP && (flags & ISLASTCN))
1407 cnp->cn_flags |= SAVENAME;
1408
1409 if ((cnp->cn_flags & MAKEENTRY)) {
1410 if (!error && (cnp->cn_nameiop != DELETE || !islastcn)) {
1411 VTOSMB(*vpp)->n_ctime = VTOSMB(*vpp)->n_mtime.tv_sec;
1412 cache_enter(dvp, *vpp, cnp);
1413 } else if (error == ENOENT && cnp->cn_nameiop != CREATE) {
1414 VTOSMB(*vpp)->n_nctime = VTOSMB(*vpp)->n_mtime.tv_sec;
1415 cache_enter(dvp, *vpp, cnp);
1416 }
1417 }
1418
1419 return (0);
1420 }
Cache object: 132ab5aa0d239b6851bdee9f38f3029d
|