aboutsummaryrefslogtreecommitdiffstats
path: root/lib/kernel/test/file_SUITE.erl
diff options
context:
space:
mode:
Diffstat (limited to 'lib/kernel/test/file_SUITE.erl')
-rw-r--r--lib/kernel/test/file_SUITE.erl838
1 files changed, 528 insertions, 310 deletions
diff --git a/lib/kernel/test/file_SUITE.erl b/lib/kernel/test/file_SUITE.erl
index 848db06e82..a7993dc21b 100644
--- a/lib/kernel/test/file_SUITE.erl
+++ b/lib/kernel/test/file_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2012. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2013. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -45,6 +45,8 @@
init_per_testcase/2, end_per_testcase/2,
read_write_file/1, names/1]).
-export([cur_dir_0/1, cur_dir_1/1, make_del_dir/1,
+ list_dir/1,list_dir_error/1,
+ untranslatable_names/1, untranslatable_names_error/1,
pos1/1, pos2/1]).
-export([close/1, consult1/1, path_consult/1, delete/1]).
-export([ eval1/1, path_eval/1, script1/1, path_script/1,
@@ -60,7 +62,8 @@
-export([ read_not_really_compressed/1,
read_compressed_cooked/1, read_compressed_cooked_binary/1,
read_cooked_tar_problem/1,
- write_compressed/1, compress_errors/1, catenated_gzips/1]).
+ write_compressed/1, compress_errors/1, catenated_gzips/1,
+ compress_async_crash/1]).
-export([ make_link/1, read_link_info_for_non_link/1, symlinks/1]).
@@ -84,6 +87,8 @@
-export([advise/1]).
+-export([allocate/1]).
+
-export([standard_io/1,mini_server/1]).
%% Debug exports
@@ -112,11 +117,13 @@ all() ->
read_line_4, standard_io].
groups() ->
- [{dirs, [], [make_del_dir, cur_dir_0, cur_dir_1]},
+ [{dirs, [], [make_del_dir, cur_dir_0, cur_dir_1,
+ list_dir, list_dir_error, untranslatable_names,
+ untranslatable_names_error]},
{files, [],
[{group, open}, {group, pos}, {group, file_info},
{group, consult}, {group, eval}, {group, script},
- truncate, sync, datasync, advise]},
+ truncate, sync, datasync, advise, allocate]},
{open, [],
[open1, old_modes, new_modes, path_open, close, access,
read_write, pread_write, append, open_errors,
@@ -133,7 +140,8 @@ groups() ->
{compression, [],
[read_compressed_cooked, read_compressed_cooked_binary,
read_cooked_tar_problem, read_not_really_compressed,
- write_compressed, compress_errors, catenated_gzips]},
+ write_compressed, compress_errors, catenated_gzips,
+ compress_async_crash]},
{links, [],
[make_link, read_link_info_for_non_link, symlinks]}].
@@ -228,7 +236,7 @@ mini_server(Parent) ->
receive
die ->
ok;
- {io_request,From,To,{put_chars,Data}} ->
+ {io_request,From,To,{put_chars,_Encoding,Data}} ->
Parent ! {io_request,From,To,{put_chars,Data}},
From ! {io_reply, To, ok},
mini_server(Parent);
@@ -492,8 +500,6 @@ cur_dir_1(Config) when is_list(Config) ->
?line case os:type() of
{unix, _} ->
?line {error, enotsup} = ?FILE_MODULE:get_cwd("d:");
- vxworks ->
- ?line {error, enotsup} = ?FILE_MODULE:get_cwd("d:");
{win32, _} ->
win_cur_dir_1(Config)
end,
@@ -517,6 +523,148 @@ win_cur_dir_1(_Config) ->
ok.
+
+%%%
+%%% Test list_dir() on a non-existing pathname.
+%%%
+
+list_dir_error(Config) ->
+ Priv = ?config(priv_dir, Config),
+ NonExisting = filename:join(Priv, "non-existing-dir"),
+ {error,enoent} = ?FILE_MODULE:list_dir(NonExisting),
+ ok.
+
+%%%
+%%% Test list_dir() and list_dir_all().
+%%%
+
+list_dir(Config) ->
+ RootDir = ?config(priv_dir, Config),
+ TestDir = filename:join(RootDir, ?MODULE_STRING++"_list_dir"),
+ ?FILE_MODULE:make_dir(TestDir),
+ list_dir_1(TestDir, 42, []).
+
+list_dir_1(TestDir, 0, Sorted) ->
+ [ok = ?FILE_MODULE:delete(filename:join(TestDir, F)) ||
+ F <- Sorted],
+ ok = ?FILE_MODULE:del_dir(TestDir);
+list_dir_1(TestDir, Cnt, Sorted0) ->
+ Base = "file" ++ integer_to_list(Cnt),
+ Name = filename:join(TestDir, Base),
+ ok = ?FILE_MODULE:write_file(Name, Base),
+ Sorted = lists:merge([Base], Sorted0),
+ {ok,DirList0} = ?FILE_MODULE:list_dir(TestDir),
+ {ok,DirList1} = ?FILE_MODULE:list_dir_all(TestDir),
+ Sorted = lists:sort(DirList0),
+ Sorted = lists:sort(DirList1),
+ list_dir_1(TestDir, Cnt-1, Sorted).
+
+untranslatable_names(Config) ->
+ case no_untranslatable_names() of
+ true ->
+ {skip,"Not a problem on this OS"};
+ false ->
+ untranslatable_names_1(Config)
+ end.
+
+untranslatable_names_1(Config) ->
+ {ok,OldCwd} = file:get_cwd(),
+ PrivDir = ?config(priv_dir, Config),
+ Dir = filename:join(PrivDir, "untranslatable_names"),
+ ok = file:make_dir(Dir),
+ Node = start_node(untranslatable_names, "+fnu"),
+ try
+ ok = file:set_cwd(Dir),
+ [ok = file:write_file(F, F) || {_,F} <- untranslatable_names()],
+
+ ExpectedListDir0 = [unicode:characters_to_list(N, utf8) ||
+ {utf8,N} <- untranslatable_names()],
+ ExpectedListDir = lists:sort(ExpectedListDir0),
+ io:format("ExpectedListDir: ~p\n", [ExpectedListDir]),
+ ExpectedListDir = call_and_sort(Node, file, list_dir, [Dir]),
+
+ ExpectedListDirAll0 = [case Enc of
+ utf8 ->
+ unicode:characters_to_list(N, utf8);
+ latin1 ->
+ N
+ end || {Enc,N} <- untranslatable_names()],
+ ExpectedListDirAll = lists:sort(ExpectedListDirAll0),
+ io:format("ExpectedListDirAll: ~p\n", [ExpectedListDirAll]),
+ ExpectedListDirAll = call_and_sort(Node, file, list_dir_all, [Dir])
+ after
+ catch test_server:stop_node(Node),
+ file:set_cwd(OldCwd),
+ [file:delete(F) || {_,F} <- untranslatable_names()],
+ file:del_dir(Dir)
+ end,
+ ok.
+
+untranslatable_names_error(Config) ->
+ case no_untranslatable_names() of
+ true ->
+ {skip,"Not a problem on this OS"};
+ false ->
+ untranslatable_names_error_1(Config)
+ end.
+
+untranslatable_names_error_1(Config) ->
+ {ok,OldCwd} = file:get_cwd(),
+ PrivDir = ?config(priv_dir, Config),
+ Dir = filename:join(PrivDir, "untranslatable_names_error"),
+ ok = file:make_dir(Dir),
+ Node = start_node(untranslatable_names, "+fnue"),
+ try
+ ok = file:set_cwd(Dir),
+ [ok = file:write_file(F, F) || {_,F} <- untranslatable_names()],
+
+ ExpectedListDir0 = [unicode:characters_to_list(N, utf8) ||
+ {utf8,N} <- untranslatable_names()],
+ ExpectedListDir = lists:sort(ExpectedListDir0),
+ io:format("ExpectedListDir: ~p\n", [ExpectedListDir]),
+ {error,{no_translation,BadFile}} =
+ rpc:call(Node, file, list_dir, [Dir]),
+ true = lists:keymember(BadFile, 2, untranslatable_names())
+
+ after
+ catch test_server:stop_node(Node),
+ file:set_cwd(OldCwd),
+ [file:delete(F) || {_,F} <- untranslatable_names()],
+ file:del_dir(Dir)
+ end,
+ ok.
+
+untranslatable_names() ->
+ [{utf8,<<"abc">>},
+ {utf8,<<"def">>},
+ {utf8,<<"Lagerl",195,182,"f">>},
+ {utf8,<<195,150,"stra Emterwik">>},
+ {latin1,<<"M",229,"rbacka">>},
+ {latin1,<<"V",228,"rmland">>}].
+
+call_and_sort(Node, M, F, A) ->
+ {ok,Res} = rpc:call(Node, M, F, A),
+ lists:sort(Res).
+
+no_untranslatable_names() ->
+ case os:type() of
+ {unix,darwin} -> true;
+ {win32,_} -> true;
+ _ -> false
+ end.
+
+start_node(Name, Args) ->
+ [_,Host] = string:tokens(atom_to_list(node()), "@"),
+ ct:log("Trying to start ~w@~s~n", [Name,Host]),
+ case test_server:start_node(Name, peer, [{args,Args}]) of
+ {error,Reason} ->
+ test_server:fail(Reason);
+ {ok,Node} ->
+ ct:log("Node ~p started~n", [Node]),
+ Node
+ end.
+
+
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
@@ -1038,32 +1186,29 @@ file_info_basic_file(Config) when is_list(Config) ->
file_info_basic_directory(suite) -> [];
file_info_basic_directory(doc) -> [];
file_info_basic_directory(Config) when is_list(Config) ->
- ?line Dog = test_server:timetrap(test_server:seconds(5)),
+ Dog = test_server:timetrap(test_server:seconds(5)),
%% Note: filename:join/1 removes any trailing slash,
%% which is essential for ?FILE_MODULE:file_info/1 to work on
%% platforms such as Windows95.
- ?line RootDir = filename:join([?config(priv_dir, Config)]),
+ RootDir = filename:join([?config(priv_dir, Config)]),
%% Test that the RootDir directory has the expected attributes.
- ?line test_directory(RootDir, read_write),
+ test_directory(RootDir, read_write),
%% Note that on Windows file systems,
%% "/" or "c:/" are *NOT* directories.
%% Therefore, test that ?FILE_MODULE:file_info/1 behaves as if they were
%% directories.
- ?line case os:type() of
- {win32, _} ->
- ?line test_directory("/", read_write),
- ?line test_directory("c:/", read_write),
- ?line test_directory("c:\\", read_write);
- {unix, _} ->
- ?line test_directory("/", read);
- vxworks ->
- %% Check is just done for owner
- ?line test_directory("/", read_write)
- end,
- ?line test_server:timetrap_cancel(Dog).
+ case os:type() of
+ {win32, _} ->
+ ?line test_directory("/", read_write),
+ ?line test_directory("c:/", read_write),
+ ?line test_directory("c:\\", read_write);
+ {unix, _} ->
+ ?line test_directory("/", read)
+ end,
+ test_server:timetrap_cancel(Dog).
test_directory(Name, ExpectedAccess) ->
?line {ok,#file_info{size=Size,type=Type,access=Access,
@@ -1622,6 +1767,74 @@ advise(Config) when is_list(Config) ->
?line test_server:timetrap_cancel(Dog),
ok.
+allocate(suite) -> [];
+allocate(doc) -> "Tests that ?FILE_MODULE:allocate/3 at least doesn't crash.";
+allocate(Config) when is_list(Config) ->
+ ?line Dog = test_server:timetrap(test_server:seconds(5)),
+ ?line PrivDir = ?config(priv_dir, Config),
+ ?line Allocate = filename:join(PrivDir,
+ atom_to_list(?MODULE)
+ ++"_allocate.fil"),
+
+ Line1 = "Hello\n",
+ Line2 = "World!\n",
+
+ ?line {ok, Fd} = ?FILE_MODULE:open(Allocate, [write, binary]),
+ allocate_and_assert(Fd, 1, iolist_size([Line1, Line2])),
+ ?line ok = io:format(Fd, "~s", [Line1]),
+ ?line ok = io:format(Fd, "~s", [Line2]),
+ ?line ok = ?FILE_MODULE:close(Fd),
+
+ ?line {ok, Fd2} = ?FILE_MODULE:open(Allocate, [write, binary]),
+ allocate_and_assert(Fd2, 1, iolist_size(Line1)),
+ ?line ok = io:format(Fd2, "~s", [Line1]),
+ ?line ok = io:format(Fd2, "~s", [Line2]),
+ ?line ok = ?FILE_MODULE:close(Fd2),
+
+ ?line {ok, Fd3} = ?FILE_MODULE:open(Allocate, [write, binary]),
+ allocate_and_assert(Fd3, 1, iolist_size(Line1) + 1),
+ ?line ok = io:format(Fd3, "~s", [Line1]),
+ ?line ok = io:format(Fd3, "~s", [Line2]),
+ ?line ok = ?FILE_MODULE:close(Fd3),
+
+ ?line {ok, Fd4} = ?FILE_MODULE:open(Allocate, [write, binary]),
+ allocate_and_assert(Fd4, 1, 4 * iolist_size([Line1, Line2])),
+ ?line ok = io:format(Fd4, "~s", [Line1]),
+ ?line ok = io:format(Fd4, "~s", [Line2]),
+ ?line ok = ?FILE_MODULE:close(Fd4),
+
+ ?line [] = flush(),
+ ?line test_server:timetrap_cancel(Dog),
+ ok.
+
+allocate_and_assert(Fd, Offset, Length) ->
+ % Just verify that calls to ?PRIM_FILE:allocate/3 don't crash or have
+ % any other negative side effect. We can't really asssert against a
+ % specific return value, because support for file space pre-allocation
+ % depends on the OS, OS version and underlying filesystem.
+ %
+ % The Linux kernel added support for fallocate() in version 2.6.23,
+ % which currently works only for the ext4, ocfs2, xfs and btrfs file
+ % systems. posix_fallocate() is available in glibc as of version
+ % 2.1.94, but it was buggy until glibc version 2.7.
+ %
+ % Mac OS X, as of version 10.3, supports the fcntl operation F_PREALLOCATE.
+ %
+ % Solaris supports posix_fallocate() but only for the UFS file system
+ % apparently (not supported for ZFS).
+ %
+ % FreeBSD 9.0 is the first FreeBSD release supporting posix_fallocate().
+ %
+ % For Windows there's apparently no way to pre-allocate file space, at
+ % least with same semantics as posix_fallocate(), fallocate() and
+ % fcntl F_PREALLOCATE.
+ Result = ?FILE_MODULE:allocate(Fd, Offset, Length),
+ case os:type() of
+ {win32, _} ->
+ ?line {error, enotsup} = Result;
+ _ ->
+ ?line _ = Result
+ end.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
@@ -1784,9 +1997,7 @@ e_delete(Config) when is_list(Config) ->
Base, #file_info {mode=8#600});
{win32, _} ->
%% Remove a character device.
- ?line {error, eacces} = ?FILE_MODULE:delete("nul");
- vxworks ->
- ok
+ ?line {error, eacces} = ?FILE_MODULE:delete("nul")
end,
?line [] = flush(),
@@ -1801,148 +2012,133 @@ e_delete(Config) when is_list(Config) ->
e_rename(suite) -> [];
e_rename(doc) -> [];
e_rename(Config) when is_list(Config) ->
- case os:type() of
- vxworks ->
- {comment, "Windriver: dosFs must be fixed first!"};
- _ ->
- ?line Dog = test_server:timetrap(test_server:seconds(10)),
- ?line RootDir = ?config(priv_dir, Config),
- ?line Base = filename:join(RootDir,
- atom_to_list(?MODULE)++"_e_rename"),
- ?line ok = ?FILE_MODULE:make_dir(Base),
-
- %% Create an empty directory.
- ?line EmptyDir = filename:join(Base, "empty_dir"),
- ?line ok = ?FILE_MODULE:make_dir(EmptyDir),
-
- %% Create a non-empty directory.
- ?line NonEmptyDir = filename:join(Base, "non_empty_dir"),
- ?line ok = ?FILE_MODULE:make_dir(NonEmptyDir),
- ?line ok = ?FILE_MODULE:write_file(
- filename:join(NonEmptyDir, "a_file"),
- "hello\n"),
-
- %% Create another non-empty directory.
- ?line ADirectory = filename:join(Base, "a_directory"),
- ?line ok = ?FILE_MODULE:make_dir(ADirectory),
- ?line ok = ?FILE_MODULE:write_file(
- filename:join(ADirectory, "a_file"),
- "howdy\n\n"),
-
- %% Create a data file.
- ?line File = filename:join(Base, "just_a_file"),
- ?line ok = ?FILE_MODULE:write_file(File, "anything goes\n\n"),
-
- %% Move an existing directory to a non-empty directory.
- ?line {error, eexist} =
- ?FILE_MODULE:rename(ADirectory, NonEmptyDir),
-
- %% Move a root directory.
- ?line {error, einval} = ?FILE_MODULE:rename("/", "arne"),
-
- %% Move Base into Base/new_name.
- ?line {error, einval} =
- ?FILE_MODULE:rename(Base, filename:join(Base, "new_name")),
-
- %% Overwrite a directory with a file.
- ?line expect({error, eexist}, %FreeBSD (?)
- {error, eisdir},
- ?FILE_MODULE:rename(File, EmptyDir)),
- ?line expect({error, eexist}, %FreeBSD (?)
- {error, eisdir},
- ?FILE_MODULE:rename(File, NonEmptyDir)),
-
- %% Move a non-existing file.
- ?line NonExistingFile =
- filename:join(Base, "non_existing_file"),
- ?line {error, enoent} =
- ?FILE_MODULE:rename(NonExistingFile, NonEmptyDir),
-
- %% Overwrite a file with a directory.
- ?line expect({error, eexist}, %FreeBSD (?)
- {error, enotdir},
- ?FILE_MODULE:rename(ADirectory, File)),
-
- %% Move a file to another filesystem.
- %% XXX - This test case is bogus. We cannot be guaranteed that
- %% the source and destination are on
- %% different filesystems.
- %%
- %% XXX - Gross hack!
- ?line Comment =
- case os:type() of
- {unix, _} ->
- OtherFs = "/tmp",
- ?line NameOnOtherFs =
- filename:join(OtherFs, filename:basename(File)),
- ?line {ok, Com} =
- case ?FILE_MODULE:rename(File, NameOnOtherFs) of
- {error, exdev} ->
- %% The file could be in
- %% the same filesystem!
- {ok, ok};
- ok ->
- {ok, {comment,
- "Moving between filesystems "
- "suceeded, files are probably "
- "in the same filesystem!"}};
- {error, eperm} ->
- {ok, {comment, "SBS! You don't "
- "have the permission to do "
- "this test!"}};
- Else ->
- Else
- end,
- Com;
- {win32, _} ->
- %% At least Windows NT can
- %% successfully move a file to
- %% another drive.
- ok
- end,
- ?line [] = flush(),
- ?line test_server:timetrap_cancel(Dog),
- Comment
- end.
+ Dog = test_server:timetrap(test_server:seconds(10)),
+ RootDir = ?config(priv_dir, Config),
+ Base = filename:join(RootDir,
+ atom_to_list(?MODULE)++"_e_rename"),
+ ok = ?FILE_MODULE:make_dir(Base),
+
+ %% Create an empty directory.
+ EmptyDir = filename:join(Base, "empty_dir"),
+ ok = ?FILE_MODULE:make_dir(EmptyDir),
+
+ %% Create a non-empty directory.
+ NonEmptyDir = filename:join(Base, "non_empty_dir"),
+ ok = ?FILE_MODULE:make_dir(NonEmptyDir),
+ ok = ?FILE_MODULE:write_file(
+ filename:join(NonEmptyDir, "a_file"),
+ "hello\n"),
+
+ %% Create another non-empty directory.
+ ADirectory = filename:join(Base, "a_directory"),
+ ok = ?FILE_MODULE:make_dir(ADirectory),
+ ok = ?FILE_MODULE:write_file(
+ filename:join(ADirectory, "a_file"),
+ "howdy\n\n"),
+
+ %% Create a data file.
+ File = filename:join(Base, "just_a_file"),
+ ok = ?FILE_MODULE:write_file(File, "anything goes\n\n"),
+
+ %% Move an existing directory to a non-empty directory.
+ {error, eexist} = ?FILE_MODULE:rename(ADirectory, NonEmptyDir),
+
+ %% Move a root directory.
+ {error, einval} = ?FILE_MODULE:rename("/", "arne"),
+
+ %% Move Base into Base/new_name.
+ {error, einval} =
+ ?FILE_MODULE:rename(Base, filename:join(Base, "new_name")),
+
+ %% Overwrite a directory with a file.
+ expect({error, eexist}, %FreeBSD (?)
+ {error, eisdir},
+ ?FILE_MODULE:rename(File, EmptyDir)),
+ expect({error, eexist}, %FreeBSD (?)
+ {error, eisdir},
+ ?FILE_MODULE:rename(File, NonEmptyDir)),
+
+ %% Move a non-existing file.
+ NonExistingFile = filename:join(Base, "non_existing_file"),
+ {error, enoent} = ?FILE_MODULE:rename(NonExistingFile, NonEmptyDir),
+
+ %% Overwrite a file with a directory.
+ expect({error, eexist}, %FreeBSD (?)
+ {error, enotdir},
+ ?FILE_MODULE:rename(ADirectory, File)),
+
+ %% Move a file to another filesystem.
+ %% XXX - This test case is bogus. We cannot be guaranteed that
+ %% the source and destination are on
+ %% different filesystems.
+ %%
+ %% XXX - Gross hack!
+ Comment = case os:type() of
+ {unix, _} ->
+ OtherFs = "/tmp",
+ NameOnOtherFs = filename:join(OtherFs, filename:basename(File)),
+ {ok, Com} = case ?FILE_MODULE:rename(File, NameOnOtherFs) of
+ {error, exdev} ->
+ %% The file could be in
+ %% the same filesystem!
+ {ok, ok};
+ ok ->
+ {ok, {comment,
+ "Moving between filesystems "
+ "suceeded, files are probably "
+ "in the same filesystem!"}};
+ {error, eperm} ->
+ {ok, {comment, "SBS! You don't "
+ "have the permission to do "
+ "this test!"}};
+ Else ->
+ Else
+ end,
+ Com;
+ {win32, _} ->
+ %% At least Windows NT can
+ %% successfully move a file to
+ %% another drive.
+ ok
+ end,
+ [] = flush(),
+ test_server:timetrap_cancel(Dog),
+ Comment.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
e_make_dir(suite) -> [];
e_make_dir(doc) -> [];
e_make_dir(Config) when is_list(Config) ->
- ?line Dog = test_server:timetrap(test_server:seconds(10)),
- ?line RootDir = ?config(priv_dir, Config),
- ?line Base = filename:join(RootDir,
- atom_to_list(?MODULE)++"_e_make_dir"),
- ?line ok = ?FILE_MODULE:make_dir(Base),
+ Dog = test_server:timetrap(test_server:seconds(10)),
+ RootDir = ?config(priv_dir, Config),
+ Base = filename:join(RootDir,
+ atom_to_list(?MODULE)++"_e_make_dir"),
+ ok = ?FILE_MODULE:make_dir(Base),
%% A component of the path does not exist.
- ?line {error, enoent} =
- ?FILE_MODULE:make_dir(filename:join([Base, "a", "b"])),
+ {error, enoent} = ?FILE_MODULE:make_dir(filename:join([Base, "a", "b"])),
%% Use a path-name with a non-directory component.
- ?line Afile = filename:join(Base, "a_directory"),
- ?line ok = ?FILE_MODULE:write_file(Afile, "hello\n"),
- ?line case ?FILE_MODULE:make_dir(
- filename:join(Afile, "another_directory")) of
- {error, enotdir} -> io:format("Result: enotdir");
- {error, enoent} -> io:format("Result: enoent")
- end,
+ Afile = filename:join(Base, "a_directory"),
+ ok = ?FILE_MODULE:write_file(Afile, "hello\n"),
+ case ?FILE_MODULE:make_dir(
+ filename:join(Afile, "another_directory")) of
+ {error, enotdir} -> io:format("Result: enotdir");
+ {error, enoent} -> io:format("Result: enoent")
+ end,
%% No permission (on Unix only).
case os:type() of
{unix, _} ->
- ?line ?FILE_MODULE:write_file_info(Base, #file_info {mode=0}),
- ?line {error, eacces} =
- ?FILE_MODULE:make_dir(filename:join(Base, "xxxx")),
- ?line ?FILE_MODULE:write_file_info(
+ ?FILE_MODULE:write_file_info(Base, #file_info {mode=0}),
+ {error, eacces} = ?FILE_MODULE:make_dir(filename:join(Base, "xxxx")),
+ ?FILE_MODULE:write_file_info(
Base, #file_info {mode=8#600});
{win32, _} ->
- ok;
- vxworks ->
ok
end,
- ?line test_server:timetrap_cancel(Dog),
+ test_server:timetrap_cancel(Dog),
ok.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
@@ -1950,57 +2146,50 @@ e_make_dir(Config) when is_list(Config) ->
e_del_dir(suite) -> [];
e_del_dir(doc) -> [];
e_del_dir(Config) when is_list(Config) ->
- ?line Dog = test_server:timetrap(test_server:seconds(10)),
- ?line RootDir = ?config(priv_dir, Config),
- ?line Base = test_server:temp_name(filename:join(RootDir, "e_del_dir")),
- ?line io:format("Base: ~p", [Base]),
- ?line ok = ?FILE_MODULE:make_dir(Base),
+ Dog = test_server:timetrap(test_server:seconds(10)),
+ RootDir = ?config(priv_dir, Config),
+ Base = test_server:temp_name(filename:join(RootDir, "e_del_dir")),
+ io:format("Base: ~p", [Base]),
+ ok = ?FILE_MODULE:make_dir(Base),
%% Delete a non-existent directory.
- ?line {error, enoent} =
+ {error, enoent} =
?FILE_MODULE:del_dir(filename:join(Base, "non_existing")),
%% Use a path-name with a non-directory component.
- ?line Afile = filename:join(Base, "a_directory"),
- ?line ok = ?FILE_MODULE:write_file(Afile, "hello\n"),
- ?line {error, E1} =
- expect({error, enotdir}, {error, enoent},
- ?FILE_MODULE:del_dir(
- filename:join(Afile, "another_directory"))),
- ?line io:format("Result: ~p", [E1]),
+ Afile = filename:join(Base, "a_directory"),
+ ok = ?FILE_MODULE:write_file(Afile, "hello\n"),
+ {error, E1} = expect({error, enotdir}, {error, enoent},
+ ?FILE_MODULE:del_dir(
+ filename:join(Afile, "another_directory"))),
+ io:format("Result: ~p", [E1]),
%% Delete a non-empty directory.
- ?line {error, E2} =
- expect({error, enotempty}, {error, eexist}, {error, eacces},
+ {error, E2} = expect({error, enotempty}, {error, eexist}, {error, eacces},
?FILE_MODULE:del_dir(Base)),
- ?line io:format("Result: ~p", [E2]),
+ io:format("Result: ~p", [E2]),
%% Remove the current directory.
- ?line {error, E3} =
- expect({error, einval},
+ {error, E3} = expect({error, einval},
{error, eperm}, % Linux and DUX
{error, eacces},
{error, ebusy},
?FILE_MODULE:del_dir(".")),
- ?line io:format("Result: ~p", [E3]),
+ io:format("Result: ~p", [E3]),
%% No permission.
case os:type() of
{unix, _} ->
- ?line ADirectory = filename:join(Base, "no_perm"),
- ?line ok = ?FILE_MODULE:make_dir(ADirectory),
- ?line ?FILE_MODULE:write_file_info(
- Base, #file_info {mode=0}),
- ?line {error, eacces} = ?FILE_MODULE:del_dir(ADirectory),
- ?line ?FILE_MODULE:write_file_info(
- Base, #file_info {mode=8#600});
+ ADirectory = filename:join(Base, "no_perm"),
+ ok = ?FILE_MODULE:make_dir(ADirectory),
+ ?FILE_MODULE:write_file_info( Base, #file_info {mode=0}),
+ {error, eacces} = ?FILE_MODULE:del_dir(ADirectory),
+ ?FILE_MODULE:write_file_info( Base, #file_info {mode=8#600});
{win32, _} ->
- ok;
- vxworks ->
ok
end,
- ?line [] = flush(),
- ?line test_server:timetrap_cancel(Dog),
+ [] = flush(),
+ test_server:timetrap_cancel(Dog),
ok.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
@@ -2271,6 +2460,57 @@ compress_errors(Config) when is_list(Config) ->
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+compress_async_crash(suite) -> [];
+compress_async_crash(doc) -> [];
+compress_async_crash(Config) when is_list(Config) ->
+ ?line DataDir = ?config(data_dir, Config),
+ ?line Path = filename:join(DataDir, "test.gz"),
+ ExpectedData = <<"qwerty">>,
+
+ ?line _ = ?FILE_MODULE:delete(Path),
+ ?line {ok, Fd} = ?FILE_MODULE:open(Path, [write, binary, compressed]),
+ ?line ok = ?FILE_MODULE:write(Fd, ExpectedData),
+ ?line ok = ?FILE_MODULE:close(Fd),
+
+ % Test that when using async thread pool, the emulator doesn't crash
+ % when the efile port driver is stopped while a compressed file operation
+ % is in progress (being carried by an async thread).
+ ?line ok = compress_async_crash_loop(10000, Path, ExpectedData),
+ ?line ok = ?FILE_MODULE:delete(Path),
+ ok.
+
+compress_async_crash_loop(0, _Path, _ExpectedData) ->
+ ok;
+compress_async_crash_loop(N, Path, ExpectedData) ->
+ Parent = self(),
+ {Pid, Ref} = spawn_monitor(
+ fun() ->
+ ?line {ok, Fd} = ?FILE_MODULE:open(
+ Path, [read, compressed, raw, binary]),
+ Len = byte_size(ExpectedData),
+ Parent ! {self(), continue},
+ ?line {ok, ExpectedData} = ?FILE_MODULE:read(Fd, Len),
+ ?line ok = ?FILE_MODULE:close(Fd),
+ receive foobar -> ok end
+ end),
+ receive
+ {Pid, continue} ->
+ exit(Pid, shutdown),
+ receive
+ {'DOWN', Ref, _, _, Reason} ->
+ ?line shutdown = Reason
+ end;
+ {'DOWN', Ref, _, _, Reason2} ->
+ test_server:fail({worker_exited, Reason2})
+ after 60000 ->
+ exit(Pid, shutdown),
+ erlang:demonitor(Ref, [flush]),
+ test_server:fail(worker_timeout)
+ end,
+ compress_async_crash_loop(N - 1, Path, ExpectedData).
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
altname(doc) ->
"Test the file:altname/1 function";
altname(suite) ->
@@ -2359,6 +2599,7 @@ symlinks(suite) -> [];
symlinks(Config) when is_list(Config) ->
?line Dog = test_server:timetrap(test_server:seconds(10)),
?line {error, _} = ?FILE_MODULE:read_link(lists:duplicate(10000,$a)),
+ {error, _} = ?FILE_MODULE:read_link_all(lists:duplicate(10000,$a)),
?line RootDir = ?config(priv_dir, Config),
?line NewDir = filename:join(RootDir,
atom_to_list(?MODULE)
@@ -2382,6 +2623,7 @@ symlinks(Config) when is_list(Config) ->
?line {ok, Info2} = ?FILE_MODULE:read_link_info(Alias),
?line #file_info{links=1, type=symlink} = Info2,
?line {ok, Name} = ?FILE_MODULE:read_link(Alias),
+ {ok, Name} = ?FILE_MODULE:read_link_all(Alias),
ok
end,
@@ -2564,147 +2806,123 @@ delayed_write(doc) ->
["Tests the file open option {delayed_write, Size, Delay}"];
delayed_write(Config) when is_list(Config) ->
- ?line Dog = ?t:timetrap(?t:seconds(20)),
- %%
- ?line RootDir = ?config(priv_dir, Config),
- ?line File = filename:join(RootDir,
- atom_to_list(?MODULE)++"_delayed_write.txt"),
- ?line Data1 = "asdfghjkl",
- ?line Data2 = "qwertyuio",
- ?line Data3 = "zxcvbnm,.",
- ?line Size = length(Data1),
- ?line Size = length(Data2),
- ?line Size = length(Data3),
- ?line Data1Data1 = Data1++Data1,
- ?line Data1Data1Data1 = Data1Data1++Data1,
- ?line Data1Data1Data1Data1 = Data1Data1++Data1Data1,
+ Dog = ?t:timetrap(?t:seconds(20)),
+
+ RootDir = ?config(priv_dir, Config),
+ File = filename:join(RootDir,
+ atom_to_list(?MODULE)++"_delayed_write.txt"),
+ Data1 = "asdfghjkl",
+ Data2 = "qwertyuio",
+ Data3 = "zxcvbnm,.",
+ Size = length(Data1),
+ Size = length(Data2),
+ Size = length(Data3),
+ Data1Data1 = Data1++Data1,
+ Data1Data1Data1 = Data1Data1++Data1,
+ Data1Data1Data1Data1 = Data1Data1++Data1Data1,
%%
%% Test caching and normal close of non-raw file
- ?line {ok, Fd1} =
+ {ok, Fd1} =
?FILE_MODULE:open(File, [write, {delayed_write, Size+1, 2000}]),
- ?line ok = ?FILE_MODULE:write(Fd1, Data1),
- ?line ?t:sleep(1000), % Just in case the file system is slow
- ?line {ok, Fd2} = ?FILE_MODULE:open(File, [read]),
- ?line case os:type() of
- vxworks ->
- io:format("Line ~p skipped on vxworks", [?LINE]);
- _ ->
- ?line eof = ?FILE_MODULE:read(Fd2, 1)
- end,
- ?line ok = ?FILE_MODULE:write(Fd1, Data1), % Data flush on size
- ?line ?t:sleep(1000), % Just in case the file system is slow
- ?line {ok, Data1Data1} = ?FILE_MODULE:pread(Fd2, bof, 2*Size+1),
- ?line ok = ?FILE_MODULE:write(Fd1, Data1),
- ?line ?t:sleep(3000), % Wait until data flush on timeout
- ?line {ok, Data1Data1Data1} = ?FILE_MODULE:pread(Fd2, bof, 3*Size+1),
- ?line ok = ?FILE_MODULE:write(Fd1, Data1),
- ?line ok = ?FILE_MODULE:close(Fd1), % Data flush on close
- ?line ?t:sleep(1000), % Just in case the file system is slow
- ?line {ok, Data1Data1Data1Data1} = ?FILE_MODULE:pread(Fd2, bof, 4*Size+1),
- ?line ok = ?FILE_MODULE:close(Fd2),
+ ok = ?FILE_MODULE:write(Fd1, Data1),
+ ?t:sleep(1000), % Just in case the file system is slow
+ {ok, Fd2} = ?FILE_MODULE:open(File, [read]),
+ eof = ?FILE_MODULE:read(Fd2, 1),
+ ok = ?FILE_MODULE:write(Fd1, Data1), % Data flush on size
+ ?t:sleep(1000), % Just in case the file system is slow
+ {ok, Data1Data1} = ?FILE_MODULE:pread(Fd2, bof, 2*Size+1),
+ ok = ?FILE_MODULE:write(Fd1, Data1),
+ ?t:sleep(3000), % Wait until data flush on timeout
+ {ok, Data1Data1Data1} = ?FILE_MODULE:pread(Fd2, bof, 3*Size+1),
+ ok = ?FILE_MODULE:write(Fd1, Data1),
+ ok = ?FILE_MODULE:close(Fd1), % Data flush on close
+ ?t:sleep(1000), % Just in case the file system is slow
+ {ok, Data1Data1Data1Data1} = ?FILE_MODULE:pread(Fd2, bof, 4*Size+1),
+ ok = ?FILE_MODULE:close(Fd2),
%%
%% Test implicit close through exit by file owning process,
%% raw file, default parameters.
- ?line Parent = self(),
- ?line Fun =
- fun () ->
- Child = self(),
- Test =
- fun () ->
- ?line {ok, Fd} =
- ?FILE_MODULE:open(File,
- [raw, write,
- delayed_write]),
- ?line ok = ?FILE_MODULE:write(Fd, Data1),
- ?line Parent ! {Child, wrote},
- ?line receive
- {Parent, continue, Reason} ->
- {ok, Reason}
- end
- end,
- case (catch Test()) of
- {ok, Reason} ->
- exit(Reason);
- Unknown ->
- exit({Unknown, get(test_server_loc)})
- end
- end,
- ?line Child1 = spawn(Fun),
- ?line Mref1 = erlang:monitor(process, Child1),
- ?line receive
- {Child1, wrote} ->
- ok;
- {'DOWN', Mref1, _, _, _} = Down1a ->
- ?t:fail(Down1a)
- end,
- ?line ?t:sleep(1000), % Just in case the file system is slow
- ?line {ok, Fd3} = ?FILE_MODULE:open(File, [read]),
- ?line case os:type() of
- vxworks ->
- io:format("Line ~p skipped on vxworks", [?LINE]);
- _ ->
- ?line eof = ?FILE_MODULE:read(Fd3, 1)
- end,
- ?line Child1 ! {Parent, continue, normal},
- ?line receive
- {'DOWN', Mref1, process, Child1, normal} ->
- ok;
- {'DOWN', Mref1, _, _, _} = Down1b ->
- ?t:fail(Down1b)
- end,
- ?line ?t:sleep(1000), % Just in case the file system is slow
- ?line {ok, Data1} = ?FILE_MODULE:pread(Fd3, bof, Size+1),
- ?line ok = ?FILE_MODULE:close(Fd3),
+ Parent = self(),
+ Fun = fun() ->
+ Child = self(),
+ Test =
+ fun () ->
+ {ok, Fd} = ?FILE_MODULE:open(File,
+ [raw, write, delayed_write]),
+ ok = ?FILE_MODULE:write(Fd, Data1),
+ Parent ! {Child, wrote},
+ receive
+ {Parent, continue, Reason} ->
+ {ok, Reason}
+ end
+ end,
+ case (catch Test()) of
+ {ok, Reason} -> exit(Reason);
+ Unknown ->
+ exit({Unknown, get(test_server_loc)})
+ end
+ end,
+ Child1 = spawn(Fun),
+ Mref1 = erlang:monitor(process, Child1),
+ receive
+ {Child1, wrote} ->
+ ok;
+ {'DOWN', Mref1, _, _, _} = Down1a ->
+ ?t:fail(Down1a)
+ end,
+ ?t:sleep(1000), % Just in case the file system is slow
+ {ok, Fd3} = ?FILE_MODULE:open(File, [read]),
+ eof = ?FILE_MODULE:read(Fd3, 1),
+ Child1 ! {Parent, continue, normal},
+ receive
+ {'DOWN', Mref1, process, Child1, normal} ->
+ ok;
+ {'DOWN', Mref1, _, _, _} = Down1b ->
+ ?t:fail(Down1b)
+ end,
+ ?t:sleep(1000), % Just in case the file system is slow
+ {ok, Data1} = ?FILE_MODULE:pread(Fd3, bof, Size+1),
+ ok = ?FILE_MODULE:close(Fd3),
%%
%% The same again, but this time with reason 'kill'.
- ?line Child2 = spawn(Fun),
- ?line Mref2 = erlang:monitor(process, Child2),
- ?line receive
- {Child2, wrote} ->
- ok;
- {'DOWN', Mref2, _, _, _} = Down2a ->
- ?t:fail(Down2a)
- end,
- ?line ?t:sleep(1000), % Just in case the file system is slow
- ?line {ok, Fd4} = ?FILE_MODULE:open(File, [read]),
- ?line case os:type() of
- vxworks ->
- io:format("Line ~p skipped on vxworks", [?LINE]);
- _ ->
- ?line eof = ?FILE_MODULE:read(Fd4, 1)
- end,
- ?line Child2 ! {Parent, continue, kill},
- ?line receive
- {'DOWN', Mref2, process, Child2, kill} ->
- ok;
- {'DOWN', Mref2, _, _, _} = Down2b ->
- ?t:fail(Down2b)
- end,
- ?line ?t:sleep(1000), % Just in case the file system is slow
- ?line eof = ?FILE_MODULE:pread(Fd4, bof, 1),
- ?line ok = ?FILE_MODULE:close(Fd4),
+ Child2 = spawn(Fun),
+ Mref2 = erlang:monitor(process, Child2),
+ receive
+ {Child2, wrote} ->
+ ok;
+ {'DOWN', Mref2, _, _, _} = Down2a ->
+ ?t:fail(Down2a)
+ end,
+ ?t:sleep(1000), % Just in case the file system is slow
+ {ok, Fd4} = ?FILE_MODULE:open(File, [read]),
+ eof = ?FILE_MODULE:read(Fd4, 1),
+ Child2 ! {Parent, continue, kill},
+ receive
+ {'DOWN', Mref2, process, Child2, kill} ->
+ ok;
+ {'DOWN', Mref2, _, _, _} = Down2b ->
+ ?t:fail(Down2b)
+ end,
+ ?t:sleep(1000), % Just in case the file system is slow
+ eof = ?FILE_MODULE:pread(Fd4, bof, 1),
+ ok = ?FILE_MODULE:close(Fd4),
%%
%% Test if file position works with delayed_write
- ?line {ok, Fd5} = ?FILE_MODULE:open(File, [raw, read, write,
- delayed_write]),
- ?line ok = ?FILE_MODULE:truncate(Fd5),
- ?line ok = ?FILE_MODULE:write(Fd5, [Data1|Data2]),
- ?line {ok, 0} = ?FILE_MODULE:position(Fd5, bof),
- ?line ok = ?FILE_MODULE:write(Fd5, [Data3]),
- ?line {ok, Data2} = ?FILE_MODULE:read(Fd5, Size+1),
- ?line {ok, 0} = ?FILE_MODULE:position(Fd5, bof),
- ?line Data3Data2 = Data3++Data2,
- ?line {ok, Data3Data2} = ?FILE_MODULE:read(Fd5, 2*Size+1),
- ?line ok = ?FILE_MODULE:close(Fd5),
+ {ok, Fd5} = ?FILE_MODULE:open(File, [raw, read, write,
+ delayed_write]),
+ ok = ?FILE_MODULE:truncate(Fd5),
+ ok = ?FILE_MODULE:write(Fd5, [Data1|Data2]),
+ {ok, 0} = ?FILE_MODULE:position(Fd5, bof),
+ ok = ?FILE_MODULE:write(Fd5, [Data3]),
+ {ok, Data2} = ?FILE_MODULE:read(Fd5, Size+1),
+ {ok, 0} = ?FILE_MODULE:position(Fd5, bof),
+ Data3Data2 = Data3++Data2,
+ {ok, Data3Data2} = ?FILE_MODULE:read(Fd5, 2*Size+1),
+ ok = ?FILE_MODULE:close(Fd5),
%%
- ?line [] = flush(),
- ?line ?t:timetrap_cancel(Dog),
- ?line case os:type() of
- vxworks ->
- {comment, "Some lines skipped on vxworks"};
- _ ->
- ok
- end.
+ [] = flush(),
+ ?t:timetrap_cancel(Dog),
+ ok.
pid2name(doc) -> "Tests file:pid2name/1.";