From 1fcd47ba4efe3cfa48bc709077ac8974287321f8 Mon Sep 17 00:00:00 2001 From: Derrell Lipman Date: Tue, 10 Feb 2009 15:03:32 -0500 Subject: [PATCH] [Bug 6069] Add a fstatvfs function for libsmbclient - Fill in the remainder of the data (or at least as much as we can get) for the fstatvfs return value. Derrell (cherry picked from commit eeeceea8b92b8b814209f496a7ab953dcd0a8367) --- examples/libsmbclient/testfstatvfs.c | 15 +++- source/include/includes.h | 2 + source/include/proto.h | 15 ++++ source/libsmb/clifsinfo.c | 145 +++++++++++++++++++++++++++++++++++ source/libsmb/libsmb_stat.c | 64 ++++++++++++++++ 5 files changed, 240 insertions(+), 1 deletion(-) diff --git a/examples/libsmbclient/testfstatvfs.c b/examples/libsmbclient/testfstatvfs.c index fbb51f14814..f8a6870a921 100644 --- a/examples/libsmbclient/testfstatvfs.c +++ b/examples/libsmbclient/testfstatvfs.c @@ -72,7 +72,20 @@ int main(int argc, char * argv[]) } else { - printf("Features: "); + printf("\n"); + printf("Block Size: %lu\n", statvfsbuf.f_bsize); + printf("Fragment Size: %lu\n", statvfsbuf.f_frsize); + printf("Blocks: %llu\n", statvfsbuf.f_blocks); + printf("Free Blocks: %llu\n", statvfsbuf.f_bfree); + printf("Available Blocks: %llu\n", statvfsbuf.f_bavail); + printf("Files : %llu\n", statvfsbuf.f_files); + printf("Free Files: %llu\n", statvfsbuf.f_ffree); + printf("Available Files: %llu\n", statvfsbuf.f_favail); + printf("File System ID: %lu\n", statvfsbuf.f_fsid); + printf("\n"); + + printf("Flags: 0x%lx\n", statvfsbuf.f_flag); + printf("Extended Features: "); if (statvfsbuf.f_flag & SMBC_VFS_FEATURE_NO_UNIXCIFS) { diff --git a/source/include/includes.h b/source/include/includes.h index d1301711c26..65b42429e2b 100644 --- a/source/include/includes.h +++ b/source/include/includes.h @@ -470,10 +470,12 @@ typedef int VOLATILE SIG_ATOMIC_T; #define SMB_BIG_UINT unsigned long long #define SMB_BIG_INT long long #define SBIG_UINT(p, ofs, v) (SIVAL(p,ofs,(v)&0xFFFFFFFF), SIVAL(p,(ofs)+4,(v)>>32)) +#define BIG_UINT(p, ofs) ((((SMB_BIG_UINT) IVAL(p,(ofs)+4))<<32)|IVAL(p,ofs)) #else #define SMB_BIG_UINT unsigned long #define SMB_BIG_INT long #define SBIG_UINT(p, ofs, v) (SIVAL(p,ofs,v),SIVAL(p,(ofs)+4,0)) +#define BIG_UINT(p, ofs) (IVAL(p,ofs)) #endif #define SMB_BIG_UINT_BITS (sizeof(SMB_BIG_UINT)*8) diff --git a/source/include/proto.h b/source/include/proto.h index 226f7be30a7..04ceb83db45 100644 --- a/source/include/proto.h +++ b/source/include/proto.h @@ -4333,6 +4333,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, + SMB_BIG_UINT *total_allocation_units, + SMB_BIG_UINT *caller_allocation_units, + SMB_BIG_UINT *actual_allocation_units, + SMB_BIG_UINT *sectors_per_allocation_unit, + SMB_BIG_UINT *bytes_per_sector); +bool cli_get_posix_fs_info(struct cli_state *cli, + uint32 *optimal_transfer_size, + uint32 *block_size, + SMB_BIG_UINT *total_blocks, + SMB_BIG_UINT *blocks_available, + SMB_BIG_UINT *user_blocks_available, + SMB_BIG_UINT *total_file_nodes, + SMB_BIG_UINT *free_file_nodes, + SMB_BIG_UINT *fs_identifier); NTSTATUS cli_raw_ntlm_smb_encryption_start(struct cli_state *cli, const char *user, const char *pass, diff --git a/source/libsmb/clifsinfo.c b/source/libsmb/clifsinfo.c index 5e73b61cd20..dd56f30d2d0 100644 --- a/source/libsmb/clifsinfo.c +++ b/source/libsmb/clifsinfo.c @@ -303,6 +303,151 @@ cleanup: return ret; } +bool cli_get_fs_full_size_info(struct cli_state *cli, + SMB_BIG_UINT *total_allocation_units, + SMB_BIG_UINT *caller_allocation_units, + SMB_BIG_UINT *actual_allocation_units, + SMB_BIG_UINT *sectors_per_allocation_unit, + SMB_BIG_UINT *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, + SMB_BIG_UINT *total_blocks, + SMB_BIG_UINT *blocks_available, + SMB_BIG_UINT *user_blocks_available, + SMB_BIG_UINT *total_file_nodes, + SMB_BIG_UINT *free_file_nodes, + SMB_BIG_UINT *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/source/libsmb/libsmb_stat.c b/source/libsmb/libsmb_stat.c index e5eac59da66..02088c368bb 100644 --- a/source/libsmb/libsmb_stat.c +++ b/source/libsmb/libsmb_stat.c @@ -312,6 +312,7 @@ SMBC_fstatvfs_ctx(SMBCCTX *context, { 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)); @@ -327,7 +328,70 @@ SMBC_fstatvfs_ctx(SMBCCTX *context, /* See if the server has UNIX CIFS support */ if (! SERVER_HAS_UNIX_CIFS(cli)) { + SMB_BIG_UINT total_allocation_units; + SMB_BIG_UINT caller_allocation_units; + SMB_BIG_UINT actual_allocation_units; + SMB_BIG_UINT sectors_per_allocation_unit; + SMB_BIG_UINT 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; + SMB_BIG_UINT total_blocks; + SMB_BIG_UINT blocks_available; + SMB_BIG_UINT user_blocks_available; + SMB_BIG_UINT total_file_nodes; + SMB_BIG_UINT free_file_nodes; + SMB_BIG_UINT 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 */ -- 2.11.4.GIT