summaryrefslogtreecommitdiff
path: root/source4/ntvfs
diff options
context:
space:
mode:
Diffstat (limited to 'source4/ntvfs')
-rw-r--r--source4/ntvfs/common/brlock.c2
-rw-r--r--source4/ntvfs/common/brlock_tdb.c8
-rw-r--r--source4/ntvfs/common/opendb.c24
-rw-r--r--source4/ntvfs/common/opendb.h9
-rw-r--r--source4/ntvfs/common/opendb_tdb.c51
-rw-r--r--source4/ntvfs/ntvfs.h2
-rw-r--r--source4/ntvfs/ntvfs_generic.c45
-rw-r--r--source4/ntvfs/posix/pvfs_fileinfo.c31
-rw-r--r--source4/ntvfs/posix/pvfs_lock.c2
-rw-r--r--source4/ntvfs/posix/pvfs_open.c80
-rw-r--r--source4/ntvfs/posix/pvfs_oplock.c2
-rw-r--r--source4/ntvfs/posix/pvfs_rename.c8
-rw-r--r--source4/ntvfs/posix/pvfs_resolve.c32
-rw-r--r--source4/ntvfs/posix/pvfs_search.c2
-rw-r--r--source4/ntvfs/posix/pvfs_seek.c2
-rw-r--r--source4/ntvfs/posix/pvfs_setfileinfo.c87
-rw-r--r--source4/ntvfs/posix/pvfs_unlink.c9
-rw-r--r--source4/ntvfs/posix/pvfs_write.c55
-rw-r--r--source4/ntvfs/posix/vfs_posix.c4
-rw-r--r--source4/ntvfs/posix/vfs_posix.h14
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