]> git.saurik.com Git - apt.git/blob - apt-pkg/contrib/fileutl.cc
e410f52d6f892e3648e1655cb2b81d9c1ec3c12b
[apt.git] / apt-pkg / contrib / fileutl.cc
1 // -*- mode: cpp; mode: fold -*-
2 // Description /*{{{*/
3 /* ######################################################################
4
5 File Utilities
6
7 CopyFile - Buffered copy of a single file
8 GetLock - dpkg compatible lock file manipulation (fcntl)
9
10 Most of this source is placed in the Public Domain, do with it what
11 you will
12 It was originally written by Jason Gunthorpe <jgg@debian.org>.
13 FileFd gzip support added by Martin Pitt <martin.pitt@canonical.com>
14
15 The exception is RunScripts() it is under the GPLv2
16
17 ##################################################################### */
18 /*}}}*/
19 // Include Files /*{{{*/
20 #include <config.h>
21
22 #include <apt-pkg/fileutl.h>
23 #include <apt-pkg/strutl.h>
24 #include <apt-pkg/error.h>
25 #include <apt-pkg/sptr.h>
26 #include <apt-pkg/aptconfiguration.h>
27 #include <apt-pkg/configuration.h>
28 #include <apt-pkg/macros.h>
29
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>
37 #include <cstdlib>
38 #include <cstring>
39 #include <cstdio>
40 #include <iostream>
41 #include <unistd.h>
42 #include <fcntl.h>
43 #include <sys/stat.h>
44 #include <sys/time.h>
45 #include <sys/wait.h>
46 #include <dirent.h>
47 #include <signal.h>
48 #include <errno.h>
49 #include <glob.h>
50 #include <pwd.h>
51 #include <grp.h>
52
53 #include <set>
54 #include <algorithm>
55 #include <memory>
56
57 #ifdef HAVE_ZLIB
58 #include <zlib.h>
59 #endif
60 #ifdef HAVE_BZ2
61 #include <bzlib.h>
62 #endif
63 #ifdef HAVE_LZMA
64 #include <lzma.h>
65 #endif
66 #ifdef HAVE_LZ4
67 #include <lz4frame.h>
68 #endif
69 #include <endian.h>
70 #include <stdint.h>
71
72 #if __gnu_linux__
73 #include <sys/prctl.h>
74 #endif
75
76 #include <apti18n.h>
77 /*}}}*/
78
79 using namespace std;
80
81 /* Should be a multiple of the common page size (4096) */
82 static constexpr unsigned long long APT_BUFFER_SIZE = 64 * 1024;
83
84 // RunScripts - Run a set of scripts from a configuration subtree /*{{{*/
85 // ---------------------------------------------------------------------
86 /* */
87 bool 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 {
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
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;
117
118 if(_config->FindB("Debug::RunScripts", false) == true)
119 std::clog << "Running external script: '"
120 << Opts->Value << "'" << std::endl;
121
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
159 // CopyFile - Buffered copy of a file /*{{{*/
160 // ---------------------------------------------------------------------
161 /* The caller is expected to set things so that failure causes erasure */
162 bool CopyFile(FileFd &From,FileFd &To)
163 {
164 if (From.IsOpen() == false || To.IsOpen() == false ||
165 From.Failed() == true || To.Failed() == true)
166 return false;
167
168 // Buffered copy between fds
169 constexpr size_t BufSize = APT_BUFFER_SIZE;
170 std::unique_ptr<unsigned char[]> Buf(new unsigned char[BufSize]);
171 unsigned long long ToRead = 0;
172 do {
173 if (From.Read(Buf.get(),BufSize, &ToRead) == false ||
174 To.Write(Buf.get(),ToRead) == false)
175 return false;
176 } while (ToRead != 0);
177
178 return true;
179 }
180 /*}}}*/
181 bool 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 }
193 return true;
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. */
202 int GetLock(string File,bool Errors)
203 {
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);
207 if (FD < 0)
208 {
209 // Read only .. can't have locking problems there.
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
216 if (Errors == true)
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;
221 return -1;
222 }
223 SetCloseExec(FD,true);
224
225 // Acquire a write lock
226 struct flock fl;
227 fl.l_type = F_WRLCK;
228 fl.l_whence = SEEK_SET;
229 fl.l_start = 0;
230 fl.l_len = 0;
231 if (fcntl(FD,F_SETLK,&fl) == -1)
232 {
233 // always close to not leak resources
234 int Tmp = errno;
235 close(FD);
236 errno = Tmp;
237
238 if (errno == ENOLCK)
239 {
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
242 }
243
244 if (Errors == true)
245 _error->Errno("open",_("Could not get lock %s"),File.c_str());
246
247 return -1;
248 }
249
250 return FD;
251 }
252 /*}}}*/
253 // FileExists - Check if a file exists /*{{{*/
254 // ---------------------------------------------------------------------
255 /* Beware: Directories are also files! */
256 bool FileExists(string File)
257 {
258 struct stat Buf;
259 if (stat(File.c_str(),&Buf) != 0)
260 return false;
261 return true;
262 }
263 /*}}}*/
264 // RealFileExists - Check if a file exists and if it is really a file /*{{{*/
265 // ---------------------------------------------------------------------
266 /* */
267 bool 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 /*}}}*/
275 // DirectoryExists - Check if a directory exists and is really one /*{{{*/
276 // ---------------------------------------------------------------------
277 /* */
278 bool 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. */
294 bool 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"
306 if (Path.compare(0, Parent.length(), Parent) != 0)
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 /*}}}*/
326 // CreateAPTDirectoryIfNeeded - ensure that the given directory exists /*{{{*/
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 */
330 bool CreateAPTDirectoryIfNeeded(string const &Parent, string const &Path)
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 /*}}}*/
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. */
351 std::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 }
362 std::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
378 std::vector<string> List;
379
380 if (DirectoryExists(Dir) == false)
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
386 Configuration::MatchAgainstConfig SilentIgnore("Dir::Ignore-Files-Silently");
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 {
396 // skip "hidden" files
397 if (Ent->d_name[0] == '.')
398 continue;
399
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 {
406 if (RealFileExists(File) == false)
407 {
408 // do not show ignoration warnings for directories
409 if (
410 #ifdef _DIRENT_HAVE_D_TYPE
411 Ent->d_type == DT_DIR ||
412 #endif
413 DirectoryExists(File) == true)
414 continue;
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
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;
433 if (SilentIgnore.Match(Ent->d_name) == false)
434 _error->Notice(_("Ignoring file '%s' in directory '%s' as it has no filename extension"), Ent->d_name, Dir.c_str());
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;
442 if (SilentIgnore.Match(Ent->d_name) == false)
443 _error->Notice(_("Ignoring file '%s' in directory '%s' as it has an invalid filename extension"), Ent->d_name, Dir.c_str());
444 continue;
445 }
446 }
447
448 // Skip bad filenames ala run-parts
449 const char *C = Ent->d_name;
450 for (; *C != 0; ++C)
451 if (isalpha(*C) == 0 && isdigit(*C) == 0
452 && *C != '_' && *C != '-' && *C != ':') {
453 // no required extension -> dot is a bad character
454 if (*C == '.' && Ext.empty() == false)
455 continue;
456 break;
457 }
458
459 // we don't reach the end of the name -> bad character included
460 if (*C != 0)
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
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 }
486 std::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
494 if (DirectoryExists(Dir) == false)
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 {
519 if (RealFileExists(File) == false)
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
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;
547 continue;
548 }
549
550 if (Debug == true)
551 std::clog << "Accept file: " << Ent->d_name << " in " << Dir << std::endl;
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 /*}}}*/
561 // SafeGetCWD - This is a safer getcwd that returns a dynamic string /*{{{*/
562 // ---------------------------------------------------------------------
563 /* We return / on failure. */
564 string SafeGetCWD()
565 {
566 // Stash the current dir.
567 char S[300];
568 S[0] = 0;
569 if (getcwd(S,sizeof(S)-2) == 0)
570 return "/";
571 unsigned int Len = strlen(S);
572 S[Len] = '/';
573 S[Len+1] = 0;
574 return S;
575 }
576 /*}}}*/
577 // GetModificationTime - Get the mtime of the given file or -1 on error /*{{{*/
578 // ---------------------------------------------------------------------
579 /* We return / on failure. */
580 time_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 /*}}}*/
588 // flNotDir - Strip the directory from the filename /*{{{*/
589 // ---------------------------------------------------------------------
590 /* */
591 string 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 /*}}}*/
600 // flNotFile - Strip the file from the directory name /*{{{*/
601 // ---------------------------------------------------------------------
602 /* Result ends in a / */
603 string flNotFile(string File)
604 {
605 string::size_type Res = File.rfind('/');
606 if (Res == string::npos)
607 return "./";
608 Res++;
609 return string(File,0,Res);
610 }
611 /*}}}*/
612 // flExtension - Return the extension for the file /*{{{*/
613 // ---------------------------------------------------------------------
614 /* */
615 string 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 /*}}}*/
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. */
627 string 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
643 ssize_t Res;
644 if ((Res = readlink(NFile.c_str(),Buffer,sizeof(Buffer))) <= 0 ||
645 (size_t)Res >= sizeof(Buffer))
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 /*}}}*/
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. */
667 string 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 /*}}}*/
681 // flAbsPath - Return the absolute path of the filename /*{{{*/
682 // ---------------------------------------------------------------------
683 /* */
684 string flAbsPath(string File)
685 {
686 char *p = realpath(File.c_str(), NULL);
687 if (p == NULL)
688 {
689 _error->Errno("realpath", "flAbsPath on %s failed", File.c_str());
690 return "";
691 }
692 std::string AbsPath(p);
693 free(p);
694 return AbsPath;
695 }
696 /*}}}*/
697 // SetCloseExec - Set the close on exec flag /*{{{*/
698 // ---------------------------------------------------------------------
699 /* */
700 void 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 /* */
712 void SetNonBlock(int Fd,bool Block)
713 {
714 int Flags = fcntl(Fd,F_GETFL) & (~O_NONBLOCK);
715 if (fcntl(Fd,F_SETFL,Flags | ((Block == false)?0:O_NONBLOCK)) != 0)
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 // ---------------------------------------------------------------------
724 /* This waits for a FD to become readable using select. It is useful for
725 applications making use of non-blocking sockets. The timeout is
726 in seconds. */
727 bool WaitFd(int Fd,bool write,unsigned long timeout)
728 {
729 fd_set Set;
730 struct timeval tv;
731 FD_ZERO(&Set);
732 FD_SET(Fd,&Set);
733 tv.tv_sec = timeout;
734 tv.tv_usec = 0;
735 if (write == true)
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;
746 }
747 else
748 {
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;
758 }
759
760 return true;
761 }
762 /*}}}*/
763 // MergeKeepFdsFromConfiguration - Merge APT::Keep-Fds configuration /*{{{*/
764 // ---------------------------------------------------------------------
765 /* This is used to merge the APT::Keep-Fds with the provided KeepFDs
766 * set.
767 */
768 void MergeKeepFdsFromConfiguration(std::set<int> &KeepFDs)
769 {
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 }
782 }
783 /*}}}*/
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. */
789 pid_t ExecFork()
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);
795 return ExecFork(KeepFDs);
796 }
797
798 pid_t ExecFork(std::set<int> KeepFDs)
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);
818
819 DIR *dir = opendir("/proc/self/fd");
820 if (dir != NULL)
821 {
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 }
839 }
840 }
841
842 return Process;
843 }
844 /*}}}*/
845 // ExecWait - Fancy waitpid /*{{{*/
846 // ---------------------------------------------------------------------
847 /* Waits for the given sub process. If Reap is set then no errors are
848 generated. Otherwise a failed subprocess will generate a proper descriptive
849 message */
850 bool ExecWait(pid_t Pid,const char *Name,bool Reap)
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
865 return _error->Error(_("Waited for %s but it wasn't there"),Name);
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;
874 if (WIFSIGNALED(Status) != 0)
875 {
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));
880 }
881
882 if (WIFEXITED(Status) != 0)
883 return _error->Error(_("Sub-process %s returned an error code (%u)"),Name,WEXITSTATUS(Status));
884
885 return _error->Error(_("Sub-process %s exited unexpectedly"),Name);
886 }
887
888 return true;
889 }
890 /*}}}*/
891 // StartsWithGPGClearTextSignature - Check if a file is Pgp/GPG clearsigned /*{{{*/
892 bool StartsWithGPGClearTextSignature(string const &FileName)
893 {
894 static const char* SIGMSG = "-----BEGIN PGP SIGNED MESSAGE-----\n";
895 char buffer[strlen(SIGMSG)+1];
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 }
907 /*}}}*/
908 // ChangeOwnerAndPermissionOfFile - set file attributes to requested values /*{{{*/
909 bool 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 && lchown(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 struct stat Buf;
923 if (lstat(file, &Buf) != 0 || S_ISLNK(Buf.st_mode))
924 return Res;
925 if (chmod(file, mode) != 0)
926 Res &= _error->WarningE(requester, "chmod 0%o of file %s failed", mode, file);
927 return Res;
928 }
929 /*}}}*/
930
931 struct APT_HIDDEN simple_buffer { /*{{{*/
932 size_t buffersize_max = 0;
933 unsigned long long bufferstart = 0;
934 unsigned long long bufferend = 0;
935 char *buffer = nullptr;
936
937 simple_buffer() {
938 reset(4096);
939 }
940 ~simple_buffer() {
941 delete[] buffer;
942 }
943
944 const char *get() const { return buffer + bufferstart; }
945 char *get() { return buffer + bufferstart; }
946 const char *getend() const { return buffer + bufferend; }
947 char *getend() { return buffer + bufferend; }
948 bool empty() const { return bufferend <= bufferstart; }
949 bool full() const { return bufferend == buffersize_max; }
950 unsigned long long free() const { return buffersize_max - bufferend; }
951 unsigned long long size() const { return bufferend-bufferstart; }
952 void reset(size_t size)
953 {
954 if (size > buffersize_max) {
955 delete[] buffer;
956 buffersize_max = size;
957 buffer = new char[size];
958 }
959 reset();
960 }
961 void reset() { bufferend = bufferstart = 0; }
962 ssize_t read(void *to, unsigned long long requested_size) APT_MUSTCHECK
963 {
964 if (size() < requested_size)
965 requested_size = size();
966 memcpy(to, buffer + bufferstart, requested_size);
967 bufferstart += requested_size;
968 if (bufferstart == bufferend)
969 bufferstart = bufferend = 0;
970 return requested_size;
971 }
972 ssize_t write(const void *from, unsigned long long requested_size) APT_MUSTCHECK
973 {
974 if (free() < requested_size)
975 requested_size = free();
976 memcpy(getend(), from, requested_size);
977 bufferend += requested_size;
978 if (bufferstart == bufferend)
979 bufferstart = bufferend = 0;
980 return requested_size;
981 }
982 };
983 /*}}}*/
984
985 class APT_HIDDEN FileFdPrivate { /*{{{*/
986 friend class BufferedWriteFileFdPrivate;
987 protected:
988 FileFd * const filefd;
989 simple_buffer buffer;
990 int compressed_fd;
991 pid_t compressor_pid;
992 bool is_pipe;
993 APT::Configuration::Compressor compressor;
994 unsigned int openmode;
995 unsigned long long seekpos;
996 public:
997
998 explicit FileFdPrivate(FileFd * const pfilefd) : filefd(pfilefd),
999 compressed_fd(-1), compressor_pid(-1), is_pipe(false),
1000 openmode(0), seekpos(0) {};
1001 virtual APT::Configuration::Compressor get_compressor() const
1002 {
1003 return compressor;
1004 }
1005 virtual void set_compressor(APT::Configuration::Compressor const &compressor)
1006 {
1007 this->compressor = compressor;
1008 }
1009 virtual unsigned int get_openmode() const
1010 {
1011 return openmode;
1012 }
1013 virtual void set_openmode(unsigned int openmode)
1014 {
1015 this->openmode = openmode;
1016 }
1017 virtual bool get_is_pipe() const
1018 {
1019 return is_pipe;
1020 }
1021 virtual void set_is_pipe(bool is_pipe)
1022 {
1023 this->is_pipe = is_pipe;
1024 }
1025 virtual unsigned long long get_seekpos() const
1026 {
1027 return seekpos;
1028 }
1029 virtual void set_seekpos(unsigned long long seekpos)
1030 {
1031 this->seekpos = seekpos;
1032 }
1033
1034 virtual bool InternalOpen(int const iFd, unsigned int const Mode) = 0;
1035 ssize_t InternalRead(void * To, unsigned long long Size)
1036 {
1037 // Drain the buffer if needed.
1038 if (buffer.empty() == false)
1039 {
1040 return buffer.read(To, Size);
1041 }
1042 return InternalUnbufferedRead(To, Size);
1043 }
1044 virtual ssize_t InternalUnbufferedRead(void * const To, unsigned long long const Size) = 0;
1045 virtual bool InternalReadError() { return filefd->FileFdErrno("read",_("Read error")); }
1046 virtual char * InternalReadLine(char * To, unsigned long long Size)
1047 {
1048 if (unlikely(Size == 0))
1049 return nullptr;
1050 // Read one byte less than buffer size to have space for trailing 0.
1051 --Size;
1052
1053 char * const InitialTo = To;
1054
1055 while (Size > 0) {
1056 if (buffer.empty() == true)
1057 {
1058 buffer.reset();
1059 unsigned long long actualread = 0;
1060 if (filefd->Read(buffer.getend(), buffer.free(), &actualread) == false)
1061 return nullptr;
1062 buffer.bufferend = actualread;
1063 if (buffer.size() == 0)
1064 {
1065 if (To == InitialTo)
1066 return nullptr;
1067 break;
1068 }
1069 filefd->Flags &= ~FileFd::HitEof;
1070 }
1071
1072 unsigned long long const OutputSize = std::min(Size, buffer.size());
1073 char const * const newline = static_cast<char const * const>(memchr(buffer.get(), '\n', OutputSize));
1074 // Read until end of line or up to Size bytes from the buffer.
1075 unsigned long long actualread = buffer.read(To,
1076 (newline != nullptr)
1077 ? (newline - buffer.get()) + 1
1078 : OutputSize);
1079 To += actualread;
1080 Size -= actualread;
1081 if (newline != nullptr)
1082 break;
1083 }
1084 *To = '\0';
1085 return InitialTo;
1086 }
1087 virtual bool InternalFlush()
1088 {
1089 return true;
1090 }
1091 virtual ssize_t InternalWrite(void const * const From, unsigned long long const Size) = 0;
1092 virtual bool InternalWriteError() { return filefd->FileFdErrno("write",_("Write error")); }
1093 virtual bool InternalSeek(unsigned long long const To)
1094 {
1095 // Our poor man seeking is costly, so try to avoid it
1096 unsigned long long const iseekpos = filefd->Tell();
1097 if (iseekpos == To)
1098 return true;
1099 else if (iseekpos < To)
1100 return filefd->Skip(To - iseekpos);
1101
1102 if ((openmode & FileFd::ReadOnly) != FileFd::ReadOnly)
1103 return filefd->FileFdError("Reopen is only implemented for read-only files!");
1104 InternalClose(filefd->FileName);
1105 if (filefd->iFd != -1)
1106 close(filefd->iFd);
1107 filefd->iFd = -1;
1108 if (filefd->TemporaryFileName.empty() == false)
1109 filefd->iFd = open(filefd->TemporaryFileName.c_str(), O_RDONLY);
1110 else if (filefd->FileName.empty() == false)
1111 filefd->iFd = open(filefd->FileName.c_str(), O_RDONLY);
1112 else
1113 {
1114 if (compressed_fd > 0)
1115 if (lseek(compressed_fd, 0, SEEK_SET) != 0)
1116 filefd->iFd = compressed_fd;
1117 if (filefd->iFd < 0)
1118 return filefd->FileFdError("Reopen is not implemented for pipes opened with FileFd::OpenDescriptor()!");
1119 }
1120
1121 if (filefd->OpenInternDescriptor(openmode, compressor) == false)
1122 return filefd->FileFdError("Seek on file %s because it couldn't be reopened", filefd->FileName.c_str());
1123
1124 buffer.reset();
1125 set_seekpos(0);
1126 if (To != 0)
1127 return filefd->Skip(To);
1128
1129 seekpos = To;
1130 return true;
1131 }
1132 virtual bool InternalSkip(unsigned long long Over)
1133 {
1134 unsigned long long constexpr buffersize = 1024;
1135 char buffer[buffersize];
1136 while (Over != 0)
1137 {
1138 unsigned long long toread = std::min(buffersize, Over);
1139 if (filefd->Read(buffer, toread) == false)
1140 return filefd->FileFdError("Unable to seek ahead %llu",Over);
1141 Over -= toread;
1142 }
1143 return true;
1144 }
1145 virtual bool InternalTruncate(unsigned long long const)
1146 {
1147 return filefd->FileFdError("Truncating compressed files is not implemented (%s)", filefd->FileName.c_str());
1148 }
1149 virtual unsigned long long InternalTell()
1150 {
1151 // In theory, we could just return seekpos here always instead of
1152 // seeking around, but not all users of FileFd use always Seek() and co
1153 // so d->seekpos isn't always true and we can just use it as a hint if
1154 // we have nothing else, but not always as an authority…
1155 return seekpos - buffer.size();
1156 }
1157 virtual unsigned long long InternalSize()
1158 {
1159 unsigned long long size = 0;
1160 unsigned long long const oldSeek = filefd->Tell();
1161 unsigned long long constexpr ignoresize = 1024;
1162 char ignore[ignoresize];
1163 unsigned long long read = 0;
1164 do {
1165 if (filefd->Read(ignore, ignoresize, &read) == false)
1166 {
1167 filefd->Seek(oldSeek);
1168 return 0;
1169 }
1170 } while(read != 0);
1171 size = filefd->Tell();
1172 filefd->Seek(oldSeek);
1173 return size;
1174 }
1175 virtual bool InternalClose(std::string const &FileName) = 0;
1176 virtual bool InternalStream() const { return false; }
1177 virtual bool InternalAlwaysAutoClose() const { return true; }
1178
1179 virtual ~FileFdPrivate() {}
1180 };
1181 /*}}}*/
1182 class APT_HIDDEN BufferedWriteFileFdPrivate : public FileFdPrivate { /*{{{*/
1183 protected:
1184 FileFdPrivate *wrapped;
1185 simple_buffer writebuffer;
1186
1187 public:
1188
1189 explicit BufferedWriteFileFdPrivate(FileFdPrivate *Priv) :
1190 FileFdPrivate(Priv->filefd), wrapped(Priv) {};
1191
1192 virtual APT::Configuration::Compressor get_compressor() const APT_OVERRIDE
1193 {
1194 return wrapped->get_compressor();
1195 }
1196 virtual void set_compressor(APT::Configuration::Compressor const &compressor) APT_OVERRIDE
1197 {
1198 return wrapped->set_compressor(compressor);
1199 }
1200 virtual unsigned int get_openmode() const APT_OVERRIDE
1201 {
1202 return wrapped->get_openmode();
1203 }
1204 virtual void set_openmode(unsigned int openmode) APT_OVERRIDE
1205 {
1206 return wrapped->set_openmode(openmode);
1207 }
1208 virtual bool get_is_pipe() const APT_OVERRIDE
1209 {
1210 return wrapped->get_is_pipe();
1211 }
1212 virtual void set_is_pipe(bool is_pipe) APT_OVERRIDE
1213 {
1214 FileFdPrivate::set_is_pipe(is_pipe);
1215 wrapped->set_is_pipe(is_pipe);
1216 }
1217 virtual unsigned long long get_seekpos() const APT_OVERRIDE
1218 {
1219 return wrapped->get_seekpos();
1220 }
1221 virtual void set_seekpos(unsigned long long seekpos) APT_OVERRIDE
1222 {
1223 return wrapped->set_seekpos(seekpos);
1224 }
1225 virtual bool InternalOpen(int const iFd, unsigned int const Mode) APT_OVERRIDE
1226 {
1227 if (InternalFlush() == false)
1228 return false;
1229 return wrapped->InternalOpen(iFd, Mode);
1230 }
1231 virtual ssize_t InternalUnbufferedRead(void * const To, unsigned long long const Size) APT_OVERRIDE
1232 {
1233 if (InternalFlush() == false)
1234 return -1;
1235 return wrapped->InternalUnbufferedRead(To, Size);
1236
1237 }
1238 virtual bool InternalReadError() APT_OVERRIDE
1239 {
1240 return wrapped->InternalReadError();
1241 }
1242 virtual char * InternalReadLine(char * To, unsigned long long Size) APT_OVERRIDE
1243 {
1244 if (InternalFlush() == false)
1245 return nullptr;
1246 return wrapped->InternalReadLine(To, Size);
1247 }
1248 virtual bool InternalFlush() APT_OVERRIDE
1249 {
1250 while (writebuffer.empty() == false) {
1251 auto written = wrapped->InternalWrite(writebuffer.get(),
1252 writebuffer.size());
1253 // Ignore interrupted syscalls
1254 if (written < 0 && errno == EINTR)
1255 continue;
1256 if (written < 0)
1257 return wrapped->InternalWriteError();
1258
1259 writebuffer.bufferstart += written;
1260 }
1261
1262 writebuffer.reset();
1263 return true;
1264 }
1265 virtual ssize_t InternalWrite(void const * const From, unsigned long long const Size) APT_OVERRIDE
1266 {
1267 // Optimisation: If the buffer is empty and we have more to write than
1268 // would fit in the buffer (or equal number of bytes), write directly.
1269 if (writebuffer.empty() == true && Size >= writebuffer.free())
1270 return wrapped->InternalWrite(From, Size);
1271
1272 // Write as much into the buffer as possible and then flush if needed
1273 auto written = writebuffer.write(From, Size);
1274
1275 if (writebuffer.full() && InternalFlush() == false)
1276 return -1;
1277
1278 return written;
1279 }
1280 virtual bool InternalWriteError() APT_OVERRIDE
1281 {
1282 return wrapped->InternalWriteError();
1283 }
1284 virtual bool InternalSeek(unsigned long long const To) APT_OVERRIDE
1285 {
1286 if (InternalFlush() == false)
1287 return false;
1288 return wrapped->InternalSeek(To);
1289 }
1290 virtual bool InternalSkip(unsigned long long Over) APT_OVERRIDE
1291 {
1292 if (InternalFlush() == false)
1293 return false;
1294 return wrapped->InternalSkip(Over);
1295 }
1296 virtual bool InternalTruncate(unsigned long long const Size) APT_OVERRIDE
1297 {
1298 if (InternalFlush() == false)
1299 return false;
1300 return wrapped->InternalTruncate(Size);
1301 }
1302 virtual unsigned long long InternalTell() APT_OVERRIDE
1303 {
1304 if (InternalFlush() == false)
1305 return -1;
1306 return wrapped->InternalTell();
1307 }
1308 virtual unsigned long long InternalSize() APT_OVERRIDE
1309 {
1310 if (InternalFlush() == false)
1311 return -1;
1312 return wrapped->InternalSize();
1313 }
1314 virtual bool InternalClose(std::string const &FileName) APT_OVERRIDE
1315 {
1316 return wrapped->InternalClose(FileName);
1317 }
1318 virtual bool InternalAlwaysAutoClose() const APT_OVERRIDE
1319 {
1320 return wrapped->InternalAlwaysAutoClose();
1321 }
1322 virtual ~BufferedWriteFileFdPrivate()
1323 {
1324 delete wrapped;
1325 }
1326 };
1327 /*}}}*/
1328 class APT_HIDDEN GzipFileFdPrivate: public FileFdPrivate { /*{{{*/
1329 #ifdef HAVE_ZLIB
1330 public:
1331 gzFile gz;
1332 virtual bool InternalOpen(int const iFd, unsigned int const Mode) APT_OVERRIDE
1333 {
1334 if ((Mode & FileFd::ReadWrite) == FileFd::ReadWrite)
1335 gz = gzdopen(iFd, "r+");
1336 else if ((Mode & FileFd::WriteOnly) == FileFd::WriteOnly)
1337 gz = gzdopen(iFd, "w");
1338 else
1339 gz = gzdopen(iFd, "r");
1340 filefd->Flags |= FileFd::Compressed;
1341 return gz != nullptr;
1342 }
1343 virtual ssize_t InternalUnbufferedRead(void * const To, unsigned long long const Size) APT_OVERRIDE
1344 {
1345 return gzread(gz, To, Size);
1346 }
1347 virtual bool InternalReadError() APT_OVERRIDE
1348 {
1349 int err;
1350 char const * const errmsg = gzerror(gz, &err);
1351 if (err != Z_ERRNO)
1352 return filefd->FileFdError("gzread: %s (%d: %s)", _("Read error"), err, errmsg);
1353 return FileFdPrivate::InternalReadError();
1354 }
1355 virtual char * InternalReadLine(char * To, unsigned long long Size) APT_OVERRIDE
1356 {
1357 return gzgets(gz, To, Size);
1358 }
1359 virtual ssize_t InternalWrite(void const * const From, unsigned long long const Size) APT_OVERRIDE
1360 {
1361 return gzwrite(gz,From,Size);
1362 }
1363 virtual bool InternalWriteError() APT_OVERRIDE
1364 {
1365 int err;
1366 char const * const errmsg = gzerror(gz, &err);
1367 if (err != Z_ERRNO)
1368 return filefd->FileFdError("gzwrite: %s (%d: %s)", _("Write error"), err, errmsg);
1369 return FileFdPrivate::InternalWriteError();
1370 }
1371 virtual bool InternalSeek(unsigned long long const To) APT_OVERRIDE
1372 {
1373 off_t const res = gzseek(gz, To, SEEK_SET);
1374 if (res != (off_t)To)
1375 return filefd->FileFdError("Unable to seek to %llu", To);
1376 seekpos = To;
1377 buffer.reset();
1378 return true;
1379 }
1380 virtual bool InternalSkip(unsigned long long Over) APT_OVERRIDE
1381 {
1382 if (Over >= buffer.size())
1383 {
1384 Over -= buffer.size();
1385 buffer.reset();
1386 }
1387 else
1388 {
1389 buffer.bufferstart += Over;
1390 return true;
1391 }
1392 if (Over == 0)
1393 return true;
1394 off_t const res = gzseek(gz, Over, SEEK_CUR);
1395 if (res < 0)
1396 return filefd->FileFdError("Unable to seek ahead %llu",Over);
1397 seekpos = res;
1398 return true;
1399 }
1400 virtual unsigned long long InternalTell() APT_OVERRIDE
1401 {
1402 return gztell(gz) - buffer.size();
1403 }
1404 virtual unsigned long long InternalSize() APT_OVERRIDE
1405 {
1406 unsigned long long filesize = FileFdPrivate::InternalSize();
1407 // only check gzsize if we are actually a gzip file, just checking for
1408 // "gz" is not sufficient as uncompressed files could be opened with
1409 // gzopen in "direct" mode as well
1410 if (filesize == 0 || gzdirect(gz))
1411 return filesize;
1412
1413 off_t const oldPos = lseek(filefd->iFd, 0, SEEK_CUR);
1414 /* unfortunately zlib.h doesn't provide a gzsize(), so we have to do
1415 * this ourselves; the original (uncompressed) file size is the last 32
1416 * bits of the file */
1417 // FIXME: Size for gz-files is limited by 32bit… no largefile support
1418 if (lseek(filefd->iFd, -4, SEEK_END) < 0)
1419 {
1420 filefd->FileFdErrno("lseek","Unable to seek to end of gzipped file");
1421 return 0;
1422 }
1423 uint32_t size = 0;
1424 if (read(filefd->iFd, &size, 4) != 4)
1425 {
1426 filefd->FileFdErrno("read","Unable to read original size of gzipped file");
1427 return 0;
1428 }
1429 size = le32toh(size);
1430
1431 if (lseek(filefd->iFd, oldPos, SEEK_SET) < 0)
1432 {
1433 filefd->FileFdErrno("lseek","Unable to seek in gzipped file");
1434 return 0;
1435 }
1436 return size;
1437 }
1438 virtual bool InternalClose(std::string const &FileName) APT_OVERRIDE
1439 {
1440 if (gz == nullptr)
1441 return true;
1442 int const e = gzclose(gz);
1443 gz = nullptr;
1444 // gzdclose() on empty files always fails with "buffer error" here, ignore that
1445 if (e != 0 && e != Z_BUF_ERROR)
1446 return _error->Errno("close",_("Problem closing the gzip file %s"), FileName.c_str());
1447 return true;
1448 }
1449
1450 explicit GzipFileFdPrivate(FileFd * const filefd) : FileFdPrivate(filefd), gz(nullptr) {}
1451 virtual ~GzipFileFdPrivate() { InternalClose(""); }
1452 #endif
1453 };
1454 /*}}}*/
1455 class APT_HIDDEN Bz2FileFdPrivate: public FileFdPrivate { /*{{{*/
1456 #ifdef HAVE_BZ2
1457 BZFILE* bz2;
1458 public:
1459 virtual bool InternalOpen(int const iFd, unsigned int const Mode) APT_OVERRIDE
1460 {
1461 if ((Mode & FileFd::ReadWrite) == FileFd::ReadWrite)
1462 bz2 = BZ2_bzdopen(iFd, "r+");
1463 else if ((Mode & FileFd::WriteOnly) == FileFd::WriteOnly)
1464 bz2 = BZ2_bzdopen(iFd, "w");
1465 else
1466 bz2 = BZ2_bzdopen(iFd, "r");
1467 filefd->Flags |= FileFd::Compressed;
1468 return bz2 != nullptr;
1469 }
1470 virtual ssize_t InternalUnbufferedRead(void * const To, unsigned long long const Size) APT_OVERRIDE
1471 {
1472 return BZ2_bzread(bz2, To, Size);
1473 }
1474 virtual bool InternalReadError() APT_OVERRIDE
1475 {
1476 int err;
1477 char const * const errmsg = BZ2_bzerror(bz2, &err);
1478 if (err != BZ_IO_ERROR)
1479 return filefd->FileFdError("BZ2_bzread: %s %s (%d: %s)", filefd->FileName.c_str(), _("Read error"), err, errmsg);
1480 return FileFdPrivate::InternalReadError();
1481 }
1482 virtual ssize_t InternalWrite(void const * const From, unsigned long long const Size) APT_OVERRIDE
1483 {
1484 return BZ2_bzwrite(bz2, (void*)From, Size);
1485 }
1486 virtual bool InternalWriteError() APT_OVERRIDE
1487 {
1488 int err;
1489 char const * const errmsg = BZ2_bzerror(bz2, &err);
1490 if (err != BZ_IO_ERROR)
1491 return filefd->FileFdError("BZ2_bzwrite: %s %s (%d: %s)", filefd->FileName.c_str(), _("Write error"), err, errmsg);
1492 return FileFdPrivate::InternalWriteError();
1493 }
1494 virtual bool InternalStream() const APT_OVERRIDE { return true; }
1495 virtual bool InternalClose(std::string const &) APT_OVERRIDE
1496 {
1497 if (bz2 == nullptr)
1498 return true;
1499 BZ2_bzclose(bz2);
1500 bz2 = nullptr;
1501 return true;
1502 }
1503
1504 explicit Bz2FileFdPrivate(FileFd * const filefd) : FileFdPrivate(filefd), bz2(nullptr) {}
1505 virtual ~Bz2FileFdPrivate() { InternalClose(""); }
1506 #endif
1507 };
1508 /*}}}*/
1509 class APT_HIDDEN Lz4FileFdPrivate: public FileFdPrivate { /*{{{*/
1510 static constexpr unsigned long long LZ4_HEADER_SIZE = 19;
1511 static constexpr unsigned long long LZ4_FOOTER_SIZE = 4;
1512 #ifdef HAVE_LZ4
1513 LZ4F_decompressionContext_t dctx;
1514 LZ4F_compressionContext_t cctx;
1515 LZ4F_errorCode_t res;
1516 FileFd backend;
1517 simple_buffer lz4_buffer;
1518 // Count of bytes that the decompressor expects to read next, or buffer size.
1519 size_t next_to_load = APT_BUFFER_SIZE;
1520 public:
1521 virtual bool InternalOpen(int const iFd, unsigned int const Mode) APT_OVERRIDE
1522 {
1523 if ((Mode & FileFd::ReadWrite) == FileFd::ReadWrite)
1524 return _error->Error("lz4 only supports write or read mode");
1525
1526 if ((Mode & FileFd::WriteOnly) == FileFd::WriteOnly) {
1527 res = LZ4F_createCompressionContext(&cctx, LZ4F_VERSION);
1528 lz4_buffer.reset(LZ4F_compressBound(APT_BUFFER_SIZE, nullptr)
1529 + LZ4_HEADER_SIZE + LZ4_FOOTER_SIZE);
1530 } else {
1531 res = LZ4F_createDecompressionContext(&dctx, LZ4F_VERSION);
1532 lz4_buffer.reset(APT_BUFFER_SIZE);
1533 }
1534
1535 filefd->Flags |= FileFd::Compressed;
1536
1537 if (LZ4F_isError(res))
1538 return false;
1539
1540 unsigned int flags = (Mode & (FileFd::WriteOnly|FileFd::ReadOnly));
1541 if (backend.OpenDescriptor(iFd, flags, FileFd::None, true) == false)
1542 return false;
1543
1544 // Write the file header
1545 if ((Mode & FileFd::WriteOnly) == FileFd::WriteOnly)
1546 {
1547 res = LZ4F_compressBegin(cctx, lz4_buffer.buffer, lz4_buffer.buffersize_max, nullptr);
1548 if (LZ4F_isError(res) || backend.Write(lz4_buffer.buffer, res) == false)
1549 return false;
1550 }
1551
1552 return true;
1553 }
1554 virtual ssize_t InternalUnbufferedRead(void * const To, unsigned long long const Size) APT_OVERRIDE
1555 {
1556 /* Keep reading as long as the compressor still wants to read */
1557 while (next_to_load) {
1558 // Fill compressed buffer;
1559 if (lz4_buffer.empty()) {
1560 unsigned long long read;
1561 /* Reset - if LZ4 decompressor wants to read more, allocate more */
1562 lz4_buffer.reset(next_to_load);
1563 if (backend.Read(lz4_buffer.getend(), lz4_buffer.free(), &read) == false)
1564 return -1;
1565 lz4_buffer.bufferend += read;
1566
1567 /* Expected EOF */
1568 if (read == 0) {
1569 res = -1;
1570 return filefd->FileFdError("LZ4F: %s %s",
1571 filefd->FileName.c_str(),
1572 _("Unexpected end of file")), -1;
1573 }
1574 }
1575 // Drain compressed buffer as far as possible.
1576 size_t in = lz4_buffer.size();
1577 size_t out = Size;
1578
1579 res = LZ4F_decompress(dctx, To, &out, lz4_buffer.get(), &in, nullptr);
1580 if (LZ4F_isError(res))
1581 return -1;
1582
1583 next_to_load = res;
1584 lz4_buffer.bufferstart += in;
1585
1586 if (out != 0)
1587 return out;
1588 }
1589
1590 return 0;
1591 }
1592 virtual bool InternalReadError() APT_OVERRIDE
1593 {
1594 char const * const errmsg = LZ4F_getErrorName(res);
1595
1596 return filefd->FileFdError("LZ4F: %s %s (%zu: %s)", filefd->FileName.c_str(), _("Read error"), res, errmsg);
1597 }
1598 virtual ssize_t InternalWrite(void const * const From, unsigned long long const Size) APT_OVERRIDE
1599 {
1600 unsigned long long const towrite = std::min(APT_BUFFER_SIZE, Size);
1601
1602 res = LZ4F_compressUpdate(cctx,
1603 lz4_buffer.buffer, lz4_buffer.buffersize_max,
1604 From, towrite, nullptr);
1605
1606 if (LZ4F_isError(res) || backend.Write(lz4_buffer.buffer, res) == false)
1607 return -1;
1608
1609 return towrite;
1610 }
1611 virtual bool InternalWriteError() APT_OVERRIDE
1612 {
1613 char const * const errmsg = LZ4F_getErrorName(res);
1614
1615 return filefd->FileFdError("LZ4F: %s %s (%zu: %s)", filefd->FileName.c_str(), _("Write error"), res, errmsg);
1616 }
1617 virtual bool InternalStream() const APT_OVERRIDE { return true; }
1618
1619 virtual bool InternalFlush() APT_OVERRIDE
1620 {
1621 return backend.Flush();
1622 }
1623
1624 virtual bool InternalClose(std::string const &) APT_OVERRIDE
1625 {
1626 /* Reset variables */
1627 res = 0;
1628 next_to_load = APT_BUFFER_SIZE;
1629
1630 if (cctx != nullptr)
1631 {
1632 if (filefd->Failed() == false)
1633 {
1634 res = LZ4F_compressEnd(cctx, lz4_buffer.buffer, lz4_buffer.buffersize_max, nullptr);
1635 if (LZ4F_isError(res) || backend.Write(lz4_buffer.buffer, res) == false)
1636 return false;
1637 if (!backend.Flush())
1638 return false;
1639 }
1640 if (!backend.Close())
1641 return false;
1642
1643 res = LZ4F_freeCompressionContext(cctx);
1644 cctx = nullptr;
1645 }
1646
1647 if (dctx != nullptr)
1648 {
1649 res = LZ4F_freeDecompressionContext(dctx);
1650 dctx = nullptr;
1651 }
1652 if (backend.IsOpen())
1653 {
1654 backend.Close();
1655 filefd->iFd = -1;
1656 }
1657
1658 return LZ4F_isError(res) == false;
1659 }
1660
1661 explicit Lz4FileFdPrivate(FileFd * const filefd) : FileFdPrivate(filefd), dctx(nullptr), cctx(nullptr) {}
1662 virtual ~Lz4FileFdPrivate() {
1663 InternalClose("");
1664 }
1665 #endif
1666 };
1667 /*}}}*/
1668 class APT_HIDDEN LzmaFileFdPrivate: public FileFdPrivate { /*{{{*/
1669 #ifdef HAVE_LZMA
1670 struct LZMAFILE {
1671 FILE* file;
1672 FileFd * const filefd;
1673 uint8_t buffer[4096];
1674 lzma_stream stream;
1675 lzma_ret err;
1676 bool eof;
1677 bool compressing;
1678
1679 LZMAFILE(FileFd * const fd) : file(nullptr), filefd(fd), eof(false), compressing(false) { buffer[0] = '\0'; }
1680 ~LZMAFILE()
1681 {
1682 if (compressing == true && filefd->Failed() == false)
1683 {
1684 size_t constexpr buffersize = sizeof(buffer)/sizeof(buffer[0]);
1685 while(true)
1686 {
1687 stream.avail_out = buffersize;
1688 stream.next_out = buffer;
1689 err = lzma_code(&stream, LZMA_FINISH);
1690 if (err != LZMA_OK && err != LZMA_STREAM_END)
1691 {
1692 _error->Error("~LZMAFILE: Compress finalisation failed");
1693 break;
1694 }
1695 size_t const n = buffersize - stream.avail_out;
1696 if (n && fwrite(buffer, 1, n, file) != n)
1697 {
1698 _error->Errno("~LZMAFILE",_("Write error"));
1699 break;
1700 }
1701 if (err == LZMA_STREAM_END)
1702 break;
1703 }
1704 }
1705 lzma_end(&stream);
1706 fclose(file);
1707 }
1708 };
1709 LZMAFILE* lzma;
1710 static uint32_t findXZlevel(std::vector<std::string> const &Args)
1711 {
1712 for (auto a = Args.rbegin(); a != Args.rend(); ++a)
1713 if (a->empty() == false && (*a)[0] == '-' && (*a)[1] != '-')
1714 {
1715 auto const number = a->find_last_of("0123456789");
1716 if (number == std::string::npos)
1717 continue;
1718 auto const extreme = a->find("e", number);
1719 uint32_t level = (extreme != std::string::npos) ? LZMA_PRESET_EXTREME : 0;
1720 switch ((*a)[number])
1721 {
1722 case '0': return level | 0;
1723 case '1': return level | 1;
1724 case '2': return level | 2;
1725 case '3': return level | 3;
1726 case '4': return level | 4;
1727 case '5': return level | 5;
1728 case '6': return level | 6;
1729 case '7': return level | 7;
1730 case '8': return level | 8;
1731 case '9': return level | 9;
1732 }
1733 }
1734 return 6;
1735 }
1736 public:
1737 virtual bool InternalOpen(int const iFd, unsigned int const Mode) APT_OVERRIDE
1738 {
1739 if ((Mode & FileFd::ReadWrite) == FileFd::ReadWrite)
1740 return filefd->FileFdError("ReadWrite mode is not supported for lzma/xz files %s", filefd->FileName.c_str());
1741
1742 if (lzma == nullptr)
1743 lzma = new LzmaFileFdPrivate::LZMAFILE(filefd);
1744 if ((Mode & FileFd::WriteOnly) == FileFd::WriteOnly)
1745 lzma->file = fdopen(iFd, "w");
1746 else
1747 lzma->file = fdopen(iFd, "r");
1748 filefd->Flags |= FileFd::Compressed;
1749 if (lzma->file == nullptr)
1750 return false;
1751
1752 lzma_stream tmp_stream = LZMA_STREAM_INIT;
1753 lzma->stream = tmp_stream;
1754
1755 if ((Mode & FileFd::WriteOnly) == FileFd::WriteOnly)
1756 {
1757 uint32_t const xzlevel = findXZlevel(compressor.CompressArgs);
1758 if (compressor.Name == "xz")
1759 {
1760 if (lzma_easy_encoder(&lzma->stream, xzlevel, LZMA_CHECK_CRC64) != LZMA_OK)
1761 return false;
1762 }
1763 else
1764 {
1765 lzma_options_lzma options;
1766 lzma_lzma_preset(&options, xzlevel);
1767 if (lzma_alone_encoder(&lzma->stream, &options) != LZMA_OK)
1768 return false;
1769 }
1770 lzma->compressing = true;
1771 }
1772 else
1773 {
1774 uint64_t const memlimit = UINT64_MAX;
1775 if (compressor.Name == "xz")
1776 {
1777 if (lzma_auto_decoder(&lzma->stream, memlimit, 0) != LZMA_OK)
1778 return false;
1779 }
1780 else
1781 {
1782 if (lzma_alone_decoder(&lzma->stream, memlimit) != LZMA_OK)
1783 return false;
1784 }
1785 lzma->compressing = false;
1786 }
1787 return true;
1788 }
1789 virtual ssize_t InternalUnbufferedRead(void * const To, unsigned long long const Size) APT_OVERRIDE
1790 {
1791 ssize_t Res;
1792 if (lzma->eof == true)
1793 return 0;
1794
1795 lzma->stream.next_out = (uint8_t *) To;
1796 lzma->stream.avail_out = Size;
1797 if (lzma->stream.avail_in == 0)
1798 {
1799 lzma->stream.next_in = lzma->buffer;
1800 lzma->stream.avail_in = fread(lzma->buffer, 1, sizeof(lzma->buffer)/sizeof(lzma->buffer[0]), lzma->file);
1801 }
1802 lzma->err = lzma_code(&lzma->stream, LZMA_RUN);
1803 if (lzma->err == LZMA_STREAM_END)
1804 {
1805 lzma->eof = true;
1806 Res = Size - lzma->stream.avail_out;
1807 }
1808 else if (lzma->err != LZMA_OK)
1809 {
1810 Res = -1;
1811 errno = 0;
1812 }
1813 else
1814 {
1815 Res = Size - lzma->stream.avail_out;
1816 if (Res == 0)
1817 {
1818 // lzma run was okay, but produced no output…
1819 Res = -1;
1820 errno = EINTR;
1821 }
1822 }
1823 return Res;
1824 }
1825 virtual bool InternalReadError() APT_OVERRIDE
1826 {
1827 return filefd->FileFdError("lzma_read: %s (%d)", _("Read error"), lzma->err);
1828 }
1829 virtual ssize_t InternalWrite(void const * const From, unsigned long long const Size) APT_OVERRIDE
1830 {
1831 ssize_t Res;
1832 lzma->stream.next_in = (uint8_t *)From;
1833 lzma->stream.avail_in = Size;
1834 lzma->stream.next_out = lzma->buffer;
1835 lzma->stream.avail_out = sizeof(lzma->buffer)/sizeof(lzma->buffer[0]);
1836 lzma->err = lzma_code(&lzma->stream, LZMA_RUN);
1837 if (lzma->err != LZMA_OK)
1838 return -1;
1839 size_t const n = sizeof(lzma->buffer)/sizeof(lzma->buffer[0]) - lzma->stream.avail_out;
1840 size_t const m = (n == 0) ? 0 : fwrite(lzma->buffer, 1, n, lzma->file);
1841 if (m != n)
1842 {
1843 Res = -1;
1844 errno = 0;
1845 }
1846 else
1847 {
1848 Res = Size - lzma->stream.avail_in;
1849 if (Res == 0)
1850 {
1851 // lzma run was okay, but produced no output…
1852 Res = -1;
1853 errno = EINTR;
1854 }
1855 }
1856 return Res;
1857 }
1858 virtual bool InternalWriteError() APT_OVERRIDE
1859 {
1860 return filefd->FileFdError("lzma_write: %s (%d)", _("Write error"), lzma->err);
1861 }
1862 virtual bool InternalStream() const APT_OVERRIDE { return true; }
1863 virtual bool InternalClose(std::string const &) APT_OVERRIDE
1864 {
1865 delete lzma;
1866 lzma = nullptr;
1867 return true;
1868 }
1869
1870 explicit LzmaFileFdPrivate(FileFd * const filefd) : FileFdPrivate(filefd), lzma(nullptr) {}
1871 virtual ~LzmaFileFdPrivate() { InternalClose(""); }
1872 #endif
1873 };
1874 /*}}}*/
1875 class APT_HIDDEN PipedFileFdPrivate: public FileFdPrivate /*{{{*/
1876 /* if we don't have a specific class dealing with library calls, we (un)compress
1877 by executing a specified binary and pipe in/out what we need */
1878 {
1879 public:
1880 virtual bool InternalOpen(int const, unsigned int const Mode) APT_OVERRIDE
1881 {
1882 // collect zombies here in case we reopen
1883 if (compressor_pid > 0)
1884 ExecWait(compressor_pid, "FileFdCompressor", true);
1885
1886 if ((Mode & FileFd::ReadWrite) == FileFd::ReadWrite)
1887 return filefd->FileFdError("ReadWrite mode is not supported for file %s", filefd->FileName.c_str());
1888 if (compressor.Binary == "false")
1889 return filefd->FileFdError("libapt has inbuilt support for the %s compression,"
1890 " but was forced to ignore it in favor of an external binary – which isn't installed.", compressor.Name.c_str());
1891
1892 bool const Comp = (Mode & FileFd::WriteOnly) == FileFd::WriteOnly;
1893 if (Comp == false)
1894 {
1895 // Handle 'decompression' of empty files
1896 struct stat Buf;
1897 fstat(filefd->iFd, &Buf);
1898 if (Buf.st_size == 0 && S_ISFIFO(Buf.st_mode) == false)
1899 return true;
1900
1901 // We don't need the file open - instead let the compressor open it
1902 // as he properly knows better how to efficiently read from 'his' file
1903 if (filefd->FileName.empty() == false)
1904 {
1905 close(filefd->iFd);
1906 filefd->iFd = -1;
1907 }
1908 }
1909
1910 // Create a data pipe
1911 int Pipe[2] = {-1,-1};
1912 if (pipe(Pipe) != 0)
1913 return filefd->FileFdErrno("pipe",_("Failed to create subprocess IPC"));
1914 for (int J = 0; J != 2; J++)
1915 SetCloseExec(Pipe[J],true);
1916
1917 compressed_fd = filefd->iFd;
1918 set_is_pipe(true);
1919
1920 if (Comp == true)
1921 filefd->iFd = Pipe[1];
1922 else
1923 filefd->iFd = Pipe[0];
1924
1925 // The child..
1926 compressor_pid = ExecFork();
1927 if (compressor_pid == 0)
1928 {
1929 if (Comp == true)
1930 {
1931 dup2(compressed_fd,STDOUT_FILENO);
1932 dup2(Pipe[0],STDIN_FILENO);
1933 }
1934 else
1935 {
1936 if (compressed_fd != -1)
1937 dup2(compressed_fd,STDIN_FILENO);
1938 dup2(Pipe[1],STDOUT_FILENO);
1939 }
1940 int const nullfd = open("/dev/null", O_WRONLY);
1941 if (nullfd != -1)
1942 {
1943 dup2(nullfd,STDERR_FILENO);
1944 close(nullfd);
1945 }
1946
1947 SetCloseExec(STDOUT_FILENO,false);
1948 SetCloseExec(STDIN_FILENO,false);
1949
1950 std::vector<char const*> Args;
1951 Args.push_back(compressor.Binary.c_str());
1952 std::vector<std::string> const * const addArgs =
1953 (Comp == true) ? &(compressor.CompressArgs) : &(compressor.UncompressArgs);
1954 for (std::vector<std::string>::const_iterator a = addArgs->begin();
1955 a != addArgs->end(); ++a)
1956 Args.push_back(a->c_str());
1957 if (Comp == false && filefd->FileName.empty() == false)
1958 {
1959 // commands not needing arguments, do not need to be told about using standard output
1960 // in reality, only testcases with tools like cat, rev, rot13, … are able to trigger this
1961 if (compressor.CompressArgs.empty() == false && compressor.UncompressArgs.empty() == false)
1962 Args.push_back("--stdout");
1963 if (filefd->TemporaryFileName.empty() == false)
1964 Args.push_back(filefd->TemporaryFileName.c_str());
1965 else
1966 Args.push_back(filefd->FileName.c_str());
1967 }
1968 Args.push_back(NULL);
1969
1970 execvp(Args[0],(char **)&Args[0]);
1971 cerr << _("Failed to exec compressor ") << Args[0] << endl;
1972 _exit(100);
1973 }
1974 if (Comp == true)
1975 close(Pipe[0]);
1976 else
1977 close(Pipe[1]);
1978
1979 return true;
1980 }
1981 virtual ssize_t InternalUnbufferedRead(void * const To, unsigned long long const Size) APT_OVERRIDE
1982 {
1983 return read(filefd->iFd, To, Size);
1984 }
1985 virtual ssize_t InternalWrite(void const * const From, unsigned long long const Size) APT_OVERRIDE
1986 {
1987 return write(filefd->iFd, From, Size);
1988 }
1989 virtual bool InternalClose(std::string const &) APT_OVERRIDE
1990 {
1991 bool Ret = true;
1992 if (filefd->iFd != -1)
1993 {
1994 close(filefd->iFd);
1995 filefd->iFd = -1;
1996 }
1997 if (compressor_pid > 0)
1998 Ret &= ExecWait(compressor_pid, "FileFdCompressor", true);
1999 compressor_pid = -1;
2000 return Ret;
2001 }
2002 explicit PipedFileFdPrivate(FileFd * const filefd) : FileFdPrivate(filefd) {}
2003 virtual ~PipedFileFdPrivate() { InternalClose(""); }
2004 };
2005 /*}}}*/
2006 class APT_HIDDEN DirectFileFdPrivate: public FileFdPrivate /*{{{*/
2007 {
2008 public:
2009 virtual bool InternalOpen(int const, unsigned int const) APT_OVERRIDE { return true; }
2010 virtual ssize_t InternalUnbufferedRead(void * const To, unsigned long long const Size) APT_OVERRIDE
2011 {
2012 return read(filefd->iFd, To, Size);
2013 }
2014 virtual ssize_t InternalWrite(void const * const From, unsigned long long const Size) APT_OVERRIDE
2015 {
2016 // files opened read+write are strange and only really "supported" for direct files
2017 if (buffer.size() != 0)
2018 {
2019 lseek(filefd->iFd, -buffer.size(), SEEK_CUR);
2020 buffer.reset();
2021 }
2022 return write(filefd->iFd, From, Size);
2023 }
2024 virtual bool InternalSeek(unsigned long long const To) APT_OVERRIDE
2025 {
2026 off_t const res = lseek(filefd->iFd, To, SEEK_SET);
2027 if (res != (off_t)To)
2028 return filefd->FileFdError("Unable to seek to %llu", To);
2029 seekpos = To;
2030 buffer.reset();
2031 return true;
2032 }
2033 virtual bool InternalSkip(unsigned long long Over) APT_OVERRIDE
2034 {
2035 if (Over >= buffer.size())
2036 {
2037 Over -= buffer.size();
2038 buffer.reset();
2039 }
2040 else
2041 {
2042 buffer.bufferstart += Over;
2043 return true;
2044 }
2045 if (Over == 0)
2046 return true;
2047 off_t const res = lseek(filefd->iFd, Over, SEEK_CUR);
2048 if (res < 0)
2049 return filefd->FileFdError("Unable to seek ahead %llu",Over);
2050 seekpos = res;
2051 return true;
2052 }
2053 virtual bool InternalTruncate(unsigned long long const To) APT_OVERRIDE
2054 {
2055 if (buffer.size() != 0)
2056 {
2057 unsigned long long const seekpos = lseek(filefd->iFd, 0, SEEK_CUR);
2058 if ((seekpos - buffer.size()) >= To)
2059 buffer.reset();
2060 else if (seekpos >= To)
2061 buffer.bufferend = (To - seekpos) + buffer.bufferstart;
2062 else
2063 buffer.reset();
2064 }
2065 if (ftruncate(filefd->iFd, To) != 0)
2066 return filefd->FileFdError("Unable to truncate to %llu",To);
2067 return true;
2068 }
2069 virtual unsigned long long InternalTell() APT_OVERRIDE
2070 {
2071 return lseek(filefd->iFd,0,SEEK_CUR) - buffer.size();
2072 }
2073 virtual unsigned long long InternalSize() APT_OVERRIDE
2074 {
2075 return filefd->FileSize();
2076 }
2077 virtual bool InternalClose(std::string const &) APT_OVERRIDE { return true; }
2078 virtual bool InternalAlwaysAutoClose() const APT_OVERRIDE { return false; }
2079
2080 explicit DirectFileFdPrivate(FileFd * const filefd) : FileFdPrivate(filefd) {}
2081 virtual ~DirectFileFdPrivate() { InternalClose(""); }
2082 };
2083 /*}}}*/
2084 // FileFd Constructors /*{{{*/
2085 FileFd::FileFd(std::string FileName,unsigned int const Mode,unsigned long AccessMode) : iFd(-1), Flags(0), d(NULL)
2086 {
2087 Open(FileName,Mode, None, AccessMode);
2088 }
2089 FileFd::FileFd(std::string FileName,unsigned int const Mode, CompressMode Compress, unsigned long AccessMode) : iFd(-1), Flags(0), d(NULL)
2090 {
2091 Open(FileName,Mode, Compress, AccessMode);
2092 }
2093 FileFd::FileFd() : iFd(-1), Flags(AutoClose), d(NULL) {}
2094 FileFd::FileFd(int const Fd, unsigned int const Mode, CompressMode Compress) : iFd(-1), Flags(0), d(NULL)
2095 {
2096 OpenDescriptor(Fd, Mode, Compress);
2097 }
2098 FileFd::FileFd(int const Fd, bool const AutoClose) : iFd(-1), Flags(0), d(NULL)
2099 {
2100 OpenDescriptor(Fd, ReadWrite, None, AutoClose);
2101 }
2102 /*}}}*/
2103 // FileFd::Open - Open a file /*{{{*/
2104 // ---------------------------------------------------------------------
2105 /* The most commonly used open mode combinations are given with Mode */
2106 bool FileFd::Open(string FileName,unsigned int const Mode,CompressMode Compress, unsigned long const AccessMode)
2107 {
2108 if (Mode == ReadOnlyGzip)
2109 return Open(FileName, ReadOnly, Gzip, AccessMode);
2110
2111 if (Compress == Auto && (Mode & WriteOnly) == WriteOnly)
2112 return FileFdError("Autodetection on %s only works in ReadOnly openmode!", FileName.c_str());
2113
2114 std::vector<APT::Configuration::Compressor> const compressors = APT::Configuration::getCompressors();
2115 std::vector<APT::Configuration::Compressor>::const_iterator compressor = compressors.begin();
2116 if (Compress == Auto)
2117 {
2118 for (; compressor != compressors.end(); ++compressor)
2119 {
2120 std::string file = FileName + compressor->Extension;
2121 if (FileExists(file) == false)
2122 continue;
2123 FileName = file;
2124 break;
2125 }
2126 }
2127 else if (Compress == Extension)
2128 {
2129 std::string::size_type const found = FileName.find_last_of('.');
2130 std::string ext;
2131 if (found != std::string::npos)
2132 {
2133 ext = FileName.substr(found);
2134 if (ext == ".new" || ext == ".bak")
2135 {
2136 std::string::size_type const found2 = FileName.find_last_of('.', found - 1);
2137 if (found2 != std::string::npos)
2138 ext = FileName.substr(found2, found - found2);
2139 else
2140 ext.clear();
2141 }
2142 }
2143 for (; compressor != compressors.end(); ++compressor)
2144 if (ext == compressor->Extension)
2145 break;
2146 // no matching extension - assume uncompressed (imagine files like 'example.org_Packages')
2147 if (compressor == compressors.end())
2148 for (compressor = compressors.begin(); compressor != compressors.end(); ++compressor)
2149 if (compressor->Name == ".")
2150 break;
2151 }
2152 else
2153 {
2154 std::string name;
2155 switch (Compress)
2156 {
2157 case None: name = "."; break;
2158 case Gzip: name = "gzip"; break;
2159 case Bzip2: name = "bzip2"; break;
2160 case Lzma: name = "lzma"; break;
2161 case Xz: name = "xz"; break;
2162 case Lz4: name = "lz4"; break;
2163 case Auto:
2164 case Extension:
2165 // Unreachable
2166 return FileFdError("Opening File %s in None, Auto or Extension should be already handled?!?", FileName.c_str());
2167 }
2168 for (; compressor != compressors.end(); ++compressor)
2169 if (compressor->Name == name)
2170 break;
2171 if (compressor == compressors.end())
2172 return FileFdError("Can't find a configured compressor %s for file %s", name.c_str(), FileName.c_str());
2173 }
2174
2175 if (compressor == compressors.end())
2176 return FileFdError("Can't find a match for specified compressor mode for file %s", FileName.c_str());
2177 return Open(FileName, Mode, *compressor, AccessMode);
2178 }
2179 bool FileFd::Open(string FileName,unsigned int const Mode,APT::Configuration::Compressor const &compressor, unsigned long const AccessMode)
2180 {
2181 Close();
2182 Flags = AutoClose;
2183
2184 if ((Mode & WriteOnly) != WriteOnly && (Mode & (Atomic | Create | Empty | Exclusive)) != 0)
2185 return FileFdError("ReadOnly mode for %s doesn't accept additional flags!", FileName.c_str());
2186 if ((Mode & ReadWrite) == 0)
2187 return FileFdError("No openmode provided in FileFd::Open for %s", FileName.c_str());
2188
2189 unsigned int OpenMode = Mode;
2190 if (FileName == "/dev/null")
2191 OpenMode = OpenMode & ~(Atomic | Exclusive | Create | Empty);
2192
2193 if ((OpenMode & Atomic) == Atomic)
2194 {
2195 Flags |= Replace;
2196 }
2197 else if ((OpenMode & (Exclusive | Create)) == (Exclusive | Create))
2198 {
2199 // for atomic, this will be done by rename in Close()
2200 RemoveFile("FileFd::Open", FileName);
2201 }
2202 if ((OpenMode & Empty) == Empty)
2203 {
2204 struct stat Buf;
2205 if (lstat(FileName.c_str(),&Buf) == 0 && S_ISLNK(Buf.st_mode))
2206 RemoveFile("FileFd::Open", FileName);
2207 }
2208
2209 int fileflags = 0;
2210 #define if_FLAGGED_SET(FLAG, MODE) if ((OpenMode & FLAG) == FLAG) fileflags |= MODE
2211 if_FLAGGED_SET(ReadWrite, O_RDWR);
2212 else if_FLAGGED_SET(ReadOnly, O_RDONLY);
2213 else if_FLAGGED_SET(WriteOnly, O_WRONLY);
2214
2215 if_FLAGGED_SET(Create, O_CREAT);
2216 if_FLAGGED_SET(Empty, O_TRUNC);
2217 if_FLAGGED_SET(Exclusive, O_EXCL);
2218 #undef if_FLAGGED_SET
2219
2220 if ((OpenMode & Atomic) == Atomic)
2221 {
2222 char *name = strdup((FileName + ".XXXXXX").c_str());
2223
2224 if((iFd = mkstemp(name)) == -1)
2225 {
2226 free(name);
2227 return FileFdErrno("mkstemp", "Could not create temporary file for %s", FileName.c_str());
2228 }
2229
2230 TemporaryFileName = string(name);
2231 free(name);
2232
2233 // umask() will always set the umask and return the previous value, so
2234 // we first set the umask and then reset it to the old value
2235 mode_t const CurrentUmask = umask(0);
2236 umask(CurrentUmask);
2237 // calculate the actual file permissions (just like open/creat)
2238 mode_t const FilePermissions = (AccessMode & ~CurrentUmask);
2239
2240 if(fchmod(iFd, FilePermissions) == -1)
2241 return FileFdErrno("fchmod", "Could not change permissions for temporary file %s", TemporaryFileName.c_str());
2242 }
2243 else
2244 iFd = open(FileName.c_str(), fileflags, AccessMode);
2245
2246 this->FileName = FileName;
2247 if (iFd == -1 || OpenInternDescriptor(OpenMode, compressor) == false)
2248 {
2249 if (iFd != -1)
2250 {
2251 close (iFd);
2252 iFd = -1;
2253 }
2254 return FileFdErrno("open",_("Could not open file %s"), FileName.c_str());
2255 }
2256
2257 SetCloseExec(iFd,true);
2258 return true;
2259 }
2260 /*}}}*/
2261 // FileFd::OpenDescriptor - Open a filedescriptor /*{{{*/
2262 bool FileFd::OpenDescriptor(int Fd, unsigned int const Mode, CompressMode Compress, bool AutoClose)
2263 {
2264 std::vector<APT::Configuration::Compressor> const compressors = APT::Configuration::getCompressors();
2265 std::vector<APT::Configuration::Compressor>::const_iterator compressor = compressors.begin();
2266 std::string name;
2267
2268 // compat with the old API
2269 if (Mode == ReadOnlyGzip && Compress == None)
2270 Compress = Gzip;
2271
2272 switch (Compress)
2273 {
2274 case None: name = "."; break;
2275 case Gzip: name = "gzip"; break;
2276 case Bzip2: name = "bzip2"; break;
2277 case Lzma: name = "lzma"; break;
2278 case Xz: name = "xz"; break;
2279 case Lz4: name = "lz4"; break;
2280 case Auto:
2281 case Extension:
2282 if (AutoClose == true && Fd != -1)
2283 close(Fd);
2284 return FileFdError("Opening Fd %d in Auto or Extension compression mode is not supported", Fd);
2285 }
2286 for (; compressor != compressors.end(); ++compressor)
2287 if (compressor->Name == name)
2288 break;
2289 if (compressor == compressors.end())
2290 {
2291 if (AutoClose == true && Fd != -1)
2292 close(Fd);
2293 return FileFdError("Can't find a configured compressor %s for file %s", name.c_str(), FileName.c_str());
2294 }
2295 return OpenDescriptor(Fd, Mode, *compressor, AutoClose);
2296 }
2297 bool FileFd::OpenDescriptor(int Fd, unsigned int const Mode, APT::Configuration::Compressor const &compressor, bool AutoClose)
2298 {
2299 Close();
2300 Flags = (AutoClose) ? FileFd::AutoClose : 0;
2301 iFd = Fd;
2302 this->FileName = "";
2303 if (OpenInternDescriptor(Mode, compressor) == false)
2304 {
2305 if (iFd != -1 && (
2306 (Flags & Compressed) == Compressed ||
2307 AutoClose == true))
2308 {
2309 close (iFd);
2310 iFd = -1;
2311 }
2312 return FileFdError(_("Could not open file descriptor %d"), Fd);
2313 }
2314 return true;
2315 }
2316 bool FileFd::OpenInternDescriptor(unsigned int const Mode, APT::Configuration::Compressor const &compressor)
2317 {
2318 if (iFd == -1)
2319 return false;
2320
2321 if (d != nullptr)
2322 d->InternalClose(FileName);
2323
2324 if (d == nullptr)
2325 {
2326 if (false)
2327 /* dummy so that the rest can be 'else if's */;
2328 #define APT_COMPRESS_INIT(NAME, CONSTRUCTOR) \
2329 else if (compressor.Name == NAME) \
2330 d = new CONSTRUCTOR(this)
2331 #ifdef HAVE_ZLIB
2332 APT_COMPRESS_INIT("gzip", GzipFileFdPrivate);
2333 #endif
2334 #ifdef HAVE_BZ2
2335 APT_COMPRESS_INIT("bzip2", Bz2FileFdPrivate);
2336 #endif
2337 #ifdef HAVE_LZMA
2338 APT_COMPRESS_INIT("xz", LzmaFileFdPrivate);
2339 APT_COMPRESS_INIT("lzma", LzmaFileFdPrivate);
2340 #endif
2341 #ifdef HAVE_LZ4
2342 APT_COMPRESS_INIT("lz4", Lz4FileFdPrivate);
2343 #endif
2344 #undef APT_COMPRESS_INIT
2345 else if (compressor.Name == "." || compressor.Binary.empty() == true)
2346 d = new DirectFileFdPrivate(this);
2347 else
2348 d = new PipedFileFdPrivate(this);
2349
2350 if (Mode & BufferedWrite)
2351 d = new BufferedWriteFileFdPrivate(d);
2352
2353 d->set_openmode(Mode);
2354 d->set_compressor(compressor);
2355 if ((Flags & AutoClose) != AutoClose && d->InternalAlwaysAutoClose())
2356 {
2357 // Need to duplicate fd here or gz/bz2 close for cleanup will close the fd as well
2358 int const internFd = dup(iFd);
2359 if (internFd == -1)
2360 return FileFdErrno("OpenInternDescriptor", _("Could not open file descriptor %d"), iFd);
2361 iFd = internFd;
2362 }
2363 }
2364 return d->InternalOpen(iFd, Mode);
2365 }
2366 /*}}}*/
2367 // FileFd::~File - Closes the file /*{{{*/
2368 // ---------------------------------------------------------------------
2369 /* If the proper modes are selected then we close the Fd and possibly
2370 unlink the file on error. */
2371 FileFd::~FileFd()
2372 {
2373 Close();
2374 if (d != NULL)
2375 d->InternalClose(FileName);
2376 delete d;
2377 d = NULL;
2378 }
2379 /*}}}*/
2380 // FileFd::Read - Read a bit of the file /*{{{*/
2381 // ---------------------------------------------------------------------
2382 /* We are careful to handle interruption by a signal while reading
2383 gracefully. */
2384 bool FileFd::Read(void *To,unsigned long long Size,unsigned long long *Actual)
2385 {
2386 if (d == nullptr)
2387 return false;
2388 ssize_t Res = 1;
2389 errno = 0;
2390 if (Actual != 0)
2391 *Actual = 0;
2392 *((char *)To) = '\0';
2393 while (Res > 0 && Size > 0)
2394 {
2395 Res = d->InternalRead(To, Size);
2396
2397 if (Res < 0)
2398 {
2399 if (errno == EINTR)
2400 {
2401 // trick the while-loop into running again
2402 Res = 1;
2403 errno = 0;
2404 continue;
2405 }
2406 return d->InternalReadError();
2407 }
2408
2409 To = (char *)To + Res;
2410 Size -= Res;
2411 if (d != NULL)
2412 d->set_seekpos(d->get_seekpos() + Res);
2413 if (Actual != 0)
2414 *Actual += Res;
2415 }
2416
2417 if (Size == 0)
2418 return true;
2419
2420 // Eof handling
2421 if (Actual != 0)
2422 {
2423 Flags |= HitEof;
2424 return true;
2425 }
2426
2427 return FileFdError(_("read, still have %llu to read but none left"), Size);
2428 }
2429 /*}}}*/
2430 // FileFd::ReadLine - Read a complete line from the file /*{{{*/
2431 // ---------------------------------------------------------------------
2432 /* Beware: This method can be quite slow for big buffers on UNcompressed
2433 files because of the naive implementation! */
2434 char* FileFd::ReadLine(char *To, unsigned long long const Size)
2435 {
2436 *To = '\0';
2437 if (d == nullptr)
2438 return nullptr;
2439 return d->InternalReadLine(To, Size);
2440 }
2441 /*}}}*/
2442 // FileFd::Flush - Flush the file /*{{{*/
2443 bool FileFd::Flush()
2444 {
2445 if (d == nullptr)
2446 return true;
2447
2448 return d->InternalFlush();
2449 }
2450 /*}}}*/
2451 // FileFd::Write - Write to the file /*{{{*/
2452 bool FileFd::Write(const void *From,unsigned long long Size)
2453 {
2454 if (d == nullptr)
2455 return false;
2456 ssize_t Res = 1;
2457 errno = 0;
2458 while (Res > 0 && Size > 0)
2459 {
2460 Res = d->InternalWrite(From, Size);
2461
2462 if (Res < 0)
2463 {
2464 if (errno == EINTR)
2465 {
2466 // trick the while-loop into running again
2467 Res = 1;
2468 errno = 0;
2469 continue;
2470 }
2471 return d->InternalWriteError();
2472 }
2473
2474 From = (char const *)From + Res;
2475 Size -= Res;
2476 if (d != NULL)
2477 d->set_seekpos(d->get_seekpos() + Res);
2478 }
2479
2480 if (Size == 0)
2481 return true;
2482
2483 return FileFdError(_("write, still have %llu to write but couldn't"), Size);
2484 }
2485 bool FileFd::Write(int Fd, const void *From, unsigned long long Size)
2486 {
2487 ssize_t Res = 1;
2488 errno = 0;
2489 while (Res > 0 && Size > 0)
2490 {
2491 Res = write(Fd,From,Size);
2492 if (Res < 0 && errno == EINTR)
2493 continue;
2494 if (Res < 0)
2495 return _error->Errno("write",_("Write error"));
2496
2497 From = (char const *)From + Res;
2498 Size -= Res;
2499 }
2500
2501 if (Size == 0)
2502 return true;
2503
2504 return _error->Error(_("write, still have %llu to write but couldn't"), Size);
2505 }
2506 /*}}}*/
2507 // FileFd::Seek - Seek in the file /*{{{*/
2508 bool FileFd::Seek(unsigned long long To)
2509 {
2510 if (d == nullptr)
2511 return false;
2512 Flags &= ~HitEof;
2513 return d->InternalSeek(To);
2514 }
2515 /*}}}*/
2516 // FileFd::Skip - Skip over data in the file /*{{{*/
2517 bool FileFd::Skip(unsigned long long Over)
2518 {
2519 if (d == nullptr)
2520 return false;
2521 return d->InternalSkip(Over);
2522 }
2523 /*}}}*/
2524 // FileFd::Truncate - Truncate the file /*{{{*/
2525 bool FileFd::Truncate(unsigned long long To)
2526 {
2527 if (d == nullptr)
2528 return false;
2529 // truncating /dev/null is always successful - as we get an error otherwise
2530 if (To == 0 && FileName == "/dev/null")
2531 return true;
2532 return d->InternalTruncate(To);
2533 }
2534 /*}}}*/
2535 // FileFd::Tell - Current seek position /*{{{*/
2536 // ---------------------------------------------------------------------
2537 /* */
2538 unsigned long long FileFd::Tell()
2539 {
2540 if (d == nullptr)
2541 return false;
2542 off_t const Res = d->InternalTell();
2543 if (Res == (off_t)-1)
2544 FileFdErrno("lseek","Failed to determine the current file position");
2545 d->set_seekpos(Res);
2546 return Res;
2547 }
2548 /*}}}*/
2549 static bool StatFileFd(char const * const msg, int const iFd, std::string const &FileName, struct stat &Buf, FileFdPrivate * const d) /*{{{*/
2550 {
2551 bool ispipe = (d != NULL && d->get_is_pipe() == true);
2552 if (ispipe == false)
2553 {
2554 if (fstat(iFd,&Buf) != 0)
2555 // higher-level code will generate more meaningful messages,
2556 // even translated this would be meaningless for users
2557 return _error->Errno("fstat", "Unable to determine %s for fd %i", msg, iFd);
2558 if (FileName.empty() == false)
2559 ispipe = S_ISFIFO(Buf.st_mode);
2560 }
2561
2562 // for compressor pipes st_size is undefined and at 'best' zero
2563 if (ispipe == true)
2564 {
2565 // we set it here, too, as we get the info here for free
2566 // in theory the Open-methods should take care of it already
2567 if (d != NULL)
2568 d->set_is_pipe(true);
2569 if (stat(FileName.c_str(), &Buf) != 0)
2570 return _error->Errno("fstat", "Unable to determine %s for file %s", msg, FileName.c_str());
2571 }
2572 return true;
2573 }
2574 /*}}}*/
2575 // FileFd::FileSize - Return the size of the file /*{{{*/
2576 unsigned long long FileFd::FileSize()
2577 {
2578 struct stat Buf;
2579 if (StatFileFd("file size", iFd, FileName, Buf, d) == false)
2580 {
2581 Flags |= Fail;
2582 return 0;
2583 }
2584 return Buf.st_size;
2585 }
2586 /*}}}*/
2587 // FileFd::ModificationTime - Return the time of last touch /*{{{*/
2588 time_t FileFd::ModificationTime()
2589 {
2590 struct stat Buf;
2591 if (StatFileFd("modification time", iFd, FileName, Buf, d) == false)
2592 {
2593 Flags |= Fail;
2594 return 0;
2595 }
2596 return Buf.st_mtime;
2597 }
2598 /*}}}*/
2599 // FileFd::Size - Return the size of the content in the file /*{{{*/
2600 unsigned long long FileFd::Size()
2601 {
2602 if (d == nullptr)
2603 return false;
2604 return d->InternalSize();
2605 }
2606 /*}}}*/
2607 // FileFd::Close - Close the file if the close flag is set /*{{{*/
2608 // ---------------------------------------------------------------------
2609 /* */
2610 bool FileFd::Close()
2611 {
2612 if (Failed() == false && Flush() == false)
2613 return false;
2614 if (iFd == -1)
2615 return true;
2616
2617 bool Res = true;
2618 if ((Flags & AutoClose) == AutoClose)
2619 {
2620 if ((Flags & Compressed) != Compressed && iFd > 0 && close(iFd) != 0)
2621 Res &= _error->Errno("close",_("Problem closing the file %s"), FileName.c_str());
2622 }
2623
2624 if (d != NULL)
2625 {
2626 Res &= d->InternalClose(FileName);
2627 delete d;
2628 d = NULL;
2629 }
2630
2631 if ((Flags & Replace) == Replace) {
2632 if (Failed() == false && rename(TemporaryFileName.c_str(), FileName.c_str()) != 0)
2633 Res &= _error->Errno("rename",_("Problem renaming the file %s to %s"), TemporaryFileName.c_str(), FileName.c_str());
2634
2635 FileName = TemporaryFileName; // for the unlink() below.
2636 TemporaryFileName.clear();
2637 }
2638
2639 iFd = -1;
2640
2641 if ((Flags & Fail) == Fail && (Flags & DelOnFail) == DelOnFail &&
2642 FileName.empty() == false)
2643 Res &= RemoveFile("FileFd::Close", FileName);
2644
2645 if (Res == false)
2646 Flags |= Fail;
2647 return Res;
2648 }
2649 /*}}}*/
2650 // FileFd::Sync - Sync the file /*{{{*/
2651 // ---------------------------------------------------------------------
2652 /* */
2653 bool FileFd::Sync()
2654 {
2655 if (fsync(iFd) != 0)
2656 return FileFdErrno("sync",_("Problem syncing the file"));
2657 return true;
2658 }
2659 /*}}}*/
2660 // FileFd::FileFdErrno - set Fail and call _error->Errno *{{{*/
2661 bool FileFd::FileFdErrno(const char *Function, const char *Description,...)
2662 {
2663 Flags |= Fail;
2664 va_list args;
2665 size_t msgSize = 400;
2666 int const errsv = errno;
2667 while (true)
2668 {
2669 va_start(args,Description);
2670 if (_error->InsertErrno(GlobalError::ERROR, Function, Description, args, errsv, msgSize) == false)
2671 break;
2672 va_end(args);
2673 }
2674 return false;
2675 }
2676 /*}}}*/
2677 // FileFd::FileFdError - set Fail and call _error->Error *{{{*/
2678 bool FileFd::FileFdError(const char *Description,...) {
2679 Flags |= Fail;
2680 va_list args;
2681 size_t msgSize = 400;
2682 while (true)
2683 {
2684 va_start(args,Description);
2685 if (_error->Insert(GlobalError::ERROR, Description, args, msgSize) == false)
2686 break;
2687 va_end(args);
2688 }
2689 return false;
2690 }
2691 /*}}}*/
2692 gzFile FileFd::gzFd() { /*{{{*/
2693 #ifdef HAVE_ZLIB
2694 GzipFileFdPrivate * const gzipd = dynamic_cast<GzipFileFdPrivate*>(d);
2695 if (gzipd == nullptr)
2696 return nullptr;
2697 else
2698 return gzipd->gz;
2699 #else
2700 return nullptr;
2701 #endif
2702 }
2703 /*}}}*/
2704
2705 // Glob - wrapper around "glob()" /*{{{*/
2706 std::vector<std::string> Glob(std::string const &pattern, int flags)
2707 {
2708 std::vector<std::string> result;
2709 glob_t globbuf;
2710 int glob_res;
2711 unsigned int i;
2712
2713 glob_res = glob(pattern.c_str(), flags, NULL, &globbuf);
2714
2715 if (glob_res != 0)
2716 {
2717 if(glob_res != GLOB_NOMATCH) {
2718 _error->Errno("glob", "Problem with glob");
2719 return result;
2720 }
2721 }
2722
2723 // append results
2724 for(i=0;i<globbuf.gl_pathc;i++)
2725 result.push_back(string(globbuf.gl_pathv[i]));
2726
2727 globfree(&globbuf);
2728 return result;
2729 }
2730 /*}}}*/
2731 std::string GetTempDir() /*{{{*/
2732 {
2733 const char *tmpdir = getenv("TMPDIR");
2734
2735 #ifdef P_tmpdir
2736 if (!tmpdir)
2737 tmpdir = P_tmpdir;
2738 #endif
2739
2740 struct stat st;
2741 if (!tmpdir || strlen(tmpdir) == 0 || // tmpdir is set
2742 stat(tmpdir, &st) != 0 || (st.st_mode & S_IFDIR) == 0) // exists and is directory
2743 tmpdir = "/tmp";
2744 else if (geteuid() != 0 && // root can do everything anyway
2745 faccessat(-1, tmpdir, R_OK | W_OK | X_OK, AT_EACCESS | AT_SYMLINK_NOFOLLOW) != 0) // current user has rwx access to directory
2746 tmpdir = "/tmp";
2747
2748 return string(tmpdir);
2749 }
2750 std::string GetTempDir(std::string const &User)
2751 {
2752 // no need/possibility to drop privs
2753 if(getuid() != 0 || User.empty() || User == "root")
2754 return GetTempDir();
2755
2756 struct passwd const * const pw = getpwnam(User.c_str());
2757 if (pw == NULL)
2758 return GetTempDir();
2759
2760 gid_t const old_euid = geteuid();
2761 gid_t const old_egid = getegid();
2762 if (setegid(pw->pw_gid) != 0)
2763 _error->Errno("setegid", "setegid %u failed", pw->pw_gid);
2764 if (seteuid(pw->pw_uid) != 0)
2765 _error->Errno("seteuid", "seteuid %u failed", pw->pw_uid);
2766
2767 std::string const tmp = GetTempDir();
2768
2769 if (seteuid(old_euid) != 0)
2770 _error->Errno("seteuid", "seteuid %u failed", old_euid);
2771 if (setegid(old_egid) != 0)
2772 _error->Errno("setegid", "setegid %u failed", old_egid);
2773
2774 return tmp;
2775 }
2776 /*}}}*/
2777 FileFd* GetTempFile(std::string const &Prefix, bool ImmediateUnlink, FileFd * const TmpFd) /*{{{*/
2778 {
2779 char fn[512];
2780 FileFd * const Fd = TmpFd == NULL ? new FileFd() : TmpFd;
2781
2782 std::string const tempdir = GetTempDir();
2783 snprintf(fn, sizeof(fn), "%s/%s.XXXXXX",
2784 tempdir.c_str(), Prefix.c_str());
2785 int const fd = mkstemp(fn);
2786 if(ImmediateUnlink)
2787 unlink(fn);
2788 if (fd < 0)
2789 {
2790 _error->Errno("GetTempFile",_("Unable to mkstemp %s"), fn);
2791 return NULL;
2792 }
2793 if (!Fd->OpenDescriptor(fd, FileFd::ReadWrite, FileFd::None, true))
2794 {
2795 _error->Errno("GetTempFile",_("Unable to write to %s"),fn);
2796 return NULL;
2797 }
2798 return Fd;
2799 }
2800 /*}}}*/
2801 bool Rename(std::string From, std::string To) /*{{{*/
2802 {
2803 if (rename(From.c_str(),To.c_str()) != 0)
2804 {
2805 _error->Error(_("rename failed, %s (%s -> %s)."),strerror(errno),
2806 From.c_str(),To.c_str());
2807 return false;
2808 }
2809 return true;
2810 }
2811 /*}}}*/
2812 bool Popen(const char* Args[], FileFd &Fd, pid_t &Child, FileFd::OpenMode Mode)/*{{{*/
2813 {
2814 int fd;
2815 if (Mode != FileFd::ReadOnly && Mode != FileFd::WriteOnly)
2816 return _error->Error("Popen supports ReadOnly (x)or WriteOnly mode only");
2817
2818 int Pipe[2] = {-1, -1};
2819 if(pipe(Pipe) != 0)
2820 return _error->Errno("pipe", _("Failed to create subprocess IPC"));
2821
2822 std::set<int> keep_fds;
2823 keep_fds.insert(Pipe[0]);
2824 keep_fds.insert(Pipe[1]);
2825 Child = ExecFork(keep_fds);
2826 if(Child < 0)
2827 return _error->Errno("fork", "Failed to fork");
2828 if(Child == 0)
2829 {
2830 if(Mode == FileFd::ReadOnly)
2831 {
2832 close(Pipe[0]);
2833 fd = Pipe[1];
2834 }
2835 else if(Mode == FileFd::WriteOnly)
2836 {
2837 close(Pipe[1]);
2838 fd = Pipe[0];
2839 }
2840
2841 if(Mode == FileFd::ReadOnly)
2842 {
2843 dup2(fd, 1);
2844 dup2(fd, 2);
2845 } else if(Mode == FileFd::WriteOnly)
2846 dup2(fd, 0);
2847
2848 execv(Args[0], (char**)Args);
2849 _exit(100);
2850 }
2851 if(Mode == FileFd::ReadOnly)
2852 {
2853 close(Pipe[1]);
2854 fd = Pipe[0];
2855 }
2856 else if(Mode == FileFd::WriteOnly)
2857 {
2858 close(Pipe[0]);
2859 fd = Pipe[1];
2860 }
2861 else
2862 return _error->Error("Popen supports ReadOnly (x)or WriteOnly mode only");
2863 Fd.OpenDescriptor(fd, Mode, FileFd::None, true);
2864
2865 return true;
2866 }
2867 /*}}}*/
2868 bool DropPrivileges() /*{{{*/
2869 {
2870 if(_config->FindB("Debug::NoDropPrivs", false) == true)
2871 return true;
2872
2873 #if __gnu_linux__
2874 #if defined(PR_SET_NO_NEW_PRIVS) && ( PR_SET_NO_NEW_PRIVS != 38 )
2875 #error "PR_SET_NO_NEW_PRIVS is defined, but with a different value than expected!"
2876 #endif
2877 // see prctl(2), needs linux3.5 at runtime - magic constant to avoid it at buildtime
2878 int ret = prctl(38, 1, 0, 0, 0);
2879 // ignore EINVAL - kernel is too old to understand the option
2880 if(ret < 0 && errno != EINVAL)
2881 _error->Warning("PR_SET_NO_NEW_PRIVS failed with %i", ret);
2882 #endif
2883
2884 // empty setting disables privilege dropping - this also ensures
2885 // backward compatibility, see bug #764506
2886 const std::string toUser = _config->Find("APT::Sandbox::User");
2887 if (toUser.empty() || toUser == "root")
2888 return true;
2889
2890 // a lot can go wrong trying to drop privileges completely,
2891 // so ideally we would like to verify that we have done it –
2892 // but the verify asks for too much in case of fakeroot (and alike)
2893 // [Specific checks can be overridden with dedicated options]
2894 bool const VerifySandboxing = _config->FindB("APT::Sandbox::Verify", false);
2895
2896 // uid will be 0 in the end, but gid might be different anyway
2897 uid_t const old_uid = getuid();
2898 gid_t const old_gid = getgid();
2899
2900 if (old_uid != 0)
2901 return true;
2902
2903 struct passwd *pw = getpwnam(toUser.c_str());
2904 if (pw == NULL)
2905 return _error->Error("No user %s, can not drop rights", toUser.c_str());
2906
2907 // Do not change the order here, it might break things
2908 // Get rid of all our supplementary groups first
2909 if (setgroups(1, &pw->pw_gid))
2910 return _error->Errno("setgroups", "Failed to setgroups");
2911
2912 // Now change the group ids to the new user
2913 #ifdef HAVE_SETRESGID
2914 if (setresgid(pw->pw_gid, pw->pw_gid, pw->pw_gid) != 0)
2915 return _error->Errno("setresgid", "Failed to set new group ids");
2916 #else
2917 if (setegid(pw->pw_gid) != 0)
2918 return _error->Errno("setegid", "Failed to setegid");
2919
2920 if (setgid(pw->pw_gid) != 0)
2921 return _error->Errno("setgid", "Failed to setgid");
2922 #endif
2923
2924 // Change the user ids to the new user
2925 #ifdef HAVE_SETRESUID
2926 if (setresuid(pw->pw_uid, pw->pw_uid, pw->pw_uid) != 0)
2927 return _error->Errno("setresuid", "Failed to set new user ids");
2928 #else
2929 if (setuid(pw->pw_uid) != 0)
2930 return _error->Errno("setuid", "Failed to setuid");
2931 if (seteuid(pw->pw_uid) != 0)
2932 return _error->Errno("seteuid", "Failed to seteuid");
2933 #endif
2934
2935 // disabled by default as fakeroot doesn't implement getgroups currently (#806521)
2936 if (VerifySandboxing == true || _config->FindB("APT::Sandbox::Verify::Groups", false) == true)
2937 {
2938 // Verify that the user isn't still in any supplementary groups
2939 long const ngroups_max = sysconf(_SC_NGROUPS_MAX);
2940 std::unique_ptr<gid_t[]> gidlist(new gid_t[ngroups_max]);
2941 if (unlikely(gidlist == NULL))
2942 return _error->Error("Allocation of a list of size %lu for getgroups failed", ngroups_max);
2943 ssize_t gidlist_nr;
2944 if ((gidlist_nr = getgroups(ngroups_max, gidlist.get())) < 0)
2945 return _error->Errno("getgroups", "Could not get new groups (%lu)", ngroups_max);
2946 for (ssize_t i = 0; i < gidlist_nr; ++i)
2947 if (gidlist[i] != pw->pw_gid)
2948 return _error->Error("Could not switch group, user %s is still in group %d", toUser.c_str(), gidlist[i]);
2949 }
2950
2951 // enabled by default as all fakeroot-lookalikes should fake that accordingly
2952 if (VerifySandboxing == true || _config->FindB("APT::Sandbox::Verify::IDs", true) == true)
2953 {
2954 // Verify that gid, egid, uid, and euid changed
2955 if (getgid() != pw->pw_gid)
2956 return _error->Error("Could not switch group");
2957 if (getegid() != pw->pw_gid)
2958 return _error->Error("Could not switch effective group");
2959 if (getuid() != pw->pw_uid)
2960 return _error->Error("Could not switch user");
2961 if (geteuid() != pw->pw_uid)
2962 return _error->Error("Could not switch effective user");
2963
2964 #ifdef HAVE_GETRESUID
2965 // verify that the saved set-user-id was changed as well
2966 uid_t ruid = 0;
2967 uid_t euid = 0;
2968 uid_t suid = 0;
2969 if (getresuid(&ruid, &euid, &suid))
2970 return _error->Errno("getresuid", "Could not get saved set-user-ID");
2971 if (suid != pw->pw_uid)
2972 return _error->Error("Could not switch saved set-user-ID");
2973 #endif
2974
2975 #ifdef HAVE_GETRESGID
2976 // verify that the saved set-group-id was changed as well
2977 gid_t rgid = 0;
2978 gid_t egid = 0;
2979 gid_t sgid = 0;
2980 if (getresgid(&rgid, &egid, &sgid))
2981 return _error->Errno("getresuid", "Could not get saved set-group-ID");
2982 if (sgid != pw->pw_gid)
2983 return _error->Error("Could not switch saved set-group-ID");
2984 #endif
2985 }
2986
2987 // disabled as fakeroot doesn't forbid (by design) (re)gaining root from unprivileged
2988 if (VerifySandboxing == true || _config->FindB("APT::Sandbox::Verify::Regain", false) == true)
2989 {
2990 // Check that uid and gid changes do not work anymore
2991 if (pw->pw_gid != old_gid && (setgid(old_gid) != -1 || setegid(old_gid) != -1))
2992 return _error->Error("Could restore a gid to root, privilege dropping did not work");
2993
2994 if (pw->pw_uid != old_uid && (setuid(old_uid) != -1 || seteuid(old_uid) != -1))
2995 return _error->Error("Could restore a uid to root, privilege dropping did not work");
2996 }
2997
2998 return true;
2999 }
3000 /*}}}*/