Fix bug #7410 - samba sends "raw" inode number as uniqueid with unix extensions.
authorJeremy Allison <jra@samba.org>
Thu, 20 May 2010 18:36:47 +0000 (11:36 -0700)
committerKarolin Seeger <kseeger@samba.org>
Fri, 18 Jun 2010 06:33:26 +0000 (08:33 +0200)
Move to a consistent get_FileIndex() function for all inode returns,
that checks if st_dev on the file is identical to the top directory
dev_t of the exported share, and if so uses the raw 64-bit inode
number. If it isn't (we've traversed a mount point) - return what
we used to do for Windows which is the concatination of the bottom
32-bits of the inode with the 32-bit device number. We can get more
creative with this over time (hashing?) if we want as now all inode returns go
through this single function.

Jeremy.
(cherry picked from commit 920ffe49290cacd30d9bc582c1c3fee38308c260)

source3/include/proto.h
source3/include/smb.h
source3/smbd/service.c
source3/smbd/smb2_create.c
source3/smbd/trans2.c

index f30939a8857ff9585c3bd07d6ae865386a07b947..04065b0c5a2151b6c023d9bb052df3aad7768203 100644 (file)
@@ -7050,6 +7050,7 @@ int sys_statvfs(const char *path, vfs_statvfs_struct *statbuf);
 /* The following definitions come from smbd/trans2.c  */
 
 uint64_t smb_roundup(connection_struct *conn, uint64_t val);
+uint64_t get_FileIndex(connection_struct *conn, const SMB_STRUCT_STAT *psbuf);
 NTSTATUS get_ea_value(TALLOC_CTX *mem_ctx, connection_struct *conn,
                      files_struct *fsp, const char *fname,
                      const char *ea_name, struct ea_struct *pea);
