Fixed problem with not being able to open files
[ntk/apt.git] / apt-pkg / acquire-item.cc
CommitLineData
0118833a
AL
1// -*- mode: cpp; mode: fold -*-
2// Description /*{{{*/
a6568219 3// $Id: acquire-item.cc,v 1.12 1998/11/13 07:08:48 jgg Exp $
0118833a
AL
4/* ######################################################################
5
6 Acquire Item - Item to acquire
7
8 Each item can download to exactly one file at a time. This means you
9 cannot create an item that fetches two uri's to two files at the same
10 time. The pkgAcqIndex class creates a second class upon instantiation
11 to fetch the other index files because of this.
12
13 ##################################################################### */
14 /*}}}*/
15// Include Files /*{{{*/
16#ifdef __GNUG__
17#pragma implementation "apt-pkg/acquire-item.h"
18#endif
19#include <apt-pkg/acquire-item.h>
20#include <apt-pkg/configuration.h>
03e39e59 21#include <apt-pkg/error.h>
0118833a 22#include <strutl.h>
0a8a80e5
AL
23
24#include <sys/stat.h>
25#include <unistd.h>
c88edf1d
AL
26#include <errno.h>
27#include <string.h>
28#include <stdio.h>
0118833a
AL
29 /*}}}*/
30
31// Acquire::Item::Item - Constructor /*{{{*/
32// ---------------------------------------------------------------------
33/* */
8267fe24 34pkgAcquire::Item::Item(pkgAcquire *Owner) : Owner(Owner), FileSize(0),
a6568219
AL
35 Mode(0), ID(0), Complete(false), Local(false),
36 QueueCounter(0)
0118833a
AL
37{
38 Owner->Add(this);
c88edf1d 39 Status = StatIdle;
0118833a
AL
40}
41 /*}}}*/
42// Acquire::Item::~Item - Destructor /*{{{*/
43// ---------------------------------------------------------------------
44/* */
45pkgAcquire::Item::~Item()
46{
47 Owner->Remove(this);
48}
49 /*}}}*/
c88edf1d
AL
50// Acquire::Item::Failed - Item failed to download /*{{{*/
51// ---------------------------------------------------------------------
93bf083d
AL
52/* We return to an idle state if there are still other queues that could
53 fetch this object */
c88edf1d
AL
54void pkgAcquire::Item::Failed(string Message)
55{
93bf083d 56 Status = StatIdle;
c88edf1d 57 if (QueueCounter <= 1)
93bf083d
AL
58 {
59 ErrorText = LookupTag(Message,"Message");
60 Status = StatError;
c88edf1d 61 Owner->Dequeue(this);
93bf083d 62 }
c88edf1d
AL
63}
64 /*}}}*/
8267fe24
AL
65// Acquire::Item::Start - Item has begun to download /*{{{*/
66// ---------------------------------------------------------------------
67/* */
68void pkgAcquire::Item::Start(string Message,unsigned long Size)
69{
70 Status = StatFetching;
71 if (FileSize == 0 && Complete == false)
72 FileSize = Size;
73}
74 /*}}}*/
c88edf1d
AL
75// Acquire::Item::Done - Item downloaded OK /*{{{*/
76// ---------------------------------------------------------------------
77/* */
b98f2859 78void pkgAcquire::Item::Done(string Message,unsigned long Size,string)
c88edf1d 79{
b98f2859
AL
80 // We just downloaded something..
81 string FileName = LookupTag(Message,"Filename");
82 if (Complete == false && FileName == DestFile)
83 {
84 if (Owner->Log != 0)
85 Owner->Log->Fetched(Size,atoi(LookupTag(Message,"Resume-Point","0").c_str()));
86 }
87
c88edf1d
AL
88 Status = StatDone;
89 ErrorText = string();
90 Owner->Dequeue(this);
91}
92 /*}}}*/
8b89e57f
AL
93// Acquire::Item::Rename - Rename a file /*{{{*/
94// ---------------------------------------------------------------------
95/* This helper function is used by alot of item methods as thier final
96 step */
97void pkgAcquire::Item::Rename(string From,string To)
98{
99 if (rename(From.c_str(),To.c_str()) != 0)
100 {
101 char S[300];
102 sprintf(S,"rename failed, %s (%s -> %s).",strerror(errno),
103 From.c_str(),To.c_str());
104 Status = StatError;
105 ErrorText = S;
106 }
107}
108 /*}}}*/
0118833a
AL
109
110// AcqIndex::AcqIndex - Constructor /*{{{*/
111// ---------------------------------------------------------------------
112/* The package file is added to the queue and a second class is
113 instantiated to fetch the revision file */
114pkgAcqIndex::pkgAcqIndex(pkgAcquire *Owner,const pkgSourceList::Item *Location) :
115 Item(Owner), Location(Location)
116{
8b89e57f 117 Decompression = false;
bfd22fc0 118 Erase = false;
8b89e57f 119
0a8a80e5
AL
120 DestFile = _config->FindDir("Dir::State::lists") + "partial/";
121 DestFile += URItoFileName(Location->PackagesURI());
8267fe24
AL
122
123 // Create the item
124 Desc.URI = Location->PackagesURI() + ".gz";
125 Desc.Description = Location->PackagesInfo();
126 Desc.Owner = this;
127
128 // Set the short description to the archive component
129 if (Location->Dist[Location->Dist.size() - 1] == '/')
130 Desc.ShortDesc = Location->Dist;
131 else
132 Desc.ShortDesc = Location->Dist + '/' + Location->Section;
133
134 QueueURI(Desc);
0118833a 135
0a8a80e5 136 // Create the Release fetch class
0118833a
AL
137 new pkgAcqIndexRel(Owner,Location);
138}
139 /*}}}*/
0a8a80e5 140// AcqIndex::Custom600Headers - Insert custom request headers /*{{{*/
0118833a 141// ---------------------------------------------------------------------
0a8a80e5
AL
142/* The only header we use is the last-modified header. */
143string pkgAcqIndex::Custom600Headers()
0118833a 144{
0a8a80e5
AL
145 string Final = _config->FindDir("Dir::State::lists");
146 Final += URItoFileName(Location->PackagesURI());
147
148 struct stat Buf;
149 if (stat(Final.c_str(),&Buf) != 0)
150 return string();
0118833a 151
0a8a80e5 152 return "\nLast-Modified: " + TimeRFC1123(Buf.st_mtime);
0118833a
AL
153}
154 /*}}}*/
8b89e57f
AL
155// AcqIndex::Done - Finished a fetch /*{{{*/
156// ---------------------------------------------------------------------
157/* This goes through a number of states.. On the initial fetch the
158 method could possibly return an alternate filename which points
159 to the uncompressed version of the file. If this is so the file
160 is copied into the partial directory. In all other cases the file
161 is decompressed with a gzip uri. */
162void pkgAcqIndex::Done(string Message,unsigned long Size,string MD5)
163{
164 Item::Done(Message,Size,MD5);
165
166 if (Decompression == true)
167 {
168 // Done, move it into position
169 string FinalFile = _config->FindDir("Dir::State::lists");
170 FinalFile += URItoFileName(Location->PackagesURI());
171 Rename(DestFile,FinalFile);
bfd22fc0 172
7a7fa5f0
AL
173 /* We restore the original name to DestFile so that the clean operation
174 will work OK */
175 DestFile = _config->FindDir("Dir::State::lists") + "partial/";
176 DestFile += URItoFileName(Location->PackagesURI());
177
bfd22fc0
AL
178 // Remove the compressed version.
179 if (Erase == true)
bfd22fc0 180 unlink(DestFile.c_str());
8b89e57f
AL
181 return;
182 }
bfd22fc0
AL
183
184 Erase = false;
8267fe24 185 Complete = true;
bfd22fc0 186
8b89e57f
AL
187 // Handle the unzipd case
188 string FileName = LookupTag(Message,"Alt-Filename");
189 if (FileName.empty() == false)
190 {
191 // The files timestamp matches
192 if (StringToBool(LookupTag(Message,"Alt-IMS-Hit"),false) == true)
193 return;
194
195 Decompression = true;
a6568219 196 Local = true;
8b89e57f 197 DestFile += ".decomp";
8267fe24
AL
198 Desc.URI = "copy:" + FileName;
199 QueueURI(Desc);
b98f2859 200 Mode = "copy";
8b89e57f
AL
201 return;
202 }
203
204 FileName = LookupTag(Message,"Filename");
205 if (FileName.empty() == true)
206 {
207 Status = StatError;
208 ErrorText = "Method gave a blank filename";
209 }
210
211 // The files timestamp matches
212 if (StringToBool(LookupTag(Message,"IMS-Hit"),false) == true)
213 return;
bfd22fc0
AL
214
215 if (FileName == DestFile)
216 Erase = true;
8267fe24 217 else
a6568219 218 Local = true;
8b89e57f
AL
219
220 Decompression = true;
221 DestFile += ".decomp";
8267fe24
AL
222 Desc.URI = "gzip:" + FileName,Location->PackagesInfo();
223 QueueURI(Desc);
b98f2859 224 Mode = "gzip";
8b89e57f
AL
225}
226 /*}}}*/
227
0118833a
AL
228// AcqIndexRel::pkgAcqIndexRel - Constructor /*{{{*/
229// ---------------------------------------------------------------------
230/* The Release file is added to the queue */
231pkgAcqIndexRel::pkgAcqIndexRel(pkgAcquire *Owner,
232 const pkgSourceList::Item *Location) :
233 Item(Owner), Location(Location)
234{
0a8a80e5
AL
235 DestFile = _config->FindDir("Dir::State::lists") + "partial/";
236 DestFile += URItoFileName(Location->ReleaseURI());
237
8267fe24
AL
238 // Create the item
239 Desc.URI = Location->ReleaseURI();
240 Desc.Description = Location->ReleaseInfo();
241 Desc.Owner = this;
242
243 // Set the short description to the archive component
244 if (Location->Dist[Location->Dist.size() - 1] == '/')
245 Desc.ShortDesc = Location->Dist;
246 else
247 Desc.ShortDesc = Location->Dist + '/' + Location->Section;
248
249 QueueURI(Desc);
0118833a
AL
250}
251 /*}}}*/
0a8a80e5 252// AcqIndexRel::Custom600Headers - Insert custom request headers /*{{{*/
0118833a 253// ---------------------------------------------------------------------
0a8a80e5
AL
254/* The only header we use is the last-modified header. */
255string pkgAcqIndexRel::Custom600Headers()
0118833a 256{
0a8a80e5
AL
257 string Final = _config->FindDir("Dir::State::lists");
258 Final += URItoFileName(Location->ReleaseURI());
259
260 struct stat Buf;
261 if (stat(Final.c_str(),&Buf) != 0)
262 return string();
0118833a 263
0a8a80e5 264 return "\nLast-Modified: " + TimeRFC1123(Buf.st_mtime);
0118833a
AL
265}
266 /*}}}*/
c88edf1d
AL
267// AcqIndexRel::Done - Item downloaded OK /*{{{*/
268// ---------------------------------------------------------------------
269/* The release file was not placed into the download directory then
270 a copy URI is generated and it is copied there otherwise the file
271 in the partial directory is moved into .. and the URI is finished. */
272void pkgAcqIndexRel::Done(string Message,unsigned long Size,string MD5)
273{
274 Item::Done(Message,Size,MD5);
275
276 string FileName = LookupTag(Message,"Filename");
277 if (FileName.empty() == true)
278 {
279 Status = StatError;
280 ErrorText = "Method gave a blank filename";
8b89e57f 281 return;
c88edf1d 282 }
8b89e57f 283
8267fe24
AL
284 Complete = true;
285
8b89e57f
AL
286 // The files timestamp matches
287 if (StringToBool(LookupTag(Message,"IMS-Hit"),false) == true)
288 return;
c88edf1d
AL
289
290 // We have to copy it into place
291 if (FileName != DestFile)
292 {
a6568219 293 Local = true;
8267fe24
AL
294 Desc.URI = "copy:" + FileName;
295 QueueURI(Desc);
c88edf1d
AL
296 return;
297 }
298
299 // Done, move it into position
300 string FinalFile = _config->FindDir("Dir::State::lists");
301 FinalFile += URItoFileName(Location->ReleaseURI());
8b89e57f 302 Rename(DestFile,FinalFile);
c88edf1d
AL
303}
304 /*}}}*/
03e39e59
AL
305
306// AcqArchive::AcqArchive - Constructor /*{{{*/
307// ---------------------------------------------------------------------
308/* */
309pkgAcqArchive::pkgAcqArchive(pkgAcquire *Owner,pkgSourceList *Sources,
310 pkgRecords *Recs,pkgCache::VerIterator const &Version) :
311 Item(Owner), Version(Version), Sources(Sources), Recs(Recs)
312{
313 // Select a source
314 pkgCache::VerFileIterator Vf = Version.FileList();
315 for (; Vf.end() == false; Vf++)
316 {
317 // Ignore not source sources
318 if ((Vf.File()->Flags & pkgCache::Flag::NotSource) != 0)
319 continue;
320
321 // Try to cross match against the source list
322 string PkgFile = flNotDir(Vf.File().FileName());
323 pkgSourceList::const_iterator Location;
324 for (Location = Sources->begin(); Location != Sources->end(); Location++)
325 if (PkgFile == URItoFileName(Location->PackagesURI()))
326 break;
327
328 if (Location == Sources->end())
329 continue;
330
331 // Grab the text package record
332 pkgRecords::Parser &Parse = Recs->Lookup(Vf);
333 if (_error->PendingError() == true)
334 return;
335
336 PkgFile = Parse.FileName();
337 MD5 = Parse.MD5Hash();
338 if (PkgFile.empty() == true)
339 {
340 _error->Error("Unable to locate a file name for package %s, "
341 "perhaps the package files are corrupted.",
342 Version.ParentPkg().Name());
343 return;
344 }
a6568219
AL
345
346 // See if we already have the file.
347 FileSize = Version->Size;
348 string FinalFile = _config->FindDir("Dir::Cache::Archives") + flNotDir(PkgFile);
349 struct stat Buf;
350 if (stat(FinalFile.c_str(),&Buf) == 0)
351 {
352 // Make sure the size matches
353 if ((unsigned)Buf.st_size == Version->Size)
354 {
355 Complete = true;
356 Local = true;
357 Status = StatDone;
358 DestFile = FinalFile;
359 return;
360 }
361
362 /* Hmm, we have a file and its size does not match, this shouldnt
363 happen.. */
364 unlink(FinalFile.c_str());
365 }
366
367 DestFile = _config->FindDir("Dir::Cache::Archives") + "partial/" + flNotDir(PkgFile);
03e39e59
AL
368
369 // Create the item
370 Desc.URI = Location->ArchiveURI(PkgFile);
371 Desc.Description = Location->ArchiveInfo(Version);
372 Desc.Owner = this;
373 Desc.ShortDesc = Version.ParentPkg().Name();
374 QueueURI(Desc);
375
03e39e59
AL
376 return;
377 }
378
379 _error->Error("I wasn't able to locate file for the %s package. "
380 "This probably means you need to rerun update.",
381 Version.ParentPkg().Name());
382}
383 /*}}}*/
384// AcqArchive::Done - Finished fetching /*{{{*/
385// ---------------------------------------------------------------------
386/* */
387void pkgAcqArchive::Done(string Message,unsigned long Size,string Md5Hash)
388{
389 Item::Done(Message,Size,MD5);
390
391 // Check the size
392 if (Size != Version->Size)
393 {
394 _error->Error("Size mismatch for package %s",Version.ParentPkg().Name());
395 return;
396 }
397
398 // Check the md5
399 if (Md5Hash.empty() == false && MD5.empty() == false)
400 {
401 if (Md5Hash != MD5)
402 {
403 _error->Error("MD5Sum mismatch for package %s",Version.ParentPkg().Name());
404 return;
405 }
406 }
a6568219
AL
407
408 // Grab the output filename
03e39e59
AL
409 string FileName = LookupTag(Message,"Filename");
410 if (FileName.empty() == true)
411 {
412 Status = StatError;
413 ErrorText = "Method gave a blank filename";
414 return;
415 }
a6568219
AL
416
417 Complete = true;
418
419 // We have to copy it into place
420 if (FileName != DestFile)
421 {
422 DestFile = FileName;
423 Local = true;
424 return;
425 }
426
427 // Done, move it into position
428 string FinalFile = _config->FindDir("Dir::Cache::Archives");
429 FinalFile += flNotDir(DestFile);
430 Rename(DestFile,FinalFile);
03e39e59 431
a6568219 432 DestFile = FinalFile;
03e39e59
AL
433 Complete = true;
434}
435 /*}}}*/