linux 2.6.16.38 w/ vs2.0.3-rc1
[linux-2.6.git] / fs / ntfs / dir.c
index ed9838e..b0690d4 100644 (file)
@@ -1,7 +1,7 @@
 /**
  * dir.c - NTFS kernel directory operations. Part of the Linux-NTFS project.
  *
- * Copyright (c) 2001-2004 Anton Altaparmakov
+ * Copyright (c) 2001-2005 Anton Altaparmakov
  * Copyright (c) 2002 Richard Russon
  *
  * This program/include file is free software; you can redistribute it and/or
  */
 
 #include <linux/smp_lock.h>
-#include "ntfs.h"
+#include <linux/buffer_head.h>
+
 #include "dir.h"
+#include "aops.h"
+#include "attrib.h"
+#include "mft.h"
+#include "debug.h"
+#include "ntfs.h"
 
 /**
  * The little endian Unicode string $I30 as a global constant.
@@ -63,7 +69,7 @@ ntfschar I30[5] = { const_cpu_to_le16('$'), const_cpu_to_le16('I'),
  * work but we don't care for how quickly one can access them. This also fixes
  * the dcache aliasing issues.
  *
- * Locking:  - Caller must hold i_sem on the directory.
+ * Locking:  - Caller must hold i_mutex on the directory.
  *          - Each page cache page in the index allocation mapping must be
  *            locked whilst being accessed otherwise we may find a corrupt
  *            page due to it being under ->writepage at the moment which
@@ -177,8 +183,7 @@ found_it:
                                name->len = 0;
                                *res = name;
                        } else {
-                               if (name)
-                                       kfree(name);
+                               kfree(name);
                                *res = NULL;
                        }
                        mref = le64_to_cpu(ie->data.dir.indexed_file);
@@ -294,7 +299,6 @@ found_it:
                ntfs_error(sb, "No index allocation attribute but index entry "
                                "requires one. Directory inode 0x%lx is "
                                "corrupt or driver bug.", dir_ni->mft_no);
-               err = -EIO;
                goto err_out;
        }
        /* Get the starting vcn of the index_block holding the child node. */
@@ -332,7 +336,13 @@ fast_descend_into_child_node:
        if ((u8*)ia < kaddr || (u8*)ia > kaddr + PAGE_CACHE_SIZE) {
                ntfs_error(sb, "Out of bounds check failed. Corrupt directory "
                                "inode 0x%lx or driver bug.", dir_ni->mft_no);
-               err = -EIO;
+               goto unm_err_out;
+       }
+       /* Catch multi sector transfer fixup errors. */
+       if (unlikely(!ntfs_is_indx_record(ia->magic))) {
+               ntfs_error(sb, "Directory index record with vcn 0x%llx is "
+                               "corrupt.  Corrupt inode 0x%lx.  Run chkdsk.",
+                               (unsigned long long)vcn, dir_ni->mft_no);
                goto unm_err_out;
        }
        if (sle64_to_cpu(ia->index_block_vcn) != vcn) {
@@ -342,7 +352,6 @@ fast_descend_into_child_node:
                                "bug.", (unsigned long long)
                                sle64_to_cpu(ia->index_block_vcn),
                                (unsigned long long)vcn, dir_ni->mft_no);
-               err = -EIO;
                goto unm_err_out;
        }
        if (le32_to_cpu(ia->index.allocated_size) + 0x18 !=
@@ -354,7 +363,6 @@ fast_descend_into_child_node:
                                (unsigned long long)vcn, dir_ni->mft_no,
                                le32_to_cpu(ia->index.allocated_size) + 0x18,
                                dir_ni->itype.index.block_size);
-               err = -EIO;
                goto unm_err_out;
        }
        index_end = (u8*)ia + dir_ni->itype.index.block_size;
@@ -364,7 +372,6 @@ fast_descend_into_child_node:
                                "Cannot access! This is probably a bug in the "
                                "driver.", (unsigned long long)vcn,
                                dir_ni->mft_no);
-               err = -EIO;
                goto unm_err_out;
        }
        index_end = (u8*)&ia->index + le32_to_cpu(ia->index.index_length);
@@ -372,7 +379,6 @@ fast_descend_into_child_node:
                ntfs_error(sb, "Size of index buffer (VCN 0x%llx) of directory "
                                "inode 0x%lx exceeds maximum size.",
                                (unsigned long long)vcn, dir_ni->mft_no);
-               err = -EIO;
                goto unm_err_out;
        }
        /* The first index entry. */
@@ -392,7 +398,6 @@ fast_descend_into_child_node:
                        ntfs_error(sb, "Index entry out of bounds in "
                                        "directory inode 0x%lx.",
                                        dir_ni->mft_no);