index bc7a90d5492911bcf418e894dbd81a24b35c69de..202f9d77db6ea03a22ea994d26acc483a231ea4a 100644 (file)
@@ -607,6 +607,9 @@ typedef struct connection_struct {
 
        /* Semantics provided by the underlying filesystem. */
        int fs_capabilities;
+       /* Device number of the directory of the share mount.
+          Used to ensure unique FileIndex returns. */
+       SMB_DEV_T base_share_dev;
 
        name_compare_entry *hide_list; /* Per-share list of files to return as hidden. */
        name_compare_entry *veto_list; /* Per-share list of files to veto (never show). */
index 25e0eb10f8e6dd77bc925e5643167f53f853db72..bc2cdaf2d8574078a9db6cf89d8003d1ffbd7f37 100644 (file)
@@ -1033,6 +1033,7 @@ connection_struct *make_connection_snum(struct smbd_server_connection *sconn,
                *pstatus = NT_STATUS_BAD_NETWORK_NAME;
                goto err_root_exit;
        }
+       conn->base_share_dev = smb_fname_cpath->st.st_ex_dev;
 
        string_set(&conn->origpath,conn->connectpath);
 
index 3cf8b185b08caba28deb622d369ef32fdd091a48..3e0d180bf349c87a5073c75979fb52903a16b6cd 100644 (file)
@@ -651,13 +651,18 @@ static struct tevent_req *smbd_smb2_create_send(TALLOC_CTX *mem_ctx,
 
                if (qfid) {
                        uint8_t p[32];
+                       uint64_t file_index = get_FileIndex(result->conn,
+                                                       &result->fsp_name->st);
                        DATA_BLOB blob = data_blob_const(p, sizeof(p));
 
                        ZERO_STRUCT(p);
 
-                       /* TODO: maybe use result->file_id */
-                       SIVAL(p, 0, result->fsp_name->st.st_ex_ino);/* FileIndexLow */
-                       SIVAL(p, 4, result->fsp_name->st.st_ex_dev);/* FileIndexHigh */
+                       /* From conversations with Microsoft engineers at
+                          the MS plugfest. The first 8 bytes are the "volume index"
+                          == inode, the second 8 bytes are the "volume id",
+                          == dev. This will be updated in the SMB2 doc. */
+                       SBVAL(p, 0, file_index);
+                       SIVAL(p, 8, result->fsp_name->st.st_ex_dev);/* FileIndexHigh */
 
                        status = smb2_create_blob_add(state, &out_context_blobs,
                                                      SMB2_CREATE_TAG_QFID,
index 963103c85b8f2b897fbbf79bee63dee9f2460e6f..fb4d46b76bf39c58eedaa433e4d7991de2d839d4 100644 (file)
@@ -57,6 +57,23 @@ uint64_t smb_roundup(connection_struct *conn, uint64_t val)
        return val;
 }
 
+/********************************************************************
+ Create a 64 bit FileIndex. If the file is on the same device as
+ the root of the share, just return the 64-bit inode. If it isn't,
+ mangle as we used to do.
+********************************************************************/
+
+uint64_t get_FileIndex(connection_struct *conn, const SMB_STRUCT_STAT *psbuf)
+{
+       uint64_t file_index;
+       if (conn->base_share_dev == psbuf->st_ex_dev) {
+               return (uint64_t)psbuf->st_ex_ino;
+       }
+       file_index = ((psbuf->st_ex_ino) & UINT32_MAX); /* FileIndexLow */
+       file_index |= ((uint64_t)((psbuf->st_ex_dev) & UINT32_MAX)) << 32; /* FileIndexHigh */
+       return file_index;
+}
+
 /****************************************************************************
  Utility functions for dealing with extended attributes.
 ****************************************************************************/
@@ -1474,6 +1491,7 @@ static bool smbd_marshall_dir_entry(TALLOC_CTX *ctx,
        uint32_t reskey=0;
        uint64_t file_size = 0;
        uint64_t allocation_size = 0;
+       uint64_t file_index = 0;
        uint32_t len;
        struct timespec mdate_ts, adate_ts, cdate_ts, create_date_ts;
        time_t mdate = (time_t)0, adate = (time_t)0, create_date = (time_t)0;
@@ -1496,6 +1514,8 @@ static bool smbd_marshall_dir_entry(TALLOC_CTX *ctx,
        }
        allocation_size = SMB_VFS_GET_ALLOC_SIZE(conn, NULL, &smb_fname->st);
 
+       file_index = get_FileIndex(conn, &smb_fname->st);
+
        mdate_ts = smb_fname->st.st_ex_mtime;
        adate_ts = smb_fname->st.st_ex_atime;
        create_date_ts = get_create_timespec(conn, NULL, smb_fname);
@@ -1864,8 +1884,7 @@ static bool smbd_marshall_dir_entry(TALLOC_CTX *ctx,
                        p +=4;
                }
                SIVAL(p,0,0); p += 4; /* Unknown - reserved ? */
-               SIVAL(p,0,smb_fname->st.st_ex_ino); p += 4; /* FileIndexLow */
-               SIVAL(p,0,smb_fname->st.st_ex_dev); p += 4; /* FileIndexHigh */
+               SBVAL(p,0,file_index); p += 8;
                len = srvstr_push(base_data, flags2, p,
                                  fname, PTR_DIFF(end_data, p),
                                  STR_TERMINATE_ASCII);
@@ -1935,8 +1954,7 @@ static bool smbd_marshall_dir_entry(TALLOC_CTX *ctx,
                }
                p += 26;
                SSVAL(p,0,0); p += 2; /* Reserved ? */
-               SIVAL(p,0,smb_fname->st.st_ex_ino); p += 4; /* FileIndexLow */
-               SIVAL(p,0,smb_fname->st.st_ex_dev); p += 4; /* FileIndexHigh */
+               SBVAL(p,0,file_index); p += 8;
                len = srvstr_push(base_data, flags2, p,
                                  fname, PTR_DIFF(end_data, p),
                                  STR_TERMINATE_ASCII);
@@ -3850,6 +3868,8 @@ static char *store_file_unix_basic(connection_struct *conn,
                                files_struct *fsp,
                                const SMB_STRUCT_STAT *psbuf)
 {
+       uint64_t file_index = get_FileIndex(conn, psbuf);
+
        DEBUG(10,("store_file_unix_basic: SMB_QUERY_FILE_UNIX_BASIC\n"));
        DEBUG(4,("store_file_unix_basic: st_mode=%o\n",(int)psbuf->st_ex_mode));
 
@@ -3883,7 +3903,7 @@ static char *store_file_unix_basic(connection_struct *conn,
        SIVAL(pdata,4,0);
        pdata += 8;
 
-       SINO_T_VAL(pdata,0,(SMB_INO_T)psbuf->st_ex_ino);   /* inode number */
+       SINO_T_VAL(pdata,0,(SMB_INO_T)file_index);   /* inode number */
        pdata += 8;
 
        SIVAL(pdata,0, unix_perms_to_wire(psbuf->st_ex_mode));     /* Standard UNIX file permissions */
@@ -4285,8 +4305,7 @@ NTSTATUS smbd_do_qfilepathinfo(connection_struct *conn,
 
           I think this causes us to fail the IFSKIT
           BasicFileInformationTest. -tpot */
-       file_index =  ((psbuf->st_ex_ino) & UINT32_MAX); /* FileIndexLow */
-       file_index |= ((uint64_t)((psbuf->st_ex_dev) & UINT32_MAX)) << 32; /* FileIndexHigh */
+       file_index = get_FileIndex(conn, psbuf);
 
        switch (info_level) {
                case SMB_INFO_STANDARD: