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
+3 -3
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.
+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();
}
}