diff options
Diffstat (limited to 'source4/ntvfs')
-rw-r--r-- | source4/ntvfs/common/brlock.c | 2 | ||||
-rw-r--r-- | source4/ntvfs/common/brlock_tdb.c | 8 | ||||
-rw-r--r-- | source4/ntvfs/common/opendb.c | 24 | ||||
-rw-r--r-- | source4/ntvfs/common/opendb.h | 9 | ||||
-rw-r--r-- | source4/ntvfs/common/opendb_tdb.c | 51 | ||||
-rw-r--r-- | source4/ntvfs/ntvfs.h | 2 | ||||
-rw-r--r-- | source4/ntvfs/ntvfs_generic.c | 45 | ||||
-rw-r--r-- | source4/ntvfs/posix/pvfs_fileinfo.c | 31 | ||||
-rw-r--r-- | source4/ntvfs/posix/pvfs_lock.c | 2 | ||||
-rw-r--r-- | source4/ntvfs/posix/pvfs_open.c | 80 | ||||
-rw-r--r-- | source4/ntvfs/posix/pvfs_oplock.c | 2 | ||||
-rw-r--r-- | source4/ntvfs/posix/pvfs_rename.c | 8 | ||||
-rw-r--r-- | source4/ntvfs/posix/pvfs_resolve.c | 32 | ||||
-rw-r--r-- | source4/ntvfs/posix/pvfs_search.c | 2 | ||||
-rw-r--r-- | source4/ntvfs/posix/pvfs_seek.c | 2 | ||||
-rw-r--r-- | source4/ntvfs/posix/pvfs_setfileinfo.c | 87 | ||||
-rw-r--r-- | source4/ntvfs/posix/pvfs_unlink.c | 9 | ||||
-rw-r--r-- | source4/ntvfs/posix/pvfs_write.c | 55 | ||||
-rw-r--r-- | source4/ntvfs/posix/vfs_posix.c | 4 | ||||
-rw-r--r-- | source4/ntvfs/posix/vfs_posix.h | 14 |
20 files changed, 374 insertions, 95 deletions
diff --git a/source4/ntvfs/common/brlock.c b/source4/ntvfs/common/brlock.c index c87eca8aff..3b34873152 100644 --- a/source4/ntvfs/common/brlock.c +++ b/source4/ntvfs/common/brlock.c @@ -109,7 +109,7 @@ NTSTATUS brl_remove_pending(struct brl_context *brl, */ NTSTATUS brl_locktest(struct brl_context *brl, struct brl_handle *brlh, - uint16_t smbpid, + uint32_t smbpid, uint64_t start, uint64_t size, enum brl_type lock_type) { diff --git a/source4/ntvfs/common/brlock_tdb.c b/source4/ntvfs/common/brlock_tdb.c index 362a6d01e2..c94b9b446e 100644 --- a/source4/ntvfs/common/brlock_tdb.c +++ b/source4/ntvfs/common/brlock_tdb.c @@ -57,7 +57,7 @@ struct brl_context { */ struct lock_context { struct server_id server; - uint16_t smbpid; + uint32_t smbpid; struct brl_context *ctx; }; @@ -286,7 +286,7 @@ static NTSTATUS brl_tdb_lock_failed(struct brl_handle *brlh, struct lock_struct */ static NTSTATUS brl_tdb_lock(struct brl_context *brl, struct brl_handle *brlh, - uint16_t smbpid, + uint32_t smbpid, uint64_t start, uint64_t size, enum brl_type lock_type, void *notify_ptr) @@ -436,7 +436,7 @@ static void brl_tdb_notify_all(struct brl_context *brl, */ static NTSTATUS brl_tdb_unlock(struct brl_context *brl, struct brl_handle *brlh, - uint16_t smbpid, + uint32_t smbpid, uint64_t start, uint64_t size) { TDB_DATA kbuf, dbuf; @@ -581,7 +581,7 @@ static NTSTATUS brl_tdb_remove_pending(struct brl_context *brl, */ static NTSTATUS brl_tdb_locktest(struct brl_context *brl, struct brl_handle *brlh, - uint16_t smbpid, + uint32_t smbpid, uint64_t start, uint64_t size, enum brl_type lock_type) { diff --git a/source4/ntvfs/common/opendb.c b/source4/ntvfs/common/opendb.c index 2913ea8431..6917bad52a 100644 --- a/source4/ntvfs/common/opendb.c +++ b/source4/ntvfs/common/opendb.c @@ -97,11 +97,13 @@ DATA_BLOB odb_get_key(TALLOC_CTX *mem_ctx, struct odb_lock *lck) */ NTSTATUS odb_open_file(struct odb_lock *lck, void *file_handle, const char *path, - int *fd, bool allow_level_II_oplock, + int *fd, NTTIME open_write_time, + bool allow_level_II_oplock, uint32_t oplock_level, uint32_t *oplock_granted) { return ops->odb_open_file(lck, file_handle, path, - fd, allow_level_II_oplock, + fd, open_write_time, + allow_level_II_oplock, oplock_level, oplock_granted); } @@ -159,15 +161,23 @@ NTSTATUS odb_set_delete_on_close(struct odb_lock *lck, bool del_on_close) } /* - return the current value of the delete_on_close bit, and how many - people still have the file open + update the write time on an open file */ -NTSTATUS odb_get_delete_on_close(struct odb_context *odb, - DATA_BLOB *key, bool *del_on_close) +NTSTATUS odb_set_write_time(struct odb_lock *lck, + NTTIME write_time, bool force) { - return ops->odb_get_delete_on_close(odb, key, del_on_close); + return ops->odb_set_write_time(lck, write_time, force); } +/* + return the current value of the delete_on_close bit, + and the current write time. +*/ +NTSTATUS odb_get_file_infos(struct odb_context *odb, DATA_BLOB *key, + bool *del_on_close, NTTIME *write_time) +{ + return ops->odb_get_file_infos(odb, key, del_on_close, write_time); +} /* determine if a file can be opened with the given share_access, diff --git a/source4/ntvfs/common/opendb.h b/source4/ntvfs/common/opendb.h index 045476337a..179db111ca 100644 --- a/source4/ntvfs/common/opendb.h +++ b/source4/ntvfs/common/opendb.h @@ -27,7 +27,8 @@ struct opendb_ops { DATA_BLOB (*odb_get_key)(TALLOC_CTX *mem_ctx, struct odb_lock *lck); NTSTATUS (*odb_open_file)(struct odb_lock *lck, void *file_handle, const char *path, - int *fd, bool allow_level_II_oplock, + int *fd, NTTIME open_write_time, + bool allow_level_II_oplock, uint32_t oplock_level, uint32_t *oplock_granted); NTSTATUS (*odb_open_file_pending)(struct odb_lock *lck, void *private); NTSTATUS (*odb_close_file)(struct odb_lock *lck, void *file_handle, @@ -36,8 +37,10 @@ struct opendb_ops { NTSTATUS (*odb_rename)(struct odb_lock *lck, const char *path); NTSTATUS (*odb_get_path)(struct odb_lock *lck, const char **path); NTSTATUS (*odb_set_delete_on_close)(struct odb_lock *lck, bool del_on_close); - NTSTATUS (*odb_get_delete_on_close)(struct odb_context *odb, - DATA_BLOB *key, bool *del_on_close); + NTSTATUS (*odb_set_write_time)(struct odb_lock *lck, + NTTIME write_time, bool force); + NTSTATUS (*odb_get_file_infos)(struct odb_context *odb, DATA_BLOB *key, + bool *del_on_close, NTTIME *write_time); NTSTATUS (*odb_can_open)(struct odb_lock *lck, uint32_t stream_id, uint32_t share_access, uint32_t access_mask, bool delete_on_close, diff --git a/source4/ntvfs/common/opendb_tdb.c b/source4/ntvfs/common/opendb_tdb.c index 99c0a95c20..d7531297ed 100644 --- a/source4/ntvfs/common/opendb_tdb.c +++ b/source4/ntvfs/common/opendb_tdb.c @@ -452,7 +452,8 @@ static NTSTATUS odb_tdb_open_can_internal(struct odb_context *odb, */ static NTSTATUS odb_tdb_open_file(struct odb_lock *lck, void *file_handle, const char *path, - int *fd, bool allow_level_II_oplock, + int *fd, NTTIME open_write_time, + bool allow_level_II_oplock, uint32_t oplock_level, uint32_t *oplock_granted) { struct odb_context *odb = lck->odb; @@ -474,6 +475,10 @@ static NTSTATUS odb_tdb_open_file(struct odb_lock *lck, NT_STATUS_HAVE_NO_MEMORY(lck->file.path); } + if (lck->file.open_write_time == 0) { + lck->file.open_write_time = open_write_time; + } + /* possibly grant an exclusive, batch or level2 oplock */ @@ -785,20 +790,53 @@ static NTSTATUS odb_tdb_set_delete_on_close(struct odb_lock *lck, bool del_on_cl } /* + update the write time on an open file +*/ +static NTSTATUS odb_tdb_set_write_time(struct odb_lock *lck, + NTTIME write_time, bool force) +{ + if (lck->file.path == NULL) { + return NT_STATUS_OBJECT_NAME_NOT_FOUND; + } + + if (lck->file.changed_write_time != 0 && !force) { + return NT_STATUS_OK; + } + + lck->file.changed_write_time = write_time; + + return odb_push_record(lck, &lck->file); +} + +/* return the current value of the delete_on_close bit, and how many people still have the file open */ -static NTSTATUS odb_tdb_get_delete_on_close(struct odb_context *odb, - DATA_BLOB *key, bool *del_on_close) +static NTSTATUS odb_tdb_get_file_infos(struct odb_context *odb, DATA_BLOB *key, + bool *del_on_close, NTTIME *write_time) { struct odb_lock *lck; - (*del_on_close) = false; + if (del_on_close) { + *del_on_close = false; + } + if (write_time) { + *write_time = 0; + } lck = odb_lock(odb, odb, key); NT_STATUS_HAVE_NO_MEMORY(lck); - (*del_on_close) = lck->file.delete_on_close; + if (del_on_close) { + *del_on_close = lck->file.delete_on_close; + } + if (write_time) { + if (lck->file.changed_write_time == 0) { + *write_time = lck->file.open_write_time; + } else { + *write_time = lck->file.changed_write_time; + } + } talloc_free(lck); @@ -852,7 +890,8 @@ static const struct opendb_ops opendb_tdb_ops = { .odb_rename = odb_tdb_rename, .odb_get_path = odb_tdb_get_path, .odb_set_delete_on_close = odb_tdb_set_delete_on_close, - .odb_get_delete_on_close = odb_tdb_get_delete_on_close, + .odb_set_write_time = odb_tdb_set_write_time, + .odb_get_file_infos = odb_tdb_get_file_infos, .odb_can_open = odb_tdb_can_open, .odb_update_oplock = odb_tdb_update_oplock, .odb_break_oplocks = odb_tdb_break_oplocks diff --git a/source4/ntvfs/ntvfs.h b/source4/ntvfs/ntvfs.h index 7a2edc7e2c..5de8a8b649 100644 --- a/source4/ntvfs/ntvfs.h +++ b/source4/ntvfs/ntvfs.h @@ -263,7 +263,7 @@ struct ntvfs_request { struct auth_session_info *session_info; /* the smb pid is needed for locking contexts */ - uint16_t smbpid; + uint32_t smbpid; /* * client capabilities diff --git a/source4/ntvfs/ntvfs_generic.c b/source4/ntvfs/ntvfs_generic.c index d705758475..4f3a7e2198 100644 --- a/source4/ntvfs/ntvfs_generic.c +++ b/source4/ntvfs/ntvfs_generic.c @@ -986,8 +986,8 @@ NTSTATUS ntvfs_map_qpathinfo(struct ntvfs_module_context *ntvfs, NTVFS lock generic to any mapper */ NTSTATUS ntvfs_map_lock(struct ntvfs_module_context *ntvfs, - struct ntvfs_request *req, - union smb_lock *lck) + struct ntvfs_request *req, + union smb_lock *lck) { union smb_lock *lck2; struct smb_lock_entry *locks; @@ -1035,7 +1035,8 @@ NTSTATUS ntvfs_map_lock(struct ntvfs_module_context *ntvfs, case RAW_LOCK_SMB2: { /* this is only approximate! We need to change the generic structure to fix this properly */ - int i, j; + int i; + bool isunlock; if (lck->smb2.in.lock_count < 1) { return NT_STATUS_INVALID_PARAMETER; } @@ -1051,32 +1052,28 @@ NTSTATUS ntvfs_map_lock(struct ntvfs_module_context *ntvfs, if (lck2->generic.in.locks == NULL) { return NT_STATUS_NO_MEMORY; } + /* only the first lock gives the UNLOCK bit - see + MS-SMB2 3.3.5.14 */ + if (lck->smb2.in.locks[0].flags & SMB2_LOCK_FLAG_UNLOCK) { + lck2->generic.in.ulock_cnt = lck->smb2.in.lock_count; + isunlock = true; + } else { + lck2->generic.in.lock_cnt = lck->smb2.in.lock_count; + isunlock = false; + } for (i=0;i<lck->smb2.in.lock_count;i++) { - if (!(lck->smb2.in.locks[i].flags & SMB2_LOCK_FLAG_UNLOCK)) { - break; - } - j = lck2->generic.in.ulock_cnt; - if (lck->smb2.in.locks[i].flags & - (SMB2_LOCK_FLAG_SHARED|SMB2_LOCK_FLAG_EXCLUSIVE)) { + if (isunlock && + (lck->smb2.in.locks[i].flags & + (SMB2_LOCK_FLAG_SHARED|SMB2_LOCK_FLAG_EXCLUSIVE))) { return NT_STATUS_INVALID_PARAMETER; } - lck2->generic.in.ulock_cnt++; - lck2->generic.in.locks[j].pid = 0; - lck2->generic.in.locks[j].offset = lck->smb2.in.locks[i].offset; - lck2->generic.in.locks[j].count = lck->smb2.in.locks[i].length; - lck2->generic.in.locks[j].pid = 0; - } - for (;i<lck->smb2.in.lock_count;i++) { - if (lck->smb2.in.locks[i].flags & SMB2_LOCK_FLAG_UNLOCK) { - /* w2008 requires unlocks to come first */ + if (!isunlock && + (lck->smb2.in.locks[i].flags & SMB2_LOCK_FLAG_UNLOCK)) { return NT_STATUS_INVALID_PARAMETER; } - j = lck2->generic.in.ulock_cnt + lck2->generic.in.lock_cnt; - lck2->generic.in.lock_cnt++; - lck2->generic.in.locks[j].pid = 0; - lck2->generic.in.locks[j].offset = lck->smb2.in.locks[i].offset; - lck2->generic.in.locks[j].count = lck->smb2.in.locks[i].length; - lck2->generic.in.locks[j].pid = 0; + lck2->generic.in.locks[i].pid = req->smbpid; + lck2->generic.in.locks[i].offset = lck->smb2.in.locks[i].offset; + lck2->generic.in.locks[i].count = lck->smb2.in.locks[i].length; if (!(lck->smb2.in.locks[i].flags & SMB2_LOCK_FLAG_EXCLUSIVE)) { lck2->generic.in.mode = LOCKING_ANDX_SHARED_LOCK; } diff --git a/source4/ntvfs/posix/pvfs_fileinfo.c b/source4/ntvfs/posix/pvfs_fileinfo.c index 04f6ad78d0..a14c8f64ae 100644 --- a/source4/ntvfs/posix/pvfs_fileinfo.c +++ b/source4/ntvfs/posix/pvfs_fileinfo.c @@ -52,8 +52,13 @@ static uint32_t dos_mode_from_stat(struct pvfs_state *pvfs, struct stat *st) /* fill in the dos file attributes for a file */ -NTSTATUS pvfs_fill_dos_info(struct pvfs_state *pvfs, struct pvfs_filename *name, int fd) +NTSTATUS pvfs_fill_dos_info(struct pvfs_state *pvfs, struct pvfs_filename *name, + uint_t flags, int fd) { + NTSTATUS status; + DATA_BLOB lkey; + NTTIME write_time; + /* make directories appear as size 0 with 1 link */ if (S_ISDIR(name->st.st_mode)) { name->st.st_size = 0; @@ -85,7 +90,29 @@ NTSTATUS pvfs_fill_dos_info(struct pvfs_state *pvfs, struct pvfs_filename *name, name->dos.file_id = (((uint64_t)name->st.st_dev)<<32) | name->st.st_ino; name->dos.flags = 0; - return pvfs_dosattrib_load(pvfs, name, fd); + status = pvfs_dosattrib_load(pvfs, name, fd); + NT_STATUS_NOT_OK_RETURN(status); + + if (flags & PVFS_RESOLVE_NO_OPENDB) { + return NT_STATUS_OK; + } + + status = pvfs_locking_key(name, name, &lkey); + NT_STATUS_NOT_OK_RETURN(status); + + status = odb_get_file_infos(pvfs->odb_context, &lkey, + NULL, &write_time); + data_blob_free(&lkey); + if (!NT_STATUS_IS_OK(status)) { + DEBUG(1,("WARNING: odb_get_file_infos: %s\n", nt_errstr(status))); + return status; + } + + if (!null_time(write_time)) { + name->dos.write_time = write_time; + } + + return NT_STATUS_OK; } diff --git a/source4/ntvfs/posix/pvfs_lock.c b/source4/ntvfs/posix/pvfs_lock.c index 822b28246a..0054455838 100644 --- a/source4/ntvfs/posix/pvfs_lock.c +++ b/source4/ntvfs/posix/pvfs_lock.c @@ -31,7 +31,7 @@ */ NTSTATUS pvfs_check_lock(struct pvfs_state *pvfs, struct pvfs_file *f, - uint16_t smbpid, + uint32_t smbpid, uint64_t offset, uint64_t count, enum brl_type rw) { diff --git a/source4/ntvfs/posix/pvfs_open.c b/source4/ntvfs/posix/pvfs_open.c index dada9f503f..43203086f8 100644 --- a/source4/ntvfs/posix/pvfs_open.c +++ b/source4/ntvfs/posix/pvfs_open.c @@ -280,6 +280,7 @@ static NTSTATUS pvfs_open_directory(struct pvfs_state *pvfs, f->handle->position = 0; f->handle->mode = 0; f->handle->oplock = NULL; + ZERO_STRUCT(f->handle->write_time); f->handle->open_completed = false; if ((create_options & NTCREATEX_OPTIONS_DELETE_ON_CLOSE) && @@ -317,7 +318,8 @@ static NTSTATUS pvfs_open_directory(struct pvfs_state *pvfs, /* now really mark the file as open */ status = odb_open_file(lck, f->handle, name->full_name, - NULL, false, OPLOCK_NONE, NULL); + NULL, name->dos.write_time, + false, OPLOCK_NONE, NULL); if (!NT_STATUS_IS_OK(status)) { talloc_free(lck); @@ -377,7 +379,8 @@ static NTSTATUS pvfs_open_directory(struct pvfs_state *pvfs, } status = odb_open_file(lck, f->handle, name->full_name, - NULL, false, OPLOCK_NONE, NULL); + NULL, name->dos.write_time, + false, OPLOCK_NONE, NULL); if (!NT_STATUS_IS_OK(status)) { goto cleanup_delete; @@ -433,6 +436,9 @@ cleanup_delete: */ static int pvfs_handle_destructor(struct pvfs_file_handle *h) { + talloc_free(h->write_time.update_event); + h->write_time.update_event = NULL; + if ((h->create_options & NTCREATEX_OPTIONS_DELETE_ON_CLOSE) && h->name->stream_name) { NTSTATUS status; @@ -451,6 +457,14 @@ static int pvfs_handle_destructor(struct pvfs_file_handle *h) h->fd = -1; } + if (!h->write_time.update_forced && + h->write_time.update_on_close && + h->write_time.close_time == 0) { + struct timeval tv; + tv = timeval_current(); + h->write_time.close_time = timeval_to_nttime(&tv); + } + if (h->have_opendb_entry) { struct odb_lock *lck; NTSTATUS status; @@ -462,6 +476,26 @@ static int pvfs_handle_destructor(struct pvfs_file_handle *h) return 0; } + if (h->write_time.update_forced) { + status = odb_get_file_infos(h->pvfs->odb_context, + &h->odb_locking_key, + NULL, + &h->write_time.close_time); + if (!NT_STATUS_IS_OK(status)) { + DEBUG(0,("Unable get write time for '%s' - %s\n", + h->name->full_name, nt_errstr(status))); + } + + h->write_time.update_forced = false; + h->write_time.update_on_close = true; + } else if (h->write_time.update_on_close) { + status = odb_set_write_time(lck, h->write_time.close_time, true); + if (!NT_STATUS_IS_OK(status)) { + DEBUG(0,("Unable set write time for '%s' - %s\n", + h->name->full_name, nt_errstr(status))); + } + } + status = odb_close_file(lck, h, &delete_path); if (!NT_STATUS_IS_OK(status)) { DEBUG(0,("Unable to remove opendb entry for '%s' - %s\n", @@ -484,11 +518,26 @@ static int pvfs_handle_destructor(struct pvfs_file_handle *h) FILE_NOTIFY_CHANGE_FILE_NAME, delete_path); } + h->write_time.update_on_close = false; } talloc_free(lck); } + if (h->write_time.update_on_close) { + struct timeval tv[2]; + + nttime_to_timeval(&tv[0], h->name->dos.access_time); + nttime_to_timeval(&tv[1], h->write_time.close_time); + + if (!timeval_is_zero(&tv[0]) || !timeval_is_zero(&tv[1])) { + if (utimes(h->name->full_name, tv) == -1) { + DEBUG(0,("pvfs_handle_destructor: utimes() failed '%s' - %s\n", + h->name->full_name, strerror(errno))); + } + } + } + return 0; } @@ -594,8 +643,8 @@ static NTSTATUS pvfs_create_file(struct pvfs_state *pvfs, DATA_BLOB locking_key; status = pvfs_locking_key(parent, req, &locking_key); NT_STATUS_NOT_OK_RETURN(status); - status = odb_get_delete_on_close(pvfs->odb_context, &locking_key, - &del_on_close); + status = odb_get_file_infos(pvfs->odb_context, &locking_key, + &del_on_close, NULL); NT_STATUS_NOT_OK_RETURN(status); if (del_on_close) { return NT_STATUS_DELETE_PENDING; @@ -638,7 +687,7 @@ static NTSTATUS pvfs_create_file(struct pvfs_state *pvfs, } /* re-resolve the open fd */ - status = pvfs_resolve_name_fd(pvfs, fd, name); + status = pvfs_resolve_name_fd(pvfs, fd, name, 0); if (!NT_STATUS_IS_OK(status)) { close(fd); return status; @@ -730,10 +779,12 @@ static NTSTATUS pvfs_create_file(struct pvfs_state *pvfs, f->handle->mode = 0; f->handle->oplock = NULL; f->handle->have_opendb_entry = true; + ZERO_STRUCT(f->handle->write_time); f->handle->open_completed = false; status = odb_open_file(lck, f->handle, name->full_name, - &f->handle->fd, allow_level_II_oplock, + &f->handle->fd, name->dos.write_time, + allow_level_II_oplock, oplock_level, &oplock_granted); talloc_free(lck); if (!NT_STATUS_IS_OK(status)) { @@ -1334,6 +1385,7 @@ NTSTATUS pvfs_open(struct ntvfs_module_context *ntvfs, f->handle->mode = 0; f->handle->oplock = NULL; f->handle->have_opendb_entry = false; + ZERO_STRUCT(f->handle->write_time); f->handle->open_completed = false; /* form the lock context used for byte range locking and @@ -1437,7 +1489,8 @@ NTSTATUS pvfs_open(struct ntvfs_module_context *ntvfs, /* now really mark the file as open */ status = odb_open_file(lck, f->handle, name->full_name, - &f->handle->fd, allow_level_II_oplock, + &f->handle->fd, name->dos.write_time, + allow_level_II_oplock, oplock_level, &oplock_granted); if (!NT_STATUS_IS_OK(status)) { @@ -1476,7 +1529,7 @@ NTSTATUS pvfs_open(struct ntvfs_module_context *ntvfs, } /* re-resolve the open fd */ - status = pvfs_resolve_name_fd(f->pvfs, fd, f->handle->name); + status = pvfs_resolve_name_fd(f->pvfs, fd, f->handle->name, PVFS_RESOLVE_NO_OPENDB); if (!NT_STATUS_IS_OK(status)) { talloc_free(lck); return status; @@ -1538,7 +1591,6 @@ NTSTATUS pvfs_close(struct ntvfs_module_context *ntvfs, { struct pvfs_state *pvfs = ntvfs->private_data; struct pvfs_file *f; - struct utimbuf unix_times; if (io->generic.level == RAW_CLOSE_SPLCLOSE) { return NT_STATUS_DOS(ERRSRV, ERRerror); @@ -1554,9 +1606,9 @@ NTSTATUS pvfs_close(struct ntvfs_module_context *ntvfs, } if (!null_time(io->generic.in.write_time)) { - unix_times.actime = 0; - unix_times.modtime = io->close.in.write_time; - utime(f->handle->name->full_name, &unix_times); + f->handle->write_time.update_forced = false; + f->handle->write_time.update_on_close = true; + unix_to_nt_time(&f->handle->write_time.close_time, io->generic.in.write_time); } if (io->generic.in.flags & SMB2_CLOSE_FLAGS_FULL_INFORMATION) { @@ -1915,8 +1967,8 @@ bool pvfs_delete_on_close_set(struct pvfs_state *pvfs, struct pvfs_file_handle * NTSTATUS status; bool del_on_close; - status = odb_get_delete_on_close(pvfs->odb_context, &h->odb_locking_key, - &del_on_close); + status = odb_get_file_infos(pvfs->odb_context, &h->odb_locking_key, + &del_on_close, NULL); if (!NT_STATUS_IS_OK(status)) { DEBUG(1,("WARNING: unable to determine delete on close status for open file\n")); return false; diff --git a/source4/ntvfs/posix/pvfs_oplock.c b/source4/ntvfs/posix/pvfs_oplock.c index dfa3697af7..71add72987 100644 --- a/source4/ntvfs/posix/pvfs_oplock.c +++ b/source4/ntvfs/posix/pvfs_oplock.c @@ -177,7 +177,7 @@ static void pvfs_oplock_break_dispatch(struct messaging_context *msg, opb = *p; } else { DEBUG(0,("%s: ignore oplock break with length[%u]\n", - __location__, data->length)); + __location__, (unsigned)data->length)); return; } if (opb.file_handle != opl->handle) { diff --git a/source4/ntvfs/posix/pvfs_rename.c b/source4/ntvfs/posix/pvfs_rename.c index 5c2a627084..d8ea5896e5 100644 --- a/source4/ntvfs/posix/pvfs_rename.c +++ b/source4/ntvfs/posix/pvfs_rename.c @@ -287,7 +287,9 @@ static NTSTATUS pvfs_rename_one(struct pvfs_state *pvfs, /* get a pvfs_filename source object */ status = pvfs_resolve_partial(pvfs, mem_ctx, - dir_path, fname1, &name1); + dir_path, fname1, + PVFS_RESOLVE_NO_OPENDB, + &name1); if (!NT_STATUS_IS_OK(status)) { goto failed; } @@ -306,7 +308,9 @@ static NTSTATUS pvfs_rename_one(struct pvfs_state *pvfs, /* get a pvfs_filename dest object */ status = pvfs_resolve_partial(pvfs, mem_ctx, - dir_path, fname2, &name2); + dir_path, fname2, + PVFS_RESOLVE_NO_OPENDB, + &name2); if (NT_STATUS_IS_OK(status)) { status = pvfs_can_delete(pvfs, req, name2, NULL); if (!NT_STATUS_IS_OK(status)) { diff --git a/source4/ntvfs/posix/pvfs_resolve.c b/source4/ntvfs/posix/pvfs_resolve.c index 2e97925c49..0f19788b97 100644 --- a/source4/ntvfs/posix/pvfs_resolve.c +++ b/source4/ntvfs/posix/pvfs_resolve.c @@ -57,7 +57,9 @@ static int component_compare(struct pvfs_state *pvfs, const char *comp, const ch TODO: add a cache for previously resolved case-insensitive names TODO: add mangled name support */ -static NTSTATUS pvfs_case_search(struct pvfs_state *pvfs, struct pvfs_filename *name) +static NTSTATUS pvfs_case_search(struct pvfs_state *pvfs, + struct pvfs_filename *name, + uint_t flags) { /* break into a series of components */ int num_components; @@ -175,7 +177,7 @@ static NTSTATUS pvfs_case_search(struct pvfs_state *pvfs, struct pvfs_filename * name->full_name = partial_name; if (name->exists) { - return pvfs_fill_dos_info(pvfs, name, -1); + return pvfs_fill_dos_info(pvfs, name, flags, -1); } return NT_STATUS_OK; @@ -515,7 +517,7 @@ NTSTATUS pvfs_resolve_name(struct pvfs_state *pvfs, TALLOC_CTX *mem_ctx, /* we need to search for a matching name */ saved_name = (*name)->full_name; (*name)->full_name = dir_name; - status = pvfs_case_search(pvfs, *name); + status = pvfs_case_search(pvfs, *name, flags); if (!NT_STATUS_IS_OK(status)) { /* the directory doesn't exist */ (*name)->full_name = saved_name; @@ -536,11 +538,11 @@ NTSTATUS pvfs_resolve_name(struct pvfs_state *pvfs, TALLOC_CTX *mem_ctx, /* if we can stat() the full name now then we are done */ if (stat((*name)->full_name, &(*name)->st) == 0) { (*name)->exists = true; - return pvfs_fill_dos_info(pvfs, *name, -1); + return pvfs_fill_dos_info(pvfs, *name, flags, -1); } /* search for a matching filename */ - status = pvfs_case_search(pvfs, *name); + status = pvfs_case_search(pvfs, *name, flags); return status; } @@ -556,7 +558,7 @@ NTSTATUS pvfs_resolve_name(struct pvfs_state *pvfs, TALLOC_CTX *mem_ctx, */ NTSTATUS pvfs_resolve_partial(struct pvfs_state *pvfs, TALLOC_CTX *mem_ctx, const char *unix_dir, const char *fname, - struct pvfs_filename **name) + uint_t flags, struct pvfs_filename **name) { NTSTATUS status; @@ -581,7 +583,7 @@ NTSTATUS pvfs_resolve_partial(struct pvfs_state *pvfs, TALLOC_CTX *mem_ctx, (*name)->stream_name = NULL; (*name)->stream_id = 0; - status = pvfs_fill_dos_info(pvfs, *name, -1); + status = pvfs_fill_dos_info(pvfs, *name, flags, -1); return status; } @@ -593,7 +595,7 @@ NTSTATUS pvfs_resolve_partial(struct pvfs_state *pvfs, TALLOC_CTX *mem_ctx, to update the pvfs_filename stat information, and by pvfs_open() */ NTSTATUS pvfs_resolve_name_fd(struct pvfs_state *pvfs, int fd, - struct pvfs_filename *name) + struct pvfs_filename *name, uint_t flags) { dev_t device = (dev_t)0; ino_t inode = 0; @@ -626,7 +628,7 @@ NTSTATUS pvfs_resolve_name_fd(struct pvfs_state *pvfs, int fd, name->exists = true; - return pvfs_fill_dos_info(pvfs, name, fd); + return pvfs_fill_dos_info(pvfs, name, flags, fd); } /* @@ -703,9 +705,17 @@ NTSTATUS pvfs_resolve_name_handle(struct pvfs_state *pvfs, talloc_free(lck); } - status = pvfs_resolve_name_fd(pvfs, h->fd, h->name); + /* + * TODO: pass PVFS_RESOLVE_NO_OPENDB and get + * the write time from odb_lock() above. + */ + status = pvfs_resolve_name_fd(pvfs, h->fd, h->name, 0); NT_STATUS_NOT_OK_RETURN(status); + if (!null_nttime(h->write_time.close_time)) { + h->name->dos.write_time = h->write_time.close_time; + } + return NT_STATUS_OK; } @@ -755,7 +765,7 @@ NTSTATUS pvfs_resolve_parent(struct pvfs_state *pvfs, TALLOC_CTX *mem_ctx, (*name)->stream_name = NULL; (*name)->stream_id = 0; - status = pvfs_fill_dos_info(pvfs, *name, -1); + status = pvfs_fill_dos_info(pvfs, *name, PVFS_RESOLVE_NO_OPENDB, -1); return status; } diff --git a/source4/ntvfs/posix/pvfs_search.c b/source4/ntvfs/posix/pvfs_search.c index e47406dc09..e0fe4fb64d 100644 --- a/source4/ntvfs/posix/pvfs_search.c +++ b/source4/ntvfs/posix/pvfs_search.c @@ -84,7 +84,7 @@ static NTSTATUS fill_search_info(struct pvfs_state *pvfs, in pvfs_list_seek_ofs() for how we cope with this */ - status = pvfs_resolve_partial(pvfs, file, unix_path, fname, &name); + status = pvfs_resolve_partial(pvfs, file, unix_path, fname, 0, &name); if (!NT_STATUS_IS_OK(status)) { return status; } diff --git a/source4/ntvfs/posix/pvfs_seek.c b/source4/ntvfs/posix/pvfs_seek.c index 3ea8b7cb6e..a3c4024ed7 100644 --- a/source4/ntvfs/posix/pvfs_seek.c +++ b/source4/ntvfs/posix/pvfs_seek.c @@ -52,7 +52,7 @@ NTSTATUS pvfs_seek(struct ntvfs_module_context *ntvfs, break; case SEEK_MODE_END: - status = pvfs_resolve_name_fd(pvfs, h->fd, h->name); + status = pvfs_resolve_name_fd(pvfs, h->fd, h->name, PVFS_RESOLVE_NO_OPENDB); h->seek_offset = h->name->st.st_size + io->lseek.in.offset; break; } diff --git a/source4/ntvfs/posix/pvfs_setfileinfo.c b/source4/ntvfs/posix/pvfs_setfileinfo.c index 1dd2c075d9..2cde5f42aa 100644 --- a/source4/ntvfs/posix/pvfs_setfileinfo.c +++ b/source4/ntvfs/posix/pvfs_setfileinfo.c @@ -273,7 +273,6 @@ NTSTATUS pvfs_setfileinfo(struct ntvfs_module_context *ntvfs, union smb_setfileinfo *info) { struct pvfs_state *pvfs = ntvfs->private_data; - struct utimbuf unix_times; struct pvfs_file *f; struct pvfs_file_handle *h; struct pvfs_filename newstats; @@ -437,23 +436,54 @@ NTSTATUS pvfs_setfileinfo(struct ntvfs_module_context *ntvfs, } /* possibly change the file timestamps */ - ZERO_STRUCT(unix_times); if (newstats.dos.create_time != h->name->dos.create_time) { change_mask |= FILE_NOTIFY_CHANGE_CREATION; } if (newstats.dos.access_time != h->name->dos.access_time) { - unix_times.actime = nt_time_to_unix(newstats.dos.access_time); change_mask |= FILE_NOTIFY_CHANGE_LAST_ACCESS; } if (newstats.dos.write_time != h->name->dos.write_time) { - unix_times.modtime = nt_time_to_unix(newstats.dos.write_time); change_mask |= FILE_NOTIFY_CHANGE_LAST_WRITE; } - if (unix_times.actime != 0 || unix_times.modtime != 0) { - if (utime(h->name->full_name, &unix_times) == -1) { - return pvfs_map_errno(pvfs, errno); + if ((change_mask & FILE_NOTIFY_CHANGE_LAST_ACCESS) || + (change_mask & FILE_NOTIFY_CHANGE_LAST_WRITE)) { + struct timeval tv[2]; + + nttime_to_timeval(&tv[0], newstats.dos.access_time); + nttime_to_timeval(&tv[1], newstats.dos.write_time); + + if (!timeval_is_zero(&tv[0]) || !timeval_is_zero(&tv[1])) { + if (utimes(h->name->full_name, tv) == -1) { + DEBUG(0,("pvfs_setfileinfo: utimes() failed '%s' - %s\n", + h->name->full_name, strerror(errno))); + return pvfs_map_errno(pvfs, errno); + } } } + if (change_mask & FILE_NOTIFY_CHANGE_LAST_WRITE) { + struct odb_lock *lck; + + lck = odb_lock(req, h->pvfs->odb_context, &h->odb_locking_key); + if (lck == NULL) { + DEBUG(0,("Unable to lock opendb for write time update\n")); + return NT_STATUS_INTERNAL_ERROR; + } + + status = odb_set_write_time(lck, newstats.dos.write_time, true); + if (!NT_STATUS_IS_OK(status)) { + DEBUG(0,("Unable to update write time: %s\n", + nt_errstr(status))); + talloc_free(lck); + return status; + } + + talloc_free(lck); + + h->write_time.update_forced = true; + h->write_time.update_on_close = false; + talloc_free(h->write_time.update_event); + h->write_time.update_event = NULL; + } /* possibly change the attribute */ if (newstats.dos.attrib != h->name->dos.attrib) { @@ -570,7 +600,6 @@ NTSTATUS pvfs_setpathinfo(struct ntvfs_module_context *ntvfs, struct pvfs_filename *name; struct pvfs_filename newstats; NTSTATUS status; - struct utimbuf unix_times; uint32_t access_needed; uint32_t change_mask = 0; struct odb_lock *lck = NULL; @@ -736,21 +765,51 @@ NTSTATUS pvfs_setpathinfo(struct ntvfs_module_context *ntvfs, } /* possibly change the file timestamps */ - ZERO_STRUCT(unix_times); if (newstats.dos.create_time != name->dos.create_time) { change_mask |= FILE_NOTIFY_CHANGE_CREATION; } if (newstats.dos.access_time != name->dos.access_time) { - unix_times.actime = nt_time_to_unix(newstats.dos.access_time); change_mask |= FILE_NOTIFY_CHANGE_LAST_ACCESS; } if (newstats.dos.write_time != name->dos.write_time) { - unix_times.modtime = nt_time_to_unix(newstats.dos.write_time); change_mask |= FILE_NOTIFY_CHANGE_LAST_WRITE; } - if (unix_times.actime != 0 || unix_times.modtime != 0) { - if (utime(name->full_name, &unix_times) == -1) { - return pvfs_map_errno(pvfs, errno); + if ((change_mask & FILE_NOTIFY_CHANGE_LAST_ACCESS) || + (change_mask & FILE_NOTIFY_CHANGE_LAST_WRITE)) { + struct timeval tv[2]; + + nttime_to_timeval(&tv[0], newstats.dos.access_time); + nttime_to_timeval(&tv[1], newstats.dos.write_time); + + if (!timeval_is_zero(&tv[0]) || !timeval_is_zero(&tv[1])) { + if (utimes(name->full_name, tv) == -1) { + DEBUG(0,("pvfs_setpathinfo: utimes() failed '%s' - %s\n", + name->full_name, strerror(errno))); + return pvfs_map_errno(pvfs, errno); + } + } + } + if (change_mask & FILE_NOTIFY_CHANGE_LAST_WRITE) { + if (lck == NULL) { + DATA_BLOB lkey; + status = pvfs_locking_key(name, name, &lkey); + NT_STATUS_NOT_OK_RETURN(status); + + lck = odb_lock(req, pvfs->odb_context, &lkey); + data_blob_free(&lkey); + if (lck == NULL) { + DEBUG(0,("Unable to lock opendb for write time update\n")); + return NT_STATUS_INTERNAL_ERROR; + } + } + + status = odb_set_write_time(lck, newstats.dos.write_time, true); + if (NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_NOT_FOUND)) { + /* it could be that nobody has opened the file */ + } else if (!NT_STATUS_IS_OK(status)) { + DEBUG(0,("Unable to update write time: %s\n", + nt_errstr(status))); + return status; } } diff --git a/source4/ntvfs/posix/pvfs_unlink.c b/source4/ntvfs/posix/pvfs_unlink.c index 4cb47a4f1f..6a57041770 100644 --- a/source4/ntvfs/posix/pvfs_unlink.c +++ b/source4/ntvfs/posix/pvfs_unlink.c @@ -201,7 +201,10 @@ NTSTATUS pvfs_unlink(struct ntvfs_module_context *ntvfs, /* resolve the cifs name to a posix name */ status = pvfs_resolve_name(pvfs, req, unl->unlink.in.pattern, - PVFS_RESOLVE_WILDCARD | PVFS_RESOLVE_STREAMS, &name); + PVFS_RESOLVE_WILDCARD | + PVFS_RESOLVE_STREAMS | + PVFS_RESOLVE_NO_OPENDB, + &name); if (!NT_STATUS_IS_OK(status)) { return status; } @@ -246,7 +249,9 @@ NTSTATUS pvfs_unlink(struct ntvfs_module_context *ntvfs, /* get a pvfs_filename object */ status = pvfs_resolve_partial(pvfs, req, pvfs_list_unix_path(dir), - fname, &name); + fname, + PVFS_RESOLVE_NO_OPENDB, + &name); if (!NT_STATUS_IS_OK(status)) { return status; } diff --git a/source4/ntvfs/posix/pvfs_write.c b/source4/ntvfs/posix/pvfs_write.c index 1f662f13fc..2da0e4bb3a 100644 --- a/source4/ntvfs/posix/pvfs_write.c +++ b/source4/ntvfs/posix/pvfs_write.c @@ -22,7 +22,60 @@ #include "includes.h" #include "vfs_posix.h" #include "librpc/gen_ndr/security.h" +#include "lib/events/events.h" +static void pvfs_write_time_update_handler(struct event_context *ev, + struct timed_event *te, + struct timeval tv, + void *private_data) +{ + struct pvfs_file_handle *h = talloc_get_type(private_data, + struct pvfs_file_handle); + struct odb_lock *lck; + NTSTATUS status; + NTTIME write_time; + + lck = odb_lock(h, h->pvfs->odb_context, &h->odb_locking_key); + if (lck == NULL) { + DEBUG(0,("Unable to lock opendb for write time update\n")); + return; + } + + write_time = timeval_to_nttime(&tv); + + status = odb_set_write_time(lck, write_time, false); + if (!NT_STATUS_IS_OK(status)) { + DEBUG(0,("Unable to update write time: %s\n", + nt_errstr(status))); + return; + } + + talloc_free(lck); + + h->write_time.update_event = NULL; +} + +static void pvfs_trigger_write_time_update(struct pvfs_file_handle *h) +{ + struct pvfs_state *pvfs = h->pvfs; + struct timeval tv; + + if (h->write_time.update_triggered) { + return; + } + + tv = timeval_current_ofs(0, pvfs->writetime_delay); + + h->write_time.update_triggered = true; + h->write_time.update_on_close = true; + h->write_time.update_event = event_add_timed(pvfs->ntvfs->ctx->event_ctx, + h, tv, + pvfs_write_time_update_handler, + h); + if (!h->write_time.update_event) { + DEBUG(0,("Failed event_add_timed\n")); + } +} /* write to a file @@ -61,6 +114,8 @@ NTSTATUS pvfs_write(struct ntvfs_module_context *ntvfs, status = pvfs_break_level2_oplocks(f); NT_STATUS_NOT_OK_RETURN(status); + pvfs_trigger_write_time_update(f->handle); + if (f->handle->name->stream_name) { ret = pvfs_stream_write(pvfs, f->handle, diff --git a/source4/ntvfs/posix/vfs_posix.c b/source4/ntvfs/posix/vfs_posix.c index 14b5210fd0..b5dd270346 100644 --- a/source4/ntvfs/posix/vfs_posix.c +++ b/source4/ntvfs/posix/vfs_posix.c @@ -95,6 +95,10 @@ static void pvfs_setup_options(struct pvfs_state *pvfs) PVFS_OPLOCK_TIMEOUT, PVFS_OPLOCK_TIMEOUT_DEFAULT); + pvfs->writetime_delay = share_int_option(scfg, + PVFS_WRITETIME_DELAY, + PVFS_WRITETIME_DELAY_DEFAULT); + pvfs->share_name = talloc_strdup(pvfs, scfg->name); pvfs->fs_attribs = diff --git a/source4/ntvfs/posix/vfs_posix.h b/source4/ntvfs/posix/vfs_posix.h index c194698b64..cf39bcf0ac 100644 --- a/source4/ntvfs/posix/vfs_posix.h +++ b/source4/ntvfs/posix/vfs_posix.h @@ -59,6 +59,9 @@ struct pvfs_state { /* the oplock break timeout (secs) */ uint_t oplock_break_timeout; + /* the write time update delay (nsecs) */ + uint_t writetime_delay; + /* filesystem attributes (see FS_ATTR_*) */ uint32_t fs_attribs; @@ -169,6 +172,14 @@ struct pvfs_file_handle { /* we need this hook back to our parent for lock destruction */ struct pvfs_state *pvfs; + struct { + bool update_triggered; + struct timed_event *update_event; + bool update_on_close; + NTTIME close_time; + bool update_forced; + } write_time; + /* the open went through to completion */ bool open_completed; }; @@ -220,6 +231,7 @@ struct pvfs_search_state { /* flags to pvfs_resolve_name() */ #define PVFS_RESOLVE_WILDCARD (1<<0) #define PVFS_RESOLVE_STREAMS (1<<1) +#define PVFS_RESOLVE_NO_OPENDB (1<<2) /* flags in pvfs->flags */ #define PVFS_FLAG_CI_FILESYSTEM (1<<0) /* the filesystem is case insensitive */ @@ -249,6 +261,7 @@ struct pvfs_odb_retry; #define PVFS_FAKE_OPLOCKS "posix:fakeoplocks" #define PVFS_SHARE_DELAY "posix:sharedelay" #define PVFS_OPLOCK_TIMEOUT "posix:oplocktimeout" +#define PVFS_WRITETIME_DELAY "posix:writetimeupdatedelay" #define PVFS_ALLOCATION_ROUNDING "posix:allocationrounding" #define PVFS_SEARCH_INACTIVITY "posix:searchinactivity" #define PVFS_ACL "posix:acl" @@ -258,6 +271,7 @@ struct pvfs_odb_retry; #define PVFS_FAKE_OPLOCKS_DEFAULT false #define PVFS_SHARE_DELAY_DEFAULT 1000000 /* nsecs */ #define PVFS_OPLOCK_TIMEOUT_DEFAULT 30 /* secs */ +#define PVFS_WRITETIME_DELAY_DEFAULT 2000000 /* nsecs */ #define PVFS_ALLOCATION_ROUNDING_DEFAULT 512 #define PVFS_SEARCH_INACTIVITY_DEFAULT 300 |