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"
2020-08-05 03:49:42 +03:00
# include "lib/util/time.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
*/
2019-10-18 19:24:38 +03:00
static ino_t generate_inode ( const char * name )
2008-02-28 19:23:20 +03:00
{
2019-10-18 19:24:38 +03:00
if ( name = = NULL ) {
return ( ino_t ) - 1 ;
2008-02-28 19:23:20 +03:00
}
return ( ino_t ) str_checksum ( name ) ;
}
/*
* Routine to put basic stat info into a stat structure . . . Used by stat and
* fstat below .
*/
2019-10-18 19:24:38 +03:00
void setup_stat ( struct stat * st ,
const char * fname ,
off_t size ,
2020-06-03 22:46:26 +03:00
int attr ,
2019-10-18 20:48:55 +03:00
ino_t ino ,
dev_t dev ,
struct timespec access_time_ts ,
struct timespec change_time_ts ,
struct timespec write_time_ts )
2008-02-28 19:23:20 +03:00
{
st - > st_mode = 0 ;
2009-11-22 00:52:12 +03:00
2020-06-03 22:46:26 +03:00
if ( IS_DOS_DIR ( attr ) ) {
2008-02-28 19:23:20 +03:00
st - > st_mode = SMBC_DIR_MODE ;
} else {
st - > st_mode = SMBC_FILE_MODE ;
}
2009-11-22 00:52:12 +03:00
2020-06-03 22:46:26 +03:00
if ( IS_DOS_ARCHIVE ( attr ) ) {
2019-10-18 19:24:38 +03:00
st - > st_mode | = S_IXUSR ;
}
2020-06-03 22:46:26 +03:00
if ( IS_DOS_SYSTEM ( attr ) ) {
2019-10-18 19:24:38 +03:00
st - > st_mode | = S_IXGRP ;
}
2020-06-03 22:46:26 +03:00
if ( IS_DOS_HIDDEN ( attr ) ) {
2019-10-18 19:24:38 +03:00
st - > st_mode | = S_IXOTH ;
}
2020-06-03 22:46:26 +03:00
if ( ! IS_DOS_READONLY ( attr ) ) {
2019-10-18 19:24:38 +03:00
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
2020-06-03 22:46:26 +03:00
if ( IS_DOS_DIR ( attr ) ) {
2008-02-28 19:23:20 +03:00
st - > st_nlink = 2 ;
} else {
st - > st_nlink = 1 ;
}
2009-11-22 00:52:12 +03:00
2019-10-18 19:34:02 +03:00
if ( ino ! = 0 ) {
st - > st_ino = ino ;
} else {
2019-10-18 19:24:38 +03:00
st - > st_ino = generate_inode ( fname ) ;
2008-02-28 19:23:20 +03:00
}
2019-10-18 20:48:55 +03:00
st - > st_dev = dev ;
2020-08-05 03:49:42 +03:00
st - > st_atime = access_time_ts . tv_sec ;
set_atimensec ( st , access_time_ts . tv_nsec ) ;
st - > st_ctime = change_time_ts . tv_sec ;
set_ctimensec ( st , change_time_ts . tv_nsec ) ;
st - > st_mtime = write_time_ts . tv_sec ;
set_mtimensec ( st , write_time_ts . tv_nsec ) ;
2008-02-28 19:23:20 +03:00
}
2019-11-25 13:10:49 +03:00
void setup_stat_from_stat_ex ( const struct stat_ex * stex ,
const char * fname ,
struct stat * st )
{
2020-08-05 03:49:42 +03:00
st - > st_atime = stex - > st_ex_atime . tv_sec ;
set_atimensec ( st , stex - > st_ex_atime . tv_nsec ) ;
st - > st_ctime = stex - > st_ex_ctime . tv_sec ;
set_ctimensec ( st , stex - > st_ex_ctime . tv_nsec ) ;
st - > st_mtime = stex - > st_ex_mtime . tv_sec ;
set_mtimensec ( st , stex - > st_ex_mtime . tv_nsec ) ;
2019-11-25 13:10:49 +03:00
st - > st_mode = stex - > st_ex_mode ;
st - > st_size = stex - > st_ex_size ;
# ifdef HAVE_STAT_ST_BLKSIZE
st - > st_blksize = 512 ;
# endif
# ifdef HAVE_STAT_ST_BLOCKS
st - > st_blocks = ( st - > st_size + 511 ) / 512 ;
# endif
# ifdef HAVE_STRUCT_STAT_ST_RDEV
st - > st_rdev = 0 ;
# endif
st - > st_uid = stex - > st_ex_uid ;
st - > st_gid = stex - > st_ex_gid ;
st - > st_nlink = stex - > st_ex_nlink ;
if ( stex - > st_ex_ino = = 0 ) {
st - > st_ino = 0 ;
if ( fname ! = NULL ) {
st - > st_ino = generate_inode ( fname ) ;
}
} else {
st - > st_ino = stex - > st_ex_ino ;
}
st - > st_dev = stex - > st_ex_dev ;
}
2008-02-28 19:23:20 +03:00
/*
* 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 ;
2013-04-16 23:09:41 +04:00
uint16_t port = 0 ;
2022-01-21 23:15:06 +03:00
NTSTATUS status ;
2008-02-28 19:23:20 +03:00
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
2022-01-21 23:15:06 +03:00
status = SMBC_getatr ( context , srv , path , st ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
2008-02-28 19:23:20 +03:00
TALLOC_FREE ( frame ) ;
2022-01-21 23:15:06 +03:00
errno = cli_status_to_errno ( status ) ;
2008-02-28 19:23:20 +03:00
return - 1 ;
}
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 ;
2020-06-03 22:54:10 +03:00
uint32_t attr ;
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 ;
2020-08-18 18:42:25 +03:00
struct cli_credentials * creds = NULL ;
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
2020-02-22 00:35:44 +03:00
if ( ! 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
2021-01-13 18:11:17 +03:00
creds = context - > internal - > creds ;
2020-08-18 18:42:25 +03:00
2008-02-28 19:23:20 +03:00
/*d_printf(">>>fstat: resolving %s\n", path);*/
2020-08-18 18:42:25 +03:00
status = cli_resolve_path ( frame , " " ,
creds ,
2011-07-03 22:53:55 +04:00
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 (
2020-06-03 22:46:26 +03:00
targetcli , file - > cli_fd , & attr , & size ,
2010-10-24 00:37:16 +04:00
NULL ,
& access_time_ts ,
& write_time_ts ,
& change_time_ts ,
& ino ) ) ) {
2020-06-04 09:43:49 +03:00
errno = EINVAL ;
TALLOC_FREE ( frame ) ;
return - 1 ;
2008-02-28 19:23:20 +03:00
}
2009-11-22 00:52:12 +03:00
2019-10-18 20:48:55 +03:00
setup_stat ( st ,
2019-12-18 15:27:26 +03:00
path ,
2019-10-18 20:48:55 +03:00
size ,
2020-06-03 22:46:26 +03:00
attr ,
2019-10-18 20:48:55 +03:00
ino ,
file - > srv - > dev ,
access_time_ts ,
change_time_ts ,
write_time_ts ) ;
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) */
2020-10-18 23:43:24 +03:00
ZERO_STRUCTP ( st ) ;
2009-02-12 18:39:17 +03:00
/*
* 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 ;
2018-11-20 17:53:23 +03:00
# ifdef 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 ;
2017-06-08 19:20:46 +03:00
st - > f_bavail =
( fsblkcnt_t ) caller_allocation_units ;
2009-02-12 18:39:17 +03:00
}
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 ;
2018-11-20 17:53:23 +03:00
# ifdef 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
}
2018-11-20 17:53:23 +03:00
# if defined(HAVE_STATVFS_F_FLAG)
2009-02-15 00:00:51 +03:00
st - > f_flag = flags ;
2018-11-20 17:53:23 +03:00
# elif defined(HAVE_STATVFS_F_FLAGS)
2009-02-15 00:00:51 +03:00
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 ;
}