2005-04-16 22:20:36 +00:00
|
|
|
/*
|
|
|
|
* namei.c - NTFS kernel directory inode operations. Part of the Linux-NTFS
|
|
|
|
* project.
|
|
|
|
*
|
2006-03-23 14:57:43 +00:00
|
|
|
* Copyright (c) 2001-2006 Anton Altaparmakov
|
2005-04-16 22:20:36 +00:00
|
|
|
*
|
|
|
|
* 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
|
|
|
|
* 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
|
|
|
|
* 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
|
|
|
|
* distribution in the file COPYING); if not, write to the Free Software
|
|
|
|
* Foundation,Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include <linux/dcache.h>
|
2007-07-17 11:04:28 +00:00
|
|
|
#include <linux/exportfs.h>
|
2005-04-16 22:20:36 +00:00
|
|
|
#include <linux/security.h>
|
include cleanup: Update gfp.h and slab.h includes to prepare for breaking implicit slab.h inclusion from percpu.h
percpu.h is included by sched.h and module.h and thus ends up being
included when building most .c files. percpu.h includes slab.h which
in turn includes gfp.h making everything defined by the two files
universally available and complicating inclusion dependencies.
percpu.h -> slab.h dependency is about to be removed. Prepare for
this change by updating users of gfp and slab facilities include those
headers directly instead of assuming availability. As this conversion
needs to touch large number of source files, the following script is
used as the basis of conversion.
http://userweb.kernel.org/~tj/misc/slabh-sweep.py
The script does the followings.
* Scan files for gfp and slab usages and update includes such that
only the necessary includes are there. ie. if only gfp is used,
gfp.h, if slab is used, slab.h.
* When the script inserts a new include, it looks at the include
blocks and try to put the new include such that its order conforms
to its surrounding. It's put in the include block which contains
core kernel includes, in the same order that the rest are ordered -
alphabetical, Christmas tree, rev-Xmas-tree or at the end if there
doesn't seem to be any matching order.
* If the script can't find a place to put a new include (mostly
because the file doesn't have fitting include block), it prints out
an error message indicating which .h file needs to be added to the
file.
The conversion was done in the following steps.
1. The initial automatic conversion of all .c files updated slightly
over 4000 files, deleting around 700 includes and adding ~480 gfp.h
and ~3000 slab.h inclusions. The script emitted errors for ~400
files.
2. Each error was manually checked. Some didn't need the inclusion,
some needed manual addition while adding it to implementation .h or
embedding .c file was more appropriate for others. This step added
inclusions to around 150 files.
3. The script was run again and the output was compared to the edits
from #2 to make sure no file was left behind.
4. Several build tests were done and a couple of problems were fixed.
e.g. lib/decompress_*.c used malloc/free() wrappers around slab
APIs requiring slab.h to be added manually.
5. The script was run on all .h files but without automatically
editing them as sprinkling gfp.h and slab.h inclusions around .h
files could easily lead to inclusion dependency hell. Most gfp.h
inclusion directives were ignored as stuff from gfp.h was usually
wildly available and often used in preprocessor macros. Each
slab.h inclusion directive was examined and added manually as
necessary.
6. percpu.h was updated not to include slab.h.
7. Build test were done on the following configurations and failures
were fixed. CONFIG_GCOV_KERNEL was turned off for all tests (as my
distributed build env didn't work with gcov compiles) and a few
more options had to be turned off depending on archs to make things
build (like ipr on powerpc/64 which failed due to missing writeq).
* x86 and x86_64 UP and SMP allmodconfig and a custom test config.
* powerpc and powerpc64 SMP allmodconfig
* sparc and sparc64 SMP allmodconfig
* ia64 SMP allmodconfig
* s390 SMP allmodconfig
* alpha SMP allmodconfig
* um on x86_64 SMP allmodconfig
8. percpu.h modifications were reverted so that it could be applied as
a separate patch and serve as bisection point.
Given the fact that I had only a couple of failures from tests on step
6, I'm fairly confident about the coverage of this conversion patch.
If there is a breakage, it's likely to be something in one of the arch
headers which should be easily discoverable easily on most builds of
the specific arch.
Signed-off-by: Tejun Heo <tj@kernel.org>
Guess-its-ok-by: Christoph Lameter <cl@linux-foundation.org>
Cc: Ingo Molnar <mingo@redhat.com>
Cc: Lee Schermerhorn <Lee.Schermerhorn@hp.com>
2010-03-24 08:04:11 +00:00
|
|
|
#include <linux/slab.h>
|
2005-04-16 22:20:36 +00:00
|
|
|
|
|
|
|
#include "attrib.h"
|
|
|
|
#include "debug.h"
|
|
|
|
#include "dir.h"
|
|
|
|
#include "mft.h"
|
|
|
|
#include "ntfs.h"
|
|
|
|
|
|
|
|
/**
|
|
|
|
* ntfs_lookup - find the inode represented by a dentry in a directory inode
|
|
|
|
* @dir_ino: directory inode in which to look for the inode
|
|
|
|
* @dent: dentry representing the inode to look for
|
|
|
|
* @nd: lookup nameidata
|
|
|
|
*
|
|
|
|
* In short, ntfs_lookup() looks for the inode represented by the dentry @dent
|
|
|
|
* in the directory inode @dir_ino and if found attaches the inode to the
|
|
|
|
* dentry @dent.
|
|
|
|
*
|
|
|
|
* In more detail, the dentry @dent specifies which inode to look for by
|
|
|
|
* supplying the name of the inode in @dent->d_name.name. ntfs_lookup()
|
|
|
|
* converts the name to Unicode and walks the contents of the directory inode
|
|
|
|
* @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_splice_alias().
|
|
|
|
*
|
|
|
|
* If the name is not found in the directory, a NULL inode is inserted into the
|
|
|
|
* 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 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
|
|
|
|
* name) will not find anything in dcache and will enter ->ntfs_lookup()
|
|
|
|
* instead, where we search the directory for a fully matching file name
|
|
|
|
* (including case) and if that is not found, we search for a file name that
|
|
|
|
* matches with different case and if that has non-POSIX semantics we return
|
|
|
|
* that. We actually do only one search (case sensitive) and keep tabs on
|
|
|
|
* whether we have found a case insensitive match in the process.
|
|
|
|
*
|
|
|
|
* To simplify matters for us, we do not treat the short vs long filenames as
|
|
|
|
* two hard links but instead if the lookup matches a short filename, we
|
|
|
|
* return the dentry for the corresponding long filename instead.
|
|
|
|
*
|
|
|
|
* There are three cases we need to distinguish here:
|
|
|
|
*
|
|
|
|
* 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_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. 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
|
|
|
|
* kmalloc()ed ntfs_name structure containing the mft reference (cpu endian)
|
|
|
|
* of the inode. We use the mft reference to read the inode and to find the
|
|
|
|
* file name in the WIN32 namespace corresponding to the matched short file
|
|
|
|
* 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.
|
|
|
|
*
|
2006-01-09 23:59:24 +00:00
|
|
|
* Locking: Caller must hold i_mutex on the directory.
|
2005-04-16 22:20:36 +00:00
|
|
|
*/
|
|
|
|
static struct dentry *ntfs_lookup(struct inode *dir_ino, struct dentry *dent,
|
2012-06-10 21:13:09 +00:00
|
|
|
unsigned int flags)
|
2005-04-16 22:20:36 +00:00
|
|
|
{
|
|
|
|
ntfs_volume *vol = NTFS_SB(dir_ino->i_sb);
|
|
|
|
struct inode *dent_inode;
|
|
|
|
ntfschar *uname;
|
|
|
|
ntfs_name *name = NULL;
|
|
|
|
MFT_REF mref;
|
|
|
|
unsigned long dent_ino;
|
|
|
|
int uname_len;
|
|
|
|
|
2014-10-22 00:11:25 +00:00
|
|
|
ntfs_debug("Looking up %pd in directory inode 0x%lx.",
|
|
|
|
dent, dir_ino->i_ino);
|
2005-04-16 22:20:36 +00:00
|
|
|
/* Convert the name of the dentry to Unicode. */
|
|
|
|
uname_len = ntfs_nlstoucs(vol, dent->d_name.name, dent->d_name.len,
|
|
|
|
&uname);
|
|
|
|
if (uname_len < 0) {
|
2006-03-23 16:25:23 +00:00
|
|
|
if (uname_len != -ENAMETOOLONG)
|
|
|
|
ntfs_error(vol->sb, "Failed to convert name to "
|
|
|
|
"Unicode.");
|
2005-04-16 22:20:36 +00:00
|
|
|
return ERR_PTR(uname_len);
|
|
|
|
}
|
|
|
|
mref = ntfs_lookup_inode_by_name(NTFS_I(dir_ino), uname, uname_len,
|
|
|
|
&name);
|
|
|
|
kmem_cache_free(ntfs_name_cache, uname);
|
|
|
|
if (!IS_ERR_MREF(mref)) {
|
|
|
|
dent_ino = MREF(mref);
|
|
|
|
ntfs_debug("Found inode 0x%lx. Calling ntfs_iget.", dent_ino);
|
|
|
|
dent_inode = ntfs_iget(vol->sb, dent_ino);
|
|
|
|
if (likely(!IS_ERR(dent_inode))) {
|
|
|
|
/* Consistency check. */
|
|
|
|
if (is_bad_inode(dent_inode) || MSEQNO(mref) ==
|
|
|
|
NTFS_I(dent_inode)->seq_no ||
|
|
|
|
dent_ino == FILE_MFT) {
|
|
|
|
/* Perfect WIN32/POSIX match. -- Case 1. */
|
|
|
|
if (!name) {
|
|
|
|
ntfs_debug("Done. (Case 1.)");
|
|
|
|
return d_splice_alias(dent_inode, dent);
|
|
|
|
}
|
|
|
|
/*
|
|
|
|
* We are too indented. Handle imperfect
|
|
|
|
* matches and short file names further below.
|
|
|
|
*/
|
|
|
|
goto handle_name;
|
|
|
|
}
|
|
|
|
ntfs_error(vol->sb, "Found stale reference to inode "
|
|
|
|
"0x%lx (reference sequence number = "
|
|
|
|
"0x%x, inode sequence number = 0x%x), "
|
|
|
|
"returning -EIO. Run chkdsk.",
|
|
|
|
dent_ino, MSEQNO(mref),
|
|
|
|
NTFS_I(dent_inode)->seq_no);
|
|
|
|
iput(dent_inode);
|
|
|
|
dent_inode = ERR_PTR(-EIO);
|
|
|
|
} else
|
|
|
|
ntfs_error(vol->sb, "ntfs_iget(0x%lx) failed with "
|
|
|
|
"error code %li.", dent_ino,
|
|
|
|
PTR_ERR(dent_inode));
|
2005-04-04 13:59:56 +00:00
|
|
|
kfree(name);
|
2005-04-16 22:20:36 +00:00
|
|
|
/* Return the error code. */
|
|
|
|
return (struct dentry *)dent_inode;
|
|
|
|
}
|
2006-03-23 16:25:23 +00:00
|
|
|
/* It is guaranteed that @name is no longer allocated at this point. */
|
2005-04-16 22:20:36 +00:00
|
|
|
if (MREF_ERR(mref) == -ENOENT) {
|
|
|
|
ntfs_debug("Entry was not found, adding negative dentry.");
|
|
|
|
/* The dcache will handle negative entries. */
|
|
|
|
d_add(dent, NULL);
|
|
|
|
ntfs_debug("Done.");
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
ntfs_error(vol->sb, "ntfs_lookup_ino_by_name() failed with error "
|
|
|
|
"code %i.", -MREF_ERR(mref));
|
|
|
|
return ERR_PTR(MREF_ERR(mref));
|
|
|
|
// TODO: Consider moving this lot to a separate function! (AIA)
|
|
|
|
handle_name:
|
|
|
|
{
|
|
|
|
MFT_RECORD *m;
|
|
|
|
ntfs_attr_search_ctx *ctx;
|
|
|
|
ntfs_inode *ni = NTFS_I(dent_inode);
|
|
|
|
int err;
|
|
|
|
struct qstr nls_name;
|
|
|
|
|
|
|
|
nls_name.name = NULL;
|
|
|
|
if (name->type != FILE_NAME_DOS) { /* Case 2. */
|
|
|
|
ntfs_debug("Case 2.");
|
|
|
|
nls_name.len = (unsigned)ntfs_ucstonls(vol,
|
|
|
|
(ntfschar*)&name->name, name->len,
|
|
|
|
(unsigned char**)&nls_name.name, 0);
|
|
|
|
kfree(name);
|
|
|
|
} else /* if (name->type == FILE_NAME_DOS) */ { /* Case 3. */
|
|
|
|
FILE_NAME_ATTR *fn;
|
|
|
|
|
|
|
|
ntfs_debug("Case 3.");
|
|
|
|
kfree(name);
|
|
|
|
|
|
|
|
/* Find the WIN32 name corresponding to the matched DOS name. */
|
|
|
|
ni = NTFS_I(dent_inode);
|
|
|
|
m = map_mft_record(ni);
|
|
|
|
if (IS_ERR(m)) {
|
|
|
|
err = PTR_ERR(m);
|
|
|
|
m = NULL;
|
|
|
|
ctx = NULL;
|
|
|
|
goto err_out;
|
|
|
|
}
|
|
|
|
ctx = ntfs_attr_get_search_ctx(ni, m);
|
|
|
|
if (unlikely(!ctx)) {
|
|
|
|
err = -ENOMEM;
|
|
|
|
goto err_out;
|
|
|
|
}
|
|
|
|
do {
|
|
|
|
ATTR_RECORD *a;
|
|
|
|
u32 val_len;
|
|
|
|
|
|
|
|
err = ntfs_attr_lookup(AT_FILE_NAME, NULL, 0, 0, 0,
|
|
|
|
NULL, 0, ctx);
|
|
|
|
if (unlikely(err)) {
|
|
|
|
ntfs_error(vol->sb, "Inode corrupt: No WIN32 "
|
|
|
|
"namespace counterpart to DOS "
|
|
|
|
"file name. Run chkdsk.");
|
|
|
|
if (err == -ENOENT)
|
|
|
|
err = -EIO;
|
|
|
|
goto err_out;
|
|
|
|
}
|
|
|
|
/* Consistency checks. */
|
|
|
|
a = ctx->attr;
|
|
|
|
if (a->non_resident || a->flags)
|
|
|
|
goto eio_err_out;
|
|
|
|
val_len = le32_to_cpu(a->data.resident.value_length);
|
|
|
|
if (le16_to_cpu(a->data.resident.value_offset) +
|
|
|
|
val_len > le32_to_cpu(a->length))
|
|
|
|
goto eio_err_out;
|
|
|
|
fn = (FILE_NAME_ATTR*)((u8*)ctx->attr + le16_to_cpu(
|
|
|
|
ctx->attr->data.resident.value_offset));
|
|
|
|
if ((u32)(fn->file_name_length * sizeof(ntfschar) +
|
|
|
|
sizeof(FILE_NAME_ATTR)) > val_len)
|
|
|
|
goto eio_err_out;
|
|
|
|
} while (fn->file_name_type != FILE_NAME_WIN32);
|
|
|
|
|
|
|
|
/* Convert the found WIN32 name to current NLS code page. */
|
|
|
|
nls_name.len = (unsigned)ntfs_ucstonls(vol,
|
|
|
|
(ntfschar*)&fn->file_name, fn->file_name_length,
|
|
|
|
(unsigned char**)&nls_name.name, 0);
|
|
|
|
|
|
|
|
ntfs_attr_put_search_ctx(ctx);
|
|
|
|
unmap_mft_record(ni);
|
|
|
|
}
|
|
|
|
m = NULL;
|
|
|
|
ctx = NULL;
|
|
|
|
|
|
|
|
/* Check if a conversion error occurred. */
|
|
|
|
if ((signed)nls_name.len < 0) {
|
|
|
|
err = (signed)nls_name.len;
|
|
|
|
goto err_out;
|
|
|
|
}
|
|
|
|
nls_name.hash = full_name_hash(nls_name.name, nls_name.len);
|
|
|
|
|
2008-08-07 21:50:21 +00:00
|
|
|
dent = d_add_ci(dent, dent_inode, &nls_name);
|
2005-04-16 22:20:36 +00:00
|
|
|
kfree(nls_name.name);
|
2008-08-07 21:50:21 +00:00
|
|
|
return dent;
|
2005-04-16 22:20:36 +00:00
|
|
|
|
|
|
|
eio_err_out:
|
|
|
|
ntfs_error(vol->sb, "Illegal file name attribute. Run chkdsk.");
|
|
|
|
err = -EIO;
|
|
|
|
err_out:
|
|
|
|
if (ctx)
|
|
|
|
ntfs_attr_put_search_ctx(ctx);
|
|
|
|
if (m)
|
|
|
|
unmap_mft_record(ni);
|
|
|
|
iput(dent_inode);
|
|
|
|
ntfs_error(vol->sb, "Failed, returning error code %i.", err);
|
|
|
|
return ERR_PTR(err);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Inode operations for directories.
|
|
|
|
*/
|
2007-02-12 08:55:39 +00:00
|
|
|
const struct inode_operations ntfs_dir_inode_ops = {
|
2005-04-16 22:20:36 +00:00
|
|
|
.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().
|
|
|
|
*
|
2015-03-17 22:25:59 +00:00
|
|
|
* Note: ntfs_get_parent() is called with @d_inode(child_dent)->i_mutex down.
|
2005-04-16 22:20:36 +00:00
|
|
|
*
|
|
|
|
* Return the dentry of the parent directory on success or the error code on
|
|
|
|
* error (IS_ERR() is true).
|
|
|
|
*/
|
2005-03-03 13:44:15 +00:00
|
|
|
static struct dentry *ntfs_get_parent(struct dentry *child_dent)
|
2005-04-16 22:20:36 +00:00
|
|
|
{
|
2015-03-17 22:25:59 +00:00
|
|
|
struct inode *vi = d_inode(child_dent);
|
2005-04-16 22:20:36 +00:00
|
|
|
ntfs_inode *ni = NTFS_I(vi);
|
|
|
|
MFT_RECORD *mrec;
|
|
|
|
ntfs_attr_search_ctx *ctx;
|
|
|
|
ATTR_RECORD *attr;
|
|
|
|
FILE_NAME_ATTR *fn;
|
|
|
|
unsigned long parent_ino;
|
|
|
|
int err;
|
|
|
|
|
|
|
|
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 (IS_ERR(mrec))
|
|
|
|
return (struct dentry *)mrec;
|
|
|
|
/* Find the first file name attribute in the mft record. */
|
|
|
|
ctx = ntfs_attr_get_search_ctx(ni, mrec);
|
|
|
|
if (unlikely(!ctx)) {
|
|
|
|
unmap_mft_record(ni);
|
|
|
|
return ERR_PTR(-ENOMEM);
|
|
|
|
}
|
|
|
|
try_next:
|
|
|
|
err = ntfs_attr_lookup(AT_FILE_NAME, NULL, 0, CASE_SENSITIVE, 0, NULL,
|
|
|
|
0, ctx);
|
|
|
|
if (unlikely(err)) {
|
|
|
|
ntfs_attr_put_search_ctx(ctx);
|
|
|
|
unmap_mft_record(ni);
|
|
|
|
if (err == -ENOENT)
|
|
|
|
ntfs_error(vi->i_sb, "Inode 0x%lx does not have a "
|
|
|
|
"file name attribute. Run chkdsk.",
|
|
|
|
vi->i_ino);
|
|
|
|
return ERR_PTR(err);
|
|
|
|
}
|
|
|
|
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. */
|
|
|
|
ntfs_attr_put_search_ctx(ctx);
|
|
|
|
unmap_mft_record(ni);
|
2008-08-11 13:49:04 +00:00
|
|
|
|
|
|
|
return d_obtain_alias(ntfs_iget(vi->i_sb, parent_ino));
|
2005-04-16 22:20:36 +00:00
|
|
|
}
|
|
|
|
|
2007-10-21 23:42:10 +00:00
|
|
|
static struct inode *ntfs_nfs_get_inode(struct super_block *sb,
|
|
|
|
u64 ino, u32 generation)
|
2005-04-16 22:20:36 +00:00
|
|
|
{
|
2007-10-21 23:42:10 +00:00
|
|
|
struct inode *inode;
|
2005-04-16 22:20:36 +00:00
|
|
|
|
2007-10-21 23:42:10 +00:00
|
|
|
inode = ntfs_iget(sb, ino);
|
|
|
|
if (!IS_ERR(inode)) {
|
|
|
|
if (is_bad_inode(inode) || inode->i_generation != generation) {
|
|
|
|
iput(inode);
|
|
|
|
inode = ERR_PTR(-ESTALE);
|
|
|
|
}
|
2005-04-16 22:20:36 +00:00
|
|
|
}
|
2007-10-21 23:42:10 +00:00
|
|
|
|
|
|
|
return inode;
|
|
|
|
}
|
|
|
|
|
|
|
|
static struct dentry *ntfs_fh_to_dentry(struct super_block *sb, struct fid *fid,
|
|
|
|
int fh_len, int fh_type)
|
|
|
|
{
|
|
|
|
return generic_fh_to_dentry(sb, fid, fh_len, fh_type,
|
|
|
|
ntfs_nfs_get_inode);
|
|
|
|
}
|
|
|
|
|
|
|
|
static struct dentry *ntfs_fh_to_parent(struct super_block *sb, struct fid *fid,
|
|
|
|
int fh_len, int fh_type)
|
|
|
|
{
|
|
|
|
return generic_fh_to_parent(sb, fid, fh_len, fh_type,
|
|
|
|
ntfs_nfs_get_inode);
|
2005-04-16 22:20:36 +00:00
|
|
|
}
|
2005-03-03 13:44:15 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Export operations allowing NFS exporting of mounted NTFS partitions.
|
|
|
|
*
|
2007-10-21 23:42:10 +00:00
|
|
|
* We use the default ->encode_fh() for now. Note that they
|
2005-03-03 13:44:15 +00:00
|
|
|
* 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().
|
|
|
|
*/
|
2007-10-21 23:42:17 +00:00
|
|
|
const struct export_operations ntfs_export_ops = {
|
2005-03-03 13:44:15 +00:00
|
|
|
.get_parent = ntfs_get_parent, /* Find the parent of a given
|
|
|
|
directory. */
|
2007-10-21 23:42:10 +00:00
|
|
|
.fh_to_dentry = ntfs_fh_to_dentry,
|
|
|
|
.fh_to_parent = ntfs_fh_to_parent,
|
2005-03-03 13:44:15 +00:00
|
|
|
};
|