52c64ff137ba49f38d7bc31d0601f3037ad8a10d
[project/opkg-lede.git] / libopkg / pkg_hash.c
1 /* opkg_hash.c - the opkg package management system
2
3 Steven M. Ayer
4
5 Copyright (C) 2002 Compaq Computer Corporation
6
7 This program is free software; you can redistribute it and/or
8 modify it under the terms of the GNU General Public License as
9 published by the Free Software Foundation; either version 2, or (at
10 your option) any later version.
11
12 This program is distributed in the hope that it will be useful, but
13 WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 General Public License for more details.
16 */
17
18 #include <stdio.h>
19
20 #include "hash_table.h"
21 #include "pkg.h"
22 #include "opkg_message.h"
23 #include "pkg_vec.h"
24 #include "pkg_hash.h"
25 #include "parse_util.h"
26 #include "pkg_parse.h"
27 #include "opkg_utils.h"
28 #include "sprintf_alloc.h"
29 #include "file_util.h"
30 #include "libbb/libbb.h"
31 #include "libbb/gzip.h"
32
33 void pkg_hash_init(void)
34 {
35 hash_table_init("pkg-hash", &conf->pkg_hash,
36 OPKG_CONF_DEFAULT_HASH_LEN);
37 }
38
39 static void free_pkgs(const char *key, void *entry, void *data)
40 {
41 int i;
42 abstract_pkg_t *ab_pkg;
43
44 /* Each entry in the hash table is an abstract package, which contains
45 * a list of packages that provide the abstract package.
46 */
47
48 ab_pkg = (abstract_pkg_t *) entry;
49
50 if (ab_pkg->pkgs) {
51 for (i = 0; i < ab_pkg->pkgs->len; i++) {
52 pkg_deinit(ab_pkg->pkgs->pkgs[i]);
53 free(ab_pkg->pkgs->pkgs[i]);
54 }
55 }
56
57 abstract_pkg_vec_free(ab_pkg->provided_by);
58 abstract_pkg_vec_free(ab_pkg->replaced_by);
59 pkg_vec_free(ab_pkg->pkgs);
60 free(ab_pkg->depended_upon_by);
61 free(ab_pkg->name);
62 free(ab_pkg);
63 }
64
65 void pkg_hash_deinit(void)
66 {
67 hash_table_foreach(&conf->pkg_hash, free_pkgs, NULL);
68 hash_table_deinit(&conf->pkg_hash);
69 }
70
71 int dist_hash_add_from_file(const char *lists_dir, pkg_src_t * dist)
72 {
73 nv_pair_list_elt_t *l;
74 char *list_file, *subname;
75
76 list_for_each_entry(l, &conf->arch_list.head, node) {
77 nv_pair_t *nv = (nv_pair_t *) l->data;
78 sprintf_alloc(&subname, "%s-%s", dist->name, nv->name);
79 sprintf_alloc(&list_file, "%s/%s", lists_dir, subname);
80
81 if (file_exists(list_file)) {
82 if (pkg_hash_add_from_file(list_file, dist, NULL, 0, 0, NULL, NULL)) {
83 free(list_file);
84 return -1;
85 }
86 pkg_src_list_append(&conf->pkg_src_list, subname,
87 dist->value, "__dummy__", 0);
88 }
89
90 free(list_file);
91 }
92
93 return 0;
94 }
95
96 int
97 pkg_hash_add_from_file(const char *file_name,
98 pkg_src_t * src, pkg_dest_t * dest, int is_status_file, int state_flags,
99 void (*cb)(pkg_t *, void *), void *priv)
100 {
101 pkg_t *pkg;
102 FILE *fp;
103 char *buf;
104 const size_t len = 4096;
105 int ret = 0;
106 struct gzip_handle zh;
107
108 if (src && src->gzip) {
109 fp = gzip_fdopen(&zh, file_name);
110 } else {
111 fp = fopen(file_name, "r");
112 }
113
114 if (fp == NULL) {
115 opkg_perror(ERROR, "Failed to open %s", file_name);
116 return -1;
117 }
118
119 buf = xmalloc(len);
120
121 do {
122 pkg = pkg_new();
123 pkg->src = src;
124 pkg->dest = dest;
125 pkg->state_flag |= state_flags;
126
127 ret = parse_from_stream_nomalloc(pkg_parse_line, pkg, fp, 0,
128 &buf, len);
129
130 if (pkg->name == NULL) {
131 /* probably just a blank line */
132 ret = 1;
133 }
134
135 if (ret) {
136 pkg_deinit(pkg);
137 free(pkg);
138 if (ret == -1)
139 break;
140 if (ret == 1)
141 /* Probably a blank line, continue parsing. */
142 ret = 0;
143 continue;
144 }
145
146 if (!(pkg->state_flag & SF_NEED_DETAIL)) {
147 //opkg_msg(DEBUG, "Package %s is unrelated, ignoring.\n", pkg->name);
148 pkg_deinit(pkg);
149 free(pkg);
150 continue;
151 }
152
153 if (!pkg_get_architecture(pkg) || !pkg_get_arch_priority(pkg)) {
154 char *version_str = pkg_version_str_alloc(pkg);
155 opkg_msg(NOTICE, "Package %s version %s has no "
156 "valid architecture, ignoring.\n",
157 pkg->name, version_str);
158 free(version_str);
159 continue;
160 }
161
162 if (cb)
163 cb(pkg, priv);
164 else
165 hash_insert_pkg(pkg, is_status_file);
166
167 } while (!feof(fp));
168
169 free(buf);
170 fclose(fp);
171
172 if (src && src->gzip)
173 gzip_close(&zh);
174
175 return ret;
176 }
177
178 /*
179 * Load in feed files from the cached "src" and/or "src/gz" locations.
180 */
181 int pkg_hash_load_feeds(int state_flags, void (*cb)(pkg_t *, void *), void *priv)
182 {
183 pkg_src_list_elt_t *iter;
184 pkg_src_t *src;
185 char *list_file, *lists_dir;
186
187 opkg_msg(INFO, "\n");
188
189 lists_dir = conf->restrict_to_default_dest ?
190 conf->default_dest->lists_dir : conf->lists_dir;
191
192 for (iter = void_list_first(&conf->pkg_src_list); iter;
193 iter = void_list_next(&conf->pkg_src_list, iter)) {
194
195 src = (pkg_src_t *) iter->data;
196
197 sprintf_alloc(&list_file, "%s/%s", lists_dir, src->name);
198
199 if (file_exists(list_file)) {
200 if (pkg_hash_add_from_file(list_file, src, NULL, 0, state_flags, cb, priv)) {
201 free(list_file);
202 return -1;
203 }
204 }
205 free(list_file);
206 }
207
208 return 0;
209 }
210
211 /*
212 * Load in status files from the configured "dest"s.
213 */
214 int pkg_hash_load_status_files(void (*cb)(pkg_t *, void *), void *priv)
215 {
216 pkg_dest_list_elt_t *iter;
217 pkg_dest_t *dest;
218
219 opkg_msg(INFO, "\n");
220
221 for (iter = void_list_first(&conf->pkg_dest_list); iter;
222 iter = void_list_next(&conf->pkg_dest_list, iter)) {
223
224 dest = (pkg_dest_t *) iter->data;
225
226 if (file_exists(dest->status_file_name)) {
227 if (pkg_hash_add_from_file
228 (dest->status_file_name, NULL, dest, 1, SF_NEED_DETAIL, cb, priv))
229 return -1;
230 }
231 }
232
233 return 0;
234 }
235
236 static void
237 pkg_hash_load_package_details_helper(const char *pkg_name, void *entry, void *data)
238 {
239 int *count = data;
240 abstract_pkg_t *ab_pkg = (abstract_pkg_t *) entry;
241
242 if (ab_pkg->state_flag & SF_NEED_DETAIL) {
243 if (ab_pkg->state_flag & SF_MARKED) {
244 opkg_msg(DEBUG, "skipping already seen flagged abpkg %s\n",
245 ab_pkg->name);
246 return;
247 }
248
249 opkg_msg(DEBUG, "found yet incomplete flagged abpkg %s\n",
250 ab_pkg->name);
251
252 (*count)++;
253 ab_pkg->state_flag |= SF_MARKED;
254 }
255 }
256
257 int pkg_hash_load_package_details(void)
258 {
259 int n_need_detail;
260
261 while (1) {
262 pkg_hash_load_feeds(0, NULL, NULL);
263
264 n_need_detail = 0;
265 hash_table_foreach(&conf->pkg_hash, pkg_hash_load_package_details_helper, &n_need_detail);
266
267 if (n_need_detail > 0)
268 opkg_msg(DEBUG, "Found %d packages requiring details, reloading feeds\n", n_need_detail);
269 else
270 break;
271 }
272
273 return 0;
274 }
275
276 pkg_t *pkg_hash_fetch_best_installation_candidate(abstract_pkg_t * apkg,
277 int (*constraint_fcn) (pkg_t *
278 pkg,
279 void
280 *cdata),
281 void *cdata, int quiet)
282 {
283 int i, j;
284 int nprovides = 0;
285 int nmatching = 0;
286 int wrong_arch_found = 0;
287 int arch_priority;
288 pkg_vec_t *matching_pkgs;
289 abstract_pkg_vec_t *matching_apkgs;
290 abstract_pkg_vec_t *provided_apkg_vec;
291 abstract_pkg_t **provided_apkgs;
292 abstract_pkg_vec_t *providers;
293 pkg_t *latest_installed_parent = NULL;
294 pkg_t *latest_matching = NULL;
295 pkg_t *priorized_matching = NULL;
296 pkg_t *held_pkg = NULL;
297 pkg_t *good_pkg_by_name = NULL;
298
299 if (apkg == NULL || apkg->provided_by == NULL
300 || (apkg->provided_by->len == 0))
301 return NULL;
302
303 matching_pkgs = pkg_vec_alloc();
304 matching_apkgs = abstract_pkg_vec_alloc();
305 providers = abstract_pkg_vec_alloc();
306
307 opkg_msg(DEBUG, "Best installation candidate for %s:\n", apkg->name);
308
309 provided_apkg_vec = apkg->provided_by;
310 nprovides = provided_apkg_vec->len;
311 provided_apkgs = provided_apkg_vec->pkgs;
312 if (nprovides > 1)
313 opkg_msg(DEBUG, "apkg=%s nprovides=%d.\n", apkg->name,
314 nprovides);
315
316 /* accumulate all the providers */
317 for (i = 0; i < nprovides; i++) {
318 abstract_pkg_t *provider_apkg = provided_apkgs[i];
319 opkg_msg(DEBUG, "Adding %s to providers.\n",
320 provider_apkg->name);
321 abstract_pkg_vec_insert(providers, provider_apkg);
322 }
323 nprovides = providers->len;
324
325 for (i = 0; i < nprovides; i++) {
326 abstract_pkg_t *provider_apkg =
327 abstract_pkg_vec_get(providers, i);
328 abstract_pkg_t *replacement_apkg = NULL;
329 pkg_vec_t *vec;
330
331 if (provider_apkg->replaced_by
332 && provider_apkg->replaced_by->len) {
333 replacement_apkg = provider_apkg->replaced_by->pkgs[0];
334 if (provider_apkg->replaced_by->len > 1) {
335 opkg_msg(NOTICE, "Multiple replacers for %s, "
336 "using first one (%s).\n",
337 provider_apkg->name,
338 replacement_apkg->name);
339 }
340 }
341
342 if (replacement_apkg)
343 opkg_msg(DEBUG,
344 "replacement_apkg=%s for provider_apkg=%s.\n",
345 replacement_apkg->name, provider_apkg->name);
346
347 if (replacement_apkg && (replacement_apkg != provider_apkg)) {
348 if (abstract_pkg_vec_contains
349 (providers, replacement_apkg))
350 continue;
351 else
352 provider_apkg = replacement_apkg;
353 }
354
355 if (!(vec = provider_apkg->pkgs)) {
356 opkg_msg(DEBUG, "No pkgs for provider_apkg %s.\n",
357 provider_apkg->name);
358 continue;
359 }
360
361 /* now check for supported architecture */
362 {
363 int max_count = 0;
364
365 /* count packages matching max arch priority and keep track of last one */
366 for (j = 0; j < vec->len; j++) {
367 pkg_t *maybe = vec->pkgs[j];
368 arch_priority = pkg_get_arch_priority(maybe);
369
370 opkg_msg(DEBUG,
371 "%s arch=%s arch_priority=%d version=%s.\n",
372 maybe->name, pkg_get_architecture(maybe),
373 arch_priority, pkg_get_string(maybe, PKG_VERSION));
374 /* We make sure not to add the same package twice. Need to search for the reason why
375 they show up twice sometimes. */
376 if ((arch_priority > 0)
377 &&
378 (!pkg_vec_contains(matching_pkgs, maybe))) {
379 max_count++;
380 abstract_pkg_vec_insert(matching_apkgs,
381 maybe->parent);
382 pkg_vec_insert(matching_pkgs, maybe);
383 }
384 }
385
386 if (vec->len > 0 && matching_pkgs->len < 1)
387 wrong_arch_found = 1;
388 }
389 }
390
391 if (matching_pkgs->len < 1) {
392 if (wrong_arch_found)
393 opkg_msg(ERROR, "Packages for %s found, but"
394 " incompatible with the architectures configured\n",
395 apkg->name);
396 pkg_vec_free(matching_pkgs);
397 abstract_pkg_vec_free(matching_apkgs);
398 abstract_pkg_vec_free(providers);
399 return NULL;
400 }
401
402 if (matching_pkgs->len > 1)
403 pkg_vec_sort(matching_pkgs,
404 pkg_name_version_and_architecture_compare);
405 if (matching_apkgs->len > 1)
406 abstract_pkg_vec_sort(matching_apkgs, abstract_pkg_name_compare);
407
408 for (i = 0; i < matching_pkgs->len; i++) {
409 pkg_t *matching = matching_pkgs->pkgs[i];
410 if (constraint_fcn(matching, cdata)) {
411 opkg_msg(DEBUG, "Candidate: %s %s.\n",
412 matching->name, pkg_get_string(matching, PKG_VERSION));
413 good_pkg_by_name = matching;
414 /* It has been provided by hand, so it is what user want */
415 if (matching->provided_by_hand == 1)
416 break;
417 }
418 }
419
420 for (i = 0; i < matching_pkgs->len; i++) {
421 pkg_t *matching = matching_pkgs->pkgs[i];
422 latest_matching = matching;
423 if (matching->parent->state_status == SS_INSTALLED
424 || matching->parent->state_status == SS_UNPACKED)
425 latest_installed_parent = matching;
426 if (matching->state_flag & (SF_HOLD | SF_PREFER)) {
427 if (held_pkg)
428 opkg_msg(NOTICE,
429 "Multiple packages (%s and %s) providing"
430 " same name marked HOLD or PREFER. "
431 "Using latest.\n", held_pkg->name,
432 matching->name);
433 held_pkg = matching;
434 }
435 }
436
437 if (!good_pkg_by_name && !held_pkg && !latest_installed_parent
438 && matching_apkgs->len > 1 && !quiet) {
439 int prio = 0;
440 for (i = 0; i < matching_pkgs->len; i++) {
441 pkg_t *matching = matching_pkgs->pkgs[i];
442 arch_priority = pkg_get_arch_priority(matching);
443 if (arch_priority > prio) {
444 priorized_matching = matching;
445 prio = arch_priority;
446 opkg_msg(DEBUG, "Match %s with priority %i.\n",
447 matching->name, prio);
448 }
449 }
450
451 }
452
453 if (conf->verbosity >= INFO && matching_apkgs->len > 1) {
454 opkg_msg(INFO, "%d matching pkgs for apkg=%s:\n",
455 matching_pkgs->len, apkg->name);
456 for (i = 0; i < matching_pkgs->len; i++) {
457 pkg_t *matching = matching_pkgs->pkgs[i];
458 opkg_msg(INFO, "%s %s %s\n",
459 matching->name, pkg_get_string(matching, PKG_VERSION),
460 pkg_get_architecture(matching));
461 }
462 }
463
464 nmatching = matching_apkgs->len;
465
466 pkg_vec_free(matching_pkgs);
467 abstract_pkg_vec_free(matching_apkgs);
468 abstract_pkg_vec_free(providers);
469
470 if (good_pkg_by_name) { /* We found a good candidate, we will install it */
471 return good_pkg_by_name;
472 }
473 if (held_pkg) {
474 opkg_msg(INFO, "Using held package %s.\n", held_pkg->name);
475 return held_pkg;
476 }
477 if (latest_installed_parent) {
478 opkg_msg(INFO,
479 "Using latest version of installed package %s.\n",
480 latest_installed_parent->name);
481 return latest_installed_parent;
482 }
483 if (priorized_matching) {
484 opkg_msg(INFO, "Using priorized matching %s %s %s.\n",
485 priorized_matching->name, pkg_get_string(priorized_matching, PKG_VERSION),
486 pkg_get_architecture(priorized_matching));
487 return priorized_matching;
488 }
489 if (nmatching > 1) {
490 opkg_msg(INFO, "No matching pkg out of %d matching_apkgs.\n",
491 nmatching);
492 return NULL;
493 }
494 if (latest_matching) {
495 opkg_msg(INFO, "Using latest matching %s %s %s.\n",
496 latest_matching->name, pkg_get_string(latest_matching, PKG_VERSION),
497 pkg_get_architecture(latest_matching));
498 return latest_matching;
499 }
500 return NULL;
501 }
502
503 static int pkg_name_constraint_fcn(pkg_t * pkg, void *cdata)
504 {
505 const char *name = (const char *)cdata;
506
507 if (strcmp(pkg->name, name) == 0)
508 return 1;
509 else
510 return 0;
511 }
512
513 static pkg_vec_t *pkg_vec_fetch_by_name(const char *pkg_name)
514 {
515 abstract_pkg_t *ab_pkg;
516
517 if (!(ab_pkg = abstract_pkg_fetch_by_name(pkg_name)))
518 return NULL;
519
520 if (ab_pkg->pkgs)
521 return ab_pkg->pkgs;
522
523 if (ab_pkg->provided_by) {
524 abstract_pkg_t *abpkg =
525 abstract_pkg_vec_get(ab_pkg->provided_by, 0);
526 if (abpkg != NULL)
527 return abpkg->pkgs;
528 else
529 return ab_pkg->pkgs;
530 }
531
532 return NULL;
533 }
534
535 pkg_t *pkg_hash_fetch_best_installation_candidate_by_name(const char *name)
536 {
537 abstract_pkg_t *apkg = NULL;
538
539 if (!(apkg = abstract_pkg_fetch_by_name(name)))
540 return NULL;
541
542 return pkg_hash_fetch_best_installation_candidate(apkg,
543 pkg_name_constraint_fcn,
544 apkg->name, 0);
545 }
546
547 pkg_t *pkg_hash_fetch_by_name_version(const char *pkg_name, const char *version)
548 {
549 pkg_vec_t *vec;
550 int i;
551 char *version_str = NULL;
552
553 if (!(vec = pkg_vec_fetch_by_name(pkg_name)))
554 return NULL;
555
556 for (i = 0; i < vec->len; i++) {
557 version_str = pkg_version_str_alloc(vec->pkgs[i]);
558 if (!strcmp(version_str, version)) {
559 free(version_str);
560 break;
561 }
562 free(version_str);
563 }
564
565 if (i == vec->len)
566 return NULL;
567
568 return vec->pkgs[i];
569 }
570
571 pkg_t *pkg_hash_fetch_installed_by_name_dest(const char *pkg_name,
572 pkg_dest_t * dest)
573 {
574 pkg_vec_t *vec;
575 int i;
576
577 if (!(vec = pkg_vec_fetch_by_name(pkg_name))) {
578 return NULL;
579 }
580
581 for (i = 0; i < vec->len; i++)
582 if ((vec->pkgs[i]->state_status == SS_INSTALLED
583 || vec->pkgs[i]->state_status == SS_UNPACKED)
584 && vec->pkgs[i]->dest == dest) {
585 return vec->pkgs[i];
586 }
587
588 return NULL;
589 }
590
591 pkg_t *pkg_hash_fetch_installed_by_name(const char *pkg_name)
592 {
593 pkg_vec_t *vec;
594 int i;
595
596 if (!(vec = pkg_vec_fetch_by_name(pkg_name))) {
597 return NULL;
598 }
599
600 for (i = 0; i < vec->len; i++) {
601 if (vec->pkgs[i]->state_status == SS_INSTALLED
602 || vec->pkgs[i]->state_status == SS_UNPACKED) {
603 return vec->pkgs[i];
604 }
605 }
606
607 return NULL;
608 }
609
610 static void
611 pkg_hash_fetch_available_helper(const char *pkg_name, void *entry, void *data)
612 {
613 int j;
614 abstract_pkg_t *ab_pkg = (abstract_pkg_t *) entry;
615 pkg_vec_t *all = (pkg_vec_t *) data;
616 pkg_vec_t *pkg_vec = ab_pkg->pkgs;
617
618 if (!pkg_vec)
619 return;
620
621 for (j = 0; j < pkg_vec->len; j++) {
622 pkg_t *pkg = pkg_vec->pkgs[j];
623 pkg_vec_insert(all, pkg);
624 }
625 }
626
627 void pkg_hash_fetch_available(pkg_vec_t * all)
628 {
629 hash_table_foreach(&conf->pkg_hash, pkg_hash_fetch_available_helper,
630 all);
631 }
632
633 static void
634 pkg_hash_fetch_all_installed_helper(const char *pkg_name, void *entry,
635 void *data)
636 {
637 abstract_pkg_t *ab_pkg = (abstract_pkg_t *) entry;
638 pkg_vec_t *all = (pkg_vec_t *) data;
639 pkg_vec_t *pkg_vec = ab_pkg->pkgs;
640 int j;
641
642 if (!pkg_vec)
643 return;
644
645 for (j = 0; j < pkg_vec->len; j++) {
646 pkg_t *pkg = pkg_vec->pkgs[j];
647 if (pkg->state_status == SS_INSTALLED
648 || pkg->state_status == SS_UNPACKED)
649 pkg_vec_insert(all, pkg);
650 }
651 }
652
653 void pkg_hash_fetch_all_installed(pkg_vec_t * all)
654 {
655 hash_table_foreach(&conf->pkg_hash, pkg_hash_fetch_all_installed_helper,
656 all);
657 }
658
659 /*
660 * This assumes that the abstract pkg doesn't exist.
661 */
662 static abstract_pkg_t *add_new_abstract_pkg_by_name(const char *pkg_name)
663 {
664 abstract_pkg_t *ab_pkg;
665
666 ab_pkg = abstract_pkg_new();
667
668 ab_pkg->name = xstrdup(pkg_name);
669 hash_table_insert(&conf->pkg_hash, pkg_name, ab_pkg);
670
671 return ab_pkg;
672 }
673
674 abstract_pkg_t *ensure_abstract_pkg_by_name(const char *pkg_name)
675 {
676 abstract_pkg_t *ab_pkg;
677
678 if (!(ab_pkg = abstract_pkg_fetch_by_name(pkg_name)))
679 ab_pkg = add_new_abstract_pkg_by_name(pkg_name);
680
681 return ab_pkg;
682 }
683
684 void hash_insert_pkg(pkg_t * pkg, int set_status)
685 {
686 abstract_pkg_t *ab_pkg;
687
688 ab_pkg = ensure_abstract_pkg_by_name(pkg->name);
689 if (!ab_pkg->pkgs)
690 ab_pkg->pkgs = pkg_vec_alloc();
691
692 if (pkg->state_status == SS_INSTALLED) {
693 ab_pkg->state_status = SS_INSTALLED;
694 } else if (pkg->state_status == SS_UNPACKED) {
695 ab_pkg->state_status = SS_UNPACKED;
696 }
697
698 buildDepends(pkg);
699
700 buildProvides(ab_pkg, pkg);
701
702 init_providelist(pkg, NULL);
703
704 /* Need to build the conflicts graph before replaces for correct
705 * calculation of replaced_by relation.
706 */
707 buildConflicts(pkg);
708
709 buildReplaces(ab_pkg, pkg);
710
711 buildDependedUponBy(pkg, ab_pkg);
712
713 pkg_vec_insert_merge(ab_pkg->pkgs, pkg, set_status);
714 pkg->parent = ab_pkg;
715 }
716
717 static const char *strip_offline_root(const char *file_name)
718 {
719 unsigned int len;
720
721 if (conf->offline_root) {
722 len = strlen(conf->offline_root);
723 if (strncmp(file_name, conf->offline_root, len) == 0)
724 file_name += len;
725 }
726
727 return file_name;
728 }
729
730 void file_hash_remove(const char *file_name)
731 {
732 file_name = strip_offline_root(file_name);
733 hash_table_remove(&conf->file_hash, file_name);
734 }
735
736 pkg_t *file_hash_get_file_owner(const char *file_name)
737 {
738 file_name = strip_offline_root(file_name);
739 return hash_table_get(&conf->file_hash, file_name);
740 }
741
742 void file_hash_set_file_owner(const char *file_name, pkg_t * owning_pkg)
743 {
744 pkg_t *old_owning_pkg;
745 int file_name_len = strlen(file_name);
746
747 if (file_name[file_name_len - 1] == '/')
748 return;
749
750 file_name = strip_offline_root(file_name);
751
752 old_owning_pkg = hash_table_get(&conf->file_hash, file_name);
753 hash_table_insert(&conf->file_hash, file_name, owning_pkg);
754
755 if (old_owning_pkg) {
756 pkg_get_installed_files(old_owning_pkg);
757 str_list_remove_elt(old_owning_pkg->installed_files, file_name);
758 pkg_free_installed_files(old_owning_pkg);
759
760 /* mark this package to have its filelist written */
761 old_owning_pkg->state_flag |= SF_FILELIST_CHANGED;
762 owning_pkg->state_flag |= SF_FILELIST_CHANGED;
763 }
764 }