summaryrefslogtreecommitdiff
path: root/source3
diff options
context:
space:
mode:
authorJeremy Allison <jra@samba.org>2007-07-11 22:39:11 +0000
committerGerald (Jerry) Carter <jerry@samba.org>2007-10-10 12:28:34 -0500
commitf01698027d15ca546d9a92c799d0cad18a625789 (patch)
treec40bf1479539632bdff4f8a526b39be5ecc25780 /source3
parent188b84f9d07ec33f8780ea5494d5892568cdbfe8 (diff)
downloadsamba-f01698027d15ca546d9a92c799d0cad18a625789.tar.gz
samba-f01698027d15ca546d9a92c799d0cad18a625789.tar.bz2
samba-f01698027d15ca546d9a92c799d0cad18a625789.zip
r23844: Add patch series from Volker (after review and consultation).
0001-Save-a-strdup-in-stat_cache_add.patch 0002-Use-ISDOT-and-ISDOTDOT.patch 0003-Move-fname_equal-around.patch 0004-unix_convert-pstring-dirpath-char.patch 0005-Ignore-.o-files.patch 0006-Get-rid-of-pstrings-inside-unix_convert.patch 0007-revert-pstring-unix_convert.patch 0008-Make-name-an-allocated-pstring-inside-unix_convert.patch 0009-Pass-explicit-pstring-to-mangle_check_cache.patch 0010-Don-t-overwrite-orig_path-unnecessarily.patch 0011-Defer-allocating-name.patch 0012-Make-sure-dirpath-is-always-correctly-allocated.patch 0013-Remove-one-pstring-dependency-in-unix_convert.patch 0014-Remove-more-name-pstring-dependencies.patch 0015-Hide-the-nasty-API-of-mangle_check_cache-in-mangle_c.patch 0016-name-does-not-need-to-be-pstring-size-anymore.patch 0017-Make-use-of-ISDOT-and-ISDOTDOT.patch 0018-Remove-pstring-from-stat_cache_lookup.patch 0019-Add-my-copyright.patch To remove pstrings from statcache and unix_convert. Jeremy. (This used to be commit ea6ef368891af24164d2e76700c405a82b3dfc19)
Diffstat (limited to 'source3')
-rw-r--r--source3/smbd/filename.c306
-rw-r--r--source3/smbd/mangle.c15
-rw-r--r--source3/smbd/statcache.c84
3 files changed, 273 insertions, 132 deletions
diff --git a/source3/smbd/filename.c b/source3/smbd/filename.c
index 737ed5a89c..fd7727c594 100644
--- a/source3/smbd/filename.c
+++ b/source3/smbd/filename.c
@@ -4,6 +4,7 @@
Copyright (C) Andrew Tridgell 1992-1998
Copyright (C) Jeremy Allison 1999-2004
Copyright (C) Ying Chen 2000
+ Copyright (C) Volker Lendecke 2007
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -25,21 +26,8 @@
#include "includes.h"
-static BOOL scan_directory(connection_struct *conn, const char *path, char *name,size_t maxlength);
-
-/****************************************************************************
- Check if two filenames are equal.
- This needs to be careful about whether we are case sensitive.
-****************************************************************************/
-
-static BOOL fname_equal(const char *name1, const char *name2, BOOL case_sensitive)
-{
- /* Normal filename handling */
- if (case_sensitive)
- return(strcmp(name1,name2) == 0);
-
- return(strequal(name1,name2));
-}
+static BOOL scan_directory(connection_struct *conn, const char *path,
+ char *name, char **found_name);
/****************************************************************************
Mangle the 2nd name and check if it is then equal to the first name.
@@ -117,22 +105,21 @@ for nlinks = 0, which can never be true for any file).
****************************************************************************/
NTSTATUS unix_convert(connection_struct *conn,
- pstring name,
+ pstring orig_path,
BOOL allow_wcard_last_component,
- char *saved_last_component,
+ char *saved_last_component,
SMB_STRUCT_STAT *pst)
{
SMB_STRUCT_STAT st;
char *start, *end;
- pstring dirpath;
- pstring orig_path;
+ char *dirpath = NULL;
+ char *name = NULL;
BOOL component_was_mangled = False;
BOOL name_has_wildcard = False;
+ NTSTATUS result;
SET_STAT_INVALID(*pst);
- *dirpath = 0;
-
if(saved_last_component) {
*saved_last_component = 0;
}
@@ -143,19 +130,19 @@ NTSTATUS unix_convert(connection_struct *conn,
return NT_STATUS_OK;
}
- DEBUG(5, ("unix_convert called on file \"%s\"\n", name));
+ DEBUG(5, ("unix_convert called on file \"%s\"\n", orig_path));
- /*
+ /*
* Conversion to basic unix format is already done in check_path_syntax().
*/
- /*
+ /*
* Names must be relative to the root of the service - any leading /.
* and trailing /'s should have been trimmed by check_path_syntax().
*/
#ifdef DEVELOPER
- SMB_ASSERT(*name != '/');
+ SMB_ASSERT(*orig_path != '/');
#endif
/*
@@ -166,23 +153,27 @@ NTSTATUS unix_convert(connection_struct *conn,
* As we know this is valid we can return true here.
*/
- if (!*name) {
- name[0] = '.';
- name[1] = '\0';
+ if (!*orig_path) {
+ if (!(name = SMB_STRDUP("."))) {
+ result = NT_STATUS_NO_MEMORY;
+ goto fail;
+ }
if (SMB_VFS_STAT(conn,name,&st) == 0) {
*pst = st;
}
DEBUG(5,("conversion finished \"\" -> %s\n",name));
- return NT_STATUS_OK;
+ goto done;
}
- if (name[0] == '.' && (name[1] == '/' || name[1] == '\0')) {
+ if (orig_path[0] == '.' && (orig_path[1] == '/' || orig_path[1] == '\0')) {
/* Start of pathname can't be "." only. */
- if (name[1] == '\0' || name[2] == '\0') {
- return NT_STATUS_OBJECT_NAME_INVALID;
+ if (orig_path[1] == '\0' || orig_path[2] == '\0') {
+ result = NT_STATUS_OBJECT_NAME_INVALID;
} else {
- return determine_path_error(&name[2], allow_wcard_last_component);
+ result =determine_path_error(
+ &orig_path[2], allow_wcard_last_component);
}
+ goto fail;
}
/*
@@ -190,14 +181,19 @@ NTSTATUS unix_convert(connection_struct *conn,
*/
if(saved_last_component) {
- end = strrchr_m(name, '/');
+ end = strrchr_m(orig_path, '/');
if (end) {
pstrcpy(saved_last_component, end + 1);
} else {
- pstrcpy(saved_last_component, name);
+ pstrcpy(saved_last_component, orig_path);
}
}
+ if (!(name = SMB_STRDUP(orig_path))) {
+ DEBUG(0, ("strdup failed\n"));
+ return NT_STATUS_NO_MEMORY;
+ }
+
/*
* Large directory fix normalization. If we're case sensitive, and
* the case preserving parameters are set to "no", normalize the case of
@@ -210,16 +206,27 @@ NTSTATUS unix_convert(connection_struct *conn,
if (conn->case_sensitive && !conn->case_preserve && !conn->short_case_preserve) {
strnorm(name, lp_defaultcase(SNUM(conn)));
}
-
+
start = name;
- pstrcpy(orig_path, name);
- if(!conn->case_sensitive && stat_cache_lookup(conn, name, dirpath, &start, &st)) {
+ if(!conn->case_sensitive
+ && stat_cache_lookup(conn, &name, &dirpath, &start, &st)) {
*pst = st;
- return NT_STATUS_OK;
+ goto done;
+ }
+
+ /*
+ * Make sure "dirpath" is an allocated string, we use this for
+ * building the directories with asprintf and free it.
+ */
+
+ if ((dirpath == NULL) && (!(dirpath = SMB_STRDUP("")))) {
+ DEBUG(0, ("strdup failed\n"));
+ result = NT_STATUS_NO_MEMORY;
+ goto fail;
}
- /*
+ /*
* stat the name - if it exists then we are all done!
*/
@@ -239,24 +246,24 @@ NTSTATUS unix_convert(connection_struct *conn,
stat_cache_add(orig_path, name, conn->case_sensitive);
DEBUG(5,("conversion finished %s -> %s\n",orig_path, name));
*pst = st;
- return NT_STATUS_OK;
+ goto done;
}
DEBUG(5,("unix_convert begin: name = %s, dirpath = %s, start = %s\n", name, dirpath, start));
- /*
+ /*
* A special case - if we don't have any mangling chars and are case
* sensitive then searching won't help.
*/
- if (conn->case_sensitive &&
+ if (conn->case_sensitive &&
!mangle_is_mangled(name, conn->params) &&
!*lp_mangled_map(conn->params)) {
- return NT_STATUS_OK;
+ goto done;
}
- /*
- * is_mangled() was changed to look at an entire pathname, not
+ /*
+ * is_mangled() was changed to look at an entire pathname, not
* just a component. JRA.
*/
@@ -264,23 +271,23 @@ NTSTATUS unix_convert(connection_struct *conn,
component_was_mangled = True;
}
- /*
- * Now we need to recursively match the name against the real
+ /*
+ * Now we need to recursively match the name against the real
* directory structure.
*/
- /*
+ /*
* Match each part of the path name separately, trying the names
* as is first, then trying to scan the directory for matching names.
*/
for (; start ; start = (end?end+1:(char *)NULL)) {
- /*
+ /*
* Pinpoint the end of this section of the filename.
*/
end = strchr(start, '/'); /* mb safe. '/' can't be in any encoded char. */
- /*
+ /*
* Chop the name at this point.
*/
if (end) {
@@ -296,9 +303,12 @@ NTSTATUS unix_convert(connection_struct *conn,
if (ISDOT(start)) {
if (!end) {
/* Error code at the end of a pathname. */
- return NT_STATUS_OBJECT_NAME_INVALID;
+ result = NT_STATUS_OBJECT_NAME_INVALID;
+ } else {
+ result = determine_path_error(end+1,
+ allow_wcard_last_component);
}
- return determine_path_error(end+1, allow_wcard_last_component);
+ goto fail;
}
/* The name cannot have a wildcard if it's not
@@ -308,15 +318,17 @@ NTSTATUS unix_convert(connection_struct *conn,
/* Wildcard not valid anywhere. */
if (name_has_wildcard && !allow_wcard_last_component) {
- return NT_STATUS_OBJECT_NAME_INVALID;
+ result = NT_STATUS_OBJECT_NAME_INVALID;
+ goto fail;
}
/* Wildcards never valid within a pathname. */
if (name_has_wildcard && end) {
- return NT_STATUS_OBJECT_NAME_INVALID;
+ result = NT_STATUS_OBJECT_NAME_INVALID;
+ goto fail;
}
- /*
+ /*
* Check if the name exists up to this point.
*/
@@ -331,14 +343,15 @@ NTSTATUS unix_convert(connection_struct *conn,
*/
DEBUG(5,("Not a dir %s\n",start));
*end = '/';
- /*
+ /*
* We need to return the fact that the intermediate
* name resolution failed. This is used to return an
* error of ERRbadpath rather than ERRbadfile. Some
* Windows applications depend on the difference between
* these two errors.
*/
- return NT_STATUS_OBJECT_PATH_NOT_FOUND;
+ result = NT_STATUS_OBJECT_PATH_NOT_FOUND;
+ goto fail;
}
if (!end) {
@@ -352,20 +365,10 @@ NTSTATUS unix_convert(connection_struct *conn,
}
} else {
- pstring rest;
+ char *found_name = NULL;
/* Stat failed - ensure we don't use it. */
SET_STAT_INVALID(st);
- *rest = 0;
-
- /*
- * Remember the rest of the pathname so it can be restored
- * later.
- */
-
- if (end) {
- pstrcpy(rest,end+1);
- }
/* Reset errno so we can detect directory open errors. */
errno = 0;
@@ -375,7 +378,9 @@ NTSTATUS unix_convert(connection_struct *conn,
*/
if (name_has_wildcard ||
- !scan_directory(conn, dirpath, start, sizeof(pstring) - 1 - (start - name))) {
+ !scan_directory(conn, dirpath, start, &found_name)) {
+ char *unmangled;
+
if (end) {
/*
* An intermediate part of the name can't be found.
@@ -383,7 +388,7 @@ NTSTATUS unix_convert(connection_struct *conn,
DEBUG(5,("Intermediate not found %s\n",start));
*end = '/';
- /*
+ /*
* We need to return the fact that the intermediate
* name resolution failed. This is used to return an
* error of ERRbadpath rather than ERRbadfile. Some
@@ -395,19 +400,25 @@ NTSTATUS unix_convert(connection_struct *conn,
in the filename walk. */
if (errno == ENOENT || errno == ENOTDIR) {
- return NT_STATUS_OBJECT_PATH_NOT_FOUND;
+ result = NT_STATUS_OBJECT_PATH_NOT_FOUND;
+ }
+ else {
+ result = map_nt_error_from_unix(errno);
}
- return map_nt_error_from_unix(errno);
+ goto fail;
}
-
+
/* ENOENT is the only valid error here. */
if (errno != ENOENT) {
/* ENOENT and ENOTDIR both map to NT_STATUS_OBJECT_PATH_NOT_FOUND
in the filename walk. */
if (errno == ENOTDIR) {
- return NT_STATUS_OBJECT_PATH_NOT_FOUND;
+ result = NT_STATUS_OBJECT_PATH_NOT_FOUND;
+ }
+ else {
+ result = map_nt_error_from_unix(errno);
}
- return map_nt_error_from_unix(errno);
+ goto fail;
}
/*
@@ -427,26 +438,79 @@ NTSTATUS unix_convert(connection_struct *conn,
* base of the filename.
*/
- if (mangle_is_mangled(start, conn->params)) {
- mangle_check_cache( start, sizeof(pstring) - 1 - (start - name), conn->params);
+ if (mangle_is_mangled(start, conn->params)
+ && mangle_check_cache_alloc(start, &unmangled,
+ conn->params)) {
+ char *tmp;
+ size_t start_ofs = start - name;
+
+ if (*dirpath != '\0') {
+ asprintf(&tmp, "%s/%s", dirpath,
+ unmangled);
+ SAFE_FREE(unmangled);
+ }
+ else {
+ tmp = unmangled;
+ }
+ if (tmp == NULL) {
+ DEBUG(0, ("malloc failed\n"));
+ result = NT_STATUS_NO_MEMORY;
+ }
+ SAFE_FREE(name);
+ name = tmp;
+ start = name + start_ofs;
+ end = start + strlen(start);
}
DEBUG(5,("New file %s\n",start));
- return NT_STATUS_OK;
+ goto done;
}
- /*
+
+ /*
* Restore the rest of the string. If the string was mangled the size
* may have changed.
*/
if (end) {
- end = start + strlen(start);
- if (!safe_strcat(start, "/", sizeof(pstring) - 1 - (start - name)) ||
- !safe_strcat(start, rest, sizeof(pstring) - 1 - (start - name))) {
- return map_nt_error_from_unix(ENAMETOOLONG);
+ char *tmp;
+ size_t start_ofs = start - name;
+
+ if (*dirpath != '\0') {
+ asprintf(&tmp, "%s/%s/%s", dirpath,
+ found_name, end+1);
}
+ else {
+ asprintf(&tmp, "%s/%s", found_name,
+ end+1);
+ }
+ if (tmp == NULL) {
+ DEBUG(0, ("asprintf failed\n"));
+ result = NT_STATUS_NO_MEMORY;
+ }
+ SAFE_FREE(name);
+ name = tmp;
+ start = name + start_ofs;
+ end = start + strlen(found_name);
*end = '\0';
} else {
+ char *tmp;
+ size_t start_ofs = start - name;
+
+ if (*dirpath != '\0') {
+ asprintf(&tmp, "%s/%s", dirpath,
+ found_name);
+ }
+ else {
+ tmp = SMB_STRDUP(found_name);
+ }
+ if (tmp == NULL) {
+ DEBUG(0, ("malloc failed\n"));
+ result = NT_STATUS_NO_MEMORY;
+ }
+ SAFE_FREE(name);
+ name = tmp;
+ start = name + start_ofs;
+
/*
* We just scanned for, and found the end of the path.
* We must return a valid stat struct if it exists.
@@ -459,40 +523,56 @@ NTSTATUS unix_convert(connection_struct *conn,
SET_STAT_INVALID(st);
}
}
+
+ SAFE_FREE(found_name);
} /* end else */
#ifdef DEVELOPER
if (VALID_STAT(st) && get_delete_on_close_flag(file_id_sbuf(&st))) {
- return NT_STATUS_DELETE_PENDING;
+ result = NT_STATUS_DELETE_PENDING;
+ goto fail;
}
#endif
/*
* Add to the dirpath that we have resolved so far.
*/
- if (*dirpath) {
- pstrcat(dirpath,"/");
- }
- pstrcat(dirpath,start);
+ if (*dirpath != '\0') {
+ char *tmp;
+
+ if (asprintf(&tmp, "%s/%s", dirpath, start) == -1) {
+ DEBUG(0, ("asprintf failed\n"));
+ return NT_STATUS_NO_MEMORY;
+ }
+ SAFE_FREE(dirpath);
+ dirpath = tmp;
+ }
+ else {
+ SAFE_FREE(dirpath);
+ if (!(dirpath = SMB_STRDUP(start))) {
+ DEBUG(0, ("strdup failed\n"));
+ return NT_STATUS_NO_MEMORY;
+ }
+ }
/*
* Don't cache a name with mangled or wildcard components
* as this can change the size.
*/
-
+
if(!component_was_mangled && !name_has_wildcard) {
stat_cache_add(orig_path, dirpath, conn->case_sensitive);
}
-
- /*
+
+ /*
* Restore the / that we wiped out earlier.
*/
if (end) {
*end = '/';
}
}
-
+
/*
* Don't cache a name with mangled or wildcard components
* as this can change the size.
@@ -502,12 +582,19 @@ NTSTATUS unix_convert(connection_struct *conn,
stat_cache_add(orig_path, name, conn->case_sensitive);
}
- /*
+ /*
* The name has been resolved.
*/
DEBUG(5,("conversion finished %s -> %s\n",orig_path, name));
- return NT_STATUS_OK;
+
+ done:
+ result = NT_STATUS_OK;
+ pstrcpy(orig_path, name);
+ fail:
+ SAFE_FREE(name);
+ SAFE_FREE(dirpath);
+ return result;
}
/****************************************************************************
@@ -539,21 +626,37 @@ NTSTATUS check_name(connection_struct *conn, const pstring name)
}
/****************************************************************************
+ Check if two filenames are equal.
+ This needs to be careful about whether we are case sensitive.
+****************************************************************************/
+
+static BOOL fname_equal(const char *name1, const char *name2, BOOL case_sensitive)
+{
+ /* Normal filename handling */
+ if (case_sensitive)
+ return(strcmp(name1,name2) == 0);
+
+ return(strequal(name1,name2));
+}
+
+/****************************************************************************
Scan a directory to find a filename, matching without case sensitivity.
If the name looks like a mangled name then try via the mangling functions
****************************************************************************/
-static BOOL scan_directory(connection_struct *conn, const char *path, char *name, size_t maxlength)
+static BOOL scan_directory(connection_struct *conn, const char *path,
+ char *name, char **found_name)
{
struct smb_Dir *cur_dir;
const char *dname;
BOOL mangled;
+ char *unmangled_name = NULL;
long curpos;
mangled = mangle_is_mangled(name, conn->params);
/* handle null paths */
- if (*path == 0)
+ if ((path == NULL) || (*path == 0))
path = ".";
/*
@@ -572,12 +675,15 @@ static BOOL scan_directory(connection_struct *conn, const char *path, char *name
*/
if (mangled && !conn->case_sensitive) {
- mangled = !mangle_check_cache( name, maxlength, conn->params);
+ mangled = !mangle_check_cache_alloc(name, &unmangled_name,
+ conn->params);
+ name = unmangled_name;
}
/* open the directory */
if (!(cur_dir = OpenDir(conn, path, NULL, 0))) {
DEBUG(3,("scan dir didn't open dir [%s]\n",path));
+ SAFE_FREE(unmangled_name);
return(False);
}
@@ -603,12 +709,14 @@ static BOOL scan_directory(connection_struct *conn, const char *path, char *name
if ((mangled && mangled_equal(name,dname,conn->params)) || fname_equal(name, dname, conn->case_sensitive)) {
/* we've found the file, change it's name and return */
- safe_strcpy(name, dname, maxlength);
+ *found_name = SMB_STRDUP(dname);
+ SAFE_FREE(unmangled_name);
CloseDir(cur_dir);
return(True);
}
}
+ SAFE_FREE(unmangled_name);
CloseDir(cur_dir);
errno = ENOENT;
return(False);
diff --git a/source3/smbd/mangle.c b/source3/smbd/mangle.c
index d7f2eb8db2..f69c940539 100644
--- a/source3/smbd/mangle.c
+++ b/source3/smbd/mangle.c
@@ -112,6 +112,21 @@ BOOL mangle_check_cache(char *s, size_t maxlen,
return mangle_fns->check_cache(s, maxlen, p);
}
+BOOL mangle_check_cache_alloc(const char *name, char **presult,
+ const struct share_params *p)
+{
+ pstring tmp;
+ char *result;
+ pstrcpy(tmp, name);
+
+ if (!mangle_check_cache(tmp, sizeof(pstring), p)
+ || !(result = SMB_STRDUP(tmp))) {
+ return False;
+ }
+ *presult = result;
+ return True;
+}
+
/*
map a long filename to a 8.3 name.
*/
diff --git a/source3/smbd/statcache.c b/source3/smbd/statcache.c
index 51e8c0417a..24cfe3beb8 100644
--- a/source3/smbd/statcache.c
+++ b/source3/smbd/statcache.c
@@ -4,6 +4,7 @@
Copyright (C) Andrew Tridgell 1992-2000
Copyright (C) Jeremy Allison 1999-2004
Copyright (C) Andrew Bartlett <abartlet@samba.org> 2003
+ Copyright (C) Volker Lendecke 2007
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -39,9 +40,8 @@ static TDB_CONTEXT *tdb_stat_cache;
*
*/
-void stat_cache_add( const char *full_orig_name, const char *orig_translated_path, BOOL case_sensitive)
+void stat_cache_add( const char *full_orig_name, const char *translated_path, BOOL case_sensitive)
{
- char *translated_path;
size_t translated_path_length;
TDB_DATA data_val;
char *original_path;
@@ -61,10 +61,10 @@ void stat_cache_add( const char *full_orig_name, const char *orig_translated_pat
* Don't cache trivial valid directory entries such as . and ..
*/
- if((*full_orig_name == '\0') || (full_orig_name[0] == '.' &&
- ((full_orig_name[1] == '\0') ||
- (full_orig_name[1] == '.' && full_orig_name[2] == '\0'))))
+ if ((*full_orig_name == '\0')
+ || ISDOT(full_orig_name) || ISDOTDOT(full_orig_name)) {
return;
+ }
/*
* If we are in case insentive mode, we don't need to
@@ -72,7 +72,7 @@ void stat_cache_add( const char *full_orig_name, const char *orig_translated_pat
* would be a waste.
*/
- if(case_sensitive && (strcmp(full_orig_name, orig_translated_path) == 0))
+ if (case_sensitive && (strcmp(full_orig_name, translated_path) == 0))
return;
/*
@@ -80,14 +80,15 @@ void stat_cache_add( const char *full_orig_name, const char *orig_translated_pat
* translated path.
*/
- translated_path = SMB_STRDUP(orig_translated_path);
- if (!translated_path)
- return;
+ /*
+ * To save a strdup we don't necessarily 0-terminate the translated
+ * path in the tdb. Instead, we do it directly after the tdb_fetch in
+ * stat_cache_lookup.
+ */
translated_path_length = strlen(translated_path);
if(translated_path[translated_path_length-1] == '/') {
- translated_path[translated_path_length-1] = '\0';
translated_path_length--;
}
@@ -98,7 +99,6 @@ void stat_cache_add( const char *full_orig_name, const char *orig_translated_pat
}
if (!original_path) {
- SAFE_FREE(translated_path);
return;
}
@@ -114,7 +114,6 @@ void stat_cache_add( const char *full_orig_name, const char *orig_translated_pat
DEBUG(0, ("OOPS - tried to store stat cache entry for weird length paths [%s] %lu and [%s] %lu)!\n",
original_path, (unsigned long)original_path_length, translated_path, (unsigned long)translated_path_length));
SAFE_FREE(original_path);
- SAFE_FREE(translated_path);
return;
}
@@ -140,7 +139,6 @@ void stat_cache_add( const char *full_orig_name, const char *orig_translated_pat
}
SAFE_FREE(original_path);
- SAFE_FREE(translated_path);
}
/**
@@ -148,7 +146,8 @@ void stat_cache_add( const char *full_orig_name, const char *orig_translated_pat
*
* @param conn A connection struct to do the stat() with.
* @param name The path we are attempting to cache, modified by this routine
- * to be correct as far as the cache can tell us
+ * to be correct as far as the cache can tell us. We assume that
+ * it is a malloc'ed string, we free it if necessary.
* @param dirpath The path as far as the stat cache told us.
* @param start A pointer into name, for where to 'start' in fixing the rest of the name up.
* @param psd A stat buffer, NOT from the cache, but just a side-effect.
@@ -157,7 +156,7 @@ void stat_cache_add( const char *full_orig_name, const char *orig_translated_pat
*
*/
-BOOL stat_cache_lookup(connection_struct *conn, pstring name, pstring dirpath,
+BOOL stat_cache_lookup(connection_struct *conn, char **pname, char **dirpath,
char **start, SMB_STRUCT_STAT *pst)
{
char *chk_name;
@@ -167,10 +166,12 @@ BOOL stat_cache_lookup(connection_struct *conn, pstring name, pstring dirpath,
char *translated_path;
size_t translated_path_length;
TDB_DATA data_val;
+ char *name;
if (!lp_stat_cache())
return False;
+ name = *pname;
namelen = strlen(name);
*start = name;
@@ -180,10 +181,9 @@ BOOL stat_cache_lookup(connection_struct *conn, pstring name, pstring dirpath,
/*
* Don't lookup trivial valid directory entries.
*/
- if((*name == '\0') || (name[0] == '.' &&
- ((name[1] == '\0') ||
- (name[1] == '.' && name[1] == '\0'))))
+ if ((*name == '\0') || ISDOT(name) || ISDOTDOT(name)) {
return False;
+ }
if (conn->case_sensitive) {
chk_name = SMB_STRDUP(name);
@@ -250,6 +250,12 @@ BOOL stat_cache_lookup(connection_struct *conn, pstring name, pstring dirpath,
translated_path = (char *)data_val.dptr;
translated_path_length = data_val.dsize - 1;
+ /*
+ * In stat_cache_add we did not necessarily 0-terminate the translated
+ * path. Do it here, where we do have a freshly malloc'ed blob.
+ */
+ translated_path[translated_path_length] = '\0';
+
DEBUG(10,("stat_cache_lookup: lookup succeeded for name [%s] "
"-> [%s]\n", chk_name, translated_path ));
DO_PROFILE_INC(statcache_hits);
@@ -264,31 +270,43 @@ BOOL stat_cache_lookup(connection_struct *conn, pstring name, pstring dirpath,
if (!sizechanged) {
memcpy(name, translated_path,
- MIN(sizeof(pstring)-1, translated_path_length));
- } else if (num_components == 0) {
- pstrcpy(name, translated_path);
- } else {
- char *sp;
-
- sp = strnrchr_m(name, '/', num_components);
- if (sp) {
- pstring last_component;
- pstrcpy(last_component, sp);
- pstrcpy(name, translated_path);
- pstrcat(name, last_component);
+ MIN(namelen, translated_path_length));
+ }
+ else {
+ if (num_components == 0) {
+ name = SMB_STRNDUP(translated_path,
+ translated_path_length);
} else {
- pstrcpy(name, translated_path);
+ char *sp;
+
+ sp = strnrchr_m(name, '/', num_components);
+ if (sp) {
+ asprintf(&name, "%.*s%s",
+ (int)translated_path_length,
+ translated_path, sp);
+ } else {
+ name = SMB_STRNDUP(translated_path,
+ translated_path_length);
+ }
}
+ if (name == NULL) {
+ /*
+ * TODO: Get us out of here with a real error message
+ */
+ smb_panic("malloc failed");
+ }
+ SAFE_FREE(*pname);
+ *pname = name;
}
+
/* set pointer for 'where to start' on fixing the rest of the name */
*start = &name[translated_path_length];
if (**start == '/')
++*start;
- pstrcpy(dirpath, translated_path);
+ *dirpath = translated_path;
SAFE_FREE(chk_name);
- SAFE_FREE(data_val.dptr);
return (namelen == translated_path_length);
}