Use sane umask for repo db downloads
[pacman-ng.git] / lib / libalpm / be_sync.c
blob98516fd8e501e6930da4f6a94afb36931275e0ac
1 /*
2 * be_sync.c
4 * Copyright (c) 2006-2011 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 <errno.h>
24 #include <limits.h>
26 /* libarchive */
27 #include <archive.h>
28 #include <archive_entry.h>
30 /* libalpm */
31 #include "util.h"
32 #include "log.h"
33 #include "alpm.h"
34 #include "alpm_list.h"
35 #include "package.h"
36 #include "handle.h"
37 #include "delta.h"
38 #include "deps.h"
39 #include "dload.h"
41 /** Update a package database
43 * An update of the package database \a db will be attempted. Unless
44 * \a force is true, the update will only be performed if the remote
45 * database was modified since the last update.
47 * A transaction is necessary for this operation, in order to obtain a
48 * database lock. During this transaction the front-end will be informed
49 * of the download progress of the database via the download callback.
51 * Example:
52 * @code
53 * alpm_list_t *syncs = alpm_option_get_syncdbs();
54 * if(alpm_trans_init(0, NULL, NULL, NULL) == 0) {
55 * for(i = syncs; i; i = alpm_list_next(i)) {
56 * pmdb_t *db = alpm_list_getdata(i);
57 * result = alpm_db_update(0, db);
58 * alpm_trans_release();
60 * if(result < 0) {
61 * printf("Unable to update database: %s\n", alpm_strerrorlast());
62 * } else if(result == 1) {
63 * printf("Database already up to date\n");
64 * } else {
65 * printf("Database updated\n");
66 * }
67 * }
68 * }
69 * @endcode
71 * @ingroup alpm_databases
72 * @note After a successful update, the \link alpm_db_get_pkgcache()
73 * package cache \endlink will be invalidated
74 * @param force if true, then forces the update, otherwise update only in case
75 * the database isn't up to date
76 * @param db pointer to the package database to update
77 * @return 0 on success, -1 on error (pm_errno is set accordingly), 1 if up to
78 * to date
80 int SYMEXPORT alpm_db_update(int force, pmdb_t *db)
82 char *dbfile, *syncpath;
83 const char *dbpath;
84 struct stat buf;
85 size_t len;
86 int ret;
87 mode_t oldmask;
89 ALPM_LOG_FUNC;
91 /* Sanity checks */
92 ASSERT(handle != NULL, RET_ERR(PM_ERR_HANDLE_NULL, -1));
93 ASSERT(db != NULL && db != handle->db_local, RET_ERR(PM_ERR_WRONG_ARGS, -1));
95 if(!alpm_list_find_ptr(handle->dbs_sync, db)) {
96 RET_ERR(PM_ERR_DB_NOT_FOUND, -1);
99 len = strlen(db->treename) + 4;
100 MALLOC(dbfile, len, RET_ERR(PM_ERR_MEMORY, -1));
101 sprintf(dbfile, "%s.db", db->treename);
103 dbpath = alpm_option_get_dbpath();
104 len = strlen(dbpath) + 6;
105 MALLOC(syncpath, len, RET_ERR(PM_ERR_MEMORY, -1));
106 sprintf(syncpath, "%s%s", dbpath, "sync/");
108 /* make sure we have a sane umask */
109 oldmask = umask(0022);
111 if(stat(syncpath, &buf) != 0) {
112 _alpm_log(PM_LOG_DEBUG, "database dir '%s' does not exist, creating it\n",
113 syncpath);
114 if(_alpm_makepath(syncpath) != 0) {
115 free(dbfile);
116 free(syncpath);
117 RET_ERR(PM_ERR_SYSTEM, -1);
119 } else if(!S_ISDIR(buf.st_mode)) {
120 _alpm_log(PM_LOG_WARNING, _("removing invalid file: %s\n"), syncpath);
121 if(unlink(syncpath) != 0 || _alpm_makepath(syncpath) != 0) {
122 free(dbfile);
123 free(syncpath);
124 RET_ERR(PM_ERR_SYSTEM, -1);
128 ret = _alpm_download_single_file(dbfile, db->servers, syncpath, force);
129 free(dbfile);
130 free(syncpath);
131 umask(oldmask);
133 if(ret == 1) {
134 /* files match, do nothing */
135 pm_errno = 0;
136 return(1);
137 } else if(ret == -1) {
138 /* pm_errno was set by the download code */
139 _alpm_log(PM_LOG_DEBUG, "failed to sync db: %s\n", alpm_strerrorlast());
140 return(-1);
143 /* Cache needs to be rebuilt */
144 _alpm_db_free_pkgcache(db);
146 return(0);
149 /* Forward decl so I don't reorganize the whole file right now */
150 static int sync_db_read(pmdb_t *db, struct archive *archive,
151 struct archive_entry *entry, pmpkg_t *likely_pkg);
154 * This is the data table used to generate the estimating function below.
155 * "Weighted Avg" means averaging the bottom table values; thus each repo, big
156 * or small, will have equal influence. "Unweighted Avg" means averaging the
157 * sums of the top table columns, thus each package has equal influence. The
158 * final values are calculated by (surprise) averaging the averages, because
159 * why the hell not.
161 * Database Pkgs tar bz2 gz xz
162 * community 2096 5294080 256391 421227 301296
163 * core 180 460800 25257 36850 29356
164 * extra 2606 6635520 294647 470818 339392
165 * multilib 126 327680 16120 23261 18732
166 * testing 76 204800 10902 14348 12100
168 * Bytes Per Package
169 * community 2096 2525.80 122.32 200.97 143.75
170 * core 180 2560.00 140.32 204.72 163.09
171 * extra 2606 2546.25 113.06 180.67 130.23
172 * multilib 126 2600.63 127.94 184.61 148.67
173 * testing 76 2694.74 143.45 188.79 159.21
175 * Weighted Avg 2585.48 129.42 191.95 148.99
176 * Unweighted Avg 2543.39 118.74 190.16 137.93
177 * Average of Avgs 2564.44 124.08 191.06 143.46
179 static size_t estimate_package_count(struct stat *st, struct archive *archive)
181 unsigned int per_package;
183 switch(archive_compression(archive)) {
184 case ARCHIVE_COMPRESSION_NONE:
185 per_package = 2564;
186 break;
187 case ARCHIVE_COMPRESSION_GZIP:
188 per_package = 191;
189 break;
190 case ARCHIVE_COMPRESSION_BZIP2:
191 per_package = 124;
192 break;
193 case ARCHIVE_COMPRESSION_COMPRESS:
194 per_package = 193;
195 break;
196 case ARCHIVE_COMPRESSION_LZMA:
197 case ARCHIVE_COMPRESSION_XZ:
198 per_package = 143;
199 break;
200 case ARCHIVE_COMPRESSION_UU:
201 per_package = 3543;
202 break;
203 default:
204 /* assume it is at least somewhat compressed */
205 per_package = 200;
207 return((size_t)(st->st_size / per_package) + 1);
210 static int sync_db_populate(pmdb_t *db)
212 size_t est_count;
213 int count = 0;
214 struct stat buf;
215 struct archive *archive;
216 struct archive_entry *entry;
217 pmpkg_t *pkg = NULL;
219 ALPM_LOG_FUNC;
221 ASSERT(db != NULL, RET_ERR(PM_ERR_DB_NULL, -1));
223 if((archive = archive_read_new()) == NULL)
224 RET_ERR(PM_ERR_LIBARCHIVE, 1);
226 archive_read_support_compression_all(archive);
227 archive_read_support_format_all(archive);
229 if(archive_read_open_filename(archive, _alpm_db_path(db),
230 ARCHIVE_DEFAULT_BYTES_PER_BLOCK) != ARCHIVE_OK) {
231 _alpm_log(PM_LOG_ERROR, _("could not open file %s: %s\n"), _alpm_db_path(db),
232 archive_error_string(archive));
233 archive_read_finish(archive);
234 RET_ERR(PM_ERR_DB_OPEN, 1);
236 if(stat(_alpm_db_path(db), &buf) != 0) {
237 RET_ERR(PM_ERR_DB_OPEN, 1);
239 est_count = estimate_package_count(&buf, archive);
241 /* initialize hash at 66% full */
242 db->pkgcache = _alpm_pkghash_create(est_count * 3 / 2);
243 if(db->pkgcache == NULL) {
244 RET_ERR(PM_ERR_MEMORY, -1);
247 while(archive_read_next_header(archive, &entry) == ARCHIVE_OK) {
248 const struct stat *st;
250 st = archive_entry_stat(entry);
252 if(S_ISDIR(st->st_mode)) {
253 const char *name;
255 pkg = _alpm_pkg_new();
256 if(pkg == NULL) {
257 archive_read_finish(archive);
258 RET_ERR(PM_ERR_MEMORY, -1);
261 name = archive_entry_pathname(entry);
263 if(_alpm_splitname(name, pkg) != 0) {
264 _alpm_log(PM_LOG_ERROR, _("invalid name for database entry '%s'\n"),
265 name);
266 _alpm_pkg_free(pkg);
267 continue;
270 /* duplicated database entries are not allowed */
271 if(_alpm_pkghash_find(db->pkgcache, pkg->name)) {
272 _alpm_log(PM_LOG_ERROR, _("duplicated database entry '%s'\n"), pkg->name);
273 _alpm_pkg_free(pkg);
274 continue;
277 pkg->origin = PKG_FROM_SYNCDB;
278 pkg->ops = &default_pkg_ops;
279 pkg->origin_data.db = db;
281 /* add to the collection */
282 _alpm_log(PM_LOG_FUNCTION, "adding '%s' to package cache for db '%s'\n",
283 pkg->name, db->treename);
284 db->pkgcache = _alpm_pkghash_add(db->pkgcache, pkg);
285 count++;
286 } else {
287 /* we have desc, depends or deltas - parse it */
288 sync_db_read(db, archive, entry, pkg);
292 if(count > 0) {
293 db->pkgcache->list = alpm_list_msort(db->pkgcache->list, (size_t)count, _alpm_pkg_cmp);
295 archive_read_finish(archive);
297 return(count);
300 #define READ_NEXT(s) do { \
301 if(_alpm_archive_fgets(archive, &buf) != ARCHIVE_OK) goto error; \
302 s = _alpm_strtrim(buf.line); \
303 } while(0)
305 #define READ_AND_STORE(f) do { \
306 READ_NEXT(line); \
307 STRDUP(f, line, goto error); \
308 } while(0)
310 #define READ_AND_STORE_ALL(f) do { \
311 char *linedup; \
312 READ_NEXT(line); \
313 if(strlen(line) == 0) break; \
314 STRDUP(linedup, line, goto error); \
315 f = alpm_list_add(f, linedup); \
316 } while(1) /* note the while(1) and not (0) */
318 static int sync_db_read(pmdb_t *db, struct archive *archive,
319 struct archive_entry *entry, pmpkg_t *likely_pkg)
321 const char *entryname = NULL, *filename;
322 char *pkgname, *p, *q;
323 pmpkg_t *pkg;
324 struct archive_read_buffer buf;
326 ALPM_LOG_FUNC;
328 if(db == NULL) {
329 RET_ERR(PM_ERR_DB_NULL, -1);
332 if(entry != NULL) {
333 entryname = archive_entry_pathname(entry);
335 if(entryname == NULL) {
336 _alpm_log(PM_LOG_DEBUG, "invalid archive entry provided to _alpm_sync_db_read, skipping\n");
337 return(-1);
340 _alpm_log(PM_LOG_FUNCTION, "loading package data from archive entry %s\n",
341 entryname);
343 memset(&buf, 0, sizeof(buf));
344 /* 512K for a line length seems reasonable */
345 buf.max_line_size = 512 * 1024;
347 /* get package and db file names */
348 STRDUP(pkgname, entryname, RET_ERR(PM_ERR_MEMORY, -1));
349 p = pkgname + strlen(pkgname);
350 for(q = --p; *q && *q != '/'; q--);
351 filename = q + 1;
352 for(p = --q; *p && *p != '-'; p--);
353 for(q = --p; *q && *q != '-'; q--);
354 *q = '\0';
356 /* package is already in db due to parsing of directory name */
357 if(likely_pkg && strcmp(likely_pkg->name, pkgname) == 0) {
358 pkg = likely_pkg;
359 } else {
360 if(db->pkgcache == NULL) {
361 RET_ERR(PM_ERR_MEMORY, -1);
363 pkg = _alpm_pkghash_find(db->pkgcache, pkgname);
365 if(pkg == NULL) {
366 _alpm_log(PM_LOG_DEBUG, "package %s not found in %s sync database",
367 pkgname, db->treename);
368 return(-1);
371 if(strcmp(filename, "desc") == 0 || strcmp(filename, "depends") == 0
372 || strcmp(filename, "deltas") == 0) {
373 while(_alpm_archive_fgets(archive, &buf) == ARCHIVE_OK) {
374 char *line = _alpm_strtrim(buf.line);
376 if(strcmp(line, "%NAME%") == 0) {
377 READ_NEXT(line);
378 if(strcmp(line, pkg->name) != 0) {
379 _alpm_log(PM_LOG_ERROR, _("%s database is inconsistent: name "
380 "mismatch on package %s\n"), db->treename, pkg->name);
382 } else if(strcmp(line, "%VERSION%") == 0) {
383 READ_NEXT(line);
384 if(strcmp(line, pkg->version) != 0) {
385 _alpm_log(PM_LOG_ERROR, _("%s database is inconsistent: version "
386 "mismatch on package %s\n"), db->treename, pkg->name);
388 } else if(strcmp(line, "%FILENAME%") == 0) {
389 READ_AND_STORE(pkg->filename);
390 } else if(strcmp(line, "%DESC%") == 0) {
391 READ_AND_STORE(pkg->desc);
392 } else if(strcmp(line, "%GROUPS%") == 0) {
393 READ_AND_STORE_ALL(pkg->groups);
394 } else if(strcmp(line, "%URL%") == 0) {
395 READ_AND_STORE(pkg->url);
396 } else if(strcmp(line, "%LICENSE%") == 0) {
397 READ_AND_STORE_ALL(pkg->licenses);
398 } else if(strcmp(line, "%ARCH%") == 0) {
399 READ_AND_STORE(pkg->arch);
400 } else if(strcmp(line, "%BUILDDATE%") == 0) {
401 READ_NEXT(line);
402 pkg->builddate = _alpm_parsedate(line);
403 } else if(strcmp(line, "%PACKAGER%") == 0) {
404 READ_AND_STORE(pkg->packager);
405 } else if(strcmp(line, "%CSIZE%") == 0) {
406 /* Note: the CSIZE and SIZE fields both share the "size" field in the
407 * pkginfo_t struct. This can be done b/c CSIZE is currently only used
408 * in sync databases, and SIZE is only used in local databases.
410 READ_NEXT(line);
411 pkg->size = atol(line);
412 /* also store this value to isize if isize is unset */
413 if(pkg->isize == 0) {
414 pkg->isize = pkg->size;
416 } else if(strcmp(line, "%ISIZE%") == 0) {
417 READ_NEXT(line);
418 pkg->isize = atol(line);
419 } else if(strcmp(line, "%MD5SUM%") == 0) {
420 READ_AND_STORE(pkg->md5sum);
421 } else if(strcmp(line, "%REPLACES%") == 0) {
422 READ_AND_STORE_ALL(pkg->replaces);
423 } else if(strcmp(line, "%DEPENDS%") == 0) {
424 /* Different than the rest because of the _alpm_splitdep call. */
425 while(1) {
426 READ_NEXT(line);
427 if(strlen(line) == 0) break;
428 pkg->depends = alpm_list_add(pkg->depends, _alpm_splitdep(line));
430 } else if(strcmp(line, "%OPTDEPENDS%") == 0) {
431 READ_AND_STORE_ALL(pkg->optdepends);
432 } else if(strcmp(line, "%CONFLICTS%") == 0) {
433 READ_AND_STORE_ALL(pkg->conflicts);
434 } else if(strcmp(line, "%PROVIDES%") == 0) {
435 READ_AND_STORE_ALL(pkg->provides);
436 } else if(strcmp(line, "%DELTAS%") == 0) {
437 /* Different than the rest because of the _alpm_delta_parse call. */
438 while(1) {
439 READ_NEXT(line);
440 if(strlen(line) == 0) break;
441 pkg->deltas = alpm_list_add(pkg->deltas, _alpm_delta_parse(line));
445 } else if(strcmp(filename, "files") == 0) {
446 /* currently do nothing with this file */
447 } else {
448 /* unknown database file */
449 _alpm_log(PM_LOG_DEBUG, "unknown database file: %s\n", filename);
452 error:
453 FREE(pkgname);
454 /* TODO: return 0 always? */
455 return(0);
458 static int sync_db_version(pmdb_t *db)
460 return(2);
463 struct db_operations sync_db_ops = {
464 .populate = sync_db_populate,
465 .unregister = _alpm_db_unregister,
466 .version = sync_db_version,
469 pmdb_t *_alpm_db_register_sync(const char *treename)
471 pmdb_t *db;
472 alpm_list_t *i;
474 ALPM_LOG_FUNC;
476 for(i = handle->dbs_sync; i; i = i->next) {
477 pmdb_t *sdb = i->data;
478 if(strcmp(treename, sdb->treename) == 0) {
479 _alpm_log(PM_LOG_DEBUG, "attempt to re-register the '%s' database, using existing\n", sdb->treename);
480 return sdb;
484 _alpm_log(PM_LOG_DEBUG, "registering sync database '%s'\n", treename);
486 db = _alpm_db_new(treename, 0);
487 if(db == NULL) {
488 RET_ERR(PM_ERR_DB_CREATE, NULL);
490 db->ops = &sync_db_ops;
492 handle->dbs_sync = alpm_list_add(handle->dbs_sync, db);
493 return(db);
497 /* vim: set ts=2 sw=2 noet: */