1
0
mirror of https://github.com/samba-team/samba.git synced 2024-12-23 17:34:34 +03:00

smbd: Move copy_file to smb2_reply.c

Signed-off-by: David Mulder <dmulder@suse.com>
Reviewed-by: Jeremy Allison <jra@samba.org>
This commit is contained in:
David Mulder 2022-03-17 11:34:46 -06:00 committed by Jeremy Allison
parent 160849a822
commit fdf5727c1e
3 changed files with 195 additions and 195 deletions

View File

@ -956,13 +956,6 @@ void reply_printwrite(struct smb_request *req);
void reply_mkdir(struct smb_request *req);
void reply_rmdir(struct smb_request *req);
void reply_mv(struct smb_request *req);
NTSTATUS copy_file(TALLOC_CTX *ctx,
connection_struct *conn,
struct smb_filename *smb_fname_src,
struct smb_filename *smb_fname_dst,
int ofun,
int count,
bool target_is_directory);
void reply_copy(struct smb_request *req);
uint64_t get_lock_pid(const uint8_t *data, int data_offset,
bool large_file_format);
@ -1036,6 +1029,13 @@ NTSTATUS rename_internals(TALLOC_CTX *ctx,
uint32_t attrs,
bool replace_if_exists,
uint32_t access_mask);
NTSTATUS copy_file(TALLOC_CTX *ctx,
connection_struct *conn,
struct smb_filename *smb_fname_src,
struct smb_filename *smb_fname_dst,
int ofun,
int count,
bool target_is_directory);
/* The following definitions come from smbd/seal.c */

View File

