/* * Copyright (c) 2007-2016, SUSE LLC * * This program is licensed under the BSD license, read LICENSE.BSD * for further information */ /* * diskusage.c * * calculate needed space on partitions */ #include #include #include #include #include #include "pool.h" #include "poolarch.h" #include "repo.h" #include "util.h" #include "bitmap.h" struct mptree { Id sibling; Id child; const char *comp; int compl; Id mountpoint; }; struct ducbdata { DUChanges *mps; struct mptree *mptree; int addsub; int hasdu; Id *dirmap; int nmap; Repodata *olddata; }; static int solver_fill_DU_cb(void *cbdata, Solvable *s, Repodata *data, Repokey *key, KeyValue *value) { struct ducbdata *cbd = cbdata; Id mp; if (data != cbd->olddata) { Id dn, mp, comp, *dirmap, *dirs; int i, compl; const char *compstr; struct mptree *mptree; /* create map from dir to mptree */ cbd->dirmap = solv_free(cbd->dirmap); cbd->nmap = 0; dirmap = solv_calloc(data->dirpool.ndirs, sizeof(Id)); mptree = cbd->mptree; mp = 0; for (dn = 2, dirs = data->dirpool.dirs + dn; dn < data->dirpool.ndirs; dn++) { comp = *dirs++; if (comp <= 0) { mp = dirmap[-comp]; continue; } if (mp < 0) { /* unconnected */ dirmap[dn] = mp; continue; } if (!mptree[mp].child) { dirmap[dn] = -mp; continue; } if (data->localpool) compstr = stringpool_id2str(&data->spool, comp); else compstr = pool_id2str(data->repo->pool, comp); compl = strlen(compstr); for (i = mptree[mp].child; i; i = mptree[i].sibling) if (mptree[i].compl == compl && !strncmp(mptree[i].comp, compstr, compl)) break; dirmap[dn] = i ? i : -mp; } /* change dirmap to point to mountpoint instead of mptree */ for (dn = 0; dn < data->dirpool.ndirs; dn++) { mp = dirmap[dn]; dirmap[dn] = mptree[mp > 0 ? mp : -mp].mountpoint; } cbd->dirmap = dirmap; cbd->nmap = data->dirpool.ndirs; cbd->olddata = data; } cbd->hasdu = 1; if (value->id < 0 || value->id >= cbd->nmap) return 0; mp = cbd->dirmap[value->id]; if (mp < 0) return 0; if (cbd->addsub > 0) { cbd->mps[mp].kbytes += value->num; cbd->mps[mp].files += value->num2; } else if (!(cbd->mps[mp].flags & DUCHANGES_ONLYADD)) { cbd->mps[mp].kbytes -= value->num; cbd->mps[mp].files -= value->num2; } return 0; } static void propagate_mountpoints(struct mptree *mptree, int pos, Id mountpoint) { int i; if (mptree[pos].mountpoint == -1) mptree[pos].mountpoint = mountpoint; else mountpoint = mptree[pos].mountpoint; for (i = mptree[pos].child; i; i = mptree[i].sibling) propagate_mountpoints(mptree, i, mountpoint); } #define MPTREE_BLOCK 15 static struct mptree * create_mptree(DUChanges *mps, int nmps) { int i, nmptree; struct mptree *mptree; int pos, compl; int mp; const char *p, *path, *compstr; mptree = solv_extend_resize(0, 1, sizeof(struct mptree), MPTREE_BLOCK); /* our root node */ mptree[0].sibling = 0; mptree[0].child = 0; mptree[0].comp = 0; mptree[0].compl = 0; mptree[0].mountpoint = -1; nmptree = 1; /* create component tree */ for (mp = 0; mp < nmps; mp++) { mps[mp].kbytes = 0; mps[mp].files = 0; pos = 0; path = mps[mp].path; while(*path == '/') path++; while (*path) { if ((p = strchr(path, '/')) == 0) { compstr = path; compl = strlen(compstr); path += compl; } else { compstr = path; compl = p - path; path = p + 1; while(*path == '/') path++; } for (i = mptree[pos].child; i; i = mptree[i].sibling) if (mptree[i].compl == compl && !strncmp(mptree[i].comp, compstr, compl)) break; if (!i) { /* create new node */ mptree = solv_extend(mptree, nmptree, 1, sizeof(struct mptree), MPTREE_BLOCK); i = nmptree++; mptree[i].sibling = mptree[pos].child; mptree[i].child = 0; mptree[i].comp = compstr; mptree[i].compl = compl; mptree[i].mountpoint = -1; mptree[pos].child = i; } pos = i; } mptree[pos].mountpoint = mp; } propagate_mountpoints(mptree, 0, mptree[0].mountpoint); #if 0 for (i = 0; i < nmptree; i++) { printf("#%d sibling: %d\n", i, mptree[i].sibling); printf("#%d child: %d\n", i, mptree[i].child); printf("#%d comp: %s\n", i, mptree[i].comp); printf("#%d compl: %d\n", i, mptree[i].compl); printf("#%d mountpont: %d\n", i, mptree[i].mountpoint); } #endif return mptree; } void pool_calc_duchanges(Pool *pool, Map *installedmap, DUChanges *mps, int nmps) { struct mptree *mptree; struct ducbdata cbd; Solvable *s; int i, sp; Map ignoredu; Repo *oldinstalled = pool->installed; int haveonlyadd = 0; map_init(&ignoredu, 0); mptree = create_mptree(mps, nmps); for (i = 0; i < nmps; i++) if ((mps[i].flags & DUCHANGES_ONLYADD) != 0) haveonlyadd = 1; cbd.mps = mps; cbd.dirmap = 0; cbd.nmap = 0; cbd.olddata = 0; cbd.mptree = mptree; cbd.addsub = 1; for (sp = 1, s = pool->solvables + sp; sp < pool->nsolvables; sp++, s++) { if (!s->repo || (oldinstalled && s->repo == oldinstalled)) continue; if (!MAPTST(installedmap, sp)) continue; cbd.hasdu = 0; repo_search(s->repo, sp, SOLVABLE_DISKUSAGE, 0, 0, solver_fill_DU_cb, &cbd); if (!cbd.hasdu && oldinstalled) { Id op, opp; int didonlyadd = 0; /* no du data available, ignore data of all installed solvables we obsolete */ if (!ignoredu.size) map_grow(&ignoredu, oldinstalled->end - oldinstalled->start); FOR_PROVIDES(op, opp, s->name) { Solvable *s2 = pool->solvables + op; if (!pool->implicitobsoleteusesprovides && s->name != s2->name) continue; if (pool->implicitobsoleteusescolors && !pool_colormatch(pool, s, s2)) continue; if (op >= oldinstalled->start && op < oldinstalled->end) { MAPSET(&ignoredu, op - oldinstalled->start); if (haveonlyadd && pool->solvables[op].repo == oldinstalled && !didonlyadd) { repo_search(oldinstalled, op, SOLVABLE_DISKUSAGE, 0, 0, solver_fill_DU_cb, &cbd); cbd.addsub = -1; repo_search(oldinstalled, op, SOLVABLE_DISKUSAGE, 0, 0, solver_fill_DU_cb, &cbd); cbd.addsub = 1; didonlyadd = 1; } } } if (s->obsoletes) { Id obs, *obsp = s->repo->idarraydata + s->obsoletes; while ((obs = *obsp++) != 0) FOR_PROVIDES(op, opp, obs) { Solvable *s2 = pool->solvables + op; if (!pool->obsoleteusesprovides && !pool_match_nevr(pool, s2, obs)) continue; if (pool->obsoleteusescolors && !pool_colormatch(pool, s, s2)) continue; if (op >= oldinstalled->start && op < oldinstalled->end) { MAPSET(&ignoredu, op - oldinstalled->start); if (haveonlyadd && pool->solvables[op].repo == oldinstalled && !didonlyadd) { repo_search(oldinstalled, op, SOLVABLE_DISKUSAGE, 0, 0, solver_fill_DU_cb, &cbd); cbd.addsub = -1; repo_search(oldinstalled, op, SOLVABLE_DISKUSAGE, 0, 0, solver_fill_DU_cb, &cbd); cbd.addsub = 1; didonlyadd = 1; } } } } } } cbd.addsub = -1; if (oldinstalled) { /* assumes we allways have du data for installed solvables */ FOR_REPO_SOLVABLES(oldinstalled, sp, s) { if (MAPTST(installedmap, sp)) continue; if (ignoredu.size && MAPTST(&ignoredu, sp - oldinstalled->start)) continue; repo_search(oldinstalled, sp, SOLVABLE_DISKUSAGE, 0, 0, solver_fill_DU_cb, &cbd); } } map_free(&ignoredu); solv_free(cbd.dirmap); solv_free(mptree); } long long pool_calc_installsizechange(Pool *pool, Map *installedmap) { Id sp; Solvable *s; long long change = 0; Repo *oldinstalled = pool->installed; for (sp = 1, s = pool->solvables + sp; sp < pool->nsolvables; sp++, s++) { if (!s->repo || (oldinstalled && s->repo == oldinstalled)) continue; if (!MAPTST(installedmap, sp)) continue; change += solvable_lookup_sizek(s, SOLVABLE_INSTALLSIZE, 0); } if (oldinstalled) { FOR_REPO_SOLVABLES(oldinstalled, sp, s) { if (MAPTST(installedmap, sp)) continue; change -= solvable_lookup_sizek(s, SOLVABLE_INSTALLSIZE, 0); } } return change; }