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