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>
(cherry picked from commit 4f4a7e9532
)
This commit is contained in:
parent
7f00eebab0
commit
68aa303efb
2 changed files with 29 additions and 21 deletions
|
@ -8,7 +8,7 @@
|
||||||
include $(TOPDIR)/rules.mk
|
include $(TOPDIR)/rules.mk
|
||||||
|
|
||||||
PKG_NAME:=cgi-io
|
PKG_NAME:=cgi-io
|
||||||
PKG_RELEASE:=17
|
PKG_RELEASE:=18
|
||||||
|
|
||||||
PKG_LICENSE:=GPL-2.0-or-later
|
PKG_LICENSE:=GPL-2.0-or-later
|
||||||
|
|
||||||
|
|
|
@ -436,32 +436,44 @@ filecopy(void)
|
||||||
return response(false, "No file data received");
|
return response(false, "No file data received");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (lseek(st.tempfd, 0, SEEK_SET) < 0)
|
snprintf(buf, sizeof(buf), "/proc/self/fd/%d", st.tempfd);
|
||||||
|
|
||||||
|
if (unlink(st.filename) < 0 && errno != ENOENT)
|
||||||
{
|
{
|
||||||
close(st.tempfd);
|
close(st.tempfd);
|
||||||
return response(false, "Failed to rewind temp file");
|
return response(false, "Failed to unlink existing file");
|
||||||
}
|
}
|
||||||
|
|
||||||
st.filefd = open(st.filename, O_CREAT | O_TRUNC | O_WRONLY, 0600);
|
if (linkat(AT_FDCWD, buf, AT_FDCWD, st.filename, AT_SYMLINK_FOLLOW) < 0)
|
||||||
|
|
||||||
if (st.filefd < 0)
|
|
||||||
{
|
{
|
||||||
close(st.tempfd);
|
if (lseek(st.tempfd, 0, SEEK_SET) < 0)
|
||||||
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.tempfd);
|
||||||
close(st.filefd);
|
return response(false, "Failed to rewind temp file");
|
||||||
return response(false, "I/O failure while writing target file");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
st.filefd = open(st.filename, O_CREAT | O_TRUNC | O_WRONLY, 0600);
|
||||||
|
|
||||||
|
if (st.filefd < 0)
|
||||||
|
{
|
||||||
|
close(st.tempfd);
|
||||||
|
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.tempfd);
|
||||||
close(st.filefd);
|
|
||||||
|
|
||||||
if (chmod(st.filename, st.filemode))
|
if (chmod(st.filename, st.filemode))
|
||||||
return response(false, "Failed to chmod target file");
|
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
|
static int
|
||||||
data_begin_cb(multipart_parser *p)
|
data_begin_cb(multipart_parser *p)
|
||||||
{
|
{
|
||||||
char tmpname[24] = "/tmp/luci-upload.XXXXXX";
|
|
||||||
|
|
||||||
if (st.parttype == PART_FILEDATA)
|
if (st.parttype == PART_FILEDATA)
|
||||||
{
|
{
|
||||||
if (!st.sessionid)
|
if (!st.sessionid)
|
||||||
|
@ -523,12 +533,10 @@ data_begin_cb(multipart_parser *p)
|
||||||
if (!session_access(st.sessionid, "file", st.filename, "write"))
|
if (!session_access(st.sessionid, "file", st.filename, "write"))
|
||||||
return response(false, "Access to path denied by ACL");
|
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)
|
if (st.tempfd < 0)
|
||||||
return response(false, "Failed to create temporary file");
|
return response(false, "Failed to create temporary file");
|
||||||
|
|
||||||
unlink(tmpname);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
Loading…
Reference in a new issue