From a9ec21cf219c3aef0388c252539f315d3e606a71 Mon Sep 17 00:00:00 2001 From: Tim Prouty Date: Wed, 10 Jun 2009 10:37:57 -0700 Subject: s3: Prepare the first set of SMB_VFS_CREATE_FILE callers to take an smb_filename struct Some of the callers required minimal changes, while others (copy_internals) required significant changes. The task is simplified a little bit because we are able to do operations and checks on the base_name when a stream isn't used. This patch should cause no functional changes. Volker, Jeremy: Please check --- source3/include/proto.h | 9 +- source3/printing/nt_printing.c | 148 ++++++++++++------- source3/smbd/open.c | 12 +- source3/smbd/reply.c | 322 ++++++++++++++++++++++++----------------- source3/smbd/trans2.c | 30 ++-- source3/smbd/vfs.c | 26 +++- 6 files changed, 333 insertions(+), 214 deletions(-) diff --git a/source3/include/proto.h b/source3/include/proto.h index f5e44bad64..a0ad282242 100644 --- a/source3/include/proto.h +++ b/source3/include/proto.h @@ -6622,7 +6622,8 @@ NTSTATUS open_file_fchmod(struct smb_request *req, connection_struct *conn, const char *fname, SMB_STRUCT_STAT *psbuf, files_struct **result); NTSTATUS close_file_fchmod(struct smb_request *req, files_struct *fsp); -NTSTATUS create_directory(connection_struct *conn, struct smb_request *req, const char *directory); +NTSTATUS create_directory(connection_struct *conn, struct smb_request *req, + const struct smb_filename *smb_dname); void msg_file_was_renamed(struct messaging_context *msg, void *private_data, uint32_t msg_type, @@ -6917,8 +6918,8 @@ NTSTATUS rename_internals(TALLOC_CTX *ctx, void reply_mv(struct smb_request *req); NTSTATUS copy_file(TALLOC_CTX *ctx, connection_struct *conn, - const char *src, - const char *dest1, + struct smb_filename *smb_fname_src, + struct smb_filename *smb_fname_dst, int ofun, int count, bool target_is_directory); @@ -7122,7 +7123,7 @@ void *vfs_fetch_fsp_extension(vfs_handle_struct *handle, files_struct *fsp); bool smbd_vfs_init(connection_struct *conn); bool vfs_directory_exist(connection_struct *conn, const char *dname, SMB_STRUCT_STAT *st); bool vfs_object_exist(connection_struct *conn,const char *fname,SMB_STRUCT_STAT *sbuf); -bool vfs_file_exist(connection_struct *conn, const char *fname,SMB_STRUCT_STAT *sbuf); +NTSTATUS vfs_file_exist(connection_struct *conn, struct smb_filename *smb_fname); ssize_t vfs_read_data(files_struct *fsp, char *buf, size_t byte_count); ssize_t vfs_pread_data(files_struct *fsp, char *buf, size_t byte_count, SMB_OFF_T offset); diff --git a/source3/printing/nt_printing.c b/source3/printing/nt_printing.c index 02ac7eeca2..1aec954f12 100644 --- a/source3/printing/nt_printing.c +++ b/source3/printing/nt_printing.c @@ -634,40 +634,30 @@ bool nt_printing_init(struct messaging_context *msg_ctx) Function to allow filename parsing "the old way". ********************************************************************/ -static char *driver_unix_convert(connection_struct *conn, - const char *old_name, - SMB_STRUCT_STAT *pst) +static NTSTATUS driver_unix_convert(connection_struct *conn, + const char *old_name, + struct smb_filename **smb_fname) { NTSTATUS status; TALLOC_CTX *ctx = talloc_tos(); - struct smb_filename *smb_fname = NULL; char *name = talloc_strdup(ctx, old_name); - char *new_name = NULL; if (!name) { - return NULL; + return NT_STATUS_NO_MEMORY; } unix_format(name); name = unix_clean_name(ctx, name); if (!name) { - return NULL; + return NT_STATUS_NO_MEMORY; } trim_string(name,"/","/"); - status = unix_convert(ctx, conn, name, &smb_fname, 0); + status = unix_convert(ctx, conn, name, smb_fname, 0); if (!NT_STATUS_IS_OK(status)) { - return NULL; - } - - *pst = smb_fname->st; - status = get_full_smb_filename(ctx, smb_fname, &new_name); - if (!NT_STATUS_IS_OK(status)) { - TALLOC_FREE(smb_fname); - return NULL; + return NT_STATUS_NO_MEMORY; } - TALLOC_FREE(smb_fname); - return new_name; + return NT_STATUS_OK; } /******************************************************************* @@ -1297,11 +1287,13 @@ static int file_version_is_newer(connection_struct *conn, fstring new_file, fstr uint32 old_minor; time_t old_create_time; + struct smb_filename *smb_fname = NULL; files_struct *fsp = NULL; SMB_STRUCT_STAT st; SMB_STRUCT_STAT stat_buf; NTSTATUS status; + int ret; SET_STAT_INVALID(st); SET_STAT_INVALID(stat_buf); @@ -1309,8 +1301,13 @@ static int file_version_is_newer(connection_struct *conn, fstring new_file, fstr old_create_time = (time_t)0; /* Get file version info (if available) for previous file (if it exists) */ - filepath = driver_unix_convert(conn,old_file,&stat_buf); - if (!filepath) { + status = driver_unix_convert(conn, old_file, &smb_fname); + if (!NT_STATUS_IS_OK(status)) { + goto error_exit; + } + + status = get_full_smb_filename(talloc_tos(), smb_fname, &filepath); + if (!NT_STATUS_IS_OK(status)) { goto error_exit; } @@ -1337,10 +1334,11 @@ static int file_version_is_newer(connection_struct *conn, fstring new_file, fstr /* Old file not found, so by definition new file is in fact newer */ DEBUG(10,("file_version_is_newer: Can't open old file [%s], errno = %d\n", filepath, errno)); - return 1; + ret = 1; + goto done; } else { - int ret = get_file_version(fsp, old_file, &old_major, &old_minor); + ret = get_file_version(fsp, old_file, &old_major, &old_minor); if (ret == -1) { goto error_exit; } @@ -1361,8 +1359,13 @@ static int file_version_is_newer(connection_struct *conn, fstring new_file, fstr fsp = NULL; /* Get file version info (if available) for new file */ - filepath = driver_unix_convert(conn,new_file,&stat_buf); - if (!filepath) { + status = driver_unix_convert(conn, new_file, &smb_fname); + if (!NT_STATUS_IS_OK(status)) { + goto error_exit; + } + + status = get_full_smb_filename(talloc_tos(), smb_fname, &filepath); + if (!NT_STATUS_IS_OK(status)) { goto error_exit; } @@ -1392,7 +1395,7 @@ static int file_version_is_newer(connection_struct *conn, fstring new_file, fstr goto error_exit; } else { - int ret = get_file_version(fsp, new_file, &new_major, &new_minor); + ret = get_file_version(fsp, new_file, &new_major, &new_minor); if (ret == -1) { goto error_exit; } @@ -1418,29 +1421,36 @@ static int file_version_is_newer(connection_struct *conn, fstring new_file, fstr (new_major == old_major && new_minor > old_minor)) { DEBUG(6,("file_version_is_newer: Replacing [%s] with [%s]\n", old_file, new_file)); - return 1; + ret = 1; + goto done; } else { DEBUG(6,("file_version_is_newer: Leaving [%s] unchanged\n", old_file)); - return 0; + ret = 0; + goto done; } } else { /* Compare modification time/dates and choose the newest time/date */ if (new_create_time > old_create_time) { DEBUG(6,("file_version_is_newer: Replacing [%s] with [%s]\n", old_file, new_file)); - return 1; + ret = 1; + goto done; } else { DEBUG(6,("file_version_is_newer: Leaving [%s] unchanged\n", old_file)); - return 0; + ret = 0; + goto done; } } - error_exit: - if(fsp) - close_file(NULL, fsp, NORMAL_CLOSE); - return -1; + error_exit: + if(fsp) + close_file(NULL, fsp, NORMAL_CLOSE); + ret = -1; + done: + TALLOC_FREE(smb_fname); + return ret; } /**************************************************************************** @@ -1453,7 +1463,8 @@ static uint32 get_correct_cversion(struct pipes_struct *p, { int cversion; NTSTATUS nt_status; - char *driverpath = NULL; + struct smb_filename *smb_fname = NULL; + char *driverpath = NULL; files_struct *fsp = NULL; SMB_STRUCT_STAT st; connection_struct *conn = NULL; @@ -1509,17 +1520,24 @@ static uint32 get_correct_cversion(struct pipes_struct *p, goto error_exit; } - driverpath = driver_unix_convert(conn,driverpath,&st); - if (!driverpath) { - *perr = WERR_NOMEM; + nt_status = driver_unix_convert(conn, driverpath, &smb_fname); + if (!NT_STATUS_IS_OK(nt_status)) { + *perr = ntstatus_to_werror(nt_status); goto error_exit; } - if (!vfs_file_exist(conn, driverpath, &st)) { + nt_status = vfs_file_exist(conn, smb_fname); + if (!NT_STATUS_IS_OK(nt_status)) { *perr = WERR_BADFILE; goto error_exit; } + status = get_full_smb_filename(talloc_tos(), smb_fname, &driverpath); + if (!NT_STATUS_IS_OK(status)) { + *perr = WERR_NOMEM; + goto error_exit; + } + status = SMB_VFS_CREATE_FILE( conn, /* conn */ NULL, /* req */ @@ -1586,6 +1604,7 @@ static uint32 get_correct_cversion(struct pipes_struct *p, error_exit: cversion = -1; done: + TALLOC_FREE(smb_fname); if (fsp != NULL) { close_file(NULL, fsp, NORMAL_CLOSE); } @@ -1811,10 +1830,12 @@ static WERROR move_driver_file_to_download_area(TALLOC_CTX *mem_ctx, uint32_t driver_version, uint32_t version) { + struct smb_filename *smb_fname_old = NULL; + struct smb_filename *smb_fname_new = NULL; char *old_name = NULL; char *new_name = NULL; - SMB_STRUCT_STAT st; NTSTATUS status; + WERROR ret; old_name = talloc_asprintf(mem_ctx, "%s/%s", short_architecture, driver_file); @@ -1826,25 +1847,45 @@ static WERROR move_driver_file_to_download_area(TALLOC_CTX *mem_ctx, if (version != -1 && (version = file_version_is_newer(conn, old_name, new_name)) > 0) { - old_name = driver_unix_convert(conn, old_name, &st); - W_ERROR_HAVE_NO_MEMORY(old_name); + status = driver_unix_convert(conn, old_name, &smb_fname_old); + if (!NT_STATUS_IS_OK(status)) { + ret = WERR_NOMEM; + goto out; + } + + /* Setup a synthetic smb_filename struct */ + smb_fname_new = TALLOC_ZERO_P(mem_ctx, struct smb_filename); + if (!smb_fname_new) { + ret = WERR_NOMEM; + goto out; + } - DEBUG(10,("move_driver_file_to_download_area: copying '%s' to '%s'\n", - old_name, new_name)); + smb_fname_new->base_name = new_name; - status = copy_file(mem_ctx, conn, old_name, new_name, + DEBUG(10,("move_driver_file_to_download_area: copying '%s' to " + "'%s'\n", smb_fname_old->base_name, + smb_fname_new->base_name)); + + status = copy_file(mem_ctx, conn, smb_fname_old, smb_fname_new, OPENX_FILE_EXISTS_TRUNCATE | OPENX_FILE_CREATE_IF_NOT_EXIST, 0, false); if (!NT_STATUS_IS_OK(status)) { - DEBUG(0,("move_driver_file_to_download_area: Unable to rename [%s] to [%s]: %s\n", - old_name, new_name, nt_errstr(status))); - return WERR_ACCESS_DENIED; + DEBUG(0,("move_driver_file_to_download_area: Unable " + "to rename [%s] to [%s]: %s\n", + smb_fname_old->base_name, new_name, + nt_errstr(status))); + ret = WERR_ACCESS_DENIED; + goto out; } } - return WERR_OK; + ret = WERR_OK; + out: + TALLOC_FREE(smb_fname_old); + TALLOC_FREE(smb_fname_new); + return ret; } WERROR move_driver_to_download_area(struct pipes_struct *p, @@ -1854,10 +1895,10 @@ WERROR move_driver_to_download_area(struct pipes_struct *p, NT_PRINTER_DRIVER_INFO_LEVEL_3 *driver; NT_PRINTER_DRIVER_INFO_LEVEL_3 converted_driver; const char *short_architecture; + struct smb_filename *smb_dname = NULL; char *new_dir = NULL; connection_struct *conn = NULL; NTSTATUS nt_status; - SMB_STRUCT_STAT st; int i; TALLOC_CTX *ctx = talloc_tos(); int ver = 0; @@ -1911,15 +1952,15 @@ WERROR move_driver_to_download_area(struct pipes_struct *p, *perr = WERR_NOMEM; goto err_exit; } - new_dir = driver_unix_convert(conn,new_dir,&st); - if (!new_dir) { + nt_status = driver_unix_convert(conn, new_dir, &smb_dname); + if (!NT_STATUS_IS_OK(nt_status)) { *perr = WERR_NOMEM; goto err_exit; } - DEBUG(5,("Creating first directory: %s\n", new_dir)); + DEBUG(5,("Creating first directory: %s\n", smb_dname->base_name)); - create_directory(conn, NULL, new_dir); + create_directory(conn, NULL, smb_dname); /* For each driver file, archi\filexxx.yyy, if there is a duplicate file * listed for this driver which has already been moved, skip it (note: @@ -2044,6 +2085,7 @@ WERROR move_driver_to_download_area(struct pipes_struct *p, } err_exit: + TALLOC_FREE(smb_dname); if (conn != NULL) { vfs_ChDir(conn, oldcwd); diff --git a/source3/smbd/open.c b/source3/smbd/open.c index 773436fa8e..718feb4996 100644 --- a/source3/smbd/open.c +++ b/source3/smbd/open.c @@ -2598,10 +2598,17 @@ static NTSTATUS open_directory(connection_struct *conn, return NT_STATUS_OK; } -NTSTATUS create_directory(connection_struct *conn, struct smb_request *req, const char *directory) +NTSTATUS create_directory(connection_struct *conn, struct smb_request *req, + const struct smb_filename *smb_dname) { NTSTATUS status; files_struct *fsp; + char *directory = NULL; + + status = get_full_smb_filename(talloc_tos(), smb_dname, &directory); + if (!NT_STATUS_IS_OK(status)) { + goto out; + } status = SMB_VFS_CREATE_FILE( conn, /* conn */ @@ -2625,7 +2632,8 @@ NTSTATUS create_directory(connection_struct *conn, struct smb_request *req, cons if (NT_STATUS_IS_OK(status)) { close_file(req, fsp, NORMAL_CLOSE); } - + out: + TALLOC_FREE(directory); return status; } diff --git a/source3/smbd/reply.c b/source3/smbd/reply.c index 844bcc1882..f91a3c7550 100644 --- a/source3/smbd/reply.c +++ b/source3/smbd/reply.c @@ -5233,19 +5233,13 @@ void reply_mkdir(struct smb_request *req) goto out; } - status = get_full_smb_filename(ctx, smb_dname, &directory); - if (!NT_STATUS_IS_OK(status)) { - reply_nterror(req, status); - goto out; - } - - status = check_name(conn, directory); + status = check_name(conn, smb_dname->base_name); if (!NT_STATUS_IS_OK(status)) { reply_nterror(req, status); goto out; } - status = create_directory(conn, req, directory); + status = create_directory(conn, req, smb_dname); DEBUG(5, ("create_directory returned %s\n", nt_errstr(status))); @@ -5268,7 +5262,7 @@ void reply_mkdir(struct smb_request *req) reply_outbuf(req, 0, 0); - DEBUG( 3, ( "mkdir %s\n", directory ) ); + DEBUG(3, ("mkdir %s\n", smb_dname->base_name)); out: TALLOC_FREE(smb_dname); END_PROFILE(SMBmkdir); @@ -6434,59 +6428,80 @@ void reply_mv(struct smb_request *req) NTSTATUS copy_file(TALLOC_CTX *ctx, connection_struct *conn, - const char *src, - const char *dest1, + struct smb_filename *smb_fname_src, + struct smb_filename *smb_fname_dst, int ofun, int count, bool target_is_directory) { - SMB_STRUCT_STAT src_sbuf, sbuf2; + struct smb_filename *smb_fname_dst_tmp = NULL; + char *fname_src = NULL; + char *fname_dst = NULL; SMB_OFF_T ret=-1; files_struct *fsp1,*fsp2; - char *dest = NULL; uint32 dosattrs; uint32 new_create_disposition; NTSTATUS status; - dest = talloc_strdup(ctx, dest1); - if (!dest) { - return NT_STATUS_NO_MEMORY; + + status = copy_smb_filename(ctx, smb_fname_dst, &smb_fname_dst_tmp); + if (!NT_STATUS_IS_OK(status)) { + return status; } + + /* + * 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 = strrchr_m(src,'/'); + 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 = src; + p = smb_fname_src->base_name; } - dest = talloc_asprintf_append(dest, - "/%s", - p); - if (!dest) { - return NT_STATUS_NO_MEMORY; + 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; } } - if (!vfs_file_exist(conn,src,&src_sbuf)) { - TALLOC_FREE(dest); - return NT_STATUS_OBJECT_NAME_NOT_FOUND; + status = vfs_file_exist(conn, 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(dest1,0,ofun, - NULL, NULL, &new_create_disposition, NULL)) { - TALLOC_FREE(dest); - return NT_STATUS_INVALID_PARAMETER; + if (!map_open_params_to_ntcreate(smb_fname_dst_tmp->base_name, + 0, ofun, NULL, NULL, + &new_create_disposition, + NULL)) { + status = NT_STATUS_INVALID_PARAMETER; + goto out; } } + status = get_full_smb_filename(talloc_tos(), smb_fname_src, &fname_src); + if (!NT_STATUS_IS_OK(status)) { + goto out; + } + + /* Open the src file for reading. */ status = SMB_VFS_CREATE_FILE( conn, /* conn */ NULL, /* req */ 0, /* root_dir_fid */ - src, /* fname */ + fname_src, /* fname */ 0, /* create_file_flags */ FILE_GENERIC_READ, /* access_mask */ FILE_SHARE_READ | FILE_SHARE_WRITE, /* share_access */ @@ -6499,23 +6514,29 @@ NTSTATUS copy_file(TALLOC_CTX *ctx, NULL, /* ea_list */ &fsp1, /* result */ NULL, /* pinfo */ - &src_sbuf); /* psbuf */ + &smb_fname_src->st); /* psbuf */ if (!NT_STATUS_IS_OK(status)) { - TALLOC_FREE(dest); - return status; + goto out; + } + + dosattrs = dos_mode(conn, fname_src, &smb_fname_src->st); + + status = get_full_smb_filename(talloc_tos(), smb_fname_dst_tmp, &fname_dst); + if (!NT_STATUS_IS_OK(status)) { + goto out; } - dosattrs = dos_mode(conn, src, &src_sbuf); - if (SMB_VFS_STAT(conn,dest,&sbuf2) == -1) { - ZERO_STRUCTP(&sbuf2); + if (SMB_VFS_STAT(conn, fname_dst, &smb_fname_dst_tmp->st) == -1) { + ZERO_STRUCTP(&smb_fname_dst_tmp->st); } + /* Open the dst file for writing. */ status = SMB_VFS_CREATE_FILE( conn, /* conn */ NULL, /* req */ 0, /* root_dir_fid */ - dest, /* fname */ + fname_dst, /* fname */ 0, /* create_file_flags */ FILE_GENERIC_WRITE, /* access_mask */ FILE_SHARE_READ | FILE_SHARE_WRITE, /* share_access */ @@ -6528,13 +6549,11 @@ NTSTATUS copy_file(TALLOC_CTX *ctx, NULL, /* ea_list */ &fsp2, /* result */ NULL, /* pinfo */ - &sbuf2); /* psbuf */ - - TALLOC_FREE(dest); + &smb_fname_dst_tmp->st); /* psbuf */ if (!NT_STATUS_IS_OK(status)) { close_file(NULL, fsp1, ERROR_CLOSE); - return status; + goto out; } if ((ofun&3) == 1) { @@ -6544,18 +6563,19 @@ NTSTATUS copy_file(TALLOC_CTX *ctx, * Stop the copy from occurring. */ ret = -1; - src_sbuf.st_ex_size = 0; + smb_fname_src->st.st_ex_size = 0; } } - if (src_sbuf.st_ex_size) { - ret = vfs_transfer_file(fsp1, fsp2, src_sbuf.st_ex_size); + /* 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); } close_file(NULL, fsp1, NORMAL_CLOSE); /* Ensure the modtime is set correctly on the destination file. */ - set_close_write_time(fsp2, src_sbuf.st_ex_mtime); + set_close_write_time(fsp2, smb_fname_src->st.st_ex_mtime); /* * As we are opening fsp1 read-only we only expect @@ -6566,14 +6586,21 @@ NTSTATUS copy_file(TALLOC_CTX *ctx, status = close_file(NULL, fsp2, NORMAL_CLOSE); if (!NT_STATUS_IS_OK(status)) { - return status; + goto out; } - if (ret != (SMB_OFF_T)src_sbuf.st_ex_size) { - return NT_STATUS_DISK_FULL; + if (ret != (SMB_OFF_T)smb_fname_src->st.st_ex_size) { + status = NT_STATUS_DISK_FULL; + goto out; } - return NT_STATUS_OK; + status = NT_STATUS_OK; + + out: + TALLOC_FREE(smb_fname_dst_tmp); + TALLOC_FREE(fname_src); + TALLOC_FREE(fname_dst); + return status; } /**************************************************************************** @@ -6583,13 +6610,12 @@ NTSTATUS copy_file(TALLOC_CTX *ctx, void reply_copy(struct smb_request *req) { connection_struct *conn = req->conn; - struct smb_filename *smb_fname = NULL; - struct smb_filename *smb_fname_new = NULL; - char *name = NULL; - char *newname = NULL; - char *directory = NULL; - const char *mask = NULL; - const char mask_star[] = "*"; + struct smb_filename *smb_fname_src = NULL; + struct smb_filename *smb_fname_dst = NULL; + char *fname_src = NULL; + char *fname_dst = NULL; + char *fname_src_mask = NULL; + char *fname_src_dir = NULL; const char *p; int count=0; int error = ERRnoaccess; @@ -6615,20 +6641,20 @@ void reply_copy(struct smb_request *req) flags = SVAL(req->vwv+2, 0); p = (const char *)req->buf; - p += srvstr_get_path_req_wcard(ctx, req, &name, p, STR_TERMINATE, + p += srvstr_get_path_req_wcard(ctx, req, &fname_src, p, STR_TERMINATE, &status, &source_has_wild); if (!NT_STATUS_IS_OK(status)) { reply_nterror(req, status); goto out; } - p += srvstr_get_path_req_wcard(ctx, req, &newname, p, STR_TERMINATE, + p += srvstr_get_path_req_wcard(ctx, req, &fname_dst, p, STR_TERMINATE, &status, &dest_has_wild); if (!NT_STATUS_IS_OK(status)) { reply_nterror(req, status); goto out; } - DEBUG(3,("reply_copy : %s -> %s\n",name,newname)); + DEBUG(3,("reply_copy : %s -> %s\n", fname_src, fname_dst)); if (tid2 != conn->cnum) { /* can't currently handle inter share copies XXXX */ @@ -6639,8 +6665,8 @@ void reply_copy(struct smb_request *req) status = resolve_dfspath_wcard(ctx, conn, req->flags2 & FLAGS2_DFS_PATHNAMES, - name, - &name, + fname_src, + &fname_src, &source_has_wild); if (!NT_STATUS_IS_OK(status)) { if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) { @@ -6654,8 +6680,8 @@ void reply_copy(struct smb_request *req) status = resolve_dfspath_wcard(ctx, conn, req->flags2 & FLAGS2_DFS_PATHNAMES, - newname, - &newname, + fname_dst, + &fname_dst, &dest_has_wild); if (!NT_STATUS_IS_OK(status)) { if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) { @@ -6667,33 +6693,21 @@ void reply_copy(struct smb_request *req) goto out; } - status = unix_convert(ctx, conn, name, &smb_fname, + status = unix_convert(ctx, conn, fname_src, &smb_fname_src, source_has_wild ? UCF_ALLOW_WCARD_LCOMP : 0); if (!NT_STATUS_IS_OK(status)) { reply_nterror(req, status); goto out; } - status = get_full_smb_filename(ctx, smb_fname, &name); - if (!NT_STATUS_IS_OK(status)) { - reply_nterror(req, status); - goto out; - } - - status = unix_convert(ctx, conn, newname, &smb_fname_new, + status = unix_convert(ctx, conn, fname_dst, &smb_fname_dst, dest_has_wild ? UCF_ALLOW_WCARD_LCOMP : 0); if (!NT_STATUS_IS_OK(status)) { reply_nterror(req, status); goto out; } - status = get_full_smb_filename(ctx, smb_fname_new, &newname); - if (!NT_STATUS_IS_OK(status)) { - reply_nterror(req, status); - goto out; - } - - target_is_directory = VALID_STAT_OF_DIR(smb_fname_new->st); + target_is_directory = VALID_STAT_OF_DIR(smb_fname_dst->st); if ((flags&1) && target_is_directory) { reply_doserror(req, ERRDOS, ERRbadfile); @@ -6705,23 +6719,25 @@ void reply_copy(struct smb_request *req) goto out; } - if ((flags&(1<<5)) && VALID_STAT_OF_DIR(smb_fname->st)) { + if ((flags&(1<<5)) && VALID_STAT_OF_DIR(smb_fname_src->st)) { /* wants a tree copy! XXXX */ DEBUG(3,("Rejecting tree copy\n")); reply_doserror(req, ERRSRV, ERRerror); goto out; } - p = strrchr_m(name,'/'); + /* Split up the directory from the filename/mask. */ + p = strrchr_m(smb_fname_src->base_name,'/'); if (p != NULL) { - directory = talloc_strndup(ctx, name, PTR_DIFF(p, name)); - mask = p+1; + fname_src_dir = talloc_strndup(ctx, smb_fname_src->base_name, + PTR_DIFF(p, smb_fname_src->base_name)); + fname_src_mask = talloc_strdup(ctx, p+1); } else { - directory = talloc_strdup(ctx, "./"); - mask = name; + fname_src_dir = talloc_strdup(ctx, "./"); + fname_src_mask = talloc_strdup(ctx, smb_fname_src->base_name); } - if (!directory) { + if (!fname_src_dir || !fname_src_mask) { reply_nterror(req, NT_STATUS_NO_MEMORY); goto out; } @@ -6734,47 +6750,62 @@ void reply_copy(struct smb_request *req) * for a possible mangle. This patch from * Tine Smukavec . */ - - if (!VALID_STAT(smb_fname->st) && - mangle_is_mangled(mask, conn->params)) { + if (!VALID_STAT(smb_fname_src->st) && + mangle_is_mangled(fname_src_mask, conn->params)) { char *new_mask = NULL; - mangle_lookup_name_from_8_3(ctx, - mask, - &new_mask, - conn->params ); + mangle_lookup_name_from_8_3(ctx, fname_src_mask, + &new_mask, conn->params); + + /* Use demangled name if one was successfully found. */ if (new_mask) { - mask = new_mask; + TALLOC_FREE(fname_src_mask); + fname_src_mask = new_mask; } } if (!source_has_wild) { - directory = talloc_asprintf_append(directory, - "/%s", - mask); + + /* + * Only one file needs to be copied. Append the mask back onto + * the directory. + */ + TALLOC_FREE(smb_fname_src->base_name); + smb_fname_src->base_name = talloc_asprintf(smb_fname_src, + "%s/%s", + fname_src_dir, + fname_src_mask); + if (!smb_fname_src->base_name) { + reply_nterror(req, NT_STATUS_NO_MEMORY); + goto out; + } + if (dest_has_wild) { - char *mod_newname = NULL; - if (!resolve_wildcards(ctx, - directory,newname,&mod_newname)) { + char *fname_dst_mod = NULL; + if (!resolve_wildcards(smb_fname_dst, + smb_fname_src->base_name, + smb_fname_dst->base_name, + &fname_dst_mod)) { reply_nterror(req, NT_STATUS_NO_MEMORY); goto out; } - newname = mod_newname; + TALLOC_FREE(smb_fname_dst->base_name); + smb_fname_dst->base_name = fname_dst_mod; } - status = check_name(conn, directory); + status = check_name(conn, smb_fname_src->base_name); if (!NT_STATUS_IS_OK(status)) { reply_nterror(req, status); goto out; } - status = check_name(conn, newname); + status = check_name(conn, smb_fname_dst->base_name); if (!NT_STATUS_IS_OK(status)) { reply_nterror(req, status); goto out; } - status = copy_file(ctx,conn,directory,newname,ofun, - count,target_is_directory); + status = copy_file(ctx, conn, smb_fname_src, smb_fname_dst, + ofun, count, target_is_directory); if(!NT_STATUS_IS_OK(status)) { reply_nterror(req, status); @@ -6787,17 +6818,34 @@ void reply_copy(struct smb_request *req) const char *dname = NULL; long offset = 0; - if (strequal(mask,"????????.???")) { - mask = mask_star; + /* + * There is a wildcard that requires us to actually read the + * src dir and copy each file matching the mask to the dst. + * Right now streams won't be copied, but this could + * presumably be added with a nested loop for reach dir entry. + */ + SMB_ASSERT(!smb_fname_src->stream_name); + SMB_ASSERT(!smb_fname_dst->stream_name); + + smb_fname_src->stream_name = NULL; + smb_fname_dst->stream_name = NULL; + + if (strequal(fname_src_mask,"????????.???")) { + TALLOC_FREE(fname_src_mask); + fname_src_mask = talloc_strdup(ctx, "*"); + if (!fname_src_mask) { + reply_nterror(req, NT_STATUS_NO_MEMORY); + goto out; + } } - status = check_name(conn, directory); + status = check_name(conn, fname_src_dir); if (!NT_STATUS_IS_OK(status)) { reply_nterror(req, status); goto out; } - dir_hnd = OpenDir(talloc_tos(), conn, directory, mask, 0); + dir_hnd = OpenDir(ctx, conn, fname_src_dir, fname_src_mask, 0); if (dir_hnd == NULL) { status = map_nt_error_from_unix(errno); reply_nterror(req, status); @@ -6806,37 +6854,42 @@ void reply_copy(struct smb_request *req) error = ERRbadfile; + /* Iterate over the src dir copying each entry to the dst. */ while ((dname = ReadDirName(dir_hnd, &offset, - &smb_fname->st))) { + &smb_fname_src->st))) { char *destname = NULL; - char *fname = NULL; if (ISDOT(dname) || ISDOTDOT(dname)) { continue; } - if (!is_visible_file(conn, directory, dname, - &smb_fname->st, False)) { + if (!is_visible_file(conn, fname_src_dir, dname, + &smb_fname_src->st, false)) { continue; } - if(!mask_match(dname, mask, conn->case_sensitive)) { + if(!mask_match(dname, fname_src_mask, + conn->case_sensitive)) { continue; } error = ERRnoaccess; - fname = talloc_asprintf(ctx, - "%s/%s", - directory, - dname); - if (!fname) { + + /* Get the src smb_fname struct setup. */ + TALLOC_FREE(smb_fname_src->base_name); + smb_fname_src->base_name = + talloc_asprintf(smb_fname_src, "%s/%s", + fname_src_dir, dname); + + if (!smb_fname_src->base_name) { TALLOC_FREE(dir_hnd); reply_nterror(req, NT_STATUS_NO_MEMORY); goto out; } - if (!resolve_wildcards(ctx, - fname,newname,&destname)) { + if (!resolve_wildcards(ctx, smb_fname_src->base_name, + smb_fname_dst->base_name, + &destname)) { continue; } if (!destname) { @@ -6845,29 +6898,33 @@ void reply_copy(struct smb_request *req) goto out; } - status = check_name(conn, fname); + TALLOC_FREE(smb_fname_dst->base_name); + smb_fname_dst->base_name = destname; + + status = check_name(conn, smb_fname_src->base_name); if (!NT_STATUS_IS_OK(status)) { TALLOC_FREE(dir_hnd); reply_nterror(req, status); goto out; } - status = check_name(conn, destname); + status = check_name(conn, smb_fname_dst->base_name); if (!NT_STATUS_IS_OK(status)) { TALLOC_FREE(dir_hnd); reply_nterror(req, status); goto out; } - DEBUG(3,("reply_copy : doing copy on %s -> %s\n",fname, destname)); + DEBUG(3,("reply_copy : doing copy on %s -> %s\n", + smb_fname_src->base_name, + smb_fname_dst->base_name)); - status = copy_file(ctx,conn,fname,destname,ofun, - count,target_is_directory); + status = copy_file(ctx, conn, smb_fname_src, + smb_fname_dst, ofun, count, + target_is_directory); if (NT_STATUS_IS_OK(status)) { count++; } - TALLOC_FREE(fname); - TALLOC_FREE(destname); } TALLOC_FREE(dir_hnd); } @@ -6887,8 +6944,13 @@ void reply_copy(struct smb_request *req) reply_outbuf(req, 1, 0); SSVAL(req->outbuf,smb_vwv0,count); out: - TALLOC_FREE(smb_fname); - TALLOC_FREE(smb_fname_new); + TALLOC_FREE(smb_fname_src); + TALLOC_FREE(smb_fname_dst); + TALLOC_FREE(fname_src); + TALLOC_FREE(fname_dst); + TALLOC_FREE(fname_src_mask); + TALLOC_FREE(fname_src_dir); + END_PROFILE(SMBcopy); return; } diff --git a/source3/smbd/trans2.c b/source3/smbd/trans2.c index a36e9f588a..dc2544c4e3 100644 --- a/source3/smbd/trans2.c +++ b/source3/smbd/trans2.c @@ -7208,23 +7208,17 @@ static void call_trans2mkdir(connection_struct *conn, struct smb_request *req, return; } - status = get_full_smb_filename(ctx, smb_dname, &directory); - if (!NT_STATUS_IS_OK(status)) { - reply_nterror(req, status); - return; - } - - status = check_name(conn, directory); + status = check_name(conn, smb_dname->base_name); if (!NT_STATUS_IS_OK(status)) { DEBUG(5,("call_trans2mkdir error (%s)\n", nt_errstr(status))); reply_nterror(req, status); - return; + goto out; } /* Any data in this call is an EA list. */ if (total_data && (total_data != 4) && !lp_ea_support(SNUM(conn))) { reply_nterror(req, NT_STATUS_EAS_NOT_SUPPORTED); - return; + goto out; } /* @@ -7236,21 +7230,21 @@ static void call_trans2mkdir(connection_struct *conn, struct smb_request *req, if (total_data != 4) { if (total_data < 10) { reply_nterror(req, NT_STATUS_INVALID_PARAMETER); - return; + goto out; } if (IVAL(pdata,0) > total_data) { DEBUG(10,("call_trans2mkdir: bad total data size (%u) > %u\n", IVAL(pdata,0), (unsigned int)total_data)); reply_nterror(req, NT_STATUS_INVALID_PARAMETER); - return; + goto out; } ea_list = read_ea_list(talloc_tos(), pdata + 4, total_data - 4); if (!ea_list) { reply_nterror(req, NT_STATUS_INVALID_PARAMETER); - return; + goto out; } } /* If total_data == 4 Windows doesn't care what values @@ -7258,19 +7252,19 @@ static void call_trans2mkdir(connection_struct *conn, struct smb_request *req, * The System i QNTC IBM SMB client puts bad values here, * so ignore them. */ - status = create_directory(conn, req, directory); + status = create_directory(conn, req, smb_dname); if (!NT_STATUS_IS_OK(status)) { reply_nterror(req, status); - return; + goto out; } /* Try and set any given EA. */ if (ea_list) { - status = set_ea(conn, NULL, directory, ea_list); + status = set_ea(conn, NULL, smb_dname->base_name, ea_list); if (!NT_STATUS_IS_OK(status)) { reply_nterror(req, status); - return; + goto out; } } @@ -7278,7 +7272,7 @@ static void call_trans2mkdir(connection_struct *conn, struct smb_request *req, *pparams = (char *)SMB_REALLOC(*pparams,2); if(*pparams == NULL) { reply_nterror(req, NT_STATUS_NO_MEMORY); - return; + goto out; } params = *pparams; @@ -7286,6 +7280,8 @@ static void call_trans2mkdir(connection_struct *conn, struct smb_request *req, send_trans2_replies(conn, req, params, 2, *ppdata, 0, max_data_bytes); + out: + TALLOC_FREE(smb_dname); return; } diff --git a/source3/smbd/vfs.c b/source3/smbd/vfs.c index 873e65e4a4..385454e587 100644 --- a/source3/smbd/vfs.c +++ b/source3/smbd/vfs.c @@ -382,18 +382,28 @@ bool vfs_object_exist(connection_struct *conn,const char *fname,SMB_STRUCT_STAT Check if a file exists in the vfs. ********************************************************************/ -bool vfs_file_exist(connection_struct *conn, const char *fname,SMB_STRUCT_STAT *sbuf) +NTSTATUS vfs_file_exist(connection_struct *conn, struct smb_filename *smb_fname) { - SMB_STRUCT_STAT st; + char *fname = NULL; + NTSTATUS status; - if (!sbuf) - sbuf = &st; + status = get_full_smb_filename(talloc_tos(), smb_fname, &fname); + if (!NT_STATUS_IS_OK(status)) { + goto out; + } - ZERO_STRUCTP(sbuf); + status = NT_STATUS_OBJECT_NAME_NOT_FOUND; + if (SMB_VFS_STAT(conn, fname, &smb_fname->st) == -1) { + goto out; + } - if (SMB_VFS_STAT(conn,fname,sbuf) == -1) - return False; - return(S_ISREG(sbuf->st_ex_mode)); + /* Only return OK if stat was successful and S_ISREG */ + if (S_ISREG(smb_fname->st.st_ex_mode)) { + status = NT_STATUS_OK; + } + out: + TALLOC_FREE(fname); + return status; } /**************************************************************************** -- cgit