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