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>
71 // RunScripts - Run a set of scripts from a configuration subtree /*{{{*/
72 // ---------------------------------------------------------------------
74 bool RunScripts(const char *Cnf
)
76 Configuration::Item
const *Opts
= _config
->Tree(Cnf
);
77 if (Opts
== 0 || Opts
->Child
== 0)
81 // Fork for running the system calls
82 pid_t Child
= ExecFork();
87 if (_config
->FindDir("DPkg::Chroot-Directory","/") != "/")
89 std::cerr
<< "Chrooting into "
90 << _config
->FindDir("DPkg::Chroot-Directory")
92 if (chroot(_config
->FindDir("DPkg::Chroot-Directory","/").c_str()) != 0)
96 if (chdir("/tmp/") != 0)
99 unsigned int Count
= 1;
100 for (; Opts
!= 0; Opts
= Opts
->Next
, Count
++)
102 if (Opts
->Value
.empty() == true)
105 if(_config
->FindB("Debug::RunScripts", false) == true)
106 std::clog
<< "Running external script: '"
107 << Opts
->Value
<< "'" << std::endl
;
109 if (system(Opts
->Value
.c_str()) != 0)
115 // Wait for the child
117 while (waitpid(Child
,&Status
,0) != Child
)
121 return _error
->Errno("waitpid","Couldn't wait for subprocess");
124 // Restore sig int/quit
125 signal(SIGQUIT
,SIG_DFL
);
126 signal(SIGINT
,SIG_DFL
);
128 // Check for an error code.
129 if (WIFEXITED(Status
) == 0 || WEXITSTATUS(Status
) != 0)
131 unsigned int Count
= WEXITSTATUS(Status
);
135 for (; Opts
!= 0 && Count
!= 1; Opts
= Opts
->Next
, Count
--);
136 _error
->Error("Problem executing scripts %s '%s'",Cnf
,Opts
->Value
.c_str());
139 return _error
->Error("Sub-process returned an error code");
146 // CopyFile - Buffered copy of a file /*{{{*/
147 // ---------------------------------------------------------------------
148 /* The caller is expected to set things so that failure causes erasure */
149 bool CopyFile(FileFd
&From
,FileFd
&To
)
151 if (From
.IsOpen() == false || To
.IsOpen() == false ||
152 From
.Failed() == true || To
.Failed() == true)
155 // Buffered copy between fds
156 SPtrArray
<unsigned char> Buf
= new unsigned char[64000];
157 unsigned long long Size
= From
.Size();
160 unsigned long long ToRead
= Size
;
164 if (From
.Read(Buf
,ToRead
) == false ||
165 To
.Write(Buf
,ToRead
) == false)
174 // GetLock - Gets a lock file /*{{{*/
175 // ---------------------------------------------------------------------
176 /* This will create an empty file of the given name and lock it. Once this
177 is done all other calls to GetLock in any other process will fail with
178 -1. The return result is the fd of the file, the call should call
179 close at some time. */
180 int GetLock(string File
,bool Errors
)
182 // GetLock() is used in aptitude on directories with public-write access
183 // Use O_NOFOLLOW here to prevent symlink traversal attacks
184 int FD
= open(File
.c_str(),O_RDWR
| O_CREAT
| O_NOFOLLOW
,0640);
187 // Read only .. can't have locking problems there.
190 _error
->Warning(_("Not using locking for read only lock file %s"),File
.c_str());
191 return dup(0); // Need something for the caller to close
195 _error
->Errno("open",_("Could not open lock file %s"),File
.c_str());
197 // Feh.. We do this to distinguish the lock vs open case..
201 SetCloseExec(FD
,true);
203 // Acquire a write lock
206 fl
.l_whence
= SEEK_SET
;
209 if (fcntl(FD
,F_SETLK
,&fl
) == -1)
211 // always close to not leak resources
218 _error
->Warning(_("Not using locking for nfs mounted lock file %s"),File
.c_str());
219 return dup(0); // Need something for the caller to close
223 _error
->Errno("open",_("Could not get lock %s"),File
.c_str());
231 // FileExists - Check if a file exists /*{{{*/
232 // ---------------------------------------------------------------------
233 /* Beware: Directories are also files! */
234 bool FileExists(string File
)
237 if (stat(File
.c_str(),&Buf
) != 0)
242 // RealFileExists - Check if a file exists and if it is really a file /*{{{*/
243 // ---------------------------------------------------------------------
245 bool RealFileExists(string File
)
248 if (stat(File
.c_str(),&Buf
) != 0)
250 return ((Buf
.st_mode
& S_IFREG
) != 0);
253 // DirectoryExists - Check if a directory exists and is really one /*{{{*/
254 // ---------------------------------------------------------------------
256 bool DirectoryExists(string
const &Path
)
259 if (stat(Path
.c_str(),&Buf
) != 0)
261 return ((Buf
.st_mode
& S_IFDIR
) != 0);
264 // CreateDirectory - poor man's mkdir -p guarded by a parent directory /*{{{*/
265 // ---------------------------------------------------------------------
266 /* This method will create all directories needed for path in good old
267 mkdir -p style but refuses to do this if Parent is not a prefix of
268 this Path. Example: /var/cache/ and /var/cache/apt/archives are given,
269 so it will create apt/archives if /var/cache exists - on the other
270 hand if the parent is /var/lib the creation will fail as this path
271 is not a parent of the path to be generated. */
272 bool CreateDirectory(string
const &Parent
, string
const &Path
)
274 if (Parent
.empty() == true || Path
.empty() == true)
277 if (DirectoryExists(Path
) == true)
280 if (DirectoryExists(Parent
) == false)
283 // we are not going to create directories "into the blue"
284 if (Path
.compare(0, Parent
.length(), Parent
) != 0)
287 vector
<string
> const dirs
= VectorizeString(Path
.substr(Parent
.size()), '/');
288 string progress
= Parent
;
289 for (vector
<string
>::const_iterator d
= dirs
.begin(); d
!= dirs
.end(); ++d
)
291 if (d
->empty() == true)
294 progress
.append("/").append(*d
);
295 if (DirectoryExists(progress
) == true)
298 if (mkdir(progress
.c_str(), 0755) != 0)
304 // CreateAPTDirectoryIfNeeded - ensure that the given directory exists /*{{{*/
305 // ---------------------------------------------------------------------
306 /* a small wrapper around CreateDirectory to check if it exists and to
307 remove the trailing "/apt/" from the parent directory if needed */
308 bool CreateAPTDirectoryIfNeeded(string
const &Parent
, string
const &Path
)
310 if (DirectoryExists(Path
) == true)
313 size_t const len
= Parent
.size();
314 if (len
> 5 && Parent
.find("/apt/", len
- 6, 5) == len
- 5)
316 if (CreateDirectory(Parent
.substr(0,len
-5), Path
) == true)
319 else if (CreateDirectory(Parent
, Path
) == true)
325 // GetListOfFilesInDir - returns a vector of files in the given dir /*{{{*/
326 // ---------------------------------------------------------------------
327 /* If an extension is given only files with this extension are included
328 in the returned vector, otherwise every "normal" file is included. */
329 std::vector
<string
> GetListOfFilesInDir(string
const &Dir
, string
const &Ext
,
330 bool const &SortList
, bool const &AllowNoExt
)
332 std::vector
<string
> ext
;
334 if (Ext
.empty() == false)
336 if (AllowNoExt
== true && ext
.empty() == false)
338 return GetListOfFilesInDir(Dir
, ext
, SortList
);
340 std::vector
<string
> GetListOfFilesInDir(string
const &Dir
, std::vector
<string
> const &Ext
,
341 bool const &SortList
)
343 // Attention debuggers: need to be set with the environment config file!
344 bool const Debug
= _config
->FindB("Debug::GetListOfFilesInDir", false);
347 std::clog
<< "Accept in " << Dir
<< " only files with the following " << Ext
.size() << " extensions:" << std::endl
;
348 if (Ext
.empty() == true)
349 std::clog
<< "\tNO extension" << std::endl
;
351 for (std::vector
<string
>::const_iterator e
= Ext
.begin();
353 std::clog
<< '\t' << (e
->empty() == true ? "NO" : *e
) << " extension" << std::endl
;
356 std::vector
<string
> List
;
358 if (DirectoryExists(Dir
) == false)
360 _error
->Error(_("List of files can't be created as '%s' is not a directory"), Dir
.c_str());
364 Configuration::MatchAgainstConfig
SilentIgnore("Dir::Ignore-Files-Silently");
365 DIR *D
= opendir(Dir
.c_str());
368 _error
->Errno("opendir",_("Unable to read %s"),Dir
.c_str());
372 for (struct dirent
*Ent
= readdir(D
); Ent
!= 0; Ent
= readdir(D
))
374 // skip "hidden" files
375 if (Ent
->d_name
[0] == '.')
378 // Make sure it is a file and not something else
379 string
const File
= flCombine(Dir
,Ent
->d_name
);
380 #ifdef _DIRENT_HAVE_D_TYPE
381 if (Ent
->d_type
!= DT_REG
)
384 if (RealFileExists(File
) == false)
386 // do not show ignoration warnings for directories
388 #ifdef _DIRENT_HAVE_D_TYPE
389 Ent
->d_type
== DT_DIR
||
391 DirectoryExists(File
) == true)
393 if (SilentIgnore
.Match(Ent
->d_name
) == false)
394 _error
->Notice(_("Ignoring '%s' in directory '%s' as it is not a regular file"), Ent
->d_name
, Dir
.c_str());
399 // check for accepted extension:
400 // no extension given -> periods are bad as hell!
401 // extensions given -> "" extension allows no extension
402 if (Ext
.empty() == false)
404 string d_ext
= flExtension(Ent
->d_name
);
405 if (d_ext
== Ent
->d_name
) // no extension
407 if (std::find(Ext
.begin(), Ext
.end(), "") == Ext
.end())
410 std::clog
<< "Bad file: " << Ent
->d_name
<< " → no extension" << std::endl
;
411 if (SilentIgnore
.Match(Ent
->d_name
) == false)
412 _error
->Notice(_("Ignoring file '%s' in directory '%s' as it has no filename extension"), Ent
->d_name
, Dir
.c_str());
416 else if (std::find(Ext
.begin(), Ext
.end(), d_ext
) == Ext
.end())
419 std::clog
<< "Bad file: " << Ent
->d_name
<< " → bad extension »" << flExtension(Ent
->d_name
) << "«" << std::endl
;
420 if (SilentIgnore
.Match(Ent
->d_name
) == false)
421 _error
->Notice(_("Ignoring file '%s' in directory '%s' as it has an invalid filename extension"), Ent
->d_name
, Dir
.c_str());
426 // Skip bad filenames ala run-parts
427 const char *C
= Ent
->d_name
;
429 if (isalpha(*C
) == 0 && isdigit(*C
) == 0
430 && *C
!= '_' && *C
!= '-' && *C
!= ':') {
431 // no required extension -> dot is a bad character
432 if (*C
== '.' && Ext
.empty() == false)
437 // we don't reach the end of the name -> bad character included
441 std::clog
<< "Bad file: " << Ent
->d_name
<< " → bad character »"
442 << *C
<< "« in filename (period allowed: " << (Ext
.empty() ? "no" : "yes") << ")" << std::endl
;
446 // skip filenames which end with a period. These are never valid
450 std::clog
<< "Bad file: " << Ent
->d_name
<< " → Period as last character" << std::endl
;
455 std::clog
<< "Accept file: " << Ent
->d_name
<< " in " << Dir
<< std::endl
;
456 List
.push_back(File
);
460 if (SortList
== true)
461 std::sort(List
.begin(),List
.end());
464 std::vector
<string
> GetListOfFilesInDir(string
const &Dir
, bool SortList
)
466 bool const Debug
= _config
->FindB("Debug::GetListOfFilesInDir", false);
468 std::clog
<< "Accept in " << Dir
<< " all regular files" << std::endl
;
470 std::vector
<string
> List
;
472 if (DirectoryExists(Dir
) == false)
474 _error
->Error(_("List of files can't be created as '%s' is not a directory"), Dir
.c_str());
478 DIR *D
= opendir(Dir
.c_str());
481 _error
->Errno("opendir",_("Unable to read %s"),Dir
.c_str());
485 for (struct dirent
*Ent
= readdir(D
); Ent
!= 0; Ent
= readdir(D
))
487 // skip "hidden" files
488 if (Ent
->d_name
[0] == '.')
491 // Make sure it is a file and not something else
492 string
const File
= flCombine(Dir
,Ent
->d_name
);
493 #ifdef _DIRENT_HAVE_D_TYPE
494 if (Ent
->d_type
!= DT_REG
)
497 if (RealFileExists(File
) == false)
500 std::clog
<< "Bad file: " << Ent
->d_name
<< " → it is not a real file" << std::endl
;
505 // Skip bad filenames ala run-parts
506 const char *C
= Ent
->d_name
;
508 if (isalpha(*C
) == 0 && isdigit(*C
) == 0
509 && *C
!= '_' && *C
!= '-' && *C
!= '.')
512 // we don't reach the end of the name -> bad character included
516 std::clog
<< "Bad file: " << Ent
->d_name
<< " → bad character »" << *C
<< "« in filename" << std::endl
;
520 // skip filenames which end with a period. These are never valid
524 std::clog
<< "Bad file: " << Ent
->d_name
<< " → Period as last character" << std::endl
;
529 std::clog
<< "Accept file: " << Ent
->d_name
<< " in " << Dir
<< std::endl
;
530 List
.push_back(File
);
534 if (SortList
== true)
535 std::sort(List
.begin(),List
.end());
539 // SafeGetCWD - This is a safer getcwd that returns a dynamic string /*{{{*/
540 // ---------------------------------------------------------------------
541 /* We return / on failure. */
544 // Stash the current dir.
547 if (getcwd(S
,sizeof(S
)-2) == 0)
549 unsigned int Len
= strlen(S
);
555 // GetModificationTime - Get the mtime of the given file or -1 on error /*{{{*/
556 // ---------------------------------------------------------------------
557 /* We return / on failure. */
558 time_t GetModificationTime(string
const &Path
)
561 if (stat(Path
.c_str(), &St
) < 0)
566 // flNotDir - Strip the directory from the filename /*{{{*/
567 // ---------------------------------------------------------------------
569 string
flNotDir(string File
)
571 string::size_type Res
= File
.rfind('/');
572 if (Res
== string::npos
)
575 return string(File
,Res
,Res
- File
.length());
578 // flNotFile - Strip the file from the directory name /*{{{*/
579 // ---------------------------------------------------------------------
580 /* Result ends in a / */
581 string
flNotFile(string File
)
583 string::size_type Res
= File
.rfind('/');
584 if (Res
== string::npos
)
587 return string(File
,0,Res
);
590 // flExtension - Return the extension for the file /*{{{*/
591 // ---------------------------------------------------------------------
593 string
flExtension(string File
)
595 string::size_type Res
= File
.rfind('.');
596 if (Res
== string::npos
)
599 return string(File
,Res
,Res
- File
.length());
602 // flNoLink - If file is a symlink then deref it /*{{{*/
603 // ---------------------------------------------------------------------
604 /* If the name is not a link then the returned path is the input. */
605 string
flNoLink(string File
)
608 if (lstat(File
.c_str(),&St
) != 0 || S_ISLNK(St
.st_mode
) == 0)
610 if (stat(File
.c_str(),&St
) != 0)
613 /* Loop resolving the link. There is no need to limit the number of
614 loops because the stat call above ensures that the symlink is not
622 if ((Res
= readlink(NFile
.c_str(),Buffer
,sizeof(Buffer
))) <= 0 ||
623 (size_t)Res
>= sizeof(Buffer
))
626 // Append or replace the previous path
628 if (Buffer
[0] == '/')
631 NFile
= flNotFile(NFile
) + Buffer
;
633 // See if we are done
634 if (lstat(NFile
.c_str(),&St
) != 0)
636 if (S_ISLNK(St
.st_mode
) == 0)
641 // flCombine - Combine a file and a directory /*{{{*/
642 // ---------------------------------------------------------------------
643 /* If the file is an absolute path then it is just returned, otherwise
644 the directory is pre-pended to it. */
645 string
flCombine(string Dir
,string File
)
647 if (File
.empty() == true)
650 if (File
[0] == '/' || Dir
.empty() == true)
652 if (File
.length() >= 2 && File
[0] == '.' && File
[1] == '/')
654 if (Dir
[Dir
.length()-1] == '/')
656 return Dir
+ '/' + File
;
659 // SetCloseExec - Set the close on exec flag /*{{{*/
660 // ---------------------------------------------------------------------
662 void SetCloseExec(int Fd
,bool Close
)
664 if (fcntl(Fd
,F_SETFD
,(Close
== false)?0:FD_CLOEXEC
) != 0)
666 cerr
<< "FATAL -> Could not set close on exec " << strerror(errno
) << endl
;
671 // SetNonBlock - Set the nonblocking flag /*{{{*/
672 // ---------------------------------------------------------------------
674 void SetNonBlock(int Fd
,bool Block
)
676 int Flags
= fcntl(Fd
,F_GETFL
) & (~O_NONBLOCK
);
677 if (fcntl(Fd
,F_SETFL
,Flags
| ((Block
== false)?0:O_NONBLOCK
)) != 0)
679 cerr
<< "FATAL -> Could not set non-blocking flag " << strerror(errno
) << endl
;
684 // WaitFd - Wait for a FD to become readable /*{{{*/
685 // ---------------------------------------------------------------------
686 /* This waits for a FD to become readable using select. It is useful for
687 applications making use of non-blocking sockets. The timeout is
689 bool WaitFd(int Fd
,bool write
,unsigned long timeout
)
702 Res
= select(Fd
+1,0,&Set
,0,(timeout
!= 0?&tv
:0));
704 while (Res
< 0 && errno
== EINTR
);
714 Res
= select(Fd
+1,&Set
,0,0,(timeout
!= 0?&tv
:0));
716 while (Res
< 0 && errno
== EINTR
);
725 // MergeKeepFdsFromConfiguration - Merge APT::Keep-Fds configuration /*{{{*/
726 // ---------------------------------------------------------------------
727 /* This is used to merge the APT::Keep-Fds with the provided KeepFDs
730 void MergeKeepFdsFromConfiguration(std::set
<int> &KeepFDs
)
732 Configuration::Item
const *Opts
= _config
->Tree("APT::Keep-Fds");
733 if (Opts
!= 0 && Opts
->Child
!= 0)
736 for (; Opts
!= 0; Opts
= Opts
->Next
)
738 if (Opts
->Value
.empty() == true)
740 int fd
= atoi(Opts
->Value
.c_str());
746 // ExecFork - Magical fork that sanitizes the context before execing /*{{{*/
747 // ---------------------------------------------------------------------
748 /* This is used if you want to cleanse the environment for the forked
749 child, it fixes up the important signals and nukes all of the fds,
750 otherwise acts like normal fork. */
754 // we need to merge the Keep-Fds as external tools like
755 // debconf-apt-progress use it
756 MergeKeepFdsFromConfiguration(KeepFDs
);
757 return ExecFork(KeepFDs
);
760 pid_t
ExecFork(std::set
<int> KeepFDs
)
762 // Fork off the process
763 pid_t Process
= fork();
766 cerr
<< "FATAL -> Failed to fork." << endl
;
770 // Spawn the subprocess
774 signal(SIGPIPE
,SIG_DFL
);
775 signal(SIGQUIT
,SIG_DFL
);
776 signal(SIGINT
,SIG_DFL
);
777 signal(SIGWINCH
,SIG_DFL
);
778 signal(SIGCONT
,SIG_DFL
);
779 signal(SIGTSTP
,SIG_DFL
);
781 // Close all of our FDs - just in case
782 for (int K
= 3; K
!= sysconf(_SC_OPEN_MAX
); K
++)
784 if(KeepFDs
.find(K
) == KeepFDs
.end())
785 fcntl(K
,F_SETFD
,FD_CLOEXEC
);
792 // ExecWait - Fancy waitpid /*{{{*/
793 // ---------------------------------------------------------------------
794 /* Waits for the given sub process. If Reap is set then no errors are
795 generated. Otherwise a failed subprocess will generate a proper descriptive
797 bool ExecWait(pid_t Pid
,const char *Name
,bool Reap
)
802 // Wait and collect the error code
804 while (waitpid(Pid
,&Status
,0) != Pid
)
812 return _error
->Error(_("Waited for %s but it wasn't there"),Name
);
816 // Check for an error code.
817 if (WIFEXITED(Status
) == 0 || WEXITSTATUS(Status
) != 0)
821 if (WIFSIGNALED(Status
) != 0)
823 if( WTERMSIG(Status
) == SIGSEGV
)
824 return _error
->Error(_("Sub-process %s received a segmentation fault."),Name
);
826 return _error
->Error(_("Sub-process %s received signal %u."),Name
, WTERMSIG(Status
));
829 if (WIFEXITED(Status
) != 0)
830 return _error
->Error(_("Sub-process %s returned an error code (%u)"),Name
,WEXITSTATUS(Status
));
832 return _error
->Error(_("Sub-process %s exited unexpectedly"),Name
);
839 class FileFdPrivate
{ /*{{{*/
850 uint8_t buffer
[4096];
856 LZMAFILE() : file(NULL
), eof(false), compressing(false) {}
858 if (compressing
== true)
861 stream
.avail_out
= sizeof(buffer
)/sizeof(buffer
[0]);
862 stream
.next_out
= buffer
;
863 err
= lzma_code(&stream
, LZMA_FINISH
);
864 if (err
!= LZMA_OK
&& err
!= LZMA_STREAM_END
)
866 _error
->Error("~LZMAFILE: Compress finalisation failed");
869 size_t const n
= sizeof(buffer
)/sizeof(buffer
[0]) - stream
.avail_out
;
870 if (n
&& fwrite(buffer
, 1, n
, file
) != n
)
872 _error
->Errno("~LZMAFILE",_("Write error"));
875 if (err
== LZMA_STREAM_END
)
886 pid_t compressor_pid
;
888 APT::Configuration::Compressor compressor
;
889 unsigned int openmode
;
890 unsigned long long seekpos
;
901 compressed_fd(-1), compressor_pid(-1), pipe(false),
902 openmode(0), seekpos(0) {};
903 bool InternalClose(std::string
const &FileName
)
906 /* dummy so that the rest can be 'else if's */;
908 else if (gz
!= NULL
) {
909 int const e
= gzclose(gz
);
911 // gzdclose() on empty files always fails with "buffer error" here, ignore that
912 if (e
!= 0 && e
!= Z_BUF_ERROR
)
913 return _error
->Errno("close",_("Problem closing the gzip file %s"), FileName
.c_str());
917 else if (bz2
!= NULL
) {
923 else if (lzma
!= NULL
) {
930 bool CloseDown(std::string
const &FileName
)
932 bool const Res
= InternalClose(FileName
);
934 if (compressor_pid
> 0)
935 ExecWait(compressor_pid
, "FileFdCompressor", true);
940 bool InternalStream() const {
952 ~FileFdPrivate() { CloseDown(""); }
955 // FileFd::Open - Open a file /*{{{*/
956 // ---------------------------------------------------------------------
957 /* The most commonly used open mode combinations are given with Mode */
958 bool FileFd::Open(string FileName
,unsigned int const Mode
,CompressMode Compress
, unsigned long const AccessMode
)
960 if (Mode
== ReadOnlyGzip
)
961 return Open(FileName
, ReadOnly
, Gzip
, AccessMode
);
963 if (Compress
== Auto
&& (Mode
& WriteOnly
) == WriteOnly
)
964 return FileFdError("Autodetection on %s only works in ReadOnly openmode!", FileName
.c_str());
966 std::vector
<APT::Configuration::Compressor
> const compressors
= APT::Configuration::getCompressors();
967 std::vector
<APT::Configuration::Compressor
>::const_iterator compressor
= compressors
.begin();
968 if (Compress
== Auto
)
970 for (; compressor
!= compressors
.end(); ++compressor
)
972 std::string file
= FileName
+ compressor
->Extension
;
973 if (FileExists(file
) == false)
979 else if (Compress
== Extension
)
981 std::string::size_type
const found
= FileName
.find_last_of('.');
983 if (found
!= std::string::npos
)
985 ext
= FileName
.substr(found
);
986 if (ext
== ".new" || ext
== ".bak")
988 std::string::size_type
const found2
= FileName
.find_last_of('.', found
- 1);
989 if (found2
!= std::string::npos
)
990 ext
= FileName
.substr(found2
, found
- found2
);
995 for (; compressor
!= compressors
.end(); ++compressor
)
996 if (ext
== compressor
->Extension
)
998 // no matching extension - assume uncompressed (imagine files like 'example.org_Packages')
999 if (compressor
== compressors
.end())
1000 for (compressor
= compressors
.begin(); compressor
!= compressors
.end(); ++compressor
)
1001 if (compressor
->Name
== ".")
1009 case None
: name
= "."; break;
1010 case Gzip
: name
= "gzip"; break;
1011 case Bzip2
: name
= "bzip2"; break;
1012 case Lzma
: name
= "lzma"; break;
1013 case Xz
: name
= "xz"; break;
1017 return FileFdError("Opening File %s in None, Auto or Extension should be already handled?!?", FileName
.c_str());
1019 for (; compressor
!= compressors
.end(); ++compressor
)
1020 if (compressor
->Name
== name
)
1022 if (compressor
== compressors
.end())
1023 return FileFdError("Can't find a configured compressor %s for file %s", name
.c_str(), FileName
.c_str());
1026 if (compressor
== compressors
.end())
1027 return FileFdError("Can't find a match for specified compressor mode for file %s", FileName
.c_str());
1028 return Open(FileName
, Mode
, *compressor
, AccessMode
);
1030 bool FileFd::Open(string FileName
,unsigned int const Mode
,APT::Configuration::Compressor
const &compressor
, unsigned long const AccessMode
)
1035 if ((Mode
& WriteOnly
) != WriteOnly
&& (Mode
& (Atomic
| Create
| Empty
| Exclusive
)) != 0)
1036 return FileFdError("ReadOnly mode for %s doesn't accept additional flags!", FileName
.c_str());
1037 if ((Mode
& ReadWrite
) == 0)
1038 return FileFdError("No openmode provided in FileFd::Open for %s", FileName
.c_str());
1040 if ((Mode
& Atomic
) == Atomic
)
1044 else if ((Mode
& (Exclusive
| Create
)) == (Exclusive
| Create
))
1046 // for atomic, this will be done by rename in Close()
1047 unlink(FileName
.c_str());
1049 if ((Mode
& Empty
) == Empty
)
1052 if (lstat(FileName
.c_str(),&Buf
) == 0 && S_ISLNK(Buf
.st_mode
))
1053 unlink(FileName
.c_str());
1057 #define if_FLAGGED_SET(FLAG, MODE) if ((Mode & FLAG) == FLAG) fileflags |= MODE
1058 if_FLAGGED_SET(ReadWrite
, O_RDWR
);
1059 else if_FLAGGED_SET(ReadOnly
, O_RDONLY
);
1060 else if_FLAGGED_SET(WriteOnly
, O_WRONLY
);
1062 if_FLAGGED_SET(Create
, O_CREAT
);
1063 if_FLAGGED_SET(Empty
, O_TRUNC
);
1064 if_FLAGGED_SET(Exclusive
, O_EXCL
);
1065 #undef if_FLAGGED_SET
1067 if ((Mode
& Atomic
) == Atomic
)
1069 char *name
= strdup((FileName
+ ".XXXXXX").c_str());
1071 if((iFd
= mkstemp(name
)) == -1)
1074 return FileFdErrno("mkstemp", "Could not create temporary file for %s", FileName
.c_str());
1077 TemporaryFileName
= string(name
);
1080 // umask() will always set the umask and return the previous value, so
1081 // we first set the umask and then reset it to the old value
1082 mode_t
const CurrentUmask
= umask(0);
1083 umask(CurrentUmask
);
1084 // calculate the actual file permissions (just like open/creat)
1085 mode_t
const FilePermissions
= (AccessMode
& ~CurrentUmask
);
1087 if(fchmod(iFd
, FilePermissions
) == -1)
1088 return FileFdErrno("fchmod", "Could not change permissions for temporary file %s", TemporaryFileName
.c_str());
1091 iFd
= open(FileName
.c_str(), fileflags
, AccessMode
);
1093 this->FileName
= FileName
;
1094 if (iFd
== -1 || OpenInternDescriptor(Mode
, compressor
) == false)
1101 return FileFdErrno("open",_("Could not open file %s"), FileName
.c_str());
1104 SetCloseExec(iFd
,true);
1108 // FileFd::OpenDescriptor - Open a filedescriptor /*{{{*/
1109 // ---------------------------------------------------------------------
1111 bool FileFd::OpenDescriptor(int Fd
, unsigned int const Mode
, CompressMode Compress
, bool AutoClose
)
1113 std::vector
<APT::Configuration::Compressor
> const compressors
= APT::Configuration::getCompressors();
1114 std::vector
<APT::Configuration::Compressor
>::const_iterator compressor
= compressors
.begin();
1117 // compat with the old API
1118 if (Mode
== ReadOnlyGzip
&& Compress
== None
)
1123 case None
: name
= "."; break;
1124 case Gzip
: name
= "gzip"; break;
1125 case Bzip2
: name
= "bzip2"; break;
1126 case Lzma
: name
= "lzma"; break;
1127 case Xz
: name
= "xz"; break;
1130 if (AutoClose
== true && Fd
!= -1)
1132 return FileFdError("Opening Fd %d in Auto or Extension compression mode is not supported", Fd
);
1134 for (; compressor
!= compressors
.end(); ++compressor
)
1135 if (compressor
->Name
== name
)
1137 if (compressor
== compressors
.end())
1139 if (AutoClose
== true && Fd
!= -1)
1141 return FileFdError("Can't find a configured compressor %s for file %s", name
.c_str(), FileName
.c_str());
1143 return OpenDescriptor(Fd
, Mode
, *compressor
, AutoClose
);
1145 bool FileFd::OpenDescriptor(int Fd
, unsigned int const Mode
, APT::Configuration::Compressor
const &compressor
, bool AutoClose
)
1148 Flags
= (AutoClose
) ? FileFd::AutoClose
: 0;
1150 this->FileName
= "";
1151 if (OpenInternDescriptor(Mode
, compressor
) == false)
1154 (Flags
& Compressed
) == Compressed
||
1160 return FileFdError(_("Could not open file descriptor %d"), Fd
);
1164 bool FileFd::OpenInternDescriptor(unsigned int const Mode
, APT::Configuration::Compressor
const &compressor
)
1168 if (compressor
.Name
== "." || compressor
.Binary
.empty() == true)
1171 #if defined HAVE_ZLIB || defined HAVE_BZ2 || defined HAVE_LZMA
1172 // the API to open files is similar, so setup to avoid code duplicates later
1173 // and while at it ensure that we close before opening (if its a reopen)
1174 void* (*compress_open
)(int, const char *) = NULL
;
1176 /* dummy so that the rest can be 'else if's */;
1177 #define APT_COMPRESS_INIT(NAME,OPEN) \
1178 else if (compressor.Name == NAME) \
1180 compress_open = (void*(*)(int, const char *)) OPEN; \
1181 if (d != NULL) d->InternalClose(FileName); \
1184 APT_COMPRESS_INIT("gzip", gzdopen
)
1187 APT_COMPRESS_INIT("bzip2", BZ2_bzdopen
)
1190 APT_COMPRESS_INIT("xz", fdopen
)
1191 APT_COMPRESS_INIT("lzma", fdopen
)
1193 #undef APT_COMPRESS_INIT
1198 d
= new FileFdPrivate();
1200 d
->compressor
= compressor
;
1201 #if defined HAVE_ZLIB || defined HAVE_BZ2 || defined HAVE_LZMA
1202 if ((Flags
& AutoClose
) != AutoClose
&& compress_open
!= NULL
)
1204 // Need to duplicate fd here or gz/bz2 close for cleanup will close the fd as well
1205 int const internFd
= dup(iFd
);
1207 return FileFdErrno("OpenInternDescriptor", _("Could not open file descriptor %d"), iFd
);
1213 #if defined HAVE_ZLIB || defined HAVE_BZ2 || defined HAVE_LZMA
1214 if (compress_open
!= NULL
)
1216 void* compress_struct
= NULL
;
1217 if ((Mode
& ReadWrite
) == ReadWrite
)
1218 compress_struct
= compress_open(iFd
, "r+");
1219 else if ((Mode
& WriteOnly
) == WriteOnly
)
1220 compress_struct
= compress_open(iFd
, "w");
1222 compress_struct
= compress_open(iFd
, "r");
1223 if (compress_struct
== NULL
)
1227 /* dummy so that the rest can be 'else if's */;
1229 else if (compressor
.Name
== "gzip")
1230 d
->gz
= (gzFile
) compress_struct
;
1233 else if (compressor
.Name
== "bzip2")
1234 d
->bz2
= (BZFILE
*) compress_struct
;
1237 else if (compressor
.Name
== "xz" || compressor
.Name
== "lzma")
1239 uint32_t const xzlevel
= 6;
1240 uint64_t const memlimit
= UINT64_MAX
;
1241 if (d
->lzma
== NULL
)
1242 d
->lzma
= new FileFdPrivate::LZMAFILE
;
1243 d
->lzma
->file
= (FILE*) compress_struct
;
1244 lzma_stream tmp_stream
= LZMA_STREAM_INIT
;
1245 d
->lzma
->stream
= tmp_stream
;
1247 if ((Mode
& ReadWrite
) == ReadWrite
)
1248 return FileFdError("ReadWrite mode is not supported for file %s", FileName
.c_str());
1250 if ((Mode
& WriteOnly
) == WriteOnly
)
1252 if (compressor
.Name
== "xz")
1254 if (lzma_easy_encoder(&d
->lzma
->stream
, xzlevel
, LZMA_CHECK_CRC32
) != LZMA_OK
)
1259 lzma_options_lzma options
;
1260 lzma_lzma_preset(&options
, xzlevel
);
1261 if (lzma_alone_encoder(&d
->lzma
->stream
, &options
) != LZMA_OK
)
1264 d
->lzma
->compressing
= true;
1268 if (compressor
.Name
== "xz")
1270 if (lzma_auto_decoder(&d
->lzma
->stream
, memlimit
, 0) != LZMA_OK
)
1275 if (lzma_alone_decoder(&d
->lzma
->stream
, memlimit
) != LZMA_OK
)
1278 d
->lzma
->compressing
= false;
1282 Flags
|= Compressed
;
1287 // collect zombies here in case we reopen
1288 if (d
->compressor_pid
> 0)
1289 ExecWait(d
->compressor_pid
, "FileFdCompressor", true);
1291 if ((Mode
& ReadWrite
) == ReadWrite
)
1292 return FileFdError("ReadWrite mode is not supported for file %s", FileName
.c_str());
1294 bool const Comp
= (Mode
& WriteOnly
) == WriteOnly
;
1297 // Handle 'decompression' of empty files
1300 if (Buf
.st_size
== 0 && S_ISFIFO(Buf
.st_mode
) == false)
1303 // We don't need the file open - instead let the compressor open it
1304 // as he properly knows better how to efficiently read from 'his' file
1305 if (FileName
.empty() == false)
1312 // Create a data pipe
1313 int Pipe
[2] = {-1,-1};
1314 if (pipe(Pipe
) != 0)
1315 return FileFdErrno("pipe",_("Failed to create subprocess IPC"));
1316 for (int J
= 0; J
!= 2; J
++)
1317 SetCloseExec(Pipe
[J
],true);
1319 d
->compressed_fd
= iFd
;
1328 d
->compressor_pid
= ExecFork();
1329 if (d
->compressor_pid
== 0)
1333 dup2(d
->compressed_fd
,STDOUT_FILENO
);
1334 dup2(Pipe
[0],STDIN_FILENO
);
1338 if (d
->compressed_fd
!= -1)
1339 dup2(d
->compressed_fd
,STDIN_FILENO
);
1340 dup2(Pipe
[1],STDOUT_FILENO
);
1342 int const nullfd
= open("/dev/null", O_WRONLY
);
1345 dup2(nullfd
,STDERR_FILENO
);
1349 SetCloseExec(STDOUT_FILENO
,false);
1350 SetCloseExec(STDIN_FILENO
,false);
1352 std::vector
<char const*> Args
;
1353 Args
.push_back(compressor
.Binary
.c_str());
1354 std::vector
<std::string
> const * const addArgs
=
1355 (Comp
== true) ? &(compressor
.CompressArgs
) : &(compressor
.UncompressArgs
);
1356 for (std::vector
<std::string
>::const_iterator a
= addArgs
->begin();
1357 a
!= addArgs
->end(); ++a
)
1358 Args
.push_back(a
->c_str());
1359 if (Comp
== false && FileName
.empty() == false)
1361 // commands not needing arguments, do not need to be told about using standard output
1362 // in reality, only testcases with tools like cat, rev, rot13, … are able to trigger this
1363 if (compressor
.CompressArgs
.empty() == false && compressor
.UncompressArgs
.empty() == false)
1364 Args
.push_back("--stdout");
1365 if (TemporaryFileName
.empty() == false)
1366 Args
.push_back(TemporaryFileName
.c_str());
1368 Args
.push_back(FileName
.c_str());
1370 Args
.push_back(NULL
);
1372 execvp(Args
[0],(char **)&Args
[0]);
1373 cerr
<< _("Failed to exec compressor ") << Args
[0] << endl
;
1384 // FileFd::~File - Closes the file /*{{{*/
1385 // ---------------------------------------------------------------------
1386 /* If the proper modes are selected then we close the Fd and possibly
1387 unlink the file on error. */
1392 d
->CloseDown(FileName
);
1397 // FileFd::Read - Read a bit of the file /*{{{*/
1398 // ---------------------------------------------------------------------
1399 /* We are careful to handle interruption by a signal while reading
1401 bool FileFd::Read(void *To
,unsigned long long Size
,unsigned long long *Actual
)
1407 *((char *)To
) = '\0';
1411 /* dummy so that the rest can be 'else if's */;
1413 else if (d
!= NULL
&& d
->gz
!= NULL
)
1414 Res
= gzread(d
->gz
,To
,Size
);
1417 else if (d
!= NULL
&& d
->bz2
!= NULL
)
1418 Res
= BZ2_bzread(d
->bz2
,To
,Size
);
1421 else if (d
!= NULL
&& d
->lzma
!= NULL
)
1423 if (d
->lzma
->eof
== true)
1426 d
->lzma
->stream
.next_out
= (uint8_t *) To
;
1427 d
->lzma
->stream
.avail_out
= Size
;
1428 if (d
->lzma
->stream
.avail_in
== 0)
1430 d
->lzma
->stream
.next_in
= d
->lzma
->buffer
;
1431 d
->lzma
->stream
.avail_in
= fread(d
->lzma
->buffer
, 1, sizeof(d
->lzma
->buffer
)/sizeof(d
->lzma
->buffer
[0]), d
->lzma
->file
);
1433 d
->lzma
->err
= lzma_code(&d
->lzma
->stream
, LZMA_RUN
);
1434 if (d
->lzma
->err
== LZMA_STREAM_END
)
1436 d
->lzma
->eof
= true;
1437 Res
= Size
- d
->lzma
->stream
.avail_out
;
1439 else if (d
->lzma
->err
!= LZMA_OK
)
1446 Res
= Size
- d
->lzma
->stream
.avail_out
;
1449 // lzma run was okay, but produced no output…
1457 Res
= read(iFd
,To
,Size
);
1463 // trick the while-loop into running again
1469 /* dummy so that the rest can be 'else if's */;
1471 else if (d
!= NULL
&& d
->gz
!= NULL
)
1474 char const * const errmsg
= gzerror(d
->gz
, &err
);
1476 return FileFdError("gzread: %s (%d: %s)", _("Read error"), err
, errmsg
);
1480 else if (d
!= NULL
&& d
->bz2
!= NULL
)
1483 char const * const errmsg
= BZ2_bzerror(d
->bz2
, &err
);
1484 if (err
!= BZ_IO_ERROR
)
1485 return FileFdError("BZ2_bzread: %s (%d: %s)", _("Read error"), err
, errmsg
);
1489 else if (d
!= NULL
&& d
->lzma
!= NULL
)
1490 return FileFdError("lzma_read: %s (%d)", _("Read error"), d
->lzma
->err
);
1492 return FileFdErrno("read",_("Read error"));
1495 To
= (char *)To
+ Res
;
1502 while (Res
> 0 && Size
> 0);
1514 return FileFdError(_("read, still have %llu to read but none left"), Size
);
1517 // FileFd::ReadLine - Read a complete line from the file /*{{{*/
1518 // ---------------------------------------------------------------------
1519 /* Beware: This method can be quiet slow for big buffers on UNcompressed
1520 files because of the naive implementation! */
1521 char* FileFd::ReadLine(char *To
, unsigned long long const Size
)
1525 if (d
!= NULL
&& d
->gz
!= NULL
)
1526 return gzgets(d
->gz
, To
, Size
);
1529 unsigned long long read
= 0;
1530 while ((Size
- 1) != read
)
1532 unsigned long long done
= 0;
1533 if (Read(To
+ read
, 1, &done
) == false)
1537 if (To
[read
++] == '\n')
1546 // FileFd::Write - Write to the file /*{{{*/
1547 // ---------------------------------------------------------------------
1549 bool FileFd::Write(const void *From
,unsigned long long Size
)
1556 /* dummy so that the rest can be 'else if's */;
1558 else if (d
!= NULL
&& d
->gz
!= NULL
)
1559 Res
= gzwrite(d
->gz
,From
,Size
);
1562 else if (d
!= NULL
&& d
->bz2
!= NULL
)
1563 Res
= BZ2_bzwrite(d
->bz2
,(void*)From
,Size
);
1566 else if (d
!= NULL
&& d
->lzma
!= NULL
)
1568 d
->lzma
->stream
.next_in
= (uint8_t *)From
;
1569 d
->lzma
->stream
.avail_in
= Size
;
1570 d
->lzma
->stream
.next_out
= d
->lzma
->buffer
;
1571 d
->lzma
->stream
.avail_out
= sizeof(d
->lzma
->buffer
)/sizeof(d
->lzma
->buffer
[0]);
1572 d
->lzma
->err
= lzma_code(&d
->lzma
->stream
, LZMA_RUN
);
1573 if (d
->lzma
->err
!= LZMA_OK
)
1575 size_t const n
= sizeof(d
->lzma
->buffer
)/sizeof(d
->lzma
->buffer
[0]) - d
->lzma
->stream
.avail_out
;
1576 size_t const m
= (n
== 0) ? 0 : fwrite(d
->lzma
->buffer
, 1, n
, d
->lzma
->file
);
1580 Res
= Size
- d
->lzma
->stream
.avail_in
;
1584 Res
= write(iFd
,From
,Size
);
1586 if (Res
< 0 && errno
== EINTR
)
1591 /* dummy so that the rest can be 'else if's */;
1593 else if (d
!= NULL
&& d
->gz
!= NULL
)
1596 char const * const errmsg
= gzerror(d
->gz
, &err
);
1598 return FileFdError("gzwrite: %s (%d: %s)", _("Write error"), err
, errmsg
);
1602 else if (d
!= NULL
&& d
->bz2
!= NULL
)
1605 char const * const errmsg
= BZ2_bzerror(d
->bz2
, &err
);
1606 if (err
!= BZ_IO_ERROR
)
1607 return FileFdError("BZ2_bzwrite: %s (%d: %s)", _("Write error"), err
, errmsg
);
1611 else if (d
!= NULL
&& d
->lzma
!= NULL
)
1612 return FileFdErrno("lzma_fwrite", _("Write error"));
1614 return FileFdErrno("write",_("Write error"));
1617 From
= (char const *)From
+ Res
;
1622 while (Res
> 0 && Size
> 0);
1627 return FileFdError(_("write, still have %llu to write but couldn't"), Size
);
1629 bool FileFd::Write(int Fd
, const void *From
, unsigned long long Size
)
1635 Res
= write(Fd
,From
,Size
);
1636 if (Res
< 0 && errno
== EINTR
)
1639 return _error
->Errno("write",_("Write error"));
1641 From
= (char const *)From
+ Res
;
1644 while (Res
> 0 && Size
> 0);
1649 return _error
->Error(_("write, still have %llu to write but couldn't"), Size
);
1652 // FileFd::Seek - Seek in the file /*{{{*/
1653 // ---------------------------------------------------------------------
1655 bool FileFd::Seek(unsigned long long To
)
1659 if (d
!= NULL
&& (d
->pipe
== true || d
->InternalStream() == true))
1661 // Our poor man seeking in pipes is costly, so try to avoid it
1662 unsigned long long seekpos
= Tell();
1665 else if (seekpos
< To
)
1666 return Skip(To
- seekpos
);
1668 if ((d
->openmode
& ReadOnly
) != ReadOnly
)
1669 return FileFdError("Reopen is only implemented for read-only files!");
1670 d
->InternalClose(FileName
);
1674 if (TemporaryFileName
.empty() == false)
1675 iFd
= open(TemporaryFileName
.c_str(), O_RDONLY
);
1676 else if (FileName
.empty() == false)
1677 iFd
= open(FileName
.c_str(), O_RDONLY
);
1680 if (d
->compressed_fd
> 0)
1681 if (lseek(d
->compressed_fd
, 0, SEEK_SET
) != 0)
1682 iFd
= d
->compressed_fd
;
1684 return FileFdError("Reopen is not implemented for pipes opened with FileFd::OpenDescriptor()!");
1687 if (OpenInternDescriptor(d
->openmode
, d
->compressor
) == false)
1688 return FileFdError("Seek on file %s because it couldn't be reopened", FileName
.c_str());
1698 if (d
!= NULL
&& d
->gz
)
1699 res
= gzseek(d
->gz
,To
,SEEK_SET
);
1702 res
= lseek(iFd
,To
,SEEK_SET
);
1703 if (res
!= (off_t
)To
)
1704 return FileFdError("Unable to seek to %llu", To
);
1711 // FileFd::Skip - Seek in the file /*{{{*/
1712 // ---------------------------------------------------------------------
1714 bool FileFd::Skip(unsigned long long Over
)
1716 if (d
!= NULL
&& (d
->pipe
== true || d
->InternalStream() == true))
1721 unsigned long long toread
= std::min((unsigned long long) sizeof(buffer
), Over
);
1722 if (Read(buffer
, toread
) == false)
1723 return FileFdError("Unable to seek ahead %llu",Over
);
1731 if (d
!= NULL
&& d
->gz
!= NULL
)
1732 res
= gzseek(d
->gz
,Over
,SEEK_CUR
);
1735 res
= lseek(iFd
,Over
,SEEK_CUR
);
1737 return FileFdError("Unable to seek ahead %llu",Over
);
1744 // FileFd::Truncate - Truncate the file /*{{{*/
1745 // ---------------------------------------------------------------------
1747 bool FileFd::Truncate(unsigned long long To
)
1749 // truncating /dev/null is always successful - as we get an error otherwise
1750 if (To
== 0 && FileName
== "/dev/null")
1752 #if defined HAVE_ZLIB || defined HAVE_BZ2 || defined HAVE_LZMA
1753 if (d
!= NULL
&& (d
->InternalStream() == true
1758 return FileFdError("Truncating compressed files is not implemented (%s)", FileName
.c_str());
1760 if (ftruncate(iFd
,To
) != 0)
1761 return FileFdError("Unable to truncate to %llu",To
);
1766 // FileFd::Tell - Current seek position /*{{{*/
1767 // ---------------------------------------------------------------------
1769 unsigned long long FileFd::Tell()
1771 // In theory, we could just return seekpos here always instead of
1772 // seeking around, but not all users of FileFd use always Seek() and co
1773 // so d->seekpos isn't always true and we can just use it as a hint if
1774 // we have nothing else, but not always as an authority…
1775 if (d
!= NULL
&& (d
->pipe
== true || d
->InternalStream() == true))
1780 if (d
!= NULL
&& d
->gz
!= NULL
)
1781 Res
= gztell(d
->gz
);
1784 Res
= lseek(iFd
,0,SEEK_CUR
);
1785 if (Res
== (off_t
)-1)
1786 FileFdErrno("lseek","Failed to determine the current file position");
1792 static bool StatFileFd(char const * const msg
, int const iFd
, std::string
const &FileName
, struct stat
&Buf
, FileFdPrivate
* const d
) /*{{{*/
1794 bool ispipe
= (d
!= NULL
&& d
->pipe
== true);
1795 if (ispipe
== false)
1797 if (fstat(iFd
,&Buf
) != 0)
1798 // higher-level code will generate more meaningful messages,
1799 // even translated this would be meaningless for users
1800 return _error
->Errno("fstat", "Unable to determine %s for fd %i", msg
, iFd
);
1801 if (FileName
.empty() == false)
1802 ispipe
= S_ISFIFO(Buf
.st_mode
);
1805 // for compressor pipes st_size is undefined and at 'best' zero
1808 // we set it here, too, as we get the info here for free
1809 // in theory the Open-methods should take care of it already
1812 if (stat(FileName
.c_str(), &Buf
) != 0)
1813 return _error
->Errno("fstat", "Unable to determine %s for file %s", msg
, FileName
.c_str());
1818 // FileFd::FileSize - Return the size of the file /*{{{*/
1819 unsigned long long FileFd::FileSize()
1822 if (StatFileFd("file size", iFd
, FileName
, Buf
, d
) == false)
1830 // FileFd::ModificationTime - Return the time of last touch /*{{{*/
1831 time_t FileFd::ModificationTime()
1834 if (StatFileFd("modification time", iFd
, FileName
, Buf
, d
) == false)
1839 return Buf
.st_mtime
;
1842 // FileFd::Size - Return the size of the content in the file /*{{{*/
1843 // ---------------------------------------------------------------------
1845 unsigned long long FileFd::Size()
1847 unsigned long long size
= FileSize();
1849 // for compressor pipes st_size is undefined and at 'best' zero,
1850 // so we 'read' the content and 'seek' back - see there
1851 if (d
!= NULL
&& (d
->pipe
== true || (d
->InternalStream() == true && size
> 0)))
1853 unsigned long long const oldSeek
= Tell();
1855 unsigned long long read
= 0;
1857 if (Read(ignore
, sizeof(ignore
), &read
) == false)
1867 // only check gzsize if we are actually a gzip file, just checking for
1868 // "gz" is not sufficient as uncompressed files could be opened with
1869 // gzopen in "direct" mode as well
1870 else if (d
!= NULL
&& d
->gz
&& !gzdirect(d
->gz
) && size
> 0)
1872 off_t
const oldPos
= lseek(iFd
,0,SEEK_CUR
);
1873 /* unfortunately zlib.h doesn't provide a gzsize(), so we have to do
1874 * this ourselves; the original (uncompressed) file size is the last 32
1875 * bits of the file */
1876 // FIXME: Size for gz-files is limited by 32bit… no largefile support
1877 if (lseek(iFd
, -4, SEEK_END
) < 0)
1879 FileFdErrno("lseek","Unable to seek to end of gzipped file");
1883 if (read(iFd
, &size
, 4) != 4)
1885 FileFdErrno("read","Unable to read original size of gzipped file");
1888 size
= le32toh(size
);
1890 if (lseek(iFd
, oldPos
, SEEK_SET
) < 0)
1892 FileFdErrno("lseek","Unable to seek in gzipped file");
1903 // FileFd::Close - Close the file if the close flag is set /*{{{*/
1904 // ---------------------------------------------------------------------
1906 bool FileFd::Close()
1912 if ((Flags
& AutoClose
) == AutoClose
)
1914 if ((Flags
& Compressed
) != Compressed
&& iFd
> 0 && close(iFd
) != 0)
1915 Res
&= _error
->Errno("close",_("Problem closing the file %s"), FileName
.c_str());
1919 Res
&= d
->CloseDown(FileName
);
1925 if ((Flags
& Replace
) == Replace
) {
1926 if (rename(TemporaryFileName
.c_str(), FileName
.c_str()) != 0)
1927 Res
&= _error
->Errno("rename",_("Problem renaming the file %s to %s"), TemporaryFileName
.c_str(), FileName
.c_str());
1929 FileName
= TemporaryFileName
; // for the unlink() below.
1930 TemporaryFileName
.clear();
1935 if ((Flags
& Fail
) == Fail
&& (Flags
& DelOnFail
) == DelOnFail
&&
1936 FileName
.empty() == false)
1937 if (unlink(FileName
.c_str()) != 0)
1938 Res
&= _error
->WarningE("unlnk",_("Problem unlinking the file %s"), FileName
.c_str());
1945 // FileFd::Sync - Sync the file /*{{{*/
1946 // ---------------------------------------------------------------------
1950 if (fsync(iFd
) != 0)
1951 return FileFdErrno("sync",_("Problem syncing the file"));
1955 // FileFd::FileFdErrno - set Fail and call _error->Errno *{{{*/
1956 bool FileFd::FileFdErrno(const char *Function
, const char *Description
,...)
1960 size_t msgSize
= 400;
1961 int const errsv
= errno
;
1964 va_start(args
,Description
);
1965 if (_error
->InsertErrno(GlobalError::ERROR
, Function
, Description
, args
, errsv
, msgSize
) == false)
1972 // FileFd::FileFdError - set Fail and call _error->Error *{{{*/
1973 bool FileFd::FileFdError(const char *Description
,...) {
1976 size_t msgSize
= 400;
1979 va_start(args
,Description
);
1980 if (_error
->Insert(GlobalError::ERROR
, Description
, args
, msgSize
) == false)
1988 APT_DEPRECATED gzFile
FileFd::gzFd() {
1997 // Glob - wrapper around "glob()" /*{{{*/
1998 // ---------------------------------------------------------------------
2000 std::vector
<std::string
> Glob(std::string
const &pattern
, int flags
)
2002 std::vector
<std::string
> result
;
2007 glob_res
= glob(pattern
.c_str(), flags
, NULL
, &globbuf
);
2011 if(glob_res
!= GLOB_NOMATCH
) {
2012 _error
->Errno("glob", "Problem with glob");
2018 for(i
=0;i
<globbuf
.gl_pathc
;i
++)
2019 result
.push_back(string(globbuf
.gl_pathv
[i
]));
2026 std::string
GetTempDir()
2028 const char *tmpdir
= getenv("TMPDIR");
2035 // check that tmpdir is set and exists
2037 if (!tmpdir
|| strlen(tmpdir
) == 0 || stat(tmpdir
, &st
) != 0)
2040 return string(tmpdir
);
2043 bool Rename(std::string From
, std::string To
)
2045 if (rename(From
.c_str(),To
.c_str()) != 0)
2047 _error
->Error(_("rename failed, %s (%s -> %s)."),strerror(errno
),
2048 From
.c_str(),To
.c_str());