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