From 3ebb065509aa027088bd1a6ea3d4ee005f4d45fe Mon Sep 17 00:00:00 2001 From: v1ne Date: Fri, 26 Jul 2019 00:20:53 +0200 Subject: [PATCH 1/3] Clean up: Use "enforce" --- source/vibe/core/file.d | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/source/vibe/core/file.d b/source/vibe/core/file.d index e32efef..4bd1cda 100644 --- a/source/vibe/core/file.d +++ b/source/vibe/core/file.d @@ -647,8 +647,7 @@ struct DirectoryWatcher { // TODO: avoid all those heap allocations! m_context = new Context; // FIME: avoid GC allocation (use FD user data slot) m_context.changeEvent = createManualEvent(); m_watcher = eventDriver.watchers.watchDirectory(path.toNativeString, recursive, &m_context.onChange); - if (m_watcher == WatcherID.invalid) - throw new Exception("Failed to watch directory."); + enforce(m_watcher != WatcherID.invalid, "Failed to watch directory."); m_context.path = path; m_context.recursive = recursive; m_context.changes = appender!(DirectoryChange[]); From ce9faec1c1e13a5afa87b705a113be68d445a36b Mon Sep 17 00:00:00 2001 From: v1ne Date: Fri, 26 Jul 2019 00:27:50 +0200 Subject: [PATCH 2/3] FileStream: Forbid seek(.) or truncate(.) when appending to a file Those functions do not work for files opened for appending. Make this clear. --- source/vibe/core/file.d | 3 +++ 1 file changed, 3 insertions(+) diff --git a/source/vibe/core/file.d b/source/vibe/core/file.d index 4bd1cda..fcec414 100644 --- a/source/vibe/core/file.d +++ b/source/vibe/core/file.d @@ -472,6 +472,7 @@ struct FileStream { void seek(ulong offset) { + enforce(ctx.mode != FileMode.append, "File opened for appending, not random access. Cannot seek."); ctx.ptr = offset; } @@ -479,6 +480,8 @@ struct FileStream { void truncate(ulong size) { + enforce(ctx.mode != FileMode.append, "File opened for appending, not random access. Cannot truncate."); + auto res = asyncAwaitUninterruptible!(FileIOCallback, cb => eventDriver.files.truncate(m_fd, size, cb) ); From 513bebcb9573280433c5939027945d93d5181143 Mon Sep 17 00:00:00 2001 From: v1ne Date: Sat, 20 Jul 2019 01:34:27 +0200 Subject: [PATCH 3/3] FileStream: Approximate the file offset better when appending Instead of starting at zero, start at the current file size. This offset is stored in FileStream. It is only an approximation because concurrent writes could advance the file without FileStream's knowledge. Add a test that shows that the offset is approximated as expected and that appending to an existing file works, too. This is also a regression test which shows that appending to an existing file works as expected. See vibe-d/eventcore#115. --- source/vibe/core/file.d | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/source/vibe/core/file.d b/source/vibe/core/file.d index fcec414..09f8754 100644 --- a/source/vibe/core/file.d +++ b/source/vibe/core/file.d @@ -438,6 +438,9 @@ struct FileStream { m_ctx.mode = mode; m_ctx.size = eventDriver.files.getSize(fd); m_ctx.driver = () @trusted { return cast(shared)eventDriver; } (); + + if (mode == FileMode.append) + m_ctx.ptr = m_ctx.size; } this(this) @@ -787,3 +790,23 @@ version (Windows) {} else unittest { testCreate(".test_foo/", ".test_foo", true); test("/", "", false); } + +unittest { + auto name = "toAppend.txt"; + scope(exit) removeFile(name); + + { + auto handle = openFile(name, FileMode.createTrunc); + handle.write("create,"); + assert(handle.tell() == "create,".length); + handle.close(); + } + { + auto handle = openFile(name, FileMode.append); + handle.write(" then append"); + assert(handle.tell() == "create, then append".length); + handle.close(); + } + + assert(readFile(name) == "create, then append"); +}