1 // -*- mode: cpp; mode: fold -*-
3 // $Id: fileutl.cc,v 1.42 2002/09/14 05:29:22 jgg Exp $
4 /* ######################################################################
8 CopyFile - Buffered copy of a single file
9 GetLock - dpkg compatible lock file manipulation (fcntl)
11 Most of this source is placed in the Public Domain, do with it what
13 It was originally written by Jason Gunthorpe <jgg@debian.org>.
14 FileFd gzip support added by Martin Pitt <martin.pitt@canonical.com>
16 The exception is RunScripts() it is under the GPLv2
18 ##################################################################### */
20 // Include Files /*{{{*/
23 #include <apt-pkg/fileutl.h>
24 #include <apt-pkg/strutl.h>
25 #include <apt-pkg/error.h>
26 #include <apt-pkg/sptr.h>
27 #include <apt-pkg/aptconfiguration.h>
28 #include <apt-pkg/configuration.h>
29 #include <apt-pkg/macros.h>
34 #include <sys/select.h>
65 #ifdef WORDS_BIGENDIAN
91 LZMAFILE() : file(NULL
), eof(false), compressing(false) {}
93 if (compressing
== true)
96 stream
.avail_out
= sizeof(buffer
)/sizeof(buffer
[0]);
97 stream
.next_out
= buffer
;
98 err
= lzma_code(&stream
, LZMA_FINISH
);
99 if (err
!= LZMA_OK
&& err
!= LZMA_STREAM_END
)
101 _error
->Error("~LZMAFILE: Compress finalisation failed");
104 size_t const n
= sizeof(buffer
)/sizeof(buffer
[0]) - stream
.avail_out
;
105 if (n
&& fwrite(buffer
, 1, n
, file
) != n
)
107 _error
->Errno("~LZMAFILE",_("Write error"));
110 if (err
== LZMA_STREAM_END
)
121 pid_t compressor_pid
;
123 APT::Configuration::Compressor compressor
;
124 unsigned int openmode
;
125 unsigned long long seekpos
;
136 compressed_fd(-1), compressor_pid(-1), pipe(false),
137 openmode(0), seekpos(0) {};
138 bool CloseDown(std::string
const &FileName
)
143 int const e
= gzclose(gz
);
145 // gzdclose() on empty files always fails with "buffer error" here, ignore that
146 if (e
!= 0 && e
!= Z_BUF_ERROR
)
147 Res
&= _error
->Errno("close",_("Problem closing the gzip file %s"), FileName
.c_str());
162 if (compressor_pid
> 0)
163 ExecWait(compressor_pid
, "FileFdCompressor", true);
168 ~FileFdPrivate() { CloseDown(""); }
171 // RunScripts - Run a set of scripts from a configuration subtree /*{{{*/
172 // ---------------------------------------------------------------------
174 bool RunScripts(const char *Cnf
)
176 Configuration::Item
const *Opts
= _config
->Tree(Cnf
);
177 if (Opts
== 0 || Opts
->Child
== 0)
181 // Fork for running the system calls
182 pid_t Child
= ExecFork();
187 if (_config
->FindDir("DPkg::Chroot-Directory","/") != "/")
189 std::cerr
<< "Chrooting into "
190 << _config
->FindDir("DPkg::Chroot-Directory")
192 if (chroot(_config
->FindDir("DPkg::Chroot-Directory","/").c_str()) != 0)
196 if (chdir("/tmp/") != 0)
199 unsigned int Count
= 1;
200 for (; Opts
!= 0; Opts
= Opts
->Next
, Count
++)
202 if (Opts
->Value
.empty() == true)
205 if (system(Opts
->Value
.c_str()) != 0)
211 // Wait for the child
213 while (waitpid(Child
,&Status
,0) != Child
)
217 return _error
->Errno("waitpid","Couldn't wait for subprocess");
220 // Restore sig int/quit
221 signal(SIGQUIT
,SIG_DFL
);
222 signal(SIGINT
,SIG_DFL
);
224 // Check for an error code.
225 if (WIFEXITED(Status
) == 0 || WEXITSTATUS(Status
) != 0)
227 unsigned int Count
= WEXITSTATUS(Status
);
231 for (; Opts
!= 0 && Count
!= 1; Opts
= Opts
->Next
, Count
--);
232 _error
->Error("Problem executing scripts %s '%s'",Cnf
,Opts
->Value
.c_str());
235 return _error
->Error("Sub-process returned an error code");
242 // CopyFile - Buffered copy of a file /*{{{*/
243 // ---------------------------------------------------------------------
244 /* The caller is expected to set things so that failure causes erasure */
245 bool CopyFile(FileFd
&From
,FileFd
&To
)
247 if (From
.IsOpen() == false || To
.IsOpen() == false ||
248 From
.Failed() == true || To
.Failed() == true)
251 // Buffered copy between fds
252 SPtrArray
<unsigned char> Buf
= new unsigned char[64000];
253 unsigned long long Size
= From
.Size();
256 unsigned long long ToRead
= Size
;
260 if (From
.Read(Buf
,ToRead
) == false ||
261 To
.Write(Buf
,ToRead
) == false)
270 // GetLock - Gets a lock file /*{{{*/
271 // ---------------------------------------------------------------------
272 /* This will create an empty file of the given name and lock it. Once this
273 is done all other calls to GetLock in any other process will fail with
274 -1. The return result is the fd of the file, the call should call
275 close at some time. */
276 int GetLock(string File
,bool Errors
)
278 // GetLock() is used in aptitude on directories with public-write access
279 // Use O_NOFOLLOW here to prevent symlink traversal attacks
280 int FD
= open(File
.c_str(),O_RDWR
| O_CREAT
| O_NOFOLLOW
,0640);
283 // Read only .. can't have locking problems there.
286 _error
->Warning(_("Not using locking for read only lock file %s"),File
.c_str());
287 return dup(0); // Need something for the caller to close
291 _error
->Errno("open",_("Could not open lock file %s"),File
.c_str());
293 // Feh.. We do this to distinguish the lock vs open case..
297 SetCloseExec(FD
,true);
299 // Acquire a write lock
302 fl
.l_whence
= SEEK_SET
;
305 if (fcntl(FD
,F_SETLK
,&fl
) == -1)
307 // always close to not leak resources
314 _error
->Warning(_("Not using locking for nfs mounted lock file %s"),File
.c_str());
315 return dup(0); // Need something for the caller to close
319 _error
->Errno("open",_("Could not get lock %s"),File
.c_str());
327 // FileExists - Check if a file exists /*{{{*/
328 // ---------------------------------------------------------------------
329 /* Beware: Directories are also files! */
330 bool FileExists(string File
)
333 if (stat(File
.c_str(),&Buf
) != 0)
338 // RealFileExists - Check if a file exists and if it is really a file /*{{{*/
339 // ---------------------------------------------------------------------
341 bool RealFileExists(string File
)
344 if (stat(File
.c_str(),&Buf
) != 0)
346 return ((Buf
.st_mode
& S_IFREG
) != 0);
349 // DirectoryExists - Check if a directory exists and is really one /*{{{*/
350 // ---------------------------------------------------------------------
352 bool DirectoryExists(string
const &Path
)
355 if (stat(Path
.c_str(),&Buf
) != 0)
357 return ((Buf
.st_mode
& S_IFDIR
) != 0);
360 // CreateDirectory - poor man's mkdir -p guarded by a parent directory /*{{{*/
361 // ---------------------------------------------------------------------
362 /* This method will create all directories needed for path in good old
363 mkdir -p style but refuses to do this if Parent is not a prefix of
364 this Path. Example: /var/cache/ and /var/cache/apt/archives are given,
365 so it will create apt/archives if /var/cache exists - on the other
366 hand if the parent is /var/lib the creation will fail as this path
367 is not a parent of the path to be generated. */
368 bool CreateDirectory(string
const &Parent
, string
const &Path
)
370 if (Parent
.empty() == true || Path
.empty() == true)
373 if (DirectoryExists(Path
) == true)
376 if (DirectoryExists(Parent
) == false)
379 // we are not going to create directories "into the blue"
380 if (Path
.compare(0, Parent
.length(), Parent
) != 0)
383 vector
<string
> const dirs
= VectorizeString(Path
.substr(Parent
.size()), '/');
384 string progress
= Parent
;
385 for (vector
<string
>::const_iterator d
= dirs
.begin(); d
!= dirs
.end(); ++d
)
387 if (d
->empty() == true)
390 progress
.append("/").append(*d
);
391 if (DirectoryExists(progress
) == true)
394 if (mkdir(progress
.c_str(), 0755) != 0)
400 // CreateAPTDirectoryIfNeeded - ensure that the given directory exists /*{{{*/
401 // ---------------------------------------------------------------------
402 /* a small wrapper around CreateDirectory to check if it exists and to
403 remove the trailing "/apt/" from the parent directory if needed */
404 bool CreateAPTDirectoryIfNeeded(string
const &Parent
, string
const &Path
)
406 if (DirectoryExists(Path
) == true)
409 size_t const len
= Parent
.size();
410 if (len
> 5 && Parent
.find("/apt/", len
- 6, 5) == len
- 5)
412 if (CreateDirectory(Parent
.substr(0,len
-5), Path
) == true)
415 else if (CreateDirectory(Parent
, Path
) == true)
421 // GetListOfFilesInDir - returns a vector of files in the given dir /*{{{*/
422 // ---------------------------------------------------------------------
423 /* If an extension is given only files with this extension are included
424 in the returned vector, otherwise every "normal" file is included. */
425 std::vector
<string
> GetListOfFilesInDir(string
const &Dir
, string
const &Ext
,
426 bool const &SortList
, bool const &AllowNoExt
)
428 std::vector
<string
> ext
;
430 if (Ext
.empty() == false)
432 if (AllowNoExt
== true && ext
.empty() == false)
434 return GetListOfFilesInDir(Dir
, ext
, SortList
);
436 std::vector
<string
> GetListOfFilesInDir(string
const &Dir
, std::vector
<string
> const &Ext
,
437 bool const &SortList
)
439 // Attention debuggers: need to be set with the environment config file!
440 bool const Debug
= _config
->FindB("Debug::GetListOfFilesInDir", false);
443 std::clog
<< "Accept in " << Dir
<< " only files with the following " << Ext
.size() << " extensions:" << std::endl
;
444 if (Ext
.empty() == true)
445 std::clog
<< "\tNO extension" << std::endl
;
447 for (std::vector
<string
>::const_iterator e
= Ext
.begin();
449 std::clog
<< '\t' << (e
->empty() == true ? "NO" : *e
) << " extension" << std::endl
;
452 std::vector
<string
> List
;
454 if (DirectoryExists(Dir
) == false)
456 _error
->Error(_("List of files can't be created as '%s' is not a directory"), Dir
.c_str());
460 Configuration::MatchAgainstConfig
SilentIgnore("Dir::Ignore-Files-Silently");
461 DIR *D
= opendir(Dir
.c_str());
464 _error
->Errno("opendir",_("Unable to read %s"),Dir
.c_str());
468 for (struct dirent
*Ent
= readdir(D
); Ent
!= 0; Ent
= readdir(D
))
470 // skip "hidden" files
471 if (Ent
->d_name
[0] == '.')
474 // Make sure it is a file and not something else
475 string
const File
= flCombine(Dir
,Ent
->d_name
);
476 #ifdef _DIRENT_HAVE_D_TYPE
477 if (Ent
->d_type
!= DT_REG
)
480 if (RealFileExists(File
) == false)
482 // do not show ignoration warnings for directories
484 #ifdef _DIRENT_HAVE_D_TYPE
485 Ent
->d_type
== DT_DIR
||
487 DirectoryExists(File
) == true)
489 if (SilentIgnore
.Match(Ent
->d_name
) == false)
490 _error
->Notice(_("Ignoring '%s' in directory '%s' as it is not a regular file"), Ent
->d_name
, Dir
.c_str());
495 // check for accepted extension:
496 // no extension given -> periods are bad as hell!
497 // extensions given -> "" extension allows no extension
498 if (Ext
.empty() == false)
500 string d_ext
= flExtension(Ent
->d_name
);
501 if (d_ext
== Ent
->d_name
) // no extension
503 if (std::find(Ext
.begin(), Ext
.end(), "") == Ext
.end())
506 std::clog
<< "Bad file: " << Ent
->d_name
<< " → no extension" << std::endl
;
507 if (SilentIgnore
.Match(Ent
->d_name
) == false)
508 _error
->Notice(_("Ignoring file '%s' in directory '%s' as it has no filename extension"), Ent
->d_name
, Dir
.c_str());
512 else if (std::find(Ext
.begin(), Ext
.end(), d_ext
) == Ext
.end())
515 std::clog
<< "Bad file: " << Ent
->d_name
<< " → bad extension »" << flExtension(Ent
->d_name
) << "«" << std::endl
;
516 if (SilentIgnore
.Match(Ent
->d_name
) == false)
517 _error
->Notice(_("Ignoring file '%s' in directory '%s' as it has an invalid filename extension"), Ent
->d_name
, Dir
.c_str());
522 // Skip bad filenames ala run-parts
523 const char *C
= Ent
->d_name
;
525 if (isalpha(*C
) == 0 && isdigit(*C
) == 0
526 && *C
!= '_' && *C
!= '-' && *C
!= ':') {
527 // no required extension -> dot is a bad character
528 if (*C
== '.' && Ext
.empty() == false)
533 // we don't reach the end of the name -> bad character included
537 std::clog
<< "Bad file: " << Ent
->d_name
<< " → bad character »"
538 << *C
<< "« in filename (period allowed: " << (Ext
.empty() ? "no" : "yes") << ")" << std::endl
;
542 // skip filenames which end with a period. These are never valid
546 std::clog
<< "Bad file: " << Ent
->d_name
<< " → Period as last character" << std::endl
;
551 std::clog
<< "Accept file: " << Ent
->d_name
<< " in " << Dir
<< std::endl
;
552 List
.push_back(File
);
556 if (SortList
== true)
557 std::sort(List
.begin(),List
.end());
560 std::vector
<string
> GetListOfFilesInDir(string
const &Dir
, bool SortList
)
562 bool const Debug
= _config
->FindB("Debug::GetListOfFilesInDir", false);
564 std::clog
<< "Accept in " << Dir
<< " all regular files" << std::endl
;
566 std::vector
<string
> List
;
568 if (DirectoryExists(Dir
) == false)
570 _error
->Error(_("List of files can't be created as '%s' is not a directory"), Dir
.c_str());
574 DIR *D
= opendir(Dir
.c_str());
577 _error
->Errno("opendir",_("Unable to read %s"),Dir
.c_str());
581 for (struct dirent
*Ent
= readdir(D
); Ent
!= 0; Ent
= readdir(D
))
583 // skip "hidden" files
584 if (Ent
->d_name
[0] == '.')
587 // Make sure it is a file and not something else
588 string
const File
= flCombine(Dir
,Ent
->d_name
);
589 #ifdef _DIRENT_HAVE_D_TYPE
590 if (Ent
->d_type
!= DT_REG
)
593 if (RealFileExists(File
) == false)
596 std::clog
<< "Bad file: " << Ent
->d_name
<< " → it is not a real file" << std::endl
;
601 // Skip bad filenames ala run-parts
602 const char *C
= Ent
->d_name
;
604 if (isalpha(*C
) == 0 && isdigit(*C
) == 0
605 && *C
!= '_' && *C
!= '-' && *C
!= '.')
608 // we don't reach the end of the name -> bad character included
612 std::clog
<< "Bad file: " << Ent
->d_name
<< " → bad character »" << *C
<< "« in filename" << std::endl
;
616 // skip filenames which end with a period. These are never valid
620 std::clog
<< "Bad file: " << Ent
->d_name
<< " → Period as last character" << std::endl
;
625 std::clog
<< "Accept file: " << Ent
->d_name
<< " in " << Dir
<< std::endl
;
626 List
.push_back(File
);
630 if (SortList
== true)
631 std::sort(List
.begin(),List
.end());
635 // SafeGetCWD - This is a safer getcwd that returns a dynamic string /*{{{*/
636 // ---------------------------------------------------------------------
637 /* We return / on failure. */
640 // Stash the current dir.
643 if (getcwd(S
,sizeof(S
)-2) == 0)
645 unsigned int Len
= strlen(S
);
651 // GetModificationTime - Get the mtime of the given file or -1 on error /*{{{*/
652 // ---------------------------------------------------------------------
653 /* We return / on failure. */
654 time_t GetModificationTime(string
const &Path
)
657 if (stat(Path
.c_str(), &St
) < 0)
662 // flNotDir - Strip the directory from the filename /*{{{*/
663 // ---------------------------------------------------------------------
665 string
flNotDir(string File
)
667 string::size_type Res
= File
.rfind('/');
668 if (Res
== string::npos
)
671 return string(File
,Res
,Res
- File
.length());
674 // flNotFile - Strip the file from the directory name /*{{{*/
675 // ---------------------------------------------------------------------
676 /* Result ends in a / */
677 string
flNotFile(string File
)
679 string::size_type Res
= File
.rfind('/');
680 if (Res
== string::npos
)
683 return string(File
,0,Res
);
686 // flExtension - Return the extension for the file /*{{{*/
687 // ---------------------------------------------------------------------
689 string
flExtension(string File
)
691 string::size_type Res
= File
.rfind('.');
692 if (Res
== string::npos
)
695 return string(File
,Res
,Res
- File
.length());
698 // flNoLink - If file is a symlink then deref it /*{{{*/
699 // ---------------------------------------------------------------------
700 /* If the name is not a link then the returned path is the input. */
701 string
flNoLink(string File
)
704 if (lstat(File
.c_str(),&St
) != 0 || S_ISLNK(St
.st_mode
) == 0)
706 if (stat(File
.c_str(),&St
) != 0)
709 /* Loop resolving the link. There is no need to limit the number of
710 loops because the stat call above ensures that the symlink is not
718 if ((Res
= readlink(NFile
.c_str(),Buffer
,sizeof(Buffer
))) <= 0 ||
719 (size_t)Res
>= sizeof(Buffer
))
722 // Append or replace the previous path
724 if (Buffer
[0] == '/')
727 NFile
= flNotFile(NFile
) + Buffer
;
729 // See if we are done
730 if (lstat(NFile
.c_str(),&St
) != 0)
732 if (S_ISLNK(St
.st_mode
) == 0)
737 // flCombine - Combine a file and a directory /*{{{*/
738 // ---------------------------------------------------------------------
739 /* If the file is an absolute path then it is just returned, otherwise
740 the directory is pre-pended to it. */
741 string
flCombine(string Dir
,string File
)
743 if (File
.empty() == true)
746 if (File
[0] == '/' || Dir
.empty() == true)
748 if (File
.length() >= 2 && File
[0] == '.' && File
[1] == '/')
750 if (Dir
[Dir
.length()-1] == '/')
752 return Dir
+ '/' + File
;
755 // SetCloseExec - Set the close on exec flag /*{{{*/
756 // ---------------------------------------------------------------------
758 void SetCloseExec(int Fd
,bool Close
)
760 if (fcntl(Fd
,F_SETFD
,(Close
== false)?0:FD_CLOEXEC
) != 0)
762 cerr
<< "FATAL -> Could not set close on exec " << strerror(errno
) << endl
;
767 // SetNonBlock - Set the nonblocking flag /*{{{*/
768 // ---------------------------------------------------------------------
770 void SetNonBlock(int Fd
,bool Block
)
772 int Flags
= fcntl(Fd
,F_GETFL
) & (~O_NONBLOCK
);
773 if (fcntl(Fd
,F_SETFL
,Flags
| ((Block
== false)?0:O_NONBLOCK
)) != 0)
775 cerr
<< "FATAL -> Could not set non-blocking flag " << strerror(errno
) << endl
;
780 // WaitFd - Wait for a FD to become readable /*{{{*/
781 // ---------------------------------------------------------------------
782 /* This waits for a FD to become readable using select. It is useful for
783 applications making use of non-blocking sockets. The timeout is
785 bool WaitFd(int Fd
,bool write
,unsigned long timeout
)
798 Res
= select(Fd
+1,0,&Set
,0,(timeout
!= 0?&tv
:0));
800 while (Res
< 0 && errno
== EINTR
);
810 Res
= select(Fd
+1,&Set
,0,0,(timeout
!= 0?&tv
:0));
812 while (Res
< 0 && errno
== EINTR
);
821 // MergeKeepFdsFromConfiguration - Merge APT::Keep-Fds configuration /*{{{*/
822 // ---------------------------------------------------------------------
823 /* This is used to merge the APT::Keep-Fds with the provided KeepFDs
826 void MergeKeepFdsFromConfiguration(std::set
<int> &KeepFDs
)
828 Configuration::Item
const *Opts
= _config
->Tree("APT::Keep-Fds");
829 if (Opts
!= 0 && Opts
->Child
!= 0)
832 for (; Opts
!= 0; Opts
= Opts
->Next
)
834 if (Opts
->Value
.empty() == true)
836 int fd
= atoi(Opts
->Value
.c_str());
842 // ExecFork - Magical fork that sanitizes the context before execing /*{{{*/
843 // ---------------------------------------------------------------------
844 /* This is used if you want to cleanse the environment for the forked
845 child, it fixes up the important signals and nukes all of the fds,
846 otherwise acts like normal fork. */
850 // we need to merge the Keep-Fds as external tools like
851 // debconf-apt-progress use it
852 MergeKeepFdsFromConfiguration(KeepFDs
);
853 return ExecFork(KeepFDs
);
856 pid_t
ExecFork(std::set
<int> KeepFDs
)
858 // Fork off the process
859 pid_t Process
= fork();
862 cerr
<< "FATAL -> Failed to fork." << endl
;
866 // Spawn the subprocess
870 signal(SIGPIPE
,SIG_DFL
);
871 signal(SIGQUIT
,SIG_DFL
);
872 signal(SIGINT
,SIG_DFL
);
873 signal(SIGWINCH
,SIG_DFL
);
874 signal(SIGCONT
,SIG_DFL
);
875 signal(SIGTSTP
,SIG_DFL
);
877 // Close all of our FDs - just in case
878 for (int K
= 3; K
!= sysconf(_SC_OPEN_MAX
); K
++)
880 if(KeepFDs
.find(K
) == KeepFDs
.end())
881 fcntl(K
,F_SETFD
,FD_CLOEXEC
);
888 // ExecWait - Fancy waitpid /*{{{*/
889 // ---------------------------------------------------------------------
890 /* Waits for the given sub process. If Reap is set then no errors are
891 generated. Otherwise a failed subprocess will generate a proper descriptive
893 bool ExecWait(pid_t Pid
,const char *Name
,bool Reap
)
898 // Wait and collect the error code
900 while (waitpid(Pid
,&Status
,0) != Pid
)
908 return _error
->Error(_("Waited for %s but it wasn't there"),Name
);
912 // Check for an error code.
913 if (WIFEXITED(Status
) == 0 || WEXITSTATUS(Status
) != 0)
917 if (WIFSIGNALED(Status
) != 0)
919 if( WTERMSIG(Status
) == SIGSEGV
)
920 return _error
->Error(_("Sub-process %s received a segmentation fault."),Name
);
922 return _error
->Error(_("Sub-process %s received signal %u."),Name
, WTERMSIG(Status
));
925 if (WIFEXITED(Status
) != 0)
926 return _error
->Error(_("Sub-process %s returned an error code (%u)"),Name
,WEXITSTATUS(Status
));
928 return _error
->Error(_("Sub-process %s exited unexpectedly"),Name
);
935 // FileFd::Open - Open a file /*{{{*/
936 // ---------------------------------------------------------------------
937 /* The most commonly used open mode combinations are given with Mode */
938 bool FileFd::Open(string FileName
,unsigned int const Mode
,CompressMode Compress
, unsigned long const Perms
)
940 if (Mode
== ReadOnlyGzip
)
941 return Open(FileName
, ReadOnly
, Gzip
, Perms
);
943 if (Compress
== Auto
&& (Mode
& WriteOnly
) == WriteOnly
)
944 return FileFdError("Autodetection on %s only works in ReadOnly openmode!", FileName
.c_str());
946 std::vector
<APT::Configuration::Compressor
> const compressors
= APT::Configuration::getCompressors();
947 std::vector
<APT::Configuration::Compressor
>::const_iterator compressor
= compressors
.begin();
948 if (Compress
== Auto
)
950 for (; compressor
!= compressors
.end(); ++compressor
)
952 std::string file
= FileName
+ compressor
->Extension
;
953 if (FileExists(file
) == false)
959 else if (Compress
== Extension
)
961 std::string::size_type
const found
= FileName
.find_last_of('.');
963 if (found
!= std::string::npos
)
965 ext
= FileName
.substr(found
);
966 if (ext
== ".new" || ext
== ".bak")
968 std::string::size_type
const found2
= FileName
.find_last_of('.', found
- 1);
969 if (found2
!= std::string::npos
)
970 ext
= FileName
.substr(found2
, found
- found2
);
975 for (; compressor
!= compressors
.end(); ++compressor
)
976 if (ext
== compressor
->Extension
)
978 // no matching extension - assume uncompressed (imagine files like 'example.org_Packages')
979 if (compressor
== compressors
.end())
980 for (compressor
= compressors
.begin(); compressor
!= compressors
.end(); ++compressor
)
981 if (compressor
->Name
== ".")
989 case None
: name
= "."; break;
990 case Gzip
: name
= "gzip"; break;
991 case Bzip2
: name
= "bzip2"; break;
992 case Lzma
: name
= "lzma"; break;
993 case Xz
: name
= "xz"; break;
997 return FileFdError("Opening File %s in None, Auto or Extension should be already handled?!?", FileName
.c_str());
999 for (; compressor
!= compressors
.end(); ++compressor
)
1000 if (compressor
->Name
== name
)
1002 if (compressor
== compressors
.end())
1003 return FileFdError("Can't find a configured compressor %s for file %s", name
.c_str(), FileName
.c_str());
1006 if (compressor
== compressors
.end())
1007 return FileFdError("Can't find a match for specified compressor mode for file %s", FileName
.c_str());
1008 return Open(FileName
, Mode
, *compressor
, Perms
);
1010 bool FileFd::Open(string FileName
,unsigned int const Mode
,APT::Configuration::Compressor
const &compressor
, unsigned long const Perms
)
1015 if ((Mode
& WriteOnly
) != WriteOnly
&& (Mode
& (Atomic
| Create
| Empty
| Exclusive
)) != 0)
1016 return FileFdError("ReadOnly mode for %s doesn't accept additional flags!", FileName
.c_str());
1017 if ((Mode
& ReadWrite
) == 0)
1018 return FileFdError("No openmode provided in FileFd::Open for %s", FileName
.c_str());
1020 if ((Mode
& Atomic
) == Atomic
)
1024 else if ((Mode
& (Exclusive
| Create
)) == (Exclusive
| Create
))
1026 // for atomic, this will be done by rename in Close()
1027 unlink(FileName
.c_str());
1029 if ((Mode
& Empty
) == Empty
)
1032 if (lstat(FileName
.c_str(),&Buf
) == 0 && S_ISLNK(Buf
.st_mode
))
1033 unlink(FileName
.c_str());
1037 #define if_FLAGGED_SET(FLAG, MODE) if ((Mode & FLAG) == FLAG) fileflags |= MODE
1038 if_FLAGGED_SET(ReadWrite
, O_RDWR
);
1039 else if_FLAGGED_SET(ReadOnly
, O_RDONLY
);
1040 else if_FLAGGED_SET(WriteOnly
, O_WRONLY
);
1042 if_FLAGGED_SET(Create
, O_CREAT
);
1043 if_FLAGGED_SET(Empty
, O_TRUNC
);
1044 if_FLAGGED_SET(Exclusive
, O_EXCL
);
1045 #undef if_FLAGGED_SET
1047 if ((Mode
& Atomic
) == Atomic
)
1049 char *name
= strdup((FileName
+ ".XXXXXX").c_str());
1051 if((iFd
= mkstemp(name
)) == -1)
1054 return FileFdErrno("mkstemp", "Could not create temporary file for %s", FileName
.c_str());
1057 TemporaryFileName
= string(name
);
1060 if(Perms
!= 600 && fchmod(iFd
, Perms
) == -1)
1061 return FileFdErrno("fchmod", "Could not change permissions for temporary file %s", TemporaryFileName
.c_str());
1064 iFd
= open(FileName
.c_str(), fileflags
, Perms
);
1066 this->FileName
= FileName
;
1067 if (iFd
== -1 || OpenInternDescriptor(Mode
, compressor
) == false)
1074 return FileFdErrno("open",_("Could not open file %s"), FileName
.c_str());
1077 SetCloseExec(iFd
,true);
1081 // FileFd::OpenDescriptor - Open a filedescriptor /*{{{*/
1082 // ---------------------------------------------------------------------
1084 bool FileFd::OpenDescriptor(int Fd
, unsigned int const Mode
, CompressMode Compress
, bool AutoClose
)
1086 std::vector
<APT::Configuration::Compressor
> const compressors
= APT::Configuration::getCompressors();
1087 std::vector
<APT::Configuration::Compressor
>::const_iterator compressor
= compressors
.begin();
1090 // compat with the old API
1091 if (Mode
== ReadOnlyGzip
&& Compress
== None
)
1096 case None
: name
= "."; break;
1097 case Gzip
: name
= "gzip"; break;
1098 case Bzip2
: name
= "bzip2"; break;
1099 case Lzma
: name
= "lzma"; break;
1100 case Xz
: name
= "xz"; break;
1103 if (AutoClose
== true && Fd
!= -1)
1105 return FileFdError("Opening Fd %d in Auto or Extension compression mode is not supported", Fd
);
1107 for (; compressor
!= compressors
.end(); ++compressor
)
1108 if (compressor
->Name
== name
)
1110 if (compressor
== compressors
.end())
1112 if (AutoClose
== true && Fd
!= -1)
1114 return FileFdError("Can't find a configured compressor %s for file %s", name
.c_str(), FileName
.c_str());
1116 return OpenDescriptor(Fd
, Mode
, *compressor
, AutoClose
);
1118 bool FileFd::OpenDescriptor(int Fd
, unsigned int const Mode
, APT::Configuration::Compressor
const &compressor
, bool AutoClose
)
1121 Flags
= (AutoClose
) ? FileFd::AutoClose
: 0;
1123 this->FileName
= "";
1124 if (OpenInternDescriptor(Mode
, compressor
) == false)
1127 (Flags
& Compressed
) == Compressed
||
1133 return FileFdError(_("Could not open file descriptor %d"), Fd
);
1137 bool FileFd::OpenInternDescriptor(unsigned int const Mode
, APT::Configuration::Compressor
const &compressor
)
1141 if (compressor
.Name
== "." || compressor
.Binary
.empty() == true)
1144 #if defined HAVE_ZLIB || defined HAVE_BZ2 || defined HAVE_LZMA
1145 // the API to open files is similar, so setup to avoid code duplicates later
1146 // and while at it ensure that we close before opening (if its a reopen)
1147 void* (*compress_open
)(int, const char *) = NULL
;
1149 /* dummy so that the rest can be 'else if's */;
1150 #define APT_COMPRESS_INIT(NAME,OPEN,CLOSE,STRUCT) \
1151 else if (compressor.Name == NAME) \
1153 compress_open = (void*(*)(int, const char *)) OPEN; \
1154 if (d != NULL && STRUCT != NULL) { CLOSE(STRUCT); STRUCT = NULL; } \
1157 APT_COMPRESS_INIT("gzip", gzdopen
, gzclose
, d
->gz
)
1160 APT_COMPRESS_INIT("bzip2", BZ2_bzdopen
, BZ2_bzclose
, d
->bz2
)
1163 else if (compressor
.Name
== "xz" || compressor
.Name
== "lzma")
1165 compress_open
= (void*(*)(int, const char*)) fdopen
;
1166 if (d
!= NULL
&& d
->lzma
!= NULL
)
1173 #undef APT_COMPRESS_INIT
1178 d
= new FileFdPrivate();
1180 d
->compressor
= compressor
;
1181 #if defined HAVE_ZLIB || defined HAVE_BZ2 || defined HAVE_LZMA
1182 if (AutoClose
== false && compress_open
!= NULL
)
1184 // Need to duplicate fd here or gz/bz2 close for cleanup will close the fd as well
1185 int const internFd
= dup(iFd
);
1187 return FileFdErrno("OpenInternDescriptor", _("Could not open file descriptor %d"), iFd
);
1193 #if defined HAVE_ZLIB || defined HAVE_BZ2 || defined HAVE_LZMA
1194 if (compress_open
!= NULL
)
1196 void* compress_struct
= NULL
;
1197 if ((Mode
& ReadWrite
) == ReadWrite
)
1198 compress_struct
= compress_open(iFd
, "r+");
1199 else if ((Mode
& WriteOnly
) == WriteOnly
)
1200 compress_struct
= compress_open(iFd
, "w");
1202 compress_struct
= compress_open(iFd
, "r");
1203 if (compress_struct
== NULL
)
1207 /* dummy so that the rest can be 'else if's */;
1209 else if (compressor
.Name
== "gzip")
1210 d
->gz
= (gzFile
) compress_struct
;
1213 else if (compressor
.Name
== "bzip2")
1214 d
->bz2
= (BZFILE
*) compress_struct
;
1217 else if (compressor
.Name
== "xz" || compressor
.Name
== "lzma")
1219 uint32_t const xzlevel
= 6;
1220 uint64_t const memlimit
= UINT64_MAX
;
1221 if (d
->lzma
== NULL
)
1222 d
->lzma
= new FileFdPrivate::LZMAFILE
;
1223 d
->lzma
->file
= (FILE*) compress_struct
;
1224 d
->lzma
->stream
= LZMA_STREAM_INIT
;
1226 if ((Mode
& ReadWrite
) == ReadWrite
)
1227 return FileFdError("ReadWrite mode is not supported for file %s", FileName
.c_str());
1229 if ((Mode
& WriteOnly
) == WriteOnly
)
1231 if (compressor
.Name
== "xz")
1233 if (lzma_easy_encoder(&d
->lzma
->stream
, xzlevel
, LZMA_CHECK_CRC32
) != LZMA_OK
)
1238 lzma_options_lzma options
;
1239 lzma_lzma_preset(&options
, xzlevel
);
1240 if (lzma_alone_encoder(&d
->lzma
->stream
, &options
) != LZMA_OK
)
1243 d
->lzma
->compressing
= true;
1247 if (compressor
.Name
== "xz")
1249 if (lzma_auto_decoder(&d
->lzma
->stream
, memlimit
, 0) != LZMA_OK
)
1254 if (lzma_alone_decoder(&d
->lzma
->stream
, memlimit
) != LZMA_OK
)
1257 d
->lzma
->compressing
= false;
1261 Flags
|= Compressed
;
1266 // collect zombies here in case we reopen
1267 if (d
->compressor_pid
> 0)
1268 ExecWait(d
->compressor_pid
, "FileFdCompressor", true);
1270 if ((Mode
& ReadWrite
) == ReadWrite
)
1271 return FileFdError("ReadWrite mode is not supported for file %s", FileName
.c_str());
1273 bool const Comp
= (Mode
& WriteOnly
) == WriteOnly
;
1276 // Handle 'decompression' of empty files
1279 if (Buf
.st_size
== 0 && S_ISFIFO(Buf
.st_mode
) == false)
1282 // We don't need the file open - instead let the compressor open it
1283 // as he properly knows better how to efficiently read from 'his' file
1284 if (FileName
.empty() == false)
1291 // Create a data pipe
1292 int Pipe
[2] = {-1,-1};
1293 if (pipe(Pipe
) != 0)
1294 return FileFdErrno("pipe",_("Failed to create subprocess IPC"));
1295 for (int J
= 0; J
!= 2; J
++)
1296 SetCloseExec(Pipe
[J
],true);
1298 d
->compressed_fd
= iFd
;
1307 d
->compressor_pid
= ExecFork();
1308 if (d
->compressor_pid
== 0)
1312 dup2(d
->compressed_fd
,STDOUT_FILENO
);
1313 dup2(Pipe
[0],STDIN_FILENO
);
1317 if (d
->compressed_fd
!= -1)
1318 dup2(d
->compressed_fd
,STDIN_FILENO
);
1319 dup2(Pipe
[1],STDOUT_FILENO
);
1321 int const nullfd
= open("/dev/null", O_WRONLY
);
1324 dup2(nullfd
,STDERR_FILENO
);
1328 SetCloseExec(STDOUT_FILENO
,false);
1329 SetCloseExec(STDIN_FILENO
,false);
1331 std::vector
<char const*> Args
;
1332 Args
.push_back(compressor
.Binary
.c_str());
1333 std::vector
<std::string
> const * const addArgs
=
1334 (Comp
== true) ? &(compressor
.CompressArgs
) : &(compressor
.UncompressArgs
);
1335 for (std::vector
<std::string
>::const_iterator a
= addArgs
->begin();
1336 a
!= addArgs
->end(); ++a
)
1337 Args
.push_back(a
->c_str());
1338 if (Comp
== false && FileName
.empty() == false)
1340 Args
.push_back("--stdout");
1341 if (TemporaryFileName
.empty() == false)
1342 Args
.push_back(TemporaryFileName
.c_str());
1344 Args
.push_back(FileName
.c_str());
1346 Args
.push_back(NULL
);
1348 execvp(Args
[0],(char **)&Args
[0]);
1349 cerr
<< _("Failed to exec compressor ") << Args
[0] << endl
;
1360 // FileFd::~File - Closes the file /*{{{*/
1361 // ---------------------------------------------------------------------
1362 /* If the proper modes are selected then we close the Fd and possibly
1363 unlink the file on error. */
1368 d
->CloseDown(FileName
);
1373 // FileFd::Read - Read a bit of the file /*{{{*/
1374 // ---------------------------------------------------------------------
1375 /* We are careful to handle interruption by a signal while reading
1377 bool FileFd::Read(void *To
,unsigned long long Size
,unsigned long long *Actual
)
1383 *((char *)To
) = '\0';
1387 /* dummy so that the rest can be 'else if's */;
1389 else if (d
!= NULL
&& d
->gz
!= NULL
)
1390 Res
= gzread(d
->gz
,To
,Size
);
1393 else if (d
!= NULL
&& d
->bz2
!= NULL
)
1394 Res
= BZ2_bzread(d
->bz2
,To
,Size
);
1397 else if (d
!= NULL
&& d
->lzma
!= NULL
)
1399 if (d
->lzma
->eof
== true)
1402 d
->lzma
->stream
.next_out
= (uint8_t *) To
;
1403 d
->lzma
->stream
.avail_out
= Size
;
1404 if (d
->lzma
->stream
.avail_in
== 0)
1406 d
->lzma
->stream
.next_in
= d
->lzma
->buffer
;
1407 d
->lzma
->stream
.avail_in
= fread(d
->lzma
->buffer
, 1, sizeof(d
->lzma
->buffer
)/sizeof(d
->lzma
->buffer
[0]), d
->lzma
->file
);
1409 d
->lzma
->err
= lzma_code(&d
->lzma
->stream
, LZMA_RUN
);
1410 if (d
->lzma
->err
== LZMA_STREAM_END
)
1412 d
->lzma
->eof
= true;
1413 Res
= Size
- d
->lzma
->stream
.avail_out
;
1415 else if (d
->lzma
->err
!= LZMA_OK
)
1421 Res
= Size
- d
->lzma
->stream
.avail_out
;
1425 Res
= read(iFd
,To
,Size
);
1432 /* dummy so that the rest can be 'else if's */;
1434 else if (d
!= NULL
&& d
->gz
!= NULL
)
1437 char const * const errmsg
= gzerror(d
->gz
, &err
);
1439 return FileFdError("gzread: %s (%d: %s)", _("Read error"), err
, errmsg
);
1443 else if (d
!= NULL
&& d
->bz2
!= NULL
)
1446 char const * const errmsg
= BZ2_bzerror(d
->bz2
, &err
);
1447 if (err
!= BZ_IO_ERROR
)
1448 return FileFdError("BZ2_bzread: %s (%d: %s)", _("Read error"), err
, errmsg
);
1452 else if (d
!= NULL
&& d
->lzma
!= NULL
)
1453 return FileFdError("lzma_read: %s (%d)", _("Read error"), d
->lzma
->err
);
1455 return FileFdErrno("read",_("Read error"));
1458 To
= (char *)To
+ Res
;
1465 while (Res
> 0 && Size
> 0);
1477 return FileFdError(_("read, still have %llu to read but none left"), Size
);
1480 // FileFd::ReadLine - Read a complete line from the file /*{{{*/
1481 // ---------------------------------------------------------------------
1482 /* Beware: This method can be quiet slow for big buffers on UNcompressed
1483 files because of the naive implementation! */
1484 char* FileFd::ReadLine(char *To
, unsigned long long const Size
)
1488 if (d
!= NULL
&& d
->gz
!= NULL
)
1489 return gzgets(d
->gz
, To
, Size
);
1492 unsigned long long read
= 0;
1493 while ((Size
- 1) != read
)
1495 unsigned long long done
= 0;
1496 if (Read(To
+ read
, 1, &done
) == false)
1500 if (To
[read
++] == '\n')
1509 // FileFd::Write - Write to the file /*{{{*/
1510 // ---------------------------------------------------------------------
1512 bool FileFd::Write(const void *From
,unsigned long long Size
)
1519 /* dummy so that the rest can be 'else if's */;
1521 else if (d
!= NULL
&& d
->gz
!= NULL
)
1522 Res
= gzwrite(d
->gz
,From
,Size
);
1525 else if (d
!= NULL
&& d
->bz2
!= NULL
)
1526 Res
= BZ2_bzwrite(d
->bz2
,(void*)From
,Size
);
1529 else if (d
!= NULL
&& d
->lzma
!= NULL
)
1531 d
->lzma
->stream
.next_in
= (uint8_t *)From
;
1532 d
->lzma
->stream
.avail_in
= Size
;
1533 d
->lzma
->stream
.next_out
= d
->lzma
->buffer
;
1534 d
->lzma
->stream
.avail_out
= sizeof(d
->lzma
->buffer
)/sizeof(d
->lzma
->buffer
[0]);
1535 d
->lzma
->err
= lzma_code(&d
->lzma
->stream
, LZMA_RUN
);
1536 if (d
->lzma
->err
!= LZMA_OK
)
1538 size_t const n
= sizeof(d
->lzma
->buffer
)/sizeof(d
->lzma
->buffer
[0]) - d
->lzma
->stream
.avail_out
;
1539 size_t const m
= (n
== 0) ? 0 : fwrite(d
->lzma
->buffer
, 1, n
, d
->lzma
->file
);
1543 Res
= Size
- d
->lzma
->stream
.avail_in
;
1547 Res
= write(iFd
,From
,Size
);
1549 if (Res
< 0 && errno
== EINTR
)
1554 /* dummy so that the rest can be 'else if's */;
1556 else if (d
!= NULL
&& d
->gz
!= NULL
)
1559 char const * const errmsg
= gzerror(d
->gz
, &err
);
1561 return FileFdError("gzwrite: %s (%d: %s)", _("Write error"), err
, errmsg
);
1565 else if (d
!= NULL
&& d
->bz2
!= NULL
)
1568 char const * const errmsg
= BZ2_bzerror(d
->bz2
, &err
);
1569 if (err
!= BZ_IO_ERROR
)
1570 return FileFdError("BZ2_bzwrite: %s (%d: %s)", _("Write error"), err
, errmsg
);
1574 else if (d
!= NULL
&& d
->lzma
!= NULL
)
1575 return FileFdErrno("lzma_fwrite", _("Write error"));
1577 return FileFdErrno("write",_("Write error"));
1580 From
= (char const *)From
+ Res
;
1585 while (Res
> 0 && Size
> 0);
1590 return FileFdError(_("write, still have %llu to write but couldn't"), Size
);
1592 bool FileFd::Write(int Fd
, const void *From
, unsigned long long Size
)
1598 Res
= write(Fd
,From
,Size
);
1599 if (Res
< 0 && errno
== EINTR
)
1602 return _error
->Errno("write",_("Write error"));
1604 From
= (char const *)From
+ Res
;
1607 while (Res
> 0 && Size
> 0);
1612 return _error
->Error(_("write, still have %llu to write but couldn't"), Size
);
1615 // FileFd::Seek - Seek in the file /*{{{*/
1616 // ---------------------------------------------------------------------
1618 bool FileFd::Seek(unsigned long long To
)
1620 if (d
!= NULL
&& (d
->pipe
== true
1629 // Our poor man seeking in pipes is costly, so try to avoid it
1630 unsigned long long seekpos
= Tell();
1633 else if (seekpos
< To
)
1634 return Skip(To
- seekpos
);
1636 if ((d
->openmode
& ReadOnly
) != ReadOnly
)
1637 return FileFdError("Reopen is only implemented for read-only files!");
1639 /* dummy so that the rest can be 'else if's */;
1641 else if (d
->bz2
!= NULL
)
1643 BZ2_bzclose(d
->bz2
);
1648 else if (d
->lzma
!= NULL
)
1657 if (TemporaryFileName
.empty() == false)
1658 iFd
= open(TemporaryFileName
.c_str(), O_RDONLY
);
1659 else if (FileName
.empty() == false)
1660 iFd
= open(FileName
.c_str(), O_RDONLY
);
1663 if (d
->compressed_fd
> 0)
1664 if (lseek(d
->compressed_fd
, 0, SEEK_SET
) != 0)
1665 iFd
= d
->compressed_fd
;
1667 return FileFdError("Reopen is not implemented for pipes opened with FileFd::OpenDescriptor()!");
1670 if (OpenInternDescriptor(d
->openmode
, d
->compressor
) == false)
1671 return FileFdError("Seek on file %s because it couldn't be reopened", FileName
.c_str());
1681 if (d
!= NULL
&& d
->gz
)
1682 res
= gzseek(d
->gz
,To
,SEEK_SET
);
1685 res
= lseek(iFd
,To
,SEEK_SET
);
1686 if (res
!= (off_t
)To
)
1687 return FileFdError("Unable to seek to %llu", To
);
1694 // FileFd::Skip - Seek in the file /*{{{*/
1695 // ---------------------------------------------------------------------
1697 bool FileFd::Skip(unsigned long long Over
)
1699 if (d
!= NULL
&& (d
->pipe
== true
1712 unsigned long long toread
= std::min((unsigned long long) sizeof(buffer
), Over
);
1713 if (Read(buffer
, toread
) == false)
1714 return FileFdError("Unable to seek ahead %llu",Over
);
1722 if (d
!= NULL
&& d
->gz
!= NULL
)
1723 res
= gzseek(d
->gz
,Over
,SEEK_CUR
);
1726 res
= lseek(iFd
,Over
,SEEK_CUR
);
1728 return FileFdError("Unable to seek ahead %llu",Over
);
1735 // FileFd::Truncate - Truncate the file /*{{{*/
1736 // ---------------------------------------------------------------------
1738 bool FileFd::Truncate(unsigned long long To
)
1740 // truncating /dev/null is always successful - as we get an error otherwise
1741 if (To
== 0 && FileName
== "/dev/null")
1743 #if defined HAVE_ZLIB || defined HAVE_BZ2 || defined HAVE_LZMA
1755 return FileFdError("Truncating compressed files is not implemented (%s)", FileName
.c_str());
1757 if (ftruncate(iFd
,To
) != 0)
1758 return FileFdError("Unable to truncate to %llu",To
);
1763 // FileFd::Tell - Current seek position /*{{{*/
1764 // ---------------------------------------------------------------------
1766 unsigned long long FileFd::Tell()
1768 // In theory, we could just return seekpos here always instead of
1769 // seeking around, but not all users of FileFd use always Seek() and co
1770 // so d->seekpos isn't always true and we can just use it as a hint if
1771 // we have nothing else, but not always as an authority…
1772 if (d
!= NULL
&& (d
->pipe
== true
1784 if (d
!= NULL
&& d
->gz
!= NULL
)
1785 Res
= gztell(d
->gz
);
1788 Res
= lseek(iFd
,0,SEEK_CUR
);
1789 if (Res
== (off_t
)-1)
1790 FileFdErrno("lseek","Failed to determine the current file position");
1796 static bool StatFileFd(char const * const msg
, int const iFd
, std::string
const &FileName
, struct stat
&Buf
, FileFdPrivate
* const d
) /*{{{*/
1798 bool ispipe
= (d
!= NULL
&& d
->pipe
== true);
1799 if (ispipe
== false)
1801 if (fstat(iFd
,&Buf
) != 0)
1802 // higher-level code will generate more meaningful messages,
1803 // even translated this would be meaningless for users
1804 return _error
->Errno("fstat", "Unable to determine %s for fd %i", msg
, iFd
);
1805 ispipe
= S_ISFIFO(Buf
.st_mode
);
1808 // for compressor pipes st_size is undefined and at 'best' zero
1811 // we set it here, too, as we get the info here for free
1812 // in theory the Open-methods should take care of it already
1815 if (stat(FileName
.c_str(), &Buf
) != 0)
1816 return _error
->Errno("fstat", "Unable to determine %s for file %s", msg
, FileName
.c_str());
1821 // FileFd::FileSize - Return the size of the file /*{{{*/
1822 unsigned long long FileFd::FileSize()
1825 if (StatFileFd("file size", iFd
, FileName
, Buf
, d
) == false)
1833 // FileFd::ModificationTime - Return the time of last touch /*{{{*/
1834 time_t FileFd::ModificationTime()
1837 if (StatFileFd("modification time", iFd
, FileName
, Buf
, d
) == false)
1842 return Buf
.st_mtime
;
1845 // FileFd::Size - Return the size of the content in the file /*{{{*/
1846 // ---------------------------------------------------------------------
1848 unsigned long long FileFd::Size()
1850 unsigned long long size
= FileSize();
1852 // for compressor pipes st_size is undefined and at 'best' zero,
1853 // so we 'read' the content and 'seek' back - see there
1854 if (d
!= NULL
&& (d
->pipe
== true
1856 || (d
->bz2
&& size
> 0)
1859 || (d
->lzma
&& size
> 0)
1863 unsigned long long const oldSeek
= Tell();
1865 unsigned long long read
= 0;
1867 if (Read(ignore
, sizeof(ignore
), &read
) == false)
1877 // only check gzsize if we are actually a gzip file, just checking for
1878 // "gz" is not sufficient as uncompressed files could be opened with
1879 // gzopen in "direct" mode as well
1880 else if (d
!= NULL
&& d
->gz
&& !gzdirect(d
->gz
) && size
> 0)
1882 off_t
const oldPos
= lseek(iFd
,0,SEEK_CUR
);
1883 /* unfortunately zlib.h doesn't provide a gzsize(), so we have to do
1884 * this ourselves; the original (uncompressed) file size is the last 32
1885 * bits of the file */
1886 // FIXME: Size for gz-files is limited by 32bit… no largefile support
1887 if (lseek(iFd
, -4, SEEK_END
) < 0)
1889 FileFdErrno("lseek","Unable to seek to end of gzipped file");
1893 if (read(iFd
, &size
, 4) != 4)
1895 FileFdErrno("read","Unable to read original size of gzipped file");
1899 #ifdef WORDS_BIGENDIAN
1900 uint32_t tmp_size
= size
;
1901 uint8_t const * const p
= (uint8_t const * const) &tmp_size
;
1902 tmp_size
= (p
[3] << 24) | (p
[2] << 16) | (p
[1] << 8) | p
[0];
1906 if (lseek(iFd
, oldPos
, SEEK_SET
) < 0)
1908 FileFdErrno("lseek","Unable to seek in gzipped file");
1919 // FileFd::Close - Close the file if the close flag is set /*{{{*/
1920 // ---------------------------------------------------------------------
1922 bool FileFd::Close()
1928 if ((Flags
& AutoClose
) == AutoClose
)
1930 if ((Flags
& Compressed
) != Compressed
&& iFd
> 0 && close(iFd
) != 0)
1931 Res
&= _error
->Errno("close",_("Problem closing the file %s"), FileName
.c_str());
1935 Res
&= d
->CloseDown(FileName
);
1941 if ((Flags
& Replace
) == Replace
) {
1942 if (rename(TemporaryFileName
.c_str(), FileName
.c_str()) != 0)
1943 Res
&= _error
->Errno("rename",_("Problem renaming the file %s to %s"), TemporaryFileName
.c_str(), FileName
.c_str());
1945 FileName
= TemporaryFileName
; // for the unlink() below.
1946 TemporaryFileName
.clear();
1951 if ((Flags
& Fail
) == Fail
&& (Flags
& DelOnFail
) == DelOnFail
&&
1952 FileName
.empty() == false)
1953 if (unlink(FileName
.c_str()) != 0)
1954 Res
&= _error
->WarningE("unlnk",_("Problem unlinking the file %s"), FileName
.c_str());
1961 // FileFd::Sync - Sync the file /*{{{*/
1962 // ---------------------------------------------------------------------
1966 if (fsync(iFd
) != 0)
1967 return FileFdErrno("sync",_("Problem syncing the file"));
1971 // FileFd::FileFdErrno - set Fail and call _error->Errno *{{{*/
1972 bool FileFd::FileFdErrno(const char *Function
, const char *Description
,...)
1976 size_t msgSize
= 400;
1977 int const errsv
= errno
;
1980 va_start(args
,Description
);
1981 if (_error
->InsertErrno(GlobalError::ERROR
, Function
, Description
, args
, errsv
, msgSize
) == false)
1988 // FileFd::FileFdError - set Fail and call _error->Error *{{{*/
1989 bool FileFd::FileFdError(const char *Description
,...) {
1992 size_t msgSize
= 400;
1995 va_start(args
,Description
);
1996 if (_error
->Insert(GlobalError::ERROR
, Description
, args
, msgSize
) == false)
2004 APT_DEPRECATED gzFile
FileFd::gzFd() {
2013 // Glob - wrapper around "glob()" /*{{{*/
2014 // ---------------------------------------------------------------------
2016 std::vector
<std::string
> Glob(std::string
const &pattern
, int flags
)
2018 std::vector
<std::string
> result
;
2023 glob_res
= glob(pattern
.c_str(), flags
, NULL
, &globbuf
);
2027 if(glob_res
!= GLOB_NOMATCH
) {
2028 _error
->Errno("glob", "Problem with glob");
2034 for(i
=0;i
<globbuf
.gl_pathc
;i
++)
2035 result
.push_back(string(globbuf
.gl_pathv
[i
]));
2042 std::string
GetTempDir()
2044 const char *tmpdir
= getenv("TMPDIR");
2051 // check that tmpdir is set and exists
2053 if (!tmpdir
|| strlen(tmpdir
) == 0 || stat(tmpdir
, &st
) != 0)
2056 return string(tmpdir
);