Add optional FD parameter to AddEntry()

If a FD is specified, instead of using the file with the given the FD is
used. Allows for adding entries without first copying them into the
directory structure.
This commit is contained in:
Ingo Weinhold
2011-07-17 16:54:51 +02:00
parent bfbb410d1a
commit 4512e8d566
4 changed files with 89 additions and 31 deletions
+1 -1
View File
@@ -48,7 +48,7 @@ public:
~BPackageWriter(); ~BPackageWriter();
status_t Init(const char* fileName); status_t Init(const char* fileName);
status_t AddEntry(const char* fileName); status_t AddEntry(const char* fileName, int fd = -1);
status_t Finish(); status_t Finish();
private: private:
@@ -38,7 +38,7 @@ public:
~PackageWriterImpl(); ~PackageWriterImpl();
status_t Init(const char* fileName); status_t Init(const char* fileName);
status_t AddEntry(const char* fileName); status_t AddEntry(const char* fileName, int fd = -1);
status_t Finish(); status_t Finish();
private: private:
@@ -52,9 +52,9 @@ private:
status_t _Init(const char* fileName); status_t _Init(const char* fileName);
status_t _Finish(); status_t _Finish();
status_t _RegisterEntry(const char* fileName); status_t _RegisterEntry(const char* fileName, int fd);
Entry* _RegisterEntry(Entry* parent, Entry* _RegisterEntry(Entry* parent,
const char* name, size_t nameLength, const char* name, size_t nameLength, int fd,
bool isImplicit); bool isImplicit);
status_t _CheckLicenses(); status_t _CheckLicenses();
+2 -2
View File
@@ -40,12 +40,12 @@ BPackageWriter::Init(const char* fileName)
status_t status_t
BPackageWriter::AddEntry(const char* fileName) BPackageWriter::AddEntry(const char* fileName, int fd)
{ {
if (fImpl == NULL) if (fImpl == NULL)
return B_NO_INIT; return B_NO_INIT;
return fImpl->AddEntry(fileName); return fImpl->AddEntry(fileName, fd);
} }
+83 -25
View File
@@ -91,10 +91,11 @@ struct PackageWriterImpl::Attribute
struct PackageWriterImpl::Entry : DoublyLinkedListLinkImpl<Entry> { struct PackageWriterImpl::Entry : DoublyLinkedListLinkImpl<Entry> {
Entry(char* name, size_t nameLength, bool isImplicit) Entry(char* name, size_t nameLength, int fd, bool isImplicit)
: :
fName(name), fName(name),
fNameLength(nameLength), fNameLength(nameLength),
fFD(fd),
fIsImplicit(isImplicit) fIsImplicit(isImplicit)
{ {
} }
@@ -105,7 +106,8 @@ struct PackageWriterImpl::Entry : DoublyLinkedListLinkImpl<Entry> {
free(fName); free(fName);
} }
static Entry* Create(const char* name, size_t nameLength, bool isImplicit) static Entry* Create(const char* name, size_t nameLength, int fd,
bool isImplicit)
{ {
char* clonedName = (char*)malloc(nameLength + 1); char* clonedName = (char*)malloc(nameLength + 1);
if (clonedName == NULL) if (clonedName == NULL)
@@ -113,7 +115,7 @@ struct PackageWriterImpl::Entry : DoublyLinkedListLinkImpl<Entry> {
memcpy(clonedName, name, nameLength); memcpy(clonedName, name, nameLength);
clonedName[nameLength] = '\0'; clonedName[nameLength] = '\0';
Entry* entry = new(std::nothrow) Entry(clonedName, nameLength, Entry* entry = new(std::nothrow) Entry(clonedName, nameLength, fd,
isImplicit); isImplicit);
if (entry == NULL) { if (entry == NULL) {
free(clonedName); free(clonedName);
@@ -128,6 +130,16 @@ struct PackageWriterImpl::Entry : DoublyLinkedListLinkImpl<Entry> {
return fName; return fName;
} }
int FD() const
{
return fFD;
}
void SetFD(int fd)
{
fFD = fd;
}
bool IsImplicit() const bool IsImplicit() const
{ {
return fIsImplicit; return fIsImplicit;
@@ -174,6 +186,7 @@ struct PackageWriterImpl::Entry : DoublyLinkedListLinkImpl<Entry> {
private: private:
char* fName; char* fName;
size_t fNameLength; size_t fNameLength;
int fFD;
bool fIsImplicit; bool fIsImplicit;
EntryList fChildren; EntryList fChildren;
}; };
@@ -253,7 +266,7 @@ PackageWriterImpl::Init(const char* fileName)
status_t status_t
PackageWriterImpl::AddEntry(const char* fileName) PackageWriterImpl::AddEntry(const char* fileName, int fd)
{ {
try { try {
// if it's ".PackageInfo", parse it // if it's ".PackageInfo", parse it
@@ -267,15 +280,48 @@ PackageWriterImpl::AddEntry(const char* fileName)
} }
BPackageWriterListener* listener; BPackageWriterListener* listener;
} errorListener(fListener); } errorListener(fListener);
BEntry packageInfoEntry(fileName);
status_t result = fPackageInfo.ReadFromConfigFile(packageInfoEntry, if (fd >= 0) {
&errorListener); // a file descriptor is given -- read the config from there
if (result != B_OK || (result = fPackageInfo.InitCheck()) != B_OK) // stat the file to get the file size
return result; struct stat st;
if (fstat(fd, &st) != 0)
return errno;
BString packageInfoString;
char* buffer = packageInfoString.LockBuffer(st.st_size);
if (buffer == NULL)
return B_NO_MEMORY;
ssize_t result = read_pos(fd, 0, buffer, st.st_size);
if (result < 0) {
packageInfoString.UnlockBuffer(0);
return errno;
}
buffer[st.st_size] = '\0';
packageInfoString.UnlockBuffer(st.st_size);
result = fPackageInfo.ReadFromConfigString(packageInfoString,
&errorListener);
if (result != B_OK)
return result;
} else {
printf(" reading by name...\n");
// use the file name
BEntry packageInfoEntry(fileName);
status_t result = fPackageInfo.ReadFromConfigFile(
packageInfoEntry, &errorListener);
if (result != B_OK
|| (result = fPackageInfo.InitCheck()) != B_OK) {
return result;
}
}
RegisterPackageInfo(PackageAttributes(), fPackageInfo); RegisterPackageInfo(PackageAttributes(), fPackageInfo);
} }
return _RegisterEntry(fileName); return _RegisterEntry(fileName, fd);
} catch (status_t error) { } catch (status_t error) {
return error; return error;
} catch (std::bad_alloc) { } catch (std::bad_alloc) {
@@ -325,7 +371,7 @@ PackageWriterImpl::_Init(const char* fileName)
throw std::bad_alloc(); throw std::bad_alloc();
// create entry list // create entry list
fRootEntry = new Entry(NULL, 0, true); fRootEntry = new Entry(NULL, 0, -1, true);
fRootAttribute = new Attribute(); fRootAttribute = new Attribute();
@@ -425,7 +471,7 @@ PackageWriterImpl::_Finish()
status_t status_t
PackageWriterImpl::_RegisterEntry(const char* fileName) PackageWriterImpl::_RegisterEntry(const char* fileName, int fd)
{ {
if (*fileName == '\0') { if (*fileName == '\0') {
fListener->PrintError("Invalid empty file name\n"); fListener->PrintError("Invalid empty file name\n");
@@ -438,7 +484,8 @@ PackageWriterImpl::_RegisterEntry(const char* fileName)
const char* nextSlash = strchr(fileName, '/'); const char* nextSlash = strchr(fileName, '/');
// no slash, just add the file name // no slash, just add the file name
if (nextSlash == NULL) { if (nextSlash == NULL) {
entry = _RegisterEntry(entry, fileName, strlen(fileName), false); entry = _RegisterEntry(entry, fileName, strlen(fileName), fd,
false);
break; break;
} }
@@ -447,13 +494,15 @@ PackageWriterImpl::_RegisterEntry(const char* fileName)
while (*nextComponent == '/') while (*nextComponent == '/')
nextComponent++; nextComponent++;
bool lastComponent = *nextComponent != '\0';
if (nextSlash == fileName) { if (nextSlash == fileName) {
// the FS root // the FS root
entry = _RegisterEntry(entry, fileName, 1, entry = _RegisterEntry(entry, fileName, 1, lastComponent ? fd : -1,
*nextComponent != '\0'); lastComponent);
} else { } else {
entry = _RegisterEntry(entry, fileName, nextSlash - fileName, entry = _RegisterEntry(entry, fileName, nextSlash - fileName,
*nextComponent != '\0'); lastComponent ? fd : -1, lastComponent);
} }
fileName = nextComponent; fileName = nextComponent;
@@ -465,7 +514,7 @@ PackageWriterImpl::_RegisterEntry(const char* fileName)
PackageWriterImpl::Entry* PackageWriterImpl::Entry*
PackageWriterImpl::_RegisterEntry(Entry* parent, const char* name, PackageWriterImpl::_RegisterEntry(Entry* parent, const char* name,
size_t nameLength, bool isImplicit) size_t nameLength, int fd, bool isImplicit)
{ {
// check the component name -- don't allow "." or ".." // check the component name -- don't allow "." or ".."
if (name[0] == '.' if (name[0] == '.'
@@ -483,10 +532,11 @@ PackageWriterImpl::_RegisterEntry(Entry* parent, const char* name,
if (entry->IsImplicit() && !isImplicit) { if (entry->IsImplicit() && !isImplicit) {
entry->DeleteChildren(); entry->DeleteChildren();
entry->SetImplicit(false); entry->SetImplicit(false);
entry->SetFD(fd);
} }
} else { } else {
// nope -- create it // nope -- create it
entry = Entry::Create(name, nameLength, isImplicit); entry = Entry::Create(name, nameLength, fd, isImplicit);
parent->AddChild(entry); parent->AddChild(entry);
} }
@@ -626,14 +676,22 @@ PackageWriterImpl::_AddEntry(int dirFD, Entry* entry, const char* fileName,
} }
// open the node // open the node
int fd = openat(dirFD, fileName, int fd;
O_RDONLY | (isImplicitEntry ? 0 : O_NOTRAVERSE)); FileDescriptorCloser fdCloser;
if (fd < 0) {
fListener->PrintError("Failed to open entry \"%s\": %s\n", fileName, if (entry != NULL && entry->FD() >= 0) {
strerror(errno)); // a file descriptor is already given -- use that
throw status_t(errno); fd = entry->FD();
} else {
fd = openat(dirFD, fileName,
O_RDONLY | (isImplicitEntry ? 0 : O_NOTRAVERSE));
if (fd < 0) {
fListener->PrintError("Failed to open entry \"%s\": %s\n", fileName,
strerror(errno));
throw status_t(errno);
}
fdCloser.SetTo(fd);
} }
FileDescriptorCloser fdCloser(fd);
// stat the node // stat the node
struct stat st; struct stat st;