1) Add in smb_file_time struct to clarify code and make room for createtime.
2) Get and set create time from SMB messages.
3) Fixup existing VFS modules + examples Some OS'es allow for the
setting of the birthtime through kernel interfaces. This value is
generically used for Windows createtime, but is not settable in the
code today.
return vfswrap_getwd(NULL, buf);
}
-static int skel_ntimes(vfs_handle_struct *handle, const char *path, const struct timespec ts[2])
+static int skel_ntimes(vfs_handle_struct *handle, const char *path, struct smb_file_time *ft)
{
- return vfswrap_ntimes(NULL, path, ts);
+ return vfswrap_ntimes(NULL, path, ft);
}
static int skel_ftruncate(vfs_handle_struct *handle, files_struct *fsp, SMB_OFF_T offset)
return SMB_VFS_NEXT_GETWD(handle, buf);
}
-static int skel_ntimes(vfs_handle_struct *handle, const char *path, const struct timespec ts[2])
+static int skel_ntimes(vfs_handle_struct *handle, const char *path, struct smb_file_time *ft)
{
- return SMB_VFS_NEXT_NTIMES(handle, path, ts);
+ return SMB_VFS_NEXT_NTIMES(handle, path, ft);
}
static int skel_ftruncate(vfs_handle_struct *handle, files_struct *fsp, SMB_OFF_T offset)
uint32 dosmode, SMB_STRUCT_STAT *st,
const char *parent_dir,
bool newfile);
-int file_ntimes(connection_struct *conn, const char *fname, const struct timespec ts[2]);
+int file_ntimes(connection_struct *conn, const char *fname,
+ struct smb_file_time *ft);
bool set_sticky_write_time_path(connection_struct *conn, const char *fname,
struct file_id fileid, const struct timespec mtime);
bool set_sticky_write_time_fsp(struct files_struct *fsp, const struct timespec mtime);
files_struct *fsp,
const char *fname,
const SMB_STRUCT_STAT *psbuf,
- struct timespec ts[2],
+ struct smb_file_time *ft,
bool setting_write_time);
void reply_findclose(struct smb_request *req);
void reply_findnclose(struct smb_request *req);
*/
#define CFF_DOS_PATH 0x00000001
+/* time info */
+struct smb_file_time {
+ struct timespec mtime;
+ struct timespec atime;
+ struct timespec create_time;
+};
+
#endif /* _SMB_H */
/* Changed to version 24 - make security descriptor const in fset_nt_acl. JRA. */
/* Changed to version 25 - Jelmer's change from SMB_BIG_UINT to uint64_t. */
/* Leave at 25 - not yet released. Add create_file call. -- tprouty. */
+/* Leave at 25 - not yet released. Add create time to ntimes. -- tstecher. */
#define SMB_VFS_INTERFACE_VERSION 25
struct vfs_statvfs_struct;
struct smb_request;
struct ea_list;
+struct smb_file_time;
/*
Available VFS operations. These values must be in sync with vfs_ops struct
int (*lchown)(struct vfs_handle_struct *handle, const char *path, uid_t uid, gid_t gid);
int (*chdir)(struct vfs_handle_struct *handle, const char *path);
char *(*getwd)(struct vfs_handle_struct *handle, char *buf);
- int (*ntimes)(struct vfs_handle_struct *handle, const char *path, const struct timespec ts[2]);
+ int (*ntimes)(struct vfs_handle_struct *handle, const char *path, struct smb_file_time *ft);
int (*ftruncate)(struct vfs_handle_struct *handle, struct files_struct *fsp, SMB_OFF_T offset);
bool (*lock)(struct vfs_handle_struct *handle, struct files_struct *fsp, int op, SMB_OFF_T offset, SMB_OFF_T count, int type);
int (*kernel_flock)(struct vfs_handle_struct *handle, struct files_struct *fsp, uint32 share_mode);
return SMB_VFS_NEXT_CHDIR(handle, cappath);
}
-static int cap_ntimes(vfs_handle_struct *handle, const char *path, const struct timespec ts[2])
+static int cap_ntimes(vfs_handle_struct *handle, const char *path,
+ struct smb_file_time *ft)
{
char *cappath = capencode(talloc_tos(), path);
errno = ENOMEM;
return -1;
}
- return SMB_VFS_NEXT_NTIMES(handle, cappath, ts);
+ return SMB_VFS_NEXT_NTIMES(handle, cappath, ft);
}
}
static int catia_ntimes(vfs_handle_struct *handle,
- const char *path, const struct timespec ts[2])
+ const char *path, struct smb_file_time *ft)
{
- return SMB_VFS_NEXT_NTIMES(handle, path, ts);
+ return SMB_VFS_NEXT_NTIMES(handle, path, ft);
}
static bool catia_symlink(vfs_handle_struct *handle,
system will support.
**********************************************************************/
-static int vfswrap_ntimes(vfs_handle_struct *handle, const char *path, const struct timespec ts[2])
+static int vfswrap_ntimes(vfs_handle_struct *handle, const char *path,
+ struct smb_file_time *ft)
{
int result;
START_PROFILE(syscall_ntimes);
#if defined(HAVE_UTIMES)
- if (ts != NULL) {
+ if (ft != NULL) {
struct timeval tv[2];
- tv[0] = convert_timespec_to_timeval(ts[0]);
- tv[1] = convert_timespec_to_timeval(ts[1]);
+ tv[0] = convert_timespec_to_timeval(ft->atime);
+ tv[1] = convert_timespec_to_timeval(ft->mtime);
result = utimes(path, tv);
} else {
result = utimes(path, NULL);
}
#elif defined(HAVE_UTIME)
- if (ts != NULL) {
+ if (ft != NULL) {
struct utimbuf times;
- times.actime = convert_timespec_to_time_t(ts[0]);
- times.modtime = convert_timespec_to_time_t(ts[1]);
+ times.actime = convert_timespec_to_time_t(ft->atime);
+ times.modtime = convert_timespec_to_time_t(ft->mtime);
result = utime(path, times);
} else {
result = utime(path, NULL);
static char *smb_full_audit_getwd(vfs_handle_struct *handle,
char *path);
static int smb_full_audit_ntimes(vfs_handle_struct *handle,
- const char *path, const struct timespec ts[2]);
+ const char *path, struct smb_file_time *ft);
static int smb_full_audit_ftruncate(vfs_handle_struct *handle, files_struct *fsp,
SMB_OFF_T len);
static bool smb_full_audit_lock(vfs_handle_struct *handle, files_struct *fsp,
}
static int smb_full_audit_ntimes(vfs_handle_struct *handle,
- const char *path, const struct timespec ts[2])
+ const char *path, struct smb_file_time *ft)
{
int result;
- result = SMB_VFS_NEXT_NTIMES(handle, path, ts);
+ result = SMB_VFS_NEXT_NTIMES(handle, path, ft);
do_log(SMB_VFS_OP_NTIMES, (result >= 0), handle, "%s", path);
bool touch_mtime)
{
SMB_STRUCT_STAT st;
- struct timespec ts[2];
+ struct smb_file_time ft;
int ret, err;
+ ZERO_STRUCT(ft);
+
if (SMB_VFS_NEXT_STAT(handle, fname, &st) != 0) {
DEBUG(0,("recycle: stat for %s returned %s\n",
fname, strerror(errno)));
return;
}
- ts[0] = timespec_current(); /* atime */
- ts[1] = touch_mtime ? ts[0] : get_mtimespec(&st); /* mtime */
+ ft.atime = timespec_current(); /* atime */
+ ft.mtime = touch_mtime ? ft.atime : get_mtimespec(&st); /* mtime */
become_root();
- ret = SMB_VFS_NEXT_NTIMES(handle, fname, ts);
+ ret = SMB_VFS_NEXT_NTIMES(handle, fname, &ft);
err = errno;
unbecome_root();
if (ret == -1 ) {
}
static int shadow_copy2_ntimes(vfs_handle_struct *handle,
- const char *fname, const struct timespec ts[2])
+ const char *fname, struct smb_file_time *ft)
{
- SHADOW2_NEXT(NTIMES, (handle, name, ts), int, -1);
+ SHADOW2_NEXT(NTIMES, (handle, name, ft), int, -1);
}
static int shadow_copy2_readlink(vfs_handle_struct *handle,
static NTSTATUS update_write_time_on_close(struct files_struct *fsp)
{
SMB_STRUCT_STAT sbuf;
- struct timespec ts[2];
+ struct smb_file_time ft;
NTSTATUS status;
ZERO_STRUCT(sbuf);
- ZERO_STRUCT(ts);
+ ZERO_STRUCT(ft);
if (!fsp->update_write_time_on_close) {
return NT_STATUS_OK;
return NT_STATUS_OK;
}
- ts[1] = fsp->close_write_time;
+ ft.mtime = fsp->close_write_time;
status = smb_set_file_time(fsp->conn, fsp, fsp->fsp_name,
- &sbuf, ts, true);
+ &sbuf, &ft, true);
if (!NT_STATUS_IS_OK(status)) {
return status;
}
than POSIX.
*******************************************************************/
-int file_ntimes(connection_struct *conn, const char *fname, const struct timespec ts[2])
+int file_ntimes(connection_struct *conn, const char *fname,
+ struct smb_file_time *ft)
{
SMB_STRUCT_STAT sbuf;
int ret = -1;
ZERO_STRUCT(sbuf);
DEBUG(6, ("file_ntime: actime: %s",
- time_to_asc(convert_timespec_to_time_t(ts[0]))));
+ time_to_asc(convert_timespec_to_time_t(ft->atime))));
DEBUG(6, ("file_ntime: modtime: %s",
- time_to_asc(convert_timespec_to_time_t(ts[1]))));
+ time_to_asc(convert_timespec_to_time_t(ft->mtime))));
+ DEBUG(6, ("file_ntime: createtime: %s",
+ time_to_asc(convert_timespec_to_time_t(ft->create_time))));
/* Don't update the time on read-only shares */
/* We need this as set_filetime (which can be called on
return 0;
}
- if(SMB_VFS_NTIMES(conn, fname, ts) == 0) {
+ if(SMB_VFS_NTIMES(conn, fname, ft) == 0) {
return 0;
}
if (can_write_to_file(conn, fname, &sbuf)) {
/* We are allowed to become root and change the filetime. */
become_root();
- ret = SMB_VFS_NTIMES(conn, fname, ts);
+ ret = SMB_VFS_NTIMES(conn, fname, ft);
unbecome_root();
}
void reply_setatr(struct smb_request *req)
{
- struct timespec ts[2];
+ struct smb_file_time ft;
connection_struct *conn = req->conn;
char *fname = NULL;
int mode;
START_PROFILE(SMBsetatr);
- ZERO_STRUCT(ts);
+ ZERO_STRUCT(ft);
if (req->wct < 2) {
reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
mode = SVAL(req->vwv+0, 0);
mtime = srv_make_unix_date3(req->vwv+1);
- ts[1] = convert_time_t_to_timespec(mtime);
+ ft.mtime = convert_time_t_to_timespec(mtime);
status = smb_set_file_time(conn, NULL, fname,
- &sbuf, ts, true);
+ &sbuf, &ft, true);
if (!NT_STATUS_IS_OK(status)) {
reply_unixerror(req, ERRDOS, ERRnoaccess);
END_PROFILE(SMBsetatr);
connection_struct *conn = req->conn;
char *fname = NULL;
uint32 fattr = 0;
- struct timespec ts[2];
+ struct smb_file_time ft;
files_struct *fsp;
int oplock_request = 0;
SMB_STRUCT_STAT sbuf;
TALLOC_CTX *ctx = talloc_tos();
START_PROFILE(SMBcreate);
+ ZERO_STRUCT(ft);
if (req->wct < 3) {
reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
fattr = SVAL(req->vwv+0, 0);
oplock_request = CORE_OPLOCK_REQUEST(req->inbuf);
- ts[1] = convert_time_t_to_timespec(srv_make_unix_date3(req->vwv+1));
- /* mtime. */
+ /* mtime. */
+ ft.mtime = convert_time_t_to_timespec(srv_make_unix_date3(req->vwv+1));
srvstr_get_path_req(ctx, req, &fname, (const char *)req->buf + 1,
STR_TERMINATE, &status);
return;
}
- ts[0] = get_atimespec(&sbuf); /* atime. */
- status = smb_set_file_time(conn, fsp, fsp->fsp_name, &sbuf, ts, true);
+ ft.atime = get_atimespec(&sbuf); /* atime. */
+ status = smb_set_file_time(conn, fsp, fsp->fsp_name, &sbuf, &ft, true);
if (!NT_STATUS_IS_OK(status)) {
END_PROFILE(SMBcreate);
reply_openerror(req, status);
void reply_setattrE(struct smb_request *req)
{
connection_struct *conn = req->conn;
- struct timespec ts[2];
+ struct smb_file_time ft;
files_struct *fsp;
SMB_STRUCT_STAT sbuf;
NTSTATUS status;
START_PROFILE(SMBsetattrE);
+ ZERO_STRUCT(ft);
if (req->wct < 7) {
reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
/*
- * Convert the DOS times into unix times. Ignore create
- * time as UNIX can't set this.
+ * Convert the DOS times into unix times.
*/
- ts[0] = convert_time_t_to_timespec(
- srv_make_unix_date2(req->vwv+3)); /* atime. */
- ts[1] = convert_time_t_to_timespec(
- srv_make_unix_date2(req->vwv+5)); /* mtime. */
+ ft.atime = convert_time_t_to_timespec(
+ srv_make_unix_date2(req->vwv+3));
+ ft.mtime = convert_time_t_to_timespec(
+ srv_make_unix_date2(req->vwv+5));
+ ft.create_time = convert_time_t_to_timespec(
+ srv_make_unix_date2(req->vwv+1));
reply_outbuf(req, 0, 0);
}
status = smb_set_file_time(conn, fsp, fsp->fsp_name,
- &sbuf, ts, true);
+ &sbuf, &ft, true);
if (!NT_STATUS_IS_OK(status)) {
reply_doserror(req, ERRDOS, ERRnoaccess);
END_PROFILE(SMBsetattrE);
return;
}
- DEBUG( 3, ( "reply_setattrE fnum=%d actime=%u modtime=%u\n",
+ DEBUG( 3, ( "reply_setattrE fnum=%d actime=%u modtime=%u "
+ " createtime=%u\n",
fsp->fnum,
- (unsigned int)ts[0].tv_sec,
- (unsigned int)ts[1].tv_sec));
+ (unsigned int)ft.atime.tv_sec,
+ (unsigned int)ft.mtime.tv_sec,
+ (unsigned int)ft.create_time.tv_sec
+ ));
END_PROFILE(SMBsetattrE);
return;
mdate_ts = get_mtimespec(&sbuf);
adate_ts = get_atimespec(&sbuf);
- create_date_ts = get_create_timespec(&sbuf,lp_fake_dir_create_times(SNUM(conn)));
+ create_date_ts = get_create_timespec(&sbuf,
+ lp_fake_dir_create_times(SNUM(conn)));
if (ask_sharemode) {
struct timespec write_time_ts;
mdate = convert_timespec_to_time_t(mdate_ts);
adate = convert_timespec_to_time_t(adate_ts);
- DEBUG(5,("get_lanman2_dir_entry: found %s fname=%s\n",pathreal,fname));
+ DEBUG(5,("get_lanman2_dir_entry: found %s fname=%s\n",
+ pathreal,fname));
found = True;
files_struct *fsp,
const char *fname,
const SMB_STRUCT_STAT *psbuf,
- struct timespec ts[2],
+ struct smb_file_time *ft,
bool setting_write_time)
{
uint32 action =
}
/* get some defaults (no modifications) if any info is zero or -1. */
- if (null_timespec(ts[0])) {
- ts[0] = get_atimespec(psbuf);
+ if (null_timespec(ft->atime)) {
+ ft->atime= get_atimespec(psbuf);
action &= ~FILE_NOTIFY_CHANGE_LAST_ACCESS;
}
- if (null_timespec(ts[1])) {
- ts[1] = get_mtimespec(psbuf);
+ if (null_timespec(ft->mtime)) {
+ ft->mtime = get_mtimespec(psbuf);
action &= ~FILE_NOTIFY_CHANGE_LAST_WRITE;
}
if (!setting_write_time) {
- /* ts[1] comes from change time, not write time. */
+ /* ft->mtime comes from change time, not write time. */
action &= ~FILE_NOTIFY_CHANGE_LAST_WRITE;
}
- DEBUG(6,("smb_set_file_time: actime: %s " , time_to_asc(convert_timespec_to_time_t(ts[0])) ));
- DEBUG(6,("smb_set_file_time: modtime: %s ", time_to_asc(convert_timespec_to_time_t(ts[1])) ));
+ 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 ",
+ time_to_asc(convert_timespec_to_time_t(ft->mtime))));
+ if (!null_timespec(ft->create_time)) {
+ DEBUG(5,("smb_set_file_time: createtime: %s\n ",
+ time_to_asc(convert_timespec_to_time_t(ft->create_time))));
+ }
/*
* Try and set the times of this file if
{
struct timespec mts = get_mtimespec(psbuf);
struct timespec ats = get_atimespec(psbuf);
- if ((timespec_compare(&ts[0], &ats) == 0) && (timespec_compare(&ts[1], &mts) == 0)) {
+ if ((timespec_compare(&ft->atime, &ats) == 0) &&
+ (timespec_compare(&ft->mtime, &mts) == 0)) {
return NT_STATUS_OK;
}
}
*/
DEBUG(10,("smb_set_file_time: setting pending modtime to %s\n",
- time_to_asc(convert_timespec_to_time_t(ts[1])) ));
+ time_to_asc(convert_timespec_to_time_t(ft->mtime))));
if (fsp != NULL) {
if (fsp->base_fsp) {
- set_sticky_write_time_fsp(fsp->base_fsp, ts[1]);
+ set_sticky_write_time_fsp(fsp->base_fsp,
+ ft->mtime);
} else {
- set_sticky_write_time_fsp(fsp, ts[1]);
+ set_sticky_write_time_fsp(fsp, ft->mtime);
}
} else {
set_sticky_write_time_path(conn, fname,
vfs_file_id_from_sbuf(conn, psbuf),
- ts[1]);
+ ft->mtime);
}
}
fname = fsp->base_fsp->fsp_name;
}
- if(file_ntimes(conn, fname, ts)!=0) {
+ if(file_ntimes(conn, fname, ft)!=0) {
return map_nt_error_from_unix(errno);
}
notify_fname(conn, NOTIFY_ACTION_MODIFIED, action, fname);
const char *fname,
const SMB_STRUCT_STAT *psbuf)
{
- struct timespec ts[2];
+ struct smb_file_time ft;
+ ZERO_STRUCT(ft);
if (total_data < 12) {
return NT_STATUS_INVALID_PARAMETER;
}
+ /* create time */
+ ft.create_time = interpret_long_date(pdata);
+
/* access time */
- ts[0] = convert_time_t_to_timespec(srv_make_unix_date2(pdata+l1_fdateLastAccess));
+ ft.atime = interpret_long_date(pdata + 8);
+
/* write time */
- ts[1] = convert_time_t_to_timespec(srv_make_unix_date2(pdata+l1_fdateLastWrite));
+ ft.mtime = interpret_long_date(pdata + 16);
DEBUG(10,("smb_set_info_standard: file %s\n",
fname ? fname : fsp->fsp_name ));
fsp,
fname,
psbuf,
- ts,
+ &ft,
true);
}
/* Patch to do this correctly from Paul Eggert <eggert@twinsun.com>. */
struct timespec write_time;
struct timespec changed_time;
+ struct smb_file_time ft;
uint32 dosmode = 0;
- struct timespec ts[2];
NTSTATUS status = NT_STATUS_OK;
bool setting_write_time = true;
+ ZERO_STRUCT(ft);
+
if (total_data < 36) {
return NT_STATUS_INVALID_PARAMETER;
}
/* Set the attributes */
dosmode = IVAL(pdata,32);
- status = smb_set_file_dosmode(conn,
- fname,
- psbuf,
- dosmode);
+ status = smb_set_file_dosmode(conn, fname, psbuf, dosmode);
if (!NT_STATUS_IS_OK(status)) {
return status;
}
- /* Ignore create time at offset pdata. */
/* access time */
- ts[0] = interpret_long_date(pdata+8);
+ ft.atime = interpret_long_date(pdata+8);
write_time = interpret_long_date(pdata+16);
changed_time = interpret_long_date(pdata+24);
/* mtime */
- ts[1] = timespec_min(&write_time, &changed_time);
+ ft.mtime = timespec_min(&write_time, &changed_time);
- if ((timespec_compare(&write_time, &ts[1]) == 1) && !null_timespec(write_time)) {
- ts[1] = write_time;
+ /* create time */
+ ft.create_time = interpret_long_date(pdata);
+
+ if ((timespec_compare(&write_time, &ft.mtime) == 1) &&
+ !null_timespec(write_time)) {
+ ft.mtime = write_time;
}
/* Prefer a defined time to an undefined one. */
- if (null_timespec(ts[1])) {
+ if (null_timespec(ft.mtime)) {
if (null_timespec(write_time)) {
- ts[1] = changed_time;
+ ft.mtime = changed_time;
setting_write_time = false;
} else {
- ts[1] = write_time;
+ ft.mtime = write_time;
}
}
fsp,
fname,
psbuf,
- ts,
+ &ft,
setting_write_time);
}
const char *fname,
SMB_STRUCT_STAT *psbuf)
{
- struct timespec ts[2];
+ struct smb_file_time ft;
uint32 raw_unixmode;
mode_t unixmode;
SMB_OFF_T size = 0;
bool delete_on_fail = False;
enum perm_type ptype;
+ ZERO_STRUCT(ft);
+
if (total_data < 100) {
return NT_STATUS_INVALID_PARAMETER;
}
#endif /* LARGE_SMB_OFF_T */
}
- ts[0] = interpret_long_date(pdata+24); /* access_time */
- ts[1] = interpret_long_date(pdata+32); /* modification_time */
+ ft.atime = interpret_long_date(pdata+24); /* access_time */
+ ft.mtime = interpret_long_date(pdata+32); /* modification_time */
set_owner = (uid_t)IVAL(pdata,40);
set_grp = (gid_t)IVAL(pdata,48);
raw_unixmode = IVAL(pdata,84);
/* Ensure we don't try and change anything else. */
raw_unixmode = SMB_MODE_NO_CHANGE;
size = get_file_size(*psbuf);
- ts[0] = get_atimespec(psbuf);
- ts[1] = get_mtimespec(psbuf);
+ ft.atime = get_atimespec(psbuf);
+ ft.mtime = get_mtimespec(psbuf);
/*
* We continue here as we might want to change the
* owner uid/gid.
fsp,
fname,
psbuf,
- ts,
+ &ft,
true);
}
static NTSTATUS cmd_utime(struct vfs_state *vfs, TALLOC_CTX *mem_ctx, int argc, const char **argv)
{
- struct timespec ts[2];
+ struct smb_file_time ft;
if (argc != 4) {
printf("Usage: utime <path> <access> <modify>\n");
return NT_STATUS_OK;
}
- ts[0] = convert_time_t_to_timespec(atoi(argv[2]));
- ts[1] = convert_time_t_to_timespec(atoi(argv[3]));
- if (SMB_VFS_NTIMES(vfs->conn, argv[1], ts) != 0) {
+
+ ZERO_STRUCT(ft);
+
+ ft.atime = convert_time_t_to_timespec(atoi(argv[2]));
+ ft.mtime = convert_time_t_to_timespec(atoi(argv[3]));
+ if (SMB_VFS_NTIMES(vfs->conn, argv[1], &ft) != 0) {
printf("utime: error=%d (%s)\n", errno, strerror(errno));
return NT_STATUS_UNSUCCESSFUL;
}