cachedb.cc 7.8 KB

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