예제 #1
0
/**
 * 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;
}
예제 #2
0
파일: yum.c 프로젝트: akozumpl/librepo
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;
}
예제 #3
0
파일: yum.c 프로젝트: sourcejedi/librepo
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;
}
예제 #4
0
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;
}
예제 #5
0
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;
}