Proper fix for #6898 - Samba duplicates file content on appending. Pointed out by...
[ira/wip.git] / source3 / smbd / nttrans.c
index 9f4074c8656b6bcedecfe91dd555e824c0ab22e6..9e982911b9c7665cee3515e57999feb48f4854a8 100644 (file)
@@ -21,7 +21,6 @@
 #include "includes.h"
 #include "smbd/globals.h"
 
-extern enum protocol_types Protocol;
 extern const struct generic_mapping file_generic_mapping;
 
 static char *nttrans_realloc(char **ptr, size_t size)
@@ -479,7 +478,8 @@ void reply_ntcreate_and_X(struct smb_request *req)
                                conn,
                                req->flags2 & FLAGS2_DFS_PATHNAMES,
                                fname,
-                               0,
+                               (file_attributes & FILE_FLAG_POSIX_SEMANTICS) ?
+                                       UCF_POSIX_PATHNAMES : 0,
                                NULL,
                                &smb_fname);
 
@@ -494,6 +494,13 @@ void reply_ntcreate_and_X(struct smb_request *req)
                goto out;
        }
 
+       /*
+        * Bug #6898 - clients using Windows opens should
+        * never be able to set this attribute into the
+        * VFS.
+        */
+       file_attributes &= ~FILE_FLAG_POSIX_SEMANTICS;
+
        status = SMB_VFS_CREATE_FILE(
                conn,                                   /* conn */
                req,                                    /* req */
@@ -555,10 +562,6 @@ void reply_ntcreate_and_X(struct smb_request *req)
        }
 
        file_len = smb_fname->st.st_ex_size;
-       fattr = dos_mode(conn, smb_fname);
-       if (fattr == 0) {
-               fattr = FILE_ATTRIBUTE_NORMAL;
-       }
 
        if (flags & EXTENDED_RESPONSE_REQUIRED) {
                /* This is very strange. We
@@ -587,6 +590,11 @@ void reply_ntcreate_and_X(struct smb_request *req)
        }
        p += 4;
 
+       fattr = dos_mode(conn, smb_fname);
+       if (fattr == 0) {
+               fattr = FILE_ATTRIBUTE_NORMAL;
+       }
+
        /* Deal with other possible opens having a modified
           write time. JRA. */
        ZERO_STRUCT(write_time_ts);
@@ -596,10 +604,10 @@ void reply_ntcreate_and_X(struct smb_request *req)
        }
 
        /* Create time. */
-       create_timespec = get_create_timespec(fsp, smb_fname);
+       create_timespec = get_create_timespec(conn, fsp, smb_fname);
        a_timespec = smb_fname->st.st_ex_atime;
        m_timespec = smb_fname->st.st_ex_mtime;
-       c_timespec = get_change_timespec(fsp, smb_fname);
+       c_timespec = get_change_timespec(conn, fsp, smb_fname);
 
        if (lp_dos_filetime_resolution(SNUM(conn))) {
                dos_filetime_timespec(&create_timespec);
@@ -608,13 +616,13 @@ void reply_ntcreate_and_X(struct smb_request *req)
                dos_filetime_timespec(&c_timespec);
        }
 
-       put_long_date_timespec(p, create_timespec); /* create time. */
+       put_long_date_timespec(conn->ts_res, p, create_timespec); /* create time. */
        p += 8;
-       put_long_date_timespec(p, a_timespec); /* access time */
+       put_long_date_timespec(conn->ts_res, p, a_timespec); /* access time */
        p += 8;
-       put_long_date_timespec(p, m_timespec); /* write time */
+       put_long_date_timespec(conn->ts_res, p, m_timespec); /* write time */
        p += 8;
-       put_long_date_timespec(p, c_timespec); /* change time */
+       put_long_date_timespec(conn->ts_res, p, c_timespec); /* change time */
        p += 8;
        SIVAL(p,0,fattr); /* File Attributes. */
        p += 4;
@@ -623,7 +631,25 @@ void reply_ntcreate_and_X(struct smb_request *req)
        SOFF_T(p,0,file_len);
        p += 8;
        if (flags & EXTENDED_RESPONSE_REQUIRED) {
-               SSVAL(p,2,0x7);
+               uint16_t file_status = (NO_EAS|NO_SUBSTREAMS|NO_REPARSETAG);
+               size_t num_names = 0;
+               unsigned int num_streams;
+               struct stream_struct *streams = NULL;
+
+               /* Do we have any EA's ? */
+               status = get_ea_names_from_file(ctx, conn, fsp,
+                               smb_fname->base_name, NULL, &num_names);
+               if (NT_STATUS_IS_OK(status) && num_names) {
+                       file_status &= ~NO_EAS;
+               }
+               status = SMB_VFS_STREAMINFO(conn, NULL, smb_fname->base_name, ctx,
+                       &num_streams, &streams);
+               /* There is always one stream, ::$DATA. */
+               if (NT_STATUS_IS_OK(status) && num_streams > 1) {
+                       file_status &= ~NO_SUBSTREAMS;
+               }
+               TALLOC_FREE(streams);
+               SSVAL(p,2,file_status);
        }
        p += 4;
        SCVAL(p,0,fsp->is_directory ? 1 : 0);
