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>
70 #include <sys/prctl.h>
78 // RunScripts - Run a set of scripts from a configuration subtree /*{{{*/
79 // ---------------------------------------------------------------------
81 bool RunScripts(const char *Cnf
)
83 Configuration::Item
const *Opts
= _config
->Tree(Cnf
);
84 if (Opts
== 0 || Opts
->Child
== 0)
88 // Fork for running the system calls
89 pid_t Child
= ExecFork();
94 if (_config
->FindDir("DPkg::Chroot-Directory","/") != "/")
96 std::cerr
<< "Chrooting into "
97 << _config
->FindDir("DPkg::Chroot-Directory")
99 if (chroot(_config
->FindDir("DPkg::Chroot-Directory","/").c_str()) != 0)
103 if (chdir("/tmp/") != 0)
106 unsigned int Count
= 1;
107 for (; Opts
!= 0; Opts
= Opts
->Next
, Count
++)
109 if (Opts
->Value
.empty() == true)
112 if(_config
->FindB("Debug::RunScripts", false) == true)
113 std::clog
<< "Running external script: '"
114 << Opts
->Value
<< "'" << std::endl
;
116 if (system(Opts
->Value
.c_str()) != 0)
122 // Wait for the child
124 while (waitpid(Child
,&Status
,0) != Child
)
128 return _error
->Errno("waitpid","Couldn't wait for subprocess");
131 // Restore sig int/quit
132 signal(SIGQUIT
,SIG_DFL
);
133 signal(SIGINT
,SIG_DFL
);
135 // Check for an error code.
136 if (WIFEXITED(Status
) == 0 || WEXITSTATUS(Status
) != 0)
138 unsigned int Count
= WEXITSTATUS(Status
);
142 for (; Opts
!= 0 && Count
!= 1; Opts
= Opts
->Next
, Count
--);
143 _error
->Error("Problem executing scripts %s '%s'",Cnf
,Opts
->Value
.c_str());
146 return _error
->Error("Sub-process returned an error code");
153 // CopyFile - Buffered copy of a file /*{{{*/
154 // ---------------------------------------------------------------------
155 /* The caller is expected to set things so that failure causes erasure */
156 bool CopyFile(FileFd
&From
,FileFd
&To
)
158 if (From
.IsOpen() == false || To
.IsOpen() == false ||
159 From
.Failed() == true || To
.Failed() == true)
162 // Buffered copy between fds
163 std::unique_ptr
<unsigned char[]> Buf(new unsigned char[64000]);
164 unsigned long long Size
= From
.Size();
167 unsigned long long ToRead
= Size
;
171 if (From
.Read(Buf
.get(),ToRead
) == false ||
172 To
.Write(Buf
.get(),ToRead
) == false)
181 // GetLock - Gets a lock file /*{{{*/
182 // ---------------------------------------------------------------------
183 /* This will create an empty file of the given name and lock it. Once this
184 is done all other calls to GetLock in any other process will fail with
185 -1. The return result is the fd of the file, the call should call
186 close at some time. */
187 int GetLock(string File
,bool Errors
)
189 // GetLock() is used in aptitude on directories with public-write access
190 // Use O_NOFOLLOW here to prevent symlink traversal attacks
191 int FD
= open(File
.c_str(),O_RDWR
| O_CREAT
| O_NOFOLLOW
,0640);
194 // Read only .. can't have locking problems there.
197 _error
->Warning(_("Not using locking for read only lock file %s"),File
.c_str());
198 return dup(0); // Need something for the caller to close
202 _error
->Errno("open",_("Could not open lock file %s"),File
.c_str());
204 // Feh.. We do this to distinguish the lock vs open case..
208 SetCloseExec(FD
,true);
210 // Acquire a write lock
213 fl
.l_whence
= SEEK_SET
;
216 if (fcntl(FD
,F_SETLK
,&fl
) == -1)
218 // always close to not leak resources
225 _error
->Warning(_("Not using locking for nfs mounted lock file %s"),File
.c_str());
226 return dup(0); // Need something for the caller to close
230 _error
->Errno("open",_("Could not get lock %s"),File
.c_str());
238 // FileExists - Check if a file exists /*{{{*/
239 // ---------------------------------------------------------------------
240 /* Beware: Directories are also files! */
241 bool FileExists(string File
)
244 if (stat(File
.c_str(),&Buf
) != 0)
249 // RealFileExists - Check if a file exists and if it is really a file /*{{{*/
250 // ---------------------------------------------------------------------
252 bool RealFileExists(string File
)
255 if (stat(File
.c_str(),&Buf
) != 0)
257 return ((Buf
.st_mode
& S_IFREG
) != 0);
260 // DirectoryExists - Check if a directory exists and is really one /*{{{*/
261 // ---------------------------------------------------------------------
263 bool DirectoryExists(string
const &Path
)
266 if (stat(Path
.c_str(),&Buf
) != 0)
268 return ((Buf
.st_mode
& S_IFDIR
) != 0);
271 // CreateDirectory - poor man's mkdir -p guarded by a parent directory /*{{{*/
272 // ---------------------------------------------------------------------
273 /* This method will create all directories needed for path in good old
274 mkdir -p style but refuses to do this if Parent is not a prefix of
275 this Path. Example: /var/cache/ and /var/cache/apt/archives are given,
276 so it will create apt/archives if /var/cache exists - on the other
277 hand if the parent is /var/lib the creation will fail as this path
278 is not a parent of the path to be generated. */
279 bool CreateDirectory(string
const &Parent
, string
const &Path
)
281 if (Parent
.empty() == true || Path
.empty() == true)
284 if (DirectoryExists(Path
) == true)
287 if (DirectoryExists(Parent
) == false)
290 // we are not going to create directories "into the blue"
291 if (Path
.compare(0, Parent
.length(), Parent
) != 0)
294 vector
<string
> const dirs
= VectorizeString(Path
.substr(Parent
.size()), '/');
295 string progress
= Parent
;
296 for (vector
<string
>::const_iterator d
= dirs
.begin(); d
!= dirs
.end(); ++d
)
298 if (d
->empty() == true)
301 progress
.append("/").append(*d
);
302 if (DirectoryExists(progress
) == true)
305 if (mkdir(progress
.c_str(), 0755) != 0)
311 // CreateAPTDirectoryIfNeeded - ensure that the given directory exists /*{{{*/
312 // ---------------------------------------------------------------------
313 /* a small wrapper around CreateDirectory to check if it exists and to
314 remove the trailing "/apt/" from the parent directory if needed */
315 bool CreateAPTDirectoryIfNeeded(string
const &Parent
, string
const &Path
)
317 if (DirectoryExists(Path
) == true)
320 size_t const len
= Parent
.size();
321 if (len
> 5 && Parent
.find("/apt/", len
- 6, 5) == len
- 5)
323 if (CreateDirectory(Parent
.substr(0,len
-5), Path
) == true)
326 else if (CreateDirectory(Parent
, Path
) == true)
332 // GetListOfFilesInDir - returns a vector of files in the given dir /*{{{*/
333 // ---------------------------------------------------------------------
334 /* If an extension is given only files with this extension are included
335 in the returned vector, otherwise every "normal" file is included. */
336 std::vector
<string
> GetListOfFilesInDir(string
const &Dir
, string
const &Ext
,
337 bool const &SortList
, bool const &AllowNoExt
)
339 std::vector
<string
> ext
;
341 if (Ext
.empty() == false)
343 if (AllowNoExt
== true && ext
.empty() == false)
345 return GetListOfFilesInDir(Dir
, ext
, SortList
);
347 std::vector
<string
> GetListOfFilesInDir(string
const &Dir
, std::vector
<string
> const &Ext
,
348 bool const &SortList
)
350 // Attention debuggers: need to be set with the environment config file!
351 bool const Debug
= _config
->FindB("Debug::GetListOfFilesInDir", false);
354 std::clog
<< "Accept in " << Dir
<< " only files with the following " << Ext
.size() << " extensions:" << std::endl
;
355 if (Ext
.empty() == true)
356 std::clog
<< "\tNO extension" << std::endl
;
358 for (std::vector
<string
>::const_iterator e
= Ext
.begin();
360 std::clog
<< '\t' << (e
->empty() == true ? "NO" : *e
) << " extension" << std::endl
;
363 std::vector
<string
> List
;
365 if (DirectoryExists(Dir
) == false)
367 _error
->Error(_("List of files can't be created as '%s' is not a directory"), Dir
.c_str());
371 Configuration::MatchAgainstConfig
SilentIgnore("Dir::Ignore-Files-Silently");
372 DIR *D
= opendir(Dir
.c_str());
375 _error
->Errno("opendir",_("Unable to read %s"),Dir
.c_str());
379 for (struct dirent
*Ent
= readdir(D
); Ent
!= 0; Ent
= readdir(D
))
381 // skip "hidden" files
382 if (Ent
->d_name
[0] == '.')
385 // Make sure it is a file and not something else
386 string
const File
= flCombine(Dir
,Ent
->d_name
);
387 #ifdef _DIRENT_HAVE_D_TYPE
388 if (Ent
->d_type
!= DT_REG
)
391 if (RealFileExists(File
) == false)
393 // do not show ignoration warnings for directories
395 #ifdef _DIRENT_HAVE_D_TYPE
396 Ent
->d_type
== DT_DIR
||
398 DirectoryExists(File
) == true)
400 if (SilentIgnore
.Match(Ent
->d_name
) == false)
401 _error
->Notice(_("Ignoring '%s' in directory '%s' as it is not a regular file"), Ent
->d_name
, Dir
.c_str());
406 // check for accepted extension:
407 // no extension given -> periods are bad as hell!
408 // extensions given -> "" extension allows no extension
409 if (Ext
.empty() == false)
411 string d_ext
= flExtension(Ent
->d_name
);
412 if (d_ext
== Ent
->d_name
) // no extension
414 if (std::find(Ext
.begin(), Ext
.end(), "") == Ext
.end())
417 std::clog
<< "Bad file: " << Ent
->d_name
<< " → no extension" << std::endl
;
418 if (SilentIgnore
.Match(Ent
->d_name
) == false)
419 _error
->Notice(_("Ignoring file '%s' in directory '%s' as it has no filename extension"), Ent
->d_name
, Dir
.c_str());
423 else if (std::find(Ext
.begin(), Ext
.end(), d_ext
) == Ext
.end())
426 std::clog
<< "Bad file: " << Ent
->d_name
<< " → bad extension »" << flExtension(Ent
->d_name
) << "«" << std::endl
;
427 if (SilentIgnore
.Match(Ent
->d_name
) == false)
428 _error
->Notice(_("Ignoring file '%s' in directory '%s' as it has an invalid filename extension"), Ent
->d_name
, Dir
.c_str());
433 // Skip bad filenames ala run-parts
434 const char *C
= Ent
->d_name
;
436 if (isalpha(*C
) == 0 && isdigit(*C
) == 0
437 && *C
!= '_' && *C
!= '-' && *C
!= ':') {
438 // no required extension -> dot is a bad character
439 if (*C
== '.' && Ext
.empty() == false)
444 // we don't reach the end of the name -> bad character included
448 std::clog
<< "Bad file: " << Ent
->d_name
<< " → bad character »"
449 << *C
<< "« in filename (period allowed: " << (Ext
.empty() ? "no" : "yes") << ")" << std::endl
;
453 // skip filenames which end with a period. These are never valid
457 std::clog
<< "Bad file: " << Ent
->d_name
<< " → Period as last character" << std::endl
;
462 std::clog
<< "Accept file: " << Ent
->d_name
<< " in " << Dir
<< std::endl
;
463 List
.push_back(File
);
467 if (SortList
== true)
468 std::sort(List
.begin(),List
.end());
471 std::vector
<string
> GetListOfFilesInDir(string
const &Dir
, bool SortList
)
473 bool const Debug
= _config
->FindB("Debug::GetListOfFilesInDir", false);
475 std::clog
<< "Accept in " << Dir
<< " all regular files" << std::endl
;
477 std::vector
<string
> List
;
479 if (DirectoryExists(Dir
) == false)
481 _error
->Error(_("List of files can't be created as '%s' is not a directory"), Dir
.c_str());
485 DIR *D
= opendir(Dir
.c_str());
488 _error
->Errno("opendir",_("Unable to read %s"),Dir
.c_str());
492 for (struct dirent
*Ent
= readdir(D
); Ent
!= 0; Ent
= readdir(D
))
494 // skip "hidden" files
495 if (Ent
->d_name
[0] == '.')
498 // Make sure it is a file and not something else
499 string
const File
= flCombine(Dir
,Ent
->d_name
);
500 #ifdef _DIRENT_HAVE_D_TYPE
501 if (Ent
->d_type
!= DT_REG
)
504 if (RealFileExists(File
) == false)
507 std::clog
<< "Bad file: " << Ent
->d_name
<< " → it is not a real file" << std::endl
;
512 // Skip bad filenames ala run-parts
513 const char *C
= Ent
->d_name
;
515 if (isalpha(*C
) == 0 && isdigit(*C
) == 0
516 && *C
!= '_' && *C
!= '-' && *C
!= '.')
519 // we don't reach the end of the name -> bad character included
523 std::clog
<< "Bad file: " << Ent
->d_name
<< " → bad character »" << *C
<< "« in filename" << std::endl
;
527 // skip filenames which end with a period. These are never valid
531 std::clog
<< "Bad file: " << Ent
->d_name
<< " → Period as last character" << std::endl
;
536 std::clog
<< "Accept file: " << Ent
->d_name
<< " in " << Dir
<< std::endl
;
537 List
.push_back(File
);
541 if (SortList
== true)
542 std::sort(List
.begin(),List
.end());
546 // SafeGetCWD - This is a safer getcwd that returns a dynamic string /*{{{*/
547 // ---------------------------------------------------------------------
548 /* We return / on failure. */
551 // Stash the current dir.
554 if (getcwd(S
,sizeof(S
)-2) == 0)
556 unsigned int Len
= strlen(S
);
562 // GetModificationTime - Get the mtime of the given file or -1 on error /*{{{*/
563 // ---------------------------------------------------------------------
564 /* We return / on failure. */
565 time_t GetModificationTime(string
const &Path
)
568 if (stat(Path
.c_str(), &St
) < 0)
573 // flNotDir - Strip the directory from the filename /*{{{*/
574 // ---------------------------------------------------------------------
576 string
flNotDir(string File
)
578 string::size_type Res
= File
.rfind('/');
579 if (Res
== string::npos
)
582 return string(File
,Res
,Res
- File
.length());
585 // flNotFile - Strip the file from the directory name /*{{{*/
586 // ---------------------------------------------------------------------
587 /* Result ends in a / */
588 string
flNotFile(string File
)
590 string::size_type Res
= File
.rfind('/');
591 if (Res
== string::npos
)
594 return string(File
,0,Res
);
597 // flExtension - Return the extension for the file /*{{{*/
598 // ---------------------------------------------------------------------
600 string
flExtension(string File
)
602 string::size_type Res
= File
.rfind('.');
603 if (Res
== string::npos
)
606 return string(File
,Res
,Res
- File
.length());
609 // flNoLink - If file is a symlink then deref it /*{{{*/
610 // ---------------------------------------------------------------------
611 /* If the name is not a link then the returned path is the input. */
612 string
flNoLink(string File
)
615 if (lstat(File
.c_str(),&St
) != 0 || S_ISLNK(St
.st_mode
) == 0)
617 if (stat(File
.c_str(),&St
) != 0)
620 /* Loop resolving the link. There is no need to limit the number of
621 loops because the stat call above ensures that the symlink is not
629 if ((Res
= readlink(NFile
.c_str(),Buffer
,sizeof(Buffer
))) <= 0 ||
630 (size_t)Res
>= sizeof(Buffer
))
633 // Append or replace the previous path
635 if (Buffer
[0] == '/')
638 NFile
= flNotFile(NFile
) + Buffer
;
640 // See if we are done
641 if (lstat(NFile
.c_str(),&St
) != 0)
643 if (S_ISLNK(St
.st_mode
) == 0)
648 // flCombine - Combine a file and a directory /*{{{*/
649 // ---------------------------------------------------------------------
650 /* If the file is an absolute path then it is just returned, otherwise
651 the directory is pre-pended to it. */
652 string
flCombine(string Dir
,string File
)
654 if (File
.empty() == true)
657 if (File
[0] == '/' || Dir
.empty() == true)
659 if (File
.length() >= 2 && File
[0] == '.' && File
[1] == '/')
661 if (Dir
[Dir
.length()-1] == '/')
663 return Dir
+ '/' + File
;
666 // flAbsPath - Return the absolute path of the filename /*{{{*/
667 // ---------------------------------------------------------------------
669 string
flAbsPath(string File
)
671 char *p
= realpath(File
.c_str(), NULL
);
674 _error
->Errno("realpath", "flAbsPath failed");
677 std::string
AbsPath(p
);
682 // SetCloseExec - Set the close on exec flag /*{{{*/
683 // ---------------------------------------------------------------------
685 void SetCloseExec(int Fd
,bool Close
)
687 if (fcntl(Fd
,F_SETFD
,(Close
== false)?0:FD_CLOEXEC
) != 0)
689 cerr
<< "FATAL -> Could not set close on exec " << strerror(errno
) << endl
;
694 // SetNonBlock - Set the nonblocking flag /*{{{*/
695 // ---------------------------------------------------------------------
697 void SetNonBlock(int Fd
,bool Block
)
699 int Flags
= fcntl(Fd
,F_GETFL
) & (~O_NONBLOCK
);
700 if (fcntl(Fd
,F_SETFL
,Flags
| ((Block
== false)?0:O_NONBLOCK
)) != 0)
702 cerr
<< "FATAL -> Could not set non-blocking flag " << strerror(errno
) << endl
;
707 // WaitFd - Wait for a FD to become readable /*{{{*/
708 // ---------------------------------------------------------------------
709 /* This waits for a FD to become readable using select. It is useful for
710 applications making use of non-blocking sockets. The timeout is
712 bool WaitFd(int Fd
,bool write
,unsigned long timeout
)
725 Res
= select(Fd
+1,0,&Set
,0,(timeout
!= 0?&tv
:0));
727 while (Res
< 0 && errno
== EINTR
);
737 Res
= select(Fd
+1,&Set
,0,0,(timeout
!= 0?&tv
:0));
739 while (Res
< 0 && errno
== EINTR
);
748 // MergeKeepFdsFromConfiguration - Merge APT::Keep-Fds configuration /*{{{*/
749 // ---------------------------------------------------------------------
750 /* This is used to merge the APT::Keep-Fds with the provided KeepFDs
753 void MergeKeepFdsFromConfiguration(std::set
<int> &KeepFDs
)
755 Configuration::Item
const *Opts
= _config
->Tree("APT::Keep-Fds");
756 if (Opts
!= 0 && Opts
->Child
!= 0)
759 for (; Opts
!= 0; Opts
= Opts
->Next
)
761 if (Opts
->Value
.empty() == true)
763 int fd
= atoi(Opts
->Value
.c_str());
769 // ExecFork - Magical fork that sanitizes the context before execing /*{{{*/
770 // ---------------------------------------------------------------------
771 /* This is used if you want to cleanse the environment for the forked
772 child, it fixes up the important signals and nukes all of the fds,
773 otherwise acts like normal fork. */
777 // we need to merge the Keep-Fds as external tools like
778 // debconf-apt-progress use it
779 MergeKeepFdsFromConfiguration(KeepFDs
);
780 return ExecFork(KeepFDs
);
783 pid_t
ExecFork(std::set
<int> KeepFDs
)
785 // Fork off the process
786 pid_t Process
= fork();
789 cerr
<< "FATAL -> Failed to fork." << endl
;
793 // Spawn the subprocess
797 signal(SIGPIPE
,SIG_DFL
);
798 signal(SIGQUIT
,SIG_DFL
);
799 signal(SIGINT
,SIG_DFL
);
800 signal(SIGWINCH
,SIG_DFL
);
801 signal(SIGCONT
,SIG_DFL
);
802 signal(SIGTSTP
,SIG_DFL
);
804 DIR *dir
= opendir("/proc/self/fd");
808 while ((ent
= readdir(dir
)))
810 int fd
= atoi(ent
->d_name
);
811 // If fd > 0, it was a fd number and not . or ..
812 if (fd
>= 3 && KeepFDs
.find(fd
) == KeepFDs
.end())
813 fcntl(fd
,F_SETFD
,FD_CLOEXEC
);
817 long ScOpenMax
= sysconf(_SC_OPEN_MAX
);
818 // Close all of our FDs - just in case
819 for (int K
= 3; K
!= ScOpenMax
; K
++)
821 if(KeepFDs
.find(K
) == KeepFDs
.end())
822 fcntl(K
,F_SETFD
,FD_CLOEXEC
);
830 // ExecWait - Fancy waitpid /*{{{*/
831 // ---------------------------------------------------------------------
832 /* Waits for the given sub process. If Reap is set then no errors are
833 generated. Otherwise a failed subprocess will generate a proper descriptive
835 bool ExecWait(pid_t Pid
,const char *Name
,bool Reap
)
840 // Wait and collect the error code
842 while (waitpid(Pid
,&Status
,0) != Pid
)
850 return _error
->Error(_("Waited for %s but it wasn't there"),Name
);
854 // Check for an error code.
855 if (WIFEXITED(Status
) == 0 || WEXITSTATUS(Status
) != 0)
859 if (WIFSIGNALED(Status
) != 0)
861 if( WTERMSIG(Status
) == SIGSEGV
)
862 return _error
->Error(_("Sub-process %s received a segmentation fault."),Name
);
864 return _error
->Error(_("Sub-process %s received signal %u."),Name
, WTERMSIG(Status
));
867 if (WIFEXITED(Status
) != 0)
868 return _error
->Error(_("Sub-process %s returned an error code (%u)"),Name
,WEXITSTATUS(Status
));
870 return _error
->Error(_("Sub-process %s exited unexpectedly"),Name
);
876 // StartsWithGPGClearTextSignature - Check if a file is Pgp/GPG clearsigned /*{{{*/
877 bool StartsWithGPGClearTextSignature(string
const &FileName
)
879 static const char* SIGMSG
= "-----BEGIN PGP SIGNED MESSAGE-----\n";
880 char buffer
[strlen(SIGMSG
)+1];
881 FILE* gpg
= fopen(FileName
.c_str(), "r");
885 char const * const test
= fgets(buffer
, sizeof(buffer
), gpg
);
887 if (test
== NULL
|| strcmp(buffer
, SIGMSG
) != 0)
893 // ChangeOwnerAndPermissionOfFile - set file attributes to requested values /*{{{*/
894 bool ChangeOwnerAndPermissionOfFile(char const * const requester
, char const * const file
, char const * const user
, char const * const group
, mode_t
const mode
)
896 if (strcmp(file
, "/dev/null") == 0)
899 if (getuid() == 0 && strlen(user
) != 0 && strlen(group
) != 0) // if we aren't root, we can't chown, so don't try it
901 // ensure the file is owned by root and has good permissions
902 struct passwd
const * const pw
= getpwnam(user
);
903 struct group
const * const gr
= getgrnam(group
);
904 if (pw
!= NULL
&& gr
!= NULL
&& chown(file
, pw
->pw_uid
, gr
->gr_gid
) != 0)
905 Res
&= _error
->WarningE(requester
, "chown to %s:%s of file %s failed", user
, group
, file
);
907 if (chmod(file
, mode
) != 0)
908 Res
&= _error
->WarningE(requester
, "chmod 0%o of file %s failed", mode
, file
);
913 class FileFdPrivate
{ /*{{{*/
924 uint8_t buffer
[4096];
930 LZMAFILE() : file(NULL
), eof(false), compressing(false) { buffer
[0] = '\0'; }
932 if (compressing
== true)
935 stream
.avail_out
= sizeof(buffer
)/sizeof(buffer
[0]);
936 stream
.next_out
= buffer
;
937 err
= lzma_code(&stream
, LZMA_FINISH
);
938 if (err
!= LZMA_OK
&& err
!= LZMA_STREAM_END
)
940 _error
->Error("~LZMAFILE: Compress finalisation failed");
943 size_t const n
= sizeof(buffer
)/sizeof(buffer
[0]) - stream
.avail_out
;
944 if (n
&& fwrite(buffer
, 1, n
, file
) != n
)
946 _error
->Errno("~LZMAFILE",_("Write error"));
949 if (err
== LZMA_STREAM_END
)
960 pid_t compressor_pid
;
962 APT::Configuration::Compressor compressor
;
963 unsigned int openmode
;
964 unsigned long long seekpos
;
975 compressed_fd(-1), compressor_pid(-1), pipe(false),
976 openmode(0), seekpos(0) {};
977 bool InternalClose(std::string
const &FileName
)
980 /* dummy so that the rest can be 'else if's */;
982 else if (gz
!= NULL
) {
983 int const e
= gzclose(gz
);
985 // gzdclose() on empty files always fails with "buffer error" here, ignore that
986 if (e
!= 0 && e
!= Z_BUF_ERROR
)
987 return _error
->Errno("close",_("Problem closing the gzip file %s"), FileName
.c_str());
991 else if (bz2
!= NULL
) {
997 else if (lzma
!= NULL
) {
1004 bool CloseDown(std::string
const &FileName
)
1006 bool const Res
= InternalClose(FileName
);
1008 if (compressor_pid
> 0)
1009 ExecWait(compressor_pid
, "FileFdCompressor", true);
1010 compressor_pid
= -1;
1014 bool InternalStream() const {
1026 ~FileFdPrivate() { CloseDown(""); }
1029 // FileFd Constructors /*{{{*/
1030 FileFd::FileFd(std::string FileName
,unsigned int const Mode
,unsigned long AccessMode
) : iFd(-1), Flags(0), d(NULL
)
1032 Open(FileName
,Mode
, None
, AccessMode
);
1034 FileFd::FileFd(std::string FileName
,unsigned int const Mode
, CompressMode Compress
, unsigned long AccessMode
) : iFd(-1), Flags(0), d(NULL
)
1036 Open(FileName
,Mode
, Compress
, AccessMode
);
1038 FileFd::FileFd() : iFd(-1), Flags(AutoClose
), d(NULL
) {}
1039 FileFd::FileFd(int const Fd
, unsigned int const Mode
, CompressMode Compress
) : iFd(-1), Flags(0), d(NULL
)
1041 OpenDescriptor(Fd
, Mode
, Compress
);
1043 FileFd::FileFd(int const Fd
, bool const AutoClose
) : iFd(-1), Flags(0), d(NULL
)
1045 OpenDescriptor(Fd
, ReadWrite
, None
, AutoClose
);
1048 // FileFd::Open - Open a file /*{{{*/
1049 // ---------------------------------------------------------------------
1050 /* The most commonly used open mode combinations are given with Mode */
1051 bool FileFd::Open(string FileName
,unsigned int const Mode
,CompressMode Compress
, unsigned long const AccessMode
)
1053 if (Mode
== ReadOnlyGzip
)
1054 return Open(FileName
, ReadOnly
, Gzip
, AccessMode
);
1056 if (Compress
== Auto
&& (Mode
& WriteOnly
) == WriteOnly
)
1057 return FileFdError("Autodetection on %s only works in ReadOnly openmode!", FileName
.c_str());
1059 std::vector
<APT::Configuration::Compressor
> const compressors
= APT::Configuration::getCompressors();
1060 std::vector
<APT::Configuration::Compressor
>::const_iterator compressor
= compressors
.begin();
1061 if (Compress
== Auto
)
1063 for (; compressor
!= compressors
.end(); ++compressor
)
1065 std::string file
= FileName
+ compressor
->Extension
;
1066 if (FileExists(file
) == false)
1072 else if (Compress
== Extension
)
1074 std::string::size_type
const found
= FileName
.find_last_of('.');
1076 if (found
!= std::string::npos
)
1078 ext
= FileName
.substr(found
);
1079 if (ext
== ".new" || ext
== ".bak")
1081 std::string::size_type
const found2
= FileName
.find_last_of('.', found
- 1);
1082 if (found2
!= std::string::npos
)
1083 ext
= FileName
.substr(found2
, found
- found2
);
1088 for (; compressor
!= compressors
.end(); ++compressor
)
1089 if (ext
== compressor
->Extension
)
1091 // no matching extension - assume uncompressed (imagine files like 'example.org_Packages')
1092 if (compressor
== compressors
.end())
1093 for (compressor
= compressors
.begin(); compressor
!= compressors
.end(); ++compressor
)
1094 if (compressor
->Name
== ".")
1102 case None
: name
= "."; break;
1103 case Gzip
: name
= "gzip"; break;
1104 case Bzip2
: name
= "bzip2"; break;
1105 case Lzma
: name
= "lzma"; break;
1106 case Xz
: name
= "xz"; break;
1110 return FileFdError("Opening File %s in None, Auto or Extension should be already handled?!?", FileName
.c_str());
1112 for (; compressor
!= compressors
.end(); ++compressor
)
1113 if (compressor
->Name
== name
)
1115 if (compressor
== compressors
.end())
1116 return FileFdError("Can't find a configured compressor %s for file %s", name
.c_str(), FileName
.c_str());
1119 if (compressor
== compressors
.end())
1120 return FileFdError("Can't find a match for specified compressor mode for file %s", FileName
.c_str());
1121 return Open(FileName
, Mode
, *compressor
, AccessMode
);
1123 bool FileFd::Open(string FileName
,unsigned int const Mode
,APT::Configuration::Compressor
const &compressor
, unsigned long const AccessMode
)
1128 if ((Mode
& WriteOnly
) != WriteOnly
&& (Mode
& (Atomic
| Create
| Empty
| Exclusive
)) != 0)
1129 return FileFdError("ReadOnly mode for %s doesn't accept additional flags!", FileName
.c_str());
1130 if ((Mode
& ReadWrite
) == 0)
1131 return FileFdError("No openmode provided in FileFd::Open for %s", FileName
.c_str());
1133 if ((Mode
& Atomic
) == Atomic
)
1137 else if ((Mode
& (Exclusive
| Create
)) == (Exclusive
| Create
))
1139 // for atomic, this will be done by rename in Close()
1140 unlink(FileName
.c_str());
1142 if ((Mode
& Empty
) == Empty
)
1145 if (lstat(FileName
.c_str(),&Buf
) == 0 && S_ISLNK(Buf
.st_mode
))
1146 unlink(FileName
.c_str());
1150 #define if_FLAGGED_SET(FLAG, MODE) if ((Mode & FLAG) == FLAG) fileflags |= MODE
1151 if_FLAGGED_SET(ReadWrite
, O_RDWR
);
1152 else if_FLAGGED_SET(ReadOnly
, O_RDONLY
);
1153 else if_FLAGGED_SET(WriteOnly
, O_WRONLY
);
1155 if_FLAGGED_SET(Create
, O_CREAT
);
1156 if_FLAGGED_SET(Empty
, O_TRUNC
);
1157 if_FLAGGED_SET(Exclusive
, O_EXCL
);
1158 #undef if_FLAGGED_SET
1160 if ((Mode
& Atomic
) == Atomic
)
1162 char *name
= strdup((FileName
+ ".XXXXXX").c_str());
1164 if((iFd
= mkstemp(name
)) == -1)
1167 return FileFdErrno("mkstemp", "Could not create temporary file for %s", FileName
.c_str());
1170 TemporaryFileName
= string(name
);
1173 // umask() will always set the umask and return the previous value, so
1174 // we first set the umask and then reset it to the old value
1175 mode_t
const CurrentUmask
= umask(0);
1176 umask(CurrentUmask
);
1177 // calculate the actual file permissions (just like open/creat)
1178 mode_t
const FilePermissions
= (AccessMode
& ~CurrentUmask
);
1180 if(fchmod(iFd
, FilePermissions
) == -1)
1181 return FileFdErrno("fchmod", "Could not change permissions for temporary file %s", TemporaryFileName
.c_str());
1184 iFd
= open(FileName
.c_str(), fileflags
, AccessMode
);
1186 this->FileName
= FileName
;
1187 if (iFd
== -1 || OpenInternDescriptor(Mode
, compressor
) == false)
1194 return FileFdErrno("open",_("Could not open file %s"), FileName
.c_str());
1197 SetCloseExec(iFd
,true);
1201 // FileFd::OpenDescriptor - Open a filedescriptor /*{{{*/
1202 // ---------------------------------------------------------------------
1204 bool FileFd::OpenDescriptor(int Fd
, unsigned int const Mode
, CompressMode Compress
, bool AutoClose
)
1206 std::vector
<APT::Configuration::Compressor
> const compressors
= APT::Configuration::getCompressors();
1207 std::vector
<APT::Configuration::Compressor
>::const_iterator compressor
= compressors
.begin();
1210 // compat with the old API
1211 if (Mode
== ReadOnlyGzip
&& Compress
== None
)
1216 case None
: name
= "."; break;
1217 case Gzip
: name
= "gzip"; break;
1218 case Bzip2
: name
= "bzip2"; break;
1219 case Lzma
: name
= "lzma"; break;
1220 case Xz
: name
= "xz"; break;
1223 if (AutoClose
== true && Fd
!= -1)
1225 return FileFdError("Opening Fd %d in Auto or Extension compression mode is not supported", Fd
);
1227 for (; compressor
!= compressors
.end(); ++compressor
)
1228 if (compressor
->Name
== name
)
1230 if (compressor
== compressors
.end())
1232 if (AutoClose
== true && Fd
!= -1)
1234 return FileFdError("Can't find a configured compressor %s for file %s", name
.c_str(), FileName
.c_str());
1236 return OpenDescriptor(Fd
, Mode
, *compressor
, AutoClose
);
1238 bool FileFd::OpenDescriptor(int Fd
, unsigned int const Mode
, APT::Configuration::Compressor
const &compressor
, bool AutoClose
)
1241 Flags
= (AutoClose
) ? FileFd::AutoClose
: 0;
1243 this->FileName
= "";
1244 if (OpenInternDescriptor(Mode
, compressor
) == false)
1247 (Flags
& Compressed
) == Compressed
||
1253 return FileFdError(_("Could not open file descriptor %d"), Fd
);
1257 bool FileFd::OpenInternDescriptor(unsigned int const Mode
, APT::Configuration::Compressor
const &compressor
)
1261 if (compressor
.Name
== "." || compressor
.Binary
.empty() == true)
1264 #if defined HAVE_ZLIB || defined HAVE_BZ2 || defined HAVE_LZMA
1265 // the API to open files is similar, so setup to avoid code duplicates later
1266 // and while at it ensure that we close before opening (if its a reopen)
1267 void* (*compress_open
)(int, const char *) = NULL
;
1269 /* dummy so that the rest can be 'else if's */;
1270 #define APT_COMPRESS_INIT(NAME,OPEN) \
1271 else if (compressor.Name == NAME) \
1273 compress_open = (void*(*)(int, const char *)) OPEN; \
1274 if (d != NULL) d->InternalClose(FileName); \
1277 APT_COMPRESS_INIT("gzip", gzdopen
)
1280 APT_COMPRESS_INIT("bzip2", BZ2_bzdopen
)
1283 APT_COMPRESS_INIT("xz", fdopen
)
1284 APT_COMPRESS_INIT("lzma", fdopen
)
1286 #undef APT_COMPRESS_INIT
1291 d
= new FileFdPrivate();
1293 d
->compressor
= compressor
;
1294 #if defined HAVE_ZLIB || defined HAVE_BZ2 || defined HAVE_LZMA
1295 if ((Flags
& AutoClose
) != AutoClose
&& compress_open
!= NULL
)
1297 // Need to duplicate fd here or gz/bz2 close for cleanup will close the fd as well
1298 int const internFd
= dup(iFd
);
1300 return FileFdErrno("OpenInternDescriptor", _("Could not open file descriptor %d"), iFd
);
1306 #if defined HAVE_ZLIB || defined HAVE_BZ2 || defined HAVE_LZMA
1307 if (compress_open
!= NULL
)
1309 void* compress_struct
= NULL
;
1310 if ((Mode
& ReadWrite
) == ReadWrite
)
1311 compress_struct
= compress_open(iFd
, "r+");
1312 else if ((Mode
& WriteOnly
) == WriteOnly
)
1313 compress_struct
= compress_open(iFd
, "w");
1315 compress_struct
= compress_open(iFd
, "r");
1316 if (compress_struct
== NULL
)
1320 /* dummy so that the rest can be 'else if's */;
1322 else if (compressor
.Name
== "gzip")
1323 d
->gz
= (gzFile
) compress_struct
;
1326 else if (compressor
.Name
== "bzip2")
1327 d
->bz2
= (BZFILE
*) compress_struct
;
1330 else if (compressor
.Name
== "xz" || compressor
.Name
== "lzma")
1332 uint32_t const xzlevel
= 6;
1333 uint64_t const memlimit
= UINT64_MAX
;
1334 if (d
->lzma
== NULL
)
1335 d
->lzma
= new FileFdPrivate::LZMAFILE
;
1336 d
->lzma
->file
= (FILE*) compress_struct
;
1337 lzma_stream tmp_stream
= LZMA_STREAM_INIT
;
1338 d
->lzma
->stream
= tmp_stream
;
1340 if ((Mode
& ReadWrite
) == ReadWrite
)
1341 return FileFdError("ReadWrite mode is not supported for file %s", FileName
.c_str());
1343 if ((Mode
& WriteOnly
) == WriteOnly
)
1345 if (compressor
.Name
== "xz")
1347 if (lzma_easy_encoder(&d
->lzma
->stream
, xzlevel
, LZMA_CHECK_CRC32
) != LZMA_OK
)
1352 lzma_options_lzma options
;
1353 lzma_lzma_preset(&options
, xzlevel
);
1354 if (lzma_alone_encoder(&d
->lzma
->stream
, &options
) != LZMA_OK
)
1357 d
->lzma
->compressing
= true;
1361 if (compressor
.Name
== "xz")
1363 if (lzma_auto_decoder(&d
->lzma
->stream
, memlimit
, 0) != LZMA_OK
)
1368 if (lzma_alone_decoder(&d
->lzma
->stream
, memlimit
) != LZMA_OK
)
1371 d
->lzma
->compressing
= false;
1375 Flags
|= Compressed
;
1380 // collect zombies here in case we reopen
1381 if (d
->compressor_pid
> 0)
1382 ExecWait(d
->compressor_pid
, "FileFdCompressor", true);
1384 if ((Mode
& ReadWrite
) == ReadWrite
)
1385 return FileFdError("ReadWrite mode is not supported for file %s", FileName
.c_str());
1387 bool const Comp
= (Mode
& WriteOnly
) == WriteOnly
;
1390 // Handle 'decompression' of empty files
1393 if (Buf
.st_size
== 0 && S_ISFIFO(Buf
.st_mode
) == false)
1396 // We don't need the file open - instead let the compressor open it
1397 // as he properly knows better how to efficiently read from 'his' file
1398 if (FileName
.empty() == false)
1405 // Create a data pipe
1406 int Pipe
[2] = {-1,-1};
1407 if (pipe(Pipe
) != 0)
1408 return FileFdErrno("pipe",_("Failed to create subprocess IPC"));
1409 for (int J
= 0; J
!= 2; J
++)
1410 SetCloseExec(Pipe
[J
],true);
1412 d
->compressed_fd
= iFd
;
1421 d
->compressor_pid
= ExecFork();
1422 if (d
->compressor_pid
== 0)
1426 dup2(d
->compressed_fd
,STDOUT_FILENO
);
1427 dup2(Pipe
[0],STDIN_FILENO
);
1431 if (d
->compressed_fd
!= -1)
1432 dup2(d
->compressed_fd
,STDIN_FILENO
);
1433 dup2(Pipe
[1],STDOUT_FILENO
);
1435 int const nullfd
= open("/dev/null", O_WRONLY
);
1438 dup2(nullfd
,STDERR_FILENO
);
1442 SetCloseExec(STDOUT_FILENO
,false);
1443 SetCloseExec(STDIN_FILENO
,false);
1445 std::vector
<char const*> Args
;
1446 Args
.push_back(compressor
.Binary
.c_str());
1447 std::vector
<std::string
> const * const addArgs
=
1448 (Comp
== true) ? &(compressor
.CompressArgs
) : &(compressor
.UncompressArgs
);
1449 for (std::vector
<std::string
>::const_iterator a
= addArgs
->begin();
1450 a
!= addArgs
->end(); ++a
)
1451 Args
.push_back(a
->c_str());
1452 if (Comp
== false && FileName
.empty() == false)
1454 // commands not needing arguments, do not need to be told about using standard output
1455 // in reality, only testcases with tools like cat, rev, rot13, … are able to trigger this
1456 if (compressor
.CompressArgs
.empty() == false && compressor
.UncompressArgs
.empty() == false)
1457 Args
.push_back("--stdout");
1458 if (TemporaryFileName
.empty() == false)
1459 Args
.push_back(TemporaryFileName
.c_str());
1461 Args
.push_back(FileName
.c_str());
1463 Args
.push_back(NULL
);
1465 execvp(Args
[0],(char **)&Args
[0]);
1466 cerr
<< _("Failed to exec compressor ") << Args
[0] << endl
;
1477 // FileFd::~File - Closes the file /*{{{*/
1478 // ---------------------------------------------------------------------
1479 /* If the proper modes are selected then we close the Fd and possibly
1480 unlink the file on error. */
1485 d
->CloseDown(FileName
);
1490 // FileFd::Read - Read a bit of the file /*{{{*/
1491 // ---------------------------------------------------------------------
1492 /* We are careful to handle interruption by a signal while reading
1494 bool FileFd::Read(void *To
,unsigned long long Size
,unsigned long long *Actual
)
1500 *((char *)To
) = '\0';
1504 /* dummy so that the rest can be 'else if's */;
1506 else if (d
!= NULL
&& d
->gz
!= NULL
)
1507 Res
= gzread(d
->gz
,To
,Size
);
1510 else if (d
!= NULL
&& d
->bz2
!= NULL
)
1511 Res
= BZ2_bzread(d
->bz2
,To
,Size
);
1514 else if (d
!= NULL
&& d
->lzma
!= NULL
)
1516 if (d
->lzma
->eof
== true)
1519 d
->lzma
->stream
.next_out
= (uint8_t *) To
;
1520 d
->lzma
->stream
.avail_out
= Size
;
1521 if (d
->lzma
->stream
.avail_in
== 0)
1523 d
->lzma
->stream
.next_in
= d
->lzma
->buffer
;
1524 d
->lzma
->stream
.avail_in
= fread(d
->lzma
->buffer
, 1, sizeof(d
->lzma
->buffer
)/sizeof(d
->lzma
->buffer
[0]), d
->lzma
->file
);
1526 d
->lzma
->err
= lzma_code(&d
->lzma
->stream
, LZMA_RUN
);
1527 if (d
->lzma
->err
== LZMA_STREAM_END
)
1529 d
->lzma
->eof
= true;
1530 Res
= Size
- d
->lzma
->stream
.avail_out
;
1532 else if (d
->lzma
->err
!= LZMA_OK
)
1539 Res
= Size
- d
->lzma
->stream
.avail_out
;
1542 // lzma run was okay, but produced no output…
1550 Res
= read(iFd
,To
,Size
);
1556 // trick the while-loop into running again
1562 /* dummy so that the rest can be 'else if's */;
1564 else if (d
!= NULL
&& d
->gz
!= NULL
)
1567 char const * const errmsg
= gzerror(d
->gz
, &err
);
1569 return FileFdError("gzread: %s (%d: %s)", _("Read error"), err
, errmsg
);
1573 else if (d
!= NULL
&& d
->bz2
!= NULL
)
1576 char const * const errmsg
= BZ2_bzerror(d
->bz2
, &err
);
1577 if (err
!= BZ_IO_ERROR
)
1578 return FileFdError("BZ2_bzread: %s %s (%d: %s)", FileName
.c_str(), _("Read error"), err
, errmsg
);
1582 else if (d
!= NULL
&& d
->lzma
!= NULL
)
1583 return FileFdError("lzma_read: %s (%d)", _("Read error"), d
->lzma
->err
);
1585 return FileFdErrno("read",_("Read error"));
1588 To
= (char *)To
+ Res
;
1595 while (Res
> 0 && Size
> 0);
1607 return FileFdError(_("read, still have %llu to read but none left"), Size
);
1610 // FileFd::ReadLine - Read a complete line from the file /*{{{*/
1611 // ---------------------------------------------------------------------
1612 /* Beware: This method can be quiet slow for big buffers on UNcompressed
1613 files because of the naive implementation! */
1614 char* FileFd::ReadLine(char *To
, unsigned long long const Size
)
1618 if (d
!= NULL
&& d
->gz
!= NULL
)
1619 return gzgets(d
->gz
, To
, Size
);
1622 unsigned long long read
= 0;
1623 while ((Size
- 1) != read
)
1625 unsigned long long done
= 0;
1626 if (Read(To
+ read
, 1, &done
) == false)
1630 if (To
[read
++] == '\n')
1639 // FileFd::Write - Write to the file /*{{{*/
1640 // ---------------------------------------------------------------------
1642 bool FileFd::Write(const void *From
,unsigned long long Size
)
1649 /* dummy so that the rest can be 'else if's */;
1651 else if (d
!= NULL
&& d
->gz
!= NULL
)
1652 Res
= gzwrite(d
->gz
,From
,Size
);
1655 else if (d
!= NULL
&& d
->bz2
!= NULL
)
1656 Res
= BZ2_bzwrite(d
->bz2
,(void*)From
,Size
);
1659 else if (d
!= NULL
&& d
->lzma
!= NULL
)
1661 d
->lzma
->stream
.next_in
= (uint8_t *)From
;
1662 d
->lzma
->stream
.avail_in
= Size
;
1663 d
->lzma
->stream
.next_out
= d
->lzma
->buffer
;
1664 d
->lzma
->stream
.avail_out
= sizeof(d
->lzma
->buffer
)/sizeof(d
->lzma
->buffer
[0]);
1665 d
->lzma
->err
= lzma_code(&d
->lzma
->stream
, LZMA_RUN
);
1666 if (d
->lzma
->err
!= LZMA_OK
)
1668 size_t const n
= sizeof(d
->lzma
->buffer
)/sizeof(d
->lzma
->buffer
[0]) - d
->lzma
->stream
.avail_out
;
1669 size_t const m
= (n
== 0) ? 0 : fwrite(d
->lzma
->buffer
, 1, n
, d
->lzma
->file
);
1673 Res
= Size
- d
->lzma
->stream
.avail_in
;
1677 Res
= write(iFd
,From
,Size
);
1679 if (Res
< 0 && errno
== EINTR
)
1684 /* dummy so that the rest can be 'else if's */;
1686 else if (d
!= NULL
&& d
->gz
!= NULL
)
1689 char const * const errmsg
= gzerror(d
->gz
, &err
);
1691 return FileFdError("gzwrite: %s (%d: %s)", _("Write error"), err
, errmsg
);
1695 else if (d
!= NULL
&& d
->bz2
!= NULL
)
1698 char const * const errmsg
= BZ2_bzerror(d
->bz2
, &err
);
1699 if (err
!= BZ_IO_ERROR
)
1700 return FileFdError("BZ2_bzwrite: %s (%d: %s)", _("Write error"), err
, errmsg
);
1704 else if (d
!= NULL
&& d
->lzma
!= NULL
)
1705 return FileFdErrno("lzma_fwrite", _("Write error"));
1707 return FileFdErrno("write",_("Write error"));
1710 From
= (char const *)From
+ Res
;
1715 while (Res
> 0 && Size
> 0);
1720 return FileFdError(_("write, still have %llu to write but couldn't"), Size
);
1722 bool FileFd::Write(int Fd
, const void *From
, unsigned long long Size
)
1728 Res
= write(Fd
,From
,Size
);
1729 if (Res
< 0 && errno
== EINTR
)
1732 return _error
->Errno("write",_("Write error"));
1734 From
= (char const *)From
+ Res
;
1737 while (Res
> 0 && Size
> 0);
1742 return _error
->Error(_("write, still have %llu to write but couldn't"), Size
);
1745 // FileFd::Seek - Seek in the file /*{{{*/
1746 // ---------------------------------------------------------------------
1748 bool FileFd::Seek(unsigned long long To
)
1752 if (d
!= NULL
&& (d
->pipe
== true || d
->InternalStream() == true))
1754 // Our poor man seeking in pipes is costly, so try to avoid it
1755 unsigned long long seekpos
= Tell();
1758 else if (seekpos
< To
)
1759 return Skip(To
- seekpos
);
1761 if ((d
->openmode
& ReadOnly
) != ReadOnly
)
1762 return FileFdError("Reopen is only implemented for read-only files!");
1763 d
->InternalClose(FileName
);
1767 if (TemporaryFileName
.empty() == false)
1768 iFd
= open(TemporaryFileName
.c_str(), O_RDONLY
);
1769 else if (FileName
.empty() == false)
1770 iFd
= open(FileName
.c_str(), O_RDONLY
);
1773 if (d
->compressed_fd
> 0)
1774 if (lseek(d
->compressed_fd
, 0, SEEK_SET
) != 0)
1775 iFd
= d
->compressed_fd
;
1777 return FileFdError("Reopen is not implemented for pipes opened with FileFd::OpenDescriptor()!");
1780 if (OpenInternDescriptor(d
->openmode
, d
->compressor
) == false)
1781 return FileFdError("Seek on file %s because it couldn't be reopened", FileName
.c_str());
1791 if (d
!= NULL
&& d
->gz
)
1792 res
= gzseek(d
->gz
,To
,SEEK_SET
);
1795 res
= lseek(iFd
,To
,SEEK_SET
);
1796 if (res
!= (off_t
)To
)
1797 return FileFdError("Unable to seek to %llu", To
);
1804 // FileFd::Skip - Seek in the file /*{{{*/
1805 // ---------------------------------------------------------------------
1807 bool FileFd::Skip(unsigned long long Over
)
1809 if (d
!= NULL
&& (d
->pipe
== true || d
->InternalStream() == true))
1814 unsigned long long toread
= std::min((unsigned long long) sizeof(buffer
), Over
);
1815 if (Read(buffer
, toread
) == false)
1816 return FileFdError("Unable to seek ahead %llu",Over
);
1824 if (d
!= NULL
&& d
->gz
!= NULL
)
1825 res
= gzseek(d
->gz
,Over
,SEEK_CUR
);
1828 res
= lseek(iFd
,Over
,SEEK_CUR
);
1830 return FileFdError("Unable to seek ahead %llu",Over
);
1837 // FileFd::Truncate - Truncate the file /*{{{*/
1838 // ---------------------------------------------------------------------
1840 bool FileFd::Truncate(unsigned long long To
)
1842 // truncating /dev/null is always successful - as we get an error otherwise
1843 if (To
== 0 && FileName
== "/dev/null")
1845 #if defined HAVE_ZLIB || defined HAVE_BZ2 || defined HAVE_LZMA
1846 if (d
!= NULL
&& (d
->InternalStream() == true
1851 return FileFdError("Truncating compressed files is not implemented (%s)", FileName
.c_str());
1853 if (ftruncate(iFd
,To
) != 0)
1854 return FileFdError("Unable to truncate to %llu",To
);
1859 // FileFd::Tell - Current seek position /*{{{*/
1860 // ---------------------------------------------------------------------
1862 unsigned long long FileFd::Tell()
1864 // In theory, we could just return seekpos here always instead of
1865 // seeking around, but not all users of FileFd use always Seek() and co
1866 // so d->seekpos isn't always true and we can just use it as a hint if
1867 // we have nothing else, but not always as an authority…
1868 if (d
!= NULL
&& (d
->pipe
== true || d
->InternalStream() == true))
1873 if (d
!= NULL
&& d
->gz
!= NULL
)
1874 Res
= gztell(d
->gz
);
1877 Res
= lseek(iFd
,0,SEEK_CUR
);
1878 if (Res
== (off_t
)-1)
1879 FileFdErrno("lseek","Failed to determine the current file position");
1885 static bool StatFileFd(char const * const msg
, int const iFd
, std::string
const &FileName
, struct stat
&Buf
, FileFdPrivate
* const d
) /*{{{*/
1887 bool ispipe
= (d
!= NULL
&& d
->pipe
== true);
1888 if (ispipe
== false)
1890 if (fstat(iFd
,&Buf
) != 0)
1891 // higher-level code will generate more meaningful messages,
1892 // even translated this would be meaningless for users
1893 return _error
->Errno("fstat", "Unable to determine %s for fd %i", msg
, iFd
);
1894 if (FileName
.empty() == false)
1895 ispipe
= S_ISFIFO(Buf
.st_mode
);
1898 // for compressor pipes st_size is undefined and at 'best' zero
1901 // we set it here, too, as we get the info here for free
1902 // in theory the Open-methods should take care of it already
1905 if (stat(FileName
.c_str(), &Buf
) != 0)
1906 return _error
->Errno("fstat", "Unable to determine %s for file %s", msg
, FileName
.c_str());
1911 // FileFd::FileSize - Return the size of the file /*{{{*/
1912 unsigned long long FileFd::FileSize()
1915 if (StatFileFd("file size", iFd
, FileName
, Buf
, d
) == false)
1923 // FileFd::ModificationTime - Return the time of last touch /*{{{*/
1924 time_t FileFd::ModificationTime()
1927 if (StatFileFd("modification time", iFd
, FileName
, Buf
, d
) == false)
1932 return Buf
.st_mtime
;
1935 // FileFd::Size - Return the size of the content in the file /*{{{*/
1936 // ---------------------------------------------------------------------
1938 unsigned long long FileFd::Size()
1940 unsigned long long size
= FileSize();
1942 // for compressor pipes st_size is undefined and at 'best' zero,
1943 // so we 'read' the content and 'seek' back - see there
1944 if (d
!= NULL
&& (d
->pipe
== true || (d
->InternalStream() == true && size
> 0)))
1946 unsigned long long const oldSeek
= Tell();
1948 unsigned long long read
= 0;
1950 if (Read(ignore
, sizeof(ignore
), &read
) == false)
1960 // only check gzsize if we are actually a gzip file, just checking for
1961 // "gz" is not sufficient as uncompressed files could be opened with
1962 // gzopen in "direct" mode as well
1963 else if (d
!= NULL
&& d
->gz
&& !gzdirect(d
->gz
) && size
> 0)
1965 off_t
const oldPos
= lseek(iFd
,0,SEEK_CUR
);
1966 /* unfortunately zlib.h doesn't provide a gzsize(), so we have to do
1967 * this ourselves; the original (uncompressed) file size is the last 32
1968 * bits of the file */
1969 // FIXME: Size for gz-files is limited by 32bit… no largefile support
1970 if (lseek(iFd
, -4, SEEK_END
) < 0)
1972 FileFdErrno("lseek","Unable to seek to end of gzipped file");
1976 if (read(iFd
, &size
, 4) != 4)
1978 FileFdErrno("read","Unable to read original size of gzipped file");
1981 size
= le32toh(size
);
1983 if (lseek(iFd
, oldPos
, SEEK_SET
) < 0)
1985 FileFdErrno("lseek","Unable to seek in gzipped file");
1996 // FileFd::Close - Close the file if the close flag is set /*{{{*/
1997 // ---------------------------------------------------------------------
1999 bool FileFd::Close()
2005 if ((Flags
& AutoClose
) == AutoClose
)
2007 if ((Flags
& Compressed
) != Compressed
&& iFd
> 0 && close(iFd
) != 0)
2008 Res
&= _error
->Errno("close",_("Problem closing the file %s"), FileName
.c_str());
2013 Res
&= d
->CloseDown(FileName
);
2018 if ((Flags
& Replace
) == Replace
) {
2019 if (rename(TemporaryFileName
.c_str(), FileName
.c_str()) != 0)
2020 Res
&= _error
->Errno("rename",_("Problem renaming the file %s to %s"), TemporaryFileName
.c_str(), FileName
.c_str());
2022 FileName
= TemporaryFileName
; // for the unlink() below.
2023 TemporaryFileName
.clear();
2028 if ((Flags
& Fail
) == Fail
&& (Flags
& DelOnFail
) == DelOnFail
&&
2029 FileName
.empty() == false)
2030 if (unlink(FileName
.c_str()) != 0)
2031 Res
&= _error
->WarningE("unlnk",_("Problem unlinking the file %s"), FileName
.c_str());
2038 // FileFd::Sync - Sync the file /*{{{*/
2039 // ---------------------------------------------------------------------
2043 if (fsync(iFd
) != 0)
2044 return FileFdErrno("sync",_("Problem syncing the file"));
2048 // FileFd::FileFdErrno - set Fail and call _error->Errno *{{{*/
2049 bool FileFd::FileFdErrno(const char *Function
, const char *Description
,...)
2053 size_t msgSize
= 400;
2054 int const errsv
= errno
;
2057 va_start(args
,Description
);
2058 if (_error
->InsertErrno(GlobalError::ERROR
, Function
, Description
, args
, errsv
, msgSize
) == false)
2065 // FileFd::FileFdError - set Fail and call _error->Error *{{{*/
2066 bool FileFd::FileFdError(const char *Description
,...) {
2069 size_t msgSize
= 400;
2072 va_start(args
,Description
);
2073 if (_error
->Insert(GlobalError::ERROR
, Description
, args
, msgSize
) == false)
2081 APT_DEPRECATED gzFile
FileFd::gzFd() {
2089 // Glob - wrapper around "glob()" /*{{{*/
2090 std::vector
<std::string
> Glob(std::string
const &pattern
, int flags
)
2092 std::vector
<std::string
> result
;
2097 glob_res
= glob(pattern
.c_str(), flags
, NULL
, &globbuf
);
2101 if(glob_res
!= GLOB_NOMATCH
) {
2102 _error
->Errno("glob", "Problem with glob");
2108 for(i
=0;i
<globbuf
.gl_pathc
;i
++)
2109 result
.push_back(string(globbuf
.gl_pathv
[i
]));
2115 std::string
GetTempDir() /*{{{*/
2117 const char *tmpdir
= getenv("TMPDIR");
2125 if (!tmpdir
|| strlen(tmpdir
) == 0 || // tmpdir is set
2126 stat(tmpdir
, &st
) != 0 || (st
.st_mode
& S_IFDIR
) == 0) // exists and is directory
2128 else if (geteuid() != 0 && // root can do everything anyway
2129 faccessat(-1, tmpdir
, R_OK
| W_OK
| X_OK
, AT_EACCESS
| AT_SYMLINK_NOFOLLOW
) != 0) // current user has rwx access to directory
2132 return string(tmpdir
);
2134 std::string
GetTempDir(std::string
const &User
)
2136 // no need/possibility to drop privs
2137 if(getuid() != 0 || User
.empty() || User
== "root")
2138 return GetTempDir();
2140 struct passwd
const * const pw
= getpwnam(User
.c_str());
2142 return GetTempDir();
2144 gid_t
const old_euid
= geteuid();
2145 gid_t
const old_egid
= getegid();
2146 if (setegid(pw
->pw_gid
) != 0)
2147 _error
->Errno("setegid", "setegid %u failed", pw
->pw_gid
);
2148 if (seteuid(pw
->pw_uid
) != 0)
2149 _error
->Errno("seteuid", "seteuid %u failed", pw
->pw_uid
);
2151 std::string
const tmp
= GetTempDir();
2153 if (seteuid(old_euid
) != 0)
2154 _error
->Errno("seteuid", "seteuid %u failed", old_euid
);
2155 if (setegid(old_egid
) != 0)
2156 _error
->Errno("setegid", "setegid %u failed", old_egid
);
2161 FileFd
* GetTempFile(std::string
const &Prefix
, bool ImmediateUnlink
, FileFd
* const TmpFd
) /*{{{*/
2164 FileFd
* const Fd
= TmpFd
== NULL
? new FileFd() : TmpFd
;
2166 std::string
const tempdir
= GetTempDir();
2167 snprintf(fn
, sizeof(fn
), "%s/%s.XXXXXX",
2168 tempdir
.c_str(), Prefix
.c_str());
2169 int const fd
= mkstemp(fn
);
2174 _error
->Errno("GetTempFile",_("Unable to mkstemp %s"), fn
);
2177 if (!Fd
->OpenDescriptor(fd
, FileFd::ReadWrite
, FileFd::None
, true))
2179 _error
->Errno("GetTempFile",_("Unable to write to %s"),fn
);
2185 bool Rename(std::string From
, std::string To
) /*{{{*/
2187 if (rename(From
.c_str(),To
.c_str()) != 0)
2189 _error
->Error(_("rename failed, %s (%s -> %s)."),strerror(errno
),
2190 From
.c_str(),To
.c_str());
2196 bool Popen(const char* Args
[], FileFd
&Fd
, pid_t
&Child
, FileFd::OpenMode Mode
)/*{{{*/
2199 if (Mode
!= FileFd::ReadOnly
&& Mode
!= FileFd::WriteOnly
)
2200 return _error
->Error("Popen supports ReadOnly (x)or WriteOnly mode only");
2202 int Pipe
[2] = {-1, -1};
2204 return _error
->Errno("pipe", _("Failed to create subprocess IPC"));
2206 std::set
<int> keep_fds
;
2207 keep_fds
.insert(Pipe
[0]);
2208 keep_fds
.insert(Pipe
[1]);
2209 Child
= ExecFork(keep_fds
);
2211 return _error
->Errno("fork", "Failed to fork");
2214 if(Mode
== FileFd::ReadOnly
)
2219 else if(Mode
== FileFd::WriteOnly
)
2225 if(Mode
== FileFd::ReadOnly
)
2229 } else if(Mode
== FileFd::WriteOnly
)
2232 execv(Args
[0], (char**)Args
);
2235 if(Mode
== FileFd::ReadOnly
)
2239 } else if(Mode
== FileFd::WriteOnly
)
2244 Fd
.OpenDescriptor(fd
, Mode
, FileFd::None
, true);
2249 bool DropPrivileges() /*{{{*/
2251 if(_config
->FindB("Debug::NoDropPrivs", false) == true)
2255 #if defined(PR_SET_NO_NEW_PRIVS) && ( PR_SET_NO_NEW_PRIVS != 38 )
2256 #error "PR_SET_NO_NEW_PRIVS is defined, but with a different value than expected!"
2258 // see prctl(2), needs linux3.5 at runtime - magic constant to avoid it at buildtime
2259 int ret
= prctl(38, 1, 0, 0, 0);
2260 // ignore EINVAL - kernel is too old to understand the option
2261 if(ret
< 0 && errno
!= EINVAL
)
2262 _error
->Warning("PR_SET_NO_NEW_PRIVS failed with %i", ret
);
2265 // empty setting disables privilege dropping - this also ensures
2266 // backward compatibility, see bug #764506
2267 const std::string toUser
= _config
->Find("APT::Sandbox::User");
2271 // uid will be 0 in the end, but gid might be different anyway
2272 uid_t
const old_uid
= getuid();
2273 gid_t
const old_gid
= getgid();
2278 struct passwd
*pw
= getpwnam(toUser
.c_str());
2280 return _error
->Error("No user %s, can not drop rights", toUser
.c_str());
2282 // Do not change the order here, it might break things
2283 // Get rid of all our supplementary groups first
2284 if (setgroups(1, &pw
->pw_gid
))
2285 return _error
->Errno("setgroups", "Failed to setgroups");
2287 // Now change the group ids to the new user
2288 #ifdef HAVE_SETRESGID
2289 if (setresgid(pw
->pw_gid
, pw
->pw_gid
, pw
->pw_gid
) != 0)
2290 return _error
->Errno("setresgid", "Failed to set new group ids");
2292 if (setegid(pw
->pw_gid
) != 0)
2293 return _error
->Errno("setegid", "Failed to setegid");
2295 if (setgid(pw
->pw_gid
) != 0)
2296 return _error
->Errno("setgid", "Failed to setgid");
2299 // Change the user ids to the new user
2300 #ifdef HAVE_SETRESUID
2301 if (setresuid(pw
->pw_uid
, pw
->pw_uid
, pw
->pw_uid
) != 0)
2302 return _error
->Errno("setresuid", "Failed to set new user ids");
2304 if (setuid(pw
->pw_uid
) != 0)
2305 return _error
->Errno("setuid", "Failed to setuid");
2306 if (seteuid(pw
->pw_uid
) != 0)
2307 return _error
->Errno("seteuid", "Failed to seteuid");
2310 // Verify that the user has only a single group, and the correct one
2312 if (getgroups(1, groups
) != 1)
2313 return _error
->Errno("getgroups", "Could not get new groups");
2314 if (groups
[0] != pw
->pw_gid
)
2315 return _error
->Error("Could not switch group");
2317 // Verify that gid, egid, uid, and euid changed
2318 if (getgid() != pw
->pw_gid
)
2319 return _error
->Error("Could not switch group");
2320 if (getegid() != pw
->pw_gid
)
2321 return _error
->Error("Could not switch effective group");
2322 if (getuid() != pw
->pw_uid
)
2323 return _error
->Error("Could not switch user");
2324 if (geteuid() != pw
->pw_uid
)
2325 return _error
->Error("Could not switch effective user");
2327 #ifdef HAVE_GETRESUID
2328 // verify that the saved set-user-id was changed as well
2332 if (getresuid(&ruid
, &euid
, &suid
))
2333 return _error
->Errno("getresuid", "Could not get saved set-user-ID");
2334 if (suid
!= pw
->pw_uid
)
2335 return _error
->Error("Could not switch saved set-user-ID");
2338 #ifdef HAVE_GETRESGID
2339 // verify that the saved set-group-id was changed as well
2343 if (getresgid(&rgid
, &egid
, &sgid
))
2344 return _error
->Errno("getresuid", "Could not get saved set-group-ID");
2345 if (sgid
!= pw
->pw_gid
)
2346 return _error
->Error("Could not switch saved set-group-ID");
2349 // Check that uid and gid changes do not work anymore
2350 if (pw
->pw_gid
!= old_gid
&& (setgid(old_gid
) != -1 || setegid(old_gid
) != -1))
2351 return _error
->Error("Could restore a gid to root, privilege dropping did not work");
2353 if (pw
->pw_uid
!= old_uid
&& (setuid(old_uid
) != -1 || seteuid(old_uid
) != -1))
2354 return _error
->Error("Could restore a uid to root, privilege dropping did not work");