]>
git.saurik.com Git - apt.git/blob - apt-inst/deb/debfile.cc
1 // -*- mode: cpp; mode: fold -*-
3 // $Id: debfile.cc,v 1.3.2.1 2004/01/16 18:58:50 mdz Exp $
4 /* ######################################################################
6 Debian Archive File (.deb)
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.
13 It also uses the deb package list parser to parse the control file
16 ##################################################################### */
18 // Include Files /*{{{*/
21 #include <apt-pkg/database.h>
22 #include <apt-pkg/debfile.h>
23 #include <apt-pkg/extracttar.h>
24 #include <apt-pkg/error.h>
25 #include <apt-pkg/deblistparser.h>
26 #include <apt-pkg/aptconfiguration.h>
33 // DebFile::debDebFile - Constructor /*{{{*/
34 // ---------------------------------------------------------------------
35 /* Open the AR file and check for consistency */
36 debDebFile::debDebFile(FileFd
&File
) : File(File
), AR(File
)
38 if (_error
->PendingError() == true)
41 if (!CheckMember("debian-binary")) {
42 _error
->Error(_("This is not a valid DEB archive, missing '%s' member"), "debian-binary");
46 if (!CheckMember("control.tar.gz")) {
47 _error
->Error(_("This is not a valid DEB archive, missing '%s' member"), "control.tar.gz");
51 if (!CheckMember("data.tar.gz") &&
52 !CheckMember("data.tar.bz2") &&
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
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");
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. */
65 bool debDebFile::CheckMember(const char *Name
)
67 if (AR
.FindMember(Name
) == 0)
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! */
79 const ARArchive::Member
*debDebFile::GotoMember(const char *Name
)
81 // Get the archive member and positition the file
82 const ARArchive::Member
*Member
= AR
.FindMember(Name
);
87 if (File
.Seek(Member
->Start
) == false)
93 // DebFile::ExtractControl - Extract Control information /*{{{*/
94 // ---------------------------------------------------------------------
95 /* Extract the control information into the Database's temporary
97 bool debDebFile::ExtractControl(pkgDataBase
&DB
)
99 // Get the archive member and positition the file
100 const ARArchive::Member
*Member
= GotoMember("control.tar.gz");
105 ControlExtract Extract
;
106 ExtractTar
Tar(File
,Member
->Size
,"gzip");
107 if (_error
->PendingError() == true)
110 // Get into the temporary directory
111 std::string Cwd
= SafeGetCWD();
113 if (DB
.GetMetaTmp(Tmp
) == false)
115 if (chdir(Tmp
.c_str()) != 0)
116 return _error
->Errno("chdir",_("Couldn't change to %s"),Tmp
.c_str());
119 if (Tar
.Go(Extract
) == false)
122 // Switch out of the tmp directory.
123 if (chdir(Cwd
.c_str()) != 0)
129 // DebFile::ExtractArchive - Extract the archive data itself /*{{{*/
130 // ---------------------------------------------------------------------
131 /* Simple wrapper around tar.. */
132 bool debDebFile::ExtractArchive(pkgDirStream
&Stream
)
134 // Get the archive member
135 const ARArchive::Member
*Member
= NULL
;
136 std::string Compressor
;
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
)
143 Member
= AR
.FindMember(std::string(data
).append(c
->Extension
).c_str());
146 Compressor
= c
->Binary
;
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));
157 return _error
->Error(_("Internal error, could not locate member %s"), ext
.c_str());
160 if (File
.Seek(Member
->Start
) == false)
164 ExtractTar
Tar(File
,Member
->Size
,Compressor
);
165 if (_error
->PendingError() == true)
167 return Tar
.Go(Stream
);
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. */
175 pkgCache::VerIterator
debDebFile::MergeControl(pkgDataBase
&DB
)
177 // Open the control file
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());
186 debListParser
Parse(&Fd
);
187 pkgCache::VerIterator
Ver(DB
.GetCache());
188 if (DB
.GetGenerator().MergeList(Parse
,&Ver
) == false)
189 return pkgCache::VerIterator(DB
.GetCache());
191 if (Ver
.end() == true)
192 _error
->Error(_("Failed to locate a valid control file"));
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. */
202 bool debDebFile::ControlExtract::DoItem(Item
&Itm
,int &Fd
)
204 if (Itm
.Type
!= Item::File
)
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
++)
213 /* Force the ownership to be root and ensure correct permissions,
214 go-w, the rest are left untouched */
217 Itm
.Mode
&= ~(S_IWGRP
| S_IWOTH
);
219 return pkgDirStream::DoItem(Itm
,Fd
);
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. */
227 bool debDebFile::MemControlExtract::DoItem(Item
&Itm
,int &Fd
)
229 // At the control file, allocate buffer memory.
230 if (Member
== Itm
.Name
)
233 Control
= new char[Itm
.Size
+2];
235 Fd
= -2; // Signal to pass to Process
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. */
248 bool debDebFile::MemControlExtract::Process(Item
&Itm
,const unsigned char *Data
,
249 unsigned long Size
,unsigned long Pos
)
251 memcpy(Control
+ Pos
, Data
,Size
);
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. */
259 bool debDebFile::MemControlExtract::Read(debDebFile
&Deb
)
261 // Get the archive member and positition the file
262 const ARArchive::Member
*Member
= Deb
.GotoMember("control.tar.gz");
267 ExtractTar
Tar(Deb
.GetFile(),Member
->Size
,"gzip");
268 if (Tar
.Go(*this) == false)
274 Control
[Length
] = '\n';
275 Control
[Length
+1] = '\n';
276 if (Section
.Scan(Control
,Length
+2) == false)
277 return _error
->Error(_("Unparsable control file"));
281 // MemControlExtract::TakeControl - Parse a memory block /*{{{*/
282 // ---------------------------------------------------------------------
283 /* The given memory block is loaded into the parser and parsed as a control
285 bool debDebFile::MemControlExtract::TakeControl(const void *Data
,unsigned long Size
)
288 Control
= new char[Size
+2];
290 memcpy(Control
,Data
,Size
);
292 Control
[Length
] = '\n';
293 Control
[Length
+1] = '\n';
294 return Section
.Scan(Control
,Length
+2);