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

debfile.cc
Go to the documentation of this file.
1 // -*- mode: cpp; mode: fold -*-
2 // Description /*{{{*/
3 /* ######################################################################
4 
5  Debian Archive File (.deb)
6 
7  .DEB archives are AR files containing two tars and an empty marker
8  member called 'debian-binary'. The two tars contain the meta data and
9  the actual archive contents. Thus this class is a very simple wrapper
10  around ar/tar to simply extract the right tar files.
11 
12  It also uses the deb package list parser to parse the control file
13  into the cache.
14 
15  ##################################################################### */
16  /*}}}*/
17 // Include Files /*{{{*/
18 #include <config.h>
19 
21 #include <apt-pkg/arfile.h>
22 #include <apt-pkg/debfile.h>
23 #include <apt-pkg/dirstream.h>
24 #include <apt-pkg/error.h>
25 #include <apt-pkg/extracttar.h>
26 #include <apt-pkg/fileutl.h>
27 #include <apt-pkg/strutl.h>
28 #include <apt-pkg/tagfile.h>
29 
30 #include <algorithm>
31 #include <string>
32 #include <sstream>
33 #include <vector>
34 #include <string.h>
35 #include <sys/stat.h>
36 
37 #include <apti18n.h>
38  /*}}}*/
39 
40 // DebFile::debDebFile - Constructor /*{{{*/
41 // ---------------------------------------------------------------------
42 /* Open the AR file and check for consistency */
43 debDebFile::debDebFile(FileFd &File) : File(File), AR(File)
44 {
45  if (_error->PendingError() == true)
46  return;
47 
48  if (!CheckMember("debian-binary")) {
49  _error->Error(_("This is not a valid DEB archive, missing '%s' member"), "debian-binary");
50  return;
51  }
52 
53  if (!CheckMember("control.tar") &&
54  !CheckMember("control.tar.gz") &&
55  !CheckMember("control.tar.xz") &&
56  !CheckMember("control.tar.zst"))
57  {
58  _error->Error(_("This is not a valid DEB archive, missing '%s' member"), "control.tar");
59  return;
60  }
61 
62  if (!CheckMember("data.tar") &&
63  !CheckMember("data.tar.gz") &&
64  !CheckMember("data.tar.bz2") &&
65  !CheckMember("data.tar.lzma") &&
66  !CheckMember("data.tar.xz") &&
67  !CheckMember("data.tar.zst"))
68  {
69  _error->Error(_("This is not a valid DEB archive, missing '%s' member"), "data.tar");
70  return;
71  }
72 }
73  /*}}}*/
74 // DebFile::CheckMember - Check if a named member is in the archive /*{{{*/
75 // ---------------------------------------------------------------------
76 /* This is used to check for a correct deb and to give nicer error messages
77  for people playing around. */
78 bool debDebFile::CheckMember(const char *Name)
79 {
80  if (AR.FindMember(Name) == 0)
81  return false;
82  return true;
83 }
84  /*}}}*/
85 // DebFile::GotoMember - Jump to a Member /*{{{*/
86 // ---------------------------------------------------------------------
87 /* Jump in the file to the start of a named member and return the information
88  about that member. The caller can then read from the file up to the
89  returned size. Note, since this relies on the file position this is
90  a destructive operation, it also changes the last returned Member
91  structure - so don't nest them! */
92 const ARArchive::Member *debDebFile::GotoMember(const char *Name)
93 {
94  // Get the archive member and positition the file
95  const ARArchive::Member *Member = AR.FindMember(Name);
96  if (Member == 0)
97  {
98  return 0;
99  }
100  if (File.Seek(Member->Start) == false)
101  return 0;
102 
103  return Member;
104 }
105  /*}}}*/
106 // DebFile::ExtractTarMember - Extract the contents of a tar member /*{{{*/
107 // ---------------------------------------------------------------------
108 /* Simple wrapper around tar.. */
109 bool debDebFile::ExtractTarMember(pkgDirStream &Stream,const char *Name)
110 {
111  std::string Compressor;
112  auto const Compressors = APT::Configuration::getCompressors();
113 
114  ARArchive::Member const *Member = AR.FindMember(Name);
115  if (Member != nullptr)
116  {
117  auto const found = std::find_if(Compressors.cbegin(), Compressors.cend(), [&](auto const &c) {
118  return not c.Extension.empty() && APT::String::Endswith(Name, c.Extension);
119  });
120  if (found != Compressors.cend())
121  Compressor = found->Name;
122  }
123  else
124  {
125  for (auto const &c : Compressors)
126  {
127  if (c.Extension.empty())
128  continue;
129  Member = AR.FindMember(std::string(Name).append(c.Extension).c_str());
130  if (Member == nullptr)
131  continue;
132  Compressor = c.Name;
133  break;
134  }
135  }
136 
137  if (Member == nullptr)
138  {
139  std::ostringstream ext;
140  ext << Name << '{';
141  for (auto const &c : Compressors)
142  if (not c.Extension.empty())
143  ext << c.Extension << ',';
144  ext << '}';
145  return _error->Error(_("Internal error, could not locate member %s"), ext.str().c_str());
146  }
147 
148  if (not File.Seek(Member->Start))
149  return false;
150 
151  ExtractTar Tar(File,Member->Size,Compressor);
152  if (_error->PendingError())
153  return false;
154  return Tar.Go(Stream);
155 }
156  /*}}}*/
157 // DebFile::ExtractArchive - Extract the archive data itself /*{{{*/
158 // ---------------------------------------------------------------------
159 /* Simple wrapper around DebFile::ExtractTarMember. */
161 {
162  return ExtractTarMember(Stream, "data.tar");
163 }
164  /*}}}*/
165 
166 // DebFile::ControlExtract::DoItem - Control Tar Extraction /*{{{*/
167 // ---------------------------------------------------------------------
168 /* This directory stream handler for the control tar handles extracting
169  it into the temporary meta directory. It only extracts files, it does
170  not create directories, links or anything else. */
171 bool debDebFile::ControlExtract::DoItem(Item &Itm,int &Fd)
172 {
173  if (Itm.Type != Item::File)
174  return true;
175 
176  /* Cleanse the file name, prevent people from trying to unpack into
177  absolute paths, .., etc */
178  for (char *I = Itm.Name; *I != 0; I++)
179  if (*I == '/')
180  *I = '_';
181 
182  /* Force the ownership to be root and ensure correct permissions,
183  go-w, the rest are left untouched */
184  Itm.UID = 0;
185  Itm.GID = 0;
186  Itm.Mode &= ~(S_IWGRP | S_IWOTH);
187 
188  return pkgDirStream::DoItem(Itm,Fd);
189 }
190  /*}}}*/
191 
192 // MemControlExtract::DoItem - Check if it is the control file /*{{{*/
193 // ---------------------------------------------------------------------
194 /* This sets up to extract the control block member file into a memory
195  block of just the right size. All other files go into the bit bucket. */
196 
197 // Upper size limit for control files. Two reasons for having a limit here:
198 //
199 // 1. We read those files into memory and want to avoid being killed by OOM
200 //
201 // 2. We allocate (Itm.Size+2)-large arrays, so this can overflow if Itm.Size
202 // becomes 2**64-2 or larger. This is obviously
203 //
204 // 64 MiB seems like a terribly large size that everyone should be happy with.
205 static const unsigned long long DEB_CONTROL_SIZE_LIMIT = 64 * 1024 * 1024;
206 bool debDebFile::MemControlExtract::DoItem(Item &Itm,int &Fd)
207 {
208  // At the control file, allocate buffer memory.
209  if (Member == Itm.Name)
210  {
211  if (Itm.Size > DEB_CONTROL_SIZE_LIMIT)
212  return _error->Error("Control file too large: %llu > %llu bytes", Itm.Size, DEB_CONTROL_SIZE_LIMIT);
213  delete [] Control;
214  Control = new char[Itm.Size+2];
215  IsControl = true;
216  Fd = -2; // Signal to pass to Process
217  Length = Itm.Size;
218  }
219  else
220  IsControl = false;
221 
222  return true;
223 }
224  /*}}}*/
225 // MemControlExtract::Process - Process extracting the control file /*{{{*/
226 // ---------------------------------------------------------------------
227 /* Just memcopy the block from the tar extractor and put it in the right
228  place in the pre-allocated memory block. */
229 bool debDebFile::MemControlExtract::Process(Item &/*Itm*/,const unsigned char *Data,
230  unsigned long long Size,unsigned long long Pos)
231 {
232  memcpy(Control + Pos, Data,Size);
233  return true;
234 }
235  /*}}}*/
236 // MemControlExtract::Read - Read the control information from the deb /*{{{*/
237 // ---------------------------------------------------------------------
238 /* This uses the internal tar extractor to fetch the control file, and then
239  it parses it into a tag section parser. */
240 bool debDebFile::MemControlExtract::Read(debDebFile &Deb)
241 {
242  if (Deb.ExtractTarMember(*this, "control.tar") == false)
243  return false;
244 
245  if (Control == 0)
246  return true;
247 
248  Control[Length] = '\n';
249  Control[Length+1] = '\n';
250  if (Section.Scan(Control,Length+2) == false)
251  return _error->Error(_("Unparsable control file"));
252  return true;
253 }
254  /*}}}*/
255 // MemControlExtract::TakeControl - Parse a memory block /*{{{*/
256 // ---------------------------------------------------------------------
257 /* The given memory block is loaded into the parser and parsed as a control
258  record. */
259 bool debDebFile::MemControlExtract::TakeControl(const void *Data,unsigned long long Size)
260 {
261  if (Size > DEB_CONTROL_SIZE_LIMIT)
262  return _error->Error("Control file too large: %llu > %llu bytes", Size, DEB_CONTROL_SIZE_LIMIT);
263 
264  delete [] Control;
265  Control = new char[Size+2];
266  Length = Size;
267  memcpy(Control,Data,Size);
268 
269  Control[Length] = '\n';
270  Control[Length+1] = '\n';
271  return Section.Scan(Control,Length+2);
272 }
273  /*}}}*/
274 
static bool std::string const metaIndex const *const pkgAcqMetaClearSig *const pkgAcquire::Item *const I
const Member * FindMember(const char *Name) const
Definition: arfile.cc:167
bool Go(pkgDirStream &Stream)
Definition: extracttar.cc:125
Definition: fileutl.h:39
bool Seek(unsigned long long To)
Definition: fileutl.cc:2875
ARArchive AR
Definition: debfile.h:40
bool ExtractTarMember(pkgDirStream &Stream, const char *Name)
Definition: debfile.cc:109
debDebFile(FileFd &File)
Definition: debfile.cc:43
bool ExtractArchive(pkgDirStream &Stream)
Definition: debfile.cc:160
std::string Member
Definition: debfile.h:72
const ARArchive::Member * GotoMember(const char *Name)
Definition: debfile.cc:92
bool CheckMember(const char *Name)
Definition: debfile.cc:78
FileFd & File
Definition: debfile.h:39
virtual bool DoItem(Item &Itm, int &Fd)
Definition: dirstream.cc:30
static const unsigned long long DEB_CONTROL_SIZE_LIMIT
Definition: debfile.cc:205
APT_PUBLIC std::vector< Compressor > const getCompressors(bool const Cached=true)
Return a vector of Compressors supported for data.tar's.
std::string Name
Definition: arfile.h:52