Skip to content

@xslogic /gist:700908
Created

Embed URL

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
FTP Patch for resuming FTP download..
diff --git a/lib/inets/src/ftp/ftp.erl b/lib/inets/src/ftp/ftp.erl
index 534fcae..1062c08 100644
--- a/lib/inets/src/ftp/ftp.erl
+++ b/lib/inets/src/ftp/ftp.erl
@@ -31,11 +31,11 @@
%% API - Client interface
-export([cd/2, close/1, delete/2, formaterror/1,
lcd/2, lpwd/1, ls/1, ls/2,
- mkdir/2, nlist/1, nlist/2,
+ mkdir/2, nlist/1, nlist/2, sizeof/2,
open/1, open/2, open/3, force_active/1,
pwd/1, quote/2,
recv/2, recv/3, recv_bin/2,
- recv_chunk_start/2, recv_chunk/1,
+ recv_chunk_start/2, recv_chunk_start/3, recv_chunk/1,
rename/3, rmdir/2,
send/2, send/3, send_bin/3,
send_chunk_start/2, send_chunk/2, send_chunk_end/1,
@@ -250,12 +250,26 @@ cd(Pid, Dir) ->
lcd(Pid, Dir) ->
call(Pid, {lcd, Dir}, string).
+
+%%--------------------------------------------------------------------------
+%% sizeof(Pid, File) -> ok | {error, <something>}
+%% Pid = pid()
+%% Dir = string()
+%%
+%% Description: Return size of file.
+%%--------------------------------------------------------------------------
+sizeof(Pid, File) ->
+ call(Pid, {sizeof, File}, string).
+
+
%%--------------------------------------------------------------------------
%% ls(Pid) -> Result
%% ls(Pid, <Dir>) -> Result
+%% ls(Pid, <Dir>, RType) -> Result
%%
%% Pid = pid()
%% Dir = string()
+%% RType = string | binary
%% Result = {ok, Listing} | {error, Reason}
%% Listing = string()
%% Reason = epath | elogin | econn
@@ -263,9 +277,11 @@ lcd(Pid, Dir) ->
%% Description: Returns a list of files in long format.
%%--------------------------------------------------------------------------
ls(Pid) ->
- ls(Pid, "").
+ ls(Pid, "", string).
ls(Pid, Dir) ->
- call(Pid, {dir, long, Dir}, string).
+ ls(Pid, Dir, string).
+ls(Pid, Dir, RType) ->
+ call(Pid, {dir, long, Dir}, RType).
%%--------------------------------------------------------------------------
%% nlist(Pid) -> Result
@@ -373,6 +389,9 @@ recv_bin(Pid, RemoteFile) ->
recv_chunk_start(Pid, RemoteFile) ->
call(Pid, {recv_chunk_start, RemoteFile}, atom).
+recv_chunk_start(Pid, RemoteFile, Pos) ->
+ call(Pid, {recv_chunk_start, RemoteFile, Pos}, atom).
+
%%--------------------------------------------------------------------------
%% recv_chunk(Pid, RemoteFile) -> ok | {ok, Bin} | {error, Reason}
%% Pid = pid()
@@ -938,6 +957,12 @@ handle_call({_, {delete, File}}, {_Pid, _} = From,
activate_ctrl_connection(State),
{noreply, State#state{client = From}};
+handle_call({_, {sizeof, File}}, {_Pid, _} = From,
+ #state{chunk = false} = State) ->
+ send_ctrl_message(State, mk_cmd("SIZE ~s", [File])),
+ activate_ctrl_connection(State),
+ {noreply, State#state{client = From, caller = sizeof}};
+
handle_call({_, {mkdir, Dir}}, From, #state{chunk = false} = State) ->
send_ctrl_message(State, mk_cmd("MKD ~s", [Dir])),
activate_ctrl_connection(State),
@@ -985,6 +1010,12 @@ handle_call({_, {recv_bin, RemoteFile}}, From, #state{chunk = false} =
setup_data_connection(State#state{caller = {recv_bin, RemoteFile},
client = From});
+handle_call({_,{recv_chunk_start, RemoteFile, Pos}}, From, #state{chunk = false}
+ = State) ->
+ setup_data_connection(State#state{caller = {start_chunk_transfer,
+ "RETR", RemoteFile, Pos},
+ client = From});
+
handle_call({_,{recv_chunk_start, RemoteFile}}, From, #state{chunk = false}
= State) ->
setup_data_connection(State#state{caller = {start_chunk_transfer,
@@ -992,6 +1023,10 @@ handle_call({_,{recv_chunk_start, RemoteFile}}, From, #state{chunk = false}
client = From});
handle_call({_, recv_chunk}, _, #state{chunk = false} = State) ->
+ activate_ctrl_connection(State#state{chunk = flush_ctrl}),
+ {reply, ok, State#state{chunk = flush_ctrl}};
+
+handle_call({_, recv_chunk}, _, #state{chunk = flush_ctrl} = State) ->
{reply, {error, "ftp:recv_chunk_start/2 not called"}, State};
handle_call({_, recv_chunk}, From, #state{chunk = true} = State) ->
@@ -1047,13 +1082,12 @@ handle_call({_, {quote, Cmd}}, From, #state{chunk = false} = State) ->
activate_ctrl_connection(State),
{noreply, State#state{client = From, caller = quote}};
-handle_call({_, _Req}, _From, #state{csock = CSock} = State)
- when (CSock =:= undefined) ->
- {reply, {error, not_connected}, State};
-
handle_call(_, _, #state{chunk = true} = State) ->
{reply, {error, echunk}, State};
+handle_call(_Request, _, #state{chunk = flush_ctrl} = State) ->
+ {reply, {wait, "Awaiting flush"}, State};
+
%% Catch all - This can only happen if the application programmer writes
%% really bad code that violates the API.
handle_call(Request, _Timeout, State) ->
@@ -1366,6 +1400,15 @@ handle_user_account(Acc, State) ->
%%--------------------------------------------------------------------------
%%--------------------------------------------------------------------------
%% Handling of control connection setup
+handle_ctrl_result({pos_size, Size}, State) ->
+ ctrl_result_response({pos_size, Size}, State, ok);
+
+handle_ctrl_result({pos_complx, _}, State) ->
+ handle_caller(State);
+
+handle_ctrl_result(_, #state{chunk = flush_ctrl} = State) ->
+ {noreply, State#state{chunk = false}};
+
handle_ctrl_result({pos_compl, _}, #state{caller = open, client = From}
= State) ->
gen_server:reply(From, {ok, self()}),
@@ -1631,6 +1674,10 @@ handle_ctrl_result({Status, Lines}, #state{client = From} = State)
%%--------------------------------------------------------------------------
%% Help functions to handle_ctrl_result
%%--------------------------------------------------------------------------
+ctrl_result_response({pos_size, Size}, #state{client = From} = State, _) ->
+ gen_server:reply(From, {ok, Size}),
+ {noreply, State#state{client = undefined, caller = undefined}};
+
ctrl_result_response(pos_compl, #state{client = From} = State, _) ->
gen_server:reply(From, ok),
{noreply, State#state{client = undefined, caller = undefined}};
@@ -1669,6 +1716,13 @@ handle_caller(#state{caller = {recv_bin, RemoteFile}} = State) ->
activate_ctrl_connection(State),
{noreply, State#state{caller = recv_bin}};
+
+handle_caller(#state{caller = {start_chunk_transfer, Cmd, RemoteFile, Pos}} =
+ State) ->
+ send_ctrl_message(State, mk_cmd("~s ~p", ["REST", Pos])),
+ activate_ctrl_connection(State),
+ {noreply, State#state{caller = {start_chunk_transfer, Cmd, RemoteFile}}};
+
handle_caller(#state{caller = {start_chunk_transfer, Cmd, RemoteFile}} =
State) ->
send_ctrl_message(State, mk_cmd("~s ~s", [Cmd, RemoteFile])),
@@ -1924,9 +1978,16 @@ file_write(Bytes, Fd) ->
call(GenServer, Msg, Format) ->
call(GenServer, Msg, Format, infinity).
call(GenServer, Msg, Format, Timeout) ->
- Req = {self(), Msg},
- case (catch gen_server:call(GenServer, Req, Timeout)) of
- {ok, Bin} when is_binary(Bin) andalso (Format =:= string) ->
+
+ Result = (catch gen_server:call(GenServer, {self(), Msg}, Timeout)),
+
+ case Result of
+ {wait, _} ->
+ receive
+ after 1500 ->
+ call(GenServer, Msg, Format, Timeout)
+ end;
+ {ok, Bin} when is_binary(Bin), Format == string ->
{ok, binary_to_list(Bin)};
{'EXIT', _} ->
{error, eclosed};
diff --git a/lib/inets/src/ftp/ftp_response.erl b/lib/inets/src/ftp/ftp_response.erl
index faeacb3..404e3ae 100644
--- a/lib/inets/src/ftp/ftp_response.erl
+++ b/lib/inets/src/ftp/ftp_response.erl
@@ -175,9 +175,11 @@ error_string(Reason) ->
%% Positive Preleminary Reply
interpret_status(?POS_PREL,_,_) -> pos_prel;
%% Positive Completion Reply
+interpret_status(?POS_COMPL,?INFORMATION,3) -> pos_size;
interpret_status(?POS_COMPL,_,_) -> pos_compl;
%% Positive Intermediate Reply nedd account
interpret_status(?POS_INTERM,?AUTH_ACC,2) -> pos_interm_acct;
+interpret_status(?POS_INTERM,?FILE_SYSTEM,_) -> pos_complx;
%% Positive Intermediate Reply
interpret_status(?POS_INTERM,_,_) -> pos_interm;
%% No storage area no action taken
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Something went wrong with that request. Please try again.