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