예제 #1
0
NTSTATUS close_stat(files_struct *fsp)
{
	/*
	 * Do the code common to files and directories.
	 */
	close_filestruct(fsp);
	file_free(fsp);
	return NT_STATUS_OK;
}
예제 #2
0
static int close_stat(files_struct *fsp)
{
	/*
	 * Do the code common to files and directories.
	 */
	close_filestruct(fsp);
	file_free(fsp);
	return 0;
}
예제 #3
0
파일: close.c 프로젝트: vormetriclabs/samba
static NTSTATUS close_normal_file(struct smb_request *req, files_struct *fsp,
				  enum file_close_type close_type)
{
	NTSTATUS status = NT_STATUS_OK;
	NTSTATUS tmp;
	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");
		}

		/*
		 * 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]);
		}
	}

	/*
	 * If we're flushing on a close we can get a write
	 * 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;
	}

	if (close_type != SHUTDOWN_CLOSE) {
		is_durable = false;
	}

	if (is_durable) {
		DATA_BLOB new_cookie = data_blob_null;

		tmp = SMB_VFS_DURABLE_DISCONNECT(fsp,
					fsp->op->global->backend_cookie,
					fsp->op,
					&new_cookie);
		if (NT_STATUS_IS_OK(tmp)) {
			struct timeval tv;
			NTTIME now;

			if (req != NULL) {
				tv = req->request_time;
			} else {
				tv = timeval_current();
			}
			now = timeval_to_nttime(&tv);

			data_blob_free(&fsp->op->global->backend_cookie);
			fsp->op->global->backend_cookie = new_cookie;

			fsp->op->compat = NULL;
			tmp = smbXsrv_open_close(fsp->op, now);
			if (!NT_STATUS_IS_OK(tmp)) {
				DEBUG(1, ("Failed to update smbXsrv_open "
					  "record when disconnecting durable "
					  "handle for file %s: %s - "
					  "proceeding with normal close\n",
					  fsp_str_dbg(fsp), nt_errstr(tmp)));
			}
			scavenger_schedule_disconnected(fsp);
		} else {
			DEBUG(1, ("Failed to disconnect durable handle for "
				  "file %s: %s - proceeding with normal "
				  "close\n", fsp_str_dbg(fsp), nt_errstr(tmp)));
		}
		if (!NT_STATUS_IS_OK(tmp)) {
			is_durable = false;
		}
	}

	if (is_durable) {
		/*
		 * This is the case where we successfully disconnected
		 * a durable handle and closed the underlying file.
		 * In all other cases, we proceed with a genuine close.
		 */
		DEBUG(10, ("%s disconnected durable handle for file %s\n",
			   conn->session_info->unix_info->unix_name,
			   fsp_str_dbg(fsp)));
		file_free(req, fsp);
		return NT_STATUS_OK;
	}

	if (fsp->op != NULL) {
		/*
		 * Make sure the handle is not marked as durable anymore
		 */
		fsp->op->global->durable = false;
	}

	if (fsp->print_file) {
		/* FIXME: return spool errors */
		print_spool_end(fsp, close_type);
		file_free(req, fsp);
		return NT_STATUS_OK;
	}

	/* Remove the oplock before potentially deleting the file. */
	if(fsp->oplock_type) {
		remove_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. */

	if (fsp->fh->ref_count == 1) {
		/* Should we return on error here... ? */
		tmp = close_remove_share_mode(fsp, close_type);
		status = ntstatus_keeperror(status, tmp);
	}

	locking_close_file(conn->sconn->msg_ctx, fsp, close_type);

	tmp = fd_close(fsp);
	status = ntstatus_keeperror(status, tmp);

	/* check for magic scripts */
	if (close_type == NORMAL_CLOSE) {
		tmp = check_magic(fsp);
		status = ntstatus_keeperror(status, tmp);
	}

	/*
	 * Ensure pending modtime is set after close.
	 */

	tmp = update_write_time_on_close(fsp);
	if (NT_STATUS_EQUAL(tmp, 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. */

		tmp = NT_STATUS_OK;
	}

	status = ntstatus_keeperror(status, tmp);

	DEBUG(2,("%s closed file %s (numopen=%d) %s\n",
		conn->session_info->unix_info->unix_name, fsp_str_dbg(fsp),
		conn->num_files_open - 1,
		nt_errstr(status) ));

	file_free(req, fsp);
	return status;
}
예제 #4
0
파일: close.c 프로젝트: vormetriclabs/samba
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;
}
예제 #5
0
static NTSTATUS close_normal_file(struct smb_request *req, files_struct *fsp,
				  enum file_close_type close_type)
{
	NTSTATUS status = NT_STATUS_OK;
	NTSTATUS tmp;
	connection_struct *conn = fsp->conn;

	if (close_type == ERROR_CLOSE) {
		cancel_aio_by_fsp(fsp);
	} else {
		/*
	 	 * If we're finishing async io on a close we can get a write
		 * error here, we must remember this.
		 */
		int ret = wait_for_aio_completion(fsp);
		if (ret) {
			status = ntstatus_keeperror(
				status, map_nt_error_from_unix(ret));
		}
	}

