diff --git a/headers/os/package/hpkg/PackageWriter.h b/headers/os/package/hpkg/PackageWriter.h index f64087bec0..7ab04a5d5e 100644 --- a/headers/os/package/hpkg/PackageWriter.h +++ b/headers/os/package/hpkg/PackageWriter.h @@ -48,7 +48,7 @@ public: ~BPackageWriter(); status_t Init(const char* fileName); - status_t AddEntry(const char* fileName); + status_t AddEntry(const char* fileName, int fd = -1); status_t Finish(); private: diff --git a/headers/private/package/hpkg/PackageWriterImpl.h b/headers/private/package/hpkg/PackageWriterImpl.h index ec28e1d77f..e70514457d 100644 --- a/headers/private/package/hpkg/PackageWriterImpl.h +++ b/headers/private/package/hpkg/PackageWriterImpl.h @@ -38,7 +38,7 @@ public: ~PackageWriterImpl(); status_t Init(const char* fileName); - status_t AddEntry(const char* fileName); + status_t AddEntry(const char* fileName, int fd = -1); status_t Finish(); private: @@ -52,9 +52,9 @@ private: status_t _Init(const char* fileName); status_t _Finish(); - status_t _RegisterEntry(const char* fileName); + status_t _RegisterEntry(const char* fileName, int fd); Entry* _RegisterEntry(Entry* parent, - const char* name, size_t nameLength, + const char* name, size_t nameLength, int fd, bool isImplicit); status_t _CheckLicenses(); diff --git a/src/kits/package/hpkg/PackageWriter.cpp b/src/kits/package/hpkg/PackageWriter.cpp index 52428c608e..1966b5a84f 100644 --- a/src/kits/package/hpkg/PackageWriter.cpp +++ b/src/kits/package/hpkg/PackageWriter.cpp @@ -40,12 +40,12 @@ BPackageWriter::Init(const char* fileName) status_t -BPackageWriter::AddEntry(const char* fileName) +BPackageWriter::AddEntry(const char* fileName, int fd) { if (fImpl == NULL) return B_NO_INIT; - return fImpl->AddEntry(fileName); + return fImpl->AddEntry(fileName, fd); } diff --git a/src/kits/package/hpkg/PackageWriterImpl.cpp b/src/kits/package/hpkg/PackageWriterImpl.cpp index dd12e7f90e..cd9791b354 100644 --- a/src/kits/package/hpkg/PackageWriterImpl.cpp +++ b/src/kits/package/hpkg/PackageWriterImpl.cpp @@ -91,10 +91,11 @@ struct PackageWriterImpl::Attribute struct PackageWriterImpl::Entry : DoublyLinkedListLinkImpl { - Entry(char* name, size_t nameLength, bool isImplicit) + Entry(char* name, size_t nameLength, int fd, bool isImplicit) : fName(name), fNameLength(nameLength), + fFD(fd), fIsImplicit(isImplicit) { } @@ -105,7 +106,8 @@ struct PackageWriterImpl::Entry : DoublyLinkedListLinkImpl { 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); if (clonedName == NULL) @@ -113,7 +115,7 @@ struct PackageWriterImpl::Entry : DoublyLinkedListLinkImpl { memcpy(clonedName, name, nameLength); clonedName[nameLength] = '\0'; - Entry* entry = new(std::nothrow) Entry(clonedName, nameLength, + Entry* entry = new(std::nothrow) Entry(clonedName, nameLength, fd, isImplicit); if (entry == NULL) { free(clonedName); @@ -128,6 +130,16 @@ struct PackageWriterImpl::Entry : DoublyLinkedListLinkImpl { return fName; } + int FD() const + { + return fFD; + } + + void SetFD(int fd) + { + fFD = fd; + } + bool IsImplicit() const { return fIsImplicit; @@ -174,6 +186,7 @@ struct PackageWriterImpl::Entry : DoublyLinkedListLinkImpl { private: char* fName; size_t fNameLength; + int fFD; bool fIsImplicit; EntryList fChildren; }; @@ -253,7 +266,7 @@ PackageWriterImpl::Init(const char* fileName) status_t -PackageWriterImpl::AddEntry(const char* fileName) +PackageWriterImpl::AddEntry(const char* fileName, int fd) { try { // if it's ".PackageInfo", parse it @@ -267,15 +280,48 @@ PackageWriterImpl::AddEntry(const char* fileName) } BPackageWriterListener* listener; } errorListener(fListener); - BEntry packageInfoEntry(fileName); - status_t result = fPackageInfo.ReadFromConfigFile(packageInfoEntry, - &errorListener); - if (result != B_OK || (result = fPackageInfo.InitCheck()) != B_OK) - return result; + + if (fd >= 0) { + // a file descriptor is given -- read the config from there + // stat the file to get the file size + 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); } - return _RegisterEntry(fileName); + return _RegisterEntry(fileName, fd); } catch (status_t error) { return error; } catch (std::bad_alloc) { @@ -325,7 +371,7 @@ PackageWriterImpl::_Init(const char* fileName) throw std::bad_alloc(); // create entry list - fRootEntry = new Entry(NULL, 0, true); + fRootEntry = new Entry(NULL, 0, -1, true); fRootAttribute = new Attribute(); @@ -425,7 +471,7 @@ PackageWriterImpl::_Finish() status_t -PackageWriterImpl::_RegisterEntry(const char* fileName) +PackageWriterImpl::_RegisterEntry(const char* fileName, int fd) { if (*fileName == '\0') { fListener->PrintError("Invalid empty file name\n"); @@ -438,7 +484,8 @@ PackageWriterImpl::_RegisterEntry(const char* fileName) const char* nextSlash = strchr(fileName, '/'); // no slash, just add the file name if (nextSlash == NULL) { - entry = _RegisterEntry(entry, fileName, strlen(fileName), false); + entry = _RegisterEntry(entry, fileName, strlen(fileName), fd, + false); break; } @@ -447,13 +494,15 @@ PackageWriterImpl::_RegisterEntry(const char* fileName) while (*nextComponent == '/') nextComponent++; + bool lastComponent = *nextComponent != '\0'; + if (nextSlash == fileName) { // the FS root - entry = _RegisterEntry(entry, fileName, 1, - *nextComponent != '\0'); + entry = _RegisterEntry(entry, fileName, 1, lastComponent ? fd : -1, + lastComponent); } else { entry = _RegisterEntry(entry, fileName, nextSlash - fileName, - *nextComponent != '\0'); + lastComponent ? fd : -1, lastComponent); } fileName = nextComponent; @@ -465,7 +514,7 @@ PackageWriterImpl::_RegisterEntry(const char* fileName) PackageWriterImpl::Entry* 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 ".." if (name[0] == '.' @@ -483,10 +532,11 @@ PackageWriterImpl::_RegisterEntry(Entry* parent, const char* name, if (entry->IsImplicit() && !isImplicit) { entry->DeleteChildren(); entry->SetImplicit(false); + entry->SetFD(fd); } } else { // nope -- create it - entry = Entry::Create(name, nameLength, isImplicit); + entry = Entry::Create(name, nameLength, fd, isImplicit); parent->AddChild(entry); } @@ -626,14 +676,22 @@ PackageWriterImpl::_AddEntry(int dirFD, Entry* entry, const char* fileName, } // open the node - int 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); + int fd; + FileDescriptorCloser fdCloser; + + if (entry != NULL && entry->FD() >= 0) { + // a file descriptor is already given -- use that + 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 struct stat st;