X-Git-Url: https://git.saurik.com/apt.git/blobdiff_plain/f98233c1b1e93ef1bb595bfc6e59c74d9e05eb6a..060a7b746c87d4717222df5bb14d85b756f39208:/ftparchive/writer.cc?ds=sidebyside diff --git a/ftparchive/writer.cc b/ftparchive/writer.cc index 293e851f5..d7d699ddc 100644 --- a/ftparchive/writer.cc +++ b/ftparchive/writer.cc @@ -28,6 +28,7 @@ #include #include #include +#include #include #include "cachedb.h" @@ -54,14 +55,10 @@ inline void SetTFRewriteData(struct TFRewriteData &tfrd, // FTWScanner::FTWScanner - Constructor /*{{{*/ // --------------------------------------------------------------------- /* */ -FTWScanner::FTWScanner() +FTWScanner::FTWScanner(string const &Arch): Arch(Arch) { ErrorPrinted = false; NoLinkAct = !_config->FindB("APT::FTPArchive::DeLinkAct",true); - RealPath = 0; - long PMax = pathconf(".",_PC_PATH_MAX); - if (PMax > 0) - RealPath = new char[PMax]; } /*}}}*/ // FTWScanner::Scanner - FTW Scanner /*{{{*/ @@ -89,15 +86,17 @@ int FTWScanner::ScannerFTW(const char *File,const struct stat *sb,int Flag) // FTWScanner::ScannerFile - File Scanner /*{{{*/ // --------------------------------------------------------------------- /* */ -int FTWScanner::ScannerFile(const char *File, bool ReadLink) +int FTWScanner::ScannerFile(const char *File, bool const &ReadLink) { const char *LastComponent = strrchr(File, '/'); + char *RealPath = NULL; + if (LastComponent == NULL) LastComponent = File; else LastComponent++; - vector::iterator I; + vector::const_iterator I; for(I = Owner->Patterns.begin(); I != Owner->Patterns.end(); ++I) { if (fnmatch((*I).c_str(), LastComponent, 0) == 0) @@ -111,10 +110,13 @@ int FTWScanner::ScannerFile(const char *File, bool ReadLink) given are not links themselves. */ char Jnk[2]; Owner->OriginalPath = File; - if (ReadLink && Owner->RealPath != 0 && + if (ReadLink && readlink(File,Jnk,sizeof(Jnk)) != -1 && - realpath(File,Owner->RealPath) != 0) - Owner->DoPackage(Owner->RealPath); + (RealPath = realpath(File,NULL)) != 0) + { + Owner->DoPackage(RealPath); + free(RealPath); + } else Owner->DoPackage(File); @@ -127,7 +129,7 @@ int FTWScanner::ScannerFile(const char *File, bool ReadLink) { Owner->NewLine(1); - bool Type = _error->PopMessage(Err); + bool const Type = _error->PopMessage(Err); if (Type == true) cerr << _("E: ") << Err << endl; else @@ -148,20 +150,22 @@ int FTWScanner::ScannerFile(const char *File, bool ReadLink) // FTWScanner::RecursiveScan - Just scan a directory tree /*{{{*/ // --------------------------------------------------------------------- /* */ -bool FTWScanner::RecursiveScan(string Dir) +bool FTWScanner::RecursiveScan(string const &Dir) { + char *RealPath = NULL; /* If noprefix is set then jam the scan root in, so we don't generate link followed paths out of control */ if (InternalPrefix.empty() == true) { - if (realpath(Dir.c_str(),RealPath) == 0) + if ((RealPath = realpath(Dir.c_str(),NULL)) == 0) return _error->Errno("realpath",_("Failed to resolve %s"),Dir.c_str()); - InternalPrefix = RealPath; + InternalPrefix = RealPath; + free(RealPath); } // Do recursive directory searching Owner = this; - int Res = ftw(Dir.c_str(),ScannerFTW,30); + int const Res = ftw(Dir.c_str(),ScannerFTW,30); // Error treewalking? if (Res != 0) @@ -178,15 +182,17 @@ bool FTWScanner::RecursiveScan(string Dir) // --------------------------------------------------------------------- /* This is an alternative to using FTW to locate files, it reads the list of files from another file. */ -bool FTWScanner::LoadFileList(string Dir,string File) +bool FTWScanner::LoadFileList(string const &Dir, string const &File) { + char *RealPath = NULL; /* If noprefix is set then jam the scan root in, so we don't generate link followed paths out of control */ if (InternalPrefix.empty() == true) { - if (realpath(Dir.c_str(),RealPath) == 0) + if ((RealPath = realpath(Dir.c_str(),NULL)) == 0) return _error->Errno("realpath",_("Failed to resolve %s"),Dir.c_str()); InternalPrefix = RealPath; + free(RealPath); } Owner = this; @@ -236,7 +242,7 @@ bool FTWScanner::LoadFileList(string Dir,string File) /* */ bool FTWScanner::Delink(string &FileName,const char *OriginalPath, unsigned long &DeLinkBytes, - off_t FileSize) + off_t const &FileSize) { // See if this isn't an internaly prefix'd file name. if (InternalPrefix.empty() == false && @@ -293,25 +299,26 @@ bool FTWScanner::Delink(string &FileName,const char *OriginalPath, // PackagesWriter::PackagesWriter - Constructor /*{{{*/ // --------------------------------------------------------------------- /* */ -PackagesWriter::PackagesWriter(string DB,string Overrides,string ExtOverrides, - string aArch) : - Db(DB),Stats(Db.Stats), Arch(aArch) +PackagesWriter::PackagesWriter(string const &DB,string const &Overrides,string const &ExtOverrides, + string const &Arch) : + FTWScanner(Arch), Db(DB), Stats(Db.Stats), TransWriter(NULL) { Output = stdout; - SetExts(".deb .udeb .foo .bar .baz"); - AddPattern("*.deb"); + SetExts(".deb .udeb"); DeLinkLimit = 0; // Process the command line options DoMD5 = _config->FindB("APT::FTPArchive::MD5",true); DoSHA1 = _config->FindB("APT::FTPArchive::SHA1",true); DoSHA256 = _config->FindB("APT::FTPArchive::SHA256",true); + DoAlwaysStat = _config->FindB("APT::FTPArchive::AlwaysStat", false); DoContents = _config->FindB("APT::FTPArchive::Contents",true); NoOverride = _config->FindB("APT::FTPArchive::NoOverrideMsg",false); + LongDescription = _config->FindB("APT::FTPArchive::LongDescription",true); if (Db.Loaded() == false) DoContents = false; - + // Read the override file if (Overrides.empty() == false && Over.ReadOverride(Overrides) == false) return; @@ -327,23 +334,22 @@ PackagesWriter::PackagesWriter(string DB,string Overrides,string ExtOverrides, // FTWScanner::SetExts - Set extensions to support /*{{{*/ // --------------------------------------------------------------------- /* */ -bool FTWScanner::SetExts(string Vals) +bool FTWScanner::SetExts(string const &Vals) { ClearPatterns(); string::size_type Start = 0; while (Start <= Vals.length()-1) { - string::size_type Space = Vals.find(' ',Start); - string::size_type Length; - if (Space == string::npos) + string::size_type const Space = Vals.find(' ',Start); + string::size_type const Length = ((Space == string::npos) ? Vals.length() : Space) - Start; + if ( Arch.empty() == false ) { - Length = Vals.length()-Start; + AddPattern(string("*_") + Arch + Vals.substr(Start, Length)); + AddPattern(string("*_all") + Vals.substr(Start, Length)); } else - { - Length = Space-Start; - } - AddPattern(string("*") + Vals.substr(Start, Length)); + AddPattern(string("*") + Vals.substr(Start, Length)); + Start += Length + 1; } @@ -359,7 +365,7 @@ bool FTWScanner::SetExts(string Vals) bool PackagesWriter::DoPackage(string FileName) { // Pull all the data we need form the DB - if (Db.GetFileInfo(FileName, true, DoContents, true, DoMD5, DoSHA1, DoSHA256) + if (Db.GetFileInfo(FileName, true, DoContents, true, DoMD5, DoSHA1, DoSHA256, DoAlwaysStat) == false) { return false; @@ -414,10 +420,18 @@ bool PackagesWriter::DoPackage(string FileName) NewFileName = FileName; if (PathPrefix.empty() == false) NewFileName = flCombine(PathPrefix,NewFileName); - + + /* Configuration says we don't want to include the long Description + in the package file - instead we want to ship a separated file */ + string desc; + if (LongDescription == false) { + desc = Tags.FindS("Description").append("\n"); + OverItem->FieldOverride["Description"] = desc.substr(0, desc.find('\n')).c_str(); + } + // This lists all the changes to the fields we are going to make. // (7 hardcoded + maintainer + suggests + end marker) - TFRewriteData Changes[6+2+OverItem->FieldOverride.size()+1]; + TFRewriteData Changes[6+2+OverItem->FieldOverride.size()+1+1]; unsigned int End = 0; SetTFRewriteData(Changes[End++], "Size", Size); @@ -429,6 +443,16 @@ bool PackagesWriter::DoPackage(string FileName) SetTFRewriteData(Changes[End++], "Status", 0); SetTFRewriteData(Changes[End++], "Optional", 0); + string DescriptionMd5; + if (LongDescription == false) { + MD5Summation descmd5; + descmd5.Add(desc.c_str()); + DescriptionMd5 = descmd5.Result().Value(); + SetTFRewriteData(Changes[End++], "Description-md5", DescriptionMd5.c_str()); + if (TransWriter != NULL) + TransWriter->DoPackage(Package, desc, DescriptionMd5); + } + // Rewrite the maintainer field if necessary bool MaintFailed; string NewMaint = OverItem->SwapMaint(Tags.FindS("Maintainer"),MaintFailed); @@ -446,7 +470,7 @@ bool PackagesWriter::DoPackage(string FileName) SetTFRewriteData(Changes[End++], "Maintainer", NewMaint.c_str()); /* Get rid of the Optional tag. This is an ugly, ugly, ugly hack that - dpkg-scanpackages does.. Well sort of. dpkg-scanpackages just does renaming + dpkg-scanpackages does. Well sort of. dpkg-scanpackages just does renaming but dpkg does this append bit. So we do the append bit, at least that way the status file and package file will remain similar. There are other transforms but optional is the only legacy one still in use for some lazy reason. */ @@ -458,7 +482,7 @@ bool PackagesWriter::DoPackage(string FileName) SetTFRewriteData(Changes[End++], "Suggests", OptionalStr.c_str()); } - for (map::iterator I = OverItem->FieldOverride.begin(); + for (map::const_iterator I = OverItem->FieldOverride.begin(); I != OverItem->FieldOverride.end(); I++) SetTFRewriteData(Changes[End++],I->first.c_str(),I->second.c_str()); @@ -473,11 +497,60 @@ bool PackagesWriter::DoPackage(string FileName) } /*}}}*/ +// TranslationWriter::TranslationWriter - Constructor /*{{{*/ +// --------------------------------------------------------------------- +/* Create a Translation-Master file for this Packages file */ +TranslationWriter::TranslationWriter(string const &File, string const &TransCompress, + mode_t const &Permissions) : Output(NULL), + RefCounter(0) +{ + if (File.empty() == true) + return; + + Comp = new MultiCompress(File, TransCompress, Permissions); + Output = Comp->Input; +} + /*}}}*/ +// TranslationWriter::DoPackage - Process a single package /*{{{*/ +// --------------------------------------------------------------------- +/* Create a Translation-Master file for this Packages file */ +bool TranslationWriter::DoPackage(string const &Pkg, string const &Desc, + string const &MD5) +{ + if (Output == NULL) + return true; + + // Different archs can include different versions and therefore + // different descriptions - so we need to check for both name and md5. + string const Record = Pkg + ":" + MD5; + + if (Included.find(Record) != Included.end()) + return true; + + fprintf(Output, "Package: %s\nDescription-md5: %s\nDescription-en: %s\n", + Pkg.c_str(), MD5.c_str(), Desc.c_str()); + + Included.insert(Record); + return true; +} + /*}}}*/ +// TranslationWriter::~TranslationWriter - Destructor /*{{{*/ +// --------------------------------------------------------------------- +/* */ +TranslationWriter::~TranslationWriter() +{ + if (Comp == NULL) + return; + + delete Comp; +} + /*}}}*/ + // SourcesWriter::SourcesWriter - Constructor /*{{{*/ // --------------------------------------------------------------------- /* */ -SourcesWriter::SourcesWriter(string BOverrides,string SOverrides, - string ExtOverrides) +SourcesWriter::SourcesWriter(string const &BOverrides,string const &SOverrides, + string const &ExtOverrides) { Output = stdout; AddPattern("*.dsc"); @@ -537,7 +610,12 @@ bool SourcesWriter::DoPackage(string FileName) char *BlkEnd = Buffer + St.st_size; MD5Summation MD5; MD5.Add((unsigned char *)Start,BlkEnd - Start); - + + SHA1Summation SHA1; + SHA256Summation SHA256; + SHA1.Add((unsigned char *)Start,BlkEnd - Start); + SHA256.Add((unsigned char *)Start,BlkEnd - Start); + // Add an extra \n to the end, just in case *BlkEnd++ = '\n'; @@ -628,12 +706,25 @@ bool SourcesWriter::DoPackage(string FileName) } // Add the dsc to the files hash list - char Files[1000]; - snprintf(Files,sizeof(Files),"\n %s %lu %s\n %s", - string(MD5.Result()).c_str(),St.st_size, - flNotDir(FileName).c_str(), - Tags.FindS("Files").c_str()); - + string const strippedName = flNotDir(FileName); + std::ostringstream ostreamFiles; + if (Tags.Exists("Files")) + ostreamFiles << "\n " << string(MD5.Result()) << " " << St.st_size << " " + << strippedName << "\n " << Tags.FindS("Files"); + string const Files = ostreamFiles.str(); + + std::ostringstream ostreamSha1; + if (Tags.Exists("Checksums-Sha1")) + ostreamSha1 << "\n " << string(SHA1.Result()) << " " << St.st_size << " " + << strippedName << "\n " << Tags.FindS("Checksums-Sha1"); + string const ChecksumsSha1 = ostreamSha1.str(); + + std::ostringstream ostreamSha256; + if (Tags.Exists("Checksums-Sha256")) + ostreamSha256 << "\n " << string(SHA256.Result()) << " " << St.st_size << " " + << strippedName << "\n " << Tags.FindS("Checksums-Sha256"); + string const ChecksumsSha256 = ostreamSha256.str(); + // Strip the DirStrip prefix from the FileName and add the PathPrefix string NewFileName; if (DirStrip.empty() == false && @@ -650,7 +741,8 @@ bool SourcesWriter::DoPackage(string FileName) // Perform the delinking operation over all of the files string ParseJnk; - const char *C = Files; + const char *C = Files.c_str(); + char *RealPath = NULL; for (;isspace(*C); C++); while (*C != 0) { @@ -662,10 +754,11 @@ bool SourcesWriter::DoPackage(string FileName) char Jnk[2]; string OriginalPath = Directory + ParseJnk; - if (RealPath != 0 && readlink(OriginalPath.c_str(),Jnk,sizeof(Jnk)) != -1 && - realpath(OriginalPath.c_str(),RealPath) != 0) + if (readlink(OriginalPath.c_str(),Jnk,sizeof(Jnk)) != -1 && + (RealPath = realpath(OriginalPath.c_str(),NULL)) != 0) { string RP = RealPath; + free(RealPath); if (Delink(RP,OriginalPath.c_str(),Stats.DeLinkBytes,St.st_size) == false) return false; } @@ -676,12 +769,14 @@ bool SourcesWriter::DoPackage(string FileName) Directory.erase(Directory.end()-1); // This lists all the changes to the fields we are going to make. - // (5 hardcoded + maintainer + end marker) - TFRewriteData Changes[5+1+SOverItem->FieldOverride.size()+1]; + // (5 hardcoded + checksums + maintainer + end marker) + TFRewriteData Changes[5+2+1+SOverItem->FieldOverride.size()+1]; unsigned int End = 0; SetTFRewriteData(Changes[End++],"Source",Package.c_str(),"Package"); - SetTFRewriteData(Changes[End++],"Files",Files); + SetTFRewriteData(Changes[End++],"Files",Files.c_str()); + SetTFRewriteData(Changes[End++],"Checksums-Sha1",ChecksumsSha1.c_str()); + SetTFRewriteData(Changes[End++],"Checksums-Sha256",ChecksumsSha256.c_str()); if (Directory != "./") SetTFRewriteData(Changes[End++],"Directory",Directory.c_str()); SetTFRewriteData(Changes[End++],"Priority",BestPrio.c_str()); @@ -702,7 +797,7 @@ bool SourcesWriter::DoPackage(string FileName) if (NewMaint.empty() == false) SetTFRewriteData(Changes[End++], "Maintainer", NewMaint.c_str()); - for (map::iterator I = SOverItem->FieldOverride.begin(); + for (map::const_iterator I = SOverItem->FieldOverride.begin(); I != SOverItem->FieldOverride.end(); I++) SetTFRewriteData(Changes[End++],I->first.c_str(),I->second.c_str()); @@ -722,11 +817,11 @@ bool SourcesWriter::DoPackage(string FileName) // ContentsWriter::ContentsWriter - Constructor /*{{{*/ // --------------------------------------------------------------------- /* */ -ContentsWriter::ContentsWriter(string DB) : - Db(DB), Stats(Db.Stats) +ContentsWriter::ContentsWriter(string const &DB, string const &Arch) : + FTWScanner(Arch), Db(DB), Stats(Db.Stats) { - AddPattern("*.deb"); + SetExts(".deb"); Output = stdout; } /*}}}*/ @@ -734,9 +829,9 @@ ContentsWriter::ContentsWriter(string DB) : // --------------------------------------------------------------------- /* If Package is the empty string the control record will be parsed to determine what the package name is. */ -bool ContentsWriter::DoPackage(string FileName,string Package) +bool ContentsWriter::DoPackage(string FileName, string Package) { - if (!Db.GetFileInfo(FileName, Package.empty(), true, false, false, false, false)) + if (!Db.GetFileInfo(FileName, Package.empty(), true, false, false, false, false, false)) { return false; } @@ -755,7 +850,7 @@ bool ContentsWriter::DoPackage(string FileName,string Package) // ContentsWriter::ReadFromPkgs - Read from a packages file /*{{{*/ // --------------------------------------------------------------------- /* */ -bool ContentsWriter::ReadFromPkgs(string PkgFile,string PkgCompress) +bool ContentsWriter::ReadFromPkgs(string const &PkgFile,string const &PkgCompress) { MultiCompress Pkgs(PkgFile,PkgCompress,0,false); if (_error->PendingError() == true) @@ -810,7 +905,7 @@ bool ContentsWriter::ReadFromPkgs(string PkgFile,string PkgCompress) // ReleaseWriter::ReleaseWriter - Constructor /*{{{*/ // --------------------------------------------------------------------- /* */ -ReleaseWriter::ReleaseWriter(string DB) +ReleaseWriter::ReleaseWriter(string const &DB) { AddPattern("Packages"); AddPattern("Packages.gz"); @@ -824,7 +919,7 @@ ReleaseWriter::ReleaseWriter(string DB) AddPattern("md5sum.txt"); Output = stdout; - time_t now = time(NULL); + time_t const now = time(NULL); char datestr[128]; if (strftime(datestr, sizeof(datestr), "%a, %d %b %Y %H:%M:%S UTC", gmtime(&now)) == 0) @@ -832,6 +927,15 @@ ReleaseWriter::ReleaseWriter(string DB) datestr[0] = '\0'; } + time_t const validuntil = now + _config->FindI("APT::FTPArchive::Release::ValidTime", 0); + char validstr[128]; + if (now == validuntil || + strftime(validstr, sizeof(validstr), "%a, %d %b %Y %H:%M:%S UTC", + gmtime(&validuntil)) == 0) + { + validstr[0] = '\0'; + } + map Fields; Fields["Origin"] = ""; Fields["Label"] = ""; @@ -839,6 +943,7 @@ ReleaseWriter::ReleaseWriter(string DB) Fields["Version"] = ""; Fields["Codename"] = ""; Fields["Date"] = datestr; + Fields["Valid-Until"] = validstr; Fields["Architectures"] = ""; Fields["Components"] = ""; Fields["Description"] = ""; @@ -911,7 +1016,7 @@ bool ReleaseWriter::DoPackage(string FileName) void ReleaseWriter::Finish() { fprintf(Output, "MD5Sum:\n"); - for(map::iterator I = CheckSums.begin(); + for(map::const_iterator I = CheckSums.begin(); I != CheckSums.end(); ++I) { @@ -922,7 +1027,7 @@ void ReleaseWriter::Finish() } fprintf(Output, "SHA1:\n"); - for(map::iterator I = CheckSums.begin(); + for(map::const_iterator I = CheckSums.begin(); I != CheckSums.end(); ++I) { @@ -933,7 +1038,7 @@ void ReleaseWriter::Finish() } fprintf(Output, "SHA256:\n"); - for(map::iterator I = CheckSums.begin(); + for(map::const_iterator I = CheckSums.begin(); I != CheckSums.end(); ++I) {