X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=fs%2Fntfs%2Fdir.c;h=b0690d4c89065f946c706877d7bced88ff399d8e;hb=987b0145d94eecf292d8b301228356f44611ab7c;hp=ed9838e0c5d08ae7bde8762c86e1d3aa05cc066a;hpb=ec9397bab20a628530ce3051167d3d0fcc2c1af7;p=linux-2.6.git diff --git a/fs/ntfs/dir.c b/fs/ntfs/dir.c index ed9838e0c..b0690d4c8 100644 --- a/fs/ntfs/dir.c +++ b/fs/ntfs/dir.c @@ -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 @@ -21,8 +21,14 @@ */ #include -#include "ntfs.h" +#include + #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