The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/fs/smbfs/smbfs_vnops.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

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

Cache object: 79c9d5b161b69268c9118e666f30cb16


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.