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 */
NTSTATUS get_full_smb_filename(TALLOC_CTX *ctx, const struct smb_filename *smb_fname,
char **full_name);
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);
connection_struct *conn,
const char *orig_path,
struct smb_filename **smb_fname,
uint32_t ucf_flags);
NTSTATUS check_name(connection_struct *conn, const char *name);
int get_real_filename(connection_struct *conn, const char *path,
const char *name, TALLOC_CTX *mem_ctx,

View File

@ -1925,4 +1925,20 @@ struct smb_file_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 */

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. */
if (create_file_flags & CFF_DOS_PATH) {
struct smb_filename *smb_fname = NULL;
char *converted_fname;
SET_STAT_INVALID(sbuf);
status = unix_convert(talloc_tos(), conn, fname, False,
&converted_fname, NULL, &sbuf);
status = unix_convert(talloc_tos(), conn, fname, &smb_fname,
0);
if (!NT_STATUS_IS_OK(status)) {
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;
TALLOC_FREE(smb_fname);
} else {
if (psbuf != NULL) {
sbuf = *psbuf;

View File

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

View File

@ -29,10 +29,7 @@
static NTSTATUS build_stream_path(TALLOC_CTX *mem_ctx,
connection_struct *conn,
const char *orig_path,
const char *basepath,
const char *streamname,
SMB_STRUCT_STAT *pst,
char **path);
struct smb_filename *smb_fname);
/****************************************************************************
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
namespace. It needs to handle any case conversions, mangling, format
changes etc.
namespace. It needs to handle any case conversions, mangling, format changes,
streams etc.
We assume that we have already done a chdir() to the right "root" directory
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 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
get any fatal errors that should immediately terminate the calling
SMB processing whilst resolving.
Note NT_STATUS_OK doesn't mean the name exists or is valid, just that we
didn't get any fatal errors that should immediately terminate the calling SMB
processing whilst resolving.
If the saved_last_component != 0, then the unmodified last component
of the pathname is returned there. If saved_last_component == 0 then nothing
is returned there.
If the UCF_SAVE_LCOMP flag is passed in, then the unmodified last component
of the pathname is set in smb_filename->original_lcomp.
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.
On exit from unix_convert, if *pst was not null, then the file stat
struct will be returned 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).
If the orig_path was a stream, smb_filename->base_name will point to the base
filename, and smb_filename->stream_name will point to the stream name. If
orig_path was not a stream, then smb_filename->stream_name will be NULL.
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,
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)
connection_struct *conn,
const char *orig_path,
struct smb_filename **smb_fname_out,
uint32_t ucf_flags)
{
SMB_STRUCT_STAT st;
struct smb_filename *smb_fname = NULL;
char *start, *end;
char *dirpath = NULL;
char *name = NULL;
@ -127,21 +143,26 @@ NTSTATUS unix_convert(TALLOC_CTX *ctx,
bool component_was_mangled = False;
bool name_has_wildcard = 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;
int ret = -1;
SET_STAT_INVALID(*pst);
*pp_conv_path = NULL;
if(pp_saved_last_component) {
*pp_saved_last_component = NULL;
*smb_fname_out = NULL;
smb_fname = TALLOC_ZERO_P(talloc_tos(), struct smb_filename);
if (smb_fname == NULL) {
return NT_STATUS_NO_MEMORY;
}
if (conn->printer) {
/* we don't ever use the filenames on a printer share as a
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;
}
*smb_fname_out = smb_fname;
return NT_STATUS_OK;
}
@ -174,7 +195,7 @@ NTSTATUS unix_convert(TALLOC_CTX *ctx,
return NT_STATUS_NO_MEMORY;
}
if (SMB_VFS_STAT(conn,name,&st) == 0) {
*pst = st;
smb_fname->st = st;
} else {
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.
*/
if(pp_saved_last_component) {
if(save_last_component) {
end = strrchr_m(name, '/');
if (end) {
*pp_saved_last_component = talloc_strdup(ctx, end + 1);
smb_fname->original_lcomp = talloc_strdup(ctx,
end + 1);
} else {
*pp_saved_last_component = talloc_strdup(ctx,
name);
smb_fname->original_lcomp = talloc_strdup(ctx, name);
}
}
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) {
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)) &&
stat_cache_lookup(conn, &name, &dirpath, &start, &st)) {
*pst = st;
smb_fname->st = st;
goto done;
}
@ -295,7 +318,7 @@ NTSTATUS unix_convert(TALLOC_CTX *ctx,
}
stat_cache_add(orig_path, name, conn->case_sensitive);
DEBUG(5,("conversion finished %s -> %s\n",orig_path, name));
*pst = st;
smb_fname->st = st;
goto done;
}
@ -346,11 +369,11 @@ NTSTATUS unix_convert(TALLOC_CTX *ctx,
*end = 0;
}
if (pp_saved_last_component) {
TALLOC_FREE(*pp_saved_last_component);
*pp_saved_last_component = talloc_strdup(ctx,
if (save_last_component) {
TALLOC_FREE(smb_fname->original_lcomp);
smb_fname->original_lcomp = talloc_strdup(ctx,
end ? end + 1 : start);
if (!*pp_saved_last_component) {
if (!smb_fname->original_lcomp) {
DEBUG(0, ("talloc failed\n"));
return NT_STATUS_NO_MEMORY;
}
@ -427,7 +450,7 @@ NTSTATUS unix_convert(TALLOC_CTX *ctx,
* struct. JRA.
*/
*pst = st;
smb_fname->st = st;
}
} else {
@ -621,7 +644,7 @@ NTSTATUS unix_convert(TALLOC_CTX *ctx,
}
if (ret == 0) {
*pst = st;
smb_fname->st = st;
} else {
SET_STAT_INVALID(st);
}
@ -703,35 +726,34 @@ NTSTATUS unix_convert(TALLOC_CTX *ctx,
DEBUG(5,("conversion finished %s -> %s\n",orig_path, name));
done:
if (stream != NULL) {
char *tmp = NULL;
smb_fname->base_name = name;
result = build_stream_path(ctx, conn, orig_path, name, stream,
pst, &tmp);
if (stream != NULL) {
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)) {
goto fail;
}
DEBUG(10, ("build_stream_path returned %s\n", tmp));
TALLOC_FREE(name);
name = tmp;
}
*pp_conv_path = name;
TALLOC_FREE(dirpath);
*smb_fname_out = smb_fname;
return NT_STATUS_OK;
fail:
DEBUG(10, ("dirpath = [%s] start = [%s]\n", dirpath, start));
if (*dirpath != '\0') {
*pp_conv_path = talloc_asprintf(ctx,
"%s/%s", dirpath, start);
smb_fname->base_name = talloc_asprintf(ctx, "%s/%s", dirpath,
start);
} 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"));
return NT_STATUS_NO_MEMORY;
}
*smb_fname_out = smb_fname;
TALLOC_FREE(name);
TALLOC_FREE(dirpath);
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,
connection_struct *conn,
const char *orig_path,
const char *basepath,
const char *streamname,
SMB_STRUCT_STAT *pst,
char **path)
struct smb_filename *smb_fname)
{
SMB_STRUCT_STAT st;
char *result = NULL;
NTSTATUS status;
unsigned int i, num_streams;
struct stream_struct *streams = NULL;
result = talloc_asprintf(mem_ctx, "%s%s", basepath, streamname);
if (result == NULL) {
status = get_full_smb_filename(mem_ctx, smb_fname, &result);
if (!NT_STATUS_IS_OK(status)) {
return NT_STATUS_NO_MEMORY;
}
if (SMB_VFS_STAT(conn, result, &st) == 0) {
*pst = st;
*path = result;
if (SMB_VFS_STAT(conn, result, &smb_fname->st) == 0) {
return NT_STATUS_OK;
}
@ -951,12 +967,12 @@ static NTSTATUS build_stream_path(TALLOC_CTX *mem_ctx,
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);
if (NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_NOT_FOUND)) {
SET_STAT_INVALID(*pst);
*path = result;
SET_STAT_INVALID(smb_fname->st);
return NT_STATUS_OK;
}
@ -967,8 +983,8 @@ static NTSTATUS build_stream_path(TALLOC_CTX *mem_ctx,
for (i=0; i<num_streams; i++) {
DEBUG(10, ("comparing [%s] and [%s]: ",
streamname, streams[i].name));
if (fname_equal(streamname, streams[i].name,
smb_fname->stream_name, streams[i].name));
if (fname_equal(smb_fname->stream_name, streams[i].name,
conn->case_sensitive)) {
DEBUGADD(10, ("equal\n"));
break;
@ -976,28 +992,33 @@ static NTSTATUS build_stream_path(TALLOC_CTX *mem_ctx,
DEBUGADD(10, ("not equal\n"));
}
/* Couldn't find the stream. */
if (i == num_streams) {
SET_STAT_INVALID(*pst);
*path = result;
SET_STAT_INVALID(smb_fname->st);
TALLOC_FREE(streams);
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;
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);
}
*path = result;
TALLOC_FREE(streams);
return NT_STATUS_OK;

View File

@ -515,8 +515,8 @@ static NTSTATUS dfs_path_lookup(TALLOC_CTX *ctx,
{
char *p = NULL;
char *q = NULL;
SMB_STRUCT_STAT sbuf;
NTSTATUS status;
struct smb_filename *smb_fname = NULL;
char *localpath = NULL;
char *canon_dfspath = NULL; /* Canonicalized dfs path. (only '/'
components). */
@ -536,13 +536,22 @@ static NTSTATUS dfs_path_lookup(TALLOC_CTX *ctx,
* think this is needed. JRA.
*/
status = unix_convert(ctx, conn, pdp->reqpath, search_flag, &localpath,
NULL, &sbuf);
status = unix_convert(ctx, conn, pdp->reqpath, &smb_fname,
search_flag ? UCF_ALLOW_WCARD_LCOMP : 0);
if (!NT_STATUS_IS_OK(status) && !NT_STATUS_EQUAL(status,
NT_STATUS_OBJECT_PATH_NOT_FOUND)) {
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. */
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,
uint32 attrs)
{
SMB_STRUCT_STAT sbuf1, sbuf2;
struct smb_filename *smb_fname = NULL;
struct smb_filename *smb_fname_new = NULL;
char *oldname = NULL;
char *newname = NULL;
char *last_component_oldname = NULL;
char *last_component_newname = NULL;
files_struct *fsp1,*fsp2;
uint32 fattr;
int info;
@ -1167,59 +1166,69 @@ static NTSTATUS copy_internals(TALLOC_CTX *ctx,
NTSTATUS status = NT_STATUS_OK;
char *parent;
ZERO_STRUCT(sbuf1);
ZERO_STRUCT(sbuf2);
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,
&last_component_oldname, &sbuf1);
status = unix_convert(ctx, conn, oldname_in, &smb_fname, 0);
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);
if (!NT_STATUS_IS_OK(status)) {
return status;
goto out;
}
/* Source must already exist. */
if (!VALID_STAT(sbuf1)) {
return NT_STATUS_OBJECT_NAME_NOT_FOUND;
if (!VALID_STAT(smb_fname->st)) {
status = NT_STATUS_OBJECT_NAME_NOT_FOUND;
goto out;
}
/* Ensure attributes match. */
fattr = dos_mode(conn,oldname,&sbuf1);
fattr = dos_mode(conn, oldname, &smb_fname->st);
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,
&last_component_newname, &sbuf2);
status = unix_convert(ctx, conn, newname_in, &smb_fname_new, 0);
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);
if (!NT_STATUS_IS_OK(status)) {
return status;
goto out;
}
/* Disallow if newname already exists. */
if (VALID_STAT(sbuf2)) {
return NT_STATUS_OBJECT_NAME_COLLISION;
if (VALID_STAT(smb_fname_new->st)) {
status = NT_STATUS_OBJECT_NAME_COLLISION;
goto out;
}
/* No links from a directory. */
if (S_ISDIR(sbuf1.st_mode)) {
return NT_STATUS_FILE_IS_A_DIRECTORY;
if (S_ISDIR(smb_fname->st.st_mode)) {
status = NT_STATUS_FILE_IS_A_DIRECTORY;
goto out;
}
/* Ensure this is within the share. */
status = check_reduced_name(conn, oldname);
if (!NT_STATUS_IS_OK(status)) {
return status;
goto out;
}
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 */
&fsp1, /* result */
&info, /* pinfo */
&sbuf1); /* psbuf */
&smb_fname->st); /* psbuf */
if (!NT_STATUS_IS_OK(status)) {
return status;
goto out;
}
status = SMB_VFS_CREATE_FILE(
@ -1267,15 +1276,15 @@ static NTSTATUS copy_internals(TALLOC_CTX *ctx,
NULL, /* ea_list */
&fsp2, /* result */
&info, /* pinfo */
&sbuf2); /* psbuf */
&smb_fname_new->st); /* psbuf */
if (!NT_STATUS_IS_OK(status)) {
close_file(NULL, fsp1, ERROR_CLOSE);
return status;
goto out;
}
if (sbuf1.st_size) {
ret = vfs_transfer_file(fsp1, fsp2, sbuf1.st_size);
if (smb_fname->st.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);
/* 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);
@ -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
case. JRA */
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);
if (ret < (SMB_OFF_T)sbuf1.st_size) {
return NT_STATUS_DISK_FULL;
if (ret < (SMB_OFF_T)smb_fname->st.st_size) {
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)) {
DEBUG(3,("copy_internals: Error %s copy file %s to %s\n",
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) {
struct smb_filename *smb_fname = NULL;
char *converted_fname;
SET_STAT_INVALID(sbuf);
status = unix_convert(talloc_tos(), conn, fname, False,
&converted_fname, NULL, &sbuf);
status = unix_convert(talloc_tos(), conn, fname, &smb_fname,
0);
if (!NT_STATUS_IS_OK(status)) {
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;
TALLOC_FREE(smb_fname);
} else {
if (psbuf != NULL) {
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
enough room for the fixed number of parameter bytes it has
requested. */
struct smb_filename *smb_dname = NULL;
char *params = *pparams;
char *pdata = *ppdata;
char *data_end;
@ -1904,7 +1905,6 @@ static void call_trans2findfirst(connection_struct *conn,
bool out_of_space = False;
int space_remaining;
bool mask_contains_wcard = False;
SMB_STRUCT_STAT sbuf;
struct ea_list *ea_list = NULL;
NTSTATUS ntstatus = NT_STATUS_OK;
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;
}
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)) {
reply_nterror(req, ntstatus);
return;
@ -3834,6 +3844,7 @@ static void call_trans2qfilepathinfo(connection_struct *conn,
SMB_STRUCT_STAT sbuf;
char *dos_fname = NULL;
char *fname = NULL;
struct smb_filename *smb_fname = NULL;
char *fullpathname;
char *base_name;
char *p;
@ -3981,11 +3992,20 @@ static void call_trans2qfilepathinfo(connection_struct *conn,
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)) {
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)) {
reply_nterror(req, status);
return;
}
status = check_name(conn, fname);
if (!NT_STATUS_IS_OK(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 *newname_in)
{
SMB_STRUCT_STAT sbuf1, sbuf2;
char *last_component_oldname = NULL;
char *last_component_newname = NULL;
struct smb_filename *smb_fname = NULL;
struct smb_filename *smb_fname_new = NULL;
char *oldname = NULL;
char *newname = NULL;
NTSTATUS status = NT_STATUS_OK;
ZERO_STRUCT(sbuf1);
ZERO_STRUCT(sbuf2);
status = unix_convert(ctx, conn, oldname_in, False, &oldname,
&last_component_oldname, &sbuf1);
status = unix_convert(ctx, conn, oldname_in, &smb_fname, 0);
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);
if (!NT_STATUS_IS_OK(status)) {
return status;
goto out;
}
/* source must already exist. */
if (!VALID_STAT(sbuf1)) {
return NT_STATUS_OBJECT_NAME_NOT_FOUND;
if (!VALID_STAT(smb_fname->st)) {
status = NT_STATUS_OBJECT_NAME_NOT_FOUND;
goto out;
}
status = unix_convert(ctx, conn, newname_in, False, &newname,
&last_component_newname, &sbuf2);
status = unix_convert(ctx, conn, newname_in, &smb_fname_new, 0);
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);
if (!NT_STATUS_IS_OK(status)) {
return status;
goto out;
}
/* Disallow if newname already exists. */
if (VALID_STAT(sbuf2)) {
return NT_STATUS_OBJECT_NAME_COLLISION;
if (VALID_STAT(smb_fname_new->st)) {
status = NT_STATUS_OBJECT_NAME_COLLISION;
goto out;
}
/* No links from a directory. */
if (S_ISDIR(sbuf1.st_mode)) {
return NT_STATUS_FILE_IS_A_DIRECTORY;
if (S_ISDIR(smb_fname->st.st_mode)) {
status = NT_STATUS_FILE_IS_A_DIRECTORY;
goto out;
}
/* Ensure this is within the share. */
status = check_reduced_name(conn, oldname);
if (!NT_STATUS_IS_OK(status)) {
return status;
goto out;
}
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) {
status = map_nt_error_from_unix(errno);
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;
}
@ -5382,9 +5415,8 @@ static NTSTATUS smb_file_rename_information(connection_struct *conn,
uint32 len;
char *newname = NULL;
char *base_name = NULL;
struct smb_filename *smb_fname = NULL;
bool dest_has_wcard = False;
SMB_STRUCT_STAT sbuf;
char *newname_last_component = NULL;
NTSTATUS status = NT_STATUS_OK;
char *p;
TALLOC_CTX *ctx = talloc_tos();
@ -5393,8 +5425,6 @@ static NTSTATUS smb_file_rename_information(connection_struct *conn,
return NT_STATUS_INVALID_PARAMETER;
}
ZERO_STRUCT(sbuf);
overwrite = (CVAL(pdata,0) ? True : False);
root_fid = IVAL(pdata,4);
len = IVAL(pdata,8);
@ -5466,10 +5496,8 @@ static NTSTATUS smb_file_rename_information(connection_struct *conn,
return NT_STATUS_NO_MEMORY;
}
status = unix_convert(ctx, conn, newname, False,
&newname,
&newname_last_component,
&sbuf);
status = unix_convert(ctx, conn, newname, &smb_fname,
UCF_SAVE_LCOMP);
/* If an error we expect this to be
* 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)
&& !NT_STATUS_EQUAL(NT_STATUS_OBJECT_PATH_NOT_FOUND,
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",
fsp->fnum, fsp->fsp_name, base_name ));
status = rename_internals_fsp(conn, fsp, base_name,
newname_last_component, 0,
overwrite);
smb_fname ?
smb_fname->original_lcomp : NULL,
0, overwrite);
} else {
DEBUG(10,("smb_file_rename_information: SMB_FILE_RENAME_INFORMATION %s -> %s\n",
fname, base_name ));
@ -5494,7 +5523,10 @@ static NTSTATUS smb_file_rename_information(connection_struct *conn,
overwrite, False, dest_has_wcard,
FILE_WRITE_ATTRIBUTES);
}
out:
if (smb_fname) {
TALLOC_FREE(smb_fname);
}
return status;
}
@ -6700,6 +6732,7 @@ static void call_trans2setfilepathinfo(connection_struct *conn,
uint16 info_level;
SMB_STRUCT_STAT sbuf;
char *fname = NULL;
struct smb_filename *smb_fname = NULL;
files_struct *fsp = NULL;
NTSTATUS status = NT_STATUS_OK;
int data_return_size = 0;
@ -6814,8 +6847,15 @@ static void call_trans2setfilepathinfo(connection_struct *conn,
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)) {
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)) {
reply_nterror(req, status);
return;
@ -7129,10 +7169,10 @@ static void call_trans2mkdir(connection_struct *conn, struct smb_request *req,
char **ppdata, int total_data,
unsigned int max_data_bytes)
{
struct smb_filename *smb_dname = NULL;
char *params = *pparams;
char *pdata = *ppdata;
char *directory = NULL;
SMB_STRUCT_STAT sbuf;
NTSTATUS status = NT_STATUS_OK;
struct ea_list *ea_list = NULL;
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));
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)) {
reply_nterror(req, status);
return;