summaryrefslogtreecommitdiff
path: root/source3/modules/vfs_default.c
diff options
context:
space:
mode:
Diffstat (limited to 'source3/modules/vfs_default.c')
-rw-r--r--source3/modules/vfs_default.c80
1 files changed, 68 insertions, 12 deletions
diff --git a/source3/modules/vfs_default.c b/source3/modules/vfs_default.c
index a793b337a8..b70868eb9f 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;