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>
54 #ifdef WORDS_BIGENDIAN
78 APT::Configuration::Compressor compressor
;
79 unsigned int openmode
;
80 unsigned long long seekpos
;
81 FileFdPrivate() : gz(NULL
), bz2(NULL
),
82 compressed_fd(-1), compressor_pid(-1), pipe(false),
83 openmode(0), seekpos(0) {};
84 bool CloseDown(std::string
const &FileName
)
89 int const e
= gzclose(gz
);
91 // gzdclose() on empty files always fails with "buffer error" here, ignore that
92 if (e
!= 0 && e
!= Z_BUF_ERROR
)
93 Res
&= _error
->Errno("close",_("Problem closing the gzip file %s"), FileName
.c_str());
102 if (compressor_pid
> 0)
103 ExecWait(compressor_pid
, "FileFdCompressor", true);
108 ~FileFdPrivate() { CloseDown(""); }
111 // RunScripts - Run a set of scripts from a configuration subtree /*{{{*/
112 // ---------------------------------------------------------------------
114 bool RunScripts(const char *Cnf
)
116 Configuration::Item
const *Opts
= _config
->Tree(Cnf
);
117 if (Opts
== 0 || Opts
->Child
== 0)
121 // Fork for running the system calls
122 pid_t Child
= ExecFork();
127 if (_config
->FindDir("DPkg::Chroot-Directory","/") != "/")
129 std::cerr
<< "Chrooting into "
130 << _config
->FindDir("DPkg::Chroot-Directory")
132 if (chroot(_config
->FindDir("DPkg::Chroot-Directory","/").c_str()) != 0)
136 if (chdir("/tmp/") != 0)
139 unsigned int Count
= 1;
140 for (; Opts
!= 0; Opts
= Opts
->Next
, Count
++)
142 if (Opts
->Value
.empty() == true)
145 if (system(Opts
->Value
.c_str()) != 0)
151 // Wait for the child
153 while (waitpid(Child
,&Status
,0) != Child
)
157 return _error
->Errno("waitpid","Couldn't wait for subprocess");
160 // Restore sig int/quit
161 signal(SIGQUIT
,SIG_DFL
);
162 signal(SIGINT
,SIG_DFL
);
164 // Check for an error code.
165 if (WIFEXITED(Status
) == 0 || WEXITSTATUS(Status
) != 0)
167 unsigned int Count
= WEXITSTATUS(Status
);
171 for (; Opts
!= 0 && Count
!= 1; Opts
= Opts
->Next
, Count
--);
172 _error
->Error("Problem executing scripts %s '%s'",Cnf
,Opts
->Value
.c_str());
175 return _error
->Error("Sub-process returned an error code");
182 // CopyFile - Buffered copy of a file /*{{{*/
183 // ---------------------------------------------------------------------
184 /* The caller is expected to set things so that failure causes erasure */
185 bool CopyFile(FileFd
&From
,FileFd
&To
)
187 if (From
.IsOpen() == false || To
.IsOpen() == false)
190 // Buffered copy between fds
191 SPtrArray
<unsigned char> Buf
= new unsigned char[64000];
192 unsigned long long Size
= From
.Size();
195 unsigned long long ToRead
= Size
;
199 if (From
.Read(Buf
,ToRead
) == false ||
200 To
.Write(Buf
,ToRead
) == false)
209 // GetLock - Gets a lock file /*{{{*/
210 // ---------------------------------------------------------------------
211 /* This will create an empty file of the given name and lock it. Once this
212 is done all other calls to GetLock in any other process will fail with
213 -1. The return result is the fd of the file, the call should call
214 close at some time. */
215 int GetLock(string File
,bool Errors
)
217 // GetLock() is used in aptitude on directories with public-write access
218 // Use O_NOFOLLOW here to prevent symlink traversal attacks
219 int FD
= open(File
.c_str(),O_RDWR
| O_CREAT
| O_NOFOLLOW
,0640);
222 // Read only .. cant have locking problems there.
225 _error
->Warning(_("Not using locking for read only lock file %s"),File
.c_str());
226 return dup(0); // Need something for the caller to close
230 _error
->Errno("open",_("Could not open lock file %s"),File
.c_str());
232 // Feh.. We do this to distinguish the lock vs open case..
236 SetCloseExec(FD
,true);
238 // Aquire a write lock
241 fl
.l_whence
= SEEK_SET
;
244 if (fcntl(FD
,F_SETLK
,&fl
) == -1)
248 _error
->Warning(_("Not using locking for nfs mounted lock file %s"),File
.c_str());
249 return dup(0); // Need something for the caller to close
252 _error
->Errno("open",_("Could not get lock %s"),File
.c_str());
263 // FileExists - Check if a file exists /*{{{*/
264 // ---------------------------------------------------------------------
265 /* Beware: Directories are also files! */
266 bool FileExists(string File
)
269 if (stat(File
.c_str(),&Buf
) != 0)
274 // RealFileExists - Check if a file exists and if it is really a file /*{{{*/
275 // ---------------------------------------------------------------------
277 bool RealFileExists(string File
)
280 if (stat(File
.c_str(),&Buf
) != 0)
282 return ((Buf
.st_mode
& S_IFREG
) != 0);
285 // DirectoryExists - Check if a directory exists and is really one /*{{{*/
286 // ---------------------------------------------------------------------
288 bool DirectoryExists(string
const &Path
)
291 if (stat(Path
.c_str(),&Buf
) != 0)
293 return ((Buf
.st_mode
& S_IFDIR
) != 0);
296 // CreateDirectory - poor man's mkdir -p guarded by a parent directory /*{{{*/
297 // ---------------------------------------------------------------------
298 /* This method will create all directories needed for path in good old
299 mkdir -p style but refuses to do this if Parent is not a prefix of
300 this Path. Example: /var/cache/ and /var/cache/apt/archives are given,
301 so it will create apt/archives if /var/cache exists - on the other
302 hand if the parent is /var/lib the creation will fail as this path
303 is not a parent of the path to be generated. */
304 bool CreateDirectory(string
const &Parent
, string
const &Path
)
306 if (Parent
.empty() == true || Path
.empty() == true)
309 if (DirectoryExists(Path
) == true)
312 if (DirectoryExists(Parent
) == false)
315 // we are not going to create directories "into the blue"
316 if (Path
.find(Parent
, 0) != 0)
319 vector
<string
> const dirs
= VectorizeString(Path
.substr(Parent
.size()), '/');
320 string progress
= Parent
;
321 for (vector
<string
>::const_iterator d
= dirs
.begin(); d
!= dirs
.end(); ++d
)
323 if (d
->empty() == true)
326 progress
.append("/").append(*d
);
327 if (DirectoryExists(progress
) == true)
330 if (mkdir(progress
.c_str(), 0755) != 0)
336 // CreateAPTDirectoryIfNeeded - ensure that the given directory exists /*{{{*/
337 // ---------------------------------------------------------------------
338 /* a small wrapper around CreateDirectory to check if it exists and to
339 remove the trailing "/apt/" from the parent directory if needed */
340 bool CreateAPTDirectoryIfNeeded(string
const &Parent
, string
const &Path
)
342 if (DirectoryExists(Path
) == true)
345 size_t const len
= Parent
.size();
346 if (len
> 5 && Parent
.find("/apt/", len
- 6, 5) == len
- 5)
348 if (CreateDirectory(Parent
.substr(0,len
-5), Path
) == true)
351 else if (CreateDirectory(Parent
, Path
) == true)
357 // GetListOfFilesInDir - returns a vector of files in the given dir /*{{{*/
358 // ---------------------------------------------------------------------
359 /* If an extension is given only files with this extension are included
360 in the returned vector, otherwise every "normal" file is included. */
361 std::vector
<string
> GetListOfFilesInDir(string
const &Dir
, string
const &Ext
,
362 bool const &SortList
, bool const &AllowNoExt
)
364 std::vector
<string
> ext
;
366 if (Ext
.empty() == false)
368 if (AllowNoExt
== true && ext
.empty() == false)
370 return GetListOfFilesInDir(Dir
, ext
, SortList
);
372 std::vector
<string
> GetListOfFilesInDir(string
const &Dir
, std::vector
<string
> const &Ext
,
373 bool const &SortList
)
375 // Attention debuggers: need to be set with the environment config file!
376 bool const Debug
= _config
->FindB("Debug::GetListOfFilesInDir", false);
379 std::clog
<< "Accept in " << Dir
<< " only files with the following " << Ext
.size() << " extensions:" << std::endl
;
380 if (Ext
.empty() == true)
381 std::clog
<< "\tNO extension" << std::endl
;
383 for (std::vector
<string
>::const_iterator e
= Ext
.begin();
385 std::clog
<< '\t' << (e
->empty() == true ? "NO" : *e
) << " extension" << std::endl
;
388 std::vector
<string
> List
;
390 if (DirectoryExists(Dir
) == false)
392 _error
->Error(_("List of files can't be created as '%s' is not a directory"), Dir
.c_str());
396 Configuration::MatchAgainstConfig
SilentIgnore("Dir::Ignore-Files-Silently");
397 DIR *D
= opendir(Dir
.c_str());
400 _error
->Errno("opendir",_("Unable to read %s"),Dir
.c_str());
404 for (struct dirent
*Ent
= readdir(D
); Ent
!= 0; Ent
= readdir(D
))
406 // skip "hidden" files
407 if (Ent
->d_name
[0] == '.')
410 // Make sure it is a file and not something else
411 string
const File
= flCombine(Dir
,Ent
->d_name
);
412 #ifdef _DIRENT_HAVE_D_TYPE
413 if (Ent
->d_type
!= DT_REG
)
416 if (RealFileExists(File
) == false)
418 // do not show ignoration warnings for directories
420 #ifdef _DIRENT_HAVE_D_TYPE
421 Ent
->d_type
== DT_DIR
||
423 DirectoryExists(File
) == true)
425 if (SilentIgnore
.Match(Ent
->d_name
) == false)
426 _error
->Notice(_("Ignoring '%s' in directory '%s' as it is not a regular file"), Ent
->d_name
, Dir
.c_str());
431 // check for accepted extension:
432 // no extension given -> periods are bad as hell!
433 // extensions given -> "" extension allows no extension
434 if (Ext
.empty() == false)
436 string d_ext
= flExtension(Ent
->d_name
);
437 if (d_ext
== Ent
->d_name
) // no extension
439 if (std::find(Ext
.begin(), Ext
.end(), "") == Ext
.end())
442 std::clog
<< "Bad file: " << Ent
->d_name
<< " → no extension" << std::endl
;
443 if (SilentIgnore
.Match(Ent
->d_name
) == false)
444 _error
->Notice(_("Ignoring file '%s' in directory '%s' as it has no filename extension"), Ent
->d_name
, Dir
.c_str());
448 else if (std::find(Ext
.begin(), Ext
.end(), d_ext
) == Ext
.end())
451 std::clog
<< "Bad file: " << Ent
->d_name
<< " → bad extension »" << flExtension(Ent
->d_name
) << "«" << std::endl
;
452 if (SilentIgnore
.Match(Ent
->d_name
) == false)
453 _error
->Notice(_("Ignoring file '%s' in directory '%s' as it has an invalid filename extension"), Ent
->d_name
, Dir
.c_str());
458 // Skip bad filenames ala run-parts
459 const char *C
= Ent
->d_name
;
461 if (isalpha(*C
) == 0 && isdigit(*C
) == 0
462 && *C
!= '_' && *C
!= '-') {
463 // no required extension -> dot is a bad character
464 if (*C
== '.' && Ext
.empty() == false)
469 // we don't reach the end of the name -> bad character included
473 std::clog
<< "Bad file: " << Ent
->d_name
<< " → bad character »"
474 << *C
<< "« in filename (period allowed: " << (Ext
.empty() ? "no" : "yes") << ")" << std::endl
;
478 // skip filenames which end with a period. These are never valid
482 std::clog
<< "Bad file: " << Ent
->d_name
<< " → Period as last character" << std::endl
;
487 std::clog
<< "Accept file: " << Ent
->d_name
<< " in " << Dir
<< std::endl
;
488 List
.push_back(File
);
492 if (SortList
== true)
493 std::sort(List
.begin(),List
.end());
496 std::vector
<string
> GetListOfFilesInDir(string
const &Dir
, bool SortList
)
498 bool const Debug
= _config
->FindB("Debug::GetListOfFilesInDir", false);
500 std::clog
<< "Accept in " << Dir
<< " all regular files" << std::endl
;
502 std::vector
<string
> List
;
504 if (DirectoryExists(Dir
) == false)
506 _error
->Error(_("List of files can't be created as '%s' is not a directory"), Dir
.c_str());
510 DIR *D
= opendir(Dir
.c_str());
513 _error
->Errno("opendir",_("Unable to read %s"),Dir
.c_str());
517 for (struct dirent
*Ent
= readdir(D
); Ent
!= 0; Ent
= readdir(D
))
519 // skip "hidden" files
520 if (Ent
->d_name
[0] == '.')
523 // Make sure it is a file and not something else
524 string
const File
= flCombine(Dir
,Ent
->d_name
);
525 #ifdef _DIRENT_HAVE_D_TYPE
526 if (Ent
->d_type
!= DT_REG
)
529 if (RealFileExists(File
) == false)
532 std::clog
<< "Bad file: " << Ent
->d_name
<< " → it is not a real file" << std::endl
;
537 // Skip bad filenames ala run-parts
538 const char *C
= Ent
->d_name
;
540 if (isalpha(*C
) == 0 && isdigit(*C
) == 0
541 && *C
!= '_' && *C
!= '-' && *C
!= '.')
544 // we don't reach the end of the name -> bad character included
548 std::clog
<< "Bad file: " << Ent
->d_name
<< " → bad character »" << *C
<< "« in filename" << std::endl
;
552 // skip filenames which end with a period. These are never valid
556 std::clog
<< "Bad file: " << Ent
->d_name
<< " → Period as last character" << std::endl
;
561 std::clog
<< "Accept file: " << Ent
->d_name
<< " in " << Dir
<< std::endl
;
562 List
.push_back(File
);
566 if (SortList
== true)
567 std::sort(List
.begin(),List
.end());
571 // SafeGetCWD - This is a safer getcwd that returns a dynamic string /*{{{*/
572 // ---------------------------------------------------------------------
573 /* We return / on failure. */
576 // Stash the current dir.
579 if (getcwd(S
,sizeof(S
)-2) == 0)
581 unsigned int Len
= strlen(S
);
587 // GetModificationTime - Get the mtime of the given file or -1 on error /*{{{*/
588 // ---------------------------------------------------------------------
589 /* We return / on failure. */
590 time_t GetModificationTime(string
const &Path
)
593 if (stat(Path
.c_str(), &St
) < 0)
598 // flNotDir - Strip the directory from the filename /*{{{*/
599 // ---------------------------------------------------------------------
601 string
flNotDir(string File
)
603 string::size_type Res
= File
.rfind('/');
604 if (Res
== string::npos
)
607 return string(File
,Res
,Res
- File
.length());
610 // flNotFile - Strip the file from the directory name /*{{{*/
611 // ---------------------------------------------------------------------
612 /* Result ends in a / */
613 string
flNotFile(string File
)
615 string::size_type Res
= File
.rfind('/');
616 if (Res
== string::npos
)
619 return string(File
,0,Res
);
622 // flExtension - Return the extension for the file /*{{{*/
623 // ---------------------------------------------------------------------
625 string
flExtension(string File
)
627 string::size_type Res
= File
.rfind('.');
628 if (Res
== string::npos
)
631 return string(File
,Res
,Res
- File
.length());
634 // flNoLink - If file is a symlink then deref it /*{{{*/
635 // ---------------------------------------------------------------------
636 /* If the name is not a link then the returned path is the input. */
637 string
flNoLink(string File
)
640 if (lstat(File
.c_str(),&St
) != 0 || S_ISLNK(St
.st_mode
) == 0)
642 if (stat(File
.c_str(),&St
) != 0)
645 /* Loop resolving the link. There is no need to limit the number of
646 loops because the stat call above ensures that the symlink is not
654 if ((Res
= readlink(NFile
.c_str(),Buffer
,sizeof(Buffer
))) <= 0 ||
655 (unsigned)Res
>= sizeof(Buffer
))
658 // Append or replace the previous path
660 if (Buffer
[0] == '/')
663 NFile
= flNotFile(NFile
) + Buffer
;
665 // See if we are done
666 if (lstat(NFile
.c_str(),&St
) != 0)
668 if (S_ISLNK(St
.st_mode
) == 0)
673 // flCombine - Combine a file and a directory /*{{{*/
674 // ---------------------------------------------------------------------
675 /* If the file is an absolute path then it is just returned, otherwise
676 the directory is pre-pended to it. */
677 string
flCombine(string Dir
,string File
)
679 if (File
.empty() == true)
682 if (File
[0] == '/' || Dir
.empty() == true)
684 if (File
.length() >= 2 && File
[0] == '.' && File
[1] == '/')
686 if (Dir
[Dir
.length()-1] == '/')
688 return Dir
+ '/' + File
;
691 // SetCloseExec - Set the close on exec flag /*{{{*/
692 // ---------------------------------------------------------------------
694 void SetCloseExec(int Fd
,bool Close
)
696 if (fcntl(Fd
,F_SETFD
,(Close
== false)?0:FD_CLOEXEC
) != 0)
698 cerr
<< "FATAL -> Could not set close on exec " << strerror(errno
) << endl
;
703 // SetNonBlock - Set the nonblocking flag /*{{{*/
704 // ---------------------------------------------------------------------
706 void SetNonBlock(int Fd
,bool Block
)
708 int Flags
= fcntl(Fd
,F_GETFL
) & (~O_NONBLOCK
);
709 if (fcntl(Fd
,F_SETFL
,Flags
| ((Block
== false)?0:O_NONBLOCK
)) != 0)
711 cerr
<< "FATAL -> Could not set non-blocking flag " << strerror(errno
) << endl
;
716 // WaitFd - Wait for a FD to become readable /*{{{*/
717 // ---------------------------------------------------------------------
718 /* This waits for a FD to become readable using select. It is useful for
719 applications making use of non-blocking sockets. The timeout is
721 bool WaitFd(int Fd
,bool write
,unsigned long timeout
)
734 Res
= select(Fd
+1,0,&Set
,0,(timeout
!= 0?&tv
:0));
736 while (Res
< 0 && errno
== EINTR
);
746 Res
= select(Fd
+1,&Set
,0,0,(timeout
!= 0?&tv
:0));
748 while (Res
< 0 && errno
== EINTR
);
757 // ExecFork - Magical fork that sanitizes the context before execing /*{{{*/
758 // ---------------------------------------------------------------------
759 /* This is used if you want to cleanse the environment for the forked
760 child, it fixes up the important signals and nukes all of the fds,
761 otherwise acts like normal fork. */
764 // Fork off the process
765 pid_t Process
= fork();
768 cerr
<< "FATAL -> Failed to fork." << endl
;
772 // Spawn the subprocess
776 signal(SIGPIPE
,SIG_DFL
);
777 signal(SIGQUIT
,SIG_DFL
);
778 signal(SIGINT
,SIG_DFL
);
779 signal(SIGWINCH
,SIG_DFL
);
780 signal(SIGCONT
,SIG_DFL
);
781 signal(SIGTSTP
,SIG_DFL
);
784 Configuration::Item
const *Opts
= _config
->Tree("APT::Keep-Fds");
785 if (Opts
!= 0 && Opts
->Child
!= 0)
788 for (; Opts
!= 0; Opts
= Opts
->Next
)
790 if (Opts
->Value
.empty() == true)
792 int fd
= atoi(Opts
->Value
.c_str());
797 // Close all of our FDs - just in case
798 for (int K
= 3; K
!= 40; K
++)
800 if(KeepFDs
.find(K
) == KeepFDs
.end())
801 fcntl(K
,F_SETFD
,FD_CLOEXEC
);
808 // ExecWait - Fancy waitpid /*{{{*/
809 // ---------------------------------------------------------------------
810 /* Waits for the given sub process. If Reap is set then no errors are
811 generated. Otherwise a failed subprocess will generate a proper descriptive
813 bool ExecWait(pid_t Pid
,const char *Name
,bool Reap
)
818 // Wait and collect the error code
820 while (waitpid(Pid
,&Status
,0) != Pid
)
828 return _error
->Error(_("Waited for %s but it wasn't there"),Name
);
832 // Check for an error code.
833 if (WIFEXITED(Status
) == 0 || WEXITSTATUS(Status
) != 0)
837 if (WIFSIGNALED(Status
) != 0)
839 if( WTERMSIG(Status
) == SIGSEGV
)
840 return _error
->Error(_("Sub-process %s received a segmentation fault."),Name
);
842 return _error
->Error(_("Sub-process %s received signal %u."),Name
, WTERMSIG(Status
));
845 if (WIFEXITED(Status
) != 0)
846 return _error
->Error(_("Sub-process %s returned an error code (%u)"),Name
,WEXITSTATUS(Status
));
848 return _error
->Error(_("Sub-process %s exited unexpectedly"),Name
);
855 // FileFd::Open - Open a file /*{{{*/
856 // ---------------------------------------------------------------------
857 /* The most commonly used open mode combinations are given with Mode */
858 bool FileFd::Open(string FileName
,unsigned int const Mode
,CompressMode Compress
, unsigned long const Perms
)
860 if (Mode
== ReadOnlyGzip
)
861 return Open(FileName
, ReadOnly
, Gzip
, Perms
);
863 if (Compress
== Auto
&& (Mode
& WriteOnly
) == WriteOnly
)
864 return FileFdError("Autodetection on %s only works in ReadOnly openmode!", FileName
.c_str());
866 std::vector
<APT::Configuration::Compressor
> const compressors
= APT::Configuration::getCompressors();
867 std::vector
<APT::Configuration::Compressor
>::const_iterator compressor
= compressors
.begin();
868 if (Compress
== Auto
)
870 for (; compressor
!= compressors
.end(); ++compressor
)
872 std::string file
= std::string(FileName
).append(compressor
->Extension
);
873 if (FileExists(file
) == false)
879 else if (Compress
== Extension
)
881 std::string::size_type
const found
= FileName
.find_last_of('.');
883 if (found
!= std::string::npos
)
885 ext
= FileName
.substr(found
);
886 if (ext
== ".new" || ext
== ".bak")
888 std::string::size_type
const found2
= FileName
.find_last_of('.', found
- 1);
889 if (found2
!= std::string::npos
)
890 ext
= FileName
.substr(found2
, found
- found2
);
895 for (; compressor
!= compressors
.end(); ++compressor
)
896 if (ext
== compressor
->Extension
)
898 // no matching extension - assume uncompressed (imagine files like 'example.org_Packages')
899 if (compressor
== compressors
.end())
900 for (compressor
= compressors
.begin(); compressor
!= compressors
.end(); ++compressor
)
901 if (compressor
->Name
== ".")
909 case None
: name
= "."; break;
910 case Gzip
: name
= "gzip"; break;
911 case Bzip2
: name
= "bzip2"; break;
912 case Lzma
: name
= "lzma"; break;
913 case Xz
: name
= "xz"; break;
917 return FileFdError("Opening File %s in None, Auto or Extension should be already handled?!?", FileName
.c_str());
919 for (; compressor
!= compressors
.end(); ++compressor
)
920 if (compressor
->Name
== name
)
922 if (compressor
== compressors
.end())
923 return FileFdError("Can't find a configured compressor %s for file %s", name
.c_str(), FileName
.c_str());
926 if (compressor
== compressors
.end())
927 return FileFdError("Can't find a match for specified compressor mode for file %s", FileName
.c_str());
928 return Open(FileName
, Mode
, *compressor
, Perms
);
930 bool FileFd::Open(string FileName
,unsigned int const Mode
,APT::Configuration::Compressor
const &compressor
, unsigned long const Perms
)
935 if ((Mode
& WriteOnly
) != WriteOnly
&& (Mode
& (Atomic
| Create
| Empty
| Exclusive
)) != 0)
936 return FileFdError("ReadOnly mode for %s doesn't accept additional flags!", FileName
.c_str());
937 if ((Mode
& ReadWrite
) == 0)
938 return FileFdError("No openmode provided in FileFd::Open for %s", FileName
.c_str());
940 if ((Mode
& Atomic
) == Atomic
)
943 char *name
= strdup((FileName
+ ".XXXXXX").c_str());
944 TemporaryFileName
= string(mktemp(name
));
947 else if ((Mode
& (Exclusive
| Create
)) == (Exclusive
| Create
))
949 // for atomic, this will be done by rename in Close()
950 unlink(FileName
.c_str());
952 if ((Mode
& Empty
) == Empty
)
955 if (lstat(FileName
.c_str(),&Buf
) == 0 && S_ISLNK(Buf
.st_mode
))
956 unlink(FileName
.c_str());
960 #define if_FLAGGED_SET(FLAG, MODE) if ((Mode & FLAG) == FLAG) fileflags |= MODE
961 if_FLAGGED_SET(ReadWrite
, O_RDWR
);
962 else if_FLAGGED_SET(ReadOnly
, O_RDONLY
);
963 else if_FLAGGED_SET(WriteOnly
, O_WRONLY
);
965 if_FLAGGED_SET(Create
, O_CREAT
);
966 if_FLAGGED_SET(Empty
, O_TRUNC
);
967 if_FLAGGED_SET(Exclusive
, O_EXCL
);
968 else if_FLAGGED_SET(Atomic
, O_EXCL
);
969 #undef if_FLAGGED_SET
971 if (TemporaryFileName
.empty() == false)
972 iFd
= open(TemporaryFileName
.c_str(), fileflags
, Perms
);
974 iFd
= open(FileName
.c_str(), fileflags
, Perms
);
976 this->FileName
= FileName
;
977 if (iFd
== -1 || OpenInternDescriptor(Mode
, compressor
) == false)
984 return FileFdErrno("open",_("Could not open file %s"), FileName
.c_str());
987 SetCloseExec(iFd
,true);
991 // FileFd::OpenDescriptor - Open a filedescriptor /*{{{*/
992 // ---------------------------------------------------------------------
994 bool FileFd::OpenDescriptor(int Fd
, unsigned int const Mode
, CompressMode Compress
, bool AutoClose
)
996 std::vector
<APT::Configuration::Compressor
> const compressors
= APT::Configuration::getCompressors();
997 std::vector
<APT::Configuration::Compressor
>::const_iterator compressor
= compressors
.begin();
1000 // compat with the old API
1001 if (Mode
== ReadOnlyGzip
&& Compress
== None
)
1006 case None
: name
= "."; break;
1007 case Gzip
: name
= "gzip"; break;
1008 case Bzip2
: name
= "bzip2"; break;
1009 case Lzma
: name
= "lzma"; break;
1010 case Xz
: name
= "xz"; break;
1013 if (AutoClose
== true && Fd
!= -1)
1015 return FileFdError("Opening Fd %d in Auto or Extension compression mode is not supported", Fd
);
1017 for (; compressor
!= compressors
.end(); ++compressor
)
1018 if (compressor
->Name
== name
)
1020 if (compressor
== compressors
.end())
1022 if (AutoClose
== true && Fd
!= -1)
1024 return FileFdError("Can't find a configured compressor %s for file %s", name
.c_str(), FileName
.c_str());
1026 return OpenDescriptor(Fd
, Mode
, *compressor
, AutoClose
);
1028 bool FileFd::OpenDescriptor(int Fd
, unsigned int const Mode
, APT::Configuration::Compressor
const &compressor
, bool AutoClose
)
1031 Flags
= (AutoClose
) ? FileFd::AutoClose
: 0;
1032 if (AutoClose
== false && (
1034 compressor
.Name
== "gzip" ||
1037 compressor
.Name
== "bzip2" ||
1041 // Need to duplicate fd here or gzclose for cleanup will close the fd as well
1046 this->FileName
= "";
1047 if (Fd
== -1 || OpenInternDescriptor(Mode
, compressor
) == false)
1051 compressor
.Name
== "gzip" ||
1054 compressor
.Name
== "bzip2" ||
1061 return FileFdError(_("Could not open file descriptor %d"), Fd
);
1065 bool FileFd::OpenInternDescriptor(unsigned int const Mode
, APT::Configuration::Compressor
const &compressor
)
1067 if (compressor
.Name
== "." || compressor
.Binary
.empty() == true)
1072 d
= new FileFdPrivate();
1074 d
->compressor
= compressor
;
1078 if (compressor
.Name
== "gzip")
1085 if ((Mode
& ReadWrite
) == ReadWrite
)
1086 d
->gz
= gzdopen(iFd
, "r+");
1087 else if ((Mode
& WriteOnly
) == WriteOnly
)
1088 d
->gz
= gzdopen(iFd
, "w");
1090 d
->gz
= gzdopen(iFd
, "r");
1093 Flags
|= Compressed
;
1098 if (compressor
.Name
== "bzip2")
1102 BZ2_bzclose(d
->bz2
);
1105 if ((Mode
& ReadWrite
) == ReadWrite
)
1106 d
->bz2
= BZ2_bzdopen(iFd
, "r+");
1107 else if ((Mode
& WriteOnly
) == WriteOnly
)
1108 d
->bz2
= BZ2_bzdopen(iFd
, "w");
1110 d
->bz2
= BZ2_bzdopen(iFd
, "r");
1113 Flags
|= Compressed
;
1118 // collect zombies here in case we reopen
1119 if (d
->compressor_pid
> 0)
1120 ExecWait(d
->compressor_pid
, "FileFdCompressor", true);
1122 if ((Mode
& ReadWrite
) == ReadWrite
)
1123 return FileFdError("ReadWrite mode is not supported for file %s", FileName
.c_str());
1125 bool const Comp
= (Mode
& WriteOnly
) == WriteOnly
;
1128 // Handle 'decompression' of empty files
1131 if (Buf
.st_size
== 0 && S_ISFIFO(Buf
.st_mode
) == false)
1134 // We don't need the file open - instead let the compressor open it
1135 // as he properly knows better how to efficiently read from 'his' file
1136 if (FileName
.empty() == false)
1143 // Create a data pipe
1144 int Pipe
[2] = {-1,-1};
1145 if (pipe(Pipe
) != 0)
1146 return FileFdErrno("pipe",_("Failed to create subprocess IPC"));
1147 for (int J
= 0; J
!= 2; J
++)
1148 SetCloseExec(Pipe
[J
],true);
1150 d
->compressed_fd
= iFd
;
1159 d
->compressor_pid
= ExecFork();
1160 if (d
->compressor_pid
== 0)
1164 dup2(d
->compressed_fd
,STDOUT_FILENO
);
1165 dup2(Pipe
[0],STDIN_FILENO
);
1169 if (FileName
.empty() == true)
1170 dup2(d
->compressed_fd
,STDIN_FILENO
);
1171 dup2(Pipe
[1],STDOUT_FILENO
);
1173 int const nullfd
= open("/dev/null", O_WRONLY
);
1176 dup2(nullfd
,STDERR_FILENO
);
1180 SetCloseExec(STDOUT_FILENO
,false);
1181 SetCloseExec(STDIN_FILENO
,false);
1183 std::vector
<char const*> Args
;
1184 Args
.push_back(compressor
.Binary
.c_str());
1185 std::vector
<std::string
> const * const addArgs
=
1186 (Comp
== true) ? &(compressor
.CompressArgs
) : &(compressor
.UncompressArgs
);
1187 for (std::vector
<std::string
>::const_iterator a
= addArgs
->begin();
1188 a
!= addArgs
->end(); ++a
)
1189 Args
.push_back(a
->c_str());
1190 if (Comp
== false && FileName
.empty() == false)
1192 Args
.push_back("--stdout");
1193 if (TemporaryFileName
.empty() == false)
1194 Args
.push_back(TemporaryFileName
.c_str());
1196 Args
.push_back(FileName
.c_str());
1198 Args
.push_back(NULL
);
1200 execvp(Args
[0],(char **)&Args
[0]);
1201 cerr
<< _("Failed to exec compressor ") << Args
[0] << endl
;
1212 // FileFd::~File - Closes the file /*{{{*/
1213 // ---------------------------------------------------------------------
1214 /* If the proper modes are selected then we close the Fd and possibly
1215 unlink the file on error. */
1221 d
->CloseDown(FileName
);
1227 // FileFd::Read - Read a bit of the file /*{{{*/
1228 // ---------------------------------------------------------------------
1229 /* We are carefull to handle interruption by a signal while reading
1231 bool FileFd::Read(void *To
,unsigned long long Size
,unsigned long long *Actual
)
1237 *((char *)To
) = '\0';
1241 if (d
!= NULL
&& d
->gz
!= NULL
)
1242 Res
= gzread(d
->gz
,To
,Size
);
1246 if (d
!= NULL
&& d
->bz2
!= NULL
)
1247 Res
= BZ2_bzread(d
->bz2
,To
,Size
);
1250 Res
= read(iFd
,To
,Size
);
1257 if (d
!= NULL
&& d
->gz
!= NULL
)
1260 char const * const errmsg
= gzerror(d
->gz
, &err
);
1262 return FileFdError("gzread: %s (%d: %s)", _("Read error"), err
, errmsg
);
1266 if (d
!= NULL
&& d
->bz2
!= NULL
)
1269 char const * const errmsg
= BZ2_bzerror(d
->bz2
, &err
);
1270 if (err
!= BZ_IO_ERROR
)
1271 return FileFdError("BZ2_bzread: %s (%d: %s)", _("Read error"), err
, errmsg
);
1274 return FileFdErrno("read",_("Read error"));
1277 To
= (char *)To
+ Res
;
1284 while (Res
> 0 && Size
> 0);
1296 return FileFdError(_("read, still have %llu to read but none left"), Size
);
1299 // FileFd::ReadLine - Read a complete line from the file /*{{{*/
1300 // ---------------------------------------------------------------------
1301 /* Beware: This method can be quiet slow for big buffers on UNcompressed
1302 files because of the naive implementation! */
1303 char* FileFd::ReadLine(char *To
, unsigned long long const Size
)
1307 if (d
!= NULL
&& d
->gz
!= NULL
)
1308 return gzgets(d
->gz
, To
, Size
);
1311 unsigned long long read
= 0;
1312 while ((Size
- 1) != read
)
1314 unsigned long long done
= 0;
1315 if (Read(To
+ read
, 1, &done
) == false)
1319 if (To
[read
++] == '\n')
1328 // FileFd::Write - Write to the file /*{{{*/
1329 // ---------------------------------------------------------------------
1331 bool FileFd::Write(const void *From
,unsigned long long Size
)
1338 if (d
!= NULL
&& d
->gz
!= NULL
)
1339 Res
= gzwrite(d
->gz
,From
,Size
);
1343 if (d
!= NULL
&& d
->bz2
!= NULL
)
1344 Res
= BZ2_bzwrite(d
->bz2
,(void*)From
,Size
);
1347 Res
= write(iFd
,From
,Size
);
1348 if (Res
< 0 && errno
== EINTR
)
1353 if (d
!= NULL
&& d
->gz
!= NULL
)
1356 char const * const errmsg
= gzerror(d
->gz
, &err
);
1358 return FileFdError("gzwrite: %s (%d: %s)", _("Write error"), err
, errmsg
);
1362 if (d
!= NULL
&& d
->bz2
!= NULL
)
1365 char const * const errmsg
= BZ2_bzerror(d
->bz2
, &err
);
1366 if (err
!= BZ_IO_ERROR
)
1367 return FileFdError("BZ2_bzwrite: %s (%d: %s)", _("Write error"), err
, errmsg
);
1370 return FileFdErrno("write",_("Write error"));
1373 From
= (char *)From
+ Res
;
1378 while (Res
> 0 && Size
> 0);
1383 return FileFdError(_("write, still have %llu to write but couldn't"), Size
);
1385 bool FileFd::Write(int Fd
, const void *From
, unsigned long long Size
)
1391 Res
= write(Fd
,From
,Size
);
1392 if (Res
< 0 && errno
== EINTR
)
1395 return _error
->Errno("write",_("Write error"));
1397 From
= (char *)From
+ Res
;
1400 while (Res
> 0 && Size
> 0);
1405 return _error
->Error(_("write, still have %llu to write but couldn't"), Size
);
1408 // FileFd::Seek - Seek in the file /*{{{*/
1409 // ---------------------------------------------------------------------
1411 bool FileFd::Seek(unsigned long long To
)
1413 if (d
!= NULL
&& (d
->pipe
== true
1419 // Our poor man seeking in pipes is costly, so try to avoid it
1420 unsigned long long seekpos
= Tell();
1423 else if (seekpos
< To
)
1424 return Skip(To
- seekpos
);
1426 if ((d
->openmode
& ReadOnly
) != ReadOnly
)
1427 return FileFdError("Reopen is only implemented for read-only files!");
1431 BZ2_bzclose(d
->bz2
);
1438 if (TemporaryFileName
.empty() == false)
1439 iFd
= open(TemporaryFileName
.c_str(), O_RDONLY
);
1440 else if (FileName
.empty() == false)
1441 iFd
= open(FileName
.c_str(), O_RDONLY
);
1444 if (d
->compressed_fd
> 0)
1445 if (lseek(d
->compressed_fd
, 0, SEEK_SET
) != 0)
1446 iFd
= d
->compressed_fd
;
1448 return FileFdError("Reopen is not implemented for pipes opened with FileFd::OpenDescriptor()!");
1451 if (OpenInternDescriptor(d
->openmode
, d
->compressor
) == false)
1452 return FileFdError("Seek on file %s because it couldn't be reopened", FileName
.c_str());
1462 if (d
!= NULL
&& d
->gz
)
1463 res
= gzseek(d
->gz
,To
,SEEK_SET
);
1466 res
= lseek(iFd
,To
,SEEK_SET
);
1467 if (res
!= (signed)To
)
1468 return FileFdError("Unable to seek to %llu", To
);
1475 // FileFd::Skip - Seek in the file /*{{{*/
1476 // ---------------------------------------------------------------------
1478 bool FileFd::Skip(unsigned long long Over
)
1480 if (d
!= NULL
&& (d
->pipe
== true
1490 unsigned long long toread
= std::min((unsigned long long) sizeof(buffer
), Over
);
1491 if (Read(buffer
, toread
) == false)
1492 return FileFdError("Unable to seek ahead %llu",Over
);
1500 if (d
!= NULL
&& d
->gz
!= NULL
)
1501 res
= gzseek(d
->gz
,Over
,SEEK_CUR
);
1504 res
= lseek(iFd
,Over
,SEEK_CUR
);
1506 return FileFdError("Unable to seek ahead %llu",Over
);
1513 // FileFd::Truncate - Truncate the file /*{{{*/
1514 // ---------------------------------------------------------------------
1516 bool FileFd::Truncate(unsigned long long To
)
1518 #if defined HAVE_ZLIB || defined HAVE_BZ2
1519 if (d
!= NULL
&& (d
->gz
!= NULL
|| d
->bz2
!= NULL
))
1520 return FileFdError("Truncating compressed files is not implemented (%s)", FileName
.c_str());
1522 if (ftruncate(iFd
,To
) != 0)
1523 return FileFdError("Unable to truncate to %llu",To
);
1528 // FileFd::Tell - Current seek position /*{{{*/
1529 // ---------------------------------------------------------------------
1531 unsigned long long FileFd::Tell()
1533 // In theory, we could just return seekpos here always instead of
1534 // seeking around, but not all users of FileFd use always Seek() and co
1535 // so d->seekpos isn't always true and we can just use it as a hint if
1536 // we have nothing else, but not always as an authority…
1537 if (d
!= NULL
&& (d
->pipe
== true
1546 if (d
!= NULL
&& d
->gz
!= NULL
)
1547 Res
= gztell(d
->gz
);
1550 Res
= lseek(iFd
,0,SEEK_CUR
);
1551 if (Res
== (off_t
)-1)
1552 FileFdErrno("lseek","Failed to determine the current file position");
1558 // FileFd::FileSize - Return the size of the file /*{{{*/
1559 // ---------------------------------------------------------------------
1561 unsigned long long FileFd::FileSize()
1564 if ((d
== NULL
|| d
->pipe
== false) && fstat(iFd
,&Buf
) != 0)
1565 return FileFdErrno("fstat","Unable to determine the file size");
1567 // for compressor pipes st_size is undefined and at 'best' zero
1568 if ((d
!= NULL
&& d
->pipe
== true) || S_ISFIFO(Buf
.st_mode
))
1570 // we set it here, too, as we get the info here for free
1571 // in theory the Open-methods should take care of it already
1574 if (stat(FileName
.c_str(), &Buf
) != 0)
1575 return FileFdErrno("stat","Unable to determine the file size");
1581 // FileFd::Size - Return the size of the content in the file /*{{{*/
1582 // ---------------------------------------------------------------------
1584 unsigned long long FileFd::Size()
1586 unsigned long long size
= FileSize();
1588 // for compressor pipes st_size is undefined and at 'best' zero,
1589 // so we 'read' the content and 'seek' back - see there
1590 if (d
!= NULL
&& (d
->pipe
== true
1592 || (d
->bz2
&& size
> 0)
1596 unsigned long long const oldSeek
= Tell();
1598 unsigned long long read
= 0;
1600 Read(ignore
, sizeof(ignore
), &read
);
1606 // only check gzsize if we are actually a gzip file, just checking for
1607 // "gz" is not sufficient as uncompressed files could be opened with
1608 // gzopen in "direct" mode as well
1609 else if (d
!= NULL
&& d
->gz
&& !gzdirect(d
->gz
) && size
> 0)
1611 off_t
const oldPos
= lseek(iFd
,0,SEEK_CUR
);
1612 /* unfortunately zlib.h doesn't provide a gzsize(), so we have to do
1613 * this ourselves; the original (uncompressed) file size is the last 32
1614 * bits of the file */
1615 // FIXME: Size for gz-files is limited by 32bit… no largefile support
1616 if (lseek(iFd
, -4, SEEK_END
) < 0)
1617 return FileFdErrno("lseek","Unable to seek to end of gzipped file");
1619 if (read(iFd
, &size
, 4) != 4)
1620 return FileFdErrno("read","Unable to read original size of gzipped file");
1622 #ifdef WORDS_BIGENDIAN
1623 uint32_t tmp_size
= size
;
1624 uint8_t const * const p
= (uint8_t const * const) &tmp_size
;
1625 tmp_size
= (p
[3] << 24) | (p
[2] << 16) | (p
[1] << 8) | p
[0];
1629 if (lseek(iFd
, oldPos
, SEEK_SET
) < 0)
1630 return FileFdErrno("lseek","Unable to seek in gzipped file");
1639 // FileFd::ModificationTime - Return the time of last touch /*{{{*/
1640 // ---------------------------------------------------------------------
1642 time_t FileFd::ModificationTime()
1645 if ((d
== NULL
|| d
->pipe
== false) && fstat(iFd
,&Buf
) != 0)
1647 FileFdErrno("fstat","Unable to determine the modification time of file %s", FileName
.c_str());
1651 // for compressor pipes st_size is undefined and at 'best' zero
1652 if ((d
!= NULL
&& d
->pipe
== true) || S_ISFIFO(Buf
.st_mode
))
1654 // we set it here, too, as we get the info here for free
1655 // in theory the Open-methods should take care of it already
1658 if (stat(FileName
.c_str(), &Buf
) != 0)
1660 FileFdErrno("fstat","Unable to determine the modification time of file %s", FileName
.c_str());
1665 return Buf
.st_mtime
;
1668 // FileFd::Close - Close the file if the close flag is set /*{{{*/
1669 // ---------------------------------------------------------------------
1671 bool FileFd::Close()
1677 if ((Flags
& AutoClose
) == AutoClose
)
1679 if ((Flags
& Compressed
) != Compressed
&& iFd
> 0 && close(iFd
) != 0)
1680 Res
&= _error
->Errno("close",_("Problem closing the file %s"), FileName
.c_str());
1684 Res
&= d
->CloseDown(FileName
);
1690 if ((Flags
& Replace
) == Replace
) {
1691 if (rename(TemporaryFileName
.c_str(), FileName
.c_str()) != 0)
1692 Res
&= _error
->Errno("rename",_("Problem renaming the file %s to %s"), TemporaryFileName
.c_str(), FileName
.c_str());
1694 FileName
= TemporaryFileName
; // for the unlink() below.
1695 TemporaryFileName
.clear();
1700 if ((Flags
& Fail
) == Fail
&& (Flags
& DelOnFail
) == DelOnFail
&&
1701 FileName
.empty() == false)
1702 if (unlink(FileName
.c_str()) != 0)
1703 Res
&= _error
->WarningE("unlnk",_("Problem unlinking the file %s"), FileName
.c_str());
1710 // FileFd::Sync - Sync the file /*{{{*/
1711 // ---------------------------------------------------------------------
1715 if (fsync(iFd
) != 0)
1716 return FileFdErrno("sync",_("Problem syncing the file"));
1720 // FileFd::FileFdErrno - set Fail and call _error->Errno *{{{*/
1721 bool FileFd::FileFdErrno(const char *Function
, const char *Description
,...)
1725 size_t msgSize
= 400;
1726 int const errsv
= errno
;
1729 va_start(args
,Description
);
1730 if (_error
->InsertErrno(GlobalError::ERROR
, Function
, Description
, args
, errsv
, msgSize
) == false)
1737 // FileFd::FileFdError - set Fail and call _error->Error *{{{*/
1738 bool FileFd::FileFdError(const char *Description
,...) {
1741 size_t msgSize
= 400;
1744 va_start(args
,Description
);
1745 if (_error
->Insert(GlobalError::ERROR
, Description
, args
, msgSize
) == false)
1753 gzFile
FileFd::gzFd() { return (gzFile
) d
->gz
; }