smbd: move files_struct.is_directory to a bitfield
[samba.git] / source3 / smbd / trans2.c
index 2617da9b17a4925ba1e9131d92ce17fe065e7413..19706d32bd5d24b4b85aae3a26066a40c79ef273 100644 (file)
@@ -43,6 +43,7 @@
 #include "lib/readdir_attr.h"
 #include "messages.h"
 #include "smb1_utils.h"
+#include "libcli/smb/smb2_posix.h"
 
 #define DIR_ENTRY_SAFETY_MARGIN 4096
 
@@ -118,11 +119,13 @@ static NTSTATUS get_posix_fsp(connection_struct *conn,
        uint32_t share_access = FILE_SHARE_READ|
                                FILE_SHARE_WRITE|
                                FILE_SHARE_DELETE;
+       struct smb2_create_blobs *posx = NULL;
+
        /*
         * Only FILE_FLAG_POSIX_SEMANTICS matters on existing files,
         * but set reasonable defaults.
         */
-       uint32_t file_attributes = 0664|FILE_FLAG_POSIX_SEMANTICS;
+       uint32_t file_attributes = 0664;
        uint32_t oplock = NO_OPLOCK;
        uint32_t create_options = FILE_NON_DIRECTORY_FILE;
 
@@ -140,7 +143,7 @@ static NTSTATUS get_posix_fsp(connection_struct *conn,
                 * Only FILE_FLAG_POSIX_SEMANTICS matters on existing
                 * directories, but set reasonable defaults.
                 */
-               file_attributes = 0775|FILE_FLAG_POSIX_SEMANTICS;
+               file_attributes = 0775;
                create_options = FILE_DIRECTORY_FILE;
        }
 
@@ -152,6 +155,14 @@ static NTSTATUS get_posix_fsp(connection_struct *conn,
                goto done;
        }
 
+       status = make_smb2_posix_create_ctx(
+               talloc_tos(), &posx, file_attributes);
+       if (!NT_STATUS_IS_OK(status)) {
+               DBG_WARNING("make_smb2_posix_create_ctx failed: %s\n",
+                           nt_errstr(status));
+               goto done;
+       }
+
        status = SMB_VFS_CREATE_FILE(
                conn,           /* conn */
                req,            /* req */
@@ -170,10 +181,11 @@ static NTSTATUS get_posix_fsp(connection_struct *conn,
                NULL,           /* ea_list */
                ret_fsp,        /* result */
                NULL,           /* pinfo */
-               NULL,           /* in_context */
+               posx,           /* in_context */
                NULL);          /* out_context */
 
 done:
+       TALLOC_FREE(posx);
        TALLOC_FREE(smb_fname_tmp);
        return status;
 }
@@ -2717,7 +2729,7 @@ static void call_trans2findfirst(connection_struct *conn,
        NTSTATUS ntstatus = NT_STATUS_OK;
        bool ask_sharemode = lp_smbd_search_ask_sharemode(SNUM(conn));
        struct smbd_server_connection *sconn = req->sconn;
-       uint32_t ucf_flags = UCF_SAVE_LCOMP | UCF_ALWAYS_ALLOW_WCARD_LCOMP |
+       uint32_t ucf_flags = UCF_ALWAYS_ALLOW_WCARD_LCOMP |
                        ucf_flags_from_smb_request(req);
        bool backup_priv = false;
        bool as_root = false;
@@ -2835,7 +2847,14 @@ close_if_end = %d requires_resume_key = %d backup_priv = %d level = 0x%x, max_da
                goto out;
        }
 
-       mask = smb_dname->original_lcomp;
+       mask = get_original_lcomp(talloc_tos(),
+                               conn,
+                               directory,
+                               ucf_flags);
+       if (mask == NULL) {
+               reply_nterror(req, NT_STATUS_NO_MEMORY);
+               goto out;
+       }
 
        directory = smb_dname->base_name;
 
@@ -4984,7 +5003,7 @@ static NTSTATUS smb_query_posix_acl(connection_struct *conn,
                 * We can only have default POSIX ACLs on
                 * directories.
                 */
-               if (!fsp->is_directory) {
+               if (!fsp->fsp_flags.is_directory) {
                        DBG_INFO("Non-directory open %s\n",
                                fsp_str_dbg(fsp));
                        status = NT_STATUS_INVALID_HANDLE;
@@ -6675,6 +6694,13 @@ static NTSTATUS smb_set_file_size(connection_struct *conn,
                 get_file_size_stat(psbuf));
 
        if (size == get_file_size_stat(psbuf)) {
+               if (fsp == NULL) {
+                       return NT_STATUS_OK;
+               }
+               if (!fsp->fsp_flags.modified) {
+                       return NT_STATUS_OK;
+               }
+               trigger_write_time_update_immediate(fsp);
                return NT_STATUS_OK;
        }
 
@@ -7057,8 +7083,8 @@ static NTSTATUS smb2_file_rename_information(connection_struct *conn,
        uint32_t len;
        char *newname = NULL;
        struct smb_filename *smb_fname_dst = NULL;
-       uint32_t ucf_flags = UCF_SAVE_LCOMP |
-               ucf_flags_from_smb_request(req);
+       const char *dst_original_lcomp = NULL;
+       uint32_t ucf_flags = ucf_flags_from_smb_request(req);
        NTSTATUS status = NT_STATUS_OK;
        TALLOC_CTX *ctx = talloc_tos();
 
@@ -7130,25 +7156,29 @@ static NTSTATUS smb2_file_rename_information(connection_struct *conn,
                        status = NT_STATUS_NO_MEMORY;
                        goto out;
                }
+       }
 
-               /*
-                * Set the original last component, since
-                * rename_internals_fsp() requires it.
-                */
-               smb_fname_dst->original_lcomp = talloc_strdup(smb_fname_dst,
-                                                             newname);
-               if (smb_fname_dst->original_lcomp == NULL) {
-                       status = NT_STATUS_NO_MEMORY;
-                       goto out;
-               }
-
+       /*
+        * Set the original last component, since
+        * rename_internals_fsp() requires it.
+        */
+       dst_original_lcomp = get_original_lcomp(smb_fname_dst,
+                                       conn,
+                                       newname,
+                                       ucf_flags);
+       if (dst_original_lcomp == NULL) {
+               status = NT_STATUS_NO_MEMORY;
+               goto out;
        }
 
        DEBUG(10,("smb2_file_rename_information: "
                  "SMB_FILE_RENAME_INFORMATION (%s) %s -> %s\n",
                  fsp_fnum_dbg(fsp), fsp_str_dbg(fsp),
                  smb_fname_str_dbg(smb_fname_dst)));
-       status = rename_internals_fsp(conn, fsp, smb_fname_dst,
+       status = rename_internals_fsp(conn,
+                               fsp,
+                               smb_fname_dst,
+                               dst_original_lcomp,
                                (FILE_ATTRIBUTE_HIDDEN|FILE_ATTRIBUTE_SYSTEM),
                                overwrite);
 
@@ -7169,8 +7199,7 @@ static NTSTATUS smb_file_link_information(connection_struct *conn,
        char *newname = NULL;
        struct smb_filename *smb_fname_dst = NULL;
        NTSTATUS status = NT_STATUS_OK;
-       uint32_t ucf_flags = UCF_SAVE_LCOMP |
-               ucf_flags_from_smb_request(req);
+       uint32_t ucf_flags = ucf_flags_from_smb_request(req);
        TALLOC_CTX *ctx = talloc_tos();
 
        if (!fsp) {
@@ -7262,6 +7291,7 @@ static NTSTATUS smb_file_rename_information(connection_struct *conn,
        uint32_t len;
        char *newname = NULL;
        struct smb_filename *smb_fname_dst = NULL;
+       const char *dst_original_lcomp = NULL;
        bool dest_has_wcard = False;
        NTSTATUS status = NT_STATUS_OK;
        char *p;
@@ -7307,18 +7337,6 @@ static NTSTATUS smb_file_rename_information(connection_struct *conn,
        DEBUG(10,("smb_file_rename_information: got name |%s|\n",
                                newname));
 
-       if (req->flags2 & FLAGS2_DFS_PATHNAMES) {
-               status = resolve_dfspath_wcard(ctx, conn,
-                                      newname,
-                                      UCF_COND_ALLOW_WCARD_LCOMP,
-                                      !conn->sconn->using_smb2,
-                                      &newname,
-                                      &dest_has_wcard);
-               if (!NT_STATUS_IS_OK(status)) {
-                       return status;
-               }
-       }
-
        /* Check the new name has no '/' characters. */
        if (strchr_m(newname, '/')) {
                return NT_STATUS_NOT_SUPPORTED;
@@ -7342,12 +7360,14 @@ static NTSTATUS smb_file_rename_information(connection_struct *conn,
                }
 
                /*
-                * Set the original last component, since
+                * Get the original last component, since
                 * rename_internals_fsp() requires it.
                 */
-               smb_fname_dst->original_lcomp = talloc_strdup(smb_fname_dst,
-                                                             newname);
-               if (smb_fname_dst->original_lcomp == NULL) {
+               dst_original_lcomp = get_original_lcomp(smb_fname_dst,
+                                       conn,
+                                       newname,
+                                       0);
+               if (dst_original_lcomp == NULL) {
                        status = NT_STATUS_NO_MEMORY;
                        goto out;
                }
@@ -7359,8 +7379,7 @@ static NTSTATUS smb_file_rename_information(connection_struct *conn,
                 * the newname instead.
                 */
                char *base_name = NULL;
-               uint32_t ucf_flags = UCF_SAVE_LCOMP |
-                       ucf_flags_from_smb_request(req);
+               uint32_t ucf_flags = ucf_flags_from_smb_request(req);
 
                if (dest_has_wcard) {
                        ucf_flags |= UCF_ALWAYS_ALLOW_WCARD_LCOMP;
@@ -7396,8 +7415,13 @@ static NTSTATUS smb_file_rename_information(connection_struct *conn,
                        return NT_STATUS_NO_MEMORY;
                }
 
-               status = unix_convert(ctx, conn, base_name, &smb_fname_dst,
-                                       ucf_flags);
+               status = filename_convert(ctx,
+                                         conn,
+                                         base_name,
+                                         ucf_flags,
+                                         NULL,
+                                         NULL,
+                                         &smb_fname_dst);
 
                /* If an error we expect this to be
                 * NT_STATUS_OBJECT_PATH_NOT_FOUND */
@@ -7418,6 +7442,14 @@ static NTSTATUS smb_file_rename_information(connection_struct *conn,
                                goto out;
                        }
                }
+               dst_original_lcomp = get_original_lcomp(smb_fname_dst,
+                                       conn,
+                                       newname,
+                                       ucf_flags);
+               if (dst_original_lcomp == NULL) {
+                       status = NT_STATUS_NO_MEMORY;
+                       goto out;
+               }
        }
 
        if (fsp) {
@@ -7425,17 +7457,28 @@ static NTSTATUS smb_file_rename_information(connection_struct *conn,
                          "SMB_FILE_RENAME_INFORMATION (%s) %s -> %s\n",
                          fsp_fnum_dbg(fsp), fsp_str_dbg(fsp),
                          smb_fname_str_dbg(smb_fname_dst)));
-               status = rename_internals_fsp(conn, fsp, smb_fname_dst, 0,
-                                             overwrite);
+               status = rename_internals_fsp(conn,
+                                       fsp,
+                                       smb_fname_dst,
+                                       dst_original_lcomp,
+                                       0,
+                                       overwrite);
        } else {
                DEBUG(10,("smb_file_rename_information: "
                          "SMB_FILE_RENAME_INFORMATION %s -> %s\n",
                          smb_fname_str_dbg(smb_fname_src),
                          smb_fname_str_dbg(smb_fname_dst)));
-               status = rename_internals(ctx, conn, req, smb_fname_src,
-                                         smb_fname_dst, 0, overwrite, false,
-                                         dest_has_wcard,
-                                         FILE_WRITE_ATTRIBUTES);
+               status = rename_internals(ctx,
+                                       conn,
+                                       req,
+                                       smb_fname_src,
+                                       smb_fname_dst,
+                                       dst_original_lcomp,
+                                       0,
+                                       overwrite,
+                                       false,
+                                       dest_has_wcard,
+                                       FILE_WRITE_ATTRIBUTES);
        }
  out:
        TALLOC_FREE(smb_fname_dst);
@@ -7555,7 +7598,7 @@ static NTSTATUS smb_set_posix_acl(connection_struct *conn,
        }
 
        /* If we have a default acl, this *must* be a directory. */
-       if (valid_def_acls && !fsp->is_directory) {
+       if (valid_def_acls && !fsp->fsp_flags.is_directory) {
                DBG_INFO("Can't set default acls on "
                         "non-directory %s\n",
                         fsp_str_dbg(fsp));
@@ -7642,7 +7685,7 @@ static NTSTATUS smb_set_posix_lock(connection_struct *conn,
                        break;
                case POSIX_LOCK_TYPE_WRITE:
                        /* Return the right POSIX-mappable error code for files opened read-only. */
-                       if (!fsp->can_write) {
+                       if (!fsp->fsp_flags.can_write) {
                                return NT_STATUS_INVALID_HANDLE;
                        }
                        lock_type = WRITE_LOCK;
@@ -7817,8 +7860,15 @@ static NTSTATUS smb_set_file_basic_info(connection_struct *conn,
        DEBUG(10, ("smb_set_file_basic_info: file %s\n",
                   smb_fname_str_dbg(smb_fname)));
 
-       return smb_set_file_time(conn, fsp, smb_fname, &ft,
-                                true);
+       status = smb_set_file_time(conn, fsp, smb_fname, &ft, true);
+       if (!NT_STATUS_IS_OK(status)) {
+               return status;
+       }
+
+       if (fsp != NULL && fsp->fsp_flags.modified) {
+               trigger_write_time_update_immediate(fsp);
+       }
+       return NT_STATUS_OK;
 }
 
 /****************************************************************************
@@ -7855,11 +7905,15 @@ static NTSTATUS smb_set_info_standard(connection_struct *conn,
                return status;
        }
 
-        return smb_set_file_time(conn,
-                                fsp,
-                               smb_fname,
-                               &ft,
-                                true);
+       status = smb_set_file_time(conn, fsp, smb_fname, &ft, true);
+       if (!NT_STATUS_IS_OK(status)) {
+               return status;
+       }
+
+       if (fsp != NULL && fsp->fsp_flags.modified) {
+               trigger_write_time_update_immediate(fsp);
+       }
+       return NT_STATUS_OK;
 }
 
 /****************************************************************************
@@ -8297,7 +8351,7 @@ static NTSTATUS smb_set_file_unix_basic(connection_struct *conn,
                 * We're setting the time explicitly for UNIX.
                 * Cancel any pending changes over all handles.
                 */
-               all_fsps->update_write_time_on_close = false;
+               all_fsps->fsp_flags.update_write_time_on_close = false;
                TALLOC_FREE(all_fsps->update_write_time_event);
        }
 
@@ -8398,12 +8452,12 @@ static NTSTATUS smb_posix_mkdir(connection_struct *conn,
 {
        NTSTATUS status = NT_STATUS_OK;
        uint32_t raw_unixmode = 0;
-       uint32_t mod_unixmode = 0;
        mode_t unixmode = (mode_t)0;
        files_struct *fsp = NULL;
        uint16_t info_level_return = 0;
        int info;
        char *pdata = *ppdata;
+       struct smb2_create_blobs *posx = NULL;
 
        if (total_data < 18) {
                return NT_STATUS_INVALID_PARAMETER;
@@ -8418,7 +8472,12 @@ static NTSTATUS smb_posix_mkdir(connection_struct *conn,
                return status;
        }
 
-       mod_unixmode = (uint32_t)unixmode | FILE_FLAG_POSIX_SEMANTICS;
+       status = make_smb2_posix_create_ctx(talloc_tos(), &posx, unixmode);
+       if (!NT_STATUS_IS_OK(status)) {
+               DBG_WARNING("make_smb2_posix_create_ctx failed: %s\n",
+                           nt_errstr(status));
+               return status;
+       }
 
        DEBUG(10,("smb_posix_mkdir: file %s, mode 0%o\n",
                  smb_fname_str_dbg(smb_fname), (unsigned int)unixmode));
@@ -8432,7 +8491,7 @@ static NTSTATUS smb_posix_mkdir(connection_struct *conn,
                FILE_SHARE_NONE,                        /* share_access */
                FILE_CREATE,                            /* create_disposition*/
                FILE_DIRECTORY_FILE,                    /* create_options */
-               mod_unixmode,                           /* file_attributes */
+               0,                                      /* file_attributes */
                0,                                      /* oplock_request */
                NULL,                                   /* lease */
                0,                                      /* allocation_size */
@@ -8441,7 +8500,10 @@ static NTSTATUS smb_posix_mkdir(connection_struct *conn,
                NULL,                                   /* ea_list */
                &fsp,                                   /* result */
                &info,                                  /* pinfo */
-               NULL, NULL);                            /* create context */
+               posx,                                   /* in_context_blobs */
+               NULL);                                  /* out_context_blobs */
+
+       TALLOC_FREE(posx);
 
         if (NT_STATUS_IS_OK(status)) {
                 close_file(req, fsp, NORMAL_CLOSE);
@@ -8510,7 +8572,7 @@ static NTSTATUS smb_posix_open(connection_struct *conn,
        uint32_t flags = 0;
        uint32_t wire_open_mode = 0;
        uint32_t raw_unixmode = 0;
-       uint32_t mod_unixmode = 0;
+       uint32_t attributes = 0;
        uint32_t create_disp = 0;
        uint32_t access_mask = 0;
        uint32_t create_options = FILE_NON_DIRECTORY_FILE;
@@ -8520,6 +8582,7 @@ static NTSTATUS smb_posix_open(connection_struct *conn,
        int oplock_request = 0;
        int info = 0;
        uint16_t info_level_return = 0;
+       struct smb2_create_blobs *posx = NULL;
 
        if (total_data < 18) {
                return NT_STATUS_INVALID_PARAMETER;
@@ -8630,7 +8693,12 @@ static NTSTATUS smb_posix_open(connection_struct *conn,
                return status;
        }
 
-       mod_unixmode = (uint32_t)unixmode | FILE_FLAG_POSIX_SEMANTICS;
+       status = make_smb2_posix_create_ctx(talloc_tos(), &posx, unixmode);
+       if (!NT_STATUS_IS_OK(status)) {
+               DBG_WARNING("make_smb2_posix_create_ctx failed: %s\n",
+                           nt_errstr(status));
+               return status;
+       }
 
        if (wire_open_mode & SMB_O_SYNC) {
                create_options |= FILE_WRITE_THROUGH;
@@ -8639,7 +8707,7 @@ static NTSTATUS smb_posix_open(connection_struct *conn,
                access_mask |= FILE_APPEND_DATA;
        }
        if (wire_open_mode & SMB_O_DIRECT) {
-               mod_unixmode |= FILE_FLAG_NO_BUFFERING;
+               attributes |= FILE_FLAG_NO_BUFFERING;
        }
 
        if ((wire_open_mode & SMB_O_DIRECTORY) ||
@@ -8666,7 +8734,7 @@ static NTSTATUS smb_posix_open(connection_struct *conn,
                    FILE_SHARE_DELETE),
                create_disp,                            /* create_disposition*/
                create_options,                         /* create_options */
-               mod_unixmode,                           /* file_attributes */
+               attributes,                             /* file_attributes */
                oplock_request,                         /* oplock_request */
                NULL,                                   /* lease */
                0,                                      /* allocation_size */
@@ -8675,7 +8743,10 @@ static NTSTATUS smb_posix_open(connection_struct *conn,
                NULL,                                   /* ea_list */
                &fsp,                                   /* result */
                &info,                                  /* pinfo */
-               NULL, NULL);                            /* create context */
+               posx,                                   /* in_context_blobs */
+               NULL);                                  /* out_context_blobs */
+
+       TALLOC_FREE(posx);
 
        if (!NT_STATUS_IS_OK(status)) {
                return status;
@@ -8764,6 +8835,7 @@ static NTSTATUS smb_posix_unlink(connection_struct *conn,
        int create_options = 0;
        struct share_mode_lock *lck = NULL;
        bool other_nonposix_opens;
+       struct smb2_create_blobs *posx = NULL;
 
        if (total_data < 2) {
                return NT_STATUS_INVALID_PARAMETER;
@@ -8788,6 +8860,13 @@ static NTSTATUS smb_posix_unlink(connection_struct *conn,
                create_options |= FILE_DIRECTORY_FILE;
        }
 
+       status = make_smb2_posix_create_ctx(talloc_tos(), &posx, 0777);
+       if (!NT_STATUS_IS_OK(status)) {
+               DBG_WARNING("make_smb2_posix_create_ctx failed: %s\n",
+                           nt_errstr(status));
+               return status;
+       }
+
         status = SMB_VFS_CREATE_FILE(
                conn,                                   /* conn */
                req,                                    /* req */
@@ -8798,7 +8877,7 @@ static NTSTATUS smb_posix_unlink(connection_struct *conn,
                    FILE_SHARE_DELETE),
                FILE_OPEN,                              /* create_disposition*/
                create_options,                         /* create_options */
-               FILE_FLAG_POSIX_SEMANTICS|0777,         /* file_attributes */
+               0,                                      /* file_attributes */
                0,                                      /* oplock_request */
                NULL,                                   /* lease */
                0,                                      /* allocation_size */
@@ -8807,7 +8886,10 @@ static NTSTATUS smb_posix_unlink(connection_struct *conn,
                NULL,                                   /* ea_list */
                &fsp,                                   /* result */
                &info,                                  /* pinfo */
-               NULL, NULL);                            /* create context */
+               posx,                                   /* in_context_blobs */
+               NULL);                                  /* out_context_blobs */
+
+       TALLOC_FREE(posx);
 
        if (!NT_STATUS_IS_OK(status)) {
                return status;