-                       err = -EIO;
                        goto unm_err_out;
                }
                /*
@@ -438,8 +443,7 @@ found_it2:
                                name->len = 0;
                                *res = name;
                        } else {
-                               if (name)
-                                       kfree(name);
+                               kfree(name);
                                *res = NULL;
                        }
                        mref = le64_to_cpu(ie->data.dir.indexed_file);
@@ -545,7 +549,6 @@ found_it2:
                        ntfs_error(sb, "Index entry with child node found in "
                                        "a leaf node in directory inode 0x%lx.",
                                        dir_ni->mft_no);
-                       err = -EIO;
                        goto unm_err_out;
                }
                /* Child node present, descend into it. */
@@ -566,7 +569,6 @@ found_it2:
                }
                ntfs_error(sb, "Negative child node vcn in directory inode "
                                "0x%lx.", dir_ni->mft_no);
-               err = -EIO;
                goto unm_err_out;
        }
        /*
@@ -585,6 +587,8 @@ unm_err_out:
        unlock_page(page);
        ntfs_unmap_page(page);
 err_out:
+       if (!err)
+               err = -EIO;
        if (ctx)
                ntfs_attr_put_search_ctx(ctx);
        if (m)
@@ -595,8 +599,7 @@ err_out:
        }
        return ERR_MREF(err);
 dir_err_out:
-       ntfs_error(sb, "Corrupt directory. Aborting lookup.");
-       err = -EIO;
+       ntfs_error(sb, "Corrupt directory.  Aborting lookup.");
        goto err_out;
 }
 
@@ -605,7 +608,7 @@ dir_err_out:
 // TODO: (AIA)
 // The algorithm embedded in this code will be required for the time when we
 // want to support adding of entries to directories, where we require correct
-// collation of file names in order not to cause corruption of the file system.
+// collation of file names in order not to cause corruption of the filesystem.
 
 /**
  * ntfs_lookup_inode_by_name - find an inode in a directory given its name
@@ -774,7 +777,6 @@ found_it:
                ntfs_error(sb, "No index allocation attribute but index entry "
                                "requires one. Directory inode 0x%lx is "
                                "corrupt or driver bug.", dir_ni->mft_no);
-               err = -EIO;
                goto err_out;
        }
        /* Get the starting vcn of the index_block holding the child node. */
@@ -812,7 +814,13 @@ fast_descend_into_child_node:
        if ((u8*)ia < kaddr || (u8*)ia > kaddr + PAGE_CACHE_SIZE) {
                ntfs_error(sb, "Out of bounds check failed. Corrupt directory "
                                "inode 0x%lx or driver bug.", dir_ni->mft_no);
-               err = -EIO;
+               goto unm_err_out;
+       }
+       /* Catch multi sector transfer fixup errors. */
+       if (unlikely(!ntfs_is_indx_record(ia->magic))) {
+               ntfs_error(sb, "Directory index record with vcn 0x%llx is "
+                               "corrupt.  Corrupt inode 0x%lx.  Run chkdsk.",
+                               (unsigned long long)vcn, dir_ni->mft_no);
                goto unm_err_out;
        }
        if (sle64_to_cpu(ia->index_block_vcn) != vcn) {
@@ -822,7 +830,6 @@ fast_descend_into_child_node:
                                "bug.", (unsigned long long)
                                sle64_to_cpu(ia->index_block_vcn),
                                (unsigned long long)vcn, dir_ni->mft_no);
-               err = -EIO;
                goto unm_err_out;
        }
        if (le32_to_cpu(ia->index.allocated_size) + 0x18 !=
@@ -834,7 +841,6 @@ fast_descend_into_child_node:
                                (unsigned long long)vcn, dir_ni->mft_no,
                                le32_to_cpu(ia->index.allocated_size) + 0x18,
                                dir_ni->itype.index.block_size);
-               err = -EIO;
                goto unm_err_out;
        }
        index_end = (u8*)ia + dir_ni->itype.index.block_size;
@@ -844,7 +850,6 @@ fast_descend_into_child_node:
                                "Cannot access! This is probably a bug in the "
                                "driver.", (unsigned long long)vcn,
                                dir_ni->mft_no);
-               err = -EIO;
                goto unm_err_out;
        }
        index_end = (u8*)&ia->index + le32_to_cpu(ia->index.index_length);
@@ -852,7 +857,6 @@ fast_descend_into_child_node:
                ntfs_error(sb, "Size of index buffer (VCN 0x%llx) of directory "
                                "inode 0x%lx exceeds maximum size.",
                                (unsigned long long)vcn, dir_ni->mft_no);
