Due to continuing issues with VOP_READ/VOP_WRITE ops being called without
[dragonfly.git] / sys / vfs / ntfs / ntfs_vnops.c
index 610e74c..ff64f61 100644 (file)
@@ -36,7 +36,7 @@
  * SUCH DAMAGE.
  *
  * $FreeBSD: src/sys/ntfs/ntfs_vnops.c,v 1.9.2.4 2002/08/06 19:35:18 semenu Exp $
- * $DragonFly: src/sys/vfs/ntfs/ntfs_vnops.c,v 1.22 2005/02/15 08:32:18 joerg Exp $
+ * $DragonFly: src/sys/vfs/ntfs/ntfs_vnops.c,v 1.29 2006/04/07 06:38:33 dillon Exp $
  *
  */
 
@@ -53,6 +53,7 @@
 #include <sys/malloc.h>
 #include <sys/buf.h>
 #include <sys/dirent.h>
+#include <machine/limits.h>
 
 #include <vm/vm.h>
 #include <vm/vm_param.h>
@@ -91,7 +92,7 @@ static int    ntfs_access (struct vop_access_args *ap);
 static int     ntfs_open (struct vop_open_args *ap);
 static int     ntfs_close (struct vop_close_args *ap);
 static int     ntfs_readdir (struct vop_readdir_args *ap);
-static int     ntfs_lookup (struct vop_lookup_args *ap);
+static int     ntfs_lookup (struct vop_old_lookup_args *ap);
 static int     ntfs_bmap (struct vop_bmap_args *ap);
 #if defined(__DragonFly__)
 static int     ntfs_getpages (struct vop_getpages_args *ap);
@@ -123,8 +124,8 @@ ntfs_putpages(struct vop_putpages_args *ap)
 /*
  * This is a noop, simply returning what one has been given.
  *
- * ntfs_bmap(struct vnode *a_vp, daddr_t a_bn, struct vnode **a_vpp,
- *          daddr_t *a_bnp, int *a_runp, int *a_runb)
+ * ntfs_bmap(struct vnode *a_vp, off_t a_loffset, struct vnode **a_vpp,
+ *          daddr_t *a_doffsetp, int *a_runp, int *a_runb)
  */
 int
 ntfs_bmap(struct vop_bmap_args *ap)
@@ -132,8 +133,8 @@ ntfs_bmap(struct vop_bmap_args *ap)
        dprintf(("ntfs_bmap: vn: %p, blk: %d\n", ap->a_vp,(u_int32_t)ap->a_bn));
        if (ap->a_vpp != NULL)
                *ap->a_vpp = ap->a_vp;
-       if (ap->a_bnp != NULL)
-               *ap->a_bnp = ap->a_bn;
+       if (ap->a_doffsetp != NULL)
+               *ap->a_doffsetp = ap->a_loffset;
        if (ap->a_runp != NULL)
                *ap->a_runp = 0;
 #if !defined(__NetBSD__)
@@ -179,7 +180,7 @@ ntfs_read(struct vop_read_args *ap)
 
                toread = min(off + resid, ntfs_cntob(1));
 
