##################################################################### */
/*}}}*/
// Include Files /*{{{*/
+#include <config.h>
+
#include <apt-pkg/fileutl.h>
#include <apt-pkg/strutl.h>
#include <apt-pkg/error.h>
#include <apt-pkg/sptr.h>
+#include <apt-pkg/aptconfiguration.h>
#include <apt-pkg/configuration.h>
-#include <apti18n.h>
-
#include <cstdlib>
#include <cstring>
#include <cstdio>
#include <errno.h>
#include <set>
#include <algorithm>
+
+#ifdef WORDS_BIGENDIAN
+#include <inttypes.h>
+#endif
+
+#include <apti18n.h>
/*}}}*/
using namespace std;
// This is the child
if (Child == 0)
{
+ if (_config->FindDir("DPkg::Chroot-Directory","/") != "/")
+ {
+ std::cerr << "Chrooting into "
+ << _config->FindDir("DPkg::Chroot-Directory")
+ << std::endl;
+ if (chroot(_config->FindDir("DPkg::Chroot-Directory","/").c_str()) != 0)
+ _exit(100);
+ }
+
if (chdir("/tmp/") != 0)
_exit(100);
// Buffered copy between fds
SPtrArray<unsigned char> Buf = new unsigned char[64000];
- unsigned long Size = From.Size();
+ unsigned long long Size = From.Size();
while (Size != 0)
{
- unsigned long ToRead = Size;
+ unsigned long long ToRead = Size;
if (Size > 64000)
ToRead = 64000;
/*}}}*/
// FileExists - Check if a file exists /*{{{*/
// ---------------------------------------------------------------------
-/* */
+/* Beware: Directories are also files! */
bool FileExists(string File)
{
struct stat Buf;
return true;
}
/*}}}*/
+// RealFileExists - Check if a file exists and if it is really a file /*{{{*/
+// ---------------------------------------------------------------------
+/* */
+bool RealFileExists(string File)
+{
+ struct stat Buf;
+ if (stat(File.c_str(),&Buf) != 0)
+ return false;
+ return ((Buf.st_mode & S_IFREG) != 0);
+}
+ /*}}}*/
// DirectoryExists - Check if a directory exists and is really one /*{{{*/
// ---------------------------------------------------------------------
/* */
}
std::vector<string> List;
+
+ if (DirectoryExists(Dir.c_str()) == false)
+ {
+ _error->Error(_("List of files can't be created as '%s' is not a directory"), Dir.c_str());
+ return List;
+ }
+
Configuration::MatchAgainstConfig SilentIgnore("Dir::Ignore-Files-Silently");
DIR *D = opendir(Dir.c_str());
if (D == 0)
if (Ent->d_name[0] == '.')
continue;
+ // Make sure it is a file and not something else
+ string const File = flCombine(Dir,Ent->d_name);
+#ifdef _DIRENT_HAVE_D_TYPE
+ if (Ent->d_type != DT_REG)
+#endif
+ {
+ if (RealFileExists(File.c_str()) == false)
+ {
+ if (SilentIgnore.Match(Ent->d_name) == false)
+ _error->Notice(_("Ignoring '%s' in directory '%s' as it is not a regular file"), Ent->d_name, Dir.c_str());
+ continue;
+ }
+ }
+
// check for accepted extension:
// no extension given -> periods are bad as hell!
// extensions given -> "" extension allows no extension
if (Debug == true)
std::clog << "Bad file: " << Ent->d_name << " → no extension" << std::endl;
if (SilentIgnore.Match(Ent->d_name) == false)
- _error->Notice("Ignoring file '%s' in directory '%s' as it has no filename extension", Ent->d_name, Dir.c_str());
+ _error->Notice(_("Ignoring file '%s' in directory '%s' as it has no filename extension"), Ent->d_name, Dir.c_str());
continue;
}
}
if (Debug == true)
std::clog << "Bad file: " << Ent->d_name << " → bad extension »" << flExtension(Ent->d_name) << "«" << std::endl;
if (SilentIgnore.Match(Ent->d_name) == false)
- _error->Notice("Ignoring file '%s' in directory '%s' as it has an invalid filename extension", Ent->d_name, Dir.c_str());
+ _error->Notice(_("Ignoring file '%s' in directory '%s' as it has an invalid filename extension"), Ent->d_name, Dir.c_str());
continue;
}
}
continue;
}
- // Make sure it is a file and not something else
- string const File = flCombine(Dir,Ent->d_name);
- struct stat St;
- if (stat(File.c_str(),&St) != 0 || S_ISREG(St.st_mode) == 0)
- {
- if (Debug == true)
- std::clog << "Bad file: " << Ent->d_name << " → stat says not a good file" << std::endl;
- continue;
- }
-
if (Debug == true)
std::clog << "Accept file: " << Ent->d_name << " in " << Dir << std::endl;
List.push_back(File);
return S;
}
/*}}}*/
+// GetModificationTime - Get the mtime of the given file or -1 on error /*{{{*/
+// ---------------------------------------------------------------------
+/* We return / on failure. */
+time_t GetModificationTime(string const &Path)
+{
+ struct stat St;
+ if (stat(Path.c_str(), &St) < 0)
+ return -1;
+ return St.st_mtime;
+}
+ /*}}}*/
// flNotDir - Strip the directory from the filename /*{{{*/
// ---------------------------------------------------------------------
/* */
// FileFd::Open - Open a file /*{{{*/
// ---------------------------------------------------------------------
/* The most commonly used open mode combinations are given with Mode */
-bool FileFd::Open(string FileName,OpenMode Mode, unsigned long Perms)
+bool FileFd::Open(string FileName,OpenMode Mode,CompressMode Compress, unsigned long Perms)
{
+ if (Mode == ReadOnlyGzip)
+ return Open(FileName, ReadOnly, Gzip, Perms);
Close();
Flags = AutoClose;
- switch (Mode)
- {
- case ReadOnly:
- iFd = open(FileName.c_str(),O_RDONLY);
- break;
- case ReadOnlyGzip:
- iFd = open(FileName.c_str(),O_RDONLY);
- if (iFd > 0) {
- gz = gzdopen (iFd, "r");
- if (gz == NULL) {
- close (iFd);
- iFd = -1;
- }
- }
- break;
-
- case WriteAtomic:
+ if (Compress == Auto && (Mode & WriteOnly) == WriteOnly)
+ return _error->Error("Autodetection on %s only works in ReadOnly openmode!", FileName.c_str());
+ if ((Mode & WriteOnly) != WriteOnly && (Mode & (Atomic | Create | Empty | Exclusive)) != 0)
+ return _error->Error("ReadOnly mode for %s doesn't accept additional flags!", FileName.c_str());
+
+ int fileflags = 0;
+#define if_FLAGGED_SET(FLAG, MODE) if ((Mode & FLAG) == FLAG) fileflags |= MODE
+ if_FLAGGED_SET(ReadWrite, O_RDWR);
+ else if_FLAGGED_SET(ReadOnly, O_RDONLY);
+ else if_FLAGGED_SET(WriteOnly, O_WRONLY);
+ else return _error->Error("No openmode provided in FileFd::Open for %s", FileName.c_str());
+
+ if_FLAGGED_SET(Create, O_CREAT);
+ if_FLAGGED_SET(Exclusive, O_EXCL);
+ else if_FLAGGED_SET(Atomic, O_EXCL);
+ if_FLAGGED_SET(Empty, O_TRUNC);
+#undef if_FLAGGED_SET
+
+ // FIXME: Denote inbuilt compressors somehow - as we don't need to have the binaries for them
+ std::vector<APT::Configuration::Compressor> const compressors = APT::Configuration::getCompressors();
+ std::vector<APT::Configuration::Compressor>::const_iterator compressor = compressors.begin();
+ if (Compress == Auto)
+ {
+ Compress = None;
+ for (; compressor != compressors.end(); ++compressor)
{
- Flags |= Replace;
- char *name = strdup((FileName + ".XXXXXX").c_str());
- TemporaryFileName = string(mktemp(name));
- iFd = open(TemporaryFileName.c_str(),O_RDWR | O_CREAT | O_EXCL,Perms);
- free(name);
+ std::string file = std::string(FileName).append(compressor->Extension);
+ if (FileExists(file) == false)
+ continue;
+ FileName = file;
+ if (compressor->Binary == ".")
+ Compress = None;
+ else
+ Compress = Extension;
break;
}
-
- case WriteEmpty:
+ }
+ else if (Compress == Extension)
+ {
+ Compress = None;
+ std::string ext = flExtension(FileName);
+ if (ext != FileName)
{
- struct stat Buf;
- if (lstat(FileName.c_str(),&Buf) == 0 && S_ISLNK(Buf.st_mode))
- unlink(FileName.c_str());
- iFd = open(FileName.c_str(),O_RDWR | O_CREAT | O_TRUNC,Perms);
- break;
+ ext = "." + ext;
+ for (; compressor != compressors.end(); ++compressor)
+ if (ext == compressor->Extension)
+ break;
}
-
- case WriteExists:
- iFd = open(FileName.c_str(),O_RDWR);
- break;
+ }
+ else if (Compress != None)
+ {
+ std::string name;
+ switch (Compress)
+ {
+ case Gzip: name = "gzip"; break;
+ case Bzip2: name = "bzip2"; break;
+ case Lzma: name = "lzma"; break;
+ case Xz: name = "xz"; break;
+ default: return _error->Error("Can't find a match for specified compressor mode for file %s", FileName.c_str());
+ }
+ for (; compressor != compressors.end(); ++compressor)
+ if (compressor->Name == name)
+ break;
+ if (compressor == compressors.end() && name != "gzip")
+ return _error->Error("Can't find a configured compressor %s for file %s", name.c_str(), FileName.c_str());
+ }
- case WriteAny:
- iFd = open(FileName.c_str(),O_RDWR | O_CREAT,Perms);
- break;
+ // if we have them, use inbuilt compressors instead of forking
+ if (compressor != compressors.end())
+ {
+ if (compressor->Name == "gzip")
+ {
+ Compress = Gzip;
+ compressor = compressors.end();
+ }
+ else if (compressor->Name == "." || Compress == None)
+ {
+ Compress = None;
+ compressor = compressors.end();
+ }
+ }
- case WriteTemp:
+ if ((Mode & Atomic) == Atomic)
+ {
+ Flags |= Replace;
+ char *name = strdup((FileName + ".XXXXXX").c_str());
+ TemporaryFileName = string(mktemp(name));
+ free(name);
+ }
+ else if ((Mode & (Exclusive | Create)) == (Exclusive | Create))
+ {
+ // for atomic, this will be done by rename in Close()
unlink(FileName.c_str());
- iFd = open(FileName.c_str(),O_RDWR | O_CREAT | O_EXCL,Perms);
- break;
- }
+ }
+ if ((Mode & Empty) == Empty)
+ {
+ struct stat Buf;
+ if (lstat(FileName.c_str(),&Buf) == 0 && S_ISLNK(Buf.st_mode))
+ unlink(FileName.c_str());
+ }
- if (iFd < 0)
+ if (compressor != compressors.end())
+ {
+ if ((Mode & ReadWrite) == ReadWrite)
+ _error->Error("External compressors like %s do not support readwrite mode for file %s", compressor->Name.c_str(), FileName.c_str());
+
+ _error->Error("Forking external compressor %s is not implemented for %s", compressor->Name.c_str(), FileName.c_str());
+ }
+ else
+ {
+ if (TemporaryFileName.empty() == false)
+ iFd = open(TemporaryFileName.c_str(), fileflags, Perms);
+ else
+ iFd = open(FileName.c_str(), fileflags, Perms);
+
+ if (iFd != -1)
+ {
+ if (OpenInternDescriptor(Mode, Compress) == false)
+ {
+ close (iFd);
+ iFd = -1;
+ }
+ }
+ }
+
+ if (iFd == -1)
return _error->Errno("open",_("Could not open file %s"),FileName.c_str());
-
+
this->FileName = FileName;
SetCloseExec(iFd,true);
return true;
}
-
-bool FileFd::OpenDescriptor(int Fd, OpenMode Mode, bool AutoClose)
+ /*}}}*/
+// FileFd::OpenDescriptor - Open a filedescriptor /*{{{*/
+// ---------------------------------------------------------------------
+/* */
+bool FileFd::OpenDescriptor(int Fd, OpenMode Mode, CompressMode Compress, bool AutoClose)
{
Close();
Flags = (AutoClose) ? FileFd::AutoClose : 0;
iFd = Fd;
- if (Mode == ReadOnlyGzip) {
- gz = gzdopen (iFd, "r");
- if (gz == NULL) {
- if (AutoClose)
- close (iFd);
- return _error->Errno("gzdopen",_("Could not open file descriptor %d"),
- Fd);
- }
+ if (OpenInternDescriptor(Mode, Compress) == false)
+ {
+ if (AutoClose)
+ close (iFd);
+ return _error->Errno("gzdopen",_("Could not open file descriptor %d"), Fd);
}
this->FileName = "";
return true;
+}
+bool FileFd::OpenInternDescriptor(OpenMode Mode, CompressMode Compress)
+{
+ if (Compress == None)
+ return true;
+ else if (Compress == Gzip)
+ {
+ if ((Mode & ReadWrite) == ReadWrite)
+ gz = gzdopen(iFd, "r+");
+ else if ((Mode & WriteOnly) == WriteOnly)
+ gz = gzdopen(iFd, "w");
+ else
+ gz = gzdopen (iFd, "r");
+ if (gz == NULL)
+ return false;
+ }
+ else
+ return false;
+ return true;
}
/*}}}*/
// FileFd::~File - Closes the file /*{{{*/
// ---------------------------------------------------------------------
/* We are carefull to handle interruption by a signal while reading
gracefully. */
-bool FileFd::Read(void *To,unsigned long Size,unsigned long *Actual)
+bool FileFd::Read(void *To,unsigned long long Size,unsigned long long *Actual)
{
int Res;
errno = 0;
}
Flags |= Fail;
- return _error->Error(_("read, still have %lu to read but none left"),Size);
+ return _error->Error(_("read, still have %llu to read but none left"), Size);
}
/*}}}*/
// FileFd::Write - Write to the file /*{{{*/
// ---------------------------------------------------------------------
/* */
-bool FileFd::Write(const void *From,unsigned long Size)
+bool FileFd::Write(const void *From,unsigned long long Size)
{
int Res;
errno = 0;
return true;
Flags |= Fail;
- return _error->Error(_("write, still have %lu to write but couldn't"),Size);
+ return _error->Error(_("write, still have %llu to write but couldn't"), Size);
}
/*}}}*/
// FileFd::Seek - Seek in the file /*{{{*/
// ---------------------------------------------------------------------
/* */
-bool FileFd::Seek(unsigned long To)
+bool FileFd::Seek(unsigned long long To)
{
int res;
if (gz)
if (res != (signed)To)
{
Flags |= Fail;
- return _error->Error("Unable to seek to %lu",To);
+ return _error->Error("Unable to seek to %llu", To);
}
return true;
// FileFd::Skip - Seek in the file /*{{{*/
// ---------------------------------------------------------------------
/* */
-bool FileFd::Skip(unsigned long Over)
+bool FileFd::Skip(unsigned long long Over)
{
int res;
if (gz)
if (res < 0)
{
Flags |= Fail;
- return _error->Error("Unable to seek ahead %lu",Over);
+ return _error->Error("Unable to seek ahead %llu",Over);
}
return true;
// FileFd::Truncate - Truncate the file /*{{{*/
// ---------------------------------------------------------------------
/* */
-bool FileFd::Truncate(unsigned long To)
+bool FileFd::Truncate(unsigned long long To)
{
if (gz)
{
if (ftruncate(iFd,To) != 0)
{
Flags |= Fail;
- return _error->Error("Unable to truncate to %lu",To);
+ return _error->Error("Unable to truncate to %llu",To);
}
return true;
// FileFd::Tell - Current seek position /*{{{*/
// ---------------------------------------------------------------------
/* */
-unsigned long FileFd::Tell()
+unsigned long long FileFd::Tell()
{
off_t Res;
if (gz)
return Res;
}
/*}}}*/
-// FileFd::Size - Return the size of the file /*{{{*/
+// FileFd::FileSize - Return the size of the file /*{{{*/
// ---------------------------------------------------------------------
/* */
-unsigned long FileFd::Size()
+unsigned long long FileFd::FileSize()
{
struct stat Buf;
- unsigned long size;
- off_t orig_pos;
if (fstat(iFd,&Buf) != 0)
return _error->Errno("fstat","Unable to determine the file size");
- size = Buf.st_size;
+ return Buf.st_size;
+}
+ /*}}}*/
+// FileFd::Size - Return the size of the content in the file /*{{{*/
+// ---------------------------------------------------------------------
+/* */
+unsigned long long FileFd::Size()
+{
+ unsigned long long size = FileSize();
// only check gzsize if we are actually a gzip file, just checking for
// "gz" is not sufficient as uncompressed files will be opened with
/* unfortunately zlib.h doesn't provide a gzsize(), so we have to do
* this ourselves; the original (uncompressed) file size is the last 32
* bits of the file */
- orig_pos = lseek(iFd, 0, SEEK_CUR);
+ // FIXME: Size for gz-files is limited by 32bit… no largefile support
+ off_t orig_pos = lseek(iFd, 0, SEEK_CUR);
if (lseek(iFd, -4, SEEK_END) < 0)
return _error->Errno("lseek","Unable to seek to end of gzipped file");
+ size = 0L;
if (read(iFd, &size, 4) != 4)
return _error->Errno("read","Unable to read original size of gzipped file");
- size &= 0xFFFFFFFF;
+
+#ifdef WORDS_BIGENDIAN
+ uint32_t tmp_size = size;
+ uint8_t const * const p = (uint8_t const * const) &tmp_size;
+ tmp_size = (p[3] << 24) | (p[2] << 16) | (p[1] << 8) | p[0];
+ size = tmp_size;
+#endif
if (lseek(iFd, orig_pos, SEEK_SET) < 0)
return _error->Errno("lseek","Unable to seek in gzipped file");
Res &= _error->Errno("rename",_("Problem renaming the file %s to %s"), TemporaryFileName.c_str(), FileName.c_str());
FileName = TemporaryFileName; // for the unlink() below.
+ TemporaryFileName.clear();
}
iFd = -1;