WARNING: THIS SITE IS A MIRROR OF GITHUB.COM / IT CANNOT LOGIN OR REGISTER ACCOUNTS / THE CONTENTS ARE PROVIDED AS-IS / THIS SITE ASSUMES NO RESPONSIBILITY FOR ANY DISPLAYED CONTENT OR LINKS / IF YOU FOUND SOMETHING MAY NOT GOOD FOR EVERYONE, CONTACT ADMIN AT ilovescratch@foxmail.com
Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ FIND_PACKAGE(PkgConfig)
PKG_CHECK_MODULES(GLIB2 glib-2.0>=2.66 gio-2.0 REQUIRED)
PKG_SEARCH_MODULE(LIBCRYPTO REQUIRED libcrypto openssl)
PKG_CHECK_MODULES(LIBXML2 libxml-2.0 REQUIRED)
PKG_CHECK_MODULES(JSONGLIB json-glib-1.0 REQUIRED)
FIND_PACKAGE(CURL 7.52.0 REQUIRED)

IF (USE_GPGME)
Expand Down Expand Up @@ -106,6 +107,7 @@ INCLUDE_DIRECTORIES("${CMAKE_CURRENT_BINARY_DIR}" "${CMAKE_CURRENT_BINARY_DIR}/l

INCLUDE_DIRECTORIES(${LIBXML2_INCLUDE_DIRS})
INCLUDE_DIRECTORIES(${CURL_INCLUDE_DIR})
INCLUDE_DIRECTORIES(${JSONGLIB_INCLUDE_DIRS})
#INCLUDE_DIRECTORIES(${CHECK_INCLUDE_DIR})
IF (USE_GPGME AND ENABLE_SELINUX)
INCLUDE_DIRECTORIES(${SELINUX_INCLUDE_DIRS})
Expand Down
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ Fedora/Ubuntu name
* glib2 (http://developer.gnome.org/glib/) - glib2-devel/libglib2.0-dev
* libattr (https://savannah.nongnu.org/projects/attr) - libattr-devel/libattr1-dev
* libcurl (http://curl.haxx.se/libcurl/) - libcurl-devel/libcurl4-openssl-dev
* json-glib (https://wiki.gnome.org/Projects/JsonGlib) - json-glib/json-glib-devel
* openssl (http://www.openssl.org/) - openssl-devel/libssl-dev
* python (http://python.org/) - python3-devel/libpython3-dev
* One of the libraries:
Expand Down
1 change: 1 addition & 0 deletions librepo.spec
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ BuildRequires: pkgconfig(rpm) >= 4.18.0
%endif
BuildRequires: libattr-devel
BuildRequires: libcurl-devel >= %{libcurl_version}
BuildRequires: pkgconfig(json-glib-1.0)
BuildRequires: pkgconfig(libxml-2.0)
BuildRequires: pkgconfig(libcrypto)
%if %{need_selinux}
Expand Down
1 change: 1 addition & 0 deletions librepo/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@ TARGET_LINK_LIBRARIES(librepo
${LIBXML2_LIBRARIES}
${CURL_LIBRARY}
${LIBCRYPTO_LIBRARIES}
${JSONGLIB_LIBRARIES}
${GLIB2_LIBRARIES}
)
IF (USE_GPGME)
Expand Down
197 changes: 164 additions & 33 deletions librepo/downloader.c
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@
#include <sys/xattr.h>
#include <fcntl.h>
#include <curl/curl.h>
#include <json-glib/json-glib.h>

#ifdef WITH_ZCHUNK
#include <zck.h>
Expand Down Expand Up @@ -85,6 +86,16 @@ typedef enum {
All headers which we were looking for are already found*/
} LrHeaderCbState;

/** Enum with OCI file status */
typedef enum {
LR_OCI_DL_WAITING, /*!<
The OCI file is waiting to be processed. */
LR_OCI_DL_MANIFEST, /*!<
The OCI manifest file is being downloaded. */
LR_OCI_DL_LAYER, /*!<
The OCI layer is being downloaded. */
} LrOciState;

/** Enum with zchunk file status */
typedef enum {
LR_ZCK_DL_HEADER_CK, /*!<
Expand Down Expand Up @@ -185,6 +196,8 @@ typedef struct {
Last cb return code. */
struct curl_slist *curl_rqheaders; /*!<
Extra headers for request. */
LrOciState oci_state; /*!<
OCI download state. */

#ifdef WITH_ZCHUNK
LrZckState zck_state; /*!<
Expand Down Expand Up @@ -1399,7 +1412,19 @@ open_target_file(LrTarget *target, GError **err)
int fd;
FILE *f;

if (target->target->fd != -1) {
if (target->oci_state == LR_OCI_DL_MANIFEST) {
if (target->target->fn == NULL) {
// Create a temporary file for the OCI manifest
const char *tmpdir = getenv("TMPDIR");
if (tmpdir == NULL)
tmpdir = "/tmp";
char *tmpname = g_strdup_printf("%s/librepo-oci-XXXXXX", tmpdir);
close (mkstemp(tmpname));
target->target->fn = tmpname;
}
}

if (target->oci_state != LR_OCI_DL_MANIFEST && target->target->fd != -1) {
// Use supplied filedescriptor
fd = dup(target->target->fd);
if (fd == -1) {
Expand Down Expand Up @@ -1435,6 +1460,80 @@ open_target_file(LrTarget *target, GError **err)
return f;
}

/** Get the OCI manifest URL
*/
static char *
get_oci_manifest_url(char *oci_url, GError **err)
{
assert(!err || *err == NULL);

// Remove the 'oci://' prefix
char *hostname = strdup(oci_url + 6);

char *first_slash = strchr(hostname, '/');
if (first_slash == NULL || first_slash[1] == 0) {
g_set_error(err, LR_DOWNLOADER_ERROR, LRE_IO,
"invalid OCI URL format: %s",
oci_url);
return NULL;
}
*first_slash = 0;

char *result = g_strdup_printf ("https://%s/v2/%s/manifests/latest",
hostname,
first_slash + 1);
free (hostname);
return result;
}

static char *
get_oci_layer_url(char *oci_url, char *fn, GError **err) {
assert(!err || *err == NULL);

// Load the JSON manifest file
JsonParser *parser = json_parser_new();

// Load the JSON manifest file
if (!json_parser_load_from_file(parser, fn, err)) {
g_object_unref(parser);
return NULL;
}

// Delete the manifest file
unlink(fn);

// Get the root object
JsonNode *root = json_parser_get_root(parser);
JsonObject *root_obj = json_node_get_object(root);

// Navigate to the layers array
JsonArray *layers = json_object_get_array_member(root_obj, "layers");
JsonObject *first_layer = json_array_get_object_element(layers, 0);

// Extract the digest for the first layer
const char *digest = json_object_get_string_member(first_layer, "digest");

// Remove the 'oci://' prefix
char *hostname = strdup(oci_url + 6);

char *first_slash = strchr(hostname, '/');
if (first_slash == NULL || first_slash[1] == 0) {
g_set_error(err, LR_DOWNLOADER_ERROR, LRE_IO,
"invalid OCI URL format: %s",
oci_url);
return NULL;
}
*first_slash = 0;

char *result = g_strdup_printf ("https://%s/v2/%s/blobs/%s",
hostname,
first_slash + 1,
digest);
free (hostname);
g_object_unref(parser);
return result;
}

/** Prepare next transfer
*/
static gboolean
Expand Down Expand Up @@ -1478,6 +1577,17 @@ prepare_next_transfer(LrDownload *dd, gboolean *candidatefound, GError **err)

protocol = lr_detect_protocol(full_url);

if (protocol == LR_PROTOCOL_OCI) {
if (target->oci_state == LR_OCI_DL_WAITING) {
target->oci_state = LR_OCI_DL_MANIFEST;
full_url = get_oci_manifest_url(full_url, err);
} else if (target->oci_state == LR_OCI_DL_LAYER) {
full_url = get_oci_layer_url(full_url, target->target->fn, err);
}
if (!full_url)
goto fail;
}

// Prepare CURL easy handle
CURLcode c_rc;
CURL *h;
Expand Down Expand Up @@ -1656,6 +1766,18 @@ prepare_next_transfer(LrDownload *dd, gboolean *candidatefound, GError **err)
if (!headers)
lr_out_of_memory();
}
if (target->oci_state == LR_OCI_DL_MANIFEST) {
headers = curl_slist_append(headers, "Authorization: Bearer QQ==");
if (!headers)
lr_out_of_memory();
headers = curl_slist_append(headers, "Accept: application/vnd.oci.image.manifest.v1+json");
if (!headers)
lr_out_of_memory();
} else if (target->oci_state == LR_OCI_DL_LAYER) {
headers = curl_slist_append(headers, "Authorization: Bearer QQ==");
if (!headers)
lr_out_of_memory();
}
target->curl_rqheaders = headers;
c_rc = curl_easy_setopt(h, CURLOPT_HTTPHEADER, headers);
assert(c_rc == CURLE_OK);
Expand Down Expand Up @@ -2324,15 +2446,17 @@ check_transfer_statuses(LrDownload *dd, GError **err)
// New file was downloaded - clear checksums cached in extended attributes
lr_checksum_clear_cache(fd);

ret = check_finished_transfer_checksum(fd,
target->target->checksums,
&matches,
&transfer_err,
&tmp_err);
ret = target->oci_state != LR_OCI_DL_MANIFEST
? check_finished_transfer_checksum(fd,
target->target->checksums,
&matches,
&transfer_err,
&tmp_err)
: 1;
if (!ret) { // Error
g_propagate_prefixed_error(err, tmp_err, "Downloading from %s"
"was successful but error encountered while "
"checksumming: ", effective_url);
"was successful but error encountered while "
"checksumming: ", effective_url);
return FALSE;
}
#ifdef WITH_ZCHUNK
Expand Down Expand Up @@ -2506,31 +2630,38 @@ check_transfer_statuses(LrDownload *dd, GError **err)
target->tried_mirrors = g_slist_remove(target->tried_mirrors, target->mirror);
} else {
#endif /* WITH_ZCHUNK */
target->state = LR_DS_FINISHED;

// Remove xattr that states that the file is being downloaded
// by librepo, because the file is now completely downloaded
// and the xattr is not needed (is is useful only for resuming)
remove_librepo_xattr(target->target);

// Call end callback
LrEndCb end_cb = target->target->endcb;
if (end_cb) {
int rc = end_cb(target->target->cbdata,
LR_TRANSFER_SUCCESSFUL,
NULL);
if (rc == LR_CB_ERROR) {
target->cb_return_code = LR_CB_ERROR;
g_debug("%s: Downloading was aborted by LR_CB_ERROR "
"from end callback", __func__);
g_set_error(&fail_fast_error, LR_DOWNLOADER_ERROR,
LRE_CBINTERRUPTED,
"Interrupted by LR_CB_ERROR from end callback");
}
}
if (target->mirror)
lr_downloadtarget_set_usedmirror(target->target,
target->mirror->mirror->url);
if (target->oci_state == LR_OCI_DL_MANIFEST) {
// Now that we have the manifest, let's download the
// layer blob.
target->oci_state = LR_OCI_DL_LAYER;
target->state = LR_DS_WAITING;
} else {
target->state = LR_DS_FINISHED;

// Remove xattr that states that the file is being downloaded
// by librepo, because the file is now completely downloaded
// and the xattr is not needed (is is useful only for resuming)
remove_librepo_xattr(target->target);

// Call end callback
LrEndCb end_cb = target->target->endcb;
if (end_cb) {
int rc = end_cb(target->target->cbdata,
LR_TRANSFER_SUCCESSFUL,
NULL);
if (rc == LR_CB_ERROR) {
target->cb_return_code = LR_CB_ERROR;
g_debug("%s: Downloading was aborted by LR_CB_ERROR "
"from end callback", __func__);
g_set_error(&fail_fast_error, LR_DOWNLOADER_ERROR,
LRE_CBINTERRUPTED,
"Interrupted by LR_CB_ERROR from end callback");
}
}
if (target->mirror)
lr_downloadtarget_set_usedmirror(target->target,
target->mirror->mirror->url);
}
#ifdef WITH_ZCHUNK
}
#endif /* WITH_ZCHUNK */
Expand Down
3 changes: 3 additions & 0 deletions librepo/lrmirrorlist.c
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,9 @@ lr_detect_protocol(const char *url)
if (g_str_has_prefix(url, "rsync://"))
return LR_PROTOCOL_RSYNC;

if (g_str_has_prefix(url, "oci://"))
return LR_PROTOCOL_OCI;

return LR_PROTOCOL_OTHER;
}

Expand Down
1 change: 1 addition & 0 deletions librepo/lrmirrorlist.h
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ typedef enum {
LR_PROTOCOL_HTTP,
LR_PROTOCOL_FTP,
LR_PROTOCOL_RSYNC,
LR_PROTOCOL_OCI,
} LrProtocol;

/** A internal representation of a mirror */
Expand Down