static NTSTATUS close_directory(files_struct *fsp, enum file_close_type close_type) { struct share_mode_lock *lck = 0; BOOL delete_dir = False; NTSTATUS status = NT_STATUS_OK; /* * NT can set delete_on_close of the last open * reference to a directory also. */ lck = get_share_mode_lock(NULL, fsp->dev, fsp->inode, NULL, NULL); if (lck == NULL) { DEBUG(0, ("close_directory: Could not get share mode lock for %s\n", fsp->fsp_name)); return NT_STATUS_INVALID_PARAMETER; } if (!del_share_mode(lck, fsp)) { DEBUG(0, ("close_directory: Could not delete share entry for %s\n", fsp->fsp_name)); } if (fsp->initial_delete_on_close) { BOOL became_user = False; /* Initial delete on close was set - for * directories we don't care if anyone else * wrote a real delete on close. */ if (current_user.vuid != fsp->vuid) { become_user(fsp->conn, fsp->vuid); became_user = True; } send_stat_cache_delete_message(fsp->fsp_name); set_delete_on_close_lck(lck, True, ¤t_user.ut); if (became_user) { unbecome_user(); } } delete_dir = lck->delete_on_close; 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->num_share_modes; i++) { struct share_mode_entry *e = &lck->share_modes[i]; if (is_valid_share_mode_entry(e)) { if (fsp->posix_open && (e->flags & SHARE_MODE_FLAG_POSIX_OPEN)) { continue; } delete_dir = False; break; } } } if ((close_type == NORMAL_CLOSE || close_type == SHUTDOWN_CLOSE) && delete_dir && lck->delete_token) { /* Become the user who requested the delete. */ if (!push_sec_ctx()) { 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, NULL); TALLOC_FREE(lck); status = rmdir_internals(fsp->conn, fsp->fsp_name); DEBUG(5,("close_directory: %s. Delete on close was set - " "deleting directory returned %s.\n", fsp->fsp_name, nt_errstr(status))); /* unbecome user. */ pop_sec_ctx(); /* * Ensure we remove any change notify requests that would * now fail as the directory has been deleted. */ if(NT_STATUS_IS_OK(status)) { remove_pending_change_notify_requests_by_fid(fsp, NT_STATUS_DELETE_PENDING); } } else { TALLOC_FREE(lck); remove_pending_change_notify_requests_by_fid( fsp, NT_STATUS_OK); } /* * Do the code common to files and directories. */ close_filestruct(fsp); file_free(fsp); return status; }
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; NTSTATUS status1 = NT_STATUS_OK; const struct security_token *del_nt_token = NULL; const struct security_unix_token *del_token = NULL; NTSTATUS notify_status; if (fsp->conn->sconn->using_smb2) { notify_status = STATUS_NOTIFY_CLEANUP; } else { notify_status = NT_STATUS_OK; } /* * NT can set delete_on_close of the last open * reference to a directory also. */ lck = get_existing_share_mode_lock(talloc_tos(), fsp->file_id); if (lck == NULL) { DEBUG(0, ("close_directory: Could not get share mode lock for " "%s\n", fsp_str_dbg(fsp))); return NT_STATUS_INVALID_PARAMETER; } if (fsp->initial_delete_on_close) { bool became_user = False; /* Initial delete on close was set - for * directories we don't care if anyone else * wrote a real delete on close. */ if (get_current_vuid(fsp->conn) != fsp->vuid) { become_user(fsp->conn, fsp->vuid); became_user = True; } send_stat_cache_delete_message(fsp->conn->sconn->msg_ctx, fsp->fsp_name->base_name); set_delete_on_close_lck(fsp, lck, get_current_nttok(fsp->conn), get_current_utok(fsp->conn)); fsp->delete_on_close = true; if (became_user) { unbecome_user(); } } 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; } } } if ((close_type == NORMAL_CLOSE || close_type == SHUTDOWN_CLOSE) && delete_dir) { /* Become the user who requested the delete. */ if (!push_sec_ctx()) { smb_panic("close_directory: failed to push sec_ctx.\n"); } set_sec_ctx(del_token->uid, del_token->gid, del_token->ngroups, del_token->groups, del_nt_token); if (!del_share_mode(lck, fsp)) { DEBUG(0, ("close_directory: Could not delete share entry for " "%s\n", fsp_str_dbg(fsp))); } TALLOC_FREE(lck); if ((fsp->conn->fs_capabilities & FILE_NAMED_STREAMS) && !is_ntfs_stream_smb_fname(fsp->fsp_name)) { status = delete_all_streams(fsp->conn, fsp->fsp_name->base_name); if (!NT_STATUS_IS_OK(status)) { DEBUG(5, ("delete_all_streams failed: %s\n", nt_errstr(status))); return status; } } status = rmdir_internals(talloc_tos(), fsp); DEBUG(5,("close_directory: %s. Delete on close was set - " "deleting directory returned %s.\n", fsp_str_dbg(fsp), nt_errstr(status))); /* unbecome user. */ pop_sec_ctx(); /* * Ensure we remove any change notify requests that would * now fail as the directory has been deleted. */ if (NT_STATUS_IS_OK(status)) { notify_status = NT_STATUS_DELETE_PENDING; } } else { if (!del_share_mode(lck, fsp)) { DEBUG(0, ("close_directory: Could not delete share entry for " "%s\n", fsp_str_dbg(fsp))); } TALLOC_FREE(lck); } remove_pending_change_notify_requests_by_fid(fsp, notify_status); status1 = fd_close(fsp); if (!NT_STATUS_IS_OK(status1)) { DEBUG(0, ("Could not close dir! fname=%s, fd=%d, err=%d=%s\n", fsp_str_dbg(fsp), fsp->fh->fd, errno, strerror(errno))); } /* * 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)) { status = status1; } return status; }
static int close_directory(files_struct *fsp, enum file_close_type close_type) { struct share_mode_lock *lck = 0; BOOL delete_dir = False; /* * NT can set delete_on_close of the last open * reference to a directory also. */ lck = get_share_mode_lock(NULL, fsp->dev, fsp->inode, NULL, NULL); if (lck == NULL) { DEBUG(0, ("close_directory: Could not get share mode lock for %s\n", fsp->fsp_name)); return EINVAL; } if (!del_share_mode(lck, fsp)) { DEBUG(0, ("close_directory: Could not delete share entry for %s\n", fsp->fsp_name)); } delete_dir = (lck->delete_on_close | lck->initial_delete_on_close); if ((close_type == NORMAL_CLOSE || close_type == SHUTDOWN_CLOSE) && delete_dir && lck->delete_token) { BOOL ok; /* Become the user who requested the delete. */ if (!push_sec_ctx()) { 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, NULL); TALLOC_FREE(lck); ok = rmdir_internals(fsp->conn, fsp->fsp_name); DEBUG(5,("close_directory: %s. Delete on close was set - deleting directory %s.\n", fsp->fsp_name, ok ? "succeeded" : "failed" )); /* unbecome user. */ pop_sec_ctx(); /* * Ensure we remove any change notify requests that would * now fail as the directory has been deleted. */ if(ok) { remove_pending_change_notify_requests_by_fid(fsp, NT_STATUS_DELETE_PENDING); remove_pending_change_notify_requests_by_filename(fsp, NT_STATUS_DELETE_PENDING); } process_pending_change_notify_queue((time_t)0); } else { TALLOC_FREE(lck); remove_pending_change_notify_requests_by_fid(fsp, NT_STATUS_CANCELLED); } /* * Do the code common to files and directories. */ close_filestruct(fsp); file_free(fsp); return 0; }