aboutsummaryrefslogtreecommitdiffstats
path: root/lib/kernel/test
diff options
context:
space:
mode:
Diffstat (limited to 'lib/kernel/test')
-rw-r--r--lib/kernel/test/Makefile1
-rw-r--r--lib/kernel/test/code_SUITE.erl198
-rw-r--r--lib/kernel/test/code_SUITE_data/on_load_app-1.0/src/on_load_embedded.erl9
-rw-r--r--lib/kernel/test/disk_log_SUITE.erl23
-rw-r--r--lib/kernel/test/file_SUITE.erl229
-rw-r--r--lib/kernel/test/file_name_SUITE.erl1729
-rw-r--r--lib/kernel/test/gen_sctp_SUITE.erl244
-rw-r--r--lib/kernel/test/gen_tcp_api_SUITE.erl57
-rw-r--r--lib/kernel/test/gen_tcp_misc_SUITE.erl17
-rw-r--r--lib/kernel/test/gen_udp_SUITE.erl81
-rw-r--r--lib/kernel/test/global_SUITE.erl41
-rw-r--r--lib/kernel/test/inet_SUITE.erl153
-rw-r--r--lib/kernel/test/inet_sockopt_SUITE_data/sockopt_helper.c2
-rw-r--r--lib/kernel/test/os_SUITE.erl10
-rw-r--r--lib/kernel/test/pg2_SUITE.erl135
-rw-r--r--lib/kernel/test/prim_file_SUITE.erl130
16 files changed, 2910 insertions, 149 deletions
diff --git a/lib/kernel/test/Makefile b/lib/kernel/test/Makefile
index 293c368e2a..f84b343de8 100644
--- a/lib/kernel/test/Makefile
+++ b/lib/kernel/test/Makefile
@@ -51,6 +51,7 @@ MODULES= \
error_logger_SUITE \
error_logger_warn_SUITE \
file_SUITE \
+ file_name_SUITE \
prim_file_SUITE \
ram_file_SUITE \
gen_tcp_api_SUITE \
diff --git a/lib/kernel/test/code_SUITE.erl b/lib/kernel/test/code_SUITE.erl
index 37b9200942..e52f8a0e37 100644
--- a/lib/kernel/test/code_SUITE.erl
+++ b/lib/kernel/test/code_SUITE.erl
@@ -19,7 +19,7 @@
-module(code_SUITE).
-include("test_server.hrl").
-
+%-compile(export_all).
-export([all/1]).
-export([set_path/1, get_path/1, add_path/1, add_paths/1, del_path/1,
replace_path/1, load_file/1, load_abs/1, ensure_loaded/1,
@@ -31,7 +31,8 @@
where_is_file_cached/1, where_is_file_no_cache/1,
purge_stacktrace/1, mult_lib_roots/1, bad_erl_libs/1,
code_archive/1, code_archive2/1, on_load/1,
- on_load_embedded/1, on_load_errors/1]).
+ big_boot_embedded/1,
+ on_load_embedded/1, on_load_errors/1, native_early_modules/1]).
-export([init_per_testcase/2, fin_per_testcase/2,
init_per_suite/1, end_per_suite/1,
@@ -53,7 +54,8 @@ all(suite) ->
where_is_file_no_cache, where_is_file_cached,
purge_stacktrace, mult_lib_roots, bad_erl_libs,
code_archive, code_archive2, on_load, on_load_embedded,
- on_load_errors].
+ big_boot_embedded,
+ on_load_errors, native_early_modules].
init_per_suite(Config) ->
%% The compiler will no longer create a Beam file if
@@ -543,8 +545,8 @@ add_del_path(Config) when is_list(Config) ->
?line code:del_path(Dir2),
?line PrivDir1 = code:priv_dir(dummy_app),
ok.
-
-
+
+
clash(Config) when is_list(Config) ->
DDir = ?config(data_dir,Config)++"clash/",
P = code:get_path(),
@@ -555,11 +557,11 @@ clash(Config) when is_list(Config) ->
?line true = code:del_path("."),
?line true = code:add_path(DDir++"foobar-0.1/ebin"),
?line true = code:add_path(DDir++"zork-0.8/ebin"),
- ?line test_server:capture_start(),
- ?line code:clash(),
- ?line test_server:capture_stop(),
- ?line OKMsg = test_server:capture_get(),
- ?line lists:prefix("** Found 0 name clashes in code paths", OKMsg),
+ test_server:capture_start(),
+ ?line ok = code:clash(),
+ test_server:capture_stop(),
+ ?line [OKMsg|_] = test_server:capture_get(),
+ ?line true = lists:prefix("** Found 0 name clashes", OKMsg),
?line true = code:set_path(P),
%% test clashing entries
@@ -568,13 +570,37 @@ clash(Config) when is_list(Config) ->
?line true = code:del_path("."),
?line true = code:add_path(DDir++"foobar-0.1/ebin"),
?line true = code:add_path(DDir++"foobar-0.1.ez/foobar-0.1/ebin"),
- ?line test_server:capture_start(),
- ?line code:clash(),
- ?line test_server:capture_stop(),
- ?line [ErrMsg1|_] = test_server:capture_get(),
- ?line {match, [" hides "]} = re:run(ErrMsg1, "\\*\\* .*( hides ).*",
+ test_server:capture_start(),
+ ?line ok = code:clash(),
+ test_server:capture_stop(),
+ ?line [ClashMsg|_] = test_server:capture_get(),
+ ?line {match, [" hides "]} = re:run(ClashMsg, "\\*\\* .*( hides ).*",
[{capture,all_but_first,list}]),
?line true = code:set_path(P),
+
+ %% test "Bad path can't read"
+
+ %% remove "." to prevent clash with test-server path
+ Priv = ?config(priv_dir, Config),
+ ?line true = code:del_path("."),
+ TmpEzFile = Priv++"foobar-0.tmp.ez",
+ ?line {ok, _} = file:copy(DDir++"foobar-0.1.ez", TmpEzFile),
+ ?line true = code:add_path(TmpEzFile++"/foobar-0.1/ebin"),
+ case os:type() of
+ {win32,_} ->
+ %% The file wont be deleted on windows until it's closed, why we
+ %% need to rename instead.
+ ?line ok = file:rename(TmpEzFile,TmpEzFile++".moved");
+ _ ->
+ ?line ok = file:delete(TmpEzFile)
+ end,
+ test_server:capture_start(),
+ ?line ok = code:clash(),
+ test_server:capture_stop(),
+ ?line [BadPathMsg|_] = test_server:capture_get(),
+ ?line true = lists:prefix("** Bad path can't read", BadPathMsg),
+ ?line true = code:set_path(P),
+ file:delete(TmpEzFile++".moved"), %% Only effect on windows
ok.
ext_mod_dep(suite) ->
@@ -619,7 +645,7 @@ analyse([], [This={M,F,A}|Path], Visited, ErrCnt0) ->
%% These modules should be loaded by code.erl before
%% the code_server is started.
OK = [erlang, os, prim_file, erl_prim_loader, init, ets,
- code_server, lists, lists_sort, filename, packages,
+ code_server, lists, lists_sort, unicode, binary, filename, packages,
gb_sets, gb_trees, hipe_unified_loader, hipe_bifs,
prim_zip, zlib],
ErrCnt1 =
@@ -648,6 +674,22 @@ analyse2(MFA={_,_,_}, Path, Visited0) ->
%%%% We need to check these manually...
% fun's are ok as long as they are defined locally.
check_funs({'$M_EXPR','$F_EXPR',_},
+ [{unicode,characters_to_binary_int,3},
+ {unicode,characters_to_binary,3},
+ {filename,filename_string_to_binary,1}|_]) -> 0;
+check_funs({'$M_EXPR','$F_EXPR',_},
+ [{unicode,ml_map,3},
+ {unicode,characters_to_binary_int,3},
+ {unicode,characters_to_binary,3},
+ {filename,filename_string_to_binary,1}|_]) -> 0;
+check_funs({'$M_EXPR','$F_EXPR',_},
+ [{unicode,do_o_binary2,2},
+ {unicode,do_o_binary,2},
+ {unicode,o_trans,1},
+ {unicode,characters_to_binary_int,3},
+ {unicode,characters_to_binary,3},
+ {filename,filename_string_to_binary,1}|_]) -> 0;
+check_funs({'$M_EXPR','$F_EXPR',_},
[{code_server,load_native_code,4},
{code_server,load_native_code_1,2},
{code_server,load_native_code,2},
@@ -1129,6 +1171,22 @@ compile_files([File | Files], SrcDir, OutDir) ->
compile_files([], _, _) ->
ok.
+big_boot_embedded(suite) ->
+ [];
+big_boot_embedded(doc) ->
+ ["Test that a boot file with (almost) all of OTP can be used to start an"
+ " embeddedd system."];
+big_boot_embedded(Config) when is_list(Config) ->
+ ?line {BootArg,AppsInBoot} = create_big_boot(Config),
+ ?line {ok, Node} =
+ ?t:start_node(big_boot_embedded, slave,
+ [{args,"-boot "++BootArg++" -mode embedded"}]),
+ ?line RemoteNodeApps =
+ [ {X,Y} || {X,_,Y} <-
+ rpc:call(Node,application,loaded_applications,[]) ],
+ ?line true = lists:sort(AppsInBoot) =:= lists:sort(RemoteNodeApps),
+ ok.
+
on_load(Config) when is_list(Config) ->
Master = on_load_test_case_process,
@@ -1210,7 +1268,8 @@ on_load_embedded_1(Config) ->
?line LibRoot = code:lib_dir(),
?line LinkName = filename:join(LibRoot, "on_load_app-1.0"),
?line OnLoadApp = filename:join(DataDir, "on_load_app-1.0"),
- ?line file:delete(LinkName),
+ ?line del_link(LinkName),
+ io:format("LinkName :~p, OnLoadApp: ~p~n",[LinkName,OnLoadApp]),
case file:make_symlink(OnLoadApp, LinkName) of
{error,enotsup} ->
throw({skip,"Support for symlinks required"});
@@ -1239,7 +1298,15 @@ on_load_embedded_1(Config) ->
%% Clean up.
?line stop_node(Node),
- ?line ok = file:delete(LinkName).
+ ?line ok = del_link(LinkName).
+
+del_link(LinkName) ->
+ case file:delete(LinkName) of
+ {error,eperm} ->
+ file:del_dir(LinkName);
+ Other ->
+ Other
+ end.
create_boot(Config, Options) ->
?line {ok, OldDir} = file:get_cwd(),
@@ -1265,6 +1332,73 @@ create_script(Config) ->
?line file:close(Fd),
{filename:dirname(Name),filename:basename(Name)}.
+create_big_boot(Config) ->
+ ?line {ok, OldDir} = file:get_cwd(),
+ ?line {Options,Local} = case is_source_dir() of
+ true -> {[no_module_tests,local],true};
+ _ -> {[no_module_tests],false}
+ end,
+ ?line {LatestDir,LatestName,Apps} = create_big_script(Config,Local),
+ ?line ok = file:set_cwd(LatestDir),
+ ?line ok = systools:make_script(LatestName, Options),
+ ?line ok = file:set_cwd(OldDir),
+ {filename:join(LatestDir, LatestName),Apps}.
+
+% The following apps cannot be loaded
+% hipe .app references (or can reference) files that have no
+% corresponding beam file (if hipe is not enabled)
+filter_app("hipe",_) ->
+ false;
+% Dialyzer and typer depends on hipe
+filter_app("dialyzer",_) ->
+ false;
+filter_app("typer",_) ->
+ false;
+% Orber requires explicit configuration
+filter_app("orber",_) ->
+ false;
+% cos* depends on orber
+filter_app("cos"++_,_) ->
+ false;
+% ic has a mod instruction in the app file but no corresponding start function
+filter_app("ic",_) ->
+ false;
+% Netconf has some dependency that I really do not understand (maybe like orber)
+filter_app("netconf",_) ->
+ false;
+% Safe has the same kind of error in the .app file as ic
+filter_app("safe",_) ->
+ false;
+% OS_mon does not find it's port program when running cerl
+filter_app("os_mon",true) ->
+ false;
+% Other apps should be OK.
+filter_app(_,_) ->
+ true.
+create_big_script(Config,Local) ->
+ ?line PrivDir = ?config(priv_dir, Config),
+ ?line Name = filename:join(PrivDir,"full_script_test"),
+ ?line InitialApplications=application:loaded_applications(),
+ %% Applications left loaded by the application suite, unload them!
+ ?line UnloadFix=[app0,app1,app2,group_leader,app_start_error],
+ ?line [application:unload(Leftover) ||
+ Leftover <- UnloadFix,
+ lists:keymember(Leftover,1,InitialApplications) ],
+ %% Now we should have only "real" applications...
+ ?line [application:load(list_to_atom(Y)) || {match,[Y]} <- [ re:run(X,code:lib_dir()++"/"++"([^/-]*).*/ebin",[{capture,[1],list}]) || X <- code:get_path()],filter_app(Y,Local)],
+ ?line Apps = [ {N,V} || {N,_,V} <- application:loaded_applications()],
+ ?line {ok,Fd} = file:open(Name ++ ".rel", write),
+ ?line io:format(Fd,
+ "{release, {\"Test release 3\", \"P2A\"}, \n"
+ " {erts, \"9.42\"}, \n"
+ " ~p}.\n",
+ [Apps]),
+ ?line file:close(Fd),
+ ?line NewlyLoaded =
+ application:loaded_applications() -- InitialApplications,
+ ?line [ application:unload(N) || {N,_,_} <- NewlyLoaded],
+ {filename:dirname(Name),filename:basename(Name),Apps}.
+
is_source_dir() ->
filename:basename(code:lib_dir(kernel)) =:= "kernel" andalso
filename:basename(code:lib_dir(stdlib)) =:= "stdlib".
@@ -1317,6 +1451,34 @@ do_on_load_error(ReturnValue) ->
?line {undef,[{on_load_error,main,[]}|_]} = Exit
end.
+native_early_modules(suite) -> [];
+native_early_modules(doc) -> ["Test that the native code of early loaded modules is loaded"];
+native_early_modules(Config) when is_list(Config) ->
+ case erlang:system_info(hipe_architecture) of
+ undefined ->
+ {skip,"Native code support is not enabled"};
+ Architecture ->
+ native_early_modules_1(Architecture)
+ end.
+
+native_early_modules_1(Architecture) ->
+ ?line {lists, ListsBinary, _ListsFilename} = code:get_object_code(lists),
+ ?line ChunkName = hipe_unified_loader:chunk_name(Architecture),
+ ?line NativeChunk = beam_lib:chunks(ListsBinary, [ChunkName]),
+ ?line IsHipeCompiled = case NativeChunk of
+ {ok,{_,[{_,Bin}]}} when is_binary(Bin) -> true;
+ {error, beam_lib, _} -> false
+ end,
+ case IsHipeCompiled of
+ false ->
+ {skip,"OTP apparently not configured with --enable-native-libs"};
+ true ->
+ ?line true = lists:all(fun code:is_module_native/1,
+ [ets,file,filename,gb_sets,gb_trees,
+ hipe_unified_loader,lists,os,packages]),
+ ok
+ end.
+
%%-----------------------------------------------------------------
%% error_logger handler.
%% (Copied from stdlib/test/proc_lib_SUITE.erl.)
diff --git a/lib/kernel/test/code_SUITE_data/on_load_app-1.0/src/on_load_embedded.erl b/lib/kernel/test/code_SUITE_data/on_load_app-1.0/src/on_load_embedded.erl
index a39332f81d..646921026d 100644
--- a/lib/kernel/test/code_SUITE_data/on_load_app-1.0/src/on_load_embedded.erl
+++ b/lib/kernel/test/code_SUITE_data/on_load_app-1.0/src/on_load_embedded.erl
@@ -3,6 +3,15 @@
-on_load(run_me/0).
run_me() ->
+ %% An onload handler typically calls code:priv_dir/1
+ %% or code:lib_dir/1, so make sure that it works.
+ LibDir = code:lib_dir(on_load_app),
+ PrivDir = code:priv_dir(on_load_app),
+ LibDir = filename:dirname(PrivDir),
+ ModPath = filename:join(filename:split(code:which(?MODULE))),
+ LibDir = filename:dirname(filename:dirname(ModPath)),
+
+ %% Start a process to remember that the on_load was called.
spawn(fun() ->
register(everything_is_fine, self()),
receive Any ->
diff --git a/lib/kernel/test/disk_log_SUITE.erl b/lib/kernel/test/disk_log_SUITE.erl
index ade9644c15..1bfe76f5ea 100644
--- a/lib/kernel/test/disk_log_SUITE.erl
+++ b/lib/kernel/test/disk_log_SUITE.erl
@@ -1,19 +1,19 @@
%%
%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 1997-2009. All Rights Reserved.
-%%
+%%
+%% Copyright Ericsson AB 1997-2010. 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
%% compliance with the License. You should have received a copy of the
%% Erlang Public License along with this software. If not, it can be
%% retrieved online at http://www.erlang.org/.
-%%
+%%
%% Software distributed under the License is distributed on an "AS IS"
%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
%% the License for the specific language governing rights and limitations
%% under the License.
-%%
+%%
%% %CopyrightEnd%
%%
-module(disk_log_SUITE).
@@ -384,7 +384,7 @@ halt_misc(Conf) when is_list(Conf) ->
?line {error, {read_only_mode, a}} =
disk_log:change_header(a, {head,header}),
?line {error, {read_only_mode, a}} =
- disk_log:change_size(a, inifinity),
+ disk_log:change_size(a, infinity),
?line ok = disk_log:close(a),
?line ok = file:delete(File).
@@ -1574,7 +1574,7 @@ block_blocked(Conf) when is_list(Conf) ->
?line "The blocked disk" ++ _ = format_error(Error1),
?line {error, {blocked_log, halt}} = disk_log:sync(halt),
?line {error, {blocked_log, halt}} = disk_log:truncate(halt),
- ?line {error, {blocked_log, halt}} = disk_log:change_size(halt, inifinity),
+ ?line {error, {blocked_log, halt}} = disk_log:change_size(halt, infinity),
?line {error, {blocked_log, halt}} =
disk_log:change_notify(halt, self(), false),
?line {error, {blocked_log, halt}} =
@@ -2423,6 +2423,9 @@ get_reply() ->
sync_do(Pid, Req) ->
Pid ! {self(), Req},
receive
+ Reply when Req =:= terminate ->
+ timer:sleep(500),
+ Reply;
Reply ->
Reply
end.
@@ -3165,7 +3168,7 @@ many_users(Conf) when is_list(Conf) ->
?line true = lists:duplicate(NoClients, ok) == C1,
?line true = length(T1) == N*NoClients,
?line {C2, T2} = many(Fun1, NoClients, N, halt, internal, 1000, Dir),
- ?line true = lists:duplicate(NoClients, {error, {full,'log.LOG'}}) == C2,
+ ?line true = lists:duplicate(NoClients, {error, {full,"log.LOG"}}) == C2,
?line true = length(T2) > 0,
?line {C3, T3} = many(Fun2, NoClients, N, wrap, internal,
{300*NoClients,20}, Dir),
@@ -3174,7 +3177,7 @@ many_users(Conf) when is_list(Conf) ->
ok.
many(Fun, NoClients, N, Type, Format, Size, Dir) ->
- Name = 'log.LOG',
+ Name = "log.LOG",
File = filename:join(Dir, Name),
del_files(Size, File),
?line Q = qlen(),
@@ -4328,11 +4331,9 @@ dist_terminate(Conf) when is_list(Conf) ->
?line 0 = sync_do(Pid1, users),
?line 0 = sync_do(Pid2, users),
?line sync_do(Pid1, terminate),
- ?line timer:sleep(500),
?line [_] = sync_do(Pid2, owners),
?line 0 = sync_do(Pid2, users),
?line sync_do(Pid2, terminate),
- ?line timer:sleep(500),
?line {error, no_such_log} = disk_log:info(n),
%% Users terminate (no link...).
diff --git a/lib/kernel/test/file_SUITE.erl b/lib/kernel/test/file_SUITE.erl
index d01e1f1fcf..47592ddb14 100644
--- a/lib/kernel/test/file_SUITE.erl
+++ b/lib/kernel/test/file_SUITE.erl
@@ -52,8 +52,8 @@
old_modes/1, new_modes/1, path_open/1, open_errors/1]).
-export([file_info/1, file_info_basic_file/1, file_info_basic_directory/1,
file_info_bad/1, file_info_times/1, file_write_file_info/1]).
--export([rename/1, access/1, truncate/1, sync/1,
- read_write/1, pread_write/1, append/1]).
+-export([rename/1, access/1, truncate/1, datasync/1, sync/1,
+ read_write/1, pread_write/1, append/1, exclusive/1]).
-export([errors/1, e_delete/1, e_rename/1, e_make_dir/1, e_del_dir/1]).
-export([otp_5814/1]).
@@ -82,6 +82,10 @@
-export([read_line_1/1, read_line_2/1, read_line_3/1,read_line_4/1]).
+-export([advise/1]).
+
+-export([standard_io/1,mini_server/1]).
+
%% Debug exports
-export([create_file_slow/2, create_file/2, create_bin/2]).
-export([verify_file/2, verify_bin/3]).
@@ -101,7 +105,8 @@ all(suite) ->
compression, links, copy,
delayed_write, read_ahead, segment_read, segment_write,
ipread, pid2name, interleaved_read_write,
- otp_5814, large_file, read_line_1, read_line_2, read_line_3, read_line_4],
+ otp_5814, large_file, read_line_1, read_line_2, read_line_3, read_line_4,
+ standard_io],
fini}.
init(Config) when is_list(Config) ->
@@ -170,6 +175,85 @@ time_dist({_D1, _T1} = DT1, {_D2, _T2} = DT2) ->
- calendar:datetime_to_gregorian_seconds(DT1).
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+mini_server(Parent) ->
+ receive
+ die ->
+ ok;
+ {io_request,From,To,{put_chars,Data}} ->
+ Parent ! {io_request,From,To,{put_chars,Data}},
+ From ! {io_reply, To, ok},
+ mini_server(Parent);
+ {io_request,From,To,{get_chars,'',N}} ->
+ Parent ! {io_request,From,To,{get_chars,'',N}},
+ From ! {io_reply, To, {ok, lists:duplicate(N,$a)}},
+ mini_server(Parent);
+ {io_request,From,To,{get_line,''}} ->
+ Parent ! {io_request,From,To,{get_line,''}},
+ From ! {io_reply, To, {ok, "hej\n"}},
+ mini_server(Parent)
+ end.
+
+standard_io(suite) ->
+ [];
+standard_io(doc) ->
+ ["Test that standard i/o-servers work with file module"];
+standard_io(Config) when is_list(Config) ->
+ %% Really just a smoke test
+ ?line Pid = spawn(?MODULE,mini_server,[self()]),
+ ?line register(mini_server,Pid),
+ ?line ok = file:write(mini_server,<<"hej\n">>),
+ ?line receive
+ {io_request,_,_,{put_chars,<<"hej\n">>}} ->
+ ok
+ after 1000 ->
+ exit(noreply)
+ end,
+ ?line {ok,"aaaaa"} = file:read(mini_server,5),
+ ?line receive
+ {io_request,_,_,{get_chars,'',5}} ->
+ ok
+ after 1000 ->
+ exit(noreply)
+ end,
+ ?line {ok,"hej\n"} = file:read_line(mini_server),
+ ?line receive
+ {io_request,_,_,{get_line,''}} ->
+ ok
+ after 1000 ->
+ exit(noreply)
+ end,
+ ?line OldGL = group_leader(),
+ ?line group_leader(Pid,self()),
+ ?line ok = file:write(standard_io,<<"hej\n">>),
+ ?line group_leader(OldGL,self()),
+ ?line receive
+ {io_request,_,_,{put_chars,<<"hej\n">>}} ->
+ ok
+ after 1000 ->
+ exit(noreply)
+ end,
+ ?line group_leader(Pid,self()),
+ ?line {ok,"aaaaa"} = file:read(standard_io,5),
+ ?line group_leader(OldGL,self()),
+ ?line receive
+ {io_request,_,_,{get_chars,'',5}} ->
+ ok
+ after 1000 ->
+ exit(noreply)
+ end,
+ ?line group_leader(Pid,self()),
+ ?line {ok,"hej\n"} = file:read_line(standard_io),
+ ?line group_leader(OldGL,self()),
+ ?line receive
+ {io_request,_,_,{get_line,''}} ->
+ ok
+ after 1000 ->
+ exit(noreply)
+ end,
+ Pid ! die,
+ receive after 1000 -> ok end.
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
read_write_file(suite) -> [];
read_write_file(doc) -> [];
@@ -270,7 +354,10 @@ make_del_dir(Config) when is_list(Config) ->
%% Try deleting some bad directories
%% Deleting the parent directory to the current, sounds dangerous, huh?
%% Don't worry ;-) the parent directory should never be empty, right?
- ?line {error, eexist} = ?FILE_MODULE:del_dir('..'),
+ case ?FILE_MODULE:del_dir('..') of
+ {error, eexist} -> ok;
+ {error, einval} -> ok %FreeBSD
+ end,
?line {error, enoent} = ?FILE_MODULE:del_dir(""),
?line {error, badarg} = ?FILE_MODULE:del_dir([3,2,1,{}]),
@@ -374,10 +461,12 @@ win_cur_dir_1(_Config) ->
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-files(suite) -> [open,pos,file_info,consult,eval,script,truncate,sync].
+files(suite) ->
+ [open,pos,file_info,consult,eval,script,truncate,
+ sync,datasync,advise].
open(suite) -> [open1,old_modes,new_modes,path_open,close,access,read_write,
- pread_write,append,open_errors].
+ pread_write,append,open_errors,exclusive].
open1(suite) -> [];
open1(doc) -> [];
@@ -751,6 +840,22 @@ open_errors(Config) when is_list(Config) ->
?line test_server:timetrap_cancel(Dog),
ok.
+exclusive(suite) -> [];
+exclusive(doc) -> "Test exclusive access to a file.";
+exclusive(Config) when is_list(Config) ->
+ ?line Dog = test_server:timetrap(test_server:seconds(5)),
+ ?line RootDir = ?config(priv_dir,Config),
+ ?line NewDir = filename:join(RootDir,
+ atom_to_list(?MODULE)
+ ++"_exclusive"),
+ ?line ok = ?FILE_MODULE:make_dir(NewDir),
+ ?line Name = filename:join(NewDir, "ex_file.txt"),
+ ?line {ok, Fd} = ?FILE_MODULE:open(Name, [write, exclusive]),
+ ?line {error, eexist} = ?FILE_MODULE:open(Name, [write, exclusive]),
+ ?line ok = ?FILE_MODULE:close(Fd),
+ ?line test_server:timetrap_cancel(Dog),
+ ok.
+
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
pos(suite) -> [pos1,pos2].
@@ -1352,6 +1457,30 @@ truncate(Config) when is_list(Config) ->
ok.
+datasync(suite) -> [];
+datasync(doc) -> "Tests that ?FILE_MODULE:datasync/1 at least doesn't crash.";
+datasync(Config) when is_list(Config) ->
+ ?line Dog = test_server:timetrap(test_server:seconds(5)),
+ ?line PrivDir = ?config(priv_dir, Config),
+ ?line Sync = filename:join(PrivDir,
+ atom_to_list(?MODULE)
+ ++"_sync.fil"),
+
+ %% Raw open.
+ ?line {ok, Fd} = ?FILE_MODULE:open(Sync, [write, raw]),
+ ?line ok = ?FILE_MODULE:datasync(Fd),
+ ?line ok = ?FILE_MODULE:close(Fd),
+
+ %% Ordinary open.
+ ?line {ok, Fd2} = ?FILE_MODULE:open(Sync, [write]),
+ ?line ok = ?FILE_MODULE:datasync(Fd2),
+ ?line ok = ?FILE_MODULE:close(Fd2),
+
+ ?line [] = flush(),
+ ?line test_server:timetrap_cancel(Dog),
+ ok.
+
+
sync(suite) -> [];
sync(doc) -> "Tests that ?FILE_MODULE:sync/1 at least doesn't crash.";
sync(Config) when is_list(Config) ->
@@ -1375,6 +1504,77 @@ sync(Config) when is_list(Config) ->
?line test_server:timetrap_cancel(Dog),
ok.
+advise(suite) -> [];
+advise(doc) -> "Tests that ?FILE_MODULE:advise/4 at least doesn't crash.";
+advise(Config) when is_list(Config) ->
+ ?line Dog = test_server:timetrap(test_server:seconds(5)),
+ ?line PrivDir = ?config(priv_dir, Config),
+ ?line Advise = filename:join(PrivDir,
+ atom_to_list(?MODULE)
+ ++"_advise.fil"),
+
+ Line1 = "Hello\n",
+ Line2 = "World!\n",
+
+ ?line {ok, Fd} = ?FILE_MODULE:open(Advise, [write]),
+ ?line ok = ?FILE_MODULE:advise(Fd, 0, 0, normal),
+ ?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(Advise, [write]),
+ ?line ok = ?FILE_MODULE:advise(Fd2, 0, 0, random),
+ ?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(Advise, [write]),
+ ?line ok = ?FILE_MODULE:advise(Fd3, 0, 0, sequential),
+ ?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(Advise, [write]),
+ ?line ok = ?FILE_MODULE:advise(Fd4, 0, 0, will_need),
+ ?line ok = io:format(Fd4, "~s", [Line1]),
+ ?line ok = io:format(Fd4, "~s", [Line2]),
+ ?line ok = ?FILE_MODULE:close(Fd4),
+
+ ?line {ok, Fd5} = ?FILE_MODULE:open(Advise, [write]),
+ ?line ok = ?FILE_MODULE:advise(Fd5, 0, 0, dont_need),
+ ?line ok = io:format(Fd5, "~s", [Line1]),
+ ?line ok = io:format(Fd5, "~s", [Line2]),
+ ?line ok = ?FILE_MODULE:close(Fd5),
+
+ ?line {ok, Fd6} = ?FILE_MODULE:open(Advise, [write]),
+ ?line ok = ?FILE_MODULE:advise(Fd6, 0, 0, no_reuse),
+ ?line ok = io:format(Fd6, "~s", [Line1]),
+ ?line ok = io:format(Fd6, "~s", [Line2]),
+ ?line ok = ?FILE_MODULE:close(Fd6),
+
+ ?line {ok, Fd7} = ?FILE_MODULE:open(Advise, [write]),
+ ?line {error, einval} = ?FILE_MODULE:advise(Fd7, 0, 0, bad_advise),
+ ?line ok = ?FILE_MODULE:close(Fd7),
+
+ %% test write without advise, then a read after an advise
+ ?line {ok, Fd8} = ?FILE_MODULE:open(Advise, [write]),
+ ?line ok = io:format(Fd8, "~s", [Line1]),
+ ?line ok = io:format(Fd8, "~s", [Line2]),
+ ?line ok = ?FILE_MODULE:close(Fd8),
+ ?line {ok, Fd9} = ?FILE_MODULE:open(Advise, [read]),
+ Offset = 0,
+ %% same as a 0 length in some implementations
+ Length = length(Line1) + length(Line2),
+ ?line ok = ?FILE_MODULE:advise(Fd9, Offset, Length, sequential),
+ ?line {ok, Line1} = ?FILE_MODULE:read_line(Fd9),
+ ?line {ok, Line2} = ?FILE_MODULE:read_line(Fd9),
+ ?line eof = ?FILE_MODULE:read_line(Fd9),
+ ?line ok = ?FILE_MODULE:close(Fd9),
+
+ ?line [] = flush(),
+ ?line test_server:timetrap_cancel(Dog),
+ ok.
+
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
@@ -3068,7 +3268,7 @@ large_file(Config) when is_list(Config) ->
{{unix,sunos},{A,B,C}}
when A == 5, B == 5, C >= 1; A == 5, B >= 6; A >= 6 ->
do_large_file(Config);
- {{unix,Unix},_} when Unix =:= linux; Unix =:= darwin ->
+ {{unix,Unix},_} when Unix =/= sunos ->
N = unix_free(Config),
io:format("Free: ~w KByte~n", [N]),
if N < 5 * (1 bsl 20) ->
@@ -3078,7 +3278,7 @@ large_file(Config) when is_list(Config) ->
do_large_file(Config)
end;
_ ->
- {skipped,"Only supported on Win32, Linux, or SunOS >= 5.5.1"}
+ {skipped,"Only supported on Win32, Unix or SunOS >= 5.5.1"}
end.
unix_free(Config) ->
@@ -3090,7 +3290,7 @@ unix_free(Config) ->
N.
do_large_file(Config) ->
- ?line Watchdog = ?t:timetrap(?t:minutes(4)),
+ ?line Watchdog = ?t:timetrap(?t:minutes(5)),
%%
?line Name = filename:join(?config(priv_dir, Config),
?MODULE_STRING ++ "_large_file"),
@@ -3129,6 +3329,17 @@ do_large_file(Config) ->
?line {ok,P} = ?FILE_MODULE:position(F, {eof,-L}),
?line {ok,Rs} = ?FILE_MODULE:read(F, L+1),
?line ok = ?FILE_MODULE:close(F),
+ %% Reopen the file with 'append'; used to fail on Windows causing
+ %% writes to go to the beginning of the file for files > 4GB.
+ ?line PL = P + L,
+ ?line PLL = PL + L,
+ ?line {ok,F1} = ?FILE_MODULE:open(Name, [raw,read,write,append]),
+ ?line ok = ?FILE_MODULE:write(F1, R),
+ ?line {ok,PLL} = ?FILE_MODULE:position(F1, {cur,0}),
+ ?line {ok,Rs} = ?FILE_MODULE:pread(F1, P, L),
+ ?line {ok,PL} = ?FILE_MODULE:position(F1, {eof,-L}),
+ ?line {ok,R} = ?FILE_MODULE:read(F1, L+1),
+ ?line ok = ?FILE_MODULE:close(F1),
%%
?line Mref = erlang:monitor(process, Deleter),
?line Deleter ! {Tester,done},
diff --git a/lib/kernel/test/file_name_SUITE.erl b/lib/kernel/test/file_name_SUITE.erl
new file mode 100644
index 0000000000..fea4df8539
--- /dev/null
+++ b/lib/kernel/test/file_name_SUITE.erl
@@ -0,0 +1,1729 @@
+-module(file_name_SUITE).
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 1996-2010. 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
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved online at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% %CopyrightEnd%
+%%
+
+-include("test_server.hrl").
+-include_lib("kernel/include/file.hrl").
+
+%%
+%% File operations that take filenames as parameters (* not prim_file operation) (** a drive):
+%% altname
+%% copy (*)
+%% del_dir
+%% delete
+%% get_cwd (**)
+%% list_dir
+%% make_dir
+%% make_link
+%% make_symlink
+%% open
+%% read_file
+%% read_file_info
+%% read_link
+%% read_link_info
+%% rename
+%% set_cwd
+%% write_file
+%% write_file_info
+%%
+%% File operations that opens/uses separate driver port (not connected to file)
+%% altname
+%% del_dir
+%% delete
+%% get_cwd
+%% list_dir
+%% make_dir
+%% make_link
+%% make_symlink
+%% read_file_info
+%% read_link
+%% read_link_info
+%% rename
+%% set_cwd
+%% write_file_info
+%%
+%% Operations that use ?FD_DRV in prim_file
+%% open
+%% read_file
+%% write_file
+%%
+%%
+%% Operations that return a filename/path
+%% altname
+%% get_cwd
+%% list_dir
+%% read_link
+
+-export([all/1,init_per_testcase/2, fin_per_testcase/2]).
+-export([normal/1,icky/1,very_icky/1,normalize/1]).
+
+
+init_per_testcase(_Func, Config) ->
+ Dog = test_server:timetrap(test_server:seconds(60)),
+ [{watchdog,Dog}|Config].
+
+fin_per_testcase(_Func, Config) ->
+ Dog = ?config(watchdog, Config),
+ test_server:timetrap_cancel(Dog).
+
+
+all(suite) ->
+ [normal,icky,very_icky,normalize].
+
+normalize(suite) ->
+ [];
+normalize(doc) ->
+ ["Check that filename normalization works"];
+normalize(Config) when is_list(Config) ->
+ random:seed({1290,431421,830412}),
+ try
+ ?line UniMode = file:native_name_encoding() =/= latin1,
+ if
+ not UniMode ->
+ throw(need_unicode_mode);
+ true ->
+ ok
+ end,
+ ?line Pairs = [rand_comp_decomp(200) || _ <- lists:seq(1,1000)],
+ case os:type() of
+ {unix,darwin} ->
+ ?line [ true = (A =:= prim_file:internal_native2name(B)) ||
+ {A,B} <- Pairs ];
+ _ ->
+ ok
+ end,
+ ?line [ true = (A =:= prim_file:internal_normalize_utf8(B)) ||
+ {A,B} <- Pairs ]
+
+ catch
+ throw:need_unicode_mode ->
+ io:format("Sorry, can only run in unicode mode.~n"),
+ {skipped,"VM needs to be started in Unicode filename mode"}
+ end.
+
+normal(suite) ->
+ [];
+normal(doc) ->
+ "Check file operations on normal file names regardless of unicode mode";
+normal(Config) when is_list(Config) ->
+ {ok,Dir} = file:get_cwd(),
+ try
+ Priv = ?config(priv_dir, Config),
+ file:set_cwd(Priv),
+ put(file_module,prim_file),
+ ok = check_normal(prim_file),
+ put(file_module,file),
+ ok = check_normal(file)
+ after
+ file:set_cwd(Dir)
+ end.
+
+
+icky(suite) ->
+ [];
+icky(doc) ->
+ "Check file operations on normal file names regardless of unicode mode";
+icky(Config) when is_list(Config) ->
+ case hopeless_darwin() of
+ true ->
+ {skipped,"This version of darwin does not support icky names at all."};
+ false ->
+ {ok,Dir} = file:get_cwd(),
+ try
+ Priv = ?config(priv_dir, Config),
+ file:set_cwd(Priv),
+ put(file_module,prim_file),
+ ok = check_icky(prim_file),
+ put(file_module,file),
+ ok = check_icky(file)
+ after
+ file:set_cwd(Dir)
+ end
+ end.
+very_icky(suite) ->
+ [];
+very_icky(doc) ->
+ "Check file operations on normal file names regardless of unicode mode";
+very_icky(Config) when is_list(Config) ->
+ case hopeless_darwin() of
+ true ->
+ {skipped,"This version of darwin does not support icky names at all."};
+ false ->
+ {ok,Dir} = file:get_cwd(),
+ try
+ Priv = ?config(priv_dir, Config),
+ file:set_cwd(Priv),
+ put(file_module,prim_file),
+ case check_very_icky(prim_file) of
+ need_unicode_mode ->
+ {skipped,"VM needs to be started in Unicode filename mode"};
+ ok ->
+ put(file_module,file),
+ ok = check_very_icky(file)
+ end
+ after
+ file:set_cwd(Dir)
+ end
+ end.
+
+
+check_normal(Mod) ->
+ {ok,Dir} = Mod:get_cwd(),
+ try
+ ?line make_normal_dir(Mod),
+ ?line {ok, L0} = Mod:list_dir("."),
+ ?line L1 = lists:sort(L0),
+ %erlang:display(L1),
+ ?line L1 = lists:sort(list(normal_dir())),
+ ?line {ok,D2} = Mod:get_cwd(),
+ ?line true = is_list(D2),
+ ?line case Mod:altname("fil1") of
+ {error,enotsup} ->
+ ok;
+ {ok,LLL} when is_list(LLL) ->
+ ok
+ end,
+ ?line [ true = is_list(El) || El <- L1],
+ ?line Syms = [ {S,Targ,list_to_binary(get_data(Targ,normal_dir()))}
+ || {T,S,Targ} <- normal_dir(), T =:= symlink ],
+ ?line [ {ok, Cont} = Mod:read_file(SymL) || {SymL,_,Cont} <- Syms ],
+ ?line [ {ok, Targ} = fixlink(Mod:read_link(SymL)) || {SymL,Targ,_} <- Syms ],
+ ?line chk_cre_dir(Mod,[{directory,"temp_dir",normal_dir()}]),
+ ?line {ok,BeginAt} = Mod:get_cwd(),
+ ?line true = is_list(BeginAt),
+ ?line {error,enoent} = Mod:set_cwd("tmp_dir"),
+ ?line ok = Mod:set_cwd("temp_dir"),
+ ?line {ok, NowAt} = Mod:get_cwd(),
+ ?line true = BeginAt =/= NowAt,
+ ?line ok = Mod:set_cwd(".."),
+ ?line {ok,BeginAt} = Mod:get_cwd(),
+ ?line rm_r(Mod,"temp_dir"),
+ ?line true = is_list(Dir),
+ ?line [ true = is_list(FN) || FN <- L0 ],
+ case has_links() of
+ true ->
+ ?line ok = Mod:make_link("fil1","nisse"),
+ ?line {ok, <<"fil1">>} = Mod:read_file("nisse"),
+ ?line {ok, #file_info{type = regular}} = Mod:read_link_info("nisse"),
+ ?line ok = Mod:delete("nisse"),
+ ?line {ok, <<"fil1">>} = Mod:read_file("fil1"),
+ ?line {error,enoent} = Mod:read_file("nisse"),
+ ?line {error,enoent} = Mod:read_link_info("nisse");
+ false ->
+ ok
+ end,
+ ?line [ begin
+ ?line {ok, FD} = Mod:open(Name,[read]),
+ ?line {ok, Content} = Mod:read(FD,1024),
+ ?line ok = file:close(FD)
+ end || {regular,Name,Content} <- normal_dir() ],
+ ?line [ begin
+ ?line {ok, FD} = Mod:open(Name,[read,binary]),
+ ?line BC = list_to_binary(Content),
+ ?line {ok, BC} = Mod:read(FD,1024),
+ ?line ok = file:close(FD)
+ end || {regular,Name,Content} <- normal_dir() ],
+ ?line Mod:rename("fil1","tmp_fil1"),
+ ?line {ok, <<"fil1">>} = Mod:read_file("tmp_fil1"),
+ ?line {error,enoent} = Mod:read_file("fil1"),
+ ?line Mod:rename("tmp_fil1","fil1"),
+ ?line {ok, <<"fil1">>} = Mod:read_file("fil1"),
+ ?line {error,enoent} = Mod:read_file("tmp_fil1"),
+ ?line {ok,FI} = Mod:read_file_info("fil1"),
+ ?line NewMode = FI#file_info.mode band (bnot 8#333),
+ ?line NewMode2 = NewMode bor 8#222,
+ ?line true = NewMode2 =/= NewMode,
+ ?line ok = Mod:write_file_info("fil1",FI#file_info{mode = NewMode}),
+ ?line {ok,#file_info{mode = NewMode}} = Mod:read_file_info("fil1"),
+ ?line ok = Mod:write_file_info("fil1",FI#file_info{mode = NewMode2}),
+ ?line {ok,#file_info{mode = NewMode2}} = Mod:read_file_info("fil1"),
+ ok
+ after
+ case Mod:read_file_info("fil1") of
+ {ok,FII} ->
+ NewModeI = FII#file_info.mode bor 8#777,
+ Mod:write_file_info("fil1",FII#file_info{mode = NewModeI});
+ _ ->
+ ok
+ end,
+ Mod:set_cwd(Dir),
+ io:format("Wd now: ~s~n",[Dir])
+ end.
+
+check_icky(Mod) ->
+ {ok,Dir} = Mod:get_cwd(),
+ try
+ ?line true=(length("���") =:= 3),
+ ?line UniMode = file:native_name_encoding() =/= latin1,
+ ?line make_icky_dir(Mod),
+ ?line {ok, L0} = Mod:list_dir("."),
+ ?line L1 = lists:sort(L0),
+ io:format("~p ~p~n",[L1,list(icky_dir())]),
+ ?line L1 = lists:sort(convlist(list(icky_dir()))),
+ ?line {ok,D2} = Mod:get_cwd(),
+ ?line true = is_list(D2),
+%% Altname only on windows, and there are no non native filenames there
+%% ?line case Mod:altname("fil1") of
+%% {error,enotsup} ->
+%% ok;
+%% {ok,LLL} when is_list(LLL) ->
+%% ok
+%% end,
+ ?line [ true = ((is_list(El) or (UniMode and is_binary(El)))) || El <- L1],
+ ?line Syms = [ {S,conv(Targ),list_to_binary(get_data(Targ,icky_dir()))}
+ || {T,S,Targ} <- icky_dir(), T =:= symlink ],
+ ?line [ {ok, Cont} = Mod:read_file(SymL) || {SymL,_,Cont} <- Syms ],
+ ?line [ {ok, Targ} = fixlink(Mod:read_link(SymL)) || {SymL,Targ,_} <- Syms ],
+ ?line chk_cre_dir(Mod,[{directory,"���_dir",icky_dir()}]),
+ ?line {ok,BeginAt} = Mod:get_cwd(),
+ ?line true = is_list(BeginAt),
+ ?line {error,enoent} = Mod:set_cwd("��_dir"),
+ ?line ok = Mod:set_cwd("���_dir"),
+ ?line {ok, NowAt} = Mod:get_cwd(),
+ ?line true = is_list(NowAt),
+ ?line true = BeginAt =/= NowAt,
+ ?line ok = Mod:set_cwd(".."),
+ ?line {ok,BeginAt} = Mod:get_cwd(),
+ ?line rm_r2(Mod,"���_dir"),
+ {OS,TYPE} = os:type(),
+ % Check that treat_icky really converts to the same as the OS
+ case UniMode of
+ true ->
+ ?line chk_cre_dir(Mod,[{directory,"���_dir",[]}]),
+ ?line ok = Mod:set_cwd("���_dir"),
+ ?line ok = Mod:write_file(<<"���">>,<<"hello">>),
+ ?line Treated = treat_icky(<<"���">>),
+ ?line {ok,[Treated]} = Mod:list_dir("."),
+ ?line ok = Mod:delete(<<"���">>),
+ ?line {ok,[]} = Mod:list_dir("."),
+ ?line ok = Mod:set_cwd(".."),
+ ?line rm_r2(Mod,"���_dir");
+ false ->
+ ok
+ end,
+
+ ?line chk_cre_dir(Mod,[{directory,treat_icky(<<"���_dir">>),icky_dir()}]),
+ if
+ UniMode and (OS =/= win32) ->
+ ?line {error,enoent} = Mod:set_cwd("���_dir");
+ true ->
+ ok
+ end,
+ ?line ok = Mod:set_cwd(treat_icky(<<"���_dir">>)),
+ ?line {ok, NowAt2} = Mod:get_cwd(),
+ io:format("~p~n",[NowAt2]),
+ % Cannot create raw unicode-breaking filenames on windows or macos
+ ?line true = ((((not UniMode) or (OS =:= win32) or (TYPE=:=darwin)) and is_list(NowAt2)) orelse ((UniMode) and is_binary(NowAt2))),
+ ?line true = BeginAt =/= NowAt2,
+ ?line ok = Mod:set_cwd(".."),
+ ?line {ok,BeginAt} = Mod:get_cwd(),
+ ?line rm_r2(Mod,conv(treat_icky(<<"���_dir">>))),
+ case has_links() of
+ true ->
+ ?line ok = Mod:make_link("fil1","nisse�"),
+ ?line {ok, <<"fil1">>} = Mod:read_file("nisse�"),
+ ?line {ok, #file_info{type = regular}} = Mod:read_link_info("nisse�"),
+ ?line ok = Mod:delete("nisse�"),
+ ?line ok = Mod:make_link("fil1",treat_icky(<<"nisse�">>)),
+ ?line {ok, <<"fil1">>} = Mod:read_file(treat_icky(<<"nisse�">>)),
+ ?line {ok, #file_info{type = regular}} = Mod:read_link_info(treat_icky(<<"nisse�">>)),
+ ?line ok = Mod:delete(treat_icky(<<"nisse�">>)),
+ ?line {ok, <<"fil1">>} = Mod:read_file("fil1"),
+ ?line {error,enoent} = Mod:read_file("nisse�"),
+ ?line {error,enoent} = Mod:read_link_info("nisse�"),
+ ?line {error,enoent} = Mod:read_file(treat_icky(<<"nisse�">>)),
+ ?line {error,enoent} = Mod:read_link_info(treat_icky(<<"nisse�">>));
+ false ->
+ ok
+ end,
+ ?line [ begin
+ ?line {ok, FD} = Mod:open(Name,[read]),
+ ?line {ok, Content} = Mod:read(FD,1024),
+ ?line ok = file:close(FD)
+ end || {regular,Name,Content} <- icky_dir() ],
+ ?line [ begin
+ ?line {ok, FD} = Mod:open(Name,[read,binary]),
+ ?line BC = list_to_binary([Content]),
+ ?line {ok, BC} = Mod:read(FD,1024),
+ ?line ok = file:close(FD)
+ end || {regular,Name,Content} <- icky_dir() ],
+ ?line Mod:rename("���2","���_fil1"),
+ ?line {ok, <<"���2">>} = Mod:read_file("���_fil1"),
+ ?line {error,enoent} = Mod:read_file("���2"),
+ ?line Mod:rename("���_fil1","���2"),
+ ?line {ok, <<"���2">>} = Mod:read_file("���2"),
+ ?line {error,enoent} = Mod:read_file("���_fil1"),
+
+ ?line Mod:rename("���2",treat_icky(<<"���_fil1">>)),
+ ?line {ok, <<"���2">>} = Mod:read_file(treat_icky(<<"���_fil1">>)),
+ if
+ UniMode and (OS =/= win32) ->
+ {error,enoent} = Mod:read_file("���_fil1");
+ true ->
+ ok
+ end,
+ ?line {error,enoent} = Mod:read_file("���2"),
+ ?line Mod:rename(treat_icky(<<"���_fil1">>),"���2"),
+ ?line {ok, <<"���2">>} = Mod:read_file("���2"),
+ ?line {error,enoent} = Mod:read_file("���_fil1"),
+ ?line {error,enoent} = Mod:read_file(treat_icky(<<"���_fil1">>)),
+
+ ?line {ok,FI} = Mod:read_file_info("���2"),
+ ?line NewMode = FI#file_info.mode band (bnot 8#333),
+ ?line NewMode2 = NewMode bor 8#222,
+ ?line true = NewMode2 =/= NewMode,
+ ?line ok = Mod:write_file_info("���2",FI#file_info{mode = NewMode}),
+ ?line {ok,#file_info{mode = NewMode}} = Mod:read_file_info("���2"),
+ ?line ok = Mod:write_file_info("���2",FI#file_info{mode = NewMode2}),
+ ?line {ok,#file_info{mode = NewMode2}} = Mod:read_file_info("���2"),
+
+ ?line {ok,FII} = Mod:read_file_info(treat_icky(<<"���5">>)),
+ ?line true = NewMode2 =/= NewMode,
+ ?line ok = Mod:write_file_info(treat_icky(<<"���5">>),FII#file_info{mode = NewMode}),
+ ?line {ok,#file_info{mode = NewMode}} = Mod:read_file_info(treat_icky(<<"���5">>)),
+ ?line ok = Mod:write_file_info(<<"���5">>,FII#file_info{mode = NewMode2}),
+ ?line {ok,#file_info{mode = NewMode2}} = Mod:read_file_info(treat_icky(<<"���5">>)),
+ ok
+ after
+ Mod:set_cwd(Dir),
+ io:format("Wd now: ~s~n",[Dir])
+ end.
+
+check_very_icky(Mod) ->
+ {ok,Dir} = Mod:get_cwd(),
+ try
+ ?line true=(length("���") =:= 3),
+ ?line UniMode = file:native_name_encoding() =/= latin1,
+ if
+ not UniMode ->
+ throw(need_unicode_mode);
+ true ->
+ ok
+ end,
+ ?line make_very_icky_dir(Mod),
+ ?line {ok, L0} = Mod:list_dir("."),
+ ?line L1 = lists:sort(L0),
+ ?line L1 = lists:sort(convlist(list(very_icky_dir()))),
+ ?line {ok,D2} = Mod:get_cwd(),
+ ?line true = is_list(D2),
+ ?line [ true = ((is_list(El) or is_binary(El))) || El <- L1],
+ ?line Syms = [ {S,conv(Targ),list_to_binary(get_data(Targ,very_icky_dir()))}
+ || {T,S,Targ} <- very_icky_dir(), T =:= symlink ],
+ ?line [ {ok, Cont} = Mod:read_file(SymL) || {SymL,_,Cont} <- Syms ],
+ ?line [ {ok, Targ} = fixlink(Mod:read_link(SymL)) || {SymL,Targ,_} <- Syms ],
+ ?line chk_cre_dir(Mod,[{directory,[1088,1079,1091]++"_dir",very_icky_dir()}]),
+ ?line {ok,BeginAt} = Mod:get_cwd(),
+ ?line true = is_list(BeginAt),
+ ?line {error,enoent} = Mod:set_cwd("��_dir"),
+ ?line ok = Mod:set_cwd([1088,1079,1091]++"_dir"),
+ ?line {ok, NowAt} = Mod:get_cwd(),
+ ?line true = is_list(NowAt),
+ ?line true = BeginAt =/= NowAt,
+ ?line ok = Mod:set_cwd(".."),
+ ?line {ok,BeginAt} = Mod:get_cwd(),
+ ?line rm_r2(Mod,[1088,1079,1091]++"_dir"),
+
+ case has_links() of
+ true ->
+ ?line ok = Mod:make_link("fil1","nisse"++[1088,1079,1091]),
+ ?line {ok, <<"fil1">>} =
+ Mod:read_file("nisse"++[1088,1079,1091]),
+ ?line {ok, #file_info{type = regular}} =
+ Mod:read_link_info("nisse"++[1088,1079,1091]),
+ ?line ok = Mod:delete("nisse"++[1088,1079,1091]),
+ ?line ok = Mod:make_link("fil1",<<"nisse�">>),
+ ?line {ok, <<"fil1">>} = Mod:read_file(<<"nisse�">>),
+ ?line {ok, #file_info{type = regular}} =
+ Mod:read_link_info(<<"nisse�">>),
+ ?line ok = Mod:delete(<<"nisse�">>),
+ ?line {ok, <<"fil1">>} = Mod:read_file("fil1"),
+ ?line {error,enoent} = Mod:read_file("nisse"++[1088,1079,1091]),
+ ?line {error,enoent} = Mod:read_link_info("nisse"++[1088,1079,1091]),
+ ?line {error,enoent} = Mod:read_file(<<"nisse�">>),
+ ?line {error,enoent} = Mod:read_link_info(<<"nisse�">>);
+ false ->
+ ok
+ end,
+ ?line [ begin
+ ?line {ok, FD} = Mod:open(Name,[read]),
+ ?line {ok, Content} = Mod:read(FD,1024),
+ ?line ok = file:close(FD)
+ end || {regular,Name,Content} <- very_icky_dir() ],
+ ?line [ begin
+ ?line {ok, FD} = Mod:open(Name,[read,binary]),
+ ?line BC = list_to_binary([Content]),
+ ?line {ok, BC} = Mod:read(FD,1024),
+ ?line ok = file:close(FD)
+ end || {regular,Name,Content} <- very_icky_dir() ],
+ ?line Mod:rename([956,965,963,954,959,49],
+ [956,965,963,954,959]++"_fil1"),
+ ?line {ok, <<"���2">>} = Mod:read_file([956,965,963,954,959]++"_fil1"),
+ ?line {error,enoent} = Mod:read_file([956,965,963,954,959,49]),
+ ?line Mod:rename([956,965,963,954,959]++"_fil1",[956,965,963,954,959,49]),
+ ?line {ok, <<"���2">>} = Mod:read_file([956,965,963,954,959,49]),
+ ?line {error,enoent} = Mod:read_file([956,965,963,954,959]++"_fil1"),
+
+ ?line {ok,FI} = Mod:read_file_info([956,965,963,954,959,49]),
+ ?line NewMode = FI#file_info.mode band (bnot 8#333),
+ ?line NewMode2 = NewMode bor 8#222,
+ ?line true = NewMode2 =/= NewMode,
+ ?line ok = Mod:write_file_info([956,965,963,954,959,49],
+ FI#file_info{mode = NewMode}),
+ ?line {ok,#file_info{mode = NewMode}} =
+ Mod:read_file_info([956,965,963,954,959,49]),
+ ?line ok = Mod:write_file_info([956,965,963,954,959,49],
+ FI#file_info{mode = NewMode2}),
+ ?line {ok,#file_info{mode = NewMode2}} =
+ Mod:read_file_info([956,965,963,954,959,49]),
+ ?line NumOK0 = case has_links() of
+ true -> 5;
+ false -> 3
+ end,
+ ?line NumNOK0 = case has_links() of
+ true -> 4;
+ false -> 3
+ end,
+ ?line {NumOK,NumNOK} = case is_binary(treat_icky(<<"foo">>)) of
+ false ->
+ {NumOK0+NumNOK0,0};
+ true ->
+ {NumOK0,NumNOK0}
+ end,
+ ?line {NumOK,NumNOK} = filelib:fold_files(".",".*",true,fun(_F,{N,M}) when is_list(_F) -> io:format("~ts~n",[_F]),{N+1,M}; (_F,{N,M}) -> io:format("~p~n",[_F]),{N,M+1} end,{0,0}),
+ ?line ok = filelib:fold_files(".",[1076,1089,1072,124,46,42],true,fun(_F,_) -> ok end,false),
+ ?line SF3 = unicode:characters_to_binary("���subfil3",file:native_name_encoding()),
+ ?line Sorted = lists:sort([SF3,<<"���subfil2">>]),
+ ?line Sorted = lists:sort(filelib:wildcard("*",<<"���subdir2">>)),
+ ok
+ catch
+ throw:need_unicode_mode ->
+ io:format("Sorry, can only run in unicode mode.~n"),
+ need_unicode_mode
+ after
+ Mod:set_cwd(Dir),
+ io:format("Wd now: ~s~n",[Dir])
+ end.
+
+%%
+%% Utilities
+%%
+
+
+rm_rf(Mod,Dir) ->
+ case Mod:read_link_info(Dir) of
+ {ok, #file_info{type = directory}} ->
+ {ok, Content} = Mod:list_dir(Dir),
+ [ rm_rf(Mod,filename:join(Dir,C)) || C <- Content ],
+ Mod:del_dir(Dir),
+ ok;
+ {ok, #file_info{}} ->
+ Mod:delete(Dir);
+ _ ->
+ ok
+ end.
+
+rm_r(Mod,Dir) ->
+ %erlang:display({rm_r,Dir}),
+ case Mod:read_link_info(Dir) of
+ {ok, #file_info{type = directory}} ->
+ {ok,#file_info{type = directory}} = Mod:read_file_info(Dir),
+ {ok, Content} = Mod:list_dir(Dir),
+ [ true = is_list(Part) || Part <- Content ],
+ [ true = is_list(filename:join(Dir,Part)) || Part <- Content ],
+ [ rm_r(Mod,filename:join(Dir,C)) || C <- Content ],
+ ok = Mod:del_dir(Dir),
+ ok;
+ {ok, #file_info{type = regular}} ->
+ {ok,#file_info{type = regular}} = Mod:read_file_info(Dir),
+ ok = Mod:delete(Dir);
+ {ok, #file_info{type = symlink}} ->
+ ok = Mod:delete(Dir)
+ end.
+%% For icky test, allow binaries sometimes
+rm_r2(Mod,Dir) ->
+ %erlang:display({rm_r2,Dir}),
+ case Mod:read_link_info(Dir) of
+ {ok, #file_info{type = directory}} ->
+ {ok,#file_info{type = directory}} = Mod:read_file_info(Dir),
+ {ok, Content} = Mod:list_dir(Dir),
+ UniMode = file:native_name_encoding() =/= latin1,
+ [ true = (is_list(Part) orelse UniMode) || Part <- Content ],
+ [ true = (is_list(filename:join(Dir,Part)) orelse UniMode) || Part <- Content ],
+ [ rm_r2(Mod,filename:join(Dir,C)) || C <- Content ],
+ ok = Mod:del_dir(Dir),
+ ok;
+ {ok, #file_info{type = regular}} ->
+ {ok,#file_info{type = regular}} = Mod:read_file_info(Dir),
+ ok = Mod:delete(Dir);
+ {ok, #file_info{type = symlink}} ->
+ ok = Mod:delete(Dir)
+ end.
+chk_cre_dir(_,[]) ->
+ ok;
+chk_cre_dir(Mod,[{regular,Name,Content}|T]) ->
+ %io:format("~p~n",[Name]),
+ ok = Mod:write_file(Name,Content),
+ chk_cre_dir(Mod,T);
+chk_cre_dir(Mod,[{link,Name,Target}|T]) ->
+ ok = Mod:make_link(Target,Name),
+ chk_cre_dir(Mod,T);
+chk_cre_dir(Mod,[{symlink,Name,Target}|T]) ->
+ ok = Mod:make_symlink(Target,Name),
+ chk_cre_dir(Mod,T);
+chk_cre_dir(Mod,[{directory,Name,Content}|T]) ->
+ ok = Mod:make_dir(Name),
+ %io:format("Content = ~p~n",[Content]),
+ Content2 = [{Ty,filename:join(Name,N),case Ty of link -> filename:join(Name,C); _ -> C end} || {Ty,N,C} <- Content ],
+ %io:format("Content2 = ~p~n",[Content2]),
+ chk_cre_dir(Mod,Content2),
+ chk_cre_dir(Mod,T).
+
+has_links() ->
+ case os:type() of
+ {win32,_} ->
+ case os:version() of
+ {N,NN,_} when (N > 5) andalso (NN >= 1) ->
+ true;
+ _ ->
+ false
+ end;
+ _ ->
+ true
+ end.
+
+make_normal_dir(Mod) ->
+ rm_rf(Mod,"normal_dir"),
+ Mod:make_dir("normal_dir"),
+ Mod:set_cwd("normal_dir"),
+ Mod:write_file("fil1","fil1"),
+ Mod:write_file("fil2","fil2"),
+ case has_links() of
+ true ->
+ Mod:make_link("fil2","fil3"),
+ Mod:make_symlink("fil2","fil4");
+ _ ->
+ ok
+ end,
+ Mod:make_dir("subdir"),
+ Mod:write_file(filename:join("subdir","subfil1"),"subfil1"),
+ ok.
+
+normal_dir() ->
+ [{regular,"fil1","fil1"},
+ {regular,"fil2","fil2"}] ++
+ case has_links() of
+ true ->
+ [{regular,"fil3","fil2"},
+ {symlink,"fil4","fil2"}];
+ false ->
+ []
+ end ++
+ [{directory,"subdir",
+ [{regular,"subfil1","subfil1"}]}].
+
+make_icky_dir(Mod) ->
+ rm_rf(Mod,"icky_dir"),
+ Icky=icky_dir(),
+ chk_cre_dir(Mod,[{directory,"icky_dir",linkify([],Icky)}]),
+ Mod:set_cwd("icky_dir"),
+ ok.
+
+linkify(_Passed,[]) ->
+ [];
+linkify(Passed,[{regular,Name,Content}|T]) ->
+ Regulars = [ {N,C} || {regular,N,C} <- Passed, N =/= Name ],
+ case lists:keysearch(Content,2,Regulars) of
+ {value, {Linkto, Content}} ->
+ [{link,Name,Linkto} | linkify(Passed,T)];
+ _ ->
+ [{regular,Name,Content} | linkify([{regular,Name,Content}|Passed],T)]
+ end;
+linkify(Passed,[{directory, Name, Content}|T]) ->
+ [{directory,Name, linkify(Content,Content)}|linkify(Passed,T)];
+linkify(Passed,[H|T]) ->
+ [H|linkify([H|Passed],T)].
+
+hopeless_darwin() ->
+ case {os:type(),os:version()} of
+ {{unix,darwin},{Major,_,_}} when Major < 9 ->
+ true;
+ _ ->
+ false
+ end.
+
+icky_dir() ->
+ [{regular,"fil1","fil1"},
+ {regular,"���2","���2"}] ++
+ case has_links() of
+ true ->
+ [{regular,"���3","���2"},
+ {symlink,"���4","���2"}];
+ false ->
+ []
+ end ++
+ [{regular,treat_icky(<<"���5">>),"���5"}] ++
+ case has_links() of
+ true ->
+ [{symlink,treat_icky(<<"���6">>),treat_icky(<<"���5">>)}];
+ false ->
+ []
+ end ++
+ [{directory,treat_icky(<<"���subdir2">>),
+ [{regular,treat_icky(<<"���subfil2">>),"���subfil12"},
+ {regular,"���subfil3","���subfil13"}]},
+ {directory,"���subdir",
+ [{regular,"���subfil1","���subfil1"}]}].
+
+make_very_icky_dir(Mod) ->
+ rm_rf(Mod,"very_icky_dir"),
+ Icky=very_icky_dir(),
+ chk_cre_dir(Mod,[{directory,"very_icky_dir",linkify([],Icky)}]),
+ Mod:set_cwd("very_icky_dir"),
+ ok.
+
+very_icky_dir() ->
+ [{regular,"fil1","fil1"},
+ {regular,[956,965,963,954,959,49],"���2"}] ++
+ case has_links() of
+ true ->
+ [{regular,[956,965,963,954,959,50],"���2"},
+ {symlink,[956,965,963,954,959,51],[956,965,963,954,959,49]}];
+ false ->
+ []
+ end ++
+ [{regular,treat_icky(<<"���5">>),"���5"}] ++
+ case has_links() of
+ true ->
+ [{symlink,treat_icky(<<"���6">>),treat_icky(<<"���5">>)}];
+ false ->
+ []
+ end ++
+ [{directory,treat_icky(<<"���subdir2">>),
+ [{regular,treat_icky(<<"���subfil2">>),"���subfil12"},
+ {regular,"���subfil3","���subfil13"}]},
+ {directory,[956,965,963,954,959]++"subdir1",
+ [{regular,[956,965,963,954,959]++"subfil1","���subfil1"}]}].
+
+%% Some OS'es simply do not allow non UTF8 filenames
+treat_icky(Bin) ->
+ case os:type() of
+ {unix,darwin} ->
+ binary_to_list(procentify(Bin));
+ {win32,_} ->
+ binary_to_list(Bin);
+ _ ->
+ Bin
+ end.
+
+% Handle windows having absolute soft link targets.
+fixlink({ok,Link}) ->
+ case os:type() of
+ {win32,_} ->
+ {ok,filename:basename(Link)};
+ _ ->
+ {ok,Link}
+ end;
+fixlink(X) ->
+ X.
+
+procentify(<<>>) ->
+ <<>>;
+procentify(<<X:8,Rst/binary>>) when X > 127 ->
+ T=procentify(Rst),
+ Y = list_to_binary([$%
+ | io_lib:format("~2.16B",[X])]),
+ <<Y/binary,T/binary>>;
+procentify(<<X:8,Rst/binary>>) ->
+ T=procentify(Rst),
+ <<X:8,T/binary>>.
+
+
+list([]) ->
+ [];
+list([{_,Name,_} | T]) ->
+ [Name | list(T)].
+
+
+get_data(FN,List) ->
+ case lists:keysearch(FN,2,List) of
+ {value,{regular,FN,C}} ->
+ C;
+ {value,{symlink,FN,NewFN}} ->
+ get_data(NewFN,List);
+ _->
+ []
+ end.
+
+
+convlist(L) ->
+ convlist(file:native_name_encoding(),L).
+convlist(latin1,[Bin|T]) when is_binary(Bin) ->
+ %erlang:display('Convert...'),
+ [binary_to_list(Bin)| convlist(latin1,T)];
+convlist(Any,[H|T]) ->
+ [H|convlist(Any,T)];
+convlist(_,[]) ->
+ [].
+
+conv(L) ->
+ NoUniMode = file:native_name_encoding() =:= latin1,
+ if
+ NoUniMode, is_binary(L) ->
+ binary_to_list(L);
+ true ->
+ L
+ end.
+
+
+rand_comp_decomp(Max) ->
+ N = random:uniform(Max),
+ L = [ rand_decomp() || _ <- lists:seq(1,N) ],
+ LC = [ A || {A,_} <- L],
+ LD = lists:flatten([B || {_,B} <- L]),
+ LB = unicode:characters_to_binary(LD,unicode,utf8),
+ {LC,LB}.
+
+rand_decomp() ->
+ BT = bigtup(),
+ SZ = tuple_size(BT),
+ element(random:uniform(SZ),BT).
+bigtup() ->
+ {{192,[65,768]},
+ {200,[69,768]},
+ {204,[73,768]},
+ {210,[79,768]},
+ {217,[85,768]},
+ {7808,[87,768]},
+ {7922,[89,768]},
+ {224,[97,768]},
+ {232,[101,768]},
+ {236,[105,768]},
+ {242,[111,768]},
+ {249,[117,768]},
+ {7809,[119,768]},
+ {7923,[121,768]},
+ {8173,[168,768]},
+ {7846,[65,770,768]},
+ {7872,[69,770,768]},
+ {7890,[79,770,768]},
+ {7847,[97,770,768]},
+ {7873,[101,770,768]},
+ {7891,[111,770,768]},
+ {7700,[69,772,768]},
+ {7760,[79,772,768]},
+ {7701,[101,772,768]},
+ {7761,[111,772,768]},
+ {7856,[65,774,768]},
+ {7857,[97,774,768]},
+ {475,[85,776,768]},
+ {476,[117,776,768]},
+ {8146,[953,776,768]},
+ {8162,[965,776,768]},
+ {8074,[913,837,787,768]},
+ {8090,[919,837,787,768]},
+ {8106,[937,837,787,768]},
+ {8066,[945,837,787,768]},
+ {8082,[951,837,787,768]},
+ {8098,[969,837,787,768]},
+ {7946,[913,787,768]},
+ {7962,[917,787,768]},
+ {7978,[919,787,768]},
+ {7994,[921,787,768]},
+ {8010,[927,787,768]},
+ {8042,[937,787,768]},
+ {7938,[945,787,768]},
+ {7954,[949,787,768]},
+ {7970,[951,787,768]},
+ {7986,[953,787,768]},
+ {8002,[959,787,768]},
+ {8018,[965,787,768]},
+ {8034,[969,787,768]},
+ {8075,[913,837,788,768]},
+ {8091,[919,837,788,768]},
+ {8107,[937,837,788,768]},
+ {8067,[945,837,788,768]},
+ {8083,[951,837,788,768]},
+ {8099,[969,837,788,768]},
+ {7947,[913,788,768]},
+ {7963,[917,788,768]},
+ {7979,[919,788,768]},
+ {7995,[921,788,768]},
+ {8011,[927,788,768]},
+ {8027,[933,788,768]},
+ {8043,[937,788,768]},
+ {7939,[945,788,768]},
+ {7955,[949,788,768]},
+ {7971,[951,788,768]},
+ {7987,[953,788,768]},
+ {8003,[959,788,768]},
+ {8019,[965,788,768]},
+ {8035,[969,788,768]},
+ {7900,[79,795,768]},
+ {7914,[85,795,768]},
+ {7901,[111,795,768]},
+ {7915,[117,795,768]},
+ {8114,[945,837,768]},
+ {8130,[951,837,768]},
+ {8178,[969,837,768]},
+ {8122,[913,768]},
+ {8136,[917,768]},
+ {8138,[919,768]},
+ {8154,[921,768]},
+ {8184,[927,768]},
+ {8170,[933,768]},
+ {8186,[937,768]},
+ {8048,[945,768]},
+ {8050,[949,768]},
+ {8052,[951,768]},
+ {8054,[953,768]},
+ {8056,[959,768]},
+ {8058,[965,768]},
+ {8060,[969,768]},
+ {8141,[8127,768]},
+ {8157,[8190,768]},
+ {193,[65,769]},
+ {262,[67,769]},
+ {201,[69,769]},
+ {500,[71,769]},
+ {205,[73,769]},
+ {7728,[75,769]},
+ {313,[76,769]},
+ {7742,[77,769]},
+ {323,[78,769]},
+ {211,[79,769]},
+ {7764,[80,769]},
+ {340,[82,769]},
+ {346,[83,769]},
+ {218,[85,769]},
+ {7810,[87,769]},
+ {221,[89,769]},
+ {377,[90,769]},
+ {225,[97,769]},
+ {263,[99,769]},
+ {233,[101,769]},
+ {501,[103,769]},
+ {237,[105,769]},
+ {7729,[107,769]},
+ {314,[108,769]},
+ {7743,[109,769]},
+ {324,[110,769]},
+ {243,[111,769]},
+ {7765,[112,769]},
+ {341,[114,769]},
+ {347,[115,769]},
+ {250,[117,769]},
+ {7811,[119,769]},
+ {253,[121,769]},
+ {378,[122,769]},
+ {8174,[168,769]},
+ {508,[198,769]},
+ {510,[216,769]},
+ {509,[230,769]},
+ {511,[248,769]},
+ {7844,[65,770,769]},
+ {7870,[69,770,769]},
+ {7888,[79,770,769]},
+ {7845,[97,770,769]},
+ {7871,[101,770,769]},
+ {7889,[111,770,769]},
+ {7756,[79,771,769]},
+ {7800,[85,771,769]},
+ {7757,[111,771,769]},
+ {7801,[117,771,769]},
+ {7702,[69,772,769]},
+ {7762,[79,772,769]},
+ {7703,[101,772,769]},
+ {7763,[111,772,769]},
+ {7854,[65,774,769]},
+ {7855,[97,774,769]},
+ {7726,[73,776,769]},
+ {471,[85,776,769]},
+ {7727,[105,776,769]},
+ {472,[117,776,769]},
+ {8147,[953,776,769]},
+ {8163,[965,776,769]},
+ {506,[65,778,769]},
+ {507,[97,778,769]},
+ {8076,[913,837,787,769]},
+ {8092,[919,837,787,769]},
+ {8108,[937,837,787,769]},
+ {8068,[945,837,787,769]},
+ {8084,[951,837,787,769]},
+ {8100,[969,837,787,769]},
+ {7948,[913,787,769]},
+ {7964,[917,787,769]},
+ {7980,[919,787,769]},
+ {7996,[921,787,769]},
+ {8012,[927,787,769]},
+ {8044,[937,787,769]},
+ {7940,[945,787,769]},
+ {7956,[949,787,769]},
+ {7972,[951,787,769]},
+ {7988,[953,787,769]},
+ {8004,[959,787,769]},
+ {8020,[965,787,769]},
+ {8036,[969,787,769]},
+ {8077,[913,837,788,769]},
+ {8093,[919,837,788,769]},
+ {8109,[937,837,788,769]},
+ {8069,[945,837,788,769]},
+ {8085,[951,837,788,769]},
+ {8101,[969,837,788,769]},
+ {7949,[913,788,769]},
+ {7965,[917,788,769]},
+ {7981,[919,788,769]},
+ {7997,[921,788,769]},
+ {8013,[927,788,769]},
+ {8029,[933,788,769]},
+ {8045,[937,788,769]},
+ {7941,[945,788,769]},
+ {7957,[949,788,769]},
+ {7973,[951,788,769]},
+ {7989,[953,788,769]},
+ {8005,[959,788,769]},
+ {8021,[965,788,769]},
+ {8037,[969,788,769]},
+ {7898,[79,795,769]},
+ {7912,[85,795,769]},
+ {7899,[111,795,769]},
+ {7913,[117,795,769]},
+ {7688,[67,807,769]},
+ {7689,[99,807,769]},
+ {8116,[945,837,769]},
+ {8132,[951,837,769]},
+ {8180,[959,837,769]},
+ {8123,[913,769]},
+ {8137,[917,769]},
+ {8139,[919,769]},
+ {8155,[921,769]},
+ {8185,[927,769]},
+ {8171,[933,769]},
+ {8187,[937,769]},
+ {8049,[945,769]},
+ {8051,[949,769]},
+ {8053,[951,769]},
+ {8055,[953,769]},
+ {8057,[959,769]},
+ {8059,[965,769]},
+ {8061,[969,769]},
+ {1027,[1043,769]},
+ {1036,[1050,769]},
+ {1107,[1075,769]},
+ {1116,[1082,769]},
+ {8142,[8127,769]},
+ {8158,[8190,769]},
+ {194,[65,770]},
+ {264,[67,770]},
+ {202,[69,770]},
+ {284,[71,770]},
+ {292,[72,770]},
+ {206,[73,770]},
+ {308,[74,770]},
+ {212,[79,770]},
+ {348,[83,770]},
+ {219,[85,770]},
+ {372,[87,770]},
+ {374,[89,770]},
+ {7824,[90,770]},
+ {226,[97,770]},
+ {265,[99,770]},
+ {234,[101,770]},
+ {285,[103,770]},
+ {293,[104,770]},
+ {238,[105,770]},
+ {309,[106,770]},
+ {244,[111,770]},
+ {349,[115,770]},
+ {251,[117,770]},
+ {373,[119,770]},
+ {375,[121,770]},
+ {7825,[122,770]},
+ {7852,[65,803,770]},
+ {7878,[69,803,770]},
+ {7896,[79,803,770]},
+ {7853,[97,803,770]},
+ {7879,[101,803,770]},
+ {7897,[111,803,770]},
+ {195,[65,771]},
+ {7868,[69,771]},
+ {296,[73,771]},
+ {209,[78,771]},
+ {213,[79,771]},
+ {360,[85,771]},
+ {7804,[86,771]},
+ {7928,[89,771]},
+ {227,[97,771]},
+ {7869,[101,771]},
+ {297,[105,771]},
+ {241,[110,771]},
+ {245,[111,771]},
+ {361,[117,771]},
+ {7805,[118,771]},
+ {7929,[121,771]},
+ {7850,[65,770,771]},
+ {7876,[69,770,771]},
+ {7894,[79,770,771]},
+ {7851,[97,770,771]},
+ {7877,[101,770,771]},
+ {7895,[111,770,771]},
+ {7860,[65,774,771]},
+ {7861,[97,774,771]},
+ {7904,[79,795,771]},
+ {7918,[85,795,771]},
+ {7905,[111,795,771]},
+ {7919,[117,795,771]},
+ {256,[65,772]},
+ {274,[69,772]},
+ {7712,[71,772]},
+ {298,[73,772]},
+ {332,[79,772]},
+ {362,[85,772]},
+ {257,[97,772]},
+ {275,[101,772]},
+ {7713,[103,772]},
+ {299,[105,772]},
+ {333,[111,772]},
+ {363,[117,772]},
+ {482,[198,772]},
+ {483,[230,772]},
+ {480,[65,775,772]},
+ {481,[97,775,772]},
+ {478,[65,776,772]},
+ {469,[85,776,772]},
+ {479,[97,776,772]},
+ {470,[117,776,772]},
+ {7736,[76,803,772]},
+ {7772,[82,803,772]},
+ {7737,[108,803,772]},
+ {7773,[114,803,772]},
+ {492,[79,808,772]},
+ {493,[111,808,772]},
+ {8121,[913,772]},
+ {8153,[921,772]},
+ {8169,[933,772]},
+ {8113,[945,772]},
+ {8145,[953,772]},
+ {8161,[965,772]},
+ {1250,[1048,772]},
+ {1262,[1059,772]},
+ {1251,[1080,772]},
+ {1263,[1091,772]},
+ {258,[65,774]},
+ {276,[69,774]},
+ {286,[71,774]},
+ {300,[73,774]},
+ {334,[79,774]},
+ {364,[85,774]},
+ {259,[97,774]},
+ {277,[101,774]},
+ {287,[103,774]},
+ {301,[105,774]},
+ {335,[111,774]},
+ {365,[117,774]},
+ {7862,[65,803,774]},
+ {7863,[97,803,774]},
+ {7708,[69,807,774]},
+ {7709,[101,807,774]},
+ {8120,[913,774]},
+ {8152,[921,774]},
+ {8168,[933,774]},
+ {8112,[945,774]},
+ {8144,[953,774]},
+ {8160,[965,774]},
+ {1232,[1040,774]},
+ {1238,[1045,774]},
+ {1217,[1046,774]},
+ {1049,[1048,774]},
+ {1038,[1059,774]},
+ {1233,[1072,774]},
+ {1239,[1077,774]},
+ {1218,[1078,774]},
+ {1081,[1080,774]},
+ {1118,[1091,774]},
+ {7682,[66,775]},
+ {266,[67,775]},
+ {7690,[68,775]},
+ {278,[69,775]},
+ {7710,[70,775]},
+ {288,[71,775]},
+ {7714,[72,775]},
+ {304,[73,775]},
+ {7744,[77,775]},
+ {7748,[78,775]},
+ {7766,[80,775]},
+ {7768,[82,775]},
+ {7776,[83,775]},
+ {7786,[84,775]},
+ {7814,[87,775]},
+ {7818,[88,775]},
+ {7822,[89,775]},
+ {379,[90,775]},
+ {7683,[98,775]},
+ {267,[99,775]},
+ {7691,[100,775]},
+ {279,[101,775]},
+ {7711,[102,775]},
+ {289,[103,775]},
+ {7715,[104,775]},
+ {7745,[109,775]},
+ {7749,[110,775]},
+ {7767,[112,775]},
+ {7769,[114,775]},
+ {7777,[115,775]},
+ {7787,[116,775]},
+ {7815,[119,775]},
+ {7819,[120,775]},
+ {7823,[121,775]},
+ {380,[122,775]},
+ {7835,[383,775]},
+ {7780,[83,769,775]},
+ {7781,[115,769,775]},
+ {784,[774,775]},
+ {7782,[83,780,775]},
+ {7783,[115,780,775]},
+ {7784,[83,803,775]},
+ {7785,[115,803,775]},
+ {196,[65,776]},
+ {203,[69,776]},
+ {7718,[72,776]},
+ {207,[73,776]},
+ {214,[79,776]},
+ {220,[85,776]},
+ {7812,[87,776]},
+ {7820,[88,776]},
+ {376,[89,776]},
+ {228,[97,776]},
+ {235,[101,776]},
+ {7719,[104,776]},
+ {239,[105,776]},
+ {246,[111,776]},
+ {7831,[116,776]},
+ {252,[117,776]},
+ {7813,[119,776]},
+ {7821,[120,776]},
+ {255,[121,776]},
+ {1242,[399,776]},
+ {1258,[415,776]},
+ {1243,[601,776]},
+ {1259,[629,776]},
+ {7758,[79,771,776]},
+ {7759,[111,771,776]},
+ {7802,[85,772,776]},
+ {7803,[117,772,776]},
+ {938,[921,776]},
+ {939,[933,776]},
+ {970,[953,776]},
+ {971,[965,776]},
+ {980,[978,776]},
+ {1031,[1030,776]},
+ {1234,[1040,776]},
+ {1025,[1045,776]},
+ {1244,[1046,776]},
+ {1246,[1047,776]},
+ {1252,[1048,776]},
+ {1254,[1054,776]},
+ {1264,[1059,776]},
+ {1268,[1063,776]},
+ {1272,[1067,776]},
+ {1235,[1072,776]},
+ {1105,[1077,776]},
+ {1245,[1078,776]},
+ {1247,[1079,776]},
+ {1253,[1080,776]},
+ {1255,[1086,776]},
+ {1265,[1091,776]},
+ {1269,[1095,776]},
+ {1273,[1099,776]},
+ {1111,[1110,776]},
+ {7842,[65,777]},
+ {7866,[69,777]},
+ {7880,[73,777]},
+ {7886,[79,777]},
+ {7910,[85,777]},
+ {7926,[89,777]},
+ {7843,[97,777]},
+ {7867,[101,777]},
+ {7881,[105,777]},
+ {7887,[111,777]},
+ {7911,[117,777]},
+ {7927,[121,777]},
+ {7848,[65,770,777]},
+ {7874,[69,770,777]},
+ {7892,[79,770,777]},
+ {7849,[97,770,777]},
+ {7875,[101,770,777]},
+ {7893,[111,770,777]},
+ {7858,[65,774,777]},
+ {7859,[97,774,777]},
+ {7902,[79,795,777]},
+ {7916,[85,795,777]},
+ {7903,[111,795,777]},
+ {7917,[117,795,777]},
+ {197,[65,778]},
+ {366,[85,778]},
+ {229,[97,778]},
+ {367,[117,778]},
+ {7832,[119,778]},
+ {7833,[121,778]},
+ {336,[79,779]},
+ {368,[85,779]},
+ {337,[111,779]},
+ {369,[117,779]},
+ {1266,[1059,779]},
+ {1267,[1091,779]},
+ {461,[65,780]},
+ {268,[67,780]},
+ {270,[68,780]},
+ {282,[69,780]},
+ {486,[71,780]},
+ {463,[73,780]},
+ {488,[75,780]},
+ {317,[76,780]},
+ {327,[78,780]},
+ {465,[79,780]},
+ {344,[82,780]},
+ {352,[83,780]},
+ {356,[84,780]},
+ {467,[85,780]},
+ {381,[90,780]},
+ {462,[97,780]},
+ {269,[99,780]},
+ {271,[100,780]},
+ {283,[101,780]},
+ {487,[103,780]},
+ {464,[105,780]},
+ {496,[106,780]},
+ {489,[107,780]},
+ {318,[108,780]},
+ {328,[110,780]},
+ {466,[111,780]},
+ {345,[114,780]},
+ {353,[115,780]},
+ {357,[116,780]},
+ {468,[117,780]},
+ {382,[122,780]},
+ {494,[439,780]},
+ {495,[658,780]},
+ {473,[85,776,780]},
+ {474,[117,776,780]},
+ {901,[168,781]},
+ {912,[953,776,781]},
+ {944,[965,776,781]},
+ {902,[913,781]},
+ {904,[917,781]},
+ {905,[919,781]},
+ {906,[921,781]},
+ {908,[927,781]},
+ {910,[933,781]},
+ {911,[937,781]},
+ {940,[945,781]},
+ {941,[949,781]},
+ {942,[951,781]},
+ {943,[953,781]},
+ {972,[959,781]},
+ {973,[965,781]},
+ {974,[969,781]},
+ {979,[978,781]},
+ {512,[65,783]},
+ {516,[69,783]},
+ {520,[73,783]},
+ {524,[79,783]},
+ {528,[82,783]},
+ {532,[85,783]},
+ {513,[97,783]},
+ {517,[101,783]},
+ {521,[105,783]},
+ {525,[111,783]},
+ {529,[114,783]},
+ {533,[117,783]},
+ {1142,[1140,783]},
+ {1143,[1141,783]},
+ {514,[65,785]},
+ {518,[69,785]},
+ {522,[73,785]},
+ {526,[79,785]},
+ {530,[82,785]},
+ {534,[85,785]},
+ {515,[97,785]},
+ {519,[101,785]},
+ {523,[105,785]},
+ {527,[111,785]},
+ {531,[114,785]},
+ {535,[117,785]},
+ {8072,[913,837,787]},
+ {8088,[919,837,787]},
+ {8104,[937,837,787]},
+ {8064,[945,837,787]},
+ {8080,[951,837,787]},
+ {8096,[969,837,787]},
+ {7944,[913,787]},
+ {7960,[917,787]},
+ {7976,[919,787]},
+ {7992,[921,787]},
+ {8008,[927,787]},
+ {8040,[937,787]},
+ {7936,[945,787]},
+ {7952,[949,787]},
+ {7968,[951,787]},
+ {7984,[953,787]},
+ {8000,[959,787]},
+ {8164,[961,787]},
+ {8016,[965,787]},
+ {8032,[969,787]},
+ {8073,[913,837,788]},
+ {8089,[919,837,788]},
+ {8105,[937,837,788]},
+ {8065,[945,837,788]},
+ {8081,[951,837,788]},
+ {8097,[969,837,788]},
+ {7945,[913,788]},
+ {7961,[917,788]},
+ {7977,[919,788]},
+ {7993,[921,788]},
+ {8009,[927,788]},
+ {8172,[929,788]},
+ {8025,[933,788]},
+ {8041,[937,788]},
+ {7937,[945,788]},
+ {7953,[949,788]},
+ {7969,[951,788]},
+ {7985,[953,788]},
+ {8001,[959,788]},
+ {8165,[961,788]},
+ {8017,[965,788]},
+ {8033,[969,788]},
+ {416,[79,795]},
+ {431,[85,795]},
+ {417,[111,795]},
+ {432,[117,795]},
+ {7840,[65,803]},
+ {7684,[66,803]},
+ {7692,[68,803]},
+ {7864,[69,803]},
+ {7716,[72,803]},
+ {7882,[73,803]},
+ {7730,[75,803]},
+ {7734,[76,803]},
+ {7746,[77,803]},
+ {7750,[78,803]},
+ {7884,[79,803]},
+ {7770,[82,803]},
+ {7778,[83,803]},
+ {7788,[84,803]},
+ {7908,[85,803]},
+ {7806,[86,803]},
+ {7816,[87,803]},
+ {7924,[89,803]},
+ {7826,[90,803]},
+ {7841,[97,803]},
+ {7685,[98,803]},
+ {7693,[100,803]},
+ {7865,[101,803]},
+ {7717,[104,803]},
+ {7883,[105,803]},
+ {7731,[107,803]},
+ {7735,[108,803]},
+ {7747,[109,803]},
+ {7751,[110,803]},
+ {7885,[111,803]},
+ {7771,[114,803]},
+ {7779,[115,803]},
+ {7789,[116,803]},
+ {7909,[117,803]},
+ {7807,[118,803]},
+ {7817,[119,803]},
+ {7925,[121,803]},
+ {7827,[122,803]},
+ {7906,[79,795,803]},
+ {7920,[85,795,803]},
+ {7907,[111,795,803]},
+ {7921,[117,795,803]},
+ {7794,[85,804]},
+ {7795,[117,804]},
+ {7680,[65,805]},
+ {7681,[97,805]},
+ {199,[67,807]},
+ {7696,[68,807]},
+ {290,[71,807]},
+ {7720,[72,807]},
+ {310,[75,807]},
+ {315,[76,807]},
+ {325,[78,807]},
+ {342,[82,807]},
+ {350,[83,807]},
+ {354,[84,807]},
+ {231,[99,807]},
+ {7697,[100,807]},
+ {291,[103,807]},
+ {7721,[104,807]},
+ {311,[107,807]},
+ {316,[108,807]},
+ {326,[110,807]},
+ {343,[114,807]},
+ {351,[115,807]},
+ {355,[116,807]},
+ {260,[65,808]},
+ {280,[69,808]},
+ {302,[73,808]},
+ {490,[79,808]},
+ {370,[85,808]},
+ {261,[97,808]},
+ {281,[101,808]},
+ {303,[105,808]},
+ {491,[111,808]},
+ {371,[117,808]},
+ {7698,[68,813]},
+ {7704,[69,813]},
+ {7740,[76,813]},
+ {7754,[78,813]},
+ {7792,[84,813]},
+ {7798,[85,813]},
+ {7699,[100,813]},
+ {7705,[101,813]},
+ {7741,[108,813]},
+ {7755,[110,813]},
+ {7793,[116,813]},
+ {7799,[117,813]},
+ {7722,[72,814]},
+ {7723,[104,814]},
+ {7706,[69,816]},
+ {7724,[73,816]},
+ {7796,[85,816]},
+ {7707,[101,816]},
+ {7725,[105,816]},
+ {7797,[117,816]},
+ {7686,[66,817]},
+ {7694,[68,817]},
+ {7732,[75,817]},
+ {7738,[76,817]},
+ {7752,[78,817]},
+ {7774,[82,817]},
+ {7790,[84,817]},
+ {7828,[90,817]},
+ {7687,[98,817]},
+ {7695,[100,817]},
+ {7830,[104,817]},
+ {7733,[107,817]},
+ {7739,[108,817]},
+ {7753,[110,817]},
+ {7775,[114,817]},
+ {7791,[116,817]},
+ {7829,[122,817]},
+ {8129,[168,834]},
+ {8151,[953,776,834]},
+ {8167,[965,776,834]},
+ {8078,[913,837,787,834]},
+ {8094,[919,837,787,834]},
+ {8110,[937,837,787,834]},
+ {8070,[945,837,787,834]},
+ {8086,[951,837,787,834]},
+ {8102,[969,837,787,834]},
+ {7950,[913,787,834]},
+ {7982,[919,787,834]},
+ {7998,[921,787,834]},
+ {8046,[937,787,834]},
+ {7942,[945,787,834]},
+ {7974,[951,787,834]},
+ {7990,[953,787,834]},
+ {8022,[965,787,834]},
+ {8038,[969,787,834]},
+ {8079,[913,837,788,834]},
+ {8095,[919,837,788,834]},
+ {8111,[937,837,788,834]},
+ {8071,[945,837,788,834]},
+ {8087,[951,837,788,834]},
+ {8103,[969,837,788,834]},
+ {7951,[913,788,834]},
+ {7983,[919,788,834]},
+ {7999,[921,788,834]},
+ {8031,[933,788,834]},
+ {8047,[937,788,834]},
+ {7943,[945,788,834]},
+ {7975,[951,788,834]},
+ {7991,[953,788,834]},
+ {8023,[965,788,834]},
+ {8039,[969,788,834]},
+ {8119,[945,837,834]},
+ {8135,[951,837,834]},
+ {8183,[969,837,834]},
+ {8118,[945,834]},
+ {8134,[951,834]},
+ {8150,[953,834]},
+ {8166,[965,834]},
+ {8182,[969,834]},
+ {8143,[8127,834]},
+ {8159,[8190,834]},
+ {8124,[913,837]},
+ {8140,[919,837]},
+ {8188,[937,837]},
+ {8115,[945,837]},
+ {8131,[951,837]},
+ {8179,[969,837]},
+ {64302,[1488,1463]},
+ {64287,[1522,1463]},
+ {64303,[1488,1464]},
+ {64331,[1493,1465]},
+ {64304,[1488,1468]},
+ {64305,[1489,1468]},
+ {64306,[1490,1468]},
+ {64307,[1491,1468]},
+ {64308,[1492,1468]},
+ {64309,[1493,1468]},
+ {64310,[1494,1468]},
+ {64312,[1496,1468]},
+ {64313,[1497,1468]},
+ {64314,[1498,1468]},
+ {64315,[1499,1468]},
+ {64316,[1500,1468]},
+ {64318,[1502,1468]},
+ {64320,[1504,1468]},
+ {64321,[1505,1468]},
+ {64323,[1507,1468]},
+ {64324,[1508,1468]},
+ {64326,[1510,1468]},
+ {64327,[1511,1468]},
+ {64328,[1512,1468]},
+ {64329,[1513,1468]},
+ {64330,[1514,1468]},
+ {64332,[1489,1471]},
+ {64333,[1499,1471]},
+ {64334,[1508,1471]},
+ {64300,[1513,1468,1473]},
+ {64298,[1513,1473]},
+ {64301,[1513,1468,1474]},
+ {64299,[1513,1474]},
+ {2392,[2325,2364]},
+ {2393,[2326,2364]},
+ {2394,[2327,2364]},
+ {2395,[2332,2364]},
+ {2396,[2337,2364]},
+ {2397,[2338,2364]},
+ {2345,[2344,2364]},
+ {2398,[2347,2364]},
+ {2399,[2351,2364]},
+ {2353,[2352,2364]},
+ {2356,[2355,2364]},
+ {2524,[2465,2492]},
+ {2525,[2466,2492]},
+ {2480,[2476,2492]},
+ {2527,[2479,2492]},
+ {2507,[2503,2494]},
+ {2508,[2503,2519]},
+ {2649,[2582,2620]},
+ {2650,[2583,2620]},
+ {2651,[2588,2620]},
+ {2652,[2593,2620]},
+ {2654,[2603,2620]},
+ {2908,[2849,2876]},
+ {2909,[2850,2876]},
+ {2911,[2863,2876]},
+ {2891,[2887,2878]},
+ {2888,[2887,2902]},
+ {2892,[2887,2903]},
+ {3018,[3014,3006]},
+ {3019,[3015,3006]},
+ {2964,[2962,3031]},
+ {3020,[3014,3031]},
+ {3144,[3142,3158]},
+ {3274,[3270,3266]},
+ {3264,[3263,3285]},
+ {3275,[3270,3266,3285]},
+ {3271,[3270,3285]},
+ {3272,[3270,3286]},
+ {3402,[3398,3390]},
+ {3403,[3399,3390]},
+ {3404,[3398,3415]},
+ {3635,[3661,3634]},
+ {3763,[3789,3762]},
+ {3955,[3954,3953]},
+ {3957,[3956,3953]},
+ {3959,[4018,3968,3953]},
+ {3961,[4019,3968,3953]},
+ {3958,[4018,3968]},
+ {3960,[4019,3968]},
+ {3945,[3904,4021]},
+ {4025,[3984,4021]},
+ {3907,[3906,4023]},
+ {3917,[3916,4023]},
+ {3922,[3921,4023]},
+ {3927,[3926,4023]},
+ {3932,[3931,4023]},
+ {3987,[3986,4023]},
+ {3997,[3996,4023]},
+ {4002,[4001,4023]},
+ {4007,[4006,4023]},
+ {4012,[4011,4023]},
+ {12436,[12358,12441]},
+ {12364,[12363,12441]},
+ {12366,[12365,12441]},
+ {12368,[12367,12441]},
+ {12370,[12369,12441]},
+ {12372,[12371,12441]},
+ {12374,[12373,12441]},
+ {12376,[12375,12441]},
+ {12378,[12377,12441]},
+ {12380,[12379,12441]},
+ {12382,[12381,12441]},
+ {12384,[12383,12441]},
+ {12386,[12385,12441]},
+ {12389,[12388,12441]},
+ {12391,[12390,12441]},
+ {12393,[12392,12441]},
+ {12400,[12399,12441]},
+ {12403,[12402,12441]},
+ {12406,[12405,12441]},
+ {12409,[12408,12441]},
+ {12412,[12411,12441]},
+ {12446,[12445,12441]},
+ {12532,[12454,12441]},
+ {12460,[12459,12441]},
+ {12462,[12461,12441]},
+ {12464,[12463,12441]},
+ {12466,[12465,12441]},
+ {12468,[12467,12441]},
+ {12470,[12469,12441]},
+ {12472,[12471,12441]},
+ {12474,[12473,12441]},
+ {12476,[12475,12441]},
+ {12478,[12477,12441]},
+ {12480,[12479,12441]},
+ {12482,[12481,12441]},
+ {12485,[12484,12441]},
+ {12487,[12486,12441]},
+ {12489,[12488,12441]},
+ {12496,[12495,12441]},
+ {12499,[12498,12441]},
+ {12502,[12501,12441]},
+ {12505,[12504,12441]},
+ {12508,[12507,12441]},
+ {12535,[12527,12441]},
+ {12536,[12528,12441]},
+ {12537,[12529,12441]},
+ {12538,[12530,12441]},
+ {12542,[12541,12441]},
+ {12401,[12399,12442]},
+ {12404,[12402,12442]},
+ {12407,[12405,12442]},
+ {12410,[12408,12442]},
+ {12413,[12411,12442]},
+ {12497,[12495,12442]},
+ {12500,[12498,12442]},
+ {12503,[12501,12442]},
+ {12506,[12504,12442]},
+ {12509,[12507,12442]}}.
diff --git a/lib/kernel/test/gen_sctp_SUITE.erl b/lib/kernel/test/gen_sctp_SUITE.erl
index fad8c7398b..9aa94a0868 100644
--- a/lib/kernel/test/gen_sctp_SUITE.erl
+++ b/lib/kernel/test/gen_sctp_SUITE.erl
@@ -23,12 +23,16 @@
%%-compile(export_all).
--export([all/1,init_per_testcase/2,fin_per_testcase/2,
- basic/1,api_open_close/1,api_listen/1,api_connect_init/1,
- xfer_min/1,xfer_active/1]).
+-export([all/1,init_per_testcase/2,fin_per_testcase/2]).
+-export(
+ [basic/1,
+ api_open_close/1,api_listen/1,api_connect_init/1,api_opts/1,
+ xfer_min/1,xfer_active/1,def_sndrcvinfo/1,implicit_inet6/1]).
all(suite) ->
- [basic,api_open_close,api_listen,api_connect_init,xfer_min,xfer_active].
+ [basic,
+ api_open_close,api_listen,api_connect_init,api_opts,
+ xfer_min,xfer_active,def_sndrcvinfo,implicit_inet6].
init_per_testcase(_Func, Config) ->
Dog = test_server:timetrap(test_server:seconds(15)),
@@ -39,6 +43,10 @@ fin_per_testcase(_Func, Config) ->
+-define(LOGVAR(Var), begin io:format(??Var" = ~p~n", [Var]) end).
+
+
+
basic(doc) ->
"Hello world";
basic(suite) ->
@@ -214,12 +222,17 @@ xfer_active(Config) when is_list(Config) ->
end,
?line ok = gen_sctp:close(Sb),
?line receive
- {sctp,Sa,Loopback,Pb,
- {[],
- #sctp_assoc_change{state=comm_lost,
- assoc_id=SaAssocId}}} -> ok
- after 17 -> ok %% On Solaris this does not arrive
- end,
+ {sctp,Sa,Loopback,Pb,
+ {[],
+ #sctp_assoc_change{state=comm_lost,
+ assoc_id=SaAssocId}}} -> ok
+ after Timeout ->
+ ?line test_server:fail({unexpected,flush()})
+ end,
+ ?line receive
+ {sctp_error,Sa,enotconn} -> ok % Solaris
+ after 17 -> ok %% Only happens on Solaris
+ end,
?line ok = gen_sctp:close(Sa),
%%
?line receive
@@ -228,6 +241,148 @@ xfer_active(Config) when is_list(Config) ->
end,
ok.
+def_sndrcvinfo(doc) ->
+ "Test that #sctp_sndrcvinfo{} parameters set on a socket "
+ "are used by gen_sctp:send/4";
+def_sndrcvinfo(suite) ->
+ [];
+def_sndrcvinfo(Config) when is_list(Config) ->
+ ?line Loopback = {127,0,0,1},
+ ?line Data = <<"What goes up, must come down.">>,
+ %%
+ ?line S1 =
+ ok(gen_sctp:open(
+ 0, [{sctp_default_send_param,#sctp_sndrcvinfo{ppid=17}}])),
+ ?LOGVAR(S1),
+ ?line P1 =
+ ok(inet:port(S1)),
+ ?LOGVAR(P1),
+ ?line #sctp_sndrcvinfo{ppid=17, context=0, timetolive=0, assoc_id=0} =
+ getopt(S1, sctp_default_send_param),
+ ?line ok =
+ gen_sctp:listen(S1, true),
+ %%
+ ?line S2 =
+ ok(gen_sctp:open()),
+ ?LOGVAR(S2),
+ ?line P2 =
+ ok(inet:port(S2)),
+ ?LOGVAR(P2),
+ ?line #sctp_sndrcvinfo{ppid=0, context=0, timetolive=0, assoc_id=0} =
+ getopt(S2, sctp_default_send_param),
+ %%
+ ?line #sctp_assoc_change{
+ state=comm_up,
+ error=0,
+ assoc_id=S2AssocId} = S2AssocChange =
+ ok(gen_sctp:connect(S2, Loopback, P1, [])),
+ ?LOGVAR(S2AssocChange),
+ ?line case ok(gen_sctp:recv(S1)) of
+ {Loopback, P2,[],
+ #sctp_assoc_change{
+ state=comm_up,
+ error=0,
+ assoc_id=S1AssocId}} ->
+ ?LOGVAR(S1AssocId)
+ end,
+ ?line #sctp_sndrcvinfo{
+ ppid=17, context=0, timetolive=0, assoc_id=S1AssocId} =
+ getopt(
+ S1, sctp_default_send_param, #sctp_sndrcvinfo{assoc_id=S1AssocId}),
+ ?line #sctp_sndrcvinfo{
+ ppid=0, context=0, timetolive=0, assoc_id=S2AssocId} =
+ getopt(
+ S2, sctp_default_send_param, #sctp_sndrcvinfo{assoc_id=S2AssocId}),
+ %%
+ ?line ok =
+ gen_sctp:send(S1, S1AssocId, 1, <<"1: ",Data/binary>>),
+ ?line case ok(gen_sctp:recv(S2)) of
+ {Loopback,P1,
+ [#sctp_sndrcvinfo{
+ stream=1, ppid=17, context=0, assoc_id=S2AssocId}],
+ <<"1: ",Data/binary>>} -> ok
+ end,
+ %%
+ ?line ok =
+ setopt(
+ S1, sctp_default_send_param, #sctp_sndrcvinfo{ppid=18}),
+ ?line ok =
+ setopt(
+ S1, sctp_default_send_param,
+ #sctp_sndrcvinfo{ppid=19, assoc_id=S1AssocId}),
+ ?line #sctp_sndrcvinfo{
+ ppid=18, context=0, timetolive=0, assoc_id=0} =
+ getopt(S1, sctp_default_send_param),
+ ?line #sctp_sndrcvinfo{
+ ppid=19, context=0, timetolive=0, assoc_id=S1AssocId} =
+ getopt(
+ S1, sctp_default_send_param, #sctp_sndrcvinfo{assoc_id=S1AssocId}),
+ %%
+ ?line ok =
+ gen_sctp:send(S1, S1AssocId, 0, <<"2: ",Data/binary>>),
+ ?line case ok(gen_sctp:recv(S2)) of
+ {Loopback,P1,
+ [#sctp_sndrcvinfo{
+ stream=0, ppid=19, context=0, assoc_id=S2AssocId}],
+ <<"2: ",Data/binary>>} -> ok
+ end,
+ ?line ok =
+ gen_sctp:send(S2, S2AssocChange, 1, <<"3: ",Data/binary>>),
+ ?line case ok(gen_sctp:recv(S1)) of
+ {Loopback,P2,
+ [#sctp_sndrcvinfo{
+ stream=1, ppid=0, context=0, assoc_id=S1AssocId}],
+ <<"3: ",Data/binary>>} -> ok;
+ {Loopback,P2,[],
+ #sctp_paddr_change{
+ addr={Loopback,_}, state=addr_available,
+ error=0, assoc_id=S1AssocId}} ->
+ ?line case ok(gen_sctp:recv(S1)) of
+ {Loopback,P2,
+ [#sctp_sndrcvinfo{
+ stream=1, ppid=0, context=0,
+ assoc_id=S1AssocId}],
+ <<"3: ",Data/binary>>} -> ok
+ end
+ end,
+ ?line ok =
+ gen_sctp:send(
+ S2,
+ #sctp_sndrcvinfo{stream=0, ppid=20, assoc_id=S2AssocId},
+ <<"4: ",Data/binary>>),
+ ?line case ok(gen_sctp:recv(S1)) of
+ {Loopback,P2,
+ [#sctp_sndrcvinfo{
+ stream=0, ppid=20, context=0, assoc_id=S1AssocId}],
+ <<"4: ",Data/binary>>} -> ok
+ end,
+ %%
+ ?line ok =
+ gen_sctp:close(S1),
+ ?line ok =
+ gen_sctp:close(S2),
+ ?line receive
+ Msg ->
+ test_server:fail({received,Msg})
+ after 17 -> ok
+ end,
+ ok.
+
+getopt(S, Opt) ->
+ {ok,[{Opt,Val}]} = inet:getopts(S, [Opt]),
+ Val.
+
+getopt(S, Opt, Param) ->
+ {ok,[{Opt,Val}]} = inet:getopts(S, [{Opt,Param}]),
+ Val.
+
+setopt(S, Opt, Val) ->
+ inet:setopts(S, [{Opt,Val}]).
+
+ok({ok,X}) ->
+ io:format("OK: ~p~n", [X]),
+ X.
+
flush() ->
receive
Msg ->
@@ -382,3 +537,72 @@ api_connect_init(Config) when is_list(Config) ->
?line ok = gen_sctp:close(Sa),
?line ok = gen_sctp:close(Sb),
ok.
+
+api_opts(doc) ->
+ "Test socket options";
+api_opts(suite) ->
+ [];
+api_opts(Config) when is_list(Config) ->
+ ?line {ok,S} = gen_sctp:open(0),
+ ?line OSType = os:type(),
+ ?line case {inet:setopts(S, [{linger,{true,2}}]),OSType} of
+ {ok,_} ->
+ ok;
+ {{error,einval},{unix,sunos}} ->
+ ok
+ end.
+
+implicit_inet6(Config) when is_list(Config) ->
+ ?line Hostname = ok(inet:gethostname()),
+ ?line
+ case gen_sctp:open(0, [inet6]) of
+ {ok,S1} ->
+ ?line
+ case inet:getaddr(Hostname, inet6) of
+ {ok,Host} ->
+ ?line Loopback = {0,0,0,0,0,0,0,1},
+ ?line io:format("~s ~p~n", ["Loopback",Loopback]),
+ ?line implicit_inet6(S1, Loopback),
+ ?line ok = gen_sctp:close(S1),
+ %%
+ ?line Localhost =
+ ok(inet:getaddr("localhost", inet6)),
+ ?line io:format("~s ~p~n", ["localhost",Localhost]),
+ ?line S2 =
+ ok(gen_sctp:open(0, [{ip,Localhost}])),
+ ?line implicit_inet6(S2, Localhost),
+ ?line ok = gen_sctp:close(S2),
+ %%
+ ?line io:format("~s ~p~n", [Hostname,Host]),
+ ?line S3 =
+ ok(gen_sctp:open(0, [{ifaddr,Host}])),
+ ?line implicit_inet6(S3, Host),
+ ?line ok = gen_sctp:close(S1);
+ {error,eafnosupport} ->
+ ?line ok = gen_sctp:close(S1),
+ {skip,"Can not look up IPv6 address"}
+ end;
+ _ ->
+ {skip,"IPv6 not supported"}
+ end.
+
+implicit_inet6(S1, Addr) ->
+ ?line ok = gen_sctp:listen(S1, true),
+ ?line P1 = ok(inet:port(S1)),
+ ?line S2 = ok(gen_sctp:open(0, [inet6])),
+ ?line P2 = ok(inet:port(S2)),
+ ?line #sctp_assoc_change{state=comm_up} =
+ ok(gen_sctp:connect(S2, Addr, P1, [])),
+ ?line case ok(gen_sctp:recv(S1)) of
+ {Addr,P2,[],#sctp_assoc_change{state=comm_up}} ->
+ ok
+ end,
+ ?line case ok(inet:sockname(S1)) of
+ {Addr,P1} -> ok;
+ {{0,0,0,0,0,0,0,0},P1} -> ok
+ end,
+ ?line case ok(inet:sockname(S2)) of
+ {Addr,P2} -> ok;
+ {{0,0,0,0,0,0,0,0},P2} -> ok
+ end,
+ ?line ok = gen_sctp:close(S2).
diff --git a/lib/kernel/test/gen_tcp_api_SUITE.erl b/lib/kernel/test/gen_tcp_api_SUITE.erl
index 11d19aaa82..94637290a1 100644
--- a/lib/kernel/test/gen_tcp_api_SUITE.erl
+++ b/lib/kernel/test/gen_tcp_api_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1998-2009. All Rights Reserved.
+%% Copyright Ericsson AB 1998-2010. 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
@@ -30,10 +30,11 @@
t_connect/1, t_connect_bad/1,
t_recv/1, t_recv_timeout/1, t_recv_eof/1,
t_shutdown_write/1, t_shutdown_both/1, t_shutdown_error/1,
- t_fdopen/1]).
+ t_fdopen/1, t_implicit_inet6/1]).
all(suite) -> [t_accept, t_connect, t_recv, t_shutdown_write,
- t_shutdown_both, t_shutdown_error, t_fdopen].
+ t_shutdown_both, t_shutdown_error, t_fdopen,
+ t_implicit_inet6].
init_per_testcase(_Func, Config) ->
Dog = test_server:timetrap(test_server:seconds(60)),
@@ -156,6 +157,54 @@ t_fdopen(Config) when is_list(Config) ->
ok.
+%%% implicit inet6 option to api functions
+
+t_implicit_inet6(Config) when is_list(Config) ->
+ ?line Hostname = ok(inet:gethostname()),
+ ?line
+ case gen_tcp:listen(0, [inet6]) of
+ {ok,S1} ->
+ ?line
+ case inet:getaddr(Hostname, inet6) of
+ {ok,Host} ->
+ ?line Loopback = {0,0,0,0,0,0,0,1},
+ ?line io:format("~s ~p~n", ["Loopback",Loopback]),
+ ?line implicit_inet6(S1, Loopback),
+ ?line ok = gen_tcp:close(S1),
+ %%
+ ?line Localhost =
+ ok(inet:getaddr("localhost", inet6)),
+ ?line io:format("~s ~p~n", ["localhost",Localhost]),
+ ?line S2 = ok(gen_tcp:listen(0, [{ip,Localhost}])),
+ ?line implicit_inet6(S2, Localhost),
+ ?line ok = gen_tcp:close(S2),
+ %%
+ ?line io:format("~s ~p~n", [Hostname,Host]),
+ ?line S3 = ok(gen_tcp:listen(0, [{ifaddr,Host}])),
+ ?line implicit_inet6(S3, Host),
+ ?line ok = gen_tcp:close(S1);
+ {error,eafnosupport} ->
+ ?line ok = gen_tcp:close(S1),
+ {skip,"Can not look up IPv6 address"}
+ end;
+ _ ->
+ {skip,"IPv6 not supported"}
+ end.
+
+implicit_inet6(S, Addr) ->
+ ?line P = ok(inet:port(S)),
+ ?line S2 = ok(gen_tcp:connect(Addr, P, [])),
+ ?line P2 = ok(inet:port(S2)),
+ ?line S1 = ok(gen_tcp:accept(S)),
+ ?line P1 = P = ok(inet:port(S1)),
+ ?line {Addr,P2} = ok(inet:peername(S1)),
+ ?line {Addr,P1} = ok(inet:peername(S2)),
+ ?line {Addr,P1} = ok(inet:sockname(S1)),
+ ?line {Addr,P2} = ok(inet:sockname(S2)),
+ ?line ok = gen_tcp:close(S2),
+ ?line ok = gen_tcp:close(S1).
+
+
%%% Utilities
@@ -217,3 +266,5 @@ unused_ip(A, B, C, D) ->
{ok, _} -> unused_ip(A, B, C, D+1);
{error, _} -> {ok, {A, B, C, D}}
end.
+
+ok({ok,V}) -> V.
diff --git a/lib/kernel/test/gen_tcp_misc_SUITE.erl b/lib/kernel/test/gen_tcp_misc_SUITE.erl
index 5d726a3b1b..d73c5fab56 100644
--- a/lib/kernel/test/gen_tcp_misc_SUITE.erl
+++ b/lib/kernel/test/gen_tcp_misc_SUITE.erl
@@ -1,19 +1,19 @@
%%
%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 1998-2009. All Rights Reserved.
-%%
+%%
+%% Copyright Ericsson AB 1998-2010. 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
%% compliance with the License. You should have received a copy of the
%% Erlang Public License along with this software. If not, it can be
%% retrieved online at http://www.erlang.org/.
-%%
+%%
%% Software distributed under the License is distributed on an "AS IS"
%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
%% the License for the specific language governing rights and limitations
%% under the License.
-%%
+%%
%% %CopyrightEnd%
%%
-module(gen_tcp_misc_SUITE).
@@ -957,12 +957,11 @@ http_bad_packet(Config) when is_list(Config) ->
http_worker(S) ->
case gen_tcp:recv(S, 0, 30000) of
+ {ok,{http_error,Error}} ->
+ io:format("Http error: ~s\n", [Error]);
{ok,Data} ->
io:format("Data: ~p\n", [Data]),
- http_worker(S);
- {error,Rsn} ->
- io:format("Error: ~p\n", [Rsn]),
- ok
+ http_worker(S)
end.
http_bad_client(Port) ->
diff --git a/lib/kernel/test/gen_udp_SUITE.erl b/lib/kernel/test/gen_udp_SUITE.erl
index bd5685952e..2ff1d7210a 100644
--- a/lib/kernel/test/gen_udp_SUITE.erl
+++ b/lib/kernel/test/gen_udp_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1998-2009. All Rights Reserved.
+%% Copyright Ericsson AB 1998-2010. 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
@@ -34,12 +34,12 @@
-export([send_to_closed/1,
buffer_size/1, binary_passive_recv/1, bad_address/1,
- read_packets/1, open_fd/1]).
+ read_packets/1, open_fd/1, connect/1, implicit_inet6/1]).
all(suite) ->
[send_to_closed,
buffer_size, binary_passive_recv, bad_address, read_packets,
- open_fd].
+ open_fd, connect, implicit_inet6].
init_per_testcase(_Case, Config) ->
?line Dog=test_server:timetrap(?default_timeout),
@@ -408,3 +408,78 @@ start_node(Name) ->
stop_node(Node) ->
?t:stop_node(Node).
+
+
+connect(suite) ->
+ [];
+connect(doc) ->
+ ["Test that connect/3 has effect"];
+connect(Config) when is_list(Config) ->
+ ?line Addr = {127,0,0,1},
+ ?line {ok,S1} = gen_udp:open(0),
+ ?line {ok,P1} = inet:port(S1),
+ ?line {ok,S2} = gen_udp:open(0),
+ ?line ok = inet:setopts(S2, [{active,false}]),
+ ?line ok = gen_udp:close(S1),
+ ?line ok = gen_udp:connect(S2, Addr, P1),
+ ?line ok = gen_udp:send(S2, <<16#deadbeef:32>>),
+ ?line ok = case gen_udp:recv(S2, 0, 5) of
+ {error,econnrefused} -> ok;
+ {error,econnreset} -> ok;
+ Other -> Other
+ end,
+ ok.
+
+implicit_inet6(Config) when is_list(Config) ->
+ ?line Hostname = ok(inet:gethostname()),
+ ?line Active = {active,false},
+ ?line
+ case gen_udp:open(0, [inet6,Active]) of
+ {ok,S1} ->
+ ?line
+ case inet:getaddr(Hostname, inet6) of
+ {ok,Host} ->
+ ?line Loopback = {0,0,0,0,0,0,0,1},
+ ?line io:format("~s ~p~n", ["Loopback",Loopback]),
+ ?line implicit_inet6(S1, Active, Loopback),
+ ?line ok = gen_udp:close(S1),
+ %%
+ ?line Localhost =
+ ok(inet:getaddr("localhost", inet6)),
+ ?line io:format("~s ~p~n", ["localhost",Localhost]),
+ ?line S2 =
+ ok(gen_udp:open(0, [{ip,Localhost},Active])),
+ ?line implicit_inet6(S2, Active, Localhost),
+ ?line ok = gen_udp:close(S2),
+ %%
+ ?line io:format("~s ~p~n", [Hostname,Host]),
+ ?line S3 =
+ ok(gen_udp:open(0, [{ifaddr,Host},Active])),
+ ?line implicit_inet6(S3, Active, Host),
+ ?line ok = gen_udp:close(S1);
+ {error,eafnosupport} ->
+ ?line ok = gen_udp:close(S1),
+ {skip,"Can not look up IPv6 address"}
+ end;
+ _ ->
+ {skip,"IPv6 not supported"}
+ end.
+
+implicit_inet6(S1, Active, Addr) ->
+ ?line P1 = ok(inet:port(S1)),
+ ?line S2 = ok(gen_udp:open(0, [inet6,Active])),
+ ?line P2 = ok(inet:port(S2)),
+ ?line ok = gen_udp:connect(S2, Addr, P1),
+ ?line ok = gen_udp:connect(S1, Addr, P2),
+ ?line {Addr,P2} = ok(inet:peername(S1)),
+ ?line {Addr,P1} = ok(inet:peername(S2)),
+ ?line {Addr,P1} = ok(inet:sockname(S1)),
+ ?line {Addr,P2} = ok(inet:sockname(S2)),
+ ?line ok = gen_udp:send(S1, Addr, P2, "ping"),
+ ?line {Addr,P1,"ping"} = ok(gen_udp:recv(S2, 1024, 1000)),
+ ?line ok = gen_udp:send(S2, Addr, P1, "pong"),
+ ?line {Addr,P2,"pong"} = ok(gen_udp:recv(S1, 1024)),
+ ?line ok = gen_udp:close(S2).
+
+
+ok({ok,V}) -> V.
diff --git a/lib/kernel/test/global_SUITE.erl b/lib/kernel/test/global_SUITE.erl
index a8c68985e2..7a84ad5e75 100644
--- a/lib/kernel/test/global_SUITE.erl
+++ b/lib/kernel/test/global_SUITE.erl
@@ -1,25 +1,23 @@
%%
%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 1997-2009. All Rights Reserved.
-%%
+%%
+%% Copyright Ericsson AB 1997-2010. 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
%% compliance with the License. You should have received a copy of the
%% Erlang Public License along with this software. If not, it can be
%% retrieved online at http://www.erlang.org/.
-%%
+%%
%% Software distributed under the License is distributed on an "AS IS"
%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
%% the License for the specific language governing rights and limitations
%% under the License.
-%%
+%%
%% %CopyrightEnd%
%%
-module(global_SUITE).
--compile(r11). % some code is run from r11-nodes
-
%-define(line_trace, 1).
-export([all/1,
@@ -2616,19 +2614,6 @@ proc(Parent) ->
name_exit(suite) -> [];
name_exit(doc) -> ["OTP-5563. Registered process dies."];
name_exit(Config) when is_list(Config) ->
- case ?t:is_release_available("r11b") of
- true ->
- StartOldFun =
- fun() ->
- {ok, N1} = start_node_rel(n_1, r11b, Config),
- {ok, N2} = start_node_rel(n_2, this, Config),
- [N1, N2]
- end,
- ?t:format("Test of r11~n"),
- do_name_exit(StartOldFun, old, Config);
- false ->
- ok
- end,
StartFun = fun() ->
{ok, N1} = start_node_rel(n_1, this, Config),
{ok, N2} = start_node_rel(n_2, this, Config),
@@ -2855,14 +2840,7 @@ many_nodes(Config) when is_list(Config) ->
N_nodes = quite_a_few_nodes(32),
{node_rel(1, N_nodes, this), N_nodes};
{unix, _} ->
- case ?t:is_release_available("r11b") of
- true ->
- This = node_rel(1, 16, this),
- R11B = node_rel(17, 32, r11b),
- {This ++ R11B, 32};
- false ->
- {node_rel(1, 32, this), 32}
- end;
+ {node_rel(1, 32, this), 32};
_ ->
{node_rel(1, 32, this), 32}
end,
@@ -3864,12 +3842,7 @@ start_node_rel(Name0, Rel, Config) ->
RelList ->
{RelList, ""}
end,
- Env = case Rel of
- r11b ->
- [{env, [{"ERL_R11B_FLAGS", []}]}];
- _ ->
- []
- end,
+ Env = [],
Pa = filename:dirname(code:which(?MODULE)),
Res = test_server:start_node(Name, peer,
[{args,
diff --git a/lib/kernel/test/inet_SUITE.erl b/lib/kernel/test/inet_SUITE.erl
index eb8f918491..ec05bf99b9 100644
--- a/lib/kernel/test/inet_SUITE.erl
+++ b/lib/kernel/test/inet_SUITE.erl
@@ -26,7 +26,8 @@
t_gethostbyaddr_v6/1, t_getaddr_v6/1, t_gethostbyname_v6/1,
ipv4_to_ipv6/1, host_and_addr/1, parse/1, t_gethostnative/1,
gethostnative_parallell/1, cname_loop/1,
- gethostnative_soft_restart/1,gethostnative_debug_level/1,getif/1]).
+ gethostnative_soft_restart/1,gethostnative_debug_level/1,getif/1,
+ getif_ifr_name_overflow/1,getservbyname_overflow/1,getifaddrs/1]).
-export([get_hosts/1, get_ipv6_hosts/1, parse_hosts/1, parse_address/1,
kill_gethost/0, parallell_gethost/0]).
@@ -39,7 +40,7 @@ all(suite) ->
ipv4_to_ipv6, host_and_addr, parse,t_gethostnative,
gethostnative_parallell, cname_loop,
gethostnative_debug_level,gethostnative_soft_restart,
- getif].
+ getif,getif_ifr_name_overflow,getservbyname_overflow,getifaddrs].
init_per_testcase(_Func, Config) ->
Dog = test_server:timetrap(test_server:seconds(60)),
@@ -872,10 +873,30 @@ getif(suite) ->
getif(doc) ->
["Tests basic functionality of getiflist, getif, and ifget"];
getif(Config) when is_list(Config) ->
+ ?line case os:type() of
+ {unix,Osname} ->
+ ?line do_getif(Osname);
+ {_,_} ->
+ {skip,"inet:getif/0 probably not supported"}
+ end.
+
+do_getif(Osname) ->
?line {ok,Hostname} = inet:gethostname(),
?line {ok,Address} = inet:getaddr(Hostname, inet),
?line {ok,Loopback} = inet:getaddr("localhost", inet),
?line {ok,Interfaces} = inet:getiflist(),
+ ?line HWAs =
+ lists:sort(
+ lists:foldl(
+ fun (I, Acc) ->
+ case inet:ifget(I, [hwaddr]) of
+ {ok,[{hwaddr,A}]} -> [A|Acc];
+ {ok,[]} -> Acc
+ end
+ end, [], Interfaces)),
+ ?line io:format("HWAs = ~p~n", [HWAs]),
+ ?line (Osname =/= sunos)
+ andalso ((length(HWAs) > 0) orelse (?t:fail(no_HWAs))),
?line Addresses =
lists:sort(
lists:foldl(
@@ -891,6 +912,134 @@ getif(Config) when is_list(Config) ->
?line true = ip_member(Loopback, Addresses),
?line ok.
+getif_ifr_name_overflow(doc) ->
+ "Test long interface names do not overrun buffer";
+getif_ifr_name_overflow(Config) when is_list(Config) ->
+ ?line case os:type() of
+ {unix,Osname} ->
+ ?line do_getif_ifr_name_overflow(Osname);
+ {_,_} ->
+ {skip,"inet:ifget/2 probably not supported"}
+ end.
+
+do_getif_ifr_name_overflow(_) ->
+ %% emulator should not crash
+ ?line {ok,[]} = inet:ifget(lists:duplicate(128, "x"), [addr]),
+ ok.
+
+getservbyname_overflow(doc) ->
+ "Test long service names do not overrun buffer";
+getservbyname_overflow(Config) when is_list(Config) ->
+ %% emulator should not crash
+ ?line {error,einval} = inet:getservbyname(list_to_atom(lists:flatten(lists:duplicate(128, "x"))), tcp),
+ ok.
+
+getifaddrs(doc) ->
+ "Test inet:gifaddrs/0";
+getifaddrs(Config) when is_list (Config) ->
+ ?line {ok,IfAddrs} = inet:getifaddrs(),
+ ?line ?t:format("IfAddrs = ~p.~n", [IfAddrs]),
+ ?line
+ case
+ {os:type(),
+ [If ||
+ {If,Opts} <- IfAddrs,
+ lists:keymember(hwaddr, 1, Opts)]} of
+ {{unix,sunos},[]} -> ok;
+ {OT,[]} ->
+ ?t:fail({should_have_hwaddr,OT});
+ _ -> ok
+ end,
+ ?line Addrs =
+ [element(1, A) || A <- ifaddrs(IfAddrs)],
+ ?line ?t:format("Addrs = ~p.~n", [Addrs]),
+ ?line [check_addr(Addr) || Addr <- Addrs],
+ ok.
+
+check_addr(Addr)
+ when tuple_size(Addr) =:= 8,
+ element(1, Addr) band 16#FFC0 =:= 16#FE80 ->
+ ?line ?t:format("Addr: ~p link local; SKIPPED!~n", [Addr]),
+ ok;
+check_addr(Addr) ->
+ ?line ?t:format("Addr: ~p.~n", [Addr]),
+ ?line Ping = "ping",
+ ?line Pong = "pong",
+ ?line {ok,L} = gen_tcp:listen(0, [{ip,Addr},{active,false}]),
+ ?line {ok,P} = inet:port(L),
+ ?line {ok,S1} = gen_tcp:connect(Addr, P, [{active,false}]),
+ ?line {ok,S2} = gen_tcp:accept(L),
+ ?line ok = gen_tcp:send(S2, Ping),
+ ?line {ok,Ping} = gen_tcp:recv(S1, length(Ping)),
+ ?line ok = gen_tcp:send(S1, Pong),
+ ?line ok = gen_tcp:close(S1),
+ ?line {ok,Pong} = gen_tcp:recv(S2, length(Pong)),
+ ?line ok = gen_tcp:close(S2),
+ ?line ok = gen_tcp:close(L),
+ ok.
+
+-record(ifopts, {name,flags,addrs=[],hwaddr}).
+
+ifaddrs([]) -> [];
+ifaddrs([{If,Opts}|IOs]) ->
+ ?line #ifopts{flags=Flags} = Ifopts =
+ check_ifopts(Opts, #ifopts{name=If}),
+ ?line case Flags =/= undefined andalso lists:member(up, Flags) of
+ true ->
+ Ifopts#ifopts.addrs;
+ false ->
+ []
+ end++ifaddrs(IOs).
+
+check_ifopts([], #ifopts{name=If,flags=Flags,addrs=Raddrs}=Ifopts) ->
+ Addrs = lists:reverse(Raddrs),
+ R = Ifopts#ifopts{addrs=Addrs},
+ ?t:format("~p.~n", [R]),
+ %% See how we did...
+ if is_list(Flags) -> ok;
+ true ->
+ ?t:fail({flags_undefined,If})
+ end,
+ case lists:member(broadcast, Flags) of
+ true ->
+ [case A of
+ {_,_,_} -> A;
+ {T,_} when tuple_size(T) =:= 8 -> A;
+ _ ->
+ ?t:fail({broaddr_missing,If,A})
+ end || A <- Addrs];
+ false ->
+ [case A of {_,_} -> A;
+ _ ->
+ ?t:fail({should_have_netmask,If,A})
+ end || A <- Addrs]
+ end,
+ R;
+check_ifopts([{flags,Flags}|Opts], #ifopts{flags=undefined}=Ifopts) ->
+ check_ifopts(Opts, Ifopts#ifopts{flags=Flags});
+check_ifopts([{flags,Fs}|Opts], #ifopts{flags=Flags}=Ifopts) ->
+ case Fs of
+ Flags ->
+ check_ifopts(Opts, Ifopts#ifopts{});
+ _ ->
+ ?t:fail({multiple_flags,Fs,Ifopts})
+ end;
+check_ifopts(
+ [{addr,Addr},{netmask,Netmask},{broadaddr,Broadaddr}|Opts],
+ #ifopts{addrs=Addrs}=Ifopts) ->
+ check_ifopts(Opts, Ifopts#ifopts{addrs=[{Addr,Netmask,Broadaddr}|Addrs]});
+check_ifopts(
+ [{addr,Addr},{netmask,Netmask}|Opts],
+ #ifopts{addrs=Addrs}=Ifopts) ->
+ check_ifopts(Opts, Ifopts#ifopts{addrs=[{Addr,Netmask}|Addrs]});
+check_ifopts([{addr,Addr}|Opts], #ifopts{addrs=Addrs}=Ifopts) ->
+ check_ifopts(Opts, Ifopts#ifopts{addrs=[{Addr}|Addrs]});
+check_ifopts([{hwaddr,Hwaddr}|Opts], #ifopts{hwaddr=undefined}=Ifopts)
+ when is_list(Hwaddr) ->
+ check_ifopts(Opts, Ifopts#ifopts{hwaddr=Hwaddr});
+check_ifopts([{hwaddr,HwAddr}|_], #ifopts{}=Ifopts) ->
+ ?t:fail({multiple_hwaddrs,HwAddr,Ifopts}).
+
%% Works just like lists:member/2, except that any {127,_,_,_} tuple
%% matches any other {127,_,_,_}. We do this to handle Linux systems
%% that use (for instance) 127.0.1.1 as the IP address for the hostname.
diff --git a/lib/kernel/test/inet_sockopt_SUITE_data/sockopt_helper.c b/lib/kernel/test/inet_sockopt_SUITE_data/sockopt_helper.c
index fb3c622909..f24c93edf5 100644
--- a/lib/kernel/test/inet_sockopt_SUITE_data/sockopt_helper.c
+++ b/lib/kernel/test/inet_sockopt_SUITE_data/sockopt_helper.c
@@ -1,4 +1,4 @@
-#if defined(VXWORKS) || defined(__OSE__)
+#if defined(VXWORKS)
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
diff --git a/lib/kernel/test/os_SUITE.erl b/lib/kernel/test/os_SUITE.erl
index 6a3534b094..eacf3c7584 100644
--- a/lib/kernel/test/os_SUITE.erl
+++ b/lib/kernel/test/os_SUITE.erl
@@ -137,6 +137,13 @@ find_executable(Config) when is_list(Config) ->
?line find_exe(Abin, "my_ar", ".exe", Path),
?line find_exe(Abin, "my_ascii", ".com", Path),
?line find_exe(Abin, "my_adb", ".bat", Path),
+ %% OTP-3626 find names of executables given with extension
+ ?line find_exe(Abin, "my_ar.exe", "", Path),
+ ?line find_exe(Abin, "my_ascii.com", "", Path),
+ ?line find_exe(Abin, "my_adb.bat", "", Path),
+ ?line find_exe(Abin, "my_ar.EXE", "", Path),
+ ?line find_exe(Abin, "my_ascii.COM", "", Path),
+ ?line find_exe(Abin, "MY_ADB.BAT", "", Path),
%% Search for programs in Abin (second element in PATH).
?line find_exe(Abin, "my_ar", ".exe", Path),
@@ -197,8 +204,9 @@ evil(Config) when is_list(Config) ->
evil_loop(Parent, ?EVIL_LOOPS,N)
end)
end, lists:seq(1, ?EVIL_PROCS)),
- Devil = spawn(fun () -> devil(hd(Ps), hd(lists:reverse(Ps))) end),
+ Devil = spawn_link(fun () -> devil(hd(Ps), hd(lists:reverse(Ps))) end),
lists:foreach(fun (P) -> receive {P, done} -> ok end end, Ps),
+ unlink(Devil),
exit(Devil, kill),
test_server:timetrap_cancel(Dog),
ok.
diff --git a/lib/kernel/test/pg2_SUITE.erl b/lib/kernel/test/pg2_SUITE.erl
index 8eb1a7ca19..df28dcf447 100644
--- a/lib/kernel/test/pg2_SUITE.erl
+++ b/lib/kernel/test/pg2_SUITE.erl
@@ -1,19 +1,19 @@
%%
%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 2008-2009. All Rights Reserved.
-%%
+%%
+%% Copyright Ericsson AB 2008-2010. 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
%% compliance with the License. You should have received a copy of the
%% Erlang Public License along with this software. If not, it can be
%% retrieved online at http://www.erlang.org/.
-%%
+%%
%% Software distributed under the License is distributed on an "AS IS"
%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
%% the License for the specific language governing rights and limitations
%% under the License.
-%%
+%%
%% %CopyrightEnd%
%%----------------------------------------------------------------
%% Purpose:Test Suite for the 'pg2' module.
@@ -26,8 +26,8 @@
-export([all/1, init_per_testcase/2, fin_per_testcase/2]).
--export([tickets/1,
- otp_7277/1, otp_8259/1,
+-export([tickets/1,
+ otp_7277/1, otp_8259/1, otp_8653/1,
compat/1, basic/1]).
% Default timetrap timeout (set in init_per_testcase).
@@ -37,7 +37,8 @@
-define(testcase, ?config(?TESTCASE, Config)).
%% Internal export.
--export([mk_part_node/3, part1/5, p_init/3, start_proc/1, sane/0]).
+-export([mk_part_node_and_group/3, part2/4,
+ mk_part_node/3, part1/5, p_init/3, start_proc/1, sane/0]).
init_per_testcase(Case, Config) ->
?line Dog = ?t:timetrap(?default_timeout),
@@ -48,11 +49,11 @@ fin_per_testcase(_Case, _Config) ->
test_server:timetrap_cancel(Dog),
ok.
-all(suite) ->
+all(suite) ->
[tickets].
tickets(suite) ->
- [otp_7277, otp_8259, compat, basic].
+ [otp_7277, otp_8259, otp_8653, compat, basic].
otp_7277(doc) ->
"OTP-7277. Bugfix leave().";
@@ -65,9 +66,9 @@ otp_7277(Config) when is_list(Config) ->
?line ok = pg2:leave(b, P),
?line true = exit(P, kill),
case {pg2:get_members(a), pg2:get_local_members(a)} of
- {[], []} ->
+ {[], []} ->
ok;
- _ ->
+ _ ->
timer:sleep(100),
?line [] = pg2:get_members(a),
?line [] = pg2:get_local_members(a)
@@ -79,6 +80,63 @@ otp_7277(Config) when is_list(Config) ->
-define(UNTIL(Seq), loop_until_true(fun() -> Seq end, Config)).
-define(UNTIL_LOOP, 300).
+otp_8653(suite) -> [];
+otp_8653(doc) ->
+ ["OTP-8259. Member was not removed after being killed."];
+otp_8653(Config) when is_list(Config) ->
+ Timeout = 15,
+ ?line Dog = test_server:timetrap({seconds,Timeout}),
+
+ ?line [A, B, C] = start_nodes([a, b, c], peer, Config),
+
+ ?line wait_for_ready_net(Config),
+
+ % make b and c connected, partitioned from node() and a
+ ?line rpc_cast(B, ?MODULE, part2, [Config, node(), A, C]),
+ ?line ?UNTIL(is_ready_partition(Config)),
+
+ % Connect to the other partition.
+ ?line pong = net_adm:ping(B),
+ timer:sleep(100),
+ ?line pong = net_adm:ping(C),
+ ?line _ = global:sync(),
+ ?line [A, B, C] = lists:sort(nodes()),
+
+ G = pg2_otp_8653,
+ ?line ?UNTIL(begin
+ GA = lists:sort(rpc:call(A, pg2, get_members, [G])),
+ GB = lists:sort(rpc:call(B, pg2, get_members, [G])),
+ GC = lists:sort(rpc:call(C, pg2, get_members, [G])),
+ GT = lists:sort(pg2:get_members(G)),
+ GA =:= GB andalso
+ GB =:= GC andalso
+ GC =:= GT andalso
+ 8 =:= length(GA)
+ end),
+ ?line ok = pg2:delete(G),
+ ?line stop_nodes([A,B,C]),
+ ?line test_server:timetrap_cancel(Dog),
+ ok.
+
+part2(Config, Main, A, C) ->
+ Function = mk_part_node_and_group,
+ case catch begin
+ make_partition(Config, [Main, A], [node(), C], Function)
+ end
+ of
+ ok -> ok
+ end.
+
+mk_part_node_and_group(File, MyPart0, Config) ->
+ touch(File, "start"), % debug
+ MyPart = lists:sort(MyPart0),
+ ?UNTIL(is_node_in_part(File, MyPart)),
+ G = pg2_otp_8653,
+ Pid = spawn(forever()),
+ ok = pg2:create(G),
+ _ = [ok = pg2:join(G, Pid) || _ <- [1,1]],
+ touch(File, "done").
+
otp_8259(suite) -> [];
otp_8259(doc) ->
["OTP-8259. Member was not removed after being killed."];
@@ -102,7 +160,7 @@ otp_8259(Config) when is_list(Config) ->
% make b and c connected, partitioned from node() and a
?line rpc_cast(B, ?MODULE, part1, [Config, node(), A, C, Name]),
?line ?UNTIL(is_ready_partition(Config)),
-
+
% Connect to the other partition.
% The resolver on node b will be called.
?line pong = net_adm:ping(B),
@@ -140,9 +198,9 @@ start_proc(Name) ->
p_init(Parent, Name, TestServer) ->
Resolve = fun(_Name, Pid1, Pid2) ->
%% The pid on node a will be chosen.
- [{_,Min}, {_,Max}] =
+ [{_,Min}, {_,Max}] =
lists:sort([{node(Pid1),Pid1}, {node(Pid2),Pid2}]),
- %% b is connected to test_server.
+ %% b is connected to test_server.
%% exit(Min, kill), % would ping a
rpc:cast(TestServer, erlang, exit, [Min, kill]),
Max
@@ -165,7 +223,7 @@ compat(Config) when is_list(Config) ->
true ->
Timeout = 15,
?line Dog = test_server:timetrap({seconds,Timeout}),
- Pid = spawn(forever()),
+ Pid = spawn(forever()),
G = a,
?line ok = pg2:create(G),
?line ok = pg2:join(G, Pid),
@@ -365,7 +423,7 @@ killit(N, P, Ps, Ns) ->
timer:sleep(100),
sane(Ns),
lists:keydelete(P, 1, Ps).
-
+
pr(Node, C) ->
_ = [?t:format("~p: ", [Node]) || Node =/= node()],
?t:format("do ~p~n", [C]).
@@ -412,27 +470,27 @@ sane(Ns) ->
wsane(Ns) ->
%% Same members on all nodes:
- {[_],gs} =
+ {[_],gs} =
{lists:usort([rpc:call(N, pg2, which_groups, []) || N <- Ns]),gs},
- _ = [{[_],ms,G} = {lists:usort([rpc:call(N, pg2, get_members, [G]) ||
+ _ = [{[_],ms,G} = {lists:usort([rpc:call(N, pg2, get_members, [G]) ||
N <- Ns]),ms,G} ||
G <- pg2:which_groups()],
%% The local members are a partitioning of the members:
- [begin
- LocalMembers =
+ [begin
+ LocalMembers =
lists:sort(lists:append(
- [rpc:call(N, pg2, get_local_members, [G]) ||
+ [rpc:call(N, pg2, get_local_members, [G]) ||
N <- Ns])),
{part, LocalMembers} = {part, lists:sort(pg2:get_members(G))}
end || G <- pg2:which_groups()],
%% The closest pid should run on the local node, if possible.
[[case rpc:call(N, pg2, get_closest_pid, [G]) of
Pid when is_pid(Pid), node(Pid) =:= N ->
- true =
+ true =
lists:member(Pid, rpc:call(N, pg2, get_local_members, [G]));
%% FIXME. Om annan nod: member, local = [].
_ -> [] = rpc:call(N, pg2, get_local_members, [G])
- end || N <- Ns]
+ end || N <- Ns]
|| G <- pg2:which_groups()].
%% Look inside the pg2_table.
@@ -482,9 +540,9 @@ start_node_rel(Name, Rel, How) ->
{RelList, ""}
end,
?line Pa = filename:dirname(code:which(?MODULE)),
- ?line Res = test_server:start_node(Name, How,
+ ?line Res = test_server:start_node(Name, How,
[{args,
- Compat ++
+ Compat ++
" -kernel net_setuptime 100 "
" -pa " ++ Pa},
{erl, Release}]),
@@ -575,29 +633,30 @@ get_known(Node) ->
case catch gen_server:call({global_name_server,Node},get_known,infinity) of
{'EXIT', _} ->
[list, without, nodenames];
- Known when is_list(Known) ->
+ Known when is_list(Known) ->
lists:sort([Node | Known])
end.
node_name(Name, Config) ->
U = "_",
{{Y,M,D}, {H,Min,S}} = calendar:now_to_local_time(now()),
- Date = io_lib:format("~4w_~2..0w_~2..0w__~2..0w_~2..0w_~2..0w",
+ Date = io_lib:format("~4w_~2..0w_~2..0w__~2..0w_~2..0w_~2..0w",
[Y,M,D, H,Min,S]),
L = lists:flatten(Date),
lists:concat([Name,U,?testcase,U,U,L]).
-%% this one runs on one node in Part2
-%% The partition is ready when is_ready_partition(Config) returns (true).
-%% this one runs on one node in Part2
+%% This one runs on one node in Part2.
%% The partition is ready when is_ready_partition(Config) returns (true).
make_partition(Config, Part1, Part2) ->
+ make_partition(Config, Part1, Part2, mk_part_node).
+
+make_partition(Config, Part1, Part2, Function) ->
Dir = ?config(priv_dir, Config),
- Ns = [begin
+ Ns = [begin
Name = lists:concat([atom_to_list(N),"_",msec(),".part"]),
File = filename:join([Dir, Name]),
file:delete(File),
- rpc_cast(N, ?MODULE, mk_part_node, [File, Part, Config], File),
+ rpc_cast(N, ?MODULE, Function, [File, Part, Config], File),
{N, File}
end || Part <- [Part1, Part2], N <- Part],
all_nodes_files(Ns, "done", Config),
@@ -614,10 +673,10 @@ mk_part_node(File, MyPart0, Config) ->
%% The calls to append_to_file are for debugging.
is_node_in_part(File, MyPart) ->
- lists:foreach(fun(N) ->
+ lists:foreach(fun(N) ->
_ = erlang:disconnect_node(N)
end, nodes() -- MyPart),
- case {(Known = get_known(node())) =:= MyPart,
+ case {(Known = get_known(node())) =:= MyPart,
(Nodes = lists:sort([node() | nodes()])) =:= MyPart} of
{true, true} ->
%% Make sure the resolvers have been terminated,
@@ -649,7 +708,7 @@ wait_for_ready_net(Nodes0, Config) ->
?t:format("wait_for_ready_net ~p~n", [Nodes]),
?UNTIL(begin
lists:all(fun(N) -> Nodes =:= get_known(N) end, Nodes) and
- lists:all(fun(N) ->
+ lists:all(fun(N) ->
LNs = rpc:call(N, erlang, nodes, []),
Nodes =:= lists:sort([N | LNs])
end, Nodes)
@@ -688,11 +747,11 @@ file_contents(File, ContentsList, Config) ->
file_contents(File, ContentsList, Config, no_log_file).
file_contents(File, ContentsList, Config, LogFile) ->
- Contents = list_to_binary(ContentsList),
+ Contents = list_to_binary(ContentsList),
Sz = size(Contents),
?UNTIL(begin
case file:read_file(File) of
- {ok, FileContents}=Reply ->
+ {ok, FileContents}=Reply ->
case catch split_binary(FileContents, Sz) of
{Contents,_} ->
true;
diff --git a/lib/kernel/test/prim_file_SUITE.erl b/lib/kernel/test/prim_file_SUITE.erl
index 860aeecbf4..1688ec45ca 100644
--- a/lib/kernel/test/prim_file_SUITE.erl
+++ b/lib/kernel/test/prim_file_SUITE.erl
@@ -1,19 +1,19 @@
%%
%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 2000-2009. All Rights Reserved.
-%%
+%%
+%% Copyright Ericsson AB 2000-2010. 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
%% compliance with the License. You should have received a copy of the
%% Erlang Public License along with this software. If not, it can be
%% retrieved online at http://www.erlang.org/.
-%%
+%%
%% Software distributed under the License is distributed on an "AS IS"
%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
%% the License for the specific language governing rights and limitations
%% under the License.
-%%
+%%
%% %CopyrightEnd%
%%
-module(prim_file_SUITE).
@@ -34,8 +34,8 @@
file_info_times_a/1, file_info_times_b/1,
file_write_file_info_a/1, file_write_file_info_b/1]).
-export([rename_a/1, rename_b/1,
- access/1, truncate/1, sync/1,
- read_write/1, pread_write/1, append/1]).
+ access/1, truncate/1, datasync/1, sync/1,
+ read_write/1, pread_write/1, append/1, exclusive/1]).
-export([errors/1, e_delete/1, e_rename/1, e_make_dir/1, e_del_dir/1]).
-export([compression/1, read_not_really_compressed/1,
@@ -48,6 +48,8 @@
symlinks_a/1, symlinks_b/1,
list_dir_limit/1]).
+-export([advise/1]).
+
-include("test_server.hrl").
-include_lib("kernel/include/file.hrl").
@@ -243,7 +245,10 @@ make_del_dir(Config, Handle, Suffix) ->
%% Try deleting some bad directories
%% Deleting the parent directory to the current, sounds dangerous, huh?
%% Don't worry ;-) the parent directory should never be empty, right?
- ?line {error, eexist} = ?PRIM_FILE_call(del_dir, Handle, [".."]),
+ case ?PRIM_FILE_call(del_dir, Handle, [".."]) of
+ {error, eexist} -> ok;
+ {error, einval} -> ok %FreeBSD
+ end,
?line {error, enoent} = ?PRIM_FILE_call(del_dir, Handle, [""]),
?line {error, badarg} = ?PRIM_FILE_call(del_dir, Handle, [[3,2,1,{}]]),
@@ -377,10 +382,10 @@ win_cur_dir_1(_Config, Handle) ->
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-files(suite) -> [open,pos,file_info,truncate,sync].
+files(suite) -> [open,pos,file_info,truncate,sync,datasync,advise].
open(suite) -> [open1,modes,close,access,read_write,
- pread_write,append].
+ pread_write,append,exclusive].
open1(suite) -> [];
open1(doc) -> [];
@@ -605,6 +610,22 @@ append(Config) when is_list(Config) ->
?line test_server:timetrap_cancel(Dog),
ok.
+exclusive(suite) -> [];
+exclusive(doc) -> "Test exclusive access to a file.";
+exclusive(Config) when is_list(Config) ->
+ ?line Dog = test_server:timetrap(test_server:seconds(5)),
+ ?line RootDir = ?config(priv_dir,Config),
+ ?line NewDir = filename:join(RootDir,
+ atom_to_list(?MODULE)
+ ++"_exclusive"),
+ ?line ok = ?PRIM_FILE:make_dir(NewDir),
+ ?line Name = filename:join(NewDir, "ex_file.txt"),
+ ?line {ok,Fd} = ?PRIM_FILE:open(Name, [write, exclusive]),
+ ?line {error, eexist} = ?PRIM_FILE:open(Name, [write, exclusive]),
+ ?line ok = ?PRIM_FILE:close(Fd),
+ ?line test_server:timetrap_cancel(Dog),
+ ok.
+
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
pos(suite) -> [pos1,pos2].
@@ -1061,6 +1082,24 @@ truncate(Config) when is_list(Config) ->
ok.
+datasync(suite) -> [];
+datasync(doc) -> "Tests that ?PRIM_FILE:datasync/1 at least doesn't crash.";
+datasync(Config) when is_list(Config) ->
+ ?line Dog = test_server:timetrap(test_server:seconds(5)),
+ ?line PrivDir = ?config(priv_dir, Config),
+ ?line Sync = filename:join(PrivDir,
+ atom_to_list(?MODULE)
+ ++"_sync.fil"),
+
+ %% Raw open.
+ ?line {ok, Fd} = ?PRIM_FILE:open(Sync, [write]),
+ ?line ok = ?PRIM_FILE:datasync(Fd),
+ ?line ok = ?PRIM_FILE:close(Fd),
+
+ ?line test_server:timetrap_cancel(Dog),
+ ok.
+
+
sync(suite) -> [];
sync(doc) -> "Tests that ?PRIM_FILE:sync/1 at least doesn't crash.";
sync(Config) when is_list(Config) ->
@@ -1079,6 +1118,77 @@ sync(Config) when is_list(Config) ->
ok.
+advise(suite) -> [];
+advise(doc) -> "Tests that ?PRIM_FILE:advise/4 at least doesn't crash.";
+advise(Config) when is_list(Config) ->
+ ?line Dog = test_server:timetrap(test_server:seconds(5)),
+ ?line PrivDir = ?config(priv_dir, Config),
+ ?line Advise = filename:join(PrivDir,
+ atom_to_list(?MODULE)
+ ++"_advise.fil"),
+
+ Line1 = "Hello\n",
+ Line2 = "World!\n",
+
+ ?line {ok, Fd} = ?PRIM_FILE:open(Advise, [write]),
+ ?line ok = ?PRIM_FILE:advise(Fd, 0, 0, normal),
+ ?line ok = ?PRIM_FILE:write(Fd, Line1),
+ ?line ok = ?PRIM_FILE:write(Fd, Line2),
+ ?line ok = ?PRIM_FILE:close(Fd),
+
+ ?line {ok, Fd2} = ?PRIM_FILE:open(Advise, [write]),
+ ?line ok = ?PRIM_FILE:advise(Fd2, 0, 0, random),
+ ?line ok = ?PRIM_FILE:write(Fd2, Line1),
+ ?line ok = ?PRIM_FILE:write(Fd2, Line2),
+ ?line ok = ?PRIM_FILE:close(Fd2),
+
+ ?line {ok, Fd3} = ?PRIM_FILE:open(Advise, [write]),
+ ?line ok = ?PRIM_FILE:advise(Fd3, 0, 0, sequential),
+ ?line ok = ?PRIM_FILE:write(Fd3, Line1),
+ ?line ok = ?PRIM_FILE:write(Fd3, Line2),
+ ?line ok = ?PRIM_FILE:close(Fd3),
+
+ ?line {ok, Fd4} = ?PRIM_FILE:open(Advise, [write]),
+ ?line ok = ?PRIM_FILE:advise(Fd4, 0, 0, will_need),
+ ?line ok = ?PRIM_FILE:write(Fd4, Line1),
+ ?line ok = ?PRIM_FILE:write(Fd4, Line2),
+ ?line ok = ?PRIM_FILE:close(Fd4),
+
+ ?line {ok, Fd5} = ?PRIM_FILE:open(Advise, [write]),
+ ?line ok = ?PRIM_FILE:advise(Fd5, 0, 0, dont_need),
+ ?line ok = ?PRIM_FILE:write(Fd5, Line1),
+ ?line ok = ?PRIM_FILE:write(Fd5, Line2),
+ ?line ok = ?PRIM_FILE:close(Fd5),
+
+ ?line {ok, Fd6} = ?PRIM_FILE:open(Advise, [write]),
+ ?line ok = ?PRIM_FILE:advise(Fd6, 0, 0, no_reuse),
+ ?line ok = ?PRIM_FILE:write(Fd6, Line1),
+ ?line ok = ?PRIM_FILE:write(Fd6, Line2),
+ ?line ok = ?PRIM_FILE:close(Fd6),
+
+ ?line {ok, Fd7} = ?PRIM_FILE:open(Advise, [write]),
+ ?line {error, einval} = ?PRIM_FILE:advise(Fd7, 0, 0, bad_advise),
+ ?line ok = ?PRIM_FILE:close(Fd7),
+
+ %% test write without advise, then a read after an advise
+ ?line {ok, Fd8} = ?PRIM_FILE:open(Advise, [write]),
+ ?line ok = ?PRIM_FILE:write(Fd8, Line1),
+ ?line ok = ?PRIM_FILE:write(Fd8, Line2),
+ ?line ok = ?PRIM_FILE:close(Fd8),
+ ?line {ok, Fd9} = ?PRIM_FILE:open(Advise, [read]),
+ Offset = 0,
+ %% same as a 0 length in some implementations
+ Length = length(Line1) + length(Line2),
+ ?line ok = ?PRIM_FILE:advise(Fd9, Offset, Length, sequential),
+ ?line {ok, Line1} = ?PRIM_FILE:read_line(Fd9),
+ ?line {ok, Line2} = ?PRIM_FILE:read_line(Fd9),
+ ?line eof = ?PRIM_FILE:read_line(Fd9),
+ ?line ok = ?PRIM_FILE:close(Fd9),
+
+ ?line test_server:timetrap_cancel(Dog),
+ ok.
+
+
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
delete_a(suite) -> [];