diff options
-rw-r--r-- | source3/include/includes.h | 2 | ||||
-rw-r--r-- | source3/include/proto.h | 1 | ||||
-rw-r--r-- | source3/lib/system.c | 72 | ||||
-rw-r--r-- | source3/smbd/nttrans.c | 18 | ||||
-rw-r--r-- | source3/smbd/reply.c | 28 | ||||
-rw-r--r-- | source3/smbd/trans2.c | 21 |
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); |