Handle HAVE_ALL and HAVE_NONE. Cleanup the BITFIELD message.
[etorrent.git] / lib / etorrent-1.0 / src / etorrent_fs_process.erl
blob436de2dfa4d00a369aa4d4707b81b55e9132d0a5
1 %%%-------------------------------------------------------------------
2 %%% File : file_process.erl
3 %%% Author : User Jlouis <jesper.louis.andersen@gmail.com>
4 %%% License : See COPYING
5 %%% Description : The file process implements an interface to a given
6 %%% file. It is possible to carry out the wished operations on the file
7 %%% in question for operating in a Torrent Client. The implementation has
8 %%% an automatic handler for file descriptors: If no request has been
9 %%% received in a given timeout, then the file is closed.
10 %%%
11 %%% Created : 18 Jun 2007 by User Jlouis <jesper.louis.andersen@gmail.com>
12 %%%-------------------------------------------------------------------
13 -module(etorrent_fs_process).
15 -include("etorrent_mnesia_table.hrl").
16 -include("log.hrl").
18 -behaviour(gen_server).
20 %% API
21 -export([start_link/2, get_data/3, put_data/4, stop/1]).
23 %% gen_server callbacks
24 -export([init/1, handle_call/3, handle_cast/2, handle_info/2,
25 terminate/2, code_change/3]).
27 -record(state, {path = none,
28 iodev = none}).
30 % If no request has been received in this interval, close the server.
31 -define(REQUEST_TIMEOUT, 60000).
33 %%====================================================================
34 %% API
35 %%====================================================================
36 %%--------------------------------------------------------------------
37 %% Function: start_link() -> {ok,Pid} | ignore | {error,Error}
38 %% Description: Starts the server
39 %%--------------------------------------------------------------------
40 start_link(Path, Id) ->
41 gen_server:start_link(?MODULE, [Path, Id], []).
43 get_data(Pid, OffSet, Size) ->
44 gen_server:call(Pid, {read_request, OffSet, Size}).
46 put_data(Pid, Chunk, Offset, _Size) ->
47 gen_server:call(Pid, {write_request, Offset, Chunk}).
49 stop(Pid) ->
50 gen_server:cast(Pid, stop).
52 %%====================================================================
53 %% gen_server callbacks
54 %%====================================================================
55 init([Id, TorrentId]) ->
56 %% We'll clean up file descriptors gracefully on termination.
57 process_flag(trap_exit, true),
58 #path_map { path = Path} = etorrent_path_map:select(Id, TorrentId),
59 {ok, Workdir} = application:get_env(etorrent, dir),
60 FullPath = filename:join([Workdir, Path]),
61 {ok, IODev} = file:open(FullPath, [read, write, binary, raw, read_ahead]),
62 {ok, #state{iodev = IODev,
63 path = FullPath}, ?REQUEST_TIMEOUT}.
65 %%--------------------------------------------------------------------
66 %% Function: %% handle_call(Request, From, State) -> {reply, Reply, State} |
67 %% {reply, Reply, State, Timeout} |
68 %% {noreply, State} |
69 %% {noreply, State, Timeout} |
70 %% {stop, Reason, Reply, State} |
71 %% {stop, Reason, State}
72 %% Description: Handling call messages
73 %%--------------------------------------------------------------------
74 handle_call({read_request, Offset, Size}, _From, State) ->
75 Data = read_request(Offset, Size, State),
76 {reply, Data, State, ?REQUEST_TIMEOUT};
77 handle_call({write_request, Offset, Data}, _From, S) ->
78 ok = write_request(Offset, Data, S),
79 {reply, ok, S, ?REQUEST_TIMEOUT}.
81 %%--------------------------------------------------------------------
82 %% Function: handle_cast(Msg, State) -> {noreply, State} |
83 %% {noreply, State, Timeout} |
84 %% {stop, Reason, State}
85 %% Description: Handling cast messages
86 %%--------------------------------------------------------------------
87 handle_cast(stop, S) ->
88 {stop, normal, S};
89 handle_cast(_Msg, State) ->
90 {noreply, State, ?REQUEST_TIMEOUT}.
92 handle_info(timeout, State) ->
93 {stop, normal, State};
94 handle_info(Info, State) ->
95 error_logger:warning_report([unknown_fs_process, Info]),
96 {noreply, State}.
98 terminate(_Reason, State) ->
99 case file:close(State#state.iodev) of
100 ok -> ok;
101 E -> ?log([cant_close_file, E]), ok
102 end.
104 %%--------------------------------------------------------------------
105 %% Func: code_change(OldVsn, State, Extra) -> {ok, NewState}
106 %% Description: Convert process state when code is changed
107 %%--------------------------------------------------------------------
108 code_change(_OldVsn, State, _Extra) ->
109 {ok, State}.
111 %%--------------------------------------------------------------------
112 %%% Internal functions
113 %%--------------------------------------------------------------------
115 %%--------------------------------------------------------------------
116 %% Func: read_request(Offset, Size, State) -> {ok, Data}
117 %% | {read_error, posix()}
118 %% | {pos_error, posix()}
119 %% Description: Attempt to read at Offset; Size bytes. Either returns
120 %% ok or an error from the positioning or reading with a posix()
121 %% error message.
122 %%--------------------------------------------------------------------
123 read_request(Offset, Size, State) ->
124 {ok, NP} = file:position(State#state.iodev, Offset),
125 Offset = NP,
126 {ok, Data} = file:read(State#state.iodev, Size),
127 Data.
129 %%--------------------------------------------------------------------
130 %% Func: write_request(Offset, Bytes, State) -> ok
131 %% | {pos_error, posix()}
132 %% | {write_error, posix()}
133 %% Description: Attempt to write Bytes at offset Offset. Either returns
134 %% ok, or an error from positioning or writing which is posix().
135 %%--------------------------------------------------------------------
136 write_request(Offset, Bytes, State) ->
137 {ok, NP} = file:position(State#state.iodev, Offset),
138 Offset = NP,
139 ok = file:write(State#state.iodev, Bytes).
141 %%--------------------------------------------------------------------
142 %% Func:
143 %% Description:
144 %%--------------------------------------------------------------------