summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorMax Kellermann <max@musicpd.org>2019-01-21 21:07:34 +0100
committerMax Kellermann <max@musicpd.org>2019-01-21 21:10:02 +0100
commitcf23fd877452977704b57790c353824791eb335e (patch)
tree965fc497d7257550a447445f7b35e72036f9bf45 /src
parentdee88723951e14283db5c814a31b7fb85dce2619 (diff)
fs/io/FileOutputStream: add constructor with directory fd
Diffstat (limited to 'src')
-rw-r--r--src/fs/io/FileOutputStream.cxx51
-rw-r--r--src/fs/io/FileOutputStream.hxx9
2 files changed, 52 insertions, 8 deletions
diff --git a/src/fs/io/FileOutputStream.cxx b/src/fs/io/FileOutputStream.cxx
index 0ee62a092..83518e177 100644
--- a/src/fs/io/FileOutputStream.cxx
+++ b/src/fs/io/FileOutputStream.cxx
@@ -31,8 +31,27 @@
#include "system/Error.hxx"
#include "util/StringFormat.hxx"
+#ifdef __linux__
+#include <fcntl.h>
+#endif
+
+#ifdef __linux__
+FileOutputStream::FileOutputStream(FileDescriptor _directory_fd,
+ Path _path, Mode _mode)
+ :path(_path),
+ directory_fd(_directory_fd),
+ mode(_mode)
+{
+ Open();
+}
+#endif
+
FileOutputStream::FileOutputStream(Path _path, Mode _mode)
- :path(_path), mode(_mode)
+ :path(_path),
+#ifdef __linux__
+ directory_fd(AT_FDCWD),
+#endif
+ mode(_mode)
{
Open();
}
@@ -155,8 +174,12 @@ FileOutputStream::Cancel() noexcept
* Open a file using Linux's O_TMPFILE for writing the given file.
*/
static bool
-OpenTempFile(FileDescriptor &fd, Path path)
+OpenTempFile(FileDescriptor directory_fd,
+ FileDescriptor &fd, Path path)
{
+ if (directory_fd != FileDescriptor(AT_FDCWD))
+ return fd.Open(directory_fd, ".", O_TMPFILE|O_WRONLY, 0666);
+
const auto directory = path.GetDirectoryName();
if (directory.IsNull())
return false;
@@ -171,11 +194,15 @@ FileOutputStream::OpenCreate(bool visible)
{
#ifdef HAVE_O_TMPFILE
/* try Linux's O_TMPFILE first */
- is_tmpfile = !visible && OpenTempFile(fd, GetPath());
+ is_tmpfile = !visible && OpenTempFile(directory_fd, fd, GetPath());
if (!is_tmpfile) {
#endif
/* fall back to plain POSIX */
- if (!fd.Open(GetPath().c_str(),
+ if (!fd.Open(
+#ifdef __linux__
+ directory_fd,
+#endif
+ GetPath().c_str(),
O_WRONLY|O_CREAT|O_TRUNC,
0666))
throw FormatErrno("Failed to create %s",
@@ -194,7 +221,11 @@ FileOutputStream::OpenAppend(bool create)
if (create)
flags |= O_CREAT;
- if (!fd.Open(path.c_str(), flags))
+ if (!fd.Open(
+#ifdef __linux__
+ directory_fd,
+#endif
+ path.c_str(), flags))
throw FormatErrno("Failed to append to %s",
path.c_str());
}
@@ -225,12 +256,12 @@ FileOutputStream::Commit()
#ifdef HAVE_O_TMPFILE
if (is_tmpfile) {
- unlink(GetPath().c_str());
+ unlinkat(directory_fd.Get(), GetPath().c_str(), 0);
/* hard-link the temporary file to the final path */
if (linkat(AT_FDCWD,
StringFormat<64>("/proc/self/fd/%d", fd.Get()),
- AT_FDCWD, path.c_str(),
+ directory_fd.Get(), path.c_str(),
AT_SYMLINK_FOLLOW) < 0)
throw FormatErrno("Failed to commit %s",
path.c_str());
@@ -259,7 +290,11 @@ FileOutputStream::Cancel() noexcept
#ifdef HAVE_O_TMPFILE
if (!is_tmpfile)
#endif
- unlink(GetPath().c_str());
+#ifdef __linux__
+ unlinkat(directory_fd.Get(), GetPath().c_str(), 0);
+#else
+ unlink(GetPath().c_str());
+#endif
break;
case Mode::CREATE_VISIBLE:
diff --git a/src/fs/io/FileOutputStream.hxx b/src/fs/io/FileOutputStream.hxx
index a17350adc..73ac4f6f8 100644
--- a/src/fs/io/FileOutputStream.hxx
+++ b/src/fs/io/FileOutputStream.hxx
@@ -59,6 +59,10 @@ class Path;
class FileOutputStream final : public OutputStream {
const AllocatedPath path;
+#ifdef __linux__
+ const FileDescriptor directory_fd;
+#endif
+
#ifdef _WIN32
HANDLE handle = INVALID_HANDLE_VALUE;
#else
@@ -108,6 +112,11 @@ private:
public:
explicit FileOutputStream(Path _path, Mode _mode=Mode::CREATE);
+#ifdef __linux__
+ FileOutputStream(FileDescriptor _directory_fd, Path _path,
+ Mode _mode=Mode::CREATE);
+#endif
+
~FileOutputStream() noexcept {
if (IsDefined())
Cancel();