/** \ingroup payload * Return next directory name (from file info). * @param dnli directory name iterator * @return next directory name */ static const char * dnlNextIterator(DNLI_t dnli) { const char * dn = NULL; if (dnli) { rpmfiles fi = dnli->fi; int dc = rpmfilesDC(fi); int i = -1; if (dnli->active) do { i = (!dnli->reverse ? dnli->i++ : --dnli->i); } while (i >= 0 && i < dc && !dnli->active[i]); if (i >= 0 && i < dc) dn = rpmfilesDN(fi, i); else i = -1; dnli->isave = i; } return dn; }
/** * Skip any files that do not match install policies. * @param ts transaction set * @param files file info set * @param fs file states */ static void skipInstallFiles(const rpmts ts, rpmfiles files, rpmfs fs) { rpm_color_t tscolor = rpmtsColor(ts); rpm_color_t FColor; int noConfigs = (rpmtsFlags(ts) & RPMTRANS_FLAG_NOCONFIGS); int noDocs = (rpmtsFlags(ts) & RPMTRANS_FLAG_NODOCS); int * drc; char * dff; int dc; int i, j, ix; rpmfi fi = rpmfilesIter(files, RPMFI_ITER_FWD); if (!noDocs) noDocs = rpmExpandNumeric("%{_excludedocs}"); /* Compute directory refcount, skip directory if now empty. */ dc = rpmfiDC(fi); drc = xcalloc(dc, sizeof(*drc)); dff = xcalloc(dc, sizeof(*dff)); fi = rpmfiInit(fi, 0); while ((i = rpmfiNext(fi)) >= 0) { char ** nsp; const char *flangs; ix = rpmfiDX(fi); drc[ix]++; /* Don't bother with skipped files */ if (XFA_SKIPPING(rpmfsGetAction(fs, i))) { drc[ix]--; dff[ix] = 1; continue; } /* Ignore colored files not in our rainbow. */ FColor = rpmfiFColor(fi); if (tscolor && FColor && !(tscolor & FColor)) { drc[ix]--; dff[ix] = 1; rpmfsSetAction(fs, i, FA_SKIPCOLOR); continue; } /* * Skip net shared paths. * Net shared paths are not relative to the current root (though * they do need to take package relocations into account). */ if (ts->netsharedPaths) { nsp = matchNetsharedpath(ts, fi); if (nsp && *nsp) { drc[ix]--; dff[ix] = 1; rpmfsSetAction(fs, i, FA_SKIPNETSHARED); continue; } } /* * Skip i18n language specific files. */ flangs = (ts->installLangs != NULL) ? rpmfiFLangs(fi) : NULL; if (flangs != NULL && *flangs != '\0') { const char *l, *le; char **lang; for (lang = ts->installLangs; *lang != NULL; lang++) { for (l = flangs; *l != '\0'; l = le) { for (le = l; *le != '\0' && *le != '|'; le++) {}; if ((le-l) > 0 && rstreqn(*lang, l, (le-l))) break; if (*le == '|') le++; /* skip over | */ } if (*l != '\0') break; } if (*lang == NULL) { drc[ix]--; dff[ix] = 1; rpmfsSetAction(fs, i, FA_SKIPNSTATE); continue; } } /* * Skip config files if requested. */ if (noConfigs && (rpmfiFFlags(fi) & RPMFILE_CONFIG)) { drc[ix]--; dff[ix] = 1; rpmfsSetAction(fs, i, FA_SKIPNSTATE); continue; } /* * Skip documentation if requested. */ if (noDocs && (rpmfiFFlags(fi) & RPMFILE_DOC)) { drc[ix]--; dff[ix] = 1; rpmfsSetAction(fs, i, FA_SKIPNSTATE); continue; } } /* Skip (now empty) directories that had skipped files. */ /* Iterate over dirs in reversed order to solve subdirs at first */ for (j = dc - 1; j >= 0; j--) { const char * dn, * bn; size_t dnlen, bnlen; if (drc[j]) continue; /* dir still has files. */ if (!dff[j]) continue; /* dir was not emptied here. */ /* Find parent directory and basename. */ dn = rpmfilesDN(files, j); dnlen = strlen(dn) - 1; bn = dn + dnlen; bnlen = 0; while (bn > dn && bn[-1] != '/') { bnlen++; dnlen--; bn--; } /* If explicitly included in the package, skip the directory. */ fi = rpmfiInit(fi, 0); while ((i = rpmfiNext(fi)) >= 0) { const char * fdn, * fbn; rpm_mode_t fFMode; if (XFA_SKIPPING(rpmfsGetAction(fs, i))) continue; fFMode = rpmfiFMode(fi); if (rpmfiWhatis(fFMode) != XDIR) continue; fdn = rpmfiDN(fi); if (strlen(fdn) != dnlen) continue; if (!rstreqn(fdn, dn, dnlen)) continue; fbn = rpmfiBN(fi); if (strlen(fbn) != bnlen) continue; if (!rstreqn(fbn, bn, bnlen)) continue; rpmlog(RPMLOG_DEBUG, "excluding directory %s\n", dn); rpmfsSetAction(fs, i, FA_SKIPNSTATE); ix = rpmfiDX(fi); /* Decrease count of files for parent directory */ drc[ix]--; /* Mark directory because something was removed from them */ dff[ix] = 1; break; } } free(drc); free(dff); rpmfiFree(fi); }
/** \ingroup payload * Create directory name iterator. * @param fi file info set * @param fs file state set * @param reverse traverse directory names in reverse order? * @return directory name iterator */ static DNLI_t dnlInitIterator(rpmfiles fi, rpmfs fs, int reverse) { DNLI_t dnli; int i, j; int dc; if (fi == NULL) return NULL; dc = rpmfilesDC(fi); dnli = xcalloc(1, sizeof(*dnli)); dnli->fi = fi; dnli->reverse = reverse; dnli->i = (reverse ? dc : 0); if (dc) { dnli->active = xcalloc(dc, sizeof(*dnli->active)); int fc = rpmfilesFC(fi); /* Identify parent directories not skipped. */ for (i = 0; i < fc; i++) if (!XFA_SKIPPING(rpmfsGetAction(fs, i))) dnli->active[rpmfilesDI(fi, i)] = 1; /* Exclude parent directories that are explicitly included. */ for (i = 0; i < fc; i++) { int dil; size_t dnlen, bnlen; if (!S_ISDIR(rpmfilesFMode(fi, i))) continue; dil = rpmfilesDI(fi, i); dnlen = strlen(rpmfilesDN(fi, dil)); bnlen = strlen(rpmfilesBN(fi, i)); for (j = 0; j < dc; j++) { const char * dnl; size_t jlen; if (!dnli->active[j] || j == dil) continue; dnl = rpmfilesDN(fi, j); jlen = strlen(dnl); if (jlen != (dnlen+bnlen+1)) continue; if (!rstreqn(dnl, rpmfilesDN(fi, dil), dnlen)) continue; if (!rstreqn(dnl+dnlen, rpmfilesBN(fi, i), bnlen)) continue; if (dnl[dnlen+bnlen] != '/' || dnl[dnlen+bnlen+1] != '\0') continue; /* This directory is included in the package. */ dnli->active[j] = 0; break; } } /* Print only once per package. */ if (!reverse) { j = 0; for (i = 0; i < dc; i++) { if (!dnli->active[i]) continue; if (j == 0) { j = 1; rpmlog(RPMLOG_DEBUG, "========== Directories not explicitly included in package:\n"); } rpmlog(RPMLOG_DEBUG, "%10d %s\n", i, rpmfilesDN(fi, i)); } if (j) rpmlog(RPMLOG_DEBUG, "==========\n"); } } return dnli; }