Initial hack at a DB operations struct
[pacman-ng.git] / lib / libalpm / be_files.c
blob5766a4b12673bb43b392a6a6f47cd7bd23888487
1 /*
2 * be_files.c
4 * Copyright (c) 2006-2010 Pacman Development Team <pacman-dev@archlinux.org>
5 * Copyright (c) 2002-2006 by Judd Vinet <jvinet@zeroflux.org>
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.
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.
17 * You should have received a copy of the GNU General Public License
18 * along with this program. If not, see <http://www.gnu.org/licenses/>.
21 #include "config.h"
23 #include <unistd.h>
24 #include <stdio.h>
25 #include <stdlib.h>
26 #include <errno.h>
27 #include <string.h>
28 #include <stdint.h> /* intmax_t */
29 #include <sys/stat.h>
30 #include <dirent.h>
31 #include <ctype.h>
32 #include <time.h>
33 #include <limits.h> /* PATH_MAX */
34 #include <locale.h> /* setlocale */
36 /* libarchive */
37 #include <archive.h>
38 #include <archive_entry.h>
40 /* libalpm */
41 #include "db.h"
42 #include "alpm_list.h"
43 #include "log.h"
44 #include "util.h"
45 #include "alpm.h"
46 #include "handle.h"
47 #include "package.h"
48 #include "group.h"
49 #include "delta.h"
50 #include "deps.h"
51 #include "dload.h"
54 #define LAZY_LOAD(info, errret) \
55 do { \
56 ALPM_LOG_FUNC; \
57 ASSERT(handle != NULL, return(errret)); \
58 ASSERT(pkg != NULL, return(errret)); \
59 if(pkg->origin != PKG_FROM_FILE && !(pkg->infolevel & info)) { \
60 _alpm_db_read(pkg->origin_data.db, pkg, info); \
61 } \
62 } while(0)
65 /* Cache-specific accessor functions. These implementations allow for lazy
66 * loading by the files backend when a data member is actually needed
67 * rather than loading all pieces of information when the package is first
68 * initialized.
71 const char *_cache_get_filename(pmpkg_t *pkg)
73 LAZY_LOAD(INFRQ_DESC, NULL);
74 return pkg->filename;
77 const char *_cache_get_name(pmpkg_t *pkg)
79 ASSERT(pkg != NULL, return(NULL));
80 return pkg->name;
83 static const char *_cache_get_version(pmpkg_t *pkg)
85 ASSERT(pkg != NULL, return(NULL));
86 return pkg->version;
89 static const char *_cache_get_desc(pmpkg_t *pkg)
91 LAZY_LOAD(INFRQ_DESC, NULL);
92 return pkg->desc;
95 const char *_cache_get_url(pmpkg_t *pkg)
97 LAZY_LOAD(INFRQ_DESC, NULL);
98 return pkg->url;
101 time_t _cache_get_builddate(pmpkg_t *pkg)
103 LAZY_LOAD(INFRQ_DESC, 0);
104 return pkg->builddate;
107 time_t _cache_get_installdate(pmpkg_t *pkg)
109 LAZY_LOAD(INFRQ_DESC, 0);
110 return pkg->installdate;
113 const char *_cache_get_packager(pmpkg_t *pkg)
115 LAZY_LOAD(INFRQ_DESC, NULL);
116 return pkg->packager;
119 const char *_cache_get_md5sum(pmpkg_t *pkg)
121 LAZY_LOAD(INFRQ_DESC, NULL);
122 return pkg->md5sum;
125 const char *_cache_get_arch(pmpkg_t *pkg)
127 LAZY_LOAD(INFRQ_DESC, NULL);
128 return pkg->arch;
131 off_t _cache_get_size(pmpkg_t *pkg)
133 LAZY_LOAD(INFRQ_DESC, -1);
134 return pkg->size;
137 off_t _cache_get_isize(pmpkg_t *pkg)
139 LAZY_LOAD(INFRQ_DESC, -1);
140 return pkg->isize;
143 pmpkgreason_t _cache_get_reason(pmpkg_t *pkg)
145 LAZY_LOAD(INFRQ_DESC, -1);
146 return pkg->reason;
149 alpm_list_t *_cache_get_licenses(pmpkg_t *pkg)
151 LAZY_LOAD(INFRQ_DESC, NULL);
152 return pkg->licenses;
155 alpm_list_t *_cache_get_groups(pmpkg_t *pkg)
157 LAZY_LOAD(INFRQ_DESC, NULL);
158 return pkg->groups;
161 int _cache_has_force(pmpkg_t *pkg)
163 LAZY_LOAD(INFRQ_DESC, -1);
164 return pkg->force;
167 alpm_list_t *_cache_get_depends(pmpkg_t *pkg)
169 LAZY_LOAD(INFRQ_DEPENDS, NULL);
170 return pkg->depends;
173 alpm_list_t *_cache_get_optdepends(pmpkg_t *pkg)
175 LAZY_LOAD(INFRQ_DEPENDS, NULL);
176 return pkg->optdepends;
179 alpm_list_t *_cache_get_conflicts(pmpkg_t *pkg)
181 LAZY_LOAD(INFRQ_DEPENDS, NULL);
182 return pkg->conflicts;
185 alpm_list_t *_cache_get_provides(pmpkg_t *pkg)
187 LAZY_LOAD(INFRQ_DEPENDS, NULL);
188 return pkg->provides;
191 alpm_list_t *_cache_get_replaces(pmpkg_t *pkg)
193 LAZY_LOAD(INFRQ_DESC, NULL);
194 return pkg->replaces;
197 alpm_list_t *_cache_get_deltas(pmpkg_t *pkg)
199 LAZY_LOAD(INFRQ_DELTAS, NULL);
200 return pkg->deltas;
203 alpm_list_t *_cache_get_files(pmpkg_t *pkg)
205 ALPM_LOG_FUNC;
207 /* Sanity checks */
208 ASSERT(handle != NULL, return(NULL));
209 ASSERT(pkg != NULL, return(NULL));
211 if(pkg->origin == PKG_FROM_LOCALDB
212 && !(pkg->infolevel & INFRQ_FILES)) {
213 _alpm_db_read(pkg->origin_data.db, pkg, INFRQ_FILES);
215 return pkg->files;
218 alpm_list_t *_cache_get_backup(pmpkg_t *pkg)
220 ALPM_LOG_FUNC;
222 /* Sanity checks */
223 ASSERT(handle != NULL, return(NULL));
224 ASSERT(pkg != NULL, return(NULL));
226 if(pkg->origin == PKG_FROM_LOCALDB
227 && !(pkg->infolevel & INFRQ_FILES)) {
228 _alpm_db_read(pkg->origin_data.db, pkg, INFRQ_FILES);
230 return pkg->backup;
234 * Open a package changelog for reading. Similar to fopen in functionality,
235 * except that the returned 'file stream' is from the database.
236 * @param pkg the package (from db) to read the changelog
237 * @return a 'file stream' to the package changelog
239 void *_cache_changelog_open(pmpkg_t *pkg)
241 ALPM_LOG_FUNC;
243 /* Sanity checks */
244 ASSERT(handle != NULL, return(NULL));
245 ASSERT(pkg != NULL, return(NULL));
247 char clfile[PATH_MAX];
248 snprintf(clfile, PATH_MAX, "%s/%s/%s-%s/changelog",
249 alpm_option_get_dbpath(),
250 alpm_db_get_name(alpm_pkg_get_db(pkg)),
251 alpm_pkg_get_name(pkg),
252 alpm_pkg_get_version(pkg));
253 return fopen(clfile, "r");
257 * Read data from an open changelog 'file stream'. Similar to fread in
258 * functionality, this function takes a buffer and amount of data to read.
259 * @param ptr a buffer to fill with raw changelog data
260 * @param size the size of the buffer
261 * @param pkg the package that the changelog is being read from
262 * @param fp a 'file stream' to the package changelog
263 * @return the number of characters read, or 0 if there is no more data
265 size_t _cache_changelog_read(void *ptr, size_t size,
266 const pmpkg_t *pkg, const void *fp)
268 return ( fread(ptr, 1, size, (FILE*)fp) );
272 int _cache_changelog_feof(const pmpkg_t *pkg, void *fp)
274 return( feof((FILE*)fp) );
279 * Close a package changelog for reading. Similar to fclose in functionality,
280 * except that the 'file stream' is from the database.
281 * @param pkg the package that the changelog was read from
282 * @param fp a 'file stream' to the package changelog
283 * @return whether closing the package changelog stream was successful
285 int _cache_changelog_close(const pmpkg_t *pkg, void *fp)
287 return( fclose((FILE*)fp) );
290 /** The sync database operations struct. Get package fields through
291 * lazy accessor methods that handle any backend loading and caching
292 * logic.
294 static struct pkg_operations sync_pkg_ops = {
295 .get_filename = _cache_get_filename,
296 .get_name = _cache_get_name,
297 .get_version = _cache_get_version,
298 .get_desc = _cache_get_desc,
299 .get_url = _cache_get_url,
300 .get_builddate = _cache_get_builddate,
301 .get_installdate = _cache_get_installdate,
302 .get_packager = _cache_get_packager,
303 .get_md5sum = _cache_get_md5sum,
304 .get_arch = _cache_get_arch,
305 .get_size = _cache_get_size,
306 .get_isize = _cache_get_isize,
307 .get_reason = _cache_get_reason,
308 .has_force = _cache_has_force,
309 .get_licenses = _cache_get_licenses,
310 .get_groups = _cache_get_groups,
311 .get_depends = _cache_get_depends,
312 .get_optdepends = _cache_get_optdepends,
313 .get_conflicts = _cache_get_conflicts,
314 .get_provides = _cache_get_provides,
315 .get_replaces = _cache_get_replaces,
316 .get_deltas = _cache_get_deltas,
317 .get_files = _cache_get_files,
318 .get_backup = _cache_get_backup,
321 /** The local database operations struct. Get package fields through
322 * lazy accessor methods that handle any backend loading and caching
323 * logic.
325 static struct pkg_operations local_pkg_ops = {
326 .get_filename = _cache_get_filename,
327 .get_name = _cache_get_name,
328 .get_version = _cache_get_version,
329 .get_desc = _cache_get_desc,
330 .get_url = _cache_get_url,
331 .get_builddate = _cache_get_builddate,
332 .get_installdate = _cache_get_installdate,
333 .get_packager = _cache_get_packager,
334 .get_md5sum = _cache_get_md5sum,
335 .get_arch = _cache_get_arch,
336 .get_size = _cache_get_size,
337 .get_isize = _cache_get_isize,
338 .get_reason = _cache_get_reason,
339 .has_force = _cache_has_force,
340 .get_licenses = _cache_get_licenses,
341 .get_groups = _cache_get_groups,
342 .get_depends = _cache_get_depends,
343 .get_optdepends = _cache_get_optdepends,
344 .get_conflicts = _cache_get_conflicts,
345 .get_provides = _cache_get_provides,
346 .get_replaces = _cache_get_replaces,
347 .get_deltas = _cache_get_deltas,
348 .get_files = _cache_get_files,
349 .get_backup = _cache_get_backup,
351 .changelog_open = _cache_changelog_open,
352 .changelog_read = _cache_changelog_read,
353 .changelog_close = _cache_changelog_close,
356 /* Returns a new package cache from db.
357 * It frees the cache if it already exists.
359 int _alpm_db_load_pkgcache(pmdb_t *db)
361 ALPM_LOG_FUNC;
363 if(db == NULL) {
364 return(-1);
366 _alpm_db_free_pkgcache(db);
368 _alpm_log(PM_LOG_DEBUG, "loading package cache for repository '%s'\n",
369 db->treename);
370 if(db->ops->populate(db) == -1) {
371 _alpm_log(PM_LOG_DEBUG,
372 "failed to load package cache for repository '%s'\n", db->treename);
373 return(-1);
376 db->pkgcache_loaded = 1;
377 return(0);
380 void _alpm_db_free_pkgcache(pmdb_t *db)
382 ALPM_LOG_FUNC;
384 if(db == NULL || !db->pkgcache_loaded) {
385 return;
388 _alpm_log(PM_LOG_DEBUG, "freeing package cache for repository '%s'\n",
389 db->treename);
391 alpm_list_free_inner(db->pkgcache, (alpm_list_fn_free)_alpm_pkg_free);
392 alpm_list_free(db->pkgcache);
393 db->pkgcache_loaded = 0;
395 _alpm_db_free_grpcache(db);
398 alpm_list_t *_alpm_db_get_pkgcache(pmdb_t *db)
400 ALPM_LOG_FUNC;
402 if(db == NULL) {
403 return(NULL);
406 if(!db->pkgcache_loaded) {
407 _alpm_db_load_pkgcache(db);
410 /* hmmm, still NULL ?*/
411 if(!db->pkgcache) {
412 _alpm_log(PM_LOG_DEBUG, "warning: pkgcache is NULL for db '%s'\n", db->treename);
415 return(db->pkgcache);
418 /* "duplicate" pkg then add it to pkgcache */
419 int _alpm_db_add_pkgincache(pmdb_t *db, pmpkg_t *pkg)
421 pmpkg_t *newpkg;
423 ALPM_LOG_FUNC;
425 if(db == NULL || !db->pkgcache_loaded || pkg == NULL) {
426 return(-1);
429 newpkg = _alpm_pkg_dup(pkg);
430 if(newpkg == NULL) {
431 return(-1);
434 _alpm_log(PM_LOG_DEBUG, "adding entry '%s' in '%s' cache\n",
435 alpm_pkg_get_name(newpkg), db->treename);
436 db->pkgcache = alpm_list_add_sorted(db->pkgcache, newpkg, _alpm_pkg_cmp);
438 _alpm_db_free_grpcache(db);
440 return(0);
443 int _alpm_db_remove_pkgfromcache(pmdb_t *db, pmpkg_t *pkg)
445 void *vdata;
446 pmpkg_t *data;
448 ALPM_LOG_FUNC;
450 if(db == NULL || !db->pkgcache_loaded || pkg == NULL) {
451 return(-1);
454 _alpm_log(PM_LOG_DEBUG, "removing entry '%s' from '%s' cache\n",
455 alpm_pkg_get_name(pkg), db->treename);
457 db->pkgcache = alpm_list_remove(db->pkgcache, pkg, _alpm_pkg_cmp, &vdata);
458 data = vdata;
459 if(data == NULL) {
460 /* package not found */
461 _alpm_log(PM_LOG_DEBUG, "cannot remove entry '%s' from '%s' cache: not found\n",
462 alpm_pkg_get_name(pkg), db->treename);
463 return(-1);
466 _alpm_pkg_free(data);
468 _alpm_db_free_grpcache(db);
470 return(0);
473 pmpkg_t *_alpm_db_get_pkgfromcache(pmdb_t *db, const char *target)
475 ALPM_LOG_FUNC;
477 if(db == NULL) {
478 return(NULL);
481 alpm_list_t *pkgcache = _alpm_db_get_pkgcache(db);
482 if(!pkgcache) {
483 _alpm_log(PM_LOG_DEBUG, "warning: failed to get '%s' from NULL pkgcache\n",
484 target);
485 return(NULL);
488 return(_alpm_pkg_find(pkgcache, target));
491 /* Returns a new group cache from db.
493 int _alpm_db_load_grpcache(pmdb_t *db)
495 alpm_list_t *lp;
497 ALPM_LOG_FUNC;
499 if(db == NULL) {
500 return(-1);
503 _alpm_log(PM_LOG_DEBUG, "loading group cache for repository '%s'\n",
504 db->treename);
506 for(lp = _alpm_db_get_pkgcache(db); lp; lp = lp->next) {
507 const alpm_list_t *i;
508 pmpkg_t *pkg = lp->data;
510 for(i = alpm_pkg_get_groups(pkg); i; i = i->next) {
511 const char *grpname = i->data;
512 alpm_list_t *j;
513 pmgrp_t *grp = NULL;
514 int found = 0;
516 /* first look through the group cache for a group with this name */
517 for(j = db->grpcache; j; j = j->next) {
518 grp = j->data;
520 if(strcmp(grp->name, grpname) == 0
521 && !alpm_list_find_ptr(grp->packages, pkg)) {
522 grp->packages = alpm_list_add(grp->packages, pkg);
523 found = 1;
524 break;
527 if(found) {
528 continue;
530 /* we didn't find the group, so create a new one with this name */
531 grp = _alpm_grp_new(grpname);
532 grp->packages = alpm_list_add(grp->packages, pkg);
533 db->grpcache = alpm_list_add(db->grpcache, grp);
537 db->grpcache_loaded = 1;
538 return(0);
541 void _alpm_db_free_grpcache(pmdb_t *db)
543 alpm_list_t *lg;
545 ALPM_LOG_FUNC;
547 if(db == NULL || !db->grpcache_loaded) {
548 return;
551 _alpm_log(PM_LOG_DEBUG, "freeing group cache for repository '%s'\n",
552 db->treename);
554 for(lg = db->grpcache; lg; lg = lg->next) {
555 _alpm_grp_free(lg->data);
556 lg->data = NULL;
558 FREELIST(db->grpcache);
559 db->grpcache_loaded = 0;
562 alpm_list_t *_alpm_db_get_grpcache(pmdb_t *db)
564 ALPM_LOG_FUNC;
566 if(db == NULL) {
567 return(NULL);
570 if(!db->grpcache_loaded) {
571 _alpm_db_load_grpcache(db);
574 return(db->grpcache);
577 pmgrp_t *_alpm_db_get_grpfromcache(pmdb_t *db, const char *target)
579 alpm_list_t *i;
581 ALPM_LOG_FUNC;
583 if(db == NULL || target == NULL || strlen(target) == 0) {
584 return(NULL);
587 for(i = _alpm_db_get_grpcache(db); i; i = i->next) {
588 pmgrp_t *info = i->data;
590 if(strcmp(info->name, target) == 0) {
591 return(info);
595 return(NULL);
598 static int checkdbdir(pmdb_t *db)
600 struct stat buf;
601 const char *path = _alpm_db_path(db);
603 if(stat(path, &buf) != 0) {
604 _alpm_log(PM_LOG_DEBUG, "database dir '%s' does not exist, creating it\n",
605 path);
606 if(_alpm_makepath(path) != 0) {
607 RET_ERR(PM_ERR_SYSTEM, -1);
609 } else if(!S_ISDIR(buf.st_mode)) {
610 _alpm_log(PM_LOG_WARNING, _("removing invalid database: %s\n"), path);
611 if(unlink(path) != 0 || _alpm_makepath(path) != 0) {
612 RET_ERR(PM_ERR_SYSTEM, -1);
615 return(0);
618 /* create list of directories in db */
619 static int dirlist_from_tar(const char *archive, alpm_list_t **dirlist)
621 struct archive *_archive;
622 struct archive_entry *entry;
624 if((_archive = archive_read_new()) == NULL)
625 RET_ERR(PM_ERR_LIBARCHIVE, -1);
627 archive_read_support_compression_all(_archive);
628 archive_read_support_format_all(_archive);
630 if(archive_read_open_filename(_archive, archive,
631 ARCHIVE_DEFAULT_BYTES_PER_BLOCK) != ARCHIVE_OK) {
632 _alpm_log(PM_LOG_ERROR, _("could not open %s: %s\n"), archive,
633 archive_error_string(_archive));
634 RET_ERR(PM_ERR_PKG_OPEN, -1);
637 while(archive_read_next_header(_archive, &entry) == ARCHIVE_OK) {
638 const struct stat *st;
639 const char *entryname; /* the name of the file in the archive */
641 st = archive_entry_stat(entry);
642 entryname = archive_entry_pathname(entry);
644 if(S_ISDIR(st->st_mode)) {
645 char *name = strdup(entryname);
646 *dirlist = alpm_list_add(*dirlist, name);
649 archive_read_finish(_archive);
651 *dirlist = alpm_list_msort(*dirlist, alpm_list_count(*dirlist), _alpm_str_cmp);
652 return(0);
655 static int is_dir(const char *path, struct dirent *entry)
657 #ifdef DT_DIR
658 return(entry->d_type == DT_DIR);
659 #else
660 char buffer[PATH_MAX];
661 snprintf(buffer, PATH_MAX, "%s/%s", path, entry->d_name);
663 struct stat sbuf;
664 if (!stat(buffer, &sbuf)) {
665 return(S_ISDIR(sbuf.st_mode));
668 return(0);
669 #endif
672 /* create list of directories in db */
673 static int dirlist_from_fs(const char *syncdbpath, alpm_list_t **dirlist)
675 DIR *dbdir;
676 struct dirent *ent = NULL;
678 dbdir = opendir(syncdbpath);
679 if (dbdir != NULL) {
680 while((ent = readdir(dbdir)) != NULL) {
681 char *name = ent->d_name;
682 size_t len;
683 char *entry;
685 if(strcmp(name, ".") == 0 || strcmp(name, "..") == 0) {
686 continue;
689 if(!is_dir(syncdbpath, ent)) {
690 continue;
693 len = strlen(name);
694 MALLOC(entry, len + 2, RET_ERR(PM_ERR_MEMORY, -1));
695 strcpy(entry, name);
696 entry[len] = '/';
697 entry[len+1] = '\0';
698 *dirlist = alpm_list_add(*dirlist, entry);
700 closedir(dbdir);
703 *dirlist = alpm_list_msort(*dirlist, alpm_list_count(*dirlist), _alpm_str_cmp);
704 return(0);
707 /* remove old directories from dbdir */
708 static int remove_olddir(const char *syncdbpath, alpm_list_t *dirlist)
710 alpm_list_t *i;
711 for (i = dirlist; i; i = i->next) {
712 const char *name = i->data;
713 char *dbdir;
714 size_t len = strlen(syncdbpath) + strlen(name) + 2;
715 MALLOC(dbdir, len, RET_ERR(PM_ERR_MEMORY, -1));
716 snprintf(dbdir, len, "%s%s", syncdbpath, name);
717 _alpm_log(PM_LOG_DEBUG, "removing: %s\n", dbdir);
718 if(_alpm_rmrf(dbdir) != 0) {
719 _alpm_log(PM_LOG_ERROR, _("could not remove database directory %s\n"), dbdir);
720 free(dbdir);
721 RET_ERR(PM_ERR_DB_REMOVE, -1);
723 free(dbdir);
725 return(0);
728 /** Update a package database
730 * An update of the package database \a db will be attempted. Unless
731 * \a force is true, the update will only be performed if the remote
732 * database was modified since the last update.
734 * A transaction is necessary for this operation, in order to obtain a
735 * database lock. During this transaction the front-end will be informed
736 * of the download progress of the database via the download callback.
738 * Example:
739 * @code
740 * pmdb_t *db;
741 * int result;
742 * db = alpm_list_getdata(alpm_option_get_syncdbs());
743 * if(alpm_trans_init(0, NULL, NULL, NULL) == 0) {
744 * result = alpm_db_update(0, db);
745 * alpm_trans_release();
747 * if(result > 0) {
748 * printf("Unable to update database: %s\n", alpm_strerrorlast());
749 * } else if(result < 0) {
750 * printf("Database already up to date\n");
751 * } else {
752 * printf("Database updated\n");
755 * @endcode
757 * @ingroup alpm_databases
758 * @note After a successful update, the \link alpm_db_get_pkgcache()
759 * package cache \endlink will be invalidated
760 * @param force if true, then forces the update, otherwise update only in case
761 * the database isn't up to date
762 * @param db pointer to the package database to update
763 * @return 0 on success, > 0 on error (pm_errno is set accordingly), < 0 if up
764 * to date
766 int SYMEXPORT alpm_db_update(int force, pmdb_t *db)
768 char *dbfile, *dbfilepath, *syncpath;
769 const char *dbpath, *syncdbpath;
770 alpm_list_t *newdirlist = NULL, *olddirlist = NULL;
771 alpm_list_t *onlynew = NULL, *onlyold = NULL;
772 size_t len;
773 int ret;
775 ALPM_LOG_FUNC;
777 /* Sanity checks */
778 ASSERT(handle != NULL, RET_ERR(PM_ERR_HANDLE_NULL, -1));
779 ASSERT(db != NULL && db != handle->db_local, RET_ERR(PM_ERR_WRONG_ARGS, -1));
780 /* Verify we are in a transaction. This is done _mainly_ because we need a DB
781 * lock - if we update without a db lock, we may kludge some other pacman
782 * process that _has_ a lock.
784 ASSERT(handle->trans != NULL, RET_ERR(PM_ERR_TRANS_NULL, -1));
785 ASSERT(handle->trans->state == STATE_INITIALIZED, RET_ERR(PM_ERR_TRANS_NOT_INITIALIZED, -1));
787 if(!alpm_list_find_ptr(handle->dbs_sync, db)) {
788 RET_ERR(PM_ERR_DB_NOT_FOUND, -1);
791 len = strlen(db->treename) + 4;
792 MALLOC(dbfile, len, RET_ERR(PM_ERR_MEMORY, -1));
793 sprintf(dbfile, "%s.db", db->treename);
795 dbpath = alpm_option_get_dbpath();
796 len = strlen(dbpath) + 6;
797 MALLOC(syncpath, len, RET_ERR(PM_ERR_MEMORY, -1));
798 sprintf(syncpath, "%s%s", dbpath, "sync/");
800 ret = _alpm_download_single_file(dbfile, db->servers, syncpath, force);
801 free(dbfile);
802 free(syncpath);
804 if(ret == 1) {
805 /* files match, do nothing */
806 pm_errno = 0;
807 return(1);
808 } else if(ret == -1) {
809 /* pm_errno was set by the download code */
810 _alpm_log(PM_LOG_DEBUG, "failed to sync db: %s\n", alpm_strerrorlast());
811 return(-1);
814 syncdbpath = _alpm_db_path(db);
816 /* form the path to the db location */
817 len = strlen(dbpath) + strlen(db->treename) + 9;
818 MALLOC(dbfilepath, len, RET_ERR(PM_ERR_MEMORY, -1));
819 sprintf(dbfilepath, "%ssync/%s.db", dbpath, db->treename);
821 if(force) {
822 /* if forcing update, remove the old dir and extract the db */
823 if(_alpm_rmrf(syncdbpath) != 0) {
824 _alpm_log(PM_LOG_ERROR, _("could not remove database %s\n"), db->treename);
825 RET_ERR(PM_ERR_DB_REMOVE, -1);
826 } else {
827 _alpm_log(PM_LOG_DEBUG, "database dir %s removed\n", _alpm_db_path(db));
829 } else {
830 /* if not forcing, only remove and extract what is necessary */
831 ret = dirlist_from_tar(dbfilepath, &newdirlist);
832 if(ret) {
833 goto cleanup;
835 ret = dirlist_from_fs(syncdbpath, &olddirlist);
836 if(ret) {
837 goto cleanup;
840 alpm_list_diff_sorted(olddirlist, newdirlist, _alpm_str_cmp, &onlyold, &onlynew);
842 ret = remove_olddir(syncdbpath, onlyold);
843 if(ret) {
844 goto cleanup;
848 /* Cache needs to be rebuilt */
849 _alpm_db_free_pkgcache(db);
851 checkdbdir(db);
852 ret = _alpm_unpack(dbfilepath, syncdbpath, onlynew, 0);
854 cleanup:
855 FREELIST(newdirlist);
856 FREELIST(olddirlist);
857 alpm_list_free(onlynew);
858 alpm_list_free(onlyold);
860 free(dbfilepath);
862 if(ret) {
863 RET_ERR(PM_ERR_SYSTEM, -1);
866 return(0);
870 static int splitname(const char *target, pmpkg_t *pkg)
872 /* the format of a db entry is as follows:
873 * package-version-rel/
874 * package name can contain hyphens, so parse from the back- go back
875 * two hyphens and we have split the version from the name.
877 char *tmp, *p, *q;
879 if(target == NULL || pkg == NULL) {
880 return(-1);
882 STRDUP(tmp, target, RET_ERR(PM_ERR_MEMORY, -1));
883 p = tmp + strlen(tmp);
885 /* do the magic parsing- find the beginning of the version string
886 * by doing two iterations of same loop to lop off two hyphens */
887 for(q = --p; *q && *q != '-'; q--);
888 for(p = --q; *p && *p != '-'; p--);
889 if(*p != '-' || p == tmp) {
890 return(-1);
893 /* copy into fields and return */
894 if(pkg->version) {
895 FREE(pkg->version);
897 STRDUP(pkg->version, p+1, RET_ERR(PM_ERR_MEMORY, -1));
898 /* insert a terminator at the end of the name (on hyphen)- then copy it */
899 *p = '\0';
900 if(pkg->name) {
901 FREE(pkg->name);
903 STRDUP(pkg->name, tmp, RET_ERR(PM_ERR_MEMORY, -1));
905 free(tmp);
906 return(0);
909 int _alpm_db_populate(pmdb_t *db)
911 int count = 0;
912 struct dirent *ent = NULL;
913 const char *dbpath;
914 DIR *dbdir;
916 ALPM_LOG_FUNC;
918 ASSERT(db != NULL, RET_ERR(PM_ERR_DB_NULL, -1));
920 dbpath = _alpm_db_path(db);
921 dbdir = opendir(dbpath);
922 if(dbdir == NULL) {
923 return(0);
925 while((ent = readdir(dbdir)) != NULL) {
926 const char *name = ent->d_name;
927 pmpkg_t *pkg;
929 if(strcmp(name, ".") == 0 || strcmp(name, "..") == 0) {
930 continue;
932 if(!is_dir(dbpath, ent)) {
933 continue;
936 pkg = _alpm_pkg_new();
937 if(pkg == NULL) {
938 closedir(dbdir);
939 return(-1);
941 /* split the db entry name */
942 if(splitname(name, pkg) != 0) {
943 _alpm_log(PM_LOG_ERROR, _("invalid name for database entry '%s'\n"),
944 name);
945 _alpm_pkg_free(pkg);
946 continue;
949 /* duplicated database entries are not allowed */
950 if(_alpm_pkg_find(db->pkgcache, pkg->name)) {
951 _alpm_log(PM_LOG_ERROR, _("duplicated database entry '%s'\n"), pkg->name);
952 _alpm_pkg_free(pkg);
953 continue;
956 /* explicitly read with only 'BASE' data, accessors will handle the rest */
957 if(_alpm_db_read(db, pkg, INFRQ_BASE) == -1) {
958 _alpm_log(PM_LOG_ERROR, _("corrupted database entry '%s'\n"), name);
959 _alpm_pkg_free(pkg);
960 continue;
962 if(db == handle->db_local) {
963 pkg->origin = PKG_FROM_LOCALDB;
964 pkg->ops = &local_pkg_ops;
965 } else {
966 pkg->origin = PKG_FROM_SYNCDB;
967 pkg->ops = &sync_pkg_ops;
969 pkg->origin_data.db = db;
970 /* add to the collection */
971 _alpm_log(PM_LOG_FUNCTION, "adding '%s' to package cache for db '%s'\n",
972 pkg->name, db->treename);
973 db->pkgcache = alpm_list_add(db->pkgcache, pkg);
974 count++;
977 closedir(dbdir);
978 db->pkgcache = alpm_list_msort(db->pkgcache, count, _alpm_pkg_cmp);
979 return(count);
982 /* Note: the return value must be freed by the caller */
983 static char *get_pkgpath(pmdb_t *db, pmpkg_t *info)
985 size_t len;
986 char *pkgpath;
987 const char *dbpath;
989 dbpath = _alpm_db_path(db);
990 len = strlen(dbpath) + strlen(info->name) + strlen(info->version) + 3;
991 MALLOC(pkgpath, len, RET_ERR(PM_ERR_MEMORY, NULL));
992 sprintf(pkgpath, "%s%s-%s/", dbpath, info->name, info->version);
993 return(pkgpath);
996 int _alpm_db_read(pmdb_t *db, pmpkg_t *info, pmdbinfrq_t inforeq)
998 FILE *fp = NULL;
999 char path[PATH_MAX];
1000 char line[1024];
1001 char *pkgpath = NULL;
1003 ALPM_LOG_FUNC;
1005 if(db == NULL) {
1006 RET_ERR(PM_ERR_DB_NULL, -1);
1009 if(info == NULL || info->name == NULL || info->version == NULL) {
1010 _alpm_log(PM_LOG_DEBUG, "invalid package entry provided to _alpm_db_read, skipping\n");
1011 return(-1);
1014 if(info->origin == PKG_FROM_FILE) {
1015 _alpm_log(PM_LOG_DEBUG, "request to read database info for a file-based package '%s', skipping...\n", info->name);
1016 return(-1);
1019 /* bitmask logic here:
1020 * infolevel: 00001111
1021 * inforeq: 00010100
1022 * & result: 00000100
1023 * == to inforeq? nope, we need to load more info. */
1024 if((info->infolevel & inforeq) == inforeq) {
1025 /* already loaded this info, do nothing */
1026 return(0);
1028 _alpm_log(PM_LOG_FUNCTION, "loading package data for %s : level=0x%x\n",
1029 info->name, inforeq);
1031 /* clear out 'line', to be certain - and to make valgrind happy */
1032 memset(line, 0, sizeof(line));
1034 pkgpath = get_pkgpath(db, info);
1036 if(access(pkgpath, F_OK)) {
1037 /* directory doesn't exist or can't be opened */
1038 _alpm_log(PM_LOG_DEBUG, "cannot find '%s-%s' in db '%s'\n",
1039 info->name, info->version, db->treename);
1040 goto error;
1043 /* DESC */
1044 if(inforeq & INFRQ_DESC) {
1045 snprintf(path, PATH_MAX, "%sdesc", pkgpath);
1046 if((fp = fopen(path, "r")) == NULL) {
1047 _alpm_log(PM_LOG_ERROR, _("could not open file %s: %s\n"), path, strerror(errno));
1048 goto error;
1050 while(!feof(fp)) {
1051 if(fgets(line, sizeof(line), fp) == NULL) {
1052 break;
1054 _alpm_strtrim(line);
1055 if(strcmp(line, "%NAME%") == 0) {
1056 if(fgets(line, sizeof(line), fp) == NULL) {
1057 goto error;
1059 if(strcmp(_alpm_strtrim(line), info->name) != 0) {
1060 _alpm_log(PM_LOG_ERROR, _("%s database is inconsistent: name "
1061 "mismatch on package %s\n"), db->treename, info->name);
1063 } else if(strcmp(line, "%VERSION%") == 0) {
1064 if(fgets(line, sizeof(line), fp) == NULL) {
1065 goto error;
1067 if(strcmp(_alpm_strtrim(line), info->version) != 0) {
1068 _alpm_log(PM_LOG_ERROR, _("%s database is inconsistent: version "
1069 "mismatch on package %s\n"), db->treename, info->name);
1071 } else if(strcmp(line, "%FILENAME%") == 0) {
1072 if(fgets(line, sizeof(line), fp) == NULL) {
1073 goto error;
1075 STRDUP(info->filename, _alpm_strtrim(line), goto error);
1076 } else if(strcmp(line, "%DESC%") == 0) {
1077 if(fgets(line, sizeof(line), fp) == NULL) {
1078 goto error;
1080 STRDUP(info->desc, _alpm_strtrim(line), goto error);
1081 } else if(strcmp(line, "%GROUPS%") == 0) {
1082 while(fgets(line, sizeof(line), fp) && strlen(_alpm_strtrim(line))) {
1083 char *linedup;
1084 STRDUP(linedup, _alpm_strtrim(line), goto error);
1085 info->groups = alpm_list_add(info->groups, linedup);
1087 } else if(strcmp(line, "%URL%") == 0) {
1088 if(fgets(line, sizeof(line), fp) == NULL) {
1089 goto error;
1091 STRDUP(info->url, _alpm_strtrim(line), goto error);
1092 } else if(strcmp(line, "%LICENSE%") == 0) {
1093 while(fgets(line, sizeof(line), fp) && strlen(_alpm_strtrim(line))) {
1094 char *linedup;
1095 STRDUP(linedup, _alpm_strtrim(line), goto error);
1096 info->licenses = alpm_list_add(info->licenses, linedup);
1098 } else if(strcmp(line, "%ARCH%") == 0) {
1099 if(fgets(line, sizeof(line), fp) == NULL) {
1100 goto error;
1102 STRDUP(info->arch, _alpm_strtrim(line), goto error);
1103 } else if(strcmp(line, "%BUILDDATE%") == 0) {
1104 if(fgets(line, sizeof(line), fp) == NULL) {
1105 goto error;
1107 _alpm_strtrim(line);
1109 char first = tolower((unsigned char)line[0]);
1110 if(first > 'a' && first < 'z') {
1111 struct tm tmp_tm = {0}; /* initialize to null in case of failure */
1112 setlocale(LC_TIME, "C");
1113 strptime(line, "%a %b %e %H:%M:%S %Y", &tmp_tm);
1114 info->builddate = mktime(&tmp_tm);
1115 setlocale(LC_TIME, "");
1116 } else {
1117 info->builddate = atol(line);
1119 } else if(strcmp(line, "%INSTALLDATE%") == 0) {
1120 if(fgets(line, sizeof(line), fp) == NULL) {
1121 goto error;
1123 _alpm_strtrim(line);
1125 char first = tolower((unsigned char)line[0]);
1126 if(first > 'a' && first < 'z') {
1127 struct tm tmp_tm = {0}; /* initialize to null in case of failure */
1128 setlocale(LC_TIME, "C");
1129 strptime(line, "%a %b %e %H:%M:%S %Y", &tmp_tm);
1130 info->installdate = mktime(&tmp_tm);
1131 setlocale(LC_TIME, "");
1132 } else {
1133 info->installdate = atol(line);
1135 } else if(strcmp(line, "%PACKAGER%") == 0) {
1136 if(fgets(line, sizeof(line), fp) == NULL) {
1137 goto error;
1139 STRDUP(info->packager, _alpm_strtrim(line), goto error);
1140 } else if(strcmp(line, "%REASON%") == 0) {
1141 if(fgets(line, sizeof(line), fp) == NULL) {
1142 goto error;
1144 info->reason = (pmpkgreason_t)atol(_alpm_strtrim(line));
1145 } else if(strcmp(line, "%SIZE%") == 0 || strcmp(line, "%CSIZE%") == 0) {
1146 /* NOTE: the CSIZE and SIZE fields both share the "size" field
1147 * in the pkginfo_t struct. This can be done b/c CSIZE
1148 * is currently only used in sync databases, and SIZE is
1149 * only used in local databases.
1151 if(fgets(line, sizeof(line), fp) == NULL) {
1152 goto error;
1154 info->size = atol(_alpm_strtrim(line));
1155 /* also store this value to isize if isize is unset */
1156 if(info->isize == 0) {
1157 info->isize = info->size;
1159 } else if(strcmp(line, "%ISIZE%") == 0) {
1160 /* ISIZE (installed size) tag only appears in sync repositories,
1161 * not the local one. */
1162 if(fgets(line, sizeof(line), fp) == NULL) {
1163 goto error;
1165 info->isize = atol(_alpm_strtrim(line));
1166 } else if(strcmp(line, "%MD5SUM%") == 0) {
1167 /* MD5SUM tag only appears in sync repositories,
1168 * not the local one. */
1169 if(fgets(line, sizeof(line), fp) == NULL) {
1170 goto error;
1172 STRDUP(info->md5sum, _alpm_strtrim(line), goto error);
1173 } else if(strcmp(line, "%REPLACES%") == 0) {
1174 while(fgets(line, sizeof(line), fp) && strlen(_alpm_strtrim(line))) {
1175 char *linedup;
1176 STRDUP(linedup, _alpm_strtrim(line), goto error);
1177 info->replaces = alpm_list_add(info->replaces, linedup);
1179 } else if(strcmp(line, "%FORCE%") == 0) {
1180 info->force = 1;
1183 fclose(fp);
1184 fp = NULL;
1187 /* FILES */
1188 if(inforeq & INFRQ_FILES) {
1189 snprintf(path, PATH_MAX, "%sfiles", pkgpath);
1190 if((fp = fopen(path, "r")) == NULL) {
1191 _alpm_log(PM_LOG_ERROR, _("could not open file %s: %s\n"), path, strerror(errno));
1192 goto error;
1194 while(fgets(line, sizeof(line), fp)) {
1195 _alpm_strtrim(line);
1196 if(strcmp(line, "%FILES%") == 0) {
1197 while(fgets(line, sizeof(line), fp) && strlen(_alpm_strtrim(line))) {
1198 char *linedup;
1199 STRDUP(linedup, _alpm_strtrim(line), goto error);
1200 info->files = alpm_list_add(info->files, linedup);
1202 } else if(strcmp(line, "%BACKUP%") == 0) {
1203 while(fgets(line, sizeof(line), fp) && strlen(_alpm_strtrim(line))) {
1204 char *linedup;
1205 STRDUP(linedup, _alpm_strtrim(line), goto error);
1206 info->backup = alpm_list_add(info->backup, linedup);
1210 fclose(fp);
1211 fp = NULL;
1214 /* DEPENDS */
1215 if(inforeq & INFRQ_DEPENDS) {
1216 snprintf(path, PATH_MAX, "%sdepends", pkgpath);
1217 if((fp = fopen(path, "r")) == NULL) {
1218 _alpm_log(PM_LOG_ERROR, _("could not open file %s: %s\n"), path, strerror(errno));
1219 goto error;
1221 while(!feof(fp)) {
1222 if(fgets(line, sizeof(line), fp) == NULL) {
1223 break;
1225 _alpm_strtrim(line);
1226 if(strcmp(line, "%DEPENDS%") == 0) {
1227 while(fgets(line, sizeof(line), fp) && strlen(_alpm_strtrim(line))) {
1228 pmdepend_t *dep = _alpm_splitdep(_alpm_strtrim(line));
1229 info->depends = alpm_list_add(info->depends, dep);
1231 } else if(strcmp(line, "%OPTDEPENDS%") == 0) {
1232 while(fgets(line, sizeof(line), fp) && strlen(_alpm_strtrim(line))) {
1233 char *linedup;
1234 STRDUP(linedup, _alpm_strtrim(line), goto error);
1235 info->optdepends = alpm_list_add(info->optdepends, linedup);
1237 } else if(strcmp(line, "%CONFLICTS%") == 0) {
1238 while(fgets(line, sizeof(line), fp) && strlen(_alpm_strtrim(line))) {
1239 char *linedup;
1240 STRDUP(linedup, _alpm_strtrim(line), goto error);
1241 info->conflicts = alpm_list_add(info->conflicts, linedup);
1243 } else if(strcmp(line, "%PROVIDES%") == 0) {
1244 while(fgets(line, sizeof(line), fp) && strlen(_alpm_strtrim(line))) {
1245 char *linedup;
1246 STRDUP(linedup, _alpm_strtrim(line), goto error);
1247 info->provides = alpm_list_add(info->provides, linedup);
1251 fclose(fp);
1252 fp = NULL;
1255 /* DELTAS */
1256 if(inforeq & INFRQ_DELTAS) {
1257 snprintf(path, PATH_MAX, "%sdeltas", pkgpath);
1258 if((fp = fopen(path, "r"))) {
1259 while(!feof(fp)) {
1260 if(fgets(line, sizeof(line), fp) == NULL) {
1261 break;
1263 _alpm_strtrim(line);
1264 if(strcmp(line, "%DELTAS%") == 0) {
1265 while(fgets(line, sizeof(line), fp) && strlen(_alpm_strtrim(line))) {
1266 pmdelta_t *delta = _alpm_delta_parse(line);
1267 if(delta) {
1268 info->deltas = alpm_list_add(info->deltas, delta);
1273 fclose(fp);
1274 fp = NULL;
1278 /* INSTALL */
1279 if(inforeq & INFRQ_SCRIPTLET) {
1280 snprintf(path, PATH_MAX, "%sinstall", pkgpath);
1281 if(access(path, F_OK) == 0) {
1282 info->scriptlet = 1;
1286 /* internal */
1287 info->infolevel |= inforeq;
1289 free(pkgpath);
1290 return(0);
1292 error:
1293 free(pkgpath);
1294 if(fp) {
1295 fclose(fp);
1297 return(-1);
1300 int _alpm_db_prepare(pmdb_t *db, pmpkg_t *info)
1302 mode_t oldmask;
1303 int retval = 0;
1304 char *pkgpath = NULL;
1306 if(checkdbdir(db) != 0) {
1307 return(-1);
1310 oldmask = umask(0000);
1311 pkgpath = get_pkgpath(db, info);
1313 if((retval = mkdir(pkgpath, 0755)) != 0) {
1314 _alpm_log(PM_LOG_ERROR, _("could not create directory %s: %s\n"),
1315 pkgpath, strerror(errno));
1318 free(pkgpath);
1319 umask(oldmask);
1321 return(retval);
1324 int _alpm_db_write(pmdb_t *db, pmpkg_t *info, pmdbinfrq_t inforeq)
1326 FILE *fp = NULL;
1327 char path[PATH_MAX];
1328 mode_t oldmask;
1329 alpm_list_t *lp = NULL;
1330 int retval = 0;
1331 int local = 0;
1332 char *pkgpath = NULL;
1334 ALPM_LOG_FUNC;
1336 if(db == NULL || info == NULL) {
1337 return(-1);
1340 pkgpath = get_pkgpath(db, info);
1342 /* make sure we have a sane umask */
1343 oldmask = umask(0022);
1345 if(strcmp(db->treename, "local") == 0) {
1346 local = 1;
1349 /* DESC */
1350 if(inforeq & INFRQ_DESC) {
1351 _alpm_log(PM_LOG_DEBUG, "writing %s-%s DESC information back to db\n",
1352 info->name, info->version);
1353 snprintf(path, PATH_MAX, "%sdesc", pkgpath);
1354 if((fp = fopen(path, "w")) == NULL) {
1355 _alpm_log(PM_LOG_ERROR, _("could not open file %s: %s\n"), path, strerror(errno));
1356 retval = -1;
1357 goto cleanup;
1359 fprintf(fp, "%%NAME%%\n%s\n\n"
1360 "%%VERSION%%\n%s\n\n", info->name, info->version);
1361 if(info->desc) {
1362 fprintf(fp, "%%DESC%%\n"
1363 "%s\n\n", info->desc);
1365 if(info->groups) {
1366 fputs("%GROUPS%\n", fp);
1367 for(lp = info->groups; lp; lp = lp->next) {
1368 fprintf(fp, "%s\n", (char *)lp->data);
1370 fprintf(fp, "\n");
1372 if(info->replaces) {
1373 fputs("%REPLACES%\n", fp);
1374 for(lp = info->replaces; lp; lp = lp->next) {
1375 fprintf(fp, "%s\n", (char *)lp->data);
1377 fprintf(fp, "\n");
1379 if(info->force) {
1380 fprintf(fp, "%%FORCE%%\n\n");
1382 if(local) {
1383 if(info->url) {
1384 fprintf(fp, "%%URL%%\n"
1385 "%s\n\n", info->url);
1387 if(info->licenses) {
1388 fputs("%LICENSE%\n", fp);
1389 for(lp = info->licenses; lp; lp = lp->next) {
1390 fprintf(fp, "%s\n", (char *)lp->data);
1392 fprintf(fp, "\n");
1394 if(info->arch) {
1395 fprintf(fp, "%%ARCH%%\n"
1396 "%s\n\n", info->arch);
1398 if(info->builddate) {
1399 fprintf(fp, "%%BUILDDATE%%\n"
1400 "%ld\n\n", info->builddate);
1402 if(info->installdate) {
1403 fprintf(fp, "%%INSTALLDATE%%\n"
1404 "%ld\n\n", info->installdate);
1406 if(info->packager) {
1407 fprintf(fp, "%%PACKAGER%%\n"
1408 "%s\n\n", info->packager);
1410 if(info->isize) {
1411 /* only write installed size, csize is irrelevant once installed */
1412 fprintf(fp, "%%SIZE%%\n"
1413 "%jd\n\n", (intmax_t)info->isize);
1415 if(info->reason) {
1416 fprintf(fp, "%%REASON%%\n"
1417 "%u\n\n", info->reason);
1419 } else {
1420 if(info->size) {
1421 fprintf(fp, "%%CSIZE%%\n"
1422 "%jd\n\n", (intmax_t)info->size);
1424 if(info->isize) {
1425 fprintf(fp, "%%ISIZE%%\n"
1426 "%jd\n\n", (intmax_t)info->isize);
1428 if(info->md5sum) {
1429 fprintf(fp, "%%MD5SUM%%\n"
1430 "%s\n\n", info->md5sum);
1433 fclose(fp);
1434 fp = NULL;
1437 /* FILES */
1438 if(local && (inforeq & INFRQ_FILES)) {
1439 _alpm_log(PM_LOG_DEBUG, "writing %s-%s FILES information back to db\n",
1440 info->name, info->version);
1441 snprintf(path, PATH_MAX, "%sfiles", pkgpath);
1442 if((fp = fopen(path, "w")) == NULL) {
1443 _alpm_log(PM_LOG_ERROR, _("could not open file %s: %s\n"), path, strerror(errno));
1444 retval = -1;
1445 goto cleanup;
1447 if(info->files) {
1448 fprintf(fp, "%%FILES%%\n");
1449 for(lp = info->files; lp; lp = lp->next) {
1450 fprintf(fp, "%s\n", (char *)lp->data);
1452 fprintf(fp, "\n");
1454 if(info->backup) {
1455 fprintf(fp, "%%BACKUP%%\n");
1456 for(lp = info->backup; lp; lp = lp->next) {
1457 fprintf(fp, "%s\n", (char *)lp->data);
1459 fprintf(fp, "\n");
1461 fclose(fp);
1462 fp = NULL;
1465 /* DEPENDS */
1466 if(inforeq & INFRQ_DEPENDS) {
1467 _alpm_log(PM_LOG_DEBUG, "writing %s-%s DEPENDS information back to db\n",
1468 info->name, info->version);
1469 snprintf(path, PATH_MAX, "%sdepends", pkgpath);
1470 if((fp = fopen(path, "w")) == NULL) {
1471 _alpm_log(PM_LOG_ERROR, _("could not open file %s: %s\n"), path, strerror(errno));
1472 retval = -1;
1473 goto cleanup;
1475 if(info->depends) {
1476 fputs("%DEPENDS%\n", fp);
1477 for(lp = info->depends; lp; lp = lp->next) {
1478 char *depstring = alpm_dep_compute_string(lp->data);
1479 fprintf(fp, "%s\n", depstring);
1480 free(depstring);
1482 fprintf(fp, "\n");
1484 if(info->optdepends) {
1485 fputs("%OPTDEPENDS%\n", fp);
1486 for(lp = info->optdepends; lp; lp = lp->next) {
1487 fprintf(fp, "%s\n", (char *)lp->data);
1489 fprintf(fp, "\n");
1491 if(info->conflicts) {
1492 fputs("%CONFLICTS%\n", fp);
1493 for(lp = info->conflicts; lp; lp = lp->next) {
1494 fprintf(fp, "%s\n", (char *)lp->data);
1496 fprintf(fp, "\n");
1498 if(info->provides) {
1499 fputs("%PROVIDES%\n", fp);
1500 for(lp = info->provides; lp; lp = lp->next) {
1501 fprintf(fp, "%s\n", (char *)lp->data);
1503 fprintf(fp, "\n");
1505 fclose(fp);
1506 fp = NULL;
1509 /* INSTALL */
1510 /* nothing needed here (script is automatically extracted) */
1512 cleanup:
1513 umask(oldmask);
1514 free(pkgpath);
1516 if(fp) {
1517 fclose(fp);
1520 return(retval);
1523 int _alpm_db_remove(pmdb_t *db, pmpkg_t *info)
1525 int ret = 0;
1526 char *pkgpath = NULL;
1528 ALPM_LOG_FUNC;
1530 if(db == NULL || info == NULL) {
1531 RET_ERR(PM_ERR_DB_NULL, -1);
1534 pkgpath = get_pkgpath(db, info);
1536 ret = _alpm_rmrf(pkgpath);
1537 free(pkgpath);
1538 if(ret != 0) {
1539 ret = -1;
1541 return(ret);
1544 /* vim: set ts=2 sw=2 noet: */