libalpm
Arch Linux Package Manager Library
|
00001 /* 00002 * be_local.c : backend for the local database 00003 * 00004 * Copyright (c) 2006-2011 Pacman Development Team <pacman-dev@archlinux.org> 00005 * Copyright (c) 2002-2006 by Judd Vinet <jvinet@zeroflux.org> 00006 * 00007 * This program is free software; you can redistribute it and/or modify 00008 * it under the terms of the GNU General Public License as published by 00009 * the Free Software Foundation; either version 2 of the License, or 00010 * (at your option) any later version. 00011 * 00012 * This program is distributed in the hope that it will be useful, 00013 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00014 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00015 * GNU General Public License for more details. 00016 * 00017 * You should have received a copy of the GNU General Public License 00018 * along with this program. If not, see <http://www.gnu.org/licenses/>. 00019 */ 00020 00021 #include <unistd.h> 00022 #include <stdio.h> 00023 #include <stdlib.h> 00024 #include <errno.h> 00025 #include <string.h> 00026 #include <stdint.h> /* intmax_t */ 00027 #include <sys/stat.h> 00028 #include <dirent.h> 00029 #include <limits.h> /* PATH_MAX */ 00030 00031 /* libalpm */ 00032 #include "db.h" 00033 #include "alpm_list.h" 00034 #include "log.h" 00035 #include "util.h" 00036 #include "alpm.h" 00037 #include "handle.h" 00038 #include "package.h" 00039 #include "deps.h" 00040 00041 static int local_db_read(alpm_pkg_t *info, alpm_dbinfrq_t inforeq); 00042 00043 #define LAZY_LOAD(info, errret) \ 00044 do { \ 00045 if(!(pkg->infolevel & info)) { \ 00046 local_db_read(pkg, info); \ 00047 } \ 00048 } while(0) 00049 00050 00051 /* Cache-specific accessor functions. These implementations allow for lazy 00052 * loading by the files backend when a data member is actually needed 00053 * rather than loading all pieces of information when the package is first 00054 * initialized. 00055 */ 00056 00057 static const char *_cache_get_desc(alpm_pkg_t *pkg) 00058 { 00059 LAZY_LOAD(INFRQ_DESC, NULL); 00060 return pkg->desc; 00061 } 00062 00063 static const char *_cache_get_url(alpm_pkg_t *pkg) 00064 { 00065 LAZY_LOAD(INFRQ_DESC, NULL); 00066 return pkg->url; 00067 } 00068 00069 static alpm_time_t _cache_get_builddate(alpm_pkg_t *pkg) 00070 { 00071 LAZY_LOAD(INFRQ_DESC, 0); 00072 return pkg->builddate; 00073 } 00074 00075 static alpm_time_t _cache_get_installdate(alpm_pkg_t *pkg) 00076 { 00077 LAZY_LOAD(INFRQ_DESC, 0); 00078 return pkg->installdate; 00079 } 00080 00081 static const char *_cache_get_packager(alpm_pkg_t *pkg) 00082 { 00083 LAZY_LOAD(INFRQ_DESC, NULL); 00084 return pkg->packager; 00085 } 00086 00087 static const char *_cache_get_arch(alpm_pkg_t *pkg) 00088 { 00089 LAZY_LOAD(INFRQ_DESC, NULL); 00090 return pkg->arch; 00091 } 00092 00093 static off_t _cache_get_isize(alpm_pkg_t *pkg) 00094 { 00095 LAZY_LOAD(INFRQ_DESC, -1); 00096 return pkg->isize; 00097 } 00098 00099 static alpm_pkgreason_t _cache_get_reason(alpm_pkg_t *pkg) 00100 { 00101 LAZY_LOAD(INFRQ_DESC, -1); 00102 return pkg->reason; 00103 } 00104 00105 static alpm_list_t *_cache_get_licenses(alpm_pkg_t *pkg) 00106 { 00107 LAZY_LOAD(INFRQ_DESC, NULL); 00108 return pkg->licenses; 00109 } 00110 00111 static alpm_list_t *_cache_get_groups(alpm_pkg_t *pkg) 00112 { 00113 LAZY_LOAD(INFRQ_DESC, NULL); 00114 return pkg->groups; 00115 } 00116 00117 static int _cache_has_scriptlet(alpm_pkg_t *pkg) 00118 { 00119 LAZY_LOAD(INFRQ_SCRIPTLET, NULL); 00120 return pkg->scriptlet; 00121 } 00122 00123 static alpm_list_t *_cache_get_depends(alpm_pkg_t *pkg) 00124 { 00125 LAZY_LOAD(INFRQ_DESC, NULL); 00126 return pkg->depends; 00127 } 00128 00129 static alpm_list_t *_cache_get_optdepends(alpm_pkg_t *pkg) 00130 { 00131 LAZY_LOAD(INFRQ_DESC, NULL); 00132 return pkg->optdepends; 00133 } 00134 00135 static alpm_list_t *_cache_get_conflicts(alpm_pkg_t *pkg) 00136 { 00137 LAZY_LOAD(INFRQ_DESC, NULL); 00138 return pkg->conflicts; 00139 } 00140 00141 static alpm_list_t *_cache_get_provides(alpm_pkg_t *pkg) 00142 { 00143 LAZY_LOAD(INFRQ_DESC, NULL); 00144 return pkg->provides; 00145 } 00146 00147 static alpm_list_t *_cache_get_replaces(alpm_pkg_t *pkg) 00148 { 00149 LAZY_LOAD(INFRQ_DESC, NULL); 00150 return pkg->replaces; 00151 } 00152 00153 static alpm_filelist_t *_cache_get_files(alpm_pkg_t *pkg) 00154 { 00155 LAZY_LOAD(INFRQ_FILES, NULL); 00156 return &(pkg->files); 00157 } 00158 00159 static alpm_list_t *_cache_get_backup(alpm_pkg_t *pkg) 00160 { 00161 LAZY_LOAD(INFRQ_FILES, NULL); 00162 return pkg->backup; 00163 } 00164 00165 /** 00166 * Open a package changelog for reading. Similar to fopen in functionality, 00167 * except that the returned 'file stream' is from the database. 00168 * @param pkg the package (from db) to read the changelog 00169 * @return a 'file stream' to the package changelog 00170 */ 00171 static void *_cache_changelog_open(alpm_pkg_t *pkg) 00172 { 00173 alpm_db_t *db = alpm_pkg_get_db(pkg); 00174 char *clfile = _alpm_local_db_pkgpath(db, pkg, "changelog"); 00175 FILE *f = fopen(clfile, "r"); 00176 free(clfile); 00177 return f; 00178 } 00179 00180 /** 00181 * Read data from an open changelog 'file stream'. Similar to fread in 00182 * functionality, this function takes a buffer and amount of data to read. 00183 * @param ptr a buffer to fill with raw changelog data 00184 * @param size the size of the buffer 00185 * @param pkg the package that the changelog is being read from 00186 * @param fp a 'file stream' to the package changelog 00187 * @return the number of characters read, or 0 if there is no more data 00188 */ 00189 static size_t _cache_changelog_read(void *ptr, size_t size, 00190 const alpm_pkg_t UNUSED *pkg, void *fp) 00191 { 00192 return fread(ptr, 1, size, (FILE *)fp); 00193 } 00194 00195 /** 00196 * Close a package changelog for reading. Similar to fclose in functionality, 00197 * except that the 'file stream' is from the database. 00198 * @param pkg the package that the changelog was read from 00199 * @param fp a 'file stream' to the package changelog 00200 * @return whether closing the package changelog stream was successful 00201 */ 00202 static int _cache_changelog_close(const alpm_pkg_t UNUSED *pkg, void *fp) 00203 { 00204 return fclose((FILE *)fp); 00205 } 00206 00207 static int _cache_force_load(alpm_pkg_t *pkg) 00208 { 00209 return local_db_read(pkg, INFRQ_ALL); 00210 } 00211 00212 00213 /** The local database operations struct. Get package fields through 00214 * lazy accessor methods that handle any backend loading and caching 00215 * logic. 00216 */ 00217 static struct pkg_operations local_pkg_ops = { 00218 .get_desc = _cache_get_desc, 00219 .get_url = _cache_get_url, 00220 .get_builddate = _cache_get_builddate, 00221 .get_installdate = _cache_get_installdate, 00222 .get_packager = _cache_get_packager, 00223 .get_arch = _cache_get_arch, 00224 .get_isize = _cache_get_isize, 00225 .get_reason = _cache_get_reason, 00226 .has_scriptlet = _cache_has_scriptlet, 00227 .get_licenses = _cache_get_licenses, 00228 .get_groups = _cache_get_groups, 00229 .get_depends = _cache_get_depends, 00230 .get_optdepends = _cache_get_optdepends, 00231 .get_conflicts = _cache_get_conflicts, 00232 .get_provides = _cache_get_provides, 00233 .get_replaces = _cache_get_replaces, 00234 .get_files = _cache_get_files, 00235 .get_backup = _cache_get_backup, 00236 00237 .changelog_open = _cache_changelog_open, 00238 .changelog_read = _cache_changelog_read, 00239 .changelog_close = _cache_changelog_close, 00240 00241 .force_load = _cache_force_load, 00242 }; 00243 00244 static int checkdbdir(alpm_db_t *db) 00245 { 00246 struct stat buf; 00247 const char *path = _alpm_db_path(db); 00248 00249 if(stat(path, &buf) != 0) { 00250 _alpm_log(db->handle, ALPM_LOG_DEBUG, "database dir '%s' does not exist, creating it\n", 00251 path); 00252 if(_alpm_makepath(path) != 0) { 00253 RET_ERR(db->handle, ALPM_ERR_SYSTEM, -1); 00254 } 00255 } else if(!S_ISDIR(buf.st_mode)) { 00256 _alpm_log(db->handle, ALPM_LOG_WARNING, _("removing invalid database: %s\n"), path); 00257 if(unlink(path) != 0 || _alpm_makepath(path) != 0) { 00258 RET_ERR(db->handle, ALPM_ERR_SYSTEM, -1); 00259 } 00260 } 00261 return 0; 00262 } 00263 00264 static int is_dir(const char *path, struct dirent *entry) 00265 { 00266 #ifdef HAVE_STRUCT_DIRENT_D_TYPE 00267 if(entry->d_type != DT_UNKNOWN) { 00268 return (entry->d_type == DT_DIR); 00269 } 00270 #endif 00271 { 00272 char buffer[PATH_MAX]; 00273 struct stat sbuf; 00274 00275 snprintf(buffer, PATH_MAX, "%s/%s", path, entry->d_name); 00276 00277 if(!stat(buffer, &sbuf)) { 00278 return S_ISDIR(sbuf.st_mode); 00279 } 00280 } 00281 00282 return 0; 00283 } 00284 00285 static int local_db_validate(alpm_db_t *db) 00286 { 00287 struct dirent *ent = NULL; 00288 const char *dbpath; 00289 DIR *dbdir; 00290 int ret = -1; 00291 00292 if(db->status & DB_STATUS_VALID) { 00293 return 0; 00294 } 00295 if(db->status & DB_STATUS_INVALID) { 00296 return -1; 00297 } 00298 00299 dbpath = _alpm_db_path(db); 00300 if(dbpath == NULL) { 00301 RET_ERR(db->handle, ALPM_ERR_DB_OPEN, -1); 00302 } 00303 dbdir = opendir(dbpath); 00304 if(dbdir == NULL) { 00305 if(errno == ENOENT) { 00306 /* database dir doesn't exist yet */ 00307 db->status |= DB_STATUS_VALID; 00308 db->status &= ~DB_STATUS_INVALID; 00309 db->status &= ~DB_STATUS_EXISTS; 00310 db->status |= DB_STATUS_MISSING; 00311 return 0; 00312 } else { 00313 RET_ERR(db->handle, ALPM_ERR_DB_OPEN, -1); 00314 } 00315 } 00316 db->status |= DB_STATUS_EXISTS; 00317 db->status &= ~DB_STATUS_MISSING; 00318 00319 while((ent = readdir(dbdir)) != NULL) { 00320 const char *name = ent->d_name; 00321 char path[PATH_MAX]; 00322 00323 if(strcmp(name, ".") == 0 || strcmp(name, "..") == 0) { 00324 continue; 00325 } 00326 if(!is_dir(dbpath, ent)) { 00327 continue; 00328 } 00329 00330 snprintf(path, PATH_MAX, "%s%s/depends", dbpath, name); 00331 if(access(path, F_OK) == 0) { 00332 /* we found a depends file- bail */ 00333 db->status &= ~DB_STATUS_VALID; 00334 db->status |= DB_STATUS_INVALID; 00335 db->handle->pm_errno = ALPM_ERR_DB_VERSION; 00336 goto done; 00337 } 00338 } 00339 /* we found no depends file after full scan */ 00340 db->status |= DB_STATUS_VALID; 00341 db->status &= ~DB_STATUS_INVALID; 00342 ret = 0; 00343 00344 done: 00345 if(dbdir) { 00346 closedir(dbdir); 00347 } 00348 00349 return ret; 00350 } 00351 00352 static int local_db_populate(alpm_db_t *db) 00353 { 00354 size_t est_count; 00355 int count = 0; 00356 struct stat buf; 00357 struct dirent *ent = NULL; 00358 const char *dbpath; 00359 DIR *dbdir; 00360 00361 if(db->status & DB_STATUS_INVALID) { 00362 RET_ERR(db->handle, ALPM_ERR_DB_INVALID, -1); 00363 } 00364 /* note: DB_STATUS_MISSING is not fatal for local database */ 00365 00366 dbpath = _alpm_db_path(db); 00367 if(dbpath == NULL) { 00368 /* pm_errno set in _alpm_db_path() */ 00369 return -1; 00370 } 00371 00372 dbdir = opendir(dbpath); 00373 if(dbdir == NULL) { 00374 if(errno == ENOENT) { 00375 /* no database existing yet is not an error */ 00376 db->status &= ~DB_STATUS_EXISTS; 00377 db->status |= DB_STATUS_MISSING; 00378 return 0; 00379 } 00380 RET_ERR(db->handle, ALPM_ERR_DB_OPEN, -1); 00381 } 00382 if(fstat(dirfd(dbdir), &buf) != 0) { 00383 RET_ERR(db->handle, ALPM_ERR_DB_OPEN, -1); 00384 } 00385 db->status |= DB_STATUS_EXISTS; 00386 db->status &= ~DB_STATUS_MISSING; 00387 if(buf.st_nlink >= 2) { 00388 est_count = buf.st_nlink; 00389 } else { 00390 /* Some filesystems don't subscribe to the two-implicit links school of 00391 * thought, e.g. BTRFS, HFS+. See 00392 * http://kerneltrap.org/mailarchive/linux-btrfs/2010/1/23/6723483/thread 00393 */ 00394 est_count = 0; 00395 while(readdir(dbdir) != NULL) { 00396 est_count++; 00397 } 00398 rewinddir(dbdir); 00399 } 00400 if(est_count >= 2) { 00401 /* subtract the two extra pointers to get # of children */ 00402 est_count -= 2; 00403 } 00404 00405 db->pkgcache = _alpm_pkghash_create(est_count); 00406 if(db->pkgcache == NULL){ 00407 closedir(dbdir); 00408 RET_ERR(db->handle, ALPM_ERR_MEMORY, -1); 00409 } 00410 00411 while((ent = readdir(dbdir)) != NULL) { 00412 const char *name = ent->d_name; 00413 00414 alpm_pkg_t *pkg; 00415 00416 if(strcmp(name, ".") == 0 || strcmp(name, "..") == 0) { 00417 continue; 00418 } 00419 if(!is_dir(dbpath, ent)) { 00420 continue; 00421 } 00422 00423 pkg = _alpm_pkg_new(); 00424 if(pkg == NULL) { 00425 closedir(dbdir); 00426 RET_ERR(db->handle, ALPM_ERR_MEMORY, -1); 00427 } 00428 /* split the db entry name */ 00429 if(_alpm_splitname(name, &(pkg->name), &(pkg->version), 00430 &(pkg->name_hash)) != 0) { 00431 _alpm_log(db->handle, ALPM_LOG_ERROR, _("invalid name for database entry '%s'\n"), 00432 name); 00433 _alpm_pkg_free(pkg); 00434 continue; 00435 } 00436 00437 /* duplicated database entries are not allowed */ 00438 if(_alpm_pkghash_find(db->pkgcache, pkg->name)) { 00439 _alpm_log(db->handle, ALPM_LOG_ERROR, _("duplicated database entry '%s'\n"), pkg->name); 00440 _alpm_pkg_free(pkg); 00441 continue; 00442 } 00443 00444 pkg->origin = PKG_FROM_LOCALDB; 00445 pkg->origin_data.db = db; 00446 pkg->ops = &local_pkg_ops; 00447 pkg->handle = db->handle; 00448 00449 /* explicitly read with only 'BASE' data, accessors will handle the rest */ 00450 if(local_db_read(pkg, INFRQ_BASE) == -1) { 00451 _alpm_log(db->handle, ALPM_LOG_ERROR, _("corrupted database entry '%s'\n"), name); 00452 _alpm_pkg_free(pkg); 00453 continue; 00454 } 00455 00456 /* add to the collection */ 00457 _alpm_log(db->handle, ALPM_LOG_FUNCTION, "adding '%s' to package cache for db '%s'\n", 00458 pkg->name, db->treename); 00459 db->pkgcache = _alpm_pkghash_add(db->pkgcache, pkg); 00460 count++; 00461 } 00462 00463 closedir(dbdir); 00464 if(count > 0) { 00465 db->pkgcache->list = alpm_list_msort(db->pkgcache->list, (size_t)count, _alpm_pkg_cmp); 00466 } 00467 _alpm_log(db->handle, ALPM_LOG_DEBUG, "added %d packages to package cache for db '%s'\n", 00468 count, db->treename); 00469 00470 return count; 00471 } 00472 00473 /* Note: the return value must be freed by the caller */ 00474 char *_alpm_local_db_pkgpath(alpm_db_t *db, alpm_pkg_t *info, 00475 const char *filename) 00476 { 00477 size_t len; 00478 char *pkgpath; 00479 const char *dbpath; 00480 00481 dbpath = _alpm_db_path(db); 00482 len = strlen(dbpath) + strlen(info->name) + strlen(info->version) + 3; 00483 len += filename ? strlen(filename) : 0; 00484 MALLOC(pkgpath, len, RET_ERR(db->handle, ALPM_ERR_MEMORY, NULL)); 00485 sprintf(pkgpath, "%s%s-%s/%s", dbpath, info->name, info->version, 00486 filename ? filename : ""); 00487 return pkgpath; 00488 } 00489 00490 #define READ_NEXT() do { \ 00491 if(fgets(line, sizeof(line), fp) == NULL && !feof(fp)) goto error; \ 00492 _alpm_strip_newline(line); \ 00493 } while(0) 00494 00495 #define READ_AND_STORE(f) do { \ 00496 READ_NEXT(); \ 00497 STRDUP(f, line, goto error); \ 00498 } while(0) 00499 00500 #define READ_AND_STORE_ALL(f) do { \ 00501 char *linedup; \ 00502 if(fgets(line, sizeof(line), fp) == NULL) {\ 00503 if(!feof(fp)) goto error; else break; \ 00504 } \ 00505 if(_alpm_strip_newline(line) == 0) break; \ 00506 STRDUP(linedup, line, goto error); \ 00507 f = alpm_list_add(f, linedup); \ 00508 } while(1) /* note the while(1) and not (0) */ 00509 00510 #define READ_AND_SPLITDEP(f) do { \ 00511 if(fgets(line, sizeof(line), fp) == NULL) {\ 00512 if(!feof(fp)) goto error; else break; \ 00513 } \ 00514 if(_alpm_strip_newline(line) == 0) break; \ 00515 f = alpm_list_add(f, _alpm_splitdep(line)); \ 00516 } while(1) /* note the while(1) and not (0) */ 00517 00518 static int local_db_read(alpm_pkg_t *info, alpm_dbinfrq_t inforeq) 00519 { 00520 FILE *fp = NULL; 00521 char line[1024]; 00522 char *pkgpath; 00523 alpm_db_t *db = info->origin_data.db; 00524 00525 /* bitmask logic here: 00526 * infolevel: 00001111 00527 * inforeq: 00010100 00528 * & result: 00000100 00529 * == to inforeq? nope, we need to load more info. */ 00530 if((info->infolevel & inforeq) == inforeq) { 00531 /* already loaded all of this info, do nothing */ 00532 return 0; 00533 } 00534 00535 if(info->infolevel & INFRQ_ERROR) { 00536 /* We've encountered an error loading this package before. Don't attempt 00537 * repeated reloads, just give up. */ 00538 return -1; 00539 } 00540 00541 _alpm_log(db->handle, ALPM_LOG_FUNCTION, "loading package data for %s : level=0x%x\n", 00542 info->name, inforeq); 00543 00544 pkgpath = _alpm_local_db_pkgpath(db, info, NULL); 00545 if(!pkgpath || access(pkgpath, F_OK)) { 00546 /* directory doesn't exist or can't be opened */ 00547 _alpm_log(db->handle, ALPM_LOG_DEBUG, "cannot find '%s-%s' in db '%s'\n", 00548 info->name, info->version, db->treename); 00549 goto error; 00550 } 00551 free(pkgpath); 00552 00553 /* clear out 'line', to be certain - and to make valgrind happy */ 00554 memset(line, 0, sizeof(line)); 00555 00556 /* DESC */ 00557 if(inforeq & INFRQ_DESC && !(info->infolevel & INFRQ_DESC)) { 00558 char *path = _alpm_local_db_pkgpath(db, info, "desc"); 00559 if(!path || (fp = fopen(path, "r")) == NULL) { 00560 _alpm_log(db->handle, ALPM_LOG_ERROR, _("could not open file %s: %s\n"), path, strerror(errno)); 00561 free(path); 00562 goto error; 00563 } 00564 free(path); 00565 while(!feof(fp)) { 00566 if(fgets(line, sizeof(line), fp) == NULL && !feof(fp)) { 00567 goto error; 00568 } 00569 if(_alpm_strip_newline(line) == 0) { 00570 /* length of stripped line was zero */ 00571 continue; 00572 } 00573 if(strcmp(line, "%NAME%") == 0) { 00574 READ_NEXT(); 00575 if(strcmp(line, info->name) != 0) { 00576 _alpm_log(db->handle, ALPM_LOG_ERROR, _("%s database is inconsistent: name " 00577 "mismatch on package %s\n"), db->treename, info->name); 00578 } 00579 } else if(strcmp(line, "%VERSION%") == 0) { 00580 READ_NEXT(); 00581 if(strcmp(line, info->version) != 0) { 00582 _alpm_log(db->handle, ALPM_LOG_ERROR, _("%s database is inconsistent: version " 00583 "mismatch on package %s\n"), db->treename, info->name); 00584 } 00585 } else if(strcmp(line, "%DESC%") == 0) { 00586 READ_AND_STORE(info->desc); 00587 } else if(strcmp(line, "%GROUPS%") == 0) { 00588 READ_AND_STORE_ALL(info->groups); 00589 } else if(strcmp(line, "%URL%") == 0) { 00590 READ_AND_STORE(info->url); 00591 } else if(strcmp(line, "%LICENSE%") == 0) { 00592 READ_AND_STORE_ALL(info->licenses); 00593 } else if(strcmp(line, "%ARCH%") == 0) { 00594 READ_AND_STORE(info->arch); 00595 } else if(strcmp(line, "%BUILDDATE%") == 0) { 00596 READ_NEXT(); 00597 info->builddate = _alpm_parsedate(line); 00598 } else if(strcmp(line, "%INSTALLDATE%") == 0) { 00599 READ_NEXT(); 00600 info->installdate = _alpm_parsedate(line); 00601 } else if(strcmp(line, "%PACKAGER%") == 0) { 00602 READ_AND_STORE(info->packager); 00603 } else if(strcmp(line, "%REASON%") == 0) { 00604 READ_NEXT(); 00605 info->reason = (alpm_pkgreason_t)atoi(line); 00606 } else if(strcmp(line, "%SIZE%") == 0) { 00607 READ_NEXT(); 00608 info->isize = _alpm_strtoofft(line); 00609 } else if(strcmp(line, "%REPLACES%") == 0) { 00610 READ_AND_SPLITDEP(info->replaces); 00611 } else if(strcmp(line, "%DEPENDS%") == 0) { 00612 READ_AND_SPLITDEP(info->depends); 00613 } else if(strcmp(line, "%OPTDEPENDS%") == 0) { 00614 READ_AND_STORE_ALL(info->optdepends); 00615 } else if(strcmp(line, "%CONFLICTS%") == 0) { 00616 READ_AND_SPLITDEP(info->conflicts); 00617 } else if(strcmp(line, "%PROVIDES%") == 0) { 00618 READ_AND_SPLITDEP(info->provides); 00619 } 00620 } 00621 fclose(fp); 00622 fp = NULL; 00623 info->infolevel |= INFRQ_DESC; 00624 } 00625 00626 /* FILES */ 00627 if(inforeq & INFRQ_FILES && !(info->infolevel & INFRQ_FILES)) { 00628 char *path = _alpm_local_db_pkgpath(db, info, "files"); 00629 if(!path || (fp = fopen(path, "r")) == NULL) { 00630 _alpm_log(db->handle, ALPM_LOG_ERROR, _("could not open file %s: %s\n"), path, strerror(errno)); 00631 free(path); 00632 goto error; 00633 } 00634 free(path); 00635 while(fgets(line, sizeof(line), fp)) { 00636 _alpm_strip_newline(line); 00637 if(strcmp(line, "%FILES%") == 0) { 00638 size_t files_count = 0, files_size = 0, len; 00639 alpm_file_t *files = NULL; 00640 00641 while(fgets(line, sizeof(line), fp) && 00642 (len = _alpm_strip_newline(line))) { 00643 if(files_count >= files_size) { 00644 size_t old_size = files_size; 00645 if(files_size == 0) { 00646 files_size = 8; 00647 } else { 00648 files_size *= 2; 00649 } 00650 files = realloc(files, sizeof(alpm_file_t) * files_size); 00651 if(!files) { 00652 ALLOC_FAIL(sizeof(alpm_file_t) * files_size); 00653 goto error; 00654 } 00655 /* ensure all new memory is zeroed out, in both the initial 00656 * allocation and later reallocs */ 00657 memset(files + old_size, 0, 00658 sizeof(alpm_file_t) * (files_size - old_size)); 00659 } 00660 /* since we know the length of the file string already, 00661 * we can do malloc + memcpy rather than strdup */ 00662 files[files_count].name = malloc(len + 1); 00663 if(files[files_count].name == NULL) { 00664 ALLOC_FAIL(len); 00665 goto error; 00666 } 00667 memcpy(files[files_count].name, line, len + 1); 00668 files_count++; 00669 } 00670 /* attempt to hand back any memory we don't need */ 00671 files = realloc(files, sizeof(alpm_file_t) * files_count); 00672 info->files.count = files_count; 00673 info->files.files = files; 00674 } else if(strcmp(line, "%BACKUP%") == 0) { 00675 while(fgets(line, sizeof(line), fp) && _alpm_strip_newline(line)) { 00676 alpm_backup_t *backup; 00677 CALLOC(backup, 1, sizeof(alpm_backup_t), goto error); 00678 if(_alpm_split_backup(line, &backup)) { 00679 goto error; 00680 } 00681 info->backup = alpm_list_add(info->backup, backup); 00682 } 00683 } 00684 } 00685 fclose(fp); 00686 fp = NULL; 00687 info->infolevel |= INFRQ_FILES; 00688 } 00689 00690 /* INSTALL */ 00691 if(inforeq & INFRQ_SCRIPTLET && !(info->infolevel & INFRQ_SCRIPTLET)) { 00692 char *path = _alpm_local_db_pkgpath(db, info, "install"); 00693 if(access(path, F_OK) == 0) { 00694 info->scriptlet = 1; 00695 } 00696 free(path); 00697 info->infolevel |= INFRQ_SCRIPTLET; 00698 } 00699 00700 return 0; 00701 00702 error: 00703 info->infolevel |= INFRQ_ERROR; 00704 if(fp) { 00705 fclose(fp); 00706 } 00707 return -1; 00708 } 00709 00710 int _alpm_local_db_prepare(alpm_db_t *db, alpm_pkg_t *info) 00711 { 00712 mode_t oldmask; 00713 int retval = 0; 00714 char *pkgpath; 00715 00716 if(checkdbdir(db) != 0) { 00717 return -1; 00718 } 00719 00720 oldmask = umask(0000); 00721 pkgpath = _alpm_local_db_pkgpath(db, info, NULL); 00722 00723 if((retval = mkdir(pkgpath, 0755)) != 0) { 00724 _alpm_log(db->handle, ALPM_LOG_ERROR, _("could not create directory %s: %s\n"), 00725 pkgpath, strerror(errno)); 00726 } 00727 00728 free(pkgpath); 00729 umask(oldmask); 00730 00731 return retval; 00732 } 00733 00734 int _alpm_local_db_write(alpm_db_t *db, alpm_pkg_t *info, alpm_dbinfrq_t inforeq) 00735 { 00736 FILE *fp = NULL; 00737 mode_t oldmask; 00738 alpm_list_t *lp; 00739 int retval = 0; 00740 00741 if(db == NULL || info == NULL || !(db->status & DB_STATUS_LOCAL)) { 00742 return -1; 00743 } 00744 00745 /* make sure we have a sane umask */ 00746 oldmask = umask(0022); 00747 00748 /* DESC */ 00749 if(inforeq & INFRQ_DESC) { 00750 char *path; 00751 _alpm_log(db->handle, ALPM_LOG_DEBUG, "writing %s-%s DESC information back to db\n", 00752 info->name, info->version); 00753 path = _alpm_local_db_pkgpath(db, info, "desc"); 00754 if(!path || (fp = fopen(path, "w")) == NULL) { 00755 _alpm_log(db->handle, ALPM_LOG_ERROR, _("could not open file %s: %s\n"), 00756 path, strerror(errno)); 00757 retval = -1; 00758 free(path); 00759 goto cleanup; 00760 } 00761 free(path); 00762 fprintf(fp, "%%NAME%%\n%s\n\n" 00763 "%%VERSION%%\n%s\n\n", info->name, info->version); 00764 if(info->desc) { 00765 fprintf(fp, "%%DESC%%\n" 00766 "%s\n\n", info->desc); 00767 } 00768 if(info->groups) { 00769 fputs("%GROUPS%\n", fp); 00770 for(lp = info->groups; lp; lp = lp->next) { 00771 fprintf(fp, "%s\n", (char *)lp->data); 00772 } 00773 fprintf(fp, "\n"); 00774 } 00775 if(info->replaces) { 00776 fputs("%REPLACES%\n", fp); 00777 for(lp = info->replaces; lp; lp = lp->next) { 00778 char *depstring = alpm_dep_compute_string(lp->data); 00779 fprintf(fp, "%s\n", depstring); 00780 free(depstring); 00781 } 00782 fprintf(fp, "\n"); 00783 } 00784 if(info->url) { 00785 fprintf(fp, "%%URL%%\n" 00786 "%s\n\n", info->url); 00787 } 00788 if(info->licenses) { 00789 fputs("%LICENSE%\n", fp); 00790 for(lp = info->licenses; lp; lp = lp->next) { 00791 fprintf(fp, "%s\n", (char *)lp->data); 00792 } 00793 fprintf(fp, "\n"); 00794 } 00795 if(info->arch) { 00796 fprintf(fp, "%%ARCH%%\n" 00797 "%s\n\n", info->arch); 00798 } 00799 if(info->builddate) { 00800 fprintf(fp, "%%BUILDDATE%%\n" 00801 "%jd\n\n", (intmax_t)info->builddate); 00802 } 00803 if(info->installdate) { 00804 fprintf(fp, "%%INSTALLDATE%%\n" 00805 "%jd\n\n", (intmax_t)info->installdate); 00806 } 00807 if(info->packager) { 00808 fprintf(fp, "%%PACKAGER%%\n" 00809 "%s\n\n", info->packager); 00810 } 00811 if(info->isize) { 00812 /* only write installed size, csize is irrelevant once installed */ 00813 fprintf(fp, "%%SIZE%%\n" 00814 "%jd\n\n", (intmax_t)info->isize); 00815 } 00816 if(info->reason) { 00817 fprintf(fp, "%%REASON%%\n" 00818 "%u\n\n", info->reason); 00819 } 00820 if(info->depends) { 00821 fputs("%DEPENDS%\n", fp); 00822 for(lp = info->depends; lp; lp = lp->next) { 00823 char *depstring = alpm_dep_compute_string(lp->data); 00824 fprintf(fp, "%s\n", depstring); 00825 free(depstring); 00826 } 00827 fprintf(fp, "\n"); 00828 } 00829 if(info->optdepends) { 00830 fputs("%OPTDEPENDS%\n", fp); 00831 for(lp = info->optdepends; lp; lp = lp->next) { 00832 fprintf(fp, "%s\n", (char *)lp->data); 00833 } 00834 fprintf(fp, "\n"); 00835 } 00836 if(info->conflicts) { 00837 fputs("%CONFLICTS%\n", fp); 00838 for(lp = info->conflicts; lp; lp = lp->next) { 00839 char *depstring = alpm_dep_compute_string(lp->data); 00840 fprintf(fp, "%s\n", depstring); 00841 free(depstring); 00842 } 00843 fprintf(fp, "\n"); 00844 } 00845 if(info->provides) { 00846 fputs("%PROVIDES%\n", fp); 00847 for(lp = info->provides; lp; lp = lp->next) { 00848 char *depstring = alpm_dep_compute_string(lp->data); 00849 fprintf(fp, "%s\n", depstring); 00850 free(depstring); 00851 } 00852 fprintf(fp, "\n"); 00853 } 00854 00855 fclose(fp); 00856 fp = NULL; 00857 } 00858 00859 /* FILES */ 00860 if(inforeq & INFRQ_FILES) { 00861 char *path; 00862 _alpm_log(db->handle, ALPM_LOG_DEBUG, "writing %s-%s FILES information back to db\n", 00863 info->name, info->version); 00864 path = _alpm_local_db_pkgpath(db, info, "files"); 00865 if(!path || (fp = fopen(path, "w")) == NULL) { 00866 _alpm_log(db->handle, ALPM_LOG_ERROR, _("could not open file %s: %s\n"), 00867 path, strerror(errno)); 00868 retval = -1; 00869 free(path); 00870 goto cleanup; 00871 } 00872 free(path); 00873 if(info->files.count) { 00874 size_t i; 00875 fprintf(fp, "%%FILES%%\n"); 00876 for(i = 0; i < info->files.count; i++) { 00877 const alpm_file_t *file = info->files.files + i; 00878 fprintf(fp, "%s\n", file->name); 00879 } 00880 fprintf(fp, "\n"); 00881 } 00882 if(info->backup) { 00883 fprintf(fp, "%%BACKUP%%\n"); 00884 for(lp = info->backup; lp; lp = lp->next) { 00885 const alpm_backup_t *backup = lp->data; 00886 fprintf(fp, "%s\t%s\n", backup->name, backup->hash); 00887 } 00888 fprintf(fp, "\n"); 00889 } 00890 fclose(fp); 00891 fp = NULL; 00892 } 00893 00894 /* INSTALL */ 00895 /* nothing needed here (script is automatically extracted) */ 00896 00897 cleanup: 00898 umask(oldmask); 00899 00900 if(fp) { 00901 fclose(fp); 00902 } 00903 00904 return retval; 00905 } 00906 00907 int _alpm_local_db_remove(alpm_db_t *db, alpm_pkg_t *info) 00908 { 00909 int ret = 0; 00910 char *pkgpath = _alpm_local_db_pkgpath(db, info, NULL); 00911 00912 /* TODO explicit file removes and then an rmdir? */ 00913 ret = _alpm_rmrf(pkgpath); 00914 free(pkgpath); 00915 if(ret != 0) { 00916 ret = -1; 00917 } 00918 return ret; 00919 } 00920 00921 struct db_operations local_db_ops = { 00922 .validate = local_db_validate, 00923 .populate = local_db_populate, 00924 .unregister = _alpm_db_unregister, 00925 }; 00926 00927 alpm_db_t *_alpm_db_register_local(alpm_handle_t *handle) 00928 { 00929 alpm_db_t *db; 00930 00931 _alpm_log(handle, ALPM_LOG_DEBUG, "registering local database\n"); 00932 00933 db = _alpm_db_new("local", 1); 00934 if(db == NULL) { 00935 handle->pm_errno = ALPM_ERR_DB_CREATE; 00936 return NULL; 00937 } 00938 db->ops = &local_db_ops; 00939 db->handle = handle; 00940 00941 if(local_db_validate(db)) { 00942 /* pm_errno set in local_db_validate() */ 00943 _alpm_db_free(db); 00944 return NULL; 00945 } 00946 00947 handle->db_local = db; 00948 return db; 00949 } 00950 00951 /* vim: set ts=2 sw=2 noet: */