2005-04-17 02:20:36 +04:00
/*
* fs / cifs / dir . c
*
* vfs operations that deal with dentries
2007-06-05 22:30:44 +04:00
*
2009-02-20 07:32:45 +03:00
* Copyright ( C ) International Business Machines Corp . , 2002 , 2009
2005-04-17 02:20:36 +04:00
* Author ( s ) : Steve French ( sfrench @ us . ibm . com )
*
* This library is free software ; you can redistribute it and / or modify
* it under the terms of the GNU Lesser General Public License as published
* by the Free Software Foundation ; either version 2.1 of the License , or
* ( at your option ) any later version .
*
* This library 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 Lesser General Public License for more details .
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library ; if not , write to the Free Software
* Foundation , Inc . , 59 Temple Place , Suite 330 , Boston , MA 02111 - 1307 USA
*/
# include <linux/fs.h>
# include <linux/stat.h>
# include <linux/slab.h>
# include <linux/namei.h>
2009-09-21 14:47:50 +04:00
# include <linux/mount.h>
2010-06-16 21:40:16 +04:00
# include <linux/file.h>
2005-04-17 02:20:36 +04:00
# include "cifsfs.h"
# include "cifspdu.h"
# include "cifsglob.h"
# include "cifsproto.h"
# include "cifs_debug.h"
# include "cifs_fs_sb.h"
2013-09-05 16:38:11 +04:00
# include "cifs_unicode.h"
2005-04-17 02:20:36 +04:00
2007-02-27 08:35:17 +03:00
static void
2005-04-17 02:20:36 +04:00
renew_parental_timestamps ( struct dentry * direntry )
{
2007-06-05 22:30:44 +04:00
/* BB check if there is a way to get the kernel to do this or if we
really need this */
2005-04-17 02:20:36 +04:00
do {
direntry - > d_time = jiffies ;
direntry = direntry - > d_parent ;
2007-06-05 22:30:44 +04:00
} while ( ! IS_ROOT ( direntry ) ) ;
2005-04-17 02:20:36 +04:00
}
2012-11-29 08:34:41 +04:00
char *
cifs_build_path_to_root ( struct smb_vol * vol , struct cifs_sb_info * cifs_sb ,
struct cifs_tcon * tcon )
{
2012-12-10 15:10:45 +04:00
int pplen = vol - > prepath ? strlen ( vol - > prepath ) + 1 : 0 ;
2012-11-29 08:34:41 +04:00
int dfsplen ;
char * full_path = NULL ;
/* if no prefix path, simply set path to the root of share to "" */
if ( pplen = = 0 ) {
full_path = kzalloc ( 1 , GFP_KERNEL ) ;
return full_path ;
}
if ( tcon - > Flags & SMB_SHARE_IS_IN_DFS )
dfsplen = strnlen ( tcon - > treeName , MAX_TREE_SIZE + 1 ) ;
else
dfsplen = 0 ;
full_path = kmalloc ( dfsplen + pplen + 1 , GFP_KERNEL ) ;
if ( full_path = = NULL )
return full_path ;
if ( dfsplen )
strncpy ( full_path , tcon - > treeName , dfsplen ) ;
2012-12-10 15:10:45 +04:00
full_path [ dfsplen ] = CIFS_DIR_SEP ( cifs_sb ) ;
strncpy ( full_path + dfsplen + 1 , vol - > prepath , pplen ) ;
2012-11-29 08:34:41 +04:00
convert_delimiter ( full_path , CIFS_DIR_SEP ( cifs_sb ) ) ;
full_path [ dfsplen + pplen ] = 0 ; /* add trailing null */
return full_path ;
}
2005-04-17 02:20:36 +04:00
/* Note: caller must free return buffer */
char *
build_path_from_dentry ( struct dentry * direntry )
{
struct dentry * temp ;
2006-09-21 11:02:52 +04:00
int namelen ;
2008-05-15 05:50:56 +04:00
int dfsplen ;
2005-04-17 02:20:36 +04:00
char * full_path ;
2006-03-10 01:21:45 +03:00
char dirsep ;
2010-09-21 03:01:35 +04:00
struct cifs_sb_info * cifs_sb = CIFS_SB ( direntry - > d_sb ) ;
2011-05-27 08:34:02 +04:00
struct cifs_tcon * tcon = cifs_sb_master_tcon ( cifs_sb ) ;
2011-07-17 07:37:20 +04:00
unsigned seq ;
2005-04-17 02:20:36 +04:00
2008-05-15 05:50:56 +04:00
dirsep = CIFS_DIR_SEP ( cifs_sb ) ;
2010-09-21 03:01:35 +04:00
if ( tcon - > Flags & SMB_SHARE_IS_IN_DFS )
dfsplen = strnlen ( tcon - > treeName , MAX_TREE_SIZE + 1 ) ;
2008-05-15 05:50:56 +04:00
else
dfsplen = 0 ;
2005-04-17 02:20:36 +04:00
cifs_bp_rename_retry :
2011-05-27 07:50:55 +04:00
namelen = dfsplen ;
2011-07-17 07:37:20 +04:00
seq = read_seqbegin ( & rename_lock ) ;
rcu_read_lock ( ) ;
2005-04-17 02:20:36 +04:00
for ( temp = direntry ; ! IS_ROOT ( temp ) ; ) {
namelen + = ( 1 + temp - > d_name . len ) ;
temp = temp - > d_parent ;
2007-06-05 22:30:44 +04:00
if ( temp = = NULL ) {
2013-05-05 07:12:25 +04:00
cifs_dbg ( VFS , " corrupt dentry \n " ) ;
2011-07-17 07:37:20 +04:00
rcu_read_unlock ( ) ;
2005-04-17 02:20:36 +04:00
return NULL ;
}
}
2011-07-17 07:37:20 +04:00
rcu_read_unlock ( ) ;
2005-04-17 02:20:36 +04:00
full_path = kmalloc ( namelen + 1 , GFP_KERNEL ) ;
2007-06-05 22:30:44 +04:00
if ( full_path = = NULL )
2005-04-17 02:20:36 +04:00
return full_path ;
full_path [ namelen ] = 0 ; /* trailing null */
2011-07-17 07:37:20 +04:00
rcu_read_lock ( ) ;
2005-04-17 02:20:36 +04:00
for ( temp = direntry ; ! IS_ROOT ( temp ) ; ) {
2011-07-17 07:37:20 +04:00
spin_lock ( & temp - > d_lock ) ;
2005-04-17 02:20:36 +04:00
namelen - = 1 + temp - > d_name . len ;
if ( namelen < 0 ) {
2011-07-17 07:37:20 +04:00
spin_unlock ( & temp - > d_lock ) ;
2005-04-17 02:20:36 +04:00
break ;
} else {
2005-08-30 22:32:14 +04:00
full_path [ namelen ] = dirsep ;
2005-04-17 02:20:36 +04:00
strncpy ( full_path + namelen + 1 , temp - > d_name . name ,
temp - > d_name . len ) ;
2013-05-05 07:12:25 +04:00
cifs_dbg ( FYI , " name: %s \n " , full_path + namelen ) ;
2005-04-17 02:20:36 +04:00
}
2011-07-17 07:37:20 +04:00
spin_unlock ( & temp - > d_lock ) ;
2005-04-17 02:20:36 +04:00
temp = temp - > d_parent ;
2007-06-05 22:30:44 +04:00
if ( temp = = NULL ) {
2013-05-05 07:12:25 +04:00
cifs_dbg ( VFS , " corrupt dentry \n " ) ;
2011-07-17 07:37:20 +04:00
rcu_read_unlock ( ) ;
2005-04-17 02:20:36 +04:00
kfree ( full_path ) ;
return NULL ;
}
}
2011-07-17 07:37:20 +04:00
rcu_read_unlock ( ) ;
if ( namelen ! = dfsplen | | read_seqretry ( & rename_lock , seq ) ) {
2013-05-05 07:12:25 +04:00
cifs_dbg ( FYI , " did not end path lookup where expected. namelen=%ddfsplen=%d \n " ,
namelen , dfsplen ) ;
2007-06-05 22:30:44 +04:00
/* presumably this is only possible if racing with a rename
2005-04-17 02:20:36 +04:00
of one of the parent directories ( we can not lock the dentries
above us to prevent this , but retrying should be harmless ) */
kfree ( full_path ) ;
goto cifs_bp_rename_retry ;
}
2006-09-21 11:02:52 +04:00
/* DIR_SEP already set for byte 0 / vs \ but not for
subsequent slashes in prepath which currently must
be entered the right way - not sure if there is an alternative
since the ' \ ' is a valid posix character so we can not switch
those safely to ' / ' if any are found in the middle of the prepath */
/* BB test paths to Windows with '/' in the midst of prepath */
2008-05-15 05:50:56 +04:00
if ( dfsplen ) {
2010-09-21 03:01:35 +04:00
strncpy ( full_path , tcon - > treeName , dfsplen ) ;
2008-05-15 05:50:56 +04:00
if ( cifs_sb - > mnt_cifs_flags & CIFS_MOUNT_POSIX_PATHS ) {
int i ;
for ( i = 0 ; i < dfsplen ; i + + ) {
if ( full_path [ i ] = = ' \\ ' )
full_path [ i ] = ' / ' ;
}
}
}
2005-04-17 02:20:36 +04:00
return full_path ;
}
2012-06-05 17:10:23 +04:00
/*
* Don ' t allow the separator character in a path component .
* The VFS will not allow " / " , but " \" is allowed by posix.
*/
static int
check_name ( struct dentry * direntry )
{
struct cifs_sb_info * cifs_sb = CIFS_SB ( direntry - > d_sb ) ;
int i ;
if ( ! ( cifs_sb - > mnt_cifs_flags & CIFS_MOUNT_POSIX_PATHS ) ) {
for ( i = 0 ; i < direntry - > d_name . len ; i + + ) {
if ( direntry - > d_name . name [ i ] = = ' \\ ' ) {
2013-05-05 07:12:25 +04:00
cifs_dbg ( FYI , " Invalid file name \n " ) ;
2012-06-05 17:10:23 +04:00
return - EINVAL ;
}
}
}
return 0 ;
}
2006-06-01 02:40:51 +04:00
/* Inode operations in similar order to how they appear in Linux file fs.h */
2005-04-17 02:20:36 +04:00
2012-06-20 11:21:16 +04:00
static int
cifs_do_create ( struct inode * inode , struct dentry * direntry , unsigned int xid ,
struct tcon_link * tlink , unsigned oflags , umode_t mode ,
2013-12-12 02:29:53 +04:00
__u32 * oplock , struct cifs_fid * fid )
2005-04-17 02:20:36 +04:00
{
int rc = - ENOENT ;
2008-05-10 02:28:02 +04:00
int create_options = CREATE_NOT_DIR ;
2012-09-19 03:20:27 +04:00
int desired_access ;
2012-06-05 17:10:23 +04:00
struct cifs_sb_info * cifs_sb = CIFS_SB ( inode - > i_sb ) ;
struct cifs_tcon * tcon = tlink_tcon ( tlink ) ;
2005-04-17 02:20:36 +04:00
char * full_path = NULL ;
2007-07-10 05:16:18 +04:00
FILE_ALL_INFO * buf = NULL ;
2005-04-17 02:20:36 +04:00
struct inode * newinode = NULL ;
2012-06-05 17:10:23 +04:00
int disposition ;
2012-09-19 03:20:27 +04:00
struct TCP_Server_Info * server = tcon - > ses - > server ;
2013-07-05 12:00:30 +04:00
struct cifs_open_parms oparms ;
2005-04-17 02:20:36 +04:00
2012-06-05 17:10:23 +04:00
* oplock = 0 ;
2012-03-20 13:55:09 +04:00
if ( tcon - > ses - > server - > oplocks )
2012-06-05 17:10:23 +04:00
* oplock = REQ_OPLOCK ;
2009-02-20 07:32:45 +03:00
2010-09-30 03:51:11 +04:00
full_path = build_path_from_dentry ( direntry ) ;
if ( full_path = = NULL ) {
rc = - ENOMEM ;
2012-06-05 17:10:23 +04:00
goto out ;
2010-09-30 03:51:11 +04:00
}
2012-07-13 13:58:14 +04:00
if ( tcon - > unix_ext & & cap_unix ( tcon - > ses ) & & ! tcon - > broken_posix_open & &
2009-02-20 07:32:45 +03:00
( CIFS_UNIX_POSIX_PATH_OPS_CAP &
le64_to_cpu ( tcon - > fsUnixInfo . Capability ) ) ) {
2012-09-19 03:20:27 +04:00
rc = cifs_posix_open ( full_path , & newinode , inode - > i_sb , mode ,
oflags , oplock , & fid - > netfid , xid ) ;
2012-06-05 17:10:23 +04:00
switch ( rc ) {
case 0 :
if ( newinode = = NULL ) {
/* query inode info */
2009-05-08 07:04:30 +04:00
goto cifs_create_get_file_info ;
2012-06-05 17:10:23 +04:00
}
if ( ! S_ISREG ( newinode - > i_mode ) ) {
/*
* The server may allow us to open things like
* FIFOs , but the client isn ' t set up to deal
* with that . If it ' s not a regular file , just
* close it and proceed as if it were a normal
* lookup .
*/
2012-09-19 03:20:27 +04:00
CIFSSMBClose ( xid , tcon , fid - > netfid ) ;
2012-06-05 17:10:23 +04:00
goto cifs_create_get_file_info ;
}
/* success, no need to query */
goto cifs_create_set_dentry ;
case - ENOENT :
goto cifs_create_get_file_info ;
case - EIO :
case - EINVAL :
/*
* EIO could indicate that ( posix open ) operation is not
* supported , despite what server claimed in capability
* negotiation .
*
* POSIX open in samba versions 3.3 .1 and earlier could
* incorrectly fail with invalid parameter .
*/
tcon - > broken_posix_open = true ;
break ;
case - EREMOTE :
case - EOPNOTSUPP :
/*
* EREMOTE indicates DFS junction , which is not handled
* in posix open . If either that or op not supported
* returned , follow the normal lookup .
*/
break ;
2005-09-07 02:18:26 +04:00
2012-06-05 17:10:23 +04:00
default :
goto out ;
}
/*
* fallthrough to retry , using older open call , this is case
* where server does not support this SMB level , and falsely
* claims capability ( also get here for DFS case which should be
* rare for path not covered on files )
*/
2005-04-17 02:20:36 +04:00
}
2012-09-19 03:20:27 +04:00
desired_access = 0 ;
2012-06-05 17:10:23 +04:00
if ( OPEN_FMODE ( oflags ) & FMODE_READ )
2012-09-19 03:20:27 +04:00
desired_access | = GENERIC_READ ; /* is this too little? */
2012-06-05 17:10:23 +04:00
if ( OPEN_FMODE ( oflags ) & FMODE_WRITE )
2012-09-19 03:20:27 +04:00
desired_access | = GENERIC_WRITE ;
2012-06-05 17:10:23 +04:00
disposition = FILE_OVERWRITE_IF ;
if ( ( oflags & ( O_CREAT | O_EXCL ) ) = = ( O_CREAT | O_EXCL ) )
disposition = FILE_CREATE ;
else if ( ( oflags & ( O_CREAT | O_TRUNC ) ) = = ( O_CREAT | O_TRUNC ) )
disposition = FILE_OVERWRITE_IF ;
else if ( ( oflags & O_CREAT ) = = O_CREAT )
disposition = FILE_OPEN_IF ;
else
2013-05-05 07:12:25 +04:00
cifs_dbg ( FYI , " Create flag not set in create function \n " ) ;
2012-06-05 17:10:23 +04:00
2012-09-19 03:20:27 +04:00
/*
* BB add processing to set equivalent of mode - e . g . via CreateX with
* ACLs
*/
if ( ! server - > ops - > open ) {
rc = - ENOSYS ;
goto out ;
}
2005-04-17 02:20:36 +04:00
2007-06-05 22:30:44 +04:00
buf = kmalloc ( sizeof ( FILE_ALL_INFO ) , GFP_KERNEL ) ;
if ( buf = = NULL ) {
2010-08-05 21:58:38 +04:00
rc = - ENOMEM ;
2012-06-05 17:10:23 +04:00
goto out ;
2005-04-17 02:20:36 +04:00
}
2008-05-10 02:28:02 +04:00
/*
* if we ' re not using unix extensions , see if we need to set
* ATTR_READONLY on the create call
*/
2009-01-19 05:38:35 +03:00
if ( ! tcon - > unix_ext & & ( mode & S_IWUGO ) = = 0 )
2008-05-10 02:28:02 +04:00
create_options | = CREATE_OPTION_READONLY ;
2011-09-26 18:56:44 +04:00
if ( backup_cred ( cifs_sb ) )
create_options | = CREATE_OPEN_BACKUP_INTENT ;
2013-07-05 12:00:30 +04:00
oparms . tcon = tcon ;
oparms . cifs_sb = cifs_sb ;
oparms . desired_access = desired_access ;
oparms . create_options = create_options ;
oparms . disposition = disposition ;
oparms . path = full_path ;
oparms . fid = fid ;
2013-07-09 18:40:58 +04:00
oparms . reconnect = false ;
2013-07-05 12:00:30 +04:00
rc = server - > ops - > open ( xid , & oparms , oplock , buf ) ;
2005-04-17 02:20:36 +04:00
if ( rc ) {
2013-05-05 07:12:25 +04:00
cifs_dbg ( FYI , " cifs_create returned 0x%x \n " , rc ) ;
2012-06-05 17:10:23 +04:00
goto out ;
2009-02-20 07:32:45 +03:00
}
2012-09-19 03:20:27 +04:00
/*
* If Open reported that we actually created a file then we now have to
* set the mode if possible .
*/
2012-06-05 17:10:23 +04:00
if ( ( tcon - > unix_ext ) & & ( * oplock & CIFS_CREATE_ACTION ) ) {
2009-02-20 07:32:45 +03:00
struct cifs_unix_set_info_args args = {
2008-08-02 15:26:12 +04:00
. mode = mode ,
. ctime = NO_CHANGE_64 ,
. atime = NO_CHANGE_64 ,
. mtime = NO_CHANGE_64 ,
. device = 0 ,
2009-02-20 07:32:45 +03:00
} ;
if ( cifs_sb - > mnt_cifs_flags & CIFS_MOUNT_SET_UID ) {
2013-02-06 12:57:56 +04:00
args . uid = current_fsuid ( ) ;
2009-02-20 07:32:45 +03:00
if ( inode - > i_mode & S_ISGID )
2013-02-06 12:57:56 +04:00
args . gid = inode - > i_gid ;
2009-02-20 07:32:45 +03:00
else
2013-02-06 12:57:56 +04:00
args . gid = current_fsgid ( ) ;
2007-06-08 18:55:14 +04:00
} else {
2013-02-06 12:57:56 +04:00
args . uid = INVALID_UID ; /* no change */
args . gid = INVALID_GID ; /* no change */
2005-04-17 02:20:36 +04:00
}
2012-09-19 03:20:27 +04:00
CIFSSMBUnixSetFileInfo ( xid , tcon , & args , fid - > netfid ,
current - > tgid ) ;
2009-02-20 07:32:45 +03:00
} else {
2012-09-19 03:20:27 +04:00
/*
* BB implement mode setting via Windows security
* descriptors e . g .
*/
2009-02-20 07:32:45 +03:00
/* CIFSSMBWinSetPerms(xid,tcon,path,mode,-1,-1,nls);*/
/* Could set r/o dos attribute if mode & 0222 == 0 */
}
2005-04-17 02:20:36 +04:00
2009-02-20 07:32:45 +03:00
cifs_create_get_file_info :
/* server might mask mode so we have to query for it */
if ( tcon - > unix_ext )
2012-09-19 03:20:27 +04:00
rc = cifs_get_inode_info_unix ( & newinode , full_path , inode - > i_sb ,
xid ) ;
2009-02-20 07:32:45 +03:00
else {
2012-09-19 03:20:27 +04:00
rc = cifs_get_inode_info ( & newinode , full_path , buf , inode - > i_sb ,
xid , & fid - > netfid ) ;
2009-02-20 07:32:45 +03:00
if ( newinode ) {
2012-09-19 17:22:44 +04:00
if ( server - > ops - > set_lease_key )
server - > ops - > set_lease_key ( newinode , fid ) ;
2009-02-20 07:32:45 +03:00
if ( cifs_sb - > mnt_cifs_flags & CIFS_MOUNT_DYNPERM )
newinode - > i_mode = mode ;
2012-06-05 17:10:23 +04:00
if ( ( * oplock & CIFS_CREATE_ACTION ) & &
2009-02-20 07:32:45 +03:00
( cifs_sb - > mnt_cifs_flags & CIFS_MOUNT_SET_UID ) ) {
newinode - > i_uid = current_fsuid ( ) ;
if ( inode - > i_mode & S_ISGID )
newinode - > i_gid = inode - > i_gid ;
else
newinode - > i_gid = current_fsgid ( ) ;
2005-11-30 07:20:10 +03:00
}
2005-04-17 02:20:36 +04:00
}
2009-02-20 07:32:45 +03:00
}
2005-04-17 02:20:36 +04:00
2009-02-20 07:32:45 +03:00
cifs_create_set_dentry :
2012-06-05 17:10:23 +04:00
if ( rc ! = 0 ) {
2013-05-05 07:12:25 +04:00
cifs_dbg ( FYI , " Create worked, get_inode_info failed rc = %d \n " ,
rc ) ;
2012-09-19 03:20:27 +04:00
if ( server - > ops - > close )
server - > ops - > close ( xid , tcon , fid ) ;
2012-06-05 17:10:23 +04:00
goto out ;
}
d_drop ( direntry ) ;
d_add ( direntry , newinode ) ;
2009-02-20 07:32:45 +03:00
2012-06-05 17:10:23 +04:00
out :
kfree ( buf ) ;
kfree ( full_path ) ;
return rc ;
}
2010-06-16 21:40:16 +04:00
2012-06-22 12:39:14 +04:00
int
2012-06-05 17:10:23 +04:00
cifs_atomic_open ( struct inode * inode , struct dentry * direntry ,
2012-06-22 12:40:19 +04:00
struct file * file , unsigned oflags , umode_t mode ,
2012-06-10 13:01:45 +04:00
int * opened )
2012-06-05 17:10:23 +04:00
{
int rc ;
2012-06-20 11:21:16 +04:00
unsigned int xid ;
2012-06-05 17:10:23 +04:00
struct tcon_link * tlink ;
struct cifs_tcon * tcon ;
2012-09-19 03:20:27 +04:00
struct TCP_Server_Info * server ;
2012-09-19 03:20:26 +04:00
struct cifs_fid fid ;
2012-09-19 17:22:45 +04:00
struct cifs_pending_open open ;
2012-06-05 17:10:23 +04:00
__u32 oplock ;
2012-09-19 03:20:26 +04:00
struct cifsFileInfo * file_info ;
2012-06-05 17:10:23 +04:00
2012-09-19 03:20:26 +04:00
/*
* Posix open is only called ( at lookup time ) for file create now . For
2012-06-05 17:10:23 +04:00
* opens ( rather than creates ) , because we do not know if it is a file
* or directory yet , and current Samba no longer allows us to do posix
* open on dirs , we could end up wasting an open call on what turns out
* to be a dir . For file opens , we wait to call posix open till
* cifs_open . It could be added to atomic_open in the future but the
* performance tradeoff of the extra network request when EISDIR or
* EACCES is returned would have to be weighed against the 50 % reduction
* in network traffic in the other paths .
*/
if ( ! ( oflags & O_CREAT ) ) {
2012-11-05 15:39:32 +04:00
struct dentry * res ;
/*
* Check for hashed negative dentry . We have already revalidated
* the dentry and it is fine . No need to perform another lookup .
*/
if ( ! d_unhashed ( direntry ) )
return - ENOENT ;
res = cifs_lookup ( inode , direntry , 0 ) ;
2012-06-05 17:10:23 +04:00
if ( IS_ERR ( res ) )
2012-06-22 12:39:14 +04:00
return PTR_ERR ( res ) ;
2012-06-05 17:10:23 +04:00
2012-06-10 14:48:09 +04:00
return finish_no_open ( file , res ) ;
2012-06-05 17:10:23 +04:00
}
rc = check_name ( direntry ) ;
if ( rc )
2012-06-22 12:39:14 +04:00
return rc ;
2012-06-05 17:10:23 +04:00
2012-06-20 11:21:16 +04:00
xid = get_xid ( ) ;
2012-06-05 17:10:23 +04:00
2013-05-05 07:12:25 +04:00
cifs_dbg ( FYI , " parent inode = 0x%p name is: %s and dentry = 0x%p \n " ,
inode , direntry - > d_name . name , direntry ) ;
2012-06-05 17:10:23 +04:00
tlink = cifs_sb_tlink ( CIFS_SB ( inode - > i_sb ) ) ;
2013-04-04 10:16:21 +04:00
if ( IS_ERR ( tlink ) ) {
rc = PTR_ERR ( tlink ) ;
2012-06-20 11:21:16 +04:00
goto out_free_xid ;
2013-04-04 10:16:21 +04:00
}
2012-06-05 17:10:23 +04:00
tcon = tlink_tcon ( tlink ) ;
2012-09-19 03:20:27 +04:00
server = tcon - > ses - > server ;
2012-06-05 17:10:23 +04:00
2012-09-19 17:22:44 +04:00
if ( server - > ops - > new_lease_key )
server - > ops - > new_lease_key ( & fid ) ;
2012-09-19 17:22:45 +04:00
cifs_add_pending_open ( & fid , tlink , & open ) ;
2012-06-05 17:10:23 +04:00
rc = cifs_do_create ( inode , direntry , xid , tlink , oflags , mode ,
2013-12-12 02:29:53 +04:00
& oplock , & fid ) ;
2012-06-05 17:10:23 +04:00
2012-09-19 17:22:45 +04:00
if ( rc ) {
cifs_del_pending_open ( & open ) ;
2012-06-05 17:10:23 +04:00
goto out ;
2012-09-19 17:22:45 +04:00
}
2012-06-05 17:10:23 +04:00
2013-12-12 02:29:53 +04:00
if ( ( oflags & ( O_CREAT | O_EXCL ) ) = = ( O_CREAT | O_EXCL ) )
* opened | = FILE_CREATED ;
2012-06-22 12:40:19 +04:00
rc = finish_open ( file , direntry , generic_file_open , opened ) ;
if ( rc ) {
2012-09-19 03:20:27 +04:00
if ( server - > ops - > close )
server - > ops - > close ( xid , tcon , & fid ) ;
2012-09-19 17:22:45 +04:00
cifs_del_pending_open ( & open ) ;
2012-06-05 17:10:23 +04:00
goto out ;
2007-06-05 22:30:44 +04:00
}
2010-06-16 21:40:16 +04:00
2012-09-19 03:20:26 +04:00
file_info = cifs_new_fileinfo ( & fid , file , tlink , oplock ) ;
if ( file_info = = NULL ) {
2012-09-19 03:20:27 +04:00
if ( server - > ops - > close )
server - > ops - > close ( xid , tcon , & fid ) ;
2012-09-19 17:22:45 +04:00
cifs_del_pending_open ( & open ) ;
2013-09-16 16:51:59 +04:00
fput ( file ) ;
2012-06-22 12:39:14 +04:00
rc = - ENOMEM ;
2012-06-05 17:10:23 +04:00
}
out :
cifs_put_tlink ( tlink ) ;
2012-06-20 11:21:16 +04:00
out_free_xid :
free_xid ( xid ) ;
2012-06-22 12:39:14 +04:00
return rc ;
2012-06-05 17:10:23 +04:00
}
int cifs_create ( struct inode * inode , struct dentry * direntry , umode_t mode ,
2012-06-11 02:05:36 +04:00
bool excl )
2012-06-05 17:10:23 +04:00
{
int rc ;
2012-06-20 11:21:16 +04:00
unsigned int xid = get_xid ( ) ;
2012-06-05 17:10:23 +04:00
/*
* BB below access is probably too much for mknod to request
* but we have to do query and setpathinfo so requesting
* less could fail ( unless we want to request getatr and setatr
* permissions ( only ) . At least for POSIX we do not have to
* request so much .
*/
unsigned oflags = O_EXCL | O_CREAT | O_RDWR ;
struct tcon_link * tlink ;
2012-09-19 03:20:27 +04:00
struct cifs_tcon * tcon ;
struct TCP_Server_Info * server ;
struct cifs_fid fid ;
2012-06-05 17:10:23 +04:00
__u32 oplock ;
2013-05-05 07:12:25 +04:00
cifs_dbg ( FYI , " cifs_create parent inode = 0x%p name is: %s and dentry = 0x%p \n " ,
inode , direntry - > d_name . name , direntry ) ;
2012-06-05 17:10:23 +04:00
tlink = cifs_sb_tlink ( CIFS_SB ( inode - > i_sb ) ) ;
rc = PTR_ERR ( tlink ) ;
if ( IS_ERR ( tlink ) )
2012-06-20 11:21:16 +04:00
goto out_free_xid ;
2012-06-05 17:10:23 +04:00
2012-09-19 03:20:27 +04:00
tcon = tlink_tcon ( tlink ) ;
server = tcon - > ses - > server ;
2012-09-19 17:22:44 +04:00
if ( server - > ops - > new_lease_key )
server - > ops - > new_lease_key ( & fid ) ;
rc = cifs_do_create ( inode , direntry , xid , tlink , oflags , mode ,
2013-12-12 02:29:53 +04:00
& oplock , & fid ) ;
2012-09-19 03:20:27 +04:00
if ( ! rc & & server - > ops - > close )
server - > ops - > close ( xid , tcon , & fid ) ;
2012-06-05 17:10:23 +04:00
2010-09-30 03:51:11 +04:00
cifs_put_tlink ( tlink ) ;
2012-06-20 11:21:16 +04:00
out_free_xid :
free_xid ( xid ) ;
2005-04-17 02:20:36 +04:00
return rc ;
}
2011-07-26 09:52:52 +04:00
int cifs_mknod ( struct inode * inode , struct dentry * direntry , umode_t mode ,
2007-06-05 22:30:44 +04:00
dev_t device_number )
2005-04-17 02:20:36 +04:00
{
int rc = - EPERM ;
2012-06-20 11:21:16 +04:00
unsigned int xid ;
2011-09-26 18:56:44 +04:00
int create_options = CREATE_NOT_DIR | CREATE_OPTION_SPECIAL ;
2005-04-17 02:20:36 +04:00
struct cifs_sb_info * cifs_sb ;
2010-09-30 03:51:11 +04:00
struct tcon_link * tlink ;
2014-01-16 15:53:34 +04:00
struct cifs_tcon * tcon ;
2011-05-26 10:01:59 +04:00
struct cifs_io_parms io_parms ;
2005-04-17 02:20:36 +04:00
char * full_path = NULL ;
2007-07-10 05:16:18 +04:00
struct inode * newinode = NULL ;
2010-08-05 21:58:22 +04:00
int oplock = 0 ;
2014-01-16 15:53:36 +04:00
struct cifs_fid fid ;
struct cifs_open_parms oparms ;
2010-08-05 21:58:22 +04:00
FILE_ALL_INFO * buf = NULL ;
unsigned int bytes_written ;
struct win_dev * pdev ;
2005-04-17 02:20:36 +04:00
if ( ! old_valid_dev ( device_number ) )
return - EINVAL ;
cifs_sb = CIFS_SB ( inode - > i_sb ) ;
2010-09-30 03:51:11 +04:00
tlink = cifs_sb_tlink ( cifs_sb ) ;
if ( IS_ERR ( tlink ) )
return PTR_ERR ( tlink ) ;
2014-01-16 15:53:34 +04:00
tcon = tlink_tcon ( tlink ) ;
2010-09-30 03:51:11 +04:00
2012-06-20 11:21:16 +04:00
xid = get_xid ( ) ;
2005-04-17 02:20:36 +04:00
full_path = build_path_from_dentry ( direntry ) ;
2010-08-05 21:58:22 +04:00
if ( full_path = = NULL ) {
2005-04-17 02:20:36 +04:00
rc = - ENOMEM ;
2010-08-05 21:58:22 +04:00
goto mknod_out ;
}
2014-01-16 15:53:34 +04:00
if ( tcon - > unix_ext ) {
2008-08-02 15:26:12 +04:00
struct cifs_unix_set_info_args args = {
2009-03-30 03:08:22 +04:00
. mode = mode & ~ current_umask ( ) ,
2008-08-02 15:26:12 +04:00
. ctime = NO_CHANGE_64 ,
. atime = NO_CHANGE_64 ,
. mtime = NO_CHANGE_64 ,
. device = device_number ,
} ;
2007-06-05 22:30:44 +04:00
if ( cifs_sb - > mnt_cifs_flags & CIFS_MOUNT_SET_UID ) {
2013-02-06 12:57:56 +04:00
args . uid = current_fsuid ( ) ;
args . gid = current_fsgid ( ) ;
2005-04-17 02:20:36 +04:00
} else {
2013-02-06 12:57:56 +04:00
args . uid = INVALID_UID ; /* no change */
args . gid = INVALID_GID ; /* no change */
2005-04-17 02:20:36 +04:00
}
2014-01-16 15:53:34 +04:00
rc = CIFSSMBUnixSetPathInfo ( xid , tcon , full_path , & args ,
2009-07-10 04:02:49 +04:00
cifs_sb - > local_nls ,
cifs_sb - > mnt_cifs_flags &
CIFS_MOUNT_MAP_SPECIAL_CHR ) ;
2010-08-05 21:58:22 +04:00
if ( rc )
goto mknod_out ;
2005-04-17 02:20:36 +04:00
2010-08-05 21:58:22 +04:00
rc = cifs_get_inode_info_unix ( & newinode , full_path ,
2007-06-05 22:30:44 +04:00
inode - > i_sb , xid ) ;
2005-07-22 02:20:28 +04:00
2010-08-05 21:58:22 +04:00
if ( rc = = 0 )
d_instantiate ( direntry , newinode ) ;
goto mknod_out ;
2005-04-17 02:20:36 +04:00
}
2010-08-05 21:58:22 +04:00
if ( ! ( cifs_sb - > mnt_cifs_flags & CIFS_MOUNT_UNX_EMUL ) )
goto mknod_out ;
2013-05-05 07:12:25 +04:00
cifs_dbg ( FYI , " sfu compat create special file \n " ) ;
2010-08-05 21:58:22 +04:00
buf = kmalloc ( sizeof ( FILE_ALL_INFO ) , GFP_KERNEL ) ;
if ( buf = = NULL ) {
kfree ( full_path ) ;
rc = - ENOMEM ;
2012-06-20 11:21:16 +04:00
free_xid ( xid ) ;
2010-08-05 21:58:22 +04:00
return rc ;
}
2011-09-26 18:56:44 +04:00
if ( backup_cred ( cifs_sb ) )
create_options | = CREATE_OPEN_BACKUP_INTENT ;
2014-01-16 15:53:36 +04:00
oparms . tcon = tcon ;
oparms . cifs_sb = cifs_sb ;
oparms . desired_access = GENERIC_WRITE ;
oparms . create_options = create_options ;
oparms . disposition = FILE_CREATE ;
oparms . path = full_path ;
oparms . fid = & fid ;
oparms . reconnect = false ;
rc = CIFS_open ( xid , & oparms , & oplock , buf ) ;
2010-08-05 21:58:22 +04:00
if ( rc )
goto mknod_out ;
2014-01-16 15:53:34 +04:00
/*
* BB Do not bother to decode buf since no local inode yet to put
* timestamps in , but we can reuse it safely .
*/
2010-08-05 21:58:22 +04:00
pdev = ( struct win_dev * ) buf ;
2014-01-16 15:53:36 +04:00
io_parms . netfid = fid . netfid ;
2011-05-26 10:01:59 +04:00
io_parms . pid = current - > tgid ;
2014-01-16 15:53:34 +04:00
io_parms . tcon = tcon ;
2011-05-26 10:01:59 +04:00
io_parms . offset = 0 ;
io_parms . length = sizeof ( struct win_dev ) ;
2010-08-05 21:58:22 +04:00
if ( S_ISCHR ( mode ) ) {
memcpy ( pdev - > type , " IntxCHR " , 8 ) ;
2014-01-16 15:53:34 +04:00
pdev - > major = cpu_to_le64 ( MAJOR ( device_number ) ) ;
pdev - > minor = cpu_to_le64 ( MINOR ( device_number ) ) ;
rc = CIFSSMBWrite ( xid , & io_parms , & bytes_written , ( char * ) pdev ,
NULL , 0 ) ;
2010-08-05 21:58:22 +04:00
} else if ( S_ISBLK ( mode ) ) {
memcpy ( pdev - > type , " IntxBLK " , 8 ) ;
2014-01-16 15:53:34 +04:00
pdev - > major = cpu_to_le64 ( MAJOR ( device_number ) ) ;
pdev - > minor = cpu_to_le64 ( MINOR ( device_number ) ) ;
rc = CIFSSMBWrite ( xid , & io_parms , & bytes_written , ( char * ) pdev ,
NULL , 0 ) ;
2010-08-05 21:58:22 +04:00
} /* else if (S_ISFIFO) */
2014-01-16 15:53:36 +04:00
CIFSSMBClose ( xid , tcon , fid . netfid ) ;
2010-08-05 21:58:22 +04:00
d_drop ( direntry ) ;
/* FIXME: add code here to set EAs */
mknod_out :
2005-04-29 09:41:05 +04:00
kfree ( full_path ) ;
2010-08-05 21:58:22 +04:00
kfree ( buf ) ;
2012-06-20 11:21:16 +04:00
free_xid ( xid ) ;
2010-09-30 03:51:11 +04:00
cifs_put_tlink ( tlink ) ;
2005-04-17 02:20:36 +04:00
return rc ;
}
struct dentry *
2007-06-05 22:30:44 +04:00
cifs_lookup ( struct inode * parent_dir_inode , struct dentry * direntry ,
2012-06-11 01:13:09 +04:00
unsigned int flags )
2005-04-17 02:20:36 +04:00
{
2012-06-20 11:21:16 +04:00
unsigned int xid ;
2005-04-17 02:20:36 +04:00
int rc = 0 ; /* to get around spurious gcc warning, set to zero here */
struct cifs_sb_info * cifs_sb ;
2010-09-30 03:51:11 +04:00
struct tcon_link * tlink ;
2011-05-27 08:34:02 +04:00
struct cifs_tcon * pTcon ;
2005-04-17 02:20:36 +04:00
struct inode * newInode = NULL ;
char * full_path = NULL ;
2012-06-20 11:21:16 +04:00
xid = get_xid ( ) ;
2005-04-17 02:20:36 +04:00
2013-05-05 07:12:25 +04:00
cifs_dbg ( FYI , " parent inode = 0x%p name is: %s and dentry = 0x%p \n " ,
parent_dir_inode , direntry - > d_name . name , direntry ) ;
2005-04-17 02:20:36 +04:00
/* check whether path exists */
cifs_sb = CIFS_SB ( parent_dir_inode - > i_sb ) ;
2010-09-30 03:51:11 +04:00
tlink = cifs_sb_tlink ( cifs_sb ) ;
if ( IS_ERR ( tlink ) ) {
2012-06-20 11:21:16 +04:00
free_xid ( xid ) ;
2010-09-30 03:51:11 +04:00
return ( struct dentry * ) tlink ;
}
pTcon = tlink_tcon ( tlink ) ;
2005-04-17 02:20:36 +04:00
2012-06-05 17:10:23 +04:00
rc = check_name ( direntry ) ;
if ( rc )
2010-09-30 03:51:11 +04:00
goto lookup_out ;
2009-07-05 19:01:02 +04:00
2005-04-17 02:20:36 +04:00
/* can not grab the rename sem here since it would
deadlock in the cases ( beginning of sys_rename itself )
in which we already have the sb rename sem */
full_path = build_path_from_dentry ( direntry ) ;
2007-06-05 22:30:44 +04:00
if ( full_path = = NULL ) {
2010-09-30 03:51:11 +04:00
rc = - ENOMEM ;
goto lookup_out ;
2005-04-17 02:20:36 +04:00
}
if ( direntry - > d_inode ! = NULL ) {
2013-05-05 07:12:25 +04:00
cifs_dbg ( FYI , " non-NULL inode in lookup \n " ) ;
2005-04-17 02:20:36 +04:00
} else {
2013-05-05 07:12:25 +04:00
cifs_dbg ( FYI , " NULL inode in lookup \n " ) ;
2005-04-17 02:20:36 +04:00
}
2013-05-05 07:12:25 +04:00
cifs_dbg ( FYI , " Full path: %s inode = 0x%p \n " ,
full_path , direntry - > d_inode ) ;
2005-04-17 02:20:36 +04:00
2009-04-09 05:14:32 +04:00
if ( pTcon - > unix_ext ) {
2012-06-05 17:10:23 +04:00
rc = cifs_get_inode_info_unix ( & newInode , full_path ,
parent_dir_inode - > i_sb , xid ) ;
} else {
2005-04-17 02:20:36 +04:00
rc = cifs_get_inode_info ( & newInode , full_path , NULL ,
2009-04-09 05:14:32 +04:00
parent_dir_inode - > i_sb , xid , NULL ) ;
2012-06-05 17:10:23 +04:00
}
2005-04-17 02:20:36 +04:00
if ( ( rc = = 0 ) & & ( newInode ! = NULL ) ) {
d_add ( direntry , newInode ) ;
2007-06-05 22:30:44 +04:00
/* since paths are not looked up by component - the parent
2005-11-28 19:16:13 +03:00
directories are presumed to be good here */
2005-04-17 02:20:36 +04:00
renew_parental_timestamps ( direntry ) ;
} else if ( rc = = - ENOENT ) {
rc = 0 ;
2005-11-28 19:16:13 +03:00
direntry - > d_time = jiffies ;
2005-04-17 02:20:36 +04:00
d_add ( direntry , NULL ) ;
2007-06-05 22:30:44 +04:00
/* if it was once a directory (but how can we tell?) we could do
shrink_dcache_parent ( direntry ) ; */
2008-01-20 03:30:29 +03:00
} else if ( rc ! = - EACCES ) {
2013-11-08 00:03:39 +04:00
cifs_dbg ( FYI , " Unexpected lookup error %d \n " , rc ) ;
2008-01-20 03:30:29 +03:00
/* We special case check for Access Denied - since that
is a common return code */
2005-04-17 02:20:36 +04:00
}
2010-06-16 21:40:16 +04:00
lookup_out :
2005-04-29 09:41:05 +04:00
kfree ( full_path ) ;
2010-09-30 03:51:11 +04:00
cifs_put_tlink ( tlink ) ;
2012-06-20 11:21:16 +04:00
free_xid ( xid ) ;
2005-04-17 02:20:36 +04:00
return ERR_PTR ( rc ) ;
}
static int
2012-06-11 00:03:43 +04:00
cifs_d_revalidate ( struct dentry * direntry , unsigned int flags )
2005-04-17 02:20:36 +04:00
{
2012-06-11 00:03:43 +04:00
if ( flags & LOOKUP_RCU )
2011-01-07 09:49:57 +03:00
return - ECHILD ;
2005-04-17 02:20:36 +04:00
if ( direntry - > d_inode ) {
2010-02-12 15:44:16 +03:00
if ( cifs_revalidate_dentry ( direntry ) )
2005-04-17 02:20:36 +04:00
return 0 ;
2011-10-18 12:58:50 +04:00
else {
/*
2012-05-02 15:19:09 +04:00
* If the inode wasn ' t known to be a dfs entry when
* the dentry was instantiated , such as when created
* via - > readdir ( ) , it needs to be set now since the
* attributes will have been updated by
* cifs_revalidate_dentry ( ) .
2011-10-18 12:58:50 +04:00
*/
2012-05-02 15:19:09 +04:00
if ( IS_AUTOMOUNT ( direntry - > d_inode ) & &
! ( direntry - > d_flags & DCACHE_NEED_AUTOMOUNT ) ) {
spin_lock ( & direntry - > d_lock ) ;
direntry - > d_flags | = DCACHE_NEED_AUTOMOUNT ;
spin_unlock ( & direntry - > d_lock ) ;
}
2010-11-11 10:42:16 +03:00
return 1 ;
2011-10-18 12:58:50 +04:00
}
2005-04-17 02:20:36 +04:00
}
2010-11-11 10:42:16 +03:00
/*
* This may be nfsd ( or something ) , anyway , we can ' t see the
* intent of this . So , since this can be for creation , drop it .
*/
2012-06-11 00:03:43 +04:00
if ( ! flags )
2010-11-11 10:42:16 +03:00
return 0 ;
/*
* Drop the negative dentry , in order to make sure to use the
* case sensitive name which is specified by user if this is
* for creation .
*/
2012-06-11 00:03:43 +04:00
if ( flags & ( LOOKUP_CREATE | LOOKUP_RENAME_TARGET ) )
2011-06-26 05:37:18 +04:00
return 0 ;
2010-11-11 10:42:16 +03:00
if ( time_after ( jiffies , direntry - > d_time + HZ ) | | ! lookupCacheEnabled )
return 0 ;
return 1 ;
2005-04-17 02:20:36 +04:00
}
/* static int cifs_d_delete(struct dentry *direntry)
{
int rc = 0 ;
2013-05-05 07:12:25 +04:00
cifs_dbg ( FYI , " In cifs d_delete, name = %s \n " , direntry - > d_name . name ) ;
2005-04-17 02:20:36 +04:00
return rc ;
} */
2009-02-20 08:57:07 +03:00
const struct dentry_operations cifs_dentry_ops = {
2005-04-17 02:20:36 +04:00
. d_revalidate = cifs_d_revalidate ,
2011-01-14 21:45:47 +03:00
. d_automount = cifs_dfs_d_automount ,
2007-06-05 22:30:44 +04:00
/* d_delete: cifs_d_delete, */ /* not needed except for debugging */
2005-04-17 02:20:36 +04:00
} ;
2005-08-23 07:09:43 +04:00
2013-05-22 02:22:44 +04:00
static int cifs_ci_hash ( const struct dentry * dentry , struct qstr * q )
2005-08-23 07:09:43 +04:00
{
2011-01-07 09:49:28 +03:00
struct nls_table * codepage = CIFS_SB ( dentry - > d_sb ) - > local_nls ;
2005-08-23 07:09:43 +04:00
unsigned long hash ;
2013-09-05 16:38:11 +04:00
wchar_t c ;
int i , charlen ;
2005-08-23 07:09:43 +04:00
hash = init_name_hash ( ) ;
2013-09-05 16:38:11 +04:00
for ( i = 0 ; i < q - > len ; i + = charlen ) {
charlen = codepage - > char2uni ( & q - > name [ i ] , q - > len - i , & c ) ;
/* error out if we can't convert the character */
if ( unlikely ( charlen < 0 ) )
return charlen ;
hash = partial_name_hash ( cifs_toupper ( c ) , hash ) ;
}
2005-08-23 07:09:43 +04:00
q - > hash = end_name_hash ( hash ) ;
return 0 ;
}
2013-05-22 02:22:44 +04:00
static int cifs_ci_compare ( const struct dentry * parent , const struct dentry * dentry ,
2011-01-07 09:49:27 +03:00
unsigned int len , const char * str , const struct qstr * name )
2005-08-23 07:09:43 +04:00
{
2013-05-22 02:22:44 +04:00
struct nls_table * codepage = CIFS_SB ( parent - > d_sb ) - > local_nls ;
2013-09-05 16:38:11 +04:00
wchar_t c1 , c2 ;
int i , l1 , l2 ;
2005-08-23 07:09:43 +04:00
2013-09-05 16:38:11 +04:00
/*
* We make the assumption here that uppercase characters in the local
* codepage are always the same length as their lowercase counterparts .
*
* If that ' s ever not the case , then this will fail to match it .
*/
if ( name - > len ! = len )
return 1 ;
for ( i = 0 ; i < len ; i + = l1 ) {
/* Convert characters in both strings to UTF-16. */
l1 = codepage - > char2uni ( & str [ i ] , len - i , & c1 ) ;
l2 = codepage - > char2uni ( & name - > name [ i ] , name - > len - i , & c2 ) ;
/*
* If we can ' t convert either character , just declare it to
* be 1 byte long and compare the original byte .
*/
if ( unlikely ( l1 < 0 & & l2 < 0 ) ) {
if ( str [ i ] ! = name - > name [ i ] )
return 1 ;
l1 = 1 ;
continue ;
}
/*
* Here , we again ass | u | me that upper / lowercase versions of
* a character are the same length in the local NLS .
*/
if ( l1 ! = l2 )
return 1 ;
/* Now compare uppercase versions of these characters */
if ( cifs_toupper ( c1 ) ! = cifs_toupper ( c2 ) )
return 1 ;
}
return 0 ;
2005-08-23 07:09:43 +04:00
}
2009-02-20 08:57:07 +03:00
const struct dentry_operations cifs_ci_dentry_ops = {
2005-08-23 07:09:43 +04:00
. d_revalidate = cifs_d_revalidate ,
. d_hash = cifs_ci_hash ,
. d_compare = cifs_ci_compare ,
2011-01-14 21:45:47 +03:00
. d_automount = cifs_dfs_d_automount ,
2005-08-23 07:09:43 +04:00
} ;