s3-smbd: fix get_ea_names_from_file() and check for pnames pointer.
[samba.git] / source3 / smbd / trans2.c
index ae4b8b0d314bcf2ac79d07aa10757dfd60ea6676..ce458126d3cc9d9765fc30b0145aacaee0700be1 100644 (file)
@@ -156,7 +156,9 @@ NTSTATUS get_ea_names_from_file(TALLOC_CTX *mem_ctx, connection_struct *conn,
        ssize_t sizeret = -1;
 
        if (!lp_ea_support(SNUM(conn))) {
-               *pnames = NULL;
+               if (pnames) {
+                       *pnames = NULL;
+               }
                *pnum_names = 0;
                return NT_STATUS_OK;
        }
@@ -207,7 +209,9 @@ NTSTATUS get_ea_names_from_file(TALLOC_CTX *mem_ctx, connection_struct *conn,
 
        if (sizeret == 0) {
                TALLOC_FREE(names);
-               *pnames = NULL;
+               if (pnames) {
+                       *pnames = NULL;
+               }
                *pnum_names = 0;
                return NT_STATUS_OK;
        }
@@ -244,7 +248,11 @@ NTSTATUS get_ea_names_from_file(TALLOC_CTX *mem_ctx, connection_struct *conn,
                names[num_names++] = p;
        }
 
-       *pnames = names;
+       if (pnames) {
+               *pnames = names;
+       } else {
+               TALLOC_FREE(names);
+       }
        *pnum_names = num_names;
        return NT_STATUS_OK;
 }
@@ -1458,6 +1466,8 @@ static bool smbd_marshall_dir_entry(TALLOC_CTX *ctx,
                                    const char *fname,
                                    const struct smb_filename *smb_fname,
                                    uint64_t space_remaining,
+                                   uint8_t align,
+                                   bool do_pad,
                                    char *base_data,
                                    char **ppdata,
                                    char *end_data,
@@ -1476,6 +1486,8 @@ static bool smbd_marshall_dir_entry(TALLOC_CTX *ctx,
        char *last_entry_ptr;
        bool was_8_3;
        uint32_t nt_extmode; /* Used for NT connections instead of mode */
+       off_t off;
+       off_t pad = 0;
 
        *out_of_space = false;
 
@@ -1506,9 +1518,22 @@ static bool smbd_marshall_dir_entry(TALLOC_CTX *ctx,
        adate = convert_timespec_to_time_t(adate_ts);
        c_date = convert_timespec_to_time_t(cdate_ts);
 
+       /* align the record */
+       off = PTR_DIFF(pdata, base_data);
+       pad = (off + (align-1)) & ~(align-1);
+       pad -= off;
+       off += pad;
+       /* initialize padding to 0 */
+       memset(pdata, 0, pad);
+       space_remaining -= pad;
+
+       pdata += pad;
        p = pdata;
        last_entry_ptr = p;
 
+       pad = 0;
+       off = 0;
+
        nt_extmode = mode ? mode : FILE_ATTRIBUTE_NORMAL;
 
        switch (info_level) {
@@ -1652,10 +1677,10 @@ static bool smbd_marshall_dir_entry(TALLOC_CTX *ctx,
                was_8_3 = mangle_is_8_3(fname, True, conn->params);
                p += 4;
                SIVAL(p,0,reskey); p += 4;
-               put_long_date_timespec(p,create_date_ts); p += 8;
-               put_long_date_timespec(p,adate_ts); p += 8;
-               put_long_date_timespec(p,mdate_ts); p += 8;
-               put_long_date_timespec(p,cdate_ts); p += 8;
+               put_long_date_timespec(conn->ts_res,p,create_date_ts); p += 8;
+               put_long_date_timespec(conn->ts_res,p,adate_ts); p += 8;
+               put_long_date_timespec(conn->ts_res,p,mdate_ts); p += 8;
+               put_long_date_timespec(conn->ts_res,p,cdate_ts); p += 8;
                SOFF_T(p,0,file_size); p += 8;
                SOFF_T(p,0,allocation_size); p += 8;
                SIVAL(p,0,nt_extmode); p += 4;
@@ -1694,21 +1719,34 @@ static bool smbd_marshall_dir_entry(TALLOC_CTX *ctx,
                                  STR_TERMINATE_ASCII);
                SIVAL(q,0,len);
                p += len;
-               SIVAL(p,0,0); /* Ensure any padding is null. */
+
                len = PTR_DIFF(p, pdata);
-               len = (len + 3) & ~3;
-               SIVAL(pdata,0,len);
-               p = pdata + len;
+               pad = (len + (align-1)) & ~(align-1);
+               /*
+                * offset to the next entry, the caller
+                * will overwrite it for the last entry
+                * that's why we always include the padding
+                */
+               SIVAL(pdata,0,pad);
+               /*
+                * set padding to zero
+                */
+               if (do_pad) {
+                       memset(p, 0, pad - len);
+                       p = pdata + pad;
+               } else {
+                       p = pdata + len;
+               }
                break;
 
        case SMB_FIND_FILE_DIRECTORY_INFO:
                DEBUG(10,("get_lanman2_dir_entry: SMB_FIND_FILE_DIRECTORY_INFO\n"));
                p += 4;
                SIVAL(p,0,reskey); p += 4;
-               put_long_date_timespec(p,create_date_ts); p += 8;
-               put_long_date_timespec(p,adate_ts); p += 8;
-               put_long_date_timespec(p,mdate_ts); p += 8;
-               put_long_date_timespec(p,cdate_ts); p += 8;
+               put_long_date_timespec(conn->ts_res,p,create_date_ts); p += 8;
+               put_long_date_timespec(conn->ts_res,p,adate_ts); p += 8;
+               put_long_date_timespec(conn->ts_res,p,mdate_ts); p += 8;
+               put_long_date_timespec(conn->ts_res,p,cdate_ts); p += 8;
                SOFF_T(p,0,file_size); p += 8;
                SOFF_T(p,0,allocation_size); p += 8;
                SIVAL(p,0,nt_extmode); p += 4;
@@ -1717,21 +1755,34 @@ static bool smbd_marshall_dir_entry(TALLOC_CTX *ctx,
                                  STR_TERMINATE_ASCII);
                SIVAL(p,0,len);
                p += 4 + len;
-               SIVAL(p,0,0); /* Ensure any padding is null. */
+
                len = PTR_DIFF(p, pdata);
-               len = (len + 3) & ~3;
-               SIVAL(pdata,0,len);
-               p = pdata + len;
+               pad = (len + (align-1)) & ~(align-1);
+               /*
+                * offset to the next entry, the caller
+                * will overwrite it for the last entry
+                * that's why we always include the padding
+                */
+               SIVAL(pdata,0,pad);
+               /*
+                * set padding to zero
+                */
+               if (do_pad) {
+                       memset(p, 0, pad - len);
+                       p = pdata + pad;
+               } else {
+                       p = pdata + len;
+               }
                break;
 
        case SMB_FIND_FILE_FULL_DIRECTORY_INFO:
                DEBUG(10,("get_lanman2_dir_entry: SMB_FIND_FILE_FULL_DIRECTORY_INFO\n"));
                p += 4;
                SIVAL(p,0,reskey); p += 4;
-               put_long_date_timespec(p,create_date_ts); p += 8;
-               put_long_date_timespec(p,adate_ts); p += 8;
-               put_long_date_timespec(p,mdate_ts); p += 8;
-               put_long_date_timespec(p,cdate_ts); p += 8;
+               put_long_date_timespec(conn->ts_res,p,create_date_ts); p += 8;
+               put_long_date_timespec(conn->ts_res,p,adate_ts); p += 8;
+               put_long_date_timespec(conn->ts_res,p,mdate_ts); p += 8;
+               put_long_date_timespec(conn->ts_res,p,cdate_ts); p += 8;
                SOFF_T(p,0,file_size); p += 8;
                SOFF_T(p,0,allocation_size); p += 8;
                SIVAL(p,0,nt_extmode); p += 4;
@@ -1748,11 +1799,23 @@ static bool smbd_marshall_dir_entry(TALLOC_CTX *ctx,
                SIVAL(q, 0, len);
                p += len;
 
-               SIVAL(p,0,0); /* Ensure any padding is null. */
                len = PTR_DIFF(p, pdata);
-               len = (len + 3) & ~3;
-               SIVAL(pdata,0,len);
-               p = pdata + len;
+               pad = (len + (align-1)) & ~(align-1);
+               /*
+                * offset to the next entry, the caller
+                * will overwrite it for the last entry
+                * that's why we always include the padding
+                */
+               SIVAL(pdata,0,pad);
+               /*
+                * set padding to zero
+                */
+               if (do_pad) {
+                       memset(p, 0, pad - len);
+                       p = pdata + pad;
+               } else {
+                       p = pdata + len;
+               }
                break;
 
        case SMB_FIND_FILE_NAMES_INFO:
@@ -1767,21 +1830,34 @@ static bool smbd_marshall_dir_entry(TALLOC_CTX *ctx,
                                  STR_TERMINATE_ASCII);
                SIVAL(p, -4, len);
                p += len;
-               SIVAL(p,0,0); /* Ensure any padding is null. */
+
                len = PTR_DIFF(p, pdata);
-               len = (len + 3) & ~3;
-               SIVAL(pdata,0,len);
-               p = pdata + len;
+               pad = (len + (align-1)) & ~(align-1);
+               /*
+                * offset to the next entry, the caller
+                * will overwrite it for the last entry
+                * that's why we always include the padding
+                */
+               SIVAL(pdata,0,pad);
+               /*
+                * set padding to zero
+                */
+               if (do_pad) {
+                       memset(p, 0, pad - len);
+                       p = pdata + pad;
+               } else {
+                       p = pdata + len;
+               }
                break;
 
        case SMB_FIND_ID_FULL_DIRECTORY_INFO:
                DEBUG(10,("get_lanman2_dir_entry: SMB_FIND_ID_FULL_DIRECTORY_INFO\n"));
                p += 4;
                SIVAL(p,0,reskey); p += 4;
-               put_long_date_timespec(p,create_date_ts); p += 8;
-               put_long_date_timespec(p,adate_ts); p += 8;
-               put_long_date_timespec(p,mdate_ts); p += 8;
-               put_long_date_timespec(p,cdate_ts); p += 8;
+               put_long_date_timespec(conn->ts_res,p,create_date_ts); p += 8;
+               put_long_date_timespec(conn->ts_res,p,adate_ts); p += 8;
+               put_long_date_timespec(conn->ts_res,p,mdate_ts); p += 8;
+               put_long_date_timespec(conn->ts_res,p,cdate_ts); p += 8;
                SOFF_T(p,0,file_size); p += 8;
                SOFF_T(p,0,allocation_size); p += 8;
                SIVAL(p,0,nt_extmode); p += 4;
@@ -1800,11 +1876,24 @@ static bool smbd_marshall_dir_entry(TALLOC_CTX *ctx,
                                  STR_TERMINATE_ASCII);
                SIVAL(q, 0, len);
                p += len;
-               SIVAL(p,0,0); /* Ensure any padding is null. */
+
                len = PTR_DIFF(p, pdata);
-               len = (len + 3) & ~3;
-               SIVAL(pdata,0,len);
-               p = pdata + len;
+               pad = (len + (align-1)) & ~(align-1);
+               /*
+                * offset to the next entry, the caller
+                * will overwrite it for the last entry
+                * that's why we always include the padding
+                */
+               SIVAL(pdata,0,pad);
+               /*
+                * set padding to zero
+                */
+               if (do_pad) {
+                       memset(p, 0, pad - len);
+                       p = pdata + pad;
+               } else {
+                       p = pdata + len;
+               }
                break;
 
        case SMB_FIND_ID_BOTH_DIRECTORY_INFO:
@@ -1812,10 +1901,10 @@ static bool smbd_marshall_dir_entry(TALLOC_CTX *ctx,
                was_8_3 = mangle_is_8_3(fname, True, conn->params);
                p += 4;
                SIVAL(p,0,reskey); p += 4;
-               put_long_date_timespec(p,create_date_ts); p += 8;
-               put_long_date_timespec(p,adate_ts); p += 8;
-               put_long_date_timespec(p,mdate_ts); p += 8;
-               put_long_date_timespec(p,cdate_ts); p += 8;
+               put_long_date_timespec(conn->ts_res,p,create_date_ts); p += 8;
+               put_long_date_timespec(conn->ts_res,p,adate_ts); p += 8;
+               put_long_date_timespec(conn->ts_res,p,mdate_ts); p += 8;
+               put_long_date_timespec(conn->ts_res,p,cdate_ts); p += 8;
                SOFF_T(p,0,file_size); p += 8;
                SOFF_T(p,0,allocation_size); p += 8;
                SIVAL(p,0,nt_extmode); p += 4;
@@ -1858,11 +1947,24 @@ static bool smbd_marshall_dir_entry(TALLOC_CTX *ctx,
                                  STR_TERMINATE_ASCII);
                SIVAL(q,0,len);
                p += len;
-               SIVAL(p,0,0); /* Ensure any padding is null. */
+
                len = PTR_DIFF(p, pdata);
-               len = (len + 3) & ~3;
-               SIVAL(pdata,0,len);
-               p = pdata + len;
+               pad = (len + (align-1)) & ~(align-1);
+               /*
+                * offset to the next entry, the caller
+                * will overwrite it for the last entry
+                * that's why we always include the padding
+                */
+               SIVAL(pdata,0,pad);
+               /*
+                * set padding to zero
+                */
+               if (do_pad) {
+                       memset(p, 0, pad - len);
+                       p = pdata + pad;
+               } else {
+                       p = pdata + len;
+               }
                break;
 
        /* CIFS UNIX Extension. */
@@ -1893,12 +1995,24 @@ static bool smbd_marshall_dir_entry(TALLOC_CTX *ctx,
                }
 
                p += len;
-               SIVAL(p,0,0); /* Ensure any padding is null. */
 
                len = PTR_DIFF(p, pdata);
-               len = (len + 3) & ~3;
-               SIVAL(pdata,0,len);     /* Offset from this structure to the beginning of the next one */
-               p = pdata + len;
+               pad = (len + (align-1)) & ~(align-1);
+               /*
+                * offset to the next entry, the caller
+                * will overwrite it for the last entry
+                * that's why we always include the padding
+                */
+               SIVAL(pdata,0,pad);
+               /*
+                * set padding to zero
+                */
+               if (do_pad) {
+                       memset(p, 0, pad - len);
+                       p = pdata + pad;
+               } else {
+                       p = pdata + len;
+               }
                /* End of SMB_QUERY_FILE_UNIX_BASIC */
 
                break;
@@ -1921,24 +2035,26 @@ static bool smbd_marshall_dir_entry(TALLOC_CTX *ctx,
        return true;
 }
 
-static bool get_lanman2_dir_entry(TALLOC_CTX *ctx,
-                               connection_struct *conn,
-                               struct dptr_struct *dirptr,
-                               uint16 flags2,
-                               const char *path_mask,
-                               uint32 dirtype,
-                               int info_level,
-                               int requires_resume_key,
-                               bool dont_descend,
-                               bool ask_sharemode,
-                               char **ppdata,
-                               char *base_data,
-                               char *end_data,
-                               int space_remaining,
-                               bool *out_of_space,
-                               bool *got_exact_match,
-                               int *_last_entry_off,
-                               struct ea_list *name_list)
+bool smbd_dirptr_lanman2_entry(TALLOC_CTX *ctx,
+                              connection_struct *conn,
+                              struct dptr_struct *dirptr,
+                              uint16 flags2,
+                              const char *path_mask,
+                              uint32 dirtype,
+                              int info_level,
+                              int requires_resume_key,
+                              bool dont_descend,
+                              bool ask_sharemode,
+                              uint8_t align,
+                              bool do_pad,
+                              char **ppdata,
+                              char *base_data,
+                              char *end_data,
+                              int space_remaining,
+                              bool *out_of_space,
+                              bool *got_exact_match,
+                              int *_last_entry_off,
+                              struct ea_list *name_list)
 {
        const char *p;
        const char *mask = NULL;
@@ -2001,6 +2117,8 @@ static bool get_lanman2_dir_entry(TALLOC_CTX *ctx,
                                     fname,
                                     smb_fname,
                                     space_remaining,
+                                    align,
+                                    do_pad,
                                     base_data,
                                     ppdata,
                                     end_data,
@@ -2020,6 +2138,43 @@ static bool get_lanman2_dir_entry(TALLOC_CTX *ctx,
        return true;
 }
 
+static bool get_lanman2_dir_entry(TALLOC_CTX *ctx,
+                               connection_struct *conn,
+                               struct dptr_struct *dirptr,
+                               uint16 flags2,
+                               const char *path_mask,
+                               uint32 dirtype,
+                               int info_level,
+                               int requires_resume_key,
+                               bool dont_descend,
+                               bool ask_sharemode,
+                               char **ppdata,
+                               char *base_data,
+                               char *end_data,
+                               int space_remaining,
+                               bool *out_of_space,
+                               bool *got_exact_match,
+                               int *last_entry_off,
+                               struct ea_list *name_list)
+{
+       bool resume_key = false;
+       const uint8_t align = 4;
+       const bool do_pad = true;
+
+       if (requires_resume_key) {
+               resume_key = true;
+       }
+
+       return smbd_dirptr_lanman2_entry(ctx, conn, dirptr, flags2,
+                                        path_mask, dirtype, info_level,
+                                        resume_key, dont_descend, ask_sharemode,
+                                        align, do_pad,
+                                        ppdata, base_data, end_data,
+                                        space_remaining,
+                                        out_of_space, got_exact_match,
+                                        last_entry_off, name_list);
+}
+
 /****************************************************************************
  Reply to a TRANS2_FINDFIRST.
 ****************************************************************************/
@@ -2835,6 +2990,9 @@ cBytesSector=%u, cUnitTotal=%u, cUnitAvail=%d\n", (unsigned int)st.st_ex_dev, (u
 
                        /* Capabilities are filled in at connection time through STATVFS call */
                        additional_flags |= conn->fs_capabilities;
+                       additional_flags |= lp_parm_int(conn->params->service,
+                                                       "share", "fake_fscaps",
+                                                       0);
 
                        SIVAL(pdata,0,FILE_CASE_PRESERVED_NAMES|FILE_CASE_SENSITIVE_SEARCH|
                                FILE_SUPPORTS_OBJECT_IDS|FILE_UNICODE_ON_DISK|
@@ -3708,9 +3866,9 @@ static char *store_file_unix_basic(connection_struct *conn,
        SOFF_T(pdata,0,SMB_VFS_GET_ALLOC_SIZE(conn,fsp,psbuf)); /* Number of bytes used on disk - 64 Bit */
        pdata += 8;
 
-       put_long_date_timespec(pdata, psbuf->st_ex_ctime);       /* Change Time 64 Bit */
-       put_long_date_timespec(pdata+8, psbuf->st_ex_atime);     /* Last access time 64 Bit */
-       put_long_date_timespec(pdata+16, psbuf->st_ex_mtime);    /* Last modification time 64 Bit */
+       put_long_date_timespec(TIMESTAMP_SET_NT_OR_BETTER, pdata, psbuf->st_ex_ctime);       /* Change Time 64 Bit */
+       put_long_date_timespec(TIMESTAMP_SET_NT_OR_BETTER ,pdata+8, psbuf->st_ex_atime);     /* Last access time 64 Bit */
+       put_long_date_timespec(TIMESTAMP_SET_NT_OR_BETTER, pdata+16, psbuf->st_ex_mtime);    /* Last modification time 64 Bit */
        pdata += 24;
 
        SIVAL(pdata,0,psbuf->st_ex_uid);               /* user id for the owner */
@@ -3844,7 +4002,7 @@ static char *store_file_unix_basic_info2(connection_struct *conn,
        pdata = store_file_unix_basic(conn, pdata, fsp, psbuf);
 
        /* Create (birth) time 64 bit */
-       put_long_date_timespec(pdata, psbuf->st_ex_btime);
+       put_long_date_timespec(TIMESTAMP_SET_NT_OR_BETTER,pdata, psbuf->st_ex_btime);
        pdata += 8;
 
        map_info2_flags_from_sbuf(psbuf, &file_flags, &flags_mask);
@@ -4223,6 +4381,9 @@ NTSTATUS smbd_do_qfilepathinfo(connection_struct *conn,
 
                case 0xFF0F:/*SMB2_INFO_QUERY_ALL_EAS*/
                {
+                       /* This is FileFullEaInformation - 0xF which maps to
+                        * 1015 (decimal) in smbd_do_setfilepathinfo. */
+
                        /* We have data_size bytes to put EA's into. */
                        size_t total_ea_len = 0;
                        struct ea_list *ea_file_list = NULL;
@@ -4261,10 +4422,10 @@ NTSTATUS smbd_do_qfilepathinfo(connection_struct *conn,
                                data_size = 40;
                                SIVAL(pdata,36,0);
                        }
-                       put_long_date_timespec(pdata,create_time_ts);
-                       put_long_date_timespec(pdata+8,atime_ts);
-                       put_long_date_timespec(pdata+16,mtime_ts); /* write time */
-                       put_long_date_timespec(pdata+24,ctime_ts); /* change time */
+                       put_long_date_timespec(conn->ts_res,pdata,create_time_ts);
+                       put_long_date_timespec(conn->ts_res,pdata+8,atime_ts);
+                       put_long_date_timespec(conn->ts_res,pdata+16,mtime_ts); /* write time */
+                       put_long_date_timespec(conn->ts_res,pdata+24,ctime_ts); /* change time */
                        SIVAL(pdata,32,mode);
 
                        DEBUG(5,("SMB_QFBI - "));
@@ -4356,10 +4517,10 @@ NTSTATUS smbd_do_qfilepathinfo(connection_struct *conn,
                        unsigned int ea_size =
                            estimate_ea_size(conn, fsp, smb_fname->base_name);
                        DEBUG(10,("smbd_do_qfilepathinfo: SMB_FILE_ALL_INFORMATION\n"));
-                       put_long_date_timespec(pdata,create_time_ts);
-                       put_long_date_timespec(pdata+8,atime_ts);
-                       put_long_date_timespec(pdata+16,mtime_ts); /* write time */
-                       put_long_date_timespec(pdata+24,ctime_ts); /* change time */
+                       put_long_date_timespec(conn->ts_res,pdata,create_time_ts);
+                       put_long_date_timespec(conn->ts_res,pdata+8,atime_ts);
+                       put_long_date_timespec(conn->ts_res,pdata+16,mtime_ts); /* write time */
+                       put_long_date_timespec(conn->ts_res,pdata+24,ctime_ts); /* change time */
                        SIVAL(pdata,32,mode);
                        SIVAL(pdata,36,0); /* padding. */
                        pdata += 40;
@@ -4388,10 +4549,10 @@ NTSTATUS smbd_do_qfilepathinfo(connection_struct *conn,
                        unsigned int ea_size =
                            estimate_ea_size(conn, fsp, smb_fname->base_name);
                        DEBUG(10,("smbd_do_qfilepathinfo: SMB2_FILE_ALL_INFORMATION\n"));
-                       put_long_date_timespec(pdata+0x00,create_time_ts);
-                       put_long_date_timespec(pdata+0x08,atime_ts);
-                       put_long_date_timespec(pdata+0x10,mtime_ts); /* write time */
-                       put_long_date_timespec(pdata+0x18,ctime_ts); /* change time */
+                       put_long_date_timespec(conn->ts_res,pdata+0x00,create_time_ts);
+                       put_long_date_timespec(conn->ts_res,pdata+0x08,atime_ts);
+                       put_long_date_timespec(conn->ts_res,pdata+0x10,mtime_ts); /* write time */
+                       put_long_date_timespec(conn->ts_res,pdata+0x18,ctime_ts); /* change time */
                        SIVAL(pdata,    0x20, mode);
                        SIVAL(pdata,    0x24, 0); /* padding. */
                        SBVAL(pdata,    0x28, allocation_size);
@@ -4521,10 +4682,10 @@ NTSTATUS smbd_do_qfilepathinfo(connection_struct *conn,
 
                case SMB_FILE_NETWORK_OPEN_INFORMATION:
                        DEBUG(10,("smbd_do_qfilepathinfo: SMB_FILE_NETWORK_OPEN_INFORMATION\n"));
-                       put_long_date_timespec(pdata,create_time_ts);
-                       put_long_date_timespec(pdata+8,atime_ts);
-                       put_long_date_timespec(pdata+16,mtime_ts); /* write time */
-                       put_long_date_timespec(pdata+24,ctime_ts); /* change time */
+                       put_long_date_timespec(conn->ts_res,pdata,create_time_ts);
+                       put_long_date_timespec(conn->ts_res,pdata+8,atime_ts);
+                       put_long_date_timespec(conn->ts_res,pdata+16,mtime_ts); /* write time */
+                       put_long_date_timespec(conn->ts_res,pdata+24,ctime_ts); /* change time */
                        SOFF_T(pdata,32,allocation_size);
                        SOFF_T(pdata,40,file_size);
                        SIVAL(pdata,48,mode);
@@ -5255,6 +5416,14 @@ NTSTATUS smb_set_file_time(connection_struct *conn,
                action &= ~FILE_NOTIFY_CHANGE_LAST_WRITE;
        }
 
+       /* Ensure the resolution is the correct for
+        * what we can store on this filesystem. */
+
+       round_timespec(conn->ts_res, &ft->create_time);
+       round_timespec(conn->ts_res, &ft->ctime);
+       round_timespec(conn->ts_res, &ft->atime);
+       round_timespec(conn->ts_res, &ft->mtime);
+
        DEBUG(5,("smb_set_filetime: actime: %s\n ",
                time_to_asc(convert_timespec_to_time_t(ft->atime))));
        DEBUG(5,("smb_set_filetime: modtime: %s\n ",
@@ -5491,6 +5660,53 @@ static NTSTATUS smb_info_set_ea(connection_struct *conn,
        return status;
 }
 
+/****************************************************************************
+ Deal with SMB_FILE_FULL_EA_INFORMATION set.
+****************************************************************************/
+
+static NTSTATUS smb_set_file_full_ea_info(connection_struct *conn,
+                               const char *pdata,
+                               int total_data,
+                               files_struct *fsp)
+{
+       struct ea_list *ea_list = NULL;
+       NTSTATUS status;
+
+       if (!fsp) {
+               return NT_STATUS_INVALID_HANDLE;
+       }
+
+       if (!lp_ea_support(SNUM(conn))) {
+               DEBUG(10, ("smb_set_file_full_ea_info - ea_len = %u but "
+                       "EA's not supported.\n",
+                       (unsigned int)total_data));
+               return NT_STATUS_EAS_NOT_SUPPORTED;
+       }
+
+       if (total_data < 10) {
+               DEBUG(10, ("smb_set_file_full_ea_info - ea_len = %u "
+                       "too small.\n",
+                       (unsigned int)total_data));
+               return NT_STATUS_INVALID_PARAMETER;
+       }
+
+       ea_list = read_nttrans_ea_list(talloc_tos(),
+                               pdata,
+                               total_data);
+
+       if (!ea_list) {
+               return NT_STATUS_INVALID_PARAMETER;
+       }
+       status = set_ea(conn, fsp, fsp->fsp_name, ea_list);
+
+       DEBUG(10, ("smb_set_file_full_ea_info on file %s returned %s\n",
+               smb_fname_str_dbg(fsp->fsp_name),
+               nt_errstr(status) ));
+
+       return status;
+}
+
+
 /****************************************************************************
  Deal with SMB_SET_FILE_DISPOSITION_INFO.
 ****************************************************************************/
@@ -7210,6 +7426,15 @@ NTSTATUS smbd_do_setfilepathinfo(connection_struct *conn,
                        break;
                }
 
+               case SMB_FILE_FULL_EA_INFORMATION:
+               {
+                       status = smb_set_file_full_ea_info(conn,
+                                               pdata,
+                                               total_data,
+                                               fsp);
+                       break;
+               }
+
                /* From tridge Samba4 : 
                 * MODE_INFORMATION in setfileinfo (I have no
                 * idea what "mode information" on a file is - it takes a value of 0,