]> git.saurik.com Git - apt.git/blame - apt-inst/deb/debfile.cc
merge lp:~mvo/apt/sha512-template to get fixes for the
[apt.git] / apt-inst / deb / debfile.cc
CommitLineData
b2e465d6
AL
1// -*- mode: cpp; mode: fold -*-
2// Description /*{{{*/
7db98ffc 3// $Id: debfile.cc,v 1.3.2.1 2004/01/16 18:58:50 mdz Exp $
b2e465d6
AL
4/* ######################################################################
5
6 Debian Archive File (.deb)
7
8 .DEB archives are AR files containing two tars and an empty marker
9 member called 'debian-binary'. The two tars contain the meta data and
10 the actual archive contents. Thus this class is a very simple wrapper
11 around ar/tar to simply extract the right tar files.
12
13 It also uses the deb package list parser to parse the control file
14 into the cache.
15
16 ##################################################################### */
17 /*}}}*/
18// Include Files /*{{{*/
b2e465d6
AL
19#include <apt-pkg/debfile.h>
20#include <apt-pkg/extracttar.h>
21#include <apt-pkg/error.h>
22#include <apt-pkg/deblistparser.h>
7296f1e6 23#include <apt-pkg/aptconfiguration.h>
b2e465d6
AL
24
25#include <sys/stat.h>
26#include <unistd.h>
d77559ac 27#include <apti18n.h>
b2e465d6
AL
28 /*}}}*/
29
30// DebFile::debDebFile - Constructor /*{{{*/
31// ---------------------------------------------------------------------
32/* Open the AR file and check for consistency */
33debDebFile::debDebFile(FileFd &File) : File(File), AR(File)
34{
35 if (_error->PendingError() == true)
36 return;
b21c0438
MZ
37
38 if (!CheckMember("debian-binary")) {
39 _error->Error(_("This is not a valid DEB archive, missing '%s' member"), "debian-binary");
40 return;
41 }
42
43 if (!CheckMember("control.tar.gz")) {
44 _error->Error(_("This is not a valid DEB archive, missing '%s' member"), "control.tar.gz");
b2e465d6 45 return;
b21c0438
MZ
46 }
47
ac005224
OS
48 if (!CheckMember("data.tar.gz") &&
49 !CheckMember("data.tar.bz2") &&
bc33e0f0
DK
50 !CheckMember("data.tar.lzma") &&
51 !CheckMember("data.tar.xz")) {
52 // FIXME: add data.tar.xz here - adding it now would require a Translation round for a very small gain
ac005224 53 _error->Error(_("This is not a valid DEB archive, it has no '%s', '%s' or '%s' member"), "data.tar.gz", "data.tar.bz2", "data.tar.lzma");
b21c0438
MZ
54 return;
55 }
b2e465d6
AL
56}
57 /*}}}*/
58// DebFile::CheckMember - Check if a named member is in the archive /*{{{*/
59// ---------------------------------------------------------------------
60/* This is used to check for a correct deb and to give nicer error messages
61 for people playing around. */
62bool debDebFile::CheckMember(const char *Name)
63{
64 if (AR.FindMember(Name) == 0)
b21c0438 65 return false;
b2e465d6
AL
66 return true;
67}
68 /*}}}*/
69// DebFile::GotoMember - Jump to a Member /*{{{*/
70// ---------------------------------------------------------------------
71/* Jump in the file to the start of a named member and return the information
72 about that member. The caller can then read from the file up to the
73 returned size. Note, since this relies on the file position this is
74 a destructive operation, it also changes the last returned Member
75 structure - so don't nest them! */
76const ARArchive::Member *debDebFile::GotoMember(const char *Name)
77{
78 // Get the archive member and positition the file
79 const ARArchive::Member *Member = AR.FindMember(Name);
80 if (Member == 0)
81 {
b2e465d6
AL
82 return 0;
83 }
84 if (File.Seek(Member->Start) == false)
85 return 0;
86
87 return Member;
88}
89 /*}}}*/
90// DebFile::ExtractControl - Extract Control information /*{{{*/
91// ---------------------------------------------------------------------
92/* Extract the control information into the Database's temporary
93 directory. */
94bool debDebFile::ExtractControl(pkgDataBase &DB)
95{
96 // Get the archive member and positition the file
97 const ARArchive::Member *Member = GotoMember("control.tar.gz");
98 if (Member == 0)
99 return false;
100
101 // Prepare Tar
102 ControlExtract Extract;
b21c0438 103 ExtractTar Tar(File,Member->Size,"gzip");
b2e465d6
AL
104 if (_error->PendingError() == true)
105 return false;
106
107 // Get into the temporary directory
108 string Cwd = SafeGetCWD();
109 string Tmp;
110 if (DB.GetMetaTmp(Tmp) == false)
111 return false;
112 if (chdir(Tmp.c_str()) != 0)
05eb7df0 113 return _error->Errno("chdir",_("Couldn't change to %s"),Tmp.c_str());
b2e465d6
AL
114
115 // Do extraction
116 if (Tar.Go(Extract) == false)
117 return false;
118
119 // Switch out of the tmp directory.
120 if (chdir(Cwd.c_str()) != 0)
121 chdir("/");
122
123 return true;
124}
125 /*}}}*/
126// DebFile::ExtractArchive - Extract the archive data itself /*{{{*/
127// ---------------------------------------------------------------------
128/* Simple wrapper around tar.. */
129bool debDebFile::ExtractArchive(pkgDirStream &Stream)
130{
7296f1e6
DK
131 // Get the archive member
132 const ARArchive::Member *Member = NULL;
133 std::string Compressor;
134
135 std::string const data = "data.tar";
136 std::vector<APT::Configuration::Compressor> compressor = APT::Configuration::getCompressors();
137 for (std::vector<APT::Configuration::Compressor>::const_iterator c = compressor.begin();
138 c != compressor.end(); ++c)
139 {
140 Member = AR.FindMember(std::string(data).append(c->Extension).c_str());
141 if (Member == NULL)
142 continue;
143 Compressor = c->Binary;
144 break;
ac005224 145 }
7296f1e6
DK
146
147 if (Member == NULL)
148 {
149 std::string ext = "data.tar.{";
150 for (std::vector<APT::Configuration::Compressor>::const_iterator c = compressor.begin();
151 c != compressor.end(); ++c)
152 ext.append(c->Extension.substr(1));
153 ext.append("}");
154 return _error->Error(_("Internal error, could not locate member %s"), ext.c_str());
bc33e0f0 155 }
7296f1e6 156
b2e465d6
AL
157 if (File.Seek(Member->Start) == false)
158 return false;
7296f1e6 159
b2e465d6 160 // Prepare Tar
b21c0438 161 ExtractTar Tar(File,Member->Size,Compressor);
b2e465d6
AL
162 if (_error->PendingError() == true)
163 return false;
164 return Tar.Go(Stream);
165}
166 /*}}}*/
167// DebFile::MergeControl - Merge the control information /*{{{*/
168// ---------------------------------------------------------------------
169/* This reads the extracted control file into the cache and returns the
170 version that was parsed. All this really does is select the correct
171 parser and correct file to parse. */
172pkgCache::VerIterator debDebFile::MergeControl(pkgDataBase &DB)
173{
174 // Open the control file
175 string Tmp;
176 if (DB.GetMetaTmp(Tmp) == false)
177 return pkgCache::VerIterator(DB.GetCache());
178 FileFd Fd(Tmp + "control",FileFd::ReadOnly);
179 if (_error->PendingError() == true)
180 return pkgCache::VerIterator(DB.GetCache());
181
182 // Parse it
183 debListParser Parse(&Fd);
184 pkgCache::VerIterator Ver(DB.GetCache());
185 if (DB.GetGenerator().MergeList(Parse,&Ver) == false)
186 return pkgCache::VerIterator(DB.GetCache());
187
188 if (Ver.end() == true)
05eb7df0 189 _error->Error(_("Failed to locate a valid control file"));
b2e465d6
AL
190 return Ver;
191}
192 /*}}}*/
193
194// DebFile::ControlExtract::DoItem - Control Tar Extraction /*{{{*/
195// ---------------------------------------------------------------------
196/* This directory stream handler for the control tar handles extracting
197 it into the temporary meta directory. It only extracts files, it does
198 not create directories, links or anything else. */
199bool debDebFile::ControlExtract::DoItem(Item &Itm,int &Fd)
200{
201 if (Itm.Type != Item::File)
202 return true;
203
204 /* Cleanse the file name, prevent people from trying to unpack into
205 absolute paths, .., etc */
206 for (char *I = Itm.Name; *I != 0; I++)
207 if (*I == '/')
208 *I = '_';
209
210 /* Force the ownership to be root and ensure correct permissions,
211 go-w, the rest are left untouched */
212 Itm.UID = 0;
213 Itm.GID = 0;
214 Itm.Mode &= ~(S_IWGRP | S_IWOTH);
215
216 return pkgDirStream::DoItem(Itm,Fd);
217}
218 /*}}}*/
219
220// MemControlExtract::DoItem - Check if it is the control file /*{{{*/
221// ---------------------------------------------------------------------
222/* This sets up to extract the control block member file into a memory
223 block of just the right size. All other files go into the bit bucket. */
224bool debDebFile::MemControlExtract::DoItem(Item &Itm,int &Fd)
225{
226 // At the control file, allocate buffer memory.
227 if (Member == Itm.Name)
228 {
229 delete [] Control;
230 Control = new char[Itm.Size+2];
231 IsControl = true;
232 Fd = -2; // Signal to pass to Process
233 Length = Itm.Size;
234 }
235 else
236 IsControl = false;
237
238 return true;
239}
240 /*}}}*/
241// MemControlExtract::Process - Process extracting the control file /*{{{*/
242// ---------------------------------------------------------------------
243/* Just memcopy the block from the tar extractor and put it in the right
244 place in the pre-allocated memory block. */
245bool debDebFile::MemControlExtract::Process(Item &Itm,const unsigned char *Data,
246 unsigned long Size,unsigned long Pos)
247{
248 memcpy(Control + Pos, Data,Size);
249 return true;
250}
251 /*}}}*/
252// MemControlExtract::Read - Read the control information from the deb /*{{{*/
253// ---------------------------------------------------------------------
254/* This uses the internal tar extractor to fetch the control file, and then
255 it parses it into a tag section parser. */
256bool debDebFile::MemControlExtract::Read(debDebFile &Deb)
257{
258 // Get the archive member and positition the file
259 const ARArchive::Member *Member = Deb.GotoMember("control.tar.gz");
260 if (Member == 0)
261 return false;
262
263 // Extract it.
b21c0438 264 ExtractTar Tar(Deb.GetFile(),Member->Size,"gzip");
b2e465d6
AL
265 if (Tar.Go(*this) == false)
266 return false;
267
268 if (Control == 0)
269 return true;
270
271 Control[Length] = '\n';
272 Control[Length+1] = '\n';
273 if (Section.Scan(Control,Length+2) == false)
db0db9fe 274 return _error->Error(_("Unparsable control file"));
b2e465d6
AL
275 return true;
276}
277 /*}}}*/
278// MemControlExtract::TakeControl - Parse a memory block /*{{{*/
279// ---------------------------------------------------------------------
280/* The given memory block is loaded into the parser and parsed as a control
281 record. */
282bool debDebFile::MemControlExtract::TakeControl(const void *Data,unsigned long Size)
283{
284 delete [] Control;
285 Control = new char[Size+2];
286 Length = Size;
287 memcpy(Control,Data,Size);
288
289 Control[Length] = '\n';
290 Control[Length+1] = '\n';
291 return Section.Scan(Control,Length+2);
292}
293 /*}}}*/
294