aboutsummaryrefslogtreecommitdiff
path: root/net
diff options
context:
space:
mode:
authorJo-Philipp Wich <jo@mein.io>2020-02-22 00:13:32 +0100
committerJohn Crispin <john@phrozen.org>2020-02-22 18:17:33 +0100
commit4f4a7e9532e55a16336b79b74b5fb0236e365279 (patch)
tree1a9d7ab384520f87873c886f448f6aeb05656d58 /net
parentc971724874fce3d9f28e23074405c03eb1303364 (diff)
cgi-io: use O_TMPFILE for uploads and attempt to directly link target file
Create an anonymous inode in /tmp using O_TMPFILE and attempt to link the file in place using linkat(). Only fall back to the old file copy when linking the tempfile fails. Avoids double memory use if both the temporary upload file and the destination file are located in /tmp. Ref: https://github.com/openwrt/luci/issues/3654 Signed-off-by: Jo-Philipp Wich <jo@mein.io>
Diffstat (limited to 'net')
-rw-r--r--net/cgi-io/Makefile2
-rw-r--r--net/cgi-io/src/main.c46
2 files changed, 28 insertions, 20 deletions
diff --git a/net/cgi-io/Makefile b/net/cgi-io/Makefile
index c8e4164ef..32498bc8e 100644
--- a/net/cgi-io/Makefile
+++ b/net/cgi-io/Makefile
@@ -8,7 +8,7 @@
include $(TOPDIR)/rules.mk
PKG_NAME:=cgi-io
-PKG_RELEASE:=17
+PKG_RELEASE:=18
PKG_LICENSE:=GPL-2.0-or-later
diff --git a/net/cgi-io/src/main.c b/net/cgi-io/src/main.c
index 6e9112c0f..d45c67b85 100644
--- a/net/cgi-io/src/main.c
+++ b/net/cgi-io/src/main.c
@@ -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;