diff options
author | Max Kellermann <max@musicpd.org> | 2019-01-21 21:07:34 +0100 |
---|---|---|
committer | Max Kellermann <max@musicpd.org> | 2019-01-21 21:10:02 +0100 |
commit | cf23fd877452977704b57790c353824791eb335e (patch) | |
tree | 965fc497d7257550a447445f7b35e72036f9bf45 /src | |
parent | dee88723951e14283db5c814a31b7fb85dce2619 (diff) |
fs/io/FileOutputStream: add constructor with directory fd
Diffstat (limited to 'src')
-rw-r--r-- | src/fs/io/FileOutputStream.cxx | 51 | ||||
-rw-r--r-- | src/fs/io/FileOutputStream.hxx | 9 |
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(); |