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 constexpr unsigned long long BufSize
= sizeof(Buf
.get())/sizeof(Buf
.get()[0]);
165 unsigned long long ToRead
= 0;
167 if (From
.Read(Buf
.get(),BufSize
, &ToRead
) == false ||
168 To
.Write(Buf
.get(),ToRead
) == false)
170 } while (ToRead
!= 0);
175 // GetLock - Gets a lock file /*{{{*/
176 // ---------------------------------------------------------------------
177 /* This will create an empty file of the given name and lock it. Once this
178 is done all other calls to GetLock in any other process will fail with
179 -1. The return result is the fd of the file, the call should call
180 close at some time. */
181 int GetLock(string File
,bool Errors
)
183 // GetLock() is used in aptitude on directories with public-write access
184 // Use O_NOFOLLOW here to prevent symlink traversal attacks
185 int FD
= open(File
.c_str(),O_RDWR
| O_CREAT
| O_NOFOLLOW
,0640);
188 // Read only .. can't have locking problems there.
191 _error
->Warning(_("Not using locking for read only lock file %s"),File
.c_str());
192 return dup(0); // Need something for the caller to close
196 _error
->Errno("open",_("Could not open lock file %s"),File
.c_str());
198 // Feh.. We do this to distinguish the lock vs open case..
202 SetCloseExec(FD
,true);
204 // Acquire a write lock
207 fl
.l_whence
= SEEK_SET
;
210 if (fcntl(FD
,F_SETLK
,&fl
) == -1)
212 // always close to not leak resources
219 _error
->Warning(_("Not using locking for nfs mounted lock file %s"),File
.c_str());
220 return dup(0); // Need something for the caller to close
224 _error
->Errno("open",_("Could not get lock %s"),File
.c_str());
232 // FileExists - Check if a file exists /*{{{*/
233 // ---------------------------------------------------------------------
234 /* Beware: Directories are also files! */
235 bool FileExists(string File
)
238 if (stat(File
.c_str(),&Buf
) != 0)
243 // RealFileExists - Check if a file exists and if it is really a file /*{{{*/
244 // ---------------------------------------------------------------------
246 bool RealFileExists(string File
)
249 if (stat(File
.c_str(),&Buf
) != 0)
251 return ((Buf
.st_mode
& S_IFREG
) != 0);
254 // DirectoryExists - Check if a directory exists and is really one /*{{{*/
255 // ---------------------------------------------------------------------
257 bool DirectoryExists(string
const &Path
)
260 if (stat(Path
.c_str(),&Buf
) != 0)
262 return ((Buf
.st_mode
& S_IFDIR
) != 0);
265 // CreateDirectory - poor man's mkdir -p guarded by a parent directory /*{{{*/
266 // ---------------------------------------------------------------------
267 /* This method will create all directories needed for path in good old
268 mkdir -p style but refuses to do this if Parent is not a prefix of
269 this Path. Example: /var/cache/ and /var/cache/apt/archives are given,
270 so it will create apt/archives if /var/cache exists - on the other
271 hand if the parent is /var/lib the creation will fail as this path
272 is not a parent of the path to be generated. */
273 bool CreateDirectory(string
const &Parent
, string
const &Path
)
275 if (Parent
.empty() == true || Path
.empty() == true)
278 if (DirectoryExists(Path
) == true)
281 if (DirectoryExists(Parent
) == false)
284 // we are not going to create directories "into the blue"
285 if (Path
.compare(0, Parent
.length(), Parent
) != 0)
288 vector
<string
> const dirs
= VectorizeString(Path
.substr(Parent
.size()), '/');
289 string progress
= Parent
;
290 for (vector
<string
>::const_iterator d
= dirs
.begin(); d
!= dirs
.end(); ++d
)
292 if (d
->empty() == true)
295 progress
.append("/").append(*d
);
296 if (DirectoryExists(progress
) == true)
299 if (mkdir(progress
.c_str(), 0755) != 0)
305 // CreateAPTDirectoryIfNeeded - ensure that the given directory exists /*{{{*/
306 // ---------------------------------------------------------------------
307 /* a small wrapper around CreateDirectory to check if it exists and to
308 remove the trailing "/apt/" from the parent directory if needed */
309 bool CreateAPTDirectoryIfNeeded(string
const &Parent
, string
const &Path
)
311 if (DirectoryExists(Path
) == true)
314 size_t const len
= Parent
.size();
315 if (len
> 5 && Parent
.find("/apt/", len
- 6, 5) == len
- 5)
317 if (CreateDirectory(Parent
.substr(0,len
-5), Path
) == true)
320 else if (CreateDirectory(Parent
, Path
) == true)
326 // GetListOfFilesInDir - returns a vector of files in the given dir /*{{{*/
327 // ---------------------------------------------------------------------
328 /* If an extension is given only files with this extension are included
329 in the returned vector, otherwise every "normal" file is included. */
330 std::vector
<string
> GetListOfFilesInDir(string
const &Dir
, string
const &Ext
,
331 bool const &SortList
, bool const &AllowNoExt
)
333 std::vector
<string
> ext
;
335 if (Ext
.empty() == false)
337 if (AllowNoExt
== true && ext
.empty() == false)
339 return GetListOfFilesInDir(Dir
, ext
, SortList
);
341 std::vector
<string
> GetListOfFilesInDir(string
const &Dir
, std::vector
<string
> const &Ext
,
342 bool const &SortList
)
344 // Attention debuggers: need to be set with the environment config file!
345 bool const Debug
= _config
->FindB("Debug::GetListOfFilesInDir", false);
348 std::clog
<< "Accept in " << Dir
<< " only files with the following " << Ext
.size() << " extensions:" << std::endl
;
349 if (Ext
.empty() == true)
350 std::clog
<< "\tNO extension" << std::endl
;
352 for (std::vector
<string
>::const_iterator e
= Ext
.begin();
354 std::clog
<< '\t' << (e
->empty() == true ? "NO" : *e
) << " extension" << std::endl
;
357 std::vector
<string
> List
;
359 if (DirectoryExists(Dir
) == false)
361 _error
->Error(_("List of files can't be created as '%s' is not a directory"), Dir
.c_str());
365 Configuration::MatchAgainstConfig
SilentIgnore("Dir::Ignore-Files-Silently");
366 DIR *D
= opendir(Dir
.c_str());
369 _error
->Errno("opendir",_("Unable to read %s"),Dir
.c_str());
373 for (struct dirent
*Ent
= readdir(D
); Ent
!= 0; Ent
= readdir(D
))
375 // skip "hidden" files
376 if (Ent
->d_name
[0] == '.')
379 // Make sure it is a file and not something else
380 string
const File
= flCombine(Dir
,Ent
->d_name
);
381 #ifdef _DIRENT_HAVE_D_TYPE
382 if (Ent
->d_type
!= DT_REG
)
385 if (RealFileExists(File
) == false)
387 // do not show ignoration warnings for directories
389 #ifdef _DIRENT_HAVE_D_TYPE
390 Ent
->d_type
== DT_DIR
||
392 DirectoryExists(File
) == true)
394 if (SilentIgnore
.Match(Ent
->d_name
) == false)
395 _error
->Notice(_("Ignoring '%s' in directory '%s' as it is not a regular file"), Ent
->d_name
, Dir
.c_str());
400 // check for accepted extension:
401 // no extension given -> periods are bad as hell!
402 // extensions given -> "" extension allows no extension
403 if (Ext
.empty() == false)
405 string d_ext
= flExtension(Ent
->d_name
);
406 if (d_ext
== Ent
->d_name
) // no extension
408 if (std::find(Ext
.begin(), Ext
.end(), "") == Ext
.end())
411 std::clog
<< "Bad file: " << Ent
->d_name
<< " → no extension" << std::endl
;
412 if (SilentIgnore
.Match(Ent
->d_name
) == false)
413 _error
->Notice(_("Ignoring file '%s' in directory '%s' as it has no filename extension"), Ent
->d_name
, Dir
.c_str());
417 else if (std::find(Ext
.begin(), Ext
.end(), d_ext
) == Ext
.end())
420 std::clog
<< "Bad file: " << Ent
->d_name
<< " → bad extension »" << flExtension(Ent
->d_name
) << "«" << std::endl
;
421 if (SilentIgnore
.Match(Ent
->d_name
) == false)
422 _error
->Notice(_("Ignoring file '%s' in directory '%s' as it has an invalid filename extension"), Ent
->d_name
, Dir
.c_str());
427 // Skip bad filenames ala run-parts
428 const char *C
= Ent
->d_name
;
430 if (isalpha(*C
) == 0 && isdigit(*C
) == 0
431 && *C
!= '_' && *C
!= '-' && *C
!= ':') {
432 // no required extension -> dot is a bad character
433 if (*C
== '.' && Ext
.empty() == false)
438 // we don't reach the end of the name -> bad character included
442 std::clog
<< "Bad file: " << Ent
->d_name
<< " → bad character »"
443 << *C
<< "« in filename (period allowed: " << (Ext
.empty() ? "no" : "yes") << ")" << std::endl
;
447 // skip filenames which end with a period. These are never valid
451 std::clog
<< "Bad file: " << Ent
->d_name
<< " → Period as last character" << std::endl
;
456 std::clog
<< "Accept file: " << Ent
->d_name
<< " in " << Dir
<< std::endl
;
457 List
.push_back(File
);
461 if (SortList
== true)
462 std::sort(List
.begin(),List
.end());
465 std::vector
<string
> GetListOfFilesInDir(string
const &Dir
, bool SortList
)
467 bool const Debug
= _config
->FindB("Debug::GetListOfFilesInDir", false);
469 std::clog
<< "Accept in " << Dir
<< " all regular files" << std::endl
;
471 std::vector
<string
> List
;
473 if (DirectoryExists(Dir
) == false)
475 _error
->Error(_("List of files can't be created as '%s' is not a directory"), Dir
.c_str());
479 DIR *D
= opendir(Dir
.c_str());
482 _error
->Errno("opendir",_("Unable to read %s"),Dir
.c_str());
486 for (struct dirent
*Ent
= readdir(D
); Ent
!= 0; Ent
= readdir(D
))
488 // skip "hidden" files
489 if (Ent
->d_name
[0] == '.')
492 // Make sure it is a file and not something else
493 string
const File
= flCombine(Dir
,Ent
->d_name
);
494 #ifdef _DIRENT_HAVE_D_TYPE
495 if (Ent
->d_type
!= DT_REG
)
498 if (RealFileExists(File
) == false)
501 std::clog
<< "Bad file: " << Ent
->d_name
<< " → it is not a real file" << std::endl
;
506 // Skip bad filenames ala run-parts
507 const char *C
= Ent
->d_name
;
509 if (isalpha(*C
) == 0 && isdigit(*C
) == 0
510 && *C
!= '_' && *C
!= '-' && *C
!= '.')
513 // we don't reach the end of the name -> bad character included
517 std::clog
<< "Bad file: " << Ent
->d_name
<< " → bad character »" << *C
<< "« in filename" << std::endl
;
521 // skip filenames which end with a period. These are never valid
525 std::clog
<< "Bad file: " << Ent
->d_name
<< " → Period as last character" << std::endl
;
530 std::clog
<< "Accept file: " << Ent
->d_name
<< " in " << Dir
<< std::endl
;
531 List
.push_back(File
);
535 if (SortList
== true)
536 std::sort(List
.begin(),List
.end());
540 // SafeGetCWD - This is a safer getcwd that returns a dynamic string /*{{{*/
541 // ---------------------------------------------------------------------
542 /* We return / on failure. */
545 // Stash the current dir.
548 if (getcwd(S
,sizeof(S
)-2) == 0)
550 unsigned int Len
= strlen(S
);
556 // GetModificationTime - Get the mtime of the given file or -1 on error /*{{{*/
557 // ---------------------------------------------------------------------
558 /* We return / on failure. */
559 time_t GetModificationTime(string
const &Path
)
562 if (stat(Path
.c_str(), &St
) < 0)
567 // flNotDir - Strip the directory from the filename /*{{{*/
568 // ---------------------------------------------------------------------
570 string
flNotDir(string File
)
572 string::size_type Res
= File
.rfind('/');
573 if (Res
== string::npos
)
576 return string(File
,Res
,Res
- File
.length());
579 // flNotFile - Strip the file from the directory name /*{{{*/
580 // ---------------------------------------------------------------------
581 /* Result ends in a / */
582 string
flNotFile(string File
)
584 string::size_type Res
= File
.rfind('/');
585 if (Res
== string::npos
)
588 return string(File
,0,Res
);
591 // flExtension - Return the extension for the file /*{{{*/
592 // ---------------------------------------------------------------------
594 string
flExtension(string File
)
596 string::size_type Res
= File
.rfind('.');
597 if (Res
== string::npos
)
600 return string(File
,Res
,Res
- File
.length());
603 // flNoLink - If file is a symlink then deref it /*{{{*/
604 // ---------------------------------------------------------------------
605 /* If the name is not a link then the returned path is the input. */
606 string
flNoLink(string File
)
609 if (lstat(File
.c_str(),&St
) != 0 || S_ISLNK(St
.st_mode
) == 0)
611 if (stat(File
.c_str(),&St
) != 0)
614 /* Loop resolving the link. There is no need to limit the number of
615 loops because the stat call above ensures that the symlink is not
623 if ((Res
= readlink(NFile
.c_str(),Buffer
,sizeof(Buffer
))) <= 0 ||
624 (size_t)Res
>= sizeof(Buffer
))
627 // Append or replace the previous path
629 if (Buffer
[0] == '/')
632 NFile
= flNotFile(NFile
) + Buffer
;
634 // See if we are done
635 if (lstat(NFile
.c_str(),&St
) != 0)
637 if (S_ISLNK(St
.st_mode
) == 0)
642 // flCombine - Combine a file and a directory /*{{{*/
643 // ---------------------------------------------------------------------
644 /* If the file is an absolute path then it is just returned, otherwise
645 the directory is pre-pended to it. */
646 string
flCombine(string Dir
,string File
)
648 if (File
.empty() == true)
651 if (File
[0] == '/' || Dir
.empty() == true)
653 if (File
.length() >= 2 && File
[0] == '.' && File
[1] == '/')
655 if (Dir
[Dir
.length()-1] == '/')
657 return Dir
+ '/' + File
;
660 // flAbsPath - Return the absolute path of the filename /*{{{*/
661 // ---------------------------------------------------------------------
663 string
flAbsPath(string File
)
665 char *p
= realpath(File
.c_str(), NULL
);
668 _error
->Errno("realpath", "flAbsPath on %s failed", File
.c_str());
671 std::string
AbsPath(p
);
676 // SetCloseExec - Set the close on exec flag /*{{{*/
677 // ---------------------------------------------------------------------
679 void SetCloseExec(int Fd
,bool Close
)
681 if (fcntl(Fd
,F_SETFD
,(Close
== false)?0:FD_CLOEXEC
) != 0)
683 cerr
<< "FATAL -> Could not set close on exec " << strerror(errno
) << endl
;
688 // SetNonBlock - Set the nonblocking flag /*{{{*/
689 // ---------------------------------------------------------------------
691 void SetNonBlock(int Fd
,bool Block
)
693 int Flags
= fcntl(Fd
,F_GETFL
) & (~O_NONBLOCK
);
694 if (fcntl(Fd
,F_SETFL
,Flags
| ((Block
== false)?0:O_NONBLOCK
)) != 0)
696 cerr
<< "FATAL -> Could not set non-blocking flag " << strerror(errno
) << endl
;
701 // WaitFd - Wait for a FD to become readable /*{{{*/
702 // ---------------------------------------------------------------------
703 /* This waits for a FD to become readable using select. It is useful for
704 applications making use of non-blocking sockets. The timeout is
706 bool WaitFd(int Fd
,bool write
,unsigned long timeout
)
719 Res
= select(Fd
+1,0,&Set
,0,(timeout
!= 0?&tv
:0));
721 while (Res
< 0 && errno
== EINTR
);
731 Res
= select(Fd
+1,&Set
,0,0,(timeout
!= 0?&tv
:0));
733 while (Res
< 0 && errno
== EINTR
);
742 // MergeKeepFdsFromConfiguration - Merge APT::Keep-Fds configuration /*{{{*/
743 // ---------------------------------------------------------------------
744 /* This is used to merge the APT::Keep-Fds with the provided KeepFDs
747 void MergeKeepFdsFromConfiguration(std::set
<int> &KeepFDs
)
749 Configuration::Item
const *Opts
= _config
->Tree("APT::Keep-Fds");
750 if (Opts
!= 0 && Opts
->Child
!= 0)
753 for (; Opts
!= 0; Opts
= Opts
->Next
)
755 if (Opts
->Value
.empty() == true)
757 int fd
= atoi(Opts
->Value
.c_str());
763 // ExecFork - Magical fork that sanitizes the context before execing /*{{{*/
764 // ---------------------------------------------------------------------
765 /* This is used if you want to cleanse the environment for the forked
766 child, it fixes up the important signals and nukes all of the fds,
767 otherwise acts like normal fork. */
771 // we need to merge the Keep-Fds as external tools like
772 // debconf-apt-progress use it
773 MergeKeepFdsFromConfiguration(KeepFDs
);
774 return ExecFork(KeepFDs
);
777 pid_t
ExecFork(std::set
<int> KeepFDs
)
779 // Fork off the process
780 pid_t Process
= fork();
783 cerr
<< "FATAL -> Failed to fork." << endl
;
787 // Spawn the subprocess
791 signal(SIGPIPE
,SIG_DFL
);
792 signal(SIGQUIT
,SIG_DFL
);
793 signal(SIGINT
,SIG_DFL
);
794 signal(SIGWINCH
,SIG_DFL
);
795 signal(SIGCONT
,SIG_DFL
);
796 signal(SIGTSTP
,SIG_DFL
);
798 DIR *dir
= opendir("/proc/self/fd");
802 while ((ent
= readdir(dir
)))
804 int fd
= atoi(ent
->d_name
);
805 // If fd > 0, it was a fd number and not . or ..
806 if (fd
>= 3 && KeepFDs
.find(fd
) == KeepFDs
.end())
807 fcntl(fd
,F_SETFD
,FD_CLOEXEC
);
811 long ScOpenMax
= sysconf(_SC_OPEN_MAX
);
812 // Close all of our FDs - just in case
813 for (int K
= 3; K
!= ScOpenMax
; K
++)
815 if(KeepFDs
.find(K
) == KeepFDs
.end())
816 fcntl(K
,F_SETFD
,FD_CLOEXEC
);
824 // ExecWait - Fancy waitpid /*{{{*/
825 // ---------------------------------------------------------------------
826 /* Waits for the given sub process. If Reap is set then no errors are
827 generated. Otherwise a failed subprocess will generate a proper descriptive
829 bool ExecWait(pid_t Pid
,const char *Name
,bool Reap
)
834 // Wait and collect the error code
836 while (waitpid(Pid
,&Status
,0) != Pid
)
844 return _error
->Error(_("Waited for %s but it wasn't there"),Name
);
848 // Check for an error code.
849 if (WIFEXITED(Status
) == 0 || WEXITSTATUS(Status
) != 0)
853 if (WIFSIGNALED(Status
) != 0)
855 if( WTERMSIG(Status
) == SIGSEGV
)
856 return _error
->Error(_("Sub-process %s received a segmentation fault."),Name
);
858 return _error
->Error(_("Sub-process %s received signal %u."),Name
, WTERMSIG(Status
));
861 if (WIFEXITED(Status
) != 0)
862 return _error
->Error(_("Sub-process %s returned an error code (%u)"),Name
,WEXITSTATUS(Status
));
864 return _error
->Error(_("Sub-process %s exited unexpectedly"),Name
);
870 // StartsWithGPGClearTextSignature - Check if a file is Pgp/GPG clearsigned /*{{{*/
871 bool StartsWithGPGClearTextSignature(string
const &FileName
)
873 static const char* SIGMSG
= "-----BEGIN PGP SIGNED MESSAGE-----\n";
874 char buffer
[strlen(SIGMSG
)+1];
875 FILE* gpg
= fopen(FileName
.c_str(), "r");
879 char const * const test
= fgets(buffer
, sizeof(buffer
), gpg
);
881 if (test
== NULL
|| strcmp(buffer
, SIGMSG
) != 0)
887 // ChangeOwnerAndPermissionOfFile - set file attributes to requested values /*{{{*/
888 bool ChangeOwnerAndPermissionOfFile(char const * const requester
, char const * const file
, char const * const user
, char const * const group
, mode_t
const mode
)
890 if (strcmp(file
, "/dev/null") == 0)
893 if (getuid() == 0 && strlen(user
) != 0 && strlen(group
) != 0) // if we aren't root, we can't chown, so don't try it
895 // ensure the file is owned by root and has good permissions
896 struct passwd
const * const pw
= getpwnam(user
);
897 struct group
const * const gr
= getgrnam(group
);
898 if (pw
!= NULL
&& gr
!= NULL
&& chown(file
, pw
->pw_uid
, gr
->gr_gid
) != 0)
899 Res
&= _error
->WarningE(requester
, "chown to %s:%s of file %s failed", user
, group
, file
);
901 if (chmod(file
, mode
) != 0)
902 Res
&= _error
->WarningE(requester
, "chmod 0%o of file %s failed", mode
, file
);
907 class FileFdPrivate
{ /*{{{*/
918 uint8_t buffer
[4096];
924 LZMAFILE() : file(NULL
), eof(false), compressing(false) { buffer
[0] = '\0'; }
926 if (compressing
== true)
929 stream
.avail_out
= sizeof(buffer
)/sizeof(buffer
[0]);
930 stream
.next_out
= buffer
;
931 err
= lzma_code(&stream
, LZMA_FINISH
);
932 if (err
!= LZMA_OK
&& err
!= LZMA_STREAM_END
)
934 _error
->Error("~LZMAFILE: Compress finalisation failed");
937 size_t const n
= sizeof(buffer
)/sizeof(buffer
[0]) - stream
.avail_out
;
938 if (n
&& fwrite(buffer
, 1, n
, file
) != n
)
940 _error
->Errno("~LZMAFILE",_("Write error"));
943 if (err
== LZMA_STREAM_END
)
954 pid_t compressor_pid
;
956 APT::Configuration::Compressor compressor
;
957 unsigned int openmode
;
958 unsigned long long seekpos
;
969 compressed_fd(-1), compressor_pid(-1), pipe(false),
970 openmode(0), seekpos(0) {};
971 bool InternalClose(std::string
const &FileName
)
974 /* dummy so that the rest can be 'else if's */;
976 else if (gz
!= NULL
) {
977 int const e
= gzclose(gz
);
979 // gzdclose() on empty files always fails with "buffer error" here, ignore that
980 if (e
!= 0 && e
!= Z_BUF_ERROR
)
981 return _error
->Errno("close",_("Problem closing the gzip file %s"), FileName
.c_str());
985 else if (bz2
!= NULL
) {
991 else if (lzma
!= NULL
) {
998 bool CloseDown(std::string
const &FileName
)
1000 bool const Res
= InternalClose(FileName
);
1002 if (compressor_pid
> 0)
1003 ExecWait(compressor_pid
, "FileFdCompressor", true);
1004 compressor_pid
= -1;
1008 bool InternalStream() const {
1020 ~FileFdPrivate() { CloseDown(""); }
1023 // FileFd Constructors /*{{{*/
1024 FileFd::FileFd(std::string FileName
,unsigned int const Mode
,unsigned long AccessMode
) : iFd(-1), Flags(0), d(NULL
)
1026 Open(FileName
,Mode
, None
, AccessMode
);
1028 FileFd::FileFd(std::string FileName
,unsigned int const Mode
, CompressMode Compress
, unsigned long AccessMode
) : iFd(-1), Flags(0), d(NULL
)
1030 Open(FileName
,Mode
, Compress
, AccessMode
);
1032 FileFd::FileFd() : iFd(-1), Flags(AutoClose
), d(NULL
) {}
1033 FileFd::FileFd(int const Fd
, unsigned int const Mode
, CompressMode Compress
) : iFd(-1), Flags(0), d(NULL
)
1035 OpenDescriptor(Fd
, Mode
, Compress
);
1037 FileFd::FileFd(int const Fd
, bool const AutoClose
) : iFd(-1), Flags(0), d(NULL
)
1039 OpenDescriptor(Fd
, ReadWrite
, None
, AutoClose
);
1042 // FileFd::Open - Open a file /*{{{*/
1043 // ---------------------------------------------------------------------
1044 /* The most commonly used open mode combinations are given with Mode */
1045 bool FileFd::Open(string FileName
,unsigned int const Mode
,CompressMode Compress
, unsigned long const AccessMode
)
1047 if (Mode
== ReadOnlyGzip
)
1048 return Open(FileName
, ReadOnly
, Gzip
, AccessMode
);
1050 if (Compress
== Auto
&& (Mode
& WriteOnly
) == WriteOnly
)
1051 return FileFdError("Autodetection on %s only works in ReadOnly openmode!", FileName
.c_str());
1053 std::vector
<APT::Configuration::Compressor
> const compressors
= APT::Configuration::getCompressors();
1054 std::vector
<APT::Configuration::Compressor
>::const_iterator compressor
= compressors
.begin();
1055 if (Compress
== Auto
)
1057 for (; compressor
!= compressors
.end(); ++compressor
)
1059 std::string file
= FileName
+ compressor
->Extension
;
1060 if (FileExists(file
) == false)
1066 else if (Compress
== Extension
)
1068 std::string::size_type
const found
= FileName
.find_last_of('.');
1070 if (found
!= std::string::npos
)
1072 ext
= FileName
.substr(found
);
1073 if (ext
== ".new" || ext
== ".bak")
1075 std::string::size_type
const found2
= FileName
.find_last_of('.', found
- 1);
1076 if (found2
!= std::string::npos
)
1077 ext
= FileName
.substr(found2
, found
- found2
);
1082 for (; compressor
!= compressors
.end(); ++compressor
)
1083 if (ext
== compressor
->Extension
)
1085 // no matching extension - assume uncompressed (imagine files like 'example.org_Packages')
1086 if (compressor
== compressors
.end())
1087 for (compressor
= compressors
.begin(); compressor
!= compressors
.end(); ++compressor
)
1088 if (compressor
->Name
== ".")
1096 case None
: name
= "."; break;
1097 case Gzip
: name
= "gzip"; break;
1098 case Bzip2
: name
= "bzip2"; break;
1099 case Lzma
: name
= "lzma"; break;
1100 case Xz
: name
= "xz"; break;
1104 return FileFdError("Opening File %s in None, Auto or Extension should be already handled?!?", FileName
.c_str());
1106 for (; compressor
!= compressors
.end(); ++compressor
)
1107 if (compressor
->Name
== name
)
1109 if (compressor
== compressors
.end())
1110 return FileFdError("Can't find a configured compressor %s for file %s", name
.c_str(), FileName
.c_str());
1113 if (compressor
== compressors
.end())
1114 return FileFdError("Can't find a match for specified compressor mode for file %s", FileName
.c_str());
1115 return Open(FileName
, Mode
, *compressor
, AccessMode
);
1117 bool FileFd::Open(string FileName
,unsigned int const Mode
,APT::Configuration::Compressor
const &compressor
, unsigned long const AccessMode
)
1122 if ((Mode
& WriteOnly
) != WriteOnly
&& (Mode
& (Atomic
| Create
| Empty
| Exclusive
)) != 0)
1123 return FileFdError("ReadOnly mode for %s doesn't accept additional flags!", FileName
.c_str());
1124 if ((Mode
& ReadWrite
) == 0)
1125 return FileFdError("No openmode provided in FileFd::Open for %s", FileName
.c_str());
1127 unsigned int OpenMode
= Mode
;
1128 if (FileName
== "/dev/null")
1129 OpenMode
= OpenMode
& ~(Atomic
| Exclusive
| Create
| Empty
);
1131 if ((OpenMode
& Atomic
) == Atomic
)
1135 else if ((OpenMode
& (Exclusive
| Create
)) == (Exclusive
| Create
))
1137 // for atomic, this will be done by rename in Close()
1138 unlink(FileName
.c_str());
1140 if ((OpenMode
& Empty
) == Empty
)
1143 if (lstat(FileName
.c_str(),&Buf
) == 0 && S_ISLNK(Buf
.st_mode
))
1144 unlink(FileName
.c_str());
1148 #define if_FLAGGED_SET(FLAG, MODE) if ((OpenMode & FLAG) == FLAG) fileflags |= MODE
1149 if_FLAGGED_SET(ReadWrite
, O_RDWR
);
1150 else if_FLAGGED_SET(ReadOnly
, O_RDONLY
);
1151 else if_FLAGGED_SET(WriteOnly
, O_WRONLY
);
1153 if_FLAGGED_SET(Create
, O_CREAT
);
1154 if_FLAGGED_SET(Empty
, O_TRUNC
);
1155 if_FLAGGED_SET(Exclusive
, O_EXCL
);
1156 #undef if_FLAGGED_SET
1158 if ((OpenMode
& Atomic
) == Atomic
)
1160 char *name
= strdup((FileName
+ ".XXXXXX").c_str());
1162 if((iFd
= mkstemp(name
)) == -1)
1165 return FileFdErrno("mkstemp", "Could not create temporary file for %s", FileName
.c_str());
1168 TemporaryFileName
= string(name
);
1171 // umask() will always set the umask and return the previous value, so
1172 // we first set the umask and then reset it to the old value
1173 mode_t
const CurrentUmask
= umask(0);
1174 umask(CurrentUmask
);
1175 // calculate the actual file permissions (just like open/creat)
1176 mode_t
const FilePermissions
= (AccessMode
& ~CurrentUmask
);
1178 if(fchmod(iFd
, FilePermissions
) == -1)
1179 return FileFdErrno("fchmod", "Could not change permissions for temporary file %s", TemporaryFileName
.c_str());
1182 iFd
= open(FileName
.c_str(), fileflags
, AccessMode
);
1184 this->FileName
= FileName
;
1185 if (iFd
== -1 || OpenInternDescriptor(OpenMode
, compressor
) == false)
1192 return FileFdErrno("open",_("Could not open file %s"), FileName
.c_str());
1195 SetCloseExec(iFd
,true);
1199 // FileFd::OpenDescriptor - Open a filedescriptor /*{{{*/
1200 // ---------------------------------------------------------------------
1202 bool FileFd::OpenDescriptor(int Fd
, unsigned int const Mode
, CompressMode Compress
, bool AutoClose
)
1204 std::vector
<APT::Configuration::Compressor
> const compressors
= APT::Configuration::getCompressors();
1205 std::vector
<APT::Configuration::Compressor
>::const_iterator compressor
= compressors
.begin();
1208 // compat with the old API
1209 if (Mode
== ReadOnlyGzip
&& Compress
== None
)
1214 case None
: name
= "."; break;
1215 case Gzip
: name
= "gzip"; break;
1216 case Bzip2
: name
= "bzip2"; break;
1217 case Lzma
: name
= "lzma"; break;
1218 case Xz
: name
= "xz"; break;
1221 if (AutoClose
== true && Fd
!= -1)
1223 return FileFdError("Opening Fd %d in Auto or Extension compression mode is not supported", Fd
);
1225 for (; compressor
!= compressors
.end(); ++compressor
)
1226 if (compressor
->Name
== name
)
1228 if (compressor
== compressors
.end())
1230 if (AutoClose
== true && Fd
!= -1)
1232 return FileFdError("Can't find a configured compressor %s for file %s", name
.c_str(), FileName
.c_str());
1234 return OpenDescriptor(Fd
, Mode
, *compressor
, AutoClose
);
1236 bool FileFd::OpenDescriptor(int Fd
, unsigned int const Mode
, APT::Configuration::Compressor
const &compressor
, bool AutoClose
)
1239 Flags
= (AutoClose
) ? FileFd::AutoClose
: 0;
1241 this->FileName
= "";
1242 if (OpenInternDescriptor(Mode
, compressor
) == false)
1245 (Flags
& Compressed
) == Compressed
||
1251 return FileFdError(_("Could not open file descriptor %d"), Fd
);
1255 bool FileFd::OpenInternDescriptor(unsigned int const Mode
, APT::Configuration::Compressor
const &compressor
)
1259 if (compressor
.Name
== "." || compressor
.Binary
.empty() == true)
1262 #if defined HAVE_ZLIB || defined HAVE_BZ2 || defined HAVE_LZMA
1263 // the API to open files is similar, so setup to avoid code duplicates later
1264 // and while at it ensure that we close before opening (if its a reopen)
1265 void* (*compress_open
)(int, const char *) = NULL
;
1267 /* dummy so that the rest can be 'else if's */;
1268 #define APT_COMPRESS_INIT(NAME,OPEN) \
1269 else if (compressor.Name == NAME) \
1271 compress_open = (void*(*)(int, const char *)) OPEN; \
1272 if (d != NULL) d->InternalClose(FileName); \
1275 APT_COMPRESS_INIT("gzip", gzdopen
)
1278 APT_COMPRESS_INIT("bzip2", BZ2_bzdopen
)
1281 APT_COMPRESS_INIT("xz", fdopen
)
1282 APT_COMPRESS_INIT("lzma", fdopen
)
1284 #undef APT_COMPRESS_INIT
1289 d
= new FileFdPrivate();
1291 d
->compressor
= compressor
;
1292 #if defined HAVE_ZLIB || defined HAVE_BZ2 || defined HAVE_LZMA
1293 if ((Flags
& AutoClose
) != AutoClose
&& compress_open
!= NULL
)
1295 // Need to duplicate fd here or gz/bz2 close for cleanup will close the fd as well
1296 int const internFd
= dup(iFd
);
1298 return FileFdErrno("OpenInternDescriptor", _("Could not open file descriptor %d"), iFd
);
1304 #if defined HAVE_ZLIB || defined HAVE_BZ2 || defined HAVE_LZMA
1305 if (compress_open
!= NULL
)
1307 void* compress_struct
= NULL
;
1308 if ((Mode
& ReadWrite
) == ReadWrite
)
1309 compress_struct
= compress_open(iFd
, "r+");
1310 else if ((Mode
& WriteOnly
) == WriteOnly
)
1311 compress_struct
= compress_open(iFd
, "w");
1313 compress_struct
= compress_open(iFd
, "r");
1314 if (compress_struct
== NULL
)
1318 /* dummy so that the rest can be 'else if's */;
1320 else if (compressor
.Name
== "gzip")
1321 d
->gz
= (gzFile
) compress_struct
;
1324 else if (compressor
.Name
== "bzip2")
1325 d
->bz2
= (BZFILE
*) compress_struct
;
1328 else if (compressor
.Name
== "xz" || compressor
.Name
== "lzma")
1330 uint32_t const xzlevel
= 6;
1331 uint64_t const memlimit
= UINT64_MAX
;
1332 if (d
->lzma
== NULL
)
1333 d
->lzma
= new FileFdPrivate::LZMAFILE
;
1334 d
->lzma
->file
= (FILE*) compress_struct
;
1335 lzma_stream tmp_stream
= LZMA_STREAM_INIT
;
1336 d
->lzma
->stream
= tmp_stream
;
1338 if ((Mode
& ReadWrite
) == ReadWrite
)
1339 return FileFdError("ReadWrite mode is not supported for file %s", FileName
.c_str());
1341 if ((Mode
& WriteOnly
) == WriteOnly
)
1343 if (compressor
.Name
== "xz")
1345 if (lzma_easy_encoder(&d
->lzma
->stream
, xzlevel
, LZMA_CHECK_CRC32
) != LZMA_OK
)
1350 lzma_options_lzma options
;
1351 lzma_lzma_preset(&options
, xzlevel
);
1352 if (lzma_alone_encoder(&d
->lzma
->stream
, &options
) != LZMA_OK
)
1355 d
->lzma
->compressing
= true;
1359 if (compressor
.Name
== "xz")
1361 if (lzma_auto_decoder(&d
->lzma
->stream
, memlimit
, 0) != LZMA_OK
)
1366 if (lzma_alone_decoder(&d
->lzma
->stream
, memlimit
) != LZMA_OK
)
1369 d
->lzma
->compressing
= false;
1373 Flags
|= Compressed
;
1378 // collect zombies here in case we reopen
1379 if (d
->compressor_pid
> 0)
1380 ExecWait(d
->compressor_pid
, "FileFdCompressor", true);
1382 if ((Mode
& ReadWrite
) == ReadWrite
)
1383 return FileFdError("ReadWrite mode is not supported for file %s", FileName
.c_str());
1385 bool const Comp
= (Mode
& WriteOnly
) == WriteOnly
;
1388 // Handle 'decompression' of empty files
1391 if (Buf
.st_size
== 0 && S_ISFIFO(Buf
.st_mode
) == false)
1394 // We don't need the file open - instead let the compressor open it
1395 // as he properly knows better how to efficiently read from 'his' file
1396 if (FileName
.empty() == false)
1403 // Create a data pipe
1404 int Pipe
[2] = {-1,-1};
1405 if (pipe(Pipe
) != 0)
1406 return FileFdErrno("pipe",_("Failed to create subprocess IPC"));
1407 for (int J
= 0; J
!= 2; J
++)
1408 SetCloseExec(Pipe
[J
],true);
1410 d
->compressed_fd
= iFd
;
1419 d
->compressor_pid
= ExecFork();
1420 if (d
->compressor_pid
== 0)
1424 dup2(d
->compressed_fd
,STDOUT_FILENO
);
1425 dup2(Pipe
[0],STDIN_FILENO
);
1429 if (d
->compressed_fd
!= -1)
1430 dup2(d
->compressed_fd
,STDIN_FILENO
);
1431 dup2(Pipe
[1],STDOUT_FILENO
);
1433 int const nullfd
= open("/dev/null", O_WRONLY
);
1436 dup2(nullfd
,STDERR_FILENO
);
1440 SetCloseExec(STDOUT_FILENO
,false);
1441 SetCloseExec(STDIN_FILENO
,false);
1443 std::vector
<char const*> Args
;
1444 Args
.push_back(compressor
.Binary
.c_str());
1445 std::vector
<std::string
> const * const addArgs
=
1446 (Comp
== true) ? &(compressor
.CompressArgs
) : &(compressor
.UncompressArgs
);
1447 for (std::vector
<std::string
>::const_iterator a
= addArgs
->begin();
1448 a
!= addArgs
->end(); ++a
)
1449 Args
.push_back(a
->c_str());
1450 if (Comp
== false && FileName
.empty() == false)
1452 // commands not needing arguments, do not need to be told about using standard output
1453 // in reality, only testcases with tools like cat, rev, rot13, … are able to trigger this
1454 if (compressor
.CompressArgs
.empty() == false && compressor
.UncompressArgs
.empty() == false)
1455 Args
.push_back("--stdout");
1456 if (TemporaryFileName
.empty() == false)
1457 Args
.push_back(TemporaryFileName
.c_str());
1459 Args
.push_back(FileName
.c_str());
1461 Args
.push_back(NULL
);
1463 execvp(Args
[0],(char **)&Args
[0]);
1464 cerr
<< _("Failed to exec compressor ") << Args
[0] << endl
;
1475 // FileFd::~File - Closes the file /*{{{*/
1476 // ---------------------------------------------------------------------
1477 /* If the proper modes are selected then we close the Fd and possibly
1478 unlink the file on error. */
1483 d
->CloseDown(FileName
);
1488 // FileFd::Read - Read a bit of the file /*{{{*/
1489 // ---------------------------------------------------------------------
1490 /* We are careful to handle interruption by a signal while reading
1492 bool FileFd::Read(void *To
,unsigned long long Size
,unsigned long long *Actual
)
1498 *((char *)To
) = '\0';
1502 /* dummy so that the rest can be 'else if's */;
1504 else if (d
!= NULL
&& d
->gz
!= NULL
)
1505 Res
= gzread(d
->gz
,To
,Size
);
1508 else if (d
!= NULL
&& d
->bz2
!= NULL
)
1509 Res
= BZ2_bzread(d
->bz2
,To
,Size
);
1512 else if (d
!= NULL
&& d
->lzma
!= NULL
)
1514 if (d
->lzma
->eof
== true)
1517 d
->lzma
->stream
.next_out
= (uint8_t *) To
;
1518 d
->lzma
->stream
.avail_out
= Size
;
1519 if (d
->lzma
->stream
.avail_in
== 0)
1521 d
->lzma
->stream
.next_in
= d
->lzma
->buffer
;
1522 d
->lzma
->stream
.avail_in
= fread(d
->lzma
->buffer
, 1, sizeof(d
->lzma
->buffer
)/sizeof(d
->lzma
->buffer
[0]), d
->lzma
->file
);
1524 d
->lzma
->err
= lzma_code(&d
->lzma
->stream
, LZMA_RUN
);
1525 if (d
->lzma
->err
== LZMA_STREAM_END
)
1527 d
->lzma
->eof
= true;
1528 Res
= Size
- d
->lzma
->stream
.avail_out
;
1530 else if (d
->lzma
->err
!= LZMA_OK
)
1537 Res
= Size
- d
->lzma
->stream
.avail_out
;
1540 // lzma run was okay, but produced no output…
1548 Res
= read(iFd
,To
,Size
);
1554 // trick the while-loop into running again
1560 /* dummy so that the rest can be 'else if's */;
1562 else if (d
!= NULL
&& d
->gz
!= NULL
)
1565 char const * const errmsg
= gzerror(d
->gz
, &err
);
1567 return FileFdError("gzread: %s (%d: %s)", _("Read error"), err
, errmsg
);
1571 else if (d
!= NULL
&& d
->bz2
!= NULL
)
1574 char const * const errmsg
= BZ2_bzerror(d
->bz2
, &err
);
1575 if (err
!= BZ_IO_ERROR
)
1576 return FileFdError("BZ2_bzread: %s %s (%d: %s)", FileName
.c_str(), _("Read error"), err
, errmsg
);
1580 else if (d
!= NULL
&& d
->lzma
!= NULL
)
1581 return FileFdError("lzma_read: %s (%d)", _("Read error"), d
->lzma
->err
);
1583 return FileFdErrno("read",_("Read error"));
1586 To
= (char *)To
+ Res
;
1593 while (Res
> 0 && Size
> 0);
1605 return FileFdError(_("read, still have %llu to read but none left"), Size
);
1608 // FileFd::ReadLine - Read a complete line from the file /*{{{*/
1609 // ---------------------------------------------------------------------
1610 /* Beware: This method can be quiet slow for big buffers on UNcompressed
1611 files because of the naive implementation! */
1612 char* FileFd::ReadLine(char *To
, unsigned long long const Size
)
1616 if (d
!= NULL
&& d
->gz
!= NULL
)
1617 return gzgets(d
->gz
, To
, Size
);
1620 unsigned long long read
= 0;
1621 while ((Size
- 1) != read
)
1623 unsigned long long done
= 0;
1624 if (Read(To
+ read
, 1, &done
) == false)
1628 if (To
[read
++] == '\n')
1637 // FileFd::Write - Write to the file /*{{{*/
1638 // ---------------------------------------------------------------------
1640 bool FileFd::Write(const void *From
,unsigned long long Size
)
1647 /* dummy so that the rest can be 'else if's */;
1649 else if (d
!= NULL
&& d
->gz
!= NULL
)
1650 Res
= gzwrite(d
->gz
,From
,Size
);
1653 else if (d
!= NULL
&& d
->bz2
!= NULL
)
1654 Res
= BZ2_bzwrite(d
->bz2
,(void*)From
,Size
);
1657 else if (d
!= NULL
&& d
->lzma
!= NULL
)
1659 d
->lzma
->stream
.next_in
= (uint8_t *)From
;
1660 d
->lzma
->stream
.avail_in
= Size
;
1661 d
->lzma
->stream
.next_out
= d
->lzma
->buffer
;
1662 d
->lzma
->stream
.avail_out
= sizeof(d
->lzma
->buffer
)/sizeof(d
->lzma
->buffer
[0]);
1663 d
->lzma
->err
= lzma_code(&d
->lzma
->stream
, LZMA_RUN
);
1664 if (d
->lzma
->err
!= LZMA_OK
)
1666 size_t const n
= sizeof(d
->lzma
->buffer
)/sizeof(d
->lzma
->buffer
[0]) - d
->lzma
->stream
.avail_out
;
1667 size_t const m
= (n
== 0) ? 0 : fwrite(d
->lzma
->buffer
, 1, n
, d
->lzma
->file
);
1671 Res
= Size
- d
->lzma
->stream
.avail_in
;
1675 Res
= write(iFd
,From
,Size
);
1677 if (Res
< 0 && errno
== EINTR
)
1682 /* dummy so that the rest can be 'else if's */;
1684 else if (d
!= NULL
&& d
->gz
!= NULL
)
1687 char const * const errmsg
= gzerror(d
->gz
, &err
);
1689 return FileFdError("gzwrite: %s (%d: %s)", _("Write error"), err
, errmsg
);
1693 else if (d
!= NULL
&& d
->bz2
!= NULL
)
1696 char const * const errmsg
= BZ2_bzerror(d
->bz2
, &err
);
1697 if (err
!= BZ_IO_ERROR
)
1698 return FileFdError("BZ2_bzwrite: %s (%d: %s)", _("Write error"), err
, errmsg
);
1702 else if (d
!= NULL
&& d
->lzma
!= NULL
)
1703 return FileFdErrno("lzma_fwrite", _("Write error"));
1705 return FileFdErrno("write",_("Write error"));
1708 From
= (char const *)From
+ Res
;
1713 while (Res
> 0 && Size
> 0);
1718 return FileFdError(_("write, still have %llu to write but couldn't"), Size
);
1720 bool FileFd::Write(int Fd
, const void *From
, unsigned long long Size
)
1726 Res
= write(Fd
,From
,Size
);
1727 if (Res
< 0 && errno
== EINTR
)
1730 return _error
->Errno("write",_("Write error"));
1732 From
= (char const *)From
+ Res
;
1735 while (Res
> 0 && Size
> 0);
1740 return _error
->Error(_("write, still have %llu to write but couldn't"), Size
);
1743 // FileFd::Seek - Seek in the file /*{{{*/
1744 // ---------------------------------------------------------------------
1746 bool FileFd::Seek(unsigned long long To
)
1750 if (d
!= NULL
&& (d
->pipe
== true || d
->InternalStream() == true))
1752 // Our poor man seeking in pipes is costly, so try to avoid it
1753 unsigned long long seekpos
= Tell();
1756 else if (seekpos
< To
)
1757 return Skip(To
- seekpos
);
1759 if ((d
->openmode
& ReadOnly
) != ReadOnly
)
1760 return FileFdError("Reopen is only implemented for read-only files!");
1761 d
->InternalClose(FileName
);
1765 if (TemporaryFileName
.empty() == false)
1766 iFd
= open(TemporaryFileName
.c_str(), O_RDONLY
);
1767 else if (FileName
.empty() == false)
1768 iFd
= open(FileName
.c_str(), O_RDONLY
);
1771 if (d
->compressed_fd
> 0)
1772 if (lseek(d
->compressed_fd
, 0, SEEK_SET
) != 0)
1773 iFd
= d
->compressed_fd
;
1775 return FileFdError("Reopen is not implemented for pipes opened with FileFd::OpenDescriptor()!");
1778 if (OpenInternDescriptor(d
->openmode
, d
->compressor
) == false)
1779 return FileFdError("Seek on file %s because it couldn't be reopened", FileName
.c_str());
1789 if (d
!= NULL
&& d
->gz
)
1790 res
= gzseek(d
->gz
,To
,SEEK_SET
);
1793 res
= lseek(iFd
,To
,SEEK_SET
);
1794 if (res
!= (off_t
)To
)
1795 return FileFdError("Unable to seek to %llu", To
);
1802 // FileFd::Skip - Seek in the file /*{{{*/
1803 // ---------------------------------------------------------------------
1805 bool FileFd::Skip(unsigned long long Over
)
1807 if (d
!= NULL
&& (d
->pipe
== true || d
->InternalStream() == true))
1812 unsigned long long toread
= std::min((unsigned long long) sizeof(buffer
), Over
);
1813 if (Read(buffer
, toread
) == false)
1814 return FileFdError("Unable to seek ahead %llu",Over
);
1822 if (d
!= NULL
&& d
->gz
!= NULL
)
1823 res
= gzseek(d
->gz
,Over
,SEEK_CUR
);
1826 res
= lseek(iFd
,Over
,SEEK_CUR
);
1828 return FileFdError("Unable to seek ahead %llu",Over
);
1835 // FileFd::Truncate - Truncate the file /*{{{*/
1836 // ---------------------------------------------------------------------
1838 bool FileFd::Truncate(unsigned long long To
)
1840 // truncating /dev/null is always successful - as we get an error otherwise
1841 if (To
== 0 && FileName
== "/dev/null")
1843 #if defined HAVE_ZLIB || defined HAVE_BZ2 || defined HAVE_LZMA
1844 if (d
!= NULL
&& (d
->InternalStream() == true
1849 return FileFdError("Truncating compressed files is not implemented (%s)", FileName
.c_str());
1851 if (ftruncate(iFd
,To
) != 0)
1852 return FileFdError("Unable to truncate to %llu",To
);
1857 // FileFd::Tell - Current seek position /*{{{*/
1858 // ---------------------------------------------------------------------
1860 unsigned long long FileFd::Tell()
1862 // In theory, we could just return seekpos here always instead of
1863 // seeking around, but not all users of FileFd use always Seek() and co
1864 // so d->seekpos isn't always true and we can just use it as a hint if
1865 // we have nothing else, but not always as an authority…
1866 if (d
!= NULL
&& (d
->pipe
== true || d
->InternalStream() == true))
1871 if (d
!= NULL
&& d
->gz
!= NULL
)
1872 Res
= gztell(d
->gz
);
1875 Res
= lseek(iFd
,0,SEEK_CUR
);
1876 if (Res
== (off_t
)-1)
1877 FileFdErrno("lseek","Failed to determine the current file position");
1883 static bool StatFileFd(char const * const msg
, int const iFd
, std::string
const &FileName
, struct stat
&Buf
, FileFdPrivate
* const d
) /*{{{*/
1885 bool ispipe
= (d
!= NULL
&& d
->pipe
== true);
1886 if (ispipe
== false)
1888 if (fstat(iFd
,&Buf
) != 0)
1889 // higher-level code will generate more meaningful messages,
1890 // even translated this would be meaningless for users
1891 return _error
->Errno("fstat", "Unable to determine %s for fd %i", msg
, iFd
);
1892 if (FileName
.empty() == false)
1893 ispipe
= S_ISFIFO(Buf
.st_mode
);
1896 // for compressor pipes st_size is undefined and at 'best' zero
1899 // we set it here, too, as we get the info here for free
1900 // in theory the Open-methods should take care of it already
1903 if (stat(FileName
.c_str(), &Buf
) != 0)
1904 return _error
->Errno("fstat", "Unable to determine %s for file %s", msg
, FileName
.c_str());
1909 // FileFd::FileSize - Return the size of the file /*{{{*/
1910 unsigned long long FileFd::FileSize()
1913 if (StatFileFd("file size", iFd
, FileName
, Buf
, d
) == false)
1921 // FileFd::ModificationTime - Return the time of last touch /*{{{*/
1922 time_t FileFd::ModificationTime()
1925 if (StatFileFd("modification time", iFd
, FileName
, Buf
, d
) == false)
1930 return Buf
.st_mtime
;
1933 // FileFd::Size - Return the size of the content in the file /*{{{*/
1934 // ---------------------------------------------------------------------
1936 unsigned long long FileFd::Size()
1938 unsigned long long size
= FileSize();
1940 // for compressor pipes st_size is undefined and at 'best' zero,
1941 // so we 'read' the content and 'seek' back - see there
1942 if (d
!= NULL
&& (d
->pipe
== true || (d
->InternalStream() == true && size
> 0)))
1944 unsigned long long const oldSeek
= Tell();
1946 unsigned long long read
= 0;
1948 if (Read(ignore
, sizeof(ignore
), &read
) == false)
1958 // only check gzsize if we are actually a gzip file, just checking for
1959 // "gz" is not sufficient as uncompressed files could be opened with
1960 // gzopen in "direct" mode as well
1961 else if (d
!= NULL
&& d
->gz
&& !gzdirect(d
->gz
) && size
> 0)
1963 off_t
const oldPos
= lseek(iFd
,0,SEEK_CUR
);
1964 /* unfortunately zlib.h doesn't provide a gzsize(), so we have to do
1965 * this ourselves; the original (uncompressed) file size is the last 32
1966 * bits of the file */
1967 // FIXME: Size for gz-files is limited by 32bit… no largefile support
1968 if (lseek(iFd
, -4, SEEK_END
) < 0)
1970 FileFdErrno("lseek","Unable to seek to end of gzipped file");
1974 if (read(iFd
, &size
, 4) != 4)
1976 FileFdErrno("read","Unable to read original size of gzipped file");
1979 size
= le32toh(size
);
1981 if (lseek(iFd
, oldPos
, SEEK_SET
) < 0)
1983 FileFdErrno("lseek","Unable to seek in gzipped file");
1994 // FileFd::Close - Close the file if the close flag is set /*{{{*/
1995 // ---------------------------------------------------------------------
1997 bool FileFd::Close()
2003 if ((Flags
& AutoClose
) == AutoClose
)
2005 if ((Flags
& Compressed
) != Compressed
&& iFd
> 0 && close(iFd
) != 0)
2006 Res
&= _error
->Errno("close",_("Problem closing the file %s"), FileName
.c_str());
2011 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
2126 else if (geteuid() != 0 && // root can do everything anyway
2127 faccessat(-1, tmpdir
, R_OK
| W_OK
| X_OK
, AT_EACCESS
| AT_SYMLINK_NOFOLLOW
) != 0) // current user has rwx access to directory
2130 return string(tmpdir
);
2132 std::string
GetTempDir(std::string
const &User
)
2134 // no need/possibility to drop privs
2135 if(getuid() != 0 || User
.empty() || User
== "root")
2136 return GetTempDir();
2138 struct passwd
const * const pw
= getpwnam(User
.c_str());
2140 return GetTempDir();
2142 gid_t
const old_euid
= geteuid();
2143 gid_t
const old_egid
= getegid();
2144 if (setegid(pw
->pw_gid
) != 0)
2145 _error
->Errno("setegid", "setegid %u failed", pw
->pw_gid
);
2146 if (seteuid(pw
->pw_uid
) != 0)
2147 _error
->Errno("seteuid", "seteuid %u failed", pw
->pw_uid
);
2149 std::string
const tmp
= GetTempDir();
2151 if (seteuid(old_euid
) != 0)
2152 _error
->Errno("seteuid", "seteuid %u failed", old_euid
);
2153 if (setegid(old_egid
) != 0)
2154 _error
->Errno("setegid", "setegid %u failed", old_egid
);
2159 FileFd
* GetTempFile(std::string
const &Prefix
, bool ImmediateUnlink
, FileFd
* const TmpFd
) /*{{{*/
2162 FileFd
* const Fd
= TmpFd
== NULL
? new FileFd() : TmpFd
;
2164 std::string
const tempdir
= GetTempDir();
2165 snprintf(fn
, sizeof(fn
), "%s/%s.XXXXXX",
2166 tempdir
.c_str(), Prefix
.c_str());
2167 int const fd
= mkstemp(fn
);
2172 _error
->Errno("GetTempFile",_("Unable to mkstemp %s"), fn
);
2175 if (!Fd
->OpenDescriptor(fd
, FileFd::ReadWrite
, FileFd::None
, true))
2177 _error
->Errno("GetTempFile",_("Unable to write to %s"),fn
);
2183 bool Rename(std::string From
, std::string To
) /*{{{*/
2185 if (rename(From
.c_str(),To
.c_str()) != 0)
2187 _error
->Error(_("rename failed, %s (%s -> %s)."),strerror(errno
),
2188 From
.c_str(),To
.c_str());
2194 bool Popen(const char* Args
[], FileFd
&Fd
, pid_t
&Child
, FileFd::OpenMode Mode
)/*{{{*/
2197 if (Mode
!= FileFd::ReadOnly
&& Mode
!= FileFd::WriteOnly
)
2198 return _error
->Error("Popen supports ReadOnly (x)or WriteOnly mode only");
2200 int Pipe
[2] = {-1, -1};
2202 return _error
->Errno("pipe", _("Failed to create subprocess IPC"));
2204 std::set
<int> keep_fds
;
2205 keep_fds
.insert(Pipe
[0]);
2206 keep_fds
.insert(Pipe
[1]);
2207 Child
= ExecFork(keep_fds
);
2209 return _error
->Errno("fork", "Failed to fork");
2212 if(Mode
== FileFd::ReadOnly
)
2217 else if(Mode
== FileFd::WriteOnly
)
2223 if(Mode
== FileFd::ReadOnly
)
2227 } else if(Mode
== FileFd::WriteOnly
)
2230 execv(Args
[0], (char**)Args
);
2233 if(Mode
== FileFd::ReadOnly
)
2238 else if(Mode
== FileFd::WriteOnly
)
2244 return _error
->Error("Popen supports ReadOnly (x)or WriteOnly mode only");
2245 Fd
.OpenDescriptor(fd
, Mode
, FileFd::None
, true);
2250 bool DropPrivileges() /*{{{*/
2252 if(_config
->FindB("Debug::NoDropPrivs", false) == true)
2256 #if defined(PR_SET_NO_NEW_PRIVS) && ( PR_SET_NO_NEW_PRIVS != 38 )
2257 #error "PR_SET_NO_NEW_PRIVS is defined, but with a different value than expected!"
2259 // see prctl(2), needs linux3.5 at runtime - magic constant to avoid it at buildtime
2260 int ret
= prctl(38, 1, 0, 0, 0);
2261 // ignore EINVAL - kernel is too old to understand the option
2262 if(ret
< 0 && errno
!= EINVAL
)
2263 _error
->Warning("PR_SET_NO_NEW_PRIVS failed with %i", ret
);
2266 // empty setting disables privilege dropping - this also ensures
2267 // backward compatibility, see bug #764506
2268 const std::string toUser
= _config
->Find("APT::Sandbox::User");
2272 // uid will be 0 in the end, but gid might be different anyway
2273 uid_t
const old_uid
= getuid();
2274 gid_t
const old_gid
= getgid();
2279 struct passwd
*pw
= getpwnam(toUser
.c_str());
2281 return _error
->Error("No user %s, can not drop rights", toUser
.c_str());
2283 // Do not change the order here, it might break things
2284 // Get rid of all our supplementary groups first
2285 if (setgroups(1, &pw
->pw_gid
))
2286 return _error
->Errno("setgroups", "Failed to setgroups");
2288 // Now change the group ids to the new user
2289 #ifdef HAVE_SETRESGID
2290 if (setresgid(pw
->pw_gid
, pw
->pw_gid
, pw
->pw_gid
) != 0)
2291 return _error
->Errno("setresgid", "Failed to set new group ids");
2293 if (setegid(pw
->pw_gid
) != 0)
2294 return _error
->Errno("setegid", "Failed to setegid");
2296 if (setgid(pw
->pw_gid
) != 0)
2297 return _error
->Errno("setgid", "Failed to setgid");
2300 // Change the user ids to the new user
2301 #ifdef HAVE_SETRESUID
2302 if (setresuid(pw
->pw_uid
, pw
->pw_uid
, pw
->pw_uid
) != 0)
2303 return _error
->Errno("setresuid", "Failed to set new user ids");
2305 if (setuid(pw
->pw_uid
) != 0)
2306 return _error
->Errno("setuid", "Failed to setuid");
2307 if (seteuid(pw
->pw_uid
) != 0)
2308 return _error
->Errno("seteuid", "Failed to seteuid");
2311 // Verify that the user has only a single group, and the correct one
2313 if (getgroups(1, groups
) != 1)
2314 return _error
->Errno("getgroups", "Could not get new groups");
2315 if (groups
[0] != pw
->pw_gid
)
2316 return _error
->Error("Could not switch group");
2318 // Verify that gid, egid, uid, and euid changed
2319 if (getgid() != pw
->pw_gid
)
2320 return _error
->Error("Could not switch group");
2321 if (getegid() != pw
->pw_gid
)
2322 return _error
->Error("Could not switch effective group");
2323 if (getuid() != pw
->pw_uid
)
2324 return _error
->Error("Could not switch user");
2325 if (geteuid() != pw
->pw_uid
)
2326 return _error
->Error("Could not switch effective user");
2328 #ifdef HAVE_GETRESUID
2329 // verify that the saved set-user-id was changed as well
2333 if (getresuid(&ruid
, &euid
, &suid
))
2334 return _error
->Errno("getresuid", "Could not get saved set-user-ID");
2335 if (suid
!= pw
->pw_uid
)
2336 return _error
->Error("Could not switch saved set-user-ID");
2339 #ifdef HAVE_GETRESGID
2340 // verify that the saved set-group-id was changed as well
2344 if (getresgid(&rgid
, &egid
, &sgid
))
2345 return _error
->Errno("getresuid", "Could not get saved set-group-ID");
2346 if (sgid
!= pw
->pw_gid
)
2347 return _error
->Error("Could not switch saved set-group-ID");
2350 // Check that uid and gid changes do not work anymore
2351 if (pw
->pw_gid
!= old_gid
&& (setgid(old_gid
) != -1 || setegid(old_gid
) != -1))
2352 return _error
->Error("Could restore a gid to root, privilege dropping did not work");
2354 if (pw
->pw_uid
!= old_uid
&& (setuid(old_uid
) != -1 || seteuid(old_uid
) != -1))
2355 return _error
->Error("Could restore a uid to root, privilege dropping did not work");