return;
}
- chmod(fsp->fsp_name,0755);
- ret = smbrun(fsp->fsp_name,&tmp_fd);
+ /* Ensure we don't depend on user's PATH. */
+ p = talloc_asprintf(ctx, "./%s", fsp->fsp_name);
+ if (!p) {
+ TALLOC_FREE(ctx);
+ return;
+ }
+
+ if (chmod(fsp->fsp_name,0755) == -1) {
+ TALLOC_FREE(ctx);
+ return;
+ }
+ ret = smbrun(p,&tmp_fd);
DEBUG(3,("Invoking magic command %s gave %d\n",
- fsp->fsp_name,ret));
+ p,ret));
unlink(fsp->fsp_name);
if (ret != 0 || tmp_fd == -1) {
static NTSTATUS close_filestruct(files_struct *fsp)
{
NTSTATUS status = NT_STATUS_OK;
- connection_struct *conn = fsp->conn;
-
+
if (fsp->fh->fd != -1) {
if(flush_write_cache(fsp, CLOSE_FLUSH) == -1) {
status = map_nt_error_from_unix(errno);
delete_write_cache(fsp);
}
- conn->num_files_open--;
return status;
-}
+}
/****************************************************************************
If any deferred opens are waiting on this close, notify them.
static void notify_deferred_opens(struct share_mode_lock *lck)
{
int i;
+
+ if (!should_notify_deferred_opens()) {
+ return;
+ }
for (i=0; i<lck->num_share_modes; i++) {
struct share_mode_entry *e = &lck->share_modes[i];
Delete all streams
****************************************************************************/
-static NTSTATUS delete_all_streams(connection_struct *conn, const char *fname)
+NTSTATUS delete_all_streams(connection_struct *conn, const char *fname)
{
struct stream_struct *stream_info;
int i;
* This prevents race conditions with the file being created. JRA.
*/
- lck = get_share_mode_lock(talloc_tos(), fsp->file_id, NULL, NULL);
+ lck = get_share_mode_lock(talloc_tos(), fsp->file_id, NULL, NULL,
+ NULL);
if (lck == NULL) {
DEBUG(0, ("close_remove_share_mode: Could not get share mode "
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));
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;
+
if (!unix_token_equal(lck->delete_token, ¤t_user.ut)) {
/* Become the user who requested the delete. */
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 smb_file_time ft;
+ NTSTATUS status;
+ int ret = -1;
+
+ ZERO_STRUCT(sbuf);
+ ZERO_STRUCT(ft);
+
+ 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) {
+ ret = SMB_VFS_FSTAT(fsp, &sbuf);
+ } else {
+ if (fsp->posix_open) {
+ ret = SMB_VFS_LSTAT(fsp->conn,fsp->fsp_name,&sbuf);
+ } else {
+ ret = SMB_VFS_STAT(fsp->conn,fsp->fsp_name,&sbuf);
+ }
+ }
+
+ if (ret == -1) {
+ return map_nt_error_from_unix(errno);
+ }
+
+ if (!VALID_STAT(sbuf)) {
+ /* if it doesn't seem to be a real file */
+ return NT_STATUS_OK;
+ }
+
+ ft.mtime = fsp->close_write_time;
+ status = smb_set_file_time(fsp->conn, fsp, fsp->fsp_name,
+ &sbuf, &ft, true);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ return NT_STATUS_OK;
+}
+
/****************************************************************************
Close a file.
delete on close is done on normal and shutdown close.
****************************************************************************/
-static NTSTATUS close_normal_file(files_struct *fsp, enum file_close_type close_type)
+static NTSTATUS close_normal_file(struct smb_request *req, files_struct *fsp,
+ enum file_close_type close_type)
{
NTSTATUS status = NT_STATUS_OK;
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) {
if (fsp->print_file) {
print_fsp_end(fsp, close_type);
- file_free(fsp);
+ file_free(req, fsp);
return NT_STATUS_OK;
}
+ /* Remove the oplock before potentially deleting the file. */
+ if(fsp->oplock_type) {
+ release_file_oplock(fsp);
+ }
+
/* If this is an old DOS or FCB open and we have multiple opens on
the same handle we only have one share mode. Ensure we only remove
the share mode on the last close. */
saved_status3 = close_remove_share_mode(fsp, close_type);
}
- if(fsp->oplock_type) {
- release_file_oplock(fsp);
- }
-
locking_close_file(smbd_messaging_context(), fsp);
status = fd_close(fsp);
* 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_EQUAL(saved_status4, NT_STATUS_OBJECT_NAME_NOT_FOUND)) {
+ /* Someone renamed the file or a parent directory containing
+ * this file. We can't do anything about this, we don't have
+ * an "update timestamp by fd" call in POSIX. Eat the error. */
+
+ saved_status4 = NT_STATUS_OK;
}
if (NT_STATUS_IS_OK(status)) {
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;
}
}
DEBUG(2,("%s closed file %s (numopen=%d) %s\n",
- conn->user,fsp->fsp_name,
- conn->num_files_open,
+ conn->server_info->unix_name,fsp->fsp_name,
+ conn->num_files_open - 1,
nt_errstr(status) ));
- file_free(fsp);
+ file_free(req, fsp);
return status;
}
Close a directory opened by an NT SMB call.
****************************************************************************/
-static NTSTATUS close_directory(files_struct *fsp, enum file_close_type close_type)
+static NTSTATUS close_directory(struct smb_request *req, files_struct *fsp,
+ enum file_close_type close_type)
{
struct share_mode_lock *lck = 0;
bool delete_dir = False;
* reference to a directory also.
*/
- lck = get_share_mode_lock(talloc_tos(), fsp->file_id, NULL, NULL);
+ lck = get_share_mode_lock(talloc_tos(), fsp->file_id, NULL, NULL,
+ NULL);
if (lck == NULL) {
DEBUG(0, ("close_directory: Could not get share mode lock for %s\n", fsp->fsp_name));
fsp, NT_STATUS_OK);
}
- /*
- * Do the code common to files and directories.
- */
- close_filestruct(fsp);
- file_free(fsp);
- return status;
-}
+ status = fd_close(fsp);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(0, ("Could not close dir! fname=%s, fd=%d, err=%d=%s\n",
+ fsp->fsp_name, fsp->fh->fd, errno, strerror(errno)));
+ }
-/****************************************************************************
- Close a 'stat file' opened internally.
-****************************************************************************/
-
-static NTSTATUS close_stat(files_struct *fsp)
-{
/*
* Do the code common to files and directories.
*/
close_filestruct(fsp);
- file_free(fsp);
- return NT_STATUS_OK;
+ file_free(req, fsp);
+ return status;
}
/****************************************************************************
Close a files_struct.
****************************************************************************/
-NTSTATUS close_file(files_struct *fsp, enum file_close_type close_type)
+NTSTATUS close_file(struct smb_request *req, files_struct *fsp,
+ enum file_close_type close_type)
{
NTSTATUS status;
struct files_struct *base_fsp = fsp->base_fsp;
if(fsp->is_directory) {
- status = close_directory(fsp, close_type);
- } else if (fsp->is_stat) {
- status = close_stat(fsp);
+ status = close_directory(req, fsp, close_type);
} else if (fsp->fake_file_handle != NULL) {
- status = close_fake_file(fsp);
+ status = close_fake_file(req, fsp);
} else {
- status = close_normal_file(fsp, close_type);
+ status = close_normal_file(req, fsp, close_type);
}
if ((base_fsp != NULL) && (close_type != SHUTDOWN_CLOSE)) {
*/
SMB_ASSERT(base_fsp->base_fsp == NULL);
- close_file(base_fsp, close_type);
+ close_file(req, base_fsp, close_type);
}
return status;
}
+
+/****************************************************************************
+ Deal with an (authorized) message to close a file given the share mode
+ entry.
+****************************************************************************/
+
+void msg_close_file(struct messaging_context *msg_ctx,
+ void *private_data,
+ uint32_t msg_type,
+ struct server_id server_id,
+ DATA_BLOB *data)
+{
+ files_struct *fsp = NULL;
+ struct share_mode_entry e;
+
+ message_to_share_mode_entry(&e, (char *)data->data);
+
+ if(DEBUGLVL(10)) {
+ char *sm_str = share_mode_str(NULL, 0, &e);
+ if (!sm_str) {
+ smb_panic("talloc failed");
+ }
+ DEBUG(10,("msg_close_file: got request to close share mode "
+ "entry %s\n", sm_str));
+ TALLOC_FREE(sm_str);
+ }
+
+ fsp = file_find_dif(e.id, e.share_file_id);
+ if (!fsp) {
+ DEBUG(10,("msg_close_file: failed to find file.\n"));
+ return;
+ }
+ close_file(NULL, fsp, NORMAL_CLOSE);
+}