make wreaddir() handle broken struct dirent

Some platforms do not correctly define `struct dirent` so that its
`d_name` member is long enough for the longest file name. Work around
such broken definitions.

Fixes #4030

(cherry picked from commit a5a9ca7d3b)
This commit is contained in:
Kurtis Rader 2017-05-17 22:35:28 -07:00
parent c9c802d3fc
commit 40679560a6

View file

@ -87,15 +87,22 @@ bool wreaddir_resolving(DIR *dir, const wcstring &dir_path, wcstring &out_name,
} }
bool wreaddir(DIR *dir, wcstring &out_name) { bool wreaddir(DIR *dir, wcstring &out_name) {
struct dirent d; // We need to use a union to ensure that the dirent struct is large enough to avoid stomping on
// the stack. Some platforms incorrectly defined the `d_name[]` member as being one element
// long when it should be at least NAME_MAX + 1.
union {
struct dirent d;
char c[offsetof(struct dirent, d_name) + NAME_MAX + 1]; /* NAME_MAX is POSIX. */
} d_u;
struct dirent *result = NULL; struct dirent *result = NULL;
int retval = readdir_r(dir, &d, &result);
int retval = readdir_r(dir, &d_u.d, &result);
if (retval || !result) { if (retval || !result) {
out_name = L""; out_name = L"";
return false; return false;
} }
out_name = str2wcstring(d.d_name);
out_name = str2wcstring(d_u.d.d_name);
return true; return true;
} }