diff options
author | Derrell Lipman <derrell.lipman@unwireduniverse.com> | 2009-02-12 10:39:17 -0500 |
---|---|---|
committer | Derrell Lipman <derrell.lipman@unwireduniverse.com> | 2009-02-12 10:39:48 -0500 |
commit | ae259575c447e61665c8e7070c476914161b953f (patch) | |
tree | 4193eb1193c1b3e7625cd01fda6f742d896635e1 /source3 | |
parent | 082ba6a1ad3a68aff118d96f855a2aa65eaeb359 (diff) | |
download | samba-ae259575c447e61665c8e7070c476914161b953f.tar.gz samba-ae259575c447e61665c8e7070c476914161b953f.tar.bz2 samba-ae259575c447e61665c8e7070c476914161b953f.zip |
[Bug 6069] Add a fstatvfs function for libsmbclient
- port functionality from v3_3_test to master
Derrell
Diffstat (limited to 'source3')
-rw-r--r-- | source3/include/includes.h | 1 | ||||
-rw-r--r-- | source3/include/libsmb_internal.h | 14 | ||||
-rw-r--r-- | source3/include/libsmbclient.h | 75 | ||||
-rw-r--r-- | source3/include/proto.h | 15 | ||||
-rw-r--r-- | source3/libsmb/clifsinfo.c | 145 | ||||
-rw-r--r-- | source3/libsmb/libsmb_compat.c | 15 | ||||
-rw-r--r-- | source3/libsmb/libsmb_context.c | 2 | ||||
-rw-r--r-- | source3/libsmb/libsmb_setget.c | 24 | ||||
-rw-r--r-- | source3/libsmb/libsmb_stat.c | 169 |
9 files changed, 460 insertions, 0 deletions
diff --git a/source3/include/includes.h b/source3/include/includes.h index fc77534402..2c033e8b69 100644 --- a/source3/include/includes.h +++ b/source3/include/includes.h @@ -396,6 +396,7 @@ typedef sig_atomic_t volatile SIG_ATOMIC_T; #endif #define SBIG_UINT(p, ofs, v) (SIVAL(p,ofs,(v)&0xFFFFFFFF), SIVAL(p,(ofs)+4,(v)>>32)) +#define BIG_UINT(p, ofs) ((((uint64_t) IVAL(p,(ofs)+4))<<32)|IVAL(p,ofs)) #define IVAL2_TO_SMB_BIG_UINT(buf,off) ( (((uint64_t)(IVAL((buf),(off)))) & ((uint64_t)0xFFFFFFFF)) | \ (( ((uint64_t)(IVAL((buf),(off+4)))) & ((uint64_t)0xFFFFFFFF) ) << 32 ) ) diff --git a/source3/include/libsmb_internal.h b/source3/include/libsmb_internal.h index 67add074bf..166685c380 100644 --- a/source3/include/libsmb_internal.h +++ b/source3/include/libsmb_internal.h @@ -197,6 +197,8 @@ struct SMBC_internal_data { smbc_stat_fn stat_fn; smbc_fstat_fn fstat_fn; #endif + smbc_statvfs_fn statvfs_fn; + smbc_fstatvfs_fn fstatvfs_fn; smbc_ftruncate_fn ftruncate_fn; #if 0 /* Left in libsmbclient.h for backward compatibility */ smbc_close_fn close_fn; @@ -501,6 +503,18 @@ SMBC_fstat_ctx(SMBCCTX *context, struct stat *st); +int +SMBC_statvfs_ctx(SMBCCTX *context, + char *path, + struct statvfs *st); + + +int +SMBC_fstatvfs_ctx(SMBCCTX *context, + SMBCFILE *file, + struct statvfs *st); + + /* Functions in libsmb_xattr.c */ int SMBC_setxattr_ctx(SMBCCTX *context, diff --git a/source3/include/libsmbclient.h b/source3/include/libsmbclient.h index b2d9483a0b..d35d9de6ea 100644 --- a/source3/include/libsmbclient.h +++ b/source3/include/libsmbclient.h @@ -75,6 +75,7 @@ extern "C" { /* Make sure we have the following includes for now ... */ #include <sys/types.h> #include <sys/stat.h> +#include <sys/statvfs.h> #include <fcntl.h> #include <utime.h> @@ -174,6 +175,22 @@ typedef enum smbc_smb_encrypt_level } smbc_smb_encrypt_level; +/** + * Capabilities set in the f_flag field of struct statvfs, from + * smbc_statvfs(). These may be OR-ed together to reflect a full set of + * available capabilities. + */ +typedef enum smbc_vfs_feature +{ + /* Defined by POSIX or in Linux include files (low-order bits) */ + SMBC_VFS_FEATURE_RDONLY = (1 << 0), + + /* Specific to libsmbclient (high-order bits) */ + SMBC_VFS_FEATURE_DFS = (1 << 29), + SMBC_VFS_FEATURE_CASE_INSENSITIVE = (1 << 30), + SMBC_VFS_FEATURE_NO_UNIXCIFS = (1 << 31) +} smbc_vfs_feature; + typedef int smbc_bool; @@ -853,6 +870,18 @@ typedef int (*smbc_fstat_fn)(SMBCCTX *c, smbc_fstat_fn smbc_getFunctionFstat(SMBCCTX *c); void smbc_setFunctionFstat(SMBCCTX *c, smbc_fstat_fn fn); +typedef int (*smbc_statvfs_fn)(SMBCCTX *c, + char *path, + struct statvfs *st); +smbc_statvfs_fn smbc_getFunctionStatVFS(SMBCCTX *c); +void smbc_setFunctionStatVFS(SMBCCTX *c, smbc_statvfs_fn fn); + +typedef int (*smbc_fstatvfs_fn)(SMBCCTX *c, + SMBCFILE *file, + struct statvfs *st); +smbc_fstatvfs_fn smbc_getFunctionFstatVFS(SMBCCTX *c); +void smbc_setFunctionFstatVFS(SMBCCTX *c, smbc_fstatvfs_fn fn); + typedef int (*smbc_ftruncate_fn)(SMBCCTX *c, SMBCFILE *f, off_t size); @@ -1592,6 +1621,52 @@ int smbc_fstat(int fd, struct stat *st); /**@ingroup attribute + * Get file system information for a specified path. + * + * @param url The smb url to get information for + * + * @param st pointer to a buffer that will be filled with + * standard Unix struct statvfs information. + * + * @return EBADF filedes is bad. + * - EACCES Permission denied. + * - EBADF fd is not a valid file descriptor + * - EINVAL Problems occurred in the underlying routines + * or smbc_init not called. + * - ENOMEM Out of memory + * + * @see Unix fstatvfs() + * + */ +int +smbc_statvfs(char *url, + struct statvfs *st); + +/**@ingroup attribute + * Get file system information via an file descriptor. + * + * @param fd Open file handle from smbc_open(), smbc_creat(), + * or smbc_opendir() + * + * @param st pointer to a buffer that will be filled with + * standard Unix struct statvfs information. + * + * @return EBADF filedes is bad. + * - EACCES Permission denied. + * - EBADF fd is not a valid file descriptor + * - EINVAL Problems occurred in the underlying routines + * or smbc_init not called. + * - ENOMEM Out of memory + * + * @see Unix fstatvfs() + * + */ +int +smbc_fstatvfs(int fd, + struct statvfs *st); + + +/**@ingroup attribute * Truncate a file given a file descriptor * * @param fd Open file handle from smbc_open() or smbc_creat() diff --git a/source3/include/proto.h b/source3/include/proto.h index 3478ea4f85..1b17e0246a 100644 --- a/source3/include/proto.h +++ b/source3/include/proto.h @@ -2606,6 +2606,21 @@ bool cli_set_unix_extensions_capabilities(struct cli_state *cli, uint16 major, u bool cli_get_fs_attr_info(struct cli_state *cli, uint32 *fs_attr); bool cli_get_fs_volume_info_old(struct cli_state *cli, fstring volume_name, uint32 *pserial_number); bool cli_get_fs_volume_info(struct cli_state *cli, fstring volume_name, uint32 *pserial_number, time_t *pdate); +bool cli_get_fs_full_size_info(struct cli_state *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); +bool cli_get_posix_fs_info(struct cli_state *cli, + uint32 *optimal_transfer_size, + uint32 *block_size, + 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); NTSTATUS cli_raw_ntlm_smb_encryption_start(struct cli_state *cli, const char *user, const char *pass, diff --git a/source3/libsmb/clifsinfo.c b/source3/libsmb/clifsinfo.c index 77290d2df9..e0ae948aaf 100644 --- a/source3/libsmb/clifsinfo.c +++ b/source3/libsmb/clifsinfo.c @@ -305,6 +305,151 @@ cleanup: return ret; } +bool cli_get_fs_full_size_info(struct cli_state *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) +{ + bool ret = False; + uint16 setup; + char param[2]; + char *rparam=NULL, *rdata=NULL; + unsigned int rparam_count=0, rdata_count=0; + + setup = TRANSACT2_QFSINFO; + + SSVAL(param,0,SMB_FS_FULL_SIZE_INFORMATION); + + if (!cli_send_trans(cli, SMBtrans2, + NULL, + 0, 0, + &setup, 1, 0, + param, 2, 0, + NULL, 0, 560)) { + goto cleanup; + } + + if (!cli_receive_trans(cli, SMBtrans2, + &rparam, &rparam_count, + &rdata, &rdata_count)) { + goto cleanup; + } + + if (cli_is_error(cli)) { + ret = False; + goto cleanup; + } else { + ret = True; + } + + if (rdata_count != 32) { + goto cleanup; + } + + if (total_allocation_units) { + *total_allocation_units = BIG_UINT(rdata, 0); + } + if (caller_allocation_units) { + *caller_allocation_units = BIG_UINT(rdata,8); + } + if (actual_allocation_units) { + *actual_allocation_units = BIG_UINT(rdata,16); + } + if (sectors_per_allocation_unit) { + *sectors_per_allocation_unit = IVAL(rdata,24); + } + if (bytes_per_sector) { + *bytes_per_sector = IVAL(rdata,28); + } + +cleanup: + SAFE_FREE(rparam); + SAFE_FREE(rdata); + + return ret; +} + +bool cli_get_posix_fs_info(struct cli_state *cli, + uint32 *optimal_transfer_size, + uint32 *block_size, + 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) +{ + bool ret = False; + uint16 setup; + char param[2]; + char *rparam=NULL, *rdata=NULL; + unsigned int rparam_count=0, rdata_count=0; + + setup = TRANSACT2_QFSINFO; + + SSVAL(param,0,SMB_QUERY_POSIX_FS_INFO); + + if (!cli_send_trans(cli, SMBtrans2, + NULL, + 0, 0, + &setup, 1, 0, + param, 2, 0, + NULL, 0, 560)) { + goto cleanup; + } + + if (!cli_receive_trans(cli, SMBtrans2, + &rparam, &rparam_count, + &rdata, &rdata_count)) { + goto cleanup; + } + + if (cli_is_error(cli)) { + ret = False; + goto cleanup; + } else { + ret = True; + } + + if (rdata_count != 56) { + goto cleanup; + } + + if (optimal_transfer_size) { + *optimal_transfer_size = IVAL(rdata, 0); + } + if (block_size) { + *block_size = IVAL(rdata,4); + } + if (total_blocks) { + *total_blocks = BIG_UINT(rdata,8); + } + if (blocks_available) { + *blocks_available = BIG_UINT(rdata,16); + } + if (user_blocks_available) { + *user_blocks_available = BIG_UINT(rdata,24); + } + if (total_file_nodes) { + *total_file_nodes = BIG_UINT(rdata,32); + } + if (free_file_nodes) { + *free_file_nodes = BIG_UINT(rdata,40); + } + if (fs_identifier) { + *fs_identifier = BIG_UINT(rdata,48); + } + +cleanup: + SAFE_FREE(rparam); + SAFE_FREE(rdata); + + return ret; +} + + /****************************************************************************** Send/receive the request encryption blob. ******************************************************************************/ diff --git a/source3/libsmb/libsmb_compat.c b/source3/libsmb/libsmb_compat.c index ad8fd922db..56d113f31a 100644 --- a/source3/libsmb/libsmb_compat.c +++ b/source3/libsmb/libsmb_compat.c @@ -330,6 +330,21 @@ smbc_fstat(int fd, } int +smbc_statvfs(char *path, + struct statvfs *st) +{ + return smbc_getFunctionStatVFS(statcont)(statcont, path, st); +} + +int +smbc_fstatvfs(int fd, + struct statvfs *st) +{ + SMBCFILE * file = find_fd(fd); + return smbc_getFunctionFstatVFS(statcont)(statcont, file, st); +} + +int smbc_ftruncate(int fd, off_t size) { diff --git a/source3/libsmb/libsmb_context.c b/source3/libsmb/libsmb_context.c index c2c33e5302..c1af48507c 100644 --- a/source3/libsmb/libsmb_context.c +++ b/source3/libsmb/libsmb_context.c @@ -94,6 +94,8 @@ smbc_new_context(void) smbc_setFunctionLseek(context, SMBC_lseek_ctx); smbc_setFunctionFtruncate(context, SMBC_ftruncate_ctx); smbc_setFunctionStat(context, SMBC_stat_ctx); + smbc_setFunctionStatVFS(context, SMBC_statvfs_ctx); + smbc_setFunctionFstatVFS(context, SMBC_fstatvfs_ctx); smbc_setFunctionFstat(context, SMBC_fstat_ctx); smbc_setFunctionOpendir(context, SMBC_opendir_ctx); smbc_setFunctionClosedir(context, SMBC_closedir_ctx); diff --git a/source3/libsmb/libsmb_setget.c b/source3/libsmb/libsmb_setget.c index 9de49a5b3f..3493e4f8dd 100644 --- a/source3/libsmb/libsmb_setget.c +++ b/source3/libsmb/libsmb_setget.c @@ -659,6 +659,30 @@ smbc_setFunctionFstat(SMBCCTX *c, smbc_fstat_fn fn) c->fstat = fn; } +smbc_statvfs_fn +smbc_getFunctionStatVFS(SMBCCTX *c) +{ + return c->internal->posix_emu.statvfs_fn; +} + +void +smbc_setFunctionStatVFS(SMBCCTX *c, smbc_statvfs_fn fn) +{ + c->internal->posix_emu.statvfs_fn = fn; +} + +smbc_fstatvfs_fn +smbc_getFunctionFstatVFS(SMBCCTX *c) +{ + return c->internal->posix_emu.fstatvfs_fn; +} + +void +smbc_setFunctionFstatVFS(SMBCCTX *c, smbc_fstatvfs_fn fn) +{ + c->internal->posix_emu.fstatvfs_fn = fn; +} + smbc_ftruncate_fn smbc_getFunctionFtruncate(SMBCCTX *c) { diff --git a/source3/libsmb/libsmb_stat.c b/source3/libsmb/libsmb_stat.c index 27546f687e..d589f7ef71 100644 --- a/source3/libsmb/libsmb_stat.c +++ b/source3/libsmb/libsmb_stat.c @@ -300,3 +300,172 @@ SMBC_fstat_ctx(SMBCCTX *context, return 0; } + + +/* + * Routine to obtain file system information given a path + */ +int +SMBC_statvfs_ctx(SMBCCTX *context, + char *path, + struct statvfs *st) +{ + int ret; + bool bIsDir; + struct stat statbuf; + SMBCFILE * pFile; + + /* Determine if the provided path is a file or a folder */ + if (SMBC_stat_ctx(context, path, &statbuf) < 0) { + return -1; + } + + /* Is it a file or a directory? */ + if (S_ISDIR(statbuf.st_mode)) { + /* It's a directory. */ + if ((pFile = SMBC_opendir_ctx(context, path)) < 0) { + return -1; + } + bIsDir = true; + } else if (S_ISREG(statbuf.st_mode)) { + /* It's a file. */ + if ((pFile = SMBC_open_ctx(context, path, O_RDONLY, 0)) < 0) { + return -1; + } + bIsDir = false; + } else { + /* It's neither a file nor a directory. Not supported. */ + 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); + } + + return ret; +} + + +/* + * Routine to obtain file system information given an fd + */ + +int +SMBC_fstatvfs_ctx(SMBCCTX *context, + SMBCFILE *file, + struct statvfs *st) +{ + uint32 fs_attrs = 0; + struct cli_state *cli = file->srv->cli; + + + /* 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; + + /* Nope. If size data is available... */ + if (cli_get_fs_full_size_info(cli, + &total_allocation_units, + &caller_allocation_units, + &actual_allocation_units, + §ors_per_allocation_unit, + &bytes_per_sector)) { + + /* ... then provide it */ + st->f_bsize = + (unsigned long) bytes_per_sector; + st->f_frsize = + (unsigned long) sectors_per_allocation_unit; + st->f_blocks = + (fsblkcnt_t) total_allocation_units; + st->f_bfree = + (fsblkcnt_t) actual_allocation_units; + } + + st->f_flag |= SMBC_VFS_FEATURE_NO_UNIXCIFS; + } else { + uint32 optimal_transfer_size; + uint32 block_size; + 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; + + /* Has UNIXCIFS. If POSIX filesystem info is available... */ + if (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)) { + + /* ... 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; + st->f_fsid = + (unsigned long) fs_identifier; + + } + } + + /* See if the share is case sensitive */ + if (!cli_get_fs_attr_info(cli, &fs_attrs)) { + /* + * 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)) { + st->f_flag |= SMBC_VFS_FEATURE_CASE_INSENSITIVE; + } + } else { + if (! (fs_attrs & FILE_CASE_SENSITIVE_SEARCH)) { + st->f_flag |= SMBC_VFS_FEATURE_CASE_INSENSITIVE; + } + } + + /* See if DFS is supported */ + if ((cli->capabilities & CAP_DFS) && cli->dfsroot) { + st->f_flag |= SMBC_VFS_FEATURE_DFS; + } + + return 0; +} |