int lr_yum_download_remote(lr_Handle handle, lr_Result result) { int rc = LRE_OK; int fd; int create_repodata_dir = 1; char *path_to_repodata; lr_YumRepo repo; lr_YumRepoMd repomd; DPRINTF("%s: Downloading/Copying repo..\n", __func__); rc = lr_handle_prepare_internal_mirrorlist(handle, "repodata/repomd.xml"); if (rc != LRE_OK) return rc; repo = result->yum_repo; repomd = result->yum_repomd; path_to_repodata = lr_pathconcat(handle->destdir, "repodata", NULL); if (handle->update) { /* Check if should create repodata/ subdir */ struct stat buf; if (stat(path_to_repodata, &buf) != -1) if (S_ISDIR(buf.st_mode)) create_repodata_dir = 0; } if (create_repodata_dir) { /* Prepare repodata/ subdir */ rc = mkdir(path_to_repodata, S_IRWXU|S_IRWXG|S_IROTH|S_IXOTH); if (rc == -1) { DPRINTF("%s: Cannot create dir: %s (%s)\n", __func__, path_to_repodata, strerror(errno)); lr_free(path_to_repodata); return LRE_CANNOTCREATEDIR; } } lr_free(path_to_repodata); if (!handle->update) { /* Prepare repomd.xml file */ char *path; path = lr_pathconcat(handle->destdir, "/repodata/repomd.xml", NULL); fd = open(path, O_CREAT|O_TRUNC|O_RDWR, 0660); if (fd == -1) { lr_free(path); return LRE_IO; } /* Download repomd.xml */ rc = lr_yum_download_repomd(handle, handle->metalink, fd); if (rc != LRE_OK) { close(fd); lr_free(path); return rc; } /* Check repomd.xml.asc if available. * Try to download and verify GPG signature (repomd.xml.asc). * Try to download only from the mirror where repomd.xml iself was * downloaded. It is because most of yum repositories are not signed * and try every mirror for signature is non effective. * Every mirror would be tried because mirrorded_download function have * no clue if 404 for repomd.xml.asc means that no signature exists or * it is just error on the mirror and should try the next one. **/ if (handle->checks & LR_CHECK_GPG) { int fd_sig; char *url, *signature; signature = lr_pathconcat(handle->destdir, "repodata/repomd.xml.asc", NULL); fd_sig = open(signature, O_CREAT|O_TRUNC|O_RDWR, 0660); if (fd_sig == -1) { DPRINTF("%s: Cannot open: %s\n", __func__, signature); close(fd); lr_free(path); lr_free(signature); return LRE_IO; } url = lr_pathconcat(handle->used_mirror, "repodata/repomd.xml.asc", NULL); rc = lr_curl_single_download(handle, url, fd_sig); lr_free(url); close(fd_sig); if (rc != LRE_OK) { // Signature doesn't exist DPRINTF("%s: GPG signature doesn't exists\n", __func__); unlink(signature); lr_free(signature); } else { // Signature downloaded repo->signature = lr_strdup(signature); rc = lr_gpg_check_signature(signature, path, NULL); if (rc != LRE_OK) { DPRINTF("%s: GPG signature verification failed\n", __func__); close(fd); lr_free(path); lr_free(signature); return rc; } DPRINTF("%s: GPG signature successfully verified\n", __func__); } } lseek(fd, 0, SEEK_SET); /* Parse repomd */ DPRINTF("%s: Parsing repomd.xml\n", __func__); rc = lr_yum_repomd_parse_file(repomd, fd); close(fd); if (rc != LRE_OK) { DPRINTF("%s: Parsing unsuccessful (%d)\n", __func__, rc); lr_free(path); return rc; } /* Fill result object */ result->destdir = lr_strdup(handle->destdir); repo->destdir = lr_strdup(handle->destdir); repo->repomd = path; if (handle->used_mirror) repo->url = lr_strdup(handle->used_mirror); else repo->url = lr_strdup(handle->baseurl); DPRINTF("%s: Repomd revision: %s\n", repomd->revision, __func__); } /* Download rest of metadata files */ if ((rc = lr_yum_download_repo(handle, repo, repomd)) != LRE_OK) return rc; DPRINTF("%s: Repository was successfully downloaded\n", __func__); return LRE_OK; }
gboolean lr_download_packages(GSList *targets, LrPackageDownloadFlag flags, GError **err) { gboolean ret; gboolean failfast = flags & LR_PACKAGEDOWNLOAD_FAILFAST; struct sigaction old_sigact; GSList *downloadtargets = NULL; gboolean interruptible = FALSE; assert(!err || *err == NULL); if (!targets) return TRUE; // Check targets for (GSList *elem = targets; elem; elem = g_slist_next(elem)) { LrPackageTarget *packagetarget = elem->data; if (!packagetarget->handle) { continue; /* g_set_error(err, LR_PACKAGE_DOWNLOADER_ERROR, LRE_BADFUNCARG, "Package target %s doesn't have specified a handle", packagetarget->relative_url); return FALSE; */ } if (packagetarget->handle->interruptible) interruptible = TRUE; // Check repotype // Note: Checked because lr_handle_prepare_internal_mirrorlist // support only LR_YUMREPO yet if (packagetarget->handle->repotype != LR_YUMREPO) { g_debug("%s: Bad repo type", __func__); g_set_error(err, LR_PACKAGE_DOWNLOADER_ERROR, LRE_BADFUNCARG, "Bad repo type"); return FALSE; } } // Setup sighandler if (interruptible) { struct sigaction sigact; g_debug("%s: Using own SIGINT handler", __func__); memset(&sigact, 0, sizeof(old_sigact)); memset(&sigact, 0, sizeof(sigact)); sigemptyset(&sigact.sa_mask); sigact.sa_handler = lr_sigint_handler; sigaddset(&sigact.sa_mask, SIGINT); sigact.sa_flags = SA_RESTART; if (sigaction(SIGINT, &sigact, &old_sigact) == -1) { g_set_error(err, LR_PACKAGE_DOWNLOADER_ERROR, LRE_SIGACTION, "Cannot set Librepo SIGINT handler"); return FALSE; } } // List of handles for fastest mirror resolving GSList *fmr_handles = NULL; // Prepare targets for (GSList *elem = targets; elem; elem = g_slist_next(elem)) { gchar *local_path; LrPackageTarget *packagetarget = elem->data; LrDownloadTarget *downloadtarget; gint64 realsize = -1; gboolean doresume = packagetarget->resume; // Reset output attributes of the handle lr_packagetarget_reset(packagetarget); // Prepare destination filename if (packagetarget->dest) { if (g_file_test(packagetarget->dest, G_FILE_TEST_IS_DIR)) { // Dir specified gchar *file_basename = g_path_get_basename(packagetarget->relative_url); local_path = g_build_filename(packagetarget->dest, file_basename, NULL); g_free(file_basename); } else { local_path = g_strdup(packagetarget->dest); } } else { // No destination path specified local_path = g_path_get_basename(packagetarget->relative_url); } packagetarget->local_path = g_string_chunk_insert(packagetarget->chunk, local_path); g_free(local_path); // Check expected size and real size if the file exists if (doresume && g_access(packagetarget->local_path, R_OK) == 0 && packagetarget->expectedsize > 0) { struct stat buf; if (stat(packagetarget->local_path, &buf)) { g_set_error(err, LR_PACKAGE_DOWNLOADER_ERROR, LRE_IO, "Cannot stat %s: %s", packagetarget->local_path, g_strerror(errno)); return FALSE; } realsize = buf.st_size; if (packagetarget->expectedsize < realsize) // Existing file is bigger then the one that is expected, // disable resuming doresume = FALSE; } if (g_access(packagetarget->local_path, R_OK) == 0 && packagetarget->checksum && packagetarget->checksum_type != LR_CHECKSUM_UNKNOWN) { /* If the file exists and checksum is ok, then is pointless to * download the file again. * Moreover, if the resume is enabled and the file is already * completely downloaded, then the download is going to fail. */ int fd_r = open(packagetarget->local_path, O_RDONLY); if (fd_r != -1) { gboolean matches; ret = lr_checksum_fd_cmp(packagetarget->checksum_type, fd_r, packagetarget->checksum, 1, &matches, NULL); close(fd_r); if (ret && matches) { // Checksum calculation was ok and checksum matches g_debug("%s: Package %s is already downloaded (checksum matches)", __func__, packagetarget->local_path); packagetarget->err = g_string_chunk_insert( packagetarget->chunk, "Already downloaded"); // Call end callback LrEndCb end_cb = packagetarget->endcb; if (end_cb) end_cb(packagetarget->cbdata, LR_TRANSFER_ALREADYEXISTS, "Already downloaded"); continue; } else if (ret) { // Checksum calculation was ok but checksum doesn't match if (realsize != -1 && realsize == packagetarget->expectedsize) // File size is the same as the expected one // Don't try to resume doresume = FALSE; } } } if (doresume && realsize != -1 && realsize == packagetarget->expectedsize) { // File's size matches the expected one, the resume is enabled and // no checksum is known => expect that the file is // the one the user wants g_debug("%s: Package %s is already downloaded (size matches)", __func__, packagetarget->local_path); packagetarget->err = g_string_chunk_insert( packagetarget->chunk, "Already downloaded"); // Call end callback LrEndCb end_cb = packagetarget->endcb; if (end_cb) end_cb(packagetarget->cbdata, LR_TRANSFER_ALREADYEXISTS, "Already downloaded"); continue; } if (packagetarget->handle) { ret = lr_handle_prepare_internal_mirrorlist(packagetarget->handle, FALSE, err); if (!ret) goto cleanup; if (packagetarget->handle->fastestmirror) { if (!g_slist_find(fmr_handles, packagetarget->handle)) fmr_handles = g_slist_prepend(fmr_handles, packagetarget->handle); } } GSList *checksums = NULL; LrDownloadTargetChecksum *checksum; checksum = lr_downloadtargetchecksum_new(packagetarget->checksum_type, packagetarget->checksum); checksums = g_slist_prepend(checksums, checksum); downloadtarget = lr_downloadtarget_new(packagetarget->handle, packagetarget->relative_url, packagetarget->base_url, -1, packagetarget->local_path, checksums, packagetarget->expectedsize, doresume, packagetarget->progresscb, packagetarget->cbdata, packagetarget->endcb, packagetarget->mirrorfailurecb, packagetarget, packagetarget->byterangestart, packagetarget->byterangeend); downloadtargets = g_slist_append(downloadtargets, downloadtarget); } // Do Fastest Mirror resolving for all handles in one shot if (fmr_handles) { fmr_handles = g_slist_reverse(fmr_handles); ret = lr_fastestmirror_sort_internalmirrorlists(fmr_handles, err); g_slist_free(fmr_handles); if (!ret) { return FALSE; } } // Start downloading ret = lr_download(downloadtargets, failfast, err); cleanup: // Copy download statuses from downloadtargets to targets for (GSList *elem = downloadtargets; elem; elem = g_slist_next(elem)) { LrDownloadTarget *downloadtarget = elem->data; LrPackageTarget *packagetarget = downloadtarget->userdata; if (downloadtarget->err) packagetarget->err = g_string_chunk_insert(packagetarget->chunk, downloadtarget->err); } // Free downloadtargets list g_slist_free_full(downloadtargets, (GDestroyNotify)lr_downloadtarget_free); // Restore original signal handler if (interruptible) { g_debug("%s: Restoring an old SIGINT handler", __func__); sigaction(SIGINT, &old_sigact, NULL); if (lr_interrupt) { if (err && *err != NULL) g_clear_error(err); g_set_error(err, LR_PACKAGE_DOWNLOADER_ERROR, LRE_INTERRUPTED, "Insterupted by a SIGINT signal"); return FALSE; } } return ret; }