From: Derrell Lipman Date: Thu, 12 Feb 2009 15:39:17 +0000 (-0500) Subject: [Bug 6069] Add a fstatvfs function for libsmbclient X-Git-Tag: samba-4.0.0alpha7~309 X-Git-Url: http://git.samba.org/?p=samba.git;a=commitdiff_plain;h=ae259575c447e61665c8e7070c476914161b953f [Bug 6069] Add a fstatvfs function for libsmbclient - port functionality from v3_3_test to master Derrell --- diff --git a/examples/libsmbclient/Makefile b/examples/libsmbclient/Makefile index 047addc8f7a..728dbe0edbc 100644 --- a/examples/libsmbclient/Makefile +++ b/examples/libsmbclient/Makefile @@ -24,6 +24,8 @@ TESTS= testsmbc \ teststat \ teststat2 \ teststat3 \ + teststatvfs \ + testfstatvfs \ testtruncate \ testchmod \ testutime \ @@ -74,6 +76,14 @@ teststat3: teststat3.o @echo Linking teststat3 $(CC) $(CFLAGS) $(LDFLAGS) -o $@ $< $(LIBSMBCLIENT) -lpopt +teststatvfs: teststatvfs.o + @echo Linking teststatvfs + $(CC) $(CFLAGS) $(LDFLAGS) -o $@ $< $(LIBSMBCLIENT) -lpopt + +testfstatvfs: testfstatvfs.o + @echo Linking testfstatvfs + $(CC) $(CFLAGS) $(LDFLAGS) -o $@ $< $(LIBSMBCLIENT) -lpopt + testtruncate: testtruncate.o @echo Linking testtruncate $(CC) $(CFLAGS) $(LDFLAGS) -o $@ $< $(LIBSMBCLIENT) -lpopt diff --git a/examples/libsmbclient/testfstatvfs.c b/examples/libsmbclient/testfstatvfs.c new file mode 100644 index 00000000000..b4dafefff60 --- /dev/null +++ b/examples/libsmbclient/testfstatvfs.c @@ -0,0 +1,122 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include "get_auth_data_fn.h" + + +int main(int argc, char * argv[]) +{ + int i; + int fd; + int ret; + int debug = 0; + char * p; + char path[2048]; + struct stat statbuf; + struct statvfs statvfsbuf; + + smbc_init(get_auth_data_fn, debug); + + for (;;) + { + fprintf(stdout, "Path: "); + *path = '\0'; + fgets(path, sizeof(path) - 1, stdin); + if (strlen(path) == 0) + { + return 0; + } + + p = path + strlen(path) - 1; + if (*p == '\n') + { + *p = '\0'; + } + + /* Determine if it's a file or a folder */ + if (smbc_stat(path, &statbuf) < 0) + { + perror("smbc_stat"); + continue; + } + + if (S_ISREG(statbuf.st_mode)) + { + if ((fd = smbc_open(path, O_RDONLY, 0)) < 0) + { + perror("smbc_open"); + continue; + } + } + else + { + if ((fd = smbc_opendir(path)) < 0) + { + perror("smbc_opendir"); + continue; + } + } + + ret = smbc_fstatvfs(fd, &statvfsbuf); + + smbc_close(fd); + + if (ret < 0) + { + perror("fstatvfs"); + } + else + { + 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) + { + printf("NO_UNIXCIFS "); + } + else + { + printf("unixcifs "); + } + + if (statvfsbuf.f_flag & SMBC_VFS_FEATURE_CASE_INSENSITIVE) + { + printf("CASE_INSENSITIVE "); + } + else + { + printf("case_sensitive "); + } + + if (statvfsbuf.f_flag & SMBC_VFS_FEATURE_DFS) + { + printf("DFS "); + } + else + { + printf("no_dfs "); + } + + printf("\n"); + } + } + + return 0; +} diff --git a/examples/libsmbclient/teststatvfs.c b/examples/libsmbclient/teststatvfs.c new file mode 100644 index 00000000000..8812002d5ce --- /dev/null +++ b/examples/libsmbclient/teststatvfs.c @@ -0,0 +1,96 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include "get_auth_data_fn.h" + + +int main(int argc, char * argv[]) +{ + int i; + int fd; + int ret; + int debug = 0; + char * p; + char path[2048]; + struct stat statbuf; + struct statvfs statvfsbuf; + + smbc_init(get_auth_data_fn, debug); + + for (;;) + { + fprintf(stdout, "Path: "); + *path = '\0'; + fgets(path, sizeof(path) - 1, stdin); + if (strlen(path) == 0) + { + return 0; + } + + p = path + strlen(path) - 1; + if (*p == '\n') + { + *p = '\0'; + } + + ret = smbc_statvfs(path, &statvfsbuf); + + if (ret < 0) + { + perror("fstatvfs"); + } + else + { + 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) + { + printf("NO_UNIXCIFS "); + } + else + { + printf("unixcifs "); + } + + if (statvfsbuf.f_flag & SMBC_VFS_FEATURE_CASE_INSENSITIVE) + { + printf("CASE_INSENSITIVE "); + } + else + { + printf("case_sensitive "); + } + + if (statvfsbuf.f_flag & SMBC_VFS_FEATURE_DFS) + { + printf("DFS "); + } + else + { + printf("no_dfs "); + } + + printf("\n"); + } + } + + return 0; +} diff --git a/source3/include/includes.h b/source3/include/includes.h index fc77534402a..2c033e8b69a 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 67add074bfc..166685c3801 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 b2d9483a0b9..d35d9de6eaf 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 #include +#include #include #include @@ -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); @@ -1591,6 +1620,52 @@ int smbc_stat(const char *url, struct stat *st); 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 * diff --git a/source3/include/proto.h b/source3/include/proto.h index 3478ea4f854..1b17e0246a9 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 77290d2df9b..e0ae948aaf4 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 ad8fd922db2..56d113f31a2 100644 --- a/source3/libsmb/libsmb_compat.c +++ b/source3/libsmb/libsmb_compat.c @@ -329,6 +329,21 @@ smbc_fstat(int fd, return smbc_getFunctionFstat(statcont)(statcont, file, st); } +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 c2c33e53025..c1af48507c8 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 9de49a5b3f6..3493e4f8dd2 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 27546f687ed..d589f7ef712 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; +}