aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--src/fs/io/FileOutputStream.cxx70
-rw-r--r--src/fs/io/FileOutputStream.hxx80
2 files changed, 101 insertions, 49 deletions
diff --git a/src/fs/io/FileOutputStream.cxx b/src/fs/io/FileOutputStream.cxx
index 85eb300e7..f587874a3 100644
--- a/src/fs/io/FileOutputStream.cxx
+++ b/src/fs/io/FileOutputStream.cxx
@@ -37,37 +37,33 @@ FileOutputStream::Create(Path path, Error &error)
#ifdef WIN32
FileOutputStream::FileOutputStream(Path _path, Error &error)
- :path(_path),
- handle(CreateFile(path.c_str(), GENERIC_WRITE, 0, nullptr,
- CREATE_ALWAYS,
- FILE_ATTRIBUTE_NORMAL|FILE_FLAG_WRITE_THROUGH,
- nullptr))
+ :BaseFileOutputStream(_path)
{
- if (handle == INVALID_HANDLE_VALUE) {
- const auto path_utf8 = path.ToUTF8();
+ SetHandle(CreateFile(_path.c_str(), GENERIC_WRITE, 0, nullptr,
+ CREATE_ALWAYS,
+ FILE_ATTRIBUTE_NORMAL|FILE_FLAG_WRITE_THROUGH,
+ nullptr));
+ if (!IsDefined())
error.FormatLastError("Failed to create %s",
- path_utf8.c_str());
- }
+ GetPath().ToUTF8().c_str());
}
bool
-FileOutputStream::Write(const void *data, size_t size, Error &error)
+BaseFileOutputStream::Write(const void *data, size_t size, Error &error)
{
assert(IsDefined());
DWORD nbytes;
if (!WriteFile(handle, data, size, &nbytes, nullptr)) {
- const auto path_utf8 = path.ToUTF8();
error.FormatLastError("Failed to write to %s",
- path_utf8.c_str());
+ path.ToUTF8().c_str());
return false;
}
if (size_t(nbytes) != size) {
- const auto path_utf8 = path.ToUTF8();
error.FormatLastError(ERROR_DISK_FULL,
"Failed to write to %s",
- path_utf8.c_str());
+ path.ToUTF8().c_str());
return false;
}
@@ -79,8 +75,7 @@ FileOutputStream::Commit(gcc_unused Error &error)
{
assert(IsDefined());
- CloseHandle(handle);
- handle = INVALID_HANDLE_VALUE;
+ Close();
return true;
}
@@ -89,9 +84,8 @@ FileOutputStream::Cancel()
{
assert(IsDefined());
- CloseHandle(handle);
- handle = INVALID_HANDLE_VALUE;
- RemoveFile(path);
+ Close();
+ RemoveFile(GetPath());
}
#else
@@ -124,35 +118,36 @@ OpenTempFile(FileDescriptor &fd, Path path)
#endif /* HAVE_LINKAT */
FileOutputStream::FileOutputStream(Path _path, Error &error)
- :path(_path)
+ :BaseFileOutputStream(_path)
{
#ifdef HAVE_LINKAT
/* try Linux's O_TMPFILE first */
- is_tmpfile = OpenTempFile(fd, path);
+ is_tmpfile = OpenTempFile(SetFD(), GetPath());
if (!is_tmpfile) {
#endif
/* fall back to plain POSIX */
- if (!fd.Open(path.c_str(),
- O_WRONLY|O_CREAT|O_TRUNC,
- 0666))
- error.FormatErrno("Failed to create %s", path.c_str());
+ if (!SetFD().Open(GetPath().c_str(),
+ O_WRONLY|O_CREAT|O_TRUNC,
+ 0666))
+ error.FormatErrno("Failed to create %s",
+ GetPath().c_str());
#ifdef HAVE_LINKAT
}
#endif
}
bool
-FileOutputStream::Write(const void *data, size_t size, Error &error)
+BaseFileOutputStream::Write(const void *data, size_t size, Error &error)
{
assert(IsDefined());
ssize_t nbytes = fd.Write(data, size);
if (nbytes < 0) {
- error.FormatErrno("Failed to write to %s", path.c_str());
+ error.FormatErrno("Failed to write to %s", GetPath().c_str());
return false;
} else if ((size_t)nbytes < size) {
error.FormatErrno(ENOSPC,
- "Failed to write to %s", path.c_str());
+ "Failed to write to %s", GetPath().c_str());
return false;
}
@@ -166,24 +161,25 @@ FileOutputStream::Commit(Error &error)
#if HAVE_LINKAT
if (is_tmpfile) {
- RemoveFile(path);
+ RemoveFile(GetPath());
/* hard-link the temporary file to the final path */
char fd_path[64];
snprintf(fd_path, sizeof(fd_path), "/proc/self/fd/%d",
- fd.Get());
- if (linkat(AT_FDCWD, fd_path, AT_FDCWD, path.c_str(),
+ GetFD().Get());
+ if (linkat(AT_FDCWD, fd_path, AT_FDCWD, GetPath().c_str(),
AT_SYMLINK_FOLLOW) < 0) {
- error.FormatErrno("Failed to commit %s", path.c_str());
- fd.Close();
+ error.FormatErrno("Failed to commit %s",
+ GetPath().c_str());
+ Close();
return false;
}
}
#endif
- bool success = fd.Close();
+ bool success = Close();
if (!success)
- error.FormatErrno("Failed to commit %s", path.c_str());
+ error.FormatErrno("Failed to commit %s", GetPath().c_str());
return success;
}
@@ -193,12 +189,12 @@ FileOutputStream::Cancel()
{
assert(IsDefined());
- fd.Close();
+ Close();
#ifdef HAVE_LINKAT
if (!is_tmpfile)
#endif
- RemoveFile(path);
+ RemoveFile(GetPath());
}
#endif
diff --git a/src/fs/io/FileOutputStream.hxx b/src/fs/io/FileOutputStream.hxx
index 7d30d95bb..ce53427e2 100644
--- a/src/fs/io/FileOutputStream.hxx
+++ b/src/fs/io/FileOutputStream.hxx
@@ -37,7 +37,7 @@
class Path;
-class FileOutputStream final : public OutputStream {
+class BaseFileOutputStream : public OutputStream {
const AllocatedPath path;
#ifdef WIN32
@@ -46,6 +46,73 @@ class FileOutputStream final : public OutputStream {
FileDescriptor fd;
#endif
+protected:
+#ifdef WIN32
+ template<typename P>
+ BaseFileOutputStream(P &&_path)
+ :path(std::forward<P>(_path)),
+ handle(INVALID_HANDLE_VALUE) {}
+#else
+ template<typename P>
+ BaseFileOutputStream(P &&_path)
+ :path(std::forward<P>(_path)),
+ fd(FileDescriptor::Undefined()) {}
+#endif
+
+ ~BaseFileOutputStream() {
+ assert(!IsDefined());
+ }
+
+#ifdef WIN32
+ void SetHandle(HANDLE _handle) {
+ assert(!IsDefined());
+
+ handle = _handle;
+
+ assert(IsDefined());
+ }
+#else
+ FileDescriptor &SetFD() {
+ assert(!IsDefined());
+
+ return fd;
+ }
+
+ const FileDescriptor &GetFD() const {
+ return fd;
+ }
+#endif
+
+ bool Close() {
+ assert(IsDefined());
+
+#ifdef WIN32
+ CloseHandle(handle);
+ handle = INVALID_HANDLE_VALUE;
+ return true;
+#else
+ return fd.Close();
+#endif
+ }
+
+public:
+ bool IsDefined() const {
+#ifdef WIN32
+ return handle != INVALID_HANDLE_VALUE;
+#else
+ return fd.IsDefined();
+#endif
+ }
+
+ Path GetPath() const {
+ return path;
+ }
+
+ /* virtual methods from class OutputStream */
+ bool Write(const void *data, size_t size, Error &error) override;
+};
+
+class FileOutputStream final : public BaseFileOutputStream {
#ifdef HAVE_LINKAT
/**
* Was O_TMPFILE used? If yes, then linkat() must be used to
@@ -64,19 +131,8 @@ public:
static FileOutputStream *Create(Path path, Error &error);
- bool IsDefined() const {
-#ifdef WIN32
- return handle != INVALID_HANDLE_VALUE;
-#else
- return fd.IsDefined();
-#endif
- }
-
bool Commit(Error &error);
void Cancel();
-
- /* virtual methods from class OutputStream */
- bool Write(const void *data, size_t size, Error &error) override;
};
#endif