aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--erts/emulator/drivers/common/erl_efile.h1
-rw-r--r--erts/emulator/drivers/unix/unix_efile.c9
-rw-r--r--erts/emulator/drivers/win32/win_efile.c7
-rw-r--r--erts/preloaded/ebin/prim_file.beambin44232 -> 44592 bytes
-rw-r--r--erts/preloaded/src/prim_file.erl6
-rw-r--r--lib/kernel/doc/src/file.xml10
-rw-r--r--lib/kernel/src/file.erl3
-rw-r--r--lib/kernel/test/file_SUITE.erl14
8 files changed, 47 insertions, 3 deletions
diff --git a/erts/emulator/drivers/common/erl_efile.h b/erts/emulator/drivers/common/erl_efile.h
index 5387f75efc..95c036db8f 100644
--- a/erts/emulator/drivers/common/erl_efile.h
+++ b/erts/emulator/drivers/common/erl_efile.h
@@ -34,6 +34,7 @@
#define EFILE_COMPRESSED 8
#define EFILE_MODE_EXCL 16
#define EFILE_NO_TRUNCATE 32 /* Special for reopening on VxWorks */
+#define EFILE_MODE_SYNC 64
/*
* Seek modes for efile_seek().
diff --git a/erts/emulator/drivers/unix/unix_efile.c b/erts/emulator/drivers/unix/unix_efile.c
index 55539b44dd..8ffc05da99 100644
--- a/erts/emulator/drivers/unix/unix_efile.c
+++ b/erts/emulator/drivers/unix/unix_efile.c
@@ -405,6 +405,15 @@ efile_openfile(Efile_error* errInfo, /* Where to return error codes. */
mode |= O_EXCL;
}
+ if (flags & EFILE_MODE_SYNC) {
+#ifdef O_SYNC
+ mode |= O_SYNC;
+#else
+ errno = ENOTSUP;
+ return check_error(-1, errInfo);
+#endif
+ }
+
fd = open(name, mode, FILE_MODE);
if (!check_error(fd, errInfo))
diff --git a/erts/emulator/drivers/win32/win_efile.c b/erts/emulator/drivers/win32/win_efile.c
index 319065f57b..d693d7d593 100644
--- a/erts/emulator/drivers/win32/win_efile.c
+++ b/erts/emulator/drivers/win32/win_efile.c
@@ -698,6 +698,7 @@ efile_openfile(Efile_error* errInfo, /* Where to return error codes. */
HANDLE fd; /* Handle to open file. */
DWORD access; /* Access mode: GENERIC_READ, GENERIC_WRITE. */
DWORD crFlags;
+ DWORD flagsAndAttrs = FILE_ATTRIBUTE_NORMAL;
WCHAR *wname = (WCHAR *) name;
switch (flags & (EFILE_MODE_READ|EFILE_MODE_WRITE)) {
@@ -719,6 +720,10 @@ efile_openfile(Efile_error* errInfo, /* Where to return error codes. */
return 0;
}
+ if (flags & EFILE_MODE_SYNC) {
+ flagsAndAttrs = FILE_FLAG_WRITE_THROUGH;
+ }
+
if (flags & EFILE_MODE_APPEND) {
crFlags = OPEN_ALWAYS;
}
@@ -727,7 +732,7 @@ efile_openfile(Efile_error* errInfo, /* Where to return error codes. */
}
fd = CreateFileW(wname, access,
FILE_SHARE_FLAGS,
- NULL, crFlags, FILE_ATTRIBUTE_NORMAL, NULL);
+ NULL, crFlags, flagsAndAttrs, NULL);
/*
* Check for errors.
diff --git a/erts/preloaded/ebin/prim_file.beam b/erts/preloaded/ebin/prim_file.beam
index a1028c5480..de88b33fea 100644
--- a/erts/preloaded/ebin/prim_file.beam
+++ b/erts/preloaded/ebin/prim_file.beam
Binary files differ
diff --git a/erts/preloaded/src/prim_file.erl b/erts/preloaded/src/prim_file.erl
index 489e8ca4ea..5999e98340 100644
--- a/erts/preloaded/src/prim_file.erl
+++ b/erts/preloaded/src/prim_file.erl
@@ -123,9 +123,11 @@
-define(EFILE_MODE_APPEND, 4).
-define(EFILE_COMPRESSED, 8).
-define(EFILE_MODE_EXCL, 16).
+%% Note: bit 5 (32) is used internally for VxWorks
+-define(EFILE_MODE_SYNC, 64).
%% Use this mask to get just the mode bits to be passed to the driver.
--define(EFILE_MODE_MASK, 31).
+-define(EFILE_MODE_MASK, 127).
%% Seek modes for the driver's seek function.
-define(EFILE_SEEK_SET, 0).
@@ -1197,6 +1199,8 @@ open_mode([append|Rest], Mode, Portopts, Setopts) ->
Portopts, Setopts);
open_mode([exclusive|Rest], Mode, Portopts, Setopts) ->
open_mode(Rest, Mode bor ?EFILE_MODE_EXCL, Portopts, Setopts);
+open_mode([sync|Rest], Mode, Portopts, Setopts) ->
+ open_mode(Rest, Mode bor ?EFILE_MODE_SYNC, Portopts, Setopts);
open_mode([delayed_write|Rest], Mode, Portopts, Setopts) ->
open_mode([{delayed_write, 64*1024, 2000}|Rest], Mode,
Portopts, Setopts);
diff --git a/lib/kernel/doc/src/file.xml b/lib/kernel/doc/src/file.xml
index 1118a8feee..0a4dd3ba47 100644
--- a/lib/kernel/doc/src/file.xml
+++ b/lib/kernel/doc/src/file.xml
@@ -826,6 +826,16 @@
<item>
<p><c>File</c> must be <c>iodata()</c>. Returns an <c>fd()</c> which lets the <c>file</c> module operate on the data in-memory as if it is a file.</p>
</item>
+ <tag><c>sync</c></tag>
+ <item>
+ <p>On platforms that support it, enables the POSIX <c>O_SYNC</c> synchronous I/O flag or its platform-dependent
+ equivalent (e.g., <c>FILE_FLAG_WRITE_THROUGH</c> on Windows) so that writes to the file block until the data has
+ been physically written to disk. Be aware, though, that the exact semantics of this flag differ from platform to
+ platform; for example, neither Linux nor Windows guarantees that all file metadata are also written before the call
+ returns. For precise semantics, check the details of your platform's documentation. On platforms with no
+ support for POSIX <c>O_SYNC</c> or equivalent, use of the <c>sync</c> flag causes <c>open</c> to return
+ <c>{error, enotsup}</c>.</p>
+ </item>
</taglist>
<p>Returns:</p>
<taglist>
diff --git a/lib/kernel/src/file.erl b/lib/kernel/src/file.erl
index 5c0f3b7ceb..b5152018e0 100644
--- a/lib/kernel/src/file.erl
+++ b/lib/kernel/src/file.erl
@@ -95,7 +95,8 @@
Delay :: non_neg_integer()}
| 'delayed_write' | {'read_ahead', Size :: pos_integer()}
| 'read_ahead' | 'compressed'
- | {'encoding', unicode:encoding()}.
+ | {'encoding', unicode:encoding()}
+ | sync.
-type deep_list() :: [char() | atom() | deep_list()].
-type name() :: string() | atom() | deep_list().
-type name_all() :: string() | atom() | deep_list() | (RawFilename :: binary()).
diff --git a/lib/kernel/test/file_SUITE.erl b/lib/kernel/test/file_SUITE.erl
index e4c8f0ffaf..c75639ae7e 100644
--- a/lib/kernel/test/file_SUITE.erl
+++ b/lib/kernel/test/file_SUITE.erl
@@ -805,6 +805,20 @@ new_modes(Config) when is_list(Config) ->
?line {ok, [$\[]} = ?FILE_MODULE:read(Fd6, 1),
?line ok = ?FILE_MODULE:close(Fd6),
+ %% write and sync
+ case ?FILE_MODULE:open(Name1, [write, sync]) of
+ {ok, Fd7} ->
+ ok = io:write(Fd7, Marker),
+ ok = io:put_chars(Fd7, ".\n"),
+ ok = ?FILE_MODULE:close(Fd7),
+ {ok, Fd8} = ?FILE_MODULE:open(Name1, [read]),
+ {ok, Marker} = io:read(Fd8, prompt),
+ ok = ?FILE_MODULE:close(Fd8);
+ {error, enotsup} ->
+ %% for platforms that don't support the sync option
+ ok
+ end,
+
?line [] = flush(),
?line test_server:timetrap_cancel(Dog),
ok.