1 // -*- mode: cpp; mode: fold -*- 
   3 /* ###################################################################### 
   7    CopyFile - Buffered copy of a single file 
   8    GetLock - dpkg compatible lock file manipulation (fcntl) 
  10    Most of this source is placed in the Public Domain, do with it what  
  12    It was originally written by Jason Gunthorpe <jgg@debian.org>. 
  13    FileFd gzip support added by Martin Pitt <martin.pitt@canonical.com> 
  15    The exception is RunScripts() it is under the GPLv2 
  17    ##################################################################### */ 
  19 // Include Files                                                        /*{{{*/ 
  22 #include <apt-pkg/fileutl.h> 
  23 #include <apt-pkg/strutl.h> 
  24 #include <apt-pkg/error.h> 
  25 #include <apt-pkg/sptr.h> 
  26 #include <apt-pkg/aptconfiguration.h> 
  27 #include <apt-pkg/configuration.h> 
  28 #include <apt-pkg/macros.h> 
  33 #include <sys/select.h> 
  65 #ifdef WORDS_BIGENDIAN 
  74 // RunScripts - Run a set of scripts from a configuration subtree       /*{{{*/ 
  75 // --------------------------------------------------------------------- 
  77 bool RunScripts(const char *Cnf
) 
  79    Configuration::Item 
const *Opts 
= _config
->Tree(Cnf
); 
  80    if (Opts 
== 0 || Opts
->Child 
== 0) 
  84    // Fork for running the system calls 
  85    pid_t Child 
= ExecFork(); 
  90       if (_config
->FindDir("DPkg::Chroot-Directory","/") != "/")  
  92          std::cerr 
<< "Chrooting into "  
  93                    << _config
->FindDir("DPkg::Chroot-Directory")  
  95          if (chroot(_config
->FindDir("DPkg::Chroot-Directory","/").c_str()) != 0) 
  99       if (chdir("/tmp/") != 0) 
 102       unsigned int Count 
= 1; 
 103       for (; Opts 
!= 0; Opts 
= Opts
->Next
, Count
++) 
 105          if (Opts
->Value
.empty() == true) 
 108          if (system(Opts
->Value
.c_str()) != 0) 
 114    // Wait for the child 
 116    while (waitpid(Child
,&Status
,0) != Child
) 
 120       return _error
->Errno("waitpid","Couldn't wait for subprocess"); 
 123    // Restore sig int/quit 
 124    signal(SIGQUIT
,SIG_DFL
); 
 125    signal(SIGINT
,SIG_DFL
);    
 127    // Check for an error code. 
 128    if (WIFEXITED(Status
) == 0 || WEXITSTATUS(Status
) != 0) 
 130       unsigned int Count 
= WEXITSTATUS(Status
); 
 134          for (; Opts 
!= 0 && Count 
!= 1; Opts 
= Opts
->Next
, Count
--); 
 135          _error
->Error("Problem executing scripts %s '%s'",Cnf
,Opts
->Value
.c_str()); 
 138       return _error
->Error("Sub-process returned an error code"); 
 145 // CopyFile - Buffered copy of a file                                   /*{{{*/ 
 146 // --------------------------------------------------------------------- 
 147 /* The caller is expected to set things so that failure causes erasure */ 
 148 bool CopyFile(FileFd 
&From
,FileFd 
&To
) 
 150    if (From
.IsOpen() == false || To
.IsOpen() == false || 
 151          From
.Failed() == true || To
.Failed() == true) 
 154    // Buffered copy between fds 
 155    SPtrArray
<unsigned char> Buf 
= new unsigned char[64000]; 
 156    unsigned long long Size 
= From
.Size(); 
 159       unsigned long long ToRead 
= Size
; 
 163       if (From
.Read(Buf
,ToRead
) == false ||  
 164           To
.Write(Buf
,ToRead
) == false) 
 173 // GetLock - Gets a lock file                                           /*{{{*/ 
 174 // --------------------------------------------------------------------- 
 175 /* This will create an empty file of the given name and lock it. Once this 
 176    is done all other calls to GetLock in any other process will fail with 
 177    -1. The return result is the fd of the file, the call should call 
 178    close at some time. */ 
 179 int GetLock(string File
,bool Errors
) 
 181    // GetLock() is used in aptitude on directories with public-write access 
 182    // Use O_NOFOLLOW here to prevent symlink traversal attacks 
 183    int FD 
= open(File
.c_str(),O_RDWR 
| O_CREAT 
| O_NOFOLLOW
,0640); 
 186       // Read only .. can't have locking problems there. 
 189          _error
->Warning(_("Not using locking for read only lock file %s"),File
.c_str()); 
 190          return dup(0);       // Need something for the caller to close 
 194          _error
->Errno("open",_("Could not open lock file %s"),File
.c_str()); 
 196       // Feh.. We do this to distinguish the lock vs open case.. 
 200    SetCloseExec(FD
,true); 
 202    // Acquire a write lock 
 205    fl
.l_whence 
= SEEK_SET
; 
 208    if (fcntl(FD
,F_SETLK
,&fl
) == -1) 
 210       // always close to not leak resources 
 217          _error
->Warning(_("Not using locking for nfs mounted lock file %s"),File
.c_str()); 
 218          return dup(0);       // Need something for the caller to close   
 222          _error
->Errno("open",_("Could not get lock %s"),File
.c_str()); 
 230 // FileExists - Check if a file exists                                  /*{{{*/ 
 231 // --------------------------------------------------------------------- 
 232 /* Beware: Directories are also files! */ 
 233 bool FileExists(string File
) 
 236    if (stat(File
.c_str(),&Buf
) != 0) 
 241 // RealFileExists - Check if a file exists and if it is really a file   /*{{{*/ 
 242 // --------------------------------------------------------------------- 
 244 bool RealFileExists(string File
) 
 247    if (stat(File
.c_str(),&Buf
) != 0) 
 249    return ((Buf
.st_mode 
& S_IFREG
) != 0); 
 252 // DirectoryExists - Check if a directory exists and is really one      /*{{{*/ 
 253 // --------------------------------------------------------------------- 
 255 bool DirectoryExists(string 
const &Path
) 
 258    if (stat(Path
.c_str(),&Buf
) != 0) 
 260    return ((Buf
.st_mode 
& S_IFDIR
) != 0); 
 263 // CreateDirectory - poor man's mkdir -p guarded by a parent directory  /*{{{*/ 
 264 // --------------------------------------------------------------------- 
 265 /* This method will create all directories needed for path in good old 
 266    mkdir -p style but refuses to do this if Parent is not a prefix of 
 267    this Path. Example: /var/cache/ and /var/cache/apt/archives are given, 
 268    so it will create apt/archives if /var/cache exists - on the other 
 269    hand if the parent is /var/lib the creation will fail as this path 
 270    is not a parent of the path to be generated. */ 
 271 bool CreateDirectory(string 
const &Parent
, string 
const &Path
) 
 273    if (Parent
.empty() == true || Path
.empty() == true) 
 276    if (DirectoryExists(Path
) == true) 
 279    if (DirectoryExists(Parent
) == false) 
 282    // we are not going to create directories "into the blue" 
 283    if (Path
.compare(0, Parent
.length(), Parent
) != 0) 
 286    vector
<string
> const dirs 
= VectorizeString(Path
.substr(Parent
.size()), '/'); 
 287    string progress 
= Parent
; 
 288    for (vector
<string
>::const_iterator d 
= dirs
.begin(); d 
!= dirs
.end(); ++d
) 
 290       if (d
->empty() == true) 
 293       progress
