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

s3: Change unix_convert (and its callers) to use struct smb_filename

This is the first of a series of patches that change path based
operations to operate on a struct smb_filename instead of a char *.
This same concept already exists in source4.

My goals for this series of patches are to eventually:

1) Solve the stream vs. posix filename that contains a colon ambiguity
   that currently exists.
2) Make unix_convert the only function that parses the stream name.
3) Clean up the unix_convert API.
4) Change all path based vfs operation to take a struct smb_filename.
5) Make is_ntfs_stream_name() a constant operation that can simply
   check the state of struct smb_filename rather than re-parse the
   filename.
6) Eliminate the need for split_ntfs_stream_name() to exist.

My strategy is to start from the inside at unix_convert() and work my
way out through the vfs layer, call by call.  This first patch does
just that, by changing unix_convert and all of its callers to operate
on struct smb_filename.  Since this is such a large change, I plan on
pushing the patches in phases, where each phase keeps full
compatibility and passes make test.

The API of unix_convert has been simplified from:

NTSTATUS unix_convert(TALLOC_CTX *ctx,
		      connection_struct *conn,
		      const char *orig_path,
		      bool allow_wcard_last_component,
		      char **pp_conv_path,
		      char **pp_saved_last_component,
		      SMB_STRUCT_STAT *pst)
to:

NTSTATUS unix_convert(TALLOC_CTX *ctx,
		      connection_struct *conn,
		      const char *orig_path,
		      struct smb_filename *smb_fname,
		      uint32_t ucf_flags)

Currently the smb_filename struct looks like:

struct smb_filename {
       char *base_name;
       char *stream_name;
       char *original_lcomp;
       SMB_STRUCT_STAT st;
};

One key point here is the decision to break up the base_name and
stream_name.  I have introduced a helper function called
get_full_smb_filename() that takes an smb_filename struct and
allocates the full_name.  I changed the callers of unix_convert() to
subsequently call get_full_smb_filename() for the time being, but I
plan to eventually eliminate get_full_smb_filename().
This commit is contained in:
Tim Prouty 2009-04-07 13:39:57 -07:00
parent 5d3d51e9ad
commit c1a21d085d
10 changed files with 591 additions and 386 deletions

View File

