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>
69 #include <sys/prctl.h>
77 // RunScripts - Run a set of scripts from a configuration subtree /*{{{*/
78 // ---------------------------------------------------------------------
80 bool RunScripts(const char *Cnf
)
82 Configuration::Item
const *Opts
= _config
->Tree(Cnf
);
83 if (Opts
== 0 || Opts
->Child
== 0)
87 // Fork for running the system calls
88 pid_t Child
= ExecFork();
93 if (_config
->FindDir("DPkg::Chroot-Directory","/") != "/")
95 std::cerr
<< "Chrooting into "
96 << _config
->FindDir("DPkg::Chroot-Directory")
98 if (chroot(_config
->FindDir("DPkg::Chroot-Directory","/").c_str()) != 0)
102 if (chdir("/tmp/") != 0)
105 unsigned int Count
= 1;
106 for (; Opts
!= 0; Opts
= Opts
->Next
, Count
++)
108 if (Opts
->Value
.empty() == true)
111 if(_config
->FindB("Debug::RunScripts", false) == true)
112 std::clog
<< "Running external script: '"
113 << Opts
->Value
<< "'" << std::endl
;
115 if (system(Opts
->Value
.c_str()) != 0)
121 // Wait for the child
123 while (waitpid(Child
,&Status
,0) != Child
)
127 return _error
->Errno("waitpid","Couldn't wait for subprocess");
130 // Restore sig int/quit
131 signal(SIGQUIT
,SIG_DFL
);
132 signal(SIGINT
,SIG_DFL
);
134 // Check for an error code.
135 if (WIFEXITED(Status
) == 0 || WEXITSTATUS(Status
) != 0)
137 unsigned int Count
= WEXITSTATUS(Status
);
141 for (; Opts
!= 0 && Count
!= 1; Opts
= Opts
->Next
, Count
--);
142 _error
->Error("Problem executing scripts %s '%s'",Cnf
,Opts
->Value
.c_str());
145 return _error
->Error("Sub-process returned an error code");
152 // CopyFile - Buffered copy of a file /*{{{*/
153 // ---------------------------------------------------------------------
154 /* The caller is expected to set things so that failure causes erasure */
155 bool CopyFile(FileFd
&From
,FileFd
&To
)
157 if (From
.IsOpen() == false || To
.IsOpen() == false ||
158 From
.Failed() == true || To
.Failed() == true)
161 // Buffered copy between fds
162 SPtrArray
<unsigned char> Buf
= new unsigned char[64000];
163 unsigned long long Size
= From
.Size();
166 unsigned long long ToRead
= Size
;
170 if (From
.Read(Buf
,ToRead
) == false ||
171 To
.Write(Buf
,ToRead
) == false)
180 // GetLock - Gets a lock file /*{{{*/
181 // ---------------------------------------------------------------------
182 /* This will create an empty file of the given name and lock it. Once this
183 is done all other calls to GetLock in any other process will fail with
184 -1. The return result is the fd of the file, the call should call
185 close at some time. */
186 int GetLock(string File
,bool Errors
)
188 // GetLock() is used in aptitude on directories with public-write access
189 // Use O_NOFOLLOW here to prevent symlink traversal attacks
190 int FD
= open(File
.c_str(),O_RDWR
| O_CREAT
| O_NOFOLLOW
,0640);
193 // Read only .. can't have locking problems there.
196 _error
->Warning(_("Not using locking for read only lock file %s"),File
.c_str());
197 return dup(0); // Need something for the caller to close
201 _error
->Errno("open",_("Could not open lock file %s"),File
.c_str());
203 // Feh.. We do this to distinguish the lock vs open case..
207 SetCloseExec(FD
,true);
209 // Acquire a write lock
212 fl
.l_whence
= SEEK_SET
;
215 if (fcntl(FD
,F_SETLK
,&fl
) == -1)
217 // always close to not leak resources
224 _error
->Warning(_("Not using locking for nfs mounted lock file %s"),File
.c_str());
225 return dup(0); // Need something for the caller to close
229 _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
.compare(0, Parent
.length(), Parent
) != 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
) == 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
) == false)
392 // do not show ignoration warnings for directories
394 #ifdef _DIRENT_HAVE_D_TYPE
395 Ent
->d_type
== DT_DIR
||
397 DirectoryExists(File
) == 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
!= '-' && *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
) == 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
) == 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 (size_t)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 // flAbsPath - Return the absolute path of the filename /*{{{*/
666 // ---------------------------------------------------------------------
668 string
flAbsPath(string File
)
670 char *p
= realpath(File
.c_str(), NULL
);
673 _error
->Errno("realpath", "flAbsPath failed");
676 std::string
AbsPath(p
);
681 // SetCloseExec - Set the close on exec flag /*{{{*/
682 // ---------------------------------------------------------------------
684 void SetCloseExec(int Fd
,bool Close
)
686 if (fcntl(Fd
,F_SETFD
,(Close
== false)?0:FD_CLOEXEC
) != 0)
688 cerr
<< "FATAL -> Could not set close on exec " << strerror(errno
) << endl
;
693 // SetNonBlock - Set the nonblocking flag /*{{{*/
694 // ---------------------------------------------------------------------
696 void SetNonBlock(int Fd
,bool Block
)
698 int Flags
= fcntl(Fd
,F_GETFL
) & (~O_NONBLOCK
);
699 if (fcntl(Fd
,F_SETFL
,Flags
| ((Block
== false)?0:O_NONBLOCK
)) != 0)
701 cerr
<< "FATAL -> Could not set non-blocking flag " << strerror(errno
) << endl
;
706 // WaitFd - Wait for a FD to become readable /*{{{*/
707 // ---------------------------------------------------------------------
708 /* This waits for a FD to become readable using select. It is useful for
709 applications making use of non-blocking sockets. The timeout is
711 bool WaitFd(int Fd
,bool write
,unsigned long timeout
)
724 Res
= select(Fd
+1,0,&Set
,0,(timeout
!= 0?&tv
:0));
726 while (Res
< 0 && errno
== EINTR
);
736 Res
= select(Fd
+1,&Set
,0,0,(timeout
!= 0?&tv
:0));
738 while (Res
< 0 && errno
== EINTR
);
747 // MergeKeepFdsFromConfiguration - Merge APT::Keep-Fds configuration /*{{{*/
748 // ---------------------------------------------------------------------
749 /* This is used to merge the APT::Keep-Fds with the provided KeepFDs
752 void MergeKeepFdsFromConfiguration(std::set
<int> &KeepFDs
)
754 Configuration::Item
const *Opts
= _config
->Tree("APT::Keep-Fds");
755 if (Opts
!= 0 && Opts
->Child
!= 0)
758 for (; Opts
!= 0; Opts
= Opts
->Next
)
760 if (Opts
->Value
.empty() == true)
762 int fd
= atoi(Opts
->Value
.c_str());
768 // ExecFork - Magical fork that sanitizes the context before execing /*{{{*/
769 // ---------------------------------------------------------------------
770 /* This is used if you want to cleanse the environment for the forked
771 child, it fixes up the important signals and nukes all of the fds,
772 otherwise acts like normal fork. */
776 // we need to merge the Keep-Fds as external tools like
777 // debconf-apt-progress use it
778 MergeKeepFdsFromConfiguration(KeepFDs
);
779 return ExecFork(KeepFDs
);
782 pid_t
ExecFork(std::set
<int> KeepFDs
)
784 // Fork off the process
785 pid_t Process
= fork();
788 cerr
<< "FATAL -> Failed to fork." << endl
;
792 // Spawn the subprocess
796 signal(SIGPIPE
,SIG_DFL
);
797 signal(SIGQUIT
,SIG_DFL
);
798 signal(SIGINT
,SIG_DFL
);
799 signal(SIGWINCH
,SIG_DFL
);
800 signal(SIGCONT
,SIG_DFL
);
801 signal(SIGTSTP
,SIG_DFL
);
803 DIR *dir
= opendir("/proc/self/fd");
807 while ((ent
= readdir(dir
)))
809 int fd
= atoi(ent
->d_name
);
810 // If fd > 0, it was a fd number and not . or ..
811 if (fd
>= 3 && KeepFDs
.find(fd
) == KeepFDs
.end())
812 fcntl(fd
,F_SETFD
,FD_CLOEXEC
);
816 long ScOpenMax
= sysconf(_SC_OPEN_MAX
);
817 // Close all of our FDs - just in case
818 for (int K
= 3; K
!= ScOpenMax
; K
++)
820 if(KeepFDs
.find(K
) == KeepFDs
.end())
821 fcntl(K
,F_SETFD
,FD_CLOEXEC
);
829 // ExecWait - Fancy waitpid /*{{{*/
830 // ---------------------------------------------------------------------
831 /* Waits for the given sub process. If Reap is set then no errors are
832 generated. Otherwise a failed subprocess will generate a proper descriptive
834 bool ExecWait(pid_t Pid
,const char *Name
,bool Reap
)
839 // Wait and collect the error code
841 while (waitpid(Pid
,&Status
,0) != Pid
)
849 return _error
->Error(_("Waited for %s but it wasn't there"),Name
);
853 // Check for an error code.
854 if (WIFEXITED(Status
) == 0 || WEXITSTATUS(Status
) != 0)
858 if (WIFSIGNALED(Status
) != 0)
860 if( WTERMSIG(Status
) == SIGSEGV
)
861 return _error
->Error(_("Sub-process %s received a segmentation fault."),Name
);
863 return _error
->Error(_("Sub-process %s received signal %u."),Name
, WTERMSIG(Status
));
866 if (WIFEXITED(Status
) != 0)
867 return _error
->Error(_("Sub-process %s returned an error code (%u)"),Name
,WEXITSTATUS(Status
));
869 return _error
->Error(_("Sub-process %s exited unexpectedly"),Name
);
875 // StartsWithGPGClearTextSignature - Check if a file is Pgp/GPG clearsigned /*{{{*/
876 bool StartsWithGPGClearTextSignature(string
const &FileName
)
878 static const char* SIGMSG
= "-----BEGIN PGP SIGNED MESSAGE-----\n";
879 char buffer
[strlen(SIGMSG
)+1];
880 FILE* gpg
= fopen(FileName
.c_str(), "r");
884 char const * const test
= fgets(buffer
, sizeof(buffer
), gpg
);
886 if (test
== NULL
|| strcmp(buffer
, SIGMSG
) != 0)
892 // ChangeOwnerAndPermissionOfFile - set file attributes to requested values /*{{{*/
893 bool ChangeOwnerAndPermissionOfFile(char const * const requester
, char const * const file
, char const * const user
, char const * const group
, mode_t
const mode
)
895 if (strcmp(file
, "/dev/null") == 0)
898 if (getuid() == 0 && strlen(user
) != 0 && strlen(group
) != 0) // if we aren't root, we can't chown, so don't try it
900 // ensure the file is owned by root and has good permissions
901 struct passwd
const * const pw
= getpwnam(user
);
902 struct group
const * const gr
= getgrnam(group
);
903 if (pw
!= NULL
&& gr
!= NULL
&& chown(file
, pw
->pw_uid
, gr
->gr_gid
) != 0)
904 Res
&= _error
->WarningE(requester
, "chown to %s:%s of file %s failed", user
, group
, file
);
906 if (chmod(file
, mode
) != 0)
907 Res
&= _error
->WarningE(requester
, "chmod 0%o of file %s failed", mode
, file
);
912 class FileFdPrivate
{ /*{{{*/
923 uint8_t buffer
[4096];
929 LZMAFILE() : file(NULL
), eof(false), compressing(false) { buffer
[0] = '\0'; }
931 if (compressing
== true)
934 stream
.avail_out
= sizeof(buffer
)/sizeof(buffer
[0]);
935 stream
.next_out
= buffer
;
936 err
= lzma_code(&stream
, LZMA_FINISH
);
937 if (err
!= LZMA_OK
&& err
!= LZMA_STREAM_END
)
939 _error
->Error("~LZMAFILE: Compress finalisation failed");
942 size_t const n
= sizeof(buffer
)/sizeof(buffer
[0]) - stream
.avail_out
;
943 if (n
&& fwrite(buffer
, 1, n
, file
) != n
)
945 _error
->Errno("~LZMAFILE",_("Write error"));
948 if (err
== LZMA_STREAM_END
)
959 pid_t compressor_pid
;
961 APT::Configuration::Compressor compressor
;
962 unsigned int openmode
;
963 unsigned long long seekpos
;
974 compressed_fd(-1), compressor_pid(-1), pipe(false),
975 openmode(0), seekpos(0) {};
976 bool InternalClose(std::string
const &FileName
)
979 /* dummy so that the rest can be 'else if's */;
981 else if (gz
!= NULL
) {
982 int const e
= gzclose(gz
);
984 // gzdclose() on empty files always fails with "buffer error" here, ignore that
985 if (e
!= 0 && e
!= Z_BUF_ERROR
)
986 return _error
->Errno("close",_("Problem closing the gzip file %s"), FileName
.c_str());
990 else if (bz2
!= NULL
) {
996 else if (lzma
!= NULL
) {
1003 bool CloseDown(std::string
const &FileName
)
1005 bool const Res
= InternalClose(FileName
);
1007 if (compressor_pid
> 0)
1008 ExecWait(compressor_pid
, "FileFdCompressor", true);
1009 compressor_pid
= -1;
1013 bool InternalStream() const {
1025 ~FileFdPrivate() { CloseDown(""); }
1028 // FileFd Constructors /*{{{*/
1029 FileFd::FileFd(std::string FileName
,unsigned int const Mode
,unsigned long AccessMode
) : iFd(-1), Flags(0), d(NULL
)
1031 Open(FileName
,Mode
, None
, AccessMode
);
1033 FileFd::FileFd(std::string FileName
,unsigned int const Mode
, CompressMode Compress
, unsigned long AccessMode
) : iFd(-1), Flags(0), d(NULL
)
1035 Open(FileName
,Mode
, Compress
, AccessMode
);
1037 FileFd::FileFd() : iFd(-1), Flags(AutoClose
), d(NULL
) {}
1038 FileFd::FileFd(int const Fd
, unsigned int const Mode
, CompressMode Compress
) : iFd(-1), Flags(0), d(NULL
)
1040 OpenDescriptor(Fd
, Mode
, Compress
);
1042 FileFd::FileFd(int const Fd
, bool const AutoClose
) : iFd(-1), Flags(0), d(NULL
)
1044 OpenDescriptor(Fd
, ReadWrite
, None
, AutoClose
);
1047 // FileFd::Open - Open a file /*{{{*/
1048 // ---------------------------------------------------------------------
1049 /* The most commonly used open mode combinations are given with Mode */
1050 bool FileFd::Open(string FileName
,unsigned int const Mode
,CompressMode Compress
, unsigned long const AccessMode
)
1052 if (Mode
== ReadOnlyGzip
)
1053 return Open(FileName
, ReadOnly
, Gzip
, AccessMode
);
1055 if (Compress
== Auto
&& (Mode
& WriteOnly
) == WriteOnly
)
1056 return FileFdError("Autodetection on %s only works in ReadOnly openmode!", FileName
.c_str());
1058 std::vector
<APT::Configuration::Compressor
> const compressors
= APT::Configuration::getCompressors();
1059 std::vector
<APT::Configuration::Compressor
>::const_iterator compressor
= compressors
.begin();
1060 if (Compress
== Auto
)
1062 for (; compressor
!= compressors
.end(); ++compressor
)
1064 std::string file
= FileName
+ compressor
->Extension
;
1065 if (FileExists(file
) == false)
1071 else if (Compress
== Extension
)
1073 std::string::size_type
const found
= FileName
.find_last_of('.');
1075 if (found
!= std::string::npos
)
1077 ext
= FileName
.substr(found
);
1078 if (ext
== ".new" || ext
== ".bak")
1080 std::string::size_type
const found2
= FileName
.find_last_of('.', found
- 1);
1081 if (found2
!= std::string::npos
)
1082 ext
= FileName
.substr(found2
, found
- found2
);
1087 for (; compressor
!= compressors
.end(); ++compressor
)
1088 if (ext
== compressor
->Extension
)
1090 // no matching extension - assume uncompressed (imagine files like 'example.org_Packages')
1091 if (compressor
== compressors
.end())
1092 for (compressor
= compressors
.begin(); compressor
!= compressors
.end(); ++compressor
)
1093 if (compressor
->Name
== ".")
1101 case None
: name
= "."; break;
1102 case Gzip
: name
= "gzip"; break;
1103 case Bzip2
: name
= "bzip2"; break;
1104 case Lzma
: name
= "lzma"; break;
1105 case Xz
: name
= "xz"; break;
1109 return FileFdError("Opening File %s in None, Auto or Extension should be already handled?!?", FileName
.c_str());
1111 for (; compressor
!= compressors
.end(); ++compressor
)
1112 if (compressor
->Name
== name
)
1114 if (compressor
== compressors
.end())
1115 return FileFdError("Can't find a configured compressor %s for file %s", name
.c_str(), FileName
.c_str());
1118 if (compressor
== compressors
.end())
1119 return FileFdError("Can't find a match for specified compressor mode for file %s", FileName
.c_str());
1120 return Open(FileName
, Mode
, *compressor
, AccessMode
);
1122 bool FileFd::Open(string FileName
,unsigned int const Mode
,APT::Configuration::Compressor
const &compressor
, unsigned long const AccessMode
)
1127 if ((Mode
& WriteOnly
) != WriteOnly
&& (Mode
& (Atomic
| Create
| Empty
| Exclusive
)) != 0)
1128 return FileFdError("ReadOnly mode for %s doesn't accept additional flags!", FileName
.c_str());
1129 if ((Mode
& ReadWrite
) == 0)
1130 return FileFdError("No openmode provided in FileFd::Open for %s", FileName
.c_str());
1132 if ((Mode
& Atomic
) == Atomic
)
1136 else if ((Mode
& (Exclusive
| Create
)) == (Exclusive
| Create
))
1138 // for atomic, this will be done by rename in Close()
1139 unlink(FileName
.c_str());
1141 if ((Mode
& Empty
) == Empty
)
1144 if (lstat(FileName
.c_str(),&Buf
) == 0 && S_ISLNK(Buf
.st_mode
))
1145 unlink(FileName
.c_str());
1149 #define if_FLAGGED_SET(FLAG, MODE) if ((Mode & FLAG) == FLAG) fileflags |= MODE
1150 if_FLAGGED_SET(ReadWrite
, O_RDWR
);
1151 else if_FLAGGED_SET(ReadOnly
, O_RDONLY
);
1152 else if_FLAGGED_SET(WriteOnly
, O_WRONLY
);
1154 if_FLAGGED_SET(Create
, O_CREAT
);
1155 if_FLAGGED_SET(Empty
, O_TRUNC
);
1156 if_FLAGGED_SET(Exclusive
, O_EXCL
);
1157 #undef if_FLAGGED_SET
1159 if ((Mode
& Atomic
) == Atomic
)
1161 char *name
= strdup((FileName
+ ".XXXXXX").c_str());
1163 if((iFd
= mkstemp(name
)) == -1)
1166 return FileFdErrno("mkstemp", "Could not create temporary file for %s", FileName
.c_str());
1169 TemporaryFileName
= string(name
);
1172 // umask() will always set the umask and return the previous value, so
1173 // we first set the umask and then reset it to the old value
1174 mode_t
const CurrentUmask
= umask(0);
1175 umask(CurrentUmask
);
1176 // calculate the actual file permissions (just like open/creat)
1177 mode_t
const FilePermissions
= (AccessMode
& ~CurrentUmask
);
1179 if(fchmod(iFd
, FilePermissions
) == -1)
1180 return FileFdErrno("fchmod", "Could not change permissions for temporary file %s", TemporaryFileName
.c_str());
1183 iFd
= open(FileName
.c_str(), fileflags
, AccessMode
);
1185 this->FileName
= FileName
;
1186 if (iFd
== -1 || OpenInternDescriptor(Mode
, compressor
) == false)
1193 return FileFdErrno("open",_("Could not open file %s"), FileName
.c_str());
1196 SetCloseExec(iFd
,true);
1200 // FileFd::OpenDescriptor - Open a filedescriptor /*{{{*/
1201 // ---------------------------------------------------------------------
1203 bool FileFd::OpenDescriptor(int Fd
, unsigned int const Mode
, CompressMode Compress
, bool AutoClose
)
1205 std::vector
<APT::Configuration::Compressor
> const compressors
= APT::Configuration::getCompressors();
1206 std::vector
<APT::Configuration::Compressor
>::const_iterator compressor
= compressors
.begin();
1209 // compat with the old API
1210 if (Mode
== ReadOnlyGzip
&& Compress
== None
)
1215 case None
: name
= "."; break;
1216 case Gzip
: name
= "gzip"; break;
1217 case Bzip2
: name
= "bzip2"; break;
1218 case Lzma
: name
= "lzma"; break;
1219 case Xz
: name
= "xz"; break;
1222 if (AutoClose
== true && Fd
!= -1)
1224 return FileFdError("Opening Fd %d in Auto or Extension compression mode is not supported", Fd
);
1226 for (; compressor
!= compressors
.end(); ++compressor
)
1227 if (compressor
->Name
== name
)
1229 if (compressor
== compressors
.end())
1231 if (AutoClose
== true && Fd
!= -1)
1233 return FileFdError("Can't find a configured compressor %s for file %s", name
.c_str(), FileName
.c_str());
1235 return OpenDescriptor(Fd
, Mode
, *compressor
, AutoClose
);
1237 bool FileFd::OpenDescriptor(int Fd
, unsigned int const Mode
, APT::Configuration::Compressor
const &compressor
, bool AutoClose
)
1240 Flags
= (AutoClose
) ? FileFd::AutoClose
: 0;
1242 this->FileName
= "";
1243 if (OpenInternDescriptor(Mode
, compressor
) == false)
1246 (Flags
& Compressed
) == Compressed
||
1252 return FileFdError(_("Could not open file descriptor %d"), Fd
);
1256 bool FileFd::OpenInternDescriptor(unsigned int const Mode
, APT::Configuration::Compressor
const &compressor
)
1260 if (compressor
.Name
== "." || compressor
.Binary
.empty() == true)
1263 #if defined HAVE_ZLIB || defined HAVE_BZ2 || defined HAVE_LZMA
1264 // the API to open files is similar, so setup to avoid code duplicates later
1265 // and while at it ensure that we close before opening (if its a reopen)
1266 void* (*compress_open
)(int, const char *) = NULL
;
1268 /* dummy so that the rest can be 'else if's */;
1269 #define APT_COMPRESS_INIT(NAME,OPEN) \
1270 else if (compressor.Name == NAME) \
1272 compress_open = (void*(*)(int, const char *)) OPEN; \
1273 if (d != NULL) d->InternalClose(FileName); \
1276 APT_COMPRESS_INIT("gzip", gzdopen
)
1279 APT_COMPRESS_INIT("bzip2", BZ2_bzdopen
)
1282 APT_COMPRESS_INIT("xz", fdopen
)
1283 APT_COMPRESS_INIT("lzma", fdopen
)
1285 #undef APT_COMPRESS_INIT
1290 d
= new FileFdPrivate();
1292 d
->compressor
= compressor
;
1293 #if defined HAVE_ZLIB || defined HAVE_BZ2 || defined HAVE_LZMA
1294 if ((Flags
& AutoClose
) != AutoClose
&& compress_open
!= NULL
)
1296 // Need to duplicate fd here or gz/bz2 close for cleanup will close the fd as well
1297 int const internFd
= dup(iFd
);
1299 return FileFdErrno("OpenInternDescriptor", _("Could not open file descriptor %d"), iFd
);
1305 #if defined HAVE_ZLIB || defined HAVE_BZ2 || defined HAVE_LZMA
1306 if (compress_open
!= NULL
)
1308 void* compress_struct
= NULL
;
1309 if ((Mode
& ReadWrite
) == ReadWrite
)
1310 compress_struct
= compress_open(iFd
, "r+");
1311 else if ((Mode
& WriteOnly
) == WriteOnly
)
1312 compress_struct
= compress_open(iFd
, "w");
1314 compress_struct
= compress_open(iFd
, "r");
1315 if (compress_struct
== NULL
)
1319 /* dummy so that the rest can be 'else if's */;
1321 else if (compressor
.Name
== "gzip")
1322 d
->gz
= (gzFile
) compress_struct
;
1325 else if (compressor
.Name
== "bzip2")
1326 d
->bz2
= (BZFILE
*) compress_struct
;
1329 else if (compressor
.Name
== "xz" || compressor
.Name
== "lzma")
1331 uint32_t const xzlevel
= 6;
1332 uint64_t const memlimit
= UINT64_MAX
;
1333 if (d
->lzma
== NULL
)
1334 d
->lzma
= new FileFdPrivate::LZMAFILE
;
1335 d
->lzma
->file
= (FILE*) compress_struct
;
1336 lzma_stream tmp_stream
= LZMA_STREAM_INIT
;
1337 d
->lzma
->stream
= tmp_stream
;
1339 if ((Mode
& ReadWrite
) == ReadWrite
)
1340 return FileFdError("ReadWrite mode is not supported for file %s", FileName
.c_str());
1342 if ((Mode
& WriteOnly
) == WriteOnly
)
1344 if (compressor
.Name
== "xz")
1346 if (lzma_easy_encoder(&d
->lzma
->stream
, xzlevel
, LZMA_CHECK_CRC32
) != LZMA_OK
)
1351 lzma_options_lzma options
;
1352 lzma_lzma_preset(&options
, xzlevel
);
1353 if (lzma_alone_encoder(&d
->lzma
->stream
, &options
) != LZMA_OK
)
1356 d
->lzma
->compressing
= true;
1360 if (compressor
.Name
== "xz")
1362 if (lzma_auto_decoder(&d
->lzma
->stream
, memlimit
, 0) != LZMA_OK
)
1367 if (lzma_alone_decoder(&d
->lzma
->stream
, memlimit
) != LZMA_OK
)
1370 d
->lzma
->compressing
= false;
1374 Flags
|= Compressed
;
1379 // collect zombies here in case we reopen
1380 if (d
->compressor_pid
> 0)
1381 ExecWait(d
->compressor_pid
, "FileFdCompressor", true);
1383 if ((Mode
& ReadWrite
) == ReadWrite
)
1384 return FileFdError("ReadWrite mode is not supported for file %s", FileName
.c_str());
1386 bool const Comp
= (Mode
& WriteOnly
) == WriteOnly
;
1389 // Handle 'decompression' of empty files
1392 if (Buf
.st_size
== 0 && S_ISFIFO(Buf
.st_mode
) == false)
1395 // We don't need the file open - instead let the compressor open it
1396 // as he properly knows better how to efficiently read from 'his' file
1397 if (FileName
.empty() == false)
1404 // Create a data pipe
1405 int Pipe
[2] = {-1,-1};
1406 if (pipe(Pipe
) != 0)
1407 return FileFdErrno("pipe",_("Failed to create subprocess IPC"));
1408 for (int J
= 0; J
!= 2; J
++)
1409 SetCloseExec(Pipe
[J
],true);
1411 d
->compressed_fd
= iFd
;
1420 d
->compressor_pid
= ExecFork();
1421 if (d
->compressor_pid
== 0)
1425 dup2(d
->compressed_fd
,STDOUT_FILENO
);
1426 dup2(Pipe
[0],STDIN_FILENO
);
1430 if (d
->compressed_fd
!= -1)
1431 dup2(d
->compressed_fd
,STDIN_FILENO
);
1432 dup2(Pipe
[1],STDOUT_FILENO
);
1434 int const nullfd
= open("/dev/null", O_WRONLY
);
1437 dup2(nullfd
,STDERR_FILENO
);
1441 SetCloseExec(STDOUT_FILENO
,false);
1442 SetCloseExec(STDIN_FILENO
,false);
1444 std::vector
<char const*> Args
;
1445 Args
.push_back(compressor
.Binary
.c_str());
1446 std::vector
<std::string
> const * const addArgs
=
1447 (Comp
== true) ? &(compressor
.CompressArgs
) : &(compressor
.UncompressArgs
);
1448 for (std::vector
<std::string
>::const_iterator a
= addArgs
->begin();
1449 a
!= addArgs
->end(); ++a
)
1450 Args
.push_back(a
->c_str());
1451 if (Comp
== false && FileName
.empty() == false)
1453 // commands not needing arguments, do not need to be told about using standard output
1454 // in reality, only testcases with tools like cat, rev, rot13, … are able to trigger this
1455 if (compressor
.CompressArgs
.empty() == false && compressor
.UncompressArgs
.empty() == false)
1456 Args
.push_back("--stdout");
1457 if (TemporaryFileName
.empty() == false)
1458 Args
.push_back(TemporaryFileName
.c_str());
1460 Args
.push_back(FileName
.c_str());
1462 Args
.push_back(NULL
);
1464 execvp(Args
[0],(char **)&Args
[0]);
1465 cerr
<< _("Failed to exec compressor ") << Args
[0] << endl
;
1476 // FileFd::~File - Closes the file /*{{{*/
1477 // ---------------------------------------------------------------------
1478 /* If the proper modes are selected then we close the Fd and possibly
1479 unlink the file on error. */
1484 d
->CloseDown(FileName
);
1489 // FileFd::Read - Read a bit of the file /*{{{*/
1490 // ---------------------------------------------------------------------
1491 /* We are careful to handle interruption by a signal while reading
1493 bool FileFd::Read(void *To
,unsigned long long Size
,unsigned long long *Actual
)
1499 *((char *)To
) = '\0';
1503 /* dummy so that the rest can be 'else if's */;
1505 else if (d
!= NULL
&& d
->gz
!= NULL
)
1506 Res
= gzread(d
->gz
,To
,Size
);
1509 else if (d
!= NULL
&& d
->bz2
!= NULL
)
1510 Res
= BZ2_bzread(d
->bz2
,To
,Size
);
1513 else if (d
!= NULL
&& d
->lzma
!= NULL
)
1515 if (d
->lzma
->eof
== true)
1518 d
->lzma
->stream
.next_out
= (uint8_t *) To
;
1519 d
->lzma
->stream
.avail_out
= Size
;
1520 if (d
->lzma
->stream
.avail_in
== 0)
1522 d
->lzma
->stream
.next_in
= d
->lzma
->buffer
;
1523 d
->lzma
->stream
.avail_in
= fread(d
->lzma
->buffer
, 1, sizeof(d
->lzma
->buffer
)/sizeof(d
->lzma
->buffer
[0]), d
->lzma
->file
);
1525 d
->lzma
->err
= lzma_code(&d
->lzma
->stream
, LZMA_RUN
);
1526 if (d
->lzma
->err
== LZMA_STREAM_END
)
1528 d
->lzma
->eof
= true;
1529 Res
= Size
- d
->lzma
->stream
.avail_out
;
1531 else if (d
->lzma
->err
!= LZMA_OK
)
1538 Res
= Size
- d
->lzma
->stream
.avail_out
;
1541 // lzma run was okay, but produced no output…
1549 Res
= read(iFd
,To
,Size
);
1555 // trick the while-loop into running again
1561 /* dummy so that the rest can be 'else if's */;
1563 else if (d
!= NULL
&& d
->gz
!= NULL
)
1566 char const * const errmsg
= gzerror(d
->gz
, &err
);
1568 return FileFdError("gzread: %s (%d: %s)", _("Read error"), err
, errmsg
);
1572 else if (d
!= NULL
&& d
->bz2
!= NULL
)
1575 char const * const errmsg
= BZ2_bzerror(d
->bz2
, &err
);
1576 if (err
!= BZ_IO_ERROR
)
1577 return FileFdError("BZ2_bzread: %s %s (%d: %s)", FileName
.c_str(), _("Read error"), err
, errmsg
);
1581 else if (d
!= NULL
&& d
->lzma
!= NULL
)
1582 return FileFdError("lzma_read: %s (%d)", _("Read error"), d
->lzma
->err
);
1584 return FileFdErrno("read",_("Read error"));
1587 To
= (char *)To
+ Res
;
1594 while (Res
> 0 && Size
> 0);
1606 return FileFdError(_("read, still have %llu to read but none left"), Size
);
1609 // FileFd::ReadLine - Read a complete line from the file /*{{{*/
1610 // ---------------------------------------------------------------------
1611 /* Beware: This method can be quiet slow for big buffers on UNcompressed
1612 files because of the naive implementation! */
1613 char* FileFd::ReadLine(char *To
, unsigned long long const Size
)
1617 if (d
!= NULL
&& d
->gz
!= NULL
)
1618 return gzgets(d
->gz
, To
, Size
);
1621 unsigned long long read
= 0;
1622 while ((Size
- 1) != read
)
1624 unsigned long long done
= 0;
1625 if (Read(To
+ read
, 1, &done
) == false)
1629 if (To
[read
++] == '\n')
1638 // FileFd::Write - Write to the file /*{{{*/
1639 // ---------------------------------------------------------------------
1641 bool FileFd::Write(const void *From
,unsigned long long Size
)
1648 /* dummy so that the rest can be 'else if's */;
1650 else if (d
!= NULL
&& d
->gz
!= NULL
)
1651 Res
= gzwrite(d
->gz
,From
,Size
);
1654 else if (d
!= NULL
&& d
->bz2
!= NULL
)
1655 Res
= BZ2_bzwrite(d
->bz2
,(void*)From
,Size
);
1658 else if (d
!= NULL
&& d
->lzma
!= NULL
)
1660 d
->lzma
->stream
.next_in
= (uint8_t *)From
;
1661 d
->lzma
->stream
.avail_in
= Size
;
1662 d
->lzma
->stream
.next_out
= d
->lzma
->buffer
;
1663 d
->lzma
->stream
.avail_out
= sizeof(d
->lzma
->buffer
)/sizeof(d
->lzma
->buffer
[0]);
1664 d
->lzma
->err
= lzma_code(&d
->lzma
->stream
, LZMA_RUN
);
1665 if (d
->lzma
->err
!= LZMA_OK
)
1667 size_t const n
= sizeof(d
->lzma
->buffer
)/sizeof(d
->lzma
->buffer
[0]) - d
->lzma
->stream
.avail_out
;
1668 size_t const m
= (n
== 0) ? 0 : fwrite(d
->lzma
->buffer
, 1, n
, d
->lzma
->file
);
1672 Res
= Size
- d
->lzma
->stream
.avail_in
;
1676 Res
= write(iFd
,From
,Size
);
1678 if (Res
< 0 && errno
== EINTR
)
1683 /* dummy so that the rest can be 'else if's */;
1685 else if (d
!= NULL
&& d
->gz
!= NULL
)
1688 char const * const errmsg
= gzerror(d
->gz
, &err
);
1690 return FileFdError("gzwrite: %s (%d: %s)", _("Write error"), err
, errmsg
);
1694 else if (d
!= NULL
&& d
->bz2
!= NULL
)
1697 char const * const errmsg
= BZ2_bzerror(d
->bz2
, &err
);
1698 if (err
!= BZ_IO_ERROR
)
1699 return FileFdError("BZ2_bzwrite: %s (%d: %s)", _("Write error"), err
, errmsg
);
1703 else if (d
!= NULL
&& d
->lzma
!= NULL
)
1704 return FileFdErrno("lzma_fwrite", _("Write error"));
1706 return FileFdErrno("write",_("Write error"));
1709 From
= (char const *)From
+ Res
;
1714 while (Res
> 0 && Size
> 0);
1719 return FileFdError(_("write, still have %llu to write but couldn't"), Size
);
1721 bool FileFd::Write(int Fd
, const void *From
, unsigned long long Size
)
1727 Res
= write(Fd
,From
,Size
);
1728 if (Res
< 0 && errno
== EINTR
)
1731 return _error
->Errno("write",_("Write error"));
1733 From
= (char const *)From
+ Res
;
1736 while (Res
> 0 && Size
> 0);
1741 return _error
->Error(_("write, still have %llu to write but couldn't"), Size
);
1744 // FileFd::Seek - Seek in the file /*{{{*/
1745 // ---------------------------------------------------------------------
1747 bool FileFd::Seek(unsigned long long To
)
1751 if (d
!= NULL
&& (d
->pipe
== true || d
->InternalStream() == true))
1753 // Our poor man seeking in pipes is costly, so try to avoid it
1754 unsigned long long seekpos
= Tell();
1757 else if (seekpos
< To
)
1758 return Skip(To
- seekpos
);
1760 if ((d
->openmode
& ReadOnly
) != ReadOnly
)
1761 return FileFdError("Reopen is only implemented for read-only files!");
1762 d
->InternalClose(FileName
);
1766 if (TemporaryFileName
.empty() == false)
1767 iFd
= open(TemporaryFileName
.c_str(), O_RDONLY
);
1768 else if (FileName
.empty() == false)
1769 iFd
= open(FileName
.c_str(), O_RDONLY
);
1772 if (d
->compressed_fd
> 0)
1773 if (lseek(d
->compressed_fd
, 0, SEEK_SET
) != 0)
1774 iFd
= d
->compressed_fd
;
1776 return FileFdError("Reopen is not implemented for pipes opened with FileFd::OpenDescriptor()!");
1779 if (OpenInternDescriptor(d
->openmode
, d
->compressor
) == false)
1780 return FileFdError("Seek on file %s because it couldn't be reopened", FileName
.c_str());
1790 if (d
!= NULL
&& d
->gz
)
1791 res
= gzseek(d
->gz
,To
,SEEK_SET
);
1794 res
= lseek(iFd
,To
,SEEK_SET
);
1795 if (res
!= (off_t
)To
)
1796 return FileFdError("Unable to seek to %llu", To
);
1803 // FileFd::Skip - Seek in the file /*{{{*/
1804 // ---------------------------------------------------------------------
1806 bool FileFd::Skip(unsigned long long Over
)
1808 if (d
!= NULL
&& (d
->pipe
== true || d
->InternalStream() == true))
1813 unsigned long long toread
= std::min((unsigned long long) sizeof(buffer
), Over
);
1814 if (Read(buffer
, toread
) == false)
1815 return FileFdError("Unable to seek ahead %llu",Over
);
1823 if (d
!= NULL
&& d
->gz
!= NULL
)
1824 res
= gzseek(d
->gz
,Over
,SEEK_CUR
);
1827 res
= lseek(iFd
,Over
,SEEK_CUR
);
1829 return FileFdError("Unable to seek ahead %llu",Over
);
1836 // FileFd::Truncate - Truncate the file /*{{{*/
1837 // ---------------------------------------------------------------------
1839 bool FileFd::Truncate(unsigned long long To
)
1841 // truncating /dev/null is always successful - as we get an error otherwise
1842 if (To
== 0 && FileName
== "/dev/null")
1844 #if defined HAVE_ZLIB || defined HAVE_BZ2 || defined HAVE_LZMA
1845 if (d
!= NULL
&& (d
->InternalStream() == true
1850 return FileFdError("Truncating compressed files is not implemented (%s)", FileName
.c_str());
1852 if (ftruncate(iFd
,To
) != 0)
1853 return FileFdError("Unable to truncate to %llu",To
);
1858 // FileFd::Tell - Current seek position /*{{{*/
1859 // ---------------------------------------------------------------------
1861 unsigned long long FileFd::Tell()
1863 // In theory, we could just return seekpos here always instead of
1864 // seeking around, but not all users of FileFd use always Seek() and co
1865 // so d->seekpos isn't always true and we can just use it as a hint if
1866 // we have nothing else, but not always as an authority…
1867 if (d
!= NULL
&& (d
->pipe
== true || d
->InternalStream() == true))
1872 if (d
!= NULL
&& d
->gz
!= NULL
)
1873 Res
= gztell(d
->gz
);
1876 Res
= lseek(iFd
,0,SEEK_CUR
);
1877 if (Res
== (off_t
)-1)
1878 FileFdErrno("lseek","Failed to determine the current file position");
1884 static bool StatFileFd(char const * const msg
, int const iFd
, std::string
const &FileName
, struct stat
&Buf
, FileFdPrivate
* const d
) /*{{{*/
1886 bool ispipe
= (d
!= NULL
&& d
->pipe
== true);
1887 if (ispipe
== false)
1889 if (fstat(iFd
,&Buf
) != 0)
1890 // higher-level code will generate more meaningful messages,
1891 // even translated this would be meaningless for users
1892 return _error
->Errno("fstat", "Unable to determine %s for fd %i", msg
, iFd
);
1893 if (FileName
.empty() == false)
1894 ispipe
= S_ISFIFO(Buf
.st_mode
);
1897 // for compressor pipes st_size is undefined and at 'best' zero
1900 // we set it here, too, as we get the info here for free
1901 // in theory the Open-methods should take care of it already
1904 if (stat(FileName
.c_str(), &Buf
) != 0)
1905 return _error
->Errno("fstat", "Unable to determine %s for file %s", msg
, FileName
.c_str());
1910 // FileFd::FileSize - Return the size of the file /*{{{*/
1911 unsigned long long FileFd::FileSize()
1914 if (StatFileFd("file size", iFd
, FileName
, Buf
, d
) == false)
1922 // FileFd::ModificationTime - Return the time of last touch /*{{{*/
1923 time_t FileFd::ModificationTime()
1926 if (StatFileFd("modification time", iFd
, FileName
, Buf
, d
) == false)
1931 return Buf
.st_mtime
;
1934 // FileFd::Size - Return the size of the content in the file /*{{{*/
1935 // ---------------------------------------------------------------------
1937 unsigned long long FileFd::Size()
1939 unsigned long long size
= FileSize();
1941 // for compressor pipes st_size is undefined and at 'best' zero,
1942 // so we 'read' the content and 'seek' back - see there
1943 if (d
!= NULL
&& (d
->pipe
== true || (d
->InternalStream() == true && size
> 0)))
1945 unsigned long long const oldSeek
= Tell();
1947 unsigned long long read
= 0;
1949 if (Read(ignore
, sizeof(ignore
), &read
) == false)
1959 // only check gzsize if we are actually a gzip file, just checking for
1960 // "gz" is not sufficient as uncompressed files could be opened with
1961 // gzopen in "direct" mode as well
1962 else if (d
!= NULL
&& d
->gz
&& !gzdirect(d
->gz
) && size
> 0)
1964 off_t
const oldPos
= lseek(iFd
,0,SEEK_CUR
);
1965 /* unfortunately zlib.h doesn't provide a gzsize(), so we have to do
1966 * this ourselves; the original (uncompressed) file size is the last 32
1967 * bits of the file */
1968 // FIXME: Size for gz-files is limited by 32bit… no largefile support
1969 if (lseek(iFd
, -4, SEEK_END
) < 0)
1971 FileFdErrno("lseek","Unable to seek to end of gzipped file");
1975 if (read(iFd
, &size
, 4) != 4)
1977 FileFdErrno("read","Unable to read original size of gzipped file");
1980 size
= le32toh(size
);
1982 if (lseek(iFd
, oldPos
, SEEK_SET
) < 0)
1984 FileFdErrno("lseek","Unable to seek in gzipped file");
1995 // FileFd::Close - Close the file if the close flag is set /*{{{*/
1996 // ---------------------------------------------------------------------
1998 bool FileFd::Close()
2004 if ((Flags
& AutoClose
) == AutoClose
)
2006 if ((Flags
& Compressed
) != Compressed
&& iFd
> 0 && close(iFd
) != 0)
2007 Res
&= _error
->Errno("close",_("Problem closing the file %s"), FileName
.c_str());
2010 Res
&= d
->CloseDown(FileName
);
2016 if ((Flags
& Replace
) == Replace
) {
2017 if (rename(TemporaryFileName
.c_str(), FileName
.c_str()) != 0)
2018 Res
&= _error
->Errno("rename",_("Problem renaming the file %s to %s"), TemporaryFileName
.c_str(), FileName
.c_str());
2020 FileName
= TemporaryFileName
; // for the unlink() below.
2021 TemporaryFileName
.clear();
2026 if ((Flags
& Fail
) == Fail
&& (Flags
& DelOnFail
) == DelOnFail
&&
2027 FileName
.empty() == false)
2028 if (unlink(FileName
.c_str()) != 0)
2029 Res
&= _error
->WarningE("unlnk",_("Problem unlinking the file %s"), FileName
.c_str());
2036 // FileFd::Sync - Sync the file /*{{{*/
2037 // ---------------------------------------------------------------------
2041 if (fsync(iFd
) != 0)
2042 return FileFdErrno("sync",_("Problem syncing the file"));
2046 // FileFd::FileFdErrno - set Fail and call _error->Errno *{{{*/
2047 bool FileFd::FileFdErrno(const char *Function
, const char *Description
,...)
2051 size_t msgSize
= 400;
2052 int const errsv
= errno
;
2055 va_start(args
,Description
);
2056 if (_error
->InsertErrno(GlobalError::ERROR
, Function
, Description
, args
, errsv
, msgSize
) == false)
2063 // FileFd::FileFdError - set Fail and call _error->Error *{{{*/
2064 bool FileFd::FileFdError(const char *Description
,...) {
2067 size_t msgSize
= 400;
2070 va_start(args
,Description
);
2071 if (_error
->Insert(GlobalError::ERROR
, Description
, args
, msgSize
) == false)
2079 APT_DEPRECATED gzFile
FileFd::gzFd() {
2087 // Glob - wrapper around "glob()" /*{{{*/
2088 std::vector
<std::string
> Glob(std::string
const &pattern
, int flags
)
2090 std::vector
<std::string
> result
;
2095 glob_res
= glob(pattern
.c_str(), flags
, NULL
, &globbuf
);
2099 if(glob_res
!= GLOB_NOMATCH
) {
2100 _error
->Errno("glob", "Problem with glob");
2106 for(i
=0;i
<globbuf
.gl_pathc
;i
++)
2107 result
.push_back(string(globbuf
.gl_pathv
[i
]));
2113 std::string
GetTempDir() /*{{{*/
2115 const char *tmpdir
= getenv("TMPDIR");
2123 if (!tmpdir
|| strlen(tmpdir
) == 0 || // tmpdir is set
2124 stat(tmpdir
, &st
) != 0 || (st
.st_mode
& S_IFDIR
) == 0 || // exists and is directory
2125 access(tmpdir
, R_OK
| W_OK
| X_OK
) != 0 // current user has rwx access to directory
2129 return string(tmpdir
);
2132 FileFd
* GetTempFile(std::string
const &Prefix
, bool ImmediateUnlink
, FileFd
* const TmpFd
) /*{{{*/
2135 FileFd
* const Fd
= TmpFd
== NULL
? new FileFd() : TmpFd
;
2137 std::string
const tempdir
= GetTempDir();
2138 snprintf(fn
, sizeof(fn
), "%s/%s.XXXXXX",
2139 tempdir
.c_str(), Prefix
.c_str());
2140 int const fd
= mkstemp(fn
);
2145 _error
->Errno("GetTempFile",_("Unable to mkstemp %s"), fn
);
2148 if (!Fd
->OpenDescriptor(fd
, FileFd::ReadWrite
, FileFd::None
, true))
2150 _error
->Errno("GetTempFile",_("Unable to write to %s"),fn
);
2156 bool Rename(std::string From
, std::string To
) /*{{{*/
2158 if (rename(From
.c_str(),To
.c_str()) != 0)
2160 _error
->Error(_("rename failed, %s (%s -> %s)."),strerror(errno
),
2161 From
.c_str(),To
.c_str());
2167 bool Popen(const char* Args
[], FileFd
&Fd
, pid_t
&Child
, FileFd::OpenMode Mode
)/*{{{*/
2170 if (Mode
!= FileFd::ReadOnly
&& Mode
!= FileFd::WriteOnly
)
2171 return _error
->Error("Popen supports ReadOnly (x)or WriteOnly mode only");
2173 int Pipe
[2] = {-1, -1};
2175 return _error
->Errno("pipe", _("Failed to create subprocess IPC"));
2177 std::set
<int> keep_fds
;
2178 keep_fds
.insert(Pipe
[0]);
2179 keep_fds
.insert(Pipe
[1]);
2180 Child
= ExecFork(keep_fds
);
2182 return _error
->Errno("fork", "Failed to fork");
2185 if(Mode
== FileFd::ReadOnly
)
2190 else if(Mode
== FileFd::WriteOnly
)
2196 if(Mode
== FileFd::ReadOnly
)
2200 } else if(Mode
== FileFd::WriteOnly
)
2203 execv(Args
[0], (char**)Args
);
2206 if(Mode
== FileFd::ReadOnly
)
2210 } else if(Mode
== FileFd::WriteOnly
)
2215 Fd
.OpenDescriptor(fd
, Mode
, FileFd::None
, true);
2220 bool DropPrivileges() /*{{{*/
2222 if(_config
->FindB("Debug::NoDropPrivs", false) == true)
2226 #if defined(PR_SET_NO_NEW_PRIVS) && ( PR_SET_NO_NEW_PRIVS != 38 )
2227 #error "PR_SET_NO_NEW_PRIVS is defined, but with a different value than expected!"
2229 // see prctl(2), needs linux3.5 at runtime - magic constant to avoid it at buildtime
2230 int ret
= prctl(38, 1, 0, 0, 0);
2231 // ignore EINVAL - kernel is too old to understand the option
2232 if(ret
< 0 && errno
!= EINVAL
)
2233 _error
->Warning("PR_SET_NO_NEW_PRIVS failed with %i", ret
);
2236 // empty setting disables privilege dropping - this also ensures
2237 // backward compatibility, see bug #764506
2238 const std::string toUser
= _config
->Find("APT::Sandbox::User");
2242 // uid will be 0 in the end, but gid might be different anyway
2243 uid_t
const old_uid
= getuid();
2244 gid_t
const old_gid
= getgid();
2249 struct passwd
*pw
= getpwnam(toUser
.c_str());
2251 return _error
->Error("No user %s, can not drop rights", toUser
.c_str());
2253 // Do not change the order here, it might break things
2254 if (setgroups(1, &pw
->pw_gid
))
2255 return _error
->Errno("setgroups", "Failed to setgroups");
2257 if (setegid(pw
->pw_gid
) != 0)
2258 return _error
->Errno("setegid", "Failed to setegid");
2260 if (setgid(pw
->pw_gid
) != 0)
2261 return _error
->Errno("setgid", "Failed to setgid");
2263 if (setuid(pw
->pw_uid
) != 0)
2264 return _error
->Errno("setuid", "Failed to setuid");
2266 // the seteuid() is probably uneeded (at least thats what the linux
2267 // man-page says about setuid(2)) but we cargo culted it anyway
2268 if (seteuid(pw
->pw_uid
) != 0)
2269 return _error
->Errno("seteuid", "Failed to seteuid");
2271 // Verify that the user has only a single group, and the correct one
2273 if (getgroups(1, groups
) != 1)
2274 return _error
->Errno("getgroups", "Could not get new groups");
2275 if (groups
[0] != pw
->pw_gid
)
2276 return _error
->Error("Could not switch group");
2278 // Verify that gid, egid, uid, and euid changed
2279 if (getgid() != pw
->pw_gid
)
2280 return _error
->Error("Could not switch group");
2281 if (getegid() != pw
->pw_gid
)
2282 return _error
->Error("Could not switch effective group");
2283 if (getuid() != pw
->pw_uid
)
2284 return _error
->Error("Could not switch user");
2285 if (geteuid() != pw
->pw_uid
)
2286 return _error
->Error("Could not switch effective user");
2288 #ifdef HAVE_GETRESUID
2289 // verify that the saved set-user-id was changed as well
2293 if (getresuid(&ruid
, &euid
, &suid
))
2294 return _error
->Errno("getresuid", "Could not get saved set-user-ID");
2295 if (suid
!= pw
->pw_uid
)
2296 return _error
->Error("Could not switch saved set-user-ID");
2299 #ifdef HAVE_GETRESGID
2300 // verify that the saved set-group-id was changed as well
2304 if (getresgid(&rgid
, &egid
, &sgid
))
2305 return _error
->Errno("getresuid", "Could not get saved set-group-ID");
2306 if (sgid
!= pw
->pw_gid
)
2307 return _error
->Error("Could not switch saved set-group-ID");
2310 // Check that uid and gid changes do not work anymore
2311 if (pw
->pw_gid
!= old_gid
&& (setgid(old_gid
) != -1 || setegid(old_gid
) != -1))
2312 return _error
->Error("Could restore a gid to root, privilege dropping did not work");
2314 if (pw
->pw_uid
!= old_uid
&& (setuid(old_uid
) != -1 || seteuid(old_uid
) != -1))
2315 return _error
->Error("Could restore a uid to root, privilege dropping did not work");