.append("/").append(*d
); 
 294       if (DirectoryExists(progress
) == true) 
 297       if (mkdir(progress
.c_str(), 0755) != 0) 
 303 // CreateAPTDirectoryIfNeeded - ensure that the given directory exists          /*{{{*/ 
 304 // --------------------------------------------------------------------- 
 305 /* a small wrapper around CreateDirectory to check if it exists and to 
 306    remove the trailing "/apt/" from the parent directory if needed */ 
 307 bool CreateAPTDirectoryIfNeeded(string 
const &Parent
, string 
const &Path
) 
 309    if (DirectoryExists(Path
) == true) 
 312    size_t const len 
= Parent
.size(); 
 313    if (len 
> 5 && Parent
.find("/apt/", len 
- 6, 5) == len 
- 5) 
 315       if (CreateDirectory(Parent
.substr(0,len
-5), Path
) == true) 
 318    else if (CreateDirectory(Parent
, Path
) == true) 
 324 // GetListOfFilesInDir - returns a vector of files in the given dir     /*{{{*/ 
 325 // --------------------------------------------------------------------- 
 326 /* If an extension is given only files with this extension are included 
 327    in the returned vector, otherwise every "normal" file is included. */ 
 328 std::vector
<string
> GetListOfFilesInDir(string 
const &Dir
, string 
const &Ext
, 
 329                                         bool const &SortList
, bool const &AllowNoExt
) 
 331    std::vector
<string
> ext
; 
 333    if (Ext
.empty() == false) 
 335    if (AllowNoExt 
== true && ext
.empty() == false) 
 337    return GetListOfFilesInDir(Dir
, ext
, SortList
); 
 339 std::vector
<string
> GetListOfFilesInDir(string 
const &Dir
, std::vector
<string
> const &Ext
, 
 340                                         bool const &SortList
) 
 342    // Attention debuggers: need to be set with the environment config file! 
 343    bool const Debug 
= _config
->FindB("Debug::GetListOfFilesInDir", false); 
 346       std::clog 
<< "Accept in " << Dir 
<< " only files with the following " << Ext
.size() << " extensions:" << std::endl
; 
 347       if (Ext
.empty() == true) 
 348          std::clog 
<< "\tNO extension" << std::endl
; 
 350          for (std::vector
<string
>::const_iterator e 
= Ext
.begin(); 
 352             std::clog 
<< '\t' << (e
->empty() == true ? "NO" : *e
) << " extension" << std::endl
; 
 355    std::vector
<string
> List
; 
 357    if (DirectoryExists(Dir
) == false) 
 359       _error
->Error(_("List of files can't be created as '%s' is not a directory"), Dir
.c_str()); 
 363    Configuration::MatchAgainstConfig 
SilentIgnore("Dir::Ignore-Files-Silently"); 
 364    DIR *D 
= opendir(Dir
.c_str()); 
 367       _error
->Errno("opendir",_("Unable to read %s"),Dir
.c_str()); 
 371    for (struct dirent 
*Ent 
= readdir(D
); Ent 
!= 0; Ent 
= readdir(D
))  
 373       // skip "hidden" files 
 374       if (Ent
->d_name
[0] == '.') 
 377       // Make sure it is a file and not something else 
 378       string 
const File 
= flCombine(Dir
,Ent
->d_name
); 
 379 #ifdef _DIRENT_HAVE_D_TYPE 
 380       if (Ent
->d_type 
!= DT_REG
) 
 383          if (RealFileExists(File
) == false) 
 385             // do not show ignoration warnings for directories 
 387 #ifdef _DIRENT_HAVE_D_TYPE 
 388                 Ent
->d_type 
== DT_DIR 
|| 
 390                 DirectoryExists(File
) == true) 
 392             if (SilentIgnore
.Match(Ent
->d_name
) == false) 
 393                _error
->Notice(_("Ignoring '%s' in directory '%s' as it is not a regular file"), Ent
->d_name
, Dir
.c_str()); 
 398       // check for accepted extension: 
 399       // no extension given -> periods are bad as hell! 
 400       // extensions given -> "" extension allows no extension 
 401       if (Ext
.empty() == false) 
 403          string d_ext 
= flExtension(Ent
->d_name
); 
 404          if (d_ext 
== Ent
->d_name
) // no extension 
 406             if (std::find(Ext
.begin(), Ext
.end(), "") == Ext
.end()) 
 409                   std::clog 
<< "Bad file: " << Ent
->d_name 
<< " → no extension" << std::endl
; 
 410                if (SilentIgnore
.Match(Ent
->d_name
) == false) 
 411                   _error
->Notice(_("Ignoring file '%s' in directory '%s' as it has no filename extension"), Ent
->d_name
, Dir
.c_str()); 
 415          else if (std::find(Ext
.begin(), Ext
.end(), d_ext
) == Ext
.end()) 
 418                std::clog 
<< "Bad file: " << Ent
->d_name 
<< " → bad extension »" << flExtension(Ent
->d_name
) << "«" << std::endl
; 
 419             if (SilentIgnore
.Match(Ent
->d_name
) == false) 
 420                _error
->Notice(_("Ignoring file '%s' in directory '%s' as it has an invalid filename extension"), Ent
->d_name
, Dir
.c_str()); 
 425       // Skip bad filenames ala run-parts 
 426       const char *C 
