summaryrefslogtreecommitdiff
path: root/source3/smbd/filename.c
diff options
context:
space:
mode:
Diffstat (limited to 'source3/smbd/filename.c')
-rw-r--r--source3/smbd/filename.c254
1 files changed, 152 insertions, 102 deletions
diff --git a/source3/smbd/filename.c b/source3/smbd/filename.c
index a6a9e7e7f0..ab5851fb5e 100644
--- a/source3/smbd/filename.c
+++ b/source3/smbd/filename.c
@@ -102,6 +102,7 @@ used to pick the correct error code to return between ENOENT and ENOTDIR
as Windows applications depend on ERRbadpath being returned if a component
of a pathname does not exist.
****************************************************************************/
+
BOOL unix_convert(char *name,connection_struct *conn,char *saved_last_component, BOOL *bad_path)
{
struct stat st;
@@ -115,17 +116,24 @@ BOOL unix_convert(char *name,connection_struct *conn,char *saved_last_component,
if(saved_last_component)
*saved_last_component = 0;
- /* convert to basic unix format - removing \ chars and cleaning it up */
+ /*
+ * Convert to basic unix format - removing \ chars and cleaning it up.
+ */
+
unix_format(name);
unix_clean_name(name);
- /* names must be relative to the root of the service - trim any leading /.
- also trim trailing /'s */
+ /*
+ * Names must be relative to the root of the service - trim any leading /.
+ * also trim trailing /'s.
+ */
+
trim_string(name,"/","/");
/*
* Ensure saved_last_component is valid even if file exists.
*/
+
if(saved_last_component) {
end = strrchr(name, '/');
if(end)
@@ -138,23 +146,30 @@ BOOL unix_convert(char *name,connection_struct *conn,char *saved_last_component,
(!case_preserve || (is_8_3(name, False) && !short_case_preserve)))
strnorm(name);
- /* check if it's a printer file */
- if (conn->printer)
- {
- if ((! *name) || strchr(name,'/') || !is_8_3(name, True))
- {
- char *s;
- fstring name2;
- slprintf(name2,sizeof(name2)-1,"%.6s.XXXXXX",remote_machine);
- /* sanitise the name */
- for (s=name2 ; *s ; s++)
- if (!issafe(*s)) *s = '_';
- pstrcpy(name,(char *)mktemp(name2));
- }
- return(True);
- }
+ /*
+ * Check if it's a printer file.
+ */
+ if (conn->printer) {
+ if ((! *name) || strchr(name,'/') || !is_8_3(name, True)) {
+ char *s;
+ fstring name2;
+ slprintf(name2,sizeof(name2)-1,"%.6s.XXXXXX",remote_machine);
+
+ /*
+ * Sanitise the name.
+ */
+
+ for (s=name2 ; *s ; s++)
+ if (!issafe(*s)) *s = '_';
+ pstrcpy(name,(char *)mktemp(name2));
+ }
+ return(True);
+ }
+
+ /*
+ * stat the name - if it exists then we are all done!
+ */
- /* stat the name - if it exists then we are all done! */
if (sys_stat(name,&st) == 0)
return(True);
@@ -162,109 +177,144 @@ BOOL unix_convert(char *name,connection_struct *conn,char *saved_last_component,
DEBUG(5,("unix_convert(%s)\n",name));
- /* a special case - if we don't have any mangling chars and are case
- sensitive then searching won't help */
+ /*
+ * A special case - if we don't have any mangling chars and are case
+ * sensitive then searching won't help.
+ */
+
if (case_sensitive && !is_mangled(name) &&
!lp_strip_dot() && !use_mangled_map && (saved_errno != ENOENT))
return(False);
- /* now we need to recursively match the name against the real
- directory structure */
+ /*
+ * Now we need to recursively match the name against the real
+ * directory structure.
+ */
start = name;
while (strncmp(start,"./",2) == 0)
start += 2;
- /* now 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 */
+ /*
+ * 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, '/');
- /* chop the name at this point */
- if (end) *end = 0;
+ /*
+ * Chop the name at this point.
+ */
+ if (end)
+ *end = 0;
if(saved_last_component != 0)
pstrcpy(saved_last_component, end ? end + 1 : start);
- /* check if the name exists up to this point */
- if (sys_stat(name, &st) == 0)
- {
- /* it exists. it must either be a directory or this must be
- the last part of the path for it to be OK */
- if (end && !(st.st_mode & S_IFDIR))
- {
- /* an intermediate part of the name isn't a directory */
- DEBUG(5,("Not a dir %s\n",start));
- *end = '/';
- return(False);
- }
- }
- else
- {
- pstring rest;
-
- *rest = 0;
-
- /* remember the rest of the pathname so it can be restored
- later */
- if (end) pstrcpy(rest,end+1);
-
- /* try to find this part of the path in the directory */
- if (strchr(start,'?') || strchr(start,'*') ||
- !scan_directory(dirpath, start, conn, end?True:False))
- {
- if (end)
- {
- /* an intermediate part of the name can't be found */
- 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
- Windows applications depend on the difference between
- these two errors.
- */
- *bad_path = True;
- return(False);
- }
+ /*
+ * Check if the name exists up to this point.
+ */
+ if (sys_stat(name, &st) == 0) {
+ /*
+ * It exists. it must either be a directory or this must be
+ * the last part of the path for it to be OK.
+ */
+ if (end && !(st.st_mode & S_IFDIR)) {
+ /*
+ * An intermediate part of the name isn't a directory.
+ */
+ DEBUG(5,("Not a dir %s\n",start));
+ *end = '/';
+ return(False);
+ }
+ } else {
+ pstring rest;
+
+ *rest = 0;
+
+ /*
+ * Remember the rest of the pathname so it can be restored
+ * later.
+ */
+
+ if (end)
+ pstrcpy(rest,end+1);
+
+ /*
+ * Try to find this part of the path in the directory.
+ */
+ if (strchr(start,'?') || strchr(start,'*') ||
+ !scan_directory(dirpath, start, conn, end?True:False)) {
+ if (end) {
+ /*
+ * An intermediate part of the name can't be found.
+ */
+ 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
+ * Windows applications depend on the difference between
+ * these two errors.
+ */
+ *bad_path = True;
+ return(False);
+ }
- /* just the last part of the name doesn't exist */
- /* we may need to strupper() or strlower() it in case
- this conversion is being used for file creation
- purposes */
- /* if the filename is of mixed case then don't normalise it */
- if (!case_preserve &&
- (!strhasupper(start) || !strhaslower(start)))
- strnorm(start);
-
- /* check on the mangled stack to see if we can recover the
- base of the filename */
- if (is_mangled(start))
- check_mangled_cache( start );
-
- DEBUG(5,("New file %s\n",start));
- return(True);
- }
-
- /* restore the rest of the string */
- if (end)
- {
- pstrcpy(start+strlen(start)+1,rest);
- end = start + strlen(start);
- }
- }
+ /*
+ * Just the last part of the name doesn't exist.
+ * We may need to strupper() or strlower() it in case
+ * this conversion is being used for file creation
+ * purposes. If the filename is of mixed case then
+ * don't normalise it.
+ */
+
+ if (!case_preserve && (!strhasupper(start) || !strhaslower(start)))
+ strnorm(start);
+
+ /*
+ * check on the mangled stack to see if we can recover the
+ * base of the filename.
+ */
+
+ if (is_mangled(start))
+ check_mangled_cache( start );
+
+ DEBUG(5,("New file %s\n",start));
+ return(True);
+ }
- /* add to the dirpath that we have resolved so far */
- if (*dirpath) pstrcat(dirpath,"/");
+ /*
+ * Restore the rest of the string.
+ */
+ if (end) {
+ pstrcpy(start+strlen(start)+1,rest);
+ end = start + strlen(start);
+ }
+ } /* end else */
+
+ /*
+ * Add to the dirpath that we have resolved so far.
+ */
+ if (*dirpath) pstrcat(dirpath,"/");
pstrcat(dirpath,start);
- /* restore the / that we wiped out earlier */
- if (end) *end = '/';
- }
+ /*
+ * Restore the / that we wiped out earlier.
+ */
+ if (end)
+ *end = '/';
+ }
- /* the name has been resolved */
+ /*
+ * The name has been resolved.
+ */
DEBUG(5,("conversion finished %s\n",name));
return(True);
}