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