root/ntfs/ntfs_vnops.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. ntfs_getpages
  2. ntfs_putpages
  3. ntfs_bmap
  4. ntfs_read
  5. ntfs_bypass
  6. ntfs_getattr
  7. ntfs_inactive
  8. ntfs_reclaim
  9. ntfs_print
  10. ntfs_strategy
  11. ntfs_write
  12. ntfs_access
  13. ntfs_open
  14. ntfs_close
  15. ntfs_readdir
  16. ntfs_lookup
  17. ntfs_fsync
  18. ntfs_pathconf

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

/* [<][>][^][v][top][bottom][index][help] */