More or less working acquire system
[ntk/apt.git] / apt-pkg / acquire-item.cc
CommitLineData
0118833a
AL
1// -*- mode: cpp; mode: fold -*-
2// Description /*{{{*/
8267fe24 3// $Id: acquire-item.cc,v 1.8 1998/11/09 01:09:19 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>
21#include <strutl.h>
0a8a80e5
AL
22
23#include <sys/stat.h>
24#include <unistd.h>
c88edf1d
AL
25#include <errno.h>
26#include <string.h>
27#include <stdio.h>
0118833a
AL
28 /*}}}*/
29
30// Acquire::Item::Item - Constructor /*{{{*/
31// ---------------------------------------------------------------------
32/* */
8267fe24
AL
33pkgAcquire::Item::Item(pkgAcquire *Owner) : Owner(Owner), FileSize(0),
34 Complete(false), QueueCounter(0)
0118833a
AL
35{
36 Owner->Add(this);
c88edf1d 37 Status = StatIdle;
0118833a
AL
38}
39 /*}}}*/
40// Acquire::Item::~Item - Destructor /*{{{*/
41// ---------------------------------------------------------------------
42/* */
43pkgAcquire::Item::~Item()
44{
45 Owner->Remove(this);
46}
47 /*}}}*/
c88edf1d
AL
48// Acquire::Item::Failed - Item failed to download /*{{{*/
49// ---------------------------------------------------------------------
93bf083d
AL
50/* We return to an idle state if there are still other queues that could
51 fetch this object */
c88edf1d
AL
52void pkgAcquire::Item::Failed(string Message)
53{
93bf083d 54 Status = StatIdle;
c88edf1d 55 if (QueueCounter <= 1)
93bf083d
AL
56 {
57 ErrorText = LookupTag(Message,"Message");
58 Status = StatError;
c88edf1d 59 Owner->Dequeue(this);
93bf083d 60 }
c88edf1d
AL
61}
62 /*}}}*/
8267fe24
AL
63// Acquire::Item::Start - Item has begun to download /*{{{*/
64// ---------------------------------------------------------------------
65/* */
66void pkgAcquire::Item::Start(string Message,unsigned long Size)
67{
68 Status = StatFetching;
69 if (FileSize == 0 && Complete == false)
70 FileSize = Size;
71}
72 /*}}}*/
c88edf1d
AL
73// Acquire::Item::Done - Item downloaded OK /*{{{*/
74// ---------------------------------------------------------------------
75/* */
76void pkgAcquire::Item::Done(string,unsigned long,string)
77{
78 Status = StatDone;
79 ErrorText = string();
80 Owner->Dequeue(this);
81}
82 /*}}}*/
8b89e57f
AL
83// Acquire::Item::Rename - Rename a file /*{{{*/
84// ---------------------------------------------------------------------
85/* This helper function is used by alot of item methods as thier final
86 step */
87void pkgAcquire::Item::Rename(string From,string To)
88{
89 if (rename(From.c_str(),To.c_str()) != 0)
90 {
91 char S[300];
92 sprintf(S,"rename failed, %s (%s -> %s).",strerror(errno),
93 From.c_str(),To.c_str());
94 Status = StatError;
95 ErrorText = S;
96 }
97}
98 /*}}}*/
0118833a
AL
99
100// AcqIndex::AcqIndex - Constructor /*{{{*/
101// ---------------------------------------------------------------------
102/* The package file is added to the queue and a second class is
103 instantiated to fetch the revision file */
104pkgAcqIndex::pkgAcqIndex(pkgAcquire *Owner,const pkgSourceList::Item *Location) :
105 Item(Owner), Location(Location)
106{
8b89e57f 107 Decompression = false;
bfd22fc0 108 Erase = false;
8b89e57f 109
0a8a80e5
AL
110 DestFile = _config->FindDir("Dir::State::lists") + "partial/";
111 DestFile += URItoFileName(Location->PackagesURI());
8267fe24
AL
112
113 // Create the item
114 Desc.URI = Location->PackagesURI() + ".gz";
115 Desc.Description = Location->PackagesInfo();
116 Desc.Owner = this;
117
118 // Set the short description to the archive component
119 if (Location->Dist[Location->Dist.size() - 1] == '/')
120 Desc.ShortDesc = Location->Dist;
121 else
122 Desc.ShortDesc = Location->Dist + '/' + Location->Section;
123
124 QueueURI(Desc);
0118833a 125
0a8a80e5 126 // Create the Release fetch class
0118833a
AL
127 new pkgAcqIndexRel(Owner,Location);
128}
129 /*}}}*/
0a8a80e5 130// AcqIndex::Custom600Headers - Insert custom request headers /*{{{*/
0118833a 131// ---------------------------------------------------------------------
0a8a80e5
AL
132/* The only header we use is the last-modified header. */
133string pkgAcqIndex::Custom600Headers()
0118833a 134{
0a8a80e5
AL
135 string Final = _config->FindDir("Dir::State::lists");
136 Final += URItoFileName(Location->PackagesURI());
137
138 struct stat Buf;
139 if (stat(Final.c_str(),&Buf) != 0)
140 return string();
0118833a 141
0a8a80e5 142 return "\nLast-Modified: " + TimeRFC1123(Buf.st_mtime);
0118833a
AL
143}
144 /*}}}*/
8b89e57f
AL
145// AcqIndex::Done - Finished a fetch /*{{{*/
146// ---------------------------------------------------------------------
147/* This goes through a number of states.. On the initial fetch the
148 method could possibly return an alternate filename which points
149 to the uncompressed version of the file. If this is so the file
150 is copied into the partial directory. In all other cases the file
151 is decompressed with a gzip uri. */
152void pkgAcqIndex::Done(string Message,unsigned long Size,string MD5)
153{
154 Item::Done(Message,Size,MD5);
155
156 if (Decompression == true)
157 {
158 // Done, move it into position
159 string FinalFile = _config->FindDir("Dir::State::lists");
160 FinalFile += URItoFileName(Location->PackagesURI());
161 Rename(DestFile,FinalFile);
bfd22fc0
AL
162
163 // Remove the compressed version.
164 if (Erase == true)
165 {
166 DestFile = _config->FindDir("Dir::State::lists") + "partial/";
167 DestFile += URItoFileName(Location->PackagesURI());
168 unlink(DestFile.c_str());
169 }
8b89e57f
AL
170 return;
171 }
bfd22fc0
AL
172
173 Erase = false;
8267fe24 174 Complete = true;
bfd22fc0 175
8b89e57f
AL
176 // Handle the unzipd case
177 string FileName = LookupTag(Message,"Alt-Filename");
178 if (FileName.empty() == false)
179 {
180 // The files timestamp matches
181 if (StringToBool(LookupTag(Message,"Alt-IMS-Hit"),false) == true)
182 return;
183
184 Decompression = true;
8267fe24 185 FileSize = 0;
8b89e57f 186 DestFile += ".decomp";
8267fe24
AL
187 Desc.URI = "copy:" + FileName;
188 QueueURI(Desc);
8b89e57f
AL
189 return;
190 }
191
192 FileName = LookupTag(Message,"Filename");
193 if (FileName.empty() == true)
194 {
195 Status = StatError;
196 ErrorText = "Method gave a blank filename";
197 }
198
199 // The files timestamp matches
200 if (StringToBool(LookupTag(Message,"IMS-Hit"),false) == true)
201 return;
bfd22fc0
AL
202
203 if (FileName == DestFile)
204 Erase = true;
8267fe24
AL
205 else
206 FileSize = 0;
8b89e57f
AL
207
208 Decompression = true;
209 DestFile += ".decomp";
8267fe24
AL
210 Desc.URI = "gzip:" + FileName,Location->PackagesInfo();
211 QueueURI(Desc);
8b89e57f
AL
212}
213 /*}}}*/
214
0118833a
AL
215// AcqIndexRel::pkgAcqIndexRel - Constructor /*{{{*/
216// ---------------------------------------------------------------------
217/* The Release file is added to the queue */
218pkgAcqIndexRel::pkgAcqIndexRel(pkgAcquire *Owner,
219 const pkgSourceList::Item *Location) :
220 Item(Owner), Location(Location)
221{
0a8a80e5
AL
222 DestFile = _config->FindDir("Dir::State::lists") + "partial/";
223 DestFile += URItoFileName(Location->ReleaseURI());
224
8267fe24
AL
225 // Create the item
226 Desc.URI = Location->ReleaseURI();
227 Desc.Description = Location->ReleaseInfo();
228 Desc.Owner = this;
229
230 // Set the short description to the archive component
231 if (Location->Dist[Location->Dist.size() - 1] == '/')
232 Desc.ShortDesc = Location->Dist;
233 else
234 Desc.ShortDesc = Location->Dist + '/' + Location->Section;
235
236 QueueURI(Desc);
0118833a
AL
237}
238 /*}}}*/
0a8a80e5 239// AcqIndexRel::Custom600Headers - Insert custom request headers /*{{{*/
0118833a 240// ---------------------------------------------------------------------
0a8a80e5
AL
241/* The only header we use is the last-modified header. */
242string pkgAcqIndexRel::Custom600Headers()
0118833a 243{
0a8a80e5
AL
244 string Final = _config->FindDir("Dir::State::lists");
245 Final += URItoFileName(Location->ReleaseURI());
246
247 struct stat Buf;
248 if (stat(Final.c_str(),&Buf) != 0)
249 return string();
0118833a 250
0a8a80e5 251 return "\nLast-Modified: " + TimeRFC1123(Buf.st_mtime);
0118833a
AL
252}
253 /*}}}*/
c88edf1d
AL
254// AcqIndexRel::Done - Item downloaded OK /*{{{*/
255// ---------------------------------------------------------------------
256/* The release file was not placed into the download directory then
257 a copy URI is generated and it is copied there otherwise the file
258 in the partial directory is moved into .. and the URI is finished. */
259void pkgAcqIndexRel::Done(string Message,unsigned long Size,string MD5)
260{
261 Item::Done(Message,Size,MD5);
262
263 string FileName = LookupTag(Message,"Filename");
264 if (FileName.empty() == true)
265 {
266 Status = StatError;
267 ErrorText = "Method gave a blank filename";
8b89e57f 268 return;
c88edf1d 269 }
8b89e57f 270
8267fe24
AL
271 Complete = true;
272
8b89e57f
AL
273 // The files timestamp matches
274 if (StringToBool(LookupTag(Message,"IMS-Hit"),false) == true)
275 return;
c88edf1d
AL
276
277 // We have to copy it into place
278 if (FileName != DestFile)
279 {
8267fe24
AL
280 FileSize = 0;
281 Desc.URI = "copy:" + FileName;
282 QueueURI(Desc);
c88edf1d
AL
283 return;
284 }
285
286 // Done, move it into position
287 string FinalFile = _config->FindDir("Dir::State::lists");
288 FinalFile += URItoFileName(Location->ReleaseURI());
8b89e57f 289 Rename(DestFile,FinalFile);
c88edf1d
AL
290}
291 /*}}}*/