diff options
author | John Högberg <john@erlang.org> | 2019-09-19 10:05:15 +0200 |
---|---|---|
committer | John Högberg <john@erlang.org> | 2019-09-19 10:05:15 +0200 |
commit | e0bd1d7ba2ed63b38cd068dbe619f023b041407f (patch) | |
tree | c655895e52397573c1a451b0308519caef6b9748 | |
parent | d3e317df172f2c6025e9dd9b0b2588e6682c8a35 (diff) | |
parent | 7666df1840a389dc453983a04995b4b934172190 (diff) | |
download | erlang-e0bd1d7ba2ed63b38cd068dbe619f023b041407f.tar.gz |
Merge branch 'maint'
* maint:
file_SUITE: Only test allocate/3 size updates on known ok platforms
Fix efile_allocate on Mac
-rw-r--r-- | erts/emulator/nifs/unix/unix_prim_file.c | 42 | ||||
-rw-r--r-- | lib/kernel/test/file_SUITE.erl | 26 |
2 files changed, 64 insertions, 4 deletions
diff --git a/erts/emulator/nifs/unix/unix_prim_file.c b/erts/emulator/nifs/unix/unix_prim_file.c index 176a9318b2..e5099dd921 100644 --- a/erts/emulator/nifs/unix/unix_prim_file.c +++ b/erts/emulator/nifs/unix/unix_prim_file.c @@ -566,18 +566,54 @@ int efile_allocate(efile_data_t *d, Sint64 offset, Sint64 length) { } while(ret < 0 && errno == EINTR); #elif defined(F_PREALLOCATE) /* Mac-specific */ + off_t original_position, eof_offset; fstore_t fs = {}; + if(offset < 0 || length < 0 || (offset > ERTS_SINT64_MAX - length)) { + u->common.posix_errno = EINVAL; + return 0; + } + + original_position = lseek(u->fd, 0, SEEK_CUR); + + if(original_position < 0) { + u->common.posix_errno = errno; + return 0; + } + + eof_offset = lseek(u->fd, 0, SEEK_END); + + if(eof_offset < 0 || lseek(u->fd, original_position, SEEK_SET) < 0) { + u->common.posix_errno = errno; + return 0; + } + + if(offset + length <= eof_offset) { + /* File is already large enough. */ + return 1; + } + fs.fst_flags = F_ALLOCATECONTIG; - fs.fst_posmode = F_VOLPOSMODE; - fs.fst_offset = offset; - fs.fst_length = length; + fs.fst_posmode = F_PEOFPOSMODE; + fs.fst_offset = 0; + fs.fst_length = (offset + length) - eof_offset; ret = fcntl(u->fd, F_PREALLOCATE, &fs); if(ret < 0) { fs.fst_flags = F_ALLOCATEALL; ret = fcntl(u->fd, F_PREALLOCATE, &fs); } + + if(ret >= 0) { + /* We MUST truncate since F_PREALLOCATE works relative to end-of-file, + * otherwise we will expand the file on repeated calls to + * file:allocate/3 with the same arguments. */ + ret = ftruncate(u->fd, offset + length); + if(ret < 0) { + u->common.posix_errno = errno; + return 0; + } + } #elif !defined(HAVE_POSIX_FALLOCATE) u->common.posix_errno = ENOTSUP; return 0; diff --git a/lib/kernel/test/file_SUITE.erl b/lib/kernel/test/file_SUITE.erl index 747f1d9e1b..e4299cd346 100644 --- a/lib/kernel/test/file_SUITE.erl +++ b/lib/kernel/test/file_SUITE.erl @@ -96,6 +96,8 @@ -export([allocate/1]). +-export([allocate_file_size/1]). + -export([standard_io/1,mini_server/1]). -export([old_io_protocol/1]). @@ -147,7 +149,7 @@ groups() -> {files, [], [{group, open}, {group, pos}, {group, file_info}, {group, consult}, {group, eval}, {group, script}, - truncate, sync, datasync, advise, allocate]}, + truncate, sync, datasync, advise, allocate, allocate_file_size]}, {open, [], [open1, old_modes, new_modes, path_open, close, access, read_write, pread_write, append, open_errors, @@ -2227,6 +2229,28 @@ allocate_and_assert(Fd, Offset, Length) -> _ = Result end. +%% Tests that asserts that file:allocate/3 changes file size +allocate_file_size(Config) when is_list(Config) -> + case os:type() of + {unix, darwin} -> + PrivDir = proplists:get_value(priv_dir, Config), + Allocate = filename:join(PrivDir, atom_to_list(?MODULE)++"_allocate_file"), + + {ok, Fd} = ?FILE_MODULE:open(Allocate, [write]), + ok = ?FILE_MODULE:allocate(Fd, 0, 1024), + {ok, 1024} = ?FILE_MODULE:position(Fd, eof), + ok = ?FILE_MODULE:close(Fd), + + [] = flush(), + ok; + {unix, linux} -> + {skip, "file:allocate/3 on Linux does not change file size"}; + {win32, _} -> + {skip, "Windows does not support file:allocate/3"}; + _ -> + {skip, "Support for allocate/3 is spotty in our test platform at the moment."} + end. + %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% delete(Config) when is_list(Config) -> |