summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDerrell Lipman <derrell.lipman@unwireduniverse.com>2009-02-10 15:03:32 -0500
committerKarolin Seeger <kseeger@samba.org>2009-02-16 09:56:59 +0100
commit1fcd47ba4efe3cfa48bc709077ac8974287321f8 (patch)
treec6807673787da92b71f9d6501be55a44793808b4
parent5ced5122517319e56e1bff1c8dd453edbf5287fd (diff)
downloadsamba-1fcd47ba4efe3cfa48bc709077ac8974287321f8.tar.gz
[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)
-rw-r--r--examples/libsmbclient/testfstatvfs.c15
-rw-r--r--source/include/includes.h2
-rw-r--r--source/include/proto.h15
-rw-r--r--source/libsmb/clifsinfo.c145
-rw-r--r--source/libsmb/libsmb_stat.c64
5 files changed, 240 insertions, 1 deletions
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,
+ &sectors_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 */