mirror of
https://github.com/fish-shell/fish-shell.git
synced 2026-06-02 05:41:16 -03:00
Fix for reported "out of memory" for filesystems that return -1 as _PC_NAME_MAX
This commit is contained in:
195
wildcard.cpp
195
wildcard.cpp
@@ -697,25 +697,19 @@ static void insert_completion_if_missing(const wcstring &str, std::vector<comple
|
|||||||
which would be too expensive to construct for all substrings.
|
which would be too expensive to construct for all substrings.
|
||||||
*/
|
*/
|
||||||
static int wildcard_expand_internal(const wchar_t *wc,
|
static int wildcard_expand_internal(const wchar_t *wc,
|
||||||
const wchar_t *base_dir,
|
const wchar_t * const base_dir,
|
||||||
expand_flags_t flags,
|
expand_flags_t flags,
|
||||||
std::vector<completion_t> &out,
|
std::vector<completion_t> &out,
|
||||||
std::set<wcstring> &completion_set,
|
std::set<wcstring> &completion_set,
|
||||||
std::set<file_id_t> &visited_files)
|
std::set<file_id_t> &visited_files)
|
||||||
{
|
{
|
||||||
|
|
||||||
/* Points to the end of the current wildcard segment */
|
|
||||||
const wchar_t *wc_end;
|
|
||||||
|
|
||||||
/* Variables for traversing a directory */
|
/* Variables for traversing a directory */
|
||||||
DIR *dir;
|
DIR *dir;
|
||||||
|
|
||||||
/* The result returned */
|
/* The result returned */
|
||||||
int res = 0;
|
int res = 0;
|
||||||
|
|
||||||
/* Length of the directory to search in */
|
|
||||||
size_t base_len;
|
|
||||||
|
|
||||||
/* Variables for testing for presense of recursive wildcards */
|
/* Variables for testing for presense of recursive wildcards */
|
||||||
const wchar_t *wc_recursive;
|
const wchar_t *wc_recursive;
|
||||||
bool is_recursive;
|
bool is_recursive;
|
||||||
@@ -735,6 +729,8 @@ static int wildcard_expand_internal(const wchar_t *wc,
|
|||||||
debug(2, L"Got null string on line %d of file %s", __LINE__, __FILE__);
|
debug(2, L"Got null string on line %d of file %s", __LINE__, __FILE__);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const size_t base_dir_len = wcslen(base_dir);
|
||||||
|
|
||||||
if (flags & ACCEPT_INCOMPLETE)
|
if (flags & ACCEPT_INCOMPLETE)
|
||||||
{
|
{
|
||||||
@@ -763,8 +759,8 @@ static int wildcard_expand_internal(const wchar_t *wc,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
wc_end = wcschr(wc,L'/');
|
/* Points to the end of the current wildcard segment */
|
||||||
base_len = wcslen(base_dir);
|
const wchar_t * const wc_end = wcschr(wc,L'/');
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Test for recursive match string in current segment
|
Test for recursive match string in current segment
|
||||||
@@ -887,56 +883,21 @@ static int wildcard_expand_internal(const wchar_t *wc,
|
|||||||
wildcard_expand for all matching subdirectories.
|
wildcard_expand for all matching subdirectories.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/*
|
|
||||||
wc_str is the part of the wildcarded string from the
|
|
||||||
beginning to the first slash
|
|
||||||
*/
|
|
||||||
wchar_t *wc_str;
|
|
||||||
|
|
||||||
/*
|
|
||||||
new_dir is a scratch area containing the full path to a
|
|
||||||
file/directory we are iterating over
|
|
||||||
*/
|
|
||||||
wchar_t *new_dir;
|
|
||||||
|
|
||||||
/*
|
|
||||||
The maximum length of a file element
|
|
||||||
*/
|
|
||||||
long ln=MAX_FILE_LENGTH;
|
|
||||||
char * narrow_dir_string = wcs2str(dir_string);
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
In recursive mode, we look through the directory twice. If
|
In recursive mode, we look through the directory twice. If
|
||||||
so, this rewind is needed.
|
so, this rewind is needed.
|
||||||
*/
|
*/
|
||||||
rewinddir(dir);
|
rewinddir(dir);
|
||||||
|
|
||||||
if (narrow_dir_string)
|
/*
|
||||||
{
|
wc_str is the part of the wildcarded string from the
|
||||||
/*
|
beginning to the first slash
|
||||||
Find out how long the filename can be in a worst case
|
*/
|
||||||
scenario
|
const wcstring wc_str = wcstring(wc, wc_end ? wc_end - wc : wcslen(wc));
|
||||||
*/
|
|
||||||
ln = pathconf(narrow_dir_string, _PC_NAME_MAX);
|
|
||||||
|
|
||||||
/*
|
|
||||||
If not specified, use som large number as fallback
|
|
||||||
*/
|
|
||||||
if (ln < 0)
|
|
||||||
ln = MAX_FILE_LENGTH;
|
|
||||||
free(narrow_dir_string);
|
|
||||||
}
|
|
||||||
new_dir= (wchar_t *)malloc(sizeof(wchar_t)*(base_len+ln+2));
|
|
||||||
|
|
||||||
wc_str = wc_end?wcsndup(wc, wc_end-wc):wcsdup(wc);
|
|
||||||
|
|
||||||
if ((!new_dir) || (!wc_str))
|
|
||||||
{
|
|
||||||
DIE_MEM();
|
|
||||||
}
|
|
||||||
|
|
||||||
wcscpy(new_dir, base_dir);
|
|
||||||
|
|
||||||
|
/* new_dir is a scratch area containing the full path to a file/directory we are iterating over */
|
||||||
|
wcstring new_dir = base_dir;
|
||||||
|
|
||||||
wcstring name_str;
|
wcstring name_str;
|
||||||
while (wreaddir(dir, name_str))
|
while (wreaddir(dir, name_str))
|
||||||
{
|
{
|
||||||
@@ -964,93 +925,83 @@ static int wildcard_expand_internal(const wchar_t *wc,
|
|||||||
if (whole_match || partial_match)
|
if (whole_match || partial_match)
|
||||||
{
|
{
|
||||||
struct stat buf;
|
struct stat buf;
|
||||||
char *dir_str;
|
|
||||||
int stat_res;
|
|
||||||
int new_res;
|
int new_res;
|
||||||
|
|
||||||
|
// new_dir is base_dir + some other path components
|
||||||
|
// Replace everything after base_dir with the new path component
|
||||||
|
new_dir.replace(base_dir_len, wcstring::npos, name_str);
|
||||||
|
|
||||||
|
int stat_res = wstat(new_dir, &buf);
|
||||||
|
|
||||||
wcscpy(&new_dir[base_len], name_str.c_str());
|
if (!stat_res)
|
||||||
dir_str = wcs2str(new_dir);
|
|
||||||
|
|
||||||
if (dir_str)
|
|
||||||
{
|
{
|
||||||
stat_res = stat(dir_str, &buf);
|
// Insert a "file ID" into visited_files
|
||||||
free(dir_str);
|
// If the insertion fails, we've already visited this file (i.e. a symlink loop)
|
||||||
|
// If we're not recursive, insert anyways (in case we loop back around in a future recursive segment), but continue on; the idea being that literal path components should still work
|
||||||
if (!stat_res)
|
const file_id_t file_id(buf.st_dev, buf.st_ino);
|
||||||
|
if (S_ISDIR(buf.st_mode) && (visited_files.insert(file_id).second || ! is_recursive))
|
||||||
{
|
{
|
||||||
// Insert a "file ID" into visited_files
|
new_dir.push_back(L'/');
|
||||||
// If the insertion fails, we've already visited this file (i.e. a symlink loop)
|
|
||||||
// If we're not recursive, insert anyways (in case we loop back around in a future recursive segment), but continue on; the idea being that literal path components should still work
|
/*
|
||||||
const file_id_t file_id(buf.st_dev, buf.st_ino);
|
Regular matching
|
||||||
if (S_ISDIR(buf.st_mode) && (visited_files.insert(file_id).second || ! is_recursive))
|
*/
|
||||||
|
if (whole_match)
|
||||||
{
|
{
|
||||||
size_t new_len = wcslen(new_dir);
|
const wchar_t *new_wc = L"";
|
||||||
new_dir[new_len] = L'/';
|
if (wc_end)
|
||||||
new_dir[new_len+1] = L'\0';
|
|
||||||
|
|
||||||
/*
|
|
||||||
Regular matching
|
|
||||||
*/
|
|
||||||
if (whole_match)
|
|
||||||
{
|
{
|
||||||
const wchar_t *new_wc = L"";
|
new_wc=wc_end+1;
|
||||||
if (wc_end)
|
/*
|
||||||
|
Accept multiple '/' as a single direcotry separator
|
||||||
|
*/
|
||||||
|
while (*new_wc==L'/')
|
||||||
{
|
{
|
||||||
new_wc=wc_end+1;
|
new_wc++;
|
||||||
/*
|
|
||||||
Accept multiple '/' as a single direcotry separator
|
|
||||||
*/
|
|
||||||
while (*new_wc==L'/')
|
|
||||||
{
|
|
||||||
new_wc++;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
new_res = wildcard_expand_internal(new_wc,
|
|
||||||
new_dir,
|
|
||||||
flags,
|
|
||||||
out,
|
|
||||||
completion_set,
|
|
||||||
visited_files);
|
|
||||||
|
|
||||||
if (new_res == -1)
|
|
||||||
{
|
|
||||||
res = -1;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
res |= new_res;
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
new_res = wildcard_expand_internal(new_wc,
|
||||||
Recursive matching
|
new_dir.c_str(),
|
||||||
*/
|
flags,
|
||||||
if (partial_match)
|
out,
|
||||||
|
completion_set,
|
||||||
|
visited_files);
|
||||||
|
|
||||||
|
if (new_res == -1)
|
||||||
{
|
{
|
||||||
|
res = -1;
|
||||||
new_res = wildcard_expand_internal(wcschr(wc, ANY_STRING_RECURSIVE),
|
break;
|
||||||
new_dir,
|
|
||||||
flags | WILDCARD_RECURSIVE,
|
|
||||||
out,
|
|
||||||
completion_set,
|
|
||||||
visited_files);
|
|
||||||
|
|
||||||
if (new_res == -1)
|
|
||||||
{
|
|
||||||
res = -1;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
res |= new_res;
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
res |= new_res;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Recursive matching
|
||||||
|
*/
|
||||||
|
if (partial_match)
|
||||||
|
{
|
||||||
|
|
||||||
|
new_res = wildcard_expand_internal(wcschr(wc, ANY_STRING_RECURSIVE),
|
||||||
|
new_dir.c_str(),
|
||||||
|
flags | WILDCARD_RECURSIVE,
|
||||||
|
out,
|
||||||
|
completion_set,
|
||||||
|
visited_files);
|
||||||
|
|
||||||
|
if (new_res == -1)
|
||||||
|
{
|
||||||
|
res = -1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
res |= new_res;
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
free(wc_str);
|
|
||||||
free(new_dir);
|
|
||||||
}
|
}
|
||||||
closedir(dir);
|
closedir(dir);
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user