]> git.ipfire.org Git - people/ms/pakfire.git/blobdiff - src/libpakfire/xfer.c
xfer: Set mtime only if we received one
[people/ms/pakfire.git] / src / libpakfire / xfer.c
index 47aa3d2f39478bad1598837c1730d96568a4514b..9814d983ad1a87d33a024b0d4b89a79573830a46 100644 (file)
@@ -19,6 +19,7 @@
 #############################################################################*/
 
 #include <errno.h>
+#include <fcntl.h>
 #include <limits.h>
 #include <sys/queue.h>
 #include <utime.h>
@@ -60,7 +61,6 @@ struct pakfire_xfer {
        char url[PATH_MAX];
        char title[NAME_MAX];
        char path[PATH_MAX];
-       pakfire_xfer_flags_t flags;
        int tries;
 
        // POST MIME Object
@@ -76,9 +76,6 @@ struct pakfire_xfer {
        size_t expected_size;
        size_t xferred;
 
-       // Temporary file
-       char tempfile[PATH_MAX];
-
        // File handles for streams
        FILE* fin;
        FILE* fout;
@@ -104,13 +101,6 @@ struct pakfire_xfer {
 };
 
 static void pakfire_xfer_free(struct pakfire_xfer* xfer) {
-       if (xfer->handle)
-               curl_easy_cleanup(xfer->handle);
-
-       // Unlink the temporary file
-       if (*xfer->tempfile)
-               unlink(xfer->tempfile);
-
        // Close any streams
        if (xfer->fin)
                fclose(xfer->fin);
@@ -119,6 +109,9 @@ static void pakfire_xfer_free(struct pakfire_xfer* xfer) {
        if (xfer->evp)
                EVP_MD_CTX_free(xfer->evp);
 
+       // cURL stuff
+       if (xfer->handle)
+               curl_easy_cleanup(xfer->handle);
        if (xfer->headers)
                curl_slist_free_all(xfer->headers);
        if (xfer->mime)
@@ -132,6 +125,8 @@ static void pakfire_xfer_free(struct pakfire_xfer* xfer) {
                pakfire_mirrorlist_unref(xfer->mirrors);
        if (xfer->progress)
                pakfire_progress_unref(xfer->progress);
+       if (xfer->client)
+               pakfire_httpclient_unref(xfer->client);
        if (xfer->ctx)
                pakfire_ctx_unref(xfer->ctx);
 
@@ -204,6 +199,10 @@ static size_t pakfire_xfer_write(
                }
        }
 
+       // If there is no output steam, we just pretent that we have consumed the data
+       if (!xfer->fin)
+               return nmemb;
+
        // Write everything to the allocated file descriptor
        return fwrite(data, size, nmemb, xfer->fin);
 }
@@ -590,9 +589,53 @@ int pakfire_xfer_set_input(struct pakfire_xfer* xfer, FILE* f) {
        return 0;
 }
 
-int pakfire_xfer_set_target(
-               struct pakfire_xfer* xfer, const char* path) {
-       return pakfire_string_set(xfer->path, path);
+static int pakfire_xfer_allocate_tmpfile(struct pakfire_xfer* xfer, const char* path) {
+       char dirname[PATH_MAX];
+       FILE* f = NULL;
+       int fd = -1;
+       int r;
+
+       // Find the directory name
+       r = pakfire_path_dirname(dirname, path);
+       if (r)
+               return r;
+
+       // Ensure the directory exists
+       r = pakfire_mkdir(dirname, 0755);
+       if (r)
+               return r;
+
+       // Open a new temporary file
+       fd = open(dirname, O_TMPFILE|O_RDWR, 0600);
+       if (fd < 0) {
+               CTX_ERROR(xfer->ctx, "Could not open temporary file in %s: %s\n",
+                       dirname, strerror(errno));
+               return -errno;
+       }
+
+       // Turn the file descriptor into a FILE handle
+       f = fdopen(fd, "w+");
+       if (!f)
+               return -errno;
+
+       // Set the handle as output
+       return pakfire_xfer_set_output(xfer, f);
+}
+
+int pakfire_xfer_set_output_path(struct pakfire_xfer* xfer, const char* path) {
+       int r;
+
+       // Store the output path
+       r = pakfire_string_set(xfer->path, path);
+       if (r)
+               return r;
+
+       // Allocate a temporary file
+       r = pakfire_xfer_allocate_tmpfile(xfer, path);
+       if (r)
+               return r;
+
+       return 0;
 }
 
 int pakfire_xfer_auth(struct pakfire_xfer* xfer) {
@@ -667,6 +710,8 @@ static int pakfire_xfer_save(struct pakfire_xfer* xfer) {
 
        CTX_DEBUG(xfer->ctx, "Download successful. Storing result in %s\n", xfer->path);
 
+       int fd = fileno(xfer->fin);
+
        // Make sure the parent directory exists
        r = pakfire_mkparentdir(xfer->path, 0755);
        if (r)
@@ -676,7 +721,7 @@ static int pakfire_xfer_save(struct pakfire_xfer* xfer) {
        unlink(xfer->path);
 
        // Move the temporary file to its destination
-       r = link(xfer->tempfile, xfer->path);
+       r = linkat(fd, "", AT_FDCWD, xfer->path, AT_EMPTY_PATH);
        if (r) {
                CTX_ERROR(xfer->ctx, "Could not link destination file %s: %m\n",
                        xfer->path);
@@ -686,7 +731,7 @@ static int pakfire_xfer_save(struct pakfire_xfer* xfer) {
        // Filetime
        curl_easy_getinfo(xfer->handle, CURLINFO_FILETIME_T, &times.modtime);
 
-       if (times.modtime) {
+       if (times.modtime > 0) {
                r = utime(xfer->path, &times);
                if (r)
                        CTX_ERROR(xfer->ctx, "Could not set mtime of %s: %m\n", xfer->path);
@@ -922,7 +967,6 @@ static int pakfire_xfer_update(void* data,
        return pakfire_progress_update(xfer->progress, xfer->xferred);
 }
 
-
 static int pakfire_xfer_prepare_progress(struct pakfire_xfer* xfer,
                struct pakfire_progress* parent, int flags) {
        const char* title = NULL;
@@ -972,26 +1016,6 @@ static int pakfire_xfer_prepare_progress(struct pakfire_xfer* xfer,
        return 0;
 }
 
-
-static int pakfire_xfer_prepare_tmpfile(struct pakfire_xfer* xfer) {
-       char path[PATH_MAX] = PAKFIRE_TMP_DIR "/pakfire-download.XXXXXX";
-       FILE* f = NULL;
-       int r;
-
-       // Allocate a temporary file
-       f = pakfire_mktemp(path, 0600);
-       if (!f)
-               return -errno;
-
-       // Set this as output
-       r = pakfire_xfer_set_output(xfer, f);
-       if (r)
-               return r;
-
-       // Store the path to the temporary file
-       return pakfire_string_set(xfer->tempfile, path);
-}
-
 static int pakfire_xfer_prepare_url(struct pakfire_xfer* xfer) {
        int r;
 
@@ -1107,15 +1131,6 @@ int pakfire_xfer_prepare(struct pakfire_xfer* xfer, struct pakfire_progress* pro
                }
        }
 
-       // If we do not have an output file, we will create a temporary file
-       if (!xfer->fout && !xfer->fin) {
-               r = pakfire_xfer_prepare_tmpfile(xfer);
-               if (r) {
-                       CTX_ERROR(xfer->ctx, "Could not open a temporary file: %s\n", strerror(-r));
-                       return r;
-               }
-       }
-
        // Authentication
        if (xfer->auth) {
                // Request SPNEGO