
This commit adds an iterator interface for reading files from the syncdbs. Instead of using alpm_pkg_get_files(), you now get the files from the database using alpm_db_files_open(), you then use alpm_db_files_next() to iterate through the files for each package. If you want to actually load the files from that package you then use alpm_db_files_load(). This means alpm_pkg_get_files() will always return empty for syncdbs, even on .files databases, however these functions still work on the localdb and loaded packages. This aproach is faster when dumping the entire file list but slower when searching for a specific package. The memory usage of pacman is drastically less. See below. build/pacman -Fl 0.55s user 0.01s system 99% cpu 0.556 total build/pacman -Fl pacman 0.46s user 0.01s system 99% cpu 0.472 total build/pacman -Fx pacman 2.88s user 0.09s system 99% cpu 2.965 total pacman -Fl 1.60s user 0.13s system 99% cpu 1.731 total pacman -Fl pacman 0.24s user 0.04s system 99% cpu 0.283 total pacman -Fx pacman 2.45s user 0.14s system 99% cpu 2.593 total Peak Memory build/pacman -Fl 43.52MB build/pacman -Fl pacmam 11.292MB pacman -Fl 677.048MB pacman -Fl pacman 163.288MB
161 lines
3.8 KiB
C
161 lines
3.8 KiB
C
/*
|
|
* filelist.c
|
|
*
|
|
* Copyright (c) 2012-2021 Pacman Development Team <pacman-dev@archlinux.org>
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation; either version 2 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
#include <limits.h>
|
|
#include <string.h>
|
|
#include <sys/stat.h>
|
|
|
|
/* libalpm */
|
|
#include "filelist.h"
|
|
#include "util.h"
|
|
|
|
/* Returns the difference of the provided two lists of files.
|
|
* Pre-condition: both lists are sorted!
|
|
* When done, free the list but NOT the contained data.
|
|
*/
|
|
alpm_list_t *_alpm_filelist_difference(alpm_filelist_t *filesA,
|
|
alpm_filelist_t *filesB)
|
|
{
|
|
alpm_list_t *ret = NULL;
|
|
size_t ctrA = 0, ctrB = 0;
|
|
|
|
while(ctrA < filesA->count && ctrB < filesB->count) {
|
|
char *strA = filesA->files[ctrA].name;
|
|
char *strB = filesB->files[ctrB].name;
|
|
|
|
int cmp = strcmp(strA, strB);
|
|
if(cmp < 0) {
|
|
/* item only in filesA, qualifies as a difference */
|
|
ret = alpm_list_add(ret, strA);
|
|
ctrA++;
|
|
} else if(cmp > 0) {
|
|
ctrB++;
|
|
} else {
|
|
ctrA++;
|
|
ctrB++;
|
|
}
|
|
}
|
|
|
|
/* ensure we have completely emptied pA */
|
|
while(ctrA < filesA->count) {
|
|
ret = alpm_list_add(ret, filesA->files[ctrA].name);
|
|
ctrA++;
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
static int _alpm_filelist_pathcmp(const char *p1, const char *p2)
|
|
{
|
|
while(*p1 && *p1 == *p2) {
|
|
p1++;
|
|
p2++;
|
|
}
|
|
|
|
/* skip trailing '/' */
|
|
if(*p1 == '\0' && *p2 == '/') {
|
|
p2++;
|
|
} else if(*p2 == '\0' && *p1 == '/') {
|
|
p1++;
|
|
}
|
|
|
|
return *p1 - *p2;
|
|
}
|
|
|
|
/* Returns the intersection of the provided two lists of files.
|
|
* Pre-condition: both lists are sorted!
|
|
* When done, free the list but NOT the contained data.
|
|
*/
|
|
alpm_list_t *_alpm_filelist_intersection(alpm_filelist_t *filesA,
|
|
alpm_filelist_t *filesB)
|
|
{
|
|
alpm_list_t *ret = NULL;
|
|
size_t ctrA = 0, ctrB = 0;
|
|
alpm_file_t *arrA = filesA->files, *arrB = filesB->files;
|
|
|
|
while(ctrA < filesA->count && ctrB < filesB->count) {
|
|
const char *strA = arrA[ctrA].name, *strB = arrB[ctrB].name;
|
|
int cmp = _alpm_filelist_pathcmp(strA, strB);
|
|
if(cmp < 0) {
|
|
ctrA++;
|
|
} else if(cmp > 0) {
|
|
ctrB++;
|
|
} else {
|
|
/* when not directories, item in both qualifies as an intersect */
|
|
if(strA[strlen(strA) - 1] != '/' || strB[strlen(strB) - 1] != '/') {
|
|
ret = alpm_list_add(ret, arrA[ctrA].name);
|
|
}
|
|
ctrA++;
|
|
ctrB++;
|
|
}
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
/* Helper function for comparing files list entries
|
|
*/
|
|
static int _alpm_files_cmp(const void *f1, const void *f2)
|
|
{
|
|
const alpm_file_t *file1 = f1;
|
|
const alpm_file_t *file2 = f2;
|
|
return strcmp(file1->name, file2->name);
|
|
}
|
|
|
|
alpm_file_t SYMEXPORT *alpm_filelist_contains(alpm_filelist_t *filelist,
|
|
const char *path)
|
|
{
|
|
alpm_file_t key;
|
|
|
|
if(!filelist) {
|
|
return NULL;
|
|
}
|
|
|
|
key.name = (char *)path;
|
|
|
|
return bsearch(&key, filelist->files, filelist->count,
|
|
sizeof(alpm_file_t), _alpm_files_cmp);
|
|
}
|
|
|
|
void _alpm_filelist_sort(alpm_filelist_t *filelist)
|
|
{
|
|
size_t i;
|
|
for(i = 1; i < filelist->count; i++) {
|
|
if(strcmp(filelist->files[i - 1].name, filelist->files[i].name) > 0) {
|
|
/* filelist is not pre-sorted */
|
|
qsort(filelist->files, filelist->count,
|
|
sizeof(alpm_file_t), _alpm_files_cmp);
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
void _alpm_filelist_truncate(alpm_filelist_t *files)
|
|
{
|
|
for(size_t i = 0; i < files->count; i++) {
|
|
FREE(files->files[i].name);
|
|
}
|
|
files->count = 0;
|
|
}
|
|
|
|
void SYMEXPORT alpm_filelist_free(alpm_filelist_t *files)
|
|
{
|
|
_alpm_filelist_truncate(files);
|
|
free(files->files);
|
|
}
|