Imported Upstream version 0.6.27
[platform/upstream/libsolv.git] / ext / pool_fileconflicts.c
index f2fb69c..cb55d58 100644 (file)
@@ -7,8 +7,6 @@
 
 #include <stdio.h>
 #include <sys/stat.h>
-#include <sys/stat.h>
-#include <fcntl.h>
 #include <unistd.h>
 
 #include "pool.h"
@@ -399,6 +397,7 @@ unifywithcanon(struct cbdata *cbdata, Id diroff, int dirl)
     dirl--;
   if (!dirl)
     return diroff;
+
   /* find dirname */
   for (i = dirl - 1; i > 0; i--)
     if (cbdata->filesspace[diroff + i] == '/')
@@ -450,11 +449,9 @@ unifywithcanon(struct cbdata *cbdata, Id diroff, int dirl)
   printf("stat()ing %s\n", cbdata->canonspace);
 #endif
   cbdata->statsmade++;
-  if (lstat(cbdata->canonspace, &stb))
-    return diroff;             /* hmm */
-  if (!S_ISLNK(stb.st_mode))
+  if (lstat(cbdata->canonspace, &stb) != 0 || !S_ISLNK(stb.st_mode))
     {
-      /* not a symlink, have new canon entry */
+      /* not a symlink or stat failed, have new canon entry */
       diroff = addfilesspace(cbdata, l + dirl - i + 2);
       strcpy((char *)cbdata->filesspace + diroff, cbdata->canonspace + cbdata->rootdirl);
       l += dirl - i;
@@ -641,7 +638,7 @@ findfileconflicts2_cb(void *cbdatav, const char *fn, struct filelistinfo *info)
   strncpy(md5padded, info->digest, 32);
   md5padded[32] = 0;
   md5padded[33] = info->color;
-  /* printf("%d, hx %x -> %s   %d %s\n", cbdata->idx, hx, fn, info->mode, info->digest); */
+  /* printf("%d, hx %x -> %s   %d %s %d\n", cbdata->idx, hx, fn, info->mode, info->digest, info->color); */
   off = addfilesspace(cbdata, strlen(fn) + (34 + 1));
   memcpy(cbdata->filesspace + off, (unsigned char *)md5padded, 34);
   strcpy((char *)cbdata->filesspace + off + 34, fn);
@@ -729,8 +726,8 @@ iterate_solvable_dirs(Pool *pool, Id p, void (*cb)(void *, const char *, struct
   dataiterator_free(&di);
 }
 
-/* before calling the expensive findfileconflicts_basename_cb we check if any of
- * the basenames match. This only makes sense when cbdata->create is off.
+/* before calling the expensive findfileconflicts_cb we check if any of
+ * the files match. This only makes sense when cbdata->create is off.
  */
 static int
 precheck_solvable_files(struct cbdata *cbdata, Pool *pool, Id p)
@@ -739,13 +736,42 @@ precheck_solvable_files(struct cbdata *cbdata, Pool *pool, Id p)
   Id hx, qx;
   Hashval h, hh;
   int found = 0;
+  int aliases = cbdata->aliases;
+  unsigned int lastdirid = -1;
+  Hashval lastdirhash = 0;
+  int lastdirlen = 0;
+  int checkthisdir = 0;
+  Repodata *lastrepodata = 0;
 
   dataiterator_init(&di, pool, 0, p, SOLVABLE_FILELIST, 0, SEARCH_COMPLETE_FILELIST);
   while (dataiterator_step(&di))
     {
-      hx = strhash(di.kv.str);
-      if (!hx)
-       hx = strlen(di.kv.str) + 1;
+      if (aliases)
+       {
+         /* hash just the basename */
+         hx = strhash(di.kv.str);
+         if (!hx)
+           hx = strlen(di.kv.str) + 1;
+       }
+      else
+       {
+         /* hash the full path */
+         if (di.data != lastrepodata || di.kv.id != lastdirid)
+           {
+             const char *dir;
+             lastrepodata = di.data;
+             lastdirid = di.kv.id;
+             dir = repodata_dir2str(lastrepodata, lastdirid, "");
+             lastdirlen = strlen(dir);
+             lastdirhash = strhash(dir);
+             checkthisdir =  isindirmap(cbdata, lastdirhash ? lastdirhash : lastdirlen + 1);
+           }
+         if (!checkthisdir)
+           continue;
+         hx = strhash_cont(di.kv.str, lastdirhash);
+         if (!hx)
+           hx = lastdirlen + strlen(di.kv.str) + 1;
+       }
       h = hx & cbdata->cflmapn;
       hh = HASHCHAIN_START;
       for (;;)
@@ -777,15 +803,18 @@ pool_findfileconflicts(Pool *pool, Queue *pkgs, int cutoff, Queue *conflicts, in
   void *handle;
   Repo *installed = pool->installed;
   Id p;
-  int obsoleteusescolors = pool_get_flag(pool, POOL_FLAG_OBSOLETEUSESCOLORS);
+  int usefilecolors;
+  int hdrfetches;
 
   queue_empty(conflicts);
   if (!pkgs->count)
     return 0;
 
   now = start = solv_timems(0);
+  /* Hmm, should we have a different flag for this? */
+  usefilecolors = pool_get_flag(pool, POOL_FLAG_IMPLICITOBSOLETEUSESCOLORS);
   POOL_DEBUG(SOLV_DEBUG_STATS, "searching for file conflicts\n");
-  POOL_DEBUG(SOLV_DEBUG_STATS, "packages: %d, cutoff %d\n", pkgs->count, cutoff);
+  POOL_DEBUG(SOLV_DEBUG_STATS, "packages: %d, cutoff %d, usefilecolors %d\n", pkgs->count, cutoff, usefilecolors);
 
   memset(&cbdata, 0, sizeof(cbdata));
   cbdata.aliases = flags & FINDFILECONFLICTS_CHECK_DIRALIASING;
@@ -813,6 +842,7 @@ pool_findfileconflicts(Pool *pool, Queue *pkgs, int cutoff, Queue *conflicts, in
   /* first pass: scan dirs */
   if (!cbdata.aliases)
     {
+      hdrfetches = 0;
       cflmapn = (cutoff + 3) * 64;
       while ((cflmapn & (cflmapn - 1)) != 0)
        cflmapn = cflmapn & (cflmapn - 1);
@@ -822,10 +852,10 @@ pool_findfileconflicts(Pool *pool, Queue *pkgs, int cutoff, Queue *conflicts, in
       idxmapset = 0;
       for (i = 0; i < pkgs->count; i++)
        {
-         p = pkgs->elements[i];
-         cbdata.idx = i;
          if (i == cutoff)
            cbdata.create = 0;
+         cbdata.idx = i;
+         p = pkgs->elements[i];
          if ((flags & FINDFILECONFLICTS_USE_SOLVABLEFILELIST) != 0 && installed)
            {
              if (p >= installed->start && p < installed->end && pool->solvables[p].repo == installed)
@@ -839,12 +869,14 @@ pool_findfileconflicts(Pool *pool, Queue *pkgs, int cutoff, Queue *conflicts, in
          handle = (*handle_cb)(pool, p, handle_cbdata);
          if (!handle)
            continue;
+         hdrfetches++;
          rpm_iterate_filelist(handle, RPM_ITERATE_FILELIST_ONLYDIRS, finddirs_cb, &cbdata);
          if (MAPTST(&cbdata.idxmap, i))
            idxmapset++;
        }
       POOL_DEBUG(SOLV_DEBUG_STATS, "dirmap size: %d, used %d\n", cbdata.dirmapn + 1, cbdata.dirmapused);
       POOL_DEBUG(SOLV_DEBUG_STATS, "dirmap memory usage: %d K\n", (cbdata.dirmapn + 1) * 2 * (int)sizeof(Id) / 1024);
+      POOL_DEBUG(SOLV_DEBUG_STATS, "header fetches: %d\n", hdrfetches);
       POOL_DEBUG(SOLV_DEBUG_STATS, "dirmap creation took %d ms\n", solv_timems(now));
       POOL_DEBUG(SOLV_DEBUG_STATS, "dir conflicts found: %d, idxmap %d of %d\n", cbdata.dirconflicts, idxmapset, pkgs->count);
     }
@@ -857,15 +889,16 @@ pool_findfileconflicts(Pool *pool, Queue *pkgs, int cutoff, Queue *conflicts, in
   cbdata.cflmap = solv_calloc(cflmapn, 2 * sizeof(Id));
   cbdata.cflmapn = cflmapn - 1;        /* make it a mask */
   cbdata.create = 1;
+  hdrfetches = 0;
   for (i = 0; i < pkgs->count; i++)
     {
+      if (i == cutoff)
+       cbdata.create = 0;
       if (!cbdata.aliases && !MAPTST(&cbdata.idxmap, i))
        continue;
-      p = pkgs->elements[i];
       cbdata.idx = i;
-      if (i == cutoff)
-       cbdata.create = 0;
-      if (cbdata.aliases && !cbdata.create && FINDFILECONFLICTS_USE_SOLVABLEFILELIST)
+      p = pkgs->elements[i];
+      if (!cbdata.create && (flags & FINDFILECONFLICTS_USE_SOLVABLEFILELIST) != 0 && installed)
        {
          if (p >= installed->start && p < installed->end && pool->solvables[p].repo == installed)
            if (!precheck_solvable_files(&cbdata, pool, p))
@@ -876,12 +909,14 @@ pool_findfileconflicts(Pool *pool, Queue *pkgs, int cutoff, Queue *conflicts, in
       handle = (*handle_cb)(pool, p, handle_cbdata);
       if (!handle)
        continue;
+      hdrfetches++;
       cbdata.lastdiridx = -1;
       rpm_iterate_filelist(handle, RPM_ITERATE_FILELIST_NOGHOSTS, cbdata.aliases ? findfileconflicts_basename_cb : findfileconflicts_cb, &cbdata);
     }
 
   POOL_DEBUG(SOLV_DEBUG_STATS, "filemap size: %d, used %d\n", cbdata.cflmapn + 1, cbdata.cflmapused);
   POOL_DEBUG(SOLV_DEBUG_STATS, "filemap memory usage: %d K\n", (cbdata.cflmapn + 1) * 2 * (int)sizeof(Id) / 1024);
+  POOL_DEBUG(SOLV_DEBUG_STATS, "header fetches: %d\n", hdrfetches);
   POOL_DEBUG(SOLV_DEBUG_STATS, "filemap creation took %d ms\n", solv_timems(now));
   POOL_DEBUG(SOLV_DEBUG_STATS, "lookat_dir size: %d\n", cbdata.lookat_dir.count);
   queue_free(&cbdata.lookat_dir);
@@ -903,6 +938,7 @@ pool_findfileconflicts(Pool *pool, Queue *pkgs, int cutoff, Queue *conflicts, in
          cbdata.statmapn = cflmapn - 1;        /* make it a mask */
        }
       cbdata.create = 0;
+      hdrfetches = 0;
       for (i = 0; i < pkgs->count; i++)
        {
          if (!MAPTST(&cbdata.idxmap, i))
@@ -914,11 +950,13 @@ pool_findfileconflicts(Pool *pool, Queue *pkgs, int cutoff, Queue *conflicts, in
          handle = (*handle_cb)(pool, p, handle_cbdata);
          if (!handle)
            continue;
+         hdrfetches++;
          cbdata.lastdiridx = -1;
          rpm_iterate_filelist(handle, RPM_ITERATE_FILELIST_NOGHOSTS, findfileconflicts_alias_cb, &cbdata);
        }
       POOL_DEBUG(SOLV_DEBUG_STATS, "normap size: %d, used %d\n", cbdata.normapn + 1, cbdata.normapused);
       POOL_DEBUG(SOLV_DEBUG_STATS, "normap memory usage: %d K\n", (cbdata.normapn + 1) * 2 * (int)sizeof(Id) / 1024);
+      POOL_DEBUG(SOLV_DEBUG_STATS, "header fetches: %d\n", hdrfetches);
       POOL_DEBUG(SOLV_DEBUG_STATS, "stats made: %d\n", cbdata.statsmade);
       if (cbdata.usestat)
        {
@@ -939,11 +977,10 @@ pool_findfileconflicts(Pool *pool, Queue *pkgs, int cutoff, Queue *conflicts, in
   cbdata.cflmapn = 0;
   cbdata.cflmapused = 0;
 
-  now = solv_timems(0);
-
   map_free(&cbdata.idxmap);
 
   /* sort and unify/prune */
+  now = solv_timems(0);
   POOL_DEBUG(SOLV_DEBUG_STATS, "raw candidates: %d, pruning\n", cbdata.lookat.count / 4);
   solv_sort(cbdata.lookat.elements, cbdata.lookat.count / 4, sizeof(Id) * 4, &lookat_hx_cmp, pool);
   for (i = j = 0; i < cbdata.lookat.count; )
@@ -978,18 +1015,23 @@ pool_findfileconflicts(Pool *pool, Queue *pkgs, int cutoff, Queue *conflicts, in
     }
   queue_truncate(&cbdata.lookat, j);
   POOL_DEBUG(SOLV_DEBUG_STATS, "candidates now: %d\n", cbdata.lookat.count / 4);
+  POOL_DEBUG(SOLV_DEBUG_STATS, "pruning took %d ms\n", solv_timems(now));
 
   /* third pass: collect file info for all files that match a hx */
+  now = solv_timems(0);
   solv_sort(cbdata.lookat.elements, cbdata.lookat.count / 4, sizeof(Id) * 4, &lookat_idx_cmp, pool);
   queue_init(&cbdata.files);
+  hdrfetches = 0;
   for (i = 0; i < cbdata.lookat.count; i += 4)
     {
       Id idx = cbdata.lookat.elements[i + 1];
       int iterflags = RPM_ITERATE_FILELIST_WITHMD5 | RPM_ITERATE_FILELIST_NOGHOSTS;
-      if (obsoleteusescolors)
+      if (usefilecolors)
        iterflags |= RPM_ITERATE_FILELIST_WITHCOL;
       p = pkgs->elements[idx];
       handle = (*handle_cb)(pool, p, handle_cbdata);
+      if (handle)
+       hdrfetches++;
       for (;; i += 4)
        {
          int fstart = cbdata.files.count;
@@ -1008,11 +1050,14 @@ pool_findfileconflicts(Pool *pool, Queue *pkgs, int cutoff, Queue *conflicts, in
            break;
        }
     }
+  POOL_DEBUG(SOLV_DEBUG_STATS, "header fetches: %d\n", hdrfetches);
+  POOL_DEBUG(SOLV_DEBUG_STATS, "file info fetching took %d ms\n", solv_timems(now));
 
   cbdata.normap = solv_free(cbdata.normap);
   cbdata.normapn = 0;
 
   /* forth pass: for each hx we have, compare all matching files against all other matching files */
+  now = solv_timems(0);
   solv_sort(cbdata.lookat.elements, cbdata.lookat.count / 4, sizeof(Id) * 4, &lookat_hx_cmp, pool);
   for (i = 0; i < cbdata.lookat.count - 4; i += 4)
     {
@@ -1038,13 +1083,13 @@ pool_findfileconflicts(Pool *pool, Queue *pkgs, int cutoff, Queue *conflicts, in
                char *fsj = (char *)cbdata.filesspace + cbdata.files.elements[jj];
                if (cbdata.aliases)
                  {
-                   /* compare just the basenames, the dirs match */
+                   /* compare just the basenames, the dirs match because of the dirid */
                    char *bsi = strrchr(fsi + 34, '/');
                    char *bsj = strrchr(fsj + 34, '/');
-                   if ((!bsi || !bsj) && bsi != bsj)
+                   if (!bsi || !bsj)
                      continue;
                    if (strcmp(bsi, bsj))
-                     continue; /* different file names */
+                     continue; /* different base names */
                  }
                else
                  {
@@ -1052,8 +1097,8 @@ pool_findfileconflicts(Pool *pool, Queue *pkgs, int cutoff, Queue *conflicts, in
                      continue; /* different file names */
                  }
                if (!strcmp(fsi, fsj))
-                 continue;     /* md5 sum matches */
-               if (obsoleteusescolors && fsi[33] && fsj[33] && (fsi[33] & fsj[33]) == 0)
+                 continue;     /* file digests match, no conflict */
+               if (usefilecolors && fsi[33] && fsj[33] && (fsi[33] & fsj[33]) == 0)
                  continue;     /* colors do not conflict */
                queue_push(conflicts, pool_str2id(pool, fsi + 34, 1));
                queue_push(conflicts, pkgs->elements[pidx]);
@@ -1075,6 +1120,6 @@ pool_findfileconflicts(Pool *pool, Queue *pkgs, int cutoff, Queue *conflicts, in
   POOL_DEBUG(SOLV_DEBUG_STATS, "found %d file conflicts\n", conflicts->count / 6);
   POOL_DEBUG(SOLV_DEBUG_STATS, "file conflict detection took %d ms\n", solv_timems(start));
 
-  return conflicts->count;
+  return conflicts->count / 6;
 }