vfs_gpfs: Create fileid from filesystem metadata
authorChristof Schmitt <cs@samba.org>
Mon, 19 Aug 2019 23:23:11 +0000 (16:23 -0700)
committerChristof Schmitt <cs@samba.org>
Tue, 19 Nov 2019 21:19:36 +0000 (21:19 +0000)
MacOS SMB clients require that file ids are not quickly reused when
files are deleted and new files are created with the same name. Inode
numbers do not satisfy that requirement, as they will be quickly reused.

To address this problem, create a unique id from the available file
system specific metadata. As that id is larger than the available 64bit,
use a hash to generate a 64bit id for usage as fileid.

Signed-off-by: Christof Schmitt <cs@samba.org>
Reviewed-by: Volker Lendecke <vl@samba.org>
source3/modules/vfs_gpfs.c

index cb0db12daabb50f6db19d51852539c6a12f1faee..f26cf0b9e6c48c61dc17f1aa657a25b6ad2c863a 100644 (file)
 #include "lib/util/tevent_unix.h"
 #include "lib/util/gpfswrap.h"
 
+#include <gnutls/gnutls.h>
+#include <gnutls/crypto.h>
+#include "lib/crypto/gnutls_helpers.h"
+
 #undef DBGC_CLASS
 #define DBGC_CLASS DBGC_VFS
 
@@ -1609,6 +1613,40 @@ static int get_dos_attr_with_capability(struct smb_filename *smb_fname,
        return ret;
 }
 
+static NTSTATUS vfs_gpfs_get_file_id(struct gpfs_iattr64 *iattr,
+                                    uint64_t *fileid)
+{
+       uint8_t input[sizeof(gpfs_ino64_t) +
+                     sizeof(gpfs_gen64_t) +
+                     sizeof(gpfs_snapid64_t)];
+       uint8_t digest[gnutls_hash_get_len(GNUTLS_DIG_SHA1)];
+       int rc;
+
+       DBG_DEBUG("ia_inode 0x%llx, ia_gen 0x%llx, ia_modsnapid 0x%llx\n",
+                 iattr->ia_inode, iattr->ia_gen, iattr->ia_modsnapid);
+
+       SBVAL(input,
+             0, iattr->ia_inode);
+       SBVAL(input,
+             sizeof(gpfs_ino64_t), iattr->ia_gen);
+       SBVAL(input,
+             sizeof(gpfs_ino64_t) + sizeof(gpfs_gen64_t), iattr->ia_modsnapid);
+
+       GNUTLS_FIPS140_SET_LAX_MODE();
+       rc = gnutls_hash_fast(GNUTLS_DIG_SHA1, input, sizeof(input), &digest);
+       GNUTLS_FIPS140_SET_STRICT_MODE();
+
+       if (rc != 0) {
+               return gnutls_error_to_ntstatus(rc,
+                                               NT_STATUS_HASH_NOT_SUPPORTED);
+       }
+
+       memcpy(fileid, &digest, sizeof(*fileid));
+       DBG_DEBUG("file_id 0x%" PRIx64 "\n", *fileid);
+
+       return NT_STATUS_OK;
+}
+
 static NTSTATUS vfs_gpfs_get_dos_attributes(struct vfs_handle_struct *handle,
                                            struct smb_filename *smb_fname,
                                            uint32_t *dosmode)
@@ -1616,6 +1654,8 @@ static NTSTATUS vfs_gpfs_get_dos_attributes(struct vfs_handle_struct *handle,
        struct gpfs_config_data *config;
        struct gpfs_iattr64 iattr = { };
        unsigned int litemask = 0;
+       uint64_t file_id;
+       NTSTATUS status;
        int ret;
 
        SMB_VFS_HANDLE_GET_DATA(handle, config,
@@ -1652,10 +1692,16 @@ static NTSTATUS vfs_gpfs_get_dos_attributes(struct vfs_handle_struct *handle,
                return map_nt_error_from_unix(errno);
        }
 
+       status = vfs_gpfs_get_file_id(&iattr, &file_id);
+       if (!NT_STATUS_IS_OK(status)) {
+               return status;
+       }
+
        *dosmode |= vfs_gpfs_winattrs_to_dosmode(iattr.ia_winflags);
        smb_fname->st.st_ex_iflags &= ~ST_EX_IFLAG_CALCULATED_BTIME;
        smb_fname->st.st_ex_btime.tv_sec = iattr.ia_createtime.tv_sec;
        smb_fname->st.st_ex_btime.tv_nsec = iattr.ia_createtime.tv_nsec;
+       update_stat_ex_file_id(&smb_fname->st, file_id);
 
        return NT_STATUS_OK;
 }
@@ -1667,6 +1713,8 @@ static NTSTATUS vfs_gpfs_fget_dos_attributes(struct vfs_handle_struct *handle,
        struct gpfs_config_data *config;
        struct gpfs_iattr64 iattr = { };
        unsigned int litemask;
+       uint64_t file_id;
+       NTSTATUS status;
        int ret;
 
        SMB_VFS_HANDLE_GET_DATA(handle, config,
@@ -1713,10 +1761,16 @@ static NTSTATUS vfs_gpfs_fget_dos_attributes(struct vfs_handle_struct *handle,
                return map_nt_error_from_unix(errno);
        }
 
+       status = vfs_gpfs_get_file_id(&iattr, &file_id);
+       if (!NT_STATUS_IS_OK(status)) {
+               return status;
+       }
+
        *dosmode |= vfs_gpfs_winattrs_to_dosmode(iattr.ia_winflags);
        fsp->fsp_name->st.st_ex_iflags &= ~ST_EX_IFLAG_CALCULATED_BTIME;
        fsp->fsp_name->st.st_ex_btime.tv_sec = iattr.ia_createtime.tv_sec;
        fsp->fsp_name->st.st_ex_btime.tv_nsec = iattr.ia_createtime.tv_nsec;
+       update_stat_ex_file_id(&fsp->fsp_name->st, file_id);
 
        return NT_STATUS_OK;
 }