* Build apt-ftparchive with libdb4.2 rather than libdb2
[ntk/apt.git] / ftparchive / cachedb.cc
CommitLineData
b2e465d6
AL
1// -*- mode: cpp; mode: fold -*-
2// Description /*{{{*/
c9569a1e 3// $Id: cachedb.cc,v 1.7 2004/05/08 19:41:01 mdz Exp $
b2e465d6
AL
4/* ######################################################################
5
6 CacheDB
7
8 Simple uniform interface to a cache database.
9
10 ##################################################################### */
11 /*}}}*/
12// Include Files /*{{{*/
13#ifdef __GNUG__
14#pragma implementation "cachedb.h"
15#endif
16
17#include "cachedb.h"
18
dc738e7a 19#include <apti18n.h>
b2e465d6
AL
20#include <apt-pkg/error.h>
21#include <apt-pkg/md5.h>
22#include <apt-pkg/strutl.h>
23#include <apt-pkg/configuration.h>
24
25#include <netinet/in.h> // htonl, etc
26 /*}}}*/
27
28// CacheDB::ReadyDB - Ready the DB2 /*{{{*/
29// ---------------------------------------------------------------------
30/* This opens the DB2 file for caching package information */
31bool CacheDB::ReadyDB(string DB)
32{
c9569a1e
AL
33 int err;
34
b2e465d6
AL
35 ReadOnly = _config->FindB("APT::FTPArchive::ReadOnlyDB",false);
36
37 // Close the old DB
38 if (Dbp != 0)
39 Dbp->close(Dbp,0);
40
41 /* Check if the DB was disabled while running and deal with a
42 corrupted DB */
43 if (DBFailed() == true)
44 {
dc738e7a 45 _error->Warning(_("DB was corrupted, file renamed to %s.old"),DBFile.c_str());
b2e465d6
AL
46 rename(DBFile.c_str(),(DBFile+".old").c_str());
47 }
48
49 DBLoaded = false;
50 Dbp = 0;
51 DBFile = string();
52
53 if (DB.empty())
54 return true;
c9569a1e
AL
55
56 db_create(&Dbp, NULL, 0);
57 if ((err = Dbp->open(Dbp, NULL, DB.c_str(), NULL, DB_HASH,
b2e465d6 58 (ReadOnly?DB_RDONLY:DB_CREATE),
c9569a1e 59 0644)) != 0)
b2e465d6 60 {
c9569a1e
AL
61 if (err == DB_OLD_VERSION)
62 {
63 _error->Warning(_("DB is old, attempting to upgrade %s"),DBFile.c_str());
64 err = Dbp->upgrade(Dbp, DB.c_str(), 0);
65 if (!err)
66 err = Dbp->open(Dbp, NULL, DB.c_str(), NULL, DB_HASH,
67 (ReadOnly?DB_RDONLY:DB_CREATE), 0644);
68
69 }
70 if (err)
71 {
72 Dbp = 0;
73 return _error->Error(_("Unable to open DB file %s: %s"),DB.c_str(), db_strerror(err));
74 }
b2e465d6
AL
75 }
76
77 DBFile = DB;
78 DBLoaded = true;
79 return true;
80}
81 /*}}}*/
82// CacheDB::SetFile - Select a file to be working with /*{{{*/
83// ---------------------------------------------------------------------
84/* All future actions will be performed against this file */
85bool CacheDB::SetFile(string FileName,struct stat St,FileFd *Fd)
86{
87 delete DebFile;
88 DebFile = 0;
89 this->FileName = FileName;
90 this->Fd = Fd;
91 this->FileStat = St;
92 FileStat = St;
93 memset(&CurStat,0,sizeof(CurStat));
94
95 Stats.Bytes += St.st_size;
96 Stats.Packages++;
97
98 if (DBLoaded == false)
99 return true;
100
101 InitQuery("st");
102
103 // Ensure alignment of the returned structure
104 Data.data = &CurStat;
105 Data.ulen = sizeof(CurStat);
106 Data.flags = DB_DBT_USERMEM;
107 // Lookup the stat info and confirm the file is unchanged
108 if (Get() == true)
109 {
c53766c7 110 if (CurStat.mtime != htonl(St.st_mtime))
b2e465d6 111 {
c53766c7 112 CurStat.mtime = htonl(St.st_mtime);
b2e465d6 113 CurStat.Flags = 0;
dc738e7a 114 _error->Warning(_("File date has changed %s"),FileName.c_str());
b2e465d6
AL
115 }
116 }
117 else
118 {
c53766c7 119 CurStat.mtime = htonl(St.st_mtime);
b2e465d6
AL
120 CurStat.Flags = 0;
121 }
122 CurStat.Flags = ntohl(CurStat.Flags);
123 OldStat = CurStat;
124 return true;
125}
126 /*}}}*/
127// CacheDB::LoadControl - Load Control information /*{{{*/
128// ---------------------------------------------------------------------
129/* */
130bool CacheDB::LoadControl()
131{
132 // Try to read the control information out of the DB.
133 if ((CurStat.Flags & FlControl) == FlControl)
134 {
135 // Lookup the control information
136 InitQuery("cl");
137 if (Get() == true && Control.TakeControl(Data.data,Data.size) == true)
138 return true;
139 CurStat.Flags &= ~FlControl;
140 }
141
142 // Create a deb instance to read the archive
143 if (DebFile == 0)
144 {
145 DebFile = new debDebFile(*Fd);
146 if (_error->PendingError() == true)
147 return false;
148 }
149
150 Stats.Misses++;
151 if (Control.Read(*DebFile) == false)
152 return false;
153
154 if (Control.Control == 0)
dc738e7a 155 return _error->Error(_("Archive has no control record"));
b2e465d6
AL
156
157 // Write back the control information
158 InitQuery("cl");
159 if (Put(Control.Control,Control.Length) == true)
160 CurStat.Flags |= FlControl;
161 return true;
162}
163 /*}}}*/
164// CacheDB::LoadContents - Load the File Listing /*{{{*/
165// ---------------------------------------------------------------------
166/* */
167bool CacheDB::LoadContents(bool GenOnly)
168{
169 // Try to read the control information out of the DB.
170 if ((CurStat.Flags & FlContents) == FlContents)
171 {
172 if (GenOnly == true)
173 return true;
174
175 // Lookup the contents information
176 InitQuery("cn");
177 if (Get() == true)
178 {
179 if (Contents.TakeContents(Data.data,Data.size) == true)
180 return true;
181 }
182
183 CurStat.Flags &= ~FlContents;
184 }
185
186 // Create a deb instance to read the archive
187 if (DebFile == 0)
188 {
189 DebFile = new debDebFile(*Fd);
190 if (_error->PendingError() == true)
191 return false;
192 }
193
194 if (Contents.Read(*DebFile) == false)
195 return false;
196
197 // Write back the control information
198 InitQuery("cn");
199 if (Put(Contents.Data,Contents.CurSize) == true)
200 CurStat.Flags |= FlContents;
201 return true;
202}
203 /*}}}*/
204// CacheDB::GetMD5 - Get the MD5 hash /*{{{*/
205// ---------------------------------------------------------------------
206/* */
207bool CacheDB::GetMD5(string &MD5Res,bool GenOnly)
208{
209 // Try to read the control information out of the DB.
210 if ((CurStat.Flags & FlMD5) == FlMD5)
211 {
212 if (GenOnly == true)
213 return true;
214
215 InitQuery("m5");
216 if (Get() == true)
217 {
218 MD5Res = string((char *)Data.data,Data.size);
219 return true;
220 }
221 CurStat.Flags &= ~FlMD5;
222 }
223
224 Stats.MD5Bytes += FileStat.st_size;
225
226 MD5Summation MD5;
227 if (Fd->Seek(0) == false || MD5.AddFD(Fd->Fd(),FileStat.st_size) == false)
228 return false;
229
230 MD5Res = MD5.Result();
231 InitQuery("m5");
812f4169 232 if (Put(MD5Res.c_str(),MD5Res.length()) == true)
b2e465d6
AL
233 CurStat.Flags |= FlMD5;
234 return true;
235}
236 /*}}}*/
237// CacheDB::Finish - Write back the cache structure /*{{{*/
238// ---------------------------------------------------------------------
239/* */
240bool CacheDB::Finish()
241{
242 // Optimize away some writes.
243 if (CurStat.Flags == OldStat.Flags &&
9bfe66dc 244 CurStat.mtime == OldStat.mtime)
b2e465d6
AL
245 return true;
246
247 // Write the stat information
248 CurStat.Flags = htonl(CurStat.Flags);
249 InitQuery("st");
250 Put(&CurStat,sizeof(CurStat));
251 CurStat.Flags = ntohl(CurStat.Flags);
252 return true;
253}
254 /*}}}*/
255// CacheDB::Clean - Clean the Database /*{{{*/
256// ---------------------------------------------------------------------
257/* Tidy the database by removing files that no longer exist at all. */
258bool CacheDB::Clean()
259{
260 if (DBLoaded == false)
261 return true;
262
263 /* I'm not sure what VERSION_MINOR should be here.. 2.4.14 certainly
264 needs the lower one and 2.7.7 needs the upper.. */
b2e465d6 265 DBC *Cursor;
c9569a1e 266 if ((errno = Dbp->cursor(Dbp, NULL, &Cursor, 0)) != 0)
dc738e7a 267 return _error->Error(_("Unable to get a cursor"));
b2e465d6
AL
268
269 DBT Key;
270 DBT Data;
271 memset(&Key,0,sizeof(Key));
272 memset(&Data,0,sizeof(Data));
273 while ((errno = Cursor->c_get(Cursor,&Key,&Data,DB_NEXT)) == 0)
274 {
275 const char *Colon = (char *)Key.data;
276 for (; Colon != (char *)Key.data+Key.size && *Colon != ':'; Colon++);
277 if ((char *)Key.data+Key.size - Colon > 2)
278 {
279 if (stringcmp((char *)Key.data,Colon,"st") == 0 ||
280 stringcmp((char *)Key.data,Colon,"cn") == 0 ||
281 stringcmp((char *)Key.data,Colon,"m5") == 0 ||
282 stringcmp((char *)Key.data,Colon,"cl") == 0)
283 {
284 if (FileExists(string(Colon+1,(const char *)Key.data+Key.size)) == true)
285 continue;
286 }
287 }
288
289 Cursor->c_del(Cursor,0);
290 }
291
292 return true;
293}
294 /*}}}*/