2 * Copyright (c) 2007-2016, SUSE LLC
4 * This program is licensed under the BSD license, read LICENSE.BSD
5 * for further information
11 * Add missing file dependencies to the package provides
32 #define SEARCHFILES_BLOCK 127
35 pool_addfileprovides_dep(Pool *pool, Id *ida, struct searchfiles *sf, struct searchfiles *isf)
39 struct searchfiles *csf;
41 while ((dep = *ida++) != 0)
47 sid = pool->ss.nstrings + GETRELID(dep);
48 if (MAPTST(&csf->seen, sid))
53 MAPSET(&csf->seen, sid);
54 rd = GETRELDEP(pool, dep);
57 else if (rd->flags == REL_NAMESPACE)
59 if (rd->name == NAMESPACE_SPLITPROVIDES)
62 if (!csf || MAPTST(&csf->seen, sid))
67 MAPSET(&csf->seen, sid);
71 else if (rd->flags == REL_FILECONFLICT)
81 pool_addfileprovides_dep(pool, ids, csf, isf);
87 if (MAPTST(&csf->seen, dep))
89 MAPSET(&csf->seen, dep);
90 s = pool_id2str(pool, dep);
93 if (csf != isf && pool->addedfileprovides == 1 && !repodata_filelistfilter_matches(0, s))
94 continue; /* skip non-standard locations csf == isf: installed case */
95 csf->ids = solv_extend(csf->ids, csf->nfiles, 1, sizeof(Id), SEARCHFILES_BLOCK);
96 csf->ids[csf->nfiles++] = dep;
100 struct addfileprovides_cbdata {
116 /* split filelist dep into basename and dirname */
118 create_dirs_names_array(struct addfileprovides_cbdata *cbd, Pool *pool)
121 cbd->dirs = solv_malloc2(cbd->nfiles, sizeof(char *));
122 cbd->names = solv_malloc2(cbd->nfiles, sizeof(char *));
123 for (i = 0; i < cbd->nfiles; i++)
125 char *s = solv_strdup(pool_id2str(pool, cbd->ids[i]));
129 cbd->names[i] = s + 1;
134 free_dirs_names_array(struct addfileprovides_cbdata *cbd)
139 for (i = 0; i < cbd->nfiles; i++)
140 solv_free(cbd->dirs[i]);
141 cbd->dirs = solv_free(cbd->dirs);
142 cbd->names = solv_free(cbd->names);
147 prune_todo_range(Repo *repo, struct addfileprovides_cbdata *cbd)
149 int start = cbd->todo_start, end = cbd->todo_end;
150 while (start < end && !MAPTST(cbd->todo, start - repo->start))
152 while (end > start && !MAPTST(cbd->todo, end - 1 - repo->start))
154 cbd->todo_start = start;
159 repodata_intersects_todo(Repodata *data, struct addfileprovides_cbdata *cbd)
162 int p, start = data->start, end = data->end;
163 if (start >= cbd->todo_end || end <= cbd->todo_start)
166 if (start < cbd->todo_start)
167 start = cbd->todo_start;
168 if (end > cbd->todo_end)
170 for (p = start; p < end; p++)
171 if (MAPTST(cbd->todo, p - repo->start))
176 /* forward declaration */
177 static void repodata_addfileprovides_search(Repodata *data, struct addfileprovides_cbdata *cbd);
179 /* search a subset of the todo range */
181 repodata_addfileprovides_search_limited(Repodata *data, struct addfileprovides_cbdata *cbd, int start, int end)
184 int old_todo_start = cbd->todo_start;
185 int old_todo_end = cbd->todo_end;
186 if (start < cbd->todo_start)
187 start = cbd->todo_start;
188 if (end > cbd->todo_end)
192 cbd->todo_start = start;
194 repodata_addfileprovides_search(data, cbd);
195 cbd->todo_start = old_todo_start;
196 cbd->todo_end = old_todo_end;
197 prune_todo_range(data->repo, cbd);
201 repodata_addfileprovides_search(Repodata *data, struct addfileprovides_cbdata *cbd)
203 Repo *repo = data->repo;
204 int i, p, start, end;
206 Map *providedids = 0;
208 /* make it available */
209 if (data->state == REPODATA_STUB)
211 if (data->state != REPODATA_AVAILABLE)
213 if (!data->incoredata || !data->dirpool.ndirs)
216 start = cbd->todo_start > data->start ? cbd->todo_start : data->start;
217 end = cbd->todo_end > data->end ? data->end : cbd->todo_end;
222 /* deal with provideids overlap */
223 if (cbd->providedids)
225 if (start >= cbd->provstart && end <= cbd->provend)
226 providedids = cbd->providedids; /* complete overlap */
227 else if (start < cbd->provend && end > cbd->provstart)
229 /* partial overlap, need to split search */
230 if (start < cbd->provstart)
232 repodata_addfileprovides_search_limited(data, cbd, start, cbd->provstart);
233 start = cbd->provstart;
235 if (end > cbd->provend)
237 repodata_addfileprovides_search_limited(data, cbd, cbd->provend, end);
241 repodata_addfileprovides_search_limited(data, cbd, start, end);
246 /* set up dirs and names array if not already done */
248 create_dirs_names_array(cbd, repo->pool);
250 /* set up useddirs map and the cbd->dids array */
251 map_init(&useddirs, data->dirpool.ndirs);
252 for (i = 0; i < cbd->nfiles; i++)
255 if (providedids && MAPTST(providedids, cbd->ids[i]))
257 cbd->dids[i] = 0; /* already included, do not add again */
260 cbd->dids[i] = did = repodata_str2dir(data, cbd->dirs[i], 0);
262 MAPSET(&useddirs, did);
264 repodata_free_dircache(data); /* repodata_str2dir created it */
266 for (p = start; p < end; p++)
268 const unsigned char *dp;
270 if (!MAPTST(cbd->todo, p - repo->start))
272 dp = repodata_lookup_packed_dirstrarray(data, p, SOLVABLE_FILELIST);
275 /* now iterate through the packed array */
276 s = repo->pool->solvables + p;
277 MAPCLR(cbd->todo, p - repo->start); /* this entry is done */
282 while ((c = *dp++) & 0x80)
283 did = (did << 7) ^ c ^ 0x80;
284 did = (did << 6) | (c & 0x3f);
285 if ((unsigned int)did < (unsigned int)data->dirpool.ndirs && MAPTST(&useddirs, did))
287 /* there is at least one entry with that did */
288 for (i = 0; i < cbd->nfiles; i++)
289 if (cbd->dids[i] == did && !strcmp(cbd->names[i], (const char *)dp))
290 s->provides = repo_addid_dep(s->repo, s->provides, cbd->ids[i], SOLVABLE_FILEMARKER);
294 dp += strlen((const char *)dp) + 1;
298 prune_todo_range(repo, cbd);
302 repo_addfileprovides_search_filtered(Repo *repo, struct addfileprovides_cbdata *cbd, int filteredid, Map *postpone)
304 Repodata *data = repo->repodata + filteredid;
305 Map *providedids = cbd->providedids;
307 int start, end, p, i;
309 int old_todo_start, old_todo_end;
311 start = cbd->todo_start > data->start ? cbd->todo_start : data->start;
312 end = cbd->todo_end > data->end ? data->end : cbd->todo_end;
316 /* check if all solvables are in the provide range */
317 if (start < cbd->provstart || end > cbd->provend)
319 /* unclear, check each solvable */
320 for (p = start; p < end; p++)
322 if (p >= cbd->provstart && p < cbd->provend)
324 if (data->incoreoffset[p - data->start] && MAPTST(cbd->todo, p - repo->start))
326 providedids = 0; /* nope, cannot prune with providedids */
333 /* check if the filtered files are enough */
334 for (i = 0; i < cbd->nfiles; i++)
336 if (providedids && MAPTST(providedids, cbd->ids[i])) /* this one is already provided */
338 if (!repodata_filelistfilter_matches(data, pool_id2str(repo->pool, cbd->ids[i])))
343 /* nope, need to search the extensions as well. postpone. */
344 for (p = start; p < end; p++)
346 if (data->incoreoffset[p - data->start] && MAPTST(cbd->todo, p - repo->start))
349 map_grow(postpone, repo->nsolvables);
350 MAPSET(postpone, p - repo->start);
351 MAPCLR(cbd->todo, p - repo->start);
354 prune_todo_range(repo, cbd);
358 /* now check if there is no data marked withour EXTENSION */
359 /* limit todo to the solvables in this repodata */
360 old_todo_start = cbd->todo_start;
361 old_todo_end = cbd->todo_end;
362 old_todo = *cbd->todo;
363 map_init(cbd->todo, repo->nsolvables);
364 for (p = start; p < end; p++)
365 if (data->incoreoffset[p - data->start] && MAPTST(&old_todo, p - repo->start))
367 MAPCLR(&old_todo, p - repo->start);
368 MAPSET(cbd->todo, p - repo->start);
370 prune_todo_range(repo, cbd);
373 for (rdid = repo->nrepodata - 1, data = repo->repodata + rdid; rdid > filteredid ; rdid--, data--)
375 if (data->filelisttype == REPODATA_FILELIST_EXTENSION)
377 if (data->start >= cbd->todo_end || data->end <= cbd->todo_start)
379 if (!repodata_has_keyname(data, SOLVABLE_FILELIST))
381 if (!repodata_intersects_todo(data, cbd))
383 /* oh no, this filelist data is not tagged with REPODATA_FILELIST_EXTENSION! */
384 /* postpone entries that have filelist data */
385 start = cbd->todo_start > data->start ? cbd->todo_start : data->start;
386 end = cbd->todo_end > data->end ? data->end : cbd->todo_end;
387 for (p = start; p < end; p++)
388 if (MAPTST(cbd->todo, p - repo->start))
389 if (repodata_lookup_type(data, p, SOLVABLE_FILELIST))
392 map_grow(postpone, repo->nsolvables);
393 MAPSET(postpone, p - repo->start);
394 MAPCLR(cbd->todo, p - repo->start);
396 prune_todo_range(repo, cbd);
397 if (cbd->todo_start >= cbd->todo_end)
401 /* do the search over the filtered file list with the remaining entries*/
402 if (cbd->todo_start < cbd->todo_end)
403 repodata_addfileprovides_search(repo->repodata + filteredid, cbd);
405 /* restore todo map */
407 *cbd->todo = old_todo;
408 cbd->todo_start = old_todo_start;
409 cbd->todo_end = old_todo_end;
410 prune_todo_range(repo, cbd);
414 repo_addfileprovides_search(Repo *repo, struct addfileprovides_cbdata *cbd, struct searchfiles *sf)
418 int provstart, provend;
422 if (repo->end <= repo->start || !repo->nsolvables || !sf->nfiles)
425 /* update search data if changed */
426 if (cbd->nfiles != sf->nfiles || cbd->ids != sf->ids)
428 free_dirs_names_array(cbd);
429 cbd->nfiles = sf->nfiles;
431 cbd->dids = solv_realloc2(cbd->dids, sf->nfiles, sizeof(Id));
434 /* create todo map and range */
435 map_init(&todo, repo->end - repo->start);
436 for (p = repo->start; p < repo->end; p++)
437 if (repo->pool->solvables[p].repo == repo)
438 MAPSET(&todo, p - repo->start);
440 cbd->todo_start = repo->start;
441 cbd->todo_end = repo->end;
442 prune_todo_range(repo, cbd);
444 provstart = provend = 0;
445 map_init(&providedids, 0);
446 data = repo_lookup_repodata(repo, SOLVID_META, REPOSITORY_ADDEDFILEPROVIDES);
450 queue_init(&fileprovidesq);
451 if (repodata_lookup_idarray(data, SOLVID_META, REPOSITORY_ADDEDFILEPROVIDES, &fileprovidesq))
453 map_grow(&providedids, repo->pool->ss.nstrings);
454 cbd->providedids = &providedids;
455 provstart = data->start;
457 for (i = 0; i < fileprovidesq.count; i++)
458 MAPSET(&providedids, fileprovidesq.elements[i]);
459 for (i = 0; i < cbd->nfiles; i++)
460 if (!MAPTST(&providedids, cbd->ids[i]))
462 if (i == cbd->nfiles)
464 /* all included, clear entries from todo list */
465 if (provstart <= cbd->todo_start && provend >= cbd->todo_end)
466 cbd->todo_end = cbd->todo_start; /* clear complete range */
469 for (p = provstart; p < provend; p++)
470 MAPCLR(&todo, p - repo->start);
471 prune_todo_range(repo, cbd);
475 queue_free(&fileprovidesq);
478 if (cbd->todo_start >= cbd->todo_end)
482 map_free(&providedids);
483 cbd->providedids = 0;
487 /* this is similar to repo_lookup_filelist_repodata in repo.c */
489 for (rdid = 1, data = repo->repodata + rdid; rdid < repo->nrepodata; rdid++, data++)
490 if (data->filelisttype == REPODATA_FILELIST_FILTERED)
492 for (; rdid < repo->nrepodata; rdid++, data++)
493 if (data->filelisttype == REPODATA_FILELIST_EXTENSION)
496 if (rdid < repo->nrepodata)
498 /* have at least one repodata with REPODATA_FILELIST_FILTERED followed by REPODATA_FILELIST_EXTENSION */
500 map_init(&postpone, 0);
501 for (rdid = repo->nrepodata - 1, data = repo->repodata + rdid; rdid > 0; rdid--, data--)
503 if (data->filelisttype != REPODATA_FILELIST_FILTERED)
505 if (!repodata_intersects_todo(data, cbd))
507 if (data->state != REPODATA_AVAILABLE)
509 if (data->state != REPODATA_STUB)
512 if (data->state != REPODATA_AVAILABLE || data->filelisttype != REPODATA_FILELIST_FILTERED)
515 repo_addfileprovides_search_filtered(repo, cbd, rdid, &postpone);
519 /* add postponed entries back to todo */
520 map_or(&todo, &postpone);
521 cbd->todo_start = repo->start;
522 cbd->todo_end = repo->end;
523 prune_todo_range(repo, cbd);
528 /* search remaining entries in the standard way */
529 if (cbd->todo_start < cbd->todo_end)
531 for (rdid = repo->nrepodata - 1, data = repo->repodata + rdid; rdid > 0; rdid--, data--)
533 if (data->start >= cbd->todo_end || data->end <= cbd->todo_start)
535 if (!repodata_has_keyname(data, SOLVABLE_FILELIST))
537 if (!repodata_intersects_todo(data, cbd))
539 repodata_addfileprovides_search(data, cbd);
540 if (cbd->todo_start >= cbd->todo_end)
547 map_free(&providedids);
548 cbd->providedids = 0;
552 pool_addfileprovides_queue(Pool *pool, Queue *idq, Queue *idqinst)
555 Repo *installed, *repo;
556 struct searchfiles sf, isf, *isfp;
557 struct addfileprovides_cbdata cbd;
561 installed = pool->installed;
562 now = solv_timems(0);
563 memset(&cbd, 0, sizeof(cbd));
564 memset(&sf, 0, sizeof(sf));
565 map_init(&sf.seen, pool->ss.nstrings + pool->nrels);
566 memset(&isf, 0, sizeof(isf));
567 map_init(&isf.seen, pool->ss.nstrings + pool->nrels);
568 pool->addedfileprovides = pool->addfileprovidesfiltered ? 1 : 2;
573 queue_empty(idqinst);
574 isfp = installed ? &isf : 0;
575 for (i = 1, s = pool->solvables + i; i < pool->nsolvables; i++, s++)
581 pool_addfileprovides_dep(pool, repo->idarraydata + s->obsoletes, &sf, isfp);
583 pool_addfileprovides_dep(pool, repo->idarraydata + s->conflicts, &sf, isfp);
585 pool_addfileprovides_dep(pool, repo->idarraydata + s->requires, &sf, isfp);
587 pool_addfileprovides_dep(pool, repo->idarraydata + s->recommends, &sf, isfp);
589 pool_addfileprovides_dep(pool, repo->idarraydata + s->suggests, &sf, isfp);
591 pool_addfileprovides_dep(pool, repo->idarraydata + s->supplements, &sf, isfp);
593 pool_addfileprovides_dep(pool, repo->idarraydata + s->enhances, &sf, isfp);
598 POOL_DEBUG(SOLV_DEBUG_STATS, "found %d file dependencies, %d installed file dependencies\n", sf.nfiles, isf.nfiles);
602 for (i = 0; i < sf.nfiles; i++)
603 POOL_DEBUG(SOLV_DEBUG_STATS, "looking up %s in filelist\n", pool_id2str(pool, sf.ids[i]));
606 repo_addfileprovides_search(repo, &cbd, &sf);
608 queue_insertn(idq, idq->count, sf.nfiles, sf.ids);
610 queue_insertn(idqinst, idqinst->count, sf.nfiles, sf.ids);
616 for (i = 0; i < isf.nfiles; i++)
617 POOL_DEBUG(SOLV_DEBUG_STATS, "looking up %s in installed filelist\n", pool_id2str(pool, isf.ids[i]));
620 repo_addfileprovides_search(installed, &cbd, &isf);
621 if (installed && idqinst)
622 for (i = 0; i < isf.nfiles; i++)
623 queue_pushunique(idqinst, isf.ids[i]);
626 free_dirs_names_array(&cbd);
628 pool_freewhatprovides(pool); /* as we have added provides */
629 POOL_DEBUG(SOLV_DEBUG_STATS, "addfileprovides took %d ms\n", solv_timems(now));
633 pool_addfileprovides(Pool *pool)
635 pool_addfileprovides_queue(pool, 0, 0);