Commit 79c914d9 authored by Linus Torvalds's avatar Linus Torvalds

Merge http://linux-ntfs.bkbits.net/ntfs-2.6

into ppc970.osdl.org:/home/torvalds/v2.6/linux
parents d9fd3c1c 7eebd09b
......@@ -272,6 +272,8 @@ ChangeLog
Note, a technical ChangeLog aimed at kernel hackers is in fs/ntfs/ChangeLog.
2.1.7:
- Enable NFS exporting of mounted NTFS volumes.
2.1.6:
- Fix minor bug in handling of compressed directories that fixes the
erroneous "du" and "stat" output people reported.
......
ToDo:
- Find and fix bugs.
- Enable NFS exporting of NTFS.
- Implement aops->set_page_dirty() in order to take control of buffer
dirtying. Not having it means if page_has_buffers(), all buffers
will be dirtied with the page. And if not they won't be. That is
......@@ -20,6 +19,26 @@ ToDo:
sufficient for synchronisation here. We then just need to make sure
ntfs_readpage/writepage/truncate interoperate properly with us.
2.1.7 - Enable NFS exporting of mounted NTFS volumes.
- Set i_generation in the VFS inode from the seq_no of the NTFS inode.
- Make ntfs_lookup() NFS export safe, i.e. use d_splice_alias(), etc.
- Implement ->get_dentry() in fs/ntfs/namei.c::ntfs_get_dentry() as the
default doesn't allow inode number 0 which is a valid inode on NTFS
and even if it did allow that it uses iget() instead of ntfs_iget()
which makes it useless for us.
- Implement ->get_parent() in fs/ntfs/namei.c::ntfs_get_parent() as the
default just returns -EACCES which is not very useful.
- Define export operations (->s_export_op) for NTFS (ntfs_export_ops)
and set them up in the super block at mount time (super.c) this
allows mounted NTFS volumes to be exported via NFS.
- Add missing return -EOPNOTSUPP; in
fs/ntfs/aops.c::ntfs_commit_nonresident_write().
- Enforce no atime and no dir atime updates at mount/remount time as
they are not implemented yet anyway.
- Move a few assignments in fs/ntfs/attrib.c::load_attribute_list() to
after a NULL check. Thanks to Dave Jones for pointing this out.
2.1.6 - Fix minor bug in handling of compressed directories.
- Fix bug in handling of compressed directories. A compressed
......@@ -60,6 +79,10 @@ ToDo:
- Reduce function local stack usage from 0x3d4 bytes to just noise in
fs/ntfs/upcase.c. (Randy Dunlap <rddunlap@osdl.ord>)
- Remove compiler warnings for newer gcc.
- Pages are no longer kmapped by mm/filemap.c::generic_file_write()
around calls to ->{prepare,commit}_write. Adapt NTFS appropriately
in fs/ntfs/aops.c::ntfs_prepare_nonresident_write() by using
kmap_atomic(KM_USER0).
2.1.0 - First steps towards write support: implement file overwrite.
......
......@@ -5,7 +5,7 @@ obj-$(CONFIG_NTFS_FS) += ntfs.o
ntfs-objs := aops.o attrib.o compress.o debug.o dir.o file.o inode.o mft.o \
mst.o namei.o super.o sysctl.o time.o unistr.o upcase.o
EXTRA_CFLAGS = -DNTFS_VERSION=\"2.1.6\"
EXTRA_CFLAGS = -DNTFS_VERSION=\"2.1.7\"
ifeq ($(CONFIG_NTFS_DEBUG),y)
EXTRA_CFLAGS += -DDEBUG
......
/**
* aops.c - NTFS kernel address space operations and page cache handling.
* Part of the Linux-NTFS project.
* Part of the Linux-NTFS project.
*
* Copyright (c) 2001-2003 Anton Altaparmakov
* Copyright (c) 2001-2004 Anton Altaparmakov
* Copyright (c) 2002 Richard Russon
*
* This program/include file is free software; you can redistribute it and/or
......@@ -10,13 +10,13 @@
* by the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program/include file is distributed in the hope that it will be
* useful, but WITHOUT ANY WARRANTY; without even the implied warranty
* This program/include file is distributed in the hope that it will be
* useful, but WITHOUT ANY WARRANTY; without even the implied warranty
* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program (in the main directory of the Linux-NTFS
* along with this program (in the main directory of the Linux-NTFS
* distribution in the file COPYING); if not, write to the Free Software
* Foundation,Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
......@@ -572,11 +572,11 @@ static int ntfs_write_block(struct writeback_control *wbc, struct page *page)
// Again for each page do:
// - wait_on_page_locked()
// - Check (PageUptodate(page) &&
// !PageError(page))
// !PageError(page))
// Update initialized size in the attribute and
// in the inode.
// Again, for each page do:
// __set_page_dirty_buffers();
// __set_page_dirty_buffers();
// page_cache_release()
// We don't need to wait on the writes.
// Update iblock.
......@@ -1112,11 +1112,11 @@ static int ntfs_prepare_nonresident_write(struct page *page,
// Again for each page do:
// - wait_on_page_locked()
// - Check (PageUptodate(page) &&
// !PageError(page))
// !PageError(page))
// Update initialized size in the attribute and
// in the inode.
// Again, for each page do:
// __set_page_dirty_buffers();
// __set_page_dirty_buffers();
// page_cache_release()
// We don't need to wait on the writes.
// Update iblock.
......@@ -1188,7 +1188,7 @@ static int ntfs_prepare_nonresident_write(struct page *page,
// TODO: Instantiate the hole.
// clear_buffer_new(bh);
// unmap_underlying_metadata(bh->b_bdev,
// bh->b_blocknr);
// bh->b_blocknr);
// For non-uptodate buffers, need to
// zero out the region outside the
// request in this bh or all bhs,
......@@ -1279,7 +1279,7 @@ static int ntfs_prepare_nonresident_write(struct page *page,
if (PageUptodate(page)) {
if (!buffer_uptodate(bh))
set_buffer_uptodate(bh);
continue;
continue;
}
/*
* The page is not uptodate. The buffer is mapped. If it is not
......@@ -1525,6 +1525,7 @@ static int ntfs_commit_nonresident_write(struct page *page,
if (pos > vi->i_size) {
ntfs_error(vi->i_sb, "Writing beyond the existing file size is "
"not supported yet. Sorry.");
return -EOPNOTSUPP;
// vi->i_size = pos;
// mark_inode_dirty(vi);
}
......@@ -1708,7 +1709,7 @@ static int ntfs_commit_write(struct file *file, struct page *page,
/*
* Bring the out of bounds area(s) uptodate by copying data
* from the mft record to the page.
*/
*/
if (from > 0)
memcpy(kaddr, kattr, from);
if (to < bytes)
......
......@@ -1235,11 +1235,11 @@ int load_attribute_list(ntfs_volume *vol, run_list *run_list, u8 *al_start,
u8 *al_end = al + initialized_size;
run_list_element *rl;
struct buffer_head *bh;
struct super_block *sb = vol->sb;
unsigned long block_size = sb->s_blocksize;
struct super_block *sb;
unsigned long block_size;
unsigned long block, max_block;
int err = 0;
unsigned char block_size_bits = sb->s_blocksize_bits;
unsigned char block_size_bits;
ntfs_debug("Entering.");
if (!vol || !run_list || !al || size <= 0 || initialized_size < 0 ||
......@@ -1249,6 +1249,9 @@ int load_attribute_list(ntfs_volume *vol, run_list *run_list, u8 *al_start,
memset(al, 0, size);
return 0;
}
sb = vol->sb;
block_size = sb->s_blocksize;
block_size_bits = sb->s_blocksize_bits;
down_read(&run_list->lock);
rl = run_list->rl;
/* Read all clusters specified by the run list one run at a time. */
......
/**
* dir.c - NTFS kernel directory operations. Part of the Linux-NTFS project.
*
* Copyright (c) 2001-2003 Anton Altaparmakov
* Copyright (c) 2001-2004 Anton Altaparmakov
* Copyright (c) 2002 Richard Russon
*
* This program/include file is free software; you can redistribute it and/or
......@@ -200,7 +200,8 @@ MFT_REF ntfs_lookup_inode_by_name(ntfs_inode *dir_ni, const uchar_t *uname,
"and if that doesn't find any "
"errors please report you saw "
"this message to "
"linux-ntfs-dev@lists.sf.net.");
"linux-ntfs-dev@lists."
"sourceforge.net.");
goto dir_err_out;
}
......@@ -457,7 +458,8 @@ MFT_REF ntfs_lookup_inode_by_name(ntfs_inode *dir_ni, const uchar_t *uname,
"and if that doesn't find any "
"errors please report you saw "
"this message to "
"linux-ntfs-dev@lists.sf.net.");
"linux-ntfs-dev@lists."
"sourceforge.net.");
ntfs_unmap_page(page);
goto dir_err_out;
}
......
......@@ -196,7 +196,7 @@ struct inode *ntfs_iget(struct super_block *sb, unsigned long mft_no)
}
/*
* There is no point in keeping bad inodes around if the failure was
* due to ENOMEM. We want to be able to retry again layer.
* due to ENOMEM. We want to be able to retry again later.
*/
if (err == -ENOMEM) {
iput(vi);
......@@ -533,7 +533,7 @@ static int ntfs_read_locked_inode(struct inode *vi)
}
/* Transfer information from mft record into vfs and ntfs inodes. */
ni->seq_no = le16_to_cpu(m->sequence_number);
vi->i_generation = ni->seq_no = le16_to_cpu(m->sequence_number);
/*
* FIXME: Keep in mind that link_count is two for files which have both
......@@ -1109,7 +1109,7 @@ static int ntfs_read_locked_attr_inode(struct inode *base_vi, struct inode *vi)
vi->i_mtime = base_vi->i_mtime;
vi->i_ctime = base_vi->i_ctime;
vi->i_atime = base_vi->i_atime;
ni->seq_no = base_ni->seq_no;
vi->i_generation = ni->seq_no = base_ni->seq_no;
/* Set inode type to zero but preserve permissions. */
vi->i_mode = base_vi->i_mode & ~S_IFMT;
......@@ -1137,7 +1137,8 @@ static int ntfs_read_locked_attr_inode(struct inode *base_vi, struct inode *vi)
"the attribute is resident (mft_no "
"0x%lx, type 0x%x, name_len %i). "
"Please report you saw this message "
"to linux-ntfs-dev@lists.sf.net",
"to linux-ntfs-dev@lists."
"sourceforge.net",
vi->i_ino, ni->type, ni->name_len);
goto unm_err_out;
}
......@@ -1157,8 +1158,9 @@ static int ntfs_read_locked_attr_inode(struct inode *base_vi, struct inode *vi)
"type 0x%x, name_len %i). "
"Please report you saw this "
"message to linux-ntfs-dev@"
"lists.sf.net", vi->i_ino,
ni->type, ni->name_len);
"lists.sourceforge.net",
vi->i_ino, ni->type,
ni->name_len);
goto unm_err_out;
}
NInoSetCompressed(ni);
......@@ -1169,7 +1171,8 @@ static int ntfs_read_locked_attr_inode(struct inode *base_vi, struct inode *vi)
"(mft_no 0x%lx, type 0x%x, "
"name_len %i). Please report "
"you saw this message to "
"linux-ntfs-dev@lists.sf.net",
"linux-ntfs-dev@lists."
"sourceforge.net",
vi->i_ino, ni->type,
ni->name_len);
goto unm_err_out;
......@@ -1224,8 +1227,9 @@ static int ntfs_read_locked_attr_inode(struct inode *base_vi, struct inode *vi)
"type 0x%x, name_len %i). "
"Please report you saw this "
"message to linux-ntfs-dev@"
"lists.sf.net", vi->i_ino,
ni->type, ni->name_len);
"lists.sourceforge.net",
vi->i_ino, ni->type,
ni->name_len);
goto unm_err_out;
}
NInoSetEncrypted(ni);
......@@ -1238,8 +1242,9 @@ static int ntfs_read_locked_attr_inode(struct inode *base_vi, struct inode *vi)
"type 0x%x, name_len %i). "
"Please report you saw this "
"message to linux-ntfs-dev@"
"lists.sf.net", vi->i_ino,
ni->type, ni->name_len);
"lists.sourceforge.net",
vi->i_ino, ni->type,
ni->name_len);
goto unm_err_out;
}
NInoSetSparse(ni);
......@@ -1414,7 +1419,7 @@ void ntfs_read_inode_mount(struct inode *vi)
}
/* Need this to sanity check attribute list references to $MFT. */
ni->seq_no = le16_to_cpu(m->sequence_number);
vi->i_generation = ni->seq_no = le16_to_cpu(m->sequence_number);
/* Provides readpage() and sync_page() for map_mft_record(). */
vi->i_mapping->a_ops = &ntfs_mft_aops;
......@@ -1541,7 +1546,8 @@ void ntfs_read_inode_mount(struct inode *vi)
"of $MFT is not in the base "
"mft record. Please report "
"you saw this message to "
"linux-ntfs-dev@lists.sf.net");
"linux-ntfs-dev@lists."
"sourceforge.net");
goto put_err_out;
} else {
/* Sequence numbers must match. */
......@@ -1662,7 +1668,8 @@ void ntfs_read_inode_mount(struct inode *vi)
"Run chkdsk and if no errors "
"are found, please report you "
"saw this message to "
"linux-ntfs-dev@lists.sf.net");
"linux-ntfs-dev@lists."
"sourceforge.net");
put_attr_search_ctx(ctx);
/* Revert to the safe super operations. */
sb->s_op = &ntfs_mount_sops;
......
......@@ -2,7 +2,7 @@
* layout.h - All NTFS associated on-disk structures. Part of the Linux-NTFS
* project.
*
* Copyright (c) 2001-2003 Anton Altaparmakov
* Copyright (c) 2001-2004 Anton Altaparmakov
* Copyright (c) 2002 Richard Russon
*
* This program/include file is free software; you can redistribute it and/or
......@@ -941,7 +941,7 @@ typedef struct {
modified. */
/* 18*/ s64 last_mft_change_time; /* Time this mft record was last
modified. */
/* 20*/ s64 last_access_time; /* Last time this mft record was
/* 20*/ s64 last_access_time; /* Time this mft record was last
accessed. */
/* 28*/ s64 allocated_size; /* Byte size of allocated space for the
data attribute. NOTE: Is a multiple
......
......@@ -2,7 +2,7 @@
* namei.c - NTFS kernel directory inode operations. Part of the Linux-NTFS
* project.
*
* Copyright (c) 2001-2003 Anton Altaparmakov
* Copyright (c) 2001-2004 Anton Altaparmakov
*
* This program/include file is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as published
......@@ -21,6 +21,7 @@
*/
#include <linux/dcache.h>
#include <linux/security.h>
#include "ntfs.h"
#include "dir.h"
......@@ -41,16 +42,17 @@
* @dir_ino looking for the converted Unicode name. If the name is found in the
* directory, the corresponding inode is loaded by calling ntfs_iget() on its
* inode number and the inode is associated with the dentry @dent via a call to
* d_add().
* d_splice_alias().
*
* If the name is not found in the directory, a NULL inode is inserted into the
* dentry @dent. The dentry is then termed a negative dentry.
* dentry @dent via a call to d_add(). The dentry is then termed a negative
* dentry.
*
* Only if an actual error occurs, do we return an error via ERR_PTR().
*
* In order to handle the case insensitivity issues of NTFS with regards to the
* dcache and the dcache requiring only one dentry per directory, we deal with
* dentry aliases that only differ in case in ->ntfs_lookup() while maintining
* dentry aliases that only differ in case in ->ntfs_lookup() while maintaining
* a case sensitive dcache. This means that we get the full benefit of dcache
* speed when the file/directory is looked up with the same case as returned by
* ->ntfs_readdir() but that a lookup for any other case (or for the short file
......@@ -70,15 +72,18 @@
* 1) @dent perfectly matches (i.e. including case) a directory entry with a
* file name in the WIN32 or POSIX namespaces. In this case
* ntfs_lookup_inode_by_name() will return with name set to NULL and we
* just d_add() @dent.
* just d_splice_alias() @dent.
* 2) @dent matches (not including case) a directory entry with a file name in
* the WIN32 namespace. In this case ntfs_lookup_inode_by_name() will return
* with name set to point to a kmalloc()ed ntfs_name structure containing
* the properly cased little endian Unicode name. We convert the name to the
* current NLS code page, search if a dentry with this name already exists
* and if so return that instead of @dent. The VFS will then destroy the old
* @dent and use the one we returned. If a dentry is not found, we allocate
* a new one, d_add() it, and return it as above.
* and if so return that instead of @dent. At this point things are
* complicated by the possibility of 'disconnected' dentries due to NFS
* which we deal with appropriately (see the code comments). The VFS will
* then destroy the old @dent and use the one we returned. If a dentry is
* not found, we allocate a new one, d_splice_alias() it, and return it as
* above.
* 3) @dent matches either perfectly or not (i.e. we don't care about case) a
* directory entry with a file name in the DOS namespace. In this case
* ntfs_lookup_inode_by_name() will return with name set to point to a
......@@ -88,7 +93,8 @@
* name. We then convert the name to the current NLS code page, and proceed
* searching for a dentry with this name, etc, as in case 2), above.
*/
static struct dentry *ntfs_lookup(struct inode *dir_ino, struct dentry *dent, struct nameidata *nd)
static struct dentry *ntfs_lookup(struct inode *dir_ino, struct dentry *dent,
struct nameidata *nd)
{
ntfs_volume *vol = NTFS_SB(dir_ino->i_sb);
struct inode *dent_inode;
......@@ -120,9 +126,8 @@ static struct dentry *ntfs_lookup(struct inode *dir_ino, struct dentry *dent, st
dent_ino == FILE_MFT) {
/* Perfect WIN32/POSIX match. -- Case 1. */
if (!name) {
d_add(dent, dent_inode);
ntfs_debug("Done.");
return NULL;
return d_splice_alias(dent_inode, dent);
}
/*
* We are too indented. Handle imperfect
......@@ -132,7 +137,7 @@ static struct dentry *ntfs_lookup(struct inode *dir_ino, struct dentry *dent, st
}
ntfs_error(vol->sb, "Found stale reference to inode "
"0x%lx (reference sequence number = "
"0x%x, inode sequence number = 0x%x, "
"0x%x, inode sequence number = 0x%x), "
"returning -EIO. Run chkdsk.",
dent_ino, MSEQNO(mref),
NTFS_I(dent_inode)->seq_no);
......@@ -162,7 +167,7 @@ static struct dentry *ntfs_lookup(struct inode *dir_ino, struct dentry *dent, st
// TODO: Consider moving this lot to a separate function! (AIA)
handle_name:
{
struct dentry *real_dent;
struct dentry *real_dent, *new_dent;
MFT_RECORD *m;
attr_search_context *ctx;
ntfs_inode *ni = NTFS_I(dent_inode);
......@@ -173,8 +178,7 @@ static struct dentry *ntfs_lookup(struct inode *dir_ino, struct dentry *dent, st
if (name->type != FILE_NAME_DOS) { /* Case 2. */
nls_name.len = (unsigned)ntfs_ucstonls(vol,
(uchar_t*)&name->name, name->len,
(unsigned char**)&nls_name.name,
name->len * 3 + 1);
(unsigned char**)&nls_name.name, 0);
kfree(name);
} else /* if (name->type == FILE_NAME_DOS) */ { /* Case 3. */
FILE_NAME_ATTR *fn;
......@@ -225,8 +229,7 @@ static struct dentry *ntfs_lookup(struct inode *dir_ino, struct dentry *dent, st
/* Convert the found WIN32 name to current NLS code page. */
nls_name.len = (unsigned)ntfs_ucstonls(vol,
(uchar_t*)&fn->file_name, fn->file_name_length,
(unsigned char**)&nls_name.name,
fn->file_name_length * 3 + 1);
(unsigned char**)&nls_name.name, 0);
put_attr_search_ctx(ctx);
unmap_mft_record(ni);
......@@ -256,8 +259,12 @@ static struct dentry *ntfs_lookup(struct inode *dir_ino, struct dentry *dent, st
err = -ENOMEM;
goto err_out;
}
d_add(real_dent, dent_inode);
return real_dent;
new_dent = d_splice_alias(dent_inode, real_dent);
if (new_dent)
dput(real_dent);
else
new_dent = real_dent;
return new_dent;
}
kfree(nls_name.name);
/* Matching dentry exists, check if it is negative. */
......@@ -266,14 +273,54 @@ static struct dentry *ntfs_lookup(struct inode *dir_ino, struct dentry *dent, st
/*
* Already have the inode and the dentry attached, decrement
* the reference count to balance the ntfs_iget() we did
* earlier on.
* earlier on. We found the dentry using d_lookup() so it
* cannot be disconnected and thus we do not need to worry
* about any NFS/disconnectedness issues here.
*/
iput(dent_inode);
return real_dent;
}
/* Negative dentry: instantiate it. */
d_instantiate(real_dent, dent_inode);
return real_dent;
/*
* Negative dentry: instantiate it unless the inode is a directory and
* has a 'disconnected' dentry (i.e. IS_ROOT and DCACHE_DISCONNECTED),
* in which case d_move() that in place of the found dentry.
*/
if (!S_ISDIR(dent_inode->i_mode)) {
/* Not a directory; everything is easy. */
d_instantiate(real_dent, dent_inode);
return real_dent;
}
spin_lock(&dcache_lock);
if (list_empty(&dent_inode->i_dentry)) {
/*
* Directory without a 'disconnected' dentry; we need to do
* d_instantiate() by hand because it takes dcache_lock which
* we already hold.
*/
list_add(&real_dent->d_alias, &dent_inode->i_dentry);
real_dent->d_inode = dent_inode;
spin_unlock(&dcache_lock);
security_d_instantiate(real_dent, dent_inode);
return real_dent;
}
/*
* Directory with a 'disconnected' dentry; get a reference to the
* 'disconnected' dentry.
*/
new_dent = list_entry(dent_inode->i_dentry.next, struct dentry,
d_alias);
dget_locked(new_dent);
spin_unlock(&dcache_lock);
/* Do security vodoo. */
security_d_instantiate(real_dent, dent_inode);
/* Move new_dent in place of real_dent. */
d_move(new_dent, real_dent);
/* Balance the ntfs_iget() we did above. */
iput(dent_inode);
/* Throw away real_dent. */
dput(real_dent);
/* Use new_dent as the actual dentry. */
return new_dent;
eio_err_out:
ntfs_error(vol->sb, "Illegal file name attribute. Run chkdsk.");
......@@ -288,10 +335,139 @@ static struct dentry *ntfs_lookup(struct inode *dir_ino, struct dentry *dent, st
}
}
/*
/**
* Inode operations for directories.
*/
struct inode_operations ntfs_dir_inode_ops = {
.lookup = ntfs_lookup, /* VFS: Lookup directory. */
};
/**
* ntfs_get_parent - find the dentry of the parent of a given directory dentry
* @child_dent: dentry of the directory whose parent directory to find
*
* Find the dentry for the parent directory of the directory specified by the
* dentry @child_dent. This function is called from
* fs/exportfs/expfs.c::find_exported_dentry() which in turn is called from the
* default ->decode_fh() which is export_decode_fh() in the same file.
*
* The code is based on the ext3 ->get_parent() implementation found in
* fs/ext3/namei.c::ext3_get_parent().
*
* Note: ntfs_get_parent() is called with @child_dent->d_inode->i_sem down.
*
* Return the dentry of the parent directory on success or the error code on
* error (IS_ERR() is true).
*/
struct dentry *ntfs_get_parent(struct dentry *child_dent)
{
struct inode *vi = child_dent->d_inode;
ntfs_inode *ni = NTFS_I(vi);
MFT_RECORD *mrec;
attr_search_context *ctx;
ATTR_RECORD *attr;
FILE_NAME_ATTR *fn;
struct inode *parent_vi;
struct dentry *parent_dent;
unsigned long parent_ino;
ntfs_debug("Entering for inode 0x%lx.", vi->i_ino);
/* Get the mft record of the inode belonging to the child dentry. */
mrec = map_mft_record(ni);
if (unlikely(IS_ERR(mrec)))
return (struct dentry *)mrec;
/* Find the first file name attribute in the mft record. */
ctx = get_attr_search_ctx(ni, mrec);
if (unlikely(!ctx)) {
unmap_mft_record(ni);
return ERR_PTR(-ENOMEM);
}
try_next:
if (unlikely(!lookup_attr(AT_FILE_NAME, NULL, 0, IGNORE_CASE, 0,
NULL, 0, ctx))) {
put_attr_search_ctx(ctx);
unmap_mft_record(ni);
ntfs_error(vi->i_sb, "Inode 0x%lx does not have a file name "
"attribute. Run chkdsk.", vi->i_ino);
return ERR_PTR(-ENOENT);
}
attr = ctx->attr;
if (unlikely(attr->non_resident))
goto try_next;
fn = (FILE_NAME_ATTR *)((u8 *)attr +
le16_to_cpu(attr->data.resident.value_offset));
if (unlikely((u8 *)fn + le32_to_cpu(attr->data.resident.value_length) >
(u8*)attr + le32_to_cpu(attr->length)))
goto try_next;
/* Get the inode number of the parent directory. */
parent_ino = MREF_LE(fn->parent_directory);
/* Release the search context and the mft record of the child. */
put_attr_search_ctx(ctx);
unmap_mft_record(ni);
/* Get the inode of the parent directory. */
parent_vi = ntfs_iget(vi->i_sb, parent_ino);
if (unlikely(IS_ERR(parent_vi) || is_bad_inode(parent_vi))) {
if (!IS_ERR(parent_vi))
iput(parent_vi);
ntfs_error(vi->i_sb, "Failed to get parent directory inode "
"0x%lx of child inode 0x%lx.", parent_ino,
vi->i_ino);
return ERR_PTR(-EACCES);
}
/* Finally get a dentry for the parent directory and return it. */
parent_dent = d_alloc_anon(parent_vi);
if (unlikely(!parent_dent)) {
iput(parent_vi);
return ERR_PTR(-ENOMEM);
}
ntfs_debug("Done for inode 0x%lx.", vi->i_ino);
return parent_dent;
}
/**
* ntfs_get_dentry - find a dentry for the inode from a file handle sub-fragment
* @sb: super block identifying the mounted ntfs volume
* @fh: the file handle sub-fragment
*
* Find a dentry for the inode given a file handle sub-fragment. This function
* is called from fs/exportfs/expfs.c::find_exported_dentry() which in turn is
* called from the default ->decode_fh() which is export_decode_fh() in the
* same file. The code is closely based on the default ->get_dentry() helper
* fs/exportfs/expfs.c::get_object().
*
* The @fh contains two 32-bit unsigned values, the first one is the inode
* number and the second one is the inode generation.
*
* Return the dentry on success or the error code on error (IS_ERR() is true).
*/
struct dentry *ntfs_get_dentry(struct super_block *sb, void *fh)
{
struct inode *vi;
struct dentry *dent;
unsigned long ino = ((u32 *)fh)[0];
u32 gen = ((u32 *)fh)[1];
ntfs_debug("Entering for inode 0x%lx, generation 0x%x.", ino, gen);
vi = ntfs_iget(sb, ino);
if (unlikely(IS_ERR(vi))) {
ntfs_error(sb, "Failed to get inode 0x%lx.", ino);
return (struct dentry *)vi;
}
if (unlikely(is_bad_inode(vi) || vi->i_generation != gen)) {
/* We didn't find the right inode. */
ntfs_error(sb, "Inode 0x%lx, bad count: %d %d or version 0x%x "
"0x%x.", vi->i_ino, vi->i_nlink,
atomic_read(&vi->i_count), vi->i_generation,
gen);
iput(vi);
return ERR_PTR(-ESTALE);
}
/* Now find a dentry. If possible, get a well-connected one. */
dent = d_alloc_anon(vi);
if (unlikely(!dent)) {
iput(vi);
return ERR_PTR(-ENOMEM);
}
ntfs_debug("Done for inode 0x%lx, generation 0x%x.", ino, gen);
return dent;
}
/*
* super.c - NTFS kernel super block handling. Part of the Linux-NTFS project.
*
* Copyright (c) 2001-2003 Anton Altaparmakov
* Copyright (c) 2001-2004 Anton Altaparmakov
* Copyright (c) 2001,2002 Richard Russon
*
* This program/include file is free software; you can redistribute it and/or
......@@ -323,6 +323,9 @@ static int ntfs_remount(struct super_block *sb, int *flags, char *opt)
return -EROFS;
}
}
// TODO: For now we enforce no atime and dir atime updates as they are
// not implemented.
*flags |= MS_NOATIME | MS_NODIRATIME;
#endif
// FIXME/TODO: If left like this we will have problems with rw->ro and
......@@ -1338,6 +1341,40 @@ struct super_operations ntfs_sops = {
.show_options = ntfs_show_options, /* Show mount options in proc. */
};
/**
* Declarations for NTFS specific export operations (fs/ntfs/namei.c).
*/
extern struct dentry *ntfs_get_parent(struct dentry *child_dent);
extern struct dentry *ntfs_get_dentry(struct super_block *sb, void *fh);
/**
* Export operations allowing NFS exporting of mounted NTFS partitions.
*
* We use the default ->decode_fh() and ->encode_fh() for now. Note that they
* use 32 bits to store the inode number which is an unsigned long so on 64-bit
* architectures is usually 64 bits so it would all fail horribly on huge
* volumes. I guess we need to define our own encode and decode fh functions
* that store 64-bit inode numbers at some point but for now we will ignore the
* problem...
*
* We also use the default ->get_name() helper (used by ->decode_fh() via
* fs/exportfs/expfs.c::find_exported_dentry()) as that is completely fs
* independent.
*
* The default ->get_parent() just returns -EACCES so we have to provide our
* own and the default ->get_dentry() is incompatible with NTFS due to not
* allowing the inode number 0 which is used in NTFS for the system file $MFT
* and due to using iget() whereas NTFS needs ntfs_iget().
*/
static struct export_operations ntfs_export_ops = {
.get_parent = ntfs_get_parent, /* Find the parent of a given
directory. */
.get_dentry = ntfs_get_dentry, /* Find a dentry for the inode
given a file handle
sub-fragment. */
};
/**
* ntfs_fill_super - mount an ntfs files system
* @sb: super block of ntfs file system to mount
......@@ -1366,6 +1403,10 @@ static int ntfs_fill_super(struct super_block *sb, void *opt, const int silent)
ntfs_debug("Entering.");
#ifndef NTFS_RW
sb->s_flags |= MS_RDONLY | MS_NOATIME | MS_NODIRATIME;
#else
// TODO: For now we enforce no atime and dir atime updates as they are
// not implemented.
sb->s_flags |= MS_NOATIME | MS_NODIRATIME;
#endif
/* Allocate a new ntfs_volume and place it in sb->s_fs_info. */
sb->s_fs_info = kmalloc(sizeof(ntfs_volume), GFP_NOFS);
......@@ -1544,6 +1585,7 @@ static int ntfs_fill_super(struct super_block *sb, void *opt, const int silent)
default_upcase = NULL;
}
up(&ntfs_lock);
sb->s_export_op = &ntfs_export_ops;
return 0;
}
ntfs_error(sb, "Failed to allocate root directory.");
......@@ -1788,13 +1830,13 @@ static void __exit exit_ntfs_fs(void)
printk(KERN_CRIT "NTFS: This causes memory to leak! There is "
"probably a BUG in the driver! Please report "
"you saw this message to "
"linux-ntfs-dev@lists.sf.net\n");
"linux-ntfs-dev@lists.sourceforge.net\n");
/* Unregister the ntfs sysctls. */
ntfs_sysctl(0);
}
MODULE_AUTHOR("Anton Altaparmakov <aia21@cantab.net>");
MODULE_DESCRIPTION("NTFS 1.2/3.x driver - Copyright (c) 2001-2003 Anton Altaparmakov");
MODULE_DESCRIPTION("NTFS 1.2/3.x driver - Copyright (c) 2001-2004 Anton Altaparmakov");
MODULE_LICENSE("GPL");
#ifdef DEBUG
MODULE_PARM(debug_msgs, "i");
......
/*
* unistr.c - NTFS Unicode string handling. Part of the Linux-NTFS project.
*
* Copyright (c) 2001-2003 Anton Altaparmakov
* Copyright (c) 2001-2004 Anton Altaparmakov
*
* This program/include file is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as published
......@@ -305,8 +305,9 @@ int ntfs_nlstoucs(const ntfs_volume *vol, const char *ins,
* Convert the input little endian, 2-byte Unicode string @ins, of length
* @ins_len into the string format dictated by the loaded NLS.
*
* If @outs is NULL, this function allocates the string and the caller is
* responsible for calling kfree(@outs); when finished with it.
* If *@outs is NULL, this function allocates the string and the caller is
* responsible for calling kfree(*@outs); when finished with it. In this case
* @outs_len is ignored and can be 0.
*
* On success the function returns the number of bytes written to the output
* string *@outs (>= 0), not counting the terminating NULL byte. If the output
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment