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:
parent
5d3d51e9ad
commit
c1a21d085d
@ -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);
|
||||
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,
|
||||
|
@ -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 */
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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)
|
||||
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;
|
||||
|
||||
|
@ -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)) {
|
||||
|
@ -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));
|
||||
|
@ -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
@ -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 ));
|
||||
@ -4881,7 +4908,13 @@ NTSTATUS hardlink_internals(TALLOC_CTX *ctx,
|
||||
DEBUG(3,("hardlink_internals: Error %s hard link %s -> %s\n",
|
||||
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;
|
||||
|
Loading…
Reference in New Issue
Block a user