smbd: add fdos_mode()
authorRalph Boehme <slow@samba.org>
Mon, 19 Oct 2020 13:44:29 +0000 (15:44 +0200)
committerRalph Boehme <slow@samba.org>
Wed, 16 Dec 2020 09:08:31 +0000 (09:08 +0000)
Note that this continues using the braindead dual path/handle based API mistake,
but only in order to reuse the util functions and because this is an
intermediate step to support transitioning to an all handle based flow.

Signed-off-by: Ralph Boehme <slow@samba.org>
Reviewed-by: Jeremy Allison <jra@samba.org>
source3/smbd/dosmode.c
source3/smbd/proto.h

index 9fc5f6ece6c9245d136ca8ce958cd2f8bc364f6d..6dca0a87d15ff558fda06ed56dba20133ca6c295 100644 (file)
@@ -633,6 +633,7 @@ uint32_t dos_mode_msdfs(connection_struct *conn,
  * check whether a file or directory is flagged as compressed.
  */
 static NTSTATUS dos_mode_check_compressed(connection_struct *conn,
+                                         struct files_struct *fsp,
                                          struct smb_filename *smb_fname,
                                          bool *is_compressed)
 {
@@ -644,7 +645,7 @@ static NTSTATUS dos_mode_check_compressed(connection_struct *conn,
                goto err_out;
        }
 
-       status = SMB_VFS_GET_COMPRESSION(conn, tmp_ctx, NULL, smb_fname,
+       status = SMB_VFS_GET_COMPRESSION(conn, tmp_ctx, fsp, smb_fname,
                                         &compression_fmt);
        if (!NT_STATUS_IS_OK(status)) {
                goto err_ctx_free;
@@ -699,11 +700,16 @@ static uint32_t dos_mode_from_name(connection_struct *conn,
 
 static uint32_t dos_mode_post(uint32_t dosmode,
                              connection_struct *conn,
+                             struct files_struct *fsp,
                              struct smb_filename *smb_fname,
                              const char *func)
 {
        NTSTATUS status;
 
+       if (fsp != NULL) {
+               smb_fname = fsp->fsp_name;
+       }
+
        /*
         * According to MS-FSA a stream name does not have
         * separate DOS attribute metadata, so we must return
@@ -724,7 +730,7 @@ static uint32_t dos_mode_post(uint32_t dosmode,
        if (conn->fs_capabilities & FILE_FILE_COMPRESSION) {
                bool compressed = false;
 
-               status = dos_mode_check_compressed(conn, smb_fname,
+               status = dos_mode_check_compressed(conn, fsp, smb_fname,
                                                   &compressed);
                if (NT_STATUS_IS_OK(status) && compressed) {
                        dosmode |= FILE_ATTRIBUTE_COMPRESSED;
@@ -773,7 +779,47 @@ uint32_t dos_mode(connection_struct *conn, struct smb_filename *smb_fname)
                }
        }
 
-       result = dos_mode_post(result, conn, smb_fname, __func__);
+       result = dos_mode_post(result, conn, NULL, smb_fname, __func__);
+       return result;
+}
+
+uint32_t fdos_mode(struct files_struct *fsp)
+{
+       uint32_t result = 0;
+       NTSTATUS status = NT_STATUS_OK;
+
+       if (fsp == NULL) {
+               /*
+                * The pathological case where a callers does
+                * fdos_mode(smb_fname->fsp) passing a pathref fsp. But as
+                * smb_fname points at a symlink in POSIX context smb_fname->fsp
+                * is NULL.
+                */
+               return FILE_ATTRIBUTE_NORMAL;
+       }
+
+       DBG_DEBUG("%s\n", fsp_str_dbg(fsp));
+
+       if (!VALID_STAT(fsp->fsp_name->st)) {
+               return 0;
+       }
+
+       if (S_ISLNK(fsp->fsp_name->st.st_ex_mode)) {
+               return FILE_ATTRIBUTE_NORMAL;
+       }
+
+       /* Get the DOS attributes via the VFS if we can */
+       status = SMB_VFS_FGET_DOS_ATTRIBUTES(fsp->conn, fsp, &result);
+       if (!NT_STATUS_IS_OK(status)) {
+               /*
+                * Only fall back to using UNIX modes if we get NOT_IMPLEMENTED.
+                */
+               if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_IMPLEMENTED)) {
+                       result |= dos_mode_from_sbuf(fsp->conn, fsp->fsp_name);
+               }
+       }
+
+       result = dos_mode_post(result, fsp->conn, fsp, NULL, __func__);
        return result;
 }
 
@@ -874,6 +920,7 @@ static void dos_mode_at_vfs_get_dosmode_done(struct tevent_req *subreq)
        if (NT_STATUS_IS_OK(status)) {
                state->dosmode = dos_mode_post(state->dosmode,
                                               state->dir_fsp->conn,
+                                              NULL,
                                               state->smb_fname,
                                               __func__);
                tevent_req_done(req);
index 7b790f17fd92412e914157c47e597c091b4ee245..32bff0a6c30a8e86513acd9d561dc3c7b3c5e069 100644 (file)
@@ -268,6 +268,7 @@ mode_t unix_mode(connection_struct *conn, int dosmode,
 uint32_t dos_mode_msdfs(connection_struct *conn,
                      const struct smb_filename *smb_fname);
 uint32_t dos_mode(connection_struct *conn, struct smb_filename *smb_fname);
+uint32_t fdos_mode(struct files_struct *fsp);
 struct tevent_req *dos_mode_at_send(TALLOC_CTX *mem_ctx,
                                    struct tevent_context *ev,
                                    files_struct *dir_fsp,