apt  2.2.4
About: Apt (Advanced Package Tool) is a management system for software packages (Debian/Ubuntu). Release series 2.2.
  Fossies Dox: apt-2.2.4.tar.gz  ("unofficial" and yet experimental doxygen-generated source code documentation)  

fileutl.cc
Go to the documentation of this file.
1 // -*- mode: cpp; mode: fold -*-
2 // Description /*{{{*/
3 /* ######################################################################
4 
5  File Utilities
6 
7  CopyFile - Buffered copy of a single file
8  GetLock - dpkg compatible lock file manipulation (fcntl)
9 
10  Most of this source is placed in the Public Domain, do with it what
11  you will
12  It was originally written by Jason Gunthorpe <jgg@debian.org>.
13  FileFd gzip support added by Martin Pitt <martin.pitt@canonical.com>
14 
15  The exception is RunScripts() it is under the GPLv2
16 
17  ##################################################################### */
18  /*}}}*/
19 // Include Files /*{{{*/
20 #include <config.h>
21 
23 #include <apt-pkg/configuration.h>
24 #include <apt-pkg/error.h>
25 #include <apt-pkg/fileutl.h>
26 #include <apt-pkg/macros.h>
27 #include <apt-pkg/pkgsystem.h>
28 #include <apt-pkg/strutl.h>
29 
30 #include <cstdio>
31 #include <cstdlib>
32 #include <cstring>
33 #include <iostream>
34 #include <string>
35 #include <vector>
36 #include <ctype.h>
37 #include <dirent.h>
38 #include <errno.h>
39 #include <fcntl.h>
40 #include <glob.h>
41 #include <grp.h>
42 #include <pwd.h>
43 #include <signal.h>
44 #include <stdarg.h>
45 #include <stddef.h>
46 #include <stdio.h>
47 #include <sys/select.h>
48 #include <sys/stat.h>
49 #include <sys/time.h>
50 #include <sys/wait.h>
51 #include <time.h>
52 #include <unistd.h>
53 
54 #include <algorithm>
55 #include <memory>
56 #include <set>
57 
58 #ifdef HAVE_ZLIB
59 #include <zlib.h>
60 #endif
61 #ifdef HAVE_BZ2
62 #include <bzlib.h>
63 #endif
64 #ifdef HAVE_LZMA
65 #include <lzma.h>
66 #endif
67 #ifdef HAVE_LZ4
68 #include <lz4frame.h>
69 #endif
70 #ifdef HAVE_ZSTD
71 #include <zstd.h>
72 #endif
73 #ifdef HAVE_SYSTEMD
74 #include <systemd/sd-bus.h>
75 #endif
76 #include <endian.h>
77 #include <stdint.h>
78 
79 #if __gnu_linux__
80 #include <sys/prctl.h>
81 #endif
82 
83 #include <apti18n.h>
84  /*}}}*/
85 
86 using namespace std;
87 
88 // RunScripts - Run a set of scripts from a configuration subtree /*{{{*/
89 // ---------------------------------------------------------------------
90 /* */
91 bool RunScripts(const char *Cnf)
92 {
93  Configuration::Item const *Opts = _config->Tree(Cnf);
94  if (Opts == 0 || Opts->Child == 0)
95  return true;
96  Opts = Opts->Child;
97 
98  // Fork for running the system calls
99  pid_t Child = ExecFork();
100 
101  // This is the child
102  if (Child == 0)
103  {
104  if (_system != nullptr && _system->IsLocked() == true && (stringcasecmp(Cnf, "dpkg::post-invoke") == 0 || stringcasecmp(Cnf, "dpkg::pre-invoke") == 0))
105  setenv("DPKG_FRONTEND_LOCKED", "true", 1);
106  if (_config->FindDir("DPkg::Chroot-Directory","/") != "/")
107  {
108  std::cerr << "Chrooting into "
109  << _config->FindDir("DPkg::Chroot-Directory")
110  << std::endl;
111  if (chroot(_config->FindDir("DPkg::Chroot-Directory","/").c_str()) != 0)
112  _exit(100);
113  }
114 
115  if (chdir("/tmp/") != 0)
116  _exit(100);
117 
118  unsigned int Count = 1;
119  for (; Opts != 0; Opts = Opts->Next, Count++)
120  {
121  if (Opts->Value.empty() == true)
122  continue;
123 
124  if(_config->FindB("Debug::RunScripts", false) == true)
125  std::clog << "Running external script: '"
126  << Opts->Value << "'" << std::endl;
127 
128  if (system(Opts->Value.c_str()) != 0)
129  _exit(100+Count);
130  }
131  _exit(0);
132  }
133 
134  // Wait for the child
135  int Status = 0;
136  while (waitpid(Child,&Status,0) != Child)
137  {
138  if (errno == EINTR)
139  continue;
140  return _error->Errno("waitpid","Couldn't wait for subprocess");
141  }
142 
143  // Check for an error code.
144  if (WIFEXITED(Status) == 0 || WEXITSTATUS(Status) != 0)
145  {
146  unsigned int Count = WEXITSTATUS(Status);
147  if (Count > 100)
148  {
149  Count -= 100;
150  for (; Opts != 0 && Count != 1; Opts = Opts->Next, Count--);
151  _error->Error("Problem executing scripts %s '%s'",Cnf,Opts->Value.c_str());
152  }
153 
154  return _error->Error("Sub-process returned an error code");
155  }
156 
157  return true;
158 }
159  /*}}}*/
160 
161 // CopyFile - Buffered copy of a file /*{{{*/
162 // ---------------------------------------------------------------------
163 /* The caller is expected to set things so that failure causes erasure */
164 bool CopyFile(FileFd &From,FileFd &To)
165 {
166  if (From.IsOpen() == false || To.IsOpen() == false ||
167  From.Failed() == true || To.Failed() == true)
168  return false;
169 
170  // Buffered copy between fds
171  constexpr size_t BufSize = APT_BUFFER_SIZE;
172  std::unique_ptr<unsigned char[]> Buf(new unsigned char[BufSize]);
173  unsigned long long ToRead = 0;
174  do {
175  if (From.Read(Buf.get(),BufSize, &ToRead) == false ||
176  To.Write(Buf.get(),ToRead) == false)
177  return false;
178  } while (ToRead != 0);
179 
180  return true;
181 }
182  /*}}}*/
183 bool RemoveFileAt(char const * const Function, int const dirfd, std::string const &FileName)/*{{{*/
184 {
185  if (FileName == "/dev/null")
186  return true;
187  errno = 0;
188  if (unlinkat(dirfd, FileName.c_str(), 0) != 0)
189  {
190  if (errno == ENOENT)
191  return true;
192 
193  return _error->WarningE(Function,_("Problem unlinking the file %s"), FileName.c_str());
194  }
195  return true;
196 }
197  /*}}}*/
198 bool RemoveFile(char const * const Function, std::string const &FileName)/*{{{*/
199 {
200  if (FileName == "/dev/null")
201  return true;
202  errno = 0;
203  if (unlink(FileName.c_str()) != 0)
204  {
205  if (errno == ENOENT)
206  return true;
207 
208  return _error->WarningE(Function,_("Problem unlinking the file %s"), FileName.c_str());
209  }
210  return true;
211 }
212  /*}}}*/
213 // GetLock - Gets a lock file /*{{{*/
214 // ---------------------------------------------------------------------
215 /* This will create an empty file of the given name and lock it. Once this
216  is done all other calls to GetLock in any other process will fail with
217  -1. The return result is the fd of the file, the call should call
218  close at some time. */
219 
220 static std::string GetProcessName(int pid)
221 {
222  struct HideError
223  {
224  int err;
225  HideError() : err(errno) { _error->PushToStack(); }
226  ~~HideError()
227  {
228  errno = err;
229  _error->RevertToStack();
230  }
231  } hideError;
232  std::string path;
233  strprintf(path, "/proc/%d/status", pid);
234  FileFd status(path, FileFd::ReadOnly);
235  std::string line;
236  while (status.ReadLine(line))
237  {
238  if (line.substr(0, 5) == "Name:")
239  return line.substr(6);
240  }
241  return "";
242 }
243 int GetLock(string File,bool Errors)
244 {
245  // GetLock() is used in aptitude on directories with public-write access
246  // Use O_NOFOLLOW here to prevent symlink traversal attacks
247  int FD = open(File.c_str(),O_RDWR | O_CREAT | O_NOFOLLOW,0640);
248  if (FD < 0)
249  {
250  // Read only .. can't have locking problems there.
251  if (errno == EROFS)
252  {
253  _error->Warning(_("Not using locking for read only lock file %s"),File.c_str());
254  return dup(0); // Need something for the caller to close
255  }
256 
257  if (Errors == true)
258  _error->Errno("open",_("Could not open lock file %s"),File.c_str());
259 
260  // Feh.. We do this to distinguish the lock vs open case..
261  errno = EPERM;
262  return -1;
263  }
264  SetCloseExec(FD,true);
265 
266  // Acquire a write lock
267  struct flock fl;
268  fl.l_type = F_WRLCK;
269  fl.l_whence = SEEK_SET;
270  fl.l_start = 0;
271  fl.l_len = 0;
272  if (fcntl(FD,F_SETLK,&fl) == -1)
273  {
274  // always close to not leak resources
275  int Tmp = errno;
276 
277  if ((errno == EACCES || errno == EAGAIN))
278  {
279  fl.l_type = F_WRLCK;
280  fl.l_whence = SEEK_SET;
281  fl.l_start = 0;
282  fl.l_len = 0;
283  fl.l_pid = -1;
284  fcntl(FD, F_GETLK, &fl);
285  }
286  else
287  {
288  fl.l_pid = -1;
289  }
290  close(FD);
291  errno = Tmp;
292 
293  if (errno == ENOLCK)
294  {
295  _error->Warning(_("Not using locking for nfs mounted lock file %s"),File.c_str());
296  return dup(0); // Need something for the caller to close
297  }
298 
299  if (Errors == true)
300  {
301  // We only do the lookup in the if ((errno == EACCES || errno == EAGAIN))
302  // case, so we do not need to show the errno strerrr here...
303  if (fl.l_pid != -1)
304  {
305  auto name = GetProcessName(fl.l_pid);
306  if (name.empty())
307  _error->Error(_("Could not get lock %s. It is held by process %d"), File.c_str(), fl.l_pid);
308  else
309  _error->Error(_("Could not get lock %s. It is held by process %d (%s)"), File.c_str(), fl.l_pid, name.c_str());
310  }
311  else
312  _error->Errno("open", _("Could not get lock %s"), File.c_str());
313 
314  _error->Notice(_("Be aware that removing the lock file is not a solution and may break your system."));
315  }
316 
317  return -1;
318  }
319 
320  return FD;
321 }
322  /*}}}*/
323 // FileExists - Check if a file exists /*{{{*/
324 // ---------------------------------------------------------------------
325 /* Beware: Directories are also files! */
326 bool FileExists(string File)
327 {
328  struct stat Buf;
329  if (stat(File.c_str(),&Buf) != 0)
330  return false;
331  return true;
332 }
333  /*}}}*/
334 // RealFileExists - Check if a file exists and if it is really a file /*{{{*/
335 // ---------------------------------------------------------------------
336 /* */
337 bool RealFileExists(string File)
338 {
339  struct stat Buf;
340  if (stat(File.c_str(),&Buf) != 0)
341  return false;
342  return ((Buf.st_mode & S_IFREG) != 0);
343 }
344  /*}}}*/
345 // DirectoryExists - Check if a directory exists and is really one /*{{{*/
346 // ---------------------------------------------------------------------
347 /* */
348 bool DirectoryExists(string const &Path)
349 {
350  struct stat Buf;
351  if (stat(Path.c_str(),&Buf) != 0)
352  return false;
353  return ((Buf.st_mode & S_IFDIR) != 0);
354 }
355  /*}}}*/
356 // CreateDirectory - poor man's mkdir -p guarded by a parent directory /*{{{*/
357 // ---------------------------------------------------------------------
358 /* This method will create all directories needed for path in good old
359  mkdir -p style but refuses to do this if Parent is not a prefix of
360  this Path. Example: /var/cache/ and /var/cache/apt/archives are given,
361  so it will create apt/archives if /var/cache exists - on the other
362  hand if the parent is /var/lib the creation will fail as this path
363  is not a parent of the path to be generated. */
364 bool CreateDirectory(string const &Parent, string const &Path)
365 {
366  if (Parent.empty() == true || Path.empty() == true)
367  return false;
368 
369  if (DirectoryExists(Path) == true)
370  return true;
371 
372  if (DirectoryExists(Parent) == false)
373  return false;
374 
375  // we are not going to create directories "into the blue"
376  if (Path.compare(0, Parent.length(), Parent) != 0)
377  return false;
378 
379  vector<string> const dirs = VectorizeString(Path.substr(Parent.size()), '/');
380  string progress = Parent;
381  for (vector<string>::const_iterator d = dirs.begin(); d != dirs.end(); ++d)
382  {
383  if (d->empty() == true)
384  continue;
385 
386  progress.append("/").append(*d);
387  if (DirectoryExists(progress) == true)
388  continue;
389 
390  if (mkdir(progress.c_str(), 0755) != 0)
391  return false;
392  }
393  return true;
394 }
395  /*}}}*/
396 // CreateAPTDirectoryIfNeeded - ensure that the given directory exists /*{{{*/
397 // ---------------------------------------------------------------------
398 /* a small wrapper around CreateDirectory to check if it exists and to
399  remove the trailing "/apt/" from the parent directory if needed */
400 bool CreateAPTDirectoryIfNeeded(string const &Parent, string const &Path)
401 {
402  if (DirectoryExists(Path) == true)
403  return true;
404 
405  size_t const len = Parent.size();
406  if (len > 5 && Parent.find("/apt/", len - 6, 5) == len - 5)
407  {
408  if (CreateDirectory(Parent.substr(0,len-5), Path) == true)
409  return true;
410  }
411  else if (CreateDirectory(Parent, Path) == true)
412  return true;
413 
414  return false;
415 }
416  /*}}}*/
417 // GetListOfFilesInDir - returns a vector of files in the given dir /*{{{*/
418 // ---------------------------------------------------------------------
419 /* If an extension is given only files with this extension are included
420  in the returned vector, otherwise every "normal" file is included. */
421 std::vector<string> GetListOfFilesInDir(string const &Dir, string const &Ext,
422  bool const &SortList, bool const &AllowNoExt)
423 {
424  std::vector<string> ext;
425  ext.reserve(2);
426  if (Ext.empty() == false)
427  ext.push_back(Ext);
428  if (AllowNoExt == true && ext.empty() == false)
429  ext.push_back("");
430  return GetListOfFilesInDir(Dir, ext, SortList);
431 }
432 std::vector<string> GetListOfFilesInDir(string const &Dir, std::vector<string> const &Ext,
433  bool const &SortList)
434 {
435  // Attention debuggers: need to be set with the environment config file!
436  bool const Debug = _config->FindB("Debug::GetListOfFilesInDir", false);
437  if (Debug == true)
438  {
439  std::clog << "Accept in " << Dir << " only files with the following " << Ext.size() << " extensions:" << std::endl;
440  if (Ext.empty() == true)
441  std::clog << "\tNO extension" << std::endl;
442  else
443  for (std::vector<string>::const_iterator e = Ext.begin();
444  e != Ext.end(); ++e)
445  std::clog << '\t' << (e->empty() == true ? "NO" : *e) << " extension" << std::endl;
446  }
447 
448  std::vector<string> List;
449 
450  if (DirectoryExists(Dir) == false)
451  {
452  _error->Error(_("List of files can't be created as '%s' is not a directory"), Dir.c_str());
453  return List;
454  }
455 
456  Configuration::MatchAgainstConfig SilentIgnore("Dir::Ignore-Files-Silently");
457  DIR *D = opendir(Dir.c_str());
458  if (D == 0)
459  {
460  if (errno == EACCES)
461  _error->WarningE("opendir", _("Unable to read %s"), Dir.c_str());
462  else
463  _error->Errno("opendir", _("Unable to read %s"), Dir.c_str());
464  return List;
465  }
466 
467  for (struct dirent *Ent = readdir(D); Ent != 0; Ent = readdir(D))
468  {
469  // skip "hidden" files
470  if (Ent->d_name[0] == '.')
471  continue;
472 
473  // Make sure it is a file and not something else
474  string const File = flCombine(Dir,Ent->d_name);
475 #ifdef _DIRENT_HAVE_D_TYPE
476  if (Ent->d_type != DT_REG)
477 #endif
478  {
479  if (RealFileExists(File) == false)
480  {
481  // do not show ignoration warnings for directories
482  if (
483 #ifdef _DIRENT_HAVE_D_TYPE
484  Ent->d_type == DT_DIR ||
485 #endif
486  DirectoryExists(File) == true)
487  continue;
488  if (SilentIgnore.Match(Ent->d_name) == false)
489  _error->Notice(_("Ignoring '%s' in directory '%s' as it is not a regular file"), Ent->d_name, Dir.c_str());
490  continue;
491  }
492  }
493 
494  // check for accepted extension:
495  // no extension given -> periods are bad as hell!
496  // extensions given -> "" extension allows no extension
497  if (Ext.empty() == false)
498  {
499  string d_ext = flExtension(Ent->d_name);
500  if (d_ext == Ent->d_name) // no extension
501  {
502  if (std::find(Ext.begin(), Ext.end(), "") == Ext.end())
503  {
504  if (Debug == true)
505  std::clog << "Bad file: " << Ent->d_name << " → no extension" << std::endl;
506  if (SilentIgnore.Match(Ent->d_name) == false)
507  _error->Notice(_("Ignoring file '%s' in directory '%s' as it has no filename extension"), Ent->d_name, Dir.c_str());
508  continue;
509  }
510  }
511  else if (std::find(Ext.begin(), Ext.end(), d_ext) == Ext.end())
512  {
513  if (Debug == true)
514  std::clog << "Bad file: " << Ent->d_name << " → bad extension »" << flExtension(Ent->d_name) << "«" << std::endl;
515  if (SilentIgnore.Match(Ent->d_name) == false)
516  _error->Notice(_("Ignoring file '%s' in directory '%s' as it has an invalid filename extension"), Ent->d_name, Dir.c_str());
517  continue;
518  }
519  }
520 
521  // Skip bad filenames ala run-parts
522  const char *C = Ent->d_name;
523  for (; *C != 0; ++C)
524  if (isalpha(*C) == 0 && isdigit(*C) == 0
525  && *C != '_' && *C != '-' && *C != ':') {
526  // no required extension -> dot is a bad character
527  if (*C == '.' && Ext.empty() == false)
528  continue;
529  break;
530  }
531 
532  // we don't reach the end of the name -> bad character included
533  if (*C != 0)
534  {
535  if (Debug == true)
536  std::clog << "Bad file: " << Ent->d_name << " → bad character »"
537  << *C << "« in filename (period allowed: " << (Ext.empty() ? "no" : "yes") << ")" << std::endl;
538  continue;
539  }
540 
541  // skip filenames which end with a period. These are never valid
542  if (*(C - 1) == '.')
543  {
544  if (Debug == true)
545  std::clog << "Bad file: " << Ent->d_name << " → Period as last character" << std::endl;
546  continue;
547  }
548 
549  if (Debug == true)
550  std::clog << "Accept file: " << Ent->d_name << " in " << Dir << std::endl;
551  List.push_back(File);
552  }
553  closedir(D);
554 
555  if (SortList == true)
556  std::sort(List.begin(),List.end());
557  return List;
558 }
559 std::vector<string> GetListOfFilesInDir(string const &Dir, bool SortList)
560 {
561  bool const Debug = _config->FindB("Debug::GetListOfFilesInDir", false);
562  if (Debug == true)
563  std::clog << "Accept in " << Dir << " all regular files" << std::endl;
564 
565  std::vector<string> List;
566 
567  if (DirectoryExists(Dir) == false)
568  {
569  _error->Error(_("List of files can't be created as '%s' is not a directory"), Dir.c_str());
570  return List;
571  }
572 
573  DIR *D = opendir(Dir.c_str());
574  if (D == 0)
575  {
576  _error->Errno("opendir",_("Unable to read %s"),Dir.c_str());
577  return List;
578  }
579 
580  for (struct dirent *Ent = readdir(D); Ent != 0; Ent = readdir(D))
581  {
582  // skip "hidden" files
583  if (Ent->d_name[0] == '.')
584  continue;
585 
586  // Make sure it is a file and not something else
587  string const File = flCombine(Dir,Ent->d_name);
588 #ifdef _DIRENT_HAVE_D_TYPE
589  if (Ent->d_type != DT_REG)
590 #endif
591  {
592  if (RealFileExists(File) == false)
593  {
594  if (Debug == true)
595  std::clog << "Bad file: " << Ent->d_name << " → it is not a real file" << std::endl;
596  continue;
597  }
598  }
599 
600  // Skip bad filenames ala run-parts
601  const char *C = Ent->d_name;
602  for (; *C != 0; ++C)
603  if (isalpha(*C) == 0 && isdigit(*C) == 0
604  && *C != '_' && *C != '-' && *C != '.')
605  break;
606 
607  // we don't reach the end of the name -> bad character included
608  if (*C != 0)
609  {
610  if (Debug == true)
611  std::clog << "Bad file: " << Ent->d_name << " → bad character »" << *C << "« in filename" << std::endl;
612  continue;
613  }
614 
615  // skip filenames which end with a period. These are never valid
616  if (*(C - 1) == '.')
617  {
618  if (Debug == true)
619  std::clog << "Bad file: " << Ent->d_name << " → Period as last character" << std::endl;
620  continue;
621  }
622 
623  if (Debug == true)
624  std::clog << "Accept file: " << Ent->d_name << " in " << Dir << std::endl;
625  List.push_back(File);
626  }
627  closedir(D);
628 
629  if (SortList == true)
630  std::sort(List.begin(),List.end());
631  return List;
632 }
633  /*}}}*/
634 // SafeGetCWD - This is a safer getcwd that returns a dynamic string /*{{{*/
635 // ---------------------------------------------------------------------
636 /* We return / on failure. */
637 string SafeGetCWD()
638 {
639  // Stash the current dir.
640  char S[300];
641  S[0] = 0;
642  if (getcwd(S,sizeof(S)-2) == 0)
643  return "/";
644  unsigned int Len = strlen(S);
645  S[Len] = '/';
646  S[Len+1] = 0;
647  return S;
648 }
649  /*}}}*/
650 // GetModificationTime - Get the mtime of the given file or -1 on error /*{{{*/
651 // ---------------------------------------------------------------------
652 /* We return / on failure. */
653 time_t GetModificationTime(string const &Path)
654 {
655  struct stat St;
656  if (stat(Path.c_str(), &St) < 0)
657  return -1;
658  return St.st_mtime;
659 }
660  /*}}}*/
661 // flNotDir - Strip the directory from the filename /*{{{*/
662 // ---------------------------------------------------------------------
663 /* */
664 string flNotDir(string File)
665 {
666  string::size_type Res = File.rfind('/');
667  if (Res == string::npos)
668  return File;
669  Res++;
670  return string(File,Res,Res - File.length());
671 }
672  /*}}}*/
673 // flNotFile - Strip the file from the directory name /*{{{*/
674 // ---------------------------------------------------------------------
675 /* Result ends in a / */
676 string flNotFile(string File)
677 {
678  string::size_type Res = File.rfind('/');
679  if (Res == string::npos)
680  return "./";
681  Res++;
682  return string(File,0,Res);
683 }
684  /*}}}*/
685 // flExtension - Return the extension for the file /*{{{*/
686 // ---------------------------------------------------------------------
687 /* */
688 string flExtension(string File)
689 {
690  string::size_type Res = File.rfind('.');
691  if (Res == string::npos)
692  return File;
693  Res++;
694  return string(File,Res,Res - File.length());
695 }
696  /*}}}*/
697 // flNoLink - If file is a symlink then deref it /*{{{*/
698 // ---------------------------------------------------------------------
699 /* If the name is not a link then the returned path is the input. */
700 string flNoLink(string File)
701 {
702  struct stat St;
703  if (lstat(File.c_str(),&St) != 0 || S_ISLNK(St.st_mode) == 0)
704  return File;
705  if (stat(File.c_str(),&St) != 0)
706  return File;
707 
708  /* Loop resolving the link. There is no need to limit the number of
709  loops because the stat call above ensures that the symlink is not
710  circular */
711  char Buffer[1024];
712  string NFile = File;
713  while (1)
714  {
715  // Read the link
716  ssize_t Res;
717  if ((Res = readlink(NFile.c_str(),Buffer,sizeof(Buffer))) <= 0 ||
718  (size_t)Res >= sizeof(Buffer))
719  return File;
720 
721  // Append or replace the previous path
722  Buffer[Res] = 0;
723  if (Buffer[0] == '/')
724  NFile = Buffer;
725  else
726  NFile = flNotFile(NFile) + Buffer;
727 
728  // See if we are done
729  if (lstat(NFile.c_str(),&St) != 0)
730  return File;
731  if (S_ISLNK(St.st_mode) == 0)
732  return NFile;
733  }
734 }
735  /*}}}*/
736 // flCombine - Combine a file and a directory /*{{{*/
737 // ---------------------------------------------------------------------
738 /* If the file is an absolute path then it is just returned, otherwise
739  the directory is pre-pended to it. */
740 string flCombine(string Dir,string File)
741 {
742  if (File.empty() == true)
743  return string();
744 
745  if (File[0] == '/' || Dir.empty() == true)
746  return File;
747  if (File.length() >= 2 && File[0] == '.' && File[1] == '/')
748  return File;
749  if (Dir[Dir.length()-1] == '/')
750  return Dir + File;
751  return Dir + '/' + File;
752 }
753  /*}}}*/
754 // flAbsPath - Return the absolute path of the filename /*{{{*/
755 // ---------------------------------------------------------------------
756 /* */
757 string flAbsPath(string File)
758 {
759  char *p = realpath(File.c_str(), NULL);
760  if (p == NULL)
761  {
762  _error->Errno("realpath", "flAbsPath on %s failed", File.c_str());
763  return "";
764  }
765  std::string AbsPath(p);
766  free(p);
767  return AbsPath;
768 }
769  /*}}}*/
770 std::string flNormalize(std::string file) /*{{{*/
771 {
772  if (file.empty())
773  return file;
774  // do some normalisation by removing // and /./ from the path
775  size_t found = string::npos;
776  while ((found = file.find("/./")) != string::npos)
777  file.replace(found, 3, "/");
778  while ((found = file.find("//")) != string::npos)
779  file.replace(found, 2, "/");
780 
781  if (APT::String::Startswith(file, "/dev/null"))
782  {
783  file.erase(strlen("/dev/null"));
784  return file;
785  }
786  return file;
787 }
788  /*}}}*/
789 // SetCloseExec - Set the close on exec flag /*{{{*/
790 // ---------------------------------------------------------------------
791 /* */
792 void SetCloseExec(int Fd,bool Close)
793 {
794  if (fcntl(Fd,F_SETFD,(Close == false)?0:FD_CLOEXEC) != 0)
795  {
796  cerr << "FATAL -> Could not set close on exec " << strerror(errno) << endl;
797  exit(100);
798  }
799 }
800  /*}}}*/
801 // SetNonBlock - Set the nonblocking flag /*{{{*/
802 // ---------------------------------------------------------------------
803 /* */
804 void SetNonBlock(int Fd,bool Block)
805 {
806  int Flags = fcntl(Fd,F_GETFL) & (~~O_NONBLOCK);
807  if (fcntl(Fd,F_SETFL,Flags | ((Block == false)?0:O_NONBLOCK)) != 0)
808  {
809  cerr << "FATAL -> Could not set non-blocking flag " << strerror(errno) << endl;
810  exit(100);
811  }
812 }
813  /*}}}*/
814 // WaitFd - Wait for a FD to become readable /*{{{*/
815 // ---------------------------------------------------------------------
816 /* This waits for a FD to become readable using select. It is useful for
817  applications making use of non-blocking sockets. The timeout is
818  in seconds. */
819 bool WaitFd(int Fd,bool write,unsigned long timeout)
820 {
821  fd_set Set;
822  struct timeval tv;
823  FD_ZERO(&Set);
824  FD_SET(Fd,&Set);
825  tv.tv_sec = timeout;
826  tv.tv_usec = 0;
827  if (write == true)
828  {
829  int Res;
830  do
831  {
832  Res = select(Fd+1,0,&Set,0,(timeout != 0?&tv:0));
833  }
834  while (Res < 0 && errno == EINTR);
835 
836  if (Res <= 0)
837  return false;
838  }
839  else
840  {
841  int Res;
842  do
843  {
844  Res = select(Fd+1,&Set,0,0,(timeout != 0?&tv:0));
845  }
846  while (Res < 0 && errno == EINTR);
847 
848  if (Res <= 0)
849  return false;
850  }
851 
852  return true;
853 }
854  /*}}}*/
855 // MergeKeepFdsFromConfiguration - Merge APT::Keep-Fds configuration /*{{{*/
856 // ---------------------------------------------------------------------
857 /* This is used to merge the APT::Keep-Fds with the provided KeepFDs
858  * set.
859  */
860 void MergeKeepFdsFromConfiguration(std::set<int> &KeepFDs)
861 {
862  Configuration::Item const *Opts = _config->Tree("APT::Keep-Fds");
863  if (Opts != 0 && Opts->Child != 0)
864  {
865  Opts = Opts->Child;
866  for (; Opts != 0; Opts = Opts->Next)
867  {
868  if (Opts->Value.empty() == true)
869  continue;
870  int fd = atoi(Opts->Value.c_str());
871  KeepFDs.insert(fd);
872  }
873  }
874 }
875  /*}}}*/
876 // ExecFork - Magical fork that sanitizes the context before execing /*{{{*/
877 // ---------------------------------------------------------------------
878 /* This is used if you want to cleanse the environment for the forked
879  child, it fixes up the important signals and nukes all of the fds,
880  otherwise acts like normal fork. */
881 pid_t ExecFork()
882 {
883  set<int> KeepFDs;
884  // we need to merge the Keep-Fds as external tools like
885  // debconf-apt-progress use it
887  return ExecFork(KeepFDs);
888 }
889 
890 pid_t ExecFork(std::set<int> KeepFDs)
891 {
892  // Fork off the process
893  pid_t Process = fork();
894  if (Process < 0)
895  {
896  cerr << "FATAL -> Failed to fork." << endl;
897  exit(100);
898  }
899 
900  // Spawn the subprocess
901  if (Process == 0)
902  {
903  // Setup the signals
904  signal(SIGPIPE,SIG_DFL);
905  signal(SIGQUIT,SIG_DFL);
906  signal(SIGINT,SIG_DFL);
907  signal(SIGWINCH,SIG_DFL);
908  signal(SIGCONT,SIG_DFL);
909  signal(SIGTSTP,SIG_DFL);
910 
911  DIR *dir = opendir("/proc/self/fd");
912  if (dir != NULL)
913  {
914  struct dirent *ent;
915  while ((ent = readdir(dir)))
916  {
917  int fd = atoi(ent->d_name);
918  // If fd > 0, it was a fd number and not . or ..
919  if (fd >= 3 && KeepFDs.find(fd) == KeepFDs.end())
920  fcntl(fd,F_SETFD,FD_CLOEXEC);
921  }
922  closedir(dir);
923  } else {
924  long ScOpenMax = sysconf(_SC_OPEN_MAX);
925  // Close all of our FDs - just in case
926  for (int K = 3; K != ScOpenMax; K++)
927  {
928  if(KeepFDs.find(K) == KeepFDs.end())
929  fcntl(K,F_SETFD,FD_CLOEXEC);
930  }
931  }
932  }
933 
934  return Process;
935 }
936  /*}}}*/
937 // ExecWait - Fancy waitpid /*{{{*/
938 // ---------------------------------------------------------------------
939 /* Waits for the given sub process. If Reap is set then no errors are
940  generated. Otherwise a failed subprocess will generate a proper descriptive
941  message */
942 bool ExecWait(pid_t Pid,const char *Name,bool Reap)
943 {
944  if (Pid <= 1)
945  return true;
946 
947  // Wait and collect the error code
948  int Status;
949  while (waitpid(Pid,&Status,0) != Pid)
950  {
951  if (errno == EINTR)
952  continue;
953 
954  if (Reap == true)
955  return false;
956 
957  return _error->Error(_("Waited for %s but it wasn't there"),Name);
958  }
959 
960 
961  // Check for an error code.
962  if (WIFEXITED(Status) == 0 || WEXITSTATUS(Status) != 0)
963  {
964  if (Reap == true)
965  return false;
966  if (WIFSIGNALED(Status) != 0)
967  {
968  if( WTERMSIG(Status) == SIGSEGV)
969  return _error->Error(_("Sub-process %s received a segmentation fault."),Name);
970  else
971  return _error->Error(_("Sub-process %s received signal %u."),Name, WTERMSIG(Status));
972  }
973 
974  if (WIFEXITED(Status) != 0)
975  return _error->Error(_("Sub-process %s returned an error code (%u)"),Name,WEXITSTATUS(Status));
976 
977  return _error->Error(_("Sub-process %s exited unexpectedly"),Name);
978  }
979 
980  return true;
981 }
982  /*}}}*/
983 // StartsWithGPGClearTextSignature - Check if a file is Pgp/GPG clearsigned /*{{{*/
984 bool StartsWithGPGClearTextSignature(string const &FileName)
985 {
986  FILE* gpg = fopen(FileName.c_str(), "r");
987  if (gpg == nullptr)
988  return false;
989 
990  char * lineptr = nullptr;
991  size_t n = 0;
992  errno = 0;
993  ssize_t const result = getline(&lineptr, &n, gpg);
994  if (errno != 0)
995  {
996  _error->Errno("getline", "Could not read from %s", FileName.c_str());
997  fclose(gpg);
998  free(lineptr);
999  return false;
1000  }
1001  fclose(gpg);
1002 
1003  _strrstrip(lineptr);
1004  static const char* SIGMSG = "-----BEGIN PGP SIGNED MESSAGE-----";
1005  if (result == -1 || strcmp(lineptr, SIGMSG) != 0)
1006  {
1007  free(lineptr);
1008  return false;
1009  }
1010  free(lineptr);
1011  return true;
1012 }
1013  /*}}}*/
1014 // ChangeOwnerAndPermissionOfFile - set file attributes to requested values /*{{{*/
1015 bool ChangeOwnerAndPermissionOfFile(char const * const requester, char const * const file, char const * const user, char const * const group, mode_t const mode)
1016 {
1017  if (strcmp(file, "/dev/null") == 0)
1018  return true;
1019  bool Res = true;
1020  if (getuid() == 0 && strlen(user) != 0 && strlen(group) != 0) // if we aren't root, we can't chown, so don't try it
1021  {
1022  // ensure the file is owned by root and has good permissions
1023  struct passwd const * const pw = getpwnam(user);
1024  struct group const * const gr = getgrnam(group);
1025  if (pw != NULL && gr != NULL && lchown(file, pw->pw_uid, gr->gr_gid) != 0)
1026  Res &= _error->WarningE(requester, "chown to %s:%s of file %s failed", user, group, file);
1027  }
1028  struct stat Buf;
1029  if (lstat(file, &Buf) != 0 || S_ISLNK(Buf.st_mode))
1030  return Res;
1031  if (chmod(file, mode) != 0)
1032  Res &= _error->WarningE(requester, "chmod 0%o of file %s failed", mode, file);
1033  return Res;
1034 }
1035  /*}}}*/
1036 
1037 struct APT_HIDDEN simple_buffer { /*{{{*/
1038  size_t buffersize_max = 0;
1039  unsigned long long bufferstart = 0;
1040  unsigned long long bufferend = 0;
1041  char *buffer = nullptr;
1042 
1044  reset(4096);
1045  }
1047  delete[] buffer;
1048  }
1049 
1050  const char *get() const { return buffer + bufferstart; }
1051  char *get() { return buffer + bufferstart; }
1052  const char *getend() const { return buffer + bufferend; }
1053  char *getend() { return buffer + bufferend; }
1054  bool empty() const { return bufferend <= bufferstart; }
1055  bool full() const { return bufferend == buffersize_max; }
1056  unsigned long long free() const { return buffersize_max - bufferend; }
1057  unsigned long long size() const { return bufferend-bufferstart; }
1058  void reset(size_t size)
1059  {
1060  if (size > buffersize_max) {
1061  delete[] buffer;
1062  buffersize_max = size;
1063  buffer = new char[size];
1064  }
1065  reset();
1066  }
1067  void reset() { bufferend = bufferstart = 0; }
1068  ssize_t read(void *to, unsigned long long requested_size) APT_MUSTCHECK
1069  {
1070  if (size() < requested_size)
1071  requested_size = size();
1072  memcpy(to, buffer + bufferstart, requested_size);
1073  bufferstart += requested_size;
1074  if (bufferstart == bufferend)
1075  bufferstart = bufferend = 0;
1076  return requested_size;
1077  }
1078  ssize_t write(const void *from, unsigned long long requested_size) APT_MUSTCHECK
1079  {
1080  if (free() < requested_size)
1081  requested_size = free();
1082  memcpy(getend(), from, requested_size);
1083  bufferend += requested_size;
1084  if (bufferstart == bufferend)
1085  bufferstart = bufferend = 0;
1086  return requested_size;
1087  }
1088 };
1089  /*}}}*/
1090 
1091 class APT_HIDDEN FileFdPrivate { /*{{{*/
1093 protected:
1094  FileFd * const filefd;
1098  bool is_pipe;
1100  unsigned int openmode;
1101  unsigned long long seekpos;
1102 public:
1103 
1104  explicit FileFdPrivate(FileFd * const pfilefd) : filefd(pfilefd),
1106  openmode(0), seekpos(0) {};
1108  {
1109  return compressor;
1110  }
1112  {
1113  this->compressor = compressor;
1114  }
1115  virtual unsigned int get_openmode() const
1116  {
1117  return openmode;
1118  }
1119  virtual void set_openmode(unsigned int openmode)
1120  {
1121  this->openmode = openmode;
1122  }
1123  virtual bool get_is_pipe() const
1124  {
1125  return is_pipe;
1126  }
1127  virtual void set_is_pipe(bool is_pipe)
1128  {
1129  this->is_pipe = is_pipe;
1130  }
1131  virtual unsigned long long get_seekpos() const
1132  {
1133  return seekpos;
1134  }
1135  virtual void set_seekpos(unsigned long long seekpos)
1136  {
1137  this->seekpos = seekpos;
1138  }
1139 
1140  virtual bool InternalOpen(int const iFd, unsigned int const Mode) = 0;
1141  ssize_t InternalRead(void * To, unsigned long long Size)
1142  {
1143  // Drain the buffer if needed.
1144  if (buffer.empty() == false)
1145  {
1146  return buffer.read(To, Size);
1147  }
1148  return InternalUnbufferedRead(To, Size);
1149  }
1150  virtual ssize_t InternalUnbufferedRead(void * const To, unsigned long long const Size) = 0;
1151  virtual bool InternalReadError() { return filefd->FileFdErrno("read",_("Read error")); }
1152  virtual char * InternalReadLine(char * To, unsigned long long Size)
1153  {
1154  if (unlikely(Size == 0))
1155  return nullptr;
1156  // Read one byte less than buffer size to have space for trailing 0.
1157  --Size;
1158 
1159  char * const InitialTo = To;
1160 
1161  while (Size > 0) {
1162  if (buffer.empty() == true)
1163  {
1164  buffer.reset();
1165  unsigned long long actualread = 0;
1166  if (filefd->Read(buffer.getend(), buffer.free(), &actualread) == false)
1167  return nullptr;
1168  buffer.bufferend = actualread;
1169  if (buffer.size() == 0)
1170  {
1171  if (To == InitialTo)
1172  return nullptr;
1173  break;
1174  }
1175  filefd->Flags &= ~~FileFd::HitEof;
1176  }
1177 
1178  unsigned long long const OutputSize = std::min(Size, buffer.size());
1179  char const * const newline = static_cast<char const *>(memchr(buffer.get(), '\n', OutputSize));
1180  // Read until end of line or up to Size bytes from the buffer.
1181  unsigned long long actualread = buffer.read(To,
1182  (newline != nullptr)
1183  ? (newline - buffer.get()) + 1
1184  : OutputSize);
1185  To += actualread;
1186  Size -= actualread;
1187  if (newline != nullptr)
1188  break;
1189  }
1190  *To = '\0';
1191  return InitialTo;
1192  }
1193  virtual bool InternalFlush()
1194  {
1195  return true;
1196  }
1197  virtual ssize_t InternalWrite(void const * const From, unsigned long long const Size) = 0;
1198  virtual bool InternalWriteError() { return filefd->FileFdErrno("write",_("Write error")); }
1199  virtual bool InternalSeek(unsigned long long const To)
1200  {
1201  // Our poor man seeking is costly, so try to avoid it
1202  unsigned long long const iseekpos = filefd->Tell();
1203  if (iseekpos == To)
1204  return true;
1205  else if (iseekpos < To)
1206  return filefd->Skip(To - iseekpos);
1207 
1209  return filefd->FileFdError("Reopen is only implemented for read-only files!");
1211  if (filefd->iFd != -1)
1212  close(filefd->iFd);
1213  filefd->iFd = -1;
1214  if (filefd->TemporaryFileName.empty() == false)
1215  filefd->iFd = open(filefd->TemporaryFileName.c_str(), O_RDONLY);
1216  else if (filefd->FileName.empty() == false)
1217  filefd->iFd = open(filefd->FileName.c_str(), O_RDONLY);
1218  else
1219  {
1220  if (compressed_fd > 0)
1221  if (lseek(compressed_fd, 0, SEEK_SET) != 0)
1223  if (filefd->iFd < 0)
1224  return filefd->FileFdError("Reopen is not implemented for pipes opened with FileFd::OpenDescriptor()!");
1225  }
1226 
1228  return filefd->FileFdError("Seek on file %s because it couldn't be reopened", filefd->FileName.c_str());
1229 
1230  buffer.reset();
1231  set_seekpos(0);
1232  if (To != 0)
1233  return filefd->Skip(To);
1234 
1235  seekpos = To;
1236  return true;
1237  }
1238  virtual bool InternalSkip(unsigned long long Over)
1239  {
1240  unsigned long long constexpr buffersize = 1024;
1241  char buffer[buffersize];
1242  while (Over != 0)
1243  {
1244  unsigned long long toread = std::min(buffersize, Over);
1245  if (filefd->Read(buffer, toread) == false)
1246  return filefd->FileFdError("Unable to seek ahead %llu",Over);
1247  Over -= toread;
1248  }
1249  return true;
1250  }
1251  virtual bool InternalTruncate(unsigned long long const)
1252  {
1253  return filefd->FileFdError("Truncating compressed files is not implemented (%s)", filefd->FileName.c_str());
1254  }
1255  virtual unsigned long long InternalTell()
1256  {
1257  // In theory, we could just return seekpos here always instead of
1258  // seeking around, but not all users of FileFd use always Seek() and co
1259  // so d->seekpos isn't always true and we can just use it as a hint if
1260  // we have nothing else, but not always as an authority…
1261  return seekpos - buffer.size();
1262  }
1263  virtual unsigned long long InternalSize()
1264  {
1265  unsigned long long size = 0;
1266  unsigned long long const oldSeek = filefd->Tell();
1267  unsigned long long constexpr ignoresize = 1024;
1268  char ignore[ignoresize];
1269  unsigned long long read = 0;
1270  do {
1271  if (filefd->Read(ignore, ignoresize, &read) == false)
1272  {
1273  filefd->Seek(oldSeek);
1274  return 0;
1275  }
1276  } while(read != 0);
1277  size = filefd->Tell();
1278  filefd->Seek(oldSeek);
1279  return size;
1280  }
1281  virtual bool InternalClose(std::string const &FileName) = 0;
1282  virtual bool InternalStream() const { return false; }
1283  virtual bool InternalAlwaysAutoClose() const { return true; }
1284 
1285  virtual ~FileFdPrivate() {}
1286 };
1287  /*}}}*/
1289 protected:
1292 
1293 public:
1294 
1296  FileFdPrivate(Priv->filefd), wrapped(Priv) {};
1297 
1299  {
1300  return wrapped->get_compressor();
1301  }
1303  {
1304  return wrapped->set_compressor(compressor);
1305  }
1306  virtual unsigned int get_openmode() const APT_OVERRIDE
1307  {
1308  return wrapped->get_openmode();
1309  }
1310  virtual void set_openmode(unsigned int openmode) APT_OVERRIDE
1311  {
1312  return wrapped->set_openmode(openmode);
1313  }
1314  virtual bool get_is_pipe() const APT_OVERRIDE
1315  {
1316  return wrapped->get_is_pipe();
1317  }
1318  virtual void set_is_pipe(bool is_pipe) APT_OVERRIDE
1319  {
1320  FileFdPrivate::set_is_pipe(is_pipe);
1321  wrapped->set_is_pipe(is_pipe);
1322  }
1323  virtual unsigned long long get_seekpos() const APT_OVERRIDE
1324  {
1325  return wrapped->get_seekpos();
1326  }
1327  virtual void set_seekpos(unsigned long long seekpos) APT_OVERRIDE
1328  {
1329  return wrapped->set_seekpos(seekpos);
1330  }
1331  virtual bool InternalOpen(int const iFd, unsigned int const Mode) APT_OVERRIDE
1332  {
1333  if (InternalFlush() == false)
1334  return false;
1335  return wrapped->InternalOpen(iFd, Mode);
1336  }
1337  virtual ssize_t InternalUnbufferedRead(void * const To, unsigned long long const Size) APT_OVERRIDE
1338  {
1339  if (InternalFlush() == false)
1340  return -1;
1341  return wrapped->InternalUnbufferedRead(To, Size);
1342 
1343  }
1345  {
1346  return wrapped->InternalReadError();
1347  }
1348  virtual char * InternalReadLine(char * To, unsigned long long Size) APT_OVERRIDE
1349  {
1350  if (InternalFlush() == false)
1351  return nullptr;
1352  return wrapped->InternalReadLine(To, Size);
1353  }
1355  {
1356  while (writebuffer.empty() == false) {
1357  auto written = wrapped->InternalWrite(writebuffer.get(),
1358  writebuffer.size());
1359  // Ignore interrupted syscalls
1360  if (written < 0 && errno == EINTR)
1361  continue;
1362  if (written < 0)
1363  return wrapped->InternalWriteError();
1364 
1365  writebuffer.bufferstart += written;
1366  }
1367  writebuffer.reset();
1368  return wrapped->InternalFlush();
1369  }
1370  virtual ssize_t InternalWrite(void const * const From, unsigned long long const Size) APT_OVERRIDE
1371  {
1372  // Optimisation: If the buffer is empty and we have more to write than
1373  // would fit in the buffer (or equal number of bytes), write directly.
1374  if (writebuffer.empty() == true && Size >= writebuffer.free())
1375  return wrapped->InternalWrite(From, Size);
1376 
1377  // Write as much into the buffer as possible and then flush if needed
1378  auto written = writebuffer.write(From, Size);
1379 
1380  if (writebuffer.full() && InternalFlush() == false)
1381  return -1;
1382 
1383  return written;
1384  }
1386  {
1387  return wrapped->InternalWriteError();
1388  }
1389  virtual bool InternalSeek(unsigned long long const To) APT_OVERRIDE
1390  {
1391  if (InternalFlush() == false)
1392  return false;
1393  return wrapped->InternalSeek(To);
1394  }
1395  virtual bool InternalSkip(unsigned long long Over) APT_OVERRIDE
1396  {
1397  if (InternalFlush() == false)
1398  return false;
1399  return wrapped->InternalSkip(Over);
1400  }
1401  virtual bool InternalTruncate(unsigned long long const Size) APT_OVERRIDE
1402  {
1403  if (InternalFlush() == false)
1404  return false;
1405  return wrapped->InternalTruncate(Size);
1406  }
1407  virtual unsigned long long InternalTell() APT_OVERRIDE
1408  {
1409  if (InternalFlush() == false)
1410  return -1;
1411  return wrapped->InternalTell();
1412  }
1413  virtual unsigned long long InternalSize() APT_OVERRIDE
1414  {
1415  if (InternalFlush() == false)
1416  return -1;
1417  return wrapped->InternalSize();
1418  }
1419  virtual bool InternalClose(std::string const &FileName) APT_OVERRIDE
1420  {
1421  return wrapped->InternalClose(FileName);
1422  }
1424  {
1425  return wrapped->InternalAlwaysAutoClose();
1426  }
1428  {
1429  delete wrapped;
1430  }
1431 };
1432  /*}}}*/
1434 #ifdef HAVE_ZLIB
1435 public:
1436  gzFile gz;
1437  virtual bool InternalOpen(int const iFd, unsigned int const Mode) APT_OVERRIDE
1438  {
1439  if ((Mode & FileFd::ReadWrite) == FileFd::ReadWrite)
1440  gz = gzdopen(iFd, "r+");
1441  else if ((Mode & FileFd::WriteOnly) == FileFd::WriteOnly)
1442  gz = gzdopen(iFd, "w");
1443  else
1444  gz = gzdopen(iFd, "r");
1445  filefd->Flags |= FileFd::Compressed;
1446  return gz != nullptr;
1447  }
1448  virtual ssize_t InternalUnbufferedRead(void * const To, unsigned long long const Size) APT_OVERRIDE
1449  {
1450  return gzread(gz, To, Size);
1451  }
1452  virtual bool InternalReadError() APT_OVERRIDE
1453  {
1454  int err;
1455  char const * const errmsg = gzerror(gz, &err);
1456  if (err != Z_ERRNO)
1457  return filefd->FileFdError("gzread: %s (%d: %s)", _("Read error"), err, errmsg);
1459  }
1460  virtual char * InternalReadLine(char * To, unsigned long long Size) APT_OVERRIDE
1461  {
1462  return gzgets(gz, To, Size);
1463  }
1464  virtual ssize_t InternalWrite(void const * const From, unsigned long long const Size) APT_OVERRIDE
1465  {
1466  return gzwrite(gz,From,Size);
1467  }
1468  virtual bool InternalWriteError() APT_OVERRIDE
1469  {
1470  int err;
1471  char const * const errmsg = gzerror(gz, &err);
1472  if (err != Z_ERRNO)
1473  return filefd->FileFdError("gzwrite: %s (%d: %s)", _("Write error"), err, errmsg);
1475  }
1476  virtual bool InternalSeek(unsigned long long const To) APT_OVERRIDE
1477  {
1478  off_t const res = gzseek(gz, To, SEEK_SET);
1479  if (res != (off_t)To)
1480  return filefd->FileFdError("Unable to seek to %llu", To);
1481  seekpos = To;
1482  buffer.reset();
1483  return true;
1484  }
1485  virtual bool InternalSkip(unsigned long long Over) APT_OVERRIDE
1486  {
1487  if (Over >= buffer.size())
1488  {
1489  Over -= buffer.size();
1490  buffer.reset();
1491  }
1492  else
1493  {
1494  buffer.bufferstart += Over;
1495  return true;
1496  }
1497  if (Over == 0)
1498  return true;
1499  off_t const res = gzseek(gz, Over, SEEK_CUR);
1500  if (res < 0)
1501  return filefd->FileFdError("Unable to seek ahead %llu",Over);
1502  seekpos = res;
1503  return true;
1504  }
1505  virtual unsigned long long InternalTell() APT_OVERRIDE
1506  {
1507  return gztell(gz) - buffer.size();
1508  }
1509  virtual unsigned long long InternalSize() APT_OVERRIDE
1510  {
1511  unsigned long long filesize = FileFdPrivate::InternalSize();
1512  // only check gzsize if we are actually a gzip file, just checking for
1513  // "gz" is not sufficient as uncompressed files could be opened with
1514  // gzopen in "direct" mode as well
1515  if (filesize == 0 || gzdirect(gz))
1516  return filesize;
1517 
1518  off_t const oldPos = lseek(filefd->iFd, 0, SEEK_CUR);
1519  /* unfortunately zlib.h doesn't provide a gzsize(), so we have to do
1520  * this ourselves; the original (uncompressed) file size is the last 32
1521  * bits of the file */
1522  // FIXME: Size for gz-files is limited by 32bit… no largefile support
1523  if (lseek(filefd->iFd, -4, SEEK_END) < 0)
1524  {
1525  filefd->FileFdErrno("lseek","Unable to seek to end of gzipped file");
1526  return 0;
1527  }
1528  uint32_t size = 0;
1529  if (read(filefd->iFd, &size, 4) != 4)
1530  {
1531  filefd->FileFdErrno("read","Unable to read original size of gzipped file");
1532  return 0;
1533  }
1534  size = le32toh(size);
1535 
1536  if (lseek(filefd->iFd, oldPos, SEEK_SET) < 0)
1537  {
1538  filefd->FileFdErrno("lseek","Unable to seek in gzipped file");
1539  return 0;
1540  }
1541  return size;
1542  }
1543  virtual bool InternalClose(std::string const &FileName) APT_OVERRIDE
1544  {
1545  if (gz == nullptr)
1546  return true;
1547  int const e = gzclose(gz);
1548  gz = nullptr;
1549  // gzdclose() on empty files always fails with "buffer error" here, ignore that
1550  if (e != 0 && e != Z_BUF_ERROR)
1551  return _error->Errno("close",_("Problem closing the gzip file %s"), FileName.c_str());
1552  return true;
1553  }
1554 
1555  explicit GzipFileFdPrivate(FileFd * const filefd) : FileFdPrivate(filefd), gz(nullptr) {}
1556  virtual ~~GzipFileFdPrivate() { InternalClose(""); }
1557 #endif
1558 };
1559  /*}}}*/
1561 #ifdef HAVE_BZ2
1562  BZFILE* bz2;
1563 public:
1564  virtual bool InternalOpen(int const iFd, unsigned int const Mode) APT_OVERRIDE
1565  {
1566  if ((Mode & FileFd::ReadWrite) == FileFd::ReadWrite)
1567  bz2 = BZ2_bzdopen(iFd, "r+");
1568  else if ((Mode & FileFd::WriteOnly) == FileFd::WriteOnly)
1569  bz2 = BZ2_bzdopen(iFd, "w");
1570  else
1571  bz2 = BZ2_bzdopen(iFd, "r");
1572  filefd->Flags |= FileFd::Compressed;
1573  return bz2 != nullptr;
1574  }
1575  virtual ssize_t InternalUnbufferedRead(void * const To, unsigned long long const Size) APT_OVERRIDE
1576  {
1577  return BZ2_bzread(bz2, To, Size);
1578  }
1579  virtual bool InternalReadError() APT_OVERRIDE
1580  {
1581  int err;
1582  char const * const errmsg = BZ2_bzerror(bz2, &err);
1583  if (err != BZ_IO_ERROR)
1584  return filefd->FileFdError("BZ2_bzread: %s %s (%d: %s)", filefd->FileName.c_str(), _("Read error"), err, errmsg);
1586  }
1587  virtual ssize_t InternalWrite(void const * const From, unsigned long long const Size) APT_OVERRIDE
1588  {
1589  return BZ2_bzwrite(bz2, (void*)From, Size);
1590  }
1591  virtual bool InternalWriteError() APT_OVERRIDE
1592  {
1593  int err;
1594  char const * const errmsg = BZ2_bzerror(bz2, &err);
1595  if (err != BZ_IO_ERROR)
1596  return filefd->FileFdError("BZ2_bzwrite: %s %s (%d: %s)", filefd->FileName.c_str(), _("Write error"), err, errmsg);
1598  }
1599  virtual bool InternalStream() const APT_OVERRIDE { return true; }
1600  virtual bool InternalClose(std::string const &) APT_OVERRIDE
1601  {
1602  if (bz2 == nullptr)
1603  return true;
1604  BZ2_bzclose(bz2);
1605  bz2 = nullptr;
1606  return true;
1607  }
1608 
1609  explicit Bz2FileFdPrivate(FileFd * const filefd) : FileFdPrivate(filefd), bz2(nullptr) {}
1610  virtual ~~Bz2FileFdPrivate() { InternalClose(""); }
1611 #endif
1612 };
1613  /*}}}*/
1615  static constexpr unsigned long long LZ4_HEADER_SIZE = 19;
1616  static constexpr unsigned long long LZ4_FOOTER_SIZE = 4;
1617 #ifdef HAVE_LZ4
1618  LZ4F_decompressionContext_t dctx;
1619  LZ4F_compressionContext_t cctx;
1620  LZ4F_errorCode_t res;
1621  FileFd backend;
1622  simple_buffer lz4_buffer;
1623  // Count of bytes that the decompressor expects to read next, or buffer size.
1624  size_t next_to_load = APT_BUFFER_SIZE;
1625 public:
1626  virtual bool InternalOpen(int const iFd, unsigned int const Mode) APT_OVERRIDE
1627  {
1628  if ((Mode & FileFd::ReadWrite) == FileFd::ReadWrite)
1629  return _error->Error("lz4 only supports write or read mode");
1630 
1631  if ((Mode & FileFd::WriteOnly) == FileFd::WriteOnly) {
1632  res = LZ4F_createCompressionContext(&cctx, LZ4F_VERSION);
1633  lz4_buffer.reset(LZ4F_compressBound(APT_BUFFER_SIZE, nullptr)
1634  + LZ4_HEADER_SIZE + LZ4_FOOTER_SIZE);
1635  } else {
1636  res = LZ4F_createDecompressionContext(&dctx, LZ4F_VERSION);
1637  lz4_buffer.reset(APT_BUFFER_SIZE);
1638  }
1639 
1640  filefd->Flags |= FileFd::Compressed;
1641 
1642  if (LZ4F_isError(res))
1643  return false;
1644 
1645  unsigned int flags = (Mode & (FileFd::WriteOnly|FileFd::ReadOnly));
1646  if (backend.OpenDescriptor(iFd, flags, FileFd::None, true) == false)
1647  return false;
1648 
1649  // Write the file header
1650  if ((Mode & FileFd::WriteOnly) == FileFd::WriteOnly)
1651  {
1652  res = LZ4F_compressBegin(cctx, lz4_buffer.buffer, lz4_buffer.buffersize_max, nullptr);
1653  if (LZ4F_isError(res) || backend.Write(lz4_buffer.buffer, res) == false)
1654  return false;
1655  }
1656 
1657  return true;
1658  }
1659  virtual ssize_t InternalUnbufferedRead(void * const To, unsigned long long const Size) APT_OVERRIDE
1660  {
1661  /* Keep reading as long as the compressor still wants to read */
1662  while (next_to_load) {
1663  // Fill compressed buffer;
1664  if (lz4_buffer.empty()) {
1665  unsigned long long read;
1666  /* Reset - if LZ4 decompressor wants to read more, allocate more */
1667  lz4_buffer.reset(next_to_load);
1668  if (backend.Read(lz4_buffer.getend(), lz4_buffer.free(), &read) == false)
1669  return -1;
1670  lz4_buffer.bufferend += read;
1671 
1672  /* Expected EOF */
1673  if (read == 0) {
1674  res = -1;
1675  return filefd->FileFdError("LZ4F: %s %s",
1676  filefd->FileName.c_str(),
1677  _("Unexpected end of file")), -1;
1678  }
1679  }
1680  // Drain compressed buffer as far as possible.
1681  size_t in = lz4_buffer.size();
1682  size_t out = Size;
1683 
1684  res = LZ4F_decompress(dctx, To, &out, lz4_buffer.get(), &in, nullptr);
1685  if (LZ4F_isError(res))
1686  return -1;
1687 
1688  next_to_load = res;
1689  lz4_buffer.bufferstart += in;
1690 
1691  if (out != 0)
1692  return out;
1693  }
1694 
1695  return 0;
1696  }
1697  virtual bool InternalReadError() APT_OVERRIDE
1698  {
1699  char const * const errmsg = LZ4F_getErrorName(res);
1700 
1701  return filefd->FileFdError("LZ4F: %s %s (%zu: %s)", filefd->FileName.c_str(), _("Read error"), res, errmsg);
1702  }
1703  virtual ssize_t InternalWrite(void const * const From, unsigned long long const Size) APT_OVERRIDE
1704  {
1705  unsigned long long const towrite = std::min(APT_BUFFER_SIZE, Size);
1706 
1707  res = LZ4F_compressUpdate(cctx,
1708  lz4_buffer.buffer, lz4_buffer.buffersize_max,
1709  From, towrite, nullptr);
1710 
1711  if (LZ4F_isError(res) || backend.Write(lz4_buffer.buffer, res) == false)
1712  return -1;
1713 
1714  return towrite;
1715  }
1716  virtual bool InternalWriteError() APT_OVERRIDE
1717  {
1718  char const * const errmsg = LZ4F_getErrorName(res);
1719 
1720  return filefd->FileFdError("LZ4F: %s %s (%zu: %s)", filefd->FileName.c_str(), _("Write error"), res, errmsg);
1721  }
1722  virtual bool InternalStream() const APT_OVERRIDE { return true; }
1723 
1724  virtual bool InternalFlush() APT_OVERRIDE
1725  {
1726  return backend.Flush();
1727  }
1728 
1729  virtual bool InternalClose(std::string const &) APT_OVERRIDE
1730  {
1731  /* Reset variables */
1732  res = 0;
1733  next_to_load = APT_BUFFER_SIZE;
1734 
1735  if (cctx != nullptr)
1736  {
1737  if (filefd->Failed() == false)
1738  {
1739  res = LZ4F_compressEnd(cctx, lz4_buffer.buffer, lz4_buffer.buffersize_max, nullptr);
1740  if (LZ4F_isError(res) || backend.Write(lz4_buffer.buffer, res) == false)
1741  return false;
1742  if (!backend.Flush())
1743  return false;
1744  }
1745  if (!backend.Close())
1746  return false;
1747 
1748  res = LZ4F_freeCompressionContext(cctx);
1749  cctx = nullptr;
1750  }
1751 
1752  if (dctx != nullptr)
1753  {
1754  res = LZ4F_freeDecompressionContext(dctx);
1755  dctx = nullptr;
1756  }
1757  if (backend.IsOpen())
1758  {
1759  backend.Close();
1760  filefd->iFd = -1;
1761  }
1762 
1763  return LZ4F_isError(res) == false;
1764  }
1765 
1766  explicit Lz4FileFdPrivate(FileFd * const filefd) : FileFdPrivate(filefd), dctx(nullptr), cctx(nullptr) {}
1767  virtual ~~Lz4FileFdPrivate() {
1768  InternalClose("");
1769  }
1770 #endif
1771 };
1772  /*}}}*/
1774 {
1775 #ifdef HAVE_ZSTD
1776  ZSTD_DStream *dctx;
1777  ZSTD_CStream *cctx;
1778  size_t res = 0;
1779  FileFd backend;
1780  simple_buffer zstd_buffer;
1781  // Count of bytes that the decompressor expects to read next, or buffer size.
1782  size_t next_to_load = APT_BUFFER_SIZE;
1783 
1784  public:
1785  virtual bool InternalOpen(int const iFd, unsigned int const Mode) APT_OVERRIDE
1786  {
1787  if ((Mode & FileFd::ReadWrite) == FileFd::ReadWrite)
1788  return _error->Error("zstd only supports write or read mode");
1789 
1790  if ((Mode & FileFd::WriteOnly) == FileFd::WriteOnly)
1791  {
1792  cctx = ZSTD_createCStream();
1793  res = ZSTD_initCStream(cctx, findLevel(compressor.CompressArgs));
1794  zstd_buffer.reset(APT_BUFFER_SIZE);
1795  }
1796  else
1797  {
1798  dctx = ZSTD_createDStream();
1799  res = ZSTD_initDStream(dctx);
1800  zstd_buffer.reset(APT_BUFFER_SIZE);
1801  }
1802 
1803  filefd->Flags |= FileFd::Compressed;
1804 
1805  if (ZSTD_isError(res))
1806  return false;
1807 
1808  unsigned int flags = (Mode & (FileFd::WriteOnly | FileFd::ReadOnly));
1809  if (backend.OpenDescriptor(iFd, flags, FileFd::None, true) == false)
1810  return false;
1811 
1812  return true;
1813  }
1814  virtual ssize_t InternalUnbufferedRead(void *const To, unsigned long long const Size) APT_OVERRIDE
1815  {
1816  /* Keep reading as long as the compressor still wants to read */
1817  while (true)
1818  {
1819  // Fill compressed buffer;
1820  if (zstd_buffer.empty())
1821  {
1822  unsigned long long read;
1823  /* Reset - if LZ4 decompressor wants to read more, allocate more */
1824  zstd_buffer.reset(next_to_load);
1825  if (backend.Read(zstd_buffer.getend(), zstd_buffer.free(), &read) == false)
1826  return -1;
1827  zstd_buffer.bufferend += read;
1828 
1829  if (read == 0)
1830  {
1831  /* Expected EOF */
1832  if (next_to_load == 0)
1833  return 0;
1834 
1835  res = -1;
1836  return filefd->FileFdError("ZSTD: %s %s",
1837  filefd->FileName.c_str(),
1838  _("Unexpected end of file")),
1839  -1;
1840  }
1841  }
1842  // Drain compressed buffer as far as possible.
1843  ZSTD_inBuffer in = {
1844  .src = zstd_buffer.get(),
1845  .size = zstd_buffer.size(),
1846  .pos = 0,
1847  };
1848  ZSTD_outBuffer out = {
1849  .dst = To,
1850  .size = Size,
1851  .pos = 0,
1852  };
1853 
1854  next_to_load = res = ZSTD_decompressStream(dctx, &out, &in);
1855 
1856  if (res == 0)
1857  {
1858  res = ZSTD_initDStream(dctx);
1859  }
1860 
1861  if (ZSTD_isError(res))
1862  return -1;
1863 
1864  zstd_buffer.bufferstart += in.pos;
1865 
1866  if (out.pos != 0)
1867  return out.pos;
1868  }
1869 
1870  return 0;
1871  }
1872  virtual bool InternalReadError() APT_OVERRIDE
1873  {
1874  char const *const errmsg = ZSTD_getErrorName(res);
1875 
1876  return filefd->FileFdError("ZSTD: %s %s (%zu: %s)", filefd->FileName.c_str(), _("Read error"), res, errmsg);
1877  }
1878  virtual ssize_t InternalWrite(void const *const From, unsigned long long const Size) APT_OVERRIDE
1879  {
1880  // Drain compressed buffer as far as possible.
1881  ZSTD_outBuffer out = {
1882  .dst = zstd_buffer.buffer,
1883  .size = zstd_buffer.buffersize_max,
1884  .pos = 0,
1885  };
1886  ZSTD_inBuffer in = {
1887  .src = From,
1888  .size = Size,
1889  .pos = 0,
1890  };
1891 
1892  res = ZSTD_compressStream(cctx, &out, &in);
1893 
1894  if (ZSTD_isError(res) || backend.Write(zstd_buffer.buffer, out.pos) == false)
1895  return -1;
1896 
1897  return in.pos;
1898  }
1899 
1900  virtual bool InternalWriteError() APT_OVERRIDE
1901  {
1902  char const *const errmsg = ZSTD_getErrorName(res);
1903 
1904  return filefd->FileFdError("ZSTD: %s %s (%zu: %s)", filefd->FileName.c_str(), _("Write error"), res, errmsg);
1905  }
1906  virtual bool InternalStream() const APT_OVERRIDE { return true; }
1907 
1908  virtual bool InternalFlush() APT_OVERRIDE
1909  {
1910  return backend.Flush();
1911  }
1912 
1913  virtual bool InternalClose(std::string const &) APT_OVERRIDE
1914  {
1915  /* Reset variables */
1916  res = 0;
1917  next_to_load = APT_BUFFER_SIZE;
1918 
1919  if (cctx != nullptr)
1920  {
1921  if (filefd->Failed() == false)
1922  {
1923  do
1924  {
1925  ZSTD_outBuffer out = {
1926  .dst = zstd_buffer.buffer,
1927  .size = zstd_buffer.buffersize_max,
1928  .pos = 0,
1929  };
1930  res = ZSTD_endStream(cctx, &out);
1931  if (ZSTD_isError(res) || backend.Write(zstd_buffer.buffer, out.pos) == false)
1932  return false;
1933  } while (res > 0);
1934 
1935  if (!backend.Flush())
1936  return false;
1937  }
1938  if (!backend.Close())
1939  return false;
1940 
1941  res = ZSTD_freeCStream(cctx);
1942  cctx = nullptr;
1943  }
1944 
1945  if (dctx != nullptr)
1946  {
1947  res = ZSTD_freeDStream(dctx);
1948  dctx = nullptr;
1949  }
1950  if (backend.IsOpen())
1951  {
1952  backend.Close();
1953  filefd->iFd = -1;
1954  }
1955 
1956  return ZSTD_isError(res) == false;
1957  }
1958 
1959  static uint32_t findLevel(std::vector<std::string> const &Args)
1960  {
1961  for (auto a = Args.rbegin(); a != Args.rend(); ++a)
1962  {
1963  if (a->size() >= 2 && (*a)[0] == '-' && (*a)[1] != '-')
1964  {
1965  auto const level = a->substr(1);
1966  auto const notANumber = level.find_first_not_of("0123456789");
1967  if (notANumber != std::string::npos)
1968  continue;
1969 
1970  return (uint32_t)stoi(level);
1971  }
1972  }
1973  return 19;
1974  }
1975 
1976  explicit ZstdFileFdPrivate(FileFd *const filefd) : FileFdPrivate(filefd), dctx(nullptr), cctx(nullptr) {}
1977  virtual ~~ZstdFileFdPrivate()
1978  {
1979  InternalClose("");
1980  }
1981 #endif
1982 };
1983  /*}}}*/
1985 #ifdef HAVE_LZMA
1986  struct LZMAFILE {
1987  FILE* file;
1988  FileFd * const filefd;
1989  uint8_t buffer[4096];
1990  lzma_stream stream;
1991  lzma_ret err;
1992  bool eof;
1993  bool compressing;
1994 
1995  explicit LZMAFILE(FileFd * const fd) : file(nullptr), filefd(fd), eof(false), compressing(false) { buffer[0] = '\0'; }
1996  ~~LZMAFILE()
1997  {
1998  if (compressing == true && filefd->Failed() == false)
1999  {
2000  size_t constexpr buffersize = sizeof(buffer)/sizeof(buffer[0]);
2001  while(true)
2002  {
2003  stream.avail_out = buffersize;
2004  stream.next_out = buffer;
2005  err = lzma_code(&stream, LZMA_FINISH);
2006  if (err != LZMA_OK && err != LZMA_STREAM_END)
2007  {
2008  _error->Error("~LZMAFILE: Compress finalisation failed");
2009  break;
2010  }
2011  size_t const n = buffersize - stream.avail_out;
2012  if (n && fwrite(buffer, 1, n, file) != n)
2013  {
2014  _error->Errno("~LZMAFILE",_("Write error"));
2015  break;
2016  }
2017  if (err == LZMA_STREAM_END)
2018  break;
2019  }
2020  }
2021  lzma_end(&stream);
2022  fclose(file);
2023  }
2024  };
2025  LZMAFILE* lzma;
2026  static uint32_t findXZlevel(std::vector<std::string> const &Args)
2027  {
2028  for (auto a = Args.rbegin(); a != Args.rend(); ++a)
2029  if (a->empty() == false && (*a)[0] == '-' && (*a)[1] != '-')
2030  {
2031  auto const number = a->find_last_of("0123456789");
2032  if (number == std::string::npos)
2033  continue;
2034  auto const extreme = a->find("e", number);
2035  uint32_t level = (extreme != std::string::npos) ? LZMA_PRESET_EXTREME : 0;
2036  switch ((*a)[number])
2037  {
2038  case '0': return level | 0;
2039  case '1': return level | 1;
2040  case '2': return level | 2;
2041  case '3': return level | 3;
2042  case '4': return level | 4;
2043  case '5': return level | 5;
2044  case '6': return level | 6;
2045  case '7': return level | 7;
2046  case '8': return level | 8;
2047  case '9': return level | 9;
2048  }
2049  }
2050  return 6;
2051  }
2052 public:
2053  virtual bool InternalOpen(int const iFd, unsigned int const Mode) APT_OVERRIDE
2054  {
2055  if ((Mode & FileFd::ReadWrite) == FileFd::ReadWrite)
2056  return filefd->FileFdError("ReadWrite mode is not supported for lzma/xz files %s", filefd->FileName.c_str());
2057 
2058  if (lzma == nullptr)
2059  lzma = new LzmaFileFdPrivate::LZMAFILE(filefd);
2060  if ((Mode & FileFd::WriteOnly) == FileFd::WriteOnly)
2061  lzma->file = fdopen(iFd, "w");
2062  else
2063  lzma->file = fdopen(iFd, "r");
2064  filefd->Flags |= FileFd::Compressed;
2065  if (lzma->file == nullptr)
2066  return false;
2067 
2068  lzma_stream tmp_stream = LZMA_STREAM_INIT;
2069  lzma->stream = tmp_stream;
2070 
2071  if ((Mode & FileFd::WriteOnly) == FileFd::WriteOnly)
2072  {
2073  uint32_t const xzlevel = findXZlevel(compressor.CompressArgs);
2074  if (compressor.Name == "xz")
2075  {
2076  if (lzma_easy_encoder(&lzma->stream, xzlevel, LZMA_CHECK_CRC64) != LZMA_OK)
2077  return false;
2078  }
2079  else
2080  {
2081  lzma_options_lzma options;
2082  lzma_lzma_preset(&options, xzlevel);
2083  if (lzma_alone_encoder(&lzma->stream, &options) != LZMA_OK)
2084  return false;
2085  }
2086  lzma->compressing = true;
2087  }
2088  else
2089  {
2090  uint64_t constexpr memlimit = 1024 * 1024 * 500;
2091  if (lzma_auto_decoder(&lzma->stream, memlimit, 0) != LZMA_OK)
2092  return false;
2093  lzma->compressing = false;
2094  }
2095  return true;
2096  }
2097  virtual ssize_t InternalUnbufferedRead(void * const To, unsigned long long const Size) APT_OVERRIDE
2098  {
2099  ssize_t Res;
2100  if (lzma->eof == true)
2101  return 0;
2102 
2103  lzma->stream.next_out = (uint8_t *) To;
2104  lzma->stream.avail_out = Size;
2105  if (lzma->stream.avail_in == 0)
2106  {
2107  lzma->stream.next_in = lzma->buffer;
2108  lzma->stream.avail_in = fread(lzma->buffer, 1, sizeof(lzma->buffer)/sizeof(lzma->buffer[0]), lzma->file);
2109  }
2110  lzma->err = lzma_code(&lzma->stream, LZMA_RUN);
2111  if (lzma->err == LZMA_STREAM_END)
2112  {
2113  lzma->eof = true;
2114  Res = Size - lzma->stream.avail_out;
2115  }
2116  else if (lzma->err != LZMA_OK)
2117  {
2118  Res = -1;
2119  errno = 0;
2120  }
2121  else
2122  {
2123  Res = Size - lzma->stream.avail_out;
2124  if (Res == 0)
2125  {
2126  // lzma run was okay, but produced no output…
2127  Res = -1;
2128  errno = EINTR;
2129  }
2130  }
2131  return Res;
2132  }
2133  virtual bool InternalReadError() APT_OVERRIDE
2134  {
2135  return filefd->FileFdError("lzma_read: %s (%d)", _("Read error"), lzma->err);
2136  }
2137  virtual ssize_t InternalWrite(void const * const From, unsigned long long const Size) APT_OVERRIDE
2138  {
2139  ssize_t Res;
2140  lzma->stream.next_in = (uint8_t *)From;
2141  lzma->stream.avail_in = Size;
2142  lzma->stream.next_out = lzma->buffer;
2143  lzma->stream.avail_out = sizeof(lzma->buffer)/sizeof(lzma->buffer[0]);
2144  lzma->err = lzma_code(&lzma->stream, LZMA_RUN);
2145  if (lzma->err != LZMA_OK)
2146  return -1;
2147  size_t const n = sizeof(lzma->buffer)/sizeof(lzma->buffer[0]) - lzma->stream.avail_out;
2148  size_t const m = (n == 0) ? 0 : fwrite(lzma->buffer, 1, n, lzma->file);
2149  if (m != n)
2150  {
2151  Res = -1;
2152  errno = 0;
2153  }
2154  else
2155  {
2156  Res = Size - lzma->stream.avail_in;
2157  if (Res == 0)
2158  {
2159  // lzma run was okay, but produced no output…
2160  Res = -1;
2161  errno = EINTR;
2162  }
2163  }
2164  return Res;
2165  }
2166  virtual bool InternalWriteError() APT_OVERRIDE
2167  {
2168  return filefd->FileFdError("lzma_write: %s (%d)", _("Write error"), lzma->err);
2169  }
2170  virtual bool InternalStream() const APT_OVERRIDE { return true; }
2171  virtual bool InternalClose(std::string const &) APT_OVERRIDE
2172  {
2173  delete lzma;
2174  lzma = nullptr;
2175  return true;
2176  }
2177 
2178  explicit LzmaFileFdPrivate(FileFd * const filefd) : FileFdPrivate(filefd), lzma(nullptr) {}
2179  virtual ~~LzmaFileFdPrivate() { InternalClose(""); }
2180 #endif
2181 };
2182  /*}}}*/
2184 /* if we don't have a specific class dealing with library calls, we (un)compress
2185  by executing a specified binary and pipe in/out what we need */
2186 {
2187 public:
2188  virtual bool InternalOpen(int const, unsigned int const Mode) APT_OVERRIDE
2189  {
2190  // collect zombies here in case we reopen
2191  if (compressor_pid > 0)
2192  ExecWait(compressor_pid, "FileFdCompressor", true);
2193 
2194  if ((Mode & FileFd::ReadWrite) == FileFd::ReadWrite)
2195  return filefd->FileFdError("ReadWrite mode is not supported for file %s", filefd->FileName.c_str());
2196  if (compressor.Binary == "false")
2197  return filefd->FileFdError("libapt has inbuilt support for the %s compression,"
2198  " but was forced to ignore it in favor of an external binary – which isn't installed.", compressor.Name.c_str());
2199 
2200  bool const Comp = (Mode & FileFd::WriteOnly) == FileFd::WriteOnly;
2201  if (Comp == false && filefd->iFd != -1)
2202  {
2203  // Handle 'decompression' of empty files
2204  struct stat Buf;
2205  if (fstat(filefd->iFd, &Buf) != 0)
2206  return filefd->FileFdErrno("fstat", "Could not stat fd %d for file %s", filefd->iFd, filefd->FileName.c_str());
2207  if (Buf.st_size == 0 && S_ISFIFO(Buf.st_mode) == false)
2208  return true;
2209 
2210  // We don't need the file open - instead let the compressor open it
2211  // as he properly knows better how to efficiently read from 'his' file
2212  if (filefd->FileName.empty() == false)
2213  {
2214  close(filefd->iFd);
2215  filefd->iFd = -1;
2216  }
2217  }
2218 
2219  // Create a data pipe
2220  int Pipe[2] = {-1,-1};
2221  if (pipe(Pipe) != 0)
2222  return filefd->FileFdErrno("pipe",_("Failed to create subprocess IPC"));
2223  for (int J = 0; J != 2; J++)
2224  SetCloseExec(Pipe[J],true);
2225 
2226  compressed_fd = filefd->iFd;
2227  set_is_pipe(true);
2228 
2229  if (Comp == true)
2230  filefd->iFd = Pipe[1];
2231  else
2232  filefd->iFd = Pipe[0];
2233 
2234  // The child..
2235  compressor_pid = ExecFork();
2236  if (compressor_pid == 0)
2237  {
2238  if (Comp == true)
2239  {
2240  dup2(compressed_fd,STDOUT_FILENO);
2241  dup2(Pipe[0],STDIN_FILENO);
2242  }
2243  else
2244  {
2245  if (compressed_fd != -1)
2246  dup2(compressed_fd,STDIN_FILENO);
2247  dup2(Pipe[1],STDOUT_FILENO);
2248  }
2249  int const nullfd = open("/dev/null", O_WRONLY);
2250  if (nullfd != -1)
2251  {
2252  dup2(nullfd,STDERR_FILENO);
2253  close(nullfd);
2254  }
2255 
2256  SetCloseExec(STDOUT_FILENO,false);
2257  SetCloseExec(STDIN_FILENO,false);
2258 
2259  std::vector<char const*> Args;
2260  Args.push_back(compressor.Binary.c_str());
2261  std::vector<std::string> const * const addArgs =
2262  (Comp == true) ? &(compressor.CompressArgs) : &(compressor.UncompressArgs);
2263  for (std::vector<std::string>::const_iterator a = addArgs->begin();
2264  a != addArgs->end(); ++a)
2265  Args.push_back(a->c_str());
2266  if (Comp == false && filefd->FileName.empty() == false)
2267  {
2268  // commands not needing arguments, do not need to be told about using standard output
2269  // in reality, only testcases with tools like cat, rev, rot13, … are able to trigger this
2270  if (compressor.CompressArgs.empty() == false && compressor.UncompressArgs.empty() == false)
2271  Args.push_back("--stdout");
2272  if (filefd->TemporaryFileName.empty() == false)
2273  Args.push_back(filefd->TemporaryFileName.c_str());
2274  else
2275  Args.push_back(filefd->FileName.c_str());
2276  }
2277  Args.push_back(NULL);
2278 
2279  execvp(Args[0],(char **)&Args[0]);
2280  cerr << _("Failed to exec compressor ") << Args[0] << endl;
2281  _exit(100);
2282  }
2283  if (Comp == true)
2284  close(Pipe[0]);
2285  else
2286  close(Pipe[1]);
2287 
2288  return true;
2289  }
2290  virtual ssize_t InternalUnbufferedRead(void * const To, unsigned long long const Size) APT_OVERRIDE
2291  {
2292  return read(filefd->iFd, To, Size);
2293  }
2294  virtual ssize_t InternalWrite(void const * const From, unsigned long long const Size) APT_OVERRIDE
2295  {
2296  return write(filefd->iFd, From, Size);
2297  }
2298  virtual bool InternalClose(std::string const &) APT_OVERRIDE
2299  {
2300  bool Ret = true;
2301  if (filefd->iFd != -1)
2302  {
2303  close(filefd->iFd);
2304  filefd->iFd = -1;
2305  }
2306  if (compressor_pid > 0)
2307  Ret &= ExecWait(compressor_pid, "FileFdCompressor", true);
2308  compressor_pid = -1;
2309  return Ret;
2310  }
2311  explicit PipedFileFdPrivate(FileFd * const filefd) : FileFdPrivate(filefd) {}
2312  virtual ~PipedFileFdPrivate() { InternalClose(""); }
2313 };
2314  /*}}}*/
2316 {
2317 public:
2318  virtual bool InternalOpen(int const, unsigned int const) APT_OVERRIDE { return true; }
2319  virtual ssize_t InternalUnbufferedRead(void * const To, unsigned long long const Size) APT_OVERRIDE
2320  {
2321  return read(filefd->iFd, To, Size);
2322  }
2323  virtual ssize_t InternalWrite(void const * const From, unsigned long long const Size) APT_OVERRIDE
2324  {
2325  // files opened read+write are strange and only really "supported" for direct files
2326  if (buffer.size() != 0)
2327  {
2328  lseek(filefd->iFd, -buffer.size(), SEEK_CUR);
2329  buffer.reset();
2330  }
2331  return write(filefd->iFd, From, Size);
2332  }
2333  virtual bool InternalSeek(unsigned long long const To) APT_OVERRIDE
2334  {
2335  off_t const res = lseek(filefd->iFd, To, SEEK_SET);
2336  if (res != (off_t)To)
2337  return filefd->FileFdError("Unable to seek to %llu", To);
2338  seekpos = To;
2339  buffer.reset();
2340  return true;
2341  }
2342  virtual bool InternalSkip(unsigned long long Over) APT_OVERRIDE
2343  {
2344  if (Over >= buffer.size())
2345  {
2346  Over -= buffer.size();
2347  buffer.reset();
2348  }
2349  else
2350  {
2351  buffer.bufferstart += Over;
2352  return true;
2353  }
2354  if (Over == 0)
2355  return true;
2356  off_t const res = lseek(filefd->iFd, Over, SEEK_CUR);
2357  if (res < 0)
2358  return filefd->FileFdError("Unable to seek ahead %llu",Over);
2359  seekpos = res;
2360  return true;
2361  }
2362  virtual bool InternalTruncate(unsigned long long const To) APT_OVERRIDE
2363  {
2364  if (buffer.size() != 0)
2365  {
2366  unsigned long long const seekpos = lseek(filefd->iFd, 0, SEEK_CUR);
2367  if ((seekpos - buffer.size()) >= To)
2368  buffer.reset();
2369  else if (seekpos >= To)
2370  buffer.bufferend = (To - seekpos) + buffer.bufferstart;
2371  else
2372  buffer.reset();
2373  }
2374  if (ftruncate(filefd->iFd, To) != 0)
2375  return filefd->FileFdError("Unable to truncate to %llu",To);
2376  return true;
2377  }
2378  virtual unsigned long long InternalTell() APT_OVERRIDE
2379  {
2380  return lseek(filefd->iFd,0,SEEK_CUR) - buffer.size();
2381  }
2382  virtual unsigned long long InternalSize() APT_OVERRIDE
2383  {
2384  return filefd->FileSize();
2385  }
2386  virtual bool InternalClose(std::string const &) APT_OVERRIDE { return true; }
2387  virtual bool InternalAlwaysAutoClose() const APT_OVERRIDE { return false; }
2388 
2389  explicit DirectFileFdPrivate(FileFd * const filefd) : FileFdPrivate(filefd) {}
2390  virtual ~DirectFileFdPrivate() { InternalClose(""); }
2391 };
2392  /*}}}*/
2393 // FileFd Constructors /*{{{*/
2394 FileFd::FileFd(std::string FileName,unsigned int const Mode,unsigned long AccessMode) : iFd(-1), Flags(0), d(NULL)
2395 {
2396  Open(FileName,Mode, None, AccessMode);
2397 }
2398 FileFd::FileFd(std::string FileName,unsigned int const Mode, CompressMode Compress, unsigned long AccessMode) : iFd(-1), Flags(0), d(NULL)
2399 {
2400  Open(FileName,Mode, Compress, AccessMode);
2401 }
2402 FileFd::FileFd() : iFd(-1), Flags(AutoClose), d(NULL) {}
2403 FileFd::FileFd(int const Fd, unsigned int const Mode, CompressMode Compress) : iFd(-1), Flags(0), d(NULL)
2404 {
2405  OpenDescriptor(Fd, Mode, Compress);
2406 }
2407 FileFd::FileFd(int const Fd, bool const AutoClose) : iFd(-1), Flags(0), d(NULL)
2408 {
2410 }
2411  /*}}}*/
2412 // FileFd::Open - Open a file /*{{{*/
2413 // ---------------------------------------------------------------------
2414 /* The most commonly used open mode combinations are given with Mode */
2415 bool FileFd::Open(string FileName,unsigned int const Mode,CompressMode Compress, unsigned long const AccessMode)
2416 {
2417  if (Mode == ReadOnlyGzip)
2418  return Open(FileName, ReadOnly, Gzip, AccessMode);
2419 
2420  if (Compress == Auto && (Mode & WriteOnly) == WriteOnly)
2421  return FileFdError("Autodetection on %s only works in ReadOnly openmode!", FileName.c_str());
2422 
2423  std::vector<APT::Configuration::Compressor> const compressors = APT::Configuration::getCompressors();
2424  std::vector<APT::Configuration::Compressor>::const_iterator compressor = compressors.begin();
2425  if (Compress == Auto)
2426  {
2427  for (; compressor != compressors.end(); ++compressor)
2428  {
2429  std::string file = FileName + compressor->Extension;
2430  if (FileExists(file) == false)
2431  continue;
2432  FileName = file;
2433  break;
2434  }
2435  }
2436  else if (Compress == Extension)
2437  {
2438  std::string::size_type const found = FileName.find_last_of('.');
2439  std::string ext;
2440  if (found != std::string::npos)
2441  {
2442  ext = FileName.substr(found);
2443  if (ext == ".new" || ext == ".bak")
2444  {
2445  std::string::size_type const found2 = FileName.find_last_of('.', found - 1);
2446  if (found2 != std::string::npos)
2447  ext = FileName.substr(found2, found - found2);
2448  else
2449  ext.clear();
2450  }
2451  }
2452  for (; compressor != compressors.end(); ++compressor)
2453  if (ext == compressor->Extension)
2454  break;
2455  // no matching extension - assume uncompressed (imagine files like 'example.org_Packages')
2456  if (compressor == compressors.end())
2457  for (compressor = compressors.begin(); compressor != compressors.end(); ++compressor)
2458  if (compressor->Name == ".")
2459  break;
2460  }
2461  else
2462  {
2463  std::string name;
2464  switch (Compress)
2465  {
2466  case None: name = "."; break;
2467  case Gzip: name = "gzip"; break;
2468  case Bzip2: name = "bzip2"; break;
2469  case Lzma: name = "lzma"; break;
2470  case Xz: name = "xz"; break;
2471  case Lz4: name = "lz4"; break;
2472  case Zstd: name = "zstd"; break;
2473  case Auto:
2474  case Extension:
2475  // Unreachable
2476  return FileFdError("Opening File %s in None, Auto or Extension should be already handled?!?", FileName.c_str());
2477  }
2478  for (; compressor != compressors.end(); ++compressor)
2479  if (compressor->Name == name)
2480  break;
2481  if (compressor == compressors.end())
2482  return FileFdError("Can't find a configured compressor %s for file %s", name.c_str(), FileName.c_str());
2483  }
2484 
2485  if (compressor == compressors.end())
2486  return FileFdError("Can't find a match for specified compressor mode for file %s", FileName.c_str());
2487  return Open(FileName, Mode, *compressor, AccessMode);
2488 }
2489 bool FileFd::Open(string FileName,unsigned int const Mode,APT::Configuration::Compressor const &compressor, unsigned long const AccessMode)
2490 {
2491  Close();
2492  Flags = AutoClose;
2493 
2494  if ((Mode & WriteOnly) != WriteOnly && (Mode & (Atomic | Create | Empty | Exclusive)) != 0)
2495  return FileFdError("ReadOnly mode for %s doesn't accept additional flags!", FileName.c_str());
2496  if ((Mode & ReadWrite) == 0)
2497  return FileFdError("No openmode provided in FileFd::Open for %s", FileName.c_str());
2498 
2499  unsigned int OpenMode = Mode;
2500  if (FileName == "/dev/null")
2502 
2503  if ((OpenMode & Atomic) == Atomic)
2504  {
2505  Flags |= Replace;
2506  }
2507  else if ((OpenMode & (Exclusive | Create)) == (Exclusive | Create))
2508  {
2509  // for atomic, this will be done by rename in Close()
2510  RemoveFile("FileFd::Open", FileName);
2511  }
2512  if ((OpenMode & Empty) == Empty)
2513  {
2514  struct stat Buf;
2515  if (lstat(FileName.c_str(),&Buf) == 0 && S_ISLNK(Buf.st_mode))
2516  RemoveFile("FileFd::Open", FileName);
2517  }
2518 
2519  int fileflags = 0;
2520  #define if_FLAGGED_SET(FLAG, MODE) if ((OpenMode & FLAG) == FLAG) fileflags |= MODE
2521  if_FLAGGED_SET(ReadWrite, O_RDWR);
2522  else if_FLAGGED_SET(ReadOnly, O_RDONLY);
2523  else if_FLAGGED_SET(WriteOnly, O_WRONLY);
2524 
2525  if_FLAGGED_SET(Create, O_CREAT);
2526  if_FLAGGED_SET(Empty, O_TRUNC);
2527  if_FLAGGED_SET(Exclusive, O_EXCL);
2528  #undef if_FLAGGED_SET
2529 
2530  if ((OpenMode & Atomic) == Atomic)
2531  {
2532  char *name = strdup((FileName + ".XXXXXX").c_str());
2533 
2534  if((iFd = mkstemp(name)) == -1)
2535  {
2536  free(name);
2537  return FileFdErrno("mkstemp", "Could not create temporary file for %s", FileName.c_str());
2538  }
2539 
2540  TemporaryFileName = string(name);
2541  free(name);
2542 
2543  // umask() will always set the umask and return the previous value, so
2544  // we first set the umask and then reset it to the old value
2545  mode_t const CurrentUmask = umask(0);
2546  umask(CurrentUmask);
2547  // calculate the actual file permissions (just like open/creat)
2548  mode_t const FilePermissions = (AccessMode & ~~CurrentUmask);
2549 
2550  if(fchmod(iFd, FilePermissions) == -1)
2551  return FileFdErrno("fchmod", "Could not change permissions for temporary file %s", TemporaryFileName.c_str());
2552  }
2553  else
2554  iFd = open(FileName.c_str(), fileflags, AccessMode);
2555 
2556  this->FileName = FileName;
2557  if (iFd == -1 || OpenInternDescriptor(OpenMode, compressor) == false)
2558  {
2559  if (iFd != -1)
2560  {
2561  close (iFd);
2562  iFd = -1;
2563  }
2564  return FileFdErrno("open",_("Could not open file %s"), FileName.c_str());
2565  }
2566 
2567  SetCloseExec(iFd,true);
2568  return true;
2569 }
2570  /*}}}*/
2571 // FileFd::OpenDescriptor - Open a filedescriptor /*{{{*/
2572 bool FileFd::OpenDescriptor(int Fd, unsigned int const Mode, CompressMode Compress, bool AutoClose)
2573 {
2574  std::vector<APT::Configuration::Compressor> const compressors = APT::Configuration::getCompressors();
2575  std::vector<APT::Configuration::Compressor>::const_iterator compressor = compressors.begin();
2576  std::string name;
2577 
2578  // compat with the old API
2579  if (Mode == ReadOnlyGzip && Compress == None)
2580  Compress = Gzip;
2581 
2582  switch (Compress)
2583  {
2584  case None: name = "."; break;
2585  case Gzip: name = "gzip"; break;
2586  case Bzip2: name = "bzip2"; break;
2587  case Lzma: name = "lzma"; break;
2588  case Xz: name = "xz"; break;
2589  case Lz4: name = "lz4"; break;
2590  case Zstd: name = "zstd"; break;
2591  case Auto:
2592  case Extension:
2593  if (AutoClose == true && Fd != -1)
2594  close(Fd);
2595  return FileFdError("Opening Fd %d in Auto or Extension compression mode is not supported", Fd);
2596  }
2597  for (; compressor != compressors.end(); ++compressor)
2598  if (compressor->Name == name)
2599  break;
2600  if (compressor == compressors.end())
2601  {
2602  if (AutoClose == true && Fd != -1)
2603  close(Fd);
2604  return FileFdError("Can't find a configured compressor %s for file %s", name.c_str(), FileName.c_str());
2605  }
2606  return OpenDescriptor(Fd, Mode, *compressor, AutoClose);
2607 }
2608 bool FileFd::OpenDescriptor(int Fd, unsigned int const Mode, APT::Configuration::Compressor const &compressor, bool AutoClose)
2609 {
2610  Close();
2611  Flags = (AutoClose) ? FileFd::AutoClose : 0;
2612  iFd = Fd;
2613  this->FileName = "";
2614  if (OpenInternDescriptor(Mode, compressor) == false)
2615  {
2616  if (iFd != -1 && (
2617  (Flags & Compressed) == Compressed ||
2618  AutoClose == true))
2619  {
2620  close (iFd);
2621  iFd = -1;
2622  }
2623  return FileFdError(_("Could not open file descriptor %d"), Fd);
2624  }
2625  return true;
2626 }
2627 bool FileFd::OpenInternDescriptor(unsigned int const Mode, APT::Configuration::Compressor const &compressor)
2628 {
2629  if (iFd == -1)
2630  return false;
2631 
2632  if (d != nullptr)
2634 
2635  if (d == nullptr)
2636  {
2637  if (false)
2638  /* dummy so that the rest can be 'else if's */;
2639 #define APT_COMPRESS_INIT(NAME, CONSTRUCTOR) \
2640  else if (compressor.Name == NAME) \
2641  d = new CONSTRUCTOR(this)
2642 #ifdef HAVE_ZLIB
2644 #endif
2645 #ifdef HAVE_BZ2
2647 #endif
2648 #ifdef HAVE_LZMA
2651 #endif
2652 #ifdef HAVE_LZ4
2654 #endif
2655 #ifdef HAVE_ZSTD
2657 #endif
2658 #undef APT_COMPRESS_INIT
2659  else if (compressor.Name == "." || compressor.Binary.empty() == true)
2660  d = new DirectFileFdPrivate(this);
2661  else
2662  d = new PipedFileFdPrivate(this);
2663 
2664  if (Mode & BufferedWrite)
2666 
2667  d->set_openmode(Mode);
2668  d->set_compressor(compressor);
2670  {
2671  // Need to duplicate fd here or gz/bz2 close for cleanup will close the fd as well
2672  int const internFd = dup(iFd);
2673  if (internFd == -1)
2674  return FileFdErrno("OpenInternDescriptor", _("Could not open file descriptor %d"), iFd);
2675  iFd = internFd;
2676  }
2677  }
2678  return d->InternalOpen(iFd, Mode);
2679 }
2680  /*}}}*/
2681 // FileFd::~File - Closes the file /*{{{*/
2682 // ---------------------------------------------------------------------
2683 /* If the proper modes are selected then we close the Fd and possibly
2684  unlink the file on error. */
2686 {
2687  Close();
2688  if (d != NULL)
2690  delete d;
2691  d = NULL;
2692 }
2693  /*}}}*/
2694 // FileFd::Read - Read a bit of the file /*{{{*/
2695 // ---------------------------------------------------------------------
2696 /* We are careful to handle interruption by a signal while reading
2697  gracefully. */
2698 bool FileFd::Read(void *To,unsigned long long Size,unsigned long long *Actual)
2699 {
2700  if (d == nullptr || Failed())
2701  return false;
2702  ssize_t Res = 1;
2703  errno = 0;
2704  if (Actual != 0)
2705  *Actual = 0;
2706  *((char *)To) = '\0';
2707  while (Res > 0 && Size > 0)
2708  {
2709  Res = d->InternalRead(To, Size);
2710 
2711  if (Res < 0)
2712  {
2713  if (errno == EINTR)
2714  {
2715  // trick the while-loop into running again
2716  Res = 1;
2717  errno = 0;
2718  continue;
2719  }
2720  return d->InternalReadError();
2721  }
2722 
2723  To = (char *)To + Res;
2724  Size -= Res;
2725  if (d != NULL)
2726  d->set_seekpos(d->get_seekpos() + Res);
2727  if (Actual != 0)
2728  *Actual += Res;
2729  }
2730 
2731  if (Size == 0)
2732  return true;
2733 
2734  // Eof handling
2735  if (Actual != 0)
2736  {
2737  Flags |= HitEof;
2738  return true;
2739  }
2740 
2741  return FileFdError(_("read, still have %llu to read but none left"), Size);
2742 }
2743 bool FileFd::Read(int const Fd, void *To, unsigned long long Size, unsigned long long * const Actual)
2744 {
2745  ssize_t Res = 1;
2746  errno = 0;
2747  if (Actual != nullptr)
2748  *Actual = 0;
2749  *static_cast<char *>(To) = '\0';
2750  while (Res > 0 && Size > 0)
2751  {
2752  Res = read(Fd, To, Size);
2753  if (Res < 0)
2754  {
2755  if (errno == EINTR)
2756  {
2757  Res = 1;
2758  errno = 0;
2759  continue;
2760  }
2761  return _error->Errno("read", _("Read error"));
2762  }
2763  To = static_cast<char *>(To) + Res;
2764  Size -= Res;
2765  if (Actual != 0)
2766  *Actual += Res;
2767  }
2768  if (Size == 0)
2769  return true;
2770  if (Actual != nullptr)
2771  return true;
2772  return _error->Error(_("read, still have %llu to read but none left"), Size);
2773 }
2774  /*}}}*/
2775 // FileFd::ReadLine - Read a complete line from the file /*{{{*/
2776 char* FileFd::ReadLine(char *To, unsigned long long const Size)
2777 {
2778  *To = '\0';
2779  if (d == nullptr || Failed())
2780  return nullptr;
2781  return d->InternalReadLine(To, Size);
2782 }
2783 bool FileFd::ReadLine(std::string &To)
2784 {
2785  To.clear();
2786  if (d == nullptr || Failed())
2787  return false;
2788  constexpr size_t buflen = 4096;
2789  char buffer[buflen];
2790  size_t len;
2791  do
2792  {
2793  if (d->InternalReadLine(buffer, buflen) == nullptr)
2794  return false;
2795  len = strlen(buffer);
2796  To.append(buffer, len);
2797  } while (len == buflen - 1 && buffer[len - 2] != '\n');
2798  // remove the newline at the end
2799  auto const i = To.find_last_not_of("\r\n");
2800  if (i == std::string::npos)
2801  To.clear();
2802  else
2803  To.erase(i + 1);
2804  return true;
2805 }
2806  /*}}}*/
2807 // FileFd::Flush - Flush the file /*{{{*/
2809 {
2810  if (Failed())
2811  return false;
2812  if (d == nullptr)
2813  return true;
2814 
2815  return d->InternalFlush();
2816 }
2817  /*}}}*/
2818 // FileFd::Write - Write to the file /*{{{*/
2819 bool FileFd::Write(const void *From,unsigned long long Size)
2820 {
2821  if (d == nullptr || Failed())
2822  return false;
2823  ssize_t Res = 1;
2824  errno = 0;
2825  while (Res > 0 && Size > 0)
2826  {
2827  Res = d->InternalWrite(From, Size);
2828 
2829  if (Res < 0)
2830  {
2831  if (errno == EINTR)
2832  {
2833  // trick the while-loop into running again
2834  Res = 1;
2835  errno = 0;
2836  continue;
2837  }
2838  return d->InternalWriteError();
2839  }
2840 
2841  From = (char const *)From + Res;
2842  Size -= Res;
2843  if (d != NULL)
2844  d->set_seekpos(d->get_seekpos() + Res);
2845  }
2846 
2847  if (Size == 0)
2848  return true;
2849 
2850  return FileFdError(_("write, still have %llu to write but couldn't"), Size);
2851 }
2852 bool FileFd::Write(int Fd, const void *From, unsigned long long Size)
2853 {
2854  ssize_t Res = 1;
2855  errno = 0;
2856  while (Res > 0 && Size > 0)
2857  {
2858  Res = write(Fd,From,Size);
2859  if (Res < 0 && errno == EINTR)
2860  continue;
2861  if (Res < 0)
2862  return _error->Errno("write",_("Write error"));
2863 
2864  From = (char const *)From + Res;
2865  Size -= Res;
2866  }
2867 
2868  if (Size == 0)
2869  return true;
2870 
2871  return _error->Error(_("write, still have %llu to write but couldn't"), Size);
2872 }
2873  /*}}}*/
2874 // FileFd::Seek - Seek in the file /*{{{*/
2875 bool FileFd::Seek(unsigned long long To)
2876 {
2877  if (d == nullptr || Failed())
2878  return false;
2879  Flags &= ~~HitEof;
2880  return d->InternalSeek(To);
2881 }
2882  /*}}}*/
2883 // FileFd::Skip - Skip over data in the file /*{{{*/
2884 bool FileFd::Skip(unsigned long long Over)
2885 {
2886  if (d == nullptr || Failed())
2887  return false;
2888  return d->InternalSkip(Over);
2889 }
2890  /*}}}*/
2891 // FileFd::Truncate - Truncate the file /*{{{*/
2892 bool FileFd::Truncate(unsigned long long To)
2893 {
2894  if (d == nullptr || Failed())
2895  return false;
2896  // truncating /dev/null is always successful - as we get an error otherwise
2897  if (To == 0 && FileName == "/dev/null")
2898  return true;
2899  return d->InternalTruncate(To);
2900 }
2901  /*}}}*/
2902 // FileFd::Tell - Current seek position /*{{{*/
2903 // ---------------------------------------------------------------------
2904 /* */
2905 unsigned long long FileFd::Tell()
2906 {
2907  if (d == nullptr || Failed())
2908  return false;
2909  off_t const Res = d->InternalTell();
2910  if (Res == (off_t)-1)
2911  FileFdErrno("lseek","Failed to determine the current file position");
2912  d->set_seekpos(Res);
2913  return Res;
2914 }
2915  /*}}}*/
2916 static bool StatFileFd(char const * const msg, int const iFd, std::string const &FileName, struct stat &Buf, FileFdPrivate * const d) /*{{{*/
2917 {
2918  bool ispipe = (d != NULL && d->get_is_pipe() == true);
2919  if (ispipe == false)
2920  {
2921  if (fstat(iFd,&Buf) != 0)
2922  // higher-level code will generate more meaningful messages,
2923  // even translated this would be meaningless for users
2924  return _error->Errno("fstat", "Unable to determine %s for fd %i", msg, iFd);
2925  if (FileName.empty() == false)
2926  ispipe = S_ISFIFO(Buf.st_mode);
2927  }
2928 
2929  // for compressor pipes st_size is undefined and at 'best' zero
2930  if (ispipe == true)
2931  {
2932  // we set it here, too, as we get the info here for free
2933  // in theory the Open-methods should take care of it already
2934  if (d != NULL)
2935  d->set_is_pipe(true);
2936  if (stat(FileName.c_str(), &Buf) != 0)
2937  return _error->Errno("fstat", "Unable to determine %s for file %s", msg, FileName.c_str());
2938  }
2939  return true;
2940 }
2941  /*}}}*/
2942 // FileFd::FileSize - Return the size of the file /*{{{*/
2943 unsigned long long FileFd::FileSize()
2944 {
2945  struct stat Buf;
2946  if (StatFileFd("file size", iFd, FileName, Buf, d) == false)
2947  {
2948  Flags |= Fail;
2949  return 0;
2950  }
2951  return Buf.st_size;
2952 }
2953  /*}}}*/
2954 // FileFd::ModificationTime - Return the time of last touch /*{{{*/
2956 {
2957  struct stat Buf;
2958  if (StatFileFd("modification time", iFd, FileName, Buf, d) == false)
2959  {
2960  Flags |= Fail;
2961  return 0;
2962  }
2963  return Buf.st_mtime;
2964 }
2965  /*}}}*/
2966 // FileFd::Size - Return the size of the content in the file /*{{{*/
2967 unsigned long long FileFd::Size()
2968 {
2969  if (d == nullptr)
2970  return 0;
2971  return d->InternalSize();
2972 }
2973  /*}}}*/
2974 // FileFd::Close - Close the file if the close flag is set /*{{{*/
2975 // ---------------------------------------------------------------------
2976 /* */
2978 {
2979  if (Failed() == false && Flush() == false)
2980  return false;
2981  if (iFd == -1)
2982  return true;
2983 
2984  bool Res = true;
2985  if ((Flags & AutoClose) == AutoClose)
2986  {
2987  if ((Flags & Compressed) != Compressed && iFd > 0 && close(iFd) != 0)
2988  Res &= _error->Errno("close",_("Problem closing the file %s"), FileName.c_str());
2989  }
2990 
2991  if (d != NULL)
2992  {
2993  Res &= d->InternalClose(FileName);
2994  delete d;
2995  d = NULL;
2996  }
2997 
2998  if ((Flags & Replace) == Replace) {
2999  if (Failed() == false && rename(TemporaryFileName.c_str(), FileName.c_str()) != 0)
3000  Res &= _error->Errno("rename",_("Problem renaming the file %s to %s"), TemporaryFileName.c_str(), FileName.c_str());
3001 
3002  FileName = TemporaryFileName; // for the unlink() below.
3003  TemporaryFileName.clear();
3004  }
3005 
3006  iFd = -1;
3007 
3008  if ((Flags & Fail) == Fail && (Flags & DelOnFail) == DelOnFail &&
3009  FileName.empty() == false)
3010  Res &= RemoveFile("FileFd::Close", FileName);
3011 
3012  if (Res == false)
3013  Flags |= Fail;
3014  return Res;
3015 }
3016  /*}}}*/
3017 // FileFd::Sync - Sync the file /*{{{*/
3018 // ---------------------------------------------------------------------
3019 /* */
3021 {
3022  if (fsync(iFd) != 0)
3023  return FileFdErrno("sync",_("Problem syncing the file"));
3024  return true;
3025 }
3026  /*}}}*/
3027 // FileFd::FileFdErrno - set Fail and call _error->Errno *{{{*/
3028 bool FileFd::FileFdErrno(const char *Function, const char *Description,...)
3029 {
3030  Flags |= Fail;
3031  va_list args;
3032  size_t msgSize = 400;
3033  int const errsv = errno;
3034  bool retry;
3035  do {
3036  va_start(args,Description);
3037  retry = _error->InsertErrno(GlobalError::ERROR, Function, Description, args, errsv, msgSize);
3038  va_end(args);
3039  } while (retry);
3040  return false;
3041 }
3042  /*}}}*/
3043 // FileFd::FileFdError - set Fail and call _error->Error *{{{*/
3044 bool FileFd::FileFdError(const char *Description,...) {
3045  Flags |= Fail;
3046  va_list args;
3047  size_t msgSize = 400;
3048  bool retry;
3049  do {
3050  va_start(args,Description);
3051  retry = _error->Insert(GlobalError::ERROR, Description, args, msgSize);
3052  va_end(args);
3053  } while (retry);
3054  return false;
3055 }
3056  /*}}}*/
3057 // Glob - wrapper around "glob()" /*{{{*/
3058 std::vector<std::string> Glob(std::string const &pattern, int flags)
3059 {
3060  std::vector<std::string> result;
3061  glob_t globbuf;
3062  int glob_res;
3063  unsigned int i;
3064 
3065  glob_res = glob(pattern.c_str(), flags, NULL, &globbuf);
3066 
3067  if (glob_res != 0)
3068  {
3069  if(glob_res != GLOB_NOMATCH) {
3070  _error->Errno("glob", "Problem with glob");
3071  return result;
3072  }
3073  }
3074 
3075  // append results
3076  for(i=0;i<globbuf.gl_pathc;i++)
3077  result.push_back(string(globbuf.gl_pathv[i]));
3078 
3079  globfree(&globbuf);
3080  return result;
3081 }
3082  /*}}}*/
3083 static std::string APT_NONNULL(1) GetTempDirEnv(char const * const env) /*{{{*/
3084 {
3085  const char *tmpdir = getenv(env);
3086 
3087 #ifdef P_tmpdir
3088  if (!tmpdir)
3089  tmpdir = P_tmpdir;
3090 #endif
3091 
3092  struct stat st;
3093  if (!tmpdir || strlen(tmpdir) == 0 || // tmpdir is set
3094  stat(tmpdir, &st) != 0 || (st.st_mode & S_IFDIR) == 0) // exists and is directory
3095  tmpdir = "/tmp";
3096  else if (geteuid() != 0 && // root can do everything anyway
3097  faccessat(AT_FDCWD, tmpdir, R_OK | W_OK | X_OK, AT_EACCESS) != 0) // current user has rwx access to directory
3098  tmpdir = "/tmp";
3099 
3100  return string(tmpdir);
3101 }
3102  /*}}}*/
3103 std::string GetTempDir() /*{{{*/
3104 {
3105  return GetTempDirEnv("TMPDIR");
3106 }
3107 std::string GetTempDir(std::string const &User)
3108 {
3109  // no need/possibility to drop privs
3110  if(getuid() != 0 || User.empty() || User == "root")
3111  return GetTempDir();
3112 
3113  struct passwd const * const pw = getpwnam(User.c_str());
3114  if (pw == NULL)
3115  return GetTempDir();
3116 
3117  gid_t const old_euid = geteuid();
3118  gid_t const old_egid = getegid();
3119  if (setegid(pw->pw_gid) != 0)
3120  _error->Errno("setegid", "setegid %u failed", pw->pw_gid);
3121  if (seteuid(pw->pw_uid) != 0)
3122  _error->Errno("seteuid", "seteuid %u failed", pw->pw_uid);
3123 
3124  std::string const tmp = GetTempDir();
3125 
3126  if (seteuid(old_euid) != 0)
3127  _error->Errno("seteuid", "seteuid %u failed", old_euid);
3128  if (setegid(old_egid) != 0)
3129  _error->Errno("setegid", "setegid %u failed", old_egid);
3130 
3131  return tmp;
3132 }
3133  /*}}}*/
3134 FileFd* GetTempFile(std::string const &Prefix, bool ImmediateUnlink, FileFd * const TmpFd) /*{{{*/
3135 {
3136  return GetTempFile(Prefix, ImmediateUnlink, TmpFd, false);
3137 }
3138 FileFd* GetTempFile(std::string const &Prefix, bool ImmediateUnlink, FileFd * const TmpFd, bool Buffered)
3139 {
3140  std::string fn;
3141  std::string const tempdir = GetTempDir();
3142  int fd = -1;
3143 #ifdef O_TMPFILE
3144  if (ImmediateUnlink)
3145  fd = open(tempdir.c_str(), O_RDWR|O_TMPFILE|O_EXCL|O_CLOEXEC, 0600);
3146  if (fd < 0)
3147 #endif
3148  {
3149  auto const suffix = Prefix.find(".XXXXXX.");
3150  std::vector<char> buffer(tempdir.length() + 1 + Prefix.length() + (suffix == std::string::npos ? 7 : 0) + 1, '\0');
3151  if (suffix != std::string::npos)
3152  {
3153  if (snprintf(buffer.data(), buffer.size(), "%s/%s", tempdir.c_str(), Prefix.c_str()) > 0)
3154  {
3155  ssize_t const suffixlen = (buffer.size() - 1) - (tempdir.length() + 1 + suffix + 7);
3156  if (likely(suffixlen > 0))
3157  fd = mkstemps(buffer.data(), suffixlen);
3158  }
3159  }
3160  else
3161  {
3162  if (snprintf(buffer.data(), buffer.size(), "%s/%s.XXXXXX", tempdir.c_str(), Prefix.c_str()) > 0)
3163  fd = mkstemp(buffer.data());
3164  }
3165  fn.assign(buffer.data(), buffer.size() - 1);
3166  if (ImmediateUnlink && fd != -1)
3167  unlink(fn.c_str());
3168  }
3169  if (fd < 0)
3170  {
3171  _error->Errno("GetTempFile",_("Unable to mkstemp %s"), fn.c_str());
3172  return nullptr;
3173  }
3174  FileFd * const Fd = TmpFd == nullptr ? new FileFd() : TmpFd;
3175  if (not Fd->OpenDescriptor(fd, FileFd::ReadWrite | (Buffered ? FileFd::BufferedWrite : 0), FileFd::None, true))
3176  {
3177  _error->Errno("GetTempFile",_("Unable to write to %s"),fn.c_str());
3178  if (TmpFd == nullptr)
3179  delete Fd;
3180  return nullptr;
3181  }
3182  if (not ImmediateUnlink)
3183  Fd->SetFileName(fn);
3184  return Fd;
3185 }
3186  /*}}}*/
3187 bool Rename(std::string From, std::string To) /*{{{*/
3188 {
3189  if (rename(From.c_str(),To.c_str()) != 0)
3190  {
3191  _error->Error(_("rename failed, %s (%s -> %s)."),strerror(errno),
3192  From.c_str(),To.c_str());
3193  return false;
3194  }
3195  return true;
3196 }
3197  /*}}}*/
3198 bool Popen(const char *Args[], FileFd &Fd, pid_t &Child, FileFd::OpenMode Mode, bool CaptureStderr, bool Sandbox) /*{{{*/
3199 {
3200  int fd;
3201  if (Mode != FileFd::ReadOnly && Mode != FileFd::WriteOnly)
3202  return _error->Error("Popen supports ReadOnly (x)or WriteOnly mode only");
3203 
3204  int Pipe[2] = {-1, -1};
3205  if(pipe(Pipe) != 0)
3206  return _error->Errno("pipe", _("Failed to create subprocess IPC"));
3207 
3208  std::set<int> keep_fds;
3209  keep_fds.insert(Pipe[0]);
3210  keep_fds.insert(Pipe[1]);
3211  Child = ExecFork(keep_fds);
3212  if(Child < 0)
3213  return _error->Errno("fork", "Failed to fork");
3214  if(Child == 0)
3215  {
3216  if (Sandbox && (getuid() == 0 || geteuid() == 0) && !DropPrivileges())
3217  {
3218  _error->DumpErrors();
3219  _exit(1);
3220  }
3221  if(Mode == FileFd::ReadOnly)
3222  {
3223  close(Pipe[0]);
3224  fd = Pipe[1];
3225  }
3226  else if(Mode == FileFd::WriteOnly)
3227  {
3228  close(Pipe[1]);
3229  fd = Pipe[0];
3230  }
3231 
3232  if(Mode == FileFd::ReadOnly)
3233  {
3234  dup2(fd, 1);
3235  if (CaptureStderr == true)
3236  dup2(fd, 2);
3237  } else if(Mode == FileFd::WriteOnly)
3238  dup2(fd, 0);
3239 
3240  execv(Args[0], (char**)Args);
3241  _exit(100);
3242  }
3243  if(Mode == FileFd::ReadOnly)
3244  {
3245  close(Pipe[1]);
3246  fd = Pipe[0];
3247  }
3248  else if(Mode == FileFd::WriteOnly)
3249  {
3250  close(Pipe[0]);
3251  fd = Pipe[1];
3252  }
3253  else
3254  return _error->Error("Popen supports ReadOnly (x)or WriteOnly mode only");
3255  Fd.OpenDescriptor(fd, Mode, FileFd::None, true);
3256 
3257  return true;
3258 }
3259  /*}}}*/
3260 bool DropPrivileges() /*{{{*/
3261 {
3262  if(_config->FindB("Debug::NoDropPrivs", false) == true)
3263  return true;
3264 
3265 #if __gnu_linux__
3266 #if defined(PR_SET_NO_NEW_PRIVS) && ( PR_SET_NO_NEW_PRIVS != 38 )
3267 #error "PR_SET_NO_NEW_PRIVS is defined, but with a different value than expected!"
3268 #endif
3269  // see prctl(2), needs linux3.5 at runtime - magic constant to avoid it at buildtime
3270  int ret = prctl(38, 1, 0, 0, 0);
3271  // ignore EINVAL - kernel is too old to understand the option
3272  if(ret < 0 && errno != EINVAL)
3273  _error->Warning("PR_SET_NO_NEW_PRIVS failed with %i", ret);
3274 #endif
3275 
3276  // empty setting disables privilege dropping - this also ensures
3277  // backward compatibility, see bug #764506
3278  const std::string toUser = _config->Find("APT::Sandbox::User");
3279  if (toUser.empty() || toUser == "root")
3280  return true;
3281 
3282  // a lot can go wrong trying to drop privileges completely,
3283  // so ideally we would like to verify that we have done it –
3284  // but the verify asks for too much in case of fakeroot (and alike)
3285  // [Specific checks can be overridden with dedicated options]
3286  bool const VerifySandboxing = _config->FindB("APT::Sandbox::Verify", false);
3287 
3288  // uid will be 0 in the end, but gid might be different anyway
3289  uid_t const old_uid = getuid();
3290  gid_t const old_gid = getgid();
3291 
3292  if (old_uid != 0)
3293  return true;
3294 
3295  struct passwd *pw = getpwnam(toUser.c_str());
3296  if (pw == NULL)
3297  return _error->Error("No user %s, can not drop rights", toUser.c_str());
3298 
3299  // Do not change the order here, it might break things
3300  // Get rid of all our supplementary groups first
3301  if (setgroups(1, &pw->pw_gid))
3302  return _error->Errno("setgroups", "Failed to setgroups");
3303 
3304  // Now change the group ids to the new user
3305 #ifdef HAVE_SETRESGID
3306  if (setresgid(pw->pw_gid, pw->pw_gid, pw->pw_gid) != 0)
3307  return _error->Errno("setresgid", "Failed to set new group ids");
3308 #else
3309  if (setegid(pw->pw_gid) != 0)
3310  return _error->Errno("setegid", "Failed to setegid");
3311 
3312  if (setgid(pw->pw_gid) != 0)
3313  return _error->Errno("setgid", "Failed to setgid");
3314 #endif
3315 
3316  // Change the user ids to the new user
3317 #ifdef HAVE_SETRESUID
3318  if (setresuid(pw->pw_uid, pw->pw_uid, pw->pw_uid) != 0)
3319  return _error->Errno("setresuid", "Failed to set new user ids");
3320 #else
3321  if (setuid(pw->pw_uid) != 0)
3322  return _error->Errno("setuid", "Failed to setuid");
3323  if (seteuid(pw->pw_uid) != 0)
3324  return _error->Errno("seteuid", "Failed to seteuid");
3325 #endif
3326 
3327  // disabled by default as fakeroot doesn't implement getgroups currently (#806521)
3328  if (VerifySandboxing == true || _config->FindB("APT::Sandbox::Verify::Groups", false) == true)
3329  {
3330  // Verify that the user isn't still in any supplementary groups
3331  long const ngroups_max = sysconf(_SC_NGROUPS_MAX);
3332  std::unique_ptr<gid_t[]> gidlist(new gid_t[ngroups_max]);
3333  if (unlikely(gidlist == NULL))
3334  return _error->Error("Allocation of a list of size %lu for getgroups failed", ngroups_max);
3335  ssize_t gidlist_nr;
3336  if ((gidlist_nr = getgroups(ngroups_max, gidlist.get())) < 0)
3337  return _error->Errno("getgroups", "Could not get new groups (%lu)", ngroups_max);
3338  for (ssize_t i = 0; i < gidlist_nr; ++i)
3339  if (gidlist[i] != pw->pw_gid)
3340  return _error->Error("Could not switch group, user %s is still in group %d", toUser.c_str(), gidlist[i]);
3341  }
3342 
3343  // enabled by default as all fakeroot-lookalikes should fake that accordingly
3344  if (VerifySandboxing == true || _config->FindB("APT::Sandbox::Verify::IDs", true) == true)
3345  {
3346  // Verify that gid, egid, uid, and euid changed
3347  if (getgid() != pw->pw_gid)
3348  return _error->Error("Could not switch group");
3349  if (getegid() != pw->pw_gid)
3350  return _error->Error("Could not switch effective group");
3351  if (getuid() != pw->pw_uid)
3352  return _error->Error("Could not switch user");
3353  if (geteuid() != pw->pw_uid)
3354  return _error->Error("Could not switch effective user");
3355 
3356 #ifdef HAVE_GETRESUID
3357  // verify that the saved set-user-id was changed as well
3358  uid_t ruid = 0;
3359  uid_t euid = 0;
3360  uid_t suid = 0;
3361  if (getresuid(&ruid, &euid, &suid))
3362  return _error->Errno("getresuid", "Could not get saved set-user-ID");
3363  if (suid != pw->pw_uid)
3364  return _error->Error("Could not switch saved set-user-ID");
3365 #endif
3366 
3367 #ifdef HAVE_GETRESGID
3368  // verify that the saved set-group-id was changed as well
3369  gid_t rgid = 0;
3370  gid_t egid = 0;
3371  gid_t sgid = 0;
3372  if (getresgid(&rgid, &egid, &sgid))
3373  return _error->Errno("getresuid", "Could not get saved set-group-ID");
3374  if (sgid != pw->pw_gid)
3375  return _error->Error("Could not switch saved set-group-ID");
3376 #endif
3377  }
3378 
3379  // disabled as fakeroot doesn't forbid (by design) (re)gaining root from unprivileged
3380  if (VerifySandboxing == true || _config->FindB("APT::Sandbox::Verify::Regain", false) == true)
3381  {
3382  // Check that uid and gid changes do not work anymore
3383  if (pw->pw_gid != old_gid && (setgid(old_gid) != -1 || setegid(old_gid) != -1))
3384  return _error->Error("Could restore a gid to root, privilege dropping did not work");
3385 
3386  if (pw->pw_uid != old_uid && (setuid(old_uid) != -1 || seteuid(old_uid) != -1))
3387  return _error->Error("Could restore a uid to root, privilege dropping did not work");
3388  }
3389 
3390  if (_config->FindB("APT::Sandbox::ResetEnvironment", true))
3391  {
3392  setenv("HOME", pw->pw_dir, 1);
3393  setenv("USER", pw->pw_name, 1);
3394  setenv("USERNAME", pw->pw_name, 1);
3395  setenv("LOGNAME", pw->pw_name, 1);
3396  auto const shell = flNotDir(pw->pw_shell);
3397  if (shell == "false" || shell == "nologin")
3398  setenv("SHELL", "/bin/sh", 1);
3399  else
3400  setenv("SHELL", pw->pw_shell, 1);
3401  auto const apt_setenv_tmp = [](char const * const env) {
3402  auto const tmpdir = getenv(env);
3403  if (tmpdir != nullptr)
3404  {
3405  auto const ourtmpdir = GetTempDirEnv(env);
3406  if (ourtmpdir != tmpdir)
3407  setenv(env, ourtmpdir.c_str(), 1);
3408  }
3409  };
3410  apt_setenv_tmp("TMPDIR");
3411  apt_setenv_tmp("TEMPDIR");
3412  apt_setenv_tmp("TMP");
3413  apt_setenv_tmp("TEMP");
3414  }
3415 
3416  return true;
3417 }
3418  /*}}}*/
3419 bool OpenConfigurationFileFd(std::string const &File, FileFd &Fd) /*{{{*/
3420 {
3421  int const fd = open(File.c_str(), O_RDONLY | O_CLOEXEC | O_NOCTTY);
3422  if (fd == -1)
3423  return _error->WarningE("open", _("Unable to read %s"), File.c_str());
3424  APT::Configuration::Compressor none(".", "", "", nullptr, nullptr, 0);
3425  if (Fd.OpenDescriptor(fd, FileFd::ReadOnly, none, true) == false)
3426  return false;
3427  Fd.SetFileName(File);
3428  return true;
3429 }
3430  /*}}}*/
3431 int Inhibit(const char *what, const char *who, const char *why, const char *mode) /*{{{*/
3432 {
3433 #ifdef HAVE_SYSTEMD
3434  sd_bus_error error = SD_BUS_ERROR_NULL;
3435  sd_bus_message *m = NULL;
3436  sd_bus *bus = NULL;
3437  int fd;
3438  int r;
3439 
3440  r = sd_bus_open_system(&bus);
3441  if (r < 0)
3442  goto out;
3443 
3444  r = sd_bus_call_method(bus,
3445  "org.freedesktop.login1",
3446  "/org/freedesktop/login1",
3447  "org.freedesktop.login1.Manager",
3448  "Inhibit",
3449  &error,
3450  &m,
3451  "ssss",
3452  what,
3453  who,
3454  why,
3455  mode);
3456  if (r < 0)
3457  goto out;
3458 
3459  r = sd_bus_message_read(m, "h", &fd);
3460  if (r < 0)
3461  goto out;
3462 
3463  // We received a file descriptor, return it - systemd will close the read fd
3464  // on free, so let's duplicate it here.
3465  r = dup(fd);
3466 out:
3467  sd_bus_error_free(&error);
3468  sd_bus_message_unref(m);
3469  sd_bus_unref(bus);
3470  return r;
3471 #else
3472  return -ENOTSUP;
3473 #endif
3474 }
3475  /*}}}*/
strprintf(m, msg, repo.c_str())
return false
I Status
static char const *const msg
virtual bool InternalClose(std::string const &FileName) APT_OVERRIDE
Definition: fileutl.cc:1419
virtual void set_seekpos(unsigned long long seekpos) APT_OVERRIDE
Definition: fileutl.cc:1327
virtual unsigned long long get_seekpos() const APT_OVERRIDE
Definition: fileutl.cc:1323
virtual ~BufferedWriteFileFdPrivate()
Definition: fileutl.cc:1427
virtual bool InternalReadError() APT_OVERRIDE
Definition: fileutl.cc:1344
virtual bool InternalFlush() APT_OVERRIDE
Definition: fileutl.cc:1354
virtual unsigned long long InternalTell() APT_OVERRIDE
Definition: fileutl.cc:1407
simple_buffer writebuffer
Definition: fileutl.cc:1291
virtual bool get_is_pipe() const APT_OVERRIDE
Definition: fileutl.cc:1314
virtual void set_openmode(unsigned int openmode) APT_OVERRIDE
Definition: fileutl.cc:1310
FileFdPrivate * wrapped
Definition: fileutl.cc:1290
virtual APT::Configuration::Compressor get_compressor() const APT_OVERRIDE
Definition: fileutl.cc:1298
virtual bool InternalAlwaysAutoClose() const APT_OVERRIDE
Definition: fileutl.cc:1423
virtual bool InternalTruncate(unsigned long long const Size) APT_OVERRIDE
Definition: fileutl.cc:1401
virtual bool InternalWriteError() APT_OVERRIDE
Definition: fileutl.cc:1385
virtual void set_is_pipe(bool is_pipe) APT_OVERRIDE
Definition: fileutl.cc:1318
virtual void set_compressor(APT::Configuration::Compressor const &compressor) APT_OVERRIDE
Definition: fileutl.cc:1302
virtual bool InternalOpen(int const iFd, unsigned int const Mode) APT_OVERRIDE
Definition: fileutl.cc:1331
virtual ssize_t InternalWrite(void const *const From, unsigned long long const Size) APT_OVERRIDE
Definition: fileutl.cc:1370
virtual bool InternalSeek(unsigned long long const To) APT_OVERRIDE
Definition: fileutl.cc:1389
virtual unsigned long long InternalSize() APT_OVERRIDE
Definition: fileutl.cc:1413
virtual unsigned int get_openmode() const APT_OVERRIDE
Definition: fileutl.cc:1306
virtual bool InternalSkip(unsigned long long Over) APT_OVERRIDE
Definition: fileutl.cc:1395
virtual ssize_t InternalUnbufferedRead(void *const To, unsigned long long const Size) APT_OVERRIDE
Definition: fileutl.cc:1337
virtual char * InternalReadLine(char *To, unsigned long long Size) APT_OVERRIDE
Definition: fileutl.cc:1348
BufferedWriteFileFdPrivate(FileFdPrivate *Priv)
Definition: fileutl.cc:1295
match a string against a configurable list of patterns
bool Match(char const *str) const
Returns true for a string matching one of the patterns.
virtual unsigned long long InternalTell() APT_OVERRIDE
Definition: fileutl.cc:2378
virtual bool InternalOpen(int const, unsigned int const) APT_OVERRIDE
Definition: fileutl.cc:2318
virtual ~DirectFileFdPrivate()
Definition: fileutl.cc:2390
virtual bool InternalClose(std::string const &) APT_OVERRIDE
Definition: fileutl.cc:2386
virtual bool InternalAlwaysAutoClose() const APT_OVERRIDE
Definition: fileutl.cc:2387
virtual ssize_t InternalWrite(void const *const From, unsigned long long const Size) APT_OVERRIDE
Definition: fileutl.cc:2323
virtual bool InternalSeek(unsigned long long const To) APT_OVERRIDE
Definition: fileutl.cc:2333
virtual unsigned long long InternalSize() APT_OVERRIDE
Definition: fileutl.cc:2382
virtual bool InternalTruncate(unsigned long long const To) APT_OVERRIDE
Definition: fileutl.cc:2362
virtual bool InternalSkip(unsigned long long Over) APT_OVERRIDE
Definition: fileutl.cc:2342
virtual ssize_t InternalUnbufferedRead(void *const To, unsigned long long const Size) APT_OVERRIDE
Definition: fileutl.cc:2319
DirectFileFdPrivate(FileFd *const filefd)
Definition: fileutl.cc:2389
virtual ssize_t InternalWrite(void const *const From, unsigned long long const Size)=0
virtual unsigned long long InternalSize()
Definition: fileutl.cc:1263
APT::Configuration::Compressor compressor
Definition: fileutl.cc:1099
virtual char * InternalReadLine(char *To, unsigned long long Size)
Definition: fileutl.cc:1152
virtual bool InternalOpen(int const iFd, unsigned int const Mode)=0
virtual void set_is_pipe(bool is_pipe)
Definition: fileutl.cc:1127
virtual void set_openmode(unsigned int openmode)
Definition: fileutl.cc:1119
virtual bool InternalStream() const
Definition: fileutl.cc:1282
virtual void set_compressor(APT::Configuration::Compressor const &compressor)
Definition: fileutl.cc:1111
virtual bool InternalAlwaysAutoClose() const
Definition: fileutl.cc:1283
virtual unsigned long long InternalTell()
Definition: fileutl.cc:1255
virtual bool InternalSeek(unsigned long long const To)
Definition: fileutl.cc:1199
virtual void set_seekpos(unsigned long long seekpos)
Definition: fileutl.cc:1135
simple_buffer buffer
Definition: fileutl.cc:1095
virtual unsigned long long get_seekpos() const
Definition: fileutl.cc:1131
virtual unsigned int get_openmode() const
Definition: fileutl.cc:1115
virtual bool InternalTruncate(unsigned long long const)
Definition: fileutl.cc:1251
virtual bool InternalSkip(unsigned long long Over)
Definition: fileutl.cc:1238
unsigned int openmode
Definition: fileutl.cc:1100
virtual bool get_is_pipe() const
Definition: fileutl.cc:1123
virtual bool InternalFlush()
Definition: fileutl.cc:1193
virtual ~FileFdPrivate()
Definition: fileutl.cc:1285
virtual APT::Configuration::Compressor get_compressor() const
Definition: fileutl.cc:1107
FileFdPrivate(FileFd *const pfilefd)
Definition: fileutl.cc:1104
virtual bool InternalWriteError()
Definition: fileutl.cc:1198
unsigned long long seekpos
Definition: fileutl.cc:1101
virtual ssize_t InternalUnbufferedRead(void *const To, unsigned long long const Size)=0
virtual bool InternalClose(std::string const &FileName)=0
virtual bool InternalReadError()
Definition: fileutl.cc:1151
ssize_t InternalRead(void *To, unsigned long long Size)
Definition: fileutl.cc:1141
FileFd *const filefd
Definition: fileutl.cc:1094
pid_t compressor_pid
Definition: fileutl.cc:1097
int compressed_fd
Definition: fileutl.cc:1096
Definition: fileutl.h:39
bool OpenDescriptor(int Fd, unsigned int const Mode, CompressMode Compress, bool AutoClose=false)
Definition: fileutl.cc:2572
bool Sync()
Definition: fileutl.cc:3020
friend class DirectFileFdPrivate
Definition: fileutl.h:46
unsigned long Flags
Definition: fileutl.h:53
bool IsOpen()
Definition: fileutl.h:150
bool Skip(unsigned long long To)
Definition: fileutl.cc:2884
std::string FileName
Definition: fileutl.h:54
FileFd()
Definition: fileutl.cc:2402
CompressMode
Definition: fileutl.h:77
@ Lzma
Definition: fileutl.h:83
@ Zstd
Definition: fileutl.h:86
@ Lz4
Definition: fileutl.h:85
@ Xz
Definition: fileutl.h:84
@ Extension
Definition: fileutl.h:80
@ Auto
Definition: fileutl.h:78
@ Gzip
Definition: fileutl.h:81
@ None
Definition: fileutl.h:79
@ Bzip2
Definition: fileutl.h:82
OpenMode
Definition: fileutl.h:58
@ WriteOnly
Definition: fileutl.h:60
@ ReadOnlyGzip
Definition: fileutl.h:73
@ BufferedWrite
Definition: fileutl.h:67
@ Atomic
Definition: fileutl.h:65
@ Exclusive
Definition: fileutl.h:64
@ ReadWrite
Definition: fileutl.h:61
@ Empty
Definition: fileutl.h:66
@ Create
Definition: fileutl.h:63
@ ReadOnly
Definition: fileutl.h:59
virtual ~FileFd()
Definition: fileutl.cc:2685
std::string TemporaryFileName
Definition: fileutl.h:55
unsigned long long FileSize()
Definition: fileutl.cc:2943
@ HitEof
Definition: fileutl.h:52
@ Fail
Definition: fileutl.h:51
@ Compressed
Definition: fileutl.h:52
@ Replace
Definition: fileutl.h:52
@ DelOnFail
Definition: fileutl.h:51
@ AutoClose
Definition: fileutl.h:51
bool Flush()
Definition: fileutl.cc:2808
void SetFileName(std::string const &name)
Definition: fileutl.h:157
APT_HIDDEN bool OpenInternDescriptor(unsigned int const Mode, APT::Configuration::Compressor const &compressor)
Definition: fileutl.cc:2627
APT_HIDDEN bool FileFdError(const char *Description,...) APT_PRINTF(2) APT_COLD
Definition: fileutl.cc:3044
bool Write(const void *From, unsigned long long Size)
Definition: fileutl.cc:2819
unsigned long long Tell()
Definition: fileutl.cc:2905
bool Seek(unsigned long long To)
Definition: fileutl.cc:2875
bool Truncate(unsigned long long To)
Definition: fileutl.cc:2892
APT_HIDDEN bool FileFdErrno(const char *Function, const char *Description,...) APT_PRINTF(3) APT_COLD
Definition: fileutl.cc:3028
bool Failed()
Definition: fileutl.h:151
char * ReadLine(char *To, unsigned long long const Size)
Definition: fileutl.cc:2776
bool Open(std::string FileName, unsigned int const Mode, CompressMode Compress, unsigned long const AccessMode=0666)
Definition: fileutl.cc:2415
friend class PipedFileFdPrivate
Definition: fileutl.h:47
int Fd()
Definition: fileutl.h:147
time_t ModificationTime()
Definition: fileutl.cc:2955
bool Read(void *To, unsigned long long Size, bool AllowEof)
Definition: fileutl.h:89
FileFdPrivate * d
Definition: fileutl.h:167
unsigned long long Size()
Definition: fileutl.cc:2967
bool Close()
Definition: fileutl.cc:2977
int iFd
Definition: fileutl.h:49
@ ERROR
An error does hinder the correct execution and should be corrected.
Definition: error.h:60
PipedFileFdPrivate(FileFd *const filefd)
Definition: fileutl.cc:2311
virtual ~PipedFileFdPrivate()
Definition: fileutl.cc:2312
virtual bool InternalClose(std::string const &) APT_OVERRIDE
Definition: fileutl.cc:2298
virtual bool InternalOpen(int const, unsigned int const Mode) APT_OVERRIDE
Definition: fileutl.cc:2188
virtual ssize_t InternalWrite(void const *const From, unsigned long long const Size) APT_OVERRIDE
Definition: fileutl.cc:2294
virtual ssize_t InternalUnbufferedRead(void *const To, unsigned long long const Size) APT_OVERRIDE
Definition: fileutl.cc:2290
virtual bool IsLocked()=0
checks if the system is currently locked
FILE
DIR
Configuration * _config
int GetLock(string File, bool Errors)
Definition: fileutl.cc:243
static std::string APT_NONNULL(1) GetTempDirEnv(char const *const env)
Definition: fileutl.cc:3083
#define APT_COMPRESS_INIT(NAME, CONSTRUCTOR)
void SetCloseExec(int Fd, bool Close)
Definition: fileutl.cc:792
string flNotFile(string File)
Definition: fileutl.cc:676
string flExtension(string File)
Definition: fileutl.cc:688
void SetNonBlock(int Fd, bool Block)
Definition: fileutl.cc:804
bool DirectoryExists(string const &Path)
Definition: fileutl.cc:348
bool ExecWait(pid_t Pid, const char *Name, bool Reap)
Definition: fileutl.cc:942
bool CreateAPTDirectoryIfNeeded(string const &Parent, string const &Path)
Ensure the existence of the given Path.
Definition: fileutl.cc:400
string flNotDir(string File)
Definition: fileutl.cc:664
std::string flNormalize(std::string file)
removes superfluous /./ and // from path
Definition: fileutl.cc:770
std::vector< std::string > Glob(std::string const &pattern, int flags)
Definition: fileutl.cc:3058
bool WaitFd(int Fd, bool write, unsigned long timeout)
Definition: fileutl.cc:819
static bool StatFileFd(char const *const msg, int const iFd, std::string const &FileName, struct stat &Buf, FileFdPrivate *const d)
Definition: fileutl.cc:2916
static std::string GetProcessName(int pid)
Definition: fileutl.cc:220
bool FileExists(string File)
Definition: fileutl.cc:326
#define if_FLAGGED_SET(FLAG, MODE)
time_t GetModificationTime(string const &Path)
Definition: fileutl.cc:653
FileFd * GetTempFile(std::string const &Prefix, bool ImmediateUnlink, FileFd *const TmpFd)
Definition: fileutl.cc:3134
bool OpenConfigurationFileFd(std::string const &File, FileFd &Fd)
Definition: fileutl.cc:3419
std::string GetTempDir()
Definition: fileutl.cc:3103
bool ChangeOwnerAndPermissionOfFile(char const *const requester, char const *const file, char const *const user, char const *const group, mode_t const mode)
Definition: fileutl.cc:1015
bool DropPrivileges()
Drop privileges.
Definition: fileutl.cc:3260
string flCombine(string Dir, string File)
Definition: fileutl.cc:740
bool RemoveFile(char const *const Function, std::string const &FileName)
Definition: fileutl.cc:198
bool Rename(std::string From, std::string To)
Definition: fileutl.cc:3187
int Inhibit(const char *what, const char *who, const char *why, const char *mode)
Definition: fileutl.cc:3431
bool StartsWithGPGClearTextSignature(string const &FileName)
Definition: fileutl.cc:984
bool RealFileExists(string File)
Definition: fileutl.cc:337
bool CreateDirectory(string const &Parent, string const &Path)
Definition: fileutl.cc:364
bool RemoveFileAt(char const *const Function, int const dirfd, std::string const &FileName)
Definition: fileutl.cc:183
bool RunScripts(const char *Cnf)
Definition: fileutl.cc:91
string SafeGetCWD()
Definition: fileutl.cc:637
void MergeKeepFdsFromConfiguration(std::set< int > &KeepFDs)
Definition: fileutl.cc:860
std::vector< string > GetListOfFilesInDir(string const &Dir, string const &Ext, bool const &SortList, bool const &AllowNoExt)
Definition: fileutl.cc:421
bool Popen(const char *Args[], FileFd &Fd, pid_t &Child, FileFd::OpenMode Mode, bool CaptureStderr, bool Sandbox)
Popen() implementation that execv() instead of using a shell.
Definition: fileutl.cc:3198
bool CopyFile(FileFd &From, FileFd &To)
Definition: fileutl.cc:164
pid_t ExecFork()
Definition: fileutl.cc:881
string flAbsPath(string File)
Takes a file path and returns the absolute path.
Definition: fileutl.cc:757
string flNoLink(string File)
Definition: fileutl.cc:700
#define APT_OVERRIDE
Definition: macros.h:111
#define APT_MUSTCHECK
Definition: macros.h:68
static constexpr unsigned long long APT_BUFFER_SIZE
Definition: macros.h:125
#define APT_HIDDEN
Definition: macros.h:78
APT_PUBLIC std::vector< Compressor > const getCompressors(bool const Cached=true)
Return a vector of Compressors supported for data.tar's.
bool Startswith(const std::string &s, const std::string &start)
Definition: strutl.cc:84
pkgSystem * _system
Definition: pkgsystem.cc:24
Representation of supported compressors.
void reset(size_t size)
Definition: fileutl.cc:1058
char * getend()
Definition: fileutl.cc:1053
unsigned long long bufferend
Definition: fileutl.cc:1040
const char * get() const
Definition: fileutl.cc:1050
ssize_t write(const void *from, unsigned long long requested_size) APT_MUSTCHECK
Definition: fileutl.cc:1078
unsigned long long free() const
Definition: fileutl.cc:1056
bool empty() const
Definition: fileutl.cc:1054
const char * getend() const
Definition: fileutl.cc:1052
bool full() const
Definition: fileutl.cc:1055
unsigned long long size() const
Definition: fileutl.cc:1057
char * get()
Definition: fileutl.cc:1051
void reset()
Definition: fileutl.cc:1067
ssize_t read(void *to, unsigned long long requested_size) APT_MUSTCHECK
Definition: fileutl.cc:1068
unsigned long long bufferstart
Definition: fileutl.cc:1039
size_t buffersize_max
Definition: fileutl.cc:1038
char * buffer
Definition: fileutl.cc:1041
int stringcasecmp(const char *A, const char *AEnd, const char *B, const char *BEnd)
Definition: strutl.cc:685
vector< string > VectorizeString(string const &haystack, char const &split)
Definition: strutl.cc:1308
char * _strrstrip(char *String)
Definition: strutl.cc:237