@ -6264,13 +6264,13 @@ int fsp_stat(files_struct *fsp, SMB_STRUCT_STAT *pst);
/* The following definitions come from smbd/filename.c */ /* The following definitions come from smbd/filename.c */
NTSTATUS get_full_smb_filename(TALLOC_CTX *ctx, const struct smb_filename *smb_fname,
char **full_name);
NTSTATUS unix_convert(TALLOC_CTX *ctx, NTSTATUS unix_convert(TALLOC_CTX *ctx,
connection_struct *conn, connection_struct *conn,
const char *orig_path, const char *orig_path,
bool allow_wcard_last_component, struct smb_filename **smb_fname,
char **pp_conv_path, uint32_t ucf_flags);
char **pp_saved_last_component,
SMB_STRUCT_STAT *pst);
NTSTATUS check_name(connection_struct *conn, const char *name); NTSTATUS check_name(connection_struct *conn, const char *name);
int get_real_filename(connection_struct *conn, const char *path, int get_real_filename(connection_struct *conn, const char *path,
const char *name, TALLOC_CTX *mem_ctx, const char *name, TALLOC_CTX *mem_ctx,

View File

@ -1925,4 +1925,20 @@ struct smb_file_time {
struct timespec create_time; struct timespec create_time;
}; };
/*
* unix_convert_flags
*/
#define UCF_SAVE_LCOMP 0x00000001
#define UCF_ALLOW_WCARD_LCOMP 0x00000002
/*
* smb_filename
*/
struct smb_filename {
char *base_name;
char *stream_name;
char *original_lcomp;
SMB_STRUCT_STAT st;
};
#endif /* _SMB_H */ #endif /* _SMB_H */

View File

@ -2058,16 +2058,27 @@ NTSTATUS onefs_create_file(vfs_handle_struct *handle,
/* Convert dos path to unix path if it hasn't already been done. */ /* Convert dos path to unix path if it hasn't already been done. */
if (create_file_flags & CFF_DOS_PATH) { if (create_file_flags & CFF_DOS_PATH) {
struct smb_filename *smb_fname = NULL;
char *converted_fname; char *converted_fname;
SET_STAT_INVALID(sbuf); SET_STAT_INVALID(sbuf);
status = unix_convert(talloc_tos(), conn, fname, False, status = unix_convert(talloc_tos(), conn, fname, &smb_fname,
&converted_fname, NULL, &sbuf); 0);
if (!NT_STATUS_IS_OK(status)) { if (!NT_STATUS_IS_OK(status)) {
goto fail; goto fail;
} }
status = get_full_smb_filename(talloc_tos(), &smb_fname,
&converted_fname);
if (!NT_STATUS_IS_OK(status)) {
TALLOC_FREE(smb_fname);
goto fail;
}
sbuf = smb_fname->st;
fname = converted_fname; fname = converted_fname;
TALLOC_FREE(smb_fname);
} else { } else {
if (psbuf != NULL) { if (psbuf != NULL) {
sbuf = *psbuf; sbuf = *psbuf;

View File

@ -638,7 +638,9 @@ static char *driver_unix_convert(connection_struct *conn,
const char *old_name, const char *old_name,
SMB_STRUCT_STAT *pst) SMB_STRUCT_STAT *pst)
{ {
NTSTATUS status;
TALLOC_CTX *ctx = talloc_tos(); TALLOC_CTX *ctx = talloc_tos();
struct smb_filename *smb_fname = NULL;
char *name = talloc_strdup(ctx, old_name); char *name = talloc_strdup(ctx, old_name);
char *new_name = NULL; char *new_name = NULL;
@ -651,7 +653,20 @@ static char *driver_unix_convert(connection_struct *conn,
return NULL; return NULL;
} }
trim_string(name,"/","/"); trim_string(name,"/","/");
unix_convert(ctx,conn, name, false, &new_name, NULL, pst);
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;
}
TALLOC_FREE(smb_fname);
return new_name; return new_name;
} }

View File

@ -29,10 +29,7 @@
static NTSTATUS build_stream_path(TALLOC_CTX *mem_ctx, static NTSTATUS build_stream_path(TALLOC_CTX *mem_ctx,
connection_struct *conn, connection_struct *conn,
const char *orig_path, const char *orig_path,
const char *basepath, struct smb_filename *smb_fname);
const char *streamname,
SMB_STRUCT_STAT *pst,
char **path);
/**************************************************************************** /****************************************************************************
Mangle the 2nd name and check if it is then equal to the first name. Mangle the 2nd name and check if it is then equal to the first name.
@ -83,10 +80,27 @@ static NTSTATUS determine_path_error(const char *name,
} }
} }
NTSTATUS get_full_smb_filename(TALLOC_CTX *ctx, const struct smb_filename *smb_fname,
char **full_name)
{
if (smb_fname->stream_name) {
*full_name = talloc_asprintf(ctx, "%s%s", smb_fname->base_name,
smb_fname->stream_name);
} else {
*full_name = talloc_strdup(ctx, smb_fname->base_name);
}
if (!*full_name) {
return NT_STATUS_NO_MEMORY;
}
return NT_STATUS_OK;
}
/**************************************************************************** /****************************************************************************
This routine is called to convert names from the dos namespace to unix This routine is called to convert names from the dos namespace to unix
namespace. It needs to handle any case conversions, mangling, format namespace. It needs to handle any case conversions, mangling, format changes,
changes etc. streams etc.
We assume that we have already done a chdir() to the right "root" directory We assume that we have already done a chdir() to the right "root" directory
for this service. for this service.
@ -94,32 +108,34 @@ for this service.
The function will return an NTSTATUS error if some part of the name except for The function will return an NTSTATUS error if some part of the name except for
the last part cannot be resolved, else NT_STATUS_OK. the last part cannot be resolved, else NT_STATUS_OK.
Note NT_STATUS_OK doesn't mean the name exists or is valid, just that we didn't Note NT_STATUS_OK doesn't mean the name exists or is valid, just that we
get any fatal errors that should immediately terminate the calling didn't get any fatal errors that should immediately terminate the calling SMB
SMB processing whilst resolving. processing whilst resolving.
If the saved_last_component != 0, then the unmodified last component If the UCF_SAVE_LCOMP flag is passed in, then the unmodified last component
of the pathname is returned there. If saved_last_component == 0 then nothing of the pathname is set in smb_filename->original_lcomp.
is returned there.
If last_component_wcard is true then a MS wildcard was detected and If UCF_ALLOW_WCARD_LCOMP is passed in, then a MS wildcard was detected and
should be allowed in the last component of the path only. should be allowed in the last component of the path only.
On exit from unix_convert, if *pst was not null, then the file stat If the orig_path was a stream, smb_filename->base_name will point to the base
struct will be returned if the file exists and was found, if not this filename, and smb_filename->stream_name will point to the stream name. If
stat struct will be filled with zeros (and this can be detected by checking orig_path was not a stream, then smb_filename->stream_name will be NULL.
for nlinks = 0, which can never be true for any file).
On exit from unix_convert, the smb_filename->st stat struct will be populated
if the file exists and was found, if not this stat struct will be filled with
zeros (and this can be detected by checking for nlinks = 0, which can never be
true for any file).
****************************************************************************/ ****************************************************************************/
NTSTATUS unix_convert(TALLOC_CTX *ctx, NTSTATUS unix_convert(TALLOC_CTX *ctx,
connection_struct *conn, connection_struct *conn,
const char *orig_path, const char *orig_path,
bool allow_wcard_last_component, struct smb_filename **smb_fname_out,
char **pp_conv_path, uint32_t ucf_flags)
char **pp_saved_last_component,
SMB_STRUCT_STAT *pst)
{ {
SMB_STRUCT_STAT st; SMB_STRUCT_STAT st;
struct smb_filename *smb_fname = NULL;
char *start, *end; char *start, *end;
char *dirpath = NULL; char *dirpath = NULL;
char *name = NULL; char *name = NULL;
@ -127,21 +143,26 @@ NTSTATUS unix_convert(TALLOC_CTX *ctx,
bool component_was_mangled = False; bool component_was_mangled = False;
bool name_has_wildcard = False; bool name_has_wildcard = False;
bool posix_pathnames = false; bool posix_pathnames = false;
bool allow_wcard_last_component = ucf_flags & UCF_ALLOW_WCARD_LCOMP;
bool save_last_component = ucf_flags & UCF_SAVE_LCOMP;
NTSTATUS result; NTSTATUS result;
int ret = -1; int ret = -1;
SET_STAT_INVALID(*pst); *smb_fname_out = NULL;
*pp_conv_path = NULL;
if(pp_saved_last_component) { smb_fname = TALLOC_ZERO_P(talloc_tos(), struct smb_filename);
*pp_saved_last_component = NULL; if (smb_fname == NULL) {
return NT_STATUS_NO_MEMORY;
} }
if (conn->printer) { if (conn->printer) {
/* we don't ever use the filenames on a printer share as a /* we don't ever use the filenames on a printer share as a
filename - so don't convert them */ filename - so don't convert them */
if (!(*pp_conv_path = talloc_strdup(ctx,orig_path))) { if (!(smb_fname->base_name = talloc_strdup(smb_fname,
orig_path))) {
return NT_STATUS_NO_MEMORY; return NT_STATUS_NO_MEMORY;
} }
*smb_fname_out = smb_fname;
return NT_STATUS_OK; return NT_STATUS_OK;
} }
@ -174,7 +195,7 @@ NTSTATUS unix_convert(TALLOC_CTX *ctx,
return NT_STATUS_NO_MEMORY; return NT_STATUS_NO_MEMORY;
} }
if (SMB_VFS_STAT(conn,name,&st) == 0) { if (SMB_VFS_STAT(conn,name,&st) == 0) {
*pst = st; smb_fname->st = st;
} else { } else {
return map_nt_error_from_unix(errno); return map_nt_error_from_unix(errno);
} }
@ -217,18 +238,20 @@ NTSTATUS unix_convert(TALLOC_CTX *ctx,
* Ensure saved_last_component is valid even if file exists. * Ensure saved_last_component is valid even if file exists.
*/ */
if(pp_saved_last_component) { if(save_last_component) {
end = strrchr_m(name, '/'); end = strrchr_m(name, '/');
if (end) { if (end) {
*pp_saved_last_component = talloc_strdup(ctx, end + 1); smb_fname->original_lcomp = talloc_strdup(ctx,
end + 1);
} else { } else {
*pp_saved_last_component = talloc_strdup(ctx, smb_fname->original_lcomp = talloc_strdup(ctx, name);
name);
} }
} }
posix_pathnames = lp_posix_pathnames(); posix_pathnames = lp_posix_pathnames();
/* Strip off the stream. Should we use any of the other stream parsing
* at this point? Also, should we set the is_stream bit? */
if (!posix_pathnames) { if (!posix_pathnames) {
stream = strchr_m(name, ':'); stream = strchr_m(name, ':');
@ -253,7 +276,7 @@ NTSTATUS unix_convert(TALLOC_CTX *ctx,
if((!conn->case_sensitive || !(conn->fs_capabilities & FILE_CASE_SENSITIVE_SEARCH)) && if((!conn->case_sensitive || !(conn->fs_capabilities & FILE_CASE_SENSITIVE_SEARCH)) &&
stat_cache_lookup(conn, &name, &dirpath, &start, &st)) { stat_cache_lookup(conn, &name, &dirpath, &start, &st)) {
*pst = st; smb_fname->st = st;
goto done; goto done;
} }
@ -295,7 +318,7 @@ NTSTATUS unix_convert(TALLOC_CTX *ctx,
} }
stat_cache_add(orig_path, name, conn->case_sensitive); stat_cache_add(orig_path, name, conn->case_sensitive);
DEBUG(5,("conversion finished %s -> %s\n",orig_path, name)); DEBUG(5,("conversion finished %s -> %s\n",orig_path, name));
*pst = st; smb_fname->st = st;
goto done; goto done;
} }
@ -346,11 +369,11 @@ NTSTATUS unix_convert(TALLOC_CTX *ctx,
*end = 0; *end = 0;
} }
if (pp_saved_last_component) { if (save_last_component) {
TALLOC_FREE(*pp_saved_last_component); TALLOC_FREE(smb_fname->original_lcomp);
*pp_saved_last_component = talloc_strdup(ctx, smb_fname->original_lcomp = talloc_strdup(ctx,
end ? end + 1 : start); end ? end + 1 : start);
if (!*pp_saved_last_component) { if (!smb_fname->original_lcomp) {
DEBUG(0, ("talloc failed\n")); DEBUG(0, ("talloc failed\n"));
return NT_STATUS_NO_MEMORY; return NT_STATUS_NO_MEMORY;
} }
@ -427,7 +450,7 @@ NTSTATUS unix_convert(TALLOC_CTX *ctx,
* struct. JRA. * struct. JRA.
*/ */
*pst = st; smb_fname->st = st;
} }
} else { } else {
@ -621,7 +644,7 @@ NTSTATUS unix_convert(TALLOC_CTX *ctx,
} }
if (ret == 0) { if (ret == 0) {
*pst = st; smb_fname->st = st;
} else { } else {
SET_STAT_INVALID(st); SET_STAT_INVALID(st);
} }
@ -703,35 +726,34 @@ NTSTATUS unix_convert(TALLOC_CTX *ctx,
DEBUG(5,("conversion finished %s -> %s\n",orig_path, name)); DEBUG(5,("conversion finished %s -> %s\n",orig_path, name));
done: done:
if (stream != NULL) { smb_fname->base_name = name;
char *tmp = NULL;
result = build_stream_path(ctx, conn, orig_path, name, stream, if (stream != NULL) {
pst, &tmp); smb_fname->stream_name = stream;
/* Check path now that the base_name has been converted. */
result = build_stream_path(ctx, conn, orig_path, smb_fname);
if (!NT_STATUS_IS_OK(result)) { if (!NT_STATUS_IS_OK(result)) {
goto fail; goto fail;
} }
DEBUG(10, ("build_stream_path returned %s\n", tmp));
TALLOC_FREE(name);
name = tmp;
} }
*pp_conv_path = name;
TALLOC_FREE(dirpath); TALLOC_FREE(dirpath);
*smb_fname_out = smb_fname;
return NT_STATUS_OK; return NT_STATUS_OK;
fail: fail:
DEBUG(10, ("dirpath = [%s] start = [%s]\n", dirpath, start)); DEBUG(10, ("dirpath = [%s] start = [%s]\n", dirpath, start));
if (*dirpath != '\0') { if (*dirpath != '\0') {
*pp_conv_path = talloc_asprintf(ctx, smb_fname->base_name = talloc_asprintf(ctx, "%s/%s", dirpath,
"%s/%s", dirpath, start); start);
} else { } else {
*pp_conv_path = talloc_strdup(ctx, start); smb_fname->base_name = talloc_strdup(ctx, start);
} }
if (!*pp_conv_path) { if (!smb_fname->base_name) {
DEBUG(0, ("talloc_asprintf failed\n")); DEBUG(0, ("talloc_asprintf failed\n"));
return NT_STATUS_NO_MEMORY; return NT_STATUS_NO_MEMORY;
} }
*smb_fname_out = smb_fname;
TALLOC_FREE(name); TALLOC_FREE(name);
TALLOC_FREE(dirpath); TALLOC_FREE(dirpath);
return result; return result;
@ -923,25 +945,19 @@ int get_real_filename(connection_struct *conn, const char *path,
static NTSTATUS build_stream_path(TALLOC_CTX *mem_ctx, static NTSTATUS build_stream_path(TALLOC_CTX *mem_ctx,
connection_struct *conn, connection_struct *conn,
const char *orig_path, const char *orig_path,
const char *basepath, struct smb_filename *smb_fname)
const char *streamname,
SMB_STRUCT_STAT *pst,
char **path)
{ {
SMB_STRUCT_STAT st;
char *result = NULL; char *result = NULL;
NTSTATUS status; NTSTATUS status;
unsigned int i, num_streams; unsigned int i, num_streams;
struct stream_struct *streams = NULL; struct stream_struct *streams = NULL;
result = talloc_asprintf(mem_ctx, "%s%s", basepath, streamname); status = get_full_smb_filename(mem_ctx, smb_fname, &result);
if (result == NULL) { if (!NT_STATUS_IS_OK(status)) {
return NT_STATUS_NO_MEMORY; return NT_STATUS_NO_MEMORY;
} }
if (SMB_VFS_STAT(conn, result, &st) == 0) { if (SMB_VFS_STAT(conn, result, &smb_fname->st) == 0) {
*pst = st;
*path = result;
return NT_STATUS_OK; return NT_STATUS_OK;
} }
@ -951,12 +967,12 @@ static NTSTATUS build_stream_path(TALLOC_CTX *mem_ctx,
goto fail; goto fail;
} }
status = SMB_VFS_STREAMINFO(conn, NULL, basepath, mem_ctx, /* Fall back to a case-insensitive scan of all streams on the file. */
status = SMB_VFS_STREAMINFO(conn, NULL, smb_fname->base_name, mem_ctx,
&num_streams, &streams); &num_streams, &streams);
if (NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_NOT_FOUND)) { if (NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_NOT_FOUND)) {
SET_STAT_INVALID(*pst); SET_STAT_INVALID(smb_fname->st);
*path = result;
return NT_STATUS_OK; return NT_STATUS_OK;
} }
@ -967,8 +983,8 @@ static NTSTATUS build_stream_path(TALLOC_CTX *mem_ctx,
for (i=0; i<num_streams; i++) { for (i=0; i<num_streams; i++) {
DEBUG(10, ("comparing [%s] and [%s]: ", DEBUG(10, ("comparing [%s] and [%s]: ",
streamname, streams[i].name)); smb_fname->stream_name, streams[i].name));
if (fname_equal(streamname, streams[i].name, if (fname_equal(smb_fname->stream_name, streams[i].name,
conn->case_sensitive)) { conn->case_sensitive)) {
DEBUGADD(10, ("equal\n")); DEBUGADD(10, ("equal\n"));
break; break;
@ -976,28 +992,33 @@ static NTSTATUS build_stream_path(TALLOC_CTX *mem_ctx,
DEBUGADD(10, ("not equal\n")); DEBUGADD(10, ("not equal\n"));
} }
/* Couldn't find the stream. */
if (i == num_streams) { if (i == num_streams) {
SET_STAT_INVALID(*pst); SET_STAT_INVALID(smb_fname->st);
*path = result;
TALLOC_FREE(streams); TALLOC_FREE(streams);
return NT_STATUS_OK; return NT_STATUS_OK;
} }
TALLOC_FREE(result); DEBUG(10, ("case insensitive stream. requested: %s, actual: %s\n",
smb_fname->stream_name, streams[i].name));
result = talloc_asprintf(mem_ctx, "%s%s", basepath, streams[i].name);
if (result == NULL) { TALLOC_FREE(smb_fname->stream_name);
smb_fname->stream_name = talloc_strdup(mem_ctx, streams[i].name);
TALLOC_FREE(result);
status = get_full_smb_filename(mem_ctx, smb_fname, &result);
if (!NT_STATUS_IS_OK(status)) {
status = NT_STATUS_NO_MEMORY; status = NT_STATUS_NO_MEMORY;
goto fail; goto fail;
} }
SET_STAT_INVALID(*pst); SET_STAT_INVALID(smb_fname->st);
if (SMB_VFS_STAT(conn, result, pst) == 0) { if (SMB_VFS_STAT(conn, result, &smb_fname->st) == 0) {
stat_cache_add(orig_path, result, conn->case_sensitive); stat_cache_add(orig_path, result, conn->case_sensitive);
} }
*path = result;
TALLOC_FREE(streams); TALLOC_FREE(streams);
return NT_STATUS_OK; return NT_STATUS_OK;

View File

@ -515,8 +515,8 @@ static NTSTATUS dfs_path_lookup(TALLOC_CTX *ctx,
{ {
char *p = NULL; char *p = NULL;
char *q = NULL; char *q = NULL;
SMB_STRUCT_STAT sbuf;
NTSTATUS status; NTSTATUS status;
struct smb_filename *smb_fname = NULL;
char *localpath = NULL; char *localpath = NULL;
char *canon_dfspath = NULL; /* Canonicalized dfs path. (only '/' char *canon_dfspath = NULL; /* Canonicalized dfs path. (only '/'
components). */ components). */
@ -536,13 +536,22 @@ static NTSTATUS dfs_path_lookup(TALLOC_CTX *ctx,
* think this is needed. JRA. * think this is needed. JRA.
*/ */
status = unix_convert(ctx, conn, pdp->reqpath, search_flag, &localpath, status = unix_convert(ctx, conn, pdp->reqpath, &smb_fname,
NULL, &sbuf); search_flag ? UCF_ALLOW_WCARD_LCOMP : 0);
if (!NT_STATUS_IS_OK(status) && !NT_STATUS_EQUAL(status, if (!NT_STATUS_IS_OK(status) && !NT_STATUS_EQUAL(status,
NT_STATUS_OBJECT_PATH_NOT_FOUND)) { NT_STATUS_OBJECT_PATH_NOT_FOUND)) {
return status; return status;
} }
status = get_full_smb_filename(ctx, smb_fname, &localpath);
if (!NT_STATUS_IS_OK(status)) {
TALLOC_FREE(smb_fname);
return status;
}
TALLOC_FREE(smb_fname);
/* Optimization - check if we can redirect the whole path. */ /* Optimization - check if we can redirect the whole path. */
if (is_msdfs_link_internal(ctx, conn, localpath, pp_targetpath, NULL)) { if (is_msdfs_link_internal(ctx, conn, localpath, pp_targetpath, NULL)) {

View File

@ -1155,11 +1155,10 @@ static NTSTATUS copy_internals(TALLOC_CTX *ctx,
const char *newname_in, const char *newname_in,
uint32 attrs) uint32 attrs)
{ {
SMB_STRUCT_STAT sbuf1, sbuf2; struct smb_filename *smb_fname = NULL;
struct smb_filename *smb_fname_new = NULL;
char *oldname = NULL; char *oldname = NULL;
char *newname = NULL; char *newname = NULL;
char *last_component_oldname = NULL;
char *last_component_newname = NULL;
files_struct *fsp1,*fsp2; files_struct *fsp1,*fsp2;
uint32 fattr; uint32 fattr;
int info; int info;
@ -1167,59 +1166,69 @@ static NTSTATUS copy_internals(TALLOC_CTX *ctx,
NTSTATUS status = NT_STATUS_OK; NTSTATUS status = NT_STATUS_OK;
char *parent; char *parent;
ZERO_STRUCT(sbuf1);
ZERO_STRUCT(sbuf2);
if (!CAN_WRITE(conn)) { if (!CAN_WRITE(conn)) {
return NT_STATUS_MEDIA_WRITE_PROTECTED; status = NT_STATUS_MEDIA_WRITE_PROTECTED;
goto out;
} }
status = unix_convert(ctx, conn, oldname_in, False, &oldname, status = unix_convert(ctx, conn, oldname_in, &smb_fname, 0);
&last_component_oldname, &sbuf1);
if (!NT_STATUS_IS_OK(status)) { if (!NT_STATUS_IS_OK(status)) {
return status; goto out;
}
status = get_full_smb_filename(ctx, smb_fname, &oldname);
if (!NT_STATUS_IS_OK(status)) {
goto out;
} }
status = check_name(conn, oldname); status = check_name(conn, oldname);
if (!NT_STATUS_IS_OK(status)) { if (!NT_STATUS_IS_OK(status)) {
return status; goto out;
} }
/* Source must already exist. */ /* Source must already exist. */
if (!VALID_STAT(sbuf1)) { if (!VALID_STAT(smb_fname->st)) {
return NT_STATUS_OBJECT_NAME_NOT_FOUND; status = NT_STATUS_OBJECT_NAME_NOT_FOUND;
goto out;
} }
/* Ensure attributes match. */ /* Ensure attributes match. */
fattr = dos_mode(conn,oldname,&sbuf1); fattr = dos_mode(conn, oldname, &smb_fname->st);
if ((fattr & ~attrs) & (aHIDDEN | aSYSTEM)) { if ((fattr & ~attrs) & (aHIDDEN | aSYSTEM)) {
return NT_STATUS_NO_SUCH_FILE; status = NT_STATUS_NO_SUCH_FILE;
goto out;
} }
status = unix_convert(ctx, conn, newname_in, False, &newname, status = unix_convert(ctx, conn, newname_in, &smb_fname_new, 0);
&last_component_newname, &sbuf2);
if (!NT_STATUS_IS_OK(status)) { if (!NT_STATUS_IS_OK(status)) {
return status; goto out;
}
status = get_full_smb_filename(ctx, smb_fname_new, &newname);
if (!NT_STATUS_IS_OK(status)) {
goto out;
} }
status = check_name(conn, newname); status = check_name(conn, newname);
if (!NT_STATUS_IS_OK(status)) { if (!NT_STATUS_IS_OK(status)) {
return status; goto out;
} }
/* Disallow if newname already exists. */ /* Disallow if newname already exists. */
if (VALID_STAT(sbuf2)) { if (VALID_STAT(smb_fname_new->st)) {
return NT_STATUS_OBJECT_NAME_COLLISION; status = NT_STATUS_OBJECT_NAME_COLLISION;
goto out;
} }
/* No links from a directory. */ /* No links from a directory. */
if (S_ISDIR(sbuf1.st_mode)) { if (S_ISDIR(smb_fname->st.st_mode)) {
return NT_STATUS_FILE_IS_A_DIRECTORY; status = NT_STATUS_FILE_IS_A_DIRECTORY;
goto out;
} }
/* Ensure this is within the share. */ /* Ensure this is within the share. */
status = check_reduced_name(conn, oldname); status = check_reduced_name(conn, oldname);
if (!NT_STATUS_IS_OK(status)) { if (!NT_STATUS_IS_OK(status)) {
return status; goto out;
} }
DEBUG(10,("copy_internals: doing file copy %s to %s\n", DEBUG(10,("copy_internals: doing file copy %s to %s\n",
@ -1243,10 +1252,10 @@ static NTSTATUS copy_internals(TALLOC_CTX *ctx,
NULL, /* ea_list */ NULL, /* ea_list */
&fsp1, /* result */ &fsp1, /* result */
&info, /* pinfo */ &info, /* pinfo */
&sbuf1); /* psbuf */ &smb_fname->st); /* psbuf */
if (!NT_STATUS_IS_OK(status)) { if (!NT_STATUS_IS_OK(status)) {
return status; goto out;
} }
status = SMB_VFS_CREATE_FILE( status = SMB_VFS_CREATE_FILE(
@ -1267,15 +1276,15 @@ static NTSTATUS copy_internals(TALLOC_CTX *ctx,
NULL, /* ea_list */ NULL, /* ea_list */
&fsp2, /* result */ &fsp2, /* result */
&info, /* pinfo */ &info, /* pinfo */
&sbuf2); /* psbuf */ &smb_fname_new->st); /* psbuf */
if (!NT_STATUS_IS_OK(status)) { if (!NT_STATUS_IS_OK(status)) {
close_file(NULL, fsp1, ERROR_CLOSE); close_file(NULL, fsp1, ERROR_CLOSE);
return status; goto out;
} }
if (sbuf1.st_size) { if (smb_fname->st.st_size) {
ret = vfs_transfer_file(fsp1, fsp2, sbuf1.st_size); ret = vfs_transfer_file(fsp1, fsp2, smb_fname->st.st_size);
} }
/* /*
@ -1287,7 +1296,7 @@ static NTSTATUS copy_internals(TALLOC_CTX *ctx,
close_file(NULL, fsp1, NORMAL_CLOSE); close_file(NULL, fsp1, NORMAL_CLOSE);
/* Ensure the modtime is set correctly on the destination file. */ /* Ensure the modtime is set correctly on the destination file. */
set_close_write_time(fsp2, get_mtimespec(&sbuf1)); set_close_write_time(fsp2, get_mtimespec(&smb_fname->st));
status = close_file(NULL, fsp2, NORMAL_CLOSE); status = close_file(NULL, fsp2, NORMAL_CLOSE);
@ -1295,15 +1304,24 @@ static NTSTATUS copy_internals(TALLOC_CTX *ctx,
creates the file. This isn't the correct thing to do in the copy creates the file. This isn't the correct thing to do in the copy
case. JRA */ case. JRA */
if (!parent_dirname(talloc_tos(), newname, &parent, NULL)) { if (!parent_dirname(talloc_tos(), newname, &parent, NULL)) {
return NT_STATUS_NO_MEMORY; status = NT_STATUS_NO_MEMORY;
goto out;
} }
file_set_dosmode(conn, newname, fattr, &sbuf2, parent, false); file_set_dosmode(conn, newname, fattr, &smb_fname_new->st, parent,
false);
TALLOC_FREE(parent); TALLOC_FREE(parent);
if (ret < (SMB_OFF_T)sbuf1.st_size) { if (ret < (SMB_OFF_T)smb_fname->st.st_size) {
return NT_STATUS_DISK_FULL; status = NT_STATUS_DISK_FULL;
goto out;
}
out:
if (smb_fname) {
TALLOC_FREE(smb_fname);
}
if (smb_fname_new) {
TALLOC_FREE(smb_fname_new);
} }
if (!NT_STATUS_IS_OK(status)) { if (!NT_STATUS_IS_OK(status)) {
DEBUG(3,("copy_internals: Error %s copy file %s to %s\n", DEBUG(3,("copy_internals: Error %s copy file %s to %s\n",
nt_errstr(status), oldname, newname)); nt_errstr(status), oldname, newname));

View File

@ -3442,16 +3442,27 @@ NTSTATUS create_file_default(connection_struct *conn,
} }
if (create_file_flags & CFF_DOS_PATH) { if (create_file_flags & CFF_DOS_PATH) {
struct smb_filename *smb_fname = NULL;
char *converted_fname; char *converted_fname;
SET_STAT_INVALID(sbuf); SET_STAT_INVALID(sbuf);
status = unix_convert(talloc_tos(), conn, fname, False, status = unix_convert(talloc_tos(), conn, fname, &smb_fname,
&converted_fname, NULL, &sbuf); 0);
if (!NT_STATUS_IS_OK(status)) { if (!NT_STATUS_IS_OK(status)) {
goto fail; goto fail;
} }
status = get_full_smb_filename(talloc_tos(), smb_fname,
&converted_fname);
if (!NT_STATUS_IS_OK(status)) {
TALLOC_FREE(smb_fname);
goto fail;
}
sbuf = smb_fname->st;
fname = converted_fname; fname = converted_fname;
TALLOC_FREE(smb_fname);
} else { } else {
if (psbuf != NULL) { if (psbuf != NULL) {
sbuf = *psbuf; sbuf = *psbuf;

File diff suppressed because it is too large Load Diff

View File

@ -1882,6 +1882,7 @@ static void call_trans2findfirst(connection_struct *conn,
maxentries then so be it. We assume that the redirector has maxentries then so be it. We assume that the redirector has
enough room for the fixed number of parameter bytes it has enough room for the fixed number of parameter bytes it has
requested. */ requested. */
struct smb_filename *smb_dname = NULL;
char *params = *pparams; char *params = *pparams;
char *pdata = *ppdata; char *pdata = *ppdata;
char *data_end; char *data_end;
@ -1904,7 +1905,6 @@ static void call_trans2findfirst(connection_struct *conn,
bool out_of_space = False; bool out_of_space = False;
int space_remaining; int space_remaining;
bool mask_contains_wcard = False; bool mask_contains_wcard = False;
SMB_STRUCT_STAT sbuf;
struct ea_list *ea_list = NULL; struct ea_list *ea_list = NULL;
NTSTATUS ntstatus = NT_STATUS_OK; NTSTATUS ntstatus = NT_STATUS_OK;
bool ask_sharemode = lp_parm_bool(SNUM(conn), "smbd", "search ask sharemode", true); bool ask_sharemode = lp_parm_bool(SNUM(conn), "smbd", "search ask sharemode", true);
@ -1981,7 +1981,17 @@ close_if_end = %d requires_resume_key = %d level = 0x%x, max_data_bytes = %d\n",
return; return;
} }
ntstatus = unix_convert(ctx, conn, directory, True, &directory, &mask, &sbuf); ntstatus = unix_convert(ctx, conn, directory, &smb_dname,
(UCF_SAVE_LCOMP | UCF_ALLOW_WCARD_LCOMP));
if (!NT_STATUS_IS_OK(ntstatus)) {
reply_nterror(req, ntstatus);
return;
}
mask = smb_dname->original_lcomp;
ntstatus = get_full_smb_filename(ctx, smb_dname, &directory);
TALLOC_FREE(smb_dname);
if (!NT_STATUS_IS_OK(ntstatus)) { if (!NT_STATUS_IS_OK(ntstatus)) {
reply_nterror(req, ntstatus); reply_nterror(req, ntstatus);
return; return;
@ -3834,6 +3844,7 @@ static void call_trans2qfilepathinfo(connection_struct *conn,
SMB_STRUCT_STAT sbuf; SMB_STRUCT_STAT sbuf;
char *dos_fname = NULL; char *dos_fname = NULL;
char *fname = NULL; char *fname = NULL;
struct smb_filename *smb_fname = NULL;
char *fullpathname; char *fullpathname;
char *base_name; char *base_name;
char *p; char *p;
@ -3981,11 +3992,20 @@ static void call_trans2qfilepathinfo(connection_struct *conn,
return; return;
} }
status = unix_convert(ctx, conn, fname, False, &fname, NULL, &sbuf); status = unix_convert(ctx, conn, fname, &smb_fname, 0);
if (!NT_STATUS_IS_OK(status)) { if (!NT_STATUS_IS_OK(status)) {
reply_nterror(req, status); reply_nterror(req, status);
return; return;
} }
sbuf = smb_fname->st;
status = get_full_smb_filename(ctx, smb_fname, &fname);
TALLOC_FREE(smb_fname);
if (!NT_STATUS_IS_OK(status)) {
reply_nterror(req, status);
return;
}
status = check_name(conn, fname); status = check_name(conn, fname);
if (!NT_STATUS_IS_OK(status)) { if (!NT_STATUS_IS_OK(status)) {
DEBUG(3,("call_trans2qfilepathinfo: fileinfo of %s failed (%s)\n",fname,nt_errstr(status))); DEBUG(3,("call_trans2qfilepathinfo: fileinfo of %s failed (%s)\n",fname,nt_errstr(status)));
@ -4821,57 +4841,64 @@ NTSTATUS hardlink_internals(TALLOC_CTX *ctx,
const char *oldname_in, const char *oldname_in,
const char *newname_in) const char *newname_in)
{ {
SMB_STRUCT_STAT sbuf1, sbuf2; struct smb_filename *smb_fname = NULL;
char *last_component_oldname = NULL; struct smb_filename *smb_fname_new = NULL;
char *last_component_newname = NULL;
char *oldname = NULL; char *oldname = NULL;
char *newname = NULL; char *newname = NULL;
NTSTATUS status = NT_STATUS_OK; NTSTATUS status = NT_STATUS_OK;
ZERO_STRUCT(sbuf1); status = unix_convert(ctx, conn, oldname_in, &smb_fname, 0);
ZERO_STRUCT(sbuf2);
status = unix_convert(ctx, conn, oldname_in, False, &oldname,
&last_component_oldname, &sbuf1);
if (!NT_STATUS_IS_OK(status)) { if (!NT_STATUS_IS_OK(status)) {
return status; goto out;
}
status = get_full_smb_filename(ctx, smb_fname, &oldname);
if (!NT_STATUS_IS_OK(status)) {
goto out;
} }
status = check_name(conn, oldname); status = check_name(conn, oldname);
if (!NT_STATUS_IS_OK(status)) { if (!NT_STATUS_IS_OK(status)) {
return status; goto out;
} }
/* source must already exist. */ /* source must already exist. */
if (!VALID_STAT(sbuf1)) { if (!VALID_STAT(smb_fname->st)) {
return NT_STATUS_OBJECT_NAME_NOT_FOUND; status = NT_STATUS_OBJECT_NAME_NOT_FOUND;
goto out;
} }
status = unix_convert(ctx, conn, newname_in, False, &newname, status = unix_convert(ctx, conn, newname_in, &smb_fname_new, 0);
&last_component_newname, &sbuf2);
if (!NT_STATUS_IS_OK(status)) { if (!NT_STATUS_IS_OK(status)) {
return status; goto out;
}
status = get_full_smb_filename(ctx, smb_fname_new, &newname);
if (!NT_STATUS_IS_OK(status)) {
goto out;
} }
status = check_name(conn, newname); status = check_name(conn, newname);
if (!NT_STATUS_IS_OK(status)) { if (!NT_STATUS_IS_OK(status)) {
return status; goto out;
} }
/* Disallow if newname already exists. */ /* Disallow if newname already exists. */
if (VALID_STAT(sbuf2)) { if (VALID_STAT(smb_fname_new->st)) {
return NT_STATUS_OBJECT_NAME_COLLISION; status = NT_STATUS_OBJECT_NAME_COLLISION;
goto out;
} }
/* No links from a directory. */ /* No links from a directory. */
if (S_ISDIR(sbuf1.st_mode)) { if (S_ISDIR(smb_fname->st.st_mode)) {
return NT_STATUS_FILE_IS_A_DIRECTORY; status = NT_STATUS_FILE_IS_A_DIRECTORY;
goto out;
} }
/* Ensure this is within the share. */ /* Ensure this is within the share. */
status = check_reduced_name(conn, oldname); status = check_reduced_name(conn, oldname);
if (!NT_STATUS_IS_OK(status)) { if (!NT_STATUS_IS_OK(status)) {
return status; goto out;
} }
DEBUG(10,("hardlink_internals: doing hard link %s -> %s\n", newname, oldname )); DEBUG(10,("hardlink_internals: doing hard link %s -> %s\n", newname, oldname ));
@ -4879,9 +4906,15 @@ NTSTATUS hardlink_internals(TALLOC_CTX *ctx,
if (SMB_VFS_LINK(conn,oldname,newname) != 0) { if (SMB_VFS_LINK(conn,oldname,newname) != 0) {
status = map_nt_error_from_unix(errno); status = map_nt_error_from_unix(errno);
DEBUG(3,("hardlink_internals: Error %s hard link %s -> %s\n", DEBUG(3,("hardlink_internals: Error %s hard link %s -> %s\n",
nt_errstr(status), newname, oldname)); nt_errstr(status), newname, oldname));
}
out:
if (smb_fname) {
TALLOC_FREE(smb_fname);
}
if (smb_fname_new) {
TALLOC_FREE(smb_fname_new);
} }
return status; return status;
} }
@ -5382,9 +5415,8 @@ static NTSTATUS smb_file_rename_information(connection_struct *conn,
uint32 len; uint32 len;
char *newname = NULL; char *newname = NULL;
char *base_name = NULL; char *base_name = NULL;
struct smb_filename *smb_fname = NULL;
bool dest_has_wcard = False; bool dest_has_wcard = False;
SMB_STRUCT_STAT sbuf;
char *newname_last_component = NULL;
NTSTATUS status = NT_STATUS_OK; NTSTATUS status = NT_STATUS_OK;
char *p; char *p;
TALLOC_CTX *ctx = talloc_tos(); TALLOC_CTX *ctx = talloc_tos();
@ -5393,8 +5425,6 @@ static NTSTATUS smb_file_rename_information(connection_struct *conn,
return NT_STATUS_INVALID_PARAMETER; return NT_STATUS_INVALID_PARAMETER;
} }
ZERO_STRUCT(sbuf);
overwrite = (CVAL(pdata,0) ? True : False); overwrite = (CVAL(pdata,0) ? True : False);
root_fid = IVAL(pdata,4); root_fid = IVAL(pdata,4);
len = IVAL(pdata,8); len = IVAL(pdata,8);
@ -5466,10 +5496,8 @@ static NTSTATUS smb_file_rename_information(connection_struct *conn,
return NT_STATUS_NO_MEMORY; return NT_STATUS_NO_MEMORY;
} }
status = unix_convert(ctx, conn, newname, False, status = unix_convert(ctx, conn, newname, &smb_fname,
&newname, UCF_SAVE_LCOMP);
&newname_last_component,
&sbuf);
/* If an error we expect this to be /* If an error we expect this to be
* NT_STATUS_OBJECT_PATH_NOT_FOUND */ * NT_STATUS_OBJECT_PATH_NOT_FOUND */
@ -5477,7 +5505,7 @@ static NTSTATUS smb_file_rename_information(connection_struct *conn,
if (!NT_STATUS_IS_OK(status) if (!NT_STATUS_IS_OK(status)
&& !NT_STATUS_EQUAL(NT_STATUS_OBJECT_PATH_NOT_FOUND, && !NT_STATUS_EQUAL(NT_STATUS_OBJECT_PATH_NOT_FOUND,
status)) { status)) {
return status; goto out;
} }
} }
@ -5485,8 +5513,9 @@ static NTSTATUS smb_file_rename_information(connection_struct *conn,
DEBUG(10,("smb_file_rename_information: SMB_FILE_RENAME_INFORMATION (fnum %d) %s -> %s\n", DEBUG(10,("smb_file_rename_information: SMB_FILE_RENAME_INFORMATION (fnum %d) %s -> %s\n",
fsp->fnum, fsp->fsp_name, base_name )); fsp->fnum, fsp->fsp_name, base_name ));
status = rename_internals_fsp(conn, fsp, base_name, status = rename_internals_fsp(conn, fsp, base_name,
newname_last_component, 0, smb_fname ?
overwrite); smb_fname->original_lcomp : NULL,
0, overwrite);
} else { } else {
DEBUG(10,("smb_file_rename_information: SMB_FILE_RENAME_INFORMATION %s -> %s\n", DEBUG(10,("smb_file_rename_information: SMB_FILE_RENAME_INFORMATION %s -> %s\n",
fname, base_name )); fname, base_name ));
@ -5494,7 +5523,10 @@ static NTSTATUS smb_file_rename_information(connection_struct *conn,
overwrite, False, dest_has_wcard, overwrite, False, dest_has_wcard,
FILE_WRITE_ATTRIBUTES); FILE_WRITE_ATTRIBUTES);
} }
out:
if (smb_fname) {
TALLOC_FREE(smb_fname);
}
return status; return status;
} }
@ -6700,6 +6732,7 @@ static void call_trans2setfilepathinfo(connection_struct *conn,
uint16 info_level; uint16 info_level;
SMB_STRUCT_STAT sbuf; SMB_STRUCT_STAT sbuf;
char *fname = NULL; char *fname = NULL;
struct smb_filename *smb_fname = NULL;
files_struct *fsp = NULL; files_struct *fsp = NULL;
NTSTATUS status = NT_STATUS_OK; NTSTATUS status = NT_STATUS_OK;
int data_return_size = 0; int data_return_size = 0;
@ -6814,8 +6847,15 @@ static void call_trans2setfilepathinfo(connection_struct *conn,
return; return;
} }
status = unix_convert(ctx, conn, fname, False, status = unix_convert(ctx, conn, fname, &smb_fname, 0);
&fname, NULL, &sbuf); if (!NT_STATUS_IS_OK(status)) {
reply_nterror(req, status);
return;
}
sbuf = smb_fname->st;
status = get_full_smb_filename(ctx, smb_fname, &fname);
TALLOC_FREE(smb_fname);
if (!NT_STATUS_IS_OK(status)) { if (!NT_STATUS_IS_OK(status)) {
reply_nterror(req, status); reply_nterror(req, status);
return; return;
@ -7129,10 +7169,10 @@ static void call_trans2mkdir(connection_struct *conn, struct smb_request *req,
char **ppdata, int total_data, char **ppdata, int total_data,
unsigned int max_data_bytes) unsigned int max_data_bytes)
{ {
struct smb_filename *smb_dname = NULL;
char *params = *pparams; char *params = *pparams;
char *pdata = *ppdata; char *pdata = *ppdata;
char *directory = NULL; char *directory = NULL;
SMB_STRUCT_STAT sbuf;
NTSTATUS status = NT_STATUS_OK; NTSTATUS status = NT_STATUS_OK;
struct ea_list *ea_list = NULL; struct ea_list *ea_list = NULL;
TALLOC_CTX *ctx = talloc_tos(); TALLOC_CTX *ctx = talloc_tos();
@ -7157,7 +7197,13 @@ static void call_trans2mkdir(connection_struct *conn, struct smb_request *req,
DEBUG(3,("call_trans2mkdir : name = %s\n", directory)); DEBUG(3,("call_trans2mkdir : name = %s\n", directory));
status = unix_convert(ctx, conn, directory, False, &directory, NULL, &sbuf); status = unix_convert(ctx, conn, directory, &smb_dname, 0);
if (!NT_STATUS_IS_OK(status)) {
reply_nterror(req, status);
return;
}
status = get_full_smb_filename(ctx, smb_dname, &directory);
if (!NT_STATUS_IS_OK(status)) { if (!NT_STATUS_IS_OK(status)) {
reply_nterror(req, status); reply_nterror(req, status);
return; return;