parse.c 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650
  1. /*
  2. * libdpkg - Debian packaging suite library routines
  3. * parse.c - database file parsing, main package/field loop
  4. *
  5. * Copyright © 1995 Ian Jackson <ian@chiark.greenend.org.uk>
  6. * Copyright © 2006,2008-2011 Guillem Jover <guillem@debian.org>
  7. *
  8. * This is free software; you can redistribute it and/or modify
  9. * it under the terms of the GNU General Public License as published by
  10. * the Free Software Foundation; either version 2 of the License, or
  11. * (at your option) any later version.
  12. *
  13. * This is distributed in the hope that it will be useful,
  14. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  15. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  16. * GNU General Public License for more details.
  17. *
  18. * You should have received a copy of the GNU General Public License
  19. * along with this program. If not, see <http://www.gnu.org/licenses/>.
  20. */
  21. #include <config.h>
  22. #include <compat.h>
  23. #include <sys/types.h>
  24. #include <sys/stat.h>
  25. #ifdef USE_MMAP
  26. #include <sys/mman.h>
  27. #endif
  28. #include <assert.h>
  29. #include <fcntl.h>
  30. #include <ctype.h>
  31. #include <string.h>
  32. #include <unistd.h>
  33. #include <stdarg.h>
  34. #include <stdlib.h>
  35. #include <stdio.h>
  36. #include <dpkg/macros.h>
  37. #include <dpkg/i18n.h>
  38. #include <dpkg/dpkg.h>
  39. #include <dpkg/dpkg-db.h>
  40. #include <dpkg/parsedump.h>
  41. #include <dpkg/fdio.h>
  42. /**
  43. * Fields information.
  44. */
  45. const struct fieldinfo fieldinfos[]= {
  46. /* Note: Capitalization of field name strings is important. */
  47. { "Package", f_name, w_name },
  48. { "Essential", f_boolean, w_booleandefno, PKGIFPOFF(essential) },
  49. { "Status", f_status, w_status },
  50. { "Multi-Arch", f_multiarch, w_multiarch, PKGIFPOFF(multiarch) },
  51. { "Priority", f_priority, w_priority },
  52. { "Section", f_section, w_section },
  53. { "Installed-Size", f_charfield, w_charfield, PKGIFPOFF(installedsize) },
  54. { "Origin", f_charfield, w_charfield, PKGIFPOFF(origin) },
  55. { "Maintainer", f_charfield, w_charfield, PKGIFPOFF(maintainer) },
  56. { "Bugs", f_charfield, w_charfield, PKGIFPOFF(bugs) },
  57. { "Architecture", f_architecture, w_architecture },
  58. { "Source", f_charfield, w_charfield, PKGIFPOFF(source) },
  59. { "Version", f_version, w_version, PKGIFPOFF(version) },
  60. { "Revision", f_revision, w_null },
  61. { "Config-Version", f_configversion, w_configversion },
  62. { "Replaces", f_dependency, w_dependency, dep_replaces },
  63. { "Provides", f_dependency, w_dependency, dep_provides },
  64. { "Depends", f_dependency, w_dependency, dep_depends },
  65. { "Pre-Depends", f_dependency, w_dependency, dep_predepends },
  66. { "Recommends", f_dependency, w_dependency, dep_recommends },
  67. { "Suggests", f_dependency, w_dependency, dep_suggests },
  68. { "Breaks", f_dependency, w_dependency, dep_breaks },
  69. { "Conflicts", f_dependency, w_dependency, dep_conflicts },
  70. { "Enhances", f_dependency, w_dependency, dep_enhances },
  71. { "Conffiles", f_conffiles, w_conffiles },
  72. { "Filename", f_filecharf, w_filecharf, FILEFOFF(name) },
  73. { "Size", f_filecharf, w_filecharf, FILEFOFF(size) },
  74. { "MD5sum", f_filecharf, w_filecharf, FILEFOFF(md5sum) },
  75. { "MSDOS-Filename", f_filecharf, w_filecharf, FILEFOFF(msdosname) },
  76. { "Description", f_charfield, w_charfield, PKGIFPOFF(description) },
  77. { "Triggers-Pending", f_trigpend, w_trigpend },
  78. { "Triggers-Awaited", f_trigaw, w_trigaw },
  79. /* Note that aliases are added to the nicknames table. */
  80. { NULL }
  81. };
  82. static const struct nickname nicknames[] = {
  83. /* Note: Capitalization of these strings is important. */
  84. { .nick = "Recommended", .canon = "Recommends" },
  85. { .nick = "Optional", .canon = "Suggests" },
  86. { .nick = "Class", .canon = "Priority" },
  87. { .nick = "Package-Revision", .canon = "Revision" },
  88. { .nick = "Package_Revision", .canon = "Revision" },
  89. { .nick = NULL }
  90. };
  91. /**
  92. * Package object being parsed.
  93. *
  94. * Structure used to hold the parsed data for the package being constructed,
  95. * before it gets properly inserted into the package database.
  96. */
  97. struct pkg_parse_object {
  98. struct pkginfo *pkg;
  99. struct pkgbin *pkgbin;
  100. };
  101. /**
  102. * Parse the field and value into the package being constructed.
  103. */
  104. static void
  105. pkg_parse_field(struct parsedb_state *ps, struct field_state *fs,
  106. void *parse_obj)
  107. {
  108. struct pkg_parse_object *pkg_obj = parse_obj;
  109. const struct nickname *nick;
  110. const struct fieldinfo *fip;
  111. int *ip;
  112. for (nick = nicknames; nick->nick; nick++)
  113. if (strncasecmp(nick->nick, fs->fieldstart, fs->fieldlen) == 0 &&
  114. nick->nick[fs->fieldlen] == '\0')
  115. break;
  116. if (nick->nick) {
  117. fs->fieldstart = nick->canon;
  118. fs->fieldlen = strlen(fs->fieldstart);
  119. }
  120. for (fip = fieldinfos, ip = fs->fieldencountered; fip->name; fip++, ip++)
  121. if (strncasecmp(fip->name, fs->fieldstart, fs->fieldlen) == 0)
  122. break;
  123. if (fip->name) {
  124. if ((*ip)++)
  125. parse_error(ps,
  126. _("duplicate value for `%s' field"), fip->name);
  127. varbuf_reset(&fs->value);
  128. varbuf_add_buf(&fs->value, fs->valuestart, fs->valuelen);
  129. varbuf_end_str(&fs->value);
  130. fip->rcall(pkg_obj->pkg, pkg_obj->pkgbin, ps, fs->value.buf, fip);
  131. } else {
  132. struct arbitraryfield *arp, **larpp;
  133. if (fs->fieldlen < 2)
  134. parse_error(ps,
  135. _("user-defined field name `%.*s' too short"),
  136. fs->fieldlen, fs->fieldstart);
  137. larpp = &pkg_obj->pkgbin->arbs;
  138. while ((arp = *larpp) != NULL) {
  139. if (!strncasecmp(arp->name, fs->fieldstart, fs->fieldlen))
  140. parse_error(ps,
  141. _("duplicate value for user-defined field `%.*s'"),
  142. fs->fieldlen, fs->fieldstart);
  143. larpp = &arp->next;
  144. }
  145. arp = nfmalloc(sizeof(struct arbitraryfield));
  146. arp->name = nfstrnsave(fs->fieldstart, fs->fieldlen);
  147. arp->value = nfstrnsave(fs->valuestart, fs->valuelen);
  148. arp->next = NULL;
  149. *larpp = arp;
  150. }
  151. }
  152. /**
  153. * Verify and fixup the package structure being constructed.
  154. */
  155. static void
  156. pkg_parse_verify(struct parsedb_state *ps,
  157. struct pkginfo *pkg, struct pkgbin *pkgbin)
  158. {
  159. parse_must_have_field(ps, pkg->name, "package name");
  160. /* XXX: We need to check for status != stat_halfinstalled as while
  161. * unpacking an unselected package, it will not have yet all data in
  162. * place. But we cannot check for > stat_halfinstalled as stat_configfiles
  163. * always should have those fields. */
  164. if ((ps->flags & pdb_recordavailable) ||
  165. (pkg->status != stat_notinstalled &&
  166. pkg->status != stat_halfinstalled)) {
  167. parse_ensure_have_field(ps, &pkgbin->description, "description");
  168. parse_ensure_have_field(ps, &pkgbin->maintainer, "maintainer");
  169. parse_must_have_field(ps, pkgbin->version.version, "version");
  170. }
  171. /* XXX: Versions before dpkg 1.10.19 did not preserve the Architecture
  172. * field in the status file. So there's still live systems with packages
  173. * in stat_configfiles, ignore those too for now. */
  174. if ((ps->flags & pdb_recordavailable) ||
  175. pkg->status > stat_halfinstalled) {
  176. /* We always want usable architecture information (as long as the package
  177. * is in such a state that it make sense), so that it can be used safely
  178. * on string comparisons and the like. */
  179. if (pkgbin->arch == NULL)
  180. parse_warn(ps, _("missing %s"), "architecture");
  181. else if (pkgbin->arch->type == arch_none)
  182. parse_warn(ps, _("empty value for %s"), "architecture");
  183. }
  184. if (pkgbin->arch == NULL)
  185. pkgbin->arch = dpkg_arch_find(NULL);
  186. /* Check the Config-Version information:
  187. * If there is a Config-Version it is definitely to be used, but
  188. * there shouldn't be one if the package is ‘installed’ (in which case
  189. * the Version and/or Revision will be copied) or if the package is
  190. * ‘not-installed’ (in which case there is no Config-Version). */
  191. if (!(ps->flags & pdb_recordavailable)) {
  192. if (pkg->configversion.version) {
  193. if (pkg->status == stat_installed || pkg->status == stat_notinstalled)
  194. parse_error(ps,
  195. _("Configured-Version for package with inappropriate Status"));
  196. } else {
  197. if (pkg->status == stat_installed)
  198. pkg->configversion = pkgbin->version;
  199. }
  200. }
  201. if (pkg->trigaw.head &&
  202. (pkg->status <= stat_configfiles ||
  203. pkg->status >= stat_triggerspending))
  204. parse_error(ps,
  205. _("package has status %s but triggers are awaited"),
  206. statusinfos[pkg->status].name);
  207. else if (pkg->status == stat_triggersawaited && !pkg->trigaw.head)
  208. parse_error(ps,
  209. _("package has status triggers-awaited but no triggers awaited"));
  210. if (pkg->trigpend_head &&
  211. !(pkg->status == stat_triggerspending ||
  212. pkg->status == stat_triggersawaited))
  213. parse_error(ps,
  214. _("package has status %s but triggers are pending"),
  215. statusinfos[pkg->status].name);
  216. else if (pkg->status == stat_triggerspending && !pkg->trigpend_head)
  217. parse_error(ps,
  218. _("package has status triggers-pending but no triggers "
  219. "pending"));
  220. /* FIXME: There was a bug that could make a not-installed package have
  221. * conffiles, so we check for them here and remove them (rather than
  222. * calling it an error, which will do at some point). */
  223. if (!(ps->flags & pdb_recordavailable) &&
  224. pkg->status == stat_notinstalled &&
  225. pkgbin->conffiles) {
  226. parse_warn(ps,
  227. _("Package which in state not-installed has conffiles, "
  228. "forgetting them"));
  229. pkgbin->conffiles = NULL;
  230. }
  231. /* XXX: Mark not-installed leftover packages for automatic removal on
  232. * next database dump. This code can be removed after dpkg 1.16.x, when
  233. * there's guarantee that no leftover is found on the status file on
  234. * major distributions. */
  235. if (!(ps->flags & pdb_recordavailable) &&
  236. pkg->status == stat_notinstalled &&
  237. pkg->eflag == eflag_ok &&
  238. (pkg->want == want_purge ||
  239. pkg->want == want_deinstall ||
  240. pkg->want == want_hold)) {
  241. pkg->want = want_unknown;
  242. }
  243. }
  244. /**
  245. * Copy into the in-core database the package being constructed.
  246. */
  247. static void
  248. pkg_parse_copy(struct parsedb_state *ps,
  249. struct pkginfo *dst_pkg, struct pkgbin *dst_pkgbin,
  250. struct pkginfo *src_pkg, struct pkgbin *src_pkgbin)
  251. {
  252. /* Copy the priority and section across, but don't overwrite existing
  253. * values if the pdb_weakclassification flag is set. */
  254. if (src_pkg->section && *src_pkg->section &&
  255. !((ps->flags & pdb_weakclassification) &&
  256. dst_pkg->section && *dst_pkg->section))
  257. dst_pkg->section = src_pkg->section;
  258. if (src_pkg->priority != pri_unknown &&
  259. !((ps->flags & pdb_weakclassification) &&
  260. dst_pkg->priority != pri_unknown)) {
  261. dst_pkg->priority = src_pkg->priority;
  262. if (src_pkg->priority == pri_other)
  263. dst_pkg->otherpriority = src_pkg->otherpriority;
  264. }
  265. /* Sort out the dependency mess. */
  266. copy_dependency_links(dst_pkg, &dst_pkgbin->depends, src_pkgbin->depends,
  267. (ps->flags & pdb_recordavailable) ? true : false);
  268. /* Leave the ‘depended’ pointer alone, we've just gone to such
  269. * trouble to get it right :-). The ‘depends’ pointer in
  270. * dst_pkgbin was indeed also updated by copy_dependency_links,
  271. * but since the value was that from src_pkgbin anyway there's
  272. * no need to copy it back. */
  273. src_pkgbin->depended = dst_pkgbin->depended;
  274. /* Copy across data. */
  275. memcpy(dst_pkgbin, src_pkgbin, sizeof(struct pkgbin));
  276. if (!(ps->flags & pdb_recordavailable)) {
  277. struct trigaw *ta;
  278. dst_pkg->want = src_pkg->want;
  279. dst_pkg->eflag = src_pkg->eflag;
  280. dst_pkg->status = src_pkg->status;
  281. dst_pkg->configversion = src_pkg->configversion;
  282. dst_pkg->files = NULL;
  283. dst_pkg->trigpend_head = src_pkg->trigpend_head;
  284. dst_pkg->trigaw = src_pkg->trigaw;
  285. for (ta = dst_pkg->trigaw.head; ta; ta = ta->sameaw.next) {
  286. assert(ta->aw == src_pkg);
  287. ta->aw = dst_pkg;
  288. /* ->othertrigaw_head is updated by trig_note_aw in *(pkg_db_find())
  289. * rather than in dst_pkg. */
  290. }
  291. } else if (!(ps->flags & pdb_ignorefiles)) {
  292. dst_pkg->files = src_pkg->files;
  293. }
  294. }
  295. /**
  296. * Open a file for RFC-822 parsing.
  297. */
  298. void
  299. parse_open(struct parsedb_state *ps, const char *filename,
  300. enum parsedbflags flags)
  301. {
  302. static int fd;
  303. struct stat st;
  304. ps->filename = filename;
  305. ps->flags = flags;
  306. ps->lno = 0;
  307. ps->pkg = NULL;
  308. ps->pkgbin = NULL;
  309. fd = open(filename, O_RDONLY);
  310. if (fd == -1)
  311. ohshite(_("failed to open package info file `%.255s' for reading"),
  312. filename);
  313. push_cleanup(cu_closefd, ~ehflag_normaltidy, NULL, 0, 1, &fd);
  314. if (fstat(fd, &st) == -1)
  315. ohshite(_("can't stat package info file `%.255s'"), filename);
  316. if (st.st_size > 0) {
  317. #ifdef USE_MMAP
  318. ps->dataptr = mmap(NULL, st.st_size, PROT_READ, MAP_SHARED, fd, 0);
  319. if (ps->dataptr == MAP_FAILED)
  320. ohshite(_("can't mmap package info file `%.255s'"), filename);
  321. #else
  322. ps->dataptr = m_malloc(st.st_size);
  323. if (fd_read(fd, ps->dataptr, st.st_size) < 0)
  324. ohshite(_("reading package info file '%.255s'"), filename);
  325. #endif
  326. ps->data = ps->dataptr;
  327. ps->endptr = ps->dataptr + st.st_size;
  328. } else {
  329. ps->data = ps->dataptr = ps->endptr = NULL;
  330. }
  331. pop_cleanup(ehflag_normaltidy);
  332. if (close(fd))
  333. ohshite(_("failed to close after read: `%.255s'"), filename);
  334. }
  335. /**
  336. * Parse an RFC-822 style stanza.
  337. */
  338. bool
  339. parse_stanza(struct parsedb_state *ps, struct field_state *fs,
  340. parse_field_func *parse_field, void *parse_obj)
  341. {
  342. int c;
  343. /* Skip adjacent new lines. */
  344. while (!parse_EOF(ps)) {
  345. c = parse_getc(ps);
  346. if (c != '\n' && c != MSDOS_EOF_CHAR)
  347. break;
  348. ps->lno++;
  349. }
  350. /* Nothing relevant parsed, bail out. */
  351. if (parse_EOF(ps))
  352. return false;
  353. /* Loop per field. */
  354. for (;;) {
  355. bool blank_line;
  356. /* Scan field name. */
  357. fs->fieldstart = ps->dataptr - 1;
  358. while (!parse_EOF(ps) && !isspace(c) && c != ':' && c != MSDOS_EOF_CHAR)
  359. c = parse_getc(ps);
  360. fs->fieldlen = ps->dataptr - fs->fieldstart - 1;
  361. /* Skip spaces before ‘:’. */
  362. while (!parse_EOF(ps) && c != '\n' && isspace(c))
  363. c = parse_getc(ps);
  364. /* Validate ‘:’. */
  365. if (parse_EOF(ps))
  366. parse_error(ps,
  367. _("EOF after field name `%.*s'"), fs->fieldlen, fs->fieldstart);
  368. if (c == '\n')
  369. parse_error(ps,
  370. _("newline in field name `%.*s'"), fs->fieldlen, fs->fieldstart);
  371. if (c == MSDOS_EOF_CHAR)
  372. parse_error(ps,
  373. _("MSDOS EOF (^Z) in field name `%.*s'"),
  374. fs->fieldlen, fs->fieldstart);
  375. if (c != ':')
  376. parse_error(ps,
  377. _("field name `%.*s' must be followed by colon"),
  378. fs->fieldlen, fs->fieldstart);
  379. /* Skip space after ‘:’ but before value and EOL. */
  380. while (!parse_EOF(ps)) {
  381. c = parse_getc(ps);
  382. if (c == '\n' || !isspace(c))
  383. break;
  384. }
  385. if (parse_EOF(ps))
  386. parse_error(ps,
  387. _("EOF before value of field `%.*s' (missing final newline)"),
  388. fs->fieldlen, fs->fieldstart);
  389. if (c == MSDOS_EOF_CHAR)
  390. parse_error(ps,
  391. _("MSDOS EOF char in value of field `%.*s' (missing newline?)"),
  392. fs->fieldlen, fs->fieldstart);
  393. blank_line = false;
  394. /* Scan field value. */
  395. fs->valuestart = ps->dataptr - 1;
  396. for (;;) {
  397. if (c == '\n' || c == MSDOS_EOF_CHAR) {
  398. if (blank_line)
  399. parse_error(ps,
  400. _("blank line in value of field '%.*s'"),
  401. fs->fieldlen, fs->fieldstart);
  402. ps->lno++;
  403. if (parse_EOF(ps))
  404. break;
  405. c = parse_getc(ps);
  406. /* Found double EOL, or start of new field. */
  407. if (parse_EOF(ps) || c == '\n' || !isspace(c))
  408. break;
  409. parse_ungetc(c, ps);
  410. c = '\n';
  411. blank_line = true;
  412. } else if (blank_line && !isspace(c)) {
  413. blank_line = false;
  414. }
  415. if (parse_EOF(ps))
  416. parse_error(ps,
  417. _("EOF during value of field `%.*s' (missing final newline)"),
  418. fs->fieldlen, fs->fieldstart);
  419. c = parse_getc(ps);
  420. }
  421. fs->valuelen = ps->dataptr - fs->valuestart - 1;
  422. /* Trim ending space on value. */
  423. while (fs->valuelen && isspace(*(fs->valuestart + fs->valuelen - 1)))
  424. fs->valuelen--;
  425. parse_field(ps, fs, parse_obj);
  426. if (parse_EOF(ps) || c == '\n' || c == MSDOS_EOF_CHAR)
  427. break;
  428. } /* Loop per field. */
  429. if (c == '\n')
  430. ps->lno++;
  431. return true;
  432. }
  433. /**
  434. * Close an RFC-822 parser context.
  435. */
  436. void
  437. parse_close(struct parsedb_state *ps)
  438. {
  439. if (ps->data != NULL) {
  440. #ifdef USE_MMAP
  441. munmap(ps->data, ps->endptr - ps->data);
  442. #else
  443. free(ps->data);
  444. #endif
  445. }
  446. }
  447. /**
  448. * Parse an RFC-822 style file.
  449. *
  450. * donep may be NULL.
  451. * If donep is not NULL only one package's information is expected.
  452. */
  453. int parsedb(const char *filename, enum parsedbflags flags,
  454. struct pkginfo **donep)
  455. {
  456. struct pkginfo tmp_pkg;
  457. struct pkginfo *new_pkg, *db_pkg;
  458. struct pkgbin *new_pkgbin, *db_pkgbin;
  459. struct pkg_parse_object pkg_obj;
  460. int fieldencountered[array_count(fieldinfos)];
  461. int pdone;
  462. struct parsedb_state ps;
  463. struct field_state fs;
  464. memset(&fs, 0, sizeof(fs));
  465. fs.fieldencountered = fieldencountered;
  466. parse_open(&ps, filename, flags);
  467. new_pkg = &tmp_pkg;
  468. if (flags & pdb_recordavailable)
  469. new_pkgbin = &new_pkg->available;
  470. else
  471. new_pkgbin = &new_pkg->installed;
  472. ps.pkg = new_pkg;
  473. ps.pkgbin = new_pkgbin;
  474. pkg_obj.pkg = new_pkg;
  475. pkg_obj.pkgbin = new_pkgbin;
  476. pdone= 0;
  477. /* Loop per package. */
  478. for (;;) {
  479. memset(fieldencountered, 0, sizeof(fieldencountered));
  480. pkg_blank(new_pkg);
  481. if (!parse_stanza(&ps, &fs, pkg_parse_field, &pkg_obj))
  482. break;
  483. if (pdone && donep)
  484. parse_error(&ps,
  485. _("several package info entries found, only one allowed"));
  486. pkg_parse_verify(&ps, new_pkg, new_pkgbin);
  487. db_pkg = pkg_db_find(new_pkg->name);
  488. if (flags & pdb_recordavailable)
  489. db_pkgbin = &db_pkg->available;
  490. else
  491. db_pkgbin = &db_pkg->installed;
  492. if ((flags & pdb_ignoreolder) &&
  493. versioncompare(&new_pkgbin->version, &db_pkgbin->version) < 0)
  494. continue;
  495. pkg_parse_copy(&ps, db_pkg, db_pkgbin, new_pkg, new_pkgbin);
  496. if (donep)
  497. *donep = db_pkg;
  498. pdone++;
  499. if (parse_EOF(&ps))
  500. break;
  501. }
  502. parse_close(&ps);
  503. varbuf_destroy(&fs.value);
  504. if (donep && !pdone) ohshit(_("no package information in `%.255s'"),filename);
  505. return pdone;
  506. }
  507. /**
  508. * Copy dependency links structures.
  509. *
  510. * This routine is used to update the ‘reverse’ dependency pointers when
  511. * new ‘forwards’ information has been constructed. It first removes all
  512. * the links based on the old information. The old information starts in
  513. * *updateme; after much brou-ha-ha the reverse structures are created
  514. * and *updateme is set to the value from newdepends.
  515. *
  516. * @param pkg The package we're doing this for. This is used to construct
  517. * correct uplinks.
  518. * @param updateme The forwards dependency pointer that we are to update.
  519. * This starts out containing the old forwards info, which we use to
  520. * unthread the old reverse links. After we're done it is updated.
  521. * @param newdepends The value that we ultimately want to have in updateme.
  522. * @param available The pkgbin to modify, available or installed.
  523. *
  524. * It is likely that the backward pointer for the package in question
  525. * (‘depended’) will be updated by this routine, but this will happen by
  526. * the routine traversing the dependency data structures. It doesn't need
  527. * to be told where to update that; I just mention it as something that
  528. * one should be cautious about.
  529. */
  530. void copy_dependency_links(struct pkginfo *pkg,
  531. struct dependency **updateme,
  532. struct dependency *newdepends,
  533. bool available)
  534. {
  535. struct dependency *dyp;
  536. struct deppossi *dop;
  537. struct pkgbin *addtopifp;
  538. /* Delete ‘backward’ (‘depended’) links from other packages to
  539. * dependencies listed in old version of this one. We do this by
  540. * going through all the dependencies in the old version of this
  541. * one and following them down to find which deppossi nodes to
  542. * remove. */
  543. for (dyp= *updateme; dyp; dyp= dyp->next) {
  544. for (dop= dyp->list; dop; dop= dop->next) {
  545. if (dop->rev_prev)
  546. dop->rev_prev->rev_next = dop->rev_next;
  547. else
  548. if (available)
  549. dop->ed->available.depended = dop->rev_next;
  550. else
  551. dop->ed->installed.depended = dop->rev_next;
  552. if (dop->rev_next)
  553. dop->rev_next->rev_prev = dop->rev_prev;
  554. }
  555. }
  556. /* Now fill in new ‘ed’ links from other packages to dependencies
  557. * listed in new version of this one, and set our uplinks correctly. */
  558. for (dyp= newdepends; dyp; dyp= dyp->next) {
  559. dyp->up= pkg;
  560. for (dop= dyp->list; dop; dop= dop->next) {
  561. addtopifp= available ? &dop->ed->available : &dop->ed->installed;
  562. dop->rev_next = addtopifp->depended;
  563. dop->rev_prev = NULL;
  564. if (addtopifp->depended)
  565. addtopifp->depended->rev_prev = dop;
  566. addtopifp->depended= dop;
  567. }
  568. }
  569. /* Finally, we fill in the new value. */
  570. *updateme= newdepends;
  571. }