cachedb.cc 7.5 KB

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