summaryrefslogtreecommitdiff
path: root/source3/libsmb
diff options
context:
space:
mode:
authorDerrell Lipman <derrell.lipman@unwireduniverse.com>2009-02-12 10:39:17 -0500
committerDerrell Lipman <derrell.lipman@unwireduniverse.com>2009-02-12 10:39:48 -0500
commitae259575c447e61665c8e7070c476914161b953f (patch)
tree4193eb1193c1b3e7625cd01fda6f742d896635e1 /source3/libsmb
parent082ba6a1ad3a68aff118d96f855a2aa65eaeb359 (diff)
downloadsamba-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/libsmb')
-rw-r--r--source3/libsmb/clifsinfo.c145
-rw-r--r--source3/libsmb/libsmb_compat.c15
-rw-r--r--source3/libsmb/libsmb_context.c2
-rw-r--r--source3/libsmb/libsmb_setget.c24
-rw-r--r--source3/libsmb/libsmb_stat.c169
5 files changed, 355 insertions, 0 deletions
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,
+ &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;
+ 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;
+}