PackageWriter::Entry* PackageWriter::_RegisterEntry(Entry* parent, const char* name, size_t nameLength, bool isImplicit) { // check the component name -- don't allow "." or ".." if (*name == '.' && (nameLength == 1 || (nameLength == 2 && name[2] == '.'))) { fprintf(stderr, "Error: Invalid file name: \".\" and \"..\" " "are not allowed as path components\n"); throw status_t(B_BAD_VALUE); } // the entry might already exist Entry* entry = parent->GetChild(name, nameLength); if (entry != NULL) { // If the entry was implicit and is no longer, we mark it non-implicit // and delete all of it's children. if (entry->IsImplicit() && !isImplicit) { entry->DeleteChildren(); entry->SetImplicit(false); } } else { // nope -- create it entry = Entry::Create(name, nameLength, isImplicit); parent->AddChild(entry); } return entry; }
virtual status_t HandleEntry(BPackageEntry* entry) { // create a token Token* token = new(std::nothrow) Token; if (token == NULL) return B_NO_MEMORY; ObjectDeleter<Token> tokenDeleter(token); // check whether this entry shall be ignored or is implicit Entry* parentFilterEntry; bool implicit; if (entry->Parent() != NULL) { Token* parentToken = (Token*)entry->Parent()->UserToken(); if (parentToken == NULL) { // parent is ignored, so ignore this entry, too return B_OK; } parentFilterEntry = parentToken->filterEntry; implicit = parentToken->implicit; } else { parentFilterEntry = &fRootFilterEntry; implicit = fRootFilterEntry.IsImplicit(); } Entry* filterEntry = parentFilterEntry != NULL ? parentFilterEntry->FindChild(entry->Name()) : NULL; if (implicit && filterEntry == NULL) { // parent is implicit and the filter doesn't include this entry // -- ignore it return B_OK; } // If the entry is in the filter, get its implicit flag. if (filterEntry != NULL) { implicit = filterEntry->IsImplicit(); filterEntry->SetSeen(); } token->filterEntry = filterEntry; token->implicit = implicit; // get parent FD and the entry name int parentFD; const char* entryName; _GetParentFDAndEntryName(entry, parentFD, entryName); // check whether something is in the way struct stat st; bool entryExists = fstatat(parentFD, entryName, &st, AT_SYMLINK_NOFOLLOW) == 0; if (entryExists) { if (S_ISREG(entry->Mode()) || S_ISLNK(entry->Mode())) { // If the entry in the way is a regular file or a symlink, // remove it, otherwise fail. if (!S_ISREG(st.st_mode) && !S_ISLNK(st.st_mode)) { fprintf(stderr, "Error: Can't create entry \"%s\", since " "something is in the way\n", _EntryPath(entry).String()); return B_FILE_EXISTS; } if (unlinkat(parentFD, entryName, 0) != 0) { fprintf(stderr, "Error: Failed to unlink entry \"%s\": %s\n", _EntryPath(entry).String(), strerror(errno)); return errno; } entryExists = false; } else if (S_ISDIR(entry->Mode())) { // If the entry in the way is a directory, merge, otherwise // fail. if (!S_ISDIR(st.st_mode)) { fprintf(stderr, "Error: Can't create directory \"%s\", " "since something is in the way\n", _EntryPath(entry).String()); return B_FILE_EXISTS; } } } // create the entry int fd = -1; if (S_ISREG(entry->Mode())) { if (implicit) { fprintf(stderr, "Error: File \"%s\" was specified as a " "path directory component.\n", _EntryPath(entry).String()); return B_BAD_VALUE; } // create the file fd = openat(parentFD, entryName, O_RDWR | O_CREAT | O_EXCL, S_IRUSR | S_IWUSR); // Note: We use read+write user permissions now -- so write // operations (e.g. attributes) won't fail, but set them to the // desired ones in HandleEntryDone(). if (fd < 0) { fprintf(stderr, "Error: Failed to create file \"%s\": %s\n", _EntryPath(entry).String(), strerror(errno)); return errno; } // write data status_t error; const BPackageData& data = entry->Data(); if (data.IsEncodedInline()) { BBufferDataReader dataReader(data.InlineData(), data.CompressedSize()); error = _ExtractFileData(&dataReader, data, fd); } else error = _ExtractFileData(&fPackageFileReader, data, fd); if (error != B_OK) return error; } else if (S_ISLNK(entry->Mode())) { if (implicit) { fprintf(stderr, "Error: Symlink \"%s\" was specified as a " "path directory component.\n", _EntryPath(entry).String()); return B_BAD_VALUE; } // create the symlink const char* symlinkPath = entry->SymlinkPath(); if (symlinkat(symlinkPath != NULL ? symlinkPath : "", parentFD, entryName) != 0) { fprintf(stderr, "Error: Failed to create symlink \"%s\": %s\n", _EntryPath(entry).String(), strerror(errno)); return errno; } // TODO: Set symlink permissions? } else if (S_ISDIR(entry->Mode())) { // create the directory, if necessary if (!entryExists && mkdirat(parentFD, entryName, S_IRWXU) != 0) { // Note: We use read+write+exec user permissions now -- so write // operations (e.g. attributes) won't fail, but set them to the // desired ones in HandleEntryDone(). fprintf(stderr, "Error: Failed to create directory \"%s\": " "%s\n", _EntryPath(entry).String(), strerror(errno)); return errno; } } else { fprintf(stderr, "Error: Invalid file type for entry \"%s\"\n", _EntryPath(entry).String()); return B_BAD_DATA; } // If not done yet (symlink, dir), open the node -- we need the FD. if (fd < 0 && (!implicit || S_ISDIR(entry->Mode()))) { fd = openat(parentFD, entryName, O_RDONLY | O_NOTRAVERSE); if (fd < 0) { fprintf(stderr, "Error: Failed to open entry \"%s\": %s\n", _EntryPath(entry).String(), strerror(errno)); return errno; } } token->fd = fd; // set the file times if (!entryExists && !implicit) { timespec times[2] = {entry->AccessTime(), entry->ModifiedTime()}; futimens(fd, times); // set user/group // TODO:... } entry->SetUserToken(tokenDeleter.Detach()); return B_OK; }