#include <apt-pkg/configuration.h>
#include <apt-pkg/tagfile.h>
#include <apt-pkg/indexrecords.h>
-#include <apt-pkg/md5.h>
#include <apt-pkg/cdrom.h>
+#include <apt-pkg/gpgv.h>
+#include <apt-pkg/hashes.h>
#include <iostream>
#include <sstream>
#include <unistd.h>
#include <sys/stat.h>
-#include <sys/types.h>
-#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
+#include <string.h>
#include "indexcopy.h"
#include <apti18n.h>
using namespace std;
-// DecompressFile - wrapper for decompressing compressed files /*{{{*/
-// ---------------------------------------------------------------------
-/* */
-bool DecompressFile(string Filename, int *fd, off_t *FileSize)
-{
- struct stat Buf;
- *fd = -1;
-
- std::vector<APT::Configuration::Compressor> const compressor = APT::Configuration::getCompressors();
- std::vector<APT::Configuration::Compressor>::const_iterator UnCompress;
- std::string file = std::string(Filename).append(UnCompress->Extension);
- for (UnCompress = compressor.begin(); UnCompress != compressor.end(); ++UnCompress)
- {
- if (stat(file.c_str(), &Buf) == 0)
- break;
- }
-
- if (UnCompress == compressor.end())
- return _error->Errno("decompressor", "Unable to parse file");
-
- *FileSize = Buf.st_size;
-
- // Create a data pipe
- int Pipe[2] = {-1,-1};
- if (pipe(Pipe) != 0)
- return _error->Errno("pipe",_("Failed to create subprocess IPC"));
- for (int J = 0; J != 2; J++)
- SetCloseExec(Pipe[J],true);
-
- *fd = Pipe[1];
-
- // The child..
- pid_t Pid = ExecFork();
- if (Pid == 0)
- {
- dup2(Pipe[1],STDOUT_FILENO);
- SetCloseExec(STDOUT_FILENO, false);
-
- std::vector<char const*> Args;
- Args.push_back(UnCompress->Binary.c_str());
- for (std::vector<std::string>::const_iterator a = UnCompress->UncompressArgs.begin();
- a != UnCompress->UncompressArgs.end(); ++a)
- Args.push_back(a->c_str());
- Args.push_back("--stdout");
- Args.push_back(file.c_str());
- Args.push_back(NULL);
-
- execvp(Args[0],(char **)&Args[0]);
- cerr << _("Failed to exec compressor ") << Args[0] << endl;
- _exit(100);
- }
-
- // Wait for decompress to finish
- if (ExecWait(Pid, UnCompress->Binary.c_str(), false) == false)
- return false;
-
- return true;
-}
- /*}}}*/
// IndexCopy::CopyPackages - Copy the package files from the CD /*{{{*/
// ---------------------------------------------------------------------
/* */
for (std::vector<APT::Configuration::Compressor>::const_iterator c = compressor.begin();
c != compressor.end(); ++c)
{
- if (stat(std::string(file + c->Extension).c_str(), &Buf) != 0)
+ if (stat((file + c->Extension).c_str(), &Buf) != 0)
continue;
found = true;
break;
for (vector<string>::iterator I = List.begin(); I != List.end(); ++I)
{
string OrigPath = string(*I,CDROM.length());
- off_t FileSize = 0;
// Open the package file
- FileFd Pkg;
- if (RealFileExists(*I + GetFileName()) == true)
- {
- Pkg.Open(*I + GetFileName(),FileFd::ReadOnly);
- FileSize = Pkg.Size();
- }
- else
- {
- int fd;
- if (!DecompressFile(string(*I + GetFileName()), &fd, &FileSize))
- return _error->Errno("decompress","Decompress failed for %s",
- string(*I + GetFileName()).c_str());
- Pkg.Fd(dup(fd));
- Pkg.Seek(0);
- }
+ FileFd Pkg(*I + GetFileName(), FileFd::ReadOnly, FileFd::Auto);
+ off_t const FileSize = Pkg.Size();
pkgTagFile Parser(&Pkg);
if (_error->PendingError() == true)
} else {
Target.Open(TargetF,FileFd::WriteAtomic);
}
- FILE *TargetFl = fdopen(dup(Target.Fd()),"w");
if (_error->PendingError() == true)
return false;
+ FILE *TargetFl = fdopen(dup(Target.Fd()),"w");
if (TargetFl == 0)
return _error->Errno("fdopen","Failed to reopen fd");
File = OrigPath + ChopDirs(File,Chop);
// See if the file exists
- bool Mangled = false;
if (NoStat == false || Hits < 10)
{
// Attempt to fix broken structure
// Get the size
struct stat Buf;
- if (stat(string(CDROM + Prefix + File).c_str(),&Buf) != 0 ||
+ if (stat((CDROM + Prefix + File).c_str(),&Buf) != 0 ||
Buf.st_size == 0)
{
+ bool Mangled = false;
// Attempt to fix busted symlink support for one instance
string OrigFile = File;
string::size_type Start = File.find("binary-");
}
if (Mangled == false ||
- stat(string(CDROM + Prefix + File).c_str(),&Buf) != 0)
+ stat((CDROM + Prefix + File).c_str(),&Buf) != 0)
{
if (Debug == true)
clog << "Missed(2): " << OrigFile << endl;
while (1)
{
struct stat Buf;
- if (stat(string(CD + MyPrefix + File).c_str(),&Buf) != 0)
+ if (stat((CD + MyPrefix + File).c_str(),&Buf) != 0)
{
if (Debug == true)
cout << "Failed, " << CD + MyPrefix + File << endl;
while (1)
{
struct stat Buf;
- if (stat(string(Dir + File).c_str(),&Buf) != 0)
+ if (stat((Dir + File).c_str(),&Buf) != 0)
{
File = ChopDirs(File,1);
Depth++;
*/
void IndexCopy::ConvertToSourceList(string CD,string &Path)
{
- char S[300];
- snprintf(S,sizeof(S),"binary-%s",_config->Find("Apt::Architecture").c_str());
-
// Strip the cdrom base path
Path = string(Path,CD.length());
if (Path.empty() == true)
return;
string Binary = string(Path,Slash+1,BinSlash - Slash-1);
- if (Binary != S && Binary != "source")
+ if (strncmp(Binary.c_str(), "binary-", strlen("binary-")) == 0)
+ {
+ Binary.erase(0, strlen("binary-"));
+ if (APT::Configuration::checkArchitecture(Binary) == false)
+ continue;
+ }
+ else if (Binary != "source")
continue;
Path = Dist + ' ' + Comp;
/* */
bool PackageCopy::RewriteEntry(FILE *Target,string File)
{
- TFRewriteData Changes[] = {{"Filename",File.c_str()},
- {}};
+ TFRewriteData Changes[] = {{ "Filename", File.c_str(), NULL },
+ { NULL, NULL, NULL }};
if (TFRewrite(Target,*Section,TFRewritePackageOrder,Changes) == false)
return false;
bool SourceCopy::RewriteEntry(FILE *Target,string File)
{
string Dir(File,0,File.rfind('/'));
- TFRewriteData Changes[] = {{"Directory",Dir.c_str()},
- {}};
+ TFRewriteData Changes[] = {{ "Directory", Dir.c_str(), NULL },
+ { NULL, NULL, NULL }};
if (TFRewrite(Target,*Section,TFRewriteSourceOrder,Changes) == false)
return false;
bool SigVerify::Verify(string prefix, string file, indexRecords *MetaIndex)
{
const indexRecords::checkSum *Record = MetaIndex->Lookup(file);
+ bool const Debug = _config->FindB("Debug::aptcdrom",false);
- // we skip non-existing files in the verifcation to support a cdrom
- // with no Packages file (just a Package.gz), see LP: #255545
- // (non-existing files are not considered a error)
+ // we skip non-existing files in the verifcation of the Release file
+ // as non-existing files do not harm, but a warning scares people and
+ // makes it hard to strip unneeded files from an ISO like uncompressed
+ // indexes as it is done on the mirrors (see also LP: #255545 )
if(!RealFileExists(prefix+file))
{
- _error->Warning(_("Skipping nonexistent file %s"), string(prefix+file).c_str());
+ if (Debug == true)
+ cout << "Skipping nonexistent in " << prefix << " file " << file << std::endl;
return true;
}
- if (!Record)
+ if (!Record)
{
_error->Warning(_("Can't find authentication record for: %s"), file.c_str());
return false;
return false;
}
- if(_config->FindB("Debug::aptcdrom",false))
+ if(Debug == true)
{
cout << "File: " << prefix+file << endl;
cout << "Expected Hash " << Record->Hash.toStr() << endl;
FileFd Rel;
Target.Open(TargetF,FileFd::WriteAtomic);
Rel.Open(prefix + file,FileFd::ReadOnly);
- if (_error->PendingError() == true)
- return false;
if (CopyFile(Rel,Target) == false)
- return false;
-
+ return _error->Error("Copying of '%s' for '%s' from '%s' failed", file.c_str(), CDName.c_str(), prefix.c_str());
+
return true;
}
/*}}}*/
bool SigVerify::CopyAndVerify(string CDROM,string Name,vector<string> &SigList, /*{{{*/
- vector<string> PkgList,vector<string> SrcList)
+ vector<string> /*PkgList*/,vector<string> /*SrcList*/)
{
if (SigList.empty() == true)
return true;
string const releasegpg = *I+"Release.gpg";
string const release = *I+"Release";
+ string const inrelease = *I+"InRelease";
+ bool useInRelease = true;
// a Release.gpg without a Release should never happen
- if(RealFileExists(release) == false)
+ if (RealFileExists(inrelease) == true)
+ ;
+ else if(RealFileExists(release) == false || RealFileExists(releasegpg) == false)
{
delete MetaIndex;
continue;
}
+ else
+ useInRelease = false;
pid_t pid = ExecFork();
if(pid < 0) {
return false;
}
if(pid == 0)
- RunGPGV(release, releasegpg);
+ {
+ if (useInRelease == true)
+ ExecGPGV(inrelease, inrelease);
+ else
+ ExecGPGV(release, releasegpg);
+ }
if(!ExecWait(pid, "gpgv")) {
_error->Warning("Signature verification failed for: %s",
- releasegpg.c_str());
+ (useInRelease ? inrelease.c_str() : releasegpg.c_str()));
// something went wrong, don't copy the Release.gpg
// FIXME: delete any existing gpg file?
+ delete MetaIndex;
continue;
}
delete MetaIndex;
// everything was fine, copy the Release and Release.gpg file
- CopyMetaIndex(CDROM, Name, prefix, "Release");
- CopyMetaIndex(CDROM, Name, prefix, "Release.gpg");
+ if (useInRelease == true)
+ CopyMetaIndex(CDROM, Name, prefix, "InRelease");
+ else
+ {
+ CopyMetaIndex(CDROM, Name, prefix, "Release");
+ CopyMetaIndex(CDROM, Name, prefix, "Release.gpg");
+ }
}
return true;
}
/*}}}*/
-// SigVerify::RunGPGV - returns the command needed for verify /*{{{*/
-// ---------------------------------------------------------------------
-/* Generating the commandline for calling gpgv is somehow complicated as
- we need to add multiple keyrings and user supplied options. Also, as
- the cdrom code currently can not use the gpgv method we have two places
- these need to be done - so the place for this method is wrong but better
- than code duplication… */
-bool SigVerify::RunGPGV(std::string const &File, std::string const &FileGPG,
- int const &statusfd, int fd[2])
-{
- if (File == FileGPG)
- {
- #define SIGMSG "-----BEGIN PGP SIGNED MESSAGE-----\n"
- char buffer[sizeof(SIGMSG)];
- FILE* gpg = fopen(File.c_str(), "r");
- if (gpg == NULL)
- return _error->Errno("RunGPGV", _("Could not open file %s"), File.c_str());
- char const * const test = fgets(buffer, sizeof(buffer), gpg);
- fclose(gpg);
- if (test == NULL || strcmp(buffer, SIGMSG) != 0)
- return _error->Error(_("File %s doesn't start with a clearsigned message"), File.c_str());
- #undef SIGMSG
- }
-
-
- string const gpgvpath = _config->Find("Dir::Bin::gpg", "/usr/bin/gpgv");
- // FIXME: remove support for deprecated APT::GPGV setting
- string const trustedFile = _config->Find("APT::GPGV::TrustedKeyring", _config->FindFile("Dir::Etc::Trusted"));
- string const trustedPath = _config->FindDir("Dir::Etc::TrustedParts");
-
- bool const Debug = _config->FindB("Debug::Acquire::gpgv", false);
-
- if (Debug == true)
- {
- std::clog << "gpgv path: " << gpgvpath << std::endl;
- std::clog << "Keyring file: " << trustedFile << std::endl;
- std::clog << "Keyring path: " << trustedPath << std::endl;
- }
-
- std::vector<string> keyrings;
- if (DirectoryExists(trustedPath))
- keyrings = GetListOfFilesInDir(trustedPath, "gpg", false, true);
- if (RealFileExists(trustedFile) == true)
- keyrings.push_back(trustedFile);
-
- std::vector<const char *> Args;
- Args.reserve(30);
-
- if (keyrings.empty() == true)
- {
- // TRANSLATOR: %s is the trusted keyring parts directory
- return _error->Error(_("No keyring installed in %s."),
- _config->FindDir("Dir::Etc::TrustedParts").c_str());
- }
-
- Args.push_back(gpgvpath.c_str());
- Args.push_back("--ignore-time-conflict");
-
- if (statusfd != -1)
- {
- Args.push_back("--status-fd");
- char fd[10];
- snprintf(fd, sizeof(fd), "%i", statusfd);
- Args.push_back(fd);
- }
-
- for (vector<string>::const_iterator K = keyrings.begin();
- K != keyrings.end(); ++K)
- {
- Args.push_back("--keyring");
- Args.push_back(K->c_str());
- }
-
- Configuration::Item const *Opts;
- Opts = _config->Tree("Acquire::gpgv::Options");
- if (Opts != 0)
- {
- Opts = Opts->Child;
- for (; Opts != 0; Opts = Opts->Next)
- {
- if (Opts->Value.empty() == true)
- continue;
- Args.push_back(Opts->Value.c_str());
- }
- }
-
- Args.push_back(FileGPG.c_str());
- if (FileGPG != File)
- Args.push_back(File.c_str());
- Args.push_back(NULL);
-
- if (Debug == true)
- {
- std::clog << "Preparing to exec: " << gpgvpath;
- for (std::vector<const char *>::const_iterator a = Args.begin(); *a != NULL; ++a)
- std::clog << " " << *a;
- std::clog << std::endl;
- }
-
- if (statusfd != -1)
- {
- int const nullfd = open("/dev/null", O_RDONLY);
- close(fd[0]);
- // Redirect output to /dev/null; we read from the status fd
- dup2(nullfd, STDOUT_FILENO);
- dup2(nullfd, STDERR_FILENO);
- // Redirect the pipe to the status fd (3)
- dup2(fd[1], statusfd);
-
- putenv((char *)"LANG=");
- putenv((char *)"LC_ALL=");
- putenv((char *)"LC_MESSAGES=");
- }
-
- execvp(gpgvpath.c_str(), (char **) &Args[0]);
- return true;
+// SigVerify::RunGPGV - deprecated wrapper calling ExecGPGV /*{{{*/
+APT_NORETURN bool SigVerify::RunGPGV(std::string const &File, std::string const &FileOut,
+ int const &statusfd, int fd[2]) {
+ ExecGPGV(File, FileOut, statusfd, fd);
+}
+APT_NORETURN bool SigVerify::RunGPGV(std::string const &File, std::string const &FileOut,
+ int const &statusfd) {
+ ExecGPGV(File, FileOut, statusfd);
}
/*}}}*/
bool TranslationsCopy::CopyTranslations(string CDROM,string Name, /*{{{*/
for (std::vector<APT::Configuration::Compressor>::const_iterator c = compressor.begin();
c != compressor.end(); ++c)
{
- if (stat(std::string(file + c->Extension).c_str(), &Buf) != 0)
+ if (stat((file + c->Extension).c_str(), &Buf) != 0)
continue;
found = true;
break;
unsigned int WrongSize = 0;
unsigned int Packages = 0;
for (vector<string>::iterator I = List.begin(); I != List.end(); ++I)
- {
- string OrigPath = string(*I,CDROM.length());
- off_t FileSize = 0;
-
+ {
// Open the package file
- FileFd Pkg;
- if (RealFileExists(*I) == true)
- {
- Pkg.Open(*I,FileFd::ReadOnly);
- FileSize = Pkg.Size();
- }
- else
- {
- int fd;
- if (!DecompressFile(*I, &fd, &FileSize))
- return _error->Errno("decompress","Decompress failed for %s", (*I).c_str());
- Pkg.Fd(dup(fd));
- Pkg.Seek(0);
- }
+ FileFd Pkg(*I, FileFd::ReadOnly, FileFd::Auto);
+ off_t const FileSize = Pkg.Size();
+
pkgTagFile Parser(&Pkg);
if (_error->PendingError() == true)
return false;
(*I).c_str() + CDROM.length());
string TargetF = _config->FindDir("Dir::State::lists") + "partial/";
TargetF += URItoFileName(S);
+ FileFd Target;
if (_config->FindB("APT::CDROM::NoAct",false) == true)
+ {
TargetF = "/dev/null";
- FileFd Target(TargetF,FileFd::WriteAtomic);
- FILE *TargetFl = fdopen(dup(Target.Fd()),"w");
+ Target.Open(TargetF,FileFd::WriteExists);
+ } else {
+ Target.Open(TargetF,FileFd::WriteAtomic);
+ }
if (_error->PendingError() == true)
return false;
+ FILE *TargetFl = fdopen(dup(Target.Fd()),"w");
if (TargetFl == 0)
return _error->Errno("fdopen","Failed to reopen fd");