@@ -792,7 +818,7 @@ static NTSTATUS set_sd(files_struct *fsp, uint8 *data, uint32 sd_len,
  Read a list of EA names and data from an incoming data buffer. Create an ea_list with them.
 ****************************************************************************/
 
-static struct ea_list *read_nttrans_ea_list(TALLOC_CTX *ctx, const char *pdata, size_t data_size)
+struct ea_list *read_nttrans_ea_list(TALLOC_CTX *ctx, const char *pdata, size_t data_size)
 {
        struct ea_list *ea_list_head = NULL;
        size_t offset = 0;
@@ -976,7 +1002,8 @@ static void call_nt_transact_create(connection_struct *conn,
                                conn,
                                req->flags2 & FLAGS2_DFS_PATHNAMES,
                                fname,
-                               0,
+                               (file_attributes & FILE_FLAG_POSIX_SEMANTICS) ?
+                                       UCF_POSIX_PATHNAMES : 0,
                                NULL,
                                &smb_fname);
 
@@ -997,6 +1024,13 @@ static void call_nt_transact_create(connection_struct *conn,
                        ? BATCH_OPLOCK : 0;
        }
 
+       /*
+        * Bug #6898 - clients using Windows opens should
+        * never be able to set this attribute into the
+        * VFS.
+        */
+       file_attributes &= ~FILE_FLAG_POSIX_SEMANTICS;
+
        status = SMB_VFS_CREATE_FILE(
                conn,                                   /* conn */
                req,                                    /* req */
@@ -1053,10 +1087,6 @@ static void call_nt_transact_create(connection_struct *conn,
        }
 
        file_len = smb_fname->st.st_ex_size;
-       fattr = dos_mode(conn, smb_fname);
-       if (fattr == 0) {
-               fattr = FILE_ATTRIBUTE_NORMAL;
-       }
 
        /* Realloc the size of parameters and data we will return */
        if (flags & EXTENDED_RESPONSE_REQUIRED) {
@@ -1085,6 +1115,11 @@ static void call_nt_transact_create(connection_struct *conn,
        }
        p += 8;
 
+       fattr = dos_mode(conn, smb_fname);
+       if (fattr == 0) {
+               fattr = FILE_ATTRIBUTE_NORMAL;
+       }
+
        /* Deal with other possible opens having a modified
           write time. JRA. */
        ZERO_STRUCT(write_time_ts);
@@ -1094,10 +1129,10 @@ static void call_nt_transact_create(connection_struct *conn,
        }
 
        /* Create time. */
-       create_timespec = get_create_timespec(fsp, smb_fname);
+       create_timespec = get_create_timespec(conn, fsp, smb_fname);
        a_timespec = smb_fname->st.st_ex_atime;
        m_timespec = smb_fname->st.st_ex_mtime;
-       c_timespec = get_change_timespec(fsp, smb_fname);
+       c_timespec = get_change_timespec(conn, fsp, smb_fname);
 
        if (lp_dos_filetime_resolution(SNUM(conn))) {
                dos_filetime_timespec(&create_timespec);
@@ -1106,13 +1141,13 @@ static void call_nt_transact_create(connection_struct *conn,
                dos_filetime_timespec(&c_timespec);
        }
 
-       put_long_date_timespec(p, create_timespec); /* create time. */
+       put_long_date_timespec(conn->ts_res, p, create_timespec); /* create time. */
        p += 8;
-       put_long_date_timespec(p, a_timespec); /* access time */
+       put_long_date_timespec(conn->ts_res, p, a_timespec); /* access time */
        p += 8;
-       put_long_date_timespec(p, m_timespec); /* write time */
+       put_long_date_timespec(conn->ts_res, p, m_timespec); /* write time */
        p += 8;
-       put_long_date_timespec(p, c_timespec); /* change time */
+       put_long_date_timespec(conn->ts_res, p, c_timespec); /* change time */
        p += 8;
        SIVAL(p,0,fattr); /* File Attributes. */
        p += 4;
@@ -2018,7 +2053,7 @@ static void call_nt_transact_ioctl(connection_struct *conn,
                }
 
                /* needed_data_count 4 bytes */
-               SIVAL(pdata,8,labels_data_count);
+               SIVAL(pdata, 8, labels_data_count+4);
 
                cur_pdata+=12;
 
@@ -2520,7 +2555,7 @@ static void handle_nttrans(connection_struct *conn,
                           struct trans_state *state,
                           struct smb_request *req)
 {
-       if (Protocol >= PROTOCOL_NT1) {
+       if (get_Protocol() >= PROTOCOL_NT1) {
                req->flags2 |= 0x40; /* IS_LONG_NAME */
                SSVAL(req->inbuf,smb_flg2,req->flags2);
        }