-               err = -EIO;
                goto unm_err_out;
        }
        /* The first index entry. */
@@ -872,7 +876,6 @@ fast_descend_into_child_node:
                        ntfs_error(sb, "Index entry out of bounds in "
                                        "directory inode 0x%lx.",
                                        dir_ni->mft_no);
-                       err = -EIO;
                        goto unm_err_out;
                }
                /*
@@ -956,7 +959,6 @@ found_it2:
                        ntfs_error(sb, "Index entry with child node found in "
                                        "a leaf node in directory inode 0x%lx.",
                                        dir_ni->mft_no);
-                       err = -EIO;
                        goto unm_err_out;
                }
                /* Child node present, descend into it. */
@@ -976,7 +978,6 @@ found_it2:
                }
                ntfs_error(sb, "Negative child node vcn in directory inode "
                                "0x%lx.", dir_ni->mft_no);
-               err = -EIO;
                goto unm_err_out;
        }
        /* No child node, return -ENOENT. */
@@ -986,6 +987,8 @@ unm_err_out:
        unlock_page(page);
        ntfs_unmap_page(page);
 err_out:
+       if (!err)
+               err = -EIO;
        if (ctx)
                ntfs_attr_put_search_ctx(ctx);
        if (m)
@@ -993,7 +996,6 @@ err_out:
        return ERR_MREF(err);
 dir_err_out:
        ntfs_error(sb, "Corrupt directory. Aborting lookup.");
-       err = -EIO;
        goto err_out;
 }
 
@@ -1049,7 +1051,8 @@ static inline int ntfs_filldir(ntfs_volume *vol, loff_t fpos,
                        ie->key.file_name.file_name_length, &name,
                        NTFS_MAX_NAME_LEN * NLS_MAX_CHARSET_SIZE + 1);
        if (name_len <= 0) {
-               ntfs_debug("Skipping unrepresentable file.");
+               ntfs_warning(vol->sb, "Skipping unrepresentable inode 0x%llx.",
+                               (long long)MREF_LE(ie->data.dir.indexed_file));
                return 0;
        }
        if (ie->key.file_name.file_attributes &
@@ -1082,11 +1085,11 @@ static inline int ntfs_filldir(ntfs_volume *vol, loff_t fpos,
  * While this will return the names in random order this doesn't matter for
  * ->readdir but OTOH results in a faster ->readdir.
  *
- * VFS calls ->readdir without BKL but with i_sem held. This protects the VFS
+ * VFS calls ->readdir without BKL but with i_mutex held. This protects the VFS
  * parts (e.g. ->f_pos and ->i_size, and it also protects against directory
  * modifications).
  *
- * Locking:  - Caller must hold i_sem on the directory.
+ * Locking:  - Caller must hold i_mutex on the directory.
  *          - Each page cache page in the index allocation mapping must be
  *            locked whilst being accessed otherwise we may find a corrupt
  *            page due to it being under ->writepage at the moment which
@@ -1097,7 +1100,7 @@ static inline int ntfs_filldir(ntfs_volume *vol, loff_t fpos,
 static int ntfs_readdir(struct file *filp, void *dirent, filldir_t filldir)
 {
        s64 ia_pos, ia_start, prev_ia_pos, bmp_pos;
-       loff_t fpos;
+       loff_t fpos, i_size;
        struct inode *bmp_vi, *vdir = filp->f_dentry->d_inode;
        struct super_block *sb = vdir->i_sb;
        ntfs_inode *ndir = NTFS_I(vdir);
@@ -1118,7 +1121,8 @@ static int ntfs_readdir(struct file *filp, void *dirent, filldir_t filldir)
                        vdir->i_ino, fpos);
        rc = err = 0;
        /* Are we at end of dir yet? */
-       if (fpos >= vdir->i_size + vol->mft_record_size)
+       i_size = i_size_read(vdir);
+       if (fpos >= i_size + vol->mft_record_size)
                goto done;
        /* Emulate . and .. for all directories. */
        if (!fpos) {
@@ -1260,7 +1264,7 @@ skip_index_root:
        bmp_mapping = bmp_vi->i_mapping;
        /* Get the starting bitmap bit position and sanity check it. */
        bmp_pos = ia_pos >> ndir->itype.index.block_size_bits;
-       if (unlikely(bmp_pos >> 3 >= bmp_vi->i_size)) {
+       if (unlikely(bmp_pos >> 3 >= i_size_read(bmp_vi))) {
                ntfs_error(sb, "Current index allocation position exceeds "
                                "index bitmap size.");
                goto err_out;
@@ -1272,7 +1276,7 @@ get_next_bmp_page:
        ntfs_debug("Reading bitmap with page index 0x%llx, bit ofs 0x%llx",
                        (unsigned long long)bmp_pos >> (3 + PAGE_CACHE_SHIFT),
                        (unsigned long long)bmp_pos &
-                       ((PAGE_CACHE_SIZE * 8) - 1));
+                       (unsigned long long)((PAGE_CACHE_SIZE * 8) - 1));
        bmp_page = ntfs_map_page(bmp_mapping,
                        bmp_pos >> (3 + PAGE_CACHE_SHIFT));
        if (IS_ERR(bmp_page)) {
@@ -1297,7 +1301,7 @@ find_next_index_buffer:
                        goto get_next_bmp_page;
                }
                /* If we have reached the end of the bitmap, we are done. */
-               if (unlikely(((bmp_pos + cur_bmp_pos) >> 3) >= vdir->i_size))
+               if (unlikely(((bmp_pos + cur_bmp_pos) >> 3) >= i_size))
                        goto unm_EOD;
                ia_pos = (bmp_pos + cur_bmp_pos) <<
                                ndir->itype.index.block_size_bits;
@@ -1305,7 +1309,8 @@ find_next_index_buffer:
        ntfs_debug("Handling index buffer 0x%llx.",
                        (unsigned long long)bmp_pos + cur_bmp_pos);
        /* If the current index buffer is in the same page we reuse the page. */
-       if ((prev_ia_pos & PAGE_CACHE_MASK) != (ia_pos & PAGE_CACHE_MASK)) {
+       if ((prev_ia_pos & (s64)PAGE_CACHE_MASK) !=
+                       (ia_pos & (s64)PAGE_CACHE_MASK)) {
                prev_ia_pos = ia_pos;
                if (likely(ia_page != NULL)) {
                        unlock_page(ia_page);
@@ -1334,6 +1339,14 @@ find_next_index_buffer:
                                "inode 0x%lx or driver bug.", vdir->i_ino);
                goto err_out;
        }
+       /* Catch multi sector transfer fixup errors. */
+       if (unlikely(!ntfs_is_indx_record(ia->magic))) {
+               ntfs_error(sb, "Directory index record with vcn 0x%llx is "
+                               "corrupt.  Corrupt inode 0x%lx.  Run chkdsk.",
+                               (unsigned long long)ia_pos >>
+                               ndir->itype.index.vcn_size_bits, vdir->i_ino);
+               goto err_out;
+       }
        if (unlikely(sle64_to_cpu(ia->index_block_vcn) != (ia_pos &
                        ~(s64)(ndir->itype.index.block_size - 1)) >>
                        ndir->itype.index.vcn_size_bits)) {
@@ -1386,8 +1399,8 @@ find_next_index_buffer:
         */
        for (;; ie = (INDEX_ENTRY*)((u8*)ie + le16_to_cpu(ie->length))) {
                ntfs_debug("In index allocation, offset 0x%llx.",
-                               (unsigned long long)ia_start + ((u8*)ie -
-                               (u8*)ia));
+                               (unsigned long long)ia_start +
+                               (unsigned long long)((u8*)ie - (u8*)ia));
                /* Bounds checks. */
                if (unlikely((u8*)ie < (u8*)ia || (u8*)ie +
                                sizeof(INDEX_ENTRY_HEADER) > index_end ||
@@ -1429,7 +1442,7 @@ unm_EOD:
        ntfs_unmap_page(bmp_page);
 EOD:
        /* We are finished, set fpos to EOD. */
-       fpos = vdir->i_size + vol->mft_record_size;
+       fpos = i_size + vol->mft_record_size;
 abort:
        kfree(name);
 done:
@@ -1449,10 +1462,8 @@ err_out:
                unlock_page(ia_page);
                ntfs_unmap_page(ia_page);
        }
-       if (ir)
-               kfree(ir);
-       if (name)
-               kfree(name);
+       kfree(ir);
+       kfree(name);
        if (ctx)
                ntfs_attr_put_search_ctx(ctx);
        if (m)
@@ -1483,7 +1494,7 @@ err_out:
 static int ntfs_dir_open(struct inode *vi, struct file *filp)
 {
        if (sizeof(unsigned long) < 8) {
-               if (vi->i_size > MAX_LFS_FILESIZE)
+               if (i_size_read(vi) > MAX_LFS_FILESIZE)
                        return -EFBIG;
        }
        return 0;
@@ -1509,7 +1520,7 @@ static int ntfs_dir_open(struct inode *vi, struct file *filp)
  * 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.
+ * Locking: Caller must hold i_mutex 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