Skip to content

Commit

Permalink
Implemented evfs_io_server and first bits of evfs_iolit_io_server
Browse files Browse the repository at this point in the history
  • Loading branch information
yrashk committed Jul 10, 2011
1 parent a5a19bd commit 420ebf8
Show file tree
Hide file tree
Showing 4 changed files with 226 additions and 3 deletions.
112 changes: 112 additions & 0 deletions src/evfs_io_server.erl
@@ -0,0 +1,112 @@
-module(evfs_io_server).
-behaviour(gen_server).
-export([behaviour_info/1]).

-export([start_link/2]).
%% gen_server callbacks
-export([init/1, handle_call/3, handle_cast/2, handle_info/2,
terminate/2, code_change/3]).

behaviour_info(callbacks) ->
[];
behaviour_info(_) ->
undefined.

-record(state,
{
module :: module(),
handle :: term()
}).

-type state() :: #state{}.

-spec start_link(module(), term()) -> {ok, pid()} | {error, term()}.

start_link(Module, Args) ->
gen_server:start_link(?MODULE, {Module, Args}, []).

-spec init(module()) -> {ok, state()} | {stop, term()}.

init({Module, Args}) ->
{ok, #state{ module = Module, handle = Args }}.

-spec handle_call(term(), term(), state()) ->
{noreply, state()} |
{stop, normal, stopped, state()}.
handle_call(_Request, _From, State) ->
{noreply, State}.

-spec handle_cast(term(), state()) -> {noreply, state()}.

handle_cast(_Msg, State) ->
{noreply, State}.

-spec handle_info(term(), state()) ->
{noreply, state()} | {stop, term(), state()}.

handle_info({file_request, From, ReplyAs, Request},
#state{ module = Module, handle = Handle } = State) when is_pid(From) ->
case file_request(Request, Module, Handle) of
{reply, Reply, Handle1} ->
From ! {file_reply, ReplyAs, Reply},
{noreply, State#state{ handle = Handle1} };
{error, Reply, Handle1} ->
From ! {file_reply, ReplyAs, Reply},
{noreply, State#state{ handle = Handle1} };
{stop, Reason, Reply, Handle1} ->
From ! {file_reply, ReplyAs, Reply},
{stop, Reason, State#state{ handle = Handle1 }}
end;

handle_info({io_request, From, ReplyAs, Request},
#state{ module = Module, handle = Handle} = State) when is_pid(From) ->
case io_request(Request, Module, Handle) of
{reply, Reply, Handle1} ->
From ! {io_reply, ReplyAs, Reply},
{noreply, State#state{ handle = Handle1} };
{error, Reply, Handle1} ->
From ! {io_reply, ReplyAs, Reply},
{noreply, State#state{ handle = Handle1} };
{stop, Reason, Reply, Handle1} ->
From ! {io_reply, ReplyAs, Reply},
{stop, Reason, State#state{ handle = Handle1 }}
end.


-spec terminate(term(), state()) -> ok.

terminate(_Reason, _State) ->
ok.

-spec code_change(term(), state(), term()) -> {ok, state()}.

code_change(_OldVsn, State, _Extra) ->
{ok, State}.

%% Private
file_request(Request, Module, Handle) ->
Command = element(1, Request),
Args = tl(tuple_to_list(Request)),
case (catch apply(Module, Command, Args ++ [Handle])) of
{'EXIT', {undef, _}} ->
file_request(Request, evfs_iolist_io_server, Module:io_list(Handle));
Result ->
Result
end.

io_request({requests, Requests}, Module, Handle) ->
io_request({requests, Requests, undefined}, Module, Handle);
io_request({requests, [], Result}, _Module, _Handle) ->
Result;
io_request({requests, [Request|Rest], _Result}, Module, Handle) ->
Result = io_request(Request, Module, Handle),
io_request({requests, Rest, Result}, Module, Handle);
io_request(Request, Module, Handle) ->
Command = element(1, Request),
Args = tl(tuple_to_list(Request)),
case (catch apply(Module, Command, Args ++ [Handle])) of
{'EXIT', {undef, _}} ->
file_request(Request, evfs_iolist_io_server, Module:io_list(Handle));
Result ->
Result
end.
99 changes: 99 additions & 0 deletions src/evfs_iolist_io_server.erl
@@ -0,0 +1,99 @@
-module(evfs_iolist_io_server).
-behaviour(evfs_io_server).
%% File requests
-export([
advise/4,
pread/3,
pwrite/3,
datasync/1,
sync/1,
close/1,
position/1,
truncate/1
]).
%% IO requests
-export([
put_chars/2,
put_chars/3,
put_chars/4,
put_chars/5,
get_until/4,
get_until/5,
get_until/6,
get_chars/3,
get_chars/4,
get_line/2,
get_line/3,
setopts/2,
getopts/1
]).

%% File requests
advise(_Offset, _Length, _Advise, Handle) ->
{reply, ok, Handle}.

pread(At, Sz, Handle) ->
Binary = iolist_to_binary(Handle),
{reply, {ok, binary_to_list(binary:part(Binary, {At, Sz}))}, Handle}.

pwrite(_At, _Data, Handle) ->
%% TODO
{reply, ok, Handle}.

datasync(Handle) ->
{reply, ok, Handle}.

sync(Handle) ->
{reply, ok, Handle}.

close(Handle) ->
{stop, normal, ok, Handle}.

position(Handle) ->
{reply, 0, Handle}.

truncate(Handle) ->
{reply, ok, Handle}.

%% IO requests
put_chars(Chars, Handle) ->
put_chars(latin1, Chars, Handle).

put_chars(_Enc, _Mod, _Func, _Args, Handle) ->
{reply, {error, notsup}, Handle}.

put_chars(Mod, Func, Args, Handle) ->
put_chars(latin1, Mod, Func, Args, Handle).


put_chars(_Enc, _Chars, Handle) ->
{reply, {error, notsup}, Handle}.


get_until(_Enc, _Prompt, _Mod, _Func, _XtraArgs, Handle) ->
{reply, {error, notsup}, Handle}.

get_until(_Enc, _Prompt, _N, Handle) ->
{reply, {error, notsup}, Handle}.

get_until(Prompt, Mod, Func, XtraArgs, Handle) ->
get_until(latin1, Prompt, Mod, Func, XtraArgs, Handle).

get_chars(_Enc, _Prompt, _N, Handle) ->
{reply, {error, notsup}, Handle}.

get_chars(Prompt, N, Handle) ->
get_chars(latin1, Prompt, N, Handle).

get_line(_Enc, _Prompt, Handle) ->
{reply, {error, notsup}, Handle}.

get_line(Prompt, Handle) ->
get_line(latin1, Prompt, Handle).

setopts(_Opts, Handle) ->
{reply, {error, notsup}, Handle}.

getopts(Handle) ->
{reply, {error, notsup}, Handle}.

10 changes: 8 additions & 2 deletions test/evfs_test_fs.erl
@@ -1,5 +1,6 @@
-module(evfs_test_fs).
-behaviour(evfs_handler).
-behaviour(evfs_io_server).
-export([init/1, supports/2, terminate/2]).
-export([open/3,
read_file/2,
Expand All @@ -21,6 +22,7 @@
make_symlink/3,
copy/6
]).
-export([io_list/1]).

init(Args) ->
{ok, Args}.
Expand All @@ -32,8 +34,9 @@ supports(_, State) ->

%% Filesystem API

open(_Filename, _Mode, State) ->
{ok, {error, enotsup}, State}.
open(Filename, _Mode, State) ->
Child = evfs_io_server:start_link(?MODULE, Filename),
{ok, Child, State}.

read_file(Filename, State) ->
{ok, {ok, list_to_binary(Filename)}, State}.
Expand Down Expand Up @@ -92,3 +95,6 @@ copy(_SourceName, _SourceOpts, _DestName, _DestOpts, _Length, State) ->
terminate(_Reason, _State) ->
ok.

%% IO server
io_list(Handle) ->
Handle.
8 changes: 7 additions & 1 deletion test/evfs_tests.erl
Expand Up @@ -17,6 +17,11 @@ t_read_file() ->
?assertEqual({error, eisdir}, file:read_file("/")),
?assertEqual({ok, <<"test://any">>}, file:read_file("test://any")).

t_pread() ->
evfs:register(evfs_test_fs, []),
{ok, File} = file:open("test://anyfile",[read]),
?assertEqual({ok, ["test://any"]}, file:pread(File, [{0,10}])).

evfs_test_() ->
{foreach,
fun () ->
Expand All @@ -28,7 +33,8 @@ evfs_test_() ->
[
{"unregister", ?_test(t_unregister())},
{"file:// scheme should route to the default file server", ?_test(t_file_scheme())},
{"test_fs read_file", ?_test(t_read_file())}
{"test_fs read_file", ?_test(t_read_file())},
{"test_fs pread", ?_test(t_pread())}
]
}.

Expand Down

0 comments on commit 420ebf8

Please sign in to comment.