aboutsummaryrefslogtreecommitdiffhomepage
path: root/wildcard.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'wildcard.cpp')
-rw-r--r--wildcard.cpp52
1 files changed, 37 insertions, 15 deletions
diff --git a/wildcard.cpp b/wildcard.cpp
index 621ece72..eb29c4e6 100644
--- a/wildcard.cpp
+++ b/wildcard.cpp
@@ -105,18 +105,14 @@ wildcards using **.
/** Hashtable containing all descriptions that describe an executable */
static std::map<wcstring, wcstring> suffix_map;
-
-bool wildcard_has(const wchar_t *str, bool internal)
+// Implementation of wildcard_has. Needs to take the length to handle embedded nulls (#1631)
+static bool wildcard_has_impl(const wchar_t *str, size_t len, bool internal)
{
- if (!str)
- {
- debug(2, L"Got null string on line %d of file %s", __LINE__, __FILE__);
- return false;
- }
-
+ assert(str != NULL);
+ const wchar_t *end = str + len;
if (internal)
{
- for (; *str; str++)
+ for (; str < end; str++)
{
if ((*str == ANY_CHAR) || (*str == ANY_STRING) || (*str == ANY_STRING_RECURSIVE))
return true;
@@ -125,7 +121,7 @@ bool wildcard_has(const wchar_t *str, bool internal)
else
{
wchar_t prev=0;
- for (; *str; str++)
+ for (; str < end; str++)
{
if (((*str == L'*') || (*str == L'?')) && (prev != L'\\'))
return true;
@@ -136,6 +132,18 @@ bool wildcard_has(const wchar_t *str, bool internal)
return false;
}
+bool wildcard_has(const wchar_t *str, bool internal)
+{
+ assert(str != NULL);
+ return wildcard_has_impl(str, wcslen(str), internal);
+}
+
+bool wildcard_has(const wcstring &str, bool internal)
+{
+ return wildcard_has_impl(str.data(), str.size(), internal);
+}
+
+
/**
Check whether the string str matches the wildcard string wc.
@@ -317,7 +325,7 @@ static bool wildcard_complete_internal(const wcstring &orig,
if (wildcard_complete_internal(orig, str + i, wc+1, false, desc, desc_func, out, expand_flags, flags))
{
res = true;
-
+
/* #929: if the recursive call gives us a prefix match, just stop. This is sloppy - what we really want to do is say, once we've seen a match of a particular type, ignore all matches of that type further down the string, such that the wildcard produces the "minimal match." */
bool has_prefix_match = false;
const size_t after_count = out.size();
@@ -424,7 +432,6 @@ static wcstring complete_get_desc_suffix(const wchar_t *suff_orig)
size_t len;
wchar_t *suff;
wchar_t *pos;
- wchar_t *tmp;
len = wcslen(suff_orig);
@@ -445,9 +452,9 @@ static wcstring complete_get_desc_suffix(const wchar_t *suff_orig)
}
}
- tmp = escape(suff, 1);
+ wcstring tmp = escape(suff, ESCAPE_ALL);
free(suff);
- suff = tmp;
+ suff = wcsdup(tmp.c_str());
std::map<wcstring, wcstring>::iterator iter = suffix_map.find(suff);
wcstring desc;
@@ -724,6 +731,16 @@ static bool test_flags(const wchar_t *filename, expand_flags_t flags)
{
if (waccess(filename, X_OK) != 0)
return false;
+ struct stat buf;
+ if (wstat(filename, &buf) == -1)
+ {
+ return false;
+ }
+
+ if (!S_ISREG(buf.st_mode))
+ {
+ return false;
+ }
}
return true;
@@ -971,7 +988,7 @@ static int wildcard_expand_internal(const wchar_t *wc,
// Insert a "file ID" into visited_files
// 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);
+ const file_id_t file_id = file_id_t::file_id_from_stat(&buf);
if (S_ISDIR(buf.st_mode) && (visited_files.insert(file_id).second || ! is_recursive))
{
new_dir.push_back(L'/');
@@ -1084,6 +1101,11 @@ int wildcard_expand(const wchar_t *wc,
int wildcard_expand_string(const wcstring &wc, const wcstring &base_dir, expand_flags_t flags, std::vector<completion_t> &outputs)
{
+ /* Hackish fix for 1631. We are about to call c_str(), which will produce a string truncated at any embedded nulls. We could fix this by passing around the size, etc. However embedded nulls are never allowed in a filename, so we just check for them and return 0 (no matches) if there is an embedded null. This isn't quite right, e.g. it will fail for \0?, but that is an edge case. */
+ if (wc.find(L'\0') != wcstring::npos)
+ {
+ return 0;
+ }
// PCA: not convinced this temporary variable is really necessary
std::vector<completion_t> lst;
int res = wildcard_expand(wc.c_str(), base_dir.c_str(), flags, lst);