	/*
	 * If we're flushing on a close we can get a write
	 * error here, we must remember this.
	 */

	tmp = close_filestruct(fsp);
	status = ntstatus_keeperror(status, tmp);

	if (fsp->print_file) {
		/* FIXME: return spool errors */
		print_spool_end(fsp, close_type);
		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. */

	if (fsp->fh->ref_count == 1) {
		/* Should we return on error here... ? */
		tmp = close_remove_share_mode(fsp, close_type);
		status = ntstatus_keeperror(status, tmp);
	}

	locking_close_file(conn->sconn->msg_ctx, fsp, close_type);

	tmp = fd_close(fsp);
	status = ntstatus_keeperror(status, tmp);

	/* check for magic scripts */
	if (close_type == NORMAL_CLOSE) {
		tmp = check_magic(fsp);
		status = ntstatus_keeperror(status, tmp);
	}

	/*
	 * Ensure pending modtime is set after close.
	 */

	tmp = update_write_time_on_close(fsp);
	if (NT_STATUS_EQUAL(tmp, 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. */

		tmp = NT_STATUS_OK;
	}

	status = ntstatus_keeperror(status, tmp);

	DEBUG(2,("%s closed file %s (numopen=%d) %s\n",
		conn->session_info->unix_info->unix_name, fsp_str_dbg(fsp),
		conn->num_files_open - 1,
		nt_errstr(status) ));

	file_free(req, fsp);
	return status;
}
예제 #6
0
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, &current_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;
}
예제 #7
0
static NTSTATUS close_normal_file(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;
	connection_struct *conn = fsp->conn;

	if (fsp->aio_write_behind) {
		/*
	 	 * If we're finishing write behind on a close we can get a write
		 * error here, we must remember this.
		 */
		int ret = wait_for_aio_completion(fsp);
		if (ret) {
			saved_status1 = map_nt_error_from_unix(ret);
		}
	} else {
		cancel_aio_by_fsp(fsp);
	}
 
	/*
	 * If we're flushing on a close we can get a write
	 * error here, we must remember this.
	 */

	saved_status2 = close_filestruct(fsp);

	if (fsp->print_file) {
		print_fsp_end(fsp, close_type);
		file_free(fsp);
		return NT_STATUS_OK;
	}

	/* 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. */

	if (fsp->fh->ref_count == 1) {
		/* Should we return on error here... ? */
		saved_status3 = close_remove_share_mode(fsp, close_type);
	}

	if(fsp->oplock_type) {
		release_file_oplock(fsp);
	}

	locking_close_file(fsp);

	status = fd_close(conn, fsp);

	/* check for magic scripts */
	if (close_type == NORMAL_CLOSE) {
		check_magic(fsp,conn);
	}

	/*
	 * 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);
	}

	if (NT_STATUS_IS_OK(status)) {
		if (!NT_STATUS_IS_OK(saved_status1)) {
			status = saved_status1;
		} else if (!NT_STATUS_IS_OK(saved_status2)) {
			status = saved_status2;
		} else if (!NT_STATUS_IS_OK(saved_status3)) {
			status = saved_status3;
		}
	}

	DEBUG(2,("%s closed file %s (numopen=%d) %s\n",
		conn->user,fsp->fsp_name,
		conn->num_files_open,
		nt_errstr(status) ));

	file_free(fsp);
	return status;
}
예제 #8
0
static NTSTATUS close_normal_file(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 we're finishing write behind on a close we can get a write
         * error here, we must remember this.
         */
        int ret = wait_for_aio_completion(fsp);
        if (ret) {
            saved_status1 = map_nt_error_from_unix(ret);
        }
    } else {
        cancel_aio_by_fsp(fsp);
    }

    /*
     * If we're flushing on a close we can get a write
     * error here, we must remember this.
     */

    saved_status2 = close_filestruct(fsp);

    if (fsp->print_file) {
#ifndef AVM_NO_PRINTING
        print_fsp_end(fsp, close_type);
#endif
        file_free(fsp);
        return NT_STATUS_OK;
    }

    /* 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. */

    if (fsp->fh->ref_count == 1) {
        /* Should we return on error here... ? */
        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);

    /* check for magic scripts */
    if (close_type == NORMAL_CLOSE) {
        check_magic(fsp);
    }

