2013-06-21 19:56:08 +04:00
/*
2008-02-28 19:23:20 +03:00
Unix SMB / Netbios implementation .
SMB client library implementation
Copyright ( C ) Andrew Tridgell 1998
Copyright ( C ) Richard Sharpe 2000 , 2002
Copyright ( C ) John Terpstra 2000
2013-06-21 19:56:08 +04:00
Copyright ( C ) Tom Jansen ( Ninja ISD ) 2002
2008-02-28 19:23:20 +03:00
Copyright ( C ) Derrell Lipman 2003 - 2008
Copyright ( C ) Jeremy Allison 2007 , 2008
2009-11-22 00:52:12 +03:00
2008-02-28 19:23:20 +03:00
This program 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 3 of the License , or
( at your option ) any later version .
2009-11-22 00:52:12 +03:00
2008-02-28 19:23:20 +03:00
This program 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 .
2009-11-22 00:52:12 +03:00
2008-02-28 19:23:20 +03:00
You should have received a copy of the GNU General Public License
along with this program . If not , see < http : //www.gnu.org/licenses/>.
*/
# include "includes.h"
2011-05-06 13:47:43 +04:00
# include "libsmb/libsmb.h"
2008-02-28 19:23:20 +03:00
# include "libsmbclient.h"
# include "libsmb_internal.h"
2012-05-19 20:23:40 +04:00
# include "../libcli/smb/smbXcli_base.h"
2008-02-28 19:23:20 +03:00
2013-06-21 19:56:08 +04:00
/*
2008-02-28 19:23:20 +03:00
* Generate an inode number from file name for those things that need it
*/
static ino_t
generate_inode ( SMBCCTX * context ,
2008-03-02 04:44:21 +03:00
const char * name )
2008-02-28 19:23:20 +03:00
{
2008-02-29 21:34:35 +03:00
if ( ! context | | ! context - > internal - > initialized ) {
2008-02-28 19:23:20 +03:00
errno = EINVAL ;
return - 1 ;
}
2009-11-22 00:52:12 +03:00
2008-02-28 19:23:20 +03:00
if ( ! * name ) return 2 ; /* FIXME, why 2 ??? */
return ( ino_t ) str_checksum ( name ) ;
}
/*
* Routine to put basic stat info into a stat structure . . . Used by stat and
* fstat below .
*/
static int
setup_stat ( SMBCCTX * context ,
2008-03-02 04:44:21 +03:00
struct stat * st ,
2011-05-06 00:42:05 +04:00
const char * fname ,
2012-04-05 08:53:08 +04:00
off_t size ,
2008-03-02 04:44:21 +03:00
int mode )
2008-02-28 19:23:20 +03:00
{
TALLOC_CTX * frame = talloc_stackframe ( ) ;
2009-11-22 00:52:12 +03:00
2008-02-28 19:23:20 +03:00
st - > st_mode = 0 ;
2009-11-22 00:52:12 +03:00
2008-02-28 19:23:20 +03:00
if ( IS_DOS_DIR ( mode ) ) {
st - > st_mode = SMBC_DIR_MODE ;
} else {
st - > st_mode = SMBC_FILE_MODE ;
}
2009-11-22 00:52:12 +03:00
2008-02-28 19:23:20 +03:00
if ( IS_DOS_ARCHIVE ( mode ) ) st - > st_mode | = S_IXUSR ;
if ( IS_DOS_SYSTEM ( mode ) ) st - > st_mode | = S_IXGRP ;
if ( IS_DOS_HIDDEN ( mode ) ) st - > st_mode | = S_IXOTH ;
if ( ! IS_DOS_READONLY ( mode ) ) st - > st_mode | = S_IWUSR ;
2009-11-22 00:52:12 +03:00
2008-02-28 19:23:20 +03:00
st - > st_size = size ;
# ifdef HAVE_STAT_ST_BLKSIZE
st - > st_blksize = 512 ;
# endif
# ifdef HAVE_STAT_ST_BLOCKS
st - > st_blocks = ( size + 511 ) / 512 ;
# endif
# ifdef HAVE_STRUCT_STAT_ST_RDEV
st - > st_rdev = 0 ;
# endif
st - > st_uid = getuid ( ) ;
st - > st_gid = getgid ( ) ;
2009-11-22 00:52:12 +03:00
2008-02-28 19:23:20 +03:00
if ( IS_DOS_DIR ( mode ) ) {
st - > st_nlink = 2 ;
} else {
st - > st_nlink = 1 ;
}
2009-11-22 00:52:12 +03:00
2008-02-28 19:23:20 +03:00
if ( st - > st_ino = = 0 ) {
st - > st_ino = generate_inode ( context , fname ) ;
}
2009-11-22 00:52:12 +03:00
2008-02-28 19:23:20 +03:00
TALLOC_FREE ( frame ) ;
return True ; /* FIXME: Is this needed ? */
}
/*
* Routine to stat a file given a name
*/
int
SMBC_stat_ctx ( SMBCCTX * context ,
const char * fname ,
struct stat * st )
{
SMBCSRV * srv = NULL ;
char * server = NULL ;
char * share = NULL ;
char * user = NULL ;
char * password = NULL ;
char * workgroup = NULL ;
char * path = NULL ;
struct timespec write_time_ts ;
struct timespec access_time_ts ;
struct timespec change_time_ts ;
2012-04-05 08:53:08 +04:00
off_t size = 0 ;
2015-05-10 02:59:45 +03:00
uint16_t mode = 0 ;
2013-04-16 23:09:41 +04:00
uint16_t port = 0 ;
2008-02-28 19:23:20 +03:00
SMB_INO_T ino = 0 ;
TALLOC_CTX * frame = talloc_stackframe ( ) ;
2009-11-22 00:52:12 +03:00
2008-02-29 21:34:35 +03:00
if ( ! context | | ! context - > internal - > initialized ) {
2008-02-28 19:23:20 +03:00
errno = EINVAL ; /* Best I can think of ... */
TALLOC_FREE ( frame ) ;
return - 1 ;
}
2009-11-22 00:52:12 +03:00
2008-02-28 19:23:20 +03:00
if ( ! fname ) {
errno = EINVAL ;
TALLOC_FREE ( frame ) ;
return - 1 ;
}
2009-11-22 00:52:12 +03:00
2008-02-28 19:23:20 +03:00
DEBUG ( 4 , ( " smbc_stat(%s) \n " , fname ) ) ;
2009-11-22 00:52:12 +03:00
2008-02-28 19:23:20 +03:00
if ( SMBC_parse_path ( frame ,
2008-03-02 04:44:21 +03:00
context ,
fname ,
& workgroup ,
& server ,
2013-04-16 23:09:41 +04:00
& port ,
2008-03-02 04:44:21 +03:00
& share ,
& path ,
& user ,
& password ,
NULL ) ) {
2008-02-28 19:23:20 +03:00
errno = EINVAL ;
TALLOC_FREE ( frame ) ;
return - 1 ;
}
2009-02-20 07:00:46 +03:00
2008-02-28 19:23:20 +03:00
if ( ! user | | user [ 0 ] = = ( char ) 0 ) {
2008-03-04 02:13:33 +03:00
user = talloc_strdup ( frame , smbc_getUser ( context ) ) ;
2008-02-28 19:23:20 +03:00
if ( ! user ) {
errno = ENOMEM ;
TALLOC_FREE ( frame ) ;
return - 1 ;
}
}
2009-11-22 00:52:12 +03:00
2008-02-28 19:23:20 +03:00
srv = SMBC_server ( frame , context , True ,
2013-04-17 01:11:08 +04:00
server , port , share , & workgroup , & user , & password ) ;
2008-02-28 19:23:20 +03:00
if ( ! srv ) {
TALLOC_FREE ( frame ) ;
return - 1 ; /* errno set by SMBC_server */
}
2009-11-22 00:52:12 +03:00
2008-02-28 19:23:20 +03:00
if ( ! SMBC_getatr ( context , srv , path , & mode , & size ,
NULL ,
& access_time_ts ,
& write_time_ts ,
& change_time_ts ,
& ino ) ) {
errno = SMBC_errno ( context , srv - > cli ) ;
TALLOC_FREE ( frame ) ;
return - 1 ;
}
2009-11-22 00:52:12 +03:00
2008-02-28 19:23:20 +03:00
st - > st_ino = ino ;
2009-11-22 00:52:12 +03:00
2011-05-06 00:42:05 +04:00
setup_stat ( context , st , fname , size , mode ) ;
2009-11-22 00:52:12 +03:00
2009-05-14 17:34:42 +04:00
st - > st_atime = convert_timespec_to_time_t ( access_time_ts ) ;
st - > st_ctime = convert_timespec_to_time_t ( change_time_ts ) ;
st - > st_mtime = convert_timespec_to_time_t ( write_time_ts ) ;
2008-02-28 19:23:20 +03:00
st - > st_dev = srv - > dev ;
2009-11-22 00:52:12 +03:00
2008-02-28 19:23:20 +03:00
TALLOC_FREE ( frame ) ;
return 0 ;
}
/*
* Routine to stat a file given an fd
*/
int
SMBC_fstat_ctx ( SMBCCTX * context ,
SMBCFILE * file ,
struct stat * st )
{
struct timespec change_time_ts ;
struct timespec access_time_ts ;
struct timespec write_time_ts ;
2012-04-05 08:53:08 +04:00
off_t size ;
2015-05-10 02:59:45 +03:00
uint16_t mode ;
2008-02-28 19:23:20 +03:00
char * server = NULL ;
char * share = NULL ;
char * user = NULL ;
char * password = NULL ;
char * path = NULL ;
char * targetpath = NULL ;
struct cli_state * targetcli = NULL ;
SMB_INO_T ino = 0 ;
2013-04-16 23:09:41 +04:00
uint16_t port = 0 ;
2008-02-28 19:23:20 +03:00
TALLOC_CTX * frame = talloc_stackframe ( ) ;
2011-07-03 22:53:55 +04:00
NTSTATUS status ;
2009-11-22 00:52:12 +03:00
2008-02-29 21:34:35 +03:00
if ( ! context | | ! context - > internal - > initialized ) {
2008-02-28 19:23:20 +03:00
errno = EINVAL ;
TALLOC_FREE ( frame ) ;
return - 1 ;
}
2009-11-22 00:52:12 +03:00
2008-02-29 21:34:35 +03:00
if ( ! file | | ! SMBC_dlist_contains ( context - > internal - > files , file ) ) {
2008-02-28 19:23:20 +03:00
errno = EBADF ;
TALLOC_FREE ( frame ) ;
return - 1 ;
}
2009-11-22 00:52:12 +03:00
2008-02-28 19:23:20 +03:00
if ( ! file - > file ) {
TALLOC_FREE ( frame ) ;
2008-03-04 02:13:33 +03:00
return smbc_getFunctionFstatdir ( context ) ( context , file , st ) ;
2008-02-28 19:23:20 +03:00
}
2009-11-22 00:52:12 +03:00
2008-02-28 19:23:20 +03:00
/*d_printf(">>>fstat: parsing %s\n", file->fname);*/
if ( SMBC_parse_path ( frame ,
2008-03-02 04:44:21 +03:00
context ,
file - > fname ,
NULL ,
& server ,
2013-04-16 23:09:41 +04:00
& port ,
2008-03-02 04:44:21 +03:00
& share ,
& path ,
& user ,
& password ,
NULL ) ) {
2008-02-28 19:23:20 +03:00
errno = EINVAL ;
TALLOC_FREE ( frame ) ;
return - 1 ;
}
2009-11-22 00:52:12 +03:00
2008-02-28 19:23:20 +03:00
/*d_printf(">>>fstat: resolving %s\n", path);*/
2011-07-03 22:53:55 +04:00
status = cli_resolve_path ( frame , " " , context - > internal - > auth_info ,
file - > srv - > cli , path ,
& targetcli , & targetpath ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
2008-02-28 19:23:20 +03:00
d_printf ( " Could not resolve %s \n " , path ) ;
2009-03-28 01:02:46 +03:00
errno = ENOENT ;
2008-02-28 19:23:20 +03:00
TALLOC_FREE ( frame ) ;
return - 1 ;
}
/*d_printf(">>>fstat: resolved path as %s\n", targetpath);*/
2009-11-22 00:52:12 +03:00
2010-10-24 00:37:16 +04:00
if ( ! NT_STATUS_IS_OK ( cli_qfileinfo_basic (
targetcli , file - > cli_fd , & mode , & size ,
NULL ,
& access_time_ts ,
& write_time_ts ,
& change_time_ts ,
& ino ) ) ) {
2008-02-28 19:23:20 +03:00
time_t change_time , access_time , write_time ;
2009-11-22 00:52:12 +03:00
2009-05-06 03:28:44 +04:00
if ( ! NT_STATUS_IS_OK ( cli_getattrE ( targetcli , file - > cli_fd , & mode , & size ,
& change_time , & access_time , & write_time ) ) ) {
2008-02-28 19:23:20 +03:00
errno = EINVAL ;
TALLOC_FREE ( frame ) ;
return - 1 ;
}
change_time_ts = convert_time_t_to_timespec ( change_time ) ;
access_time_ts = convert_time_t_to_timespec ( access_time ) ;
write_time_ts = convert_time_t_to_timespec ( write_time ) ;
}
2009-11-22 00:52:12 +03:00
2008-02-28 19:23:20 +03:00
st - > st_ino = ino ;
2009-11-22 00:52:12 +03:00
2008-02-28 19:23:20 +03:00
setup_stat ( context , st , file - > fname , size , mode ) ;
2009-11-22 00:52:12 +03:00
2009-05-14 17:34:42 +04:00
st - > st_atime = convert_timespec_to_time_t ( access_time_ts ) ;
st - > st_ctime = convert_timespec_to_time_t ( change_time_ts ) ;
st - > st_mtime = convert_timespec_to_time_t ( write_time_ts ) ;
2008-02-28 19:23:20 +03:00
st - > st_dev = file - > srv - > dev ;
2009-11-22 00:52:12 +03:00
2008-02-28 19:23:20 +03:00
TALLOC_FREE ( frame ) ;
return 0 ;
}
2009-02-12 18:39:17 +03:00
/*
* Routine to obtain file system information given a path
*/
int
SMBC_statvfs_ctx ( SMBCCTX * context ,
char * path ,
2009-02-14 00:47:54 +03:00
struct statvfs * st )
2009-02-12 18:39:17 +03:00
{
int ret ;
bool bIsDir ;
struct stat statbuf ;
SMBCFILE * pFile ;
2015-03-26 20:09:46 +03:00
TALLOC_CTX * frame = talloc_stackframe ( ) ;
2009-02-12 18:39:17 +03:00
/* Determine if the provided path is a file or a folder */
if ( SMBC_stat_ctx ( context , path , & statbuf ) < 0 ) {
2015-03-26 20:09:46 +03:00
TALLOC_FREE ( frame ) ;
2009-02-12 18:39:17 +03:00
return - 1 ;
}
/* Is it a file or a directory? */
if ( S_ISDIR ( statbuf . st_mode ) ) {
/* It's a directory. */
2009-02-14 17:41:55 +03:00
if ( ( pFile = SMBC_opendir_ctx ( context , path ) ) = = NULL ) {
2015-03-26 20:09:46 +03:00
TALLOC_FREE ( frame ) ;
2009-02-12 18:39:17 +03:00
return - 1 ;
}
bIsDir = true ;
} else if ( S_ISREG ( statbuf . st_mode ) ) {
/* It's a file. */
2009-02-14 17:41:55 +03:00
if ( ( pFile = SMBC_open_ctx ( context , path ,
O_RDONLY , 0 ) ) = = NULL ) {
2015-03-26 20:09:46 +03:00
TALLOC_FREE ( frame ) ;
2009-02-12 18:39:17 +03:00
return - 1 ;
}
bIsDir = false ;
} else {
/* It's neither a file nor a directory. Not supported. */
2015-03-26 20:09:46 +03:00
TALLOC_FREE ( frame ) ;
2009-02-12 18:39:17 +03:00
errno = ENOSYS ;
return - 1 ;
}
/* Now we have an open file handle, so just use SMBC_fstatvfs */
ret = SMBC_fstatvfs_ctx ( context , pFile , st ) ;
/* Close the file or directory */
if ( bIsDir ) {
SMBC_closedir_ctx ( context , pFile ) ;
} else {
SMBC_close_ctx ( context , pFile ) ;
}
2015-03-26 20:09:46 +03:00
TALLOC_FREE ( frame ) ;
2009-02-12 18:39:17 +03:00
return ret ;
}
/*
* Routine to obtain file system information given an fd
*/
int
SMBC_fstatvfs_ctx ( SMBCCTX * context ,
SMBCFILE * file ,
2009-02-14 00:47:54 +03:00
struct statvfs * st )
2009-02-12 18:39:17 +03:00
{
2009-02-15 00:00:51 +03:00
unsigned long flags = 0 ;
2015-05-10 02:59:45 +03:00
uint32_t fs_attrs = 0 ;
2009-02-12 18:39:17 +03:00
struct cli_state * cli = file - > srv - > cli ;
2013-09-27 07:44:33 +04:00
struct smbXcli_tcon * tcon ;
2015-03-26 20:09:46 +03:00
TALLOC_CTX * frame = talloc_stackframe ( ) ;
2013-09-27 07:44:33 +04:00
if ( smbXcli_conn_protocol ( cli - > conn ) > = PROTOCOL_SMB2_02 ) {
tcon = cli - > smb2 . tcon ;
} else {
tcon = cli - > smb1 . tcon ;
}
2009-02-12 18:39:17 +03:00
/* Initialize all fields (at least until we actually use them) */
memset ( st , 0 , sizeof ( * st ) ) ;
/*
* The state of each flag is such that the same bits are unset as
* would typically be unset on a local file system on a POSIX OS . Thus
* the bit is on , for example , only for case - insensitive file systems
* since most POSIX file systems are case sensitive and fstatvfs ( )
* would typically return zero in these bits on such a local file
* system .
*/
/* See if the server has UNIX CIFS support */
if ( ! SERVER_HAS_UNIX_CIFS ( cli ) ) {
uint64_t total_allocation_units ;
uint64_t caller_allocation_units ;
uint64_t actual_allocation_units ;
uint64_t sectors_per_allocation_unit ;
uint64_t bytes_per_sector ;
2010-11-04 21:23:06 +03:00
NTSTATUS status ;
2009-11-22 00:52:12 +03:00
2009-02-12 18:39:17 +03:00
/* Nope. If size data is available... */
2010-11-04 21:23:06 +03:00
status = cli_get_fs_full_size_info ( cli ,
& total_allocation_units ,
& caller_allocation_units ,
& actual_allocation_units ,
& sectors_per_allocation_unit ,
& bytes_per_sector ) ;
if ( NT_STATUS_IS_OK ( status ) ) {
2009-02-12 18:39:17 +03:00
/* ... then provide it */
st - > f_bsize =
( unsigned long ) bytes_per_sector ;
2009-02-14 20:30:23 +03:00
# if HAVE_FRSIZE
2009-02-12 18:39:17 +03:00
st - > f_frsize =
( unsigned long ) sectors_per_allocation_unit ;
2009-02-14 20:30:23 +03:00
# endif
2009-02-12 18:39:17 +03:00
st - > f_blocks =
( fsblkcnt_t ) total_allocation_units ;
st - > f_bfree =
( fsblkcnt_t ) actual_allocation_units ;
}
2009-02-15 00:00:51 +03:00
flags | = SMBC_VFS_FEATURE_NO_UNIXCIFS ;
2009-02-12 18:39:17 +03:00
} else {
2015-05-10 02:59:45 +03:00
uint32_t optimal_transfer_size ;
uint32_t block_size ;
2009-02-12 18:39:17 +03:00
uint64_t total_blocks ;
uint64_t blocks_available ;
uint64_t user_blocks_available ;
uint64_t total_file_nodes ;
uint64_t free_file_nodes ;
uint64_t fs_identifier ;
2010-11-11 18:29:33 +03:00
NTSTATUS status ;
2009-02-12 18:39:17 +03:00
/* Has UNIXCIFS. If POSIX filesystem info is available... */
2010-11-11 18:29:33 +03:00
status = cli_get_posix_fs_info ( cli ,
& optimal_transfer_size ,
& block_size ,
& total_blocks ,
& blocks_available ,
& user_blocks_available ,
& total_file_nodes ,
& free_file_nodes ,
& fs_identifier ) ;
if ( NT_STATUS_IS_OK ( status ) ) {
2009-02-12 18:39:17 +03:00
/* ... then what's provided here takes precedence. */
st - > f_bsize =
( unsigned long ) block_size ;
st - > f_blocks =
( fsblkcnt_t ) total_blocks ;
st - > f_bfree =
( fsblkcnt_t ) blocks_available ;
st - > f_bavail =
( fsblkcnt_t ) user_blocks_available ;
st - > f_files =
( fsfilcnt_t ) total_file_nodes ;
st - > f_ffree =
( fsfilcnt_t ) free_file_nodes ;
2009-02-14 20:27:40 +03:00
# if HAVE_FSID_INT
2009-02-12 18:39:17 +03:00
st - > f_fsid =
( unsigned long ) fs_identifier ;
2009-02-14 20:27:40 +03:00
# endif
2009-02-12 18:39:17 +03:00
}
}
/* See if the share is case sensitive */
2009-11-21 15:46:52 +03:00
if ( ! NT_STATUS_IS_OK ( cli_get_fs_attr_info ( cli , & fs_attrs ) ) ) {
2009-02-12 18:39:17 +03:00
/*
* We can ' t determine the case sensitivity of
* the share . We have no choice but to use the
* user - specified case sensitivity setting .
*/
if ( ! smbc_getOptionCaseSensitive ( context ) ) {
2009-02-15 00:00:51 +03:00
flags | = SMBC_VFS_FEATURE_CASE_INSENSITIVE ;
2009-02-12 18:39:17 +03:00
}
} else {
if ( ! ( fs_attrs & FILE_CASE_SENSITIVE_SEARCH ) ) {
2009-02-15 00:00:51 +03:00
flags | = SMBC_VFS_FEATURE_CASE_INSENSITIVE ;
2009-02-12 18:39:17 +03:00
}
}
/* See if DFS is supported */
2013-09-27 07:44:33 +04:00
if ( smbXcli_conn_dfs_supported ( cli - > conn ) & &
smbXcli_tcon_is_dfs_share ( tcon ) )
{
2009-02-15 00:00:51 +03:00
flags | = SMBC_VFS_FEATURE_DFS ;
2009-02-12 18:39:17 +03:00
}
2009-02-15 00:00:51 +03:00
# if HAVE_STATVFS_F_FLAG
st - > f_flag = flags ;
# elif HAVE_STATVFS_F_FLAGS
st - > f_flags = flags ;
# endif
2015-03-26 20:09:46 +03:00
TALLOC_FREE ( frame ) ;
2009-02-12 18:39:17 +03:00
return 0 ;
}