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/ntfs/ntfs_vnops.c

Version: -  FREEBSD  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-2  -  FREEBSD-11-1  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-4  -  FREEBSD-10-3  -  FREEBSD-10-2  -  FREEBSD-10-1  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-3  -  FREEBSD-9-2  -  FREEBSD-9-1  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-4  -  FREEBSD-8-3  -  FREEBSD-8-2  -  FREEBSD-8-1  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-4  -  FREEBSD-7-3  -  FREEBSD-7-2  -  FREEBSD-7-1  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-4  -  FREEBSD-6-3  -  FREEBSD-6-2  -  FREEBSD-6-1  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-5  -  FREEBSD-5-4  -  FREEBSD-5-3  -  FREEBSD-5-2  -  FREEBSD-5-1  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  linux-2.6  -  linux-2.4.22  -  MK83  -  MK84  -  PLAN9  -  DFBSD  -  NETBSD  -  NETBSD5  -  NETBSD4  -  NETBSD3  -  NETBSD20  -  OPENBSD  -  xnu-517  -  xnu-792  -  xnu-792.6.70  -  xnu-1228  -  xnu-1456.1.26  -  xnu-1699.24.8  -  xnu-2050.18.24  -  OPENSOLARIS  -  minix-3-1-1 
SearchContext: -  none  -  3  -  10 

    1 /*      $NetBSD: ntfs_vnops.c,v 1.30.2.1 2007/02/17 23:27:44 tron Exp $ */
    2 
    3 /*
    4  * Copyright (c) 1992, 1993
    5  *      The Regents of the University of California.  All rights reserved.
    6  *
    7  * This code is derived from software contributed to Berkeley by
    8  * John Heidemann of the UCLA Ficus project.
    9  *
   10  * Redistribution and use in source and binary forms, with or without
   11  * modification, are permitted provided that the following conditions
   12  * are met:
   13  * 1. Redistributions of source code must retain the above copyright
   14  *    notice, this list of conditions and the following disclaimer.
   15  * 2. Redistributions in binary form must reproduce the above copyright
   16  *    notice, this list of conditions and the following disclaimer in the
   17  *    documentation and/or other materials provided with the distribution.
   18  * 3. Neither the name of the University nor the names of its contributors
   19  *    may be used to endorse or promote products derived from this software
   20  *    without specific prior written permission.
   21  *
   22  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
   23  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   24  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   25  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
   26  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   27  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   28  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   29  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   30  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   31  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   32  * SUCH DAMAGE.
   33  *
   34  *      Id: ntfs_vnops.c,v 1.5 1999/05/12 09:43:06 semenu Exp
   35  *
   36  */
   37 
   38 #include <sys/cdefs.h>
   39 __KERNEL_RCSID(0, "$NetBSD: ntfs_vnops.c,v 1.30.2.1 2007/02/17 23:27:44 tron Exp $");
   40 
   41 #include <sys/param.h>
   42 #include <sys/systm.h>
   43 #include <sys/kernel.h>
   44 #include <sys/time.h>
   45 #include <sys/stat.h>
   46 #include <sys/vnode.h>
   47 #include <sys/mount.h>
   48 #include <sys/namei.h>
   49 #include <sys/malloc.h>
   50 #include <sys/buf.h>
   51 #include <sys/dirent.h>
   52 #include <sys/kauth.h>
   53 
   54 #if !defined(__NetBSD__)
   55 #include <vm/vm.h>
   56 #endif
   57 
   58 #if defined(__FreeBSD__)
   59 #include <vm/vnode_pager.h>
   60 #endif
   61 
   62 #include <sys/sysctl.h>
   63 
   64 
   65 #include <fs/ntfs/ntfs.h>
   66 #include <fs/ntfs/ntfs_inode.h>
   67 #include <fs/ntfs/ntfs_subr.h>
   68 #include <miscfs/specfs/specdev.h>
   69 #include <miscfs/genfs/genfs.h>
   70 
   71 #include <sys/unistd.h> /* for pathconf(2) constants */
   72 
   73 static int      ntfs_bypass(void *);
   74 static int      ntfs_read(void *);
   75 static int      ntfs_write(void *);
   76 static int      ntfs_getattr(void *);
   77 static int      ntfs_inactive(void *);
   78 static int      ntfs_print(void *);
   79 static int      ntfs_reclaim(void *);
   80 static int      ntfs_strategy(void *);
   81 static int      ntfs_access(void *);
   82 static int      ntfs_open(void *);
   83 static int      ntfs_close(void *);
   84 static int      ntfs_readdir(void *);
   85 static int      ntfs_lookup(void *);
   86 static int      ntfs_bmap(void *);
   87 #if defined(__FreeBSD__)
   88 static int      ntfs_getpages(struct vop_getpages_args *);
   89 static int      ntfs_putpages(struct vop_putpages_args *);
   90 #endif
   91 static int      ntfs_fsync(void *);
   92 static int      ntfs_pathconf(void *);
   93 
   94 extern int prtactive;
   95 
   96 #if defined(__FreeBSD__)
   97 int
   98 ntfs_getpages(ap)
   99         struct vop_getpages_args *ap;
  100 {
  101         return vnode_pager_generic_getpages(ap->a_vp, ap->a_m, ap->a_count,
  102                 ap->a_reqpage);
  103 }
  104 
  105 int
  106 ntfs_putpages(ap)
  107         struct vop_putpages_args *ap;
  108 {
  109         return vnode_pager_generic_putpages(ap->a_vp, ap->a_m, ap->a_count,
  110                 ap->a_sync, ap->a_rtvals);
  111 }
  112 #endif
  113 
  114 /*
  115  * This is a noop, simply returning what one has been given.
  116  */
  117 int
  118 ntfs_bmap(void *v)
  119 {
  120         struct vop_bmap_args /* {
  121                 struct vnode *a_vp;
  122                 daddr_t  a_bn;
  123                 struct vnode **a_vpp;
  124                 daddr_t *a_bnp;
  125                 int *a_runp;
  126                 int *a_runb;
  127         } */ *ap = v;
  128         dprintf(("ntfs_bmap: vn: %p, blk: %d\n", ap->a_vp,(u_int32_t)ap->a_bn));
  129         if (ap->a_vpp != NULL)
  130                 *ap->a_vpp = ap->a_vp;
  131         if (ap->a_bnp != NULL)
  132                 *ap->a_bnp = ap->a_bn;
  133         if (ap->a_runp != NULL)
  134                 *ap->a_runp = 0;
  135 #if !defined(__NetBSD__)
  136         if (ap->a_runb != NULL)
  137                 *ap->a_runb = 0;
  138 #endif
  139         return (0);
  140 }
  141 
  142 static int
  143 ntfs_read(void *v)
  144 {
  145         struct vop_read_args /* {
  146                 struct vnode *a_vp;
  147                 struct uio *a_uio;
  148                 int a_ioflag;
  149                 kauth_cred_t a_cred;
  150         } */ *ap = v;
  151         struct vnode *vp = ap->a_vp;
  152         struct fnode *fp = VTOF(vp);
  153         struct ntnode *ip = FTONT(fp);
  154         struct uio *uio = ap->a_uio;
  155         struct ntfsmount *ntmp = ip->i_mp;
  156         u_int64_t toread;
  157         int error;
  158 
  159         dprintf(("ntfs_read: ino: %llu, off: %qd resid: %qd\n",
  160             (unsigned long long)ip->i_number, (long long)uio->uio_offset,
  161             (long long)uio->uio_resid));
  162 
  163         dprintf(("ntfs_read: filesize: %qu",(long long)fp->f_size));
  164 
  165         /* don't allow reading after end of file */
  166         if (uio->uio_offset > fp->f_size)
  167                 toread = 0;
  168         else
  169                 toread = MIN(uio->uio_resid, fp->f_size - uio->uio_offset );
  170 
  171         dprintf((", toread: %qu\n",(long long)toread));
  172 
  173         if (toread == 0)
  174                 return (0);
  175 
  176         error = ntfs_readattr(ntmp, ip, fp->f_attrtype,
  177                 fp->f_attrname, uio->uio_offset, toread, NULL, uio);
  178         if (error) {
  179                 printf("ntfs_read: ntfs_readattr failed: %d\n",error);
  180                 return (error);
  181         }
  182 
  183         return (0);
  184 }
  185 
  186 static int
  187 ntfs_bypass(void *v)
  188 {
  189         struct vop_generic_args /* {
  190                 struct vnodeop_desc *a_desc;
  191                 <other random data follows, presumably>
  192         } */ *ap __unused = v;
  193         int error = ENOTTY;
  194         dprintf(("ntfs_bypass: %s\n", ap->a_desc->vdesc_name));
  195         return (error);
  196 }
  197 
  198 
  199 static int
  200 ntfs_getattr(void *v)
  201 {
  202         struct vop_getattr_args /* {
  203                 struct vnode *a_vp;
  204                 struct vattr *a_vap;
  205                 kauth_cred_t a_cred;
  206                 struct lwp *a_l;
  207         } */ *ap = v;
  208         struct vnode *vp = ap->a_vp;
  209         struct fnode *fp = VTOF(vp);
  210         struct ntnode *ip = FTONT(fp);
  211         struct vattr *vap = ap->a_vap;
  212 
  213         dprintf(("ntfs_getattr: %llu, flags: %d\n",
  214             (unsigned long long)ip->i_number, ip->i_flag));
  215 
  216 #if defined(__FreeBSD__)
  217         vap->va_fsid = dev2udev(ip->i_dev);
  218 #else /* NetBSD */
  219         vap->va_fsid = ip->i_dev;
  220 #endif
  221         vap->va_fileid = ip->i_number;
  222         vap->va_mode = ip->i_mp->ntm_mode;
  223         vap->va_nlink = ip->i_nlink;
  224         vap->va_uid = ip->i_mp->ntm_uid;
  225         vap->va_gid = ip->i_mp->ntm_gid;
  226         vap->va_rdev = 0;                               /* XXX UNODEV ? */
  227         vap->va_size = fp->f_size;
  228         vap->va_bytes = fp->f_allocated;
  229         vap->va_atime = ntfs_nttimetounix(fp->f_times.t_access);
  230         vap->va_mtime = ntfs_nttimetounix(fp->f_times.t_write);
  231         vap->va_ctime = ntfs_nttimetounix(fp->f_times.t_create);
  232         vap->va_flags = ip->i_flag;
  233         vap->va_gen = 0;
  234         vap->va_blocksize = ip->i_mp->ntm_spc * ip->i_mp->ntm_bps;
  235         vap->va_type = vp->v_type;
  236         vap->va_filerev = 0;
  237         return (0);
  238 }
  239 
  240 
  241 /*
  242  * Last reference to an ntnode.  If necessary, write or delete it.
  243  */
  244 int
  245 ntfs_inactive(void *v)
  246 {
  247         struct vop_inactive_args /* {
  248                 struct vnode *a_vp;
  249         } */ *ap = v;
  250         struct vnode *vp = ap->a_vp;
  251 #ifdef NTFS_DEBUG
  252         struct ntnode *ip = VTONT(vp);
  253 #endif
  254 
  255         dprintf(("ntfs_inactive: vnode: %p, ntnode: %llu\n", vp,
  256             (unsigned long long)ip->i_number));
  257 
  258         if (prtactive && vp->v_usecount != 0)
  259                 vprint("ntfs_inactive: pushing active", vp);
  260 
  261         VOP_UNLOCK(vp, 0);
  262 
  263         /* XXX since we don't support any filesystem changes
  264          * right now, nothing more needs to be done
  265          */
  266         return (0);
  267 }
  268 
  269 /*
  270  * Reclaim an fnode/ntnode so that it can be used for other purposes.
  271  */
  272 int
  273 ntfs_reclaim(void *v)
  274 {
  275         struct vop_reclaim_args /* {
  276                 struct vnode *a_vp;
  277         } */ *ap = v;
  278         struct vnode *vp = ap->a_vp;
  279         struct fnode *fp = VTOF(vp);
  280         struct ntnode *ip = FTONT(fp);
  281         int error;
  282 
  283         dprintf(("ntfs_reclaim: vnode: %p, ntnode: %llu\n", vp,
  284             (unsigned long long)ip->i_number));
  285 
  286         if (prtactive && vp->v_usecount != 0)
  287                 vprint("ntfs_reclaim: pushing active", vp);
  288 
  289         if ((error = ntfs_ntget(ip)) != 0)
  290                 return (error);
  291 
  292         /* Purge old data structures associated with the inode. */
  293         cache_purge(vp);
  294         if (ip->i_devvp) {
  295                 vrele(ip->i_devvp);
  296                 ip->i_devvp = NULL;
  297         }
  298 
  299         ntfs_frele(fp);
  300         ntfs_ntput(ip);
  301         vp->v_data = NULL;
  302 
  303         return (0);
  304 }
  305 
  306 static int
  307 ntfs_print(void *v)
  308 {
  309         struct vop_print_args /* {
  310                 struct vnode *a_vp;
  311         } */ *ap = v;
  312         struct ntnode *ip = VTONT(ap->a_vp);
  313 
  314         printf("tag VT_NTFS, ino %llu, flag %#x, usecount %d, nlink %ld\n",
  315             (unsigned long long)ip->i_number, ip->i_flag, ip->i_usecount,
  316             ip->i_nlink);
  317         printf("       ");
  318         lockmgr_printinfo(ap->a_vp->v_vnlock);
  319         printf("\n");
  320         return (0);
  321 }
  322 
  323 /*
  324  * Calculate the logical to physical mapping if not done already,
  325  * then call the device strategy routine.
  326  */
  327 int
  328 ntfs_strategy(void *v)
  329 {
  330         struct vop_strategy_args /* {
  331                 struct vnode *a_vp;
  332                 struct buf *a_bp;
  333         } */ *ap = v;
  334         struct buf *bp = ap->a_bp;
  335         struct vnode *vp = ap->a_vp;
  336         struct fnode *fp = VTOF(vp);
  337         struct ntnode *ip = FTONT(fp);
  338         struct ntfsmount *ntmp = ip->i_mp;
  339         int error;
  340 
  341 #ifdef __FreeBSD__
  342         dprintf(("ntfs_strategy: offset: %d, blkno: %d, lblkno: %d\n",
  343                 (u_int32_t)bp->b_offset,(u_int32_t)bp->b_blkno,
  344                 (u_int32_t)bp->b_lblkno));
  345 #else
  346         dprintf(("ntfs_strategy: blkno: %d, lblkno: %d\n",
  347                 (u_int32_t)bp->b_blkno,
  348                 (u_int32_t)bp->b_lblkno));
  349 #endif
  350 
  351         dprintf(("strategy: bcount: %u flags: 0x%x\n",
  352                 (u_int32_t)bp->b_bcount,bp->b_flags));
  353 
  354         if (bp->b_flags & B_READ) {
  355                 u_int32_t toread;
  356 
  357                 if (ntfs_cntob(bp->b_blkno) >= fp->f_size) {
  358                         clrbuf(bp);
  359                         error = 0;
  360                 } else {
  361                         toread = MIN(bp->b_bcount,
  362                                  fp->f_size - ntfs_cntob(bp->b_blkno));
  363                         dprintf(("ntfs_strategy: toread: %d, fsize: %d\n",
  364                                 toread,(u_int32_t)fp->f_size));
  365 
  366                         error = ntfs_readattr(ntmp, ip, fp->f_attrtype,
  367                                 fp->f_attrname, ntfs_cntob(bp->b_blkno),
  368                                 toread, bp->b_data, NULL);
  369 
  370                         if (error) {
  371                                 printf("ntfs_strategy: ntfs_readattr failed\n");
  372                                 bp->b_error = error;
  373                                 bp->b_flags |= B_ERROR;
  374                         }
  375 
  376                         bzero(bp->b_data + toread, bp->b_bcount - toread);
  377                 }
  378         } else {
  379                 size_t tmp;
  380                 u_int32_t towrite;
  381 
  382                 if (ntfs_cntob(bp->b_blkno) + bp->b_bcount >= fp->f_size) {
  383                         printf("ntfs_strategy: CAN'T EXTEND FILE\n");
  384                         bp->b_error = error = EFBIG;
  385                         bp->b_flags |= B_ERROR;
  386                 } else {
  387                         towrite = MIN(bp->b_bcount,
  388                                 fp->f_size - ntfs_cntob(bp->b_blkno));
  389                         dprintf(("ntfs_strategy: towrite: %d, fsize: %d\n",
  390                                 towrite,(u_int32_t)fp->f_size));
  391 
  392                         error = ntfs_writeattr_plain(ntmp, ip, fp->f_attrtype,
  393                                 fp->f_attrname, ntfs_cntob(bp->b_blkno),towrite,
  394                                 bp->b_data, &tmp, NULL);
  395 
  396                         if (error) {
  397                                 printf("ntfs_strategy: ntfs_writeattr fail\n");
  398                                 bp->b_error = error;
  399                                 bp->b_flags |= B_ERROR;
  400                         }
  401                 }
  402         }
  403         biodone(bp);
  404         return (error);
  405 }
  406 
  407 static int
  408 ntfs_write(void *v)
  409 {
  410         struct vop_write_args /* {
  411                 struct vnode *a_vp;
  412                 struct uio *a_uio;
  413                 int  a_ioflag;
  414                 kauth_cred_t a_cred;
  415         } */ *ap = v;
  416         struct vnode *vp = ap->a_vp;
  417         struct fnode *fp = VTOF(vp);
  418         struct ntnode *ip = FTONT(fp);
  419         struct uio *uio = ap->a_uio;
  420         struct ntfsmount *ntmp = ip->i_mp;
  421         u_int64_t towrite;
  422         size_t written;
  423         int error;
  424 
  425         dprintf(("ntfs_write: ino: %llu, off: %qd resid: %qd\n",
  426             (unsigned long long)ip->i_number, (long long)uio->uio_offset,
  427             (long long)uio->uio_resid));
  428         dprintf(("ntfs_write: filesize: %qu",(long long)fp->f_size));
  429 
  430         if (uio->uio_resid + uio->uio_offset > fp->f_size) {
  431                 printf("ntfs_write: CAN'T WRITE BEYOND END OF FILE\n");
  432                 return (EFBIG);
  433         }
  434 
  435         towrite = MIN(uio->uio_resid, fp->f_size - uio->uio_offset);
  436 
  437         dprintf((", towrite: %qu\n",(long long)towrite));
  438 
  439         error = ntfs_writeattr_plain(ntmp, ip, fp->f_attrtype,
  440                 fp->f_attrname, uio->uio_offset, towrite, NULL, &written, uio);
  441 #ifdef NTFS_DEBUG
  442         if (error)
  443                 printf("ntfs_write: ntfs_writeattr failed: %d\n", error);
  444 #endif
  445 
  446         return (error);
  447 }
  448 
  449 int
  450 ntfs_access(void *v)
  451 {
  452         struct vop_access_args /* {
  453                 struct vnode *a_vp;
  454                 int  a_mode;
  455                 kauth_cred_t a_cred;
  456                 struct lwp *a_l;
  457         } */ *ap = v;
  458         struct vnode *vp = ap->a_vp;
  459         struct ntnode *ip = VTONT(vp);
  460         kauth_cred_t cred = ap->a_cred;
  461         mode_t mask, mode = ap->a_mode;
  462         gid_t grp;
  463         int i;
  464         uint16_t ngroups;
  465 
  466         dprintf(("ntfs_access: %llu\n", (unsigned long long)ip->i_number));
  467 
  468         /*
  469          * Disallow write attempts on read-only file systems;
  470          * unless the file is a socket, fifo, or a block or
  471          * character device resident on the file system.
  472          */
  473         if (mode & VWRITE) {
  474                 switch ((int)vp->v_type) {
  475                 case VDIR:
  476                 case VLNK:
  477                 case VREG:
  478                         if (vp->v_mount->mnt_flag & MNT_RDONLY)
  479                                 return (EROFS);
  480                         break;
  481                 }
  482         }
  483 
  484         /* Otherwise, user id 0 always gets access. */
  485         if (kauth_authorize_generic(cred, KAUTH_GENERIC_ISSUSER, NULL) == 0)
  486                 return (0);
  487 
  488         mask = 0;
  489 
  490         /* Otherwise, check the owner. */
  491         if (kauth_cred_geteuid(cred) == ip->i_mp->ntm_uid) {
  492                 if (mode & VEXEC)
  493                         mask |= S_IXUSR;
  494                 if (mode & VREAD)
  495                         mask |= S_IRUSR;
  496                 if (mode & VWRITE)
  497                         mask |= S_IWUSR;
  498                 return ((ip->i_mp->ntm_mode & mask) == mask ? 0 : EACCES);
  499         }
  500 
  501         /* Otherwise, check the groups. */
  502         ngroups = kauth_cred_ngroups(cred);
  503         for (i = 0; i < ngroups; i++) {
  504                 grp = kauth_cred_group(cred, i);
  505                 if (ip->i_mp->ntm_gid == grp) {
  506                         if (mode & VEXEC)
  507                                 mask |= S_IXGRP;
  508                         if (mode & VREAD)
  509                                 mask |= S_IRGRP;
  510                         if (mode & VWRITE)
  511                                 mask |= S_IWGRP;
  512                         return ((ip->i_mp->ntm_mode&mask) == mask ? 0 : EACCES);
  513                 }
  514         }
  515 
  516         /* Otherwise, check everyone else. */
  517         if (mode & VEXEC)
  518                 mask |= S_IXOTH;
  519         if (mode & VREAD)
  520                 mask |= S_IROTH;
  521         if (mode & VWRITE)
  522                 mask |= S_IWOTH;
  523         return ((ip->i_mp->ntm_mode & mask) == mask ? 0 : EACCES);
  524 }
  525 
  526 /*
  527  * Open called.
  528  *
  529  * Nothing to do.
  530  */
  531 /* ARGSUSED */
  532 static int
  533 ntfs_open(void *v)
  534 {
  535         struct vop_open_args /* {
  536                 struct vnode *a_vp;
  537                 int  a_mode;
  538                 kauth_cred_t a_cred;
  539                 struct lwp *a_l;
  540         } */ *ap __unused = v;
  541 #ifdef NTFS_DEBUG
  542         struct vnode *vp = ap->a_vp;
  543         struct ntnode *ip = VTONT(vp);
  544 
  545         printf("ntfs_open: %llu\n", (unsigned long long)ip->i_number);
  546 #endif
  547 
  548         /*
  549          * Files marked append-only must be opened for appending.
  550          */
  551 
  552         return (0);
  553 }
  554 
  555 /*
  556  * Close called.
  557  *
  558  * Update the times on the inode.
  559  */
  560 /* ARGSUSED */
  561 static int
  562 ntfs_close(void *v)
  563 {
  564         struct vop_close_args /* {
  565                 struct vnode *a_vp;
  566                 int  a_fflag;
  567                 kauth_cred_t a_cred;
  568                 struct lwp *a_l;
  569         } */ *ap __unused = v;
  570 #ifdef NTFS_DEBUG
  571         struct vnode *vp = ap->a_vp;
  572         struct ntnode *ip = VTONT(vp);
  573 
  574         printf("ntfs_close: %llu\n", (unsigned long long)ip->i_number);
  575 #endif
  576 
  577         return (0);
  578 }
  579 
  580 int
  581 ntfs_readdir(void *v)
  582 {
  583         struct vop_readdir_args /* {
  584                 struct vnode *a_vp;
  585                 struct uio *a_uio;
  586                 kauth_cred_t a_cred;
  587                 int *a_ncookies;
  588                 u_int **cookies;
  589         } */ *ap = v;
  590         struct vnode *vp = ap->a_vp;
  591         struct fnode *fp = VTOF(vp);
  592         struct ntnode *ip = FTONT(fp);
  593         struct uio *uio = ap->a_uio;
  594         struct ntfsmount *ntmp = ip->i_mp;
  595         int i, error = 0;
  596         u_int32_t faked = 0, num;
  597         int ncookies = 0;
  598         struct dirent *cde;
  599         off_t off;
  600 
  601         dprintf(("ntfs_readdir %llu off: %qd resid: %qd\n",
  602             (unsigned long long)ip->i_number, (long long)uio->uio_offset,
  603             (long long)uio->uio_resid));
  604 
  605         off = uio->uio_offset;
  606 
  607         MALLOC(cde, struct dirent *, sizeof(struct dirent), M_TEMP, M_WAITOK);
  608 
  609         /* Simulate . in every dir except ROOT */
  610         if (ip->i_number != NTFS_ROOTINO
  611             && uio->uio_offset < sizeof(struct dirent)) {
  612                 cde->d_fileno = ip->i_number;
  613                 cde->d_reclen = sizeof(struct dirent);
  614                 cde->d_type = DT_DIR;
  615                 cde->d_namlen = 1;
  616                 strncpy(cde->d_name, ".", 2);
  617                 error = uiomove((void *)cde, sizeof(struct dirent), uio);
  618                 if (error)
  619                         goto out;
  620 
  621                 ncookies++;
  622         }
  623 
  624         /* Simulate .. in every dir including ROOT */
  625         if (uio->uio_offset < 2 * sizeof(struct dirent)) {
  626                 cde->d_fileno = NTFS_ROOTINO;   /* XXX */
  627                 cde->d_reclen = sizeof(struct dirent);
  628                 cde->d_type = DT_DIR;
  629                 cde->d_namlen = 2;
  630                 strncpy(cde->d_name, "..", 3);
  631 
  632                 error = uiomove((void *) cde, sizeof(struct dirent), uio);
  633                 if (error)
  634                         goto out;
  635 
  636                 ncookies++;
  637         }
  638 
  639         faked = (ip->i_number == NTFS_ROOTINO) ? 1 : 2;
  640         num = uio->uio_offset / sizeof(struct dirent) - faked;
  641 
  642         while (uio->uio_resid >= sizeof(struct dirent)) {
  643                 struct attr_indexentry *iep;
  644                 char *fname;
  645                 size_t remains;
  646                 int sz;
  647 
  648                 error = ntfs_ntreaddir(ntmp, fp, num, &iep);
  649                 if (error)
  650                         goto out;
  651 
  652                 if (NULL == iep)
  653                         break;
  654 
  655                 for(; !(iep->ie_flag & NTFS_IEFLAG_LAST) && (uio->uio_resid >= sizeof(struct dirent));
  656                         iep = NTFS_NEXTREC(iep, struct attr_indexentry *))
  657                 {
  658                         if(!ntfs_isnamepermitted(ntmp,iep))
  659                                 continue;
  660 
  661                         remains = sizeof(cde->d_name) - 1;
  662                         fname = cde->d_name;
  663                         for(i=0; i<iep->ie_fnamelen; i++) {
  664                                 sz = (*ntmp->ntm_wput)(fname, remains,
  665                                                 iep->ie_fname[i]);
  666                                 fname += sz;
  667                                 remains -= sz;
  668                         }
  669                         *fname = '\0';
  670                         dprintf(("ntfs_readdir: elem: %d, fname:[%s] type: %d, flag: %d, ",
  671                                 num, cde->d_name, iep->ie_fnametype,
  672                                 iep->ie_flag));
  673                         cde->d_namlen = fname - (char *) cde->d_name;
  674                         cde->d_fileno = iep->ie_number;
  675                         cde->d_type = (iep->ie_fflag & NTFS_FFLAG_DIR) ? DT_DIR : DT_REG;
  676                         cde->d_reclen = sizeof(struct dirent);
  677                         dprintf(("%s\n", (cde->d_type == DT_DIR) ? "dir":"reg"));
  678 
  679                         error = uiomove((void *)cde, sizeof(struct dirent), uio);
  680                         if (error)
  681                                 goto out;
  682 
  683                         ncookies++;
  684                         num++;
  685                 }
  686         }
  687 
  688         dprintf(("ntfs_readdir: %d entries (%d bytes) read\n",
  689                 ncookies,(u_int)(uio->uio_offset - off)));
  690         dprintf(("ntfs_readdir: off: %qd resid: %qu\n",
  691                 (long long)uio->uio_offset,(long long)uio->uio_resid));
  692 
  693         if (!error && ap->a_ncookies != NULL) {
  694                 struct dirent* dpStart;
  695                 struct dirent* dp;
  696 #if defined(__FreeBSD__)
  697                 u_long *cookies;
  698                 u_long *cookiep;
  699 #else /* defined(__NetBSD__) */
  700                 off_t *cookies;
  701                 off_t *cookiep;
  702 #endif
  703 
  704                 dprintf(("ntfs_readdir: %d cookies\n",ncookies));
  705                 if (!VMSPACE_IS_KERNEL_P(uio->uio_vmspace) ||
  706                     uio->uio_iovcnt != 1)
  707                         panic("ntfs_readdir: unexpected uio from NFS server");
  708                 dpStart = (struct dirent *)
  709                      ((caddr_t)uio->uio_iov->iov_base -
  710                          (uio->uio_offset - off));
  711 #if defined(__FreeBSD__)
  712                 MALLOC(cookies, u_long *, ncookies * sizeof(u_long),
  713                        M_TEMP, M_WAITOK);
  714 #else /* defined(__NetBSD__) */
  715                 cookies = malloc(ncookies * sizeof(off_t), M_TEMP, M_WAITOK);
  716 #endif
  717                 for (dp = dpStart, cookiep = cookies, i=0;
  718                      i < ncookies;
  719                      dp = (struct dirent *)((caddr_t) dp + dp->d_reclen), i++) {
  720                         off += dp->d_reclen;
  721                         *cookiep++ = (u_int) off;
  722                 }
  723                 *ap->a_ncookies = ncookies;
  724                 *ap->a_cookies = cookies;
  725         }
  726 /*
  727         if (ap->a_eofflag)
  728             *ap->a_eofflag = VTONT(ap->a_vp)->i_size <= uio->uio_offset;
  729 */
  730     out:
  731         FREE(cde, M_TEMP);
  732         return (error);
  733 }
  734 
  735 int
  736 ntfs_lookup(void *v)
  737 {
  738         struct vop_lookup_args /* {
  739                 struct vnode *a_dvp;
  740                 struct vnode **a_vpp;
  741                 struct componentname *a_cnp;
  742         } */ *ap = v;
  743         struct vnode *dvp = ap->a_dvp;
  744         struct ntnode *dip = VTONT(dvp);
  745         struct ntfsmount *ntmp = dip->i_mp;
  746         struct componentname *cnp = ap->a_cnp;
  747         kauth_cred_t cred = cnp->cn_cred;
  748         int error;
  749 
  750         dprintf(("ntfs_lookup: \"%.*s\" (%ld bytes) in %llu\n",
  751             (int)cnp->cn_namelen, cnp->cn_nameptr, cnp->cn_namelen,
  752             (unsigned long long)dip->i_number));
  753 
  754         error = VOP_ACCESS(dvp, VEXEC, cred, cnp->cn_lwp);
  755         if(error)
  756                 return (error);
  757 
  758         if ((cnp->cn_flags & ISLASTCN) &&
  759             (dvp->v_mount->mnt_flag & MNT_RDONLY) &&
  760             (cnp->cn_nameiop == DELETE || cnp->cn_nameiop == RENAME))
  761                 return (EROFS);
  762 
  763 #ifdef __NetBSD__
  764         /*
  765          * We now have a segment name to search for, and a directory
  766          * to search.
  767          *
  768          * Before tediously performing a linear scan of the directory,
  769          * check the name cache to see if the directory/name pair
  770          * we are looking for is known already.
  771          */
  772         if ((error = cache_lookup(ap->a_dvp, ap->a_vpp, cnp)) >= 0)
  773                 return (error);
  774 #endif
  775 
  776         if(cnp->cn_namelen == 1 && cnp->cn_nameptr[0] == '.') {
  777                 dprintf(("ntfs_lookup: faking . directory in %llu\n",
  778                     (unsigned long long)dip->i_number));
  779 
  780                 VREF(dvp);
  781                 *ap->a_vpp = dvp;
  782                 error = 0;
  783         } else if (cnp->cn_flags & ISDOTDOT) {
  784                 struct ntvattr *vap;
  785 
  786                 dprintf(("ntfs_lookup: faking .. directory in %llu\n",
  787                     (unsigned long long)dip->i_number));
  788 
  789                 VOP_UNLOCK(dvp, 0);
  790                 error = ntfs_ntvattrget(ntmp, dip, NTFS_A_NAME, NULL, 0, &vap);
  791                 if (error) {
  792                         vn_lock(dvp, LK_EXCLUSIVE | LK_RETRY);
  793                         return (error);
  794                 }
  795 
  796                 dprintf(("ntfs_lookup: parentdir: %d\n",
  797                          vap->va_a_name->n_pnumber));
  798                 error = VFS_VGET(ntmp->ntm_mountp,
  799                                  vap->va_a_name->n_pnumber,ap->a_vpp);
  800                 ntfs_ntvattrrele(vap);
  801                 vn_lock(dvp, LK_EXCLUSIVE | LK_RETRY);
  802                 if (error) {
  803                         return (error);
  804                 }
  805         } else {
  806                 error = ntfs_ntlookupfile(ntmp, dvp, cnp, ap->a_vpp);
  807                 if (error) {
  808                         dprintf(("ntfs_ntlookupfile: returned %d\n", error));
  809                         return (error);
  810                 }
  811 
  812                 dprintf(("ntfs_lookup: found ino: %llu\n",
  813                     (unsigned long long)VTONT(*ap->a_vpp)->i_number));
  814         }
  815 
  816         if (cnp->cn_flags & MAKEENTRY)
  817                 cache_enter(dvp, *ap->a_vpp, cnp);
  818 
  819         return (error);
  820 }
  821 
  822 /*
  823  * Flush the blocks of a file to disk.
  824  *
  825  * This function is worthless for vnodes that represent directories. Maybe we
  826  * could just do a sync if they try an fsync on a directory file.
  827  */
  828 static int
  829 ntfs_fsync(void *v)
  830 {
  831         struct vop_fsync_args /* {
  832                 struct vnode *a_vp;
  833                 kauth_cred_t a_cred;
  834                 int a_flags;
  835                 off_t offlo;
  836                 off_t offhi;
  837                 struct lwp *a_l;
  838         } */ *ap = v;
  839         struct vnode *vp = ap->a_vp;
  840         int wait;
  841 
  842         if (ap->a_flags & FSYNC_CACHE) {
  843                 return EOPNOTSUPP;
  844         }
  845 
  846         wait = (ap->a_flags & FSYNC_WAIT) != 0;
  847         vflushbuf(vp, wait);
  848 
  849         return 0;
  850 }
  851 
  852 /*
  853  * Return POSIX pathconf information applicable to NTFS filesystem
  854  */
  855 static int
  856 ntfs_pathconf(void *v)
  857 {
  858         struct vop_pathconf_args /* {
  859                 struct vnode *a_vp;
  860                 int a_name;
  861                 register_t *a_retval;
  862         } */ *ap = v;
  863 
  864         switch (ap->a_name) {
  865         case _PC_LINK_MAX:
  866                 *ap->a_retval = 1;
  867                 return (0);
  868         case _PC_NAME_MAX:
  869                 *ap->a_retval = ap->a_vp->v_mount->mnt_stat.f_namemax;
  870                 return (0);
  871         case _PC_PATH_MAX:
  872                 *ap->a_retval = PATH_MAX;
  873                 return (0);
  874         case _PC_CHOWN_RESTRICTED:
  875                 *ap->a_retval = 1;
  876                 return (0);
  877         case _PC_NO_TRUNC:
  878                 *ap->a_retval = 0;
  879                 return (0);
  880         case _PC_SYNC_IO:
  881                 *ap->a_retval = 1;
  882                 return (0);
  883         case _PC_FILESIZEBITS:
  884                 *ap->a_retval = 64;
  885                 return (0);
  886         default:
  887                 return (EINVAL);
  888         }
  889         /* NOTREACHED */
  890 }
  891 
  892 /*
  893  * Global vfs data structures
  894  */
  895 vop_t **ntfs_vnodeop_p;
  896 #if defined(__FreeBSD__)
  897 static
  898 struct vnodeopv_entry_desc ntfs_vnodeop_entries[] = {
  899         { &vop_default_desc, (vop_t *)ntfs_bypass },
  900 
  901         { &vop_getattr_desc, (vop_t *)ntfs_getattr },
  902         { &vop_inactive_desc, (vop_t *)ntfs_inactive },
  903         { &vop_reclaim_desc, (vop_t *)ntfs_reclaim },
  904         { &vop_print_desc, (vop_t *)ntfs_print },
  905         { &vop_pathconf_desc, ntfs_pathconf },
  906 
  907         { &vop_islocked_desc, (vop_t *)vop_stdislocked },
  908         { &vop_unlock_desc, (vop_t *)vop_stdunlock },
  909         { &vop_lock_desc, (vop_t *)vop_stdlock },
  910         { &vop_cachedlookup_desc, (vop_t *)ntfs_lookup },
  911         { &vop_lookup_desc, (vop_t *)vfs_cache_lookup },
  912 
  913         { &vop_access_desc, (vop_t *)ntfs_access },
  914         { &vop_close_desc, (vop_t *)ntfs_close },
  915         { &vop_open_desc, (vop_t *)ntfs_open },
  916         { &vop_readdir_desc, (vop_t *)ntfs_readdir },
  917         { &vop_fsync_desc, (vop_t *)ntfs_fsync },
  918 
  919         { &vop_bmap_desc, (vop_t *)ntfs_bmap },
  920         { &vop_getpages_desc, (vop_t *) ntfs_getpages },
  921         { &vop_putpages_desc, (vop_t *) ntfs_putpages },
  922         { &vop_strategy_desc, (vop_t *)ntfs_strategy },
  923         { &vop_bwrite_desc, (vop_t *)vop_stdbwrite },
  924         { &vop_read_desc, (vop_t *)ntfs_read },
  925         { &vop_write_desc, (vop_t *)ntfs_write },
  926 
  927         { NULL, NULL }
  928 };
  929 
  930 static
  931 struct vnodeopv_desc ntfs_vnodeop_opv_desc =
  932         { &ntfs_vnodeop_p, ntfs_vnodeop_entries };
  933 
  934 VNODEOP_SET(ntfs_vnodeop_opv_desc);
  935 
  936 #else /* !FreeBSD */
  937 
  938 const struct vnodeopv_entry_desc ntfs_vnodeop_entries[] = {
  939         { &vop_default_desc, (vop_t *) ntfs_bypass },
  940         { &vop_lookup_desc, (vop_t *) ntfs_lookup },    /* lookup */
  941         { &vop_create_desc, genfs_eopnotsupp },         /* create */
  942         { &vop_mknod_desc, genfs_eopnotsupp },          /* mknod */
  943         { &vop_open_desc, (vop_t *) ntfs_open },        /* open */
  944         { &vop_close_desc,(vop_t *)  ntfs_close },      /* close */
  945         { &vop_access_desc, (vop_t *) ntfs_access },    /* access */
  946         { &vop_getattr_desc, (vop_t *) ntfs_getattr },  /* getattr */
  947         { &vop_setattr_desc, genfs_eopnotsupp },        /* setattr */
  948         { &vop_read_desc, (vop_t *) ntfs_read },        /* read */
  949         { &vop_write_desc, (vop_t *) ntfs_write },      /* write */
  950         { &vop_lease_desc, genfs_lease_check },         /* lease */
  951         { &vop_fcntl_desc, genfs_fcntl },               /* fcntl */
  952         { &vop_ioctl_desc, genfs_enoioctl },            /* ioctl */
  953         { &vop_poll_desc, genfs_poll },                 /* poll */
  954         { &vop_kqfilter_desc, genfs_kqfilter },         /* kqfilter */
  955         { &vop_revoke_desc, genfs_revoke },             /* revoke */
  956         { &vop_mmap_desc, genfs_mmap },                 /* mmap */
  957         { &vop_fsync_desc, (vop_t *) ntfs_fsync },      /* fsync */
  958         { &vop_seek_desc, genfs_seek },                 /* seek */
  959         { &vop_remove_desc, genfs_eopnotsupp },         /* remove */
  960         { &vop_link_desc, genfs_eopnotsupp },           /* link */
  961         { &vop_rename_desc, genfs_eopnotsupp },         /* rename */
  962         { &vop_mkdir_desc, genfs_eopnotsupp },          /* mkdir */
  963         { &vop_rmdir_desc, genfs_eopnotsupp },          /* rmdir */
  964         { &vop_symlink_desc, genfs_eopnotsupp },        /* symlink */
  965         { &vop_readdir_desc, (vop_t *) ntfs_readdir },  /* readdir */
  966         { &vop_readlink_desc, genfs_eopnotsupp },       /* readlink */
  967         { &vop_abortop_desc, genfs_abortop },           /* abortop */
  968         { &vop_inactive_desc, (vop_t *) ntfs_inactive },        /* inactive */
  969         { &vop_reclaim_desc, (vop_t *) ntfs_reclaim },  /* reclaim */
  970         { &vop_lock_desc, genfs_lock },                 /* lock */
  971         { &vop_unlock_desc, genfs_unlock },             /* unlock */
  972         { &vop_bmap_desc, (vop_t *) ntfs_bmap },        /* bmap */
  973         { &vop_strategy_desc, (vop_t *) ntfs_strategy },        /* strategy */
  974         { &vop_print_desc, (vop_t *) ntfs_print },      /* print */
  975         { &vop_islocked_desc, genfs_islocked },         /* islocked */
  976         { &vop_pathconf_desc, ntfs_pathconf },          /* pathconf */
  977         { &vop_advlock_desc, genfs_nullop },            /* advlock */
  978         { &vop_bwrite_desc, vn_bwrite },                /* bwrite */
  979         { &vop_getpages_desc, genfs_compat_getpages },  /* getpages */
  980         { &vop_putpages_desc, genfs_putpages },         /* putpages */
  981         { NULL, NULL }
  982 };
  983 const struct vnodeopv_desc ntfs_vnodeop_opv_desc =
  984         { &ntfs_vnodeop_p, ntfs_vnodeop_entries };
  985 
  986 #endif

Cache object: a17ce35dc32a75d23a30b9cd7c7ab9ef


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