} else {
status = pvfs_access_check_create(pvfs, req, name, &access_mask);
}
- if (!NT_STATUS_IS_OK(status)) {
- return status;
+ NT_STATUS_NOT_OK_RETURN(status);
+
+ if (io->generic.in.query_maximal_access) {
+ status = pvfs_access_maximal_allowed(pvfs, req, name,
+ &io->generic.out.maximal_access);
+ NT_STATUS_NOT_OK_RETURN(status);
}
f->ntvfs = h;
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) &&
/* 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);
}
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;
*/
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;
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;
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",
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;
}
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;
}
/* 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;
goto cleanup_delete;
}
+ if (io->generic.in.query_maximal_access) {
+ status = pvfs_access_maximal_allowed(pvfs, req, name,
+ &io->generic.out.maximal_access);
+ NT_STATUS_NOT_OK_RETURN(status);
+ }
+
/* form the lock context used for byte range locking and
opendb locking */
status = pvfs_locking_key(name, f->handle, &f->handle->odb_locking_key);
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)) {
struct ntvfs_request *req, union smb_open *io)
{
struct pvfs_state *pvfs = ntvfs->private_data;
- int flags;
+ int flags = 0;
struct pvfs_filename *name;
struct pvfs_file *f;
struct ntvfs_handle *h;
int fd;
struct odb_lock *lck;
uint32_t create_options;
+ uint32_t create_options_must_ignore_mask;
uint32_t share_access;
uint32_t access_mask;
+ uint32_t create_action = NTCREATEX_ACTION_EXISTED;
bool del_on_close;
bool stream_existed, stream_truncate=false;
uint32_t oplock_level = OPLOCK_NONE, oplock_granted;
return ntvfs_map_open(ntvfs, req, io);
}
+ ZERO_STRUCT(io->generic.out);
+
create_options = io->generic.in.create_options;
share_access = io->generic.in.share_access;
access_mask = io->generic.in.access_mask;
return NT_STATUS_INVALID_PARAMETER;
}
- /* some create options are not supported */
+ /*
+ * These options are ignored,
+ * but we reuse some of them as private values for the generic mapping
+ */
+ create_options_must_ignore_mask = NTCREATEX_OPTIONS_MUST_IGNORE_MASK;
+ create_options_must_ignore_mask &= ~NTCREATEX_OPTIONS_PRIVATE_MASK;
+ create_options &= ~create_options_must_ignore_mask;
+
if (create_options & NTCREATEX_OPTIONS_NOT_SUPPORTED_MASK) {
return NT_STATUS_NOT_SUPPORTED;
}
+ if (create_options & NTCREATEX_OPTIONS_INVALID_PARAM_MASK) {
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ /* TODO: When we implement HSM, add a hook here not to pull
+ * the actual file off tape, when this option is passed from
+ * the client */
+ if (create_options & NTCREATEX_OPTIONS_NO_RECALL) {
+ /* no-op */
+ }
+
+ /* TODO: If (unlikely) Linux does a good compressed
+ * filesystem, we might need an ioctl call for this */
+ if (create_options & NTCREATEX_OPTIONS_NO_COMPRESSION) {
+ /* no-op */
+ }
+
+ if (create_options & NTCREATEX_OPTIONS_NO_INTERMEDIATE_BUFFERING) {
+ create_options |= NTCREATEX_OPTIONS_WRITE_THROUGH;
+ }
+
+ /* Open the file with sync, if they asked for it, but
+ 'strict sync = no' turns this client request into a no-op */
+ if (create_options & (NTCREATEX_OPTIONS_WRITE_THROUGH) && !(pvfs->flags | PVFS_FLAG_STRICT_SYNC)) {
+ flags |= O_SYNC;
+ }
+
+
/* other create options are not allowed */
if ((create_options & NTCREATEX_OPTIONS_DELETE_ON_CLOSE) &&
!(access_mask & SEC_STD_DELETE)) {
return NT_STATUS_INVALID_PARAMETER;
}
+ /* we ignore some file_attr bits */
+ io->ntcreatex.in.file_attr &= ~(FILE_ATTRIBUTE_NONINDEXED |
+ FILE_ATTRIBUTE_COMPRESSED |
+ FILE_ATTRIBUTE_REPARSE_POINT |
+ FILE_ATTRIBUTE_SPARSE |
+ FILE_ATTRIBUTE_NORMAL);
+
/* resolve the cifs name to a posix name */
status = pvfs_resolve_name(pvfs, req, io->ntcreatex.in.fname,
PVFS_RESOLVE_STREAMS, &name);
open doesn't match */
io->generic.in.file_attr &= ~FILE_ATTRIBUTE_DIRECTORY;
- flags = 0;
-
switch (io->generic.in.open_disposition) {
case NTCREATEX_DISP_SUPERSEDE:
case NTCREATEX_DISP_OVERWRITE_IF:
} else {
stream_truncate = true;
}
+ create_action = NTCREATEX_ACTION_TRUNCATED;
break;
case NTCREATEX_DISP_OPEN:
} else {
stream_truncate = true;
}
+ create_action = NTCREATEX_ACTION_TRUNCATED;
break;
case NTCREATEX_DISP_CREATE:
/* check the security descriptor */
status = pvfs_access_check(pvfs, req, name, &access_mask);
- if (!NT_STATUS_IS_OK(status)) {
- return status;
+ NT_STATUS_NOT_OK_RETURN(status);
+
+ if (io->generic.in.query_maximal_access) {
+ status = pvfs_access_maximal_allowed(pvfs, req, name,
+ &io->generic.out.maximal_access);
+ NT_STATUS_NOT_OK_RETURN(status);
}
status = ntvfs_handle_new(pvfs->ntvfs, req, &h);
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
/* 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)) {
}
/* 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;
io->generic.out.oplock_level = oplock_granted;
io->generic.out.file.ntvfs = h;
io->generic.out.create_action = stream_existed?
- NTCREATEX_ACTION_EXISTED:NTCREATEX_ACTION_CREATED;
+ create_action:NTCREATEX_ACTION_CREATED;
+
io->generic.out.create_time = name->dos.create_time;
io->generic.out.access_time = name->dos.access_time;
io->generic.out.write_time = name->dos.write_time;
{
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);
}
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) {
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;