#include "auth.h"
#include "messages.h"
#include "../librpc/gen_ndr/open_files.h"
+#include "lib/util/tevent_ntstatus.h"
/****************************************************************************
Run a file if it is a magic script.
static NTSTATUS check_magic(struct files_struct *fsp)
{
int ret;
+ const struct loadparm_substitution *lp_sub =
+ loadparm_s3_global_substitution();
const char *magic_output = NULL;
SMB_STRUCT_STAT st;
int tmp_fd, outfd;
char *fname = NULL;
NTSTATUS status;
- if (!*lp_magic_script(talloc_tos(), SNUM(conn))) {
+ if (!*lp_magic_script(talloc_tos(), lp_sub, SNUM(conn))) {
return NT_STATUS_OK;
}
p++;
}
- if (!strequal(lp_magic_script(talloc_tos(), SNUM(conn)),p)) {
+ if (!strequal(lp_magic_script(talloc_tos(), lp_sub, SNUM(conn)),p)) {
status = NT_STATUS_OK;
goto out;
}
- if (*lp_magic_output(talloc_tos(), SNUM(conn))) {
- magic_output = lp_magic_output(talloc_tos(), SNUM(conn));
+ if (*lp_magic_output(talloc_tos(), lp_sub, SNUM(conn))) {
+ magic_output = lp_magic_output(talloc_tos(), lp_sub, SNUM(conn));
} else {
magic_output = talloc_asprintf(ctx,
"%s.out",
return status;
}
-/****************************************************************************
- Common code to close a file or a directory.
-****************************************************************************/
-
-static NTSTATUS close_filestruct(files_struct *fsp)
-{
- NTSTATUS status = NT_STATUS_OK;
-
- if (fsp->fh->fd != -1) {
- if(flush_write_cache(fsp, SAMBA_CLOSE_FLUSH) == -1) {
- status = map_nt_error_from_unix(errno);
- }
- delete_write_cache(fsp);
- }
-
- return status;
-}
-
/****************************************************************************
Delete all streams
****************************************************************************/
const struct smb_filename *smb_fname)
{
struct stream_struct *stream_info = NULL;
- int i;
+ unsigned int i;
unsigned int num_streams = 0;
TALLOC_CTX *frame = talloc_stackframe();
NTSTATUS status;
goto fail;
}
- res = SMB_VFS_UNLINK(conn, smb_fname_stream);
+ res = SMB_VFS_UNLINKAT(conn,
+ conn->cwd_fsp,
+ smb_fname_stream,
+ 0);
if (res == -1) {
status = map_nt_error_from_unix(errno);
return status;
}
+struct has_other_nonposix_opens_state {
+ files_struct *fsp;
+ bool found_another;
+};
+
+static bool has_other_nonposix_opens_fn(
+ struct share_mode_entry *e,
+ bool *modified,
+ void *private_data)
+{
+ struct has_other_nonposix_opens_state *state = private_data;
+ struct files_struct *fsp = state->fsp;
+
+ if (e->name_hash != fsp->name_hash) {
+ return false;
+ }
+ if ((fsp->posix_flags & FSP_POSIX_FLAGS_OPEN) &&
+ (e->flags & SHARE_MODE_FLAG_POSIX_OPEN)) {
+ return false;
+ }
+ if (e->share_file_id == fsp->fh->gen_id) {
+ struct server_id self = messaging_server_id(
+ fsp->conn->sconn->msg_ctx);
+ if (server_id_equal(&self, &e->pid)) {
+ return false;
+ }
+ }
+ if (share_entry_stale_pid(e)) {
+ return false;
+ }
+
+ state->found_another = true;
+ return true;
+}
+
+bool has_other_nonposix_opens(struct share_mode_lock *lck,
+ struct files_struct *fsp)
+{
+ struct has_other_nonposix_opens_state state = { .fsp = fsp };
+ bool ok;
+
+ ok = share_mode_forall_entries(
+ lck, has_other_nonposix_opens_fn, &state);
+ if (!ok) {
+ return false;
+ }
+ return state.found_another;
+}
+
/****************************************************************************
Deal with removing a share mode on last close.
****************************************************************************/
enum file_close_type close_type)
{
connection_struct *conn = fsp->conn;
- struct server_id self = messaging_server_id(conn->sconn->msg_ctx);
bool delete_file = false;
bool changed_user = false;
struct share_mode_lock *lck = NULL;
const struct security_token *del_nt_token = NULL;
bool got_tokens = false;
bool normal_close;
+ int ret;
/* Ensure any pending write time updates are done. */
if (fsp->update_write_time_event) {
- update_write_time_handler(fsp->conn->sconn->ev_ctx,
- fsp->update_write_time_event,
- timeval_current(),
- (void *)fsp);
+ fsp_flush_write_time_update(fsp);
}
/*
/* Remove the oplock before potentially deleting the file. */
if(fsp->oplock_type) {
- remove_oplock_under_lock(fsp, lck);
+ remove_oplock(fsp);
}
- if (fsp->write_time_forced) {
+ if (fsp->fsp_flags.write_time_forced) {
+ struct timespec ts;
+
DEBUG(10,("close_remove_share_mode: write time forced "
"for file %s\n",
fsp_str_dbg(fsp)));
- set_close_write_time(fsp, lck->data->changed_write_time);
- } else if (fsp->update_write_time_on_close) {
+ ts = nt_time_to_full_timespec(lck->data->changed_write_time);
+ set_close_write_time(fsp, ts);
+ } else if (fsp->fsp_flags.update_write_time_on_close) {
/* Someone had a pending write. */
- if (null_timespec(fsp->close_write_time)) {
+ if (is_omit_timespec(&fsp->close_write_time)) {
DEBUG(10,("close_remove_share_mode: update to current time "
"for file %s\n",
fsp_str_dbg(fsp)));
}
}
- if (fsp->initial_delete_on_close &&
+ if (fsp->fsp_flags.initial_delete_on_close &&
!is_delete_on_close_set(lck, fsp->name_hash)) {
bool became_user = False;
* wrote a real delete on close. */
if (get_current_vuid(conn) != fsp->vuid) {
- become_user(conn, fsp->vuid);
+ become_user_without_service(conn, fsp->vuid);
became_user = True;
}
- fsp->delete_on_close = true;
+ fsp->fsp_flags.delete_on_close = true;
set_delete_on_close_lck(fsp, lck,
get_current_nttok(conn),
get_current_utok(conn));
if (became_user) {
- unbecome_user();
+ unbecome_user_without_service();
}
}
- delete_file = is_delete_on_close_set(lck, fsp->name_hash);
-
- if (delete_file) {
- int i;
- /* 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->data->num_share_modes; i++) {
- struct share_mode_entry *e = &lck->data->share_modes[i];
-
- if (!is_valid_share_mode_entry(e)) {
- continue;
- }
- if (e->name_hash != fsp->name_hash) {
- continue;
- }
- if ((fsp->posix_flags & FSP_POSIX_FLAGS_OPEN)
- && (e->flags & SHARE_MODE_FLAG_POSIX_OPEN)) {
- continue;
- }
- if (serverid_equal(&self, &e->pid) &&
- (e->share_file_id == fsp->fh->gen_id)) {
- continue;
- }
- if (share_mode_stale_pid(lck->data, i)) {
- continue;
- }
- delete_file = False;
- break;
- }
- }
+ delete_file = is_delete_on_close_set(lck, fsp->name_hash) &&
+ !has_other_nonposix_opens(lck, fsp);
/*
* NT can set delete_on_close of the last open
/*
* Don't try to update the write time when we delete the file
*/
- fsp->update_write_time_on_close = false;
+ fsp->fsp_flags.update_write_time_on_close = false;
got_tokens = get_delete_on_close_token(lck, fsp->name_hash,
&del_nt_token, &del_token);
id = vfs_file_id_from_sbuf(conn, &fsp->fsp_name->st);
if (!file_id_equal(&fsp->file_id, &id)) {
+ struct file_id_buf ftmp1, ftmp2;
DEBUG(5,("close_remove_share_mode: file %s. Delete on close "
"was set and dev and/or inode does not match\n",
fsp_str_dbg(fsp)));
DEBUG(5,("close_remove_share_mode: file %s. stored file_id %s, "
"stat file_id %s\n",
fsp_str_dbg(fsp),
- file_id_string_tos(&fsp->file_id),
- file_id_string_tos(&id)));
+ file_id_str_buf(fsp->file_id, &ftmp1),
+ file_id_str_buf(id, &ftmp2)));
/*
* Don't save the errno here, we ignore this error
*/
}
}
- if (fsp->kernel_share_modes_taken) {
+ if (fsp->fsp_flags.kernel_share_modes_taken) {
int ret_flock;
/*
fsp_str_dbg(fsp), strerror(errno));
}
- fsp->kernel_share_modes_taken = false;
+ fsp->fsp_flags.kernel_share_modes_taken = false;
}
- if (SMB_VFS_UNLINK(conn, fsp->fsp_name) != 0) {
+ ret = SMB_VFS_UNLINKAT(conn,
+ conn->cwd_fsp,
+ fsp->fsp_name,
+ 0);
+ if (ret != 0) {
/*
* This call can potentially fail as another smbd may
* have had the file open with delete on close set and
* the delete on close flag. JRA.
*/
- fsp->delete_on_close = false;
+ fsp->fsp_flags.delete_on_close = false;
reset_delete_on_close_lck(fsp, lck);
done:
pop_sec_ctx();
}
- if (fsp->kernel_share_modes_taken) {
+ if (fsp->fsp_flags.kernel_share_modes_taken) {
int ret_flock;
/* remove filesystem sharemodes */
{
DEBUG(6,("close_write_time: %s" , time_to_asc(convert_timespec_to_time_t(ts))));
- if (null_timespec(ts)) {
+ if (is_omit_timespec(&ts)) {
return;
}
- fsp->write_time_forced = false;
- fsp->update_write_time_on_close = true;
+ fsp->fsp_flags.write_time_forced = false;
+ fsp->fsp_flags.update_write_time_on_close = true;
fsp->close_write_time = ts;
}
NTSTATUS status;
struct share_mode_lock *lck = NULL;
- ZERO_STRUCT(ft);
+ init_smb_file_time(&ft);
- if (!fsp->update_write_time_on_close) {
+ if (!(fsp->fsp_flags.update_write_time_on_close)) {
return NT_STATUS_OK;
}
- if (null_timespec(fsp->close_write_time)) {
+ if (is_omit_timespec(&fsp->close_write_time)) {
fsp->close_write_time = timespec_current();
}
/* Close write times overwrite sticky write times
so we must replace any sticky write time here. */
- if (!null_timespec(lck->data->changed_write_time)) {
+ if (!null_nttime(lck->data->changed_write_time)) {
(void)set_sticky_write_time(fsp->file_id, fsp->close_write_time);
}
TALLOC_FREE(lck);
return s2;
}
+static void assert_no_pending_aio(struct files_struct *fsp,
+ enum file_close_type close_type)
+{
+ unsigned num_requests = fsp->num_aio_requests;
+
+ if (num_requests == 0) {
+ return;
+ }
+
+ DBG_ERR("fsp->num_aio_requests=%u\n", num_requests);
+ smb_panic("can not close with outstanding aio requests");
+ return;
+}
+
/****************************************************************************
Close a file.
connection_struct *conn = fsp->conn;
bool is_durable = false;
- if (fsp->num_aio_requests != 0) {
-
- if (close_type != SHUTDOWN_CLOSE) {
- /*
- * reply_close and the smb2 close must have
- * taken care of this. No other callers of
- * close_file should ever have created async
- * I/O.
- *
- * We need to panic here because if we close()
- * the fd while we have outstanding async I/O
- * requests, in the worst case we could end up
- * writing to the wrong file.
- */
- DEBUG(0, ("fsp->num_aio_requests=%u\n",
- fsp->num_aio_requests));
- smb_panic("can not close with outstanding aio "
- "requests");
- }
+ assert_no_pending_aio(fsp, close_type);
- /*
- * For shutdown close, just drop the async requests
- * including a potential close request pending for
- * this fsp. Drop the close request first, the
- * destructor for the aio_requests would execute it.
- */
- TALLOC_FREE(fsp->deferred_close);
-
- while (fsp->num_aio_requests != 0) {
- /*
- * The destructor of the req will remove
- * itself from the fsp.
- * Don't use TALLOC_FREE here, this will overwrite
- * what the destructor just wrote into
- * aio_requests[0].
- */
- talloc_free(fsp->aio_requests[0]);
- }
+ while (talloc_array_length(fsp->blocked_smb1_lock_reqs) != 0) {
+ smbd_smb1_brl_finish_by_req(
+ fsp->blocked_smb1_lock_reqs[0],
+ NT_STATUS_RANGE_NOT_LOCKED);
}
/*
* error here, we must remember this.
*/
- tmp = close_filestruct(fsp);
- status = ntstatus_keeperror(status, tmp);
-
if (NT_STATUS_IS_OK(status) && fsp->op != NULL) {
is_durable = fsp->op->global->durable;
}
status = ntstatus_keeperror(status, tmp);
}
- locking_close_file(conn->sconn->msg_ctx, fsp, close_type);
+ locking_close_file(fsp, close_type);
tmp = fd_close(fsp);
status = ntstatus_keeperror(status, tmp);
long offset = 0;
SMB_STRUCT_STAT st;
struct smb_Dir *dir_hnd;
+ int retval;
SMB_ASSERT(!is_ntfs_stream_smb_fname(smb_dname));
continue;
}
- if (!is_visible_file(conn, smb_dname->base_name, dname, &st,
- false)) {
+ if (!is_visible_file(conn,
+ smb_dname,
+ dname,
+ &st,
+ false)) {
TALLOC_FREE(talloced);
continue;
}
if(!recursive_rmdir(ctx, conn, smb_dname_full)) {
goto err_break;
}
- if(SMB_VFS_RMDIR(conn, smb_dname_full) != 0) {
+ retval = SMB_VFS_UNLINKAT(conn,
+ conn->cwd_fsp,
+ smb_dname_full,
+ AT_REMOVEDIR);
+ if (retval != 0) {
+ goto err_break;
+ }
+ } else {
+ retval = SMB_VFS_UNLINKAT(conn,
+ conn->cwd_fsp,
+ smb_dname_full,
+ 0);
+ if (retval != 0) {
goto err_break;
}
- } else if(SMB_VFS_UNLINK(conn, smb_dname_full) != 0) {
- goto err_break;
}
/* Successful iteration. */
{
connection_struct *conn = fsp->conn;
struct smb_filename *smb_dname = fsp->fsp_name;
+ const struct loadparm_substitution *lp_sub =
+ loadparm_s3_global_substitution();
int ret;
SMB_ASSERT(!is_ntfs_stream_smb_fname(smb_dname));
if (!(S_ISDIR(smb_dname->st.st_ex_mode))) {
return NT_STATUS_NOT_A_DIRECTORY;
}
- ret = SMB_VFS_UNLINK(conn, smb_dname);
+ ret = SMB_VFS_UNLINKAT(conn,
+ conn->cwd_fsp,
+ smb_dname,
+ 0);
} else {
- ret = SMB_VFS_RMDIR(conn, smb_dname);
+ ret = SMB_VFS_UNLINKAT(conn,
+ conn->cwd_fsp,
+ smb_dname,
+ AT_REMOVEDIR);
}
if (ret == 0) {
notify_fname(conn, NOTIFY_ACTION_REMOVED,
return NT_STATUS_OK;
}
- if(((errno == ENOTEMPTY)||(errno == EEXIST)) && *lp_veto_files(talloc_tos(), SNUM(conn))) {
+ if(((errno == ENOTEMPTY)||(errno == EEXIST)) && *lp_veto_files(talloc_tos(), lp_sub, SNUM(conn))) {
/*
* Check to see if the only thing in this directory are
* vetoed files/directories. If so then delete them and
TALLOC_FREE(talloced);
continue;
}
- if (!is_visible_file(conn, smb_dname->base_name, dname,
- &st, false)) {
+ if (!is_visible_file(conn,
+ smb_dname,
+ dname,
+ &st,
+ false)) {
TALLOC_FREE(talloced);
continue;
}
TALLOC_FREE(talloced);
continue;
}
- if (!is_visible_file(conn, smb_dname->base_name, dname,
- &st, false)) {
+ if (!is_visible_file(conn,
+ smb_dname,
+ dname,
+ &st,
+ false)) {
TALLOC_FREE(talloced);
continue;
}
goto err_break;
}
if(smb_dname_full->st.st_ex_mode & S_IFDIR) {
+ int retval;
if(!recursive_rmdir(ctx, conn,
smb_dname_full)) {
goto err_break;
}
- if(SMB_VFS_RMDIR(conn,
- smb_dname_full) != 0) {
+ retval = SMB_VFS_UNLINKAT(conn,
+ conn->cwd_fsp,
+ smb_dname_full,
+ AT_REMOVEDIR);
+ if(retval != 0) {
+ goto err_break;
+ }
+ } else {
+ int retval = SMB_VFS_UNLINKAT(conn,
+ conn->cwd_fsp,
+ smb_dname_full,
+ 0);
+ if(retval != 0) {
goto err_break;
}
- } else if(SMB_VFS_UNLINK(conn, smb_dname_full) != 0) {
- goto err_break;
}
/* Successful iteration. */
}
TALLOC_FREE(dir_hnd);
/* Retry the rmdir */
- ret = SMB_VFS_RMDIR(conn, smb_dname);
+ ret = SMB_VFS_UNLINKAT(conn,
+ conn->cwd_fsp,
+ smb_dname,
+ AT_REMOVEDIR);
}
err:
static NTSTATUS close_directory(struct smb_request *req, files_struct *fsp,
enum file_close_type close_type)
{
- struct server_id self = messaging_server_id(fsp->conn->sconn->msg_ctx);
struct share_mode_lock *lck = NULL;
bool delete_dir = False;
NTSTATUS status = NT_STATUS_OK;
notify_status = NT_STATUS_OK;
}
+ assert_no_pending_aio(fsp, close_type);
+
/*
* NT can set delete_on_close of the last open
* reference to a directory also.
if (lck == NULL) {
DEBUG(0, ("close_directory: Could not get share mode lock for "
"%s\n", fsp_str_dbg(fsp)));
+ file_free(req, fsp);
return NT_STATUS_INVALID_PARAMETER;
}
- if (fsp->initial_delete_on_close) {
+ if (fsp->fsp_flags.initial_delete_on_close) {
bool became_user = False;
/* Initial delete on close was set - for
* wrote a real delete on close. */
if (get_current_vuid(fsp->conn) != fsp->vuid) {
- become_user(fsp->conn, fsp->vuid);
+ become_user_without_service(fsp->conn, fsp->vuid);
became_user = True;
}
send_stat_cache_delete_message(fsp->conn->sconn->msg_ctx,
set_delete_on_close_lck(fsp, lck,
get_current_nttok(fsp->conn),
get_current_utok(fsp->conn));
- fsp->delete_on_close = true;
+ fsp->fsp_flags.delete_on_close = true;
if (became_user) {
- unbecome_user();
+ unbecome_user_without_service();
}
}
- delete_dir = get_delete_on_close_token(lck, fsp->name_hash,
- &del_nt_token, &del_token);
-
- if (delete_dir) {
- int i;
- /* See if others still have the dir open. If this is the
- * case, then don't delete. If all opens are POSIX delete now. */
- for (i=0; i<lck->data->num_share_modes; i++) {
- struct share_mode_entry *e = &lck->data->share_modes[i];
- if (is_valid_share_mode_entry(e) &&
- e->name_hash == fsp->name_hash) {
- if ((fsp->posix_flags & FSP_POSIX_FLAGS_OPEN) &&
- (e->flags & SHARE_MODE_FLAG_POSIX_OPEN))
- {
- continue;
- }
- if (serverid_equal(&self, &e->pid) &&
- (e->share_file_id == fsp->fh->gen_id)) {
- continue;
- }
- if (share_mode_stale_pid(lck->data, i)) {
- continue;
- }
- delete_dir = False;
- break;
- }
- }
- }
+ delete_dir = get_delete_on_close_token(
+ lck, fsp->name_hash, &del_nt_token, &del_token) &&
+ !has_other_nonposix_opens(lck, fsp);
if ((close_type == NORMAL_CLOSE || close_type == SHUTDOWN_CLOSE) &&
delete_dir) {
if (!NT_STATUS_IS_OK(status)) {
DEBUG(5, ("delete_all_streams failed: %s\n",
nt_errstr(status)));
+ file_free(req, fsp);
return status;
}
}
/*
* Do the code common to files and directories.
*/
- close_filestruct(fsp);
file_free(req, fsp);
if (NT_STATUS_IS_OK(status) && !NT_STATUS_IS_OK(status1)) {
NTSTATUS status;
struct files_struct *base_fsp = fsp->base_fsp;
- if(fsp->is_directory) {
+ if (fsp->fsp_flags.is_directory) {
status = close_directory(req, fsp, close_type);
} else if (fsp->fake_file_handle != NULL) {
status = close_fake_file(req, fsp);
DATA_BLOB *data)
{
files_struct *fsp = NULL;
+ struct file_id id;
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.id, &e, (char *)data->data);
+ message_to_share_mode_entry(&id, &e, (char *)data->data);
if(DEBUGLVL(10)) {
- char *sm_str = share_mode_str(NULL, 0, &e.id, &e);
+ char *sm_str = share_mode_str(NULL, 0, &id, &e);
if (!sm_str) {
smb_panic("talloc failed");
}
TALLOC_FREE(sm_str);
}
- fsp = file_find_dif(sconn, e.id, e.share_file_id);
+ fsp = file_find_dif(sconn, id, e.share_file_id);
if (!fsp) {
DEBUG(10,("msg_close_file: failed to find file.\n"));
return;