vserver 1.9.3
[linux-2.6.git] / fs / ntfs / dir.c
index 2468622..ed9838e 100644 (file)
@@ -28,8 +28,7 @@
  * The little endian Unicode string $I30 as a global constant.
  */
 ntfschar I30[5] = { const_cpu_to_le16('$'), const_cpu_to_le16('I'),
-               const_cpu_to_le16('3'), const_cpu_to_le16('0'),
-               const_cpu_to_le16(0) };
+               const_cpu_to_le16('3'), const_cpu_to_le16('0'), 0 };
 
 /**
  * ntfs_lookup_inode_by_name - find an inode in a directory given its name
@@ -83,7 +82,7 @@ MFT_REF ntfs_lookup_inode_by_name(ntfs_inode *dir_ni, const ntfschar *uname,
        INDEX_ALLOCATION *ia;
        u8 *index_end;
        u64 mref;
-       attr_search_context *ctx;
+       ntfs_attr_search_ctx *ctx;
        int err, rc;
        VCN vcn, old_vcn;
        struct address_space *ia_mapping;
@@ -95,22 +94,26 @@ MFT_REF ntfs_lookup_inode_by_name(ntfs_inode *dir_ni, const ntfschar *uname,
        BUG_ON(NInoAttr(dir_ni));
        /* Get hold of the mft record for the directory. */
        m = map_mft_record(dir_ni);
-       if (unlikely(IS_ERR(m))) {
+       if (IS_ERR(m)) {
                ntfs_error(sb, "map_mft_record() failed with error code %ld.",
                                -PTR_ERR(m));
                return ERR_MREF(PTR_ERR(m));
        }
-       ctx = get_attr_search_ctx(dir_ni, m);
+       ctx = ntfs_attr_get_search_ctx(dir_ni, m);
        if (unlikely(!ctx)) {
                err = -ENOMEM;
                goto err_out;
        }
        /* Find the index root attribute in the mft record. */
-       if (!lookup_attr(AT_INDEX_ROOT, I30, 4, CASE_SENSITIVE, 0, NULL, 0,
-                       ctx)) {
-               ntfs_error(sb, "Index root attribute missing in directory "
-                               "inode 0x%lx.", dir_ni->mft_no);
-               err = -EIO;
+       err = ntfs_attr_lookup(AT_INDEX_ROOT, I30, 4, CASE_SENSITIVE, 0, NULL,
+                       0, ctx);
+       if (unlikely(err)) {
+               if (err == -ENOENT) {
+                       ntfs_error(sb, "Index root attribute missing in "
+                                       "directory inode 0x%lx.",
+                                       dir_ni->mft_no);
+                       err = -EIO;
+               }
                goto err_out;
        }
        /* Get to the index root value (it's been verified in read_inode). */
@@ -179,7 +182,7 @@ found_it:
                                *res = NULL;
                        }
                        mref = le64_to_cpu(ie->data.dir.indexed_file);
-                       put_attr_search_ctx(ctx);
+                       ntfs_attr_put_search_ctx(ctx);
                        unmap_mft_record(dir_ni);
                        return mref;
                }
@@ -278,7 +281,7 @@ found_it:
         */
        if (!(ie->flags & INDEX_ENTRY_NODE)) {
                if (name) {
-                       put_attr_search_ctx(ctx);
+                       ntfs_attr_put_search_ctx(ctx);
                        unmap_mft_record(dir_ni);
                        return name->mref;
                }
@@ -295,13 +298,13 @@ found_it:
                goto err_out;
        }
        /* Get the starting vcn of the index_block holding the child node. */
-       vcn = sle64_to_cpup((u8*)ie + le16_to_cpu(ie->length) - 8);
+       vcn = sle64_to_cpup((sle64*)((u8*)ie + le16_to_cpu(ie->length) - 8));
        ia_mapping = VFS_I(dir_ni)->i_mapping;
        /*
         * We are done with the index root and the mft record. Release them,
         * otherwise we deadlock with ntfs_map_page().
         */
-       put_attr_search_ctx(ctx);
+       ntfs_attr_put_search_ctx(ctx);
        unmap_mft_record(dir_ni);
        m = NULL;
        ctx = NULL;
@@ -547,7 +550,8 @@ found_it2:
                }
                /* Child node present, descend into it. */
                old_vcn = vcn;
