2005-04-16 15:20:36 -07: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 15:20:36 -07: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 04:04:28 -07:00
# include <linux/exportfs.h>
2005-04-16 15:20:36 -07:00
# include <linux/security.h>
# 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 15:59:24 -08:00
* Locking : Caller must hold i_mutex on the directory .
2005-04-16 15:20:36 -07:00
*/
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 ;
ntfschar * uname ;
ntfs_name * name = NULL ;
MFT_REF mref ;
unsigned long dent_ino ;
int uname_len ;
ntfs_debug ( " Looking up %s in directory inode 0x%lx. " ,
dent - > d_name . name , dir_ino - > i_ino ) ;
/* 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 15:20:36 -07: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 14:59:56 +01:00
kfree ( name ) ;
2005-04-16 15:20:36 -07: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 15:20:36 -07: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 23:50:21 +02:00
dent = d_add_ci ( dent , dent_inode , & nls_name ) ;
2005-04-16 15:20:36 -07:00
kfree ( nls_name . name ) ;
2008-08-07 23:50:21 +02:00
return dent ;
2005-04-16 15:20:36 -07: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 00:55:39 -08:00
const struct inode_operations ntfs_dir_inode_ops = {
2005-04-16 15:20:36 -07: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 ( ) .
*
2006-01-09 15:59:24 -08:00
* Note : ntfs_get_parent ( ) is called with @ child_dent - > d_inode - > i_mutex down .
2005-04-16 15:20:36 -07: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 15:20:36 -07:00
{
struct inode * vi = child_dent - > d_inode ;
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 15:49:04 +02:00
return d_obtain_alias ( ntfs_iget ( vi - > i_sb , parent_ino ) ) ;
2005-04-16 15:20:36 -07:00
}
2007-10-21 16:42:10 -07:00
static struct inode * ntfs_nfs_get_inode ( struct super_block * sb ,
u64 ino , u32 generation )
2005-04-16 15:20:36 -07:00
{
2007-10-21 16:42:10 -07:00
struct inode * inode ;
2005-04-16 15:20:36 -07:00
2007-10-21 16:42:10 -07: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 15:20:36 -07:00
}
2007-10-21 16:42:10 -07: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 15:20:36 -07:00
}
2005-03-03 13:44:15 +00:00
/**
* Export operations allowing NFS exporting of mounted NTFS partitions .
*
2007-10-21 16:42:10 -07: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 16:42:17 -07: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 16:42:10 -07:00
. fh_to_dentry = ntfs_fh_to_dentry ,
. fh_to_parent = ntfs_fh_to_parent ,
2005-03-03 13:44:15 +00:00
} ;