Entry* FindFilterEntry(const char* fileName) { // add all components of the path Entry* entry = &fRootFilterEntry; while (entry != NULL && *fileName != 0) { const char* nextSlash = strchr(fileName, '/'); // no slash, just add the file name if (nextSlash == NULL) return entry->FindChild(fileName); // find the start of the next component, skipping slashes const char* nextComponent = nextSlash + 1; while (*nextComponent == '/') nextComponent++; BString componentName(fileName, nextSlash - fileName); entry = entry->FindChild(componentName); fileName = nextComponent; } 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; }