From db87303e2f07ed7a252a9c87f430387ab9d5589c Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Mon, 17 Dec 2007 18:46:01 +0100 Subject: [PATCH] first-part... metze --- source/include/smb.h | 4 ++ source/locking/locking.c | 99 +++++++++++++++++++++++++++++++++++++++++----- source/smbd/close.c | 5 +- source/smbd/dir.c | 8 ++++ source/smbd/open.c | 13 ++++-- source/smbd/oplock.c | 6 +- source/smbd/reply.c | 6 +- source/smbd/trans2.c | 24 +++++++++++- 8 files changed, 142 insertions(+), 23 deletions(-) diff --git a/source/include/smb.h b/source/include/smb.h index 3f2f223..9ae05a1 100644 --- a/source/include/smb.h +++ b/source/include/smb.h @@ -799,6 +799,8 @@ struct share_mode_lock { struct share_mode_entry *share_modes; UNIX_USER_TOKEN *delete_token; BOOL delete_on_close; + struct timespec old_write_time; + struct timespec changed_write_time; BOOL fresh; BOOL modified; }; @@ -813,6 +815,8 @@ struct locking_data { struct { int num_share_mode_entries; BOOL delete_on_close; + struct timespec old_write_time; + struct timespec changed_write_time; uint32 delete_token_size; /* Only valid if either of the two previous fields are True. */ diff --git a/source/locking/locking.c b/source/locking/locking.c index a0debcd..94a63e5 100644 --- a/source/locking/locking.c +++ b/source/locking/locking.c @@ -507,6 +507,7 @@ static BOOL parse_share_modes(TDB_DATA dbuf, struct share_mode_lock *lck) { struct locking_data *data; int i; + TALLOC_CTX *mem_ctx; if (dbuf.dsize < sizeof(struct locking_data)) { smb_panic("PANIC: parse_share_modes: buffer too short.\n"); @@ -515,12 +516,23 @@ static BOOL parse_share_modes(TDB_DATA dbuf, struct share_mode_lock *lck) data = (struct locking_data *)dbuf.dptr; lck->delete_on_close = data->u.s.delete_on_close; + lck->old_write_time = data->u.s.old_write_time; + lck->changed_write_time = data->u.s.changed_write_time; lck->num_share_modes = data->u.s.num_share_mode_entries; - DEBUG(10, ("parse_share_modes: delete_on_close: %d, " - "num_share_modes: %d\n", - lck->delete_on_close, - lck->num_share_modes)); + SMB_ASSERT((mem_ctx = talloc_init("parse_share_modes")) != NULL); + + DEBUG(10, ("parse_share_modes: del: %d, owrt: %s, cwrt: %s, tok: %u" + "num: %d\n", lck->delete_on_close, + timestring(mem_ctx, + convert_timespec_to_time_t(lck->old_write_time)), + timestring(mem_ctx, + convert_timespec_to_time_t( + lck->changed_write_time)), + (unsigned int)data->u.s.delete_token_size, + lck->num_share_modes)); + + TALLOC_FREE(mem_ctx); if ((lck->num_share_modes < 0) || (lck->num_share_modes > 1000000)) { DEBUG(0, ("invalid number of share modes: %d\n", @@ -641,6 +653,7 @@ static TDB_DATA unparse_share_modes(struct share_mode_lock *lck) ssize_t offset; ssize_t sp_len; uint32 delete_token_size; + TALLOC_CTX *mem_ctx; result.dptr = NULL; result.dsize = 0; @@ -674,11 +687,25 @@ static TDB_DATA unparse_share_modes(struct share_mode_lock *lck) ZERO_STRUCTP(data); data->u.s.num_share_mode_entries = lck->num_share_modes; data->u.s.delete_on_close = lck->delete_on_close; + data->u.s.old_write_time = lck->old_write_time; + data->u.s.changed_write_time = lck->changed_write_time; data->u.s.delete_token_size = delete_token_size; - DEBUG(10, ("unparse_share_modes: del: %d, tok = %u, num: %d\n", - data->u.s.delete_on_close, - (unsigned int)data->u.s.delete_token_size, - data->u.s.num_share_mode_entries)); + + SMB_ASSERT((mem_ctx = talloc_init("unparse_share_modes")) != NULL); + + DEBUG(10,("unparse_share_modes: " + "del: %d, owrt: %s cwrt: %s, tok: %u, num: %d\n", + data->u.s.delete_on_close, + timestring(mem_ctx, + convert_timespec_to_time_t(lck->old_write_time)), + timestring(mem_ctx, + convert_timespec_to_time_t( + lck->changed_write_time)), + (unsigned int)data->u.s.delete_token_size, + data->u.s.num_share_mode_entries)); + + TALLOC_FREE(mem_ctx); + memcpy(result.dptr + sizeof(*data), lck->share_modes, sizeof(struct share_mode_entry)*lck->num_share_modes); offset = sizeof(*data) + @@ -748,7 +775,8 @@ static int share_mode_lock_destructor(struct share_mode_lock *lck) struct share_mode_lock *get_share_mode_lock(TALLOC_CTX *mem_ctx, SMB_DEV_T dev, SMB_INO_T ino, const char *servicepath, - const char *fname) + const char *fname, + const struct timespec *old_write_time) { struct share_mode_lock *lck; TDB_DATA key = locking_key(dev, ino); @@ -771,6 +799,8 @@ struct share_mode_lock *get_share_mode_lock(TALLOC_CTX *mem_ctx, lck->share_modes = NULL; lck->delete_token = NULL; lck->delete_on_close = False; + ZERO_STRUCT(lck->old_write_time); + ZERO_STRUCT(lck->changed_write_time); lck->fresh = False; lck->modified = False; @@ -802,6 +832,9 @@ struct share_mode_lock *get_share_mode_lock(TALLOC_CTX *mem_ctx, TALLOC_FREE(lck); return NULL; } + lck->old_write_time = + (old_write_time != NULL) ? *old_write_time : + convert_time_t_to_timespec(-1); } else { if (!parse_share_modes(data, lck)) { DEBUG(0, ("Could not parse share modes\n")); @@ -925,6 +958,23 @@ BOOL get_delete_on_close_flag(SMB_DEV_T dev, SMB_INO_T inode) return result; } +struct timespec get_write_time(SMB_DEV_T dev, SMB_INO_T ino) +{ + struct timespec result; + struct share_mode_lock *lck; + + ZERO_STRUCT(result); + if (!(lck = get_share_mode_lock(NULL, dev, ino, NULL, NULL, NULL))) { + return result; + } + result = lck->changed_write_time; + if (null_timespec(result)) { + result = lck->old_write_time; + } + TALLOC_FREE(lck); + return result; +} + BOOL is_valid_share_mode_entry(const struct share_mode_entry *e) { int num_props = 0; @@ -1324,7 +1374,7 @@ BOOL set_delete_on_close(files_struct *fsp, BOOL delete_on_close, UNIX_USER_TOKE return True; } - lck = get_share_mode_lock(NULL, fsp->dev, fsp->inode, NULL, NULL); + lck = get_share_mode_lock(NULL, fsp->dev, fsp->inode, NULL, NULL, NULL); if (lck == NULL) { return False; } @@ -1364,6 +1414,35 @@ BOOL set_allow_initial_delete_on_close(struct share_mode_lock *lck, files_struct return True; } +BOOL set_write_time(SMB_DEV_T dev, SMB_INO_T ino, + struct timespec write_time, + bool overwrite) +{ + struct share_mode_lock *lck; + TALLOC_CTX *mem_ctx; + + SMB_ASSERT((mem_ctx = talloc_init("set_write_time")) != NULL); + + DEBUG(5,("set_write_time: %s overwrite=%d dev=%d ino=%d\n", + timestring(mem_ctx,convert_timespec_to_time_t(write_time)), + overwrite, (int)dev, (int)ino)); + + TALLOC_FREE(mem_ctx); + + lck = get_share_mode_lock(NULL, dev, ino, NULL, NULL, NULL); + if (lck == NULL) { + return False; + } + + if (overwrite || null_timespec(lck->changed_write_time)) { + lck->modified = True; + lck->changed_write_time = write_time; + } + + TALLOC_FREE(lck); + return True; +} + struct forall_state { void (*fn)(const struct share_mode_entry *entry, const char *sharepath, diff --git a/source/smbd/close.c b/source/smbd/close.c index a094d8a..07e433d 100644 --- a/source/smbd/close.c +++ b/source/smbd/close.c @@ -161,7 +161,8 @@ static NTSTATUS close_remove_share_mode(files_struct *fsp, * This prevents race conditions with the file being created. JRA. */ - lck = get_share_mode_lock(NULL, fsp->dev, fsp->inode, NULL, NULL); + lck = get_share_mode_lock(NULL, fsp->dev, fsp->inode, NULL, NULL, + NULL); if (lck == NULL) { DEBUG(0, ("close_remove_share_mode: Could not get share mode " @@ -424,7 +425,7 @@ static NTSTATUS close_directory(files_struct *fsp, enum file_close_type close_ty * reference to a directory also. */ - lck = get_share_mode_lock(NULL, fsp->dev, fsp->inode, NULL, NULL); + lck = get_share_mode_lock(NULL, fsp->dev, fsp->inode, NULL, NULL, NULL); if (lck == NULL) { DEBUG(0, ("close_directory: Could not get share mode lock for %s\n", fsp->fsp_name)); diff --git a/source/smbd/dir.c b/source/smbd/dir.c index 57ed1df..f661dbd 100644 --- a/source/smbd/dir.c +++ b/source/smbd/dir.c @@ -807,6 +807,8 @@ BOOL get_dir_entry(connection_struct *conn,char *mask,uint32 dirtype, pstring fn mask_match_search(filename,mask,False) || mangle_mask_match(conn,filename,mask)) { + struct timespec write_time_ts; + if (!mangle_is_8_3(filename, False, conn->params)) mangle_map(filename,True,False, conn->params); @@ -834,6 +836,12 @@ BOOL get_dir_entry(connection_struct *conn,char *mask,uint32 dirtype, pstring fn *size = sbuf.st_size; *date = sbuf.st_mtime; + write_time_ts = get_write_time(sbuf.st_dev, sbuf.st_ino); + if (!null_timespec(write_time_ts)) { + *date = convert_timespec_to_time_t(write_time_ts); + } + + DEBUG(3,("get_dir_entry mask=[%s] found %s fname=%s\n",mask, pathreal,fname)); found = True; diff --git a/source/smbd/open.c b/source/smbd/open.c index 0fa11a5..1b1413d 100644 --- a/source/smbd/open.c +++ b/source/smbd/open.c @@ -1194,7 +1194,8 @@ NTSTATUS open_file_ntcreate(connection_struct *conn, request_time = pml->request_time; /* Remove the deferred open entry under lock. */ - lck = get_share_mode_lock(NULL, state->dev, state->inode, NULL, NULL); + lck = get_share_mode_lock(NULL, state->dev, state->inode, NULL, + NULL, NULL); if (lck == NULL) { DEBUG(0, ("could not get share mode lock\n")); } else { @@ -1423,12 +1424,13 @@ NTSTATUS open_file_ntcreate(connection_struct *conn, } if (file_existed) { + struct timespec old_write_time = get_mtimespec(psbuf); dev = psbuf->st_dev; inode = psbuf->st_ino; lck = get_share_mode_lock(NULL, dev, inode, conn->connectpath, - fname); + fname, &old_write_time); if (lck == NULL) { file_free(fsp); @@ -1642,7 +1644,7 @@ NTSTATUS open_file_ntcreate(connection_struct *conn, lck = get_share_mode_lock(NULL, dev, inode, conn->connectpath, - fname); + fname, NULL); if (lck == NULL) { DEBUG(0, ("open_file_ntcreate: Could not get share " @@ -2038,6 +2040,7 @@ NTSTATUS open_directory(connection_struct *conn, BOOL dir_existed = VALID_STAT(*psbuf) ? True : False; struct share_mode_lock *lck = NULL; NTSTATUS status; + struct timespec mtimespec; int info = 0; DEBUG(5,("open_directory: opening directory %s, access_mask = 0x%x, " @@ -2161,9 +2164,11 @@ NTSTATUS open_directory(connection_struct *conn, string_set(&fsp->fsp_name,fname); + mtimespec = get_mtimespec(psbuf); + lck = get_share_mode_lock(NULL, fsp->dev, fsp->inode, conn->connectpath, - fname); + fname, &mtimespec); if (lck == NULL) { DEBUG(0, ("open_directory: Could not get share mode lock for %s\n", fname)); diff --git a/source/smbd/oplock.c b/source/smbd/oplock.c index 54c9492..fd1ac7b 100644 --- a/source/smbd/oplock.c +++ b/source/smbd/oplock.c @@ -186,7 +186,7 @@ BOOL remove_oplock(files_struct *fsp) struct share_mode_lock *lck; /* Remove the oplock flag from the sharemode. */ - lck = get_share_mode_lock(NULL, fsp->dev, fsp->inode, NULL, NULL); + lck = get_share_mode_lock(NULL, fsp->dev, fsp->inode, NULL, NULL, NULL); if (lck == NULL) { DEBUG(0,("remove_oplock: failed to lock share entry for " "file %s\n", fsp->fsp_name )); @@ -214,7 +214,7 @@ BOOL downgrade_oplock(files_struct *fsp) BOOL ret; struct share_mode_lock *lck; - lck = get_share_mode_lock(NULL, fsp->dev, fsp->inode, NULL, NULL); + lck = get_share_mode_lock(NULL, fsp->dev, fsp->inode, NULL, NULL, NULL); if (lck == NULL) { DEBUG(0,("downgrade_oplock: failed to lock share entry for " "file %s\n", fsp->fsp_name )); @@ -754,7 +754,7 @@ void release_level_2_oplocks_on_change(files_struct *fsp) if (!LEVEL_II_OPLOCK_TYPE(fsp->oplock_type)) return; - lck = get_share_mode_lock(NULL, fsp->dev, fsp->inode, NULL, NULL); + lck = get_share_mode_lock(NULL, fsp->dev, fsp->inode, NULL, NULL, NULL); if (lck == NULL) { DEBUG(0,("release_level_2_oplocks_on_change: failed to lock " "share mode entry for file %s.\n", fsp->fsp_name )); diff --git a/source/smbd/reply.c b/source/smbd/reply.c index 54bf888..1ce4b89 100644 --- a/source/smbd/reply.c +++ b/source/smbd/reply.c @@ -4326,7 +4326,7 @@ NTSTATUS rename_internals_fsp(connection_struct *conn, files_struct *fsp, pstrin return NT_STATUS_ACCESS_DENIED; } - lck = get_share_mode_lock(NULL, fsp->dev, fsp->inode, NULL, NULL); + lck = get_share_mode_lock(NULL, fsp->dev, fsp->inode, NULL, NULL, NULL); if(SMB_VFS_RENAME(conn,fsp->fsp_name, newname) == 0) { uint32 create_options = fsp->fh->private_options; @@ -4638,7 +4638,7 @@ NTSTATUS rename_internals(connection_struct *conn, } lck = get_share_mode_lock(NULL, sbuf1.st_dev, sbuf1.st_ino, - NULL, NULL); + NULL, NULL, NULL); if(SMB_VFS_RENAME(conn,directory, newname) == 0) { DEBUG(3,("rename_internals: succeeded doing rename " @@ -4771,7 +4771,7 @@ NTSTATUS rename_internals(connection_struct *conn, } lck = get_share_mode_lock(NULL, sbuf1.st_dev, - sbuf1.st_ino, NULL, NULL); + sbuf1.st_ino, NULL, NULL, NULL); if (!SMB_VFS_RENAME(conn,fname,destname)) { rename_open_files(conn, lck, sbuf1.st_dev, diff --git a/source/smbd/trans2.c b/source/smbd/trans2.c index 0d9dac3..56e0679 100644 --- a/source/smbd/trans2.c +++ b/source/smbd/trans2.c @@ -1118,6 +1118,7 @@ static BOOL get_lanman2_dir_entry(connection_struct *conn, uint32 nt_extmode; /* Used for NT connections instead of mode */ BOOL needslash = ( conn->dirpath[strlen(conn->dirpath) -1] != '/'); BOOL check_mangled_names = lp_manglednames(conn->params); + struct timespec write_time_ts; *fname = 0; *out_of_space = False; @@ -1242,6 +1243,12 @@ static BOOL get_lanman2_dir_entry(connection_struct *conn, adate_ts = get_atimespec(&sbuf); create_date_ts = get_create_timespec(&sbuf,lp_fake_dir_create_times(SNUM(conn))); + write_time_ts = get_write_time(sbuf.st_dev, sbuf.st_ino); + if (!null_timespec(write_time_ts)) { + mdate_ts = write_time_ts; + } + + if (lp_dos_filetime_resolution(SNUM(conn))) { dos_filetime_timespec(&create_date_ts); dos_filetime_timespec(&mdate_ts); @@ -3174,6 +3181,7 @@ static int call_trans2qfilepathinfo(connection_struct *conn, char *inbuf, char * int len; time_t create_time, mtime, atime; struct timespec create_time_ts, mtime_ts, atime_ts; + struct timespec write_time_ts; files_struct *fsp = NULL; TALLOC_CTX *data_ctx = NULL; struct ea_list *ea_list = NULL; @@ -3184,6 +3192,7 @@ static int call_trans2qfilepathinfo(connection_struct *conn, char *inbuf, char * return ERROR_NT(NT_STATUS_INVALID_PARAMETER); ZERO_STRUCT(sbuf); + ZERO_STRUCT(write_time_ts); if (tran_call == TRANSACT2_QFILEINFO) { if (total_params < 4) { @@ -3228,6 +3237,8 @@ static int call_trans2qfilepathinfo(connection_struct *conn, char *inbuf, char * } delete_pending = get_delete_on_close_flag(sbuf.st_dev, sbuf.st_ino); + write_time_ts = get_write_time(sbuf.st_dev, sbuf.st_ino); + } else { /* * Original code - this is an open file. @@ -3241,6 +3252,7 @@ static int call_trans2qfilepathinfo(connection_struct *conn, char *inbuf, char * } pos = fsp->fh->position_information; delete_pending = get_delete_on_close_flag(sbuf.st_dev, sbuf.st_ino); + write_time_ts = get_write_time(sbuf.st_dev, sbuf.st_ino); access_mask = fsp->access_mask; } } else { @@ -3297,6 +3309,7 @@ static int call_trans2qfilepathinfo(connection_struct *conn, char *inbuf, char * if (delete_pending) { return ERROR_NT(NT_STATUS_DELETE_PENDING); } + write_time_ts = get_write_time(sbuf.st_dev, sbuf.st_ino); } nlink = sbuf.st_nlink; @@ -3414,22 +3427,30 @@ total_data=%u (should be %u)\n", (unsigned int)total_data, (unsigned int)IVAL(pd allocation_size = get_allocation_size(conn,fsp,&sbuf); if (fsp) { +#if 0 if (!null_timespec(fsp->pending_modtime)) { /* the pending modtime overrides the current modtime */ mtime_ts = fsp->pending_modtime; } +#endif } else { /* Do we have this path open ? */ files_struct *fsp1 = file_find_di_first(sbuf.st_dev, sbuf.st_ino); +#if 0 if (fsp1 && !null_timespec(fsp1->pending_modtime)) { /* the pending modtime overrides the current modtime */ mtime_ts = fsp1->pending_modtime; } +#endif if (fsp1 && fsp1->initial_allocation_size) { allocation_size = get_allocation_size(conn, fsp1, &sbuf); } } + if (!null_timespec(write_time_ts)) { + mtime_ts = write_time_ts; + } + if (lp_dos_filetime_resolution(SNUM(conn))) { dos_filetime_timespec(&create_time_ts); dos_filetime_timespec(&mtime_ts); @@ -5605,7 +5626,8 @@ static NTSTATUS smb_posix_unlink(connection_struct *conn, * non-POSIX opens return SHARING_VIOLATION. */ - lck = get_share_mode_lock(NULL, fsp->dev, fsp->inode, NULL, NULL); + lck = get_share_mode_lock(NULL, fsp->dev, fsp->inode, NULL, NULL, + NULL); if (lck == NULL) { DEBUG(0, ("smb_posix_unlink: Could not get share mode " "lock for file %s\n", fsp->fsp_name)); -- 1.5.3.2 From cdd0055d0b40ce15c1f782d6d58ebead40ea8b17 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Mon, 17 Dec 2007 18:56:07 +0100 Subject: [PATCH] always pass old_write_time when creating a fresh share_mode record metze --- source/locking/locking.c | 8 +++++--- source/smbd/open.c | 3 ++- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/source/locking/locking.c b/source/locking/locking.c index 94a63e5..af58e38 100644 --- a/source/locking/locking.c +++ b/source/locking/locking.c @@ -825,6 +825,10 @@ struct share_mode_lock *get_share_mode_lock(TALLOC_CTX *mem_ctx, TALLOC_FREE(lck); return NULL; } + if (old_write_time == NULL) { + TALLOC_FREE(lck); + return NULL; + } lck->filename = talloc_strdup(lck, fname); lck->servicepath = talloc_strdup(lck, servicepath); if (lck->filename == NULL || lck->servicepath == NULL) { @@ -832,9 +836,7 @@ struct share_mode_lock *get_share_mode_lock(TALLOC_CTX *mem_ctx, TALLOC_FREE(lck); return NULL; } - lck->old_write_time = - (old_write_time != NULL) ? *old_write_time : - convert_time_t_to_timespec(-1); + lck->old_write_time = *old_write_time; } else { if (!parse_share_modes(data, lck)) { DEBUG(0, ("Could not parse share modes\n")); diff --git a/source/smbd/open.c b/source/smbd/open.c index 1b1413d..ef83239 100644 --- a/source/smbd/open.c +++ b/source/smbd/open.c @@ -1623,6 +1623,7 @@ NTSTATUS open_file_ntcreate(connection_struct *conn, } if (!file_existed) { + struct timespec old_write_time = get_mtimespec(psbuf); /* * Deal with the race condition where two smbd's detect the @@ -1644,7 +1645,7 @@ NTSTATUS open_file_ntcreate(connection_struct *conn, lck = get_share_mode_lock(NULL, dev, inode, conn->connectpath, - fname, NULL); + fname, &old_write_time); if (lck == NULL) { DEBUG(0, ("open_file_ntcreate: Could not get share " -- 1.5.3.2 From 144df6e0959f11887e978d6ceb09f141cdfee315 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Tue, 18 Dec 2007 12:32:55 +0100 Subject: [PATCH] 2nd part... metze --- source/include/smb.h | 11 +++++-- source/smbd/close.c | 73 +++++++++++++++++++++++++++++++++++++++++++++--- source/smbd/dosmode.c | 24 +++++++++++++++- source/smbd/fileio.c | 57 ++++++++++++++++++++++++-------------- source/smbd/files.c | 13 +++++++- source/smbd/nttrans.c | 2 +- source/smbd/reply.c | 41 ++++++++++++++++++++------- source/smbd/trans2.c | 40 +++++++++++--------------- 8 files changed, 193 insertions(+), 68 deletions(-) diff --git a/source/include/smb.h b/source/include/smb.h index 9ae05a1..ff57c4e 100644 --- a/source/include/smb.h +++ b/source/include/smb.h @@ -501,9 +501,11 @@ typedef struct files_struct { struct timeval open_time; uint32 access_mask; /* NTCreateX access bits (FILE_READ_DATA etc.) */ uint32 share_access; /* NTCreateX share constants (FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE). */ - BOOL pending_modtime_owner; - struct timespec pending_modtime; - struct timespec last_write_time; + BOOL update_write_time_triggered; + struct timed_event *update_write_time_event; + BOOL update_write_time_on_close; + struct timespec close_write_time; + BOOL write_time_forced; int oplock_type; int sent_oplock_break; struct timed_event *oplock_timeout; @@ -542,6 +544,9 @@ typedef struct data_blob_ { void (*free)(struct data_blob_ *data_blob); } DATA_BLOB; +#define fsp_set_pending_modtime(tfsp, mod) \ + _fsp_set_pending_modtime(tfsp, mod, __location__) + /* * Structure used to keep directory state information around. * Used in NT change-notify code. diff --git a/source/smbd/close.c b/source/smbd/close.c index 07e433d..ccac441 100644 --- a/source/smbd/close.c +++ b/source/smbd/close.c @@ -170,6 +170,10 @@ static NTSTATUS close_remove_share_mode(files_struct *fsp, return NT_STATUS_INVALID_PARAMETER; } + if (fsp->write_time_forced) { + set_close_write_time(fsp, lck->changed_write_time); + } + if (!del_share_mode(lck, fsp)) { DEBUG(0, ("close_remove_share_mode: Could not delete share " "entry for file %s\n", fsp->fsp_name)); @@ -232,6 +236,11 @@ static NTSTATUS close_remove_share_mode(files_struct *fsp, DEBUG(5,("close_remove_share_mode: file %s. Delete on close was set " "- deleting file.\n", fsp->fsp_name)); + /* + * Don't try to update the write time when we delete the file + */ + fsp->update_write_time_on_close = false; + /* Become the user who requested the delete. */ if (!push_sec_ctx()) { @@ -317,6 +326,61 @@ static NTSTATUS close_remove_share_mode(files_struct *fsp, return status; } +void set_close_write_time(struct files_struct *fsp, struct timespec ts) +{ + DEBUG(6,("close_write_time: %s" , time_to_asc(convert_timespec_to_time_t(ts)))); + + if (null_timespec(ts)) { + return; + } + /* + * if the write time on close is explict set, then don't + * need to fix it up to the value in the locking db + */ + fsp->write_time_forced = false; + + fsp->update_write_time_on_close = true; + fsp->close_write_time = ts; +} + +static NTSTATUS update_write_time_on_close(struct files_struct *fsp) +{ + SMB_STRUCT_STAT sbuf; + struct timespec ts[2]; + NTSTATUS status; + + ZERO_STRUCT(sbuf); + ZERO_STRUCT(ts); + + if (!fsp->update_write_time_on_close) { + return NT_STATUS_OK; + } + + if (null_timespec(fsp->close_write_time)) { + fsp->close_write_time = timespec_current(); + } + + /* Ensure we have a valid stat struct for the source. */ + if (fsp->fh->fd != -1) { + if (SMB_VFS_FSTAT(fsp,fsp->fh->fd,&sbuf) == -1) { + return map_nt_error_from_unix(errno); + } + } else { + if (SMB_VFS_STAT(fsp->conn,fsp->fsp_name,&sbuf) == -1) { + return map_nt_error_from_unix(errno); + } + } + + ts[1] = fsp->close_write_time; + status = smb_set_file_time(fsp->conn, fsp, fsp->fsp_name, + &sbuf, ts, true); + if (!NT_STATUS_IS_OK(status)) { + return status; + } + + return NT_STATUS_OK; +} + /**************************************************************************** Close a file. @@ -331,6 +395,7 @@ static NTSTATUS close_normal_file(files_struct *fsp, enum file_close_type close_ NTSTATUS saved_status1 = NT_STATUS_OK; NTSTATUS saved_status2 = NT_STATUS_OK; NTSTATUS saved_status3 = NT_STATUS_OK; + NTSTATUS saved_status4 = NT_STATUS_OK; connection_struct *conn = fsp->conn; if (fsp->aio_write_behind) { @@ -385,11 +450,7 @@ static NTSTATUS close_normal_file(files_struct *fsp, enum file_close_type close_ * Ensure pending modtime is set after close. */ - if (fsp->pending_modtime_owner && !null_timespec(fsp->pending_modtime)) { - set_filetime(conn, fsp->fsp_name, fsp->pending_modtime); - } else if (!null_timespec(fsp->last_write_time)) { - set_filetime(conn, fsp->fsp_name, fsp->last_write_time); - } + saved_status4 = update_write_time_on_close(fsp); if (NT_STATUS_IS_OK(status)) { if (!NT_STATUS_IS_OK(saved_status1)) { @@ -398,6 +459,8 @@ static NTSTATUS close_normal_file(files_struct *fsp, enum file_close_type close_ status = saved_status2; } else if (!NT_STATUS_IS_OK(saved_status3)) { status = saved_status3; + } else if (!NT_STATUS_IS_OK(saved_status4)) { + status = saved_status4; } } diff --git a/source/smbd/dosmode.c b/source/smbd/dosmode.c index 71d4fa1..7b0b9ea 100644 --- a/source/smbd/dosmode.c +++ b/source/smbd/dosmode.c @@ -544,6 +544,9 @@ int file_ntimes(connection_struct *conn, const char *fname, const struct timespe errno = 0; ZERO_STRUCT(sbuf); + DEBUG(6,("file_ntime: actime: %s" , time_to_asc(convert_timespec_to_time_t(ts[0])))); + DEBUG(6,("file_ntime: modtime: %s", time_to_asc(convert_timespec_to_time_t(ts[1])))); + /* Don't update the time on read-only shares */ /* We need this as set_filetime (which can be called on close and other paths) can end up calling this function @@ -588,8 +591,10 @@ int file_ntimes(connection_struct *conn, const char *fname, const struct timespe Change a filetime - possibly allowing DOS semantics. *******************************************************************/ -BOOL set_filetime(connection_struct *conn, const char *fname, - const struct timespec mtime) +BOOL set_filetime_path(connection_struct *conn, const char *fname, + SMB_DEV_T dev, SMB_INO_T ino, + const struct timespec mtime, + BOOL overwrite) { struct timespec ts[2]; @@ -605,8 +610,23 @@ BOOL set_filetime(connection_struct *conn, const char *fname, return False; } + set_write_time(dev, ino, mtime, overwrite); + notify_fname(conn, NOTIFY_ACTION_MODIFIED, FILE_NOTIFY_CHANGE_LAST_WRITE, fname); return True; } + +BOOL set_filetime(struct files_struct *fsp, + const struct timespec mtime, + BOOL overwrite) +{ + if (overwrite) { + fsp->write_time_forced = true; + } + + return set_filetime_path(fsp->conn, fsp->fsp_name, fsp->dev, + fsp->inode, mtime, overwrite); + +} diff --git a/source/smbd/fileio.c b/source/smbd/fileio.c index a5f8242..dbe422b 100644 --- a/source/smbd/fileio.c +++ b/source/smbd/fileio.c @@ -139,26 +139,6 @@ static ssize_t real_write_file(files_struct *fsp,const char *data, SMB_OFF_T pos if (ret != -1) { fsp->fh->pos += ret; - /* - * It turns out that setting the last write time from a Windows - * client stops any subsequent writes from updating the write time. - * Doing this after the write gives a race condition here where - * a stat may see the changed write time before we reset it here, - * but it's cheaper than having to store the write time in shared - * memory and look it up using dev/inode across all running smbd's. - * The 99% solution will hopefully be good enough in this case. JRA. - */ - - if (!null_timespec(fsp->pending_modtime)) { - set_filetime(fsp->conn, fsp->fsp_name, fsp->pending_modtime); - - /* If we didn't get the "set modtime" call ourselves, we must - store the last write time to restore on close. JRA. */ - if (!fsp->pending_modtime_owner) { - fsp->last_write_time = timespec_current(); - } - } - /* Yes - this is correct - writes don't update this. JRA. */ /* Found by Samba4 tests. */ #if 0 @@ -188,6 +168,39 @@ static int wcp_file_size_change(files_struct *fsp) return ret; } +static void update_write_time_handler(struct event_context *ctx, + struct timed_event *te, + const struct timeval *now, + void *private_data) +{ + files_struct *fsp = (files_struct *)private_data; + + /* Remove the timed event handler. */ + TALLOC_FREE(fsp->update_write_time_event); + DEBUG(5, ("Update write time on %s\n", fsp->fsp_name)); + + /* change the write time if not already changed by someoneelse */ +/*TODO: no syscall...*/ + set_filetime(fsp, timespec_current(), false); +} + +void trigger_write_time_update(struct files_struct *fsp, + const SMB_STRUCT_STAT *st) +{ + if (fsp->update_write_time_triggered) { + return; + } + fsp->update_write_time_triggered = true; + + /* trigger the update 2 seconds later */ + fsp->update_write_time_on_close = true; + fsp->update_write_time_event = + event_add_timed(smbd_event_context(), NULL, + timeval_current_ofs(2, 0), + "update_write_time_handler", + update_write_time_handler, fsp); +} + /**************************************************************************** Write to a file. ****************************************************************************/ @@ -222,7 +235,9 @@ ssize_t write_file(files_struct *fsp, const char *data, SMB_OFF_T pos, size_t n) fsp->modified = True; if (SMB_VFS_FSTAT(fsp,fsp->fh->fd,&st) == 0) { - int dosmode = dos_mode(fsp->conn,fsp->fsp_name,&st); + int dosmode; + trigger_write_time_update(fsp, &st); + dosmode = dos_mode(fsp->conn,fsp->fsp_name,&st); if ((lp_store_dos_attributes(SNUM(fsp->conn)) || MAP_ARCHIVE(fsp->conn)) && !IS_DOS_ARCHIVE(dosmode)) { file_set_dosmode(fsp->conn,fsp->fsp_name,dosmode | aARCH,&st, False); } diff --git a/source/smbd/files.c b/source/smbd/files.c index 9f3f72a..416107d 100644 --- a/source/smbd/files.c +++ b/source/smbd/files.c @@ -383,14 +383,17 @@ files_struct *file_find_print(void) Record the owner of that modtime. ****************************************************************************/ -void fsp_set_pending_modtime(files_struct *tfsp, const struct timespec mod) +void _fsp_set_pending_modtime(files_struct *tfsp, const struct timespec mod, + const char *loc) { - files_struct *fsp; + DEBUG(0,("%s: _fsp_set_pending_modtime: TODO: update locking.tdb!\n", + loc)); if (null_timespec(mod)) { return; } +#if 0 for (fsp = Files;fsp;fsp=fsp->next) { if ( fsp->fh->fd != -1 && fsp->dev == tfsp->dev && @@ -401,6 +404,7 @@ void fsp_set_pending_modtime(files_struct *tfsp, const struct timespec mod) } tfsp->pending_modtime_owner = True; +#endif } /**************************************************************************** @@ -447,6 +451,9 @@ void file_free(files_struct *fsp) /* Ensure this event will never fire. */ TALLOC_FREE(fsp->oplock_timeout); + /* Ensure this event will never fire. */ + TALLOC_FREE(fsp->update_write_time_event); + bitmap_clear(file_bmap, fsp->fnum - FILE_HANDLE_OFFSET); files_used--; @@ -554,9 +561,11 @@ NTSTATUS dup_file_fsp(files_struct *fsp, dup_fsp->open_time = fsp->open_time; dup_fsp->access_mask = access_mask; dup_fsp->share_access = share_access; +#if 0 dup_fsp->pending_modtime_owner = fsp->pending_modtime_owner; dup_fsp->pending_modtime = fsp->pending_modtime; dup_fsp->last_write_time = fsp->last_write_time; +#endif dup_fsp->oplock_type = fsp->oplock_type; dup_fsp->can_lock = fsp->can_lock; dup_fsp->can_read = (access_mask & (FILE_READ_DATA)) ? True : False; diff --git a/source/smbd/nttrans.c b/source/smbd/nttrans.c index 45563b4..70a4122 100644 --- a/source/smbd/nttrans.c +++ b/source/smbd/nttrans.c @@ -1757,7 +1757,7 @@ static NTSTATUS copy_internals(connection_struct *conn, char *oldname, char *new close_file(fsp1,NORMAL_CLOSE); /* Ensure the modtime is set correctly on the destination file. */ - fsp_set_pending_modtime(fsp2, get_mtimespec(&sbuf1)); + set_close_write_time(fsp2, get_mtimespec(&sbuf1)); status = close_file(fsp2,NORMAL_CLOSE); diff --git a/source/smbd/reply.c b/source/smbd/reply.c index 1ce4b89..a6583d0 100644 --- a/source/smbd/reply.c +++ b/source/smbd/reply.c @@ -902,7 +902,8 @@ int reply_setatr(connection_struct *conn, char *inbuf,char *outbuf, int dum_size } } - if (!set_filetime(conn,fname,convert_time_t_to_timespec(mtime))) { + if (!set_filetime_path(conn,fname,sbuf.st_dev,sbuf.st_ino, + convert_time_t_to_timespec(mtime), True)) { END_PROFILE(SMBsetatr); return UNIXERROR(ERRDOS, ERRnoaccess); } @@ -3329,6 +3330,7 @@ int reply_close(connection_struct *conn, char *inbuf,char *outbuf, int size, DEBUG(3,("close directory fnum=%d\n", fsp->fnum)); status = close_file(fsp,NORMAL_CLOSE); } else { + time_t t; /* * Close ordinary file. */ @@ -3341,8 +3343,8 @@ int reply_close(connection_struct *conn, char *inbuf,char *outbuf, int size, * Take care of any time sent in the close. */ - fsp_set_pending_modtime(fsp, - convert_time_t_to_timespec(srv_make_unix_date3(inbuf+smb_vwv1))); + t = srv_make_unix_date3(inbuf+smb_vwv1); + set_close_write_time(fsp, convert_time_t_to_timespec(t)); /* * close_file() returns the unix errno if an error @@ -3396,8 +3398,6 @@ int reply_writeclose(connection_struct *conn, nwritten = write_file(fsp,data,startpos,numtowrite); - set_filetime(conn, fsp->fsp_name, mtime); - /* * More insanity. W2K only closes the file if writelen > 0. * JRA. @@ -4957,7 +4957,7 @@ NTSTATUS copy_file(connection_struct *conn, close_file(fsp1,NORMAL_CLOSE); /* Ensure the modtime is set correctly on the destination file. */ - fsp_set_pending_modtime( fsp2, get_mtimespec(&src_sbuf)); + set_close_write_time(fsp2, get_mtimespec(&src_sbuf)); /* * As we are opening fsp1 read-only we only expect @@ -5797,6 +5797,9 @@ int reply_setattrE(connection_struct *conn, char *inbuf,char *outbuf, int size, struct timespec ts[2]; int outsize = 0; files_struct *fsp = file_fsp(inbuf,smb_vwv0); + SMB_STRUCT_STAT sbuf; + NTSTATUS status; + START_PROFILE(SMBsetattrE); outsize = set_message(outbuf,0,0,False); @@ -5832,17 +5835,33 @@ int reply_setattrE(connection_struct *conn, char *inbuf,char *outbuf, int size, ts[1] = ts[0]; } + /* Ensure we have a valid stat struct for the source. */ + if (fsp->fh->fd != -1) { + if (SMB_VFS_FSTAT(fsp,fsp->fh->fd,&sbuf) == -1) { + status = map_nt_error_from_unix(errno); + END_PROFILE(SMBsetattrE); + return ERROR_NT(status); + } + } else { + if (SMB_VFS_STAT(conn,fsp->fsp_name,&sbuf) == -1) { + status = map_nt_error_from_unix(errno); + END_PROFILE(SMBsetattrE); + return ERROR_NT(status); + } + } + /* Set the date on this file */ - /* Should we set pending modtime here ? JRA */ - if(file_ntimes(conn, fsp->fsp_name, ts)) { + + if (!set_filetime_path(conn, fsp->fsp_name, + sbuf.st_dev, sbuf.st_ino, ts[0], true)) { END_PROFILE(SMBsetattrE); return ERROR_DOS(ERRDOS,ERRnoaccess); } DEBUG( 3, ( "reply_setattrE fnum=%d actime=%u modtime=%u\n", - fsp->fnum, - (unsigned int)ts[0].tv_sec, - (unsigned int)ts[1].tv_sec)); + fsp->fnum, + (unsigned int)ts[0].tv_sec, + (unsigned int)ts[1].tv_sec)); END_PROFILE(SMBsetattrE); return(outsize); diff --git a/source/smbd/trans2.c b/source/smbd/trans2.c index 56e0679..b247666 100644 --- a/source/smbd/trans2.c +++ b/source/smbd/trans2.c @@ -4067,11 +4067,12 @@ NTSTATUS hardlink_internals(connection_struct *conn, pstring oldname, pstring ne Deal with setting the time from any of the setfilepathinfo functions. ****************************************************************************/ -static NTSTATUS smb_set_file_time(connection_struct *conn, - files_struct *fsp, - const char *fname, - const SMB_STRUCT_STAT *psbuf, - struct timespec ts[2]) +NTSTATUS smb_set_file_time(connection_struct *conn, + files_struct *fsp, + const char *fname, + const SMB_STRUCT_STAT *psbuf, + struct timespec ts[2], + BOOL setting_write_time) { uint32 action = FILE_NOTIFY_CHANGE_LAST_ACCESS @@ -4109,7 +4110,7 @@ static NTSTATUS smb_set_file_time(connection_struct *conn, } } - if(fsp != NULL) { + if ((fsp != NULL) && setting_write_time) { /* * This was a setfileinfo on an open file. * NT does this a lot. We also need to @@ -4120,13 +4121,11 @@ static NTSTATUS smb_set_file_time(connection_struct *conn, * away and will set it on file close and after a write. JRA. */ - if (!null_timespec(ts[1])) { - DEBUG(10,("smb_set_file_time: setting pending modtime to %s\n", - time_to_asc(convert_timespec_to_time_t(ts[1])) )); - fsp_set_pending_modtime(fsp, ts[1]); - } - + DEBUG(10,("smb_set_file_time: setting pending modtime to %s\n", + time_to_asc(convert_timespec_to_time_t(ts[1])) )); + set_filetime(fsp, ts[1], true); } + DEBUG(10,("smb_set_file_time: setting utimes to modified values.\n")); if(file_ntimes(conn, fname, ts)!=0) { @@ -4765,7 +4764,7 @@ static NTSTATUS smb_set_info_standard(connection_struct *conn, fsp, fname, psbuf, - ts); + ts, False); } /**************************************************************************** @@ -4827,7 +4826,7 @@ static NTSTATUS smb_set_file_basic_info(connection_struct *conn, fsp, fname, psbuf, - ts); + ts, False); } /**************************************************************************** @@ -4881,14 +4880,7 @@ static NTSTATUS smb_set_file_allocation_info(connection_struct *conn, return map_nt_error_from_unix(errno); } } - /* But always update the time. */ - if (null_timespec(fsp->pending_modtime)) { - /* - * This is equivalent to a write. Ensure it's seen immediately - * if there are no pending writes. - */ - set_filetime(fsp->conn, fsp->fsp_name, timespec_current()); - } + trigger_write_time_update(fsp, NULL); return NT_STATUS_OK; } @@ -5209,7 +5201,7 @@ size = %.0f, uid = %u, gid = %u, raw perms = 0%o\n", fsp, fname, psbuf, - ts); + ts, False); } /**************************************************************************** @@ -5814,10 +5806,12 @@ static int call_trans2setfilepathinfo(connection_struct *conn, char *inbuf, char SSVAL(params,0,0); +#if 0 if (fsp && !null_timespec(fsp->pending_modtime)) { /* the pending modtime overrides the current modtime */ set_mtimespec(&sbuf, fsp->pending_modtime); } +#endif switch (info_level) { -- 1.5.3.2 From 8f27ddc1654ad51721e82fec2106aff5bea6f8a9 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Tue, 18 Dec 2007 10:36:23 +0100 Subject: [PATCH] get_write_time() should not get the share mode record in write mode metze --- source/locking/locking.c | 35 +++++++++++++++++++++++++---------- 1 files changed, 25 insertions(+), 10 deletions(-) diff --git a/source/locking/locking.c b/source/locking/locking.c index af58e38..1bbf4f9 100644 --- a/source/locking/locking.c +++ b/source/locking/locking.c @@ -960,20 +960,35 @@ BOOL get_delete_on_close_flag(SMB_DEV_T dev, SMB_INO_T inode) return result; } -struct timespec get_write_time(SMB_DEV_T dev, SMB_INO_T ino) +static int pull_write_time(TDB_DATA key, TDB_DATA dbuf, + void *private_data) { - struct timespec result; - struct share_mode_lock *lck; + struct timespec *result = (struct timespec *)private_data; + struct locking_data *data; - ZERO_STRUCT(result); - if (!(lck = get_share_mode_lock(NULL, dev, ino, NULL, NULL, NULL))) { - return result; + if (dbuf.dsize < sizeof(struct locking_data)) { + smb_panic("PANIC: parse_share_modes: buffer too short.\n"); } - result = lck->changed_write_time; - if (null_timespec(result)) { - result = lck->old_write_time; + + data = (struct locking_data *)dbuf.dptr; + + *result = data->u.s.changed_write_time; + if (null_timespec(*result)) { + *result = data->u.s.old_write_time; } - TALLOC_FREE(lck); + + return 0; +} + +struct timespec get_write_time(SMB_DEV_T dev, SMB_INO_T inode) +{ + TDB_DATA key = locking_key(dev, inode); + struct timespec result; + + ZERO_STRUCT(result); + + tdb_parse_record(tdb, key, pull_write_time, + (void *)&result); return result; } -- 1.5.3.2 From 2ee4f43de6c3c590272446a5d1ebf2f1046addce Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Tue, 18 Dec 2007 10:59:01 +0100 Subject: [PATCH] pass the correct value to smb_set_file_time() metze --- source/smbd/trans2.c | 14 ++++++++++---- 1 files changed, 10 insertions(+), 4 deletions(-) diff --git a/source/smbd/trans2.c b/source/smbd/trans2.c index b247666..5a6d9f3 100644 --- a/source/smbd/trans2.c +++ b/source/smbd/trans2.c @@ -4764,7 +4764,7 @@ static NTSTATUS smb_set_info_standard(connection_struct *conn, fsp, fname, psbuf, - ts, False); + ts, True); } /**************************************************************************** @@ -4784,6 +4784,7 @@ static NTSTATUS smb_set_file_basic_info(connection_struct *conn, uint32 dosmode = 0; struct timespec ts[2]; NTSTATUS status = NT_STATUS_OK; + BOOL setting_write_time = True; if (total_data < 36) { return NT_STATUS_INVALID_PARAMETER; @@ -4816,7 +4817,12 @@ static NTSTATUS smb_set_file_basic_info(connection_struct *conn, /* Prefer a defined time to an undefined one. */ if (null_timespec(ts[1])) { - ts[1] = null_timespec(write_time) ? changed_time : write_time; + if (null_timespec(write_time)) { + ts[1] = changed_time; + setting_write_time = False; + } else { + ts[1] = write_time; + } } DEBUG(10,("smb_set_file_basic_info: file %s\n", @@ -4826,7 +4832,7 @@ static NTSTATUS smb_set_file_basic_info(connection_struct *conn, fsp, fname, psbuf, - ts, False); + ts, setting_write_time); } /**************************************************************************** @@ -5201,7 +5207,7 @@ size = %.0f, uid = %u, gid = %u, raw perms = 0%o\n", fsp, fname, psbuf, - ts, False); + ts, True); } /**************************************************************************** -- 1.5.3.2 From 233546a1228be7814a6564501a7049d52f6ec1f4 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Tue, 18 Dec 2007 11:12:54 +0100 Subject: [PATCH] - trigger_write_time_update() doesn't need a statbuf - cancel the triggered update when a forced update comes in metze --- source/smbd/dosmode.c | 1 + source/smbd/fileio.c | 10 ++++++---- source/smbd/trans2.c | 16 +++++++++++----- 3 files changed, 18 insertions(+), 9 deletions(-) diff --git a/source/smbd/dosmode.c b/source/smbd/dosmode.c index 7b0b9ea..7d131de 100644 --- a/source/smbd/dosmode.c +++ b/source/smbd/dosmode.c @@ -624,6 +624,7 @@ BOOL set_filetime(struct files_struct *fsp, { if (overwrite) { fsp->write_time_forced = true; + TALLOC_FREE(fsp->update_write_time_event); } return set_filetime_path(fsp->conn, fsp->fsp_name, fsp->dev, diff --git a/source/smbd/fileio.c b/source/smbd/fileio.c index dbe422b..e485446 100644 --- a/source/smbd/fileio.c +++ b/source/smbd/fileio.c @@ -180,13 +180,15 @@ static void update_write_time_handler(struct event_context *ctx, DEBUG(5, ("Update write time on %s\n", fsp->fsp_name)); /* change the write time if not already changed by someoneelse */ -/*TODO: no syscall...*/ set_filetime(fsp, timespec_current(), false); } -void trigger_write_time_update(struct files_struct *fsp, - const SMB_STRUCT_STAT *st) +void trigger_write_time_update(struct files_struct *fsp) { + if (fsp->write_time_forced) { + return; + } + if (fsp->update_write_time_triggered) { return; } @@ -236,7 +238,7 @@ ssize_t write_file(files_struct *fsp, const char *data, SMB_OFF_T pos, size_t n) if (SMB_VFS_FSTAT(fsp,fsp->fh->fd,&st) == 0) { int dosmode; - trigger_write_time_update(fsp, &st); + trigger_write_time_update(fsp); dosmode = dos_mode(fsp->conn,fsp->fsp_name,&st); if ((lp_store_dos_attributes(SNUM(fsp->conn)) || MAP_ARCHIVE(fsp->conn)) && !IS_DOS_ARCHIVE(dosmode)) { file_set_dosmode(fsp->conn,fsp->fsp_name,dosmode | aARCH,&st, False); diff --git a/source/smbd/trans2.c b/source/smbd/trans2.c index 5a6d9f3..70aef0f 100644 --- a/source/smbd/trans2.c +++ b/source/smbd/trans2.c @@ -4886,7 +4886,12 @@ static NTSTATUS smb_set_file_allocation_info(connection_struct *conn, return map_nt_error_from_unix(errno); } } - trigger_write_time_update(fsp, NULL); + /* But always update the time. */ + /* + * This is equivalent to a write. Ensure it's seen immediately + * if there are no pending writes. + */ + trigger_write_time_update(fsp); return NT_STATUS_OK; } @@ -4916,10 +4921,11 @@ static NTSTATUS smb_set_file_allocation_info(connection_struct *conn, } /* Changing the allocation size should set the last mod time. */ - /* Don't need to call set_filetime as this will be flushed on - * close. */ - - fsp_set_pending_modtime(new_fsp, timespec_current()); + /* + * This is equivalent to a write. Ensure it's seen immediately + * if there are no pending writes. + */ + trigger_write_time_update(new_fsp); close_file(new_fsp,NORMAL_CLOSE); return NT_STATUS_OK; -- 1.5.3.2 From db17c2c0322cab0684f9594d06727d86a6caa792 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Tue, 18 Dec 2007 11:10:47 +0100 Subject: [PATCH] try to pass more tests... --- source/script/tests/test_posix_s3.sh | 2 +- source/script/tests/test_smbtorture_s3.sh | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/source/script/tests/test_posix_s3.sh b/source/script/tests/test_posix_s3.sh index 94b3993..4fedbbf 100755 --- a/source/script/tests/test_posix_s3.sh +++ b/source/script/tests/test_posix_s3.sh @@ -47,7 +47,7 @@ fi tests="$base $raw $rpc $unix" -skipped="BASE-CHARSET BASE-DEFER_OPEN BASE-DELAYWRITE BASE-OPENATTR BASE-TCONDEV" +skipped="BASE-CHARSET BASE-DEFER_OPEN BASE-OPENATTR BASE-TCONDEV" skipped="$skipped RAW-ACLS RAW-COMPOSITE RAW-CONTEXT RAW-EAS" skipped="$skipped RAW-IOCTL RAW-MKDIR RAW-MUX RAW-NOTIFY RAW-OPEN" skipped="$skipped RAW-QFILEINFO RAW-QFSINFO RAW-RENAME RAW-SEARCH" diff --git a/source/script/tests/test_smbtorture_s3.sh b/source/script/tests/test_smbtorture_s3.sh index 38ab40f..8963261 100755 --- a/source/script/tests/test_smbtorture_s3.sh +++ b/source/script/tests/test_smbtorture_s3.sh @@ -20,6 +20,7 @@ incdir=`dirname $0` . $incdir/test_functions.sh tests="FDPASS LOCK1 LOCK2 LOCK3 LOCK4 LOCK5 LOCK6 LOCK7" +tests="$tests DENY1 DENY2 OPENATTR" tests="$tests UNLINK BROWSE ATTR TRANS2 MAXFID TORTURE " tests="$tests OPLOCK1 OPLOCK2 OPLOCK3" tests="$tests DIR DIR1 TCON TCONDEV RW1 RW2 RW3" @@ -27,7 +28,7 @@ tests="$tests OPEN XCOPY RENAME DELETE PROPERTIES W2K" tests="$tests TCON2 IOCTL CHKPATH FDSESS LOCAL-SUBSTITUTE" skipped1="RANDOMIPC NEGNOWAIT NBENCH ERRMAPEXTRACT TRANS2SCAN NTTRANSSCAN" -skipped2="DENY1 DENY2 OPENATTR CASETABLE EATEST" +skipped2="CASETABLE EATEST" skipped3="MANGLE UTABLE PIPE_NUMBER" echo "Skipping the following tests:" echo "$skipped1" -- 1.5.3.2 From 4552b4b43a2cd3bd13d94bd68e6f91518b7ce5a6 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Tue, 18 Dec 2007 12:11:18 +0100 Subject: [PATCH] always set times via smb_set_file_time() metze --- source/smbd/reply.c | 23 +++++++++++++++-------- 1 files changed, 15 insertions(+), 8 deletions(-) diff --git a/source/smbd/reply.c b/source/smbd/reply.c index a6583d0..78dd22d 100644 --- a/source/smbd/reply.c +++ b/source/smbd/reply.c @@ -1649,7 +1649,11 @@ int reply_mknew(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, } ts[0] = get_atimespec(&sbuf); /* atime. */ - file_ntimes(conn, fname, ts); + status = smb_set_file_time(conn, fsp, fname, &sbuf, ts, true); + if (!NT_STATUS_IS_OK(status)) { + END_PROFILE(SMBcreate); + return ERROR_OPEN(status); + } outsize = set_message(outbuf,1,0,True); SSVAL(outbuf,smb_vwv0,fsp->fnum); @@ -5830,9 +5834,6 @@ int reply_setattrE(connection_struct *conn, char *inbuf,char *outbuf, int size, } END_PROFILE(SMBsetattrE); return(outsize); - } else if (!null_timespec(ts[0]) && null_timespec(ts[1])) { - /* set modify time = to access time if modify time was unset */ - ts[1] = ts[0]; } /* Ensure we have a valid stat struct for the source. */ @@ -5850,14 +5851,20 @@ int reply_setattrE(connection_struct *conn, char *inbuf,char *outbuf, int size, } } - /* Set the date on this file */ +#if 0 + if (!null_timespec(ts[0]) && null_timespec(ts[1])) { + /* set modify time = to access time if modify time was unset */ + ts[1] = ts[0]; + } +#endif - if (!set_filetime_path(conn, fsp->fsp_name, - sbuf.st_dev, sbuf.st_ino, ts[0], true)) { + status = smb_set_file_time(conn, fsp, fsp->fsp_name, + &sbuf, ts, true); + if (!NT_STATUS_IS_OK(status)) { END_PROFILE(SMBsetattrE); return ERROR_DOS(ERRDOS,ERRnoaccess); } - + DEBUG( 3, ( "reply_setattrE fnum=%d actime=%u modtime=%u\n", fsp->fnum, (unsigned int)ts[0].tv_sec, -- 1.5.3.2 From 127bfcbcc061520ed3a7b18e9401b46ea09f2e82 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Tue, 18 Dec 2007 13:09:50 +0100 Subject: [PATCH] always use smb_set_file_time() to set the timestamps metze --- source/smbd/reply.c | 9 +++++++-- 1 files changed, 7 insertions(+), 2 deletions(-) diff --git a/source/smbd/reply.c b/source/smbd/reply.c index 78dd22d..5d0be36 100644 --- a/source/smbd/reply.c +++ b/source/smbd/reply.c @@ -840,6 +840,7 @@ int reply_getatr(connection_struct *conn, char *inbuf,char *outbuf, int dum_size int reply_setatr(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, int dum_buffsize) { + struct timespec ts[2]; pstring fname; int outsize = 0; int mode; @@ -848,6 +849,8 @@ int reply_setatr(connection_struct *conn, char *inbuf,char *outbuf, int dum_size char *p; NTSTATUS status; + ZERO_STRUCT(ts); + START_PROFILE(SMBsetatr); p = smb_buf(inbuf) + 1; @@ -902,8 +905,10 @@ int reply_setatr(connection_struct *conn, char *inbuf,char *outbuf, int dum_size } } - if (!set_filetime_path(conn,fname,sbuf.st_dev,sbuf.st_ino, - convert_time_t_to_timespec(mtime), True)) { + ts[1] = convert_time_t_to_timespec(mtime); + status = smb_set_file_time(conn, NULL, fname, + &sbuf, ts, true); + if (!NT_STATUS_IS_OK(status)) { END_PROFILE(SMBsetatr); return UNIXERROR(ERRDOS, ERRnoaccess); } -- 1.5.3.2 From 1ca5317a53455669b07554d9df1f302b4ab35a98 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Tue, 18 Dec 2007 14:41:58 +0100 Subject: [PATCH] only call file_ntime() from smb_set_file_time() and in the set_write_time*() function only se the share mode record times. That means the unix filesystem gets the updated time on close. And the write time update after 2 seconds is only seen by windows clients. use smb_set_file_time() also for the non fsp case. metze --- source/smbd/dosmode.c | 37 ++++++++++++++++--------------------- source/smbd/fileio.c | 2 +- source/smbd/trans2.c | 11 +++++++++-- 3 files changed, 26 insertions(+), 24 deletions(-) diff --git a/source/smbd/dosmode.c b/source/smbd/dosmode.c index 7d131de..bc4f232 100644 --- a/source/smbd/dosmode.c +++ b/source/smbd/dosmode.c @@ -591,43 +591,38 @@ int file_ntimes(connection_struct *conn, const char *fname, const struct timespe Change a filetime - possibly allowing DOS semantics. *******************************************************************/ -BOOL set_filetime_path(connection_struct *conn, const char *fname, - SMB_DEV_T dev, SMB_INO_T ino, - const struct timespec mtime, - BOOL overwrite) +BOOL set_write_time_path(connection_struct *conn, const char *fname, + SMB_DEV_T dev, SMB_INO_T ino, + const struct timespec mtime, + BOOL overwrite) { - struct timespec ts[2]; - if (null_timespec(mtime)) { return(True); } - ts[1] = mtime; /* mtime. */ - ts[0] = ts[1]; /* atime. */ - - if (file_ntimes(conn, fname, ts)) { - DEBUG(4,("set_filetime(%s) failed: %s\n",fname,strerror(errno))); + if (!set_write_time(dev, ino, mtime, overwrite)) { return False; } - set_write_time(dev, ino, mtime, overwrite); + /* in the overwrite case the caller should trigger the notify */ + if (!overwrite) { + notify_fname(conn, NOTIFY_ACTION_MODIFIED, + FILE_NOTIFY_CHANGE_LAST_WRITE, fname); + } - notify_fname(conn, NOTIFY_ACTION_MODIFIED, - FILE_NOTIFY_CHANGE_LAST_WRITE, fname); - return True; } -BOOL set_filetime(struct files_struct *fsp, - const struct timespec mtime, - BOOL overwrite) +BOOL set_write_time_fsp(struct files_struct *fsp, + const struct timespec mtime, + BOOL overwrite) { if (overwrite) { fsp->write_time_forced = true; TALLOC_FREE(fsp->update_write_time_event); } - return set_filetime_path(fsp->conn, fsp->fsp_name, fsp->dev, - fsp->inode, mtime, overwrite); - + return set_write_time_path(fsp->conn, fsp->fsp_name, + fsp->dev, fsp->inode, + mtime, overwrite); } diff --git a/source/smbd/fileio.c b/source/smbd/fileio.c index e485446..a4e718a 100644 --- a/source/smbd/fileio.c +++ b/source/smbd/fileio.c @@ -180,7 +180,7 @@ static void update_write_time_handler(struct event_context *ctx, DEBUG(5, ("Update write time on %s\n", fsp->fsp_name)); /* change the write time if not already changed by someoneelse */ - set_filetime(fsp, timespec_current(), false); + set_write_time_fsp(fsp, timespec_current(), false); } void trigger_write_time_update(struct files_struct *fsp) diff --git a/source/smbd/trans2.c b/source/smbd/trans2.c index 70aef0f..9e200a2 100644 --- a/source/smbd/trans2.c +++ b/source/smbd/trans2.c @@ -4110,7 +4110,7 @@ NTSTATUS smb_set_file_time(connection_struct *conn, } } - if ((fsp != NULL) && setting_write_time) { + if (setting_write_time) { /* * This was a setfileinfo on an open file. * NT does this a lot. We also need to @@ -4123,7 +4123,14 @@ NTSTATUS smb_set_file_time(connection_struct *conn, DEBUG(10,("smb_set_file_time: setting pending modtime to %s\n", time_to_asc(convert_timespec_to_time_t(ts[1])) )); - set_filetime(fsp, ts[1], true); + + if (fsp != NULL) { + set_write_time_fsp(fsp, ts[1], true); + } else { + set_write_time_path(conn, fname, + psbuf->st_dev, psbuf->st_ino, + ts[1], true); + } } DEBUG(10,("smb_set_file_time: setting utimes to modified values.\n")); -- 1.5.3.2 From d9622838ca6c7b43ebb3fd93a1d7e3e14c47f8cd Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Tue, 18 Dec 2007 12:33:24 +0100 Subject: [PATCH] skip RPC-SAMBA3-SPOOLSS RPC-UNIXINFO... --- source/script/tests/test_posix_s3.sh | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/source/script/tests/test_posix_s3.sh b/source/script/tests/test_posix_s3.sh index 4fedbbf..cf92622 100755 --- a/source/script/tests/test_posix_s3.sh +++ b/source/script/tests/test_posix_s3.sh @@ -51,7 +51,7 @@ skipped="BASE-CHARSET BASE-DEFER_OPEN BASE-OPENATTR BASE-TCONDEV" skipped="$skipped RAW-ACLS RAW-COMPOSITE RAW-CONTEXT RAW-EAS" skipped="$skipped RAW-IOCTL RAW-MKDIR RAW-MUX RAW-NOTIFY RAW-OPEN" skipped="$skipped RAW-QFILEINFO RAW-QFSINFO RAW-RENAME RAW-SEARCH" -skipped="$skipped RAW-SFILEINFO RAW-STREAMS RAW-WRITE" +skipped="$skipped RAW-SFILEINFO RAW-STREAMS RAW-WRITE RPC-SAMBA3-SPOOLSS RPC-UNIXINFO" echo "WARNING: Skipping tests $skipped" -- 1.5.3.2 From cc7116c46da30bed6056d2c51241abd49403ab2e Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Tue, 18 Dec 2007 14:27:04 +0100 Subject: [PATCH] don't skip test which pass metze --- source/script/tests/test_posix_s3.sh | 8 ++++---- 1 files changed, 4 insertions(+), 4 deletions(-) diff --git a/source/script/tests/test_posix_s3.sh b/source/script/tests/test_posix_s3.sh index cf92622..7e0f439 100755 --- a/source/script/tests/test_posix_s3.sh +++ b/source/script/tests/test_posix_s3.sh @@ -47,11 +47,11 @@ fi tests="$base $raw $rpc $unix" -skipped="BASE-CHARSET BASE-DEFER_OPEN BASE-OPENATTR BASE-TCONDEV" +skipped="BASE-CHARSET BASE-TCONDEV" skipped="$skipped RAW-ACLS RAW-COMPOSITE RAW-CONTEXT RAW-EAS" -skipped="$skipped RAW-IOCTL RAW-MKDIR RAW-MUX RAW-NOTIFY RAW-OPEN" -skipped="$skipped RAW-QFILEINFO RAW-QFSINFO RAW-RENAME RAW-SEARCH" -skipped="$skipped RAW-SFILEINFO RAW-STREAMS RAW-WRITE RPC-SAMBA3-SPOOLSS RPC-UNIXINFO" +skipped="$skipped RAW-IOCTL RAW-NOTIFY" +skipped="$skipped RAW-QFILEINFO RAW-QFSINFO RAW-SEARCH" +skipped="$skipped RAW-SFILEINFO RAW-STREAMS RPC-SAMBA3-SPOOLSS RPC-UNIXINFO" echo "WARNING: Skipping tests $skipped" -- 1.5.3.2 From c8ab8e0f57035dc82a6fb353f37414c01a991297 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Tue, 18 Dec 2007 15:28:36 +0100 Subject: [PATCH] set close write time in reply_writeclose() metze --- source/smbd/reply.c | 2 ++ 1 files changed, 2 insertions(+), 0 deletions(-) diff --git a/source/smbd/reply.c b/source/smbd/reply.c index 5d0be36..cadb81f 100644 --- a/source/smbd/reply.c +++ b/source/smbd/reply.c @@ -3407,6 +3407,8 @@ int reply_writeclose(connection_struct *conn, nwritten = write_file(fsp,data,startpos,numtowrite); + set_close_write_time(fsp, mtime); + /* * More insanity. W2K only closes the file if writelen > 0. * JRA. -- 1.5.3.2 From 9e502092c98b9a57773ff7de9b48cbfb21b04894 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Tue, 18 Dec 2007 15:31:33 +0100 Subject: [PATCH] remove unused pending_modtime stuff metze --- source/include/smb.h | 3 --- source/smbd/files.c | 29 ----------------------------- source/smbd/trans2.c | 7 ------- 3 files changed, 0 insertions(+), 39 deletions(-) diff --git a/source/include/smb.h b/source/include/smb.h index ff57c4e..e87bd9a 100644 --- a/source/include/smb.h +++ b/source/include/smb.h @@ -544,9 +544,6 @@ typedef struct data_blob_ { void (*free)(struct data_blob_ *data_blob); } DATA_BLOB; -#define fsp_set_pending_modtime(tfsp, mod) \ - _fsp_set_pending_modtime(tfsp, mod, __location__) - /* * Structure used to keep directory state information around. * Used in NT change-notify code. diff --git a/source/smbd/files.c b/source/smbd/files.c index 416107d..ade66f8 100644 --- a/source/smbd/files.c +++ b/source/smbd/files.c @@ -379,35 +379,6 @@ files_struct *file_find_print(void) } /**************************************************************************** - Set a pending modtime across all files with a given dev/ino pair. - Record the owner of that modtime. -****************************************************************************/ - -void _fsp_set_pending_modtime(files_struct *tfsp, const struct timespec mod, - const char *loc) -{ - DEBUG(0,("%s: _fsp_set_pending_modtime: TODO: update locking.tdb!\n", - loc)); - - if (null_timespec(mod)) { - return; - } - -#if 0 - for (fsp = Files;fsp;fsp=fsp->next) { - if ( fsp->fh->fd != -1 && - fsp->dev == tfsp->dev && - fsp->inode == tfsp->inode ) { - fsp->pending_modtime = mod; - fsp->pending_modtime_owner = False; - } - } - - tfsp->pending_modtime_owner = True; -#endif -} - -/**************************************************************************** Sync open files on a connection. ****************************************************************************/ diff --git a/source/smbd/trans2.c b/source/smbd/trans2.c index 9e200a2..ddcf1ee 100644 --- a/source/smbd/trans2.c +++ b/source/smbd/trans2.c @@ -5825,13 +5825,6 @@ static int call_trans2setfilepathinfo(connection_struct *conn, char *inbuf, char SSVAL(params,0,0); -#if 0 - if (fsp && !null_timespec(fsp->pending_modtime)) { - /* the pending modtime overrides the current modtime */ - set_mtimespec(&sbuf, fsp->pending_modtime); - } -#endif - switch (info_level) { case SMB_INFO_STANDARD: -- 1.5.3.2 From d888b9c2ea232da6110f4807ce55c57ddc2bdfed Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Tue, 18 Dec 2007 15:41:14 +0100 Subject: [PATCH] remove unused stuff metze --- source/smbd/files.c | 5 ----- source/smbd/reply.c | 7 ------- 2 files changed, 0 insertions(+), 12 deletions(-) diff --git a/source/smbd/files.c b/source/smbd/files.c index ade66f8..ffcf3f5 100644 --- a/source/smbd/files.c +++ b/source/smbd/files.c @@ -532,11 +532,6 @@ NTSTATUS dup_file_fsp(files_struct *fsp, dup_fsp->open_time = fsp->open_time; dup_fsp->access_mask = access_mask; dup_fsp->share_access = share_access; -#if 0 - dup_fsp->pending_modtime_owner = fsp->pending_modtime_owner; - dup_fsp->pending_modtime = fsp->pending_modtime; - dup_fsp->last_write_time = fsp->last_write_time; -#endif dup_fsp->oplock_type = fsp->oplock_type; dup_fsp->can_lock = fsp->can_lock; dup_fsp->can_read = (access_mask & (FILE_READ_DATA)) ? True : False; diff --git a/source/smbd/reply.c b/source/smbd/reply.c index cadb81f..61c43a7 100644 --- a/source/smbd/reply.c +++ b/source/smbd/reply.c @@ -5858,13 +5858,6 @@ int reply_setattrE(connection_struct *conn, char *inbuf,char *outbuf, int size, } } -#if 0 - if (!null_timespec(ts[0]) && null_timespec(ts[1])) { - /* set modify time = to access time if modify time was unset */ - ts[1] = ts[0]; - } -#endif - status = smb_set_file_time(conn, fsp, fsp->fsp_name, &sbuf, ts, true); if (!NT_STATUS_IS_OK(status)) { -- 1.5.3.2 From a2ca11cf9852f57fe844187b1d55ba64fa492018 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Tue, 18 Dec 2007 15:43:34 +0100 Subject: [PATCH] remove unused stuff... metze --- source/smbd/trans2.c | 15 +-------------- 1 files changed, 1 insertions(+), 14 deletions(-) diff --git a/source/smbd/trans2.c b/source/smbd/trans2.c index ddcf1ee..6366fc3 100644 --- a/source/smbd/trans2.c +++ b/source/smbd/trans2.c @@ -3426,22 +3426,9 @@ total_data=%u (should be %u)\n", (unsigned int)total_data, (unsigned int)IVAL(pd allocation_size = get_allocation_size(conn,fsp,&sbuf); - if (fsp) { -#if 0 - if (!null_timespec(fsp->pending_modtime)) { - /* the pending modtime overrides the current modtime */ - mtime_ts = fsp->pending_modtime; - } -#endif - } else { + if (!fsp) { /* Do we have this path open ? */ files_struct *fsp1 = file_find_di_first(sbuf.st_dev, sbuf.st_ino); -#if 0 - if (fsp1 && !null_timespec(fsp1->pending_modtime)) { - /* the pending modtime overrides the current modtime */ - mtime_ts = fsp1->pending_modtime; - } -#endif if (fsp1 && fsp1->initial_allocation_size) { allocation_size = get_allocation_size(conn, fsp1, &sbuf); } -- 1.5.3.2