/* front end routine to the mangled map code personally I think that the whole idea of "mangled map" is completely bogus */ void mangle_map_filename(fstring fname, const struct share_params *p) { char *map; map = lp_mangled_map(p); if (!map || !*map) return; mangled_map(fname, map); }
/* front end routine to the mangled map code personally I think that the whole idea of "mangled map" is completely bogus */ void mangle_map_filename(char *fname, int snum) { char *map; map = lp_mangled_map(snum); if (!map || !*map) return; mangled_map(fname, map); }
/**************************************************************************** load parameters specific to a connection/service ****************************************************************************/ BOOL become_service(connection_struct *conn,BOOL do_chdir) { extern char magic_char; static connection_struct *last_conn; int snum; if (!conn) { last_conn = NULL; return(False); } conn->lastused = smb_last_time.tv_sec; snum = SNUM(conn); if (do_chdir && dos_ChDir(conn->connectpath) != 0 && dos_ChDir(conn->origpath) != 0) { DEBUG(0,("chdir (%s) failed\n", conn->connectpath)); return(False); } if (conn == last_conn) return(True); last_conn = conn; case_default = lp_defaultcase(snum); case_preserve = lp_preservecase(snum); short_case_preserve = lp_shortpreservecase(snum); case_mangle = lp_casemangle(snum); case_sensitive = lp_casesensitive(snum); magic_char = lp_magicchar(snum); use_mangled_map = (*lp_mangled_map(snum) ? True:False); return(True); }
NTSTATUS unix_convert(connection_struct *conn, pstring name, BOOL allow_wcard_last_component, char *saved_last_component, SMB_STRUCT_STAT *pst) { SMB_STRUCT_STAT st; char *start, *end; pstring dirpath; pstring orig_path; BOOL component_was_mangled = False; BOOL name_has_wildcard = False; SET_STAT_INVALID(*pst); *dirpath = 0; if(saved_last_component) { *saved_last_component = 0; } if (conn->printer) { /* we don't ever use the filenames on a printer share as a filename - so don't convert them */ return NT_STATUS_OK; } DEBUG(5, ("unix_convert called on file \"%s\"\n", name)); /* * 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 != '/'); #endif /* * If we trimmed down to a single '\0' character * then we should use the "." directory to avoid * searching the cache, but not if we are in a * printing share. * As we know this is valid we can return true here. */ if (!*name) { name[0] = '.'; name[1] = '\0'; if (SMB_VFS_STAT(conn,name,&st) == 0) { *pst = st; } DEBUG(5,("conversion finished \"\" -> %s\n",name)); return NT_STATUS_OK; } if (name[0] == '.' && (name[1] == '/' || name[1] == '\0')) { /* Start of pathname can't be "." only. */ if (name[1] == '\0' || name[2] == '\0') { return NT_STATUS_OBJECT_NAME_INVALID; } else { return determine_path_error(&name[2], allow_wcard_last_component); } } /* * Ensure saved_last_component is valid even if file exists. */ if(saved_last_component) { end = strrchr_m(name, '/'); if (end) { pstrcpy(saved_last_component, end + 1); } else { pstrcpy(saved_last_component, name); } } /* * Large directory fix normalization. If we're case sensitive, and * the case preserving parameters are set to "no", normalize the case of * the incoming filename from the client WHETHER IT EXISTS OR NOT ! * This is in conflict with the current (3.0.20) man page, but is * what people expect from the "large directory howto". I'll update * the man page. Thanks to [email protected] for finding this. JRA. */ 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)) { *pst = st; return NT_STATUS_OK; } /* * stat the name - if it exists then we are all done! */ if (SMB_VFS_STAT(conn,name,&st) == 0) { /* Ensure we catch all names with in "/." this is disallowed under Windows. */ const char *p = strstr(name, "/."); /* mb safe. */ if (p) { if (p[2] == '/') { /* Error code within a pathname. */ return NT_STATUS_OBJECT_PATH_NOT_FOUND; } else if (p[2] == '\0') { /* Error code at the end of a pathname. */ return NT_STATUS_OBJECT_NAME_INVALID; } } /* * This is a case insensitive file system, we really need to * get the correct case of the name. */ if (!(conn->fs_capabilities & FILE_CASE_SENSITIVE_SEARCH)) { pstring case_preserved_name; if (SMB_VFS_GET_PRESERVED_NAME(conn, name, case_preserved_name)) { char * last_component = strrchr(name, '/'); int space_left = PSTRING_LEN; if (last_component) { last_component++; *last_component = 0; space_left = PSTRING_LEN - strlen(name); } else last_component = name; strlcpy(last_component, case_preserved_name, space_left); } } 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; } 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 && !mangle_is_mangled(name, conn->params) && !*lp_mangled_map(conn->params)) { return NT_STATUS_OK; } /* * is_mangled() was changed to look at an entire pathname, not * just a component. JRA. */ if (mangle_is_mangled(start, conn->params)) { component_was_mangled = True; } /* * 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) { *end = 0; } if (saved_last_component != 0) { pstrcpy(saved_last_component, end ? end + 1 : start); } /* The name cannot have a component of "." */ if (ISDOT(start)) { if (!end) { /* Error code at the end of a pathname. */ return NT_STATUS_OBJECT_NAME_INVALID; } return determine_path_error(end+1, allow_wcard_last_component); } /* The name cannot have a wildcard if it's not the last component. */ name_has_wildcard = ms_has_wild(start); /* Wildcard not valid anywhere. */ if (name_has_wildcard && !allow_wcard_last_component) { return NT_STATUS_OBJECT_NAME_INVALID; } /* Wildcards never valid within a pathname. */ if (name_has_wildcard && end) { return NT_STATUS_OBJECT_NAME_INVALID; } /* * Check if the name exists up to this point. */ if (SMB_VFS_STAT(conn,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 = '/'; /* * 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; } if (!end) { /* * We just scanned for, and found the end of the path. * We must return the valid stat struct. * JRA. */ *pst = st; } } else { pstring rest; /* 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; /* * Try to find this part of the path in the directory. */ if (name_has_wildcard || !scan_directory(conn, dirpath, start, sizeof(pstring) - 1 - (start - name))) { 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. */ /* ENOENT, ENOTDIR and ELOOP all map to * NT_STATUS_OBJECT_PATH_NOT_FOUND * in the filename walk. */ if (errno == ENOENT || errno == ENOTDIR || errno == ELOOP) { return NT_STATUS_OBJECT_PATH_NOT_FOUND; } return map_nt_error_from_unix(errno); } /* ENOENT is the only valid error here. */ if (errno != ENOENT) { /* ENOTDIR and ELOOP both map to * NT_STATUS_OBJECT_PATH_NOT_FOUND * in the filename walk. */ if (errno == ENOTDIR || errno == ELOOP) { return NT_STATUS_OBJECT_PATH_NOT_FOUND; } return map_nt_error_from_unix(errno); } /* * Just the last part of the name doesn't exist. * We need to strupper() or strlower() it as * this conversion may be used for file creation * purposes. Fix inspired by Thomas Neumann <*****@*****.**>. */ if (!conn->case_preserve || (mangle_is_8_3(start, False, conn->params) && !conn->short_case_preserve)) { strnorm(start, lp_defaultcase(SNUM(conn))); } /* * check on the mangled stack to see if we can recover the * base of the filename. */ if (mangle_is_mangled(start, conn->params)) { mangle_check_cache( start, sizeof(pstring) - 1 - (start - name), conn->params); } DEBUG(5,("New file %s\n",start)); return NT_STATUS_OK; } /* * 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); } *end = '\0'; } else { /* * We just scanned for, and found the end of the path. * We must return a valid stat struct if it exists. * JRA. */ if (SMB_VFS_STAT(conn,name, &st) == 0) { *pst = st; } else { SET_STAT_INVALID(st); } } } /* end else */ #ifdef DEVELOPER if (VALID_STAT(st) && get_delete_on_close_flag(st.st_dev, st.st_ino)) { return NT_STATUS_DELETE_PENDING; } #endif /* * Add to the dirpath that we have resolved so far. */ if (*dirpath) { pstrcat(dirpath,"/"); } pstrcat(dirpath,start); /* * 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. */ if(!component_was_mangled && !name_has_wildcard) { 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; }