b764b98b160de5988b73db190925d2b0bc4a8d52
[platform/upstream/libsolv.git] / src / diskusage.c
1 /*
2  * Copyright (c) 2007-2016, SUSE LLC
3  *
4  * This program is licensed under the BSD license, read LICENSE.BSD
5  * for further information
6  */
7
8 /*
9  * diskusage.c
10  *
11  * calculate needed space on partitions
12  */
13
14 #include <stdio.h>
15 #include <stdlib.h>
16 #include <stdarg.h>
17 #include <unistd.h>
18 #include <string.h>
19
20 #include "pool.h"
21 #include "poolarch.h"
22 #include "repo.h"
23 #include "util.h"
24 #include "bitmap.h"
25
26
27 struct mptree {
28   Id sibling;
29   Id child;
30   const char *comp;
31   int compl;
32   Id mountpoint;
33 };
34
35 struct ducbdata {
36   DUChanges *mps;
37   struct mptree *mptree;
38   int addsub;
39   int hasdu;
40
41   Id *dirmap;
42   int nmap;
43   Repodata *olddata;
44 };
45
46
47 static int
48 solver_fill_DU_cb(void *cbdata, Solvable *s, Repodata *data, Repokey *key, KeyValue *value)
49 {
50   struct ducbdata *cbd = cbdata;
51   Id mp;
52
53   if (data != cbd->olddata)
54     {
55       Id dn, mp, comp, *dirmap, *dirs;
56       int i, compl;
57       const char *compstr;
58       struct mptree *mptree;
59
60       /* create map from dir to mptree */
61       cbd->dirmap = solv_free(cbd->dirmap);
62       cbd->nmap = 0;
63       dirmap = solv_calloc(data->dirpool.ndirs, sizeof(Id));
64       mptree = cbd->mptree;
65       mp = 0;
66       for (dn = 2, dirs = data->dirpool.dirs + dn; dn < data->dirpool.ndirs; dn++)
67         {
68           comp = *dirs++;
69           if (comp <= 0)
70             {
71               mp = dirmap[-comp];
72               continue;
73             }
74           if (mp < 0)
75             {
76               /* unconnected */
77               dirmap[dn] = mp;
78               continue;
79             }
80           if (!mptree[mp].child)
81             {
82               dirmap[dn] = -mp;
83               continue;
84             }
85           if (data->localpool)
86             compstr = stringpool_id2str(&data->spool, comp);
87           else
88             compstr = pool_id2str(data->repo->pool, comp);
89           compl = strlen(compstr);
90           for (i = mptree[mp].child; i; i = mptree[i].sibling)
91             if (mptree[i].compl == compl && !strncmp(mptree[i].comp, compstr, compl))
92               break;
93           dirmap[dn] = i ? i : -mp;
94         }
95       /* change dirmap to point to mountpoint instead of mptree */
96       for (dn = 0; dn < data->dirpool.ndirs; dn++)
97         {
98           mp = dirmap[dn];
99           dirmap[dn] = mptree[mp > 0 ? mp : -mp].mountpoint;
100         }
101       cbd->dirmap = dirmap;
102       cbd->nmap = data->dirpool.ndirs;
103       cbd->olddata = data;
104     }
105   cbd->hasdu = 1;
106   if (value->id < 0 || value->id >= cbd->nmap)
107     return 0;
108   mp = cbd->dirmap[value->id];
109   if (mp < 0)
110     return 0;
111   if (cbd->addsub > 0)
112     {
113       cbd->mps[mp].kbytes += value->num;
114       cbd->mps[mp].files += value->num2;
115     }
116   else if (!(cbd->mps[mp].flags & DUCHANGES_ONLYADD))
117     {
118       cbd->mps[mp].kbytes -= value->num;
119       cbd->mps[mp].files -= value->num2;
120     }
121   return 0;
122 }
123
124 static void
125 propagate_mountpoints(struct mptree *mptree, int pos, Id mountpoint)
126 {
127   int i;
128   if (mptree[pos].mountpoint == -1)
129     mptree[pos].mountpoint = mountpoint;
130   else
131     mountpoint = mptree[pos].mountpoint;
132   for (i = mptree[pos].child; i; i = mptree[i].sibling)
133     propagate_mountpoints(mptree, i, mountpoint);
134 }
135
136 #define MPTREE_BLOCK 15
137
138 static struct mptree *
139 create_mptree(DUChanges *mps, int nmps)
140 {
141   int i, nmptree;
142   struct mptree *mptree;
143   int pos, compl;
144   int mp;
145   const char *p, *path, *compstr;
146
147   mptree = solv_extend_resize(0, 1, sizeof(struct mptree), MPTREE_BLOCK);
148
149   /* our root node */
150   mptree[0].sibling = 0;
151   mptree[0].child = 0;
152   mptree[0].comp = 0;
153   mptree[0].compl = 0;
154   mptree[0].mountpoint = -1;
155   nmptree = 1;
156
157   /* create component tree */
158   for (mp = 0; mp < nmps; mp++)
159     {
160       mps[mp].kbytes = 0;
161       mps[mp].files = 0;
162       pos = 0;
163       path = mps[mp].path;
164       while(*path == '/')
165         path++;
166       while (*path)
167         {
168           if ((p = strchr(path, '/')) == 0)
169             {
170               compstr = path;
171               compl = strlen(compstr);
172               path += compl;
173             }
174           else
175             {
176               compstr = path;
177               compl = p - path;
178               path = p + 1;
179               while(*path == '/')
180                 path++;
181             }
182           for (i = mptree[pos].child; i; i = mptree[i].sibling)
183             if (mptree[i].compl == compl && !strncmp(mptree[i].comp, compstr, compl))
184               break;
185           if (!i)
186             {
187               /* create new node */
188               mptree = solv_extend(mptree, nmptree, 1, sizeof(struct mptree), MPTREE_BLOCK);
189               i = nmptree++;
190               mptree[i].sibling = mptree[pos].child;
191               mptree[i].child = 0;
192               mptree[i].comp = compstr;
193               mptree[i].compl = compl;
194               mptree[i].mountpoint = -1;
195               mptree[pos].child = i;
196             }
197           pos = i;
198         }
199       mptree[pos].mountpoint = mp;
200     }
201
202   propagate_mountpoints(mptree, 0, mptree[0].mountpoint);
203
204 #if 0
205   for (i = 0; i < nmptree; i++)
206     {
207       printf("#%d sibling: %d\n", i, mptree[i].sibling);
208       printf("#%d child: %d\n", i, mptree[i].child);
209       printf("#%d comp: %s\n", i, mptree[i].comp);
210       printf("#%d compl: %d\n", i, mptree[i].compl);
211       printf("#%d mountpont: %d\n", i, mptree[i].mountpoint);
212     }
213 #endif
214
215   return mptree;
216 }
217
218 void
219 pool_calc_duchanges(Pool *pool, Map *installedmap, DUChanges *mps, int nmps)
220 {
221   struct mptree *mptree;
222   struct ducbdata cbd;
223   Solvable *s;
224   int i, sp;
225   Map ignoredu;
226   Repo *oldinstalled = pool->installed;
227   int haveonlyadd = 0;
228
229   map_init(&ignoredu, 0);
230   mptree = create_mptree(mps, nmps);
231
232   for (i = 0; i < nmps; i++)
233     if ((mps[i].flags & DUCHANGES_ONLYADD) != 0)
234       haveonlyadd = 1;
235   cbd.mps = mps;
236   cbd.dirmap = 0;
237   cbd.nmap = 0;
238   cbd.olddata = 0;
239   cbd.mptree = mptree;
240   cbd.addsub = 1;
241   for (sp = 1, s = pool->solvables + sp; sp < pool->nsolvables; sp++, s++)
242     {
243       if (!s->repo || (oldinstalled && s->repo == oldinstalled))
244         continue;
245       if (!MAPTST(installedmap, sp))
246         continue;
247       cbd.hasdu = 0;
248       repo_search(s->repo, sp, SOLVABLE_DISKUSAGE, 0, 0, solver_fill_DU_cb, &cbd);
249       if (!cbd.hasdu && oldinstalled)
250         {
251           Id op, opp;
252           int didonlyadd = 0;
253           /* no du data available, ignore data of all installed solvables we obsolete */
254           if (!ignoredu.size)
255             map_grow(&ignoredu, oldinstalled->end - oldinstalled->start);
256           FOR_PROVIDES(op, opp, s->name)
257             {
258               Solvable *s2 = pool->solvables + op;
259               if (!pool->implicitobsoleteusesprovides && s->name != s2->name)
260                 continue;
261               if (pool->implicitobsoleteusescolors && !pool_colormatch(pool, s, s2))
262                 continue;
263               if (op >= oldinstalled->start && op < oldinstalled->end)
264                 {
265                   MAPSET(&ignoredu, op - oldinstalled->start);
266                   if (haveonlyadd && pool->solvables[op].repo == oldinstalled && !didonlyadd)
267                     {
268                       repo_search(oldinstalled, op, SOLVABLE_DISKUSAGE, 0, 0, solver_fill_DU_cb, &cbd);
269                       cbd.addsub = -1;
270                       repo_search(oldinstalled, op, SOLVABLE_DISKUSAGE, 0, 0, solver_fill_DU_cb, &cbd);
271                       cbd.addsub = 1;
272                       didonlyadd = 1;
273                     }
274                 }
275             }
276           if (s->obsoletes)
277             {
278               Id obs, *obsp = s->repo->idarraydata + s->obsoletes;
279               while ((obs = *obsp++) != 0)
280                 FOR_PROVIDES(op, opp, obs)
281                   {
282                     Solvable *s2 = pool->solvables + op;
283                     if (!pool->obsoleteusesprovides && !pool_match_nevr(pool, s2, obs))
284                       continue;
285                     if (pool->obsoleteusescolors && !pool_colormatch(pool, s, s2))
286                       continue;
287                     if (op >= oldinstalled->start && op < oldinstalled->end)
288                       {
289                         MAPSET(&ignoredu, op - oldinstalled->start);
290                         if (haveonlyadd && pool->solvables[op].repo == oldinstalled && !didonlyadd)
291                           {
292                             repo_search(oldinstalled, op, SOLVABLE_DISKUSAGE, 0, 0, solver_fill_DU_cb, &cbd);
293                             cbd.addsub = -1;
294                             repo_search(oldinstalled, op, SOLVABLE_DISKUSAGE, 0, 0, solver_fill_DU_cb, &cbd);
295                             cbd.addsub = 1;
296                             didonlyadd = 1;
297                           }
298                       }
299                   }
300             }
301         }
302     }
303   cbd.addsub = -1;
304   if (oldinstalled)
305     {
306       /* assumes we allways have du data for installed solvables */
307       FOR_REPO_SOLVABLES(oldinstalled, sp, s)
308         {
309           if (MAPTST(installedmap, sp))
310             continue;
311           if (ignoredu.map && MAPTST(&ignoredu, sp - oldinstalled->start))
312             continue;
313           repo_search(oldinstalled, sp, SOLVABLE_DISKUSAGE, 0, 0, solver_fill_DU_cb, &cbd);
314         }
315     }
316   map_free(&ignoredu);
317   solv_free(cbd.dirmap);
318   solv_free(mptree);
319 }
320
321 int
322 pool_calc_installsizechange(Pool *pool, Map *installedmap)
323 {
324   Id sp;
325   Solvable *s;
326   int change = 0; 
327   Repo *oldinstalled = pool->installed;
328
329   for (sp = 1, s = pool->solvables + sp; sp < pool->nsolvables; sp++, s++) 
330     {    
331       if (!s->repo || (oldinstalled && s->repo == oldinstalled))
332         continue;
333       if (!MAPTST(installedmap, sp)) 
334         continue;
335       change += solvable_lookup_sizek(s, SOLVABLE_INSTALLSIZE, 0);
336     }    
337   if (oldinstalled)
338     {    
339       FOR_REPO_SOLVABLES(oldinstalled, sp, s)
340         {
341           if (MAPTST(installedmap, sp)) 
342             continue;
343           change -= solvable_lookup_sizek(s, SOLVABLE_INSTALLSIZE, 0);
344         }
345     }    
346   return change;
347 }
348