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