diff --git a/source3/include/includes.h b/source3/include/includes.h index 87df3b7..92a3705 100644 --- a/source3/include/includes.h +++ b/source3/include/includes.h @@ -566,6 +566,12 @@ struct timespec { }; #endif +enum timestamp_set_resolution { + TIMESTAMP_SET_SECONDS = 0, + TIMESTAMP_SET_MSEC, + TIMESTAMP_SET_NT_OR_BETTER +}; + #ifdef HAVE_BROKEN_GETGROUPS #define GID_T int #else diff --git a/source3/include/proto.h b/source3/include/proto.h index 97d05b3..c530ee5 100644 --- a/source3/include/proto.h +++ b/source3/include/proto.h @@ -1028,7 +1028,8 @@ char *current_timestring(TALLOC_CTX *ctx, bool hires); void srv_put_dos_date(char *buf,int offset,time_t unixdate); void srv_put_dos_date2(char *buf,int offset, time_t unixdate); void srv_put_dos_date3(char *buf,int offset,time_t unixdate); -void put_long_date_timespec(char *p, struct timespec ts); +void round_timespec(enum timestamp_set_resolution res, struct timespec *ts); +void put_long_date_timespec(enum timestamp_set_resolution res, char *p, struct timespec ts); void put_long_date(char *p, time_t t); void dos_filetime_timespec(struct timespec *tsp); time_t make_unix_date2(const void *date_ptr, int zone_offset); @@ -1044,7 +1045,7 @@ struct timespec timespec_current(void); struct timespec timespec_min(const struct timespec *ts1, const struct timespec *ts2); int timespec_compare(const struct timespec *ts1, const struct timespec *ts2); -void round_timespec(struct timespec *ts); +void round_timespec_to_sec(struct timespec *ts); void round_timespec_to_usec(struct timespec *ts); struct timespec interpret_long_date(const char *p); void cli_put_dos_date(struct cli_state *cli, char *buf, int offset, time_t unixdate); diff --git a/source3/include/smb.h b/source3/include/smb.h index 1347ab2..3f3d7e6 100644 --- a/source3/include/smb.h +++ b/source3/include/smb.h @@ -557,9 +557,10 @@ typedef struct connection_struct { bool ipc; bool read_only; /* Attributes for the current user of the share. */ bool admin_user; /* Attributes for the current user of the share. */ - bool hires_timestamps_avail; /* Does this filesystem honor - sub second timestamps on files - and directories ? */ + /* Does this filesystem honor + sub second timestamps on files + and directories when setting time ? */ + enum timestamp_set_resolution ts_res; char *connectpath; char *origpath; diff --git a/source3/include/vfs.h b/source3/include/vfs.h index 2722352..38a972f 100644 --- a/source3/include/vfs.h +++ b/source3/include/vfs.h @@ -121,8 +121,9 @@ /* Changed to version 26 - Plumb struct smb_filename to SMB_VFS_CREATE_FILE, SMB_VFS_OPEN, SMB_VFS_STAT, SMB_VFS_LSTAT, SMB_VFS_RENAME, SMB_VFS_UNLINK, SMB_VFS_NTIMES. */ - -#define SMB_VFS_INTERFACE_VERSION 26 +/* Changed to version 27 - not yet released. Added enum timestamp_set_resolution + * return to fs_capabilities call. JRA. */ +#define SMB_VFS_INTERFACE_VERSION 27 /* to bug old modules which are trying to compile with the old functions */ @@ -173,7 +174,7 @@ struct vfs_fn_pointers { int (*set_quota)(struct vfs_handle_struct *handle, enum SMB_QUOTA_TYPE qtype, unid_t id, SMB_DISK_QUOTA *qt); int (*get_shadow_copy_data)(struct vfs_handle_struct *handle, struct files_struct *fsp, SHADOW_COPY_DATA *shadow_copy_data, bool labels); int (*statvfs)(struct vfs_handle_struct *handle, const char *path, struct vfs_statvfs_struct *statbuf); - uint32_t (*fs_capabilities)(struct vfs_handle_struct *handle); + uint32_t (*fs_capabilities)(struct vfs_handle_struct *handle, enum timestamp_set_resolution *p_ts_res); /* Directory operations */ @@ -488,7 +489,8 @@ int smb_vfs_call_get_shadow_copy_data(struct vfs_handle_struct *handle, bool labels); int smb_vfs_call_statvfs(struct vfs_handle_struct *handle, const char *path, struct vfs_statvfs_struct *statbuf); -uint32_t smb_vfs_call_fs_capabilities(struct vfs_handle_struct *handle); +uint32_t smb_vfs_call_fs_capabilities(struct vfs_handle_struct *handle, + enum timestamp_set_resolution *p_ts_res); SMB_STRUCT_DIR *smb_vfs_call_opendir(struct vfs_handle_struct *handle, const char *fname, const char *mask, uint32 attributes); diff --git a/source3/include/vfs_macros.h b/source3/include/vfs_macros.h index 2d7344c..e271cde 100644 --- a/source3/include/vfs_macros.h +++ b/source3/include/vfs_macros.h @@ -63,10 +63,10 @@ #define SMB_VFS_NEXT_STATVFS(handle, path, statbuf) \ smb_vfs_call_statvfs((handle)->next, (path), (statbuf)) -#define SMB_VFS_FS_CAPABILITIES(conn) \ - smb_vfs_call_fs_capabilities((conn)->vfs_handles) -#define SMB_VFS_NEXT_FS_CAPABILITIES(handle) \ - smb_vfs_call_fs_capabilities((handle)->next) +#define SMB_VFS_FS_CAPABILITIES(conn, p_ts_res) \ + smb_vfs_call_fs_capabilities((conn)->vfs_handles, (p_ts_res)) +#define SMB_VFS_NEXT_FS_CAPABILITIES(handle, p_ts_res) \ + smb_vfs_call_fs_capabilities((handle)->next, (p_ts_res)) /* Directory operations */ #define SMB_VFS_OPENDIR(conn, fname, mask, attr) \ diff --git a/source3/lib/time.c b/source3/lib/time.c index a9f7899..f6ff6d3 100644 --- a/source3/lib/time.c +++ b/source3/lib/time.c @@ -301,14 +301,30 @@ void srv_put_dos_date3(char *buf,int offset,time_t unixdate) put_dos_date3(buf, offset, unixdate, server_zone_offset); } +void round_timespec(enum timestamp_set_resolution res, struct timespec *ts) +{ + switch (res) { + case TIMESTAMP_SET_SECONDS: + round_timespec_to_sec(ts); + break; + case TIMESTAMP_SET_MSEC: + round_timespec_to_usec(ts); + break; + case TIMESTAMP_SET_NT_OR_BETTER: + /* No rounding needed. */ + break; + } +} + /**************************************************************************** Take a Unix time and convert to an NTTIME structure and place in buffer - pointed to by p. + pointed to by p, rounded to the correct resolution. ****************************************************************************/ -void put_long_date_timespec(char *p, struct timespec ts) +void put_long_date_timespec(enum timestamp_set_resolution res, char *p, struct timespec ts) { NTTIME nt; + round_timespec(res, &ts); unix_timespec_to_nt_time(&nt, ts); SIVAL(p, 0, nt & 0xFFFFFFFF); SIVAL(p, 4, nt >> 32); @@ -319,7 +335,7 @@ void put_long_date(char *p, time_t t) struct timespec ts; ts.tv_sec = t; ts.tv_nsec = 0; - put_long_date_timespec(p, ts); + put_long_date_timespec(TIMESTAMP_SET_SECONDS, p, ts); } void dos_filetime_timespec(struct timespec *tsp) @@ -472,7 +488,7 @@ int timespec_compare(const struct timespec *ts1, const struct timespec *ts2) then zero nsec. ****************************************************************************/ -void round_timespec(struct timespec *ts) +void round_timespec_to_sec(struct timespec *ts) { ts->tv_sec = convert_timespec_to_time_t(*ts); ts->tv_nsec = 0; diff --git a/source3/modules/vfs_default.c b/source3/modules/vfs_default.c index a793b33..b70868e 100644 --- a/source3/modules/vfs_default.c +++ b/source3/modules/vfs_default.c @@ -90,15 +90,71 @@ static int vfswrap_statvfs(struct vfs_handle_struct *handle, const char *path, return sys_statvfs(path, statbuf); } -static uint32_t vfswrap_fs_capabilities(struct vfs_handle_struct *handle) +static uint32_t vfswrap_fs_capabilities(struct vfs_handle_struct *handle, + enum timestamp_set_resolution *p_ts_res) { + connection_struct *conn = handle->conn; + uint32_t caps = FILE_CASE_SENSITIVE_SEARCH | FILE_CASE_PRESERVED_NAMES; + struct smb_filename *smb_fname_cpath = NULL; + NTSTATUS status; + int ret = -1; + #if defined(DARWINOS) struct vfs_statvfs_struct statbuf; ZERO_STRUCT(statbuf); - sys_statvfs(handle->conn->connectpath, &statbuf); - return statbuf.FsCapabilities; + sys_statvfs(conn->connectpath, &statbuf); + caps = statbuf.FsCapabilities; #endif - return FILE_CASE_SENSITIVE_SEARCH | FILE_CASE_PRESERVED_NAMES; + + *p_ts_res = TIMESTAMP_SET_SECONDS; + + /* Work out what timestamp resolution we can + * use when setting a timestamp. */ + + status = create_synthetic_smb_fname(talloc_tos(), + conn->connectpath, + NULL, + NULL, + &smb_fname_cpath); + if (!NT_STATUS_IS_OK(status)) { + return caps; + } + + ret = SMB_VFS_STAT(conn, smb_fname_cpath); + if (ret == -1) { + TALLOC_FREE(smb_fname_cpath); + return caps; + } + + if (smb_fname_cpath->st.st_ex_mtime.tv_nsec || + smb_fname_cpath->st.st_ex_atime.tv_nsec || + smb_fname_cpath->st.st_ex_ctime.tv_nsec) { + /* If any of the normal UNIX directory timestamps + * have a non-zero tv_nsec component assume + * we might be able to set sub-second timestamps. + * See what filetime set primitives we have. + */ +#if defined(HAVE_UTIMES) + /* utimes allows msec timestamps to be set. */ + *p_ts_res = TIMESTAMP_SET_MSEC; +#elif defined(HAVE_UTIME) + /* utime only allows sec timestamps to be set. */ + *p_ts_res = TIMESTAMP_SET_SEC; +#endif + + /* TODO. Add a configure test for the Linux + * nsec timestamp set system call, and use it + * if available.... + */ + DEBUG(10,("vfswrap_fs_capabilities: timestamp " + "resolution of %s " + "available on share %s, directory %s\n", + *p_ts_res == TIMESTAMP_SET_MSEC ? "msec" : "sec", + lp_servicename(conn->cnum), + conn->connectpath )); + } + TALLOC_FREE(smb_fname_cpath); + return caps; } /* Directory operations */ @@ -788,6 +844,14 @@ static int vfswrap_ntimes(vfs_handle_struct *handle, ft->mtime = smb_fname->st.st_ex_mtime; } + if (!null_timespec(ft->create_time) && + lp_store_create_time(SNUM(handle->conn))) { + set_create_timespec_ea(handle->conn, + NULL, + smb_fname, + ft->create_time); + } + if ((timespec_compare(&ft->atime, &smb_fname->st.st_ex_atime) == 0) && (timespec_compare(&ft->mtime, @@ -818,14 +882,6 @@ static int vfswrap_ntimes(vfs_handle_struct *handle, result = -1; #endif - if (!null_timespec(ft->create_time) && - lp_store_create_time(SNUM(handle->conn))) { - set_create_timespec_ea(handle->conn, - NULL, - smb_fname, - ft->create_time); - } - out: END_PROFILE(syscall_ntimes); return result; diff --git a/source3/modules/vfs_full_audit.c b/source3/modules/vfs_full_audit.c index 4089f22..6930a55 100644 --- a/source3/modules/vfs_full_audit.c +++ b/source3/modules/vfs_full_audit.c @@ -710,11 +710,11 @@ static int smb_full_audit_statvfs(struct vfs_handle_struct *handle, return result; } -static uint32_t smb_full_audit_fs_capabilities(struct vfs_handle_struct *handle) +static uint32_t smb_full_audit_fs_capabilities(struct vfs_handle_struct *handle, enum timestamp_set_resolution *p_ts_res) { int result; - result = SMB_VFS_NEXT_FS_CAPABILITIES(handle); + result = SMB_VFS_NEXT_FS_CAPABILITIES(handle, p_ts_res); do_log(SMB_VFS_OP_FS_CAPABILITIES, true, handle, ""); diff --git a/source3/modules/vfs_onefs.c b/source3/modules/vfs_onefs.c index 31f0b85..865eccd 100644 --- a/source3/modules/vfs_onefs.c +++ b/source3/modules/vfs_onefs.c @@ -234,7 +234,7 @@ static int onefs_ntimes(vfs_handle_struct *handle, return onefs_vtimes_streams(handle, smb_fname, flags, times); } -static uint32_t onefs_fs_capabilities(struct vfs_handle_struct *handle) +static uint32_t onefs_fs_capabilities(struct vfs_handle_struct *handle, enum timestamp_set_resolution *p_ts_res) { uint32_t result = 0; @@ -243,7 +243,9 @@ static uint32_t onefs_fs_capabilities(struct vfs_handle_struct *handle) result |= FILE_NAMED_STREAMS; } - return result | SMB_VFS_NEXT_FS_CAPABILITIES(handle); + result |= SMB_VFS_NEXT_FS_CAPABILITIES(handle, p_ts_res); + *p_ts_res = TIMESTAMP_SET_MSEC; + return result; } static struct vfs_fn_pointers onefs_fns = { diff --git a/source3/modules/vfs_streams_depot.c b/source3/modules/vfs_streams_depot.c index 2581c7f..d09255a 100644 --- a/source3/modules/vfs_streams_depot.c +++ b/source3/modules/vfs_streams_depot.c @@ -875,9 +875,10 @@ static NTSTATUS streams_depot_streaminfo(vfs_handle_struct *handle, return status; } -static uint32_t streams_depot_fs_capabilities(struct vfs_handle_struct *handle) +static uint32_t streams_depot_fs_capabilities(struct vfs_handle_struct *handle, + enum timestamp_set_resolution *p_ts_res) { - return SMB_VFS_NEXT_FS_CAPABILITIES(handle) | FILE_NAMED_STREAMS; + return SMB_VFS_NEXT_FS_CAPABILITIES(handle, p_ts_res) | FILE_NAMED_STREAMS; } static struct vfs_fn_pointers vfs_streams_depot_fns = { diff --git a/source3/modules/vfs_streams_xattr.c b/source3/modules/vfs_streams_xattr.c index 3ec38d6..033d027 100644 --- a/source3/modules/vfs_streams_xattr.c +++ b/source3/modules/vfs_streams_xattr.c @@ -837,9 +837,10 @@ static NTSTATUS streams_xattr_streaminfo(vfs_handle_struct *handle, return NT_STATUS_OK; } -static uint32_t streams_xattr_fs_capabilities(struct vfs_handle_struct *handle) +static uint32_t streams_xattr_fs_capabilities(struct vfs_handle_struct *handle, + enum timestamp_set_resolution *p_ts_res) { - return SMB_VFS_NEXT_FS_CAPABILITIES(handle) | FILE_NAMED_STREAMS; + return SMB_VFS_NEXT_FS_CAPABILITIES(handle, p_ts_res) | FILE_NAMED_STREAMS; } static ssize_t streams_xattr_pwrite(vfs_handle_struct *handle, diff --git a/source3/modules/vfs_tsmsm.c b/source3/modules/vfs_tsmsm.c index 19dc79b..b510432 100644 --- a/source3/modules/vfs_tsmsm.c +++ b/source3/modules/vfs_tsmsm.c @@ -357,9 +357,10 @@ static int tsmsm_set_offline(struct vfs_handle_struct *handle, return result; } -static uint32_t tsmsm_fs_capabilities(struct vfs_handle_struct *handle) +static uint32_t tsmsm_fs_capabilities(struct vfs_handle_struct *handle, + enum timestamp_set_resolution *p_ts_res) { - return SMB_VFS_NEXT_FS_CAPABILITIES(handle) | FILE_SUPPORTS_REMOTE_STORAGE | FILE_SUPPORTS_REPARSE_POINTS; + return SMB_VFS_NEXT_FS_CAPABILITIES(handle, p_ts_res) | FILE_SUPPORTS_REMOTE_STORAGE | FILE_SUPPORTS_REPARSE_POINTS; } static struct vfs_fn_pointers tsmsm_fns = { diff --git a/source3/smbd/dosmode.c b/source3/smbd/dosmode.c index e9345cc..7cb84b3 100644 --- a/source3/smbd/dosmode.c +++ b/source3/smbd/dosmode.c @@ -868,7 +868,7 @@ NTSTATUS set_create_timespec_ea(connection_struct *conn, return NT_STATUS_OK; } - put_long_date_timespec(buf, create_time); + put_long_date_timespec(conn->ts_res, buf, create_time); if (fsp && fsp->fh->fd != -1) { ret = SMB_VFS_FSETXATTR(fsp, SAMBA_XATTR_DOSTIMESTAMPS, diff --git a/source3/smbd/msdfs.c b/source3/smbd/msdfs.c index 767c8fe..74e4652 100644 --- a/source3/smbd/msdfs.c +++ b/source3/smbd/msdfs.c @@ -272,7 +272,7 @@ NTSTATUS create_conn_struct(TALLOC_CTX *ctx, return status; } - conn->fs_capabilities = SMB_VFS_FS_CAPABILITIES(conn); + conn->fs_capabilities = SMB_VFS_FS_CAPABILITIES(conn, &conn->ts_res); /* * Windows seems to insist on doing trans2getdfsreferral() calls on diff --git a/source3/smbd/nttrans.c b/source3/smbd/nttrans.c index 03fdff3..434bf34 100644 --- a/source3/smbd/nttrans.c +++ b/source3/smbd/nttrans.c @@ -608,13 +608,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; @@ -1106,13 +1106,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; diff --git a/source3/smbd/open.c b/source3/smbd/open.c index 9b4eedf..0456355 100644 --- a/source3/smbd/open.c +++ b/source3/smbd/open.c @@ -3284,12 +3284,8 @@ static NTSTATUS create_file_unixpath(connection_struct *conn, /* Try and make a create timestamp, if required. */ if ((info == FILE_WAS_CREATED) || (info == FILE_WAS_OVERWRITTEN)) { if (lp_store_create_time(SNUM(conn))) { - struct timespec ts = smb_fname->st.st_ex_btime; - if (!conn->hires_timestamps_avail) { - round_timespec(&ts); - } set_create_timespec_ea(conn, fsp, - smb_fname, ts); + smb_fname, smb_fname->st.st_ex_btime); } } diff --git a/source3/smbd/service.c b/source3/smbd/service.c index 36b783e..3520f0d 100644 --- a/source3/smbd/service.c +++ b/source3/smbd/service.c @@ -1015,23 +1015,6 @@ connection_struct *make_connection_snum(struct smbd_server_connection *sconn, goto err_root_exit; } - if (smb_fname_cpath->st.st_ex_mtime.tv_nsec || - smb_fname_cpath->st.st_ex_atime.tv_nsec || - smb_fname_cpath->st.st_ex_ctime.tv_nsec) { - /* If any of the normal UNIX directory timestamps - * have a non-zero tv_nsec component assume - * we can fully store hires timestamps. We need - * to make a runtime/share level distinction - * as on Linux ext3 doesn't have hires timestamps, but - * ext4 does, so a compile time test won't work. JRA. - */ - DEBUG(10,("make_connection_snum: hires timestamps " - "available on share %s, directory %s\n", - lp_servicename(snum), - conn->connectpath )); - conn->hires_timestamps_avail = true; - } - string_set(&conn->origpath,conn->connectpath); #if SOFTLINK_OPTIMISATION @@ -1056,7 +1039,7 @@ connection_struct *make_connection_snum(struct smbd_server_connection *sconn, * the same characteristics, which is likely but not guaranteed. */ - conn->fs_capabilities = SMB_VFS_FS_CAPABILITIES(conn); + conn->fs_capabilities = SMB_VFS_FS_CAPABILITIES(conn, &conn->ts_res); /* * Print out the 'connected as' stuff here as we need diff --git a/source3/smbd/trans2.c b/source3/smbd/trans2.c index a1043e2..da23697 100644 --- a/source3/smbd/trans2.c +++ b/source3/smbd/trans2.c @@ -1669,10 +1669,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; @@ -1735,10 +1735,10 @@ static bool smbd_marshall_dir_entry(TALLOC_CTX *ctx, 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; @@ -1771,10 +1771,10 @@ static bool smbd_marshall_dir_entry(TALLOC_CTX *ctx, 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; @@ -1846,10 +1846,10 @@ static bool smbd_marshall_dir_entry(TALLOC_CTX *ctx, 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; @@ -1893,10 +1893,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; @@ -3855,9 +3855,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 */ @@ -3991,7 +3991,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); @@ -4408,10 +4408,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 - ")); @@ -4503,10 +4503,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; @@ -4535,10 +4535,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); @@ -4668,10 +4668,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); @@ -5402,25 +5402,13 @@ NTSTATUS smb_set_file_time(connection_struct *conn, action &= ~FILE_NOTIFY_CHANGE_LAST_WRITE; } - if (!conn->hires_timestamps_avail) { - /* We can't store sub second timestamps - * on this share. Round to seconds. */ - round_timespec(&ft->create_time); - round_timespec(&ft->ctime); - round_timespec(&ft->atime); - round_timespec(&ft->mtime); - } else { - /* The highest resolution timestamp - * setting function available in POSIX - * is utimes(), which uses usec resolution, - * not nsec resolution. So we must round to - * usec, then back to nsec. JRA. - */ - round_timespec_to_usec(&ft->create_time); - round_timespec_to_usec(&ft->ctime); - round_timespec_to_usec(&ft->atime); - round_timespec_to_usec(&ft->mtime); - } + /* 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)))); diff --git a/source3/smbd/vfs.c b/source3/smbd/vfs.c index 75fd839..5425c55 100644 --- a/source3/smbd/vfs.c +++ b/source3/smbd/vfs.c @@ -1096,10 +1096,11 @@ int smb_vfs_call_statvfs(struct vfs_handle_struct *handle, const char *path, return handle->fns->statvfs(handle, path, statbuf); } -uint32_t smb_vfs_call_fs_capabilities(struct vfs_handle_struct *handle) +uint32_t smb_vfs_call_fs_capabilities(struct vfs_handle_struct *handle, + enum timestamp_set_resolution *p_ts_res) { VFS_FIND(fs_capabilities); - return handle->fns->fs_capabilities(handle); + return handle->fns->fs_capabilities(handle, p_ts_res); } SMB_STRUCT_DIR *smb_vfs_call_opendir(struct vfs_handle_struct *handle,