    /*
     * Ensure pending modtime is set after close.
     */

    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)) {
        if (!NT_STATUS_IS_OK(saved_status1)) {
            status = saved_status1;
        } else if (!NT_STATUS_IS_OK(saved_status2)) {
            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->server_info->unix_name,fsp->fsp_name,
             conn->num_files_open - 1,
             nt_errstr(status) ));

    file_free(fsp);
    return status;
}
예제 #9
0
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;
}
예제 #10
0
static int close_normal_file(files_struct *fsp, enum file_close_type close_type)
{
	connection_struct *conn = fsp->conn;
	int saved_errno = 0;
	int err = 0;
	int err1 = 0;

	remove_pending_lock_requests_by_fid(fsp);

	if (fsp->aio_write_behind) {
		/*
	 	 * If we're finishing write behind on a close we can get a write
		 * error here, we must remember this.
		 */
		int ret = wait_for_aio_completion(fsp);
		if (ret) {
			saved_errno = ret;
			err1 = -1;
		}
	} else {
		cancel_aio_by_fsp(fsp);
	}
 
	/*
	 * If we're flushing on a close we can get a write
	 * error here, we must remember this.
	 */

	if (close_filestruct(fsp) == -1) {
		saved_errno = errno;
		err1 = -1;
	}

	if (fsp->print_file) {
#ifndef AVM_NO_PRINTING
		print_fsp_end(fsp, close_type);
#endif
		file_free(fsp);
		return 0;
	}

	/* 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. */

	if (fsp->fh->ref_count == 1) {
		/* Should we return on error here... ? */
		close_remove_share_mode(fsp, close_type);
	}

	if(fsp->oplock_type) {
		release_file_oplock(fsp);
	}

	locking_close_file(fsp);

	err = fd_close(conn, fsp);

	/* Only save errno if fd_close failed and we don't already
	   have an errno saved from a flush call. */
	if ((err1 != -1) && (err == -1)) {
		saved_errno = errno;
	}

	/* check for magic scripts */
	if (close_type == NORMAL_CLOSE) {
		check_magic(fsp,conn);
	}

	/*
	 * Ensure pending modtime is set after close.
	 */

	if(fsp->pending_modtime && fsp->pending_modtime_owner) {
		set_filetime(conn, fsp->fsp_name, fsp->pending_modtime);
	} else if (fsp->last_write_time) {
		set_filetime(conn, fsp->fsp_name, fsp->last_write_time);
	}

	DEBUG(2,("%s closed file %s (numopen=%d) %s\n",
		conn->user,fsp->fsp_name,
		conn->num_files_open,
		(err == -1 || err1 == -1) ? strerror(saved_errno) : ""));

	file_free(fsp);

	if (err == -1 || err1 == -1) {
		errno = saved_errno;
		return saved_errno;
	} else {
		return 0;
	}
}
예제 #11
0
static int close_normal_file(files_struct *fsp, BOOL normal_close)
{
	share_mode_entry *share_entry = NULL;
	size_t share_entry_count = 0;
	BOOL delete_on_close = False;
	connection_struct *conn = fsp->conn;
	int err = 0;
	int err1 = 0;

	remove_pending_lock_requests_by_fid(fsp);

	/*
	 * If we're flushing on a close we can get a write
	 * error here, we must remember this.
	 */

	if (close_filestruct(fsp) == -1)
		err1 = -1;

	if (fsp->print_file) {
		print_fsp_end(fsp, normal_close);
		file_free(fsp);
		return 0;
	}

	/*
	 * Lock the share entries, and determine if we should delete
	 * on close. If so delete whilst the lock is still in effect.
	 * This prevents race conditions with the file being created. JRA.
	 */

	lock_share_entry_fsp(fsp);

	if (fsp->delete_on_close) {

		/*
		 * Modify the share mode entry for all files open
		 * on this device and inode to tell other smbds we have
		 * changed the delete on close flag. The last closer will delete the file
		 * if flag is set.
		 */

		NTSTATUS status =set_delete_on_close_over_all(fsp, fsp->delete_on_close);
		if (NT_STATUS_V(status) !=  NT_STATUS_V(NT_STATUS_OK))
			DEBUG(0,("close_normal_file: failed to change delete on close flag for file %s\n",
				fsp->fsp_name ));
	}

	share_entry_count = del_share_mode(fsp, &share_entry);

	DEBUG(10,("close_normal_file: share_entry_count = %lu for file %s\n",
		(unsigned long)share_entry_count, fsp->fsp_name ));

	/*
	 * We delete on close if it's the last open, and the
	 * delete on close flag was set in the entry we just deleted.
	 */

	if ((share_entry_count == 0) && share_entry && 
			GET_DELETE_ON_CLOSE_FLAG(share_entry->share_mode) )
		delete_on_close = True;

	SAFE_FREE(share_entry);

	/*
	 * NT can set delete_on_close of the last open
	 * reference to a file.
	 */

	if (normal_close && delete_on_close) {
		DEBUG(5,("close_file: file %s. Delete on close was set - deleting file.\n",
			fsp->fsp_name));
		if(SMB_VFS_UNLINK(conn,fsp->fsp_name) != 0) {
			/*
			 * This call can potentially fail as another smbd may have
			 * had the file open with delete on close set and deleted
			 * it when its last reference to this file went away. Hence
			 * we log this but not at debug level zero.
			 */

		DEBUG(5,("close_file: file %s. Delete on close was set and unlink failed \
with error %s\n", fsp->fsp_name, strerror(errno) ));
		}