summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--source3/include/includes.h2
-rw-r--r--source3/include/proto.h1
-rw-r--r--source3/lib/system.c72
-rw-r--r--source3/smbd/nttrans.c18
-rw-r--r--source3/smbd/reply.c28
-rw-r--r--source3/smbd/trans2.c21
6 files changed, 118 insertions, 24 deletions
diff --git a/source3/include/includes.h b/source3/include/includes.h
index 2b36d18257..8fb240f26c 100644
--- a/source3/include/includes.h
+++ b/source3/include/includes.h
@@ -460,6 +460,8 @@ struct stat_ex {
struct timespec st_ex_mtime;
struct timespec st_ex_ctime;
struct timespec st_ex_btime; /* birthtime */
+ /* Is birthtime real, or was it calculated ? */
+ bool st_ex_calculated_birthtime;
blksize_t st_ex_blksize;
blkcnt_t st_ex_blocks;
diff --git a/source3/include/proto.h b/source3/include/proto.h
index 0315f304bb..25a104d82d 100644
--- a/source3/include/proto.h
+++ b/source3/include/proto.h
@@ -911,6 +911,7 @@ ssize_t sys_recv(int fd, void *buf, size_t count, int flags);
ssize_t sys_recvfrom(int s, void *buf, size_t len, int flags, struct sockaddr *from, socklen_t *fromlen);
int sys_fcntl_ptr(int fd, int cmd, void *arg);
int sys_fcntl_long(int fd, int cmd, long arg);
+void update_stat_ex_writetime(struct stat_ex *dst, struct timespec write_ts);
int sys_stat(const char *fname,SMB_STRUCT_STAT *sbuf);
int sys_fstat(int fd,SMB_STRUCT_STAT *sbuf);
int sys_lstat(const char *fname,SMB_STRUCT_STAT *sbuf);
diff --git a/source3/lib/system.c b/source3/lib/system.c
index 47bb5259cc..b808a36d17 100644
--- a/source3/lib/system.c
+++ b/source3/lib/system.c
@@ -404,7 +404,7 @@ static struct timespec get_ctimespec(const struct stat *pst)
structure.
****************************************************************************/
-static struct timespec calc_create_time(const struct stat *st)
+static struct timespec calc_create_time_stat(const struct stat *st)
{
struct timespec ret, ret1;
struct timespec c_time = get_ctimespec(st);
@@ -426,41 +426,85 @@ static struct timespec calc_create_time(const struct stat *st)
}
/****************************************************************************
+ Return the best approximation to a 'create time' under UNIX from a stat_ex
+ structure.
+****************************************************************************/
+
+static struct timespec calc_create_time_stat_ex(const struct stat_ex *st)
+{
+ struct timespec ret, ret1;
+ struct timespec c_time = st->st_ex_ctime;
+ struct timespec m_time = st->st_ex_mtime;
+ struct timespec a_time = st->st_ex_atime;
+
+ ret = timespec_compare(&c_time, &m_time) < 0 ? c_time : m_time;
+ ret1 = timespec_compare(&ret, &a_time) < 0 ? ret : a_time;
+
+ if(!null_timespec(ret1)) {
+ return ret1;
+ }
+
+ /*
+ * One of ctime, mtime or atime was zero (probably atime).
+ * Just return MIN(ctime, mtime).
+ */
+ return ret;
+}
+
+/****************************************************************************
Return the 'create time' from a stat struct if it exists (birthtime) or else
use the best approximation.
****************************************************************************/
-static struct timespec get_create_timespec(const struct stat *pst)
+static void get_create_timespec(const struct stat *pst, struct stat_ex *dst)
{
struct timespec ret;
if (S_ISDIR(pst->st_mode) && lp_fake_dir_create_times()) {
- ret.tv_sec = 315493200L; /* 1/1/1980 */
- ret.tv_nsec = 0;
- return ret;
+ dst->st_ex_btime.tv_sec = 315493200L; /* 1/1/1980 */
+ dst->st_ex_btime.tv_nsec = 0;
}
+ dst->st_ex_calculated_birthtime = false;
+
#if defined(HAVE_STRUCT_STAT_ST_BIRTHTIMESPEC_TV_NSEC)
- ret = pst->st_birthtimespec;
+ dst->st_ex_btime = pst->st_birthtimespec;
#elif defined(HAVE_STRUCT_STAT_ST_BIRTHTIMENSEC)
- ret.tv_sec = pst->st_birthtime;
- ret.tv_nsec = pst->st_birthtimenspec;
+ dst->st_ex_btime.tv_sec = pst->st_birthtime;
+ dst->st_ex_btime.tv_nsec = pst->st_birthtimenspec;
#elif defined(HAVE_STRUCT_STAT_ST_BIRTHTIME)
- ret.tv_sec = pst->st_birthtime;
- ret.tv_nsec = 0;
+ dst->st_ex_btime.tv_sec = pst->st_birthtime;
+ dst->st_ex_btime.tv_nsec = 0;
#else
- ret = calc_create_time(pst);
+ dst->st_ex_btime = calc_create_time_stat(pst);
+ dst->st_ex_calculated_birthtime = true;
#endif
/* Deal with systems that don't initialize birthtime correctly.
* Pointed out by SATOH Fumiyasu <fumiyas@osstech.jp>.
*/
if (null_timespec(ret)) {
- ret = calc_create_time(pst);
+ dst->st_ex_btime = calc_create_time_stat(pst);
+ dst->st_ex_calculated_birthtime = true;
}
- return ret;
}
+/****************************************************************************
+ If we update a timestamp in a stat_ex struct we may have to recalculate
+ the birthtime. For now only implement this for write time, but we may
+ also need to do it for mtime and ctime. JRA.
+****************************************************************************/
+
+void update_stat_ex_writetime(struct stat_ex *dst,
+ struct timespec write_ts)
+{
+ dst->st_ex_mtime = write_ts;
+
+ /* We may have to recalculate btime. */
+ if (dst->st_ex_calculated_birthtime) {
+ dst->st_ex_btime = calc_create_time_stat_ex(dst);
+ }
+}
static void init_stat_ex_from_stat (struct stat_ex *dst,
const struct stat *src)
@@ -476,7 +520,7 @@ static void init_stat_ex_from_stat (struct stat_ex *dst,
dst->st_ex_atime = get_atimespec(src);
dst->st_ex_mtime = get_mtimespec(src);
dst->st_ex_ctime = get_ctimespec(src);
- dst->st_ex_btime = get_create_timespec(src);
+ get_create_timespec(src, dst);
dst->st_ex_blksize = src->st_blksize;
dst->st_ex_blocks = src->st_blocks;
diff --git a/source3/smbd/nttrans.c b/source3/smbd/nttrans.c
index b970ffc05e..4f75b9f120 100644
--- a/source3/smbd/nttrans.c
+++ b/source3/smbd/nttrans.c
@@ -473,6 +473,7 @@ void reply_ntcreate_and_X(struct smb_request *req)
struct timespec c_timespec;
struct timespec a_timespec;
struct timespec m_timespec;
+ struct timespec write_time_ts;
NTSTATUS status;
int oplock_request;
uint8_t oplock_granted = NO_OPLOCK_RETURN;
@@ -651,6 +652,14 @@ void reply_ntcreate_and_X(struct smb_request *req)
}
p += 4;
+ /* Deal with other possible opens having a modified
+ write time. JRA. */
+ ZERO_STRUCT(write_time_ts);
+ get_file_infos(fsp->file_id, NULL, &write_time_ts);
+ if (!null_timespec(write_time_ts)) {
+ update_stat_ex_writetime(&smb_fname->st, write_time_ts);
+ }
+
/* Create time. */
c_timespec = smb_fname->st.st_ex_btime;
a_timespec = smb_fname->st.st_ex_atime;
@@ -908,6 +917,7 @@ static void call_nt_transact_create(connection_struct *conn,
struct timespec c_timespec;
struct timespec a_timespec;
struct timespec m_timespec;
+ struct timespec write_time_ts;
struct ea_list *ea_list = NULL;
NTSTATUS status;
size_t param_len;
@@ -1133,6 +1143,14 @@ static void call_nt_transact_create(connection_struct *conn,
}
p += 8;
+ /* Deal with other possible opens having a modified
+ write time. JRA. */
+ ZERO_STRUCT(write_time_ts);
+ get_file_infos(fsp->file_id, NULL, &write_time_ts);
+ if (!null_timespec(write_time_ts)) {
+ update_stat_ex_writetime(&smb_fname->st, write_time_ts);
+ }
+
/* Create time. */
c_timespec = smb_fname->st.st_ex_btime;
a_timespec = smb_fname->st.st_ex_atime;
diff --git a/source3/smbd/reply.c b/source3/smbd/reply.c
index c07ac33679..e02482ea4a 100644
--- a/source3/smbd/reply.c
+++ b/source3/smbd/reply.c
@@ -1065,6 +1065,7 @@ void reply_getatr(struct smb_request *req)
const char *p;
NTSTATUS status;
TALLOC_CTX *ctx = talloc_tos();
+ bool ask_sharemode = lp_parm_bool(SNUM(conn), "smbd", "search ask sharemode", true);
START_PROFILE(SMBgetatr);
@@ -1111,6 +1112,19 @@ void reply_getatr(struct smb_request *req)
mode = dos_mode(conn, fname, &smb_fname->st);
size = smb_fname->st.st_ex_size;
+
+ if (ask_sharemode) {
+ struct timespec write_time_ts;
+ struct file_id fileid;
+
+ ZERO_STRUCT(write_time_ts);
+ fileid = vfs_file_id_from_sbuf(conn, &smb_fname->st);
+ get_file_infos(fileid, NULL, &write_time_ts);
+ if (!null_timespec(write_time_ts)) {
+ update_stat_ex_writetime(&smb_fname->st, write_time_ts);
+ }
+ }
+
mtime = convert_timespec_to_time_t(smb_fname->st.st_ex_mtime);
if (mode & aDIR) {
size = 0;
@@ -1707,6 +1721,7 @@ void reply_open(struct smb_request *req)
uint32 create_disposition;
uint32 create_options = 0;
NTSTATUS status;
+ bool ask_sharemode = lp_parm_bool(SNUM(conn), "smbd", "search ask sharemode", true);
TALLOC_CTX *ctx = talloc_tos();
START_PROFILE(SMBopen);
@@ -1779,6 +1794,19 @@ void reply_open(struct smb_request *req)
size = smb_fname->st.st_ex_size;
fattr = dos_mode(conn,fsp->fsp_name,&smb_fname->st);
+
+ /* Deal with other possible opens having a modified
+ write time. JRA. */
+ if (ask_sharemode) {
+ struct timespec write_time_ts;
+
+ ZERO_STRUCT(write_time_ts);
+ get_file_infos(fsp->file_id, NULL, &write_time_ts);
+ if (!null_timespec(write_time_ts)) {
+ update_stat_ex_writetime(&smb_fname->st, write_time_ts);
+ }
+ }
+
mtime = convert_timespec_to_time_t(smb_fname->st.st_ex_mtime);
if (fattr & aDIR) {
diff --git a/source3/smbd/trans2.c b/source3/smbd/trans2.c
index e5f8039e6e..cb4f10fa79 100644
--- a/source3/smbd/trans2.c
+++ b/source3/smbd/trans2.c
@@ -1455,21 +1455,22 @@ static bool get_lanman2_dir_entry(TALLOC_CTX *ctx,
}
allocation_size = SMB_VFS_GET_ALLOC_SIZE(conn,NULL,&sbuf);
- mdate_ts = sbuf.st_ex_mtime;
- adate_ts = sbuf.st_ex_atime;
- create_date_ts = sbuf.st_ex_btime;
-
if (ask_sharemode) {
struct timespec write_time_ts;
struct file_id fileid;
+ ZERO_STRUCT(write_time_ts);
fileid = vfs_file_id_from_sbuf(conn, &sbuf);
get_file_infos(fileid, NULL, &write_time_ts);
if (!null_timespec(write_time_ts)) {
- mdate_ts = write_time_ts;
+ update_stat_ex_writetime(&sbuf, write_time_ts);
}
}
+ mdate_ts = sbuf.st_ex_mtime;
+ adate_ts = sbuf.st_ex_atime;
+ create_date_ts = sbuf.st_ex_btime;
+
if (lp_dos_filetime_resolution(SNUM(conn))) {
dos_filetime_timespec(&create_date_ts);
dos_filetime_timespec(&mdate_ts);
@@ -4244,10 +4245,6 @@ total_data=%u (should be %u)\n", (unsigned int)total_data, (unsigned int)IVAL(pd
dstart = pdata;
dend = dstart + data_size - 1;
- create_time_ts = sbuf.st_ex_btime;
- mtime_ts = sbuf.st_ex_mtime;
- atime_ts = sbuf.st_ex_atime;
-
allocation_size = SMB_VFS_GET_ALLOC_SIZE(conn,fsp,&sbuf);
if (!fsp) {
@@ -4261,9 +4258,13 @@ total_data=%u (should be %u)\n", (unsigned int)total_data, (unsigned int)IVAL(pd
}
if (!null_timespec(write_time_ts) && !INFO_LEVEL_IS_UNIX(info_level)) {
- mtime_ts = write_time_ts;
+ update_stat_ex_writetime(&sbuf, write_time_ts);
}
+ create_time_ts = sbuf.st_ex_btime;
+ mtime_ts = sbuf.st_ex_mtime;
+ atime_ts = sbuf.st_ex_atime;
+
if (lp_dos_filetime_resolution(SNUM(conn))) {
dos_filetime_timespec(&create_time_ts);
dos_filetime_timespec(&mtime_ts);