@ -6067,194 +6067,6 @@ void reply_mv(struct smb_request *req)
return;
}
/*******************************************************************
Copy a file as part of a reply_copy.
******************************************************************/
/*
* TODO: check error codes on all callers
*/
NTSTATUS copy_file(TALLOC_CTX *ctx,
connection_struct *conn,
struct smb_filename *smb_fname_src,
struct smb_filename *smb_fname_dst,
int ofun,
int count,
bool target_is_directory)
{
struct smb_filename *smb_fname_dst_tmp = NULL;
off_t ret=-1;
files_struct *fsp1,*fsp2;
uint32_t dosattrs;
uint32_t new_create_disposition;
NTSTATUS status;
smb_fname_dst_tmp = cp_smb_filename(ctx, smb_fname_dst);
if (smb_fname_dst_tmp == NULL) {
return NT_STATUS_NO_MEMORY;
}
/*
* If the target is a directory, extract the last component from the
* src filename and append it to the dst filename
*/
if (target_is_directory) {
const char *p;
/* dest/target can't be a stream if it's a directory. */
SMB_ASSERT(smb_fname_dst->stream_name == NULL);
p = strrchr_m(smb_fname_src->base_name,'/');
if (p) {
p++;
} else {
p = smb_fname_src->base_name;
}
smb_fname_dst_tmp->base_name =
talloc_asprintf_append(smb_fname_dst_tmp->base_name, "/%s",
p);
if (!smb_fname_dst_tmp->base_name) {
status = NT_STATUS_NO_MEMORY;
goto out;
}
}
status = vfs_file_exist(conn, smb_fname_src);
if (!NT_STATUS_IS_OK(status)) {
goto out;
}
status = openat_pathref_fsp(conn->cwd_fsp, smb_fname_src);
if (!NT_STATUS_IS_OK(status)) {
goto out;
}
if (!target_is_directory && count) {
new_create_disposition = FILE_OPEN;
} else {
if (!map_open_params_to_ntcreate(smb_fname_dst_tmp->base_name,
0, ofun,
NULL, NULL,
&new_create_disposition,
NULL,
NULL)) {
status = NT_STATUS_INVALID_PARAMETER;
goto out;
}
}
/* Open the src file for reading. */
status = SMB_VFS_CREATE_FILE(
conn, /* conn */
NULL, /* req */
smb_fname_src, /* fname */
FILE_GENERIC_READ, /* access_mask */
FILE_SHARE_READ | FILE_SHARE_WRITE, /* share_access */
FILE_OPEN, /* create_disposition*/
0, /* create_options */
FILE_ATTRIBUTE_NORMAL, /* file_attributes */
INTERNAL_OPEN_ONLY, /* oplock_request */
NULL, /* lease */
0, /* allocation_size */
0, /* private_flags */
NULL, /* sd */
NULL, /* ea_list */
&fsp1, /* result */
NULL, /* psbuf */
NULL, NULL); /* create context */
if (!NT_STATUS_IS_OK(status)) {
goto out;
}
dosattrs = fdos_mode(fsp1);
if (SMB_VFS_STAT(conn, smb_fname_dst_tmp) == -1) {
ZERO_STRUCTP(&smb_fname_dst_tmp->st);
}
status = openat_pathref_fsp(conn->cwd_fsp, smb_fname_dst);
if (!NT_STATUS_IS_OK(status) &&
!NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_NOT_FOUND))
{
goto out;
}
/* Open the dst file for writing. */
status = SMB_VFS_CREATE_FILE(
conn, /* conn */
NULL, /* req */
smb_fname_dst, /* fname */
FILE_GENERIC_WRITE, /* access_mask */
FILE_SHARE_READ | FILE_SHARE_WRITE, /* share_access */
new_create_disposition, /* create_disposition*/
0, /* create_options */
dosattrs, /* file_attributes */
INTERNAL_OPEN_ONLY, /* oplock_request */
NULL, /* lease */
0, /* allocation_size */
0, /* private_flags */
NULL, /* sd */
NULL, /* ea_list */
&fsp2, /* result */
NULL, /* psbuf */
NULL, NULL); /* create context */
if (!NT_STATUS_IS_OK(status)) {
close_file_free(NULL, &fsp1, ERROR_CLOSE);
goto out;
}
if (ofun & OPENX_FILE_EXISTS_OPEN) {
ret = SMB_VFS_LSEEK(fsp2, 0, SEEK_END);
if (ret == -1) {
DEBUG(0, ("error - vfs lseek returned error %s\n",
strerror(errno)));
status = map_nt_error_from_unix(errno);
close_file_free(NULL, &fsp1, ERROR_CLOSE);
close_file_free(NULL, &fsp2, ERROR_CLOSE);
goto out;
}
}
/* Do the actual copy. */
if (smb_fname_src->st.st_ex_size) {
ret = vfs_transfer_file(fsp1, fsp2, smb_fname_src->st.st_ex_size);
} else {
ret = 0;
}
close_file_free(NULL, &fsp1, NORMAL_CLOSE);
/* Ensure the modtime is set correctly on the destination file. */
set_close_write_time(fsp2, smb_fname_src->st.st_ex_mtime);
/*
* As we are opening fsp1 read-only we only expect
* an error on close on fsp2 if we are out of space.
* Thus we don't look at the error return from the
* close of fsp1.
*/
status = close_file_free(NULL, &fsp2, NORMAL_CLOSE);
if (!NT_STATUS_IS_OK(status)) {
goto out;
}
if (ret != (off_t)smb_fname_src->st.st_ex_size) {
status = NT_STATUS_DISK_FULL;
goto out;
}
status = NT_STATUS_OK;
out:
TALLOC_FREE(smb_fname_dst_tmp);
return status;
}
/****************************************************************************
Reply to a file copy.

View File

@ -1822,3 +1822,191 @@ NTSTATUS rename_internals(TALLOC_CTX *ctx,
TALLOC_FREE(posx);
return status;
}
/*******************************************************************
Copy a file as part of a reply_copy.
******************************************************************/
/*
* TODO: check error codes on all callers
*/
NTSTATUS copy_file(TALLOC_CTX *ctx,
connection_struct *conn,
struct smb_filename *smb_fname_src,
struct smb_filename *smb_fname_dst,
int ofun,
int count,
bool target_is_directory)
{
struct smb_filename *smb_fname_dst_tmp = NULL;
off_t ret=-1;
files_struct *fsp1,*fsp2;
uint32_t dosattrs;
uint32_t new_create_disposition;
NTSTATUS status;
smb_fname_dst_tmp = cp_smb_filename(ctx, smb_fname_dst);
if (smb_fname_dst_tmp == NULL) {
return NT_STATUS_NO_MEMORY;
}
/*
* If the target is a directory, extract the last component from the
* src filename and append it to the dst filename
*/
if (target_is_directory) {
const char *p;
/* dest/target can't be a stream if it's a directory. */
SMB_ASSERT(smb_fname_dst->stream_name == NULL);
p = strrchr_m(smb_fname_src->base_name,'/');
if (p) {
p++;
} else {
p = smb_fname_src->base_name;
}
smb_fname_dst_tmp->base_name =
talloc_asprintf_append(smb_fname_dst_tmp->base_name, "/%s",
p);
if (!smb_fname_dst_tmp->base_name) {
status = NT_STATUS_NO_MEMORY;
goto out;
}
}
status = vfs_file_exist(conn, smb_fname_src);
if (!NT_STATUS_IS_OK(status)) {
goto out;
}
status = openat_pathref_fsp(conn->cwd_fsp, smb_fname_src);
if (!NT_STATUS_IS_OK(status)) {
goto out;
}
if (!target_is_directory && count) {
new_create_disposition = FILE_OPEN;
} else {
if (!map_open_params_to_ntcreate(smb_fname_dst_tmp->base_name,
0, ofun,
NULL, NULL,
&new_create_disposition,
NULL,
NULL)) {
status = NT_STATUS_INVALID_PARAMETER;
goto out;
}
}
/* Open the src file for reading. */
status = SMB_VFS_CREATE_FILE(
conn, /* conn */
NULL, /* req */
smb_fname_src, /* fname */
FILE_GENERIC_READ, /* access_mask */
FILE_SHARE_READ | FILE_SHARE_WRITE, /* share_access */
FILE_OPEN, /* create_disposition*/
0, /* create_options */
FILE_ATTRIBUTE_NORMAL, /* file_attributes */
INTERNAL_OPEN_ONLY, /* oplock_request */
NULL, /* lease */
0, /* allocation_size */
0, /* private_flags */
NULL, /* sd */
NULL, /* ea_list */
&fsp1, /* result */
NULL, /* psbuf */
NULL, NULL); /* create context */
if (!NT_STATUS_IS_OK(status)) {
goto out;
}
dosattrs = fdos_mode(fsp1);
if (SMB_VFS_STAT(conn, smb_fname_dst_tmp) == -1) {
ZERO_STRUCTP(&smb_fname_dst_tmp->st);
}
status = openat_pathref_fsp(conn->cwd_fsp, smb_fname_dst);
if (!NT_STATUS_IS_OK(status) &&
!NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_NOT_FOUND))
{
goto out;
}
/* Open the dst file for writing. */
status = SMB_VFS_CREATE_FILE(
conn, /* conn */
NULL, /* req */
smb_fname_dst, /* fname */
FILE_GENERIC_WRITE, /* access_mask */
FILE_SHARE_READ | FILE_SHARE_WRITE, /* share_access */
new_create_disposition, /* create_disposition*/
0, /* create_options */
dosattrs, /* file_attributes */
INTERNAL_OPEN_ONLY, /* oplock_request */
NULL, /* lease */
0, /* allocation_size */
0, /* private_flags */
NULL, /* sd */
NULL, /* ea_list */
&fsp2, /* result */
NULL, /* psbuf */
NULL, NULL); /* create context */
if (!NT_STATUS_IS_OK(status)) {
close_file_free(NULL, &fsp1, ERROR_CLOSE);
goto out;
}
if (ofun & OPENX_FILE_EXISTS_OPEN) {
ret = SMB_VFS_LSEEK(fsp2, 0, SEEK_END);
if (ret == -1) {
DEBUG(0, ("error - vfs lseek returned error %s\n",
strerror(errno)));
status = map_nt_error_from_unix(errno);
close_file_free(NULL, &fsp1, ERROR_CLOSE);
close_file_free(NULL, &fsp2, ERROR_CLOSE);
goto out;
}
}
/* Do the actual copy. */
if (smb_fname_src->st.st_ex_size) {
ret = vfs_transfer_file(fsp1, fsp2, smb_fname_src->st.st_ex_size);
} else {
ret = 0;
}
close_file_free(NULL, &fsp1, NORMAL_CLOSE);
/* Ensure the modtime is set correctly on the destination file. */
set_close_write_time(fsp2, smb_fname_src->st.st_ex_mtime);
/*
* As we are opening fsp1 read-only we only expect
* an error on close on fsp2 if we are out of space.
* Thus we don't look at the error return from the
* close of fsp1.
*/
status = close_file_free(NULL, &fsp2, NORMAL_CLOSE);
if (!NT_STATUS_IS_OK(status)) {
goto out;
}
if (ret != (off_t)smb_fname_src->st.st_ex_size) {
status = NT_STATUS_DISK_FULL;
goto out;
}
status = NT_STATUS_OK;
out:
TALLOC_FREE(smb_fname_dst_tmp);
return status;
}