]> git.saurik.com Git - apt.git/blame - apt-pkg/acquire-item.cc
More CD support
[apt.git] / apt-pkg / acquire-item.cc
CommitLineData
0118833a
AL
1// -*- mode: cpp; mode: fold -*-
2// Description /*{{{*/
30e1eab5 3// $Id: acquire-item.cc,v 1.13 1998/11/22 03:20:30 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 /*}}}*/
30e1eab5
AL
227// AcqIndex::Describe - Describe the Item /*{{{*/
228// ---------------------------------------------------------------------
229/* */
230string pkgAcqIndex::Describe()
231{
232 return Location->PackagesURI();
233}
234 /*}}}*/
8b89e57f 235
0118833a
AL
236// AcqIndexRel::pkgAcqIndexRel - Constructor /*{{{*/
237// ---------------------------------------------------------------------
238/* The Release file is added to the queue */
239pkgAcqIndexRel::pkgAcqIndexRel(pkgAcquire *Owner,
240 const pkgSourceList::Item *Location) :
241 Item(Owner), Location(Location)
242{
0a8a80e5
AL
243 DestFile = _config->FindDir("Dir::State::lists") + "partial/";
244 DestFile += URItoFileName(Location->ReleaseURI());
245
8267fe24
AL
246 // Create the item
247 Desc.URI = Location->ReleaseURI();
248 Desc.Description = Location->ReleaseInfo();
249 Desc.Owner = this;
250
251 // Set the short description to the archive component
252 if (Location->Dist[Location->Dist.size() - 1] == '/')
253 Desc.ShortDesc = Location->Dist;
254 else
255 Desc.ShortDesc = Location->Dist + '/' + Location->Section;
256
257 QueueURI(Desc);
0118833a
AL
258}
259 /*}}}*/
0a8a80e5 260// AcqIndexRel::Custom600Headers - Insert custom request headers /*{{{*/
0118833a 261// ---------------------------------------------------------------------
0a8a80e5
AL
262/* The only header we use is the last-modified header. */
263string pkgAcqIndexRel::Custom600Headers()
0118833a 264{
0a8a80e5
AL
265 string Final = _config->FindDir("Dir::State::lists");
266 Final += URItoFileName(Location->ReleaseURI());
267
268 struct stat Buf;
269 if (stat(Final.c_str(),&Buf) != 0)
270 return string();
0118833a 271
0a8a80e5 272 return "\nLast-Modified: " + TimeRFC1123(Buf.st_mtime);
0118833a
AL
273}
274 /*}}}*/
c88edf1d
AL
275// AcqIndexRel::Done - Item downloaded OK /*{{{*/
276// ---------------------------------------------------------------------
277/* The release file was not placed into the download directory then
278 a copy URI is generated and it is copied there otherwise the file
279 in the partial directory is moved into .. and the URI is finished. */
280void pkgAcqIndexRel::Done(string Message,unsigned long Size,string MD5)
281{
282 Item::Done(Message,Size,MD5);
283
284 string FileName = LookupTag(Message,"Filename");
285 if (FileName.empty() == true)
286 {
287 Status = StatError;
288 ErrorText = "Method gave a blank filename";
8b89e57f 289 return;
c88edf1d 290 }
8b89e57f 291
8267fe24
AL
292 Complete = true;
293
8b89e57f
AL
294 // The files timestamp matches
295 if (StringToBool(LookupTag(Message,"IMS-Hit"),false) == true)
296 return;
c88edf1d
AL
297
298 // We have to copy it into place
299 if (FileName != DestFile)
300 {
a6568219 301 Local = true;
8267fe24
AL
302 Desc.URI = "copy:" + FileName;
303 QueueURI(Desc);
c88edf1d
AL
304 return;
305 }
306
307 // Done, move it into position
308 string FinalFile = _config->FindDir("Dir::State::lists");
309 FinalFile += URItoFileName(Location->ReleaseURI());
8b89e57f 310 Rename(DestFile,FinalFile);
c88edf1d
AL
311}
312 /*}}}*/
30e1eab5
AL
313// AcqIndexRel::Describe - Describe the Item /*{{{*/
314// ---------------------------------------------------------------------
315/* */
316string pkgAcqIndexRel::Describe()
317{
318 return Location->ReleaseURI();
319}
320 /*}}}*/
03e39e59
AL
321
322// AcqArchive::AcqArchive - Constructor /*{{{*/
323// ---------------------------------------------------------------------
324/* */
325pkgAcqArchive::pkgAcqArchive(pkgAcquire *Owner,pkgSourceList *Sources,
30e1eab5
AL
326 pkgRecords *Recs,pkgCache::VerIterator const &Version,
327 string &StoreFilename) :
328 Item(Owner), Version(Version), Sources(Sources), Recs(Recs),
329 StoreFilename(StoreFilename)
03e39e59
AL
330{
331 // Select a source
332 pkgCache::VerFileIterator Vf = Version.FileList();
333 for (; Vf.end() == false; Vf++)
334 {
335 // Ignore not source sources
336 if ((Vf.File()->Flags & pkgCache::Flag::NotSource) != 0)
337 continue;
338
339 // Try to cross match against the source list
340 string PkgFile = flNotDir(Vf.File().FileName());
341 pkgSourceList::const_iterator Location;
342 for (Location = Sources->begin(); Location != Sources->end(); Location++)
343 if (PkgFile == URItoFileName(Location->PackagesURI()))
344 break;
345
346 if (Location == Sources->end())
347 continue;
348
349 // Grab the text package record
350 pkgRecords::Parser &Parse = Recs->Lookup(Vf);
351 if (_error->PendingError() == true)
352 return;
353
354 PkgFile = Parse.FileName();
355 MD5 = Parse.MD5Hash();
356 if (PkgFile.empty() == true)
357 {
358 _error->Error("Unable to locate a file name for package %s, "
359 "perhaps the package files are corrupted.",
360 Version.ParentPkg().Name());
361 return;
362 }
a6568219
AL
363
364 // See if we already have the file.
365 FileSize = Version->Size;
366 string FinalFile = _config->FindDir("Dir::Cache::Archives") + flNotDir(PkgFile);
367 struct stat Buf;
368 if (stat(FinalFile.c_str(),&Buf) == 0)
369 {
370 // Make sure the size matches
371 if ((unsigned)Buf.st_size == Version->Size)
372 {
373 Complete = true;
374 Local = true;
375 Status = StatDone;
30e1eab5 376 StoreFilename = DestFile = FinalFile;
a6568219
AL
377 return;
378 }
379
380 /* Hmm, we have a file and its size does not match, this shouldnt
381 happen.. */
382 unlink(FinalFile.c_str());
383 }
384
385 DestFile = _config->FindDir("Dir::Cache::Archives") + "partial/" + flNotDir(PkgFile);
03e39e59
AL
386
387 // Create the item
388 Desc.URI = Location->ArchiveURI(PkgFile);
389 Desc.Description = Location->ArchiveInfo(Version);
390 Desc.Owner = this;
391 Desc.ShortDesc = Version.ParentPkg().Name();
392 QueueURI(Desc);
393
03e39e59
AL
394 return;
395 }
396
397 _error->Error("I wasn't able to locate file for the %s package. "
398 "This probably means you need to rerun update.",
399 Version.ParentPkg().Name());
400}
401 /*}}}*/
402// AcqArchive::Done - Finished fetching /*{{{*/
403// ---------------------------------------------------------------------
404/* */
405void pkgAcqArchive::Done(string Message,unsigned long Size,string Md5Hash)
406{
407 Item::Done(Message,Size,MD5);
408
409 // Check the size
410 if (Size != Version->Size)
411 {
412 _error->Error("Size mismatch for package %s",Version.ParentPkg().Name());
413 return;
414 }
415
416 // Check the md5
417 if (Md5Hash.empty() == false && MD5.empty() == false)
418 {
419 if (Md5Hash != MD5)
420 {
421 _error->Error("MD5Sum mismatch for package %s",Version.ParentPkg().Name());
422 return;
423 }
424 }
a6568219
AL
425
426 // Grab the output filename
03e39e59
AL
427 string FileName = LookupTag(Message,"Filename");
428 if (FileName.empty() == true)
429 {
430 Status = StatError;
431 ErrorText = "Method gave a blank filename";
432 return;
433 }
a6568219
AL
434
435 Complete = true;
30e1eab5
AL
436
437 // Reference filename
a6568219
AL
438 if (FileName != DestFile)
439 {
30e1eab5 440 StoreFilename = DestFile = FileName;
a6568219
AL
441 Local = true;
442 return;
443 }
444
445 // Done, move it into position
446 string FinalFile = _config->FindDir("Dir::Cache::Archives");
447 FinalFile += flNotDir(DestFile);
448 Rename(DestFile,FinalFile);
03e39e59 449
30e1eab5 450 StoreFilename = DestFile = FinalFile;
03e39e59
AL
451 Complete = true;
452}
453 /*}}}*/
30e1eab5
AL
454// AcqArchive::Describe - Describe the Item /*{{{*/
455// ---------------------------------------------------------------------
456/* */
457string pkgAcqArchive::Describe()
458{
459 return Desc.URI;
460}
461 /*}}}*/
462