1 /*
2  *  be_sync.c : backend for sync databases
3  *
4  *  Copyright (c) 2006-2018 Pacman Development Team <pacman-dev@archlinux.org>
5  *  Copyright (c) 2002-2006 by Judd Vinet <jvinet@zeroflux.org>
6  *
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
18  *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
19  */
20 
21 #include <errno.h>
22 #include <sys/types.h>
23 #include <sys/stat.h>
24 #include <fcntl.h>
25 #include <limits.h>
26 #include <unistd.h>
27 
28 /* libarchive */
29 #include <archive.h>
30 #include <archive_entry.h>
31 
32 /* libalpm */
33 #include "util.h"
34 #include "log.h"
35 #include "libarchive-compat.h"
36 #include "alpm.h"
37 #include "alpm_list.h"
38 #include "package.h"
39 #include "handle.h"
40 #include "delta.h"
41 #include "deps.h"
42 #include "dload.h"
43 #include "filelist.h"
44 
get_sync_dir(alpm_handle_t * handle)45 static char *get_sync_dir(alpm_handle_t *handle)
46 {
47 	size_t len = strlen(handle->dbpath) + 6;
48 	char *syncpath;
49 	struct stat buf;
50 
51 	MALLOC(syncpath, len, RET_ERR(handle, ALPM_ERR_MEMORY, NULL));
52 	sprintf(syncpath, "%s%s", handle->dbpath, "sync/");
53 
54 	if(stat(syncpath, &buf) != 0) {
55 		_alpm_log(handle, ALPM_LOG_DEBUG, "database dir '%s' does not exist, creating it\n",
56 				syncpath);
57 		if(_alpm_makepath(syncpath) != 0) {
58 			free(syncpath);
59 			RET_ERR(handle, ALPM_ERR_SYSTEM, NULL);
60 		}
61 	} else if(!S_ISDIR(buf.st_mode)) {
62 		_alpm_log(handle, ALPM_LOG_WARNING, _("removing invalid file: %s\n"), syncpath);
63 		if(unlink(syncpath) != 0 || _alpm_makepath(syncpath) != 0) {
64 			free(syncpath);
65 			RET_ERR(handle, ALPM_ERR_SYSTEM, NULL);
66 		}
67 	}
68 
69 	return syncpath;
70 }
71 
sync_db_validate(alpm_db_t * db)72 static int sync_db_validate(alpm_db_t *db)
73 {
74 	int siglevel;
75 	const char *dbpath;
76 
77 	if(db->status & DB_STATUS_VALID || db->status & DB_STATUS_MISSING) {
78 		return 0;
79 	}
80 	if(db->status & DB_STATUS_INVALID) {
81 		db->handle->pm_errno = ALPM_ERR_DB_INVALID_SIG;
82 		return -1;
83 	}
84 
85 	dbpath = _alpm_db_path(db);
86 	if(!dbpath) {
87 		/* pm_errno set in _alpm_db_path() */
88 		return -1;
89 	}
90 
91 	/* we can skip any validation if the database doesn't exist */
92 	if(_alpm_access(db->handle, NULL, dbpath, R_OK) != 0 && errno == ENOENT) {
93 		alpm_event_database_missing_t event = {
94 			.type = ALPM_EVENT_DATABASE_MISSING,
95 			.dbname = db->treename
96 		};
97 		db->status &= ~DB_STATUS_EXISTS;
98 		db->status |= DB_STATUS_MISSING;
99 		EVENT(db->handle, &event);
100 		goto valid;
101 	}
102 	db->status |= DB_STATUS_EXISTS;
103 	db->status &= ~DB_STATUS_MISSING;
104 
105 	/* this takes into account the default verification level if UNKNOWN
106 	 * was assigned to this db */
107 	siglevel = alpm_db_get_siglevel(db);
108 
109 	if(siglevel & ALPM_SIG_DATABASE) {
110 		int retry, ret;
111 		do {
112 			retry = 0;
113 			alpm_siglist_t *siglist;
114 			ret = _alpm_check_pgp_helper(db->handle, dbpath, NULL,
115 					siglevel & ALPM_SIG_DATABASE_OPTIONAL, siglevel & ALPM_SIG_DATABASE_MARGINAL_OK,
116 					siglevel & ALPM_SIG_DATABASE_UNKNOWN_OK, &siglist);
117 			if(ret) {
118 				retry = _alpm_process_siglist(db->handle, db->treename, siglist,
119 						siglevel & ALPM_SIG_DATABASE_OPTIONAL, siglevel & ALPM_SIG_DATABASE_MARGINAL_OK,
120 						siglevel & ALPM_SIG_DATABASE_UNKNOWN_OK);
121 			}
122 			alpm_siglist_cleanup(siglist);
123 			free(siglist);
124 		} while(retry);
125 
126 		if(ret) {
127 			db->status &= ~DB_STATUS_VALID;
128 			db->status |= DB_STATUS_INVALID;
129 			db->handle->pm_errno = ALPM_ERR_DB_INVALID_SIG;
130 			return 1;
131 		}
132 	}
133 
134 valid:
135 	db->status |= DB_STATUS_VALID;
136 	db->status &= ~DB_STATUS_INVALID;
137 	return 0;
138 }
139 
140 /** Update a package database
141  *
142  * An update of the package database \a db will be attempted. Unless
143  * \a force is true, the update will only be performed if the remote
144  * database was modified since the last update.
145  *
146  * This operation requires a database lock, and will return an applicable error
147  * if the lock could not be obtained.
148  *
149  * Example:
150  * @code
151  * alpm_list_t *syncs = alpm_get_syncdbs();
152  * for(i = syncs; i; i = alpm_list_next(i)) {
153  *     alpm_db_t *db = alpm_list_getdata(i);
154  *     result = alpm_db_update(0, db);
155  *
156  *     if(result < 0) {
157  *	       printf("Unable to update database: %s\n", alpm_strerrorlast());
158  *     } else if(result == 1) {
159  *         printf("Database already up to date\n");
160  *     } else {
161  *         printf("Database updated\n");
162  *     }
163  * }
164  * @endcode
165  *
166  * @ingroup alpm_databases
167  * @note After a successful update, the \link alpm_db_get_pkgcache()
168  * package cache \endlink will be invalidated
169  * @param force if true, then forces the update, otherwise update only in case
170  * the database isn't up to date
171  * @param db pointer to the package database to update
172  * @return 0 on success, -1 on error (pm_errno is set accordingly), 1 if up to
173  * to date
174  */
alpm_db_update(int force,alpm_db_t * db)175 int SYMEXPORT alpm_db_update(int force, alpm_db_t *db)
176 {
177 	char *syncpath;
178 	const char *dbext;
179 	alpm_list_t *i;
180 	int updated = 0;
181 	int ret = -1;
182 	mode_t oldmask;
183 	alpm_handle_t *handle;
184 	int siglevel;
185 
186 	/* Sanity checks */
187 	ASSERT(db != NULL, return -1);
188 	handle = db->handle;
189 	handle->pm_errno = ALPM_ERR_OK;
190 	ASSERT(db != handle->db_local, RET_ERR(handle, ALPM_ERR_WRONG_ARGS, -1));
191 	ASSERT(db->servers != NULL, RET_ERR(handle, ALPM_ERR_SERVER_NONE, -1));
192 
193 	if(!(db->usage & ALPM_DB_USAGE_SYNC)) {
194 		return 0;
195 	}
196 
197 	syncpath = get_sync_dir(handle);
198 	if(!syncpath) {
199 		return -1;
200 	}
201 
202 	/* force update of invalid databases to fix potential mismatched database/signature */
203 	if(db->status & DB_STATUS_INVALID) {
204 		force = 1;
205 	}
206 
207 	/* make sure we have a sane umask */
208 	oldmask = umask(0022);
209 
210 	siglevel = alpm_db_get_siglevel(db);
211 
212 	/* attempt to grab a lock */
213 	if(_alpm_handle_lock(handle)) {
214 		free(syncpath);
215 		umask(oldmask);
216 		RET_ERR(handle, ALPM_ERR_HANDLE_LOCK, -1);
217 	}
218 
219 	dbext = db->handle->dbext;
220 
221 	for(i = db->servers; i; i = i->next) {
222 		const char *server = i->data, *final_db_url = NULL;
223 		struct dload_payload payload;
224 		size_t len;
225 		int sig_ret = 0;
226 
227 		memset(&payload, 0, sizeof(struct dload_payload));
228 
229 		/* set hard upper limit of 25MiB */
230 		payload.max_size = 25 * 1024 * 1024;
231 
232 		/* print server + filename into a buffer */
233 		len = strlen(server) + strlen(db->treename) + strlen(dbext) + 2;
234 		MALLOC(payload.fileurl, len,
235 			{
236 				free(syncpath);
237 				umask(oldmask);
238 				RET_ERR(handle, ALPM_ERR_MEMORY, -1);
239 			}
240 		);
241 		snprintf(payload.fileurl, len, "%s/%s%s", server, db->treename, dbext);
242 		payload.handle = handle;
243 		payload.force = force;
244 		payload.unlink_on_fail = 1;
245 
246 		ret = _alpm_download(&payload, syncpath, NULL, &final_db_url);
247 		_alpm_dload_payload_reset(&payload);
248 		updated = (updated || ret == 0);
249 
250 		if(ret != -1 && updated && (siglevel & ALPM_SIG_DATABASE)) {
251 			/* an existing sig file is no good at this point */
252 			char *sigpath = _alpm_sigpath(handle, _alpm_db_path(db));
253 			if(!sigpath) {
254 				ret = -1;
255 				break;
256 			}
257 			unlink(sigpath);
258 			free(sigpath);
259 
260 
261 			/* check if the final URL from internal downloader looks reasonable */
262 			if(final_db_url != NULL) {
263 				if(strlen(final_db_url) < 3
264 						|| strcmp(final_db_url + strlen(final_db_url) - strlen(dbext),
265 								dbext) != 0) {
266 					final_db_url = NULL;
267 				}
268 			}
269 
270 			/* if we downloaded a DB, we want the .sig from the same server */
271 			if(final_db_url != NULL) {
272 				/* print final_db_url into a buffer (leave space for .sig) */
273 				len = strlen(final_db_url) + 5;
274 			} else {
275 				/* print server + filename into a buffer (leave space for separator and .sig) */
276 				len = strlen(server) + strlen(db->treename) + strlen(dbext) + 6;
277 			}
278 
279 			MALLOC(payload.fileurl, len,
280 				{
281 					free(syncpath);
282 					umask(oldmask);
283 					RET_ERR(handle, ALPM_ERR_MEMORY, -1);
284 				}
285 			);
286 
287 			if(final_db_url != NULL) {
288 				snprintf(payload.fileurl, len, "%s.sig", final_db_url);
289 			} else {
290 				snprintf(payload.fileurl, len, "%s/%s%s.sig", server, db->treename, dbext);
291 			}
292 
293 			payload.handle = handle;
294 			payload.force = 1;
295 			payload.errors_ok = (siglevel & ALPM_SIG_DATABASE_OPTIONAL);
296 
297 			/* set hard upper limit of 16KiB */
298 			payload.max_size = 16 * 1024;
299 
300 			sig_ret = _alpm_download(&payload, syncpath, NULL, NULL);
301 			/* errors_ok suppresses error messages, but not the return code */
302 			sig_ret = payload.errors_ok ? 0 : sig_ret;
303 			_alpm_dload_payload_reset(&payload);
304 		}
305 
306 		if(ret != -1 && sig_ret != -1) {
307 			break;
308 		}
309 	}
310 
311 	if(updated) {
312 		/* Cache needs to be rebuilt */
313 		_alpm_db_free_pkgcache(db);
314 
315 		/* clear all status flags regarding validity/existence */
316 		db->status &= ~DB_STATUS_VALID;
317 		db->status &= ~DB_STATUS_INVALID;
318 		db->status &= ~DB_STATUS_EXISTS;
319 		db->status &= ~DB_STATUS_MISSING;
320 
321 		/* if the download failed skip validation to preserve the download error */
322 		if(ret != -1 && sync_db_validate(db) != 0) {
323 			/* pm_errno should be set */
324 			ret = -1;
325 		}
326 	}
327 
328 	if(ret == -1) {
329 		/* pm_errno was set by the download code */
330 		_alpm_log(handle, ALPM_LOG_DEBUG, "failed to sync db: %s\n",
331 				alpm_strerror(handle->pm_errno));
332 	} else {
333 		handle->pm_errno = ALPM_ERR_OK;
334 	}
335 
336 	_alpm_handle_unlock(handle);
337 	free(syncpath);
338 	umask(oldmask);
339 	return ret;
340 }
341 
342 /* Forward decl so I don't reorganize the whole file right now */
343 static int sync_db_read(alpm_db_t *db, struct archive *archive,
344 		struct archive_entry *entry, alpm_pkg_t **likely_pkg);
345 
_sync_get_validation(alpm_pkg_t * pkg)346 static int _sync_get_validation(alpm_pkg_t *pkg)
347 {
348 	if(pkg->validation) {
349 		return pkg->validation;
350 	}
351 
352 	if(pkg->md5sum) {
353 		pkg->validation |= ALPM_PKG_VALIDATION_MD5SUM;
354 	}
355 	if(pkg->sha256sum) {
356 		pkg->validation |= ALPM_PKG_VALIDATION_SHA256SUM;
357 	}
358 	if(pkg->base64_sig) {
359 		pkg->validation |= ALPM_PKG_VALIDATION_SIGNATURE;
360 	}
361 
362 	if(!pkg->validation) {
363 		pkg->validation |= ALPM_PKG_VALIDATION_NONE;
364 	}
365 
366 	return pkg->validation;
367 }
368 
load_pkg_for_entry(alpm_db_t * db,const char * entryname,const char ** entry_filename,alpm_pkg_t * likely_pkg)369 static alpm_pkg_t *load_pkg_for_entry(alpm_db_t *db, const char *entryname,
370 		const char **entry_filename, alpm_pkg_t *likely_pkg)
371 {
372 	char *pkgname = NULL, *pkgver = NULL;
373 	unsigned long pkgname_hash;
374 	alpm_pkg_t *pkg;
375 
376 	/* get package and db file names */
377 	if(entry_filename) {
378 		char *fname = strrchr(entryname, '/');
379 		if(fname) {
380 			*entry_filename = fname + 1;
381 		} else {
382 			*entry_filename = NULL;
383 		}
384 	}
385 	if(_alpm_splitname(entryname, &pkgname, &pkgver, &pkgname_hash) != 0) {
386 		_alpm_log(db->handle, ALPM_LOG_ERROR,
387 				_("invalid name for database entry '%s'\n"), entryname);
388 		return NULL;
389 	}
390 
391 	if(likely_pkg && pkgname_hash == likely_pkg->name_hash
392 			&& strcmp(likely_pkg->name, pkgname) == 0) {
393 		pkg = likely_pkg;
394 	} else {
395 		pkg = _alpm_pkghash_find(db->pkgcache, pkgname);
396 	}
397 	if(pkg == NULL) {
398 		pkg = _alpm_pkg_new();
399 		if(pkg == NULL) {
400 			RET_ERR(db->handle, ALPM_ERR_MEMORY, NULL);
401 		}
402 
403 		pkg->name = pkgname;
404 		pkg->version = pkgver;
405 		pkg->name_hash = pkgname_hash;
406 
407 		pkg->origin = ALPM_PKG_FROM_SYNCDB;
408 		pkg->origin_data.db = db;
409 		pkg->ops = &default_pkg_ops;
410 		pkg->ops->get_validation = _sync_get_validation;
411 		pkg->handle = db->handle;
412 
413 		/* add to the collection */
414 		_alpm_log(db->handle, ALPM_LOG_FUNCTION, "adding '%s' to package cache for db '%s'\n",
415 				pkg->name, db->treename);
416 		if(_alpm_pkghash_add(&db->pkgcache, pkg) == NULL) {
417 			_alpm_pkg_free(pkg);
418 			RET_ERR(db->handle, ALPM_ERR_MEMORY, NULL);
419 		}
420 	} else {
421 		free(pkgname);
422 		free(pkgver);
423 	}
424 
425 	return pkg;
426 }
427 
428 /* This function doesn't work as well as one might think, as size of database
429  * entries varies considerably. Adding signatures nearly doubles the size of a
430  * single entry; deltas also can make for large variations in size. These
431  * current values are heavily influenced by Arch Linux; databases with no
432  * deltas and a single signature per package. */
estimate_package_count(struct stat * st,struct archive * archive)433 static size_t estimate_package_count(struct stat *st, struct archive *archive)
434 {
435 	int per_package;
436 
437 	switch(_alpm_archive_filter_code(archive)) {
438 		case ARCHIVE_COMPRESSION_NONE:
439 			per_package = 3015;
440 			break;
441 		case ARCHIVE_COMPRESSION_GZIP:
442 		case ARCHIVE_COMPRESSION_COMPRESS:
443 			per_package = 464;
444 			break;
445 		case ARCHIVE_COMPRESSION_BZIP2:
446 			per_package = 394;
447 			break;
448 		case ARCHIVE_COMPRESSION_LZMA:
449 		case ARCHIVE_COMPRESSION_XZ:
450 			per_package = 400;
451 			break;
452 #ifdef ARCHIVE_COMPRESSION_UU
453 		case ARCHIVE_COMPRESSION_UU:
454 			per_package = 3015 * 4 / 3;
455 			break;
456 #endif
457 		default:
458 			/* assume it is at least somewhat compressed */
459 			per_package = 500;
460 	}
461 
462 	return (size_t)((st->st_size / per_package) + 1);
463 }
464 
sync_db_populate(alpm_db_t * db)465 static int sync_db_populate(alpm_db_t *db)
466 {
467 	const char *dbpath;
468 	size_t est_count, count;
469 	int fd;
470 	int ret = 0;
471 	int archive_ret;
472 	struct stat buf;
473 	struct archive *archive;
474 	struct archive_entry *entry;
475 	alpm_pkg_t *pkg = NULL;
476 
477 	if(db->status & DB_STATUS_INVALID) {
478 		RET_ERR(db->handle, ALPM_ERR_DB_INVALID, -1);
479 	}
480 	if(db->status & DB_STATUS_MISSING) {
481 		RET_ERR(db->handle, ALPM_ERR_DB_NOT_FOUND, -1);
482 	}
483 	dbpath = _alpm_db_path(db);
484 	if(!dbpath) {
485 		/* pm_errno set in _alpm_db_path() */
486 		return -1;
487 	}
488 
489 	fd = _alpm_open_archive(db->handle, dbpath, &buf,
490 			&archive, ALPM_ERR_DB_OPEN);
491 	if(fd < 0) {
492 		db->status &= ~DB_STATUS_VALID;
493 		db->status |= DB_STATUS_INVALID;
494 		return -1;
495 	}
496 	est_count = estimate_package_count(&buf, archive);
497 
498 	/* currently only .files dbs contain file lists - make flexible when required*/
499 	if(strcmp(db->handle->dbext, ".files") == 0) {
500 		/* files databases are about four times larger on average */
501 		est_count /= 4;
502 	}
503 
504 	db->pkgcache = _alpm_pkghash_create(est_count);
505 	if(db->pkgcache == NULL) {
506 		db->handle->pm_errno = ALPM_ERR_MEMORY;
507 		ret = -1;
508 		goto cleanup;
509 	}
510 
511 	while((archive_ret = archive_read_next_header(archive, &entry)) == ARCHIVE_OK) {
512 		mode_t mode = archive_entry_mode(entry);
513 		if(!S_ISDIR(mode)) {
514 			/* we have desc, depends or deltas - parse it */
515 			if(sync_db_read(db, archive, entry, &pkg) != 0) {
516 				_alpm_log(db->handle, ALPM_LOG_ERROR,
517 						_("could not parse package description file '%s' from db '%s'\n"),
518 						archive_entry_pathname(entry), db->treename);
519 				ret = -1;
520 			}
521 		}
522 	}
523 	if(archive_ret != ARCHIVE_EOF) {
524 		_alpm_log(db->handle, ALPM_LOG_ERROR, _("could not read db '%s' (%s)\n"),
525 				db->treename, archive_error_string(archive));
526 		_alpm_db_free_pkgcache(db);
527 		db->handle->pm_errno = ALPM_ERR_LIBARCHIVE;
528 		ret = -1;
529 		goto cleanup;
530 	}
531 
532 	count = alpm_list_count(db->pkgcache->list);
533 	if(count > 0) {
534 		db->pkgcache->list = alpm_list_msort(db->pkgcache->list,
535 				count, _alpm_pkg_cmp);
536 	}
537 	_alpm_log(db->handle, ALPM_LOG_DEBUG,
538 			"added %zu packages to package cache for db '%s'\n",
539 			count, db->treename);
540 
541 cleanup:
542 	_alpm_archive_read_free(archive);
543 	if(fd >= 0) {
544 		close(fd);
545 	}
546 	return ret;
547 }
548 
549 /* This function validates %FILENAME%. filename must be between 3 and
550  * PATH_MAX characters and cannot be contain a path */
_alpm_validate_filename(alpm_db_t * db,const char * pkgname,const char * filename)551 static int _alpm_validate_filename(alpm_db_t *db, const char *pkgname,
552 		const char *filename)
553 {
554 	size_t len = strlen(filename);
555 
556 	if(filename[0] == '.') {
557 		errno = EINVAL;
558 		_alpm_log(db->handle, ALPM_LOG_ERROR, _("%s database is inconsistent: filename "
559 					"of package %s is illegal\n"), db->treename, pkgname);
560 		return -1;
561 	} else if(memchr(filename, '/', len) != NULL) {
562 		errno = EINVAL;
563 		_alpm_log(db->handle, ALPM_LOG_ERROR, _("%s database is inconsistent: filename "
564 					"of package %s is illegal\n"), db->treename, pkgname);
565 		return -1;
566 	} else if(len > PATH_MAX) {
567 		errno = EINVAL;
568 		_alpm_log(db->handle, ALPM_LOG_ERROR, _("%s database is inconsistent: filename "
569 					"of package %s is too long\n"), db->treename, pkgname);
570 		return -1;
571 	}
572 
573 	return 0;
574 }
575 
576 #define READ_NEXT() do { \
577 	if(_alpm_archive_fgets(archive, &buf) != ARCHIVE_OK) goto error; \
578 	line = buf.line; \
579 	_alpm_strip_newline(line, buf.real_line_size); \
580 } while(0)
581 
582 #define READ_AND_STORE(f) do { \
583 	READ_NEXT(); \
584 	STRDUP(f, line, goto error); \
585 } while(0)
586 
587 #define READ_AND_STORE_ALL(f) do { \
588 	char *linedup; \
589 	if(_alpm_archive_fgets(archive, &buf) != ARCHIVE_OK) goto error; \
590 	if(_alpm_strip_newline(buf.line, buf.real_line_size) == 0) break; \
591 	STRDUP(linedup, buf.line, goto error); \
592 	f = alpm_list_add(f, linedup); \
593 } while(1) /* note the while(1) and not (0) */
594 
595 #define READ_AND_SPLITDEP(f) do { \
596 	if(_alpm_archive_fgets(archive, &buf) != ARCHIVE_OK) goto error; \
597 	if(_alpm_strip_newline(buf.line, buf.real_line_size) == 0) break; \
598 	f = alpm_list_add(f, alpm_dep_from_string(line)); \
599 } while(1) /* note the while(1) and not (0) */
600 
sync_db_read(alpm_db_t * db,struct archive * archive,struct archive_entry * entry,alpm_pkg_t ** likely_pkg)601 static int sync_db_read(alpm_db_t *db, struct archive *archive,
602 		struct archive_entry *entry, alpm_pkg_t **likely_pkg)
603 {
604 	const char *entryname, *filename;
605 	alpm_pkg_t *pkg;
606 	struct archive_read_buffer buf;
607 
608 	entryname = archive_entry_pathname(entry);
609 	if(entryname == NULL) {
610 		_alpm_log(db->handle, ALPM_LOG_DEBUG,
611 				"invalid archive entry provided to _alpm_sync_db_read, skipping\n");
612 		return -1;
613 	}
614 
615 	_alpm_log(db->handle, ALPM_LOG_FUNCTION, "loading package data from archive entry %s\n",
616 			entryname);
617 
618 	memset(&buf, 0, sizeof(buf));
619 	/* 512K for a line length seems reasonable */
620 	buf.max_line_size = 512 * 1024;
621 
622 	pkg = load_pkg_for_entry(db, entryname, &filename, *likely_pkg);
623 
624 	if(pkg == NULL) {
625 		_alpm_log(db->handle, ALPM_LOG_DEBUG,
626 				"entry %s could not be loaded into %s sync database\n",
627 				entryname, db->treename);
628 		return -1;
629 	}
630 
631 	if(filename == NULL) {
632 		/* A file exists outside of a subdirectory. This isn't a read error, so return
633 		 * success and try to continue on. */
634 		_alpm_log(db->handle, ALPM_LOG_WARNING, _("unknown database file: %s\n"),
635 				entryname);
636 		return 0;
637 	}
638 
639 	if(strcmp(filename, "desc") == 0 || strcmp(filename, "depends") == 0
640 			|| strcmp(filename, "files") == 0
641 			|| (strcmp(filename, "deltas") == 0 && db->handle->deltaratio > 0.0) ) {
642 		int ret;
643 		while((ret = _alpm_archive_fgets(archive, &buf)) == ARCHIVE_OK) {
644 			char *line = buf.line;
645 			if(_alpm_strip_newline(line, buf.real_line_size) == 0) {
646 				/* length of stripped line was zero */
647 				continue;
648 			}
649 
650 			if(strcmp(line, "%NAME%") == 0) {
651 				READ_NEXT();
652 				if(strcmp(line, pkg->name) != 0) {
653 					_alpm_log(db->handle, ALPM_LOG_ERROR, _("%s database is inconsistent: name "
654 								"mismatch on package %s\n"), db->treename, pkg->name);
655 				}
656 			} else if(strcmp(line, "%VERSION%") == 0) {
657 				READ_NEXT();
658 				if(strcmp(line, pkg->version) != 0) {
659 					_alpm_log(db->handle, ALPM_LOG_ERROR, _("%s database is inconsistent: version "
660 								"mismatch on package %s\n"), db->treename, pkg->name);
661 				}
662 			} else if(strcmp(line, "%FILENAME%") == 0) {
663 				READ_AND_STORE(pkg->filename);
664 				if(_alpm_validate_filename(db, pkg->name, pkg->filename) < 0) {
665 					return -1;
666 				}
667 			} else if(strcmp(line, "%BASE%") == 0) {
668 				READ_AND_STORE(pkg->base);
669 			} else if(strcmp(line, "%DESC%") == 0) {
670 				READ_AND_STORE(pkg->desc);
671 			} else if(strcmp(line, "%GROUPS%") == 0) {
672 				READ_AND_STORE_ALL(pkg->groups);
673 			} else if(strcmp(line, "%URL%") == 0) {
674 				READ_AND_STORE(pkg->url);
675 			} else if(strcmp(line, "%LICENSE%") == 0) {
676 				READ_AND_STORE_ALL(pkg->licenses);
677 			} else if(strcmp(line, "%ARCH%") == 0) {
678 				READ_AND_STORE(pkg->arch);
679 			} else if(strcmp(line, "%BUILDDATE%") == 0) {
680 				READ_NEXT();
681 				pkg->builddate = _alpm_parsedate(line);
682 			} else if(strcmp(line, "%PACKAGER%") == 0) {
683 				READ_AND_STORE(pkg->packager);
684 			} else if(strcmp(line, "%CSIZE%") == 0) {
685 				READ_NEXT();
686 				pkg->size = _alpm_strtoofft(line);
687 			} else if(strcmp(line, "%ISIZE%") == 0) {
688 				READ_NEXT();
689 				pkg->isize = _alpm_strtoofft(line);
690 			} else if(strcmp(line, "%MD5SUM%") == 0) {
691 				READ_AND_STORE(pkg->md5sum);
692 			} else if(strcmp(line, "%SHA256SUM%") == 0) {
693 				READ_AND_STORE(pkg->sha256sum);
694 			} else if(strcmp(line, "%PGPSIG%") == 0) {
695 				READ_AND_STORE(pkg->base64_sig);
696 			} else if(strcmp(line, "%REPLACES%") == 0) {
697 				READ_AND_SPLITDEP(pkg->replaces);
698 			} else if(strcmp(line, "%DEPENDS%") == 0) {
699 				READ_AND_SPLITDEP(pkg->depends);
700 			} else if(strcmp(line, "%OPTDEPENDS%") == 0) {
701 				READ_AND_SPLITDEP(pkg->optdepends);
702 			} else if(strcmp(line, "%MAKEDEPENDS%") == 0) {
703 				/* currently unused */
704 				while(1) {
705 					READ_NEXT();
706 					if(strlen(line) == 0) break;
707 				}
708 			} else if(strcmp(line, "%CHECKDEPENDS%") == 0) {
709 				/* currently unused */
710 				while(1) {
711 					READ_NEXT();
712 					if(strlen(line) == 0) break;
713 				}
714 			} else if(strcmp(line, "%CONFLICTS%") == 0) {
715 				READ_AND_SPLITDEP(pkg->conflicts);
716 			} else if(strcmp(line, "%PROVIDES%") == 0) {
717 				READ_AND_SPLITDEP(pkg->provides);
718 			} else if(strcmp(line, "%DELTAS%") == 0) {
719 				/* Different than the rest because of the _alpm_delta_parse call. */
720 				while(1) {
721 					READ_NEXT();
722 					if(strlen(line) == 0) break;
723 					pkg->deltas = alpm_list_add(pkg->deltas,
724 							_alpm_delta_parse(db->handle, line));
725 				}
726 			} else if(strcmp(line, "%FILES%") == 0) {
727 				/* TODO: this could lazy load if there is future demand */
728 				size_t files_count = 0, files_size = 0;
729 				alpm_file_t *files = NULL;
730 
731 				while(1) {
732 					if(_alpm_archive_fgets(archive, &buf) != ARCHIVE_OK) {
733 						goto error;
734 					}
735 					line = buf.line;
736 					if(_alpm_strip_newline(line, buf.real_line_size) == 0) {
737 						break;
738 					}
739 
740 					if(!_alpm_greedy_grow((void **)&files, &files_size,
741 								(files_count ? (files_count + 1) * sizeof(alpm_file_t) : 8 * sizeof(alpm_file_t)))) {
742 						goto error;
743 					}
744 					STRDUP(files[files_count].name, line, goto error);
745 					files_count++;
746 				}
747 				/* attempt to hand back any memory we don't need */
748 				if(files_count > 0) {
749 					files = realloc(files, sizeof(alpm_file_t) * files_count);
750 				} else {
751 					FREE(files);
752 				}
753 				pkg->files.count = files_count;
754 				pkg->files.files = files;
755 				_alpm_filelist_sort(&pkg->files);
756 			}
757 		}
758 		if(ret != ARCHIVE_EOF) {
759 			goto error;
760 		}
761 		*likely_pkg = pkg;
762 	} else if(strcmp(filename, "deltas") == 0) {
763 		/* skip reading delta files if UseDelta is unset */
764 	} else {
765 		/* unknown database file */
766 		_alpm_log(db->handle, ALPM_LOG_DEBUG, "unknown database file: %s\n", filename);
767 	}
768 
769 	return 0;
770 
771 error:
772 	_alpm_log(db->handle, ALPM_LOG_DEBUG, "error parsing database file: %s\n", filename);
773 	return -1;
774 }
775 
776 struct db_operations sync_db_ops = {
777 	.validate         = sync_db_validate,
778 	.populate         = sync_db_populate,
779 	.unregister       = _alpm_db_unregister,
780 };
781 
_alpm_db_register_sync(alpm_handle_t * handle,const char * treename,int level)782 alpm_db_t *_alpm_db_register_sync(alpm_handle_t *handle, const char *treename,
783 		int level)
784 {
785 	alpm_db_t *db;
786 
787 	_alpm_log(handle, ALPM_LOG_DEBUG, "registering sync database '%s'\n", treename);
788 
789 #ifndef HAVE_LIBGPGME
790 	if(level != 0 && level != ALPM_SIG_USE_DEFAULT) {
791 		RET_ERR(handle, ALPM_ERR_WRONG_ARGS, NULL);
792 	}
793 #endif
794 
795 	db = _alpm_db_new(treename, 0);
796 	if(db == NULL) {
797 		RET_ERR(handle, ALPM_ERR_DB_CREATE, NULL);
798 	}
799 	db->ops = &sync_db_ops;
800 	db->handle = handle;
801 	db->siglevel = level;
802 
803 	sync_db_validate(db);
804 
805 	handle->dbs_sync = alpm_list_add(handle->dbs_sync, db);
806 	return db;
807 }
808