X-Git-Url: http://git.samba.org/metze/?a=blobdiff_plain;f=source3%2Fsmbd%2Freply.c;h=c07ac336793789ce6ca7b9c81174a04c94566510;hb=b94725cc5027d852ee264cc7d8d5d83c1a49d4b1;hp=095585a276b4a73a211782310f53df4dd7139033;hpb=75d03970b78538346308c612ca6be15559e15b5b;p=metze%2Fsamba%2Fwip.git diff --git a/source3/smbd/reply.c b/source3/smbd/reply.c index 095585a276b4..c07ac3367937 100644 --- a/source3/smbd/reply.c +++ b/source3/smbd/reply.c @@ -703,7 +703,7 @@ void reply_tcon_and_X(struct smb_request *req) /* we might have to close an old one */ if ((tcon_flags & 0x1) && conn) { - close_cnum(conn,req->vuid); + close_cnum(sconn, conn,req->vuid); req->conn = NULL; conn = NULL; } @@ -987,10 +987,15 @@ void reply_checkpath(struct smb_request *req) return; } - status = resolve_dfspath(ctx, conn, - req->flags2 & FLAGS2_DFS_PATHNAMES, - name, - &name); + DEBUG(3,("reply_checkpath %s mode=%d\n", name, (int)SVAL(req->vwv+0, 0))); + + status = filename_convert(ctx, + conn, + req->flags2 & FLAGS2_DFS_PATHNAMES, + name, + &smb_fname, + NULL); + if (!NT_STATUS_IS_OK(status)) { if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) { reply_botherror(req, NT_STATUS_PATH_NOT_COVERED, @@ -1001,27 +1006,10 @@ void reply_checkpath(struct smb_request *req) goto path_err; } - DEBUG(3,("reply_checkpath %s mode=%d\n", name, (int)SVAL(req->vwv+0, 0))); - - status = unix_convert(ctx, conn, name, &smb_fname, 0); - if (!NT_STATUS_IS_OK(status)) { - goto path_err; - } - - status = get_full_smb_filename(ctx, smb_fname, &name); - if (!NT_STATUS_IS_OK(status)) { - goto path_err; - } - - status = check_name(conn, name); - if (!NT_STATUS_IS_OK(status)) { - DEBUG(3,("reply_checkpath: check_name of %s failed (%s)\n",name,nt_errstr(status))); - goto path_err; - } - if (!VALID_STAT(smb_fname->st) && - (SMB_VFS_STAT(conn, name, &smb_fname->st) != 0)) { - DEBUG(3,("reply_checkpath: stat of %s failed (%s)\n",name,strerror(errno))); + (SMB_VFS_STAT(conn, smb_fname) != 0)) { + DEBUG(3,("reply_checkpath: stat of %s failed (%s)\n", + smb_fname_str_dbg(smb_fname), strerror(errno))); status = map_nt_error_from_unix(errno); goto path_err; } @@ -1033,17 +1021,8 @@ void reply_checkpath(struct smb_request *req) } reply_outbuf(req, 0, 0); - out: - TALLOC_FREE(smb_fname); - END_PROFILE(SMBcheckpath); - return; path_err: - - TALLOC_FREE(smb_fname); - - END_PROFILE(SMBcheckpath); - /* We special case this - as when a Windows machine is parsing a path is steps through the components one at a time - if a component fails it expects @@ -1060,10 +1039,15 @@ void reply_checkpath(struct smb_request *req) */ reply_botherror(req, NT_STATUS_OBJECT_NAME_NOT_FOUND, ERRDOS, ERRbadpath); - return; + goto out; } reply_nterror(req, status); + + out: + TALLOC_FREE(smb_fname); + END_PROFILE(SMBcheckpath); + return; } /**************************************************************************** @@ -1091,20 +1075,6 @@ void reply_getatr(struct smb_request *req) goto out; } - status = resolve_dfspath(ctx, conn, - req->flags2 & FLAGS2_DFS_PATHNAMES, - fname, - &fname); - if (!NT_STATUS_IS_OK(status)) { - if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) { - reply_botherror(req, NT_STATUS_PATH_NOT_COVERED, - ERRSRV, ERRbadpath); - goto out; - } - reply_nterror(req, status); - goto out; - } - /* dos smetimes asks for a stat of "" - it returns a "hidden directory" under WfWg - weird! */ if (*fname == '\0') { @@ -1115,25 +1085,26 @@ void reply_getatr(struct smb_request *req) size = 0; mtime = 0; } else { - status = unix_convert(ctx, conn, fname, &smb_fname, 0); - if (!NT_STATUS_IS_OK(status)) { - reply_nterror(req, status); - goto out; - } - status = get_full_smb_filename(ctx, smb_fname, &fname); - if (!NT_STATUS_IS_OK(status)) { - reply_nterror(req, status); - goto out; - } - status = check_name(conn, fname); + status = filename_convert(ctx, + conn, + req->flags2 & FLAGS2_DFS_PATHNAMES, + fname, + &smb_fname, + &fname); if (!NT_STATUS_IS_OK(status)) { - DEBUG(3,("reply_getatr: check_name of %s failed (%s)\n",fname,nt_errstr(status))); + if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) { + reply_botherror(req, NT_STATUS_PATH_NOT_COVERED, + ERRSRV, ERRbadpath); + goto out; + } reply_nterror(req, status); goto out; } if (!VALID_STAT(smb_fname->st) && - (SMB_VFS_STAT(conn, fname, &smb_fname->st) != 0)) { - DEBUG(3,("reply_getatr: stat of %s failed (%s)\n",fname,strerror(errno))); + (SMB_VFS_STAT(conn, smb_fname) != 0)) { + DEBUG(3,("reply_getatr: stat of %s failed (%s)\n", + smb_fname_str_dbg(smb_fname), + strerror(errno))); reply_unixerror(req, ERRDOS,ERRbadfile); goto out; } @@ -1161,10 +1132,12 @@ void reply_getatr(struct smb_request *req) SVAL(req->outbuf, smb_flg2) | FLAGS2_IS_LONG_NAME); } - DEBUG(3,("reply_getatr: name=%s mode=%d size=%u\n", fname, mode, (unsigned int)size ) ); + DEBUG(3,("reply_getatr: name=%s mode=%d size=%u\n", + smb_fname_str_dbg(smb_fname), mode, (unsigned int)size)); out: TALLOC_FREE(smb_fname); + TALLOC_FREE(fname); END_PROFILE(SMBgetatr); return; } @@ -1201,10 +1174,12 @@ void reply_setatr(struct smb_request *req) goto out; } - status = resolve_dfspath(ctx, conn, + status = filename_convert(ctx, + conn, req->flags2 & FLAGS2_DFS_PATHNAMES, fname, - &fname); + &smb_fname, + NULL); if (!NT_STATUS_IS_OK(status)) { if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) { reply_botherror(req, NT_STATUS_PATH_NOT_COVERED, @@ -1215,25 +1190,8 @@ void reply_setatr(struct smb_request *req) goto out; } - status = unix_convert(ctx, conn, fname, &smb_fname, 0); - if (!NT_STATUS_IS_OK(status)) { - reply_nterror(req, status); - goto out; - } - - status = get_full_smb_filename(ctx, smb_fname, &fname); - if (!NT_STATUS_IS_OK(status)) { - reply_nterror(req, status); - goto out; - } - - status = check_name(conn, fname); - if (!NT_STATUS_IS_OK(status)) { - reply_nterror(req, status); - goto out; - } - - if (fname[0] == '.' && fname[1] == '\0') { + if (smb_fname->base_name[0] == '.' && + smb_fname->base_name[1] == '\0') { /* * Not sure here is the right place to catch this * condition. Might be moved to somewhere else later -- vl @@ -1246,8 +1204,7 @@ void reply_setatr(struct smb_request *req) mtime = srv_make_unix_date3(req->vwv+1); ft.mtime = convert_time_t_to_timespec(mtime); - status = smb_set_file_time(conn, NULL, fname, - &smb_fname->st, &ft, true); + status = smb_set_file_time(conn, NULL, smb_fname, &ft, true); if (!NT_STATUS_IS_OK(status)) { reply_unixerror(req, ERRDOS, ERRnoaccess); goto out; @@ -1259,7 +1216,7 @@ void reply_setatr(struct smb_request *req) else mode &= ~aDIR; - if (file_set_dosmode(conn, fname, mode, &smb_fname->st, NULL, + if (file_set_dosmode(conn, smb_fname, mode, NULL, false) != 0) { reply_unixerror(req, ERRDOS, ERRnoaccess); goto out; @@ -1268,7 +1225,8 @@ void reply_setatr(struct smb_request *req) reply_outbuf(req, 0, 0); - DEBUG( 3, ( "setatr name=%s mode=%d\n", fname, mode ) ); + DEBUG(3, ("setatr name=%s mode=%d\n", smb_fname_str_dbg(smb_fname), + mode)); out: TALLOC_FREE(smb_fname); END_PROFILE(SMBsetatr); @@ -1327,6 +1285,38 @@ void reply_dskattr(struct smb_request *req) return; } +/* + * Utility function to split the filename from the directory. + */ +static NTSTATUS split_fname_dir_mask(TALLOC_CTX *ctx, const char *fname_in, + char **fname_dir_out, + char **fname_mask_out) +{ + const char *p = NULL; + char *fname_dir = NULL; + char *fname_mask = NULL; + + p = strrchr_m(fname_in, '/'); + if (!p) { + fname_dir = talloc_strdup(ctx, "."); + fname_mask = talloc_strdup(ctx, fname_in); + } else { + fname_dir = talloc_strndup(ctx, fname_in, + PTR_DIFF(p, fname_in)); + fname_mask = talloc_strdup(ctx, p+1); + } + + if (!fname_dir || !fname_mask) { + TALLOC_FREE(fname_dir); + TALLOC_FREE(fname_mask); + return NT_STATUS_NO_MEMORY; + } + + *fname_dir_out = fname_dir; + *fname_mask_out = fname_mask; + return NT_STATUS_OK; +} + /**************************************************************************** Reply to a search. Can be called from SMBsearch, SMBffirst or SMBfunique. @@ -1335,6 +1325,7 @@ void reply_dskattr(struct smb_request *req) void reply_search(struct smb_request *req) { connection_struct *conn = req->conn; + char *path = NULL; const char *mask = NULL; char *directory = NULL; char *fname = NULL; @@ -1347,7 +1338,6 @@ void reply_search(struct smb_request *req) bool finished = False; const char *p; int status_len; - char *path = NULL; char status[21]; int dptr_num= -1; bool check_descend = False; @@ -1389,23 +1379,6 @@ void reply_search(struct smb_request *req) return; } - nt_status = resolve_dfspath_wcard(ctx, conn, - req->flags2 & FLAGS2_DFS_PATHNAMES, - path, - &path, - &mask_contains_wcard); - if (!NT_STATUS_IS_OK(nt_status)) { - if (NT_STATUS_EQUAL(nt_status,NT_STATUS_PATH_NOT_COVERED)) { - reply_botherror(req, NT_STATUS_PATH_NOT_COVERED, - ERRSRV, ERRbadpath); - END_PROFILE(SMBsearch); - return; - } - reply_nterror(req, nt_status); - END_PROFILE(SMBsearch); - return; - } - p++; status_len = SVAL(p, 0); p += 2; @@ -1415,6 +1388,23 @@ void reply_search(struct smb_request *req) if (status_len == 0) { struct smb_filename *smb_fname = NULL; + nt_status = resolve_dfspath_wcard(ctx, conn, + req->flags2 & FLAGS2_DFS_PATHNAMES, + path, + &path, + &mask_contains_wcard); + if (!NT_STATUS_IS_OK(nt_status)) { + if (NT_STATUS_EQUAL(nt_status,NT_STATUS_PATH_NOT_COVERED)) { + reply_botherror(req, NT_STATUS_PATH_NOT_COVERED, + ERRSRV, ERRbadpath); + END_PROFILE(SMBsearch); + return; + } + reply_nterror(req, nt_status); + END_PROFILE(SMBsearch); + return; + } + nt_status = unix_convert(ctx, conn, path, &smb_fname, UCF_ALLOW_WCARD_LCOMP); if (!NT_STATUS_IS_OK(nt_status)) { @@ -1702,12 +1692,12 @@ void reply_fclose(struct smb_request *req) void reply_open(struct smb_request *req) { connection_struct *conn = req->conn; + struct smb_filename *smb_fname = NULL; char *fname = NULL; uint32 fattr=0; SMB_OFF_T size = 0; time_t mtime=0; int info; - SMB_STRUCT_STAT sbuf; files_struct *fsp; int oplock_request; int deny_mode; @@ -1721,12 +1711,9 @@ void reply_open(struct smb_request *req) START_PROFILE(SMBopen); - SET_STAT_INVALID(sbuf); - if (req->wct < 2) { reply_nterror(req, NT_STATUS_INVALID_PARAMETER); - END_PROFILE(SMBopen); - return; + goto out; } oplock_request = CORE_OPLOCK_REQUEST(req->inbuf); @@ -1737,24 +1724,38 @@ void reply_open(struct smb_request *req) STR_TERMINATE, &status); if (!NT_STATUS_IS_OK(status)) { reply_nterror(req, status); - END_PROFILE(SMBopen); - return; + goto out; + } + + status = filename_convert(ctx, + conn, + req->flags2 & FLAGS2_DFS_PATHNAMES, + fname, + &smb_fname, + &fname); + if (!NT_STATUS_IS_OK(status)) { + if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) { + reply_botherror(req, + NT_STATUS_PATH_NOT_COVERED, + ERRSRV, ERRbadpath); + goto out; + } + reply_nterror(req, status); + goto out; } if (!map_open_params_to_ntcreate( fname, deny_mode, OPENX_FILE_EXISTS_OPEN, &access_mask, &share_mode, &create_disposition, &create_options)) { reply_nterror(req, NT_STATUS_DOS(ERRDOS, ERRbadaccess)); - END_PROFILE(SMBopen); - return; + goto out; } status = SMB_VFS_CREATE_FILE( conn, /* conn */ req, /* req */ 0, /* root_dir_fid */ - fname, /* fname */ - CFF_DOS_PATH, /* create_file_flags */ + smb_fname, /* fname */ access_mask, /* access_mask */ share_mode, /* share_access */ create_disposition, /* create_disposition*/ @@ -1765,30 +1766,26 @@ void reply_open(struct smb_request *req) NULL, /* sd */ NULL, /* ea_list */ &fsp, /* result */ - &info, /* pinfo */ - &sbuf); /* psbuf */ + &info); /* pinfo */ if (!NT_STATUS_IS_OK(status)) { if (open_was_deferred(req->mid)) { /* We have re-scheduled this call. */ - END_PROFILE(SMBopen); - return; + goto out; } reply_openerror(req, status); - END_PROFILE(SMBopen); - return; + goto out; } - size = sbuf.st_ex_size; - fattr = dos_mode(conn,fsp->fsp_name,&sbuf); - mtime = convert_timespec_to_time_t(sbuf.st_ex_mtime); + size = smb_fname->st.st_ex_size; + fattr = dos_mode(conn,fsp->fsp_name,&smb_fname->st); + mtime = convert_timespec_to_time_t(smb_fname->st.st_ex_mtime); if (fattr & aDIR) { DEBUG(3,("attempt to open a directory %s\n",fsp->fsp_name)); close_file(req, fsp, ERROR_CLOSE); reply_doserror(req, ERRDOS,ERRnoaccess); - END_PROFILE(SMBopen); - return; + goto out; } reply_outbuf(req, 7, 0); @@ -1811,6 +1808,8 @@ void reply_open(struct smb_request *req) SCVAL(req->outbuf,smb_flg, CVAL(req->outbuf,smb_flg)|CORE_OPLOCK_GRANTED); } + out: + TALLOC_FREE(smb_fname); END_PROFILE(SMBopen); return; } @@ -1822,6 +1821,7 @@ void reply_open(struct smb_request *req) void reply_open_and_X(struct smb_request *req) { connection_struct *conn = req->conn; + struct smb_filename *smb_fname = NULL; char *fname = NULL; uint16 open_flags; int deny_mode; @@ -1838,7 +1838,6 @@ void reply_open_and_X(struct smb_request *req) int smb_ofun; uint32 fattr=0; int mtime=0; - SMB_STRUCT_STAT sbuf; int smb_action = 0; files_struct *fsp; NTSTATUS status; @@ -1854,12 +1853,9 @@ void reply_open_and_X(struct smb_request *req) if (req->wct < 15) { reply_nterror(req, NT_STATUS_INVALID_PARAMETER); - END_PROFILE(SMBopenX); - return; + goto out; } - SET_STAT_INVALID(sbuf); - open_flags = SVAL(req->vwv+2, 0); deny_mode = SVAL(req->vwv+3, 0); smb_attr = SVAL(req->vwv+5, 0); @@ -1876,8 +1872,7 @@ void reply_open_and_X(struct smb_request *req) } else { reply_doserror(req, ERRSRV, ERRaccess); } - END_PROFILE(SMBopenX); - return; + goto out; } /* XXXX we need to handle passed times, sattr and flags */ @@ -1885,24 +1880,38 @@ void reply_open_and_X(struct smb_request *req) STR_TERMINATE, &status); if (!NT_STATUS_IS_OK(status)) { reply_nterror(req, status); - END_PROFILE(SMBopenX); - return; + goto out; + } + + status = filename_convert(ctx, + conn, + req->flags2 & FLAGS2_DFS_PATHNAMES, + fname, + &smb_fname, + &fname); + if (!NT_STATUS_IS_OK(status)) { + if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) { + reply_botherror(req, + NT_STATUS_PATH_NOT_COVERED, + ERRSRV, ERRbadpath); + goto out; + } + reply_nterror(req, status); + goto out; } if (!map_open_params_to_ntcreate( fname, deny_mode, smb_ofun, &access_mask, &share_mode, &create_disposition, &create_options)) { reply_nterror(req, NT_STATUS_DOS(ERRDOS, ERRbadaccess)); - END_PROFILE(SMBopenX); - return; + goto out; } status = SMB_VFS_CREATE_FILE( conn, /* conn */ req, /* req */ 0, /* root_dir_fid */ - fname, /* fname */ - CFF_DOS_PATH, /* create_file_flags */ + smb_fname, /* fname */ access_mask, /* access_mask */ share_mode, /* share_access */ create_disposition, /* create_disposition*/ @@ -1913,17 +1922,15 @@ void reply_open_and_X(struct smb_request *req) NULL, /* sd */ NULL, /* ea_list */ &fsp, /* result */ - &smb_action, /* pinfo */ - &sbuf); /* psbuf */ + &smb_action); /* pinfo */ if (!NT_STATUS_IS_OK(status)) { - END_PROFILE(SMBopenX); if (open_was_deferred(req->mid)) { /* We have re-scheduled this call. */ - return; + goto out; } reply_openerror(req, status); - return; + goto out; } /* Setting the "size" field in vwv9 and vwv10 causes the file to be set to this size, @@ -1933,26 +1940,24 @@ void reply_open_and_X(struct smb_request *req) if (vfs_allocate_file_space(fsp, fsp->initial_allocation_size) == -1) { close_file(req, fsp, ERROR_CLOSE); reply_nterror(req, NT_STATUS_DISK_FULL); - END_PROFILE(SMBopenX); - return; + goto out; } retval = vfs_set_filelen(fsp, (SMB_OFF_T)allocation_size); if (retval < 0) { close_file(req, fsp, ERROR_CLOSE); reply_nterror(req, NT_STATUS_DISK_FULL); - END_PROFILE(SMBopenX); - return; + goto out; } - sbuf.st_ex_size = SMB_VFS_GET_ALLOC_SIZE(conn,fsp,&sbuf); + smb_fname->st.st_ex_size = + SMB_VFS_GET_ALLOC_SIZE(conn, fsp, &smb_fname->st); } - fattr = dos_mode(conn,fsp->fsp_name,&sbuf); - mtime = convert_timespec_to_time_t(sbuf.st_ex_mtime); + fattr = dos_mode(conn,fsp->fsp_name,&smb_fname->st); + mtime = convert_timespec_to_time_t(smb_fname->st.st_ex_mtime); if (fattr & aDIR) { close_file(req, fsp, ERROR_CLOSE); reply_doserror(req, ERRDOS, ERRnoaccess); - END_PROFILE(SMBopenX); - return; + goto out; } /* If the caller set the extended oplock request bit @@ -1996,7 +2001,7 @@ void reply_open_and_X(struct smb_request *req) } else { srv_put_dos_date3((char *)req->outbuf,smb_vwv4,mtime); } - SIVAL(req->outbuf,smb_vwv6,(uint32)sbuf.st_ex_size); + SIVAL(req->outbuf,smb_vwv6,(uint32)smb_fname->st.st_ex_size); SSVAL(req->outbuf,smb_vwv8,GET_OPENX_MODE(deny_mode)); SSVAL(req->outbuf,smb_vwv11,smb_action); @@ -2004,8 +2009,10 @@ void reply_open_and_X(struct smb_request *req) SIVAL(req->outbuf, smb_vwv15, STD_RIGHT_ALL_ACCESS); } - END_PROFILE(SMBopenX); chain_reply(req); + out: + TALLOC_FREE(smb_fname); + END_PROFILE(SMBopenX); return; } @@ -2050,12 +2057,12 @@ void reply_ulogoffX(struct smb_request *req) void reply_mknew(struct smb_request *req) { connection_struct *conn = req->conn; + struct smb_filename *smb_fname = NULL; char *fname = NULL; uint32 fattr = 0; struct smb_file_time ft; files_struct *fsp; int oplock_request = 0; - SMB_STRUCT_STAT sbuf; NTSTATUS status; uint32 access_mask = FILE_GENERIC_READ | FILE_GENERIC_WRITE; uint32 share_mode = FILE_SHARE_READ|FILE_SHARE_WRITE; @@ -2065,12 +2072,10 @@ void reply_mknew(struct smb_request *req) START_PROFILE(SMBcreate); ZERO_STRUCT(ft); - SET_STAT_INVALID(sbuf); if (req->wct < 3) { reply_nterror(req, NT_STATUS_INVALID_PARAMETER); - END_PROFILE(SMBcreate); - return; + goto out; } fattr = SVAL(req->vwv+0, 0); @@ -2083,13 +2088,30 @@ void reply_mknew(struct smb_request *req) STR_TERMINATE, &status); if (!NT_STATUS_IS_OK(status)) { reply_nterror(req, status); - END_PROFILE(SMBcreate); - return; + goto out; + } + + status = filename_convert(ctx, + conn, + req->flags2 & FLAGS2_DFS_PATHNAMES, + fname, + &smb_fname, + NULL); + if (!NT_STATUS_IS_OK(status)) { + if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) { + reply_botherror(req, + NT_STATUS_PATH_NOT_COVERED, + ERRSRV, ERRbadpath); + goto out; + } + reply_nterror(req, status); + goto out; } if (fattr & aVOLID) { DEBUG(0,("Attempt to create file (%s) with volid set - " - "please report this\n", fname)); + "please report this\n", + smb_fname_str_dbg(smb_fname))); } if(req->cmd == SMBmknew) { @@ -2104,8 +2126,7 @@ void reply_mknew(struct smb_request *req) conn, /* conn */ req, /* req */ 0, /* root_dir_fid */ - fname, /* fname */ - CFF_DOS_PATH, /* create_file_flags */ + smb_fname, /* fname */ access_mask, /* access_mask */ share_mode, /* share_access */ create_disposition, /* create_disposition*/ @@ -2116,25 +2137,22 @@ void reply_mknew(struct smb_request *req) NULL, /* sd */ NULL, /* ea_list */ &fsp, /* result */ - NULL, /* pinfo */ - &sbuf); /* psbuf */ + NULL); /* pinfo */ if (!NT_STATUS_IS_OK(status)) { - END_PROFILE(SMBcreate); if (open_was_deferred(req->mid)) { /* We have re-scheduled this call. */ - return; + goto out; } reply_openerror(req, status); - return; + goto out; } - ft.atime = sbuf.st_ex_atime; /* atime. */ - status = smb_set_file_time(conn, fsp, fsp->fsp_name, &sbuf, &ft, true); + ft.atime = smb_fname->st.st_ex_atime; /* atime. */ + status = smb_set_file_time(conn, fsp, smb_fname, &ft, true); if (!NT_STATUS_IS_OK(status)) { END_PROFILE(SMBcreate); - reply_openerror(req, status); - return; + goto out; } reply_outbuf(req, 1, 0); @@ -2150,10 +2168,13 @@ void reply_mknew(struct smb_request *req) CVAL(req->outbuf,smb_flg)|CORE_OPLOCK_GRANTED); } - DEBUG( 2, ( "reply_mknew: file %s\n", fsp->fsp_name ) ); - DEBUG( 3, ( "reply_mknew %s fd=%d dmode=0x%x\n", - fsp->fsp_name, fsp->fh->fd, (unsigned int)fattr ) ); + DEBUG(2, ("reply_mknew: file %s\n", smb_fname_str_dbg(smb_fname))); + DEBUG(3, ("reply_mknew %s fd=%d dmode=0x%x\n", + smb_fname_str_dbg(smb_fname), fsp->fh->fd, + (unsigned int)fattr)); + out: + TALLOC_FREE(smb_fname); END_PROFILE(SMBcreate); return; } @@ -2204,10 +2225,11 @@ void reply_ctemp(struct smb_request *req) goto out; } - status = resolve_dfspath(ctx, conn, + status = filename_convert(ctx, conn, req->flags2 & FLAGS2_DFS_PATHNAMES, fname, - &fname); + &smb_fname, + NULL); if (!NT_STATUS_IS_OK(status)) { if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) { reply_botherror(req, NT_STATUS_PATH_NOT_COVERED, @@ -2218,40 +2240,20 @@ void reply_ctemp(struct smb_request *req) goto out; } - status = unix_convert(ctx, conn, fname, &smb_fname, 0); - if (!NT_STATUS_IS_OK(status)) { - reply_nterror(req, status); - goto out; - } - - status = get_full_smb_filename(ctx, smb_fname, &fname); - if (!NT_STATUS_IS_OK(status)) { - reply_nterror(req, status); - goto out; - } - - status = check_name(conn, fname); - if (!NT_STATUS_IS_OK(status)) { - reply_nterror(req, status); - goto out; - } - - tmpfd = mkstemp(fname); + tmpfd = mkstemp(smb_fname->base_name); if (tmpfd == -1) { reply_unixerror(req, ERRDOS, ERRnoaccess); goto out; } - SET_STAT_INVALID(smb_fname->st); - SMB_VFS_STAT(conn, fname, &smb_fname->st); + SMB_VFS_STAT(conn, smb_fname); /* We should fail if file does not exist. */ status = SMB_VFS_CREATE_FILE( conn, /* conn */ req, /* req */ 0, /* root_dir_fid */ - fname, /* fname */ - 0, /* create_file_flags */ + smb_fname, /* fname */ FILE_GENERIC_READ | FILE_GENERIC_WRITE, /* access_mask */ FILE_SHARE_READ | FILE_SHARE_WRITE, /* share_access */ FILE_OPEN, /* create_disposition*/ @@ -2262,8 +2264,7 @@ void reply_ctemp(struct smb_request *req) NULL, /* sd */ NULL, /* ea_list */ &fsp, /* result */ - NULL, /* pinfo */ - &smb_fname->st); /* psbuf */ + NULL); /* pinfo */ /* close fd from mkstemp() */ close(tmpfd); @@ -2363,10 +2364,10 @@ static NTSTATUS can_rename(connection_struct *conn, files_struct *fsp, static NTSTATUS do_unlink(connection_struct *conn, struct smb_request *req, - const char *fname, + struct smb_filename *smb_fname, uint32 dirtype) { - SMB_STRUCT_STAT sbuf; + char *fname = NULL; uint32 fattr; files_struct *fsp; uint32 dirtype_orig = dirtype; @@ -2378,11 +2379,16 @@ static NTSTATUS do_unlink(connection_struct *conn, return NT_STATUS_MEDIA_WRITE_PROTECTED; } - if (SMB_VFS_LSTAT(conn,fname,&sbuf) != 0) { + if (SMB_VFS_LSTAT(conn, smb_fname) != 0) { return map_nt_error_from_unix(errno); } - fattr = dos_mode(conn,fname,&sbuf); + status = get_full_smb_filename(smb_fname, smb_fname, &fname); + if (!NT_STATUS_IS_OK(status)) { + return status; + } + fattr = dos_mode(conn, fname, &smb_fname->st); + TALLOC_FREE(fname); if (dirtype & FILE_ATTRIBUTE_NORMAL) { dirtype = aDIR|aARCH|aRONLY; @@ -2460,8 +2466,7 @@ static NTSTATUS do_unlink(connection_struct *conn, (conn, /* conn */ req, /* req */ 0, /* root_dir_fid */ - fname, /* fname */ - 0, /* create_file_flags */ + smb_fname, /* fname */ DELETE_ACCESS, /* access_mask */ FILE_SHARE_NONE, /* share_access */ FILE_OPEN, /* create_disposition*/ @@ -2472,8 +2477,7 @@ static NTSTATUS do_unlink(connection_struct *conn, NULL, /* sd */ NULL, /* ea_list */ &fsp, /* result */ - NULL, /* pinfo */ - &sbuf); /* psbuf */ + NULL); /* pinfo */ if (!NT_STATUS_IS_OK(status)) { DEBUG(10, ("SMB_VFS_CREATEFILE failed: %s\n", @@ -2499,39 +2503,23 @@ NTSTATUS unlink_internals(connection_struct *conn, struct smb_request *req, uint32 dirtype, const char *name_in, bool has_wild) { struct smb_filename *smb_fname = NULL; - const char *directory = NULL; - char *mask = NULL; - char *name = NULL; - char *p = NULL; + char *fname_dir = NULL; + char *fname_mask = NULL; int count=0; NTSTATUS status = NT_STATUS_OK; - SMB_STRUCT_STAT st; TALLOC_CTX *ctx = talloc_tos(); status = unix_convert(ctx, conn, name_in, &smb_fname, has_wild ? UCF_ALLOW_WCARD_LCOMP : 0); if (!NT_STATUS_IS_OK(status)) { - return status; + goto out; } - status = get_full_smb_filename(ctx, smb_fname, &name); + /* Split up the directory from the filename/mask. */ + status = split_fname_dir_mask(ctx, smb_fname->base_name, + &fname_dir, &fname_mask); if (!NT_STATUS_IS_OK(status)) { - TALLOC_FREE(smb_fname); - return status; - } - - p = strrchr_m(name,'/'); - if (!p) { - directory = talloc_strdup(ctx, "."); - if (!directory) { - TALLOC_FREE(smb_fname); - return NT_STATUS_NO_MEMORY; - } - mask = name; - } else { - *p = 0; - directory = name; - mask = p+1; + goto out; } /* @@ -2543,38 +2531,44 @@ NTSTATUS unlink_internals(connection_struct *conn, struct smb_request *req, * Tine Smukavec . */ - if (!VALID_STAT(smb_fname->st) && mangle_is_mangled(mask,conn->params)) { + if (!VALID_STAT(smb_fname->st) && + mangle_is_mangled(fname_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_mask, + &new_mask, conn->params); if (new_mask) { - mask = new_mask; + TALLOC_FREE(fname_mask); + fname_mask = new_mask; } } - TALLOC_FREE(smb_fname); if (!has_wild) { - directory = talloc_asprintf(ctx, - "%s/%s", - directory, - mask); - if (!directory) { - return NT_STATUS_NO_MEMORY; + + /* + * Only one file needs to be unlinked. Append the mask back + * onto the directory. + */ + TALLOC_FREE(smb_fname->base_name); + smb_fname->base_name = talloc_asprintf(smb_fname, + "%s/%s", + fname_dir, + fname_mask); + if (!smb_fname->base_name) { + status = NT_STATUS_NO_MEMORY; + goto out; } if (dirtype == 0) { dirtype = FILE_ATTRIBUTE_NORMAL; } - status = check_name(conn, directory); + status = check_name(conn, smb_fname->base_name); if (!NT_STATUS_IS_OK(status)) { - return status; + goto out; } - status = do_unlink(conn, req, directory, dirtype); + status = do_unlink(conn, req, smb_fname, dirtype); if (!NT_STATUS_IS_OK(status)) { - return status; + goto out; } count++; @@ -2584,23 +2578,29 @@ NTSTATUS unlink_internals(connection_struct *conn, struct smb_request *req, const char *dname; if ((dirtype & SAMBA_ATTRIBUTES_MASK) == aDIR) { - return NT_STATUS_OBJECT_NAME_INVALID; + status = NT_STATUS_OBJECT_NAME_INVALID; + goto out; } - if (strequal(mask,"????????.???")) { - mask[0] = '*'; - mask[1] = '\0'; + if (strequal(fname_mask,"????????.???")) { + TALLOC_FREE(fname_mask); + fname_mask = talloc_strdup(ctx, "*"); + if (!fname_mask) { + status = NT_STATUS_NO_MEMORY; + goto out; + } } - status = check_name(conn, directory); + status = check_name(conn, fname_dir); if (!NT_STATUS_IS_OK(status)) { - return status; + goto out; } - dir_hnd = OpenDir(talloc_tos(), conn, directory, mask, + dir_hnd = OpenDir(talloc_tos(), conn, fname_dir, fname_mask, dirtype); if (dir_hnd == NULL) { - return map_nt_error_from_unix(errno); + status = map_nt_error_from_unix(errno); + goto out; } /* XXXX the CIFS spec says that if bit0 of the flags2 field is set then @@ -2610,12 +2610,10 @@ NTSTATUS unlink_internals(connection_struct *conn, struct smb_request *req, status = NT_STATUS_NO_SUCH_FILE; - while ((dname = ReadDirName(dir_hnd, &offset, &st))) { - char *fname = NULL; - - if (!is_visible_file(conn, directory, dname, &st, - true)) - { + while ((dname = ReadDirName(dir_hnd, &offset, + &smb_fname->st))) { + if (!is_visible_file(conn, fname_dir, dname, + &smb_fname->st, true)) { continue; } @@ -2624,34 +2622,36 @@ NTSTATUS unlink_internals(connection_struct *conn, struct smb_request *req, continue; } - if(!mask_match(dname, mask, conn->case_sensitive)) { + if(!mask_match(dname, fname_mask, + conn->case_sensitive)) { continue; } - fname = talloc_asprintf(ctx, "%s/%s", - directory, - dname); - if (!fname) { - return NT_STATUS_NO_MEMORY; + TALLOC_FREE(smb_fname->base_name); + smb_fname->base_name = + talloc_asprintf(smb_fname, "%s/%s", + fname_dir, dname); + + if (!smb_fname->base_name) { + TALLOC_FREE(dir_hnd); + status = NT_STATUS_NO_MEMORY; + goto out; } - status = check_name(conn, fname); + status = check_name(conn, smb_fname->base_name); if (!NT_STATUS_IS_OK(status)) { TALLOC_FREE(dir_hnd); - return status; + goto out; } - status = do_unlink(conn, req, fname, dirtype); + status = do_unlink(conn, req, smb_fname, dirtype); if (!NT_STATUS_IS_OK(status)) { - TALLOC_FREE(fname); continue; } count++; DEBUG(3,("unlink_internals: successful unlink [%s]\n", - fname)); - - TALLOC_FREE(fname); + smb_fname->base_name)); } TALLOC_FREE(dir_hnd); } @@ -2660,6 +2660,10 @@ NTSTATUS unlink_internals(connection_struct *conn, struct smb_request *req, status = map_nt_error_from_unix(errno); } + out: + TALLOC_FREE(smb_fname); + TALLOC_FREE(fname_dir); + TALLOC_FREE(fname_mask); return status; } @@ -4140,6 +4144,7 @@ bool is_valid_writeX_buffer(const uint8_t *inbuf) connection_struct *conn = NULL; unsigned int doff = 0; size_t len = smb_len_large(inbuf); + struct smbd_server_connection *sconn = smbd_server_conn; if (is_encrypted_packet(inbuf)) { /* Can't do this on encrypted @@ -4158,7 +4163,7 @@ bool is_valid_writeX_buffer(const uint8_t *inbuf) return false; } - conn = conn_find(SVAL(inbuf, smb_tid)); + conn = conn_find(sconn, SVAL(inbuf, smb_tid)); if (conn == NULL) { DEBUG(10,("is_valid_writeX_buffer: bad tid\n")); return false; @@ -4829,6 +4834,7 @@ void reply_unlock(struct smb_request *req) void reply_tdis(struct smb_request *req) { + struct smbd_server_connection *sconn = smbd_server_conn; connection_struct *conn = req->conn; START_PROFILE(SMBtdis); @@ -4841,7 +4847,7 @@ void reply_tdis(struct smb_request *req) conn->used = False; - close_cnum(conn,req->vuid); + close_cnum(sconn, conn,req->vuid); req->conn = NULL; reply_outbuf(req, 0, 0); @@ -4951,6 +4957,7 @@ void reply_printopen(struct smb_request *req) status = print_fsp_open(req, conn, NULL, req->vuid, fsp, &sbuf); if (!NT_STATUS_IS_OK(status)) { + file_free(req, fsp); reply_nterror(req, status); END_PROFILE(SMBsplopen); return; @@ -5188,10 +5195,11 @@ void reply_mkdir(struct smb_request *req) goto out; } - status = resolve_dfspath(ctx, conn, + status = filename_convert(ctx, conn, req->flags2 & FLAGS2_DFS_PATHNAMES, directory, - &directory); + &smb_dname, + NULL); if (!NT_STATUS_IS_OK(status)) { if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) { reply_botherror(req, NT_STATUS_PATH_NOT_COVERED, @@ -5202,25 +5210,7 @@ void reply_mkdir(struct smb_request *req) goto out; } - status = unix_convert(ctx, conn, directory, &smb_dname, 0); - if (!NT_STATUS_IS_OK(status)) { - reply_nterror(req, status); - 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); - 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))); @@ -5243,7 +5233,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); @@ -5257,59 +5247,78 @@ void reply_mkdir(struct smb_request *req) static bool recursive_rmdir(TALLOC_CTX *ctx, connection_struct *conn, - char *directory) + struct smb_filename *smb_dname) { const char *dname = NULL; bool ret = True; long offset = 0; SMB_STRUCT_STAT st; - struct smb_Dir *dir_hnd = OpenDir(talloc_tos(), conn, directory, - NULL, 0); + struct smb_Dir *dir_hnd; + SMB_ASSERT(!is_ntfs_stream_smb_fname(smb_dname)); + + dir_hnd = OpenDir(talloc_tos(), conn, smb_dname->base_name, NULL, 0); if(dir_hnd == NULL) return False; while((dname = ReadDirName(dir_hnd, &offset, &st))) { + struct smb_filename *smb_dname_full = NULL; char *fullname = NULL; + bool do_break = true; + NTSTATUS status; if (ISDOT(dname) || ISDOTDOT(dname)) { continue; } - if (!is_visible_file(conn, directory, dname, &st, False)) { + if (!is_visible_file(conn, smb_dname->base_name, dname, &st, + false)) { continue; } /* Construct the full name. */ fullname = talloc_asprintf(ctx, "%s/%s", - directory, + smb_dname->base_name, dname); if (!fullname) { errno = ENOMEM; - ret = False; - break; + goto err_break; } - if(SMB_VFS_LSTAT(conn,fullname, &st) != 0) { - ret = False; - break; + status = create_synthetic_smb_fname(talloc_tos(), fullname, + NULL, NULL, + &smb_dname_full); + if (!NT_STATUS_IS_OK(status)) { + goto err_break; } - if(st.st_ex_mode & S_IFDIR) { - if(!recursive_rmdir(ctx, conn, fullname)) { - ret = False; - break; + if(SMB_VFS_LSTAT(conn, smb_dname_full) != 0) { + goto err_break; + } + + if(smb_dname_full->st.st_ex_mode & S_IFDIR) { + if(!recursive_rmdir(ctx, conn, smb_dname_full)) { + goto err_break; } - if(SMB_VFS_RMDIR(conn,fullname) != 0) { - ret = False; - break; + if(SMB_VFS_RMDIR(conn, + smb_dname_full->base_name) != 0) { + goto err_break; } - } else if(SMB_VFS_UNLINK(conn,fullname) != 0) { - ret = False; + } else if(SMB_VFS_UNLINK(conn, smb_dname_full) != 0) { + goto err_break; + } + + /* Successful iteration. */ + do_break = false; + + err_break: + TALLOC_FREE(smb_dname_full); + TALLOC_FREE(fullname); + if (do_break) { + ret = false; break; } - TALLOC_FREE(fullname); } TALLOC_FREE(dir_hnd); return ret; @@ -5320,33 +5329,35 @@ static bool recursive_rmdir(TALLOC_CTX *ctx, ****************************************************************************/ NTSTATUS rmdir_internals(TALLOC_CTX *ctx, - connection_struct *conn, - const char *directory) + connection_struct *conn, + struct smb_filename *smb_dname) { int ret; SMB_STRUCT_STAT st; + SMB_ASSERT(!is_ntfs_stream_smb_fname(smb_dname)); + /* Might be a symlink. */ - if(SMB_VFS_LSTAT(conn, directory, &st) != 0) { + if(SMB_VFS_LSTAT(conn, smb_dname) != 0) { return map_nt_error_from_unix(errno); } - if (S_ISLNK(st.st_ex_mode)) { + if (S_ISLNK(smb_dname->st.st_ex_mode)) { /* Is what it points to a directory ? */ - if(SMB_VFS_STAT(conn, directory, &st) != 0) { + if(SMB_VFS_STAT(conn, smb_dname) != 0) { return map_nt_error_from_unix(errno); } - if (!(S_ISDIR(st.st_ex_mode))) { + if (!(S_ISDIR(smb_dname->st.st_ex_mode))) { return NT_STATUS_NOT_A_DIRECTORY; } - ret = SMB_VFS_UNLINK(conn,directory); + ret = SMB_VFS_UNLINK(conn, smb_dname); } else { - ret = SMB_VFS_RMDIR(conn,directory); + ret = SMB_VFS_RMDIR(conn, smb_dname->base_name); } if (ret == 0) { notify_fname(conn, NOTIFY_ACTION_REMOVED, FILE_NOTIFY_CHANGE_DIR_NAME, - directory); + smb_dname->base_name); return NT_STATUS_OK; } @@ -5360,7 +5371,8 @@ NTSTATUS rmdir_internals(TALLOC_CTX *ctx, const char *dname; long dirpos = 0; struct smb_Dir *dir_hnd = OpenDir(talloc_tos(), conn, - directory, NULL, 0); + smb_dname->base_name, NULL, + 0); if(dir_hnd == NULL) { errno = ENOTEMPTY; @@ -5370,7 +5382,8 @@ NTSTATUS rmdir_internals(TALLOC_CTX *ctx, while ((dname = ReadDirName(dir_hnd, &dirpos, &st))) { if((strcmp(dname, ".") == 0) || (strcmp(dname, "..")==0)) continue; - if (!is_visible_file(conn, directory, dname, &st, False)) + if (!is_visible_file(conn, smb_dname->base_name, dname, + &st, false)) continue; if(!IS_VETO_PATH(conn, dname)) { TALLOC_FREE(dir_hnd); @@ -5391,56 +5404,80 @@ NTSTATUS rmdir_internals(TALLOC_CTX *ctx, /* Do a recursive delete. */ RewindDir(dir_hnd,&dirpos); while ((dname = ReadDirName(dir_hnd, &dirpos, &st))) { + struct smb_filename *smb_dname_full = NULL; char *fullname = NULL; + bool do_break = true; + NTSTATUS status; if (ISDOT(dname) || ISDOTDOT(dname)) { continue; } - if (!is_visible_file(conn, directory, dname, &st, False)) { + if (!is_visible_file(conn, smb_dname->base_name, dname, + &st, false)) { continue; } fullname = talloc_asprintf(ctx, "%s/%s", - directory, + smb_dname->base_name, dname); if(!fullname) { errno = ENOMEM; - break; + goto err_break; } - if(SMB_VFS_LSTAT(conn,fullname, &st) != 0) { - break; + status = create_synthetic_smb_fname(talloc_tos(), + fullname, NULL, + NULL, + &smb_dname_full); + if (!NT_STATUS_IS_OK(status)) { + errno = map_errno_from_nt_status(status); + goto err_break; } - if(st.st_ex_mode & S_IFDIR) { - if(!recursive_rmdir(ctx, conn, fullname)) { - break; + + if(SMB_VFS_LSTAT(conn, smb_dname_full) != 0) { + goto err_break; + } + if(smb_dname_full->st.st_ex_mode & S_IFDIR) { + if(!recursive_rmdir(ctx, conn, + smb_dname_full)) { + goto err_break; } - if(SMB_VFS_RMDIR(conn,fullname) != 0) { - break; + if(SMB_VFS_RMDIR(conn, + smb_dname_full->base_name) != 0) { + goto err_break; } - } else if(SMB_VFS_UNLINK(conn,fullname) != 0) { - break; + } else if(SMB_VFS_UNLINK(conn, smb_dname_full) != 0) { + goto err_break; } + + /* Successful iteration. */ + do_break = false; + + err_break: TALLOC_FREE(fullname); + TALLOC_FREE(smb_dname_full); + if (do_break) + break; } TALLOC_FREE(dir_hnd); /* Retry the rmdir */ - ret = SMB_VFS_RMDIR(conn,directory); + ret = SMB_VFS_RMDIR(conn, smb_dname->base_name); } err: if (ret != 0) { DEBUG(3,("rmdir_internals: couldn't remove directory %s : " - "%s\n", directory,strerror(errno))); + "%s\n", smb_fname_str_dbg(smb_dname), + strerror(errno))); return map_nt_error_from_unix(errno); } notify_fname(conn, NOTIFY_ACTION_REMOVED, FILE_NOTIFY_CHANGE_DIR_NAME, - directory); + smb_dname->base_name); return NT_STATUS_OK; } @@ -5466,9 +5503,10 @@ void reply_rmdir(struct smb_request *req) goto out; } - status = resolve_dfspath(ctx, conn, + status = filename_convert(ctx, conn, req->flags2 & FLAGS2_DFS_PATHNAMES, directory, + &smb_dname, &directory); if (!NT_STATUS_IS_OK(status)) { if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) { @@ -5480,26 +5518,8 @@ void reply_rmdir(struct smb_request *req) goto out; } - status = unix_convert(ctx, conn, directory, &smb_dname, 0); - if (!NT_STATUS_IS_OK(status)) { - reply_nterror(req, status); - 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); - if (!NT_STATUS_IS_OK(status)) { - reply_nterror(req, status); - goto out; - } - dptr_closepath(directory, req->smbpid); - status = rmdir_internals(ctx, conn, directory); + status = rmdir_internals(ctx, conn, smb_dname); if (!NT_STATUS_IS_OK(status)) { reply_nterror(req, status); goto out; @@ -5648,10 +5668,18 @@ static bool resolve_wildcards(TALLOC_CTX *ctx, static void rename_open_files(connection_struct *conn, struct share_mode_lock *lck, - const char *newname) + const struct smb_filename *smb_fname_dst) { files_struct *fsp; bool did_rename = False; + char *fname_dst = NULL; + NTSTATUS status; + + status = get_full_smb_filename(talloc_tos(), smb_fname_dst, + &fname_dst); + if (!NT_STATUS_IS_OK(status)) { + return; + } for(fsp = file_find_di_first(lck->id); fsp; fsp = file_find_di_next(fsp)) { @@ -5662,21 +5690,24 @@ static void rename_open_files(connection_struct *conn, if (!strequal(fsp->conn->connectpath, conn->connectpath)) { continue; } - DEBUG(10,("rename_open_files: renaming file fnum %d (file_id %s) from %s -> %s\n", - fsp->fnum, file_id_string_tos(&fsp->file_id), - fsp->fsp_name, newname )); - string_set(&fsp->fsp_name, newname); + DEBUG(10, ("rename_open_files: renaming file fnum %d " + "(file_id %s) from %s -> %s\n", fsp->fnum, + file_id_string_tos(&fsp->file_id), fsp->fsp_name, + smb_fname_str_dbg(smb_fname_dst))); + string_set(&fsp->fsp_name, fname_dst); did_rename = True; } if (!did_rename) { - DEBUG(10,("rename_open_files: no open files on file_id %s for %s\n", - file_id_string_tos(&lck->id), newname )); + DEBUG(10, ("rename_open_files: no open files on file_id %s " + "for %s\n", file_id_string_tos(&lck->id), + smb_fname_str_dbg(smb_fname_dst))); } /* Send messages to all smbd's (not ourself) that the name has changed. */ rename_share_filename(smbd_messaging_context(), lck, conn->connectpath, - newname); + fname_dst); + TALLOC_FREE(fname_dst); } /**************************************************************************** @@ -5690,10 +5721,11 @@ static void rename_open_files(connection_struct *conn, report from . ****************************************************************************/ -static bool rename_path_prefix_equal(const char *src, const char *dest) +static bool rename_path_prefix_equal(const struct smb_filename *smb_fname_src, + const struct smb_filename *smb_fname_dst) { - const char *psrc = src; - const char *pdst = dest; + const char *psrc = smb_fname_src->base_name; + const char *pdst = smb_fname_dst->base_name; size_t slen; if (psrc[0] == '.' && psrc[1] == '/') { @@ -5713,31 +5745,45 @@ static bool rename_path_prefix_equal(const char *src, const char *dest) */ static void notify_rename(connection_struct *conn, bool is_dir, - const char *oldpath, const char *newpath) + const struct smb_filename *smb_fname_src, + const struct smb_filename *smb_fname_dst) { - char *olddir, *newdir; - const char *oldname, *newname; + char *parent_dir_src = NULL; + char *parent_dir_dst = NULL; + char *fname_src = NULL; + char *fname_dst = NULL; + NTSTATUS status; uint32 mask; mask = is_dir ? FILE_NOTIFY_CHANGE_DIR_NAME : FILE_NOTIFY_CHANGE_FILE_NAME; - if (!parent_dirname(talloc_tos(), oldpath, &olddir, &oldname) - || !parent_dirname(talloc_tos(), newpath, &newdir, &newname)) { - TALLOC_FREE(olddir); - return; + if (!parent_dirname(talloc_tos(), smb_fname_src->base_name, + &parent_dir_src, NULL) || + !parent_dirname(talloc_tos(), smb_fname_dst->base_name, + &parent_dir_dst, NULL)) { + goto out; + } + + status = get_full_smb_filename(talloc_tos(), smb_fname_src, + &fname_src); + if (!NT_STATUS_IS_OK(status)) { + goto out; + } + status = get_full_smb_filename(talloc_tos(), smb_fname_dst, + &fname_dst); + if (!NT_STATUS_IS_OK(status)) { + goto out; } - if (strcmp(olddir, newdir) == 0) { - notify_fname(conn, NOTIFY_ACTION_OLD_NAME, mask, oldpath); - notify_fname(conn, NOTIFY_ACTION_NEW_NAME, mask, newpath); + if (strcmp(parent_dir_src, parent_dir_dst) == 0) { + notify_fname(conn, NOTIFY_ACTION_OLD_NAME, mask, fname_src); + notify_fname(conn, NOTIFY_ACTION_NEW_NAME, mask, fname_dst); } else { - notify_fname(conn, NOTIFY_ACTION_REMOVED, mask, oldpath); - notify_fname(conn, NOTIFY_ACTION_ADDED, mask, newpath); + notify_fname(conn, NOTIFY_ACTION_REMOVED, mask, fname_src); + notify_fname(conn, NOTIFY_ACTION_ADDED, mask, fname_dst); } - TALLOC_FREE(olddir); - TALLOC_FREE(newdir); /* this is a strange one. w2k3 gives an additional event for CHANGE_ATTRIBUTES and CHANGE_CREATION on the new file when renaming @@ -5746,8 +5792,13 @@ static void notify_rename(connection_struct *conn, bool is_dir, notify_fname(conn, NOTIFY_ACTION_MODIFIED, FILE_NOTIFY_CHANGE_ATTRIBUTES |FILE_NOTIFY_CHANGE_CREATION, - newpath); + fname_dst); } + out: + TALLOC_FREE(parent_dir_src); + TALLOC_FREE(parent_dir_dst); + TALLOC_FREE(fname_src); + TALLOC_FREE(fname_dst); } /**************************************************************************** @@ -5756,32 +5807,52 @@ static void notify_rename(connection_struct *conn, bool is_dir, NTSTATUS rename_internals_fsp(connection_struct *conn, files_struct *fsp, - char *newname, - const char *newname_last_component, + const struct smb_filename *smb_fname_dst_in, uint32 attrs, bool replace_if_exists) { TALLOC_CTX *ctx = talloc_tos(); - SMB_STRUCT_STAT sbuf, sbuf1; + struct smb_filename *smb_fname_src = NULL; + struct smb_filename *smb_fname_dst = NULL; + SMB_STRUCT_STAT sbuf; NTSTATUS status = NT_STATUS_OK; struct share_mode_lock *lck = NULL; bool dst_exists, old_is_stream, new_is_stream; ZERO_STRUCT(sbuf); - status = check_name(conn, newname); + status = check_name(conn, smb_fname_dst_in->base_name); if (!NT_STATUS_IS_OK(status)) { return status; } - /* Ensure newname contains a '/' */ - if(strrchr_m(newname,'/') == 0) { - newname = talloc_asprintf(ctx, - "./%s", - newname); - if (!newname) { - return NT_STATUS_NO_MEMORY; + /* Make a copy of the src and dst smb_fname structs */ + status = copy_smb_filename(ctx, smb_fname_dst_in, &smb_fname_dst); + if (!NT_STATUS_IS_OK(status)) { + goto out; + } + + /* + * This will be replaced with copy_smb_filename() when fsp->fsp_name + * is converted to store an smb_filename struct. + */ + status = create_synthetic_smb_fname_split(ctx, fsp->fsp_name, NULL, + &smb_fname_src); + if (!NT_STATUS_IS_OK(status)) { + goto out; + } + + /* Ensure the dst smb_fname contains a '/' */ + if(strrchr_m(smb_fname_dst->base_name,'/') == 0) { + char * tmp; + tmp = talloc_asprintf(smb_fname_dst, "./%s", + smb_fname_dst->base_name); + if (!tmp) { + status = NT_STATUS_NO_MEMORY; + goto out; } + TALLOC_FREE(smb_fname_dst->base_name); + smb_fname_dst->base_name = tmp; } /* @@ -5791,36 +5862,78 @@ NTSTATUS rename_internals_fsp(connection_struct *conn, * the rename (user is trying to change the case of the * filename). */ - if((conn->case_sensitive == False) && (conn->case_preserve == True) && - strequal(newname, fsp->fsp_name)) { - char *p; - char *newname_modified_last_component = NULL; + strequal(smb_fname_src->base_name, smb_fname_dst->base_name) && + strequal(smb_fname_src->stream_name, smb_fname_dst->stream_name)) { + char *last_slash; + char *fname_dst_lcomp_base_mod = NULL; + struct smb_filename *smb_fname_orig_lcomp = NULL; + + /* + * Get the last component of the destination name. Note that + * we guarantee that destination name contains a '/' character + * above. + */ + last_slash = strrchr_m(smb_fname_dst->base_name, '/'); + fname_dst_lcomp_base_mod = talloc_strdup(ctx, last_slash + 1); + if (!fname_dst_lcomp_base_mod) { + status = NT_STATUS_NO_MEMORY; + goto out; + } /* - * Get the last component of the modified name. - * Note that we guarantee that newname contains a '/' - * character above. + * Create an smb_filename struct using the original last + * component of the destination. */ - p = strrchr_m(newname,'/'); - newname_modified_last_component = talloc_strdup(ctx, - p+1); - if (!newname_modified_last_component) { - return NT_STATUS_NO_MEMORY; + status = create_synthetic_smb_fname_split(ctx, + smb_fname_dst->original_lcomp, NULL, + &smb_fname_orig_lcomp); + if (!NT_STATUS_IS_OK(status)) { + TALLOC_FREE(fname_dst_lcomp_base_mod); + goto out; } - if(strcsequal(newname_modified_last_component, - newname_last_component) == False) { + /* If the base names only differ by case, use original. */ + if(!strcsequal(fname_dst_lcomp_base_mod, + smb_fname_orig_lcomp->base_name)) { + char *tmp; /* - * Replace the modified last component with - * the original. + * Replace the modified last component with the + * original. */ - *p = '\0'; /* Truncate at the '/' */ - newname = talloc_asprintf(ctx, + *last_slash = '\0'; /* Truncate at the '/' */ + tmp = talloc_asprintf(smb_fname_dst, "%s/%s", - newname, - newname_last_component); + smb_fname_dst->base_name, + smb_fname_orig_lcomp->base_name); + if (tmp == NULL) { + status = NT_STATUS_NO_MEMORY; + TALLOC_FREE(fname_dst_lcomp_base_mod); + TALLOC_FREE(smb_fname_orig_lcomp); + goto out; + } + TALLOC_FREE(smb_fname_dst->base_name); + smb_fname_dst->base_name = tmp; + } + + /* If the stream_names only differ by case, use original. */ + if(!strcsequal(smb_fname_dst->stream_name, + smb_fname_orig_lcomp->stream_name)) { + char *tmp = NULL; + /* Use the original stream. */ + tmp = talloc_strdup(smb_fname_dst, + smb_fname_orig_lcomp->stream_name); + if (tmp == NULL) { + status = NT_STATUS_NO_MEMORY; + TALLOC_FREE(fname_dst_lcomp_base_mod); + TALLOC_FREE(smb_fname_orig_lcomp); + goto out; + } + TALLOC_FREE(smb_fname_dst->stream_name); + smb_fname_dst->stream_name = tmp; } + TALLOC_FREE(fname_dst_lcomp_base_mod); + TALLOC_FREE(smb_fname_orig_lcomp); } /* @@ -5828,74 +5941,86 @@ NTSTATUS rename_internals_fsp(connection_struct *conn, * don't do the rename, just return success. */ - if (strcsequal(fsp->fsp_name, newname)) { - DEBUG(3,("rename_internals_fsp: identical names in rename %s - returning success\n", - newname)); - return NT_STATUS_OK; + if (strcsequal(smb_fname_src->base_name, smb_fname_dst->base_name) && + strcsequal(smb_fname_src->stream_name, + smb_fname_dst->stream_name)) { + DEBUG(3, ("rename_internals_fsp: identical names in rename %s " + "- returning success\n", + smb_fname_str_dbg(smb_fname_dst))); + status = NT_STATUS_OK; + goto out; } - old_is_stream = is_ntfs_stream_name(fsp->fsp_name); - new_is_stream = is_ntfs_stream_name(newname); + old_is_stream = is_ntfs_stream_smb_fname(smb_fname_src); + new_is_stream = is_ntfs_stream_smb_fname(smb_fname_dst); /* Return the correct error code if both names aren't streams. */ if (!old_is_stream && new_is_stream) { - return NT_STATUS_OBJECT_NAME_INVALID; + status = NT_STATUS_OBJECT_NAME_INVALID; + goto out; } if (old_is_stream && !new_is_stream) { - return NT_STATUS_INVALID_PARAMETER; + status = NT_STATUS_INVALID_PARAMETER; + goto out; } - /* - * Have vfs_object_exist also fill sbuf1 - */ - dst_exists = vfs_object_exist(conn, newname, &sbuf1); + dst_exists = SMB_VFS_STAT(conn, smb_fname_dst) == 0; if(!replace_if_exists && dst_exists) { - DEBUG(3,("rename_internals_fsp: dest exists doing rename %s -> %s\n", - fsp->fsp_name,newname)); - return NT_STATUS_OBJECT_NAME_COLLISION; + DEBUG(3, ("rename_internals_fsp: dest exists doing rename " + "%s -> %s\n", smb_fname_str_dbg(smb_fname_src), + smb_fname_str_dbg(smb_fname_dst))); + status = NT_STATUS_OBJECT_NAME_COLLISION; + goto out; } if (dst_exists) { - struct file_id fileid = vfs_file_id_from_sbuf(conn, &sbuf1); + struct file_id fileid = vfs_file_id_from_sbuf(conn, + &smb_fname_dst->st); files_struct *dst_fsp = file_find_di_first(fileid); /* The file can be open when renaming a stream */ if (dst_fsp && !new_is_stream) { DEBUG(3, ("rename_internals_fsp: Target file open\n")); - return NT_STATUS_ACCESS_DENIED; + status = NT_STATUS_ACCESS_DENIED; + goto out; } } /* Ensure we have a valid stat struct for the source. */ if (fsp->fh->fd != -1) { if (SMB_VFS_FSTAT(fsp, &sbuf) == -1) { - return map_nt_error_from_unix(errno); + status = map_nt_error_from_unix(errno); + goto out; } } else { int ret = -1; if (fsp->posix_open) { - ret = SMB_VFS_LSTAT(conn,fsp->fsp_name,&sbuf); + ret = SMB_VFS_LSTAT(conn, smb_fname_src); } else { - ret = SMB_VFS_STAT(conn,fsp->fsp_name,&sbuf); + + ret = SMB_VFS_STAT(conn, smb_fname_src); } if (ret == -1) { - return map_nt_error_from_unix(errno); + status = map_nt_error_from_unix(errno); + goto out; } + sbuf = smb_fname_src->st; } status = can_rename(conn, fsp, attrs, &sbuf); if (!NT_STATUS_IS_OK(status)) { - DEBUG(3,("rename_internals_fsp: Error %s rename %s -> %s\n", - nt_errstr(status), fsp->fsp_name,newname)); + DEBUG(3, ("rename_internals_fsp: Error %s rename %s -> %s\n", + nt_errstr(status), smb_fname_str_dbg(smb_fname_src), + smb_fname_str_dbg(smb_fname_dst))); if (NT_STATUS_EQUAL(status,NT_STATUS_SHARING_VIOLATION)) status = NT_STATUS_ACCESS_DENIED; - return status; + goto out; } - if (rename_path_prefix_equal(fsp->fsp_name, newname)) { - return NT_STATUS_ACCESS_DENIED; + if (rename_path_prefix_equal(smb_fname_src, smb_fname_dst)) { + status = NT_STATUS_ACCESS_DENIED; } lck = get_share_mode_lock(talloc_tos(), fsp->file_id, NULL, NULL, @@ -5908,15 +6033,17 @@ NTSTATUS rename_internals_fsp(connection_struct *conn, SMB_ASSERT(lck != NULL); - if(SMB_VFS_RENAME(conn,fsp->fsp_name, newname) == 0) { + if(SMB_VFS_RENAME(conn, smb_fname_src, smb_fname_dst) == 0) { uint32 create_options = fsp->fh->private_options; - DEBUG(3,("rename_internals_fsp: succeeded doing rename on %s -> %s\n", - fsp->fsp_name,newname)); + DEBUG(3, ("rename_internals_fsp: succeeded doing rename on " + "%s -> %s\n", smb_fname_str_dbg(smb_fname_src), + smb_fname_str_dbg(smb_fname_dst))); - notify_rename(conn, fsp->is_directory, fsp->fsp_name, newname); + notify_rename(conn, fsp->is_directory, smb_fname_src, + smb_fname_dst); - rename_open_files(conn, lck, newname); + rename_open_files(conn, lck, smb_fname_dst); /* * A rename acts as a new file create w.r.t. allowing an initial delete @@ -5937,7 +6064,8 @@ NTSTATUS rename_internals_fsp(connection_struct *conn, } } TALLOC_FREE(lck); - return NT_STATUS_OK; + status = NT_STATUS_OK; + goto out; } TALLOC_FREE(lck); @@ -5948,8 +6076,13 @@ NTSTATUS rename_internals_fsp(connection_struct *conn, status = map_nt_error_from_unix(errno); } - DEBUG(3,("rename_internals_fsp: Error %s rename %s -> %s\n", - nt_errstr(status), fsp->fsp_name,newname)); + DEBUG(3, ("rename_internals_fsp: Error %s rename %s -> %s\n", + nt_errstr(status), smb_fname_str_dbg(smb_fname_src), + smb_fname_str_dbg(smb_fname_dst))); + + out: + TALLOC_FREE(smb_fname_src); + TALLOC_FREE(smb_fname_dst); return status; } @@ -5970,13 +6103,10 @@ NTSTATUS rename_internals(TALLOC_CTX *ctx, bool dest_has_wild, uint32_t access_mask) { - struct smb_filename *smb_fname = NULL; - struct smb_filename *smb_fname_new = NULL; - char *directory = NULL; - char *mask = NULL; - char *name = NULL; - char *newname = NULL; - char *p; + struct smb_filename *smb_fname_src = NULL; + struct smb_filename *smb_fname_dst = NULL; + char *fname_src_dir = NULL; + char *fname_src_mask = NULL; int count=0; NTSTATUS status = NT_STATUS_OK; struct smb_Dir *dir_hnd = NULL; @@ -5985,29 +6115,19 @@ NTSTATUS rename_internals(TALLOC_CTX *ctx, int create_options = 0; bool posix_pathnames = lp_posix_pathnames(); - status = unix_convert(ctx, conn, name_in, &smb_fname, + status = unix_convert(ctx, conn, name_in, &smb_fname_src, src_has_wild ? UCF_ALLOW_WCARD_LCOMP : 0); if (!NT_STATUS_IS_OK(status)) { goto out; } - status = get_full_smb_filename(ctx, smb_fname, &name); - if (!NT_STATUS_IS_OK(status)) { - goto out; - } - - status = unix_convert(ctx, conn, newname_in, &smb_fname_new, + status = unix_convert(ctx, conn, newname_in, &smb_fname_dst, (UCF_SAVE_LCOMP | (dest_has_wild ? UCF_ALLOW_WCARD_LCOMP : 0))); if (!NT_STATUS_IS_OK(status)) { goto out; } - status = get_full_smb_filename(ctx, smb_fname_new, &newname); - if (!NT_STATUS_IS_OK(status)) { - goto out; - } - /* * Split the old name into directory and last component * strings. Note that unix_convert may have stripped off a @@ -6017,23 +6137,12 @@ NTSTATUS rename_internals(TALLOC_CTX *ctx, * as this is checked in resolve_wildcards(). */ - p = strrchr_m(name,'/'); - if (!p) { - directory = talloc_strdup(ctx, "."); - if (!directory) { - status = NT_STATUS_NO_MEMORY; - goto out; - } - mask = name; - } else { - *p = 0; - directory = talloc_strdup(ctx, name); - if (!directory) { - status = NT_STATUS_NO_MEMORY; - goto out; - } - mask = p+1; - *p = '/'; /* Replace needed for exceptional test below. */ + /* Split up the directory from the filename/mask. */ + status = split_fname_dir_mask(ctx, smb_fname_src->base_name, + &fname_src_dir, &fname_src_mask); + if (!NT_STATUS_IS_OK(status)) { + status = NT_STATUS_NO_MEMORY; + goto out; } /* @@ -6045,14 +6154,14 @@ NTSTATUS rename_internals(TALLOC_CTX *ctx, * 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); if (new_mask) { - mask = new_mask; + TALLOC_FREE(fname_src_mask); + fname_src_mask = new_mask; } } @@ -6060,26 +6169,30 @@ NTSTATUS rename_internals(TALLOC_CTX *ctx, files_struct *fsp; /* - * No wildcards - just process the one file. + * Only one file needs to be renamed. Append the mask back + * onto the directory. */ - /* Add a terminating '/' to the directory name. */ - directory = talloc_asprintf_append(directory, - "/%s", - mask); - if (!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) { status = NT_STATUS_NO_MEMORY; goto out; } - /* Ensure newname contains a '/' also */ - if(strrchr_m(newname,'/') == 0) { - newname = talloc_asprintf(ctx, - "./%s", - newname); - if (!newname) { + /* Ensure dst fname contains a '/' also */ + if(strrchr_m(smb_fname_dst->base_name, '/') == 0) { + char *tmp; + tmp = talloc_asprintf(smb_fname_dst, "./%s", + smb_fname_dst->base_name); + if (!tmp) { status = NT_STATUS_NO_MEMORY; goto out; } + TALLOC_FREE(smb_fname_dst->base_name); + smb_fname_dst->base_name = tmp; } DEBUG(3, ("rename_internals: case_sensitive = %d, " @@ -6087,32 +6200,37 @@ NTSTATUS rename_internals(TALLOC_CTX *ctx, "directory = %s, newname = %s, " "last_component_dest = %s\n", conn->case_sensitive, conn->case_preserve, - conn->short_case_preserve, directory, - newname, smb_fname_new->original_lcomp)); + conn->short_case_preserve, + smb_fname_str_dbg(smb_fname_src), + smb_fname_str_dbg(smb_fname_dst), + smb_fname_dst->original_lcomp)); /* The dest name still may have wildcards. */ 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)) { DEBUG(6, ("rename_internals: resolve_wildcards " - "%s %s failed\n", - directory, - newname)); + "%s %s failed\n", + smb_fname_src->base_name, + smb_fname_dst->base_name)); status = NT_STATUS_NO_MEMORY; goto out; } - newname = mod_newname; + TALLOC_FREE(smb_fname_dst->base_name); + smb_fname_dst->base_name = fname_dst_mod; } - ZERO_STRUCT(smb_fname->st); + ZERO_STRUCT(smb_fname_src->st); if (posix_pathnames) { - SMB_VFS_LSTAT(conn, directory, &smb_fname->st); + SMB_VFS_LSTAT(conn, smb_fname_src); } else { - SMB_VFS_STAT(conn, directory, &smb_fname->st); + SMB_VFS_STAT(conn, smb_fname_src); } - if (S_ISDIR(smb_fname->st.st_ex_mode)) { + if (S_ISDIR(smb_fname_src->st.st_ex_mode)) { create_options |= FILE_DIRECTORY_FILE; } @@ -6120,8 +6238,7 @@ NTSTATUS rename_internals(TALLOC_CTX *ctx, conn, /* conn */ req, /* req */ 0, /* root_dir_fid */ - directory, /* fname */ - 0, /* create_file_flags */ + smb_fname_src, /* fname */ access_mask, /* access_mask */ (FILE_SHARE_READ | /* share_access */ FILE_SHARE_WRITE), @@ -6133,23 +6250,23 @@ NTSTATUS rename_internals(TALLOC_CTX *ctx, NULL, /* sd */ NULL, /* ea_list */ &fsp, /* result */ - NULL, /* pinfo */ - &smb_fname->st); /* psbuf */ + NULL); /* pinfo */ if (!NT_STATUS_IS_OK(status)) { DEBUG(3, ("Could not open rename source %s: %s\n", - directory, nt_errstr(status))); + smb_fname_str_dbg(smb_fname_src), + nt_errstr(status))); goto out; } - status = rename_internals_fsp(conn, fsp, newname, - smb_fname_new->original_lcomp, + status = rename_internals_fsp(conn, fsp, smb_fname_dst, attrs, replace_if_exists); close_file(req, fsp, NORMAL_CLOSE); DEBUG(3, ("rename_internals: Error %s rename %s -> %s\n", - nt_errstr(status), directory,newname)); + nt_errstr(status), smb_fname_str_dbg(smb_fname_src), + smb_fname_str_dbg(smb_fname_dst))); goto out; } @@ -6157,17 +6274,22 @@ NTSTATUS rename_internals(TALLOC_CTX *ctx, /* * Wildcards - process each file that matches. */ - if (strequal(mask,"????????.???")) { - mask[0] = '*'; - mask[1] = '\0'; + if (strequal(fname_src_mask, "????????.???")) { + TALLOC_FREE(fname_src_mask); + fname_src_mask = talloc_strdup(ctx, "*"); + if (!fname_src_mask) { + status = NT_STATUS_NO_MEMORY; + goto out; + } } - status = check_name(conn, directory); + status = check_name(conn, fname_src_dir); if (!NT_STATUS_IS_OK(status)) { goto out; } - dir_hnd = OpenDir(talloc_tos(), conn, directory, mask, attrs); + dir_hnd = OpenDir(talloc_tos(), conn, fname_src_dir, fname_src_mask, + attrs); if (dir_hnd == NULL) { status = map_nt_error_from_unix(errno); goto out; @@ -6179,9 +6301,8 @@ NTSTATUS rename_internals(TALLOC_CTX *ctx, * - gentest fix. JRA */ - while ((dname = ReadDirName(dir_hnd, &offset, &smb_fname->st))) { + while ((dname = ReadDirName(dir_hnd, &offset, &smb_fname_src->st))) { files_struct *fsp = NULL; - char *fname = NULL; char *destname = NULL; bool sysdir_entry = False; @@ -6194,12 +6315,12 @@ NTSTATUS rename_internals(TALLOC_CTX *ctx, } } - 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; } @@ -6208,20 +6329,21 @@ NTSTATUS rename_internals(TALLOC_CTX *ctx, break; } - fname = talloc_asprintf(ctx, - "%s/%s", - directory, - dname); - if (!fname) { + 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) { status = 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)) { DEBUG(6, ("resolve_wildcards %s %s failed\n", - fname, destname)); - TALLOC_FREE(fname); + smb_fname_src->base_name, destname)); continue; } if (!destname) { @@ -6229,16 +6351,19 @@ NTSTATUS rename_internals(TALLOC_CTX *ctx, goto out; } - ZERO_STRUCT(smb_fname->st); + TALLOC_FREE(smb_fname_dst->base_name); + smb_fname_dst->base_name = destname; + + ZERO_STRUCT(smb_fname_src->st); if (posix_pathnames) { - SMB_VFS_LSTAT(conn, fname, &smb_fname->st); + SMB_VFS_LSTAT(conn, smb_fname_src); } else { - SMB_VFS_STAT(conn, fname, &smb_fname->st); + SMB_VFS_STAT(conn, smb_fname_src); } create_options = 0; - if (S_ISDIR(smb_fname->st.st_ex_mode)) { + if (S_ISDIR(smb_fname_src->st.st_ex_mode)) { create_options |= FILE_DIRECTORY_FILE; } @@ -6246,8 +6371,7 @@ NTSTATUS rename_internals(TALLOC_CTX *ctx, conn, /* conn */ req, /* req */ 0, /* root_dir_fid */ - fname, /* fname */ - 0, /* create_file_flags */ + smb_fname_src, /* fname */ access_mask, /* access_mask */ (FILE_SHARE_READ | /* share_access */ FILE_SHARE_WRITE), @@ -6259,17 +6383,25 @@ NTSTATUS rename_internals(TALLOC_CTX *ctx, NULL, /* sd */ NULL, /* ea_list */ &fsp, /* result */ - NULL, /* pinfo */ - &smb_fname->st); /* psbuf */ + NULL); /* pinfo */ if (!NT_STATUS_IS_OK(status)) { DEBUG(3,("rename_internals: SMB_VFS_CREATE_FILE " "returned %s rename %s -> %s\n", - nt_errstr(status), directory, newname)); + nt_errstr(status), + smb_fname_str_dbg(smb_fname_src), + smb_fname_str_dbg(smb_fname_dst))); break; } - status = rename_internals_fsp(conn, fsp, destname, dname, + smb_fname_dst->original_lcomp = talloc_strdup(smb_fname_dst, + dname); + if (!smb_fname_dst->original_lcomp) { + status = NT_STATUS_NO_MEMORY; + goto out; + } + + status = rename_internals_fsp(conn, fsp, smb_fname_dst, attrs, replace_if_exists); close_file(req, fsp, NORMAL_CLOSE); @@ -6277,17 +6409,17 @@ NTSTATUS rename_internals(TALLOC_CTX *ctx, if (!NT_STATUS_IS_OK(status)) { DEBUG(3, ("rename_internals_fsp returned %s for " "rename %s -> %s\n", nt_errstr(status), - directory, newname)); + smb_fname_str_dbg(smb_fname_src), + smb_fname_str_dbg(smb_fname_dst))); break; } count++; DEBUG(3,("rename_internals: doing rename on %s -> " - "%s\n",fname,destname)); + "%s\n", smb_fname_str_dbg(smb_fname_src), + smb_fname_str_dbg(smb_fname_src))); - TALLOC_FREE(fname); - TALLOC_FREE(destname); } TALLOC_FREE(dir_hnd); @@ -6296,8 +6428,10 @@ NTSTATUS rename_internals(TALLOC_CTX *ctx, } out: - TALLOC_FREE(smb_fname); - TALLOC_FREE(smb_fname_new); + TALLOC_FREE(smb_fname_src); + TALLOC_FREE(smb_fname_dst); + TALLOC_FREE(fname_src_dir); + TALLOC_FREE(fname_src_mask); return status; } @@ -6409,60 +6543,74 @@ 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; 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; } } + /* Open the src file for reading. */ status = SMB_VFS_CREATE_FILE( conn, /* conn */ NULL, /* req */ 0, /* root_dir_fid */ - src, /* fname */ - 0, /* create_file_flags */ + smb_fname_src, /* fname */ FILE_GENERIC_READ, /* access_mask */ FILE_SHARE_READ | FILE_SHARE_WRITE, /* share_access */ FILE_OPEN, /* create_disposition*/ @@ -6473,25 +6621,31 @@ NTSTATUS copy_file(TALLOC_CTX *ctx, NULL, /* sd */ NULL, /* ea_list */ &fsp1, /* result */ - NULL, /* pinfo */ - &src_sbuf); /* psbuf */ + NULL); /* psbuf */ if (!NT_STATUS_IS_OK(status)) { - TALLOC_FREE(dest); - return status; + goto out; } - dosattrs = dos_mode(conn, src, &src_sbuf); - if (SMB_VFS_STAT(conn,dest,&sbuf2) == -1) { - ZERO_STRUCTP(&sbuf2); + status = get_full_smb_filename(talloc_tos(), smb_fname_src, &fname_src); + if (!NT_STATUS_IS_OK(status)) { + goto out; + } + + dosattrs = dos_mode(conn, fname_src, &smb_fname_src->st); + + TALLOC_FREE(fname_src); + + if (SMB_VFS_STAT(conn, smb_fname_dst_tmp) == -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 */ - 0, /* create_file_flags */ + smb_fname_dst, /* fname */ FILE_GENERIC_WRITE, /* access_mask */ FILE_SHARE_READ | FILE_SHARE_WRITE, /* share_access */ new_create_disposition, /* create_disposition*/ @@ -6502,14 +6656,11 @@ NTSTATUS copy_file(TALLOC_CTX *ctx, NULL, /* sd */ NULL, /* ea_list */ &fsp2, /* result */ - NULL, /* pinfo */ - &sbuf2); /* psbuf */ - - TALLOC_FREE(dest); + NULL); /* psbuf */ if (!NT_STATUS_IS_OK(status)) { close_file(NULL, fsp1, ERROR_CLOSE); - return status; + goto out; } if ((ofun&3) == 1) { @@ -6519,18 +6670,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 @@ -6541,14 +6693,19 @@ 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); + return status; } /**************************************************************************** @@ -6558,13 +6715,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; @@ -6590,20 +6746,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 */ @@ -6614,8 +6770,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)) { @@ -6629,8 +6785,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)) { @@ -6642,33 +6798,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); @@ -6680,23 +6824,17 @@ 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,'/'); - if (p != NULL) { - directory = talloc_strndup(ctx, name, PTR_DIFF(p, name)); - mask = p+1; - } else { - directory = talloc_strdup(ctx, "./"); - mask = name; - } - - if (!directory) { + /* Split up the directory from the filename/mask. */ + status = split_fname_dir_mask(ctx, smb_fname_src->base_name, + &fname_src_dir, &fname_src_mask); + if (!NT_STATUS_IS_OK(status)) { reply_nterror(req, NT_STATUS_NO_MEMORY); goto out; } @@ -6709,47 +6847,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); @@ -6762,17 +6915,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); @@ -6781,37 +6951,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) { @@ -6820,29 +6995,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); } @@ -6862,8 +7041,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; } @@ -7307,18 +7491,18 @@ void reply_lockingX(struct smb_request *req) } if (NT_STATUS_V(status)) { - END_PROFILE(SMBlockingX); - reply_nterror(req, status); - return; + break; } } /* If any of the above locks failed, then we must unlock all of the previous locks (X/Open spec). */ + if (num_locks != 0 && !NT_STATUS_IS_OK(status)) { + + if (locktype & LOCKING_ANDX_CANCEL_LOCK) { + i = -1; /* we want to skip the for loop */ + } - if (!(locktype & LOCKING_ANDX_CANCEL_LOCK) && - (i != num_locks) && - (num_locks != 0)) { /* * Ensure we don't do a remove on the lock that just failed, * as under POSIX rules, if we have a lock already there, we @@ -7399,9 +7583,9 @@ void reply_readbs(struct smb_request *req) void reply_setattrE(struct smb_request *req) { connection_struct *conn = req->conn; + struct smb_filename *smb_fname = NULL; struct smb_file_time ft; files_struct *fsp; - SMB_STRUCT_STAT sbuf; NTSTATUS status; START_PROFILE(SMBsetattrE); @@ -7409,18 +7593,23 @@ void reply_setattrE(struct smb_request *req) if (req->wct < 7) { reply_nterror(req, NT_STATUS_INVALID_PARAMETER); - END_PROFILE(SMBsetattrE); - return; + goto out; } fsp = file_fsp(req, SVAL(req->vwv+0, 0)); if(!fsp || (fsp->conn != conn)) { reply_doserror(req, ERRDOS, ERRbadfid); - END_PROFILE(SMBsetattrE); - return; + goto out; } + /* XXX: Remove when fsp->fsp_name is converted to smb_filename. */ + status = create_synthetic_smb_fname_split(talloc_tos(), fsp->fsp_name, + NULL, &smb_fname); + if (!NT_STATUS_IS_OK(status)) { + reply_nterror(req, status); + goto out; + } /* * Convert the DOS times into unix times. @@ -7442,34 +7631,30 @@ void reply_setattrE(struct smb_request *req) /* Ensure we have a valid stat struct for the source. */ if (fsp->fh->fd != -1) { - if (SMB_VFS_FSTAT(fsp, &sbuf) == -1) { + if (SMB_VFS_FSTAT(fsp, &smb_fname->st) == -1) { status = map_nt_error_from_unix(errno); reply_nterror(req, status); - END_PROFILE(SMBsetattrE); - return; + goto out; } } else { int ret = -1; if (fsp->posix_open) { - ret = SMB_VFS_LSTAT(conn, fsp->fsp_name, &sbuf); + ret = SMB_VFS_LSTAT(conn, smb_fname); } else { - ret = SMB_VFS_STAT(conn, fsp->fsp_name, &sbuf); + ret = SMB_VFS_STAT(conn, smb_fname); } if (ret == -1) { status = map_nt_error_from_unix(errno); reply_nterror(req, status); - END_PROFILE(SMBsetattrE); - return; + goto out; } } - status = smb_set_file_time(conn, fsp, fsp->fsp_name, - &sbuf, &ft, true); + status = smb_set_file_time(conn, fsp, smb_fname, &ft, true); if (!NT_STATUS_IS_OK(status)) { reply_doserror(req, ERRDOS, ERRnoaccess); - END_PROFILE(SMBsetattrE); - return; + goto out; } DEBUG( 3, ( "reply_setattrE fnum=%d actime=%u modtime=%u " @@ -7479,7 +7664,7 @@ void reply_setattrE(struct smb_request *req) (unsigned int)ft.mtime.tv_sec, (unsigned int)ft.create_time.tv_sec )); - + out: END_PROFILE(SMBsetattrE); return; }