// Pakfire
struct pakfire* pakfire;
- // Root
- const char* root;
-
// Image writer
struct pakfire_archive_writer* image;
- // Hexdigest of the layer
- char* layer_hexdigest;
+ // JSON Objects
+ struct json_object* config;
+ struct json_object* layers;
+ struct json_object* manifests;
};
static const char* pakfire_oci_arch(struct pakfire* pakfire) {
return r;
}
+static int pakfire_oci_writer_write_json_blob(
+ struct pakfire_oci_writer* self, struct json_object* json, char** hexdigest, size_t* size) {
+ struct pakfire_hashes hashes = {};
+ const char* buffer = NULL;
+ char* hd = NULL;
+ char path[PATH_MAX];
+ int r;
+
+ // Serialize the JSON object
+ buffer = json_object_to_json_string_ext(json, 0);
+ if (!buffer) {
+ r = -errno;
+ goto ERROR;
+ }
+
+ // Hash the serialized JSON object
+ r = pakfire_hash_buffer(self->ctx, buffer, strlen(buffer), PAKFIRE_HASH_SHA2_256, &hashes);
+ if (r < 0)
+ goto ERROR;
+
+ // Fetch the hexdigest
+ r = pakfire_hashes_get_hex(&hashes, PAKFIRE_HASH_SHA2_256, &hd);
+ if (r < 0)
+ goto ERROR;
+
+ // Make path
+ r = pakfire_path_format(path, "blobs/sha256/%s", hd);
+ if (r < 0)
+ goto ERROR;
+
+ // Write the file
+ r = pakfire_archive_writer_create_file(self->image, path, 0644, buffer, strlen(buffer));
+ if (r < 0) {
+ ERROR(self->ctx, "Failed to write JSON blob %s: %s\n", path, strerror(-r));
+ goto ERROR;
+ }
+
+ // If requested return the hexdigest
+ if (hexdigest)
+ *hexdigest = strdup(hd);
+
+ // If requested return the size
+ if (size)
+ *size = strlen(buffer);
+
+ERROR:
+ if (hd)
+ free(hd);
+
+ return r;
+}
+
+static int pakfire_oci_writer_write_index(struct pakfire_oci_writer* self) {
+ struct json_object* o = NULL;
+ int r;
+
+ // Make a new object
+ o = pakfire_json_new_object();
+ if (!o) {
+ r = -errno;
+ goto ERROR;
+ }
+
+ // Set schema version
+ r = pakfire_json_add_int64(o, "schemaVersion", 2);
+ if (r < 0)
+ goto ERROR;
+
+ // Set media type
+ r = pakfire_json_add_string(o, "mediaType", "application/vnd.oci.image.index.v1+json");
+ if (r < 0)
+ goto ERROR;
+
+ // Add manifests
+ r = json_object_object_add(o, "manifests", json_object_get(self->manifests));
+ if (r < 0)
+ goto ERROR;
+
+ // Write the file
+ r = pakfire_archive_writer_create_file_from_json(self->image, "index.json", 0644, o);
+ if (r < 0)
+ goto ERROR;
+
+ERROR:
+ if (o)
+ json_object_put(o);
+
+ return r;
+}
+
+static int pakfire_oci_writer_write_config(struct pakfire_oci_writer* self) {
+ struct json_object* o = NULL;
+ char* hexdigest = NULL;
+ char created[64];
+ size_t size;
+ int r;
+
+ // Make a new object
+ o = pakfire_json_new_object();
+ if (!o) {
+ r = -errno;
+ goto ERROR;
+ }
+
+ // Format creation timestamp
+ r = pakfire_strftime_now(created, "%Y-%m-%dT%H:%M:%SZ");
+ if (r < 0)
+ goto ERROR;
+
+ // Add the creation timestamp
+ r = pakfire_json_add_string(o, "created", created);
+ if (r < 0)
+ goto ERROR;
+
+ // Add author
+ const char* vendor = pakfire_get_distro_vendor(self->pakfire);
+ if (vendor) {
+ r = pakfire_json_add_string(o, "author", vendor);
+ if (r < 0)
+ goto ERROR;
+ }
+
+ // Add OS
+ r = pakfire_json_add_string(o, "os", "linux");
+ if (r < 0)
+ goto ERROR;
+
+ // Fetch OS version
+ const char* version_id = pakfire_get_distro_version_id(self->pakfire);
+
+ // Add OS version
+ if (version_id) {
+ r = pakfire_json_add_string(o, "os.version", version_id);
+ if (r < 0)
+ goto ERROR;
+ }
+
+ // Fetch arch
+ const char* arch = pakfire_oci_arch(self->pakfire);
+
+ // Add arch
+ r = pakfire_json_add_string(o, "architecture", arch);
+ if (r < 0)
+ goto ERROR;
+
+ // Write as blob
+ r = pakfire_oci_writer_write_json_blob(self, o, &hexdigest, &size);
+ if (r < 0)
+ goto ERROR;
+
+ // Add media type
+ r = pakfire_json_add_string(self->config, "mediaType", "application/vnd.oci.image.config.v1+json");
+ if (r < 0)
+ goto ERROR;
+
+ // Add digest
+ r = pakfire_json_add_stringf(self->config, "digest", "sha256:%s", hexdigest);
+ if (r < 0)
+ goto ERROR;
+
+ // Add size
+ r = pakfire_json_add_int64(self->config, "size", size);
+ if (r < 0)
+ goto ERROR;
+
+ERROR:
+ if (hexdigest)
+ free(hexdigest);
+ if (o)
+ json_object_put(o);
+
+ return r;
+}
+
+static int pakfire_oci_writer_write_manifest(struct pakfire_oci_writer* self) {
+ struct json_object* manifest = NULL;
+ struct json_object* platform = NULL;
+ struct json_object* o = NULL;
+ char* hexdigest = NULL;
+ size_t size;
+ int r;
+
+ // Make a new object
+ o = pakfire_json_new_object();
+ if (!o) {
+ r = -errno;
+ goto ERROR;
+ }
+
+ // Set schema version
+ r = pakfire_json_add_int64(o, "schemaVersion", 2);
+ if (r < 0)
+ goto ERROR;
+
+ // Set media type
+ r = pakfire_json_add_string(o, "mediaType", "application/vnd.oci.image.manifest.v1+json");
+ if (r < 0)
+ goto ERROR;
+
+ // Add config
+ r = json_object_object_add(o, "config", json_object_get(self->config));
+ if (r < 0)
+ goto ERROR;
+
+ // Add layer to the layers array
+ r = json_object_object_add(o, "layers", json_object_get(self->layers));
+ if (r < 0)
+ goto ERROR;
+
+ // Write as blob
+ r = pakfire_oci_writer_write_json_blob(self, o, &hexdigest, &size);
+ if (r < 0)
+ goto ERROR;
+
+ // Make another new object
+ manifest = pakfire_json_new_object();
+ if (!manifest) {
+ r = -errno;
+ goto ERROR;
+ }
+
+ // Add media type
+ r = pakfire_json_add_string(manifest, "mediaType", "application/vnd.oci.image.manifest.v1+json");
+ if (r < 0)
+ goto ERROR;
+
+ // Add size
+ r = pakfire_json_add_int64(manifest, "size", size);
+ if (r < 0)
+ goto ERROR;
+
+ // Add digest
+ r = pakfire_json_add_stringf(manifest, "digest", "sha256:%s", hexdigest);
+ if (r < 0)
+ goto ERROR;
+
+ // Add platform
+ r = pakfire_json_add_object(manifest, "platform", &platform);
+ if (r < 0)
+ goto ERROR;
+
+ // Fetch architecture
+ const char* arch = pakfire_oci_arch(self->pakfire);
+
+ // Add architecture
+ r = pakfire_json_add_string(platform, "architecture", arch);
+ if (r < 0)
+ goto ERROR;
+
+ // Add OS
+ r = pakfire_json_add_string(platform, "os", "linux");
+ if (r < 0)
+ goto ERROR;
+
+ // Add the manifest to the other manifests
+ r = json_object_array_add(self->manifests, json_object_get(manifest));
+ if (r < 0) {
+ ERROR(self->ctx, "Failed to add the manifest to the metadata: %m\n");
+ r = -errno;
+ goto ERROR;
+ }
+
+ERROR:
+ if (manifest)
+ json_object_put(manifest);
+ if (o)
+ json_object_put(o);
+ if (hexdigest)
+ free(hexdigest);
+
+ return r;
+}
+
static int pakfire_oci_writer_make_layer(struct pakfire_oci_writer* self) {
char path[PATH_MAX] = PAKFIRE_TMP_DIR "/pakfire-oci-layer.XXXXXX";
struct pakfire_archive_writer* layer = NULL;
struct pakfire_hashes hashes = {};
+ struct json_object* json = NULL;
char filename[PATH_MAX];
+ char* hexdigest = NULL;
FILE* f = NULL;
+ size_t size;
int r;
// Fetch the pakfire root
if (r < 0)
goto ERROR;
+ // Fetch the size
+ size = ftell(f);
+
// Rewind
r = pakfire_rewind(f);
if (r < 0)
goto ERROR;
// Compute hashes of the file
- r = pakfire_hash_file(self->ctx, f, PAKFIRE_HASH_SHA2_512, &hashes);
+ r = pakfire_hash_file(self->ctx, f, PAKFIRE_HASH_SHA2_256, &hashes);
if (r < 0)
goto ERROR;
// Read the hexdigest of the file
- r = pakfire_hashes_get_hex(&hashes, PAKFIRE_HASH_SHA2_512, &self->layer_hexdigest);
+ r = pakfire_hashes_get_hex(&hashes, PAKFIRE_HASH_SHA2_256, &hexdigest);
if (r < 0)
goto ERROR;
// Make the filename of the layer
- r = pakfire_path_format(filename, "blobs/sha512/%s", self->layer_hexdigest);
+ r = pakfire_path_format(filename, "blobs/sha256/%s", hexdigest);
if (r < 0)
goto ERROR;
+ // Create a new JSON object
+ json = pakfire_json_new_object();
+ if (!json) {
+ r = -errno;
+ goto ERROR;
+ }
+
+ // Add the media type
+ r = pakfire_json_add_string(json, "mediaType", "application/vnd.oci.image.layer.v1.tar+gzip");
+ if (r < 0)
+ goto ERROR;
+
+ // Add the digest
+ r = pakfire_json_add_stringf(json, "digest", "sha256:%s", hexdigest);
+ if (r < 0)
+ goto ERROR;
+
+ // Add the size
+ r = pakfire_json_add_int64(json, "size", size);
+ if (r < 0)
+ goto ERROR;
+
+ // Add the layer to the other layers
+ r = json_object_array_add(self->layers, json_object_get(json));
+ if (r < 0) {
+ ERROR(self->ctx, "Failed to add the layer to the metadata: %m\n");
+ r = -errno;
+ goto ERROR;
+ }
+
// Rewind
r = pakfire_rewind(f);
if (r < 0)
ERROR:
if (layer)
pakfire_archive_writer_unref(layer);
+ if (json)
+ json_object_put(json);
if (f)
fclose(f);
};
int r;
+ // Reference to the config
+ writer.config = json_object_new_object();
+ if (!writer.config) {
+ r = -errno;
+ goto ERROR;
+ }
+
+ // To store all layers
+ writer.layers = json_object_new_array();
+ if (!writer.layers) {
+ r = -errno;
+ goto ERROR;
+ }
+
+ // To store all manifests
+ writer.manifests = json_object_new_array();
+ if (!writer.manifests) {
+ r = -errno;
+ goto ERROR;
+ }
+
// Make a new archive writer
r = pakfire_archive_writer_create(&writer.image, pakfire, PAKFIRE_FORMAT_OCI, f);
if (r < 0)
// Make the layer
r = pakfire_oci_writer_make_layer(&writer);
- if (r < 0)
+ if (r < 0) {
+ ERROR(writer.ctx, "Failed to write the layer: %s\n", strerror(-r));
goto ERROR;
+ }
+
+ // Write the config
+ r = pakfire_oci_writer_write_config(&writer);
+ if (r < 0) {
+ ERROR(writer.ctx, "Failed to write the config: %s\n", strerror(-r));
+ goto ERROR;
+ }
+
+ // Write the manifest
+ r = pakfire_oci_writer_write_manifest(&writer);
+ if (r < 0) {
+ ERROR(writer.ctx, "Failed to write the manifest: %s\n", strerror(-r));
+ goto ERROR;
+ }
+
+ // Write the index
+ r = pakfire_oci_writer_write_index(&writer);
+ if (r < 0) {
+ ERROR(writer.ctx, "Failed to write the index: %s\n", strerror(-r));
+ goto ERROR;
+ }
ERROR:
+ if (writer.manifests)
+ json_object_put(writer.manifests);
+ if (writer.layers)
+ json_object_put(writer.layers);
+ if (writer.config)
+ json_object_put(writer.config);
if (writer.image)
pakfire_archive_writer_unref(writer.image);
- if (writer.layer_hexdigest)
- free(writer.layer_hexdigest);
if (writer.ctx)
pakfire_ctx_unref(writer.ctx);