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