]>
Commit | Line | Data |
---|---|---|
e2faeb46 | 1 | /* |
5b2de3d8 | 2 | * be_sync.c |
23229097 | 3 | * |
6cebd4e6 DM |
4 | * Copyright (c) 2006-2010 Pacman Development Team <pacman-dev@archlinux.org> |
5 | * Copyright (c) 2002-2006 by Judd Vinet <jvinet@zeroflux.org> | |
23229097 | 6 | * |
e2faeb46 AF |
7 | * This program is free software; you can redistribute it and/or modify |
8 | * it under the terms of the GNU General Public License as published by | |
9 | * the Free Software Foundation; either version 2 of the License, or | |
10 | * (at your option) any later version. | |
11 | * | |
12 | * This program is distributed in the hope that it will be useful, | |
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
15 | * GNU General Public License for more details. | |
16 | * | |
17 | * You should have received a copy of the GNU General Public License | |
9781d0d6 | 18 | * along with this program. If not, see <http://www.gnu.org/licenses/>. |
e2faeb46 AF |
19 | */ |
20 | ||
21 | #include "config.h" | |
869e81e1 | 22 | |
e2faeb46 | 23 | #include <errno.h> |
e2faeb46 | 24 | #include <dirent.h> |
47622eef | 25 | #include <ctype.h> |
5e61f077 | 26 | #include <locale.h> |
869e81e1 | 27 | |
2f4ee434 XC |
28 | /* libarchive */ |
29 | #include <archive.h> | |
30 | #include <archive_entry.h> | |
31 | ||
869e81e1 | 32 | /* libalpm */ |
e2faeb46 | 33 | #include "util.h" |
5b2de3d8 | 34 | #include "log.h" |
e2faeb46 | 35 | #include "alpm.h" |
5b2de3d8 | 36 | #include "alpm_list.h" |
aa1c0ba9 | 37 | #include "package.h" |
5b2de3d8 | 38 | #include "handle.h" |
0c2cc108 | 39 | #include "delta.h" |
c244cfec | 40 | #include "deps.h" |
04600384 | 41 | #include "dload.h" |
d37ad048 | 42 | |
6cebd4e6 DM |
43 | #define LAZY_LOAD(info, errret) \ |
44 | do { \ | |
45 | ALPM_LOG_FUNC; \ | |
46 | ASSERT(handle != NULL, return(errret)); \ | |
47 | ASSERT(pkg != NULL, return(errret)); \ | |
48 | if(pkg->origin != PKG_FROM_FILE && !(pkg->infolevel & info)) { \ | |
fc32faaa | 49 | _alpm_sync_db_read(pkg->origin_data.db, pkg, info); \ |
6cebd4e6 DM |
50 | } \ |
51 | } while(0) | |
52 | ||
53 | ||
54 | /* Cache-specific accessor functions. These implementations allow for lazy | |
55 | * loading by the files backend when a data member is actually needed | |
56 | * rather than loading all pieces of information when the package is first | |
57 | * initialized. | |
58 | */ | |
59 | ||
5b2de3d8 | 60 | const char *_sync_cache_get_filename(pmpkg_t *pkg) |
6cebd4e6 DM |
61 | { |
62 | LAZY_LOAD(INFRQ_DESC, NULL); | |
63 | return pkg->filename; | |
64 | } | |
65 | ||
5b2de3d8 | 66 | const char *_sync_cache_get_name(pmpkg_t *pkg) |
6cebd4e6 DM |
67 | { |
68 | ASSERT(pkg != NULL, return(NULL)); | |
69 | return pkg->name; | |
70 | } | |
71 | ||
5b2de3d8 | 72 | static const char *_sync_cache_get_version(pmpkg_t *pkg) |
6cebd4e6 DM |
73 | { |
74 | ASSERT(pkg != NULL, return(NULL)); | |
75 | return pkg->version; | |
76 | } | |
77 | ||
5b2de3d8 | 78 | static const char *_sync_cache_get_desc(pmpkg_t *pkg) |
6cebd4e6 DM |
79 | { |
80 | LAZY_LOAD(INFRQ_DESC, NULL); | |
81 | return pkg->desc; | |
82 | } | |
83 | ||
5b2de3d8 | 84 | const char *_sync_cache_get_url(pmpkg_t *pkg) |
6cebd4e6 DM |
85 | { |
86 | LAZY_LOAD(INFRQ_DESC, NULL); | |
87 | return pkg->url; | |
88 | } | |
89 | ||
5b2de3d8 | 90 | time_t _sync_cache_get_builddate(pmpkg_t *pkg) |
6cebd4e6 DM |
91 | { |
92 | LAZY_LOAD(INFRQ_DESC, 0); | |
93 | return pkg->builddate; | |
94 | } | |
95 | ||
5b2de3d8 | 96 | time_t _sync_cache_get_installdate(pmpkg_t *pkg) |
6cebd4e6 DM |
97 | { |
98 | LAZY_LOAD(INFRQ_DESC, 0); | |
99 | return pkg->installdate; | |
100 | } | |
101 | ||
5b2de3d8 | 102 | const char *_sync_cache_get_packager(pmpkg_t *pkg) |
6cebd4e6 DM |
103 | { |
104 | LAZY_LOAD(INFRQ_DESC, NULL); | |
105 | return pkg->packager; | |
106 | } | |
107 | ||
5b2de3d8 | 108 | const char *_sync_cache_get_md5sum(pmpkg_t *pkg) |
6cebd4e6 DM |
109 | { |
110 | LAZY_LOAD(INFRQ_DESC, NULL); | |
111 | return pkg->md5sum; | |
112 | } | |
113 | ||
5b2de3d8 | 114 | const char *_sync_cache_get_arch(pmpkg_t *pkg) |
6cebd4e6 DM |
115 | { |
116 | LAZY_LOAD(INFRQ_DESC, NULL); | |
117 | return pkg->arch; | |
118 | } | |
119 | ||
5b2de3d8 | 120 | off_t _sync_cache_get_size(pmpkg_t *pkg) |
6cebd4e6 DM |
121 | { |
122 | LAZY_LOAD(INFRQ_DESC, -1); | |
123 | return pkg->size; | |
124 | } | |
125 | ||
5b2de3d8 | 126 | off_t _sync_cache_get_isize(pmpkg_t *pkg) |
6cebd4e6 DM |
127 | { |
128 | LAZY_LOAD(INFRQ_DESC, -1); | |
129 | return pkg->isize; | |
130 | } | |
131 | ||
5b2de3d8 | 132 | pmpkgreason_t _sync_cache_get_reason(pmpkg_t *pkg) |
6cebd4e6 DM |
133 | { |
134 | LAZY_LOAD(INFRQ_DESC, -1); | |
135 | return pkg->reason; | |
136 | } | |
137 | ||
5b2de3d8 | 138 | alpm_list_t *_sync_cache_get_licenses(pmpkg_t *pkg) |
6cebd4e6 DM |
139 | { |
140 | LAZY_LOAD(INFRQ_DESC, NULL); | |
141 | return pkg->licenses; | |
142 | } | |
143 | ||
5b2de3d8 | 144 | alpm_list_t *_sync_cache_get_groups(pmpkg_t *pkg) |
6cebd4e6 DM |
145 | { |
146 | LAZY_LOAD(INFRQ_DESC, NULL); | |
147 | return pkg->groups; | |
148 | } | |
149 | ||
5b2de3d8 | 150 | int _sync_cache_has_force(pmpkg_t *pkg) |
6cebd4e6 DM |
151 | { |
152 | LAZY_LOAD(INFRQ_DESC, -1); | |
153 | return pkg->force; | |
154 | } | |
155 | ||
5b2de3d8 | 156 | alpm_list_t *_sync_cache_get_depends(pmpkg_t *pkg) |
6cebd4e6 DM |
157 | { |
158 | LAZY_LOAD(INFRQ_DEPENDS, NULL); | |
159 | return pkg->depends; | |
160 | } | |
161 | ||
5b2de3d8 | 162 | alpm_list_t *_sync_cache_get_optdepends(pmpkg_t *pkg) |
6cebd4e6 DM |
163 | { |
164 | LAZY_LOAD(INFRQ_DEPENDS, NULL); | |
165 | return pkg->optdepends; | |
166 | } | |
167 | ||
5b2de3d8 | 168 | alpm_list_t *_sync_cache_get_conflicts(pmpkg_t *pkg) |
6cebd4e6 DM |
169 | { |
170 | LAZY_LOAD(INFRQ_DEPENDS, NULL); | |
171 | return pkg->conflicts; | |
172 | } | |
173 | ||
5b2de3d8 | 174 | alpm_list_t *_sync_cache_get_provides(pmpkg_t *pkg) |
6cebd4e6 DM |
175 | { |
176 | LAZY_LOAD(INFRQ_DEPENDS, NULL); | |
177 | return pkg->provides; | |
178 | } | |
179 | ||
5b2de3d8 | 180 | alpm_list_t *_sync_cache_get_replaces(pmpkg_t *pkg) |
6cebd4e6 DM |
181 | { |
182 | LAZY_LOAD(INFRQ_DESC, NULL); | |
183 | return pkg->replaces; | |
184 | } | |
185 | ||
5b2de3d8 | 186 | alpm_list_t *_sync_cache_get_deltas(pmpkg_t *pkg) |
6cebd4e6 DM |
187 | { |
188 | LAZY_LOAD(INFRQ_DELTAS, NULL); | |
189 | return pkg->deltas; | |
190 | } | |
191 | ||
5b2de3d8 | 192 | alpm_list_t *_sync_cache_get_files(pmpkg_t *pkg) |
6cebd4e6 DM |
193 | { |
194 | ALPM_LOG_FUNC; | |
195 | ||
196 | /* Sanity checks */ | |
197 | ASSERT(handle != NULL, return(NULL)); | |
198 | ASSERT(pkg != NULL, return(NULL)); | |
199 | ||
200 | if(pkg->origin == PKG_FROM_LOCALDB | |
201 | && !(pkg->infolevel & INFRQ_FILES)) { | |
fc32faaa | 202 | _alpm_sync_db_read(pkg->origin_data.db, pkg, INFRQ_FILES); |
6cebd4e6 DM |
203 | } |
204 | return pkg->files; | |
205 | } | |
206 | ||
5b2de3d8 | 207 | alpm_list_t *_sync_cache_get_backup(pmpkg_t *pkg) |
6cebd4e6 DM |
208 | { |
209 | ALPM_LOG_FUNC; | |
210 | ||
211 | /* Sanity checks */ | |
212 | ASSERT(handle != NULL, return(NULL)); | |
213 | ASSERT(pkg != NULL, return(NULL)); | |
214 | ||
215 | if(pkg->origin == PKG_FROM_LOCALDB | |
216 | && !(pkg->infolevel & INFRQ_FILES)) { | |
fc32faaa | 217 | _alpm_sync_db_read(pkg->origin_data.db, pkg, INFRQ_FILES); |
6cebd4e6 DM |
218 | } |
219 | return pkg->backup; | |
220 | } | |
221 | ||
5b2de3d8 AM |
222 | /** The sync database operations struct. Get package fields through |
223 | * lazy accessor methods that handle any backend loading and caching | |
224 | * logic. | |
b9a531c2 | 225 | */ |
5b2de3d8 AM |
226 | static struct pkg_operations sync_pkg_ops = { |
227 | .get_filename = _sync_cache_get_filename, | |
228 | .get_name = _sync_cache_get_name, | |
229 | .get_version = _sync_cache_get_version, | |
230 | .get_desc = _sync_cache_get_desc, | |
231 | .get_url = _sync_cache_get_url, | |
232 | .get_builddate = _sync_cache_get_builddate, | |
233 | .get_installdate = _sync_cache_get_installdate, | |
234 | .get_packager = _sync_cache_get_packager, | |
235 | .get_md5sum = _sync_cache_get_md5sum, | |
236 | .get_arch = _sync_cache_get_arch, | |
237 | .get_size = _sync_cache_get_size, | |
238 | .get_isize = _sync_cache_get_isize, | |
239 | .get_reason = _sync_cache_get_reason, | |
240 | .has_force = _sync_cache_has_force, | |
241 | .get_licenses = _sync_cache_get_licenses, | |
242 | .get_groups = _sync_cache_get_groups, | |
243 | .get_depends = _sync_cache_get_depends, | |
244 | .get_optdepends = _sync_cache_get_optdepends, | |
245 | .get_conflicts = _sync_cache_get_conflicts, | |
246 | .get_provides = _sync_cache_get_provides, | |
247 | .get_replaces = _sync_cache_get_replaces, | |
248 | .get_deltas = _sync_cache_get_deltas, | |
249 | .get_files = _sync_cache_get_files, | |
250 | .get_backup = _sync_cache_get_backup, | |
251 | }; | |
252 | ||
2f4ee434 XC |
253 | /* create list of directories in db */ |
254 | static int dirlist_from_tar(const char *archive, alpm_list_t **dirlist) | |
255 | { | |
256 | struct archive *_archive; | |
257 | struct archive_entry *entry; | |
258 | ||
259 | if((_archive = archive_read_new()) == NULL) | |
260 | RET_ERR(PM_ERR_LIBARCHIVE, -1); | |
261 | ||
262 | archive_read_support_compression_all(_archive); | |
263 | archive_read_support_format_all(_archive); | |
264 | ||
265 | if(archive_read_open_filename(_archive, archive, | |
266 | ARCHIVE_DEFAULT_BYTES_PER_BLOCK) != ARCHIVE_OK) { | |
267 | _alpm_log(PM_LOG_ERROR, _("could not open %s: %s\n"), archive, | |
268 | archive_error_string(_archive)); | |
269 | RET_ERR(PM_ERR_PKG_OPEN, -1); | |
270 | } | |
271 | ||
272 | while(archive_read_next_header(_archive, &entry) == ARCHIVE_OK) { | |
273 | const struct stat *st; | |
274 | const char *entryname; /* the name of the file in the archive */ | |
275 | ||
276 | st = archive_entry_stat(entry); | |
277 | entryname = archive_entry_pathname(entry); | |
278 | ||
279 | if(S_ISDIR(st->st_mode)) { | |
280 | char *name = strdup(entryname); | |
281 | *dirlist = alpm_list_add(*dirlist, name); | |
282 | } | |
283 | } | |
284 | archive_read_finish(_archive); | |
285 | ||
286 | *dirlist = alpm_list_msort(*dirlist, alpm_list_count(*dirlist), _alpm_str_cmp); | |
287 | return(0); | |
288 | } | |
289 | ||
dff73a2a DM |
290 | static int is_dir(const char *path, struct dirent *entry) |
291 | { | |
292 | #ifdef DT_DIR | |
293 | return(entry->d_type == DT_DIR); | |
294 | #else | |
295 | char buffer[PATH_MAX]; | |
296 | snprintf(buffer, PATH_MAX, "%s/%s", path, entry->d_name); | |
297 | ||
298 | struct stat sbuf; | |
299 | if (!stat(buffer, &sbuf)) { | |
300 | return(S_ISDIR(sbuf.st_mode)); | |
301 | } | |
302 | ||
303 | return(0); | |
304 | #endif | |
305 | } | |
306 | ||
2f4ee434 XC |
307 | /* create list of directories in db */ |
308 | static int dirlist_from_fs(const char *syncdbpath, alpm_list_t **dirlist) | |
309 | { | |
310 | DIR *dbdir; | |
311 | struct dirent *ent = NULL; | |
2f4ee434 XC |
312 | |
313 | dbdir = opendir(syncdbpath); | |
314 | if (dbdir != NULL) { | |
315 | while((ent = readdir(dbdir)) != NULL) { | |
316 | char *name = ent->d_name; | |
317 | size_t len; | |
318 | char *entry; | |
319 | ||
320 | if(strcmp(name, ".") == 0 || strcmp(name, "..") == 0) { | |
321 | continue; | |
322 | } | |
323 | ||
dff73a2a | 324 | if(!is_dir(syncdbpath, ent)) { |
2f4ee434 XC |
325 | continue; |
326 | } | |
327 | ||
328 | len = strlen(name); | |
329 | MALLOC(entry, len + 2, RET_ERR(PM_ERR_MEMORY, -1)); | |
330 | strcpy(entry, name); | |
331 | entry[len] = '/'; | |
332 | entry[len+1] = '\0'; | |
333 | *dirlist = alpm_list_add(*dirlist, entry); | |
334 | } | |
1aa1d002 | 335 | closedir(dbdir); |
2f4ee434 | 336 | } |
2f4ee434 XC |
337 | |
338 | *dirlist = alpm_list_msort(*dirlist, alpm_list_count(*dirlist), _alpm_str_cmp); | |
339 | return(0); | |
340 | } | |
341 | ||
342 | /* remove old directories from dbdir */ | |
343 | static int remove_olddir(const char *syncdbpath, alpm_list_t *dirlist) | |
344 | { | |
345 | alpm_list_t *i; | |
346 | for (i = dirlist; i; i = i->next) { | |
347 | const char *name = i->data; | |
348 | char *dbdir; | |
349 | size_t len = strlen(syncdbpath) + strlen(name) + 2; | |
350 | MALLOC(dbdir, len, RET_ERR(PM_ERR_MEMORY, -1)); | |
351 | snprintf(dbdir, len, "%s%s", syncdbpath, name); | |
352 | _alpm_log(PM_LOG_DEBUG, "removing: %s\n", dbdir); | |
353 | if(_alpm_rmrf(dbdir) != 0) { | |
354 | _alpm_log(PM_LOG_ERROR, _("could not remove database directory %s\n"), dbdir); | |
355 | free(dbdir); | |
356 | RET_ERR(PM_ERR_DB_REMOVE, -1); | |
357 | } | |
358 | free(dbdir); | |
359 | } | |
360 | return(0); | |
361 | } | |
362 | ||
04600384 | 363 | /** Update a package database |
63fc9360 SN |
364 | * |
365 | * An update of the package database \a db will be attempted. Unless | |
366 | * \a force is true, the update will only be performed if the remote | |
367 | * database was modified since the last update. | |
368 | * | |
369 | * A transaction is necessary for this operation, in order to obtain a | |
370 | * database lock. During this transaction the front-end will be informed | |
371 | * of the download progress of the database via the download callback. | |
372 | * | |
373 | * Example: | |
374 | * @code | |
375 | * pmdb_t *db; | |
376 | * int result; | |
377 | * db = alpm_list_getdata(alpm_option_get_syncdbs()); | |
8ff3b870 | 378 | * if(alpm_trans_init(0, NULL, NULL, NULL) == 0) { |
63fc9360 SN |
379 | * result = alpm_db_update(0, db); |
380 | * alpm_trans_release(); | |
381 | * | |
382 | * if(result > 0) { | |
383 | * printf("Unable to update database: %s\n", alpm_strerrorlast()); | |
384 | * } else if(result < 0) { | |
385 | * printf("Database already up to date\n"); | |
386 | * } else { | |
387 | * printf("Database updated\n"); | |
388 | * } | |
389 | * } | |
390 | * @endcode | |
391 | * | |
392 | * @ingroup alpm_databases | |
393 | * @note After a successful update, the \link alpm_db_get_pkgcache() | |
394 | * package cache \endlink will be invalidated | |
04600384 DM |
395 | * @param force if true, then forces the update, otherwise update only in case |
396 | * the database isn't up to date | |
397 | * @param db pointer to the package database to update | |
398 | * @return 0 on success, > 0 on error (pm_errno is set accordingly), < 0 if up | |
399 | * to date | |
e8275fa9 | 400 | */ |
04600384 | 401 | int SYMEXPORT alpm_db_update(int force, pmdb_t *db) |
e8275fa9 | 402 | { |
a8355994 | 403 | char *dbfile, *dbfilepath, *syncpath; |
be2f4319 | 404 | const char *dbpath, *syncdbpath; |
f6c7de77 DM |
405 | alpm_list_t *newdirlist = NULL, *olddirlist = NULL; |
406 | alpm_list_t *onlynew = NULL, *onlyold = NULL; | |
0966c33a | 407 | size_t len; |
04600384 DM |
408 | int ret; |
409 | ||
da648bc2 AG |
410 | ALPM_LOG_FUNC; |
411 | ||
04600384 DM |
412 | /* Sanity checks */ |
413 | ASSERT(handle != NULL, RET_ERR(PM_ERR_HANDLE_NULL, -1)); | |
414 | ASSERT(db != NULL && db != handle->db_local, RET_ERR(PM_ERR_WRONG_ARGS, -1)); | |
415 | /* Verify we are in a transaction. This is done _mainly_ because we need a DB | |
416 | * lock - if we update without a db lock, we may kludge some other pacman | |
417 | * process that _has_ a lock. | |
418 | */ | |
419 | ASSERT(handle->trans != NULL, RET_ERR(PM_ERR_TRANS_NULL, -1)); | |
420 | ASSERT(handle->trans->state == STATE_INITIALIZED, RET_ERR(PM_ERR_TRANS_NOT_INITIALIZED, -1)); | |
04600384 DM |
421 | |
422 | if(!alpm_list_find_ptr(handle->dbs_sync, db)) { | |
423 | RET_ERR(PM_ERR_DB_NOT_FOUND, -1); | |
424 | } | |
425 | ||
68dcabdf | 426 | len = strlen(db->treename) + 4; |
0966c33a | 427 | MALLOC(dbfile, len, RET_ERR(PM_ERR_MEMORY, -1)); |
68dcabdf | 428 | sprintf(dbfile, "%s.db", db->treename); |
0966c33a | 429 | |
04600384 | 430 | dbpath = alpm_option_get_dbpath(); |
a8355994 AM |
431 | len = strlen(dbpath) + 6; |
432 | MALLOC(syncpath, len, RET_ERR(PM_ERR_MEMORY, -1)); | |
433 | sprintf(syncpath, "%s%s", dbpath, "sync/"); | |
04600384 | 434 | |
a8355994 | 435 | ret = _alpm_download_single_file(dbfile, db->servers, syncpath, force); |
0966c33a | 436 | free(dbfile); |
a8355994 | 437 | free(syncpath); |
04600384 DM |
438 | |
439 | if(ret == 1) { | |
d2dbb04a | 440 | /* files match, do nothing */ |
04600384 DM |
441 | pm_errno = 0; |
442 | return(1); | |
443 | } else if(ret == -1) { | |
444 | /* pm_errno was set by the download code */ | |
445 | _alpm_log(PM_LOG_DEBUG, "failed to sync db: %s\n", alpm_strerrorlast()); | |
446 | return(-1); | |
2f4ee434 XC |
447 | } |
448 | ||
be2f4319 | 449 | syncdbpath = _alpm_db_path(db); |
2f4ee434 XC |
450 | |
451 | /* form the path to the db location */ | |
a8355994 | 452 | len = strlen(dbpath) + strlen(db->treename) + 9; |
2f4ee434 | 453 | MALLOC(dbfilepath, len, RET_ERR(PM_ERR_MEMORY, -1)); |
a8355994 | 454 | sprintf(dbfilepath, "%ssync/%s.db", dbpath, db->treename); |
2f4ee434 XC |
455 | |
456 | if(force) { | |
457 | /* if forcing update, remove the old dir and extract the db */ | |
72883e3b | 458 | if(_alpm_rmrf(syncdbpath) != 0) { |
34e1413d XC |
459 | _alpm_log(PM_LOG_ERROR, _("could not remove database %s\n"), db->treename); |
460 | RET_ERR(PM_ERR_DB_REMOVE, -1); | |
d2dbb04a DM |
461 | } else { |
462 | _alpm_log(PM_LOG_DEBUG, "database dir %s removed\n", _alpm_db_path(db)); | |
04600384 | 463 | } |
be2f4319 DM |
464 | } else { |
465 | /* if not forcing, only remove and extract what is necessary */ | |
be2f4319 | 466 | ret = dirlist_from_tar(dbfilepath, &newdirlist); |
0966c33a | 467 | if(ret) { |
be2f4319 DM |
468 | goto cleanup; |
469 | } | |
470 | ret = dirlist_from_fs(syncdbpath, &olddirlist); | |
471 | if(ret) { | |
be2f4319 | 472 | goto cleanup; |
04600384 | 473 | } |
2f4ee434 | 474 | |
f6c7de77 | 475 | alpm_list_diff_sorted(olddirlist, newdirlist, _alpm_str_cmp, &onlyold, &onlynew); |
2f4ee434 | 476 | |
be2f4319 | 477 | ret = remove_olddir(syncdbpath, onlyold); |
be2f4319 DM |
478 | if(ret) { |
479 | goto cleanup; | |
480 | } | |
2f4ee434 XC |
481 | } |
482 | ||
2f4ee434 XC |
483 | /* Cache needs to be rebuilt */ |
484 | _alpm_db_free_pkgcache(db); | |
485 | ||
2f4ee434 | 486 | checkdbdir(db); |
f6c7de77 | 487 | ret = _alpm_unpack(dbfilepath, syncdbpath, onlynew, 0); |
2f4ee434 XC |
488 | |
489 | cleanup: | |
f6c7de77 DM |
490 | FREELIST(newdirlist); |
491 | FREELIST(olddirlist); | |
492 | alpm_list_free(onlynew); | |
493 | alpm_list_free(onlyold); | |
494 | ||
2f4ee434 | 495 | free(dbfilepath); |
2f4ee434 XC |
496 | |
497 | if(ret) { | |
498 | RET_ERR(PM_ERR_SYSTEM, -1); | |
e8275fa9 AG |
499 | } |
500 | ||
04600384 | 501 | return(0); |
e8275fa9 AG |
502 | } |
503 | ||
5b2de3d8 | 504 | int _alpm_sync_db_populate(pmdb_t *db) |
e2faeb46 | 505 | { |
f6711472 | 506 | int count = 0; |
5e61f077 AM |
507 | struct archive *archive; |
508 | struct archive_entry *entry; | |
509 | const char * archive_path; | |
e2faeb46 | 510 | |
da648bc2 AG |
511 | ALPM_LOG_FUNC; |
512 | ||
f6711472 | 513 | ASSERT(db != NULL, RET_ERR(PM_ERR_DB_NULL, -1)); |
e2faeb46 | 514 | |
5e61f077 AM |
515 | if((archive = archive_read_new()) == NULL) |
516 | RET_ERR(PM_ERR_LIBARCHIVE, 1); | |
517 | ||
518 | archive_read_support_compression_all(archive); | |
519 | archive_read_support_format_all(archive); | |
520 | ||
521 | if(archive_read_open_filename(archive, _alpm_db_path(db), | |
522 | ARCHIVE_DEFAULT_BYTES_PER_BLOCK) != ARCHIVE_OK) { | |
523 | _alpm_log(PM_LOG_ERROR, _("could not open %s: %s\n"), _alpm_db_path(db), | |
524 | archive_error_string(archive)); | |
525 | RET_ERR(PM_ERR_PKG_OPEN, 1); | |
14230869 | 526 | } |
5e61f077 AM |
527 | |
528 | while(archive_read_next_header(archive, &entry) == ARCHIVE_OK) { | |
529 | const struct stat *st; | |
530 | const char *name; | |
f6711472 | 531 | pmpkg_t *pkg; |
ccc1c731 | 532 | |
5e61f077 AM |
533 | st = archive_entry_stat(entry); |
534 | ||
535 | /* only parse directory names */ | |
536 | if(S_ISREG(st->st_mode)) { | |
537 | /* we have desc or depends or something else */ | |
f6711472 | 538 | continue; |
e2faeb46 | 539 | } |
0adceabe | 540 | |
5e61f077 AM |
541 | archive_path = archive_entry_pathname(entry); |
542 | ||
dd98aa85 | 543 | pkg = _alpm_pkg_new(); |
0adceabe | 544 | if(pkg == NULL) { |
5e61f077 | 545 | archive_read_finish(archive); |
f6711472 | 546 | return(-1); |
e2faeb46 | 547 | } |
5e61f077 AM |
548 | |
549 | name = archive_entry_pathname(entry); | |
550 | ||
f6711472 | 551 | if(splitname(name, pkg) != 0) { |
f7bbfe40 | 552 | _alpm_log(PM_LOG_ERROR, _("invalid name for database entry '%s'\n"), |
f6711472 XC |
553 | name); |
554 | _alpm_pkg_free(pkg); | |
9d9ac66b | 555 | continue; |
0adceabe | 556 | } |
7f5dada8 | 557 | |
444ff956 NG |
558 | /* duplicated database entries are not allowed */ |
559 | if(_alpm_pkg_find(db->pkgcache, pkg->name)) { | |
560 | _alpm_log(PM_LOG_ERROR, _("duplicated database entry '%s'\n"), pkg->name); | |
561 | _alpm_pkg_free(pkg); | |
562 | continue; | |
563 | } | |
564 | ||
5b2de3d8 AM |
565 | pkg->origin = PKG_FROM_SYNCDB; |
566 | pkg->ops = &sync_pkg_ops; | |
f6711472 | 567 | pkg->origin_data.db = db; |
5e61f077 | 568 | |
f6711472 XC |
569 | /* add to the collection */ |
570 | _alpm_log(PM_LOG_FUNCTION, "adding '%s' to package cache for db '%s'\n", | |
571 | pkg->name, db->treename); | |
572 | db->pkgcache = alpm_list_add(db->pkgcache, pkg); | |
573 | count++; | |
e2faeb46 AF |
574 | } |
575 | ||
f6711472 | 576 | db->pkgcache = alpm_list_msort(db->pkgcache, count, _alpm_pkg_cmp); |
5e61f077 AM |
577 | archive_read_finish(archive); |
578 | ||
f6711472 | 579 | return(count); |
e2faeb46 AF |
580 | } |
581 | ||
5b2de3d8 | 582 | int _alpm_sync_db_read(pmdb_t *db, pmpkg_t *info, pmdbinfrq_t inforeq) |
e2faeb46 AF |
583 | { |
584 | FILE *fp = NULL; | |
7fccfc78 | 585 | char path[PATH_MAX]; |
d896527d | 586 | char line[1024]; |
0966c33a | 587 | char *pkgpath = NULL; |
e2faeb46 | 588 | |
da648bc2 AG |
589 | ALPM_LOG_FUNC; |
590 | ||
e8275fa9 AG |
591 | if(db == NULL) { |
592 | RET_ERR(PM_ERR_DB_NULL, -1); | |
593 | } | |
594 | ||
ccc1c731 | 595 | if(info == NULL || info->name == NULL || info->version == NULL) { |
fc32faaa | 596 | _alpm_log(PM_LOG_DEBUG, "invalid package entry provided to _alpm_sync_db_read, skipping\n"); |
e2faeb46 AF |
597 | return(-1); |
598 | } | |
599 | ||
3bf918dc | 600 | if(info->origin == PKG_FROM_FILE) { |
5c9eec55 | 601 | _alpm_log(PM_LOG_DEBUG, "request to read database info for a file-based package '%s', skipping...\n", info->name); |
3bf918dc AG |
602 | return(-1); |
603 | } | |
604 | ||
ba1806f5 DM |
605 | /* bitmask logic here: |
606 | * infolevel: 00001111 | |
607 | * inforeq: 00010100 | |
608 | * & result: 00000100 | |
609 | * == to inforeq? nope, we need to load more info. */ | |
610 | if((info->infolevel & inforeq) == inforeq) { | |
986409f9 AG |
611 | /* already loaded this info, do nothing */ |
612 | return(0); | |
613 | } | |
4abd710e DM |
614 | _alpm_log(PM_LOG_FUNCTION, "loading package data for %s : level=0x%x\n", |
615 | info->name, inforeq); | |
3bf918dc | 616 | |
aa1c0ba9 | 617 | /* clear out 'line', to be certain - and to make valgrind happy */ |
d896527d | 618 | memset(line, 0, sizeof(line)); |
aa1c0ba9 | 619 | |
0966c33a XC |
620 | pkgpath = get_pkgpath(db, info); |
621 | ||
29bf6814 | 622 | if(access(pkgpath, F_OK)) { |
e2faeb46 | 623 | /* directory doesn't exist or can't be opened */ |
5c9eec55 | 624 | _alpm_log(PM_LOG_DEBUG, "cannot find '%s-%s' in db '%s'\n", |
ea1fef69 | 625 | info->name, info->version, db->treename); |
0966c33a | 626 | goto error; |
e2faeb46 AF |
627 | } |
628 | ||
629 | /* DESC */ | |
630 | if(inforeq & INFRQ_DESC) { | |
0966c33a | 631 | snprintf(path, PATH_MAX, "%sdesc", pkgpath); |
170d6319 | 632 | if((fp = fopen(path, "r")) == NULL) { |
5c9eec55 | 633 | _alpm_log(PM_LOG_ERROR, _("could not open file %s: %s\n"), path, strerror(errno)); |
e2faeb46 AF |
634 | goto error; |
635 | } | |
636 | while(!feof(fp)) { | |
d896527d | 637 | if(fgets(line, sizeof(line), fp) == NULL) { |
e2faeb46 AF |
638 | break; |
639 | } | |
640 | _alpm_strtrim(line); | |
da1c11cc | 641 | if(strcmp(line, "%NAME%") == 0) { |
d896527d | 642 | if(fgets(line, sizeof(line), fp) == NULL) { |
da1c11cc NG |
643 | goto error; |
644 | } | |
645 | if(strcmp(_alpm_strtrim(line), info->name) != 0) { | |
646 | _alpm_log(PM_LOG_ERROR, _("%s database is inconsistent: name " | |
647 | "mismatch on package %s\n"), db->treename, info->name); | |
648 | } | |
649 | } else if(strcmp(line, "%VERSION%") == 0) { | |
d896527d | 650 | if(fgets(line, sizeof(line), fp) == NULL) { |
da1c11cc NG |
651 | goto error; |
652 | } | |
653 | if(strcmp(_alpm_strtrim(line), info->version) != 0) { | |
654 | _alpm_log(PM_LOG_ERROR, _("%s database is inconsistent: version " | |
655 | "mismatch on package %s\n"), db->treename, info->name); | |
656 | } | |
657 | } else if(strcmp(line, "%FILENAME%") == 0) { | |
d896527d | 658 | if(fgets(line, sizeof(line), fp) == NULL) { |
986409f9 AG |
659 | goto error; |
660 | } | |
ccc1c731 | 661 | STRDUP(info->filename, _alpm_strtrim(line), goto error); |
da1c11cc | 662 | } else if(strcmp(line, "%DESC%") == 0) { |
d896527d | 663 | if(fgets(line, sizeof(line), fp) == NULL) { |
af48c695 AG |
664 | goto error; |
665 | } | |
ccc1c731 DM |
666 | STRDUP(info->desc, _alpm_strtrim(line), goto error); |
667 | } else if(strcmp(line, "%GROUPS%") == 0) { | |
d896527d | 668 | while(fgets(line, sizeof(line), fp) && strlen(_alpm_strtrim(line))) { |
ccc1c731 DM |
669 | char *linedup; |
670 | STRDUP(linedup, _alpm_strtrim(line), goto error); | |
671 | info->groups = alpm_list_add(info->groups, linedup); | |
e2faeb46 | 672 | } |
ccc1c731 | 673 | } else if(strcmp(line, "%URL%") == 0) { |
d896527d | 674 | if(fgets(line, sizeof(line), fp) == NULL) { |
e2faeb46 AF |
675 | goto error; |
676 | } | |
ccc1c731 DM |
677 | STRDUP(info->url, _alpm_strtrim(line), goto error); |
678 | } else if(strcmp(line, "%LICENSE%") == 0) { | |
d896527d | 679 | while(fgets(line, sizeof(line), fp) && strlen(_alpm_strtrim(line))) { |
ccc1c731 DM |
680 | char *linedup; |
681 | STRDUP(linedup, _alpm_strtrim(line), goto error); | |
682 | info->licenses = alpm_list_add(info->licenses, linedup); | |
e2faeb46 | 683 | } |
ccc1c731 | 684 | } else if(strcmp(line, "%ARCH%") == 0) { |
d896527d | 685 | if(fgets(line, sizeof(line), fp) == NULL) { |
e2faeb46 AF |
686 | goto error; |
687 | } | |
ccc1c731 DM |
688 | STRDUP(info->arch, _alpm_strtrim(line), goto error); |
689 | } else if(strcmp(line, "%BUILDDATE%") == 0) { | |
d896527d | 690 | if(fgets(line, sizeof(line), fp) == NULL) { |
e2faeb46 AF |
691 | goto error; |
692 | } | |
ccc1c731 | 693 | _alpm_strtrim(line); |
47622eef | 694 | |
caea098c | 695 | char first = tolower((unsigned char)line[0]); |
47622eef | 696 | if(first > 'a' && first < 'z') { |
ed848b1c | 697 | struct tm tmp_tm = {0}; /* initialize to null in case of failure */ |
e6673544 | 698 | setlocale(LC_TIME, "C"); |
ccc1c731 | 699 | strptime(line, "%a %b %e %H:%M:%S %Y", &tmp_tm); |
47622eef | 700 | info->builddate = mktime(&tmp_tm); |
e6673544 | 701 | setlocale(LC_TIME, ""); |
47622eef | 702 | } else { |
ccc1c731 | 703 | info->builddate = atol(line); |
47622eef | 704 | } |
ccc1c731 | 705 | } else if(strcmp(line, "%INSTALLDATE%") == 0) { |
d896527d | 706 | if(fgets(line, sizeof(line), fp) == NULL) { |
e2faeb46 AF |
707 | goto error; |
708 | } | |
ccc1c731 | 709 | _alpm_strtrim(line); |
47622eef | 710 | |
caea098c | 711 | char first = tolower((unsigned char)line[0]); |
47622eef | 712 | if(first > 'a' && first < 'z') { |
ed848b1c | 713 | struct tm tmp_tm = {0}; /* initialize to null in case of failure */ |
e6673544 | 714 | setlocale(LC_TIME, "C"); |
ccc1c731 | 715 | strptime(line, "%a %b %e %H:%M:%S %Y", &tmp_tm); |
47622eef | 716 | info->installdate = mktime(&tmp_tm); |
e6673544 | 717 | setlocale(LC_TIME, ""); |
47622eef | 718 | } else { |
ccc1c731 | 719 | info->installdate = atol(line); |
47622eef | 720 | } |
ccc1c731 | 721 | } else if(strcmp(line, "%PACKAGER%") == 0) { |
d896527d | 722 | if(fgets(line, sizeof(line), fp) == NULL) { |
e2faeb46 AF |
723 | goto error; |
724 | } | |
ccc1c731 DM |
725 | STRDUP(info->packager, _alpm_strtrim(line), goto error); |
726 | } else if(strcmp(line, "%REASON%") == 0) { | |
d896527d | 727 | if(fgets(line, sizeof(line), fp) == NULL) { |
e2faeb46 AF |
728 | goto error; |
729 | } | |
f7192b59 | 730 | info->reason = (pmpkgreason_t)atol(_alpm_strtrim(line)); |
ccc1c731 | 731 | } else if(strcmp(line, "%SIZE%") == 0 || strcmp(line, "%CSIZE%") == 0) { |
e2faeb46 AF |
732 | /* NOTE: the CSIZE and SIZE fields both share the "size" field |
733 | * in the pkginfo_t struct. This can be done b/c CSIZE | |
734 | * is currently only used in sync databases, and SIZE is | |
735 | * only used in local databases. | |
736 | */ | |
d896527d | 737 | if(fgets(line, sizeof(line), fp) == NULL) { |
e2faeb46 AF |
738 | goto error; |
739 | } | |
ccc1c731 | 740 | info->size = atol(_alpm_strtrim(line)); |
5e12d3de DM |
741 | /* also store this value to isize if isize is unset */ |
742 | if(info->isize == 0) { | |
ccc1c731 | 743 | info->isize = info->size; |
5e12d3de | 744 | } |
ccc1c731 | 745 | } else if(strcmp(line, "%ISIZE%") == 0) { |
986409f9 | 746 | /* ISIZE (installed size) tag only appears in sync repositories, |
d37ad048 | 747 | * not the local one. */ |
d896527d | 748 | if(fgets(line, sizeof(line), fp) == NULL) { |
d37ad048 AG |
749 | goto error; |
750 | } | |
ccc1c731 DM |
751 | info->isize = atol(_alpm_strtrim(line)); |
752 | } else if(strcmp(line, "%MD5SUM%") == 0) { | |
e2faeb46 AF |
753 | /* MD5SUM tag only appears in sync repositories, |
754 | * not the local one. */ | |
d896527d | 755 | if(fgets(line, sizeof(line), fp) == NULL) { |
e2faeb46 AF |
756 | goto error; |
757 | } | |
ccc1c731 DM |
758 | STRDUP(info->md5sum, _alpm_strtrim(line), goto error); |
759 | } else if(strcmp(line, "%REPLACES%") == 0) { | |
d896527d | 760 | while(fgets(line, sizeof(line), fp) && strlen(_alpm_strtrim(line))) { |
ccc1c731 DM |
761 | char *linedup; |
762 | STRDUP(linedup, _alpm_strtrim(line), goto error); | |
763 | info->replaces = alpm_list_add(info->replaces, linedup); | |
e2faeb46 | 764 | } |
ccc1c731 | 765 | } else if(strcmp(line, "%FORCE%") == 0) { |
e2faeb46 AF |
766 | info->force = 1; |
767 | } | |
768 | } | |
769 | fclose(fp); | |
770 | fp = NULL; | |
771 | } | |
772 | ||
773 | /* FILES */ | |
774 | if(inforeq & INFRQ_FILES) { | |
0966c33a | 775 | snprintf(path, PATH_MAX, "%sfiles", pkgpath); |
170d6319 | 776 | if((fp = fopen(path, "r")) == NULL) { |
5c9eec55 | 777 | _alpm_log(PM_LOG_ERROR, _("could not open file %s: %s\n"), path, strerror(errno)); |
e2faeb46 AF |
778 | goto error; |
779 | } | |
d896527d | 780 | while(fgets(line, sizeof(line), fp)) { |
e2faeb46 | 781 | _alpm_strtrim(line); |
ccc1c731 | 782 | if(strcmp(line, "%FILES%") == 0) { |
d896527d | 783 | while(fgets(line, sizeof(line), fp) && strlen(_alpm_strtrim(line))) { |
ccc1c731 DM |
784 | char *linedup; |
785 | STRDUP(linedup, _alpm_strtrim(line), goto error); | |
786 | info->files = alpm_list_add(info->files, linedup); | |
e2faeb46 | 787 | } |
ccc1c731 | 788 | } else if(strcmp(line, "%BACKUP%") == 0) { |
d896527d | 789 | while(fgets(line, sizeof(line), fp) && strlen(_alpm_strtrim(line))) { |
ccc1c731 DM |
790 | char *linedup; |
791 | STRDUP(linedup, _alpm_strtrim(line), goto error); | |
792 | info->backup = alpm_list_add(info->backup, linedup); | |
e2faeb46 AF |
793 | } |
794 | } | |
795 | } | |
796 | fclose(fp); | |
797 | fp = NULL; | |
798 | } | |
799 | ||
800 | /* DEPENDS */ | |
801 | if(inforeq & INFRQ_DEPENDS) { | |
0966c33a | 802 | snprintf(path, PATH_MAX, "%sdepends", pkgpath); |
170d6319 | 803 | if((fp = fopen(path, "r")) == NULL) { |
5c9eec55 | 804 | _alpm_log(PM_LOG_ERROR, _("could not open file %s: %s\n"), path, strerror(errno)); |
e2faeb46 AF |
805 | goto error; |
806 | } | |
807 | while(!feof(fp)) { | |
d896527d | 808 | if(fgets(line, sizeof(line), fp) == NULL) { |
60de8ec9 AM |
809 | break; |
810 | } | |
e2faeb46 | 811 | _alpm_strtrim(line); |
ccc1c731 | 812 | if(strcmp(line, "%DEPENDS%") == 0) { |
d896527d | 813 | while(fgets(line, sizeof(line), fp) && strlen(_alpm_strtrim(line))) { |
b2914bf0 | 814 | pmdepend_t *dep = _alpm_splitdep(_alpm_strtrim(line)); |
c244cfec | 815 | info->depends = alpm_list_add(info->depends, dep); |
e2faeb46 | 816 | } |
ccc1c731 | 817 | } else if(strcmp(line, "%OPTDEPENDS%") == 0) { |
d896527d | 818 | while(fgets(line, sizeof(line), fp) && strlen(_alpm_strtrim(line))) { |
ccc1c731 DM |
819 | char *linedup; |
820 | STRDUP(linedup, _alpm_strtrim(line), goto error); | |
821 | info->optdepends = alpm_list_add(info->optdepends, linedup); | |
fc0e83f0 | 822 | } |
ccc1c731 | 823 | } else if(strcmp(line, "%CONFLICTS%") == 0) { |
d896527d | 824 | while(fgets(line, sizeof(line), fp) && strlen(_alpm_strtrim(line))) { |
ccc1c731 DM |
825 | char *linedup; |
826 | STRDUP(linedup, _alpm_strtrim(line), goto error); | |
827 | info->conflicts = alpm_list_add(info->conflicts, linedup); | |
e2faeb46 | 828 | } |
ccc1c731 | 829 | } else if(strcmp(line, "%PROVIDES%") == 0) { |
d896527d | 830 | while(fgets(line, sizeof(line), fp) && strlen(_alpm_strtrim(line))) { |
ccc1c731 DM |
831 | char *linedup; |
832 | STRDUP(linedup, _alpm_strtrim(line), goto error); | |
833 | info->provides = alpm_list_add(info->provides, linedup); | |
e2faeb46 | 834 | } |
13e21110 | 835 | } |
e2faeb46 AF |
836 | } |
837 | fclose(fp); | |
838 | fp = NULL; | |
839 | } | |
840 | ||
0c2cc108 NJ |
841 | /* DELTAS */ |
842 | if(inforeq & INFRQ_DELTAS) { | |
0966c33a | 843 | snprintf(path, PATH_MAX, "%sdeltas", pkgpath); |
0c2cc108 NJ |
844 | if((fp = fopen(path, "r"))) { |
845 | while(!feof(fp)) { | |
d896527d | 846 | if(fgets(line, sizeof(line), fp) == NULL) { |
60de8ec9 AM |
847 | break; |
848 | } | |
0c2cc108 | 849 | _alpm_strtrim(line); |
ccc1c731 | 850 | if(strcmp(line, "%DELTAS%") == 0) { |
d896527d | 851 | while(fgets(line, sizeof(line), fp) && strlen(_alpm_strtrim(line))) { |
b99bebc0 DM |
852 | pmdelta_t *delta = _alpm_delta_parse(line); |
853 | if(delta) { | |
854 | info->deltas = alpm_list_add(info->deltas, delta); | |
855 | } | |
0c2cc108 NJ |
856 | } |
857 | } | |
858 | } | |
859 | fclose(fp); | |
860 | fp = NULL; | |
861 | } | |
862 | } | |
863 | ||
e2faeb46 | 864 | /* INSTALL */ |
aa1c0ba9 | 865 | if(inforeq & INFRQ_SCRIPTLET) { |
0966c33a | 866 | snprintf(path, PATH_MAX, "%sinstall", pkgpath); |
29bf6814 | 867 | if(access(path, F_OK) == 0) { |
e2faeb46 AF |
868 | info->scriptlet = 1; |
869 | } | |
870 | } | |
871 | ||
872 | /* internal */ | |
873 | info->infolevel |= inforeq; | |
874 | ||
0966c33a | 875 | free(pkgpath); |
e2faeb46 AF |
876 | return(0); |
877 | ||
878 | error: | |
0966c33a | 879 | free(pkgpath); |
e2faeb46 AF |
880 | if(fp) { |
881 | fclose(fp); | |
882 | } | |
883 | return(-1); | |
884 | } | |
885 | ||
fc32faaa AM |
886 | struct db_operations sync_db_ops = { |
887 | .populate = _alpm_sync_db_populate, | |
888 | .unregister = _alpm_db_unregister, | |
889 | }; | |
890 | ||
891 | pmdb_t *_alpm_db_register_sync(const char *treename) | |
892 | { | |
893 | pmdb_t *db; | |
894 | alpm_list_t *i; | |
895 | ||
896 | ALPM_LOG_FUNC; | |
897 | ||
898 | for(i = handle->dbs_sync; i; i = i->next) { | |
899 | pmdb_t *sdb = i->data; | |
900 | if(strcmp(treename, sdb->treename) == 0) { | |
901 | _alpm_log(PM_LOG_DEBUG, "attempt to re-register the '%s' database, using existing\n", sdb->treename); | |
902 | return sdb; | |
903 | } | |
904 | } | |
905 | ||
906 | _alpm_log(PM_LOG_DEBUG, "registering sync database '%s'\n", treename); | |
907 | ||
908 | db = _alpm_db_new(treename, 0); | |
909 | db->ops = &sync_db_ops; | |
910 | if(db == NULL) { | |
911 | RET_ERR(PM_ERR_DB_CREATE, NULL); | |
912 | } | |
913 | ||
914 | handle->dbs_sync = alpm_list_add(handle->dbs_sync, db); | |
915 | return(db); | |
916 | } | |
917 | ||
918 | ||
e2faeb46 | 919 | /* vim: set ts=2 sw=2 noet: */ |