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

Cache object: da4b9c66134d587cac72ef80a033f97d


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