cgi-io: use O_TMPFILE for uploads and attempt to directly link target file
[project/cgi-io.git] / src / main.c
index 6e9112c0f93f86c3a0bae0310094471455388519..d45c67b85f345110a54a30e8d077abcbea559c8b 100644 (file)
@@ -436,32 +436,44 @@ filecopy(void)
                return response(false, "No file data received");
        }
 
-       if (lseek(st.tempfd, 0, SEEK_SET) < 0)
-       {
-               close(st.tempfd);
-               return response(false, "Failed to rewind temp file");
-       }
+       snprintf(buf, sizeof(buf), "/proc/self/fd/%d", st.tempfd);
 
-       st.filefd = open(st.filename, O_CREAT | O_TRUNC | O_WRONLY, 0600);
-
-       if (st.filefd < 0)
+       if (unlink(st.filename) < 0 && errno != ENOENT)
        {
                close(st.tempfd);
-               return response(false, "Failed to open target file");
+               return response(false, "Failed to unlink existing file");
        }
 
-       while ((len = read(st.tempfd, buf, sizeof(buf))) > 0)
+       if (linkat(AT_FDCWD, buf, AT_FDCWD, st.filename, AT_SYMLINK_FOLLOW) < 0)
        {
-               if (write(st.filefd, buf, len) != len)
+               if (lseek(st.tempfd, 0, SEEK_SET) < 0)
+               {
+                       close(st.tempfd);
+                       return response(false, "Failed to rewind temp file");
+               }
+
+               st.filefd = open(st.filename, O_CREAT | O_TRUNC | O_WRONLY, 0600);
+
+               if (st.filefd < 0)
                {
                        close(st.tempfd);
-                       close(st.filefd);
-                       return response(false, "I/O failure while writing target file");
+                       return response(false, "Failed to open target file");
                }
+
+               while ((len = read(st.tempfd, buf, sizeof(buf))) > 0)
+               {
+                       if (write(st.filefd, buf, len) != len)
+                       {
+                               close(st.tempfd);
+                               close(st.filefd);
+                               return response(false, "I/O failure while writing target file");
+                       }
+               }
+
+               close(st.filefd);
        }
 
        close(st.tempfd);
-       close(st.filefd);
 
        if (chmod(st.filename, st.filemode))
                return response(false, "Failed to chmod target file");
@@ -510,8 +522,6 @@ header_value(multipart_parser *p, const char *data, size_t len)
 static int
 data_begin_cb(multipart_parser *p)
 {
-       char tmpname[24] = "/tmp/luci-upload.XXXXXX";
-
        if (st.parttype == PART_FILEDATA)
        {
                if (!st.sessionid)
@@ -523,12 +533,10 @@ data_begin_cb(multipart_parser *p)
                if (!session_access(st.sessionid, "file", st.filename, "write"))
                        return response(false, "Access to path denied by ACL");
 
-               st.tempfd = mkstemp(tmpname);
+               st.tempfd = open("/tmp", O_TMPFILE | O_RDWR, S_IRUSR | S_IWUSR);
 
                if (st.tempfd < 0)
                        return response(false, "Failed to create temporary file");
-
-               unlink(tmpname);
        }
 
        return 0;