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

Cache object: 9570b927894b50b1aa10d04ac4b64370


[ 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.