mirror of
https://github.com/fish-shell/fish-shell
synced 2024-12-27 05:13:10 +00:00
Fix to check for case insensitive filesystems in is_potential_path
Addresses https://github.com/fish-shell/fish-shell/issues/119
This commit is contained in:
parent
afd8d2f9ba
commit
6cf42075fc
1 changed files with 43 additions and 4 deletions
|
@ -103,6 +103,28 @@ static wcstring apply_working_directory(const wcstring &path, const wcstring &wo
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Determine if the filesystem containing the given fd is case insensitive. */
|
||||||
|
typedef std::map<wcstring, bool> case_sensitivity_cache_t;
|
||||||
|
bool fs_is_case_insensitive(const wcstring &path, int fd, case_sensitivity_cache_t &case_sensitivity_cache)
|
||||||
|
{
|
||||||
|
/* If _PC_CASE_SENSITIVE is not defined, assume case sensitive */
|
||||||
|
bool result = false;
|
||||||
|
#ifdef _PC_CASE_SENSITIVE
|
||||||
|
/* Try the cache first */
|
||||||
|
case_sensitivity_cache_t::iterator cache = case_sensitivity_cache.find(path);
|
||||||
|
if (cache != case_sensitivity_cache.end()) {
|
||||||
|
/* Use the cached value */
|
||||||
|
result = cache->second;
|
||||||
|
} else {
|
||||||
|
/* Ask the system. A -1 value means error (so assume case sensitive), a 1 value means case sensitive, and a 0 value means case insensitive */
|
||||||
|
long ret = fpathconf(fd, _PC_CASE_SENSITIVE);
|
||||||
|
result = (ret == 0);
|
||||||
|
case_sensitivity_cache[path] = result;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
/* Tests whether the specified string cpath is the prefix of anything we could cd to. directories is a list of possible parent directories (typically either the working directory, or the cdpath). This does I/O!
|
/* Tests whether the specified string cpath is the prefix of anything we could cd to. directories is a list of possible parent directories (typically either the working directory, or the cdpath). This does I/O!
|
||||||
*/
|
*/
|
||||||
bool is_potential_path(const wcstring &const_path, const wcstring_list_t &directories, bool require_dir, wcstring *out_path)
|
bool is_potential_path(const wcstring &const_path, const wcstring_list_t &directories, bool require_dir, wcstring *out_path)
|
||||||
|
@ -161,6 +183,9 @@ bool is_potential_path(const wcstring &const_path, const wcstring_list_t &direct
|
||||||
/* Don't test the same path multiple times, which can happen if the path is absolute and the CDPATH contains multiple entries */
|
/* Don't test the same path multiple times, which can happen if the path is absolute and the CDPATH contains multiple entries */
|
||||||
std::set<wcstring> checked_paths;
|
std::set<wcstring> checked_paths;
|
||||||
|
|
||||||
|
/* Keep a cache of which paths / filesystems are case sensitive */
|
||||||
|
case_sensitivity_cache_t case_sensitivity_cache;
|
||||||
|
|
||||||
for (size_t wd_idx = 0; wd_idx < directories.size() && ! result; wd_idx++) {
|
for (size_t wd_idx = 0; wd_idx < directories.size() && ! result; wd_idx++) {
|
||||||
const wcstring &wd = directories.at(wd_idx);
|
const wcstring &wd = directories.at(wd_idx);
|
||||||
|
|
||||||
|
@ -200,12 +225,23 @@ bool is_potential_path(const wcstring &const_path, const wcstring_list_t &direct
|
||||||
// We opened the dir_name; look for a string where the base name prefixes it
|
// We opened the dir_name; look for a string where the base name prefixes it
|
||||||
wcstring ent;
|
wcstring ent;
|
||||||
|
|
||||||
|
// Check if we're case insensitive
|
||||||
|
bool case_insensitive = fs_is_case_insensitive(dir_name, dirfd(dir), case_sensitivity_cache);
|
||||||
|
|
||||||
// Don't ask for the is_dir value unless we care, because it can cause extra filesystem acces */
|
// Don't ask for the is_dir value unless we care, because it can cause extra filesystem acces */
|
||||||
bool is_dir = false;
|
bool is_dir = false;
|
||||||
while (wreaddir_resolving(dir, dir_name, ent, require_dir ? &is_dir : NULL))
|
while (wreaddir_resolving(dir, dir_name, ent, require_dir ? &is_dir : NULL))
|
||||||
{
|
{
|
||||||
// TODO: support doing the right thing on case-insensitive filesystems like HFS+
|
|
||||||
if (string_prefixes_string(base_name, ent) && (! require_dir || is_dir))
|
/* Determine which function to call to check for prefixes */
|
||||||
|
bool (*prefix_func)(const wcstring &, const wcstring &);
|
||||||
|
if (case_insensitive) {
|
||||||
|
prefix_func = string_prefixes_string_case_insensitive;
|
||||||
|
} else {
|
||||||
|
prefix_func = string_prefixes_string;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (prefix_func(base_name, ent) && (! require_dir || is_dir))
|
||||||
{
|
{
|
||||||
result = true;
|
result = true;
|
||||||
if (out_path) {
|
if (out_path) {
|
||||||
|
@ -213,10 +249,13 @@ bool is_potential_path(const wcstring &const_path, const wcstring_list_t &direct
|
||||||
|
|
||||||
out_path->clear();
|
out_path->clear();
|
||||||
const wcstring path_base = wdirname(const_path);
|
const wcstring path_base = wdirname(const_path);
|
||||||
if (string_prefixes_string(path_base, const_path)) {
|
|
||||||
|
|
||||||
|
if (prefix_func(path_base, const_path)) {
|
||||||
out_path->append(path_base);
|
out_path->append(path_base);
|
||||||
if (! string_suffixes_string(L"/", *out_path))
|
if (! string_suffixes_string(L"/", *out_path))
|
||||||
out_path->push_back(L'/');
|
out_path->push_back(L'/');
|
||||||
|
printf("path: %ls\n", out_path->c_str());
|
||||||
}
|
}
|
||||||
out_path->append(ent);
|
out_path->append(ent);
|
||||||
/* We actually do want a trailing / for directories, since it makes autosuggestion a bit nicer */
|
/* We actually do want a trailing / for directories, since it makes autosuggestion a bit nicer */
|
||||||
|
|
Loading…
Reference in a new issue