]> git.ipfire.org Git - pakfire.git/commitdiff
downloader: Add support for uploading files
authorMichael Tremer <michael.tremer@ipfire.org>
Wed, 18 Oct 2023 09:50:55 +0000 (09:50 +0000)
committerMichael Tremer <michael.tremer@ipfire.org>
Wed, 18 Oct 2023 09:50:55 +0000 (09:50 +0000)
Signed-off-by: Michael Tremer <michael.tremer@ipfire.org>
src/libpakfire/downloader.c
src/libpakfire/include/pakfire/downloader.h

index f0a51563706d46cf4a0e3f5b18fe80028cc3e369..1002e102dd3d6d54a1a361581656705f98b3cd64 100644 (file)
@@ -70,6 +70,12 @@ struct pakfire_transfer {
        // POST MIME Object
        curl_mime* mime;
 
+       // Transfer direction
+       enum {
+               PAKFIRE_TRANSFER_DOWNLOAD = 0,
+               PAKFIRE_TRANSFER_UPLOAD   = 1,
+       } direction;
+
        // Size
        size_t expected_size;
        size_t transferred;
@@ -288,6 +294,24 @@ static int debug_callback(CURL *handle, curl_infotype type,
 }
 #endif
 
+static size_t pakfire_downloader_transfer_read(char* data, size_t size, size_t nmemb, void* p) {
+       struct pakfire_transfer* transfer = p;
+
+       return fread(data, size, nmemb, transfer->f);
+}
+
+static int pakfire_downloader_transfer_seek(void* p, curl_off_t offset, int origin) {
+       struct pakfire_transfer* transfer = p;
+       int r;
+
+       // Perform the seek
+       r = fseek(transfer->f, (long)offset, origin);
+       if (r < 0)
+               return CURL_SEEKFUNC_CANTSEEK;
+
+       return CURL_SEEKFUNC_OK;
+}
+
 static size_t pakfire_downloader_transfer_write(
                char* data, size_t size, size_t nmemb, void* p) {
        struct pakfire_transfer* transfer = p;
@@ -348,11 +372,21 @@ static int pakfire_downloader_transfer_setup(
        // Follow any redirects
        curl_easy_setopt(transfer->handle, CURLOPT_FOLLOWLOCATION, 1);
 
+       // Read any data from a callback function
+       curl_easy_setopt(transfer->handle,
+               CURLOPT_READFUNCTION, pakfire_downloader_transfer_read);
+       curl_easy_setopt(transfer->handle, CURLOPT_READDATA, transfer);
+
        // Write all data to the callback function
        curl_easy_setopt(transfer->handle,
                CURLOPT_WRITEFUNCTION, pakfire_downloader_transfer_write);
        curl_easy_setopt(transfer->handle, CURLOPT_WRITEDATA, transfer);
 
+       // Register the seek callback
+       curl_easy_setopt(transfer->handle,
+               CURLOPT_SEEKFUNCTION, pakfire_downloader_transfer_seek);
+       curl_easy_setopt(transfer->handle, CURLOPT_SEEKDATA, transfer);
+
        // Success
        r = 0;
 
@@ -601,6 +635,32 @@ int pakfire_downloader_transfer_set_output(struct pakfire_transfer* transfer, FI
        return 0;
 }
 
+int pakfire_downloader_transfer_set_input(struct pakfire_transfer* transfer, FILE* f) {
+       struct stat stat;
+       int r;
+
+       // Fetch the file descriptor
+       const int fd = fileno(f);
+
+       // Change direction
+       transfer->direction = PAKFIRE_TRANSFER_UPLOAD;
+
+       // Store the file handle
+       transfer->f = f;
+
+       // Try to find the upload size
+       if (fd > 0) {
+               r = fstat(fd, &stat);
+               if (r)
+                       return 0;
+
+               // Store the expected filesize
+               transfer->expected_size = stat.st_size;
+       }
+
+       return 0;
+}
+
 int pakfire_downloader_transfer_set_target(
                struct pakfire_transfer* transfer, const char* path) {
        return pakfire_string_set(transfer->path, path);
@@ -1050,6 +1110,31 @@ static int pakfire_downloader_transfer_prepare(struct pakfire_downloader* downlo
                }
        }
 
+       // Set special options for direction
+       switch (transfer->direction) {
+               case PAKFIRE_TRANSFER_DOWNLOAD:
+                       break;
+
+               case PAKFIRE_TRANSFER_UPLOAD:
+                       // Let cURL know that we are uploading things
+                       r = curl_easy_setopt(transfer->handle, CURLOPT_UPLOAD, 1L);
+                       if (r) {
+                               CTX_ERROR(downloader->ctx, "Could not enable upload\n");
+                               return r;
+                       }
+
+                       // Tell it the expected upload size
+                       if (transfer->expected_size) {
+                               r = curl_easy_setopt(transfer->handle,
+                                       CURLOPT_INFILESIZE_LARGE, (curl_off_t)transfer->expected_size);
+                               if (r) {
+                                       CTX_ERROR(downloader->ctx, "Could not set upload size\n");
+                                       return r;
+                               }
+                       }
+                       break;
+       }
+
        // If we do not have an output file, we will create a temporary file
        if (!transfer->f) {
                r = pakfire_downloader_transfer_prepare_tmpfile(transfer);
index 93d140f2cafee40ff88a076aa4778a1496dbc7f4..3f236e96ba1c5c301c65dc4432c4e2e795e8d2b4 100644 (file)
@@ -60,6 +60,7 @@ int pakfire_downloader_transfer_verify_digest(
 int pakfire_downloader_transfer_add_param(struct pakfire_transfer* transfer,
        const char* key, const char* format, ...) __attribute__((format(printf, 3, 4)));
 int pakfire_downloader_transfer_set_output(struct pakfire_transfer* transfer, FILE* f);
+int pakfire_downloader_transfer_set_input(struct pakfire_transfer* transfer, FILE* f);
 int pakfire_downloader_transfer_set_target(struct pakfire_transfer* transfer, const char* path);
 
 int pakfire_downloader_transfer_run(struct pakfire_transfer* transfer, int flags);