-               error = bread(vp, cn, ntfs_cntob(1), &bp);
+               error = bread(vp, ntfs_cntodoff(cn), ntfs_cntob(1), &bp);
                if (error) {
                        brelse(bp);
                        break;
@@ -318,27 +319,21 @@ ntfs_print(struct vop_print_args *ap)
  * Calculate the logical to physical mapping if not done already,
  * then call the device strategy routine.
  *
- * ntfs_strategy(struct buf *a_bp)
+ * ntfs_strategy(struct vnode *a_vp, struct bio *a_bio)
  */
 int
 ntfs_strategy(struct vop_strategy_args *ap)
 {
-       struct buf *bp = ap->a_bp;
-       struct vnode *vp = bp->b_vp;
+       struct bio *bio = ap->a_bio;
+       struct buf *bp = bio->bio_buf;
+       struct vnode *vp = ap->a_vp;
        struct fnode *fp = VTOF(vp);
        struct ntnode *ip = FTONT(fp);
        struct ntfsmount *ntmp = ip->i_mp;
        int error;
 
-#ifdef __DragonFly__
-       dprintf(("ntfs_strategy: offset: %d, blkno: %d, lblkno: %d\n",
-               (u_int32_t)bp->b_offset,(u_int32_t)bp->b_blkno,
-               (u_int32_t)bp->b_lblkno));
-#else
-       dprintf(("ntfs_strategy: blkno: %d, lblkno: %d\n",
-               (u_int32_t)bp->b_blkno,
-               (u_int32_t)bp->b_lblkno));
-#endif
+       dprintf(("ntfs_strategy: loffset: %lld, doffset: %lld\n",
+               bp->b_loffset, bio->bio_offset));
 
        dprintf(("strategy: bcount: %d flags: 0x%lx\n", 
                (u_int32_t)bp->b_bcount,bp->b_flags));
@@ -346,17 +341,17 @@ ntfs_strategy(struct vop_strategy_args *ap)
        if (bp->b_flags & B_READ) {
                u_int32_t toread;
 
-               if (ntfs_cntob(bp->b_blkno) >= fp->f_size) {
+               if (bio->bio_offset >= fp->f_size) {
                        clrbuf(bp);
                        error = 0;
                } else {
                        toread = min(bp->b_bcount,
-                                fp->f_size-ntfs_cntob(bp->b_blkno));
+                                fp->f_size - bio->bio_offset);
                        dprintf(("ntfs_strategy: toread: %d, fsize: %d\n",
                                toread,(u_int32_t)fp->f_size));
 
                        error = ntfs_readattr(ntmp, ip, fp->f_attrtype,
-                               fp->f_attrname, ntfs_cntob(bp->b_blkno),
+                               fp->f_attrname, bio->bio_offset,
                                toread, bp->b_data, NULL);
 
                        if (error) {
@@ -371,18 +366,18 @@ ntfs_strategy(struct vop_strategy_args *ap)
                size_t tmp;
                u_int32_t towrite;
 
-               if (ntfs_cntob(bp->b_blkno) + bp->b_bcount >= fp->f_size) {
+               if (bio->bio_offset + bp->b_bcount >= fp->f_size) {
                        printf("ntfs_strategy: CAN'T EXTEND FILE\n");
                        bp->b_error = error = EFBIG;
                        bp->b_flags |= B_ERROR;
                } else {
                        towrite = min(bp->b_bcount,
-                               fp->f_size-ntfs_cntob(bp->b_blkno));
+                                     fp->f_size - bio->bio_offset);
                        dprintf(("ntfs_strategy: towrite: %d, fsize: %d\n",
                                towrite,(u_int32_t)fp->f_size));
 
                        error = ntfs_writeattr_plain(ntmp, ip, fp->f_attrtype,  
-                               fp->f_attrname, ntfs_cntob(bp->b_blkno),towrite,
+                               fp->f_attrname, bio->bio_offset,towrite,
                                bp->b_data, &tmp, NULL);
 
                        if (error) {
@@ -392,7 +387,7 @@ ntfs_strategy(struct vop_strategy_args *ap)
                        }
                }
        }
-       biodone(bp);
+       biodone(bio);
        return (error);
 }
 
@@ -524,18 +519,7 @@ ntfs_access(struct vop_access_args *ap)
 static int
 ntfs_open(struct vop_open_args *ap)
 {
-#if NTFS_DEBUG
-       struct vnode *vp = ap->a_vp;
-       struct ntnode *ip = VTONT(vp);
-
-       printf("ntfs_open: %d\n",ip->i_number);
-#endif
-
-       /*
-        * Files marked append-only must be opened for appending.
-        */
-
-       return (0);
+       return (vop_stdopen(ap));
 }
 
 /*
@@ -557,7 +541,7 @@ ntfs_close(struct vop_close_args *ap)
        printf("ntfs_close: %d\n",ip->i_number);
 #endif
 
-       return (0);
+       return (vop_stdclose(ap));
 }
 
 /*
@@ -573,49 +557,64 @@ ntfs_readdir(struct vop_readdir_args *ap)
        struct uio *uio = ap->a_uio;
        struct ntfsmount *ntmp = ip->i_mp;
        int i, error = 0;
-       u_int32_t faked = 0, num;
+       u_int32_t faked = 0, num, off;
        int ncookies = 0;
-       struct dirent cde;
-       off_t off;
+       char convname[NTFS_MAXFILENAME + 1];
 
        dprintf(("ntfs_readdir %d off: %d resid: %d\n",ip->i_number,(u_int32_t)uio->uio_offset,uio->uio_resid));
 
-       off = uio->uio_offset;
+       if (uio->uio_offset < 0 || uio->uio_offset > INT_MAX)
+               return (EINVAL);
 
-       /* Simulate . in every dir except ROOT */
-       if( ip->i_number != NTFS_ROOTINO ) {
-               struct dirent dot = { NTFS_ROOTINO,
-                               sizeof(struct dirent), DT_DIR, 1, "." };
+       /*
+        * uio->uio_offset carries the number of the entry
+        * where we should start returning dirents.
+        *
+        * We fake up "." if we're not reading the FS root
+        * and we always fake up "..".
+        *
+        * off contains the entry we are starting at,
+        * num increments while we are reading.
+        */
 
-               if( uio->uio_offset < sizeof(struct dirent) ) {
-                       dot.d_fileno = ip->i_number;
-                       error = uiomove((char *)&dot,sizeof(struct dirent),uio);
-                       if(error)
-                               return (error);
+       off = num = uio->uio_offset;
+       faked = (ip->i_number == NTFS_ROOTINO) ? 1 : 2;
 
-                       ncookies ++;
-               }
+       /* Simulate . in every dir except ROOT */
+       if (ip->i_number != NTFS_ROOTINO && num == 0) {
+               if (vop_write_dirent(&error, uio, ip->i_number,
+                   DT_DIR, 1, "."))
+                       return (0);
+               if (error)
+                       return (error);
+
+               num++;
+               ncookies++;
        }
 
        /* Simulate .. in every dir including ROOT */
-       if( uio->uio_offset < 2 * sizeof(struct dirent) ) {
-               struct dirent dotdot = { NTFS_ROOTINO,
-                               sizeof(struct dirent), DT_DIR, 2, ".." };
-
-               error = uiomove((char *)&dotdot,sizeof(struct dirent),uio);
+       if (num == faked - 1) {
+               /* XXX NTFS_ROOTINO seems to be wrong here */
+               if (vop_write_dirent(&error, uio, NTFS_ROOTINO,
+                   DT_DIR, 2, ".."))
+                       goto readdone;
                if(error)
                        return (error);
 
-               ncookies ++;
+               num++;
+               ncookies++;
        }
 
-       faked = (ip->i_number == NTFS_ROOTINO) ? 1 : 2;
-       num = uio->uio_offset / sizeof(struct dirent) - faked;
-
-       while( uio->uio_resid >= sizeof(struct dirent) ) {
+       for (;;) {
                struct attr_indexentry *iep;
 
-               error = ntfs_ntreaddir(ntmp, fp, num, &iep);
+               /*
+                * num is the number of the entry we will return,
+                * but ntfs_ntreaddir takes the entry number of the
+                * ntfs directory listing, so subtract the faked
+                * . and .. entries.
+                */
+               error = ntfs_ntreaddir(ntmp, fp, num - faked, &iep);
 
                if(error)
                        return (error);
@@ -623,26 +622,28 @@ ntfs_readdir(struct vop_readdir_args *ap)
                if( NULL == iep )
                        break;
 
-               for(; !(iep->ie_flag & NTFS_IEFLAG_LAST) && (uio->uio_resid >= sizeof(struct dirent));
+               for (; !(iep->ie_flag & NTFS_IEFLAG_LAST);
                        iep = NTFS_NEXTREC(iep, struct attr_indexentry *))
                {
                        if(!ntfs_isnamepermitted(ntmp,iep))
                                continue;
 
-                       for(i=0; i<iep->ie_fnamelen; i++) {
-                               cde.d_name[i] = NTFS_U28(iep->ie_fname[i]);
-                       }
-                       cde.d_name[i] = '\0';
-                       dprintf(("ntfs_readdir: elem: %d, fname:[%s] type: %d, flag: %d, ",
-                               num, cde.d_name, iep->ie_fnametype,
-                               iep->ie_flag));
-                       cde.d_namlen = iep->ie_fnamelen;
-                       cde.d_fileno = iep->ie_number;
-                       cde.d_type = (iep->ie_fflag & NTFS_FFLAG_DIR) ? DT_DIR : DT_REG;
-                       cde.d_reclen = sizeof(struct dirent);
-                       dprintf(("%s\n", (cde.d_type == DT_DIR) ? "dir":"reg"));
-
-                       error = uiomove((char *)&cde, sizeof(struct dirent), uio);
+                       for (i=0; i < iep->ie_fnamelen; i++)
+                               convname[i] = NTFS_U28(iep->ie_fname[i]);
+                       convname[i] = '\0';
+
+                       if (vop_write_dirent(&error, uio, iep->ie_number,
+                           (iep->ie_fflag & NTFS_FFLAG_DIR) ? DT_DIR : DT_REG,
+                           iep->ie_fnamelen, convname))
+                               goto readdone;
+
+                       dprintf(("ntfs_readdir: elem: %d, fname:[%s] type: %d, "
+                                "flag: %d, %s\n",
+                                ncookies, convname, iep->ie_fnametype,
+                                iep->ie_flag,
+                                (iep->ie_fflag & NTFS_FFLAG_DIR) ?
+                                       "dir" : "reg"));
+
                        if(error)
                                return (error);
 
@@ -651,14 +652,15 @@ ntfs_readdir(struct vop_readdir_args *ap)
                }
        }
 
+readdone:
+       uio->uio_offset = num;
+
        dprintf(("ntfs_readdir: %d entries (%d bytes) read\n",
                ncookies,(u_int)(uio->uio_offset - off)));
        dprintf(("ntfs_readdir: off: %d resid: %d\n",
                (u_int32_t)uio->uio_offset,uio->uio_resid));
 
        if (!error && ap->a_ncookies != NULL) {
-               struct dirent* dpStart;
-               struct dirent* dp;
 #if defined(__DragonFly__)
                u_long *cookies;
                u_long *cookiep;
@@ -670,9 +672,6 @@ ntfs_readdir(struct vop_readdir_args *ap)
                ddprintf(("ntfs_readdir: %d cookies\n",ncookies));
                if (uio->uio_segflg != UIO_SYSSPACE || uio->uio_iovcnt != 1)
                        panic("ntfs_readdir: unexpected uio from NFS server");
-               dpStart = (struct dirent *)
-                    ((caddr_t)uio->uio_iov->iov_base -
-                        (uio->uio_offset - off));
 #if defined(__DragonFly__)
                MALLOC(cookies, u_long *, ncookies * sizeof(u_long),
                       M_TEMP, M_WAITOK);
@@ -680,12 +679,10 @@ ntfs_readdir(struct vop_readdir_args *ap)
                MALLOC(cookies, off_t *, ncookies * sizeof(off_t),
                       M_TEMP, M_WAITOK);
 #endif
-               for (dp = dpStart, cookiep = cookies, i=0;
-                    i < ncookies;
-                    dp = (struct dirent *)((caddr_t) dp + dp->d_reclen), i++) {
-                       off += dp->d_reclen;
-                       *cookiep++ = (u_int) off;
-               }
+               cookiep = cookies;
+               while (off < num)
+                       *cookiep++ = ++off;
+
                *ap->a_ncookies = ncookies;
                *ap->a_cookies = cookies;
        }
@@ -701,7 +698,7 @@ ntfs_readdir(struct vop_readdir_args *ap)
  *             struct componentname *a_cnp)
  */
 int
-ntfs_lookup(struct vop_lookup_args *ap)
+ntfs_lookup(struct vop_old_lookup_args *ap)
 {
        struct vnode *dvp = ap->a_dvp;
        struct ntnode *dip = VTONT(dvp);
@@ -848,7 +845,7 @@ struct vnodeopv_entry_desc ntfs_vnodeop_entries[] = {
        { &vop_islocked_desc,   (vnodeopv_entry_t)vop_stdislocked },
        { &vop_unlock_desc,     (vnodeopv_entry_t)vop_stdunlock },
        { &vop_lock_desc,       (vnodeopv_entry_t)vop_stdlock },
-       { &vop_lookup_desc,     (vnodeopv_entry_t)ntfs_lookup },
+       { &vop_old_lookup_desc, (vnodeopv_entry_t)ntfs_lookup },
 
        { &vop_access_desc,     (vnodeopv_entry_t)ntfs_access },
        { &vop_close_desc,      (vnodeopv_entry_t)ntfs_close },