newer patch to ftp.erl

Luke Gorrie <>
Mon Jan 13 10:59:13 CET 2003


Here's an update of a previously posted patch to ftp.erl, against
inets 2.6.7. The patch is to add incremental (chunked) file
downloading. This newer patch fixes a bug in the old one (on
incremental download of a non-existent file), and changes an io:format
into an error_logger call.

Also at http://www.bluetail.com/~luke/misc/erlang/otp_ftp.patch

-Luke
-------------- next part --------------
--- ftp.erl	2003-01-07 08:15:46.000000000 +0100
+++ /home/luke/misc/ftp.erl	2003-01-13 10:35:01.000000000 +0100
@@ -13,7 +13,7 @@
 %% Portions created by Ericsson are Copyright 1999, Ericsson Utvecklings
 %% AB. All Rights Reserved.''
 %% 
-%%     $Id: ftp.erl,v 1.1.1.3 2002/10/08 07:42:22 magnus Exp $
+%%     $Id: ftp.erl,v 1.1.2.3 2002/12/05 13:49:15 klacke Exp $
 %%
 -module(ftp).
 
@@ -33,7 +33,7 @@
 -export([cd/2, close/1, delete/2, formaterror/1, help/0, 
 	 lcd/2, lpwd/1, ls/1, ls/2, mkdir/2, nlist/1, 
 	 nlist/2, open/1, open/2, open/3, pwd/1, recv/2, recv/3,
-	 recv_bin/2, rename/3, rmdir/2, send/2, send/3, 
+	 recv_bin/2, recv_chunk/2, rename/3, rmdir/2, send/2, send/3, 
 	 send_bin/3, send_chunk/2, send_chunk_end/1,
 	 send_chunk_start/2, type/2, user/3,user/4,account/2,
 	 append/3,append/2,append_bin/3,
@@ -233,6 +233,11 @@
 recv_bin(Pid, RFile) ->
   gen_server:call(Pid, {recv_bin, RFile}, infinity).
 
+recv_chunk(Pid, RFile) ->
+    Ref = make_ref(),
+    gen_server:cast(Pid, {recv_chunk, self(), Ref, RFile}),
+    Ref.
+
 %% send(Pid, LFile [, RFile])
 %%
 %% Purpose:  Transfer file to remote server.
@@ -530,7 +535,7 @@
 	{error,enotconn}->
 	    ?STOP_RET(econn);
 	Error ->
-	    io:format("~p",[Error]),
+	    error_logger:info_msg("~p",[Error]),
 	    {reply, {error, eacct}, State}
     end;
 
@@ -779,6 +784,22 @@
 handle_call(_, _From, State) when State#state.chunk == true ->
   {reply, {error, echunk}, State}.
 
+handle_cast({recv_chunk, From, Ref, RFile}, State) ->
+    #state{csock = CSock, ldir = LDir} = State,
+    LSock = listen_data(CSock, binary),
+    case ctrl_cmd(CSock, "RETR ~s", [RFile]) of
+	pos_prel ->
+	    DSock = accept_data(LSock),
+	    Reply = recv_chunk(DSock,CSock,From,Ref),
+	    sock_close(DSock),
+	    {noreply, State};
+	{error, enotconn} ->
+	    ?STOP_RET(econn);
+	Err ->
+	    From ! {ftp, Ref, {finished, {error, epath}}},
+	    {noreply, State}
+    end;
+
 handle_cast(Msg, State) ->
   {noreply, State}.
 
@@ -944,6 +965,42 @@
 
 %% --------------------------------------------------
 
+%% recv_chunk(DSock, CSock, From, Ref) -> ok
+%% Streams data from DSock to the From process with this protocol:
+%% From ! {ftp, Ref, {data, Pid, Bin}}
+%% From ? {ftp_ack, Ref}
+%% ...
+%% From ! {ftp, Ref, {finished, Result}}
+
+recv_chunk(DSock,CSock, From, Ref) ->
+    Result = recv_chunk1(recv_chunk2(DSock,From,Ref,0),CSock),
+    From ! {ftp, Ref, {finished, Result}}.
+
+recv_chunk1(Reply,Sock) ->
+    case result(Sock) of
+	pos_compl -> Reply;
+	_         -> {error, epath}
+    end.
+
+recv_chunk2(Sock, From, Ref, ?OPER_TIMEOUT) ->
+    sock_close(Sock),
+    {error,eclosed};
+recv_chunk2(Sock, From, Ref, Retry) ->
+    case sock_read(Sock) of
+	{ok, Bin} ->
+	    From ! {ftp, Ref, {data, self(), Bin}},
+	    receive
+		{ftp_ack, Ref} ->
+		    recv_chunk2(Sock, From, Ref, 0)
+	    end;
+	{error, timeout} ->
+	    recv_chunk2(Sock, From, Ref, Retry+1);
+	{closed, _Why} ->
+	    ok
+  end.
+
+%% --------------------------------------------------
+
 %% recv_binary(Sock) = {ok, Bin}
 %% 
 %recv_binary(Sock) ->


More information about the erlang-questions mailing list