pacman-debian 7.3.10 → 7.3.13
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +52 -463
- package/README_zh-CN.md +50 -492
- package/dist/ar.d.ts +8 -0
- package/dist/cli/archlinux-java.d.ts +3 -0
- package/dist/cli/fix_default.d.ts +3 -0
- package/dist/cli/paclink.d.ts +3 -0
- package/dist/cli/pacman.d.ts +2 -0
- package/dist/cli/update-ca-trust.d.ts +3 -0
- package/dist/compress.d.ts +2 -0
- package/dist/config.d.ts +3 -0
- package/dist/control.d.ts +2 -0
- package/dist/core/ar.d.ts +7 -0
- package/dist/core/compress.d.ts +4 -0
- package/dist/core/control.d.ts +2 -0
- package/dist/core/deb.d.ts +4 -0
- package/dist/core/deps.d.ts +28 -0
- package/dist/core/options.d.ts +19 -0
- package/dist/core/pkgfile.d.ts +35 -0
- package/dist/core/tar.d.ts +13 -0
- package/dist/core/types.d.ts +83 -0
- package/dist/database.d.ts +20 -0
- package/dist/db/database.d.ts +17 -0
- package/dist/db/dpkg-compat.d.ts +19 -0
- package/dist/db/dpkg-compat.d.ts.map +1 -1
- package/dist/db/dpkg-compat.js +16 -1
- package/dist/db/dpkg-compat.js.map +1 -1
- package/dist/db/localdb.d.ts +9 -0
- package/dist/db/sqlite.d.ts +20 -0
- package/dist/deb.d.ts +5 -0
- package/dist/dpkg-compat.d.ts +18 -0
- package/dist/i18n/index.d.ts +4 -0
- package/dist/i18n/paclink/en.d.ts +3 -0
- package/dist/i18n/paclink/zh-CN.d.ts +3 -0
- package/dist/i18n/setup/en.d.ts +3 -0
- package/dist/i18n/setup/zh-CN.d.ts +3 -0
- package/dist/index.d.ts +3 -0
- package/dist/install.d.ts +2 -0
- package/dist/makepkg/build.d.ts +19 -0
- package/dist/makepkg/index.d.ts +3 -0
- package/dist/makepkg/pkgbuild.d.ts +36 -0
- package/dist/ops/install.d.ts +5 -0
- package/dist/ops/query.d.ts +9 -0
- package/dist/ops/remove.d.ts +4 -0
- package/dist/ops/upgrade.d.ts +4 -0
- package/dist/pacman.d.ts +2 -0
- package/dist/query.d.ts +5 -0
- package/dist/remove.d.ts +2 -0
- package/dist/repo/config.d.ts +3 -0
- package/dist/repo/repository.d.ts +20 -0
- package/dist/repository.d.ts +10 -0
- package/dist/scripts/pacman-conf.d.ts +3 -0
- package/dist/scripts/setup.d.ts +3 -0
- package/dist/tar.d.ts +17 -0
- package/dist/types.d.ts +80 -0
- package/dist/ui/colors.d.ts +13 -0
- package/dist/ui/format.d.ts +3 -0
- package/dist/ui/progress.d.ts +8 -0
- package/dist/ui/prompt.d.ts +4 -0
- package/docs/en/architecture.md +188 -0
- package/docs/en/configuration.md +84 -0
- package/docs/en/installation.md +67 -0
- package/docs/en/makepkg.md +38 -0
- package/docs/en/paclink.md +73 -0
- package/docs/en/usage.md +91 -0
- package/docs/en/yay-aur.md +65 -0
- package/docs/zh-CN/architecture.md +171 -0
- package/docs/zh-CN/configuration.md +80 -0
- package/docs/zh-CN/installation.md +65 -0
- package/docs/zh-CN/makepkg.md +32 -0
- package/docs/zh-CN/paclink.md +70 -0
- package/docs/zh-CN/usage.md +90 -0
- package/docs/zh-CN/yay-aur.md +44 -0
- package/lib/pac4deb/Makefile +26 -0
- package/lib/pac4deb/README.md +47 -0
- package/lib/pac4deb/include/alpm.h +166 -0
- package/lib/pac4deb/include/alpm_list.h +43 -0
- package/lib/pac4deb/src/alpm_list.c +120 -0
- package/lib/pac4deb/src/genstubs.sh +51 -0
- package/lib/pac4deb/src/genstubs2.sh +72 -0
- package/lib/pac4deb/src/genstubs3.sh +43 -0
- package/lib/pac4deb/src/libalpm.c +964 -0
- package/lib/pac4deb/src/stubs_manual.c +452 -0
- package/package.json +19 -1
|
@@ -0,0 +1,964 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* libalpm replacement for pacman-debian
|
|
3
|
+
* Reads JSON databases from /var/lib/pacman-debian/
|
|
4
|
+
*/
|
|
5
|
+
#define _GNU_SOURCE
|
|
6
|
+
#include <stdio.h>
|
|
7
|
+
#include <stdlib.h>
|
|
8
|
+
#include <string.h>
|
|
9
|
+
#include <stdarg.h>
|
|
10
|
+
#include <sys/stat.h>
|
|
11
|
+
#include <unistd.h>
|
|
12
|
+
#include <fcntl.h>
|
|
13
|
+
#include <dirent.h>
|
|
14
|
+
#include <sys/mman.h>
|
|
15
|
+
#include <dirent.h>
|
|
16
|
+
#include <time.h>
|
|
17
|
+
#include "alpm.h"
|
|
18
|
+
#include "alpm_list.h"
|
|
19
|
+
|
|
20
|
+
#define DB_DIR "/var/lib/pacman-debian"
|
|
21
|
+
#define PKG_CACHE "/var/cache/pacman-debian/packages"
|
|
22
|
+
#define DPKG_STATUS "/var/lib/dpkg/status"
|
|
23
|
+
|
|
24
|
+
/* ---- Simple JSON scanner ---- */
|
|
25
|
+
typedef struct { char *buf; size_t len; size_t pos; } json_ctx;
|
|
26
|
+
|
|
27
|
+
static void json_init(json_ctx *j, char *buf) {
|
|
28
|
+
j->buf = buf; j->len = strlen(buf); j->pos = 0;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
static void json_skipws(json_ctx *j) {
|
|
32
|
+
while (j->pos < j->len) {
|
|
33
|
+
char c = j->buf[j->pos];
|
|
34
|
+
if (c == ' ' || c == '\t' || c == '\n' || c == '\r') j->pos++;
|
|
35
|
+
else break;
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
static int json_peek(json_ctx *j) { json_skipws(j); return j->pos < j->len ? j->buf[j->pos] : 0; }
|
|
40
|
+
|
|
41
|
+
static int json_next(json_ctx *j) {
|
|
42
|
+
json_skipws(j);
|
|
43
|
+
return j->pos < j->len ? j->buf[j->pos++] : 0;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
static char *json_string(json_ctx *j) {
|
|
47
|
+
if (json_next(j) != '"') return NULL;
|
|
48
|
+
size_t start = j->pos;
|
|
49
|
+
while (j->pos < j->len && j->buf[j->pos] != '"') {
|
|
50
|
+
if (j->buf[j->pos] == '\\') j->pos++;
|
|
51
|
+
j->pos++;
|
|
52
|
+
}
|
|
53
|
+
if (j->pos >= j->len) return NULL;
|
|
54
|
+
size_t len = j->pos - start;
|
|
55
|
+
char *s = malloc(len + 1);
|
|
56
|
+
memcpy(s, j->buf + start, len);
|
|
57
|
+
s[len] = 0;
|
|
58
|
+
j->pos++; // skip closing quote
|
|
59
|
+
return s;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
static char *json_value(json_ctx *j) {
|
|
63
|
+
json_skipws(j);
|
|
64
|
+
if (j->pos >= j->len) return NULL;
|
|
65
|
+
char c = j->buf[j->pos];
|
|
66
|
+
if (c == '"') return json_string(j);
|
|
67
|
+
// number/bool/null (read until , ] } or whitespace)
|
|
68
|
+
size_t start = j->pos;
|
|
69
|
+
while (j->pos < j->len) {
|
|
70
|
+
c = j->buf[j->pos];
|
|
71
|
+
if (c == ',' || c == ']' || c == '}' || c == ' ' || c == '\t' || c == '\n' || c == '\r') break;
|
|
72
|
+
j->pos++;
|
|
73
|
+
}
|
|
74
|
+
size_t len = j->pos - start;
|
|
75
|
+
char *s = malloc(len + 1);
|
|
76
|
+
memcpy(s, j->buf + start, len);
|
|
77
|
+
s[len] = 0;
|
|
78
|
+
return s;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
/* ---- Internal package struct ---- */
|
|
82
|
+
typedef struct __alpm_pkg_internal {
|
|
83
|
+
char *name, *version, *desc, *url, *arch, *base64_sig, *depends, *conflicts, *provides;
|
|
84
|
+
alpm_pkgreason_t reason;
|
|
85
|
+
alpm_pkgfrom_t origin;
|
|
86
|
+
alpm_time_t builddate, installdate;
|
|
87
|
+
off_t size, isize;
|
|
88
|
+
alpm_pkgvalidation_t validation;
|
|
89
|
+
int has_scriptlet;
|
|
90
|
+
void *db; /* back-reference to owning database */
|
|
91
|
+
} pkg_internal;
|
|
92
|
+
|
|
93
|
+
static pkg_internal *pkg_new(const char *name) {
|
|
94
|
+
pkg_internal *p = calloc(1, sizeof(pkg_internal));
|
|
95
|
+
if (p) p->name = strdup(name);
|
|
96
|
+
return p;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
void pkg_free(pkg_internal *p) {
|
|
100
|
+
if (!p) return;
|
|
101
|
+
free(p->name); free(p->version); free(p->desc); free(p->url);
|
|
102
|
+
free(p->arch); free(p->base64_sig); free(p->depends);
|
|
103
|
+
free(p->conflicts); free(p->provides);
|
|
104
|
+
free(p);
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
/* ---- Handle ---- */
|
|
108
|
+
static alpm_db_t *db_new(const char *name, int is_local);
|
|
109
|
+
static alpm_list_t *load_dpkg_status(const char *path);
|
|
110
|
+
static alpm_list_t *load_localdb_dir(const char *dirpath);
|
|
111
|
+
static int load_local_db(alpm_db_t *db);
|
|
112
|
+
static int load_sync_db(alpm_db_t *db);
|
|
113
|
+
|
|
114
|
+
struct __alpm_handle_t {
|
|
115
|
+
char *dbpath;
|
|
116
|
+
char *logfile;
|
|
117
|
+
alpm_db_t *localdb;
|
|
118
|
+
alpm_list_t *syncdbs;
|
|
119
|
+
alpm_errno_t err;
|
|
120
|
+
};
|
|
121
|
+
|
|
122
|
+
alpm_handle_t *alpm_initialize(const char *root, const char *dbpath, alpm_errno_t *err) {
|
|
123
|
+
(void)root;
|
|
124
|
+
alpm_handle_t *h = calloc(1, sizeof(alpm_handle_t));
|
|
125
|
+
if (!h) { if (err) *err = ALPM_ERR_MEMORY; return NULL; }
|
|
126
|
+
h->dbpath = strdup(dbpath && *dbpath ? dbpath : DB_DIR);
|
|
127
|
+
h->localdb = db_new("local", 1);
|
|
128
|
+
load_local_db(h->localdb);
|
|
129
|
+
h->syncdbs = NULL;
|
|
130
|
+
h->err = ALPM_ERR_OK;
|
|
131
|
+
if (err) *err = ALPM_ERR_OK;
|
|
132
|
+
return h;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
int alpm_release(alpm_handle_t *handle) {
|
|
136
|
+
if (!handle) return -1;
|
|
137
|
+
alpm_db_unregister_all(handle);
|
|
138
|
+
free(handle->dbpath);
|
|
139
|
+
free(handle->logfile);
|
|
140
|
+
free(handle);
|
|
141
|
+
return 0;
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
/* ---- Errors ---- */
|
|
145
|
+
alpm_errno_t alpm_errno(alpm_handle_t *handle) { return handle ? handle->err : ALPM_ERR_HANDLE_NULL; }
|
|
146
|
+
const char *alpm_strerror(alpm_errno_t err) {
|
|
147
|
+
switch (err) {
|
|
148
|
+
case ALPM_ERR_OK: return "no error";
|
|
149
|
+
case ALPM_ERR_MEMORY: return "out of memory";
|
|
150
|
+
case ALPM_ERR_PKG_NOT_FOUND: return "package not found";
|
|
151
|
+
case ALPM_ERR_DB_NOT_FOUND: return "database not found";
|
|
152
|
+
default: return "unknown error";
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
/* ---- Database ---- */
|
|
157
|
+
struct __alpm_db_t {
|
|
158
|
+
char *treename;
|
|
159
|
+
alpm_list_t *pkgs;
|
|
160
|
+
int is_local;
|
|
161
|
+
};
|
|
162
|
+
|
|
163
|
+
static alpm_db_t *db_new(const char *name, int is_local) {
|
|
164
|
+
alpm_db_t *db = calloc(1, sizeof(alpm_db_t));
|
|
165
|
+
if (db) { db->treename = strdup(name ? name : "local"); db->is_local = is_local; }
|
|
166
|
+
return db;
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
/* Parse a single flat JSON package object and return a pkg_internal */
|
|
170
|
+
static pkg_internal *json_to_pkg(json_ctx *j) {
|
|
171
|
+
pkg_internal *p = pkg_new("");
|
|
172
|
+
while (json_peek(j) == '"') {
|
|
173
|
+
char *k = json_string(j);
|
|
174
|
+
if (!k) break;
|
|
175
|
+
json_next(j);
|
|
176
|
+
char *v = json_value(j);
|
|
177
|
+
if (strcmp(k, "name") == 0 || strcmp(k, "package") == 0) { free(p->name); p->name = v; v = NULL; }
|
|
178
|
+
else if (strcmp(k, "version") == 0) { free(p->version); p->version = v; v = NULL; }
|
|
179
|
+
else if (strcmp(k, "description") == 0) { free(p->desc); p->desc = v; v = NULL; }
|
|
180
|
+
else if (strcmp(k, "url") == 0 || strcmp(k, "homepage") == 0) { free(p->url); p->url = v; v = NULL; }
|
|
181
|
+
else if (strcmp(k, "architecture") == 0 || strcmp(k, "arch") == 0) { free(p->arch); p->arch = v; v = NULL; }
|
|
182
|
+
else if (strcmp(k, "installTime") == 0) p->installdate = atol(v ? v : "0");
|
|
183
|
+
else if (strcmp(k, "reason") == 0) p->reason = (v && strcmp(v, "explicit") == 0) ? ALPM_PKG_REASON_EXPLICIT : ALPM_PKG_REASON_DEPEND;
|
|
184
|
+
else if (strcmp(k, "installedSize") == 0) p->isize = atol(v ? v : "0");
|
|
185
|
+
else if (strcmp(k, "size") == 0) p->size = atol(v ? v : "0");
|
|
186
|
+
else if (strcmp(k, "depends") == 0) { free(p->depends); p->depends = v; v = NULL; }
|
|
187
|
+
else if (strcmp(k, "conflicts") == 0) { free(p->conflicts); p->conflicts = v; v = NULL; }
|
|
188
|
+
else if (strcmp(k, "provides") == 0) { free(p->provides); p->provides = v; v = NULL; }
|
|
189
|
+
free(k); free(v);
|
|
190
|
+
if (json_peek(j) == ',') json_next(j);
|
|
191
|
+
}
|
|
192
|
+
if (json_peek(j) == '}') json_next(j);
|
|
193
|
+
return p;
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
/* Load JSONL file (one flat JSON object per line) */
|
|
197
|
+
alpm_list_t *load_jsonl_file(const char *filepath) {
|
|
198
|
+
alpm_list_t *pkgs = NULL;
|
|
199
|
+
int fd = open(filepath, O_RDONLY);
|
|
200
|
+
if (fd < 0) return NULL;
|
|
201
|
+
struct stat st;
|
|
202
|
+
if (fstat(fd, &st) < 0) { close(fd); return NULL; }
|
|
203
|
+
if (st.st_size == 0) { close(fd); return NULL; }
|
|
204
|
+
char *buf = mmap(NULL, st.st_size, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 0);
|
|
205
|
+
close(fd);
|
|
206
|
+
if (buf == MAP_FAILED) return NULL;
|
|
207
|
+
|
|
208
|
+
char *line = buf;
|
|
209
|
+
char *end = buf + st.st_size;
|
|
210
|
+
while (line < end) {
|
|
211
|
+
char *nl = memchr(line, '\n', end - line);
|
|
212
|
+
if (nl) *nl = 0;
|
|
213
|
+
if (*line == '{') {
|
|
214
|
+
json_ctx j;
|
|
215
|
+
json_init(&j, line);
|
|
216
|
+
if (json_next(&j) == '{') {
|
|
217
|
+
pkg_internal *p = json_to_pkg(&j);
|
|
218
|
+
if (p->name && *(p->name)) {
|
|
219
|
+
p->origin = ALPM_PKG_FROM_SYNCDB;
|
|
220
|
+
pkgs = alpm_list_add(pkgs, p);
|
|
221
|
+
} else {
|
|
222
|
+
pkg_free(p);
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
line = nl ? nl + 1 : end;
|
|
227
|
+
}
|
|
228
|
+
munmap(buf, st.st_size);
|
|
229
|
+
return pkgs;
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
/* Parse a single JSON line from memory buffer */
|
|
233
|
+
alpm_list_t *load_jsonl_mem(const char *json_str) {
|
|
234
|
+
alpm_list_t *pkgs = NULL;
|
|
235
|
+
if (!json_str || *json_str != '{') return NULL;
|
|
236
|
+
json_ctx j;
|
|
237
|
+
json_init(&j, (char *)json_str);
|
|
238
|
+
if (json_next(&j) == '{') {
|
|
239
|
+
pkg_internal *p = json_to_pkg(&j);
|
|
240
|
+
if (p->name && *(p->name)) {
|
|
241
|
+
p->origin = ALPM_PKG_FROM_SYNCDB;
|
|
242
|
+
pkgs = alpm_list_add(pkgs, p);
|
|
243
|
+
} else {
|
|
244
|
+
pkg_free(p);
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
return pkgs;
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
static alpm_list_t *load_json_file(const char *filepath) {
|
|
251
|
+
return load_jsonl_file(filepath);
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
/* Load packages from dpkg status file */
|
|
255
|
+
static alpm_list_t *load_dpkg_status(const char *path) {
|
|
256
|
+
alpm_list_t *pkgs = NULL;
|
|
257
|
+
FILE *f = fopen(path, "r");
|
|
258
|
+
if (!f) return NULL;
|
|
259
|
+
fseek(f, 0, SEEK_END);
|
|
260
|
+
long len = ftell(f);
|
|
261
|
+
rewind(f);
|
|
262
|
+
char *buf = malloc(len + 1);
|
|
263
|
+
if (!buf) { fclose(f); return NULL; }
|
|
264
|
+
int n = fread(buf, 1, len, f);
|
|
265
|
+
buf[n] = 0;
|
|
266
|
+
fclose(f);
|
|
267
|
+
|
|
268
|
+
char *p = buf;
|
|
269
|
+
while (p && *p) {
|
|
270
|
+
while (*p == '\n') p++;
|
|
271
|
+
if (!*p) break;
|
|
272
|
+
char *end = strstr(p, "\n\n");
|
|
273
|
+
if (end) *end = 0;
|
|
274
|
+
|
|
275
|
+
char name[256] = {0}, version[256] = {0}, arch[64] = {0}, desc[1024] = {0};
|
|
276
|
+
char depends[4096] = {0}, provides[4096] = {0};
|
|
277
|
+
int is_installed = 0;
|
|
278
|
+
|
|
279
|
+
char *line = p;
|
|
280
|
+
while (line && *line) {
|
|
281
|
+
char *nl = strchr(line, '\n');
|
|
282
|
+
if (nl) *nl = 0;
|
|
283
|
+
if (strncmp(line, "Package: ", 9) == 0) strncpy(name, line + 9, sizeof(name) - 1);
|
|
284
|
+
else if (strncmp(line, "Version: ", 9) == 0) strncpy(version, line + 9, sizeof(version) - 1);
|
|
285
|
+
else if (strncmp(line, "Architecture: ", 14) == 0) strncpy(arch, line + 14, sizeof(arch) - 1);
|
|
286
|
+
else if (strncmp(line, "Status: ", 8) == 0 && strstr(line, "install ok installed")) is_installed = 1;
|
|
287
|
+
else if (strncmp(line, "Depends: ", 9) == 0) strncpy(depends, line + 9, sizeof(depends) - 1);
|
|
288
|
+
else if (strncmp(line, "Provides: ", 10) == 0) strncpy(provides, line + 10, sizeof(provides) - 1);
|
|
289
|
+
else if (strncmp(line, "Description: ", 13) == 0) {
|
|
290
|
+
strncpy(desc, line + 13, sizeof(desc) - 1);
|
|
291
|
+
if (nl) {
|
|
292
|
+
char *n = nl + 1;
|
|
293
|
+
while (n && (*n == ' ' || *n == '\t')) {
|
|
294
|
+
char *nnl = strchr(n, '\n');
|
|
295
|
+
if (nnl) *nnl = 0;
|
|
296
|
+
strncat(desc, " ", sizeof(desc) - strlen(desc) - 1);
|
|
297
|
+
strncat(desc, n, sizeof(desc) - strlen(desc) - 1);
|
|
298
|
+
n = nnl ? nnl + 1 : NULL;
|
|
299
|
+
}
|
|
300
|
+
}
|
|
301
|
+
}
|
|
302
|
+
line = nl ? nl + 1 : NULL;
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
if (is_installed && name[0]) {
|
|
306
|
+
pkg_internal *pkg = pkg_new(name);
|
|
307
|
+
pkg->version = strdup(version);
|
|
308
|
+
pkg->arch = strdup(arch[0] ? arch : "arm64");
|
|
309
|
+
pkg->desc = strdup(desc[0] ? desc : "");
|
|
310
|
+
pkg->depends = strdup(depends);
|
|
311
|
+
pkg->provides = strdup(provides[0] ? provides : "");
|
|
312
|
+
pkg->reason = ALPM_PKG_REASON_EXPLICIT;
|
|
313
|
+
pkgs = alpm_list_add(pkgs, pkg);
|
|
314
|
+
}
|
|
315
|
+
p = end ? end + 2 : NULL;
|
|
316
|
+
}
|
|
317
|
+
free(buf);
|
|
318
|
+
return pkgs;
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
/* Load all packages from local DB directory (each subdir has a desc file) */
|
|
322
|
+
static alpm_list_t *load_localdb_dir(const char *dirpath) {
|
|
323
|
+
alpm_list_t *pkgs = NULL;
|
|
324
|
+
DIR *d = opendir(dirpath);
|
|
325
|
+
if (!d) return NULL;
|
|
326
|
+
struct dirent *entry;
|
|
327
|
+
while ((entry = readdir(d)) != NULL) {
|
|
328
|
+
if (entry->d_name[0] == '.') continue;
|
|
329
|
+
if (strcmp(entry->d_name, "by-name") == 0) continue;
|
|
330
|
+
char path[4096];
|
|
331
|
+
snprintf(path, sizeof(path), "%s/%s/desc", dirpath, entry->d_name);
|
|
332
|
+
int fd = open(path, O_RDONLY);
|
|
333
|
+
if (fd < 0) continue;
|
|
334
|
+
struct stat st;
|
|
335
|
+
if (fstat(fd, &st) < 0 || st.st_size == 0) { close(fd); continue; }
|
|
336
|
+
char *buf = mmap(NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
|
|
337
|
+
close(fd);
|
|
338
|
+
if (buf == MAP_FAILED) continue;
|
|
339
|
+
json_ctx j;
|
|
340
|
+
json_init(&j, buf);
|
|
341
|
+
if (json_next(&j) != '{') { munmap(buf, st.st_size); continue; }
|
|
342
|
+
pkg_internal *p = json_to_pkg(&j);
|
|
343
|
+
if (p->name && *(p->name)) {
|
|
344
|
+
p->origin = ALPM_PKG_FROM_LOCALDB;
|
|
345
|
+
pkgs = alpm_list_add(pkgs, p);
|
|
346
|
+
} else {
|
|
347
|
+
pkg_free(p);
|
|
348
|
+
}
|
|
349
|
+
munmap(buf, st.st_size);
|
|
350
|
+
}
|
|
351
|
+
closedir(d);
|
|
352
|
+
return pkgs;
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
/* Resolve Debian alternatives: readlink /bin/<cmd> to find real binary,
|
|
356
|
+
then map its package name back to the virtual provide name.
|
|
357
|
+
e.g. /bin/sh -> dash -> add provides "sh" on the dash pkg_internal */
|
|
358
|
+
static void add_alternative_provides(alpm_list_t *pkgs) {
|
|
359
|
+
static const char *cmds[] = {"sh", "awk", "editor", "pager", "vi", "which", "sed", NULL};
|
|
360
|
+
for (int c = 0; cmds[c]; c++) {
|
|
361
|
+
char lnk[256], real[256];
|
|
362
|
+
snprintf(lnk, sizeof(lnk), "/bin/%s", cmds[c]);
|
|
363
|
+
ssize_t len = readlink(lnk, real, sizeof(real) - 1);
|
|
364
|
+
if (len <= 0) {
|
|
365
|
+
snprintf(lnk, sizeof(lnk), "/usr/bin/%s", cmds[c]);
|
|
366
|
+
len = readlink(lnk, real, sizeof(real) - 1);
|
|
367
|
+
}
|
|
368
|
+
if (len <= 0) continue;
|
|
369
|
+
real[len] = 0;
|
|
370
|
+
char *base = strrchr(real, '/');
|
|
371
|
+
base = base ? base + 1 : real;
|
|
372
|
+
for (alpm_list_t *it = pkgs; it; it = it->next) {
|
|
373
|
+
pkg_internal *p = it->data;
|
|
374
|
+
if (strcmp(p->name, base) != 0) continue;
|
|
375
|
+
if (p->provides && *p->provides) {
|
|
376
|
+
char tmp[512]; snprintf(tmp, sizeof(tmp), ",%s,", p->provides);
|
|
377
|
+
char needle[64]; snprintf(needle, sizeof(needle), ",%s,", cmds[c]);
|
|
378
|
+
if (strstr(tmp, needle)) break;
|
|
379
|
+
}
|
|
380
|
+
size_t old = p->provides ? strlen(p->provides) : 0;
|
|
381
|
+
size_t add = strlen(cmds[c]);
|
|
382
|
+
char *nv = malloc(old + add + 3);
|
|
383
|
+
if (!nv) break;
|
|
384
|
+
if (p->provides) {
|
|
385
|
+
memcpy(nv, p->provides, old);
|
|
386
|
+
nv[old] = ',';
|
|
387
|
+
memcpy(nv + old + 1, cmds[c], add + 1);
|
|
388
|
+
free(p->provides);
|
|
389
|
+
} else {
|
|
390
|
+
memcpy(nv, cmds[c], add + 1);
|
|
391
|
+
}
|
|
392
|
+
p->provides = nv;
|
|
393
|
+
break;
|
|
394
|
+
}
|
|
395
|
+
}
|
|
396
|
+
|
|
397
|
+
/* Map common Arch library SONAMEs to Debian packages.
|
|
398
|
+
For each lib<name>.so, check if a corresponding lib<name>* deb is installed. */
|
|
399
|
+
static const char *lib_map[][2] = {
|
|
400
|
+
{"zlib1g", "libz.so"},
|
|
401
|
+
{"libssl3t64", "libcrypto.so"}, {"libssl-dev", "libcrypto.so"},
|
|
402
|
+
{"libssl3t64", "libssl.so"}, {"libssl-dev", "libssl.so"},
|
|
403
|
+
{"libcurl4", "libcurl.so"}, {"libcurl4t64", "libcurl.so"},
|
|
404
|
+
{"libpcre3", "libpcre.so"},
|
|
405
|
+
{"liblzma5", "liblzma.so"},
|
|
406
|
+
{"libbz2-1.0", "libbz2.so"},
|
|
407
|
+
{"libzstd1", "libzstd.so"}, {"libzstd-dev", "libzstd.so"},
|
|
408
|
+
{"libgnutls30", "libgnutls.so"}, {"libgnutls30t64", "libgnutls.so"},
|
|
409
|
+
{"libgnutls30", "gnutls"}, {"libgnutls30t64", "gnutls"},
|
|
410
|
+
{"libfreetype6", "libfreetype.so"}, {"libfreetype-dev", "libfreetype.so"},
|
|
411
|
+
{"libpng16-16t64", "libpng16.so"}, {"libpng-dev", "libpng16.so"},
|
|
412
|
+
{"libjpeg62-turbo", "libjpeg.so"}, {"libjpeg62-turbo-dev", "libjpeg.so"},
|
|
413
|
+
{"libxml2", "libxml2.so"},
|
|
414
|
+
{"libexpat1", "libexpat.so"},
|
|
415
|
+
{"libsqlite3-0", "libsqlite3.so"},
|
|
416
|
+
{"libncursesw6", "libncursesw.so"},
|
|
417
|
+
{"libreadline8t64", "libreadline.so"},
|
|
418
|
+
{"libc6", "libc.so"}, {"libc6", "libm.so"}, {"libc6", "libpthread.so"}, {"libc6", "libdl.so"}, {"libc6", "librt.so"},
|
|
419
|
+
{"libsystemd0", "libsystemd.so"},
|
|
420
|
+
{NULL, NULL}
|
|
421
|
+
};
|
|
422
|
+
for (int i = 0; lib_map[i][0]; i++) {
|
|
423
|
+
for (alpm_list_t *it = pkgs; it; it = it->next) {
|
|
424
|
+
pkg_internal *p = it->data;
|
|
425
|
+
if (strcmp(p->name, lib_map[i][0]) != 0) continue;
|
|
426
|
+
const char *soname = lib_map[i][1];
|
|
427
|
+
if (p->provides && *p->provides) {
|
|
428
|
+
char tmp[512]; snprintf(tmp, sizeof(tmp), ",%s,", p->provides);
|
|
429
|
+
char needle[64]; snprintf(needle, sizeof(needle), ",%s,", soname);
|
|
430
|
+
if (strstr(tmp, needle)) break;
|
|
431
|
+
}
|
|
432
|
+
size_t old = p->provides ? strlen(p->provides) : 0;
|
|
433
|
+
size_t add = strlen(soname);
|
|
434
|
+
char *nv = malloc(old + add + 3);
|
|
435
|
+
if (!nv) break;
|
|
436
|
+
if (p->provides) {
|
|
437
|
+
memcpy(nv, p->provides, old);
|
|
438
|
+
nv[old] = ',';
|
|
439
|
+
memcpy(nv + old + 1, soname, add + 1);
|
|
440
|
+
free(p->provides);
|
|
441
|
+
} else {
|
|
442
|
+
memcpy(nv, soname, add + 1);
|
|
443
|
+
}
|
|
444
|
+
p->provides = nv;
|
|
445
|
+
break;
|
|
446
|
+
}
|
|
447
|
+
}
|
|
448
|
+
|
|
449
|
+
/* Map common Arch package names to Debian equivalents.
|
|
450
|
+
These are packages that don't map 1:1 by name but provide equivalent functionality. */
|
|
451
|
+
static const char *pkg_map[][2] = {
|
|
452
|
+
{"ca-certificates", "ca-certificates-utils"},
|
|
453
|
+
{"python3", "python"},
|
|
454
|
+
{NULL, NULL}
|
|
455
|
+
};
|
|
456
|
+
for (int i = 0; pkg_map[i][0]; i++) {
|
|
457
|
+
for (alpm_list_t *it = pkgs; it; it = it->next) {
|
|
458
|
+
pkg_internal *p = it->data;
|
|
459
|
+
if (strcmp(p->name, pkg_map[i][0]) != 0) continue;
|
|
460
|
+
const char *virt = pkg_map[i][1];
|
|
461
|
+
if (p->provides && *p->provides) {
|
|
462
|
+
char tmp[512]; snprintf(tmp, sizeof(tmp), ",%s,", p->provides);
|
|
463
|
+
char needle[64]; snprintf(needle, sizeof(needle), ",%s,", virt);
|
|
464
|
+
if (strstr(tmp, needle)) break;
|
|
465
|
+
}
|
|
466
|
+
size_t old = p->provides ? strlen(p->provides) : 0;
|
|
467
|
+
size_t add = strlen(virt);
|
|
468
|
+
char *nv = malloc(old + add + 3);
|
|
469
|
+
if (!nv) break;
|
|
470
|
+
if (p->provides) {
|
|
471
|
+
memcpy(nv, p->provides, old);
|
|
472
|
+
nv[old] = ',';
|
|
473
|
+
memcpy(nv + old + 1, virt, add + 1);
|
|
474
|
+
free(p->provides);
|
|
475
|
+
} else {
|
|
476
|
+
memcpy(nv, virt, add + 1);
|
|
477
|
+
}
|
|
478
|
+
p->provides = nv;
|
|
479
|
+
break;
|
|
480
|
+
}
|
|
481
|
+
}
|
|
482
|
+
}
|
|
483
|
+
|
|
484
|
+
/* Load local database: our packages + dpkg status */
|
|
485
|
+
static int load_local_db(alpm_db_t *db) {
|
|
486
|
+
if (db->pkgs) return 0;
|
|
487
|
+
char path[4096];
|
|
488
|
+
snprintf(path, sizeof(path), "%s/local", DB_DIR);
|
|
489
|
+
db->pkgs = load_localdb_dir(path);
|
|
490
|
+
|
|
491
|
+
// Also load dpkg status for system packages
|
|
492
|
+
char dpkg_path[4096];
|
|
493
|
+
snprintf(dpkg_path, sizeof(dpkg_path), "%s", DPKG_STATUS);
|
|
494
|
+
alpm_list_t *dpkg_pkgs = load_dpkg_status(dpkg_path);
|
|
495
|
+
if (dpkg_pkgs) {
|
|
496
|
+
add_alternative_provides(dpkg_pkgs);
|
|
497
|
+
if (db->pkgs) {
|
|
498
|
+
alpm_list_t *last = alpm_list_last(db->pkgs);
|
|
499
|
+
last->next = dpkg_pkgs;
|
|
500
|
+
dpkg_pkgs->prev = last;
|
|
501
|
+
} else {
|
|
502
|
+
db->pkgs = dpkg_pkgs;
|
|
503
|
+
}
|
|
504
|
+
}
|
|
505
|
+
return 0;
|
|
506
|
+
}
|
|
507
|
+
|
|
508
|
+
/* Load sync database from JSONL chunks */
|
|
509
|
+
static alpm_list_t *load_jsonl_dir(const char *dirpath) {
|
|
510
|
+
alpm_list_t *pkgs = NULL;
|
|
511
|
+
DIR *dir = opendir(dirpath);
|
|
512
|
+
if (!dir) return NULL;
|
|
513
|
+
struct dirent *entry;
|
|
514
|
+
while ((entry = readdir(dir)) != NULL) {
|
|
515
|
+
if (!strstr(entry->d_name, ".jsonl")) continue;
|
|
516
|
+
char path[4096];
|
|
517
|
+
snprintf(path, sizeof(path), "%s/%s", dirpath, entry->d_name);
|
|
518
|
+
alpm_list_t *chunk = load_json_file(path);
|
|
519
|
+
// Append chunk to pkgs
|
|
520
|
+
if (chunk) {
|
|
521
|
+
if (pkgs) {
|
|
522
|
+
alpm_list_t *last = alpm_list_last(pkgs);
|
|
523
|
+
last->next = chunk;
|
|
524
|
+
chunk->prev = last;
|
|
525
|
+
} else {
|
|
526
|
+
pkgs = chunk;
|
|
527
|
+
}
|
|
528
|
+
}
|
|
529
|
+
}
|
|
530
|
+
closedir(dir);
|
|
531
|
+
return pkgs;
|
|
532
|
+
}
|
|
533
|
+
|
|
534
|
+
static int load_sync_db(alpm_db_t *db) {
|
|
535
|
+
if (db->pkgs) return 0;
|
|
536
|
+
char path[4096];
|
|
537
|
+
snprintf(path, sizeof(path), "%s/%s", PKG_CACHE, db->treename);
|
|
538
|
+
db->pkgs = load_jsonl_dir(path);
|
|
539
|
+
/* Set back-reference to owning database on each package */
|
|
540
|
+
alpm_list_t *it;
|
|
541
|
+
for (it = db->pkgs; it; it = it->next) {
|
|
542
|
+
pkg_internal *p = it->data;
|
|
543
|
+
if (p) p->db = db;
|
|
544
|
+
}
|
|
545
|
+
return 0;
|
|
546
|
+
}
|
|
547
|
+
|
|
548
|
+
alpm_db_t *alpm_db_register_local(alpm_handle_t *handle) {
|
|
549
|
+
if (!handle) return NULL;
|
|
550
|
+
handle->localdb = db_new("local", 1);
|
|
551
|
+
load_local_db(handle->localdb);
|
|
552
|
+
return handle->localdb;
|
|
553
|
+
}
|
|
554
|
+
|
|
555
|
+
alpm_db_t *alpm_db_register_sync(alpm_handle_t *handle, const char *treename) {
|
|
556
|
+
if (!handle || !treename) return NULL;
|
|
557
|
+
/* check if already registered */
|
|
558
|
+
alpm_list_t *it;
|
|
559
|
+
for (it = handle->syncdbs; it; it = it->next) {
|
|
560
|
+
alpm_db_t *db = it->data;
|
|
561
|
+
if (db && strcmp(db->treename, treename) == 0) return db;
|
|
562
|
+
}
|
|
563
|
+
alpm_db_t *db = db_new(treename, 0);
|
|
564
|
+
if (!db) return NULL;
|
|
565
|
+
load_sync_db(db);
|
|
566
|
+
handle->syncdbs = alpm_list_add(handle->syncdbs, db);
|
|
567
|
+
return db;
|
|
568
|
+
}
|
|
569
|
+
|
|
570
|
+
int alpm_db_unregister_all(alpm_handle_t *handle) {
|
|
571
|
+
if (!handle) return -1;
|
|
572
|
+
if (handle->localdb) {
|
|
573
|
+
alpm_list_free_inner((alpm_list_t *)handle->localdb->pkgs, (void(*)(void*))pkg_free);
|
|
574
|
+
free(handle->localdb);
|
|
575
|
+
handle->localdb = NULL;
|
|
576
|
+
}
|
|
577
|
+
alpm_list_t *it;
|
|
578
|
+
for (it = handle->syncdbs; it; it = it->next) {
|
|
579
|
+
alpm_db_t *db = it->data;
|
|
580
|
+
if (db) {
|
|
581
|
+
alpm_list_free_inner((alpm_list_t *)db->pkgs, (void(*)(void*))pkg_free);
|
|
582
|
+
free(db);
|
|
583
|
+
}
|
|
584
|
+
}
|
|
585
|
+
alpm_list_free(handle->syncdbs);
|
|
586
|
+
handle->syncdbs = NULL;
|
|
587
|
+
return 0;
|
|
588
|
+
}
|
|
589
|
+
|
|
590
|
+
/* Read a single package from JSONL by offset (shared with stubs_manual.c) */
|
|
591
|
+
static alpm_pkg_t *pkg_from_idx_line(const char *pkgdir, const char *chunkfile, int offset) {
|
|
592
|
+
char path[4096];
|
|
593
|
+
snprintf(path, sizeof(path), "%s/%s", pkgdir, chunkfile);
|
|
594
|
+
int fd = open(path, O_RDONLY);
|
|
595
|
+
if (fd < 0) return NULL;
|
|
596
|
+
char buf[65536];
|
|
597
|
+
int n = pread(fd, buf, sizeof(buf) - 1, offset);
|
|
598
|
+
close(fd);
|
|
599
|
+
if (n <= 0) return NULL;
|
|
600
|
+
buf[n] = 0;
|
|
601
|
+
char *nl = strchr(buf, '\n');
|
|
602
|
+
if (nl) *nl = 0;
|
|
603
|
+
if (buf[0] != '{') return NULL;
|
|
604
|
+
alpm_list_t *pkgs = load_jsonl_mem(buf);
|
|
605
|
+
if (!pkgs) return NULL;
|
|
606
|
+
alpm_pkg_t *result = (alpm_pkg_t *)pkgs->data;
|
|
607
|
+
free(pkgs);
|
|
608
|
+
return result;
|
|
609
|
+
}
|
|
610
|
+
|
|
611
|
+
/* Look up package in packages.idx using binary search (fast, no full loading) */
|
|
612
|
+
static alpm_pkg_t *pkg_by_idx(alpm_db_t *db, const char *name) {
|
|
613
|
+
char idxpath[4096];
|
|
614
|
+
snprintf(idxpath, sizeof(idxpath), "%s/%s/packages.idx", PKG_CACHE, db->treename);
|
|
615
|
+
int fd = open(idxpath, O_RDONLY);
|
|
616
|
+
if (fd < 0) return NULL;
|
|
617
|
+
struct stat st;
|
|
618
|
+
if (fstat(fd, &st) < 0) { close(fd); return NULL; }
|
|
619
|
+
char *buf = malloc(st.st_size + 1);
|
|
620
|
+
if (!buf) { close(fd); return NULL; }
|
|
621
|
+
int n = read(fd, buf, st.st_size);
|
|
622
|
+
close(fd);
|
|
623
|
+
if (n <= 0) { free(buf); return NULL; }
|
|
624
|
+
buf[n] = 0;
|
|
625
|
+
|
|
626
|
+
/* Split into lines */
|
|
627
|
+
char **lines = NULL;
|
|
628
|
+
int nlines = 0;
|
|
629
|
+
char *line = buf;
|
|
630
|
+
while (line && *line) {
|
|
631
|
+
char *nl = strchr(line, '\n');
|
|
632
|
+
if (nl) *nl = 0;
|
|
633
|
+
if (*line) {
|
|
634
|
+
lines = realloc(lines, (nlines + 1) * sizeof(char*));
|
|
635
|
+
lines[nlines++] = line;
|
|
636
|
+
}
|
|
637
|
+
line = nl ? nl + 1 : NULL;
|
|
638
|
+
}
|
|
639
|
+
|
|
640
|
+
/* Binary search */
|
|
641
|
+
int lo = 0, hi = nlines - 1;
|
|
642
|
+
alpm_pkg_t *result = NULL;
|
|
643
|
+
while (lo <= hi) {
|
|
644
|
+
int mid = (lo + hi) / 2;
|
|
645
|
+
char *ln = lines[mid];
|
|
646
|
+
int name_len = 0;
|
|
647
|
+
while (ln[name_len] && ln[name_len] != ' ') name_len++;
|
|
648
|
+
int cmp = strncmp(name, ln, name_len);
|
|
649
|
+
if (cmp == 0 && name_len == (int)strlen(name)) {
|
|
650
|
+
char *last_tab = NULL, *second_last_tab = NULL;
|
|
651
|
+
int tab_count = 0;
|
|
652
|
+
for (char *q = ln; *q; q++) {
|
|
653
|
+
if (*q == '\t') { second_last_tab = last_tab; last_tab = q; tab_count++; }
|
|
654
|
+
}
|
|
655
|
+
if (tab_count >= 2 && last_tab && second_last_tab) {
|
|
656
|
+
int offset = atoi(last_tab + 1);
|
|
657
|
+
*last_tab = 0;
|
|
658
|
+
char *chunkfile = second_last_tab + 1;
|
|
659
|
+
char pkgdir[4096];
|
|
660
|
+
snprintf(pkgdir, sizeof(pkgdir), "%s/%s", PKG_CACHE, db->treename);
|
|
661
|
+
result = pkg_from_idx_line(pkgdir, chunkfile, offset);
|
|
662
|
+
if (result) ((pkg_internal *)result)->db = db;
|
|
663
|
+
}
|
|
664
|
+
break;
|
|
665
|
+
} else if (cmp < 0 || (cmp == 0 && name_len < (int)strlen(name))) {
|
|
666
|
+
hi = mid - 1;
|
|
667
|
+
} else {
|
|
668
|
+
lo = mid + 1;
|
|
669
|
+
}
|
|
670
|
+
}
|
|
671
|
+
|
|
672
|
+
free(lines);
|
|
673
|
+
free(buf);
|
|
674
|
+
return result;
|
|
675
|
+
}
|
|
676
|
+
|
|
677
|
+
alpm_pkg_t *alpm_db_get_pkg(alpm_db_t *db, const char *name) {
|
|
678
|
+
if (!db || !name) return NULL;
|
|
679
|
+
if (db->is_local) {
|
|
680
|
+
load_local_db(db);
|
|
681
|
+
alpm_list_t *it;
|
|
682
|
+
for (it = db->pkgs; it; it = it->next) {
|
|
683
|
+
pkg_internal *p = it->data;
|
|
684
|
+
if (p && p->name && strcmp(p->name, name) == 0)
|
|
685
|
+
return (alpm_pkg_t *)p;
|
|
686
|
+
}
|
|
687
|
+
return NULL;
|
|
688
|
+
}
|
|
689
|
+
/* For sync DBs, use fast idx binary search */
|
|
690
|
+
return pkg_by_idx(db, name);
|
|
691
|
+
}
|
|
692
|
+
|
|
693
|
+
/* Scan packages.idx for pattern matching (fast, no full JSONL load) */
|
|
694
|
+
static alpm_list_t *search_via_idx(alpm_db_t *db, const alpm_list_t *needles) {
|
|
695
|
+
char idxpath[4096];
|
|
696
|
+
snprintf(idxpath, sizeof(idxpath), "%s/%s/packages.idx", PKG_CACHE, db->treename);
|
|
697
|
+
int fd = open(idxpath, O_RDONLY);
|
|
698
|
+
if (fd < 0) return NULL;
|
|
699
|
+
struct stat st;
|
|
700
|
+
if (fstat(fd, &st) < 0) { close(fd); return NULL; }
|
|
701
|
+
char *buf = malloc(st.st_size + 1);
|
|
702
|
+
if (!buf) { close(fd); return NULL; }
|
|
703
|
+
int n = read(fd, buf, st.st_size);
|
|
704
|
+
close(fd);
|
|
705
|
+
if (n <= 0) { free(buf); return NULL; }
|
|
706
|
+
buf[n] = 0;
|
|
707
|
+
|
|
708
|
+
alpm_list_t *results = NULL;
|
|
709
|
+
const alpm_list_t *needle;
|
|
710
|
+
|
|
711
|
+
char *line = buf;
|
|
712
|
+
while (line && *line) {
|
|
713
|
+
char *nl = strchr(line, '\n');
|
|
714
|
+
if (nl) *nl = 0;
|
|
715
|
+
if (*line) {
|
|
716
|
+
/* line format: pkgName description\tprovides\tchunkFile\toffset */
|
|
717
|
+
const char *desc_start = line;
|
|
718
|
+
while (*desc_start && *desc_start != ' ') desc_start++;
|
|
719
|
+
if (*desc_start == ' ') desc_start++;
|
|
720
|
+
const char *desc_end = desc_start;
|
|
721
|
+
while (*desc_end && *desc_end != '\t') desc_end++;
|
|
722
|
+
|
|
723
|
+
/* Get pkgName (first token) */
|
|
724
|
+
int name_len = 0;
|
|
725
|
+
while (line[name_len] && line[name_len] != ' ') name_len++;
|
|
726
|
+
|
|
727
|
+
for (needle = needles; needle; needle = needle->next) {
|
|
728
|
+
const char *pattern = (const char *)needle->data;
|
|
729
|
+
if (!pattern || !*pattern) continue;
|
|
730
|
+
|
|
731
|
+
/* Check name match */
|
|
732
|
+
char name_buf[512];
|
|
733
|
+
if (name_len < 512) {
|
|
734
|
+
memcpy(name_buf, line, name_len);
|
|
735
|
+
name_buf[name_len] = 0;
|
|
736
|
+
}
|
|
737
|
+
|
|
738
|
+
int found = 0;
|
|
739
|
+
if (strcasestr(line, pattern)) found = 1; /* name or desc */
|
|
740
|
+
else if (desc_end > desc_start) {
|
|
741
|
+
/* Check description separately */
|
|
742
|
+
int dlen = desc_end - desc_start;
|
|
743
|
+
if (dlen < 4096) {
|
|
744
|
+
char desc_buf[4096];
|
|
745
|
+
memcpy(desc_buf, desc_start, dlen);
|
|
746
|
+
desc_buf[dlen] = 0;
|
|
747
|
+
if (strcasestr(desc_buf, pattern)) found = 1;
|
|
748
|
+
}
|
|
749
|
+
}
|
|
750
|
+
|
|
751
|
+
if (found) {
|
|
752
|
+
/* Parse idx line to get chunkfile and offset */
|
|
753
|
+
char *last_tab = NULL, *second_last_tab = NULL;
|
|
754
|
+
for (char *q = line; *q; q++) {
|
|
755
|
+
if (*q == '\t') { second_last_tab = last_tab; last_tab = q; }
|
|
756
|
+
}
|
|
757
|
+
if (last_tab && second_last_tab) {
|
|
758
|
+
int offset = atoi(last_tab + 1);
|
|
759
|
+
*last_tab = 0;
|
|
760
|
+
char *chunkfile = second_last_tab + 1;
|
|
761
|
+
char pkgdir[4096];
|
|
762
|
+
snprintf(pkgdir, sizeof(pkgdir), "%s/%s", PKG_CACHE, db->treename);
|
|
763
|
+
alpm_pkg_t *pkg = pkg_from_idx_line(pkgdir, chunkfile, offset);
|
|
764
|
+
if (pkg) {
|
|
765
|
+
((pkg_internal *)pkg)->db = db;
|
|
766
|
+
results = alpm_list_add(results, pkg);
|
|
767
|
+
}
|
|
768
|
+
}
|
|
769
|
+
break;
|
|
770
|
+
}
|
|
771
|
+
}
|
|
772
|
+
}
|
|
773
|
+
line = nl ? nl + 1 : NULL;
|
|
774
|
+
}
|
|
775
|
+
free(buf);
|
|
776
|
+
return results;
|
|
777
|
+
}
|
|
778
|
+
|
|
779
|
+
int alpm_db_search(alpm_db_t *db, const alpm_list_t *needles, alpm_list_t **ret) {
|
|
780
|
+
if (!db || !needles || !ret) return -1;
|
|
781
|
+
*ret = NULL;
|
|
782
|
+
if (db->is_local) {
|
|
783
|
+
load_local_db(db);
|
|
784
|
+
/* Local DB search: iterate packages */
|
|
785
|
+
alpm_list_t *results = NULL;
|
|
786
|
+
const alpm_list_t *p;
|
|
787
|
+
for (p = db->pkgs; p; p = p->next) {
|
|
788
|
+
pkg_internal *pkg = p->data;
|
|
789
|
+
if (!pkg || !pkg->name) continue;
|
|
790
|
+
const alpm_list_t *n;
|
|
791
|
+
for (n = needles; n; n = n->next) {
|
|
792
|
+
const char *pat = (const char *)n->data;
|
|
793
|
+
if (!pat || !*pat) continue;
|
|
794
|
+
if (strcasestr(pkg->name, pat) || (pkg->desc && strcasestr(pkg->desc, pat))) {
|
|
795
|
+
results = alpm_list_add(results, pkg);
|
|
796
|
+
break;
|
|
797
|
+
}
|
|
798
|
+
}
|
|
799
|
+
}
|
|
800
|
+
*ret = results;
|
|
801
|
+
} else {
|
|
802
|
+
/* Sync DB: use fast idx-based search */
|
|
803
|
+
*ret = search_via_idx(db, needles);
|
|
804
|
+
}
|
|
805
|
+
return 0;
|
|
806
|
+
}
|
|
807
|
+
|
|
808
|
+
alpm_list_t *alpm_db_get_pkgcache(alpm_db_t *db) {
|
|
809
|
+
if (!db) return NULL;
|
|
810
|
+
if (db->is_local) load_local_db(db);
|
|
811
|
+
else load_sync_db(db);
|
|
812
|
+
return db->pkgs;
|
|
813
|
+
}
|
|
814
|
+
|
|
815
|
+
int alpm_db_set_pkgreason(alpm_handle_t *handle, const char *name, alpm_pkgreason_t reason) {
|
|
816
|
+
(void)handle; (void)name; (void)reason;
|
|
817
|
+
return 0; // no-op for now
|
|
818
|
+
}
|
|
819
|
+
|
|
820
|
+
/* ---- Package property accessors ---- */
|
|
821
|
+
const char *alpm_pkg_get_name(alpm_pkg_t *pkg) { return pkg ? ((pkg_internal *)pkg)->name : NULL; }
|
|
822
|
+
const char *alpm_pkg_get_version(alpm_pkg_t *pkg) { return pkg ? ((pkg_internal *)pkg)->version : NULL; }
|
|
823
|
+
const char *alpm_pkg_get_desc(alpm_pkg_t *pkg) { return pkg ? ((pkg_internal *)pkg)->desc : NULL; }
|
|
824
|
+
|
|
825
|
+
int alpm_pkg_has_provide(alpm_pkg_t *pkg, const char *name) {
|
|
826
|
+
if (!pkg || !name) return 0;
|
|
827
|
+
pkg_internal *p = (pkg_internal *)pkg;
|
|
828
|
+
if (!p->provides || !*p->provides) return 0;
|
|
829
|
+
char *copy = strdup(p->provides);
|
|
830
|
+
char *token = strtok(copy, ",");
|
|
831
|
+
while (token) {
|
|
832
|
+
while (*token == ' ') token++;
|
|
833
|
+
char *end = token + strlen(token) - 1;
|
|
834
|
+
while (end > token && (*end == ' ')) end--;
|
|
835
|
+
end[1] = 0;
|
|
836
|
+
if (strcmp(token, name) == 0) { free(copy); return 1; }
|
|
837
|
+
token = strtok(NULL, ",");
|
|
838
|
+
}
|
|
839
|
+
free(copy);
|
|
840
|
+
return 0;
|
|
841
|
+
}
|
|
842
|
+
const char *alpm_pkg_get_url(alpm_pkg_t *pkg) { return pkg ? ((pkg_internal *)pkg)->url : NULL; }
|
|
843
|
+
const char *alpm_pkg_get_arch(alpm_pkg_t *pkg) { return pkg ? ((pkg_internal *)pkg)->arch : NULL; }
|
|
844
|
+
const char *alpm_pkg_get_base64_sig(alpm_pkg_t *pkg) { return pkg ? ((pkg_internal *)pkg)->base64_sig : NULL; }
|
|
845
|
+
void *alpm_pkg_get_provides(alpm_pkg_t *pkg) { (void)pkg; return NULL; }
|
|
846
|
+
alpm_pkgreason_t alpm_pkg_get_reason(alpm_pkg_t *pkg) { return pkg ? ((pkg_internal *)pkg)->reason : ALPM_PKG_REASON_DEPEND; }
|
|
847
|
+
alpm_pkgfrom_t alpm_pkg_get_origin(alpm_pkg_t *pkg) { return pkg ? ((pkg_internal *)pkg)->origin : ALPM_PKG_FROM_LOCALDB; }
|
|
848
|
+
alpm_time_t alpm_pkg_get_builddate(alpm_pkg_t *pkg) { (void)pkg; return 0; }
|
|
849
|
+
alpm_time_t alpm_pkg_get_installdate(alpm_pkg_t *pkg) { return pkg ? ((pkg_internal *)pkg)->installdate : 0; }
|
|
850
|
+
off_t alpm_pkg_get_size(alpm_pkg_t *pkg) { return pkg ? ((pkg_internal *)pkg)->size : 0; }
|
|
851
|
+
off_t alpm_pkg_get_isize(alpm_pkg_t *pkg) { return pkg ? ((pkg_internal *)pkg)->isize : 0; }
|
|
852
|
+
alpm_pkgvalidation_t alpm_pkg_get_validation(alpm_pkg_t *pkg) { (void)pkg; return ALPM_PKG_VALIDATION_NONE; }
|
|
853
|
+
int alpm_pkg_has_scriptlet(alpm_pkg_t *pkg) { return pkg ? ((pkg_internal *)pkg)->has_scriptlet : 0; }
|
|
854
|
+
void *alpm_pkg_get_db(alpm_pkg_t *pkg) { return pkg ? ((pkg_internal *)pkg)->db : NULL; }
|
|
855
|
+
void alpm_pkg_set_db(alpm_pkg_t *pkg, void *db) { if (pkg) ((pkg_internal *)pkg)->db = db; }
|
|
856
|
+
void alpm_pkg_free(alpm_pkg_t *pkg) { pkg_free((pkg_internal *)pkg); }
|
|
857
|
+
|
|
858
|
+
/* ---- Options ---- */
|
|
859
|
+
int alpm_option_add_cachedir(alpm_handle_t *handle, const char *cachedir) { (void)handle; (void)cachedir; return 0; }
|
|
860
|
+
int alpm_option_set_logfile(alpm_handle_t *handle, const char *logfile) {
|
|
861
|
+
if (handle) { free(handle->logfile); handle->logfile = strdup(logfile ? logfile : ""); }
|
|
862
|
+
return 0;
|
|
863
|
+
}
|
|
864
|
+
int alpm_option_set_cachedirs(alpm_handle_t *handle, alpm_list_t *cachedirs) { (void)handle; (void)cachedirs; return 0; }
|
|
865
|
+
int alpm_option_set_dbpath(alpm_handle_t *handle, const char *dbpath) {
|
|
866
|
+
if (handle) { free(handle->dbpath); handle->dbpath = strdup(dbpath ? dbpath : DB_DIR); }
|
|
867
|
+
return 0;
|
|
868
|
+
}
|
|
869
|
+
int alpm_option_set_gpgdir(alpm_handle_t *handle, const char *gpgdir) { (void)handle; (void)gpgdir; return 0; }
|
|
870
|
+
const char *alpm_option_get_dbpath(alpm_handle_t *handle) { return handle ? handle->dbpath : DB_DIR; }
|
|
871
|
+
alpm_db_t *alpm_option_get_localdb(alpm_handle_t *handle) { return handle ? handle->localdb : NULL; }
|
|
872
|
+
/* Check if a sync db's packages.idx exists */
|
|
873
|
+
static int sync_db_has_idx(alpm_db_t *db) {
|
|
874
|
+
char path[4096];
|
|
875
|
+
snprintf(path, sizeof(path), "%s/%s/packages.idx", PKG_CACHE, db->treename);
|
|
876
|
+
struct stat st;
|
|
877
|
+
return stat(path, &st) == 0 ? 1 : 0;
|
|
878
|
+
}
|
|
879
|
+
|
|
880
|
+
static void ensure_syncdbs(alpm_handle_t *handle) {
|
|
881
|
+
if (!handle || handle->syncdbs) return;
|
|
882
|
+
DIR *d = opendir(PKG_CACHE);
|
|
883
|
+
if (!d) return;
|
|
884
|
+
struct dirent *e;
|
|
885
|
+
while ((e = readdir(d)) != NULL) {
|
|
886
|
+
if (e->d_name[0] == '.') continue;
|
|
887
|
+
char p[4096];
|
|
888
|
+
snprintf(p, sizeof(p), "%s/%s", PKG_CACHE, e->d_name);
|
|
889
|
+
struct stat st;
|
|
890
|
+
if (stat(p, &st) == 0 && S_ISDIR(st.st_mode)) {
|
|
891
|
+
alpm_db_t *db = db_new(e->d_name, 0);
|
|
892
|
+
if (db) {
|
|
893
|
+
/* Don't load packages yet - lazy loading via idx */
|
|
894
|
+
handle->syncdbs = alpm_list_add(handle->syncdbs, db);
|
|
895
|
+
}
|
|
896
|
+
}
|
|
897
|
+
}
|
|
898
|
+
closedir(d);
|
|
899
|
+
}
|
|
900
|
+
|
|
901
|
+
alpm_list_t *alpm_option_get_syncdbs(alpm_handle_t *handle) {
|
|
902
|
+
if (handle) ensure_syncdbs(handle);
|
|
903
|
+
return handle ? handle->syncdbs : NULL;
|
|
904
|
+
}
|
|
905
|
+
|
|
906
|
+
/* ---- Logging ---- */
|
|
907
|
+
int alpm_logaction(alpm_handle_t *handle, const char *fmt, ...) {
|
|
908
|
+
(void)handle;
|
|
909
|
+
va_list ap;
|
|
910
|
+
va_start(ap, fmt);
|
|
911
|
+
vfprintf(stderr, fmt, ap);
|
|
912
|
+
va_end(ap);
|
|
913
|
+
return 0;
|
|
914
|
+
}
|
|
915
|
+
|
|
916
|
+
/* ---- Version comparison ---- */
|
|
917
|
+
int alpm_pkg_vercmp(const char *a, const char *b) {
|
|
918
|
+
if (!a && !b) return 0;
|
|
919
|
+
if (!a) return -1;
|
|
920
|
+
if (!b) return 1;
|
|
921
|
+
return strcmp(a, b); // simplified
|
|
922
|
+
}
|
|
923
|
+
|
|
924
|
+
/* ---- Misc ---- */
|
|
925
|
+
const char *alpm_version(void) { return "7.1.0"; }
|
|
926
|
+
int alpm_capabilities(void) { return ALPM_CAPABILITY_NLS; }
|
|
927
|
+
|
|
928
|
+
/* ---- Go/CGO aliases used by AUR helpers ---- */
|
|
929
|
+
alpm_db_t *alpm_register_syncdb(alpm_handle_t *handle, const char *treename, int level) {
|
|
930
|
+
(void)level;
|
|
931
|
+
if (!handle || !treename) return NULL;
|
|
932
|
+
alpm_list_t *it;
|
|
933
|
+
for (it = handle->syncdbs; it; it = it->next) {
|
|
934
|
+
alpm_db_t *db = it->data;
|
|
935
|
+
if (db && strcmp(db->treename, treename) == 0) return db;
|
|
936
|
+
}
|
|
937
|
+
alpm_db_t *db = db_new(treename, 0);
|
|
938
|
+
if (!db) return NULL;
|
|
939
|
+
load_sync_db(db);
|
|
940
|
+
handle->syncdbs = alpm_list_add(handle->syncdbs, db);
|
|
941
|
+
return db;
|
|
942
|
+
}
|
|
943
|
+
alpm_db_t *alpm_get_localdb(alpm_handle_t *handle) { return alpm_option_get_localdb(handle); }
|
|
944
|
+
alpm_list_t *alpm_get_syncdbs(alpm_handle_t *handle) { return alpm_option_get_syncdbs(handle); }
|
|
945
|
+
int alpm_db_unregister(alpm_db_t *db) { (void)db; return 0; }
|
|
946
|
+
const char *alpm_option_get_gpgdir(alpm_handle_t *handle) { (void)handle; return NULL; }
|
|
947
|
+
const char *alpm_option_get_logfile(alpm_handle_t *handle) { (void)handle; return NULL; }
|
|
948
|
+
int alpm_option_set_local_file_siglevel(alpm_handle_t *handle, int level) { (void)handle; (void)level; return 0; }
|
|
949
|
+
int alpm_option_get_local_file_siglevel(alpm_handle_t *handle) { (void)handle; return 0; }
|
|
950
|
+
int alpm_option_set_remote_file_siglevel(alpm_handle_t *handle, int level) { (void)handle; (void)level; return 0; }
|
|
951
|
+
int alpm_option_get_remote_file_siglevel(alpm_handle_t *handle) { (void)handle; return 0; }
|
|
952
|
+
int alpm_option_set_dbext(alpm_handle_t *handle, const char *ext) { (void)handle; (void)ext; return 0; }
|
|
953
|
+
const char *alpm_option_get_dbext(alpm_handle_t *handle) { (void)handle; return NULL; }
|
|
954
|
+
int alpm_option_set_disable_dl_timeout(alpm_handle_t *handle, int disable) { (void)handle; (void)disable; return 0; }
|
|
955
|
+
int alpm_option_get_disable_dl_timeout(alpm_handle_t *handle) { (void)handle; return 0; }
|
|
956
|
+
int alpm_option_set_disable_sandbox(alpm_handle_t *handle, int disable) { (void)handle; (void)disable; return 0; }
|
|
957
|
+
int alpm_option_get_disable_sandbox(alpm_handle_t *handle) { (void)handle; return 0; }
|
|
958
|
+
int alpm_trans_init(alpm_handle_t *handle, int flags) { (void)handle; (void)flags; return 0; }
|
|
959
|
+
int alpm_trans_prepare(alpm_handle_t *handle) { (void)handle; return 0; }
|
|
960
|
+
int alpm_trans_commit(alpm_handle_t *handle) { (void)handle; return 0; }
|
|
961
|
+
int alpm_trans_release(alpm_handle_t *handle) { (void)handle; return 0; }
|
|
962
|
+
int alpm_add_pkg(alpm_handle_t *handle, alpm_pkg_t *pkg) { (void)handle; (void)pkg; return 0; }
|
|
963
|
+
int alpm_remove_pkg(alpm_handle_t *handle, alpm_pkg_t *pkg) { (void)handle; (void)pkg; return 0; }
|
|
964
|
+
int alpm_sync_sysupgrade(alpm_handle_t *handle, int enable_downgrade) { (void)handle; (void)enable_downgrade; return 0; }
|