s3: Make SMB2_GETINFO multi-volume aware.
authorIra Cooper <ira@samba.org>
Wed, 6 Feb 2013 13:35:25 +0000 (13:35 +0000)
committerKarolin Seeger <kseeger@samba.org>
Tue, 12 Feb 2013 21:54:49 +0000 (22:54 +0100)
Not all shares are a single volume.  Some actually
expose multiple volumes under a single share.  In these
cases showing the amount of space free as the space free
at the base of the directory heirarchy is wrong.

Reviewed-by: Jeremy Allison <jra@samba.org>
Autobuild-User(master): Jeremy Allison <jra@samba.org>
Autobuild-Date(master): Fri Feb  8 21:44:37 CET 2013 on sn-devel-104

Fix bug #9646 - dir and similar commands are returning the wrong amount of free
space.

Autobuild-User(v4-0-test): Karolin Seeger <kseeger@samba.org>
Autobuild-Date(v4-0-test): Tue Feb 12 22:54:50 CET 2013 on sn-devel-104

source3/smbd/globals.h
source3/smbd/smb2_getinfo.c
source3/smbd/trans2.c

index 0d0ebcde09b7837fec547842c6a3692f6a256915..51f55bfafbc40484387d7d5eae9631dafc1a7539 100644 (file)
@@ -155,6 +155,7 @@ NTSTATUS smbd_do_qfsinfo(connection_struct *conn,
                         uint16_t info_level,
                         uint16_t flags2,
                         unsigned int max_data_bytes,
+                        struct smb_filename *smb_fname,
                         char **ppdata,
                         int *ret_data_len);
 
index 33cee9910c083fcd49cdcdb2da00be7be9d62167..5616c849ade6309ba156d28af6dc0811d790717d 100644 (file)
@@ -413,6 +413,7 @@ static struct tevent_req *smbd_smb2_getinfo_send(TALLOC_CTX *mem_ctx,
                                         file_info_level,
                                         STR_UNICODE,
                                         in_output_buffer_length,
+                                        fsp->fsp_name,
                                         &data,
                                         &data_size);
                if (!NT_STATUS_IS_OK(status)) {
index 27ff550f47e7736142a5752b5d26af3906c23e7c..6f3dc4e54c0945ee9d47a624a22691a9aa6abc0e 100644 (file)
@@ -3020,6 +3020,7 @@ NTSTATUS smbd_do_qfsinfo(connection_struct *conn,
                         uint16_t info_level,
                         uint16_t flags2,
                         unsigned int max_data_bytes,
+                        struct smb_filename *fname,
                         char **ppdata,
                         int *ret_data_len)
 {
@@ -3028,10 +3029,17 @@ NTSTATUS smbd_do_qfsinfo(connection_struct *conn,
        const char *vname = volume_label(talloc_tos(), SNUM(conn));
        int snum = SNUM(conn);
        char *fstype = lp_fstype(talloc_tos(), SNUM(conn));
+       char *filename = NULL;
        uint32 additional_flags = 0;
-       struct smb_filename smb_fname_dot;
+       struct smb_filename smb_fname;
        SMB_STRUCT_STAT st;
 
+       if (fname == NULL || fname->base_name == NULL) {
+               filename = ".";
+       } else {
+               filename = fname->base_name;
+       }
+
        if (IS_IPC(conn)) {
                if (info_level != SMB_QUERY_CIFS_UNIX_INFO) {
                        DEBUG(0,("smbd_do_qfsinfo: not an allowed "
@@ -3043,15 +3051,15 @@ NTSTATUS smbd_do_qfsinfo(connection_struct *conn,
 
        DEBUG(3,("smbd_do_qfsinfo: level = %d\n", info_level));
 
-       ZERO_STRUCT(smb_fname_dot);
-       smb_fname_dot.base_name = discard_const_p(char, ".");
+       ZERO_STRUCT(smb_fname);
+       smb_fname.base_name = discard_const_p(char, filename);
 
-       if(SMB_VFS_STAT(conn, &smb_fname_dot) != 0) {
+       if(SMB_VFS_STAT(conn, &smb_fname) != 0) {
                DEBUG(2,("stat of . failed (%s)\n", strerror(errno)));
                return map_nt_error_from_unix(errno);
        }
 
-       st = smb_fname_dot.st;
+       st = smb_fname.st;
 
        *ppdata = (char *)SMB_REALLOC(
                *ppdata, max_data_bytes + DIR_ENTRY_SAFETY_MARGIN);
@@ -3068,7 +3076,7 @@ NTSTATUS smbd_do_qfsinfo(connection_struct *conn,
                {
                        uint64_t dfree,dsize,bsize,block_size,sectors_per_unit,bytes_per_sector;
                        data_len = 18;
-                       if (get_dfree_info(conn,".",False,&bsize,&dfree,&dsize) == (uint64_t)-1) {
+                       if (get_dfree_info(conn,filename,False,&bsize,&dfree,&dsize) == (uint64_t)-1) {
                                return map_nt_error_from_unix(errno);
                        }
 
@@ -3192,7 +3200,7 @@ cBytesSector=%u, cUnitTotal=%u, cUnitAvail=%d\n", (unsigned int)st.st_ex_dev, (u
                {
                        uint64_t dfree,dsize,bsize,block_size,sectors_per_unit,bytes_per_sector;
                        data_len = 24;
-                       if (get_dfree_info(conn,".",False,&bsize,&dfree,&dsize) == (uint64_t)-1) {
+                       if (get_dfree_info(conn,filename,False,&bsize,&dfree,&dsize) == (uint64_t)-1) {
                                return map_nt_error_from_unix(errno);
                        }
                        block_size = lp_block_size(snum);
@@ -3224,7 +3232,7 @@ cBytesSector=%u, cUnitTotal=%u, cUnitAvail=%d\n", (unsigned int)bsize, (unsigned
                {
                        uint64_t dfree,dsize,bsize,block_size,sectors_per_unit,bytes_per_sector;
                        data_len = 32;
-                       if (get_dfree_info(conn,".",False,&bsize,&dfree,&dsize) == (uint64_t)-1) {
+                       if (get_dfree_info(conn,filename,False,&bsize,&dfree,&dsize) == (uint64_t)-1) {
                                return map_nt_error_from_unix(errno);
                        }
                        block_size = lp_block_size(snum);
@@ -3417,7 +3425,7 @@ cBytesSector=%u, cUnitTotal=%u, cUnitAvail=%d\n", (unsigned int)bsize, (unsigned
                                return NT_STATUS_INVALID_LEVEL;
                        }
 
-                       rc = SMB_VFS_STATVFS(conn, ".", &svfs);
+                       rc = SMB_VFS_STATVFS(conn, filename, &svfs);
 
                        if (!rc) {
                                data_len = 56;
@@ -3597,6 +3605,7 @@ static void call_trans2qfsinfo(connection_struct *conn,
                                 info_level,
                                 req->flags2,
                                 max_data_bytes,
+                                NULL,
                                 ppdata, &data_len);
        if (!NT_STATUS_IS_OK(status)) {
                reply_nterror(req, status);