static void graph_init_size(pmhandle_t *handle, alpm_list_t *vertices) { alpm_list_t *i; for(i = vertices; i; i = i->next) { char *fpath, *md5sum; pmgraph_t *v = i->data; pmdelta_t *vdelta = v->data; /* determine whether the delta file already exists */ fpath = _alpm_filecache_find(handle, vdelta->delta); md5sum = alpm_compute_md5sum(fpath); if(fpath && md5sum && strcmp(md5sum, vdelta->delta_md5) == 0) { vdelta->download_size = 0; } FREE(fpath); FREE(md5sum); /* determine whether a base 'from' file exists */ fpath = _alpm_filecache_find(handle, vdelta->from); if(fpath) { v->weight = vdelta->download_size; } FREE(fpath); } }
static int validate_deltas(alpm_handle_t *handle, alpm_list_t *deltas) { alpm_list_t *i, *errors = NULL; if(!deltas) { return 0; } /* Check integrity of deltas */ EVENT(handle, ALPM_EVENT_DELTA_INTEGRITY_START, NULL, NULL); for(i = deltas; i; i = i->next) { alpm_delta_t *d = i->data; char *filepath = _alpm_filecache_find(handle, d->delta); if(_alpm_test_checksum(filepath, d->delta_md5, ALPM_PKG_VALIDATION_MD5SUM)) { errors = alpm_list_add(errors, filepath); } else { FREE(filepath); } } EVENT(handle, ALPM_EVENT_DELTA_INTEGRITY_DONE, NULL, NULL); if(errors) { for(i = errors; i; i = i->next) { char *filepath = i->data; prompt_to_delete(handle, filepath, ALPM_ERR_DLT_INVALID); FREE(filepath); } alpm_list_free(errors); handle->pm_errno = ALPM_ERR_DLT_INVALID; return -1; } return 0; }
static void graph_init_size(alpm_handle_t *handle, alpm_list_t *vertices) { alpm_list_t *i; for(i = vertices; i; i = i->next) { char *fpath, *md5sum; alpm_graph_t *v = i->data; alpm_delta_t *vdelta = v->data; /* determine whether the delta file already exists */ fpath = _alpm_filecache_find(handle, vdelta->delta); if(fpath) { md5sum = alpm_compute_md5sum(fpath); if(md5sum && strcmp(md5sum, vdelta->delta_md5) == 0) { vdelta->download_size = 0; } FREE(md5sum); FREE(fpath); } else { char *fnamepart; CALLOC(fnamepart, strlen(vdelta->delta) + 6, sizeof(char), return); sprintf(fnamepart, "%s.part", vdelta->delta); fpath = _alpm_filecache_find(handle, fnamepart); if(fpath) { struct stat st; if(stat(fpath, &st) == 0) { vdelta->download_size = vdelta->delta_size - st.st_size; vdelta->download_size = vdelta->download_size < 0 ? 0 : vdelta->download_size; } FREE(fpath); } FREE(fnamepart); } /* determine whether a base 'from' file exists */ fpath = _alpm_filecache_find(handle, vdelta->from); if(fpath) { v->weight = vdelta->download_size; } FREE(fpath); } }
/** Compute the size of the files that will be downloaded to install a * package. * @param newpkg the new package to upgrade to */ static int compute_download_size(alpm_pkg_t *newpkg) { const char *fname; char *fpath; off_t size = 0; alpm_handle_t *handle = newpkg->handle; if(newpkg->origin != PKG_FROM_SYNCDB) { newpkg->infolevel |= INFRQ_DSIZE; newpkg->download_size = 0; return 0; } fname = alpm_pkg_get_filename(newpkg); ASSERT(fname != NULL, RET_ERR(handle, ALPM_ERR_PKG_INVALID_NAME, -1)); fpath = _alpm_filecache_find(handle, fname); if(fpath) { FREE(fpath); size = 0; } else if(handle->usedelta) { off_t dltsize; off_t pkgsize = alpm_pkg_get_size(newpkg); dltsize = _alpm_shortest_delta_path(handle, alpm_pkg_get_deltas(newpkg), alpm_pkg_get_filename(newpkg), &newpkg->delta_path); if(newpkg->delta_path && (dltsize < pkgsize * MAX_DELTA_RATIO)) { _alpm_log(handle, ALPM_LOG_DEBUG, "using delta size\n"); size = dltsize; } else { _alpm_log(handle, ALPM_LOG_DEBUG, "using package size\n"); size = alpm_pkg_get_size(newpkg); alpm_list_free(newpkg->delta_path); newpkg->delta_path = NULL; } } else { size = alpm_pkg_get_size(newpkg); } _alpm_log(handle, ALPM_LOG_DEBUG, "setting download size %jd for pkg %s\n", (intmax_t)size, alpm_pkg_get_name(newpkg)); newpkg->infolevel |= INFRQ_DSIZE; newpkg->download_size = size; return 0; }
static char *filecache_find_url(alpm_handle_t *handle, const char *url) { const char *filebase = strrchr(url, '/'); if(filebase == NULL) { return NULL; } filebase++; if(filebase == '\0') { return NULL; } return _alpm_filecache_find(handle, filebase); }
static int validate_deltas(alpm_handle_t *handle, alpm_list_t *deltas, alpm_list_t **data) { int errors = 0, ret = 0; alpm_list_t *i; alpm_trans_t *trans = handle->trans; if(!deltas) { return 0; } /* Check integrity of deltas */ EVENT(trans, ALPM_TRANS_EVT_DELTA_INTEGRITY_START, NULL, NULL); for(i = deltas; i; i = i->next) { alpm_delta_t *d = alpm_list_getdata(i); char *filepath = _alpm_filecache_find(handle, d->delta); if(test_md5sum(trans, filepath, d->delta_md5) != 0) { errors++; *data = alpm_list_add(*data, strdup(d->delta)); } FREE(filepath); } if(errors) { handle->pm_errno = ALPM_ERR_DLT_INVALID; return -1; } EVENT(trans, ALPM_TRANS_EVT_DELTA_INTEGRITY_DONE, NULL, NULL); /* Use the deltas to generate the packages */ EVENT(trans, ALPM_TRANS_EVT_DELTA_PATCHES_START, NULL, NULL); ret = apply_deltas(handle); EVENT(trans, ALPM_TRANS_EVT_DELTA_PATCHES_DONE, NULL, NULL); return ret; }
/** Compute the size of the files that will be downloaded to install a * package. * @param newpkg the new package to upgrade to */ static int compute_download_size(alpm_pkg_t *newpkg) { const char *fname; char *fpath, *fnamepart = NULL; off_t size = 0; alpm_handle_t *handle = newpkg->handle; int ret = 0; if(newpkg->origin != ALPM_PKG_FROM_SYNCDB) { newpkg->infolevel |= INFRQ_DSIZE; newpkg->download_size = 0; return 0; } ASSERT(newpkg->filename != NULL, RET_ERR(handle, ALPM_ERR_PKG_INVALID_NAME, -1)); fname = newpkg->filename; fpath = _alpm_filecache_find(handle, fname); /* downloaded file exists, so there's nothing to grab */ if(fpath) { size = 0; goto finish; } CALLOC(fnamepart, strlen(fname) + 6, sizeof(char), return -1); sprintf(fnamepart, "%s.part", fname); fpath = _alpm_filecache_find(handle, fnamepart); if(fpath) { struct stat st; if(stat(fpath, &st) == 0) { /* subtract the size of the .part file */ _alpm_log(handle, ALPM_LOG_DEBUG, "using (package - .part) size\n"); size = newpkg->size - st.st_size; size = size < 0 ? 0 : size; } /* tell the caller that we have a partial */ ret = 1; } else if(handle->deltaratio > 0.0) { off_t dltsize; dltsize = _alpm_shortest_delta_path(handle, newpkg->deltas, newpkg->filename, &newpkg->delta_path); if(newpkg->delta_path && (dltsize < newpkg->size * handle->deltaratio)) { _alpm_log(handle, ALPM_LOG_DEBUG, "using delta size\n"); size = dltsize; } else { _alpm_log(handle, ALPM_LOG_DEBUG, "using package size\n"); size = newpkg->size; alpm_list_free(newpkg->delta_path); newpkg->delta_path = NULL; } } else { size = newpkg->size; } finish: _alpm_log(handle, ALPM_LOG_DEBUG, "setting download size %jd for pkg %s\n", (intmax_t)size, newpkg->name); newpkg->infolevel |= INFRQ_DSIZE; newpkg->download_size = size; FREE(fpath); FREE(fnamepart); return ret; }
/** Fetch a remote pkg. */ char SYMEXPORT *alpm_fetch_pkgurl(alpm_handle_t *handle, const char *url) { char *filepath; const char *cachedir; char *final_file = NULL, *final_pkg_url = NULL; struct dload_payload payload; int ret = 0; CHECK_HANDLE(handle, return NULL); ASSERT(url, RET_ERR(handle, ALPM_ERR_WRONG_ARGS, NULL)); /* find a valid cache dir to download to */ cachedir = _alpm_filecache_setup(handle); memset(&payload, 0, sizeof(struct dload_payload)); /* attempt to find the file in our pkgcache */ filepath = filecache_find_url(handle, url); if(filepath == NULL) { STRDUP(payload.fileurl, url, RET_ERR(handle, ALPM_ERR_MEMORY, NULL)); payload.allow_resume = 1; payload.handle = handle; payload.trust_remote_name = 1; /* download the file */ ret = _alpm_download(&payload, cachedir, &final_file, &final_pkg_url); _alpm_dload_payload_reset(&payload); if(ret == -1) { _alpm_log(handle, ALPM_LOG_WARNING, _("failed to download %s\n"), url); free(final_file); return NULL; } _alpm_log(handle, ALPM_LOG_DEBUG, "successfully downloaded %s\n", url); } /* attempt to download the signature */ if(ret == 0 && final_pkg_url && (handle->siglevel & ALPM_SIG_PACKAGE)) { char *sig_filepath, *sig_final_file = NULL; size_t len; len = strlen(final_pkg_url) + 5; MALLOC(payload.fileurl, len, RET_ERR(handle, ALPM_ERR_MEMORY, NULL)); snprintf(payload.fileurl, len, "%s.sig", final_pkg_url); sig_filepath = filecache_find_url(handle, payload.fileurl); if(sig_filepath == NULL) { payload.handle = handle; payload.trust_remote_name = 1; payload.force = 1; payload.errors_ok = (handle->siglevel & ALPM_SIG_PACKAGE_OPTIONAL); /* set hard upper limit of 16KiB */ payload.max_size = 16 * 1024; ret = _alpm_download(&payload, cachedir, &sig_final_file, NULL); if(ret == -1 && !payload.errors_ok) { _alpm_log(handle, ALPM_LOG_WARNING, _("failed to download %s\n"), payload.fileurl); /* Warn now, but don't return NULL. We will fail later during package * load time. */ } else if(ret == 0) { _alpm_log(handle, ALPM_LOG_DEBUG, "successfully downloaded %s\n", payload.fileurl); } FREE(sig_final_file); } free(sig_filepath); _alpm_dload_payload_reset(&payload); } /* we should be able to find the file the second time around */ if(filepath == NULL) { filepath = _alpm_filecache_find(handle, final_file); } free(final_file); return filepath; }
int _alpm_sync_commit(alpm_handle_t *handle, alpm_list_t **data) { alpm_list_t *i; alpm_list_t *deltas = NULL; size_t numtargs, current = 0, replaces = 0; int errors; alpm_trans_t *trans = handle->trans; if(download_files(handle, &deltas)) { alpm_list_free(deltas); return -1; } if(validate_deltas(handle, deltas, data)) { alpm_list_free(deltas); return -1; } alpm_list_free(deltas); /* Check integrity of packages */ numtargs = alpm_list_count(trans->add); EVENT(trans, ALPM_TRANS_EVT_INTEGRITY_START, NULL, NULL); errors = 0; for(i = trans->add; i; i = i->next, current++) { alpm_pkg_t *spkg = i->data; int percent = (current * 100) / numtargs; const char *filename; char *filepath; alpm_siglevel_t level; PROGRESS(trans, ALPM_TRANS_PROGRESS_INTEGRITY_START, "", percent, numtargs, current); if(spkg->origin == PKG_FROM_FILE) { continue; /* pkg_load() has been already called, this package is valid */ } filename = alpm_pkg_get_filename(spkg); filepath = _alpm_filecache_find(handle, filename); alpm_db_t *sdb = alpm_pkg_get_db(spkg); level = alpm_db_get_siglevel(sdb); /* load the package file and replace pkgcache entry with it in the target list */ /* TODO: alpm_pkg_get_db() will not work on this target anymore */ _alpm_log(handle, ALPM_LOG_DEBUG, "replacing pkgcache entry with package file for target %s\n", spkg->name); alpm_pkg_t *pkgfile =_alpm_pkg_load_internal(handle, filepath, 1, spkg->md5sum, spkg->base64_sig, level); if(!pkgfile) { errors++; *data = alpm_list_add(*data, strdup(filename)); FREE(filepath); continue; } FREE(filepath); pkgfile->reason = spkg->reason; /* copy over install reason */ i->data = pkgfile; _alpm_pkg_free_trans(spkg); /* spkg has been removed from the target list */ } PROGRESS(trans, ALPM_TRANS_PROGRESS_INTEGRITY_START, "", 100, numtargs, current); EVENT(trans, ALPM_TRANS_EVT_INTEGRITY_DONE, NULL, NULL); if(errors) { RET_ERR(handle, ALPM_ERR_PKG_INVALID, -1); } if(trans->flags & ALPM_TRANS_FLAG_DOWNLOADONLY) { return 0; } trans->state = STATE_COMMITING; replaces = alpm_list_count(trans->remove); /* fileconflict check */ if(!(trans->flags & ALPM_TRANS_FLAG_FORCE)) { EVENT(trans, ALPM_TRANS_EVT_FILECONFLICTS_START, NULL, NULL); _alpm_log(handle, ALPM_LOG_DEBUG, "looking for file conflicts\n"); alpm_list_t *conflict = _alpm_db_find_fileconflicts(handle, trans->add, trans->remove); if(conflict) { if(data) { *data = conflict; } else { alpm_list_free_inner(conflict, (alpm_list_fn_free)_alpm_fileconflict_free); alpm_list_free(conflict); } RET_ERR(handle, ALPM_ERR_FILE_CONFLICTS, -1); } EVENT(trans, ALPM_TRANS_EVT_FILECONFLICTS_DONE, NULL, NULL); } /* check available disk space */ if(handle->checkspace) { EVENT(trans, ALPM_TRANS_EVT_DISKSPACE_START, NULL, NULL); _alpm_log(handle, ALPM_LOG_DEBUG, "checking available disk space\n"); if(_alpm_check_diskspace(handle) == -1) { _alpm_log(handle, ALPM_LOG_ERROR, "%s\n", _("not enough free disk space")); return -1; } EVENT(trans, ALPM_TRANS_EVT_DISKSPACE_DONE, NULL, NULL); } /* remove conflicting and to-be-replaced packages */ if(replaces) { _alpm_log(handle, ALPM_LOG_DEBUG, "removing conflicting and to-be-replaced packages\n"); /* we want the frontend to be aware of commit details */ if(_alpm_remove_packages(handle) == -1) { _alpm_log(handle, ALPM_LOG_ERROR, _("could not commit removal transaction\n")); return -1; } } /* install targets */ _alpm_log(handle, ALPM_LOG_DEBUG, "installing packages\n"); if(_alpm_upgrade_packages(handle) == -1) { _alpm_log(handle, ALPM_LOG_ERROR, _("could not commit transaction\n")); return -1; } return 0; }
/** Applies delta files to create an upgraded package file. * * All intermediate files are deleted, leaving only the starting and * ending package files. * * @param handle the context handle * * @return 0 if all delta files were able to be applied, 1 otherwise. */ static int apply_deltas(alpm_handle_t *handle) { alpm_list_t *i; int ret = 0; const char *cachedir = _alpm_filecache_setup(handle); alpm_trans_t *trans = handle->trans; for(i = trans->add; i; i = i->next) { alpm_pkg_t *spkg = i->data; alpm_list_t *delta_path = spkg->delta_path; alpm_list_t *dlts = NULL; if(!delta_path) { continue; } for(dlts = delta_path; dlts; dlts = dlts->next) { alpm_delta_t *d = dlts->data; char *delta, *from, *to; char command[PATH_MAX]; size_t len = 0; delta = _alpm_filecache_find(handle, d->delta); /* the initial package might be in a different cachedir */ if(dlts == delta_path) { from = _alpm_filecache_find(handle, d->from); } else { /* len = cachedir len + from len + '/' + null */ len = strlen(cachedir) + strlen(d->from) + 2; CALLOC(from, len, sizeof(char), RET_ERR(handle, ALPM_ERR_MEMORY, 1)); snprintf(from, len, "%s/%s", cachedir, d->from); } len = strlen(cachedir) + strlen(d->to) + 2; CALLOC(to, len, sizeof(char), RET_ERR(handle, ALPM_ERR_MEMORY, 1)); snprintf(to, len, "%s/%s", cachedir, d->to); /* build the patch command */ if(endswith(to, ".gz")) { /* special handling for gzip : we disable timestamp with -n option */ snprintf(command, PATH_MAX, "xdelta3 -d -q -R -c -s %s %s | gzip -n > %s", from, delta, to); } else { snprintf(command, PATH_MAX, "xdelta3 -d -q -s %s %s %s", from, delta, to); } _alpm_log(handle, ALPM_LOG_DEBUG, "command: %s\n", command); EVENT(trans, ALPM_TRANS_EVT_DELTA_PATCH_START, d->to, d->delta); int retval = system(command); if(retval == 0) { EVENT(trans, ALPM_TRANS_EVT_DELTA_PATCH_DONE, NULL, NULL); /* delete the delta file */ unlink(delta); /* Delete the 'from' package but only if it is an intermediate * package. The starting 'from' package should be kept, just * as if deltas were not used. */ if(dlts != delta_path) { unlink(from); } } FREE(from); FREE(to); FREE(delta); if(retval != 0) { /* one delta failed for this package, cancel the remaining ones */ EVENT(trans, ALPM_TRANS_EVT_DELTA_PATCH_FAILED, NULL, NULL); handle->pm_errno = ALPM_ERR_DLT_PATCHFAILED; ret = 1; break; } } } return ret; }