-               vcn = sle64_to_cpup((u8*)ie + le16_to_cpu(ie->length) - 8);
+               vcn = sle64_to_cpup((sle64*)((u8*)ie +
+                               le16_to_cpu(ie->length) - 8));
                if (vcn >= 0) {
                        /* If vcn is in the same page cache page as old_vcn we
                         * recycle the mapped page. */
@@ -582,7 +586,7 @@ unm_err_out:
        ntfs_unmap_page(page);
 err_out:
        if (ctx)
-               put_attr_search_ctx(ctx);
+               ntfs_attr_put_search_ctx(ctx);
        if (m)
                unmap_mft_record(dir_ni);
        if (name) {
@@ -634,7 +638,7 @@ u64 ntfs_lookup_inode_by_name(ntfs_inode *dir_ni, const ntfschar *uname,
        INDEX_ALLOCATION *ia;
        u8 *index_end;
        u64 mref;
-       attr_search_context *ctx;
+       ntfs_attr_search_ctx *ctx;
        int err, rc;
        IGNORE_CASE_BOOL ic;
        VCN vcn, old_vcn;
@@ -649,17 +653,21 @@ u64 ntfs_lookup_inode_by_name(ntfs_inode *dir_ni, const ntfschar *uname,
                                -PTR_ERR(m));
                return ERR_MREF(PTR_ERR(m));
        }
-       ctx = get_attr_search_ctx(dir_ni, m);
+       ctx = ntfs_attr_get_search_ctx(dir_ni, m);
        if (!ctx) {
                err = -ENOMEM;
                goto err_out;
        }
        /* Find the index root attribute in the mft record. */
-       if (!lookup_attr(AT_INDEX_ROOT, I30, 4, CASE_SENSITIVE, 0, NULL, 0,
-                       ctx)) {
-               ntfs_error(sb, "Index root attribute missing in directory "
-                               "inode 0x%lx.", dir_ni->mft_no);
-               err = -EIO;
+       err = ntfs_attr_lookup(AT_INDEX_ROOT, I30, 4, CASE_SENSITIVE, 0, NULL,
+                       0, ctx);
+       if (unlikely(err)) {
+               if (err == -ENOENT) {
+                       ntfs_error(sb, "Index root attribute missing in "
+                                       "directory inode 0x%lx.",
+                                       dir_ni->mft_no);
+                       err = -EIO;
+               }
                goto err_out;
        }
        /* Get to the index root value (it's been verified in read_inode). */
@@ -710,7 +718,7 @@ u64 ntfs_lookup_inode_by_name(ntfs_inode *dir_ni, const ntfschar *uname,
                                vol->upcase, vol->upcase_len)) {
 found_it:
                        mref = le64_to_cpu(ie->data.dir.indexed_file);
-                       put_attr_search_ctx(ctx);
+                       ntfs_attr_put_search_ctx(ctx);
                        unmap_mft_record(dir_ni);
                        return mref;
                }
@@ -776,7 +784,7 @@ found_it:
         * We are done with the index root and the mft record. Release them,
         * otherwise we deadlock with ntfs_map_page().
         */
-       put_attr_search_ctx(ctx);
+       ntfs_attr_put_search_ctx(ctx);
        unmap_mft_record(dir_ni);
        m = NULL;
        ctx = NULL;
@@ -979,7 +987,7 @@ unm_err_out:
        ntfs_unmap_page(page);
 err_out:
        if (ctx)
-               put_attr_search_ctx(ctx);
+               ntfs_attr_put_search_ctx(ctx);
        if (m)
                unmap_mft_record(dir_ni);
        return ERR_MREF(err);
@@ -991,23 +999,11 @@ dir_err_out:
 
 #endif
 
-typedef union {
-       INDEX_ROOT *ir;
-       INDEX_ALLOCATION *ia;
-} index_union __attribute__ ((__transparent_union__));
-
-typedef enum {
-       INDEX_TYPE_ROOT,        /* index root */
-       INDEX_TYPE_ALLOCATION,  /* index allocation */
-} INDEX_TYPE;
-
 /**
  * ntfs_filldir - ntfs specific filldir method
  * @vol:       current ntfs volume
  * @fpos:      position in the directory
  * @ndir:      ntfs inode of current directory
- * @index_type:        specifies whether @iu is an index root or an index allocation
- * @iu:                index root or index allocation attribute to which @ie belongs
  * @ia_page:   page in which the index allocation buffer @ie is in resides
  * @ie:                current index entry
  * @name:      buffer to use for the converted name
@@ -1017,9 +1013,8 @@ typedef enum {
  * Convert the Unicode @name to the loaded NLS and pass it to the @filldir
  * callback.
  *
- * If @index_type is INDEX_TYPE_ALLOCATION, @ia_page is the locked page
- * containing the index allocation block containing the index entry @ie.
- * Otherwise, @ia_page is NULL.
+ * If @ia_page is not NULL it is the locked page containing the index
+ * allocation block containing the index entry @ie.
  *
  * Note, we drop (and then reacquire) the page lock on @ia_page across the
  * @filldir() call otherwise we would deadlock with NFSd when it calls ->lookup
@@ -1027,9 +1022,8 @@ typedef enum {
  * retake the lock if we are returning a non-zero value as ntfs_readdir()
  * would need to drop the lock immediately anyway.
  */
-static inline int ntfs_filldir(ntfs_volume *vol, loff_t *fpos,
-               ntfs_inode *ndir, const INDEX_TYPE index_type,
-               index_union iu, struct page *ia_page, INDEX_ENTRY *ie,
+static inline int ntfs_filldir(ntfs_volume *vol, loff_t fpos,
+               ntfs_inode *ndir, struct page *ia_page, INDEX_ENTRY *ie,
                u8 *name, void *dirent, filldir_t filldir)
 {
        unsigned long mref;
@@ -1037,14 +1031,6 @@ static inline int ntfs_filldir(ntfs_volume *vol, loff_t *fpos,
        unsigned dt_type;
        FILE_NAME_TYPE_FLAGS name_type;
 
-       /* Advance the position even if going to skip the entry. */
-       if (index_type == INDEX_TYPE_ALLOCATION)
-               *fpos = (u8*)ie - (u8*)iu.ia +
-                               (sle64_to_cpu(iu.ia->index_block_vcn) <<
-                               ndir->itype.index.vcn_size_bits) +
-                               vol->mft_record_size;
-       else /* if (index_type == INDEX_TYPE_ROOT) */
-               *fpos = (u8*)ie - (u8*)iu.ir;
        name_type = ie->key.file_name.file_name_type;
        if (name_type == FILE_NAME_DOS) {
                ntfs_debug("Skipping DOS name space entry.");
@@ -1076,14 +1062,14 @@ static inline int ntfs_filldir(ntfs_volume *vol, loff_t *fpos,
         * Drop the page lock otherwise we deadlock with NFS when it calls
         * ->lookup since ntfs_lookup() will lock the same page.
         */
-       if (index_type == INDEX_TYPE_ALLOCATION)
+       if (ia_page)
                unlock_page(ia_page);
        ntfs_debug("Calling filldir for %s with len %i, fpos 0x%llx, inode "
-                       "0x%lx, DT_%s.", name, name_len, *fpos, mref,
+                       "0x%lx, DT_%s.", name, name_len, fpos, mref,
                        dt_type == DT_DIR ? "DIR" : "REG");
-       rc = filldir(dirent, name, name_len, *fpos, mref, dt_type);
+       rc = filldir(dirent, name, name_len, fpos, mref, dt_type);
        /* Relock the page but not if we are aborting ->readdir. */
-       if (!rc && index_type == INDEX_TYPE_ALLOCATION)
+       if (!rc && ia_page)
                lock_page(ia_page);
        return rc;
 }
@@ -1125,7 +1111,7 @@ static int ntfs_readdir(struct file *filp, void *dirent, filldir_t filldir)
        struct address_space *ia_mapping, *bmp_mapping;
        struct page *bmp_page = NULL, *ia_page = NULL;
        u8 *kaddr, *bmp, *index_end;
-       attr_search_context *ctx;
+       ntfs_attr_search_ctx *ctx;
 
        fpos = filp->f_pos;
        ntfs_debug("Entering for inode 0x%lx, fpos 0x%llx.",
@@ -1170,12 +1156,12 @@ static int ntfs_readdir(struct file *filp, void *dirent, filldir_t filldir)
                goto skip_index_root;
        /* Get hold of the mft record for the directory. */
        m = map_mft_record(ndir);
-       if (unlikely(IS_ERR(m))) {
+       if (IS_ERR(m)) {
                err = PTR_ERR(m);
                m = NULL;
                goto err_out;
        }
-       ctx = get_attr_search_ctx(ndir, m);
+       ctx = ntfs_attr_get_search_ctx(ndir, m);
        if (unlikely(!ctx)) {
                err = -ENOMEM;
                goto err_out;
@@ -1183,8 +1169,9 @@ static int ntfs_readdir(struct file *filp, void *dirent, filldir_t filldir)
        /* Get the offset into the index root attribute. */
        ir_pos = (s64)fpos;
        /* Find the index root attribute in the mft record. */
-       if (unlikely(!lookup_attr(AT_INDEX_ROOT, I30, 4, CASE_SENSITIVE, 0,
-                       NULL, 0, ctx))) {
+       err = ntfs_attr_lookup(AT_INDEX_ROOT, I30, 4, CASE_SENSITIVE, 0, NULL,
+                       0, ctx);
+       if (unlikely(err)) {
                ntfs_error(sb, "Index root attribute missing in directory "
                                "inode 0x%lx.", vdir->i_ino);
                goto err_out;
@@ -1208,7 +1195,7 @@ static int ntfs_readdir(struct file *filp, void *dirent, filldir_t filldir)
        /* Copy the index root value (it has been verified in read_inode). */
        memcpy(ir, (u8*)ctx->attr +
                        le16_to_cpu(ctx->attr->data.resident.value_offset), rc);
-       put_attr_search_ctx(ctx);
+       ntfs_attr_put_search_ctx(ctx);
        unmap_mft_record(ndir);
        ctx = NULL;
        m = NULL;
@@ -1235,9 +1222,11 @@ static int ntfs_readdir(struct file *filp, void *dirent, filldir_t filldir)
                /* Skip index root entry if continuing previous readdir. */
                if (ir_pos > (u8*)ie - (u8*)ir)
                        continue;
+               /* Advance the position even if going to skip the entry. */
+               fpos = (u8*)ie - (u8*)ir;
                /* Submit the name to the filldir callback. */
-               rc = ntfs_filldir(vol, &fpos, ndir, INDEX_TYPE_ROOT, ir, NULL,
-                               ie, name, dirent, filldir);
+               rc = ntfs_filldir(vol, fpos, ndir, NULL, ie, name, dirent,
+                               filldir);
                if (rc) {
                        kfree(ir);
                        goto abort;
@@ -1261,7 +1250,7 @@ skip_index_root:
        if (unlikely(!bmp_vi)) {
                ntfs_debug("Inode 0x%lx, regetting index bitmap.", vdir->i_ino);
                bmp_vi = ntfs_attr_iget(vdir, AT_BITMAP, I30, 4);
-               if (unlikely(IS_ERR(bmp_vi))) {
+               if (IS_ERR(bmp_vi)) {
                        ntfs_error(sb, "Failed to get bitmap attribute.");
                        err = PTR_ERR(bmp_vi);
                        goto err_out;
@@ -1286,7 +1275,7 @@ get_next_bmp_page:
                        ((PAGE_CACHE_SIZE * 8) - 1));
        bmp_page = ntfs_map_page(bmp_mapping,
                        bmp_pos >> (3 + PAGE_CACHE_SHIFT));
-       if (unlikely(IS_ERR(bmp_page))) {
+       if (IS_ERR(bmp_page)) {
                ntfs_error(sb, "Reading index bitmap failed.");
                err = PTR_ERR(bmp_page);
                bmp_page = NULL;
@@ -1327,7 +1316,7 @@ find_next_index_buffer:
                 * reading it from disk if necessary.
                 */
                ia_page = ntfs_map_page(ia_mapping, ia_pos >> PAGE_CACHE_SHIFT);
-               if (unlikely(IS_ERR(ia_page))) {
+               if (IS_ERR(ia_page)) {
                        ntfs_error(sb, "Reading index allocation data failed.");
                        err = PTR_ERR(ia_page);
                        ia_page = NULL;
@@ -1411,14 +1400,19 @@ find_next_index_buffer:
                /* Skip index block entry if continuing previous readdir. */
                if (ia_pos - ia_start > (u8*)ie - (u8*)ia)
                        continue;
+               /* Advance the position even if going to skip the entry. */
+               fpos = (u8*)ie - (u8*)ia +
+                               (sle64_to_cpu(ia->index_block_vcn) <<
+                               ndir->itype.index.vcn_size_bits) +
+                               vol->mft_record_size;
                /*
                 * Submit the name to the @filldir callback.  Note,
                 * ntfs_filldir() drops the lock on @ia_page but it retakes it
                 * before returning, unless a non-zero value is returned in
                 * which case the page is left unlocked.
                 */
-               rc = ntfs_filldir(vol, &fpos, ndir, INDEX_TYPE_ALLOCATION, ia,
-                               ia_page, ie, name, dirent, filldir);
+               rc = ntfs_filldir(vol, fpos, ndir, ia_page, ie, name, dirent,
+                               filldir);
                if (rc) {
                        /* @ia_page is already unlocked in this case. */
                        ntfs_unmap_page(ia_page);
@@ -1460,7 +1454,7 @@ err_out:
        if (name)
                kfree(name);
        if (ctx)
-               put_attr_search_ctx(ctx);
+               ntfs_attr_put_search_ctx(ctx);
        if (m)
                unmap_mft_record(ndir);
        if (!err)
@@ -1495,10 +1489,69 @@ static int ntfs_dir_open(struct inode *vi, struct file *filp)
        return 0;
 }
 
+#ifdef NTFS_RW
+
+/**
+ * ntfs_dir_fsync - sync a directory to disk
+ * @filp:      directory to be synced
+ * @dentry:    dentry describing the directory to sync
+ * @datasync:  if non-zero only flush user data and not metadata
+ *
+ * Data integrity sync of a directory to disk.  Used for fsync, fdatasync, and
+ * msync system calls.  This function is based on file.c::ntfs_file_fsync().
+ *
+ * Write the mft record and all associated extent mft records as well as the
+ * $INDEX_ALLOCATION and $BITMAP attributes and then sync the block device.
+ *
+ * If @datasync is true, we do not wait on the inode(s) to be written out
+ * but we always wait on the page cache pages to be written out.
+ *
+ * Note: In the past @filp could be NULL so we ignore it as we don't need it
+ * anyway.
+ *
+ * Locking: Caller must hold i_sem on the inode.
+ *
+ * TODO: We should probably also write all attribute/index inodes associated
+ * with this inode but since we have no simple way of getting to them we ignore
+ * this problem for now.  We do write the $BITMAP attribute if it is present
+ * which is the important one for a directory so things are not too bad.
+ */
+static int ntfs_dir_fsync(struct file *filp, struct dentry *dentry,
+               int datasync)
+{
+       struct inode *vi = dentry->d_inode;
+       ntfs_inode *ni = NTFS_I(vi);
+       int err, ret;
+
+       ntfs_debug("Entering for inode 0x%lx.", vi->i_ino);
+       BUG_ON(!S_ISDIR(vi->i_mode));
+       if (NInoIndexAllocPresent(ni) && ni->itype.index.bmp_ino)
+               write_inode_now(ni->itype.index.bmp_ino, !datasync);
+       ret = ntfs_write_inode(vi, 1);
+       write_inode_now(vi, !datasync);
+       err = sync_blockdev(vi->i_sb->s_bdev);
+       if (unlikely(err && !ret))
+               ret = err;
+       if (likely(!ret))
+               ntfs_debug("Done.");
+       else
+               ntfs_warning(vi->i_sb, "Failed to f%ssync inode 0x%lx.  Error "
+                               "%u.", datasync ? "data" : "", vi->i_ino, -ret);
+       return ret;
+}
+
+#endif /* NTFS_RW */
+
 struct file_operations ntfs_dir_ops = {
        .llseek         = generic_file_llseek,  /* Seek inside directory. */
        .read           = generic_read_dir,     /* Return -EISDIR. */
        .readdir        = ntfs_readdir,         /* Read directory contents. */
+#ifdef NTFS_RW
+       .fsync          = ntfs_dir_fsync,       /* Sync a directory to disk. */
+       /*.aio_fsync    = ,*/                   /* Sync all outstanding async
+                                                  i/o operations on a kiocb. */
+#endif /* NTFS_RW */
+       /*.ioctl        = ,*/                   /* Perform function on the
+                                                  mounted filesystem. */
        .open           = ntfs_dir_open,        /* Open directory. */
 };
-