Avoid using unions for LongDirEntry.

GCC still assumes that the dirent has no data past the end for some
scenarios here and still mis-optimizes things. Therefore, drop the
usages of unions altogether, and instead use a casted character array.

Additionally, use B_FILE_NAME_LENGTH for the array, not B_PATH_NAME_LENGTH,
and make sure to add 1 for the NULL terminator.
This commit is contained in:
Augustin Cavalier
2021-11-23 16:36:18 -05:00
parent 8be37ed439
commit 2532a28785
12 changed files with 38 additions and 39 deletions
+6 -6
View File
@@ -25,9 +25,9 @@ namespace BPrivate {
namespace Storage {
// For convenience:
union LongDirEntry {
struct dirent dirent;
char _[sizeof(struct dirent) + B_PATH_NAME_LENGTH];
struct LongDirEntry {
char _[sizeof(struct dirent) + B_FILE_NAME_LENGTH + 1];
struct dirent* dirent() { return (struct dirent*)_; }
};
//! Returns whether the supplied path is absolute.
@@ -73,9 +73,9 @@ void to_lower(const char *str, std::string &result);
/*! \brief Copies \c str into \c result, converting any uppercase alphabetics
to lowercase.
\a str and \a result may point to the same string. \a result is
assumed to be as long as or longer than \a str.
assumed to be as long as or longer than \a str.
*/
void to_lower(const char *str, char *result);
@@ -87,7 +87,7 @@ void to_lower(char *str);
\a result must be large enough to accomodate the addition of
escape sequences to \a str. \a str and \a result may *NOT* point to
the same string.
Note that this function was designed for use with the registrar's
RecentEntries class, and may not create escapes exactly like you're
hoping. Please double check the code for the function to see if this
+2 -2
View File
@@ -333,7 +333,7 @@ BDirectory::GetNextRef(entry_ref* ref)
return B_FILE_ERROR;
BPrivate::Storage::LongDirEntry longEntry;
struct dirent* entry = &longEntry.dirent;
struct dirent* entry = longEntry.dirent();
bool next = true;
while (next) {
if (GetNextDirents(entry, sizeof(longEntry), 1) != 1)
@@ -377,7 +377,7 @@ BDirectory::CountEntries()
return error;
int32 count = 0;
BPrivate::Storage::LongDirEntry longEntry;
struct dirent* entry = &longEntry.dirent;
struct dirent* entry = longEntry.dirent();
while (error == B_OK) {
if (GetNextDirents(entry, sizeof(longEntry), 1) != 1)
break;
+1 -1
View File
@@ -110,7 +110,7 @@ status_t
BMergedDirectory::GetNextRef(entry_ref* ref)
{
BPrivate::Storage::LongDirEntry longEntry;
struct dirent* dirEntry = &longEntry.dirent;
struct dirent* dirEntry = longEntry.dirent();
int32 result = GetNextDirents(dirEntry, sizeof(longEntry), 1);
if (result < 0)
return result;
+1 -1
View File
@@ -310,7 +310,7 @@ BNode::GetNextAttrName(char* buffer)
return B_FILE_ERROR;
BPrivate::Storage::LongDirEntry longEntry;
struct dirent* entry = &longEntry.dirent;
struct dirent* entry = longEntry.dirent();
ssize_t result = _kern_read_dir(fAttrFd, entry, sizeof(longEntry), 1);
if (result < 0)
return result;
+8 -8
View File
@@ -129,10 +129,10 @@ class AttributeDirectory;
typedef map<DIR*, AttributeDirectory*> AttrDirMap;
static AttrDirMap sAttributeDirectories;
// LongDirent
union LongDirent {
struct dirent dirent;
char _[sizeof(struct dirent) + B_FILE_NAME_LENGTH];
// LongDirEntry
struct LongDirEntry {
char _[sizeof(struct dirent) + B_FILE_NAME_LENGTH + 1];
struct dirent* dirent() { return (struct dirent*)_; }
};
// AttributeHeader
@@ -260,11 +260,11 @@ public:
}
// prepare the dirent
strcpy(fDirent.dirent.d_name, name);
fDirent.dirent.d_ino = 0;
strcpy(fDirent.dirent()->d_name, name);
fDirent.dirent()->d_ino = 0;
// TODO: We need the node ID!
*_entry = &fDirent.dirent;
*_entry = fDirent.dirent();
return B_OK;
}
@@ -309,7 +309,7 @@ private:
int fFileFD;
string fPath;
DIR* fFakeDir;
LongDirent fDirent;
LongDirEntry fDirent;
char* fListing;
int fListingLength;
int fListingIndex;
+2 -2
View File
@@ -353,7 +353,7 @@ BDirectory::GetNextRef(entry_ref* ref)
return B_FILE_ERROR;
BPrivate::Storage::LongDirEntry longEntry;
struct dirent* entry = &longEntry.dirent;
struct dirent* entry = longEntry.dirent();
bool next = true;
while (next) {
if (GetNextDirents(entry, sizeof(longEntry), 1) != 1)
@@ -397,7 +397,7 @@ BDirectory::CountEntries()
return error;
int32 count = 0;
BPrivate::Storage::LongDirEntry longEntry;
struct dirent* entry = &longEntry.dirent;
struct dirent* entry = longEntry.dirent();
while (error == B_OK) {
if (GetNextDirents(entry, sizeof(longEntry), 1) != 1)
break;
+1 -1
View File
@@ -112,7 +112,7 @@ status_t
BMergedDirectory::GetNextRef(entry_ref* ref)
{
BPrivate::Storage::LongDirEntry longEntry;
struct dirent* entry = &longEntry.dirent;
struct dirent* entry = longEntry.dirent();
int32 result = GetNextDirents(entry, sizeof(longEntry), 1);
if (result < 0)
return result;
+1 -1
View File
@@ -320,7 +320,7 @@ BNode::GetNextAttrName(char* buffer)
return B_FILE_ERROR;
BPrivate::Storage::LongDirEntry longEntry;
struct dirent* entry = &longEntry.dirent;
struct dirent* entry = longEntry.dirent();
ssize_t result = _kern_read_dir(fAttrFd, entry, sizeof(longEntry), 1);
if (result < 0)
return result;
+1 -1
View File
@@ -349,7 +349,7 @@ BQuery::GetNextRef(entry_ref* ref)
error = B_FILE_ERROR;
if (error == B_OK) {
BPrivate::Storage::LongDirEntry longEntry;
struct dirent* entry = &longEntry.dirent;
struct dirent* entry = longEntry.dirent();
bool next = true;
while (error == B_OK && next) {
if (GetNextDirents(entry, sizeof(longEntry), 1) != 1) {
@@ -83,7 +83,7 @@ status_t
VirtualDirectoryEntryList::GetNextRef(entry_ref* ref)
{
BPrivate::Storage::LongDirEntry longEntry;
struct dirent* entry = &longEntry.dirent;
struct dirent* entry = longEntry.dirent();
int32 result = GetNextDirents(entry, sizeof(longEntry), 1);
if (result < 0)
return result;
@@ -209,7 +209,7 @@ VirtualDirectoryPoseView::_EntryCreated(const BMessage* message)
return true;
BPrivate::Storage::LongDirEntry longEntry;
struct dirent* entry = &longEntry.dirent;
struct dirent* entry = longEntry.dirent();
while (directory.GetNextDirents(entry, sizeof(longEntry), 1) == 1) {
if (strcmp(entry->d_name, ".") != 0
&& strcmp(entry->d_name, "..") != 0) {
+13 -14
View File
@@ -42,10 +42,9 @@ using namespace boot;
struct __DIR {
Directory* directory;
void* cookie;
union {
dirent entry;
char nameBuffer[sizeof(dirent) + B_FILE_NAME_LENGTH - 1];
};
char _direntBuffer[sizeof(dirent) + B_FILE_NAME_LENGTH + 1];
dirent* entry() { return (dirent*)_direntBuffer; }
};
@@ -1260,33 +1259,33 @@ readdir(DIR* dir)
for (;;) {
status_t error = dir->directory->GetNextEntry(dir->cookie,
dir->entry.d_name, B_FILE_NAME_LENGTH);
dir->entry()->d_name, B_FILE_NAME_LENGTH);
if (error != B_OK) {
errno = error;
return NULL;
}
dir->entry.d_pdev = 0;
dir->entry()->d_pdev = 0;
// not supported
dir->entry.d_pino = dir->directory->Inode();
dir->entry.d_dev = dir->entry.d_pdev;
dir->entry()->d_pino = dir->directory->Inode();
dir->entry()->d_dev = dir->entry()->d_pdev;
// not supported
if (strcmp(dir->entry.d_name, ".") == 0
|| strcmp(dir->entry.d_name, "..") == 0) {
if (strcmp(dir->entry()->d_name, ".") == 0
|| strcmp(dir->entry()->d_name, "..") == 0) {
// Note: That's obviously not correct for "..", but we can't
// retrieve that information.
dir->entry.d_ino = dir->entry.d_pino;
dir->entry()->d_ino = dir->entry()->d_pino;
} else {
Node* node = dir->directory->Lookup(dir->entry.d_name, false);
Node* node = dir->directory->Lookup(dir->entry()->d_name, false);
if (node == NULL)
continue;
dir->entry.d_ino = node->Inode();
dir->entry()->d_ino = node->Inode();
node->Release();
}
return &dir->entry;
return dir->entry();
}
}