1 // -*- mode: cpp; mode: fold -*-
3 // $Id: fileutl.cc,v 1.42 2002/09/14 05:29:22 jgg Exp $
4 /* ######################################################################
8 CopyFile - Buffered copy of a single file
9 GetLock - dpkg compatible lock file manipulation (fcntl)
11 Most of this source is placed in the Public Domain, do with it what
13 It was originally written by Jason Gunthorpe <jgg@debian.org>.
14 FileFd gzip support added by Martin Pitt <martin.pitt@canonical.com>
16 The exception is RunScripts() it is under the GPLv2
18 ##################################################################### */
20 // Include Files /*{{{*/
23 #include <apt-pkg/fileutl.h>
24 #include <apt-pkg/strutl.h>
25 #include <apt-pkg/error.h>
26 #include <apt-pkg/sptr.h>
27 #include <apt-pkg/aptconfiguration.h>
28 #include <apt-pkg/configuration.h>
38 #include <sys/types.h>
49 // FIXME: Compressor Fds have some speed disadvantages and are a bit buggy currently,
50 // so while the current implementation satisfies the testcases it is not a real option
51 // to disable it for now
52 #define APT_USE_ZLIB 1
56 #pragma message "Usage of zlib is DISABLED!"
59 #ifdef WORDS_BIGENDIAN
78 APT::Configuration::Compressor compressor
;
79 unsigned int openmode
;
80 unsigned long long seekpos
;
81 FileFdPrivate() : gz(NULL
), compressed_fd(-1), compressor_pid(-1), pipe(false),
82 openmode(0), seekpos(0) {};
85 // RunScripts - Run a set of scripts from a configuration subtree /*{{{*/
86 // ---------------------------------------------------------------------
88 bool RunScripts(const char *Cnf
)
90 Configuration::Item
const *Opts
= _config
->Tree(Cnf
);
91 if (Opts
== 0 || Opts
->Child
== 0)
95 // Fork for running the system calls
96 pid_t Child
= ExecFork();
101 if (_config
->FindDir("DPkg::Chroot-Directory","/") != "/")
103 std::cerr
<< "Chrooting into "
104 << _config
->FindDir("DPkg::Chroot-Directory")
106 if (chroot(_config
->FindDir("DPkg::Chroot-Directory","/").c_str()) != 0)
110 if (chdir("/tmp/") != 0)
113 unsigned int Count
= 1;
114 for (; Opts
!= 0; Opts
= Opts
->Next
, Count
++)
116 if (Opts
->Value
.empty() == true)
119 if (system(Opts
->Value
.c_str()) != 0)
125 // Wait for the child
127 while (waitpid(Child
,&Status
,0) != Child
)
131 return _error
->Errno("waitpid","Couldn't wait for subprocess");
134 // Restore sig int/quit
135 signal(SIGQUIT
,SIG_DFL
);
136 signal(SIGINT
,SIG_DFL
);
138 // Check for an error code.
139 if (WIFEXITED(Status
) == 0 || WEXITSTATUS(Status
) != 0)
141 unsigned int Count
= WEXITSTATUS(Status
);
145 for (; Opts
!= 0 && Count
!= 1; Opts
= Opts
->Next
, Count
--);
146 _error
->Error("Problem executing scripts %s '%s'",Cnf
,Opts
->Value
.c_str());
149 return _error
->Error("Sub-process returned an error code");
156 // CopyFile - Buffered copy of a file /*{{{*/
157 // ---------------------------------------------------------------------
158 /* The caller is expected to set things so that failure causes erasure */
159 bool CopyFile(FileFd
&From
,FileFd
&To
)
161 if (From
.IsOpen() == false || To
.IsOpen() == false)
164 // Buffered copy between fds
165 SPtrArray
<unsigned char> Buf
= new unsigned char[64000];
166 unsigned long long Size
= From
.Size();
169 unsigned long long ToRead
= Size
;
173 if (From
.Read(Buf
,ToRead
) == false ||
174 To
.Write(Buf
,ToRead
) == false)
183 // GetLock - Gets a lock file /*{{{*/
184 // ---------------------------------------------------------------------
185 /* This will create an empty file of the given name and lock it. Once this
186 is done all other calls to GetLock in any other process will fail with
187 -1. The return result is the fd of the file, the call should call
188 close at some time. */
189 int GetLock(string File
,bool Errors
)
191 // GetLock() is used in aptitude on directories with public-write access
192 // Use O_NOFOLLOW here to prevent symlink traversal attacks
193 int FD
= open(File
.c_str(),O_RDWR
| O_CREAT
| O_NOFOLLOW
,0640);
196 // Read only .. cant have locking problems there.
199 _error
->Warning(_("Not using locking for read only lock file %s"),File
.c_str());
200 return dup(0); // Need something for the caller to close
204 _error
->Errno("open",_("Could not open lock file %s"),File
.c_str());
206 // Feh.. We do this to distinguish the lock vs open case..
210 SetCloseExec(FD
,true);
212 // Aquire a write lock
215 fl
.l_whence
= SEEK_SET
;
218 if (fcntl(FD
,F_SETLK
,&fl
) == -1)
222 _error
->Warning(_("Not using locking for nfs mounted lock file %s"),File
.c_str());
223 return dup(0); // Need something for the caller to close
226 _error
->Errno("open",_("Could not get lock %s"),File
.c_str());
237 // FileExists - Check if a file exists /*{{{*/
238 // ---------------------------------------------------------------------
239 /* Beware: Directories are also files! */
240 bool FileExists(string File
)
243 if (stat(File
.c_str(),&Buf
) != 0)
248 // RealFileExists - Check if a file exists and if it is really a file /*{{{*/
249 // ---------------------------------------------------------------------
251 bool RealFileExists(string File
)
254 if (stat(File
.c_str(),&Buf
) != 0)
256 return ((Buf
.st_mode
& S_IFREG
) != 0);
259 // DirectoryExists - Check if a directory exists and is really one /*{{{*/
260 // ---------------------------------------------------------------------
262 bool DirectoryExists(string
const &Path
)
265 if (stat(Path
.c_str(),&Buf
) != 0)
267 return ((Buf
.st_mode
& S_IFDIR
) != 0);
270 // CreateDirectory - poor man's mkdir -p guarded by a parent directory /*{{{*/
271 // ---------------------------------------------------------------------
272 /* This method will create all directories needed for path in good old
273 mkdir -p style but refuses to do this if Parent is not a prefix of
274 this Path. Example: /var/cache/ and /var/cache/apt/archives are given,
275 so it will create apt/archives if /var/cache exists - on the other
276 hand if the parent is /var/lib the creation will fail as this path
277 is not a parent of the path to be generated. */
278 bool CreateDirectory(string
const &Parent
, string
const &Path
)
280 if (Parent
.empty() == true || Path
.empty() == true)
283 if (DirectoryExists(Path
) == true)
286 if (DirectoryExists(Parent
) == false)
289 // we are not going to create directories "into the blue"
290 if (Path
.find(Parent
, 0) != 0)
293 vector
<string
> const dirs
= VectorizeString(Path
.substr(Parent
.size()), '/');
294 string progress
= Parent
;
295 for (vector
<string
>::const_iterator d
= dirs
.begin(); d
!= dirs
.end(); ++d
)
297 if (d
->empty() == true)
300 progress
.append("/").append(*d
);
301 if (DirectoryExists(progress
) == true)
304 if (mkdir(progress
.c_str(), 0755) != 0)
310 // CreateAPTDirectoryIfNeeded - ensure that the given directory exists /*{{{*/
311 // ---------------------------------------------------------------------
312 /* a small wrapper around CreateDirectory to check if it exists and to
313 remove the trailing "/apt/" from the parent directory if needed */
314 bool CreateAPTDirectoryIfNeeded(string
const &Parent
, string
const &Path
)
316 if (DirectoryExists(Path
) == true)
319 size_t const len
= Parent
.size();
320 if (len
> 5 && Parent
.find("/apt/", len
- 6, 5) == len
- 5)
322 if (CreateDirectory(Parent
.substr(0,len
-5), Path
) == true)
325 else if (CreateDirectory(Parent
, Path
) == true)
331 // GetListOfFilesInDir - returns a vector of files in the given dir /*{{{*/
332 // ---------------------------------------------------------------------
333 /* If an extension is given only files with this extension are included
334 in the returned vector, otherwise every "normal" file is included. */
335 std::vector
<string
> GetListOfFilesInDir(string
const &Dir
, string
const &Ext
,
336 bool const &SortList
, bool const &AllowNoExt
)
338 std::vector
<string
> ext
;
340 if (Ext
.empty() == false)
342 if (AllowNoExt
== true && ext
.empty() == false)
344 return GetListOfFilesInDir(Dir
, ext
, SortList
);
346 std::vector
<string
> GetListOfFilesInDir(string
const &Dir
, std::vector
<string
> const &Ext
,
347 bool const &SortList
)
349 // Attention debuggers: need to be set with the environment config file!
350 bool const Debug
= _config
->FindB("Debug::GetListOfFilesInDir", false);
353 std::clog
<< "Accept in " << Dir
<< " only files with the following " << Ext
.size() << " extensions:" << std::endl
;
354 if (Ext
.empty() == true)
355 std::clog
<< "\tNO extension" << std::endl
;
357 for (std::vector
<string
>::const_iterator e
= Ext
.begin();
359 std::clog
<< '\t' << (e
->empty() == true ? "NO" : *e
) << " extension" << std::endl
;
362 std::vector
<string
> List
;
364 if (DirectoryExists(Dir
.c_str()) == false)
366 _error
->Error(_("List of files can't be created as '%s' is not a directory"), Dir
.c_str());
370 Configuration::MatchAgainstConfig
SilentIgnore("Dir::Ignore-Files-Silently");
371 DIR *D
= opendir(Dir
.c_str());
374 _error
->Errno("opendir",_("Unable to read %s"),Dir
.c_str());
378 for (struct dirent
*Ent
= readdir(D
); Ent
!= 0; Ent
= readdir(D
))
380 // skip "hidden" files
381 if (Ent
->d_name
[0] == '.')
384 // Make sure it is a file and not something else
385 string
const File
= flCombine(Dir
,Ent
->d_name
);
386 #ifdef _DIRENT_HAVE_D_TYPE
387 if (Ent
->d_type
!= DT_REG
)
390 if (RealFileExists(File
.c_str()) == false)
392 // do not show ignoration warnings for directories
394 #ifdef _DIRENT_HAVE_D_TYPE
395 Ent
->d_type
== DT_DIR
||
397 DirectoryExists(File
.c_str()) == true)
399 if (SilentIgnore
.Match(Ent
->d_name
) == false)
400 _error
->Notice(_("Ignoring '%s' in directory '%s' as it is not a regular file"), Ent
->d_name
, Dir
.c_str());
405 // check for accepted extension:
406 // no extension given -> periods are bad as hell!
407 // extensions given -> "" extension allows no extension
408 if (Ext
.empty() == false)
410 string d_ext
= flExtension(Ent
->d_name
);
411 if (d_ext
== Ent
->d_name
) // no extension
413 if (std::find(Ext
.begin(), Ext
.end(), "") == Ext
.end())
416 std::clog
<< "Bad file: " << Ent
->d_name
<< " → no extension" << std::endl
;
417 if (SilentIgnore
.Match(Ent
->d_name
) == false)
418 _error
->Notice(_("Ignoring file '%s' in directory '%s' as it has no filename extension"), Ent
->d_name
, Dir
.c_str());
422 else if (std::find(Ext
.begin(), Ext
.end(), d_ext
) == Ext
.end())
425 std::clog
<< "Bad file: " << Ent
->d_name
<< " → bad extension »" << flExtension(Ent
->d_name
) << "«" << std::endl
;
426 if (SilentIgnore
.Match(Ent
->d_name
) == false)
427 _error
->Notice(_("Ignoring file '%s' in directory '%s' as it has an invalid filename extension"), Ent
->d_name
, Dir
.c_str());
432 // Skip bad filenames ala run-parts
433 const char *C
= Ent
->d_name
;
435 if (isalpha(*C
) == 0 && isdigit(*C
) == 0
436 && *C
!= '_' && *C
!= '-') {
437 // no required extension -> dot is a bad character
438 if (*C
== '.' && Ext
.empty() == false)
443 // we don't reach the end of the name -> bad character included
447 std::clog
<< "Bad file: " << Ent
->d_name
<< " → bad character »"
448 << *C
<< "« in filename (period allowed: " << (Ext
.empty() ? "no" : "yes") << ")" << std::endl
;
452 // skip filenames which end with a period. These are never valid
456 std::clog
<< "Bad file: " << Ent
->d_name
<< " → Period as last character" << std::endl
;
461 std::clog
<< "Accept file: " << Ent
->d_name
<< " in " << Dir
<< std::endl
;
462 List
.push_back(File
);
466 if (SortList
== true)
467 std::sort(List
.begin(),List
.end());
470 std::vector
<string
> GetListOfFilesInDir(string
const &Dir
, bool SortList
)
472 bool const Debug
= _config
->FindB("Debug::GetListOfFilesInDir", false);
474 std::clog
<< "Accept in " << Dir
<< " all regular files" << std::endl
;
476 std::vector
<string
> List
;
478 if (DirectoryExists(Dir
.c_str()) == false)
480 _error
->Error(_("List of files can't be created as '%s' is not a directory"), Dir
.c_str());
484 DIR *D
= opendir(Dir
.c_str());
487 _error
->Errno("opendir",_("Unable to read %s"),Dir
.c_str());
491 for (struct dirent
*Ent
= readdir(D
); Ent
!= 0; Ent
= readdir(D
))
493 // skip "hidden" files
494 if (Ent
->d_name
[0] == '.')
497 // Make sure it is a file and not something else
498 string
const File
= flCombine(Dir
,Ent
->d_name
);
499 #ifdef _DIRENT_HAVE_D_TYPE
500 if (Ent
->d_type
!= DT_REG
)
503 if (RealFileExists(File
.c_str()) == false)
506 std::clog
<< "Bad file: " << Ent
->d_name
<< " → it is not a real file" << std::endl
;
511 // Skip bad filenames ala run-parts
512 const char *C
= Ent
->d_name
;
514 if (isalpha(*C
) == 0 && isdigit(*C
) == 0
515 && *C
!= '_' && *C
!= '-' && *C
!= '.')
518 // we don't reach the end of the name -> bad character included
522 std::clog
<< "Bad file: " << Ent
->d_name
<< " → bad character »" << *C
<< "« in filename" << std::endl
;
526 // skip filenames which end with a period. These are never valid
530 std::clog
<< "Bad file: " << Ent
->d_name
<< " → Period as last character" << std::endl
;
535 std::clog
<< "Accept file: " << Ent
->d_name
<< " in " << Dir
<< std::endl
;
536 List
.push_back(File
);
540 if (SortList
== true)
541 std::sort(List
.begin(),List
.end());
545 // SafeGetCWD - This is a safer getcwd that returns a dynamic string /*{{{*/
546 // ---------------------------------------------------------------------
547 /* We return / on failure. */
550 // Stash the current dir.
553 if (getcwd(S
,sizeof(S
)-2) == 0)
555 unsigned int Len
= strlen(S
);
561 // GetModificationTime - Get the mtime of the given file or -1 on error /*{{{*/
562 // ---------------------------------------------------------------------
563 /* We return / on failure. */
564 time_t GetModificationTime(string
const &Path
)
567 if (stat(Path
.c_str(), &St
) < 0)
572 // flNotDir - Strip the directory from the filename /*{{{*/
573 // ---------------------------------------------------------------------
575 string
flNotDir(string File
)
577 string::size_type Res
= File
.rfind('/');
578 if (Res
== string::npos
)
581 return string(File
,Res
,Res
- File
.length());
584 // flNotFile - Strip the file from the directory name /*{{{*/
585 // ---------------------------------------------------------------------
586 /* Result ends in a / */
587 string
flNotFile(string File
)
589 string::size_type Res
= File
.rfind('/');
590 if (Res
== string::npos
)
593 return string(File
,0,Res
);
596 // flExtension - Return the extension for the file /*{{{*/
597 // ---------------------------------------------------------------------
599 string
flExtension(string File
)
601 string::size_type Res
= File
.rfind('.');
602 if (Res
== string::npos
)
605 return string(File
,Res
,Res
- File
.length());
608 // flNoLink - If file is a symlink then deref it /*{{{*/
609 // ---------------------------------------------------------------------
610 /* If the name is not a link then the returned path is the input. */
611 string
flNoLink(string File
)
614 if (lstat(File
.c_str(),&St
) != 0 || S_ISLNK(St
.st_mode
) == 0)
616 if (stat(File
.c_str(),&St
) != 0)
619 /* Loop resolving the link. There is no need to limit the number of
620 loops because the stat call above ensures that the symlink is not
628 if ((Res
= readlink(NFile
.c_str(),Buffer
,sizeof(Buffer
))) <= 0 ||
629 (unsigned)Res
>= sizeof(Buffer
))
632 // Append or replace the previous path
634 if (Buffer
[0] == '/')
637 NFile
= flNotFile(NFile
) + Buffer
;
639 // See if we are done
640 if (lstat(NFile
.c_str(),&St
) != 0)
642 if (S_ISLNK(St
.st_mode
) == 0)
647 // flCombine - Combine a file and a directory /*{{{*/
648 // ---------------------------------------------------------------------
649 /* If the file is an absolute path then it is just returned, otherwise
650 the directory is pre-pended to it. */
651 string
flCombine(string Dir
,string File
)
653 if (File
.empty() == true)
656 if (File
[0] == '/' || Dir
.empty() == true)
658 if (File
.length() >= 2 && File
[0] == '.' && File
[1] == '/')
660 if (Dir
[Dir
.length()-1] == '/')
662 return Dir
+ '/' + File
;
665 // SetCloseExec - Set the close on exec flag /*{{{*/
666 // ---------------------------------------------------------------------
668 void SetCloseExec(int Fd
,bool Close
)
670 if (fcntl(Fd
,F_SETFD
,(Close
== false)?0:FD_CLOEXEC
) != 0)
672 cerr
<< "FATAL -> Could not set close on exec " << strerror(errno
) << endl
;
677 // SetNonBlock - Set the nonblocking flag /*{{{*/
678 // ---------------------------------------------------------------------
680 void SetNonBlock(int Fd
,bool Block
)
682 int Flags
= fcntl(Fd
,F_GETFL
) & (~O_NONBLOCK
);
683 if (fcntl(Fd
,F_SETFL
,Flags
| ((Block
== false)?0:O_NONBLOCK
)) != 0)
685 cerr
<< "FATAL -> Could not set non-blocking flag " << strerror(errno
) << endl
;
690 // WaitFd - Wait for a FD to become readable /*{{{*/
691 // ---------------------------------------------------------------------
692 /* This waits for a FD to become readable using select. It is useful for
693 applications making use of non-blocking sockets. The timeout is
695 bool WaitFd(int Fd
,bool write
,unsigned long timeout
)
708 Res
= select(Fd
+1,0,&Set
,0,(timeout
!= 0?&tv
:0));
710 while (Res
< 0 && errno
== EINTR
);
720 Res
= select(Fd
+1,&Set
,0,0,(timeout
!= 0?&tv
:0));
722 while (Res
< 0 && errno
== EINTR
);
731 // ExecFork - Magical fork that sanitizes the context before execing /*{{{*/
732 // ---------------------------------------------------------------------
733 /* This is used if you want to cleanse the environment for the forked
734 child, it fixes up the important signals and nukes all of the fds,
735 otherwise acts like normal fork. */
738 // Fork off the process
739 pid_t Process
= fork();
742 cerr
<< "FATAL -> Failed to fork." << endl
;
746 // Spawn the subprocess
750 signal(SIGPIPE
,SIG_DFL
);
751 signal(SIGQUIT
,SIG_DFL
);
752 signal(SIGINT
,SIG_DFL
);
753 signal(SIGWINCH
,SIG_DFL
);
754 signal(SIGCONT
,SIG_DFL
);
755 signal(SIGTSTP
,SIG_DFL
);
758 Configuration::Item
const *Opts
= _config
->Tree("APT::Keep-Fds");
759 if (Opts
!= 0 && Opts
->Child
!= 0)
762 for (; Opts
!= 0; Opts
= Opts
->Next
)
764 if (Opts
->Value
.empty() == true)
766 int fd
= atoi(Opts
->Value
.c_str());
771 // Close all of our FDs - just in case
772 for (int K
= 3; K
!= 40; K
++)
774 if(KeepFDs
.find(K
) == KeepFDs
.end())
775 fcntl(K
,F_SETFD
,FD_CLOEXEC
);
782 // ExecWait - Fancy waitpid /*{{{*/
783 // ---------------------------------------------------------------------
784 /* Waits for the given sub process. If Reap is set then no errors are
785 generated. Otherwise a failed subprocess will generate a proper descriptive
787 bool ExecWait(pid_t Pid
,const char *Name
,bool Reap
)
792 // Wait and collect the error code
794 while (waitpid(Pid
,&Status
,0) != Pid
)
802 return _error
->Error(_("Waited for %s but it wasn't there"),Name
);
806 // Check for an error code.
807 if (WIFEXITED(Status
) == 0 || WEXITSTATUS(Status
) != 0)
811 if (WIFSIGNALED(Status
) != 0)
813 if( WTERMSIG(Status
) == SIGSEGV
)
814 return _error
->Error(_("Sub-process %s received a segmentation fault."),Name
);
816 return _error
->Error(_("Sub-process %s received signal %u."),Name
, WTERMSIG(Status
));
819 if (WIFEXITED(Status
) != 0)
820 return _error
->Error(_("Sub-process %s returned an error code (%u)"),Name
,WEXITSTATUS(Status
));
822 return _error
->Error(_("Sub-process %s exited unexpectedly"),Name
);
829 // FileFd::Open - Open a file /*{{{*/
830 // ---------------------------------------------------------------------
831 /* The most commonly used open mode combinations are given with Mode */
832 bool FileFd::Open(string FileName
,unsigned int const Mode
,CompressMode Compress
, unsigned long const Perms
)
834 if (Mode
== ReadOnlyGzip
)
835 return Open(FileName
, ReadOnly
, Gzip
, Perms
);
837 if (Compress
== Auto
&& (Mode
& WriteOnly
) == WriteOnly
)
838 return _error
->Error("Autodetection on %s only works in ReadOnly openmode!", FileName
.c_str());
840 // FIXME: Denote inbuilt compressors somehow - as we don't need to have the binaries for them
841 std::vector
<APT::Configuration::Compressor
> const compressors
= APT::Configuration::getCompressors();
842 std::vector
<APT::Configuration::Compressor
>::const_iterator compressor
= compressors
.begin();
843 if (Compress
== Auto
)
845 for (; compressor
!= compressors
.end(); ++compressor
)
847 std::string file
= std::string(FileName
).append(compressor
->Extension
);
848 if (FileExists(file
) == false)
854 else if (Compress
== Extension
)
856 std::string::size_type
const found
= FileName
.find_last_of('.');
858 if (found
!= std::string::npos
)
860 ext
= FileName
.substr(found
);
861 if (ext
== ".new" || ext
== ".bak")
863 std::string::size_type
const found2
= FileName
.find_last_of('.', found
- 1);
864 if (found2
!= std::string::npos
)
865 ext
= FileName
.substr(found2
, found
- found2
);
870 for (; compressor
!= compressors
.end(); ++compressor
)
871 if (ext
== compressor
->Extension
)
873 // no matching extension - assume uncompressed (imagine files like 'example.org_Packages')
874 if (compressor
== compressors
.end())
875 for (compressor
= compressors
.begin(); compressor
!= compressors
.end(); ++compressor
)
876 if (compressor
->Name
== ".")
884 case None
: name
= "."; break;
885 case Gzip
: name
= "gzip"; break;
886 case Bzip2
: name
= "bzip2"; break;
887 case Lzma
: name
= "lzma"; break;
888 case Xz
: name
= "xz"; break;
892 return _error
->Error("Opening File %s in None, Auto or Extension should be already handled?!?", FileName
.c_str());
894 for (; compressor
!= compressors
.end(); ++compressor
)
895 if (compressor
->Name
== name
)
897 if (compressor
== compressors
.end())
898 return _error
->Error("Can't find a configured compressor %s for file %s", name
.c_str(), FileName
.c_str());
901 if (compressor
== compressors
.end())
902 return _error
->Error("Can't find a match for specified compressor mode for file %s", FileName
.c_str());
903 return Open(FileName
, Mode
, *compressor
, Perms
);
905 bool FileFd::Open(string FileName
,unsigned int const Mode
,APT::Configuration::Compressor
const &compressor
, unsigned long const Perms
)
908 d
= new FileFdPrivate
;
912 if ((Mode
& WriteOnly
) != WriteOnly
&& (Mode
& (Atomic
| Create
| Empty
| Exclusive
)) != 0)
913 return _error
->Error("ReadOnly mode for %s doesn't accept additional flags!", FileName
.c_str());
914 if ((Mode
& ReadWrite
) == 0)
915 return _error
->Error("No openmode provided in FileFd::Open for %s", FileName
.c_str());
917 if ((Mode
& Atomic
) == Atomic
)
920 char *name
= strdup((FileName
+ ".XXXXXX").c_str());
921 TemporaryFileName
= string(mktemp(name
));
924 else if ((Mode
& (Exclusive
| Create
)) == (Exclusive
| Create
))
926 // for atomic, this will be done by rename in Close()
927 unlink(FileName
.c_str());
929 if ((Mode
& Empty
) == Empty
)
932 if (lstat(FileName
.c_str(),&Buf
) == 0 && S_ISLNK(Buf
.st_mode
))
933 unlink(FileName
.c_str());
937 #define if_FLAGGED_SET(FLAG, MODE) if ((Mode & FLAG) == FLAG) fileflags |= MODE
938 if_FLAGGED_SET(ReadWrite
, O_RDWR
);
939 else if_FLAGGED_SET(ReadOnly
, O_RDONLY
);
940 else if_FLAGGED_SET(WriteOnly
, O_WRONLY
);
942 if_FLAGGED_SET(Create
, O_CREAT
);
943 if_FLAGGED_SET(Empty
, O_TRUNC
);
944 if_FLAGGED_SET(Exclusive
, O_EXCL
);
945 else if_FLAGGED_SET(Atomic
, O_EXCL
);
946 #undef if_FLAGGED_SET
948 if (TemporaryFileName
.empty() == false)
949 iFd
= open(TemporaryFileName
.c_str(), fileflags
, Perms
);
951 iFd
= open(FileName
.c_str(), fileflags
, Perms
);
953 this->FileName
= FileName
;
954 if (iFd
== -1 || OpenInternDescriptor(Mode
, compressor
) == false)
961 return _error
->Errno("open",_("Could not open file %s"), FileName
.c_str());
964 SetCloseExec(iFd
,true);
968 // FileFd::OpenDescriptor - Open a filedescriptor /*{{{*/
969 // ---------------------------------------------------------------------
971 bool FileFd::OpenDescriptor(int Fd
, unsigned int const Mode
, CompressMode Compress
, bool AutoClose
)
973 std::vector
<APT::Configuration::Compressor
> const compressors
= APT::Configuration::getCompressors();
974 std::vector
<APT::Configuration::Compressor
>::const_iterator compressor
= compressors
.begin();
977 // compat with the old API
978 if (Mode
== ReadOnlyGzip
&& Compress
== None
)
983 case None
: name
= "."; break;
984 case Gzip
: name
= "gzip"; break;
985 case Bzip2
: name
= "bzip2"; break;
986 case Lzma
: name
= "lzma"; break;
987 case Xz
: name
= "xz"; break;
990 return _error
->Error("Opening Fd %d in Auto or Extension compression mode is not supported", Fd
);
992 for (; compressor
!= compressors
.end(); ++compressor
)
993 if (compressor
->Name
== name
)
995 if (compressor
== compressors
.end())
996 return _error
->Error("Can't find a configured compressor %s for file %s", name
.c_str(), FileName
.c_str());
998 return OpenDescriptor(Fd
, Mode
, *compressor
, AutoClose
);
1000 bool FileFd::OpenDescriptor(int Fd
, unsigned int const Mode
, APT::Configuration::Compressor
const &compressor
, bool AutoClose
)
1003 d
= new FileFdPrivate
;
1005 Flags
= (AutoClose
) ? FileFd::AutoClose
: 0;
1007 this->FileName
= "";
1008 if (OpenInternDescriptor(Mode
, compressor
) == false)
1012 return _error
->Errno("gzdopen",_("Could not open file descriptor %d"), Fd
);
1016 bool FileFd::OpenInternDescriptor(unsigned int const Mode
, APT::Configuration::Compressor
const &compressor
)
1018 d
->compressor
= compressor
;
1019 if (compressor
.Name
== "." || compressor
.Binary
.empty() == true)
1022 else if (compressor
.Name
== "gzip")
1024 if ((Mode
& ReadWrite
) == ReadWrite
)
1025 d
->gz
= gzdopen(iFd
, "r+");
1026 else if ((Mode
& WriteOnly
) == WriteOnly
)
1027 d
->gz
= gzdopen(iFd
, "w");
1029 d
->gz
= gzdopen (iFd
, "r");
1032 Flags
|= Compressed
;
1037 if ((Mode
& ReadWrite
) == ReadWrite
)
1038 return _error
->Error("ReadWrite mode is not supported for file %s", FileName
.c_str());
1040 bool const Comp
= (Mode
& WriteOnly
) == WriteOnly
;
1041 // Handle 'decompression' of empty files
1046 if (Buf
.st_size
== 0 && S_ISFIFO(Buf
.st_mode
) == false)
1049 // We don't need the file open - instead let the compressor open it
1050 // as he properly knows better how to efficiently read from 'his' file
1051 if (FileName
.empty() == false)
1055 // Create a data pipe
1056 int Pipe
[2] = {-1,-1};
1057 if (pipe(Pipe
) != 0)
1058 return _error
->Errno("pipe",_("Failed to create subprocess IPC"));
1059 for (int J
= 0; J
!= 2; J
++)
1060 SetCloseExec(Pipe
[J
],true);
1062 d
->compressed_fd
= iFd
;
1071 d
->compressor_pid
= ExecFork();
1072 if (d
->compressor_pid
== 0)
1076 dup2(d
->compressed_fd
,STDOUT_FILENO
);
1077 dup2(Pipe
[0],STDIN_FILENO
);
1081 if (FileName
.empty() == true)
1082 dup2(d
->compressed_fd
,STDIN_FILENO
);
1083 dup2(Pipe
[1],STDOUT_FILENO
);
1086 SetCloseExec(STDOUT_FILENO
,false);
1087 SetCloseExec(STDIN_FILENO
,false);
1089 std::vector
<char const*> Args
;
1090 Args
.push_back(compressor
.Binary
.c_str());
1091 std::vector
<std::string
> const * const addArgs
=
1092 (Comp
== true) ? &(compressor
.CompressArgs
) : &(compressor
.UncompressArgs
);
1093 for (std::vector
<std::string
>::const_iterator a
= addArgs
->begin();
1094 a
!= addArgs
->end(); ++a
)
1095 Args
.push_back(a
->c_str());
1096 if (Comp
== false && FileName
.empty() == false)
1098 Args
.push_back("--stdout");
1099 if (TemporaryFileName
.empty() == false)
1100 Args
.push_back(TemporaryFileName
.c_str());
1102 Args
.push_back(FileName
.c_str());
1104 Args
.push_back(NULL
);
1106 execvp(Args
[0],(char **)&Args
[0]);
1107 cerr
<< _("Failed to exec compressor ") << Args
[0] << endl
;
1114 if (Comp
== true || FileName
.empty() == true)
1115 close(d
->compressed_fd
);
1120 // FileFd::~File - Closes the file /*{{{*/
1121 // ---------------------------------------------------------------------
1122 /* If the proper modes are selected then we close the Fd and possibly
1123 unlink the file on error. */
1129 // FileFd::Read - Read a bit of the file /*{{{*/
1130 // ---------------------------------------------------------------------
1131 /* We are carefull to handle interruption by a signal while reading
1133 bool FileFd::Read(void *To
,unsigned long long Size
,unsigned long long *Actual
)
1139 *((char *)To
) = '\0';
1144 Res
= gzread(d
->gz
,To
,Size
);
1147 Res
= read(iFd
,To
,Size
);
1158 char const * const errmsg
= gzerror(d
->gz
, &err
);
1160 return _error
->Error("gzread: %s (%d: %s)", _("Read error"), err
, errmsg
);
1163 return _error
->Errno("read",_("Read error"));
1166 To
= (char *)To
+ Res
;
1172 while (Res
> 0 && Size
> 0);
1185 return _error
->Error(_("read, still have %llu to read but none left"), Size
);
1188 // FileFd::ReadLine - Read a complete line from the file /*{{{*/
1189 // ---------------------------------------------------------------------
1190 /* Beware: This method can be quiet slow for big buffers on UNcompressed
1191 files because of the naive implementation! */
1192 char* FileFd::ReadLine(char *To
, unsigned long long const Size
)
1197 return gzgets(d
->gz
, To
, Size
);
1200 unsigned long long read
= 0;
1201 while ((Size
- 1) != read
)
1203 unsigned long long done
= 0;
1204 if (Read(To
+ read
, 1, &done
) == false)
1208 if (To
[read
++] == '\n')
1217 // FileFd::Write - Write to the file /*{{{*/
1218 // ---------------------------------------------------------------------
1220 bool FileFd::Write(const void *From
,unsigned long long Size
)
1228 Res
= gzwrite(d
->gz
,From
,Size
);
1231 Res
= write(iFd
,From
,Size
);
1232 if (Res
< 0 && errno
== EINTR
)
1237 return _error
->Errno("write",_("Write error"));
1240 From
= (char *)From
+ Res
;
1244 while (Res
> 0 && Size
> 0);
1250 return _error
->Error(_("write, still have %llu to write but couldn't"), Size
);
1253 // FileFd::Seek - Seek in the file /*{{{*/
1254 // ---------------------------------------------------------------------
1256 bool FileFd::Seek(unsigned long long To
)
1258 if (d
->pipe
== true)
1260 // Our poor man seeking in pipes is costly, so try to avoid it
1261 unsigned long long seekpos
= Tell();
1264 else if (seekpos
< To
)
1265 return Skip(To
- seekpos
);
1267 if ((d
->openmode
& ReadOnly
) != ReadOnly
)
1268 return _error
->Error("Reopen is only implemented for read-only files!");
1271 if (TemporaryFileName
.empty() == false)
1272 iFd
= open(TemporaryFileName
.c_str(), O_RDONLY
);
1273 else if (FileName
.empty() == false)
1274 iFd
= open(FileName
.c_str(), O_RDONLY
);
1277 if (d
->compressed_fd
> 0)
1278 if (lseek(d
->compressed_fd
, 0, SEEK_SET
) != 0)
1279 iFd
= d
->compressed_fd
;
1281 return _error
->Error("Reopen is not implemented for pipes opened with FileFd::OpenDescriptor()!");
1284 if (OpenInternDescriptor(d
->openmode
, d
->compressor
) == false)
1285 return _error
->Error("Seek on file %s because it couldn't be reopened", FileName
.c_str());
1296 res
= gzseek(d
->gz
,To
,SEEK_SET
);
1299 res
= lseek(iFd
,To
,SEEK_SET
);
1300 if (res
!= (signed)To
)
1303 return _error
->Error("Unable to seek to %llu", To
);
1310 // FileFd::Skip - Seek in the file /*{{{*/
1311 // ---------------------------------------------------------------------
1313 bool FileFd::Skip(unsigned long long Over
)
1315 if (d
->pipe
== true)
1321 unsigned long long toread
= std::min((unsigned long long) sizeof(buffer
), Over
);
1322 if (Read(buffer
, toread
) == false)
1323 return _error
->Error("Unable to seek ahead %llu",Over
);
1332 res
= gzseek(d
->gz
,Over
,SEEK_CUR
);
1335 res
= lseek(iFd
,Over
,SEEK_CUR
);
1339 return _error
->Error("Unable to seek ahead %llu",Over
);
1346 // FileFd::Truncate - Truncate the file /*{{{*/
1347 // ---------------------------------------------------------------------
1349 bool FileFd::Truncate(unsigned long long To
)
1354 return _error
->Error("Truncating gzipped files is not implemented (%s)", FileName
.c_str());
1356 if (ftruncate(iFd
,To
) != 0)
1359 return _error
->Error("Unable to truncate to %llu",To
);
1365 // FileFd::Tell - Current seek position /*{{{*/
1366 // ---------------------------------------------------------------------
1368 unsigned long long FileFd::Tell()
1370 // In theory, we could just return seekpos here always instead of
1371 // seeking around, but not all users of FileFd use always Seek() and co
1372 // so d->seekpos isn't always true and we can just use it as a hint if
1373 // we have nothing else, but not always as an authority…
1374 if (d
->pipe
== true)
1380 Res
= gztell(d
->gz
);
1383 Res
= lseek(iFd
,0,SEEK_CUR
);
1384 if (Res
== (off_t
)-1)
1385 _error
->Errno("lseek","Failed to determine the current file position");
1390 // FileFd::FileSize - Return the size of the file /*{{{*/
1391 // ---------------------------------------------------------------------
1393 unsigned long long FileFd::FileSize()
1396 if (d
->pipe
== false && fstat(iFd
,&Buf
) != 0)
1397 return _error
->Errno("fstat","Unable to determine the file size");
1399 // for compressor pipes st_size is undefined and at 'best' zero
1400 if (d
->pipe
== true || S_ISFIFO(Buf
.st_mode
))
1402 // we set it here, too, as we get the info here for free
1403 // in theory the Open-methods should take care of it already
1405 if (stat(FileName
.c_str(), &Buf
) != 0)
1406 return _error
->Errno("stat","Unable to determine the file size");
1412 // FileFd::Size - Return the size of the content in the file /*{{{*/
1413 // ---------------------------------------------------------------------
1415 unsigned long long FileFd::Size()
1417 unsigned long long size
= FileSize();
1419 // for compressor pipes st_size is undefined and at 'best' zero,
1420 // so we 'read' the content and 'seek' back - see there
1421 if (d
->pipe
== true)
1423 unsigned long long const oldSeek
= Tell();
1425 unsigned long long read
= 0;
1427 Read(ignore
, sizeof(ignore
), &read
);
1433 // only check gzsize if we are actually a gzip file, just checking for
1434 // "gz" is not sufficient as uncompressed files could be opened with
1435 // gzopen in "direct" mode as well
1436 else if (d
->gz
&& !gzdirect(d
->gz
) && size
> 0)
1438 off_t
const oldPos
= lseek(iFd
,0,SEEK_CUR
);
1439 /* unfortunately zlib.h doesn't provide a gzsize(), so we have to do
1440 * this ourselves; the original (uncompressed) file size is the last 32
1441 * bits of the file */
1442 // FIXME: Size for gz-files is limited by 32bit… no largefile support
1443 if (lseek(iFd
, -4, SEEK_END
) < 0)
1444 return _error
->Errno("lseek","Unable to seek to end of gzipped file");
1446 if (read(iFd
, &size
, 4) != 4)
1447 return _error
->Errno("read","Unable to read original size of gzipped file");
1449 #ifdef WORDS_BIGENDIAN
1450 uint32_t tmp_size
= size
;
1451 uint8_t const * const p
= (uint8_t const * const) &tmp_size
;
1452 tmp_size
= (p
[3] << 24) | (p
[2] << 16) | (p
[1] << 8) | p
[0];
1456 if (lseek(iFd
, oldPos
, SEEK_SET
) < 0)
1457 return _error
->Errno("lseek","Unable to seek in gzipped file");
1466 // FileFd::ModificationTime - Return the time of last touch /*{{{*/
1467 // ---------------------------------------------------------------------
1469 time_t FileFd::ModificationTime()
1472 if (d
->pipe
== false && fstat(iFd
,&Buf
) != 0)
1474 _error
->Errno("fstat","Unable to determine the modification time of file %s", FileName
.c_str());
1478 // for compressor pipes st_size is undefined and at 'best' zero
1479 if (d
->pipe
== true || S_ISFIFO(Buf
.st_mode
))
1481 // we set it here, too, as we get the info here for free
1482 // in theory the Open-methods should take care of it already
1484 if (stat(FileName
.c_str(), &Buf
) != 0)
1486 _error
->Errno("fstat","Unable to determine the modification time of file %s", FileName
.c_str());
1491 return Buf
.st_mtime
;
1494 // FileFd::Close - Close the file if the close flag is set /*{{{*/
1495 // ---------------------------------------------------------------------
1497 bool FileFd::Close()
1503 if ((Flags
& AutoClose
) == AutoClose
)
1506 if (d
!= NULL
&& d
->gz
!= NULL
) {
1507 int const e
= gzclose(d
->gz
);
1508 // gzdclose() on empty files always fails with "buffer error" here, ignore that
1509 if (e
!= 0 && e
!= Z_BUF_ERROR
)
1510 Res
&= _error
->Errno("close",_("Problem closing the gzip file %s"), FileName
.c_str());
1513 if (iFd
> 0 && close(iFd
) != 0)
1514 Res
&= _error
->Errno("close",_("Problem closing the file %s"), FileName
.c_str());
1517 if ((Flags
& Replace
) == Replace
&& iFd
>= 0) {
1518 if (rename(TemporaryFileName
.c_str(), FileName
.c_str()) != 0)
1519 Res
&= _error
->Errno("rename",_("Problem renaming the file %s to %s"), TemporaryFileName
.c_str(), FileName
.c_str());
1521 FileName
= TemporaryFileName
; // for the unlink() below.
1522 TemporaryFileName
.clear();
1527 if ((Flags
& Fail
) == Fail
&& (Flags
& DelOnFail
) == DelOnFail
&&
1528 FileName
.empty() == false)
1529 if (unlink(FileName
.c_str()) != 0)
1530 Res
&= _error
->WarningE("unlnk",_("Problem unlinking the file %s"), FileName
.c_str());
1534 if (d
->compressor_pid
> 0)
1535 ExecWait(d
->compressor_pid
, "FileFdCompressor", true);
1543 // FileFd::Sync - Sync the file /*{{{*/
1544 // ---------------------------------------------------------------------
1548 #ifdef _POSIX_SYNCHRONIZED_IO
1549 if (fsync(iFd
) != 0)
1550 return _error
->Errno("sync",_("Problem syncing the file"));
1556 gzFile
FileFd::gzFd() { return (gzFile
) d
->gz
; }
1559 // Glob - wrapper around "glob()" /*{{{*/
1560 // ---------------------------------------------------------------------
1562 std::vector
<std::string
> Glob(std::string
const &pattern
, int flags
)
1564 std::vector
<std::string
> result
;
1568 glob_res
= glob(pattern
.c_str(), flags
, NULL
, &globbuf
);
1572 if(glob_res
!= GLOB_NOMATCH
) {
1573 _error
->Errno("glob", "Problem with glob");
1579 for(i
=0;i
<globbuf
.gl_pathc
;i
++)
1580 result
.push_back(string(globbuf
.gl_pathv
[i
]));