pkgcachegen.cc 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355
  1. // -*- mode: cpp; mode: fold -*-
  2. // Description /*{{{*/
  3. // $Id: pkgcachegen.cc,v 1.5 1998/07/05 05:39:53 jgg Exp $
  4. /* ######################################################################
  5. Package Cache Generator - Generator for the cache structure.
  6. This builds the cache structure from the abstract package list parser.
  7. ##################################################################### */
  8. /*}}}*/
  9. // Include Files /*{{{*/
  10. #include <pkglib/pkgcachegen.h>
  11. #include <pkglib/error.h>
  12. #include <pkglib/version.h>
  13. #include <sys/stat.h>
  14. #include <unistd.h>
  15. /*}}}*/
  16. // CacheGenerator::pkgCacheGenerator - Constructor /*{{{*/
  17. // ---------------------------------------------------------------------
  18. /* We set the diry flag and make sure that is written to the disk */
  19. pkgCacheGenerator::pkgCacheGenerator(DynamicMMap &Map) : Map(Map), Cache(Map)
  20. {
  21. if (_error->PendingError() == true)
  22. return;
  23. if (Map.Size() == 0)
  24. {
  25. Map.RawAllocate(sizeof(pkgCache::Header));
  26. *Cache.HeaderP = pkgCache::Header();
  27. }
  28. Cache.HeaderP->Dirty = true;
  29. Map.Sync(0,sizeof(pkgCache::Header));
  30. Map.UsePools(*Cache.HeaderP->Pools,sizeof(Cache.HeaderP->Pools)/sizeof(Cache.HeaderP->Pools[0]));
  31. }
  32. /*}}}*/
  33. // CacheGenerator::~pkgCacheGenerator - Destructor /*{{{*/
  34. // ---------------------------------------------------------------------
  35. /* We sync the data then unset the dirty flag in two steps so as to
  36. advoid a problem during a crash */
  37. pkgCacheGenerator::~pkgCacheGenerator()
  38. {
  39. if (_error->PendingError() == true)
  40. return;
  41. if (Map.Sync() == false)
  42. return;
  43. Cache.HeaderP->Dirty = false;
  44. Map.Sync(0,sizeof(pkgCache::Header));
  45. }
  46. /*}}}*/
  47. // CacheGenerator::MergeList - Merge the package list /*{{{*/
  48. // ---------------------------------------------------------------------
  49. /* This provides the generation of the entries in the cache. Each loop
  50. goes through a single package record from the underlying parse engine. */
  51. bool pkgCacheGenerator::MergeList(ListParser &List)
  52. {
  53. List.Owner = this;
  54. while (List.Step() == true)
  55. {
  56. // Get a pointer to the package structure
  57. string PackageName = List.Package();
  58. pkgCache::PkgIterator Pkg;
  59. Cache.FindPkg(PackageName);
  60. if (Pkg.end() == true)
  61. {
  62. if (NewPackage(Pkg,PackageName) == false)
  63. return false;
  64. }
  65. /* Get a pointer to the version structure. We know the list is sorted
  66. so we use that fact in the search. Insertion of new versions is
  67. done with correct sorting */
  68. string Version = List.Version();
  69. if (Version.empty() == true)
  70. {
  71. if (List.UsePackage(Pkg,pkgCache::VerIterator(Cache)) == false)
  72. return false;
  73. continue;
  74. }
  75. pkgCache::VerIterator Ver = Pkg.VersionList();
  76. unsigned long *Last = &Pkg->VersionList;
  77. int Res;
  78. for (; Ver.end() == false; Last = &Ver->NextVer, Ver++)
  79. {
  80. Res = pkgVersionCompare(Version.begin(),Version.end(),Ver.VerStr(),
  81. Ver.VerStr() + strlen(Ver.VerStr()));
  82. if (Res >= 0)
  83. break;
  84. }
  85. /* We already have a version for this item, record that we
  86. saw it */
  87. if (Res == 0)
  88. {
  89. if (List.UsePackage(Pkg,Ver) == false)
  90. return false;
  91. if (NewFileVer(Ver,List) == false)
  92. return false;
  93. continue;
  94. }
  95. // Add a new version
  96. *Last = NewVersion(Ver,Version,*Last);
  97. Ver->ParentPkg = Pkg.Index();
  98. if (List.NewVersion(Ver) == false)
  99. return false;
  100. if (List.UsePackage(Pkg,Ver) == false)
  101. return false;
  102. if (NewFileVer(Ver,List) == false)
  103. return false;
  104. }
  105. return true;
  106. }
  107. /*}}}*/
  108. // CacheGenerator::NewPackage - Add a new package /*{{{*/
  109. // ---------------------------------------------------------------------
  110. /* This creates a new package structure and adds it to the hash table */
  111. bool pkgCacheGenerator::NewPackage(pkgCache::PkgIterator &Pkg,string Name)
  112. {
  113. // Get a structure
  114. unsigned long Package = Map.Allocate(sizeof(pkgCache::Package));
  115. if (Package == 0)
  116. return false;
  117. Pkg = pkgCache::PkgIterator(Cache,Cache.PkgP + Package);
  118. // Insert it into the hash table
  119. unsigned long Hash = Cache.Hash(Name);
  120. Pkg->NextPackage = Cache.HeaderP->HashTable[Hash];
  121. Cache.HeaderP->HashTable[Hash] = Package;
  122. // Set the name and the ID
  123. Pkg->Name = Map.WriteString(Name);
  124. if (Pkg->Name == 0)
  125. return false;
  126. Pkg->ID = Cache.HeaderP->PackageCount++;
  127. return true;
  128. }
  129. /*}}}*/
  130. // CacheGenerator::NewFileVer - Create a new File<->Version association /*{{{*/
  131. // ---------------------------------------------------------------------
  132. /* */
  133. bool pkgCacheGenerator::NewFileVer(pkgCache::VerIterator &Ver,
  134. ListParser &List)
  135. {
  136. // Get a structure
  137. unsigned long VerFile = Map.Allocate(sizeof(pkgCache::VerFile));
  138. if (VerFile == 0)
  139. return 0;
  140. pkgCache::VerFileIterator VF(Cache,Cache.VerFileP + VerFile);
  141. VF->File = CurrentFile - Cache.PkgFileP;
  142. VF->NextFile = Ver->FileList;
  143. Ver->FileList = VF.Index();
  144. VF->Offset = List.Offset();
  145. VF->Size = List.Size();
  146. return true;
  147. }
  148. /*}}}*/
  149. // CacheGenerator::NewVersion - Create a new Version /*{{{*/
  150. // ---------------------------------------------------------------------
  151. /* This puts a version structure in the linked list */
  152. unsigned long pkgCacheGenerator::NewVersion(pkgCache::VerIterator &Ver,
  153. string VerStr,
  154. unsigned long Next)
  155. {
  156. // Get a structure
  157. unsigned long Version = Map.Allocate(sizeof(pkgCache::Version));
  158. if (Version == 0)
  159. return 0;
  160. // Fill it in
  161. Ver = pkgCache::VerIterator(Cache,Cache.VerP + Version);
  162. Ver->NextVer = Next;
  163. Ver->ID = Cache.HeaderP->VersionCount++;
  164. Ver->VerStr = Map.WriteString(VerStr);
  165. if (Ver->VerStr == 0)
  166. return 0;
  167. return Version;
  168. }
  169. /*}}}*/
  170. // ListParser::NewDepends - Create a dependency element /*{{{*/
  171. // ---------------------------------------------------------------------
  172. /* This creates a dependency element in the tree. It is linked to the
  173. version and to the package that it is pointing to. */
  174. bool pkgCacheGenerator::ListParser::NewDepends(pkgCache::VerIterator Ver,
  175. string PackageName,
  176. string Version,
  177. unsigned int Op,
  178. unsigned int Type)
  179. {
  180. pkgCache &Cache = Owner->Cache;
  181. // Get a structure
  182. unsigned long Dependency = Owner->Map.Allocate(sizeof(pkgCache::Dependency));
  183. if (Dependency == 0)
  184. return false;
  185. // Fill it in
  186. pkgCache::DepIterator Dep(Cache,Cache.DepP + Dependency);
  187. Dep->ParentVer = Ver.Index();
  188. Dep->Type = Type;
  189. Dep->CompareOp = Op;
  190. Dep->ID = Cache.HeaderP->DependsCount++;
  191. // Locate the target package
  192. pkgCache::PkgIterator Pkg = Cache.FindPkg(PackageName);
  193. if (Pkg.end() == true)
  194. if (Owner->NewPackage(Pkg,PackageName) == false)
  195. return false;
  196. // Probe the reverse dependency list for a version string that matches
  197. if (Version.empty() == false)
  198. {
  199. for (pkgCache::DepIterator I = Pkg.RevDependsList(); I.end() == false; I++)
  200. if (I->Version != 0 && I.TargetVer() == Version)
  201. Dep->Version = I->Version;
  202. if (Dep->Version == 0)
  203. if ((Dep->Version = WriteString(Version)) == 0)
  204. return false;
  205. }
  206. // Link it to the package
  207. Dep->Package = Pkg.Index();
  208. Dep->NextRevDepends = Pkg->RevDepends;
  209. Pkg->RevDepends = Dep.Index();
  210. // Link it to the version (at the end of the list)
  211. unsigned long *Last = &Ver->DependsList;
  212. for (pkgCache::DepIterator D = Ver.DependsList(); D.end() == false; D++)
  213. Last = &D->NextDepends;
  214. Dep->NextDepends = *Last;
  215. *Last = Dep.Index();
  216. return true;
  217. }
  218. /*}}}*/
  219. // ListParser::NewProvides - Create a Provides element /*{{{*/
  220. // ---------------------------------------------------------------------
  221. /* */
  222. bool pkgCacheGenerator::ListParser::NewProvides(pkgCache::VerIterator Ver,
  223. string PackageName,
  224. string Version)
  225. {
  226. pkgCache &Cache = Owner->Cache;
  227. // Get a structure
  228. unsigned long Provides = Owner->Map.Allocate(sizeof(pkgCache::Provides));
  229. if (Provides == 0)
  230. return false;
  231. // Fill it in
  232. pkgCache::PrvIterator Prv(Cache,Cache.ProvideP + Provides,Cache.PkgP);
  233. Prv->Version = Ver.Index();
  234. Prv->NextPkgProv = Ver->ProvidesList;
  235. Ver->ProvidesList = Prv.Index();
  236. if (Version.empty() == false && (Prv->Version = WriteString(Version)) == 0)
  237. return false;
  238. // Locate the target package
  239. pkgCache::PkgIterator Pkg = Cache.FindPkg(PackageName);
  240. if (Pkg.end() == true)
  241. if (Owner->NewPackage(Pkg,PackageName) == false)
  242. return false;
  243. // Link it to the package
  244. Prv->ParentPkg = Pkg.Index();
  245. Prv->NextProvides = Pkg->ProvidesList;
  246. Pkg->ProvidesList = Prv.Index();
  247. return true;
  248. }
  249. /*}}}*/
  250. // CacheGenerator::SelectFile - Select the current file being parsed /*{{{*/
  251. // ---------------------------------------------------------------------
  252. /* This is used to select which file is to be associated with all newly
  253. added versions. */
  254. bool pkgCacheGenerator::SelectFile(string File,unsigned long Flags)
  255. {
  256. struct stat Buf;
  257. if (stat(File.c_str(),&Buf) == -1)
  258. return _error->Errno("stat","Couldn't stat ",File.c_str());
  259. // Get some space for the structure
  260. CurrentFile = Cache.PkgFileP + Map.Allocate(sizeof(*CurrentFile));
  261. if (CurrentFile == Cache.PkgFileP)
  262. return false;
  263. // Fill it in
  264. CurrentFile->FileName = Map.WriteString(File);
  265. CurrentFile->Size = Buf.st_size;
  266. CurrentFile->mtime = Buf.st_mtime;
  267. CurrentFile->NextFile = Cache.HeaderP->FileList;
  268. CurrentFile->Flags = Flags;
  269. PkgFileName = File;
  270. if (CurrentFile->FileName == 0)
  271. return false;
  272. }
  273. /*}}}*/
  274. // CacheGenerator::WriteUniqueString - Insert a unique string /*{{{*/
  275. // ---------------------------------------------------------------------
  276. /* This is used to create handles to strings. Given the same text it
  277. always returns the same number */
  278. unsigned long pkgCacheGenerator::WriteUniqString(const char *S,
  279. unsigned int Size)
  280. {
  281. // Search for an insertion point
  282. pkgCache::StringItem *I = Cache.StringItemP + Cache.HeaderP->StringList;
  283. int Res = 1;
  284. unsigned long *Last = &Cache.HeaderP->StringList;
  285. for (; I != Cache.StringItemP; Last = &I->NextItem,
  286. I = Cache.StringItemP + I->NextItem)
  287. {
  288. Res = strncmp(Cache.StrP + I->String,S,Size);
  289. if (Res == 0 && *(Cache.StrP + I->String + Size) != 0)
  290. Res = 1;
  291. if (Res >= 0)
  292. break;
  293. }
  294. // Match
  295. if (Res == 0)
  296. return I->String;
  297. // Get a structure
  298. unsigned long Item = Map.Allocate(sizeof(pkgCache::StringItem));
  299. if (Item == 0)
  300. return 0;
  301. // Fill in the structure
  302. pkgCache::StringItem *ItemP = Cache.StringItemP + Item;
  303. ItemP->NextItem = I - Cache.StringItemP;
  304. *Last = Item;
  305. ItemP->String = Map.WriteString(S,Size);
  306. if (ItemP->String == 0)
  307. return 0;
  308. return ItemP->String;
  309. }
  310. /*}}}*/