diff options
author | Michael Vogt <michael.vogt@ubuntu.com> | 2005-02-08 15:33:23 +0000 |
---|---|---|
committer | Michael Vogt <michael.vogt@ubuntu.com> | 2005-02-08 15:33:23 +0000 |
commit | 8501516a89c1f333f7bc3866b05b5ce7fbf4e177 (patch) | |
tree | 023d64f1d1a53e9657e32e2a54664bf2beed9ede /cmdline | |
parent | d3fbe3fe7968190312c953ee7ba0c567be33ef09 (diff) | |
parent | 8a57929175a93466c83a8e697ad876b60b2eb3c2 (diff) |
* merged with matt's tree
Patches applied:
* apt@packages.debian.org/apt--main--0--patch-52
0.6.31
* apt@packages.debian.org/apt--main--0--patch-53
Remove debugging from apt.cron.daily
* apt@packages.debian.org/apt--main--0--patch-54
allow SHA1Summation to process a file descriptor until EOF
* apt@packages.debian.org/apt--main--0--patch-55
Fix syntax in sha1.cc
* apt@packages.debian.org/apt--main--0--patch-56
Fix build/install of Polish offline documentation
* apt@packages.debian.org/apt--main--0--patch-57
Move CD-ROM handling backend into libapt-pkg
* apt@packages.debian.org/apt--main--0--patch-58
Fix compilation errors from apt--auth-cdrom--0
* michael.vogt@ubuntu.com--2005/apt--auth-cdrom--0--base-0
tag of apt@packages.debian.org/apt--main--0--patch-51
* michael.vogt@ubuntu.com--2005/apt--auth-cdrom--0--patch-1
* added support for signed cdroms
* michael.vogt@ubuntu.com--2005/apt--auth-cdrom--0--patch-2
* merged with apt--main, seperated cmdline/apt-cdrom.cc into a library (apt-pkg/cdrom.{cc,h})
* michael.vogt@ubuntu.com--2005/apt--auth-cdrom--0--patch-3
* cleaned up the cmdline/apt-cdrom.cc code
Diffstat (limited to 'cmdline')
-rw-r--r-- | cmdline/apt-cdrom.cc | 705 | ||||
-rw-r--r-- | cmdline/indexcopy.cc | 524 | ||||
-rw-r--r-- | cmdline/indexcopy.h | 69 | ||||
-rw-r--r-- | cmdline/makefile | 2 |
4 files changed, 57 insertions, 1243 deletions
diff --git a/cmdline/apt-cdrom.cc b/cmdline/apt-cdrom.cc index 7367a55a3..8010e7b53 100644 --- a/cmdline/apt-cdrom.cc +++ b/cmdline/apt-cdrom.cc @@ -18,10 +18,13 @@ #include <apt-pkg/progress.h> #include <apt-pkg/cdromutl.h> #include <apt-pkg/strutl.h> +#include <apt-pkg/acquire.h> +#include <apt-pkg/acquire-item.h> +#include <apt-pkg/cdrom.h> #include <config.h> #include <apti18n.h> -#include "indexcopy.h" +//#include "indexcopy.h" #include <locale.h> #include <iostream> @@ -37,460 +40,65 @@ using namespace std; -// FindPackages - Find the package files on the CDROM /*{{{*/ -// --------------------------------------------------------------------- -/* We look over the cdrom for package files. This is a recursive - search that short circuits when it his a package file in the dir. - This speeds it up greatly as the majority of the size is in the - binary-* sub dirs. */ -bool FindPackages(string CD,vector<string> &List,vector<string> &SList, - string &InfoDir,unsigned int Depth = 0) + /*{{{*/ +class pkgCdromTextStatus : public pkgCdromStatus { - static ino_t Inodes[9]; - if (Depth >= 7) - return true; - - if (CD[CD.length()-1] != '/') - CD += '/'; - - if (chdir(CD.c_str()) != 0) - return _error->Errno("chdir","Unable to change to %s",CD.c_str()); - - // Look for a .disk subdirectory - struct stat Buf; - if (stat(".disk",&Buf) == 0) - { - if (InfoDir.empty() == true) - InfoDir = CD + ".disk/"; - } - - // Don't look into directories that have been marked to ingore. - if (stat(".aptignr",&Buf) == 0) - return true; - - /* Aha! We found some package files. We assume that everything under - this dir is controlled by those package files so we don't look down - anymore */ - if (stat("Packages",&Buf) == 0 || stat("Packages.gz",&Buf) == 0) - { - List.push_back(CD); - - // Continue down if thorough is given - if (_config->FindB("APT::CDROM::Thorough",false) == false) - return true; - } - if (stat("Sources.gz",&Buf) == 0 || stat("Sources",&Buf) == 0) - { - SList.push_back(CD); - - // Continue down if thorough is given - if (_config->FindB("APT::CDROM::Thorough",false) == false) - return true; - } - - DIR *D = opendir("."); - if (D == 0) - return _error->Errno("opendir","Unable to read %s",CD.c_str()); - - // Run over the directory - for (struct dirent *Dir = readdir(D); Dir != 0; Dir = readdir(D)) - { - // Skip some files.. - if (strcmp(Dir->d_name,".") == 0 || - strcmp(Dir->d_name,"..") == 0 || - //strcmp(Dir->d_name,"source") == 0 || - strcmp(Dir->d_name,".disk") == 0 || - strcmp(Dir->d_name,"experimental") == 0 || - strcmp(Dir->d_name,"binary-all") == 0 || - strcmp(Dir->d_name,"debian-installer") == 0) - continue; - - // See if the name is a sub directory - struct stat Buf; - if (stat(Dir->d_name,&Buf) != 0) - continue; - - if (S_ISDIR(Buf.st_mode) == 0) - continue; - - unsigned int I; - for (I = 0; I != Depth; I++) - if (Inodes[I] == Buf.st_ino) - break; - if (I != Depth) - continue; - - // Store the inodes weve seen - Inodes[Depth] = Buf.st_ino; - - // Descend - if (FindPackages(CD + Dir->d_name,List,SList,InfoDir,Depth+1) == false) - break; - - if (chdir(CD.c_str()) != 0) - return _error->Errno("chdir","Unable to change to %s",CD.c_str()); - }; - - closedir(D); - - return !_error->PendingError(); -} - /*}}}*/ -// DropBinaryArch - Dump dirs with a string like /binary-<foo>/ /*{{{*/ -// --------------------------------------------------------------------- -/* Here we drop everything that is not this machines arch */ -bool DropBinaryArch(vector<string> &List) +protected: + OpTextProgress Progress; + void Prompt(const char *Text); + string PromptLine(const char *Text); + bool AskCdromName(string &name); + +public: + virtual void Update(string text, int current); + virtual bool ChangeCdrom(); + virtual OpProgress* GetOpProgress(); +}; + +void pkgCdromTextStatus::Prompt(const char *Text) { - char S[300]; - snprintf(S,sizeof(S),"/binary-%s/", - _config->Find("Apt::Architecture").c_str()); - - for (unsigned int I = 0; I < List.size(); I++) - { - const char *Str = List[I].c_str(); - - const char *Res; - if ((Res = strstr(Str,"/binary-")) == 0) - continue; - - // Weird, remove it. - if (strlen(Res) < strlen(S)) - { - List.erase(List.begin() + I); - I--; - continue; - } - - // See if it is our arch - if (stringcmp(Res,Res + strlen(S),S) == 0) - continue; - - // Erase it - List.erase(List.begin() + I); - I--; - } - - return true; + char C; + cout << Text << ' ' << flush; + read(STDIN_FILENO,&C,1); + if (C != '\n') + cout << endl; } - /*}}}*/ -// Score - We compute a 'score' for a path /*{{{*/ -// --------------------------------------------------------------------- -/* Paths are scored based on how close they come to what I consider - normal. That is ones that have 'dist' 'stable' 'testing' will score - higher than ones without. */ -int Score(string Path) + +string pkgCdromTextStatus::PromptLine(const char *Text) { - int Res = 0; - if (Path.find("stable/") != string::npos) - Res += 29; - if (Path.find("/binary-") != string::npos) - Res += 20; - if (Path.find("testing/") != string::npos) - Res += 28; - if (Path.find("unstable/") != string::npos) - Res += 27; - if (Path.find("/dists/") != string::npos) - Res += 40; - if (Path.find("/main/") != string::npos) - Res += 20; - if (Path.find("/contrib/") != string::npos) - Res += 20; - if (Path.find("/non-free/") != string::npos) - Res += 20; - if (Path.find("/non-US/") != string::npos) - Res += 20; - if (Path.find("/source/") != string::npos) - Res += 10; - if (Path.find("/debian/") != string::npos) - Res -= 10; + cout << Text << ':' << endl; + + string Res; + getline(cin,Res); return Res; } - /*}}}*/ -// DropRepeats - Drop repeated files resulting from symlinks /*{{{*/ -// --------------------------------------------------------------------- -/* Here we go and stat every file that we found and strip dup inodes. */ -bool DropRepeats(vector<string> &List,const char *Name) + +bool pkgCdromTextStatus::AskCdromName(string &name) { - // Get a list of all the inodes - ino_t *Inodes = new ino_t[List.size()]; - for (unsigned int I = 0; I != List.size(); I++) - { - struct stat Buf; - if (stat((List[I] + Name).c_str(),&Buf) != 0 && - stat((List[I] + Name + ".gz").c_str(),&Buf) != 0) - _error->Errno("stat","Failed to stat %s%s",List[I].c_str(), - Name); - Inodes[I] = Buf.st_ino; - } - - if (_error->PendingError() == true) - return false; - - // Look for dups - for (unsigned int I = 0; I != List.size(); I++) - { - for (unsigned int J = I+1; J < List.size(); J++) - { - // No match - if (Inodes[J] != Inodes[I]) - continue; - - // We score the two paths.. and erase one - int ScoreA = Score(List[I]); - int ScoreB = Score(List[J]); - if (ScoreA < ScoreB) - { - List[I] = string(); - break; - } + cout << "Please provide a name for this Disc, such as 'Debian 2.1r1 Disk 1'" << flush; + name = PromptLine(""); - List[J] = string(); - } - } - - // Wipe erased entries - for (unsigned int I = 0; I < List.size();) - { - if (List[I].empty() == false) - I++; - else - List.erase(List.begin()+I); - } - return true; } - /*}}}*/ - -// ReduceSourceList - Takes the path list and reduces it /*{{{*/ -// --------------------------------------------------------------------- -/* This takes the list of source list expressed entires and collects - similar ones to form a single entry for each dist */ -void ReduceSourcelist(string CD,vector<string> &List) -{ - sort(List.begin(),List.end()); - // Collect similar entries - for (vector<string>::iterator I = List.begin(); I != List.end(); I++) - { - // Find a space.. - string::size_type Space = (*I).find(' '); - if (Space == string::npos) - continue; - string::size_type SSpace = (*I).find(' ',Space + 1); - if (SSpace == string::npos) - continue; - string Word1 = string(*I,Space,SSpace-Space); - string Prefix = string(*I,0,Space); - for (vector<string>::iterator J = List.begin(); J != I; J++) - { - // Find a space.. - string::size_type Space2 = (*J).find(' '); - if (Space2 == string::npos) - continue; - string::size_type SSpace2 = (*J).find(' ',Space2 + 1); - if (SSpace2 == string::npos) - continue; - - if (string(*J,0,Space2) != Prefix) - continue; - if (string(*J,Space2,SSpace2-Space2) != Word1) - continue; - - *J += string(*I,SSpace); - *I = string(); - } - } - - // Wipe erased entries - for (unsigned int I = 0; I < List.size();) - { - if (List[I].empty() == false) - I++; - else - List.erase(List.begin()+I); - } -} - /*}}}*/ -// WriteDatabase - Write the CDROM Database file /*{{{*/ -// --------------------------------------------------------------------- -/* We rewrite the configuration class associated with the cdrom database. */ -bool WriteDatabase(Configuration &Cnf) +void pkgCdromTextStatus::Update(string text, int current) { - string DFile = _config->FindFile("Dir::State::cdroms"); - string NewFile = DFile + ".new"; - - unlink(NewFile.c_str()); - ofstream Out(NewFile.c_str()); - if (!Out) - return _error->Errno("ofstream::ofstream", - "Failed to open %s.new",DFile.c_str()); - - /* Write out all of the configuration directives by walking the - configuration tree */ - const Configuration::Item *Top = Cnf.Tree(0); - for (; Top != 0;) - { - // Print the config entry - if (Top->Value.empty() == false) - Out << Top->FullTag() + " \"" << Top->Value << "\";" << endl; - - if (Top->Child != 0) - { - Top = Top->Child; - continue; - } - - while (Top != 0 && Top->Next == 0) - Top = Top->Parent; - if (Top != 0) - Top = Top->Next; - } - - Out.close(); - - rename(DFile.c_str(),string(DFile + '~').c_str()); - if (rename(NewFile.c_str(),DFile.c_str()) != 0) - return _error->Errno("rename","Failed to rename %s.new to %s", - DFile.c_str(),DFile.c_str()); - - return true; + if(text.size() > 0) + cout << text << flush; } - /*}}}*/ -// WriteSourceList - Write an updated sourcelist /*{{{*/ -// --------------------------------------------------------------------- -/* This reads the old source list and copies it into the new one. It - appends the new CDROM entires just after the first block of comments. - This places them first in the file. It also removes any old entries - that were the same. */ -bool WriteSourceList(string Name,vector<string> &List,bool Source) -{ - if (List.size() == 0) - return true; - - string File = _config->FindFile("Dir::Etc::sourcelist"); - - // Open the stream for reading - ifstream F((FileExists(File)?File.c_str():"/dev/null"), - ios::in ); - if (!F != 0) - return _error->Errno("ifstream::ifstream","Opening %s",File.c_str()); - - string NewFile = File + ".new"; - unlink(NewFile.c_str()); - ofstream Out(NewFile.c_str()); - if (!Out) - return _error->Errno("ofstream::ofstream", - "Failed to open %s.new",File.c_str()); - // Create a short uri without the path - string ShortURI = "cdrom:[" + Name + "]/"; - string ShortURI2 = "cdrom:" + Name + "/"; // For Compatibility - - const char *Type; - if (Source == true) - Type = "deb-src"; - else - Type = "deb"; - - char Buffer[300]; - int CurLine = 0; - bool First = true; - while (F.eof() == false) - { - F.getline(Buffer,sizeof(Buffer)); - CurLine++; - _strtabexpand(Buffer,sizeof(Buffer)); - _strstrip(Buffer); - - // Comment or blank - if (Buffer[0] == '#' || Buffer[0] == 0) - { - Out << Buffer << endl; - continue; - } - - if (First == true) - { - for (vector<string>::iterator I = List.begin(); I != List.end(); I++) - { - string::size_type Space = (*I).find(' '); - if (Space == string::npos) - return _error->Error("Internal error"); - Out << Type << " cdrom:[" << Name << "]/" << string(*I,0,Space) << - " " << string(*I,Space+1) << endl; - } - } - First = false; - - // Grok it - string cType; - string URI; - const char *C = Buffer; - if (ParseQuoteWord(C,cType) == false || - ParseQuoteWord(C,URI) == false) - { - Out << Buffer << endl; - continue; - } - - // Emit lines like this one - if (cType != Type || (string(URI,0,ShortURI.length()) != ShortURI && - string(URI,0,ShortURI.length()) != ShortURI2)) - { - Out << Buffer << endl; - continue; - } - } - - // Just in case the file was empty - if (First == true) - { - for (vector<string>::iterator I = List.begin(); I != List.end(); I++) - { - string::size_type Space = (*I).find(' '); - if (Space == string::npos) - return _error->Error("Internal error"); - - Out << "deb cdrom:[" << Name << "]/" << string(*I,0,Space) << - " " << string(*I,Space+1) << endl; - } - } - - Out.close(); - - rename(File.c_str(),string(File + '~').c_str()); - if (rename(NewFile.c_str(),File.c_str()) != 0) - return _error->Errno("rename","Failed to rename %s.new to %s", - File.c_str(),File.c_str()); - +bool pkgCdromTextStatus::ChangeCdrom() +{ + Prompt("Please insert a Disc in the drive and press enter"); return true; } - /*}}}*/ -// Prompt - Simple prompt /*{{{*/ -// --------------------------------------------------------------------- -/* */ -void Prompt(const char *Text) -{ - char C; - cout << Text << ' ' << flush; - read(STDIN_FILENO,&C,1); - if (C != '\n') - cout << endl; -} - /*}}}*/ -// PromptLine - Prompt for an input line /*{{{*/ -// --------------------------------------------------------------------- -/* */ -string PromptLine(const char *Text) -{ - cout << Text << ':' << endl; - - string Res; - getline(cin,Res); - return Res; -} +OpProgress* pkgCdromTextStatus::GetOpProgress() +{ + return &Progress; +}; + /*}}}*/ // DoAdd - Add a new CDROM /*{{{*/ @@ -501,186 +109,13 @@ string PromptLine(const char *Text) verify them. Then rewrite the database files */ bool DoAdd(CommandLine &) { - // Startup - string CDROM = _config->FindDir("Acquire::cdrom::mount","/cdrom/"); - if (CDROM[0] == '.') - CDROM= SafeGetCWD() + '/' + CDROM; - - cout << "Using CD-ROM mount point " << CDROM << endl; - - // Read the database - Configuration Database; - string DFile = _config->FindFile("Dir::State::cdroms"); - if (FileExists(DFile) == true) - { - if (ReadConfigFile(Database,DFile) == false) - return _error->Error("Unable to read the cdrom database %s", - DFile.c_str()); - } - - // Unmount the CD and get the user to put in the one they want - if (_config->FindB("APT::CDROM::NoMount",false) == false) - { - cout << "Unmounting CD-ROM" << endl; - UnmountCdrom(CDROM); - - // Mount the new CDROM - Prompt("Please insert a Disc in the drive and press enter"); - cout << "Mounting CD-ROM" << endl; - if (MountCdrom(CDROM) == false) - return _error->Error("Failed to mount the cdrom."); - } - - // Hash the CD to get an ID - cout << "Identifying.. " << flush; - string ID; - if (IdentCdrom(CDROM,ID) == false) - { - cout << endl; - return false; - } - - cout << '[' << ID << ']' << endl; - - cout << "Scanning Disc for index files.. " << flush; - // Get the CD structure - vector<string> List; - vector<string> sList; - string StartDir = SafeGetCWD(); - string InfoDir; - if (FindPackages(CDROM,List,sList,InfoDir) == false) - { - cout << endl; - return false; - } - - chdir(StartDir.c_str()); - - if (_config->FindB("Debug::aptcdrom",false) == true) - { - cout << "I found (binary):" << endl; - for (vector<string>::iterator I = List.begin(); I != List.end(); I++) - cout << *I << endl; - cout << "I found (source):" << endl; - for (vector<string>::iterator I = sList.begin(); I != sList.end(); I++) - cout << *I << endl; - } - - // Fix up the list - DropBinaryArch(List); - DropRepeats(List,"Packages"); - DropRepeats(sList,"Sources"); - cout << "Found " << List.size() << " package indexes and " << sList.size() << - " source indexes." << endl; - - if (List.size() == 0 && sList.size() == 0) - return _error->Error("Unable to locate any package files, perhaps this is not a Debian Disc"); - - // Check if the CD is in the database - string Name; - if (Database.Exists("CD::" + ID) == false || - _config->FindB("APT::CDROM::Rename",false) == true) - { - // Try to use the CDs label if at all possible - if (InfoDir.empty() == false && - FileExists(InfoDir + "/info") == true) - { - ifstream F(string(InfoDir + "/info").c_str()); - if (!F == 0) - getline(F,Name); - - if (Name.empty() == false) - { - // Escape special characters - string::iterator J = Name.begin(); - for (; J != Name.end(); J++) - if (*J == '"' || *J == ']' || *J == '[') - *J = '_'; - - cout << "Found label '" << Name << "'" << endl; - Database.Set("CD::" + ID + "::Label",Name); - } - } - - if (_config->FindB("APT::CDROM::Rename",false) == true || - Name.empty() == true) - { - cout << "Please provide a name for this Disc, such as 'Debian 2.1r1 Disk 1'"; - while (1) - { - Name = PromptLine(""); - if (Name.empty() == false && - Name.find('"') == string::npos && - Name.find('[') == string::npos && - Name.find(']') == string::npos) - break; - cout << "That is not a valid name, try again " << endl; - } - } - } - else - Name = Database.Find("CD::" + ID); - - // Escape special characters - string::iterator J = Name.begin(); - for (; J != Name.end(); J++) - if (*J == '"' || *J == ']' || *J == '[') - *J = '_'; - - Database.Set("CD::" + ID,Name); - cout << "This Disc is called:" << endl << " '" << Name << "'" << endl; - - // Copy the package files to the state directory - PackageCopy Copy; - SourceCopy SrcCopy; - if (Copy.CopyPackages(CDROM,Name,List) == false || - SrcCopy.CopyPackages(CDROM,Name,sList) == false) - return false; - - ReduceSourcelist(CDROM,List); - ReduceSourcelist(CDROM,sList); - - // Write the database and sourcelist - if (_config->FindB("APT::cdrom::NoAct",false) == false) - { - if (WriteDatabase(Database) == false) - return false; - - cout << "Writing new source list" << endl; - if (WriteSourceList(Name,List,false) == false || - WriteSourceList(Name,sList,true) == false) - return false; - } - - // Print the sourcelist entries - cout << "Source List entries for this Disc are:" << endl; - for (vector<string>::iterator I = List.begin(); I != List.end(); I++) - { - string::size_type Space = (*I).find(' '); - if (Space == string::npos) - return _error->Error("Internal error"); - - cout << "deb cdrom:[" << Name << "]/" << string(*I,0,Space) << - " " << string(*I,Space+1) << endl; - } - - for (vector<string>::iterator I = sList.begin(); I != sList.end(); I++) - { - string::size_type Space = (*I).find(' '); - if (Space == string::npos) - return _error->Error("Internal error"); - - cout << "deb-src cdrom:[" << Name << "]/" << string(*I,0,Space) << - " " << string(*I,Space+1) << endl; - } - - cout << "Repeat this process for the rest of the CDs in your set." << endl; - - // Unmount and finish - if (_config->FindB("APT::CDROM::NoMount",false) == false) - UnmountCdrom(CDROM); - - return true; + bool res = false; + pkgCdromTextStatus log; + pkgCdrom cdrom; + res = cdrom.Add(&log); + if(res) + cout << "Repeat this process for the rest of the CDs in your set." << endl; + return res; } /*}}}*/ // DoIdent - Ident a CDROM /*{{{*/ @@ -688,38 +123,10 @@ bool DoAdd(CommandLine &) /* */ bool DoIdent(CommandLine &) { - // Startup - string CDROM = _config->FindDir("Acquire::cdrom::mount","/cdrom/"); - if (CDROM[0] == '.') - CDROM= SafeGetCWD() + '/' + CDROM; - - cout << "Using CD-ROM mount point " << CDROM << endl; - cout << "Mounting CD-ROM" << endl; - if (MountCdrom(CDROM) == false) - return _error->Error("Failed to mount the cdrom."); - - // Hash the CD to get an ID - cout << "Identifying.. " << flush; - string ID; - if (IdentCdrom(CDROM,ID) == false) - { - cout << endl; - return false; - } - - cout << '[' << ID << ']' << endl; - - // Read the database - Configuration Database; - string DFile = _config->FindFile("Dir::State::cdroms"); - if (FileExists(DFile) == true) - { - if (ReadConfigFile(Database,DFile) == false) - return _error->Error("Unable to read the cdrom database %s", - DFile.c_str()); - } - cout << "Stored Label: '" << Database.Find("CD::" + ID) << "'" << endl; - return true; + string ident; + pkgCdromTextStatus log; + pkgCdrom cdrom; + return cdrom.Ident(ident, &log); } /*}}}*/ diff --git a/cmdline/indexcopy.cc b/cmdline/indexcopy.cc deleted file mode 100644 index 0a3cd1575..000000000 --- a/cmdline/indexcopy.cc +++ /dev/null @@ -1,524 +0,0 @@ -// -*- mode: cpp; mode: fold -*- -// Description /*{{{*/ -// $Id: indexcopy.cc,v 1.10 2002/03/26 07:38:58 jgg Exp $ -/* ###################################################################### - - Index Copying - Aid for copying and verifying the index files - - This class helps apt-cache reconstruct a damaged index files. - - ##################################################################### */ - /*}}}*/ -// Include Files /*{{{*/ -#include "indexcopy.h" - -#include <apt-pkg/error.h> -#include <apt-pkg/progress.h> -#include <apt-pkg/strutl.h> -#include <apt-pkg/fileutl.h> -#include <apt-pkg/configuration.h> -#include <apt-pkg/tagfile.h> - -#include <iostream> -#include <unistd.h> -#include <sys/stat.h> -#include <stdio.h> - /*}}}*/ - -using namespace std; - -// IndexCopy::CopyPackages - Copy the package files from the CD /*{{{*/ -// --------------------------------------------------------------------- -/* */ -bool IndexCopy::CopyPackages(string CDROM,string Name,vector<string> &List) -{ - if (List.size() == 0) - return true; - - OpTextProgress Progress; - - bool NoStat = _config->FindB("APT::CDROM::Fast",false); - bool Debug = _config->FindB("Debug::aptcdrom",false); - - // Prepare the progress indicator - unsigned long TotalSize = 0; - for (vector<string>::iterator I = List.begin(); I != List.end(); I++) - { - struct stat Buf; - if (stat(string(*I + GetFileName()).c_str(),&Buf) != 0 && - stat(string(*I + GetFileName() + ".gz").c_str(),&Buf) != 0) - return _error->Errno("stat","Stat failed for %s", - string(*I + GetFileName()).c_str()); - TotalSize += Buf.st_size; - } - - unsigned long CurrentSize = 0; - unsigned int NotFound = 0; - 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()); - unsigned long FileSize = 0; - - // Open the package file - FileFd Pkg; - if (FileExists(*I + GetFileName()) == true) - { - Pkg.Open(*I + GetFileName(),FileFd::ReadOnly); - FileSize = Pkg.Size(); - } - else - { - FileFd From(*I + GetFileName() + ".gz",FileFd::ReadOnly); - if (_error->PendingError() == true) - return false; - FileSize = From.Size(); - - // Get a temp file - FILE *tmp = tmpfile(); - if (tmp == 0) - return _error->Errno("tmpfile","Unable to create a tmp file"); - Pkg.Fd(dup(fileno(tmp))); - fclose(tmp); - - // Fork gzip - pid_t Process = fork(); - if (Process < 0) - return _error->Errno("fork","Couldn't fork gzip"); - - // The child - if (Process == 0) - { - dup2(From.Fd(),STDIN_FILENO); - dup2(Pkg.Fd(),STDOUT_FILENO); - SetCloseExec(STDIN_FILENO,false); - SetCloseExec(STDOUT_FILENO,false); - - const char *Args[3]; - string Tmp = _config->Find("Dir::bin::gzip","gzip"); - Args[0] = Tmp.c_str(); - Args[1] = "-d"; - Args[2] = 0; - execvp(Args[0],(char **)Args); - exit(100); - } - - // Wait for gzip to finish - if (ExecWait(Process,_config->Find("Dir::bin::gzip","gzip").c_str(),false) == false) - return _error->Error("gzip failed, perhaps the disk is full."); - - Pkg.Seek(0); - } - pkgTagFile Parser(&Pkg); - if (_error->PendingError() == true) - return false; - - // Open the output file - char S[400]; - snprintf(S,sizeof(S),"cdrom:[%s]/%s%s",Name.c_str(), - (*I).c_str() + CDROM.length(),GetFileName()); - string TargetF = _config->FindDir("Dir::State::lists") + "partial/"; - TargetF += URItoFileName(S); - if (_config->FindB("APT::CDROM::NoAct",false) == true) - TargetF = "/dev/null"; - FileFd Target(TargetF,FileFd::WriteEmpty); - FILE *TargetFl = fdopen(dup(Target.Fd()),"w"); - if (_error->PendingError() == true) - return false; - if (TargetFl == 0) - return _error->Errno("fdopen","Failed to reopen fd"); - - // Setup the progress meter - Progress.OverallProgress(CurrentSize,TotalSize,FileSize, - string("Reading ") + Type() + " Indexes"); - - // Parse - Progress.SubProgress(Pkg.Size()); - pkgTagSection Section; - this->Section = &Section; - string Prefix; - unsigned long Hits = 0; - unsigned long Chop = 0; - while (Parser.Step(Section) == true) - { - Progress.Progress(Parser.Offset()); - string File; - unsigned long Size; - if (GetFile(File,Size) == false) - { - fclose(TargetFl); - return false; - } - - if (Chop != 0) - File = OrigPath + ChopDirs(File,Chop); - - // See if the file exists - bool Mangled = false; - if (NoStat == false || Hits < 10) - { - // Attempt to fix broken structure - if (Hits == 0) - { - if (ReconstructPrefix(Prefix,OrigPath,CDROM,File) == false && - ReconstructChop(Chop,*I,File) == false) - { - if (Debug == true) - clog << "Missed: " << File << endl; - NotFound++; - continue; - } - if (Chop != 0) - File = OrigPath + ChopDirs(File,Chop); - } - - // Get the size - struct stat Buf; - if (stat(string(CDROM + Prefix + File).c_str(),&Buf) != 0 || - Buf.st_size == 0) - { - // Attempt to fix busted symlink support for one instance - string OrigFile = File; - string::size_type Start = File.find("binary-"); - string::size_type End = File.find("/",Start+3); - if (Start != string::npos && End != string::npos) - { - File.replace(Start,End-Start,"binary-all"); - Mangled = true; - } - - if (Mangled == false || - stat(string(CDROM + Prefix + File).c_str(),&Buf) != 0) - { - if (Debug == true) - clog << "Missed(2): " << OrigFile << endl; - NotFound++; - continue; - } - } - - // Size match - if ((unsigned)Buf.st_size != Size) - { - if (Debug == true) - clog << "Wrong Size: " << File << endl; - WrongSize++; - continue; - } - } - - Packages++; - Hits++; - - if (RewriteEntry(TargetFl,File) == false) - { - fclose(TargetFl); - return false; - } - } - fclose(TargetFl); - - if (Debug == true) - cout << " Processed by using Prefix '" << Prefix << "' and chop " << Chop << endl; - - if (_config->FindB("APT::CDROM::NoAct",false) == false) - { - // Move out of the partial directory - Target.Close(); - string FinalF = _config->FindDir("Dir::State::lists"); - FinalF += URItoFileName(S); - if (rename(TargetF.c_str(),FinalF.c_str()) != 0) - return _error->Errno("rename","Failed to rename"); - - // Copy the release file - snprintf(S,sizeof(S),"cdrom:[%s]/%sRelease",Name.c_str(), - (*I).c_str() + CDROM.length()); - string TargetF = _config->FindDir("Dir::State::lists") + "partial/"; - TargetF += URItoFileName(S); - if (FileExists(*I + "Release") == true) - { - FileFd Target(TargetF,FileFd::WriteEmpty); - FileFd Rel(*I + "Release",FileFd::ReadOnly); - if (_error->PendingError() == true) - return false; - - if (CopyFile(Rel,Target) == false) - return false; - } - else - { - // Empty release file - FileFd Target(TargetF,FileFd::WriteEmpty); - } - - // Rename the release file - FinalF = _config->FindDir("Dir::State::lists"); - FinalF += URItoFileName(S); - if (rename(TargetF.c_str(),FinalF.c_str()) != 0) - return _error->Errno("rename","Failed to rename"); - } - - /* Mangle the source to be in the proper notation with - prefix dist [component] */ - *I = string(*I,Prefix.length()); - ConvertToSourceList(CDROM,*I); - *I = Prefix + ' ' + *I; - - CurrentSize += FileSize; - } - Progress.Done(); - - // Some stats - cout << "Wrote " << Packages << " records" ; - if (NotFound != 0) - cout << " with " << NotFound << " missing files"; - if (NotFound != 0 && WrongSize != 0) - cout << " and"; - if (WrongSize != 0) - cout << " with " << WrongSize << " mismatched files"; - cout << '.' << endl; - - if (Packages == 0) - _error->Warning("No valid records were found."); - - if (NotFound + WrongSize > 10) - cout << "Alot of entries were discarded, something may be wrong." << endl; - - return true; -} - /*}}}*/ -// IndexCopy::ChopDirs - Chop off the leading directory components /*{{{*/ -// --------------------------------------------------------------------- -/* */ -string IndexCopy::ChopDirs(string Path,unsigned int Depth) -{ - string::size_type I = 0; - do - { - I = Path.find('/',I+1); - Depth--; - } - while (I != string::npos && Depth != 0); - - if (I == string::npos) - return string(); - - return string(Path,I+1); -} - /*}}}*/ -// IndexCopy::ReconstructPrefix - Fix strange prefixing /*{{{*/ -// --------------------------------------------------------------------- -/* This prepends dir components from the path to the package files to - the path to the deb until it is found */ -bool IndexCopy::ReconstructPrefix(string &Prefix,string OrigPath,string CD, - string File) -{ - bool Debug = _config->FindB("Debug::aptcdrom",false); - unsigned int Depth = 1; - string MyPrefix = Prefix; - while (1) - { - struct stat Buf; - if (stat(string(CD + MyPrefix + File).c_str(),&Buf) != 0) - { - if (Debug == true) - cout << "Failed, " << CD + MyPrefix + File << endl; - if (GrabFirst(OrigPath,MyPrefix,Depth++) == true) - continue; - - return false; - } - else - { - Prefix = MyPrefix; - return true; - } - } - return false; -} - /*}}}*/ -// IndexCopy::ReconstructChop - Fixes bad source paths /*{{{*/ -// --------------------------------------------------------------------- -/* This removes path components from the filename and prepends the location - of the package files until a file is found */ -bool IndexCopy::ReconstructChop(unsigned long &Chop,string Dir,string File) -{ - // Attempt to reconstruct the filename - unsigned long Depth = 0; - while (1) - { - struct stat Buf; - if (stat(string(Dir + File).c_str(),&Buf) != 0) - { - File = ChopDirs(File,1); - Depth++; - if (File.empty() == false) - continue; - return false; - } - else - { - Chop = Depth; - return true; - } - } - return false; -} - /*}}}*/ -// IndexCopy::ConvertToSourceList - Convert a Path to a sourcelist /*{{{*/ -// --------------------------------------------------------------------- -/* We look for things in dists/ notation and convert them to - <dist> <component> form otherwise it is left alone. This also strips - the CD path. - - This implements a regex sort of like: - (.*)/dists/([^/]*)/(.*)/binary-* - ^ ^ ^- Component - | |-------- Distribution - |------------------- Path - - It was deciced to use only a single word for dist (rather than say - unstable/non-us) to increase the chance that each CD gets a single - line in sources.list. - */ -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) - Path = "/"; - - // Too short to be a dists/ type - if (Path.length() < strlen("dists/")) - return; - - // Not a dists type. - if (stringcmp(Path.c_str(),Path.c_str()+strlen("dists/"),"dists/") != 0) - return; - - // Isolate the dist - string::size_type Slash = strlen("dists/"); - string::size_type Slash2 = Path.find('/',Slash + 1); - if (Slash2 == string::npos || Slash2 + 2 >= Path.length()) - return; - string Dist = string(Path,Slash,Slash2 - Slash); - - // Isolate the component - Slash = Slash2; - for (unsigned I = 0; I != 10; I++) - { - Slash = Path.find('/',Slash+1); - if (Slash == string::npos || Slash + 2 >= Path.length()) - return; - string Comp = string(Path,Slash2+1,Slash - Slash2-1); - - // Verify the trailing binary- bit - string::size_type BinSlash = Path.find('/',Slash + 1); - if (Slash == string::npos) - return; - string Binary = string(Path,Slash+1,BinSlash - Slash-1); - - if (Binary != S && Binary != "source") - continue; - - Path = Dist + ' ' + Comp; - return; - } -} - /*}}}*/ -// IndexCopy::GrabFirst - Return the first Depth path components /*{{{*/ -// --------------------------------------------------------------------- -/* */ -bool IndexCopy::GrabFirst(string Path,string &To,unsigned int Depth) -{ - string::size_type I = 0; - do - { - I = Path.find('/',I+1); - Depth--; - } - while (I != string::npos && Depth != 0); - - if (I == string::npos) - return false; - - To = string(Path,0,I+1); - return true; -} - /*}}}*/ -// PackageCopy::GetFile - Get the file information from the section /*{{{*/ -// --------------------------------------------------------------------- -/* */ -bool PackageCopy::GetFile(string &File,unsigned long &Size) -{ - File = Section->FindS("Filename"); - Size = Section->FindI("Size"); - if (File.empty() || Size == 0) - return _error->Error("Cannot find filename or size tag"); - return true; -} - /*}}}*/ -// PackageCopy::RewriteEntry - Rewrite the entry with a new filename /*{{{*/ -// --------------------------------------------------------------------- -/* */ -bool PackageCopy::RewriteEntry(FILE *Target,string File) -{ - TFRewriteData Changes[] = {{"Filename",File.c_str()}, - {}}; - - if (TFRewrite(Target,*Section,TFRewritePackageOrder,Changes) == false) - return false; - fputc('\n',Target); - return true; -} - /*}}}*/ -// SourceCopy::GetFile - Get the file information from the section /*{{{*/ -// --------------------------------------------------------------------- -/* */ -bool SourceCopy::GetFile(string &File,unsigned long &Size) -{ - string Files = Section->FindS("Files"); - if (Files.empty() == true) - return false; - - // Stash the / terminated directory prefix - string Base = Section->FindS("Directory"); - if (Base.empty() == false && Base[Base.length()-1] != '/') - Base += '/'; - - // Read the first file triplet - const char *C = Files.c_str(); - string sSize; - string MD5Hash; - - // Parse each of the elements - if (ParseQuoteWord(C,MD5Hash) == false || - ParseQuoteWord(C,sSize) == false || - ParseQuoteWord(C,File) == false) - return _error->Error("Error parsing file record"); - - // Parse the size and append the directory - Size = atoi(sSize.c_str()); - File = Base + File; - return true; -} - /*}}}*/ -// SourceCopy::RewriteEntry - Rewrite the entry with a new filename /*{{{*/ -// --------------------------------------------------------------------- -/* */ -bool SourceCopy::RewriteEntry(FILE *Target,string File) -{ - string Dir(File,0,File.rfind('/')); - TFRewriteData Changes[] = {{"Directory",Dir.c_str()}, - {}}; - - if (TFRewrite(Target,*Section,TFRewriteSourceOrder,Changes) == false) - return false; - fputc('\n',Target); - return true; -} - /*}}}*/ diff --git a/cmdline/indexcopy.h b/cmdline/indexcopy.h deleted file mode 100644 index e44a91727..000000000 --- a/cmdline/indexcopy.h +++ /dev/null @@ -1,69 +0,0 @@ -// -*- mode: cpp; mode: fold -*- -// Description /*{{{*/ -// $Id: indexcopy.h,v 1.3 2001/05/27 04:46:54 jgg Exp $ -/* ###################################################################### - - Index Copying - Aid for copying and verifying the index files - - ##################################################################### */ - /*}}}*/ -#ifndef INDEXCOPY_H -#define INDEXCOPY_H - -#include <vector> -#include <string> -#include <stdio.h> - -using std::string; -using std::vector; - -class pkgTagSection; -class FileFd; - -class IndexCopy -{ - protected: - - pkgTagSection *Section; - - string ChopDirs(string Path,unsigned int Depth); - bool ReconstructPrefix(string &Prefix,string OrigPath,string CD, - string File); - bool ReconstructChop(unsigned long &Chop,string Dir,string File); - void ConvertToSourceList(string CD,string &Path); - bool GrabFirst(string Path,string &To,unsigned int Depth); - virtual bool GetFile(string &Filename,unsigned long &Size) = 0; - virtual bool RewriteEntry(FILE *Target,string File) = 0; - virtual const char *GetFileName() = 0; - virtual const char *Type() = 0; - - public: - - bool CopyPackages(string CDROM,string Name,vector<string> &List); -}; - -class PackageCopy : public IndexCopy -{ - protected: - - virtual bool GetFile(string &Filename,unsigned long &Size); - virtual bool RewriteEntry(FILE *Target,string File); - virtual const char *GetFileName() {return "Packages";}; - virtual const char *Type() {return "Package";}; - - public: -}; - -class SourceCopy : public IndexCopy -{ - protected: - - virtual bool GetFile(string &Filename,unsigned long &Size); - virtual bool RewriteEntry(FILE *Target,string File); - virtual const char *GetFileName() {return "Sources";}; - virtual const char *Type() {return "Source";}; - - public: -}; - -#endif diff --git a/cmdline/makefile b/cmdline/makefile index 21a6d47d4..882a0e1b5 100644 --- a/cmdline/makefile +++ b/cmdline/makefile @@ -30,7 +30,7 @@ include $(PROGRAM_H) PROGRAM=apt-cdrom SLIBS = -lapt-pkg LIB_MAKES = apt-pkg/makefile -SOURCE = apt-cdrom.cc indexcopy.cc +SOURCE = apt-cdrom.cc include $(PROGRAM_H) # The apt-sortpkgs program |