*/
#include "includes.h"
-#include "librpc/gen_ndr/messaging.h"
+#include "system/filesys.h"
+#include "printing.h"
+#include "smbd/smbd.h"
#include "smbd/globals.h"
+#include "fake_file.h"
+#include "transfer_file.h"
+#include "auth.h"
+#include "messages.h"
+#include "../librpc/gen_ndr/open_files.h"
/****************************************************************************
Run a file if it is a magic script.
If any deferred opens are waiting on this close, notify them.
****************************************************************************/
-static void notify_deferred_opens(struct messaging_context *msg_ctx,
+static void notify_deferred_opens(struct smbd_server_connection *sconn,
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];
-
+
if (!is_deferred_open_entry(e)) {
continue;
}
-
+
if (procid_is_me(&e->pid)) {
/*
* We need to notify ourself to retry the open. Do
* the head of the queue and changing the wait time to
* zero.
*/
- schedule_deferred_open_message_smb(e->op_mid);
+ schedule_deferred_open_message_smb(sconn, e->op_mid);
} else {
char msg[MSG_SMB_SHARE_MODE_ENTRY_SIZE];
share_mode_entry_to_message(msg, e);
- messaging_send_buf(msg_ctx, e->pid, MSG_SMB_OPEN_RETRY,
+ messaging_send_buf(sconn->msg_ctx, e->pid,
+ MSG_SMB_OPEN_RETRY,
(uint8 *)msg,
MSG_SMB_SHARE_MODE_ENTRY_SIZE);
}
NTSTATUS delete_all_streams(connection_struct *conn, const char *fname)
{
- struct stream_struct *stream_info;
+ struct stream_struct *stream_info = NULL;
int i;
- unsigned int num_streams;
+ unsigned int num_streams = 0;
TALLOC_CTX *frame = talloc_stackframe();
NTSTATUS status;
- status = SMB_VFS_STREAMINFO(conn, NULL, fname, talloc_tos(),
- &num_streams, &stream_info);
+ status = vfs_streaminfo(conn, NULL, fname, talloc_tos(),
+ &num_streams, &stream_info);
if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_IMPLEMENTED)) {
DEBUG(10, ("no streams around\n"));
}
if (!NT_STATUS_IS_OK(status)) {
- DEBUG(10, ("SMB_VFS_STREAMINFO failed: %s\n",
+ DEBUG(10, ("vfs_streaminfo failed: %s\n",
nt_errstr(status)));
goto fail;
}
NTSTATUS status = NT_STATUS_OK;
NTSTATUS tmp_status;
struct file_id id;
+ const struct security_unix_token *del_token = NULL;
/* Ensure any pending write time updates are done. */
if (fsp->update_write_time_event) {
- update_write_time_handler(smbd_event_context(),
+ update_write_time_handler(fsp->conn->sconn->ev_ctx,
fsp->update_write_time_event,
timeval_current(),
(void *)fsp);
fsp_str_dbg(fsp)));
}
- if (fsp->initial_delete_on_close && (lck->delete_token == NULL)) {
+ if (fsp->initial_delete_on_close &&
+ !is_delete_on_close_set(lck, fsp->name_hash)) {
bool became_user = False;
/* Initial delete on close was set and no one else
became_user = True;
}
fsp->delete_on_close = true;
- set_delete_on_close_lck(lck, True, get_current_utok(conn));
+ set_delete_on_close_lck(fsp, lck, True, get_current_utok(conn));
if (became_user) {
unbecome_user();
}
}
- delete_file = lck->delete_on_close;
+ delete_file = is_delete_on_close_set(lck, fsp->name_hash);
if (delete_file) {
int i;
- /* See if others still have the file open. If this is the
- * case, then don't delete. If all opens are POSIX delete now. */
+ /* See if others still have the file open via this pathname.
+ If this is the case, then don't delete. If all opens are
+ POSIX delete now. */
for (i=0; i<lck->num_share_modes; i++) {
struct share_mode_entry *e = &lck->share_modes[i];
- if (is_valid_share_mode_entry(e)) {
+ if (is_valid_share_mode_entry(e) &&
+ e->name_hash == fsp->name_hash) {
if (fsp->posix_open && (e->flags & SHARE_MODE_FLAG_POSIX_OPEN)) {
continue;
}
}
/* Notify any deferred opens waiting on this close. */
- notify_deferred_opens(conn->sconn->msg_ctx, lck);
+ notify_deferred_opens(conn->sconn, lck);
reply_to_oplock_break_requests(fsp);
/*
* reference to a file.
*/
- if (!(close_type == NORMAL_CLOSE || close_type == SHUTDOWN_CLOSE)
- || !delete_file
- || (lck->delete_token == NULL)) {
+ if (!(close_type == NORMAL_CLOSE || close_type == SHUTDOWN_CLOSE) ||
+ !delete_file) {
TALLOC_FREE(lck);
return NT_STATUS_OK;
}
*/
fsp->update_write_time_on_close = false;
- if (!unix_token_equal(lck->delete_token, get_current_utok(conn))) {
+ del_token = get_delete_on_close_token(lck, fsp->name_hash);
+ SMB_ASSERT(del_token != NULL);
+
+ if (!unix_token_equal(del_token, get_current_utok(conn))) {
/* Become the user who requested the delete. */
DEBUG(5,("close_remove_share_mode: file %s. "
"Change user to uid %u\n",
fsp_str_dbg(fsp),
- (unsigned int)lck->delete_token->uid));
+ (unsigned int)del_token->uid));
if (!push_sec_ctx()) {
smb_panic("close_remove_share_mode: file %s. failed to push "
"sec_ctx.\n");
}
- set_sec_ctx(lck->delete_token->uid,
- lck->delete_token->gid,
- lck->delete_token->ngroups,
- lck->delete_token->groups,
+ set_sec_ctx(del_token->uid,
+ del_token->gid,
+ del_token->ngroups,
+ del_token->groups,
NULL);
changed_user = true;
status = map_nt_error_from_unix(errno);
}
- notify_fname(conn, NOTIFY_ACTION_REMOVED,
- FILE_NOTIFY_CHANGE_FILE_NAME,
- fsp->fsp_name->base_name);
-
/* As we now have POSIX opens which can unlink
* with other open files we may have taken
* this code path with more than one share mode
*/
fsp->delete_on_close = false;
- set_delete_on_close_lck(lck, False, NULL);
+ set_delete_on_close_lck(fsp, lck, false, NULL);
done:
}
TALLOC_FREE(lck);
+
+ if (delete_file) {
+ /*
+ * Do the notification after we released the share
+ * mode lock. Inside notify_fname we take out another
+ * tdb lock. With ctdb also accessing our databases,
+ * this can lead to deadlocks. Putting this notify
+ * after the TALLOC_FREE(lck) above we avoid locking
+ * two records simultaneously. Notifies are async and
+ * informational only, so calling the notify_fname
+ * without holding the share mode lock should not do
+ * any harm.
+ */
+ notify_fname(conn, NOTIFY_ACTION_REMOVED,
+ FILE_NOTIFY_CHANGE_FILE_NAME,
+ fsp->fsp_name->base_name);
+ }
+
return status;
}
}
ft.mtime = fsp->close_write_time;
+ /* As this is a close based update, we are not directly changing the
+ file attributes from a client call, but indirectly from a write. */
status = smb_set_file_time(fsp->conn, fsp, fsp->fsp_name, &ft, false);
if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(10,("update_write_time_on_close: smb_set_file_time "
+ "on file %s returned %s\n",
+ fsp_str_dbg(fsp),
+ nt_errstr(status)));
return status;
}
status = ntstatus_keeperror(status, tmp);
if (fsp->print_file) {
- print_fsp_end(fsp, close_type);
+ /* FIXME: return spool errors */
+ print_spool_end(fsp, close_type);
file_free(req, fsp);
return NT_STATUS_OK;
}
status = ntstatus_keeperror(status, tmp);
DEBUG(2,("%s closed file %s (numopen=%d) %s\n",
- conn->server_info->unix_name, fsp_str_dbg(fsp),
+ conn->session_info->unix_info->unix_name, fsp_str_dbg(fsp),
conn->num_files_open - 1,
nt_errstr(status) ));
bool delete_dir = False;
NTSTATUS status = NT_STATUS_OK;
NTSTATUS status1 = NT_STATUS_OK;
+ const struct security_unix_token *del_token = NULL;
/*
* NT can set delete_on_close of the last open
become_user(fsp->conn, fsp->vuid);
became_user = True;
}
- send_stat_cache_delete_message(fsp->fsp_name->base_name);
- set_delete_on_close_lck(lck, True, get_current_utok(fsp->conn));
+ send_stat_cache_delete_message(fsp->conn->sconn->msg_ctx,
+ fsp->fsp_name->base_name);
+ set_delete_on_close_lck(fsp, lck, true,
+ get_current_utok(fsp->conn));
fsp->delete_on_close = true;
if (became_user) {
unbecome_user();
}
}
- delete_dir = lck->delete_on_close;
+ del_token = get_delete_on_close_token(lck, fsp->name_hash);
+ delete_dir = (del_token != NULL);
if (delete_dir) {
int i;
* case, then don't delete. If all opens are POSIX delete now. */
for (i=0; i<lck->num_share_modes; i++) {
struct share_mode_entry *e = &lck->share_modes[i];
- if (is_valid_share_mode_entry(e)) {
+ if (is_valid_share_mode_entry(e) &&
+ e->name_hash == fsp->name_hash) {
if (fsp->posix_open && (e->flags & SHARE_MODE_FLAG_POSIX_OPEN)) {
continue;
}
}
if ((close_type == NORMAL_CLOSE || close_type == SHUTDOWN_CLOSE) &&
- delete_dir &&
- lck->delete_token) {
+ delete_dir) {
/* Become the user who requested the delete. */
smb_panic("close_directory: failed to push sec_ctx.\n");
}
- set_sec_ctx(lck->delete_token->uid,
- lck->delete_token->gid,
- lck->delete_token->ngroups,
- lck->delete_token->groups,
+ set_sec_ctx(del_token->uid,
+ del_token->gid,
+ del_token->ngroups,
+ del_token->groups,
NULL);
TALLOC_FREE(lck);
strerror(errno)));
}
- if (fsp->dptr) {
- dptr_CloseDir(fsp->dptr);
- }
-
/*
* Do the code common to files and directories.
*/
{
files_struct *fsp = NULL;
struct share_mode_entry e;
+ struct smbd_server_connection *sconn =
+ talloc_get_type_abort(private_data,
+ struct smbd_server_connection);
message_to_share_mode_entry(&e, (char *)data->data);
TALLOC_FREE(sm_str);
}
- fsp = file_find_dif(e.id, e.share_file_id);
+ fsp = file_find_dif(sconn, e.id, e.share_file_id);
if (!fsp) {
DEBUG(10,("msg_close_file: failed to find file.\n"));
return;