aboutsummaryrefslogtreecommitdiffstats
path: root/lib/kernel
diff options
context:
space:
mode:
Diffstat (limited to 'lib/kernel')
-rw-r--r--lib/kernel/doc/src/file.xml76
-rw-r--r--lib/kernel/doc/src/inet.xml63
-rw-r--r--lib/kernel/doc/src/notes.xml23
-rw-r--r--lib/kernel/src/code.erl12
-rw-r--r--lib/kernel/src/error_handler.erl5
-rw-r--r--lib/kernel/src/file.erl70
-rw-r--r--lib/kernel/src/file_io_server.erl4
-rw-r--r--lib/kernel/src/inet.erl12
-rw-r--r--lib/kernel/src/inet_int.hrl3
-rw-r--r--lib/kernel/src/kernel.erl9
-rw-r--r--lib/kernel/test/Makefile1
-rw-r--r--lib/kernel/test/code_SUITE.erl128
-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/file_SUITE.erl17
-rw-r--r--lib/kernel/test/file_name_SUITE.erl1729
-rw-r--r--lib/kernel/test/gen_udp_SUITE.erl6
-rw-r--r--lib/kernel/test/inet_SUITE.erl129
-rw-r--r--lib/kernel/test/os_SUITE.erl3
-rw-r--r--lib/kernel/vsn.mk2
19 files changed, 2248 insertions, 53 deletions
diff --git a/lib/kernel/doc/src/file.xml b/lib/kernel/doc/src/file.xml
index 2044b074ee..d3441d3623 100644
--- a/lib/kernel/doc/src/file.xml
+++ b/lib/kernel/doc/src/file.xml
@@ -36,6 +36,61 @@
other Erlang processes to continue executing in parallel with
the file operations. See the command line flag
<c>+A</c> in <seealso marker="erts:erl">erl(1)</seealso>.</p>
+
+ <p>The Erlang VM supports file names in Unicode to a limited
+ extent. Depending on how the VM is started (with the parameter
+ <c>+fnu</c> or <c>+fnl</c>), file names given can contain
+ characters > 255 and the VM system will convert file names
+ back and forth to the native file name encoding.</p>
+
+ <p>The default behavior for Unicode character translation depends
+ on to what extent the underlying OS/filesystem enforces consistent
+ naming. On OSes where all file names are ensured to be in one or
+ another encoding, Unicode is the default (currently this holds for
+ Windows and MacOSX). On OSes with completely transparent file
+ naming (i.e. all Unixes except MacOSX), ISO-latin-1 file naming is
+ the default. The reason for the ISO-latin-1 default is that
+ file names are not guaranteed to be possible to interpret according to
+ the Unicode encoding expected (i.e. UTF-8), and file names that
+ cannot be decoded will only be accessible by using &quot;raw
+ file names&quot;, in other word file names given as binaries.</p>
+
+ <p>As file names are traditionally not binaries in Erlang,
+ applications that need to handle raw file names need to be
+ converted, why the Unicode mode for file names is not default on
+ systems having completely transparent file naming.</p>
+
+ <note>As of R14B01, the most basic file handling modules
+ (<c>file</c>, <c>prim_file</c>, <c>filelib</c> and
+ <c>filename</c>) accept raw file names, but the rest of OTP is not
+ guaranteed to handle them, why Unicode file naming on systems
+ where it is not default is still considered experimental.</note>
+
+ <p>Raw file names is a new feature in OTP R14B01, which allows the
+ user to supply completely uninterpreted file names to the
+ underlying OS/filesystem. They are supplied as binaries, where it
+ is up to the user to supply a correct encoding for the
+ environment. The function <c>file:native_name_encoding()</c> can
+ be used to check what encoding the VM is working in. If the
+ function returns <c>latin1</c> file names are not in any way
+ converted to Unicode, if it is <c>utf8</c>, raw file names should
+ be encoded as UTF-8 if they are to follow the convention of the VM
+ (and usually the convention of the OS as well). Using raw
+ file names is useful if you have a filesystem with inconsistent
+ file naming, where some files are named in UTF-8 encoding while
+ others are not. A file:list_dir on such mixed file name systems
+ when the VM is in Unicode file name mode might return file names as
+ raw binaries as they cannot be interpreted as Unicode
+ file names. Raw file names can also be used to give UTF-8 encoded
+ file names even though the VM is not started in Unicode file name
+ translation mode.</p>
+
+ <p>Note that on Windows, <c>file:native_name_encoding()</c>
+ returns <c>utf8</c> per default, which is the format for raw
+ file names even on Windows, although the underlying OS specific
+ code works in a limited version of little endian UTF16. As far as
+ the Erlang programmer is concerned, Windows native Unicode format
+ is UTF-8...</p>
</description>
<section>
@@ -47,8 +102,14 @@ iodata() = iolist() | binary()
io_device()
as returned by file:open/2, a process handling IO protocols
-name() = string() | atom() | DeepList
+name() = string() | atom() | DeepList | RawFilename
DeepList = [char() | atom() | DeepList]
+ RawFilename = binary()
+ If VM is in unicode filename mode, string() and char() are allowed to be > 255.
+ RawFilename is a filename not subject to Unicode translation, meaning that it
+ can contain characters not conforming to the Unicode encoding expected from the
+ filesystem (i.e. non-UTF-8 characters although the VM is started in Unicode
+ filename mode).
posix()
an atom which is named from the POSIX error codes used in
@@ -598,13 +659,24 @@ f.txt: {person, "kalle", 25}.
</desc>
</func>
<func>
+ <name>native_name_encoding() -> latin1 | utf8</name>
+ <fsummary>Retunr the VMs configure filename encoding.</fsummary>
+ <desc>
+ <p>This function returns the configured default file name encoding to use for raw file names. Generally an application supplying file names raw (as binaries), should obey the character encoding returned by this function.</p>
+ <p>By default, the VM uses ISO-latin-1 file name encoding on filesystems and/or OSes that use completely transparent file naming. This includes all Unix versions except for MacOSX, where the vfs layer enforces UTF-8 file naming. By giving the experimental option <c>+fnu</c> when starting Erlang, UTF-8 translation of file names can be turned on even for those systems. If Unicode file name translation is in effect, the system behaves as usual as long as file names conform to the encoding, but will return file names that are not properly encoded in UTF-8 as raw file names (i.e. binaries).</p>
+ <p>On Windows, this function also returns <c>utf8</c> by default. The OS uses a pure Unicode naming scheme and file names are always possible to interpret as valid Unicode. The fact that the underlying Windows OS actually encodes file names using little endian UTF-16 can be ignored by the Erlang programmer. Windows and MacOSX are the only operating systems where the VM operates in Unicode file name mode by default.</p>
+ </desc>
+ </func>
+ <func>
<name>open(Filename, Modes) -> {ok, IoDevice} | {error, Reason}</name>
<fsummary>Open a file</fsummary>
<type>
<v>Filename = name()</v>
<v>Modes = [Mode]</v>
- <v>&nbsp;Mode = read | write | append | exclusive | raw | binary | {delayed_write, Size, Delay} | delayed_write | {read_ahead, Size} | read_ahead | compressed</v>
+ <v>&nbsp;Mode = read | write | append | exclusive | raw | binary | {delayed_write, Size, Delay} | delayed_write | {read_ahead, Size} | read_ahead | compressed | {encoding, Encoding}</v>
<v>&nbsp;&nbsp;Size = Delay = int()</v>
+ <v>&nbsp;&nbsp;Encoding = latin1 | unicode | utf8 | utf16 | {utf16, Endian} | utf32 | {utf32, Endian}</v>
+ <v>&nbsp;&nbsp;&nbsp;&nbsp;Endian = big | little</v>
<v>IoDevice = io_device()</v>
<v>Reason = ext_posix() | system_limit</v>
</type>
diff --git a/lib/kernel/doc/src/inet.xml b/lib/kernel/doc/src/inet.xml
index 2ae230152c..a22c0a8346 100644
--- a/lib/kernel/doc/src/inet.xml
+++ b/lib/kernel/doc/src/inet.xml
@@ -220,6 +220,69 @@ fe80::204:acff:fe17:bf38
<p>Returns the local hostname. Will never fail.</p>
</desc>
</func>
+
+ <func>
+ <name>getifaddrs() -> {ok,Iflist} | {error,posix}</name>
+ <fsummary>Return a list of interfaces and their addresses</fsummary>
+ <type>
+ <v>Iflist = {Ifname,[Ifopt]}</v>
+ <v>Ifname = string()</v>
+ <v>Ifopt = {flag,[Flag]} | {addr,Addr} | {netmask,Netmask}
+ | {broadaddr,Broadaddr} | {dstaddr,Dstaddr}
+ | {hwaddr,Hwaddr}</v>
+ <v>Flag = up | broadcast | loopback | pointtopoint
+ | running | multicast</v>
+ <v>Addr = Netmask = Broadadddr = Dstaddr = ip_address()</v>
+ <v>Hwaddr = [byte()]</v>
+ </type>
+ </func>
+ <desc>
+ <p>
+ Returns a list of 2-tuples containing interface names and the
+ interface's addresses. <c>Ifname</c> is a Unicode string.
+ <c>Hwaddr</c> is hardware dependent, e.g on Ethernet interfaces
+ it is the 6-byte Ethernet address (MAC address (EUI-48 address)).
+ </p>
+ <p>
+ The <c>{addr,Addr}</c>, <c>{netmask,_}</c> and <c>{broadaddr,_}</c>
+ tuples are repeated in the result list iff the interface has multiple
+ addresses. If you come across an interface that has
+ multiple <c>{flag,_}</c> or <c>{hwaddr,_}</c> tuples you have
+ a really strange interface or possibly a bug in this function.
+ The <c>{flag,_}</c> tuple is mandatory, all other optional.
+ </p>
+ <p>
+ Do not rely too much on the order of <c>Flag</c> atoms or
+ <c>Ifopt</c> tuples. There are some rules, though:
+ <list>
+ <item>
+ Immediately after <c>{addr,_}</c> follows <c>{netmask,_}</c>
+ </item>
+ <item>
+ Immediately thereafter follows <c>{broadaddr,_}</c> if
+ the <c>broadcast</c> flag is <em>not</em> set and the
+ <c>pointtopoint</c>flag <em>is</em> set.
+ </item>
+ <item>
+ Any <c>{netmask,_}</c>, <c>{broadaddr,_}</c> or
+ <c>{dstaddr,_}</c> tuples that follow an <c>{addr,_}</c>
+ tuple concerns that address.
+ </item>
+ </list>
+ </p>
+ <p>
+ The <c>{hwaddr,_}</c> tuple is not returned on Solaris since the
+ hardware address historically belongs to the link layer and only
+ the superuser can read such addresses.
+ </p>
+ <p>
+ On Windows, the data is fetched from quite different OS API
+ functions, so the <c>Netmask</c> and <c>Broadaddr</c>
+ values may be calculated, just as some <c>Flag</c> values.
+ You have been warned. Report flagrant bugs.
+ </p>
+ </desc>
+
<func>
<name>getopts(Socket, Options) -> {ok, OptionValues} | {error, posix()}</name>
<fsummary>Get one or more options for a socket</fsummary>
diff --git a/lib/kernel/doc/src/notes.xml b/lib/kernel/doc/src/notes.xml
index 9859183390..edd6ea52b0 100644
--- a/lib/kernel/doc/src/notes.xml
+++ b/lib/kernel/doc/src/notes.xml
@@ -30,6 +30,29 @@
</header>
<p>This document describes the changes made to the Kernel application.</p>
+<section><title>Kernel 2.14.1.1</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>In embedded mode, on_load handlers that called
+ <c>code:priv_dir/1</c> or other functions in <c>code</c>
+ would hang the system. Since the <c>crypto</c>
+ application now contains an on_loader handler that calls
+ <c>code:priv_dir/1</c>, including the <c>crypto</c>
+ application in the boot file would prevent the system
+ from starting.</p>
+ <p>Also extended the <c>-init_debug</c> option to print
+ information about on_load handlers being run to
+ facilitate debugging.</p>
+ <p>
+ Own Id: OTP-8902 Aux Id: seq11703 </p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
<section><title>Kernel 2.14.1</title>
<section><title>Fixed Bugs and Malfunctions</title>
diff --git a/lib/kernel/src/code.erl b/lib/kernel/src/code.erl
index ec256d5806..feb5131aad 100644
--- a/lib/kernel/src/code.erl
+++ b/lib/kernel/src/code.erl
@@ -213,19 +213,20 @@ unstick_mod(Mod) when is_atom(Mod) -> call({unstick_mod,Mod}).
-spec is_sticky(Module :: atom()) -> boolean().
is_sticky(Mod) when is_atom(Mod) -> call({is_sticky,Mod}).
--spec set_path(Directories :: [file:filename()]) -> 'true' | {'error', term()}.
+-spec set_path(Directories :: [file:filename()]) ->
+ 'true' | {'error', 'bad_directory' | 'bad_path'}.
set_path(PathList) when is_list(PathList) -> call({set_path,PathList}).
-spec get_path() -> [file:filename()].
get_path() -> call(get_path).
--spec add_path(Directory :: file:filename()) -> 'true' | {'error', term()}.
+-spec add_path(Directory :: file:filename()) -> 'true' | {'error', 'bad_directory'}.
add_path(Dir) when is_list(Dir) -> call({add_path,last,Dir}).
--spec add_pathz(Directory :: file:filename()) -> 'true' | {'error', term()}.
+-spec add_pathz(Directory :: file:filename()) -> 'true' | {'error', 'bad_directory'}.
add_pathz(Dir) when is_list(Dir) -> call({add_path,last,Dir}).
--spec add_patha(Directory :: file:filename()) -> 'true' | {'error', term()}.
+-spec add_patha(Directory :: file:filename()) -> 'true' | {'error', 'bad_directory'}.
add_patha(Dir) when is_list(Dir) -> call({add_path,first,Dir}).
-spec add_paths(Directories :: [file:filename()]) -> 'ok'.
@@ -237,7 +238,6 @@ add_pathsz(Dirs) when is_list(Dirs) -> call({add_paths,last,Dirs}).
-spec add_pathsa(Directories :: [file:filename()]) -> 'ok'.
add_pathsa(Dirs) when is_list(Dirs) -> call({add_paths,first,Dirs}).
-%% XXX Contract's input argument differs from add_path/1 -- why?
-spec del_path(Name :: file:filename() | atom()) -> boolean() | {'error', 'bad_name'}.
del_path(Name) when is_list(Name) ; is_atom(Name) -> call({del_path,Name}).
@@ -286,6 +286,8 @@ do_start(Flags) ->
ets:module_info(module),
os:module_info(module),
+ binary:module_info(module),
+ unicode:module_info(module),
filename:module_info(module),
lists:module_info(module),
diff --git a/lib/kernel/src/error_handler.erl b/lib/kernel/src/error_handler.erl
index 17dd02acd4..885eeb2b0f 100644
--- a/lib/kernel/src/error_handler.erl
+++ b/lib/kernel/src/error_handler.erl
@@ -17,6 +17,11 @@
%% %CopyrightEnd%
%%
-module(error_handler).
+%% FIXME: remove no_native directive after HiPE has been changed to make
+%% remote calls link to the target's Export* like BEAM does.
+%% For a detailed explanation see the commit titled
+%% "error_handler: add no_native compiler directive"
+-compile(no_native).
%% A simple error handler.
diff --git a/lib/kernel/src/file.erl b/lib/kernel/src/file.erl
index cffe4e3db5..bc95359986 100644
--- a/lib/kernel/src/file.erl
+++ b/lib/kernel/src/file.erl
@@ -75,25 +75,34 @@
-define(RAM_FILE, ram_file). % Module
%% data types
--type filename() :: string().
+-type filename() :: string() | binary().
-type file_info() :: #file_info{}.
-type fd() :: #file_descriptor{}.
-type io_device() :: pid() | fd().
-type location() :: integer() | {'bof', integer()} | {'cur', integer()}
| {'eof', integer()} | 'bof' | 'cur' | 'eof'.
--type mode() :: 'read' | 'write' | 'append' | 'raw' | 'binary' |
- {'delayed_write', non_neg_integer(), non_neg_integer()} |
- 'delayed_write' | {'read_ahead', pos_integer()} |
- 'read_ahead' | 'compressed' | 'exclusive'.
--type name() :: string() | atom() | [name()].
--type posix() :: atom().
+-type mode() :: 'read' | 'write' | 'append'
+ | 'exclusive' | 'raw' | 'binary'
+ | {'delayed_write', non_neg_integer(), non_neg_integer()}
+ | 'delayed_write' | {'read_ahead', pos_integer()}
+ | 'read_ahead' | 'compressed'
+ | {'encoding', unicode:encoding()}.
+-type name() :: string() | atom() | [name()] | binary().
+-type posix() :: 'eacces' | 'eagain' | 'ebadf' | 'ebusy' | 'edquot'
+ | 'eexist' | 'efault' | 'efbig' | 'eintr' | 'einval'
+ | 'eio' | 'eisdir' | 'eloop' | 'emfile' | 'emlink'
+ | 'enametoolong'
+ | 'enfile' | 'enodev' | 'enoent' | 'enomem' | 'enospc'
+ | 'enotblk' | 'enotdir' | 'enotsup' | 'enxio' | 'eperm'
+ | 'epipe' | 'erofs' | 'espipe' | 'esrch' | 'estale'
+ | 'exdev'.
-type bindings() :: any().
-type date() :: {pos_integer(), pos_integer(), pos_integer()}.
-type time() :: {non_neg_integer(), non_neg_integer(), non_neg_integer()}.
-type date_time() :: {date(), time()}.
--type posix_file_advise() :: 'normal' | 'sequential' | 'random' | 'no_reuse' |
- 'will_need' | 'dont_need'.
+-type posix_file_advise() :: 'normal' | 'sequential' | 'random'
+ | 'no_reuse' | 'will_need' | 'dont_need'.
%%%-----------------------------------------------------------------
%%% General functions
@@ -174,7 +183,7 @@ make_dir(Name) ->
del_dir(Name) ->
check_and_call(del_dir, [file_name(Name)]).
--spec read_file_info(Name :: name()) -> {'ok', #file_info{}} | {'error', posix()}.
+-spec read_file_info(Name :: name()) -> {'ok', file_info()} | {'error', posix()}.
read_file_info(Name) ->
check_and_call(read_file_info, [file_name(Name)]).
@@ -184,7 +193,7 @@ read_file_info(Name) ->
altname(Name) ->
check_and_call(altname, [file_name(Name)]).
--spec read_link_info(Name :: name()) -> {'ok', #file_info{}} | {'error', posix()}.
+-spec read_link_info(Name :: name()) -> {'ok', file_info()} | {'error', posix()}.
read_link_info(Name) ->
check_and_call(read_link_info, [file_name(Name)]).
@@ -194,7 +203,7 @@ read_link_info(Name) ->
read_link(Name) ->
check_and_call(read_link, [file_name(Name)]).
--spec write_file_info(Name :: name(), Info :: #file_info{}) ->
+-spec write_file_info(Name :: name(), Info :: file_info()) ->
'ok' | {'error', posix()}.
write_file_info(Name, Info = #file_info{}) ->
@@ -205,7 +214,8 @@ write_file_info(Name, Info = #file_info{}) ->
list_dir(Name) ->
check_and_call(list_dir, [file_name(Name)]).
--spec read_file(Name :: name()) -> {'ok', binary()} | {'error', posix()}.
+-spec read_file(Name :: name()) ->
+ {'ok', binary()} | {'error', posix() | 'terminated' | 'system_limit'}.
read_file(Name) ->
check_and_call(read_file, [file_name(Name)]).
@@ -220,15 +230,15 @@ make_link(Old, New) ->
make_symlink(Old, New) ->
check_and_call(make_symlink, [file_name(Old), file_name(New)]).
--spec write_file(Name :: name(), Bin :: binary()) -> 'ok' | {'error', posix()}.
+-spec write_file(Name :: name(), Bin :: iodata()) ->
+ 'ok' | {'error', posix() | 'terminated' | 'system_limit'}.
write_file(Name, Bin) ->
check_and_call(write_file, [file_name(Name), make_binary(Bin)]).
%% This whole operation should be moved to the file_server and prim_file
%% when it is time to change file server protocol again.
-%% Meanwhile, it is implemented here, slihtly less efficient.
-%%
+%% Meanwhile, it is implemented here, slightly less efficient.
-spec write_file(Name :: name(), Bin :: binary(), Modes :: [mode()]) ->
'ok' | {'error', posix()}.
@@ -286,7 +296,7 @@ raw_write_file_info(Name, #file_info{} = Info) ->
%% Contemporary mode specification - list of options
-spec open(Name :: name(), Modes :: [mode()]) ->
- {'ok', io_device()} | {'error', posix()}.
+ {'ok', io_device()} | {'error', posix() | 'system_limit'}.
open(Item, ModeList) when is_list(ModeList) ->
case lists:member(raw, ModeList) of
@@ -339,7 +349,7 @@ open(Item, Mode) ->
%%% The File argument must be either a Pid or a handle
%%% returned from ?PRIM_FILE:open.
--spec close(File :: io_device()) -> 'ok' | {'error', posix()}.
+-spec close(File :: io_device()) -> 'ok' | {'error', posix() | 'terminated'}.
close(File) when is_pid(File) ->
R = file_request(File, close),
@@ -358,7 +368,7 @@ close(_) ->
{error, badarg}.
-spec advise(File :: io_device(), Offset :: integer(),
- Length :: integer(), Advise :: posix_file_advise()) ->
+ Length :: integer(), Advise :: posix_file_advise()) ->
'ok' | {'error', posix()}.
advise(File, Offset, Length, Advise) when is_pid(File) ->
@@ -440,7 +450,7 @@ pread(_, _, _) ->
{error, badarg}.
-spec write(File :: io_device() | atom(), Byte :: iodata()) ->
- 'ok' | {'error', posix()}.
+ 'ok' | {'error', posix() | 'terminated'}.
write(File, Bytes) when (is_pid(File) orelse is_atom(File)) ->
case make_binary(Bytes) of
@@ -1024,22 +1034,26 @@ path_open_first([], _Name, _Mode, LastError) ->
%% Generates a flat file name from a deep list of atoms and
%% characters (integers).
+file_name(N) when is_binary(N) ->
+ N;
file_name(N) ->
try
- file_name_1(N)
+ file_name_1(N,file:native_name_encoding())
catch Reason ->
{error, Reason}
end.
-file_name_1([C|T]) when is_integer(C), C > 0, C =< 255 ->
- [C|file_name_1(T)];
-file_name_1([H|T]) ->
- file_name_1(H) ++ file_name_1(T);
-file_name_1([]) ->
+file_name_1([C|T],latin1) when is_integer(C), C < 256->
+ [C|file_name_1(T,latin1)];
+file_name_1([C|T],utf8) when is_integer(C) ->
+ [C|file_name_1(T,utf8)];
+file_name_1([H|T],E) ->
+ file_name_1(H,E) ++ file_name_1(T,E);
+file_name_1([],_) ->
[];
-file_name_1(N) when is_atom(N) ->
+file_name_1(N,_) when is_atom(N) ->
atom_to_list(N);
-file_name_1(_) ->
+file_name_1(_,_) ->
throw(badarg).
make_binary(Bin) when is_binary(Bin) ->
diff --git a/lib/kernel/src/file_io_server.erl b/lib/kernel/src/file_io_server.erl
index 39dc32bb79..14da9c1a55 100644
--- a/lib/kernel/src/file_io_server.erl
+++ b/lib/kernel/src/file_io_server.erl
@@ -44,11 +44,11 @@ format_error(ErrorId) ->
erl_posix_msg:message(ErrorId).
start(Owner, FileName, ModeList)
- when is_pid(Owner), is_list(FileName), is_list(ModeList) ->
+ when is_pid(Owner), (is_list(FileName) orelse is_binary(FileName)), is_list(ModeList) ->
do_start(spawn, Owner, FileName, ModeList).
start_link(Owner, FileName, ModeList)
- when is_pid(Owner), is_list(FileName), is_list(ModeList) ->
+ when is_pid(Owner), (is_list(FileName) orelse is_binary(FileName)), is_list(ModeList) ->
do_start(spawn_link, Owner, FileName, ModeList).
%%%-----------------------------------------------------------------
diff --git a/lib/kernel/src/inet.erl b/lib/kernel/src/inet.erl
index 93d75321ba..327e0f93f1 100644
--- a/lib/kernel/src/inet.erl
+++ b/lib/kernel/src/inet.erl
@@ -25,6 +25,7 @@
%% socket
-export([peername/1, sockname/1, port/1, send/2,
setopts/2, getopts/2,
+ getifaddrs/0, getifaddrs/1,
getif/1, getif/0, getiflist/0, getiflist/1,
ifget/3, ifget/2, ifset/3, ifset/2,
getstat/1, getstat/2,
@@ -265,6 +266,17 @@ setopts(Socket, Opts) ->
getopts(Socket, Opts) ->
prim_inet:getopts(Socket, Opts).
+-spec getifaddrs(Socket :: socket()) ->
+ {'ok', [string()]} | {'error', posix()}.
+
+getifaddrs(Socket) ->
+ prim_inet:getifaddrs(Socket).
+
+-spec getifaddrs() -> {'ok', [string()]} | {'error', posix()}.
+
+getifaddrs() ->
+ withsocket(fun(S) -> prim_inet:getifaddrs(S) end).
+
-spec getiflist(Socket :: socket()) ->
{'ok', [string()]} | {'error', posix()}.
diff --git a/lib/kernel/src/inet_int.hrl b/lib/kernel/src/inet_int.hrl
index cf357b7fba..6f1688c6a2 100644
--- a/lib/kernel/src/inet_int.hrl
+++ b/lib/kernel/src/inet_int.hrl
@@ -1,7 +1,7 @@
%%
%% %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
@@ -82,6 +82,7 @@
-define(INET_REQ_IFGET, 22).
-define(INET_REQ_IFSET, 23).
-define(INET_REQ_SUBSCRIBE, 24).
+-define(INET_REQ_GETIFADDRS, 25).
%% TCP requests
-define(TCP_REQ_ACCEPT, 40).
-define(TCP_REQ_LISTEN, 41).
diff --git a/lib/kernel/src/kernel.erl b/lib/kernel/src/kernel.erl
index 92ee7b441a..1e07620a3e 100644
--- a/lib/kernel/src/kernel.erl
+++ b/lib/kernel/src/kernel.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2009. All Rights Reserved.
+%% 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
@@ -143,6 +143,13 @@ init(safe) ->
Boot = start_boot_server(),
DiskLog = start_disk_log(),
Pg2 = start_pg2(),
+
+ %% Run the on_load handlers for all modules that have been
+ %% loaded so far. Running them at this point means that
+ %% on_load handlers can safely call kernel processes
+ %% (and in particular call code:priv_dir/1 or code:lib_dir/1).
+ init:run_on_load_handlers(),
+
{ok, {SupFlags, Boot ++ DiskLog ++ Pg2}}.
get_code_args() ->
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 c9437df258..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,6 +31,7 @@
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,
+ 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,
@@ -53,6 +54,7 @@ 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,
+ big_boot_embedded,
on_load_errors, native_early_modules].
init_per_suite(Config) ->
@@ -584,13 +586,21 @@ clash(Config) when is_list(Config) ->
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"),
- ?line ok = file:delete(TmpEzFile),
+ 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) ->
@@ -635,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 =
@@ -664,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},
@@ -1145,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,
@@ -1226,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"});
@@ -1255,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(),
@@ -1281,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".
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/file_SUITE.erl b/lib/kernel/test/file_SUITE.erl
index 17c47f871d..47592ddb14 100644
--- a/lib/kernel/test/file_SUITE.erl
+++ b/lib/kernel/test/file_SUITE.erl
@@ -3268,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) ->
@@ -3278,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) ->
@@ -3290,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"),
@@ -3329,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_udp_SUITE.erl b/lib/kernel/test/gen_udp_SUITE.erl
index bbdfbd3cb0..2ff1d7210a 100644
--- a/lib/kernel/test/gen_udp_SUITE.erl
+++ b/lib/kernel/test/gen_udp_SUITE.erl
@@ -423,7 +423,11 @@ connect(Config) when is_list(Config) ->
?line ok = gen_udp:close(S1),
?line ok = gen_udp:connect(S2, Addr, P1),
?line ok = gen_udp:send(S2, <<16#deadbeef:32>>),
- ?line {error,econnrefused} = gen_udp:recv(S2, 0, 5),
+ ?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) ->
diff --git a/lib/kernel/test/inet_SUITE.erl b/lib/kernel/test/inet_SUITE.erl
index f4f27933a5..ec05bf99b9 100644
--- a/lib/kernel/test/inet_SUITE.erl
+++ b/lib/kernel/test/inet_SUITE.erl
@@ -27,7 +27,7 @@
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,
- getif_ifr_name_overflow/1,getservbyname_overflow/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]).
@@ -40,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_ifr_name_overflow,getservbyname_overflow].
+ getif,getif_ifr_name_overflow,getservbyname_overflow,getifaddrs].
init_per_testcase(_Func, Config) ->
Dog = test_server:timetrap(test_server:seconds(60)),
@@ -873,6 +873,14 @@ 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),
@@ -887,7 +895,8 @@ getif(Config) when is_list(Config) ->
end
end, [], Interfaces)),
?line io:format("HWAs = ~p~n", [HWAs]),
- ?line length(HWAs) > 0 orelse ?t:fail(no_HWAs),
+ ?line (Osname =/= sunos)
+ andalso ((length(HWAs) > 0) orelse (?t:fail(no_HWAs))),
?line Addresses =
lists:sort(
lists:foldl(
@@ -906,6 +915,14 @@ getif(Config) when is_list(Config) ->
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.
@@ -917,6 +934,112 @@ getservbyname_overflow(Config) when is_list(Config) ->
?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/os_SUITE.erl b/lib/kernel/test/os_SUITE.erl
index ace9501d18..eacf3c7584 100644
--- a/lib/kernel/test/os_SUITE.erl
+++ b/lib/kernel/test/os_SUITE.erl
@@ -204,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/vsn.mk b/lib/kernel/vsn.mk
index 651d082379..03fe63e385 100644
--- a/lib/kernel/vsn.mk
+++ b/lib/kernel/vsn.mk
@@ -1 +1 @@
-KERNEL_VSN = 2.14.1
+KERNEL_VSN = 2.14.2