/** * dnf_package_check_filename: * @pkg: a #DnfPackage *instance. * @valid: Set to %TRUE if the package is valid. * @error: a #GError or %NULL.. * * Checks the package is already downloaded and valid. * * Returns: %TRUE if the package was checked successfully * * Since: 0.1.0 **/ gboolean dnf_package_check_filename(DnfPackage *pkg, gboolean *valid, GError **error) { LrChecksumType checksum_type_lr; char *checksum_valid = NULL; const gchar *path; const unsigned char *checksum; gboolean ret = TRUE; int checksum_type_hy; int fd; /* check if the file does not exist */ path = dnf_package_get_filename(pkg); g_debug("checking if %s already exists...", path); if (!g_file_test(path, G_FILE_TEST_EXISTS)) { *valid = FALSE; goto out; } /* check the checksum */ checksum = dnf_package_get_chksum(pkg, &checksum_type_hy); checksum_valid = hy_chksum_str(checksum, checksum_type_hy); checksum_type_lr = dnf_repo_checksum_hy_to_lr(checksum_type_hy); fd = g_open(path, O_RDONLY, 0); if (fd < 0) { ret = FALSE; g_set_error(error, DNF_ERROR, DNF_ERROR_INTERNAL_ERROR, "Failed to open %s", path); goto out; } ret = lr_checksum_fd_cmp(checksum_type_lr, fd, checksum_valid, TRUE, /* use xattr value */ valid, error); if (!ret) { g_close(fd, NULL); goto out; } ret = g_close(fd, error); if (!ret) goto out; out: g_free(checksum_valid); return ret; }
int lr_yum_check_checksum_of_md_record(lr_YumRepoMdRecord rec, char *path) { int ret, fd; char *expected_checksum; lr_ChecksumType checksum_type; if (!rec || !path) return LRE_OK; expected_checksum = rec->checksum; checksum_type = lr_checksum_type(rec->checksum_type); DPRINTF("%s: Checking checksum of %s (expected: %s [%s])\n", __func__, path, expected_checksum, rec->checksum_type); if (!expected_checksum) { DPRINTF("%s: No checksum in repomd\n", __func__); return LRE_OK; /* Empty checksum - suppose it's ok */ } if (checksum_type == LR_CHECKSUM_UNKNOWN) { DPRINTF("%s: Unknown checksum: %s\n", __func__, rec->checksum_type); return LRE_UNKNOWNCHECKSUM; } fd = open(path, O_RDONLY); if (fd < 0) { DPRINTF("%s: Cannot open %s\n", __func__, path); return LRE_IO; } ret = lr_checksum_fd_cmp(checksum_type, fd, expected_checksum); close(fd); if (ret) { DPRINTF("%s: Checksum check - Failed\n", __func__); return LRE_BADCHECKSUM; } DPRINTF("%s: Checksum check - Passed\n", __func__); return LRE_OK; }
static gboolean lr_yum_check_checksum_of_md_record(LrYumRepoMdRecord *rec, const char *path, GError **err) { int fd; char *expected_checksum; LrChecksumType checksum_type; gboolean ret, matches; GError *tmp_err = NULL; assert(!err || *err == NULL); if (!rec || !path) return TRUE; expected_checksum = rec->checksum; checksum_type = lr_checksum_type(rec->checksum_type); g_debug("%s: Checking checksum of %s (expected: %s [%s])", __func__, path, expected_checksum, rec->checksum_type); if (!expected_checksum) { // Empty checksum - suppose it's ok g_debug("%s: No checksum in repomd", __func__); return TRUE; } if (checksum_type == LR_CHECKSUM_UNKNOWN) { g_debug("%s: Unknown checksum: %s", __func__, rec->checksum_type); g_set_error(err, LR_YUM_ERROR, LRE_UNKNOWNCHECKSUM, "Unknown checksum type \"%s\" for %s", rec->checksum_type, path); return FALSE; } fd = open(path, O_RDONLY); if (fd < 0) { g_debug("%s: Cannot open %s", __func__, path); g_set_error(err, LR_YUM_ERROR, LRE_IO, "Cannot open %s: %s", path, g_strerror(errno)); return FALSE; } ret = lr_checksum_fd_cmp(checksum_type, fd, expected_checksum, 1, &matches, &tmp_err); close(fd); assert(ret || tmp_err); if (!ret) { // Checksum calculation error g_debug("%s: Checksum check %s - Error: %s", __func__, path, tmp_err->message); g_propagate_prefixed_error(err, tmp_err, "Checksum error %s: ", path); return FALSE; } else if (!matches) { g_debug("%s: Checksum check %s - Mismatch", __func__, path); g_set_error(err, LR_YUM_ERROR, LRE_BADCHECKSUM, "Checksum mismatch %s", path); return FALSE; } g_debug("%s: Checksum check - Passed", __func__); return TRUE; }
gboolean lr_check_packages(GSList *targets, LrPackageCheckFlag flags, GError **err) { gboolean ret = TRUE; gboolean failfast = flags & LR_PACKAGECHECK_FAILFAST; struct sigaction old_sigact; 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->interruptible) interruptible = TRUE; if (!packagetarget->checksum || packagetarget->checksum_type == LR_CHECKSUM_UNKNOWN) { g_set_error(err, LR_PACKAGE_DOWNLOADER_ERROR, LRE_BADOPTARG, "Target %s doesn't have specified " "checksum value or checksum type!", packagetarget->relative_url); return FALSE; } } // Setup sighandler if (interruptible) { g_debug("%s: Using own SIGINT handler", __func__); struct sigaction sigact; 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; } } for (GSList *elem = targets; elem; elem = g_slist_next(elem)) { gchar *local_path; LrPackageTarget *packagetarget = elem->data; // 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); if (g_access(packagetarget->local_path, R_OK) == 0) { // If the file exists check its checksum int fd_r = open(packagetarget->local_path, O_RDONLY); if (fd_r != -1) { // File was successfully opened gboolean matches; ret = lr_checksum_fd_cmp(packagetarget->checksum_type, fd_r, packagetarget->checksum, 1, &matches, NULL); close(fd_r); if (ret && matches) { // Checksum is ok packagetarget->err = NULL; g_debug("%s: Package %s is already downloaded (checksum matches)", __func__, packagetarget->local_path); } else { // Checksum doesn't match or checksuming error packagetarget->err = g_string_chunk_insert( packagetarget->chunk, "Checksum of doesn't match"); if (failfast) { ret = FALSE; g_set_error(err, LR_PACKAGE_DOWNLOADER_ERROR, LRE_BADCHECKSUM, "File with nonmatching checksum found"); break; } } } else { // Cannot open the file packagetarget->err = g_string_chunk_insert(packagetarget->chunk, "Cannot be opened"); if (failfast) { ret = FALSE; g_set_error(err, LR_PACKAGE_DOWNLOADER_ERROR, LRE_IO, "Cannot open %s", packagetarget->local_path); break; } } } else { // File doesn't exists packagetarget->err = g_string_chunk_insert(packagetarget->chunk, "Doesn't exist"); if (failfast) { ret = FALSE; g_set_error(err, LR_PACKAGE_DOWNLOADER_ERROR, LRE_IO, "File %s doesn't exists", packagetarget->local_path); break; } } } // 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; }
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; }