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