= Ent
->d_name
; 
 428          if (isalpha(*C
) == 0 && isdigit(*C
) == 0 
 429              && *C 
!= '_' && *C 
!= '-' && *C 
!= ':') { 
 430             // no required extension -> dot is a bad character 
 431             if (*C 
== '.' && Ext
.empty() == false) 
 436       // we don't reach the end of the name -> bad character included 
 440             std::clog 
<< "Bad file: " << Ent
->d_name 
<< " → bad character »" 
 441                << *C 
<< "« in filename (period allowed: " << (Ext
.empty() ? "no" : "yes") << ")" << std::endl
; 
 445       // skip filenames which end with a period. These are never valid 
 449             std::clog 
<< "Bad file: " << Ent
->d_name 
<< " → Period as last character" << std::endl
; 
 454          std::clog 
<< "Accept file: " << Ent
->d_name 
<< " in " << Dir 
<< std::endl
; 
 455       List
.push_back(File
); 
 459    if (SortList 
== true) 
 460       std::sort(List
.begin(),List
.end()); 
 463 std::vector
<string
> GetListOfFilesInDir(string 
const &Dir
, bool SortList
) 
 465    bool const Debug 
= _config
->FindB("Debug::GetListOfFilesInDir", false); 
 467       std::clog 
<< "Accept in " << Dir 
<< " all regular files" << std::endl
; 
 469    std::vector
<string
> List
; 
 471    if (DirectoryExists(Dir
) == false) 
 473       _error
->Error(_("List of files can't be created as '%s' is not a directory"), Dir
.c_str()); 
 477    DIR *D 
= opendir(Dir
.c_str()); 
 480       _error
->Errno("opendir",_("Unable to read %s"),Dir
.c_str()); 
 484    for (struct dirent 
*Ent 
= readdir(D
); Ent 
!= 0; Ent 
= readdir(D
))  
 486       // skip "hidden" files 
 487       if (Ent
->d_name
[0] == '.') 
 490       // Make sure it is a file and not something else 
 491       string 
const File 
= flCombine(Dir
,Ent
->d_name
); 
 492 #ifdef _DIRENT_HAVE_D_TYPE 
 493       if (Ent
->d_type 
!= DT_REG
) 
 496          if (RealFileExists(File
) == false) 
 499                std::clog 
<< "Bad file: " << Ent
->d_name 
<< " → it is not a real file" << std::endl
; 
 504       // Skip bad filenames ala run-parts 
 505       const char *C 
= Ent
->d_name
; 
 507          if (isalpha(*C
) == 0 && isdigit(*C
) == 0 
 508              && *C 
!= '_' && *C 
!= '-' && *C 
!= '.') 
 511       // we don't reach the end of the name -> bad character included 
 515             std::clog 
<< "Bad file: " << Ent
->d_name 
<< " → bad character »" << *C 
<< "« in filename" << std::endl
; 
 519       // skip filenames which end with a period. These are never valid 
 523             std::clog 
<< "Bad file: " << Ent
->d_name 
<< " → Period as last character" << std::endl
; 
 528          std::clog 
<< "Accept file: " << Ent
->d_name 
<< " in " << Dir 
<< std::endl
; 
 529       List
.push_back(File
); 
 533    if (SortList 
== true) 
 534       std::sort(List
.begin(),List
.end()); 
 538 // SafeGetCWD - This is a safer getcwd that returns a dynamic string    /*{{{*/ 
 539 // --------------------------------------------------------------------- 
 540 /* We return / on failure. */ 
 543    // Stash the current dir. 
 546    if (getcwd(S
,sizeof(S
)-2) == 0) 
 548    unsigned int Len 
= strlen(S
); 
 554 // GetModificationTime - Get the mtime of the given file or -1 on error /*{{{*/ 
 555 // --------------------------------------------------------------------- 
 556 /* We return / on failure. */ 
 557 time_t GetModificationTime(string 
const &Path
) 
 560    if (stat(Path
.c_str(), &St
) < 0) 
 565 // flNotDir - Strip the directory from the filename                     /*{{{*/ 
 566 // --------------------------------------------------------------------- 
 568 string 
flNotDir(string File
) 
 570    string::size_type Res 
= File
.rfind('/'); 
 571    if (Res 
== string::npos
) 
 574    return string(File
,Res
,Res 
- File
.length()); 
 577 // flNotFile - Strip the file from the directory name                   /*{{{*/ 
 578 // --------------------------------------------------------------------- 
 579 /* Result ends in a / */ 
 580 string 
flNotFile(string File
) 
 582    string::size_type Res 
= File
.rfind('/'); 
 583    if (Res 
== string::npos
) 
 586    return string(File
,0,Res
); 
 589 // flExtension - Return the extension for the file                      /*{{{*/ 
 590 // --------------------------------------------------------------------- 
 592 string 
flExtension(string File
) 
 594    string::size_type Res 
= File
.rfind('.'); 
 595    if (Res 
== string::npos
) 
 598    return string(File
,Res
,Res 
- File
.length()); 
 601 // flNoLink - If file is a symlink then deref it                        /*{{{*/ 
 602 // --------------------------------------------------------------------- 
 603 /* If the name is not a link then the returned path is the input. */ 
 604 string 
flNoLink(string File
) 
 607    if (lstat(File
.c_str(),&St
) != 0 || S_ISLNK(St
.st_mode
) == 0) 
 609    if (stat(File
.c_str(),&St
) != 0) 
 612    /* Loop resolving the link. There is no need to limit the number of  
 613       loops because the stat call above ensures that the symlink is not  
 621       if ((Res 
= readlink(NFile
.c_str(),Buffer
,sizeof(Buffer
))) <= 0 ||  
 622           (size_t)Res 
>= sizeof(Buffer
)) 
 625       // Append or replace the previous path 
 627       if (Buffer
[0] == '/') 
 630          NFile 
= flNotFile(NFile
) + Buffer
; 
 632       // See if we are done 
 633       if (lstat(NFile
.c_str(),&St
) != 0) 
 635       if (S_ISLNK(St
.st_mode
) == 0) 
 640 // flCombine - Combine a file and a directory                           /*{{{*/ 
 641 // --------------------------------------------------------------------- 
 642 /* If the file is an absolute path then it is just returned, otherwise 
 643    the directory is pre-pended to it. */ 
 644 string 
flCombine(string Dir
,string File
) 
 646    if (File
.empty() == true) 
 649    if (File
[0] == '/' || Dir
.empty() == true) 
 651    if (File
.length() >= 2 && File
[0] == '.' && File
[1] == '/') 
 653    if (Dir
[Dir
.length()-1] == '/') 
 655    return Dir 
+ '/' + File
; 
 658 // SetCloseExec - Set the close on exec flag                            /*{{{*/ 
 659 // --------------------------------------------------------------------- 
 661 void SetCloseExec(int Fd
,bool Close
) 
 663    if (fcntl(Fd
,F_SETFD
,(Close 
== false)?0:FD_CLOEXEC
) != 0) 
 665       cerr 
<< "FATAL -> Could not set close on exec " << strerror(errno
) << endl
; 
 670 // SetNonBlock - Set the nonblocking flag                               /*{{{*/ 
 671 // --------------------------------------------------------------------- 
 673 void SetNonBlock(int Fd
,bool Block
) 
 675    int Flags 
= fcntl(Fd
,F_GETFL
) & (~O_NONBLOCK
); 
 676    if (fcntl(Fd
,F_SETFL
,Flags 
| ((Block 
== false)?0:O_NONBLOCK
)) != 0) 
 678       cerr 
<< "FATAL -> Could not set non-blocking flag " << strerror(errno
) << endl
; 
 683 // WaitFd - Wait for a FD to become readable                            /*{{{*/ 
 684 // --------------------------------------------------------------------- 
 685 /* This waits for a FD to become readable using select. It is useful for 
 686    applications making use of non-blocking sockets. The timeout is  
 688 bool WaitFd(int Fd
,bool write
,unsigned long timeout
) 
 701          Res 
= select(Fd
+1,0,&Set
,0,(timeout 
!= 0?&tv
:0)); 
 703       while (Res 
< 0 && errno 
== EINTR
); 
 713          Res 
= select(Fd
+1,&Set
,0,0,(timeout 
!= 0?&tv
:0)); 
 715       while (Res 
< 0 && errno 
== EINTR
); 
 724 // MergeKeepFdsFromConfiguration - Merge APT::Keep-Fds configuration    /*{{{*/ 
 725 // --------------------------------------------------------------------- 
 726 /* This is used to merge the APT::Keep-Fds with the provided KeepFDs 
 729 void MergeKeepFdsFromConfiguration(std::set
<int> &KeepFDs
) 
 731       Configuration::Item 
const *Opts 
= _config
->Tree("APT::Keep-Fds"); 
 732       if (Opts 
!= 0 && Opts
->Child 
!= 0) 
 735          for (; Opts 
!= 0; Opts 
= Opts
->Next
) 
 737             if (Opts
->Value
.empty() == true) 
 739             int fd 
= atoi(Opts
->Value
.c_str()); 
 745 // ExecFork - Magical fork that sanitizes the context before execing    /*{{{*/ 
 746 // --------------------------------------------------------------------- 
 747 /* This is used if you want to cleanse the environment for the forked  
 748    child, it fixes up the important signals and nukes all of the fds, 
 749    otherwise acts like normal fork. */ 
 753       // we need to merge the Keep-Fds as external tools like  
 754       // debconf-apt-progress use it 
 755       MergeKeepFdsFromConfiguration(KeepFDs
); 
 756       return ExecFork(KeepFDs
); 
 759 pid_t 
ExecFork(std::set
<int> KeepFDs
) 
 761    // Fork off the process 
 762    pid_t Process 
= fork(); 
 765       cerr 
<< "FATAL -> Failed to fork." << endl
; 
 769    // Spawn the subprocess 
 773       signal(SIGPIPE
,SIG_DFL
); 
 774       signal(SIGQUIT
,SIG_DFL
); 
 775       signal(SIGINT
,SIG_DFL
); 
 776       signal(SIGWINCH
,SIG_DFL
); 
 777       signal(SIGCONT
,SIG_DFL
); 
 778       signal(SIGTSTP
,SIG_DFL
); 
 780       // Close all of our FDs - just in case 
 781       for (int K 
= 3; K 
!= sysconf(_SC_OPEN_MAX
); K
++) 
 783          if(KeepFDs
.find(K
) == KeepFDs
.end()) 
 784             fcntl(K
,F_SETFD
,FD_CLOEXEC
); 
 791 // ExecWait - Fancy waitpid                                             /*{{{*/ 
 792 // --------------------------------------------------------------------- 
 793 /* Waits for the given sub process. If Reap is set then no errors are  
 794    generated. Otherwise a failed subprocess will generate a proper descriptive 
 796 bool ExecWait(pid_t Pid
,const char *Name
,bool Reap
) 
 801    // Wait and collect the error code 
 803    while (waitpid(Pid
,&Status
,0) != Pid
) 
 811       return _error
->Error(_("Waited for %s but it wasn't there"),Name
); 
 815    // Check for an error code. 
 816    if (WIFEXITED(Status
) == 0 || WEXITSTATUS(Status
) != 0) 
 820       if (WIFSIGNALED(Status
) != 0) 
 822          if( WTERMSIG(Status
) == SIGSEGV
) 
 823             return _error
->Error(_("Sub-process %s received a segmentation fault."),Name
); 
 825             return _error
->Error(_("Sub-process %s received signal %u."),Name
, WTERMSIG(Status
)); 
 828       if (WIFEXITED(Status
) != 0) 
 829          return _error
->Error(_("Sub-process %s returned an error code (%u)"),Name
,WEXITSTATUS(Status
)); 
 831       return _error
->Error(_("Sub-process %s exited unexpectedly"),Name
); 
 838 class FileFdPrivate 
{                                                   /*{{{*/ 
 849            uint8_t buffer
[4096]; 
 855            LZMAFILE() : file(NULL
), eof(false), compressing(false) {} 
 857               if (compressing 
== true) 
 860                         stream
.avail_out 
= sizeof(buffer
)/sizeof(buffer
[0]); 
 861                         stream
.next_out 
= buffer
; 
 862                         err 
= lzma_code(&stream
, LZMA_FINISH
); 
 863                         if (err 
!= LZMA_OK 
&& err 
!= LZMA_STREAM_END
) 
 865                                 _error
->Error("~LZMAFILE: Compress finalisation failed"); 
 868                         size_t const n 
=  sizeof(buffer
)/sizeof(buffer
[0]) - stream
.avail_out
; 
 869                         if (n 
&& fwrite(buffer
, 1, n
, file
) != n
) 
 871                                 _error
->Errno("~LZMAFILE",_("Write error")); 
 874                         if (err 
== LZMA_STREAM_END
) 
 885         pid_t compressor_pid
; 
 887         APT::Configuration::Compressor compressor
; 
 888         unsigned int openmode
; 
 889         unsigned long long seekpos
; 
 900                           compressed_fd(-1), compressor_pid(-1), pipe(false), 
 901                           openmode(0), seekpos(0) {}; 
 902         bool InternalClose(std::string 
const &FileName
) 
 905               /* dummy so that the rest can be 'else if's */; 
 907            else if (gz 
!= NULL
) { 
 908               int const e 
= gzclose(gz
); 
 910               // gzdclose() on empty files always fails with "buffer error" here, ignore that 
 911               if (e 
!= 0 && e 
!= Z_BUF_ERROR
) 
 912                  return _error
->Errno("close",_("Problem closing the gzip file %s"), FileName
.c_str()); 
 916            else if (bz2 
!= NULL
) { 
 922            else if (lzma 
!= NULL
) { 
 929         bool CloseDown(std::string 
const &FileName
) 
 931            bool const Res 
= InternalClose(FileName
); 
 933            if (compressor_pid 
> 0) 
 934               ExecWait(compressor_pid
, "FileFdCompressor", true); 
 939         bool InternalStream() const { 
 951         ~FileFdPrivate() { CloseDown(""); } 
 954 // FileFd::Open - Open a file                                           /*{{{*/ 
 955 // --------------------------------------------------------------------- 
 956 /* The most commonly used open mode combinations are given with Mode */ 
 957 bool FileFd::Open(string FileName
,unsigned int const Mode
,CompressMode Compress
, unsigned long const Perms
) 
 959    if (Mode 
== ReadOnlyGzip
) 
 960       return Open(FileName
, ReadOnly
, Gzip
, Perms
); 
 962    if (Compress 
== Auto 
&& (Mode 
& WriteOnly
) == WriteOnly
) 
 963       return FileFdError("Autodetection on %s only works in ReadOnly openmode!", FileName
.c_str()); 
 965    std::vector
<APT::Configuration::Compressor
> const compressors 
= APT::Configuration::getCompressors(); 
 966    std::vector
<APT::Configuration::Compressor
>::const_iterator compressor 
= compressors
.begin(); 
 967    if (Compress 
== Auto
) 
 969       for (; compressor 
!= compressors
.end(); ++compressor
) 
 971          std::string file 
= FileName 
+ compressor
->Extension
; 
 972          if (FileExists(file
) == false) 
 978    else if (Compress 
== Extension
) 
 980       std::string::size_type 
const found 
= FileName
.find_last_of('.'); 
 982       if (found 
!= std::string::npos
) 
 984          ext 
= FileName
.substr(found
); 
 985          if (ext 
== ".new" || ext 
== ".bak") 
 987             std::string::size_type 
const found2 
= FileName
.find_last_of('.', found 
- 1); 
 988             if (found2 
!= std::string::npos
) 
 989                ext 
= FileName
.substr(found2
, found 
- found2
); 
 994       for (; compressor 
!= compressors
.end(); ++compressor
) 
 995          if (ext 
== compressor
->Extension
) 
 997       // no matching extension - assume uncompressed (imagine files like 'example.org_Packages') 
 998       if (compressor 
== compressors
.end()) 
 999          for (compressor 
= compressors
.begin(); compressor 
!= compressors
.end(); ++compressor
) 
1000             if (compressor
->Name 
== ".") 
1008       case None
: name 
= "."; break; 
1009       case Gzip
: name 
= "gzip"; break; 
1010       case Bzip2
: name 
= "bzip2"; break; 
1011       case Lzma
: name 
= "lzma"; break; 
1012       case Xz
: name 
= "xz"; break; 
1016          return FileFdError("Opening File %s in None, Auto or Extension should be already handled?!?", FileName
.c_str()); 
1018       for (; compressor 
!= compressors
.end(); ++compressor
) 
1019          if (compressor
->Name 
== name
) 
1021       if (compressor 
== compressors
.end()) 
1022          return FileFdError("Can't find a configured compressor %s for file %s", name
.c_str(), FileName
.c_str()); 
1025    if (compressor 
== compressors
.end()) 
1026       return FileFdError("Can't find a match for specified compressor mode for file %s", FileName
.c_str()); 
1027    return Open(FileName
, Mode
, *compressor
, Perms
); 
1029 bool FileFd::Open(string FileName
,unsigned int const Mode
,APT::Configuration::Compressor 
const &compressor
, unsigned long const Perms
) 
1034    if ((Mode 
& WriteOnly
) != WriteOnly 
&& (Mode 
& (Atomic 
| Create 
| Empty 
| Exclusive
)) != 0) 
1035       return FileFdError("ReadOnly mode for %s doesn't accept additional flags!", FileName
.c_str()); 
1036    if ((Mode 
& ReadWrite
) == 0) 
1037       return FileFdError("No openmode provided in FileFd::Open for %s", FileName
.c_str()); 
1039    if ((Mode 
& Atomic
) == Atomic
) 
1043    else if ((Mode 
& (Exclusive 
| Create
)) == (Exclusive 
| Create
)) 
1045       // for atomic, this will be done by rename in Close() 
1046       unlink(FileName
.c_str()); 
1048    if ((Mode 
& Empty
) == Empty
) 
1051       if (lstat(FileName
.c_str(),&Buf
) == 0 && S_ISLNK(Buf
.st_mode
)) 
1052          unlink(FileName
.c_str()); 
1056    #define if_FLAGGED_SET(FLAG, MODE) if ((Mode & FLAG) == FLAG) fileflags |= MODE 
1057    if_FLAGGED_SET(ReadWrite
, O_RDWR
); 
1058    else if_FLAGGED_SET(ReadOnly
, O_RDONLY
); 
1059    else if_FLAGGED_SET(WriteOnly
, O_WRONLY
); 
1061    if_FLAGGED_SET(Create
, O_CREAT
); 
1062    if_FLAGGED_SET(Empty
, O_TRUNC
); 
1063    if_FLAGGED_SET(Exclusive
, O_EXCL
); 
1064    #undef if_FLAGGED_SET 
1066    if ((Mode 
& Atomic
) == Atomic
) 
1068       char *name 
= strdup((FileName 
+ ".XXXXXX").c_str()); 
1070       if((iFd 
= mkstemp(name
)) == -1) 
1073           return FileFdErrno("mkstemp", "Could not create temporary file for %s", FileName
.c_str()); 
1076       TemporaryFileName 
= string(name
); 
1079       if(Perms 
!= 600 && fchmod(iFd
, Perms
) == -1) 
1080           return FileFdErrno("fchmod", "Could not change permissions for temporary file %s", TemporaryFileName
.c_str()); 
1083       iFd 
= open(FileName
.c_str(), fileflags
, Perms
); 
1085    this->FileName 
= FileName
; 
1086    if (iFd 
== -1 || OpenInternDescriptor(Mode
, compressor
) == false) 
1093       return FileFdErrno("open",_("Could not open file %s"), FileName
.c_str()); 
1096    SetCloseExec(iFd
,true); 
1100 // FileFd::OpenDescriptor - Open a filedescriptor                       /*{{{*/ 
1101 // --------------------------------------------------------------------- 
1103 bool FileFd::OpenDescriptor(int Fd
, unsigned int const Mode
, CompressMode Compress
, bool AutoClose
) 
1105    std::vector
<APT::Configuration::Compressor
> const compressors 
= APT::Configuration::getCompressors(); 
1106    std::vector
<APT::Configuration::Compressor
>::const_iterator compressor 
= compressors
.begin(); 
1109    // compat with the old API 
1110    if (Mode 
== ReadOnlyGzip 
&& Compress 
== None
) 
1115    case None
: name 
= "."; break; 
1116    case Gzip
: name 
= "gzip"; break; 
1117    case Bzip2
: name 
= "bzip2"; break; 
1118    case Lzma
: name 
= "lzma"; break; 
1119    case Xz
: name 
= "xz"; break; 
1122       if (AutoClose 
== true && Fd 
!= -1) 
1124       return FileFdError("Opening Fd %d in Auto or Extension compression mode is not supported", Fd
); 
1126    for (; compressor 
!= compressors
.end(); ++compressor
) 
1127       if (compressor
->Name 
== name
) 
1129    if (compressor 
== compressors
.end()) 
1131       if (AutoClose 
== true && Fd 
!= -1) 
1133       return FileFdError("Can't find a configured compressor %s for file %s", name
.c_str(), FileName
.c_str()); 
1135    return OpenDescriptor(Fd
, Mode
, *compressor
, AutoClose
); 
1137 bool FileFd::OpenDescriptor(int Fd
, unsigned int const Mode
, APT::Configuration::Compressor 
const &compressor
, bool AutoClose
) 
1140    Flags 
= (AutoClose
) ? FileFd::AutoClose 
: 0; 
1142    this->FileName 
= ""; 
1143    if (OpenInternDescriptor(Mode
, compressor
) == false) 
1146         (Flags 
& Compressed
) == Compressed 
|| 
1152       return FileFdError(_("Could not open file descriptor %d"), Fd
); 
1156 bool FileFd::OpenInternDescriptor(unsigned int const Mode
, APT::Configuration::Compressor 
const &compressor
) 
1160    if (compressor
.Name 
== "." || compressor
.Binary
.empty() == true) 
1163 #if defined HAVE_ZLIB || defined HAVE_BZ2 || defined HAVE_LZMA 
1164    // the API to open files is similar, so setup to avoid code duplicates later 
1165    // and while at it ensure that we close before opening (if its a reopen) 
1166    void* (*compress_open
)(int, const char *) = NULL
; 
1168       /* dummy so that the rest can be 'else if's */; 
1169 #define APT_COMPRESS_INIT(NAME,OPEN) \ 
1170    else if (compressor.Name == NAME) \ 
1172       compress_open = (void*(*)(int, const char *)) OPEN; \ 
1173       if (d != NULL) d->InternalClose(FileName); \ 
1176    APT_COMPRESS_INIT("gzip", gzdopen
) 
1179    APT_COMPRESS_INIT("bzip2", BZ2_bzdopen
) 
1182    APT_COMPRESS_INIT("xz", fdopen
) 
1183    APT_COMPRESS_INIT("lzma", fdopen
) 
1185 #undef APT_COMPRESS_INIT 
1190       d 
= new FileFdPrivate(); 
1192       d
->compressor 
= compressor
; 
1193 #if defined HAVE_ZLIB || defined HAVE_BZ2 || defined HAVE_LZMA 
1194       if (AutoClose 
== false && compress_open 
!= NULL
) 
1196          // Need to duplicate fd here or gz/bz2 close for cleanup will close the fd as well 
1197          int const internFd 
= dup(iFd
); 
1199             return FileFdErrno("OpenInternDescriptor", _("Could not open file descriptor %d"), iFd
); 
1205 #if defined HAVE_ZLIB || defined HAVE_BZ2 || defined HAVE_LZMA 
1206    if (compress_open 
!= NULL
) 
1208       void* compress_struct 
= NULL
; 
1209       if ((Mode 
& ReadWrite
) == ReadWrite
) 
1210          compress_struct 
= compress_open(iFd
, "r+"); 
1211       else if ((Mode 
& WriteOnly
) == WriteOnly
) 
1212          compress_struct 
= compress_open(iFd
, "w"); 
1214          compress_struct 
= compress_open(iFd
, "r"); 
1215       if (compress_struct 
== NULL
) 
1219          /* dummy so that the rest can be 'else if's */; 
1221       else if (compressor
.Name 
== "gzip") 
1222          d
->gz 
= (gzFile
) compress_struct
; 
1225       else if (compressor
.Name 
== "bzip2") 
1226          d
->bz2 
= (BZFILE
*) compress_struct
; 
1229       else if (compressor
.Name 
== "xz" || compressor
.Name 
== "lzma") 
1231          uint32_t const xzlevel 
= 6; 
1232          uint64_t const memlimit 
= UINT64_MAX
; 
1233          if (d
->lzma 
== NULL
) 
1234             d
->lzma 
= new FileFdPrivate::LZMAFILE
; 
1235          d
->lzma
->file 
= (FILE*) compress_struct
; 
1236          d
->lzma
->stream 
= LZMA_STREAM_INIT
; 
1238          if ((Mode 
& ReadWrite
) == ReadWrite
) 
1239             return FileFdError("ReadWrite mode is not supported for file %s", FileName
.c_str()); 
1241          if ((Mode 
& WriteOnly
) == WriteOnly
) 
1243             if (compressor
.Name 
== "xz") 
1245                if (lzma_easy_encoder(&d
->lzma
->stream
, xzlevel
, LZMA_CHECK_CRC32
) != LZMA_OK
) 
1250                lzma_options_lzma options
; 
1251                lzma_lzma_preset(&options
, xzlevel
); 
1252                if (lzma_alone_encoder(&d
->lzma
->stream
, &options
) != LZMA_OK
) 
1255             d
->lzma
->compressing 
= true; 
1259             if (compressor
.Name 
== "xz") 
1261                if (lzma_auto_decoder(&d
->lzma
->stream
, memlimit
, 0) != LZMA_OK
) 
1266                if (lzma_alone_decoder(&d
->lzma
->stream
, memlimit
) != LZMA_OK
) 
1269             d
->lzma
->compressing 
= false; 
1273       Flags 
|= Compressed
; 
1278    // collect zombies here in case we reopen 
1279    if (d
->compressor_pid 
> 0) 
1280       ExecWait(d
->compressor_pid
, "FileFdCompressor", true); 
1282    if ((Mode 
& ReadWrite
) == ReadWrite
) 
1283       return FileFdError("ReadWrite mode is not supported for file %s", FileName
.c_str()); 
1285    bool const Comp 
= (Mode 
& WriteOnly
) == WriteOnly
; 
1288       // Handle 'decompression' of empty files 
1291       if (Buf
.st_size 
== 0 && S_ISFIFO(Buf
.st_mode
) == false) 
1294       // We don't need the file open - instead let the compressor open it 
1295       // as he properly knows better how to efficiently read from 'his' file 
1296       if (FileName
.empty() == false) 
1303    // Create a data pipe 
1304    int Pipe
[2] = {-1,-1}; 
1305    if (pipe(Pipe
) != 0) 
1306       return FileFdErrno("pipe",_("Failed to create subprocess IPC")); 
1307    for (int J 
= 0; J 
!= 2; J
++) 
1308       SetCloseExec(Pipe
[J
],true); 
1310    d
->compressed_fd 
= iFd
; 
1319    d
->compressor_pid 
= ExecFork(); 
1320    if (d
->compressor_pid 
== 0) 
1324          dup2(d
->compressed_fd
,STDOUT_FILENO
); 
1325          dup2(Pipe
[0],STDIN_FILENO
); 
1329          if (d
->compressed_fd 
!= -1) 
1330             dup2(d
->compressed_fd
,STDIN_FILENO
); 
1331          dup2(Pipe
[1],STDOUT_FILENO
); 
1333       int const nullfd 
= open("/dev/null", O_WRONLY
); 
1336          dup2(nullfd
,STDERR_FILENO
); 
1340       SetCloseExec(STDOUT_FILENO
,false); 
1341       SetCloseExec(STDIN_FILENO
,false); 
1343       std::vector
<char const*> Args
; 
1344       Args
.push_back(compressor
.Binary
.c_str()); 
1345       std::vector
<std::string
> const * const addArgs 
= 
1346                 (Comp 
== true) ? &(compressor
.CompressArgs
) : &(compressor
.UncompressArgs
); 
1347       for (std::vector
<std::string
>::const_iterator a 
= addArgs
->begin(); 
1348            a 
!= addArgs
->end(); ++a
) 
1349          Args
.push_back(a
->c_str()); 
1350       if (Comp 
== false && FileName
.empty() == false) 
1352          Args
.push_back("--stdout"); 
1353          if (TemporaryFileName
.empty() == false) 
1354             Args
.push_back(TemporaryFileName
.c_str()); 
1356             Args
.push_back(FileName
.c_str()); 
1358       Args
.push_back(NULL
); 
1360       execvp(Args
[0],(char **)&Args
[0]); 
1361       cerr 
<< _("Failed to exec compressor ") << Args
[0] << endl
; 
1372 // FileFd::~File - Closes the file                                      /*{{{*/ 
1373 // --------------------------------------------------------------------- 
1374 /* If the proper modes are selected then we close the Fd and possibly 
1375    unlink the file on error. */ 
1380       d
->CloseDown(FileName
); 
1385 // FileFd::Read - Read a bit of the file                                /*{{{*/ 
1386 // --------------------------------------------------------------------- 
1387 /* We are careful to handle interruption by a signal while reading 
1389 bool FileFd::Read(void *To
,unsigned long long Size
,unsigned long long *Actual
) 
1395    *((char *)To
) = '\0'; 
1399          /* dummy so that the rest can be 'else if's */; 
1401       else if (d 
!= NULL 
&& d
->gz 
!= NULL
) 
1402          Res 
= gzread(d
->gz
,To
,Size
); 
1405       else if (d 
!= NULL 
&& d
->bz2 
!= NULL
) 
1406          Res 
= BZ2_bzread(d
->bz2
,To
,Size
); 
1409       else if (d 
!= NULL 
&& d
->lzma 
!= NULL
) 
1411          if (d
->lzma
->eof 
== true) 
1414          d
->lzma
->stream
.next_out 
= (uint8_t *) To
; 
1415          d
->lzma
->stream
.avail_out 
= Size
; 
1416          if (d
->lzma
->stream
.avail_in 
== 0) 
1418             d
->lzma
->stream
.next_in 
= d
->lzma
->buffer
; 
1419             d
->lzma
->stream
.avail_in 
= fread(d
->lzma
->buffer
, 1, sizeof(d
->lzma
->buffer
)/sizeof(d
->lzma
->buffer
[0]), d
->lzma
->file
); 
1421          d
->lzma
->err 
= lzma_code(&d
->lzma
->stream
, LZMA_RUN
); 
1422          if (d
->lzma
->err 
== LZMA_STREAM_END
) 
1424             d
->lzma
->eof 
= true; 
1425             Res 
= Size 
- d
->lzma
->stream
.avail_out
; 
1427          else if (d
->lzma
->err 
!= LZMA_OK
) 
1433             Res 
= Size 
- d
->lzma
->stream
.avail_out
; 
1437          Res 
= read(iFd
,To
,Size
); 
1444             /* dummy so that the rest can be 'else if's */; 
1446          else if (d 
!= NULL 
&& d
->gz 
!= NULL
) 
1449             char const * const errmsg 
= gzerror(d
->gz
, &err
); 
1451                return FileFdError("gzread: %s (%d: %s)", _("Read error"), err
, errmsg
); 
1455          else if (d 
!= NULL 
&& d
->bz2 
!= NULL
) 
1458             char const * const errmsg 
= BZ2_bzerror(d
->bz2
, &err
); 
1459             if (err 
!= BZ_IO_ERROR
) 
1460                return FileFdError("BZ2_bzread: %s (%d: %s)", _("Read error"), err
, errmsg
); 
1464          else if (d 
!= NULL 
&& d
->lzma 
!= NULL
) 
1465             return FileFdError("lzma_read: %s (%d)", _("Read error"), d
->lzma
->err
); 
1467          return FileFdErrno("read",_("Read error")); 
1470       To 
= (char *)To 
+ Res
; 
1477    while (Res 
> 0 && Size 
> 0); 
1489    return FileFdError(_("read, still have %llu to read but none left"), Size
); 
1492 // FileFd::ReadLine - Read a complete line from the file                /*{{{*/ 
1493 // --------------------------------------------------------------------- 
1494 /* Beware: This method can be quiet slow for big buffers on UNcompressed 
1495    files because of the naive implementation! */ 
1496 char* FileFd::ReadLine(char *To
, unsigned long long const Size
) 
1500    if (d 
!= NULL 
&& d
->gz 
!= NULL
) 
1501       return gzgets(d
->gz
, To
, Size
); 
1504    unsigned long long read 
= 0; 
1505    while ((Size 
- 1) != read
) 
1507       unsigned long long done 
= 0; 
1508       if (Read(To 
+ read
, 1, &done
) == false) 
1512       if (To
[read
++] == '\n') 
1521 // FileFd::Write - Write to the file                                    /*{{{*/ 
1522 // --------------------------------------------------------------------- 
1524 bool FileFd::Write(const void *From
,unsigned long long Size
) 
1531          /* dummy so that the rest can be 'else if's */; 
1533       else if (d 
!= NULL 
&& d
->gz 
!= NULL
) 
1534          Res 
= gzwrite(d
->gz
,From
,Size
); 
1537       else if (d 
!= NULL 
&& d
->bz2 
!= NULL
) 
1538          Res 
= BZ2_bzwrite(d
->bz2
,(void*)From
,Size
); 
1541       else if (d 
!= NULL 
&& d
->lzma 
!= NULL
) 
1543          d
->lzma
->stream
.next_in 
= (uint8_t *)From
; 
1544          d
->lzma
->stream
.avail_in 
= Size
; 
1545          d
->lzma
->stream
.next_out 
= d
->lzma
->buffer
; 
1546          d
->lzma
->stream
.avail_out 
= sizeof(d
->lzma
->buffer
)/sizeof(d
->lzma
->buffer
[0]); 
1547          d
->lzma
->err 
= lzma_code(&d
->lzma
->stream
, LZMA_RUN
); 
1548          if (d
->lzma
->err 
!= LZMA_OK
) 
1550          size_t const n 
= sizeof(d
->lzma
->buffer
)/sizeof(d
->lzma
->buffer
[0]) - d
->lzma
->stream
.avail_out
; 
1551          size_t const m 
= (n 
== 0) ? 0 : fwrite(d
->lzma
->buffer
, 1, n
, d
->lzma
->file
); 
1555             Res 
= Size 
- d
->lzma
->stream
.avail_in
; 
1559          Res 
= write(iFd
,From
,Size
); 
1561       if (Res 
< 0 && errno 
== EINTR
) 
1566             /* dummy so that the rest can be 'else if's */; 
1568          else if (d 
!= NULL 
&& d
->gz 
!= NULL
) 
1571             char const * const errmsg 
= gzerror(d
->gz
, &err
); 
1573                return FileFdError("gzwrite: %s (%d: %s)", _("Write error"), err
, errmsg
); 
1577          else if (d 
!= NULL 
&& d
->bz2 
!= NULL
) 
1580             char const * const errmsg 
= BZ2_bzerror(d
->bz2
, &err
); 
1581             if (err 
!= BZ_IO_ERROR
) 
1582                return FileFdError("BZ2_bzwrite: %s (%d: %s)", _("Write error"), err
, errmsg
); 
1586          else if (d 
!= NULL 
&& d
->lzma 
!= NULL
) 
1587             return FileFdErrno("lzma_fwrite", _("Write error")); 
1589          return FileFdErrno("write",_("Write error")); 
1592       From 
= (char const *)From 
+ Res
; 
1597    while (Res 
> 0 && Size 
> 0); 
1602    return FileFdError(_("write, still have %llu to write but couldn't"), Size
); 
1604 bool FileFd::Write(int Fd
, const void *From
, unsigned long long Size
) 
1610       Res 
= write(Fd
,From
,Size
); 
1611       if (Res 
< 0 && errno 
== EINTR
) 
1614          return _error
->Errno("write",_("Write error")); 
1616       From 
= (char const *)From 
+ Res
; 
1619    while (Res 
> 0 && Size 
> 0); 
1624    return _error
->Error(_("write, still have %llu to write but couldn't"), Size
); 
1627 // FileFd::Seek - Seek in the file                                      /*{{{*/ 
1628 // --------------------------------------------------------------------- 
1630 bool FileFd::Seek(unsigned long long To
) 
1632    if (d 
!= NULL 
&& (d
->pipe 
== true || d
->InternalStream() == true)) 
1634       // Our poor man seeking in pipes is costly, so try to avoid it 
1635       unsigned long long seekpos 
= Tell(); 
1638       else if (seekpos 
< To
) 
1639          return Skip(To 
- seekpos
); 
1641       if ((d
->openmode 
& ReadOnly
) != ReadOnly
) 
1642          return FileFdError("Reopen is only implemented for read-only files!"); 
1643       d
->InternalClose(FileName
); 
1647       if (TemporaryFileName
.empty() == false) 
1648          iFd 
= open(TemporaryFileName
.c_str(), O_RDONLY
); 
1649       else if (FileName
.empty() == false) 
1650          iFd 
= open(FileName
.c_str(), O_RDONLY
); 
1653          if (d
->compressed_fd 
> 0) 
1654             if (lseek(d
->compressed_fd
, 0, SEEK_SET
) != 0) 
1655                iFd 
= d
->compressed_fd
; 
1657             return FileFdError("Reopen is not implemented for pipes opened with FileFd::OpenDescriptor()!"); 
1660       if (OpenInternDescriptor(d
->openmode
, d
->compressor
) == false) 
1661          return FileFdError("Seek on file %s because it couldn't be reopened", FileName
.c_str()); 
1671    if (d 
!= NULL 
&& d
->gz
) 
1672       res 
= gzseek(d
->gz
,To
,SEEK_SET
); 
1675       res 
= lseek(iFd
,To
,SEEK_SET
); 
1676    if (res 
!= (off_t
)To
) 
1677       return FileFdError("Unable to seek to %llu", To
); 
1684 // FileFd::Skip - Seek in the file                                      /*{{{*/ 
1685 // --------------------------------------------------------------------- 
1687 bool FileFd::Skip(unsigned long long Over
) 
1689    if (d 
!= NULL 
&& (d
->pipe 
== true || d
->InternalStream() == true)) 
1695          unsigned long long toread 
= std::min((unsigned long long) sizeof(buffer
), Over
); 
1696          if (Read(buffer
, toread
) == false) 
1697             return FileFdError("Unable to seek ahead %llu",Over
); 
1705    if (d 
!= NULL 
&& d
->gz 
!= NULL
) 
1706       res 
= gzseek(d
->gz
,Over
,SEEK_CUR
); 
1709       res 
= lseek(iFd
,Over
,SEEK_CUR
); 
1711       return FileFdError("Unable to seek ahead %llu",Over
); 
1718 // FileFd::Truncate - Truncate the file                                 /*{{{*/ 
1719 // --------------------------------------------------------------------- 
1721 bool FileFd::Truncate(unsigned long long To
) 
1723    // truncating /dev/null is always successful - as we get an error otherwise 
1724    if (To 
== 0 && FileName 
== "/dev/null") 
1726 #if defined HAVE_ZLIB || defined HAVE_BZ2 || defined HAVE_LZMA 
1727    if (d 
!= NULL 
&& (d
->InternalStream() == true 
1732       return FileFdError("Truncating compressed files is not implemented (%s)", FileName
.c_str()); 
1734    if (ftruncate(iFd
,To
) != 0) 
1735       return FileFdError("Unable to truncate to %llu",To
); 
1740 // FileFd::Tell - Current seek position                                 /*{{{*/ 
1741 // --------------------------------------------------------------------- 
1743 unsigned long long FileFd::Tell() 
1745    // In theory, we could just return seekpos here always instead of 
1746    // seeking around, but not all users of FileFd use always Seek() and co 
1747    // so d->seekpos isn't always true and we can just use it as a hint if 
1748    // we have nothing else, but not always as an authority… 
1749    if (d 
!= NULL 
&& (d
->pipe 
== true || d
->InternalStream() == true)) 
1754    if (d 
!= NULL 
&& d
->gz 
!= NULL
) 
1755      Res 
= gztell(d
->gz
); 
1758      Res 
= lseek(iFd
,0,SEEK_CUR
); 
1759    if (Res 
== (off_t
)-1) 
1760       FileFdErrno("lseek","Failed to determine the current file position"); 
1766 static bool StatFileFd(char const * const msg
, int const iFd
, std::string 
const &FileName
, struct stat 
&Buf
, FileFdPrivate 
* const d
) /*{{{*/ 
1768    bool ispipe 
= (d 
!= NULL 
&& d
->pipe 
== true); 
1769    if (ispipe 
== false) 
1771       if (fstat(iFd
,&Buf
) != 0) 
1772          // higher-level code will generate more meaningful messages, 
1773          // even translated this would be meaningless for users 
1774          return _error
->Errno("fstat", "Unable to determine %s for fd %i", msg
, iFd
); 
1775       ispipe 
= S_ISFIFO(Buf
.st_mode
); 
1778    // for compressor pipes st_size is undefined and at 'best' zero 
1781       // we set it here, too, as we get the info here for free 
1782       // in theory the Open-methods should take care of it already 
1785       if (stat(FileName
.c_str(), &Buf
) != 0) 
1786          return _error
->Errno("fstat", "Unable to determine %s for file %s", msg
, FileName
.c_str()); 
1791 // FileFd::FileSize - Return the size of the file                       /*{{{*/ 
1792 unsigned long long FileFd::FileSize() 
1795    if (StatFileFd("file size", iFd
, FileName
, Buf
, d
) == false) 
1803 // FileFd::ModificationTime - Return the time of last touch             /*{{{*/ 
1804 time_t FileFd::ModificationTime() 
1807    if (StatFileFd("modification time", iFd
, FileName
, Buf
, d
) == false) 
1812    return Buf
.st_mtime
; 
1815 // FileFd::Size - Return the size of the content in the file            /*{{{*/ 
1816 // --------------------------------------------------------------------- 
1818 unsigned long long FileFd::Size() 
1820    unsigned long long size 
= FileSize(); 
1822    // for compressor pipes st_size is undefined and at 'best' zero, 
1823    // so we 'read' the content and 'seek' back - see there 
1824    if (d 
!= NULL 
&& (d
->pipe 
== true || (d
->InternalStream() == true && size 
> 0))) 
1826       unsigned long long const oldSeek 
= Tell(); 
1828       unsigned long long read 
= 0; 
1830          if (Read(ignore
, sizeof(ignore
), &read
) == false) 
1840    // only check gzsize if we are actually a gzip file, just checking for 
1841    // "gz" is not sufficient as uncompressed files could be opened with 
1842    // gzopen in "direct" mode as well 
1843    else if (d 
!= NULL 
&& d
->gz 
&& !gzdirect(d
->gz
) && size 
> 0) 
1845        off_t 
const oldPos 
= lseek(iFd
,0,SEEK_CUR
); 
1846        /* unfortunately zlib.h doesn't provide a gzsize(), so we have to do 
1847         * this ourselves; the original (uncompressed) file size is the last 32 
1848         * bits of the file */ 
1849        // FIXME: Size for gz-files is limited by 32bit… no largefile support 
1850        if (lseek(iFd
, -4, SEEK_END
) < 0) 
1852           FileFdErrno("lseek","Unable to seek to end of gzipped file"); 
1856        if (read(iFd
, &size
, 4) != 4) 
1858           FileFdErrno("read","Unable to read original size of gzipped file"); 
1862 #ifdef WORDS_BIGENDIAN 
1863        uint32_t tmp_size 
= size
; 
1864        uint8_t const * const p 
= (uint8_t const * const) &tmp_size
; 
1865        tmp_size 
= (p
[3] << 24) | (p
[2] << 16) | (p
[1] << 8) | p
[0]; 
1869        if (lseek(iFd
, oldPos
, SEEK_SET
) < 0) 
1871           FileFdErrno("lseek","Unable to seek in gzipped file"); 
1882 // FileFd::Close - Close the file if the close flag is set              /*{{{*/ 
1883 // --------------------------------------------------------------------- 
1885 bool FileFd::Close() 
1891    if ((Flags 
& AutoClose
) == AutoClose
) 
1893       if ((Flags 
& Compressed
) != Compressed 
&& iFd 
> 0 && close(iFd
) != 0) 
1894          Res 
&= _error
->Errno("close",_("Problem closing the file %s"), FileName
.c_str()); 
1898          Res 
&= d
->CloseDown(FileName
); 
1904    if ((Flags 
& Replace
) == Replace
) { 
1905       if (rename(TemporaryFileName
.c_str(), FileName
.c_str()) != 0) 
1906          Res 
&= _error
->Errno("rename",_("Problem renaming the file %s to %s"), TemporaryFileName
.c_str(), FileName
.c_str()); 
1908       FileName 
= TemporaryFileName
; // for the unlink() below. 
1909       TemporaryFileName
.clear(); 
1914    if ((Flags 
& Fail
) == Fail 
&& (Flags 
& DelOnFail
) == DelOnFail 
&& 
1915        FileName
.empty() == false) 
1916       if (unlink(FileName
.c_str()) != 0) 
1917          Res 
&= _error
->WarningE("unlnk",_("Problem unlinking the file %s"), FileName
.c_str()); 
1924 // FileFd::Sync - Sync the file                                         /*{{{*/ 
1925 // --------------------------------------------------------------------- 
1929    if (fsync(iFd
) != 0) 
1930       return FileFdErrno("sync",_("Problem syncing the file")); 
1934 // FileFd::FileFdErrno - set Fail and call _error->Errno                *{{{*/ 
1935 bool FileFd::FileFdErrno(const char *Function
, const char *Description
,...) 
1939    size_t msgSize 
= 400; 
1940    int const errsv 
= errno
; 
1943       va_start(args
,Description
); 
1944       if (_error
->InsertErrno(GlobalError::ERROR
, Function
, Description
, args
, errsv
, msgSize
) == false) 
1951 // FileFd::FileFdError - set Fail and call _error->Error                *{{{*/ 
1952 bool FileFd::FileFdError(const char *Description
,...) { 
1955    size_t msgSize 
= 400; 
1958       va_start(args
,Description
); 
1959       if (_error
->Insert(GlobalError::ERROR
, Description
, args
, msgSize
) == false) 
1967 APT_DEPRECATED gzFile 
FileFd::gzFd() { 
1976 // Glob - wrapper around "glob()"                                      /*{{{*/ 
1977 // --------------------------------------------------------------------- 
1979 std::vector
<std::string
> Glob(std::string 
const &pattern
, int flags
) 
1981    std::vector
<std::string
> result
; 
1986    glob_res 
= glob(pattern
.c_str(),  flags
, NULL
, &globbuf
); 
1990       if(glob_res 
!= GLOB_NOMATCH
) { 
1991          _error
->Errno("glob", "Problem with glob"); 
1997    for(i
=0;i
<globbuf
.gl_pathc
;i
++) 
1998       result
.push_back(string(globbuf
.gl_pathv
[i
])); 
2005 std::string 
GetTempDir() 
2007    const char *tmpdir 
= getenv("TMPDIR"); 
2014    // check that tmpdir is set and exists 
2016    if (!tmpdir 
|| strlen(tmpdir
) == 0 || stat(tmpdir
, &st
) != 0) 
2019    return string(tmpdir
); 
2022 bool Rename(std::string From
, std::string To
) 
2024    if (rename(From
.c_str(),To
.c_str()) != 0) 
2026       _error
->Error(_("rename failed, %s (%s -> %s)."),strerror(errno
), 
2027                     From
.c_str(),To
.c_str());