/**
* 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.
* 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
name->len = 0;
*res = name;
} else {
- if (name)
- kfree(name);
+ kfree(name);
*res = NULL;
}
mref = le64_to_cpu(ie->data.dir.indexed_file);
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. */
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) {
"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 !=
(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;
"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);
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. */
ntfs_error(sb, "Index entry out of bounds in "
"directory inode 0x%lx.",
dir_ni->mft_no);
- err = -EIO;
goto unm_err_out;
}
/*
name->len = 0;
*res = name;
} else {
- if (name)
- kfree(name);
+ kfree(name);
*res = NULL;
}
mref = le64_to_cpu(ie->data.dir.indexed_file);
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. */
}
ntfs_error(sb, "Negative child node vcn in directory inode "
"0x%lx.", dir_ni->mft_no);
- err = -EIO;
goto 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)
}
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;
}
// 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
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. */
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) {
"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 !=
(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;
"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);
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. */
ntfs_error(sb, "Index entry out of bounds in "
"directory inode 0x%lx.",
dir_ni->mft_no);
- err = -EIO;
goto unm_err_out;
}
/*
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. */
}
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. */
unlock_page(page);
ntfs_unmap_page(page);
err_out:
+ if (!err)
+ err = -EIO;
if (ctx)
ntfs_attr_put_search_ctx(ctx);
if (m)
return ERR_MREF(err);
dir_err_out:
ntfs_error(sb, "Corrupt directory. Aborting lookup.");
- err = -EIO;
goto err_out;
}
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 &
* 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
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);
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) {
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;
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)) {
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;
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);
"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)) {
*/
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 ||
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:
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)
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;
* 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