diff options
author | Stavros Aronis <[email protected]> | 2011-04-02 18:57:42 +0300 |
---|---|---|
committer | Henrik Nord <[email protected]> | 2011-05-04 15:06:15 +0200 |
commit | ca4633fd683527097451ca1398c90c87bb5c14fc (patch) | |
tree | 3d8e18c9becd4feb7d3ceb1eed24bdce2ef69dd6 /lib/dialyzer/test/r9c_tests_SUITE_data/src/inets/ftp.erl | |
parent | bc619f0cbf9555df6dfc44a499f0cd9cee8bd1be (diff) | |
download | otp-ca4633fd683527097451ca1398c90c87bb5c14fc.tar.gz otp-ca4633fd683527097451ca1398c90c87bb5c14fc.tar.bz2 otp-ca4633fd683527097451ca1398c90c87bb5c14fc.zip |
Rename suite data directories
Diffstat (limited to 'lib/dialyzer/test/r9c_tests_SUITE_data/src/inets/ftp.erl')
-rw-r--r-- | lib/dialyzer/test/r9c_tests_SUITE_data/src/inets/ftp.erl | 1582 |
1 files changed, 0 insertions, 1582 deletions
diff --git a/lib/dialyzer/test/r9c_tests_SUITE_data/src/inets/ftp.erl b/lib/dialyzer/test/r9c_tests_SUITE_data/src/inets/ftp.erl deleted file mode 100644 index be06ec654c..0000000000 --- a/lib/dialyzer/test/r9c_tests_SUITE_data/src/inets/ftp.erl +++ /dev/null @@ -1,1582 +0,0 @@ -%% ``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 via the world wide web 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. -%% -%% The Initial Developer of the Original Code is Ericsson Utvecklings AB. -%% Portions created by Ericsson are Copyright 1999, Ericsson Utvecklings -%% AB. All Rights Reserved.'' -%% -%% $Id: ftp.erl,v 1.2 2009/03/03 01:55:01 kostis Exp $ -%% --module(ftp). - --behaviour(gen_server). - -%% This module implements an ftp client based on socket(3)/gen_tcp(3), -%% file(3) and filename(3). -%% - - --define(OPEN_TIMEOUT, 60*1000). --define(BYTE_TIMEOUT, 1000). % Timeout for _ONE_ byte to arrive. (ms) --define(OPER_TIMEOUT, 300). % Operation timeout (seconds) --define(FTP_PORT, 21). - -%% Client interface --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, - recv_chunk_start/2, 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, - type/2, user/3,user/4,account/2, - append/3, append/2, append_bin/3, - append_chunk/2, append_chunk_end/1, append_chunk_start/2]). - -%% Internal --export([init/1, handle_call/3, handle_cast/2, - handle_info/2, terminate/2,code_change/3]). - - -%% -%% CLIENT FUNCTIONS -%% - -%% open(Host) -%% open(Host, Flags) -%% -%% Purpose: Start an ftp client and connect to a host. -%% Args: Host = string(), -%% Port = integer(), -%% Flags = [Flag], -%% Flag = verbose | debug -%% Returns: {ok, Pid} | {error, ehost} - -%%Tho only option was the host in textual form -open({option_list,Option_list})-> - %% Dbg = {debug,[trace,log,statistics]}, - %% Options = [Dbg], - Options = [], - {ok,Pid1}=case lists:keysearch(flags,1,Option_list) of - {value,{flags,Flags}}-> - {ok, Pid} = gen_server:start_link(?MODULE, [Flags], Options); - false -> - {ok, Pid} = gen_server:start_link(?MODULE, [], Options) - end, - gen_server:call(Pid1, {open, ip_comm,Option_list}, infinity); - - -%%The only option was the tuple form of the ip-number -open(Host)when tuple(Host) -> - open(Host, ?FTP_PORT, []); - -%%Host is the string form of the hostname -open(Host)-> - open(Host,?FTP_PORT,[]). - - - -open(Host, Port) when integer(Port) -> - open(Host,Port,[]); - -open(Host, Flags) when list(Flags) -> - open(Host,?FTP_PORT, Flags). - -open(Host,Port,Flags) when integer(Port), list(Flags) -> - %% Dbg = {debug,[trace,log,statistics]}, - %% Options = [Dbg], - Options = [], - {ok, Pid} = gen_server:start_link(?MODULE, [Flags], Options), - gen_server:call(Pid, {open, ip_comm, Host, Port}, infinity). - -%% user(Pid, User, Pass) -%% Purpose: Login. -%% Args: Pid = pid(), User = Pass = string() -%% Returns: ok | {error, euser} | {error, econn} -user(Pid, User, Pass) -> - gen_server:call(Pid, {user, User, Pass}, infinity). - -%% user(Pid, User, Pass,Acc) -%% Purpose: Login whith a supplied account name -%% Args: Pid = pid(), User = Pass = Acc = string() -%% Returns: ok | {error, euser} | {error, econn} | {error, eacct} -user(Pid, User, Pass,Acc) -> - gen_server:call(Pid, {user, User, Pass,Acc}, infinity). - -%% account(Pid,Acc) -%% Purpose: Set a user Account. -%% Args: Pid = pid(), Acc= string() -%% Returns: ok | {error, eacct} -account(Pid,Acc) -> - gen_server:call(Pid, {account,Acc}, infinity). - -%% pwd(Pid) -%% -%% Purpose: Get the current working directory at remote server. -%% Args: Pid = pid() -%% Returns: {ok, Dir} | {error, elogin} | {error, econn} -pwd(Pid) -> - gen_server:call(Pid, pwd, infinity). - -%% lpwd(Pid) -%% -%% Purpose: Get the current working directory at local server. -%% Args: Pid = pid() -%% Returns: {ok, Dir} | {error, elogin} -lpwd(Pid) -> - gen_server:call(Pid, lpwd, infinity). - -%% cd(Pid, Dir) -%% -%% Purpose: Change current working directory at remote server. -%% Args: Pid = pid(), Dir = string() -%% Returns: ok | {error, epath} | {error, elogin} | {error, econn} -cd(Pid, Dir) -> - gen_server:call(Pid, {cd, Dir}, infinity). - -%% lcd(Pid, Dir) -%% -%% Purpose: Change current working directory for the local client. -%% Args: Pid = pid(), Dir = string() -%% Returns: ok | {error, epath} -lcd(Pid, Dir) -> - gen_server:call(Pid, {lcd, Dir}, infinity). - -%% ls(Pid) -%% ls(Pid, Dir) -%% -%% Purpose: List the contents of current directory (ls/1) or directory -%% Dir (ls/2) at remote server. -%% Args: Pid = pid(), Dir = string() -%% Returns: {ok, Listing} | {error, epath} | {error, elogin} | {error, econn} -ls(Pid) -> - ls(Pid, ""). -ls(Pid, Dir) -> - gen_server:call(Pid, {dir, long, Dir}, infinity). - -%% nlist(Pid) -%% nlist(Pid, Dir) -%% -%% Purpose: List the contents of current directory (ls/1) or directory -%% Dir (ls/2) at remote server. The returned list is a stream -%% of file names. -%% Args: Pid = pid(), Dir = string() -%% Returns: {ok, Listing} | {error, epath} | {error, elogin} | {error, econn} -nlist(Pid) -> - nlist(Pid, ""). -nlist(Pid, Dir) -> - gen_server:call(Pid, {dir, short, Dir}, infinity). - -%% rename(Pid, CurrFile, NewFile) -%% -%% Purpose: Rename a file at remote server. -%% Args: Pid = pid(), CurrFile = NewFile = string() -%% Returns: ok | {error, epath} | {error, elogin} | {error, econn} -rename(Pid, CurrFile, NewFile) -> - gen_server:call(Pid, {rename, CurrFile, NewFile}, infinity). - -%% delete(Pid, File) -%% -%% Purpose: Remove file at remote server. -%% Args: Pid = pid(), File = string() -%% Returns: ok | {error, epath} | {error, elogin} | {error, econn} -delete(Pid, File) -> - gen_server:call(Pid, {delete, File}, infinity). - -%% mkdir(Pid, Dir) -%% -%% Purpose: Make directory at remote server. -%% Args: Pid = pid(), Dir = string() -%% Returns: ok | {error, epath} | {error, elogin} | {error, econn} -mkdir(Pid, Dir) -> - gen_server:call(Pid, {mkdir, Dir}, infinity). - -%% rmdir(Pid, Dir) -%% -%% Purpose: Remove directory at remote server. -%% Args: Pid = pid(), Dir = string() -%% Returns: ok | {error, epath} | {error, elogin} | {error, econn} -rmdir(Pid, Dir) -> - gen_server:call(Pid, {rmdir, Dir}, infinity). - -%% type(Pid, Type) -%% -%% Purpose: Set transfer type. -%% Args: Pid = pid(), Type = ascii | binary -%% Returns: ok | {error, etype} | {error, elogin} | {error, econn} -type(Pid, Type) -> - gen_server:call(Pid, {type, Type}, infinity). - -%% recv(Pid, RFile [, LFile]) -%% -%% Purpose: Transfer file from remote server. -%% Args: Pid = pid(), RFile = LFile = string() -%% Returns: ok | {error, epath} | {error, elogin} | {error, econn} -recv(Pid, RFile) -> - recv(Pid, RFile, ""). - -recv(Pid, RFile, LFile) -> - gen_server:call(Pid, {recv, RFile, LFile}, infinity). - -%% recv_bin(Pid, RFile) -%% -%% Purpose: Transfer file from remote server into binary. -%% Args: Pid = pid(), RFile = string() -%% Returns: {ok, Bin} | {error, epath} | {error, elogin} | {error, econn} -recv_bin(Pid, RFile) -> - gen_server:call(Pid, {recv_bin, RFile}, infinity). - -%% recv_chunk_start(Pid, RFile) -%% -%% Purpose: Start receive of chunks of remote file. -%% Args: Pid = pid(), RFile = string(). -%% Returns: ok | {error, elogin} | {error, epath} | {error, econn} -recv_chunk_start(Pid, RFile) -> - gen_server:call(Pid, {recv_chunk_start, RFile}, infinity). - - -%% recv_chunk(Pid, RFile) -%% -%% Purpose: Transfer file from remote server into binary in chunks -%% Args: Pid = pid(), RFile = string() -%% Returns: Reference -recv_chunk(Pid) -> - gen_server:call(Pid, recv_chunk, infinity). - -%% send(Pid, LFile [, RFile]) -%% -%% Purpose: Transfer file to remote server. -%% Args: Pid = pid(), LFile = RFile = string() -%% Returns: ok | {error, epath} | {error, elogin} | {error, econn} -send(Pid, LFile) -> - send(Pid, LFile, ""). - -send(Pid, LFile, RFile) -> - gen_server:call(Pid, {send, LFile, RFile}, infinity). - -%% send_bin(Pid, Bin, RFile) -%% -%% Purpose: Transfer a binary to a remote file. -%% Args: Pid = pid(), Bin = binary(), RFile = string() -%% Returns: ok | {error, epath} | {error, elogin} | {error, enotbinary} -%% | {error, econn} -send_bin(Pid, Bin, RFile) when binary(Bin) -> - gen_server:call(Pid, {send_bin, Bin, RFile}, infinity); -send_bin(Pid, Bin, RFile) -> - {error, enotbinary}. - -%% send_chunk_start(Pid, RFile) -%% -%% Purpose: Start transfer of chunks to remote file. -%% Args: Pid = pid(), RFile = string(). -%% Returns: ok | {error, elogin} | {error, epath} | {error, econn} -send_chunk_start(Pid, RFile) -> - gen_server:call(Pid, {send_chunk_start, RFile}, infinity). - - -%% append_chunk_start(Pid, RFile) -%% -%% Purpose: Start append chunks of data to remote file. -%% Args: Pid = pid(), RFile = string(). -%% Returns: ok | {error, elogin} | {error, epath} | {error, econn} -append_chunk_start(Pid, RFile) -> - gen_server:call(Pid, {append_chunk_start, RFile}, infinity). - - -%% send_chunk(Pid, Bin) -%% -%% Purpose: Send chunk to remote file. -%% Args: Pid = pid(), Bin = binary(). -%% Returns: ok | {error, elogin} | {error, enotbinary} | {error, echunk} -%% | {error, econn} -send_chunk(Pid, Bin) when binary(Bin) -> - gen_server:call(Pid, {send_chunk, Bin}, infinity); -send_chunk(Pid, Bin) -> - {error, enotbinary}. - -%%append_chunk(Pid, Bin) -%% -%% Purpose: Append chunk to remote file. -%% Args: Pid = pid(), Bin = binary(). -%% Returns: ok | {error, elogin} | {error, enotbinary} | {error, echunk} -%% | {error, econn} -append_chunk(Pid, Bin) when binary(Bin) -> - gen_server:call(Pid, {append_chunk, Bin}, infinity); -append_chunk(Pid, Bin) -> - {error, enotbinary}. - -%% send_chunk_end(Pid) -%% -%% Purpose: End sending of chunks to remote file. -%% Args: Pid = pid(). -%% Returns: ok | {error, elogin} | {error, echunk} | {error, econn} -send_chunk_end(Pid) -> - gen_server:call(Pid, send_chunk_end, infinity). - -%% append_chunk_end(Pid) -%% -%% Purpose: End appending of chunks to remote file. -%% Args: Pid = pid(). -%% Returns: ok | {error, elogin} | {error, echunk} | {error, econn} -append_chunk_end(Pid) -> - gen_server:call(Pid, append_chunk_end, infinity). - -%% append(Pid, LFile,RFile) -%% -%% Purpose: Append the local file to the remote file -%% Args: Pid = pid(), LFile = RFile = string() -%% Returns: ok | {error, epath} | {error, elogin} | {error, econn} -append(Pid, LFile) -> - append(Pid, LFile, ""). - -append(Pid, LFile, RFile) -> - gen_server:call(Pid, {append, LFile, RFile}, infinity). - -%% append_bin(Pid, Bin, RFile) -%% -%% Purpose: Append a binary to a remote file. -%% Args: Pid = pid(), Bin = binary(), RFile = string() -%% Returns: ok | {error, epath} | {error, elogin} | {error, enotbinary} -%% | {error, econn} -append_bin(Pid, Bin, RFile) when binary(Bin) -> - gen_server:call(Pid, {append_bin, Bin, RFile}, infinity); -append_bin(Pid, Bin, RFile) -> - {error, enotbinary}. - - -%% close(Pid) -%% -%% Purpose: End the ftp session. -%% Args: Pid = pid() -%% Returns: ok -close(Pid) -> - case (catch gen_server:call(Pid, close, 30000)) of - ok -> - ok; - {'EXIT',{noproc,_}} -> - %% Already gone... - ok; - Res -> - Res - end. - -%% formaterror(Tag) -%% -%% Purpose: Return diagnostics. -%% Args: Tag = atom() | {error, atom()} -%% Returns: string(). -formaterror(Tag) -> - errstr(Tag). - -%% help() -%% -%% Purpose: Print list of valid commands. -%% -%% Undocumented. -%% -help() -> - io:format("\n Commands:\n" - " ---------\n" - " cd(Pid, Dir)\n" - " close(Pid)\n" - " delete(Pid, File)\n" - " formaterror(Tag)\n" - " help()\n" - " lcd(Pid, Dir)\n" - " lpwd(Pid)\n" - " ls(Pid [, Dir])\n" - " mkdir(Pid, Dir)\n" - " nlist(Pid [, Dir])\n" - " open(Host [Port, Flags])\n" - " pwd(Pid)\n" - " recv(Pid, RFile [, LFile])\n" - " recv_bin(Pid, RFile)\n" - " recv_chunk_start(Pid, RFile)\n" - " recv_chunk(Pid)\n" - " rename(Pid, CurrFile, NewFile)\n" - " rmdir(Pid, Dir)\n" - " send(Pid, LFile [, RFile])\n" - " send_chunk(Pid, Bin)\n" - " send_chunk_start(Pid, RFile)\n" - " send_chunk_end(Pid)\n" - " send_bin(Pid, Bin, RFile)\n" - " append(Pid, LFile [, RFile])\n" - " append_chunk(Pid, Bin)\n" - " append_chunk_start(Pid, RFile)\n" - " append_chunk_end(Pid)\n" - " append_bin(Pid, Bin, RFile)\n" - " type(Pid, Type)\n" - " account(Pid,Account)\n" - " user(Pid, User, Pass)\n" - " user(Pid, User, Pass,Account)\n"). - -%% -%% INIT -%% - --record(state, {csock = undefined, dsock = undefined, flags = undefined, - ldir = undefined, type = undefined, chunk = false, - pending = undefined}). - -init([Flags]) -> - sock_start(), - put(debug,get_debug(Flags)), - put(verbose,get_verbose(Flags)), - process_flag(priority, low), - {ok, LDir} = file:get_cwd(), - {ok, #state{flags = Flags, ldir = LDir}}. - -%% -%% HANDLERS -%% - -%% First group of reply code digits --define(POS_PREL, 1). --define(POS_COMPL, 2). --define(POS_INTERM, 3). --define(TRANS_NEG_COMPL, 4). --define(PERM_NEG_COMPL, 5). - -%% Second group of reply code digits --define(SYNTAX,0). --define(INFORMATION,1). --define(CONNECTION,2). --define(AUTH_ACC,3). --define(UNSPEC,4). --define(FILE_SYSTEM,5). - - --define(STOP_RET(E),{stop, normal, {error, E}, - State#state{csock = undefined}}). - - -rescode(?POS_PREL,_,_) -> pos_prel; %%Positive Preleminary Reply -rescode(?POS_COMPL,_,_) -> pos_compl; %%Positive Completion Reply -rescode(?POS_INTERM,?AUTH_ACC,2) -> pos_interm_acct; %%Positive Intermediate Reply nedd account -rescode(?POS_INTERM,_,_) -> pos_interm; %%Positive Intermediate Reply -rescode(?TRANS_NEG_COMPL,?FILE_SYSTEM,2) -> trans_no_space; %%No storage area no action taken -rescode(?TRANS_NEG_COMPL,_,_) -> trans_neg_compl;%%Temporary Error, no action taken -rescode(?PERM_NEG_COMPL,?FILE_SYSTEM,2) -> perm_no_space; %%Permanent disk space error, the user shall not try again -rescode(?PERM_NEG_COMPL,?FILE_SYSTEM,3) -> perm_fname_not_allowed; -rescode(?PERM_NEG_COMPL,_,_) -> perm_neg_compl. - -retcode(trans_no_space,_) -> etnospc; -retcode(perm_no_space,_) -> epnospc; -retcode(perm_fname_not_allowed,_) -> efnamena; -retcode(_,Otherwise) -> Otherwise. - -handle_call({open,ip_comm,Conn_data},From,State) -> - case lists:keysearch(host,1,Conn_data) of - {value,{host,Host}}-> - Port=get_key1(port,Conn_data,?FTP_PORT), - Timeout=get_key1(timeout,Conn_data,?OPEN_TIMEOUT), - open(Host,Port,Timeout,State); - false -> - ehost - end; - -handle_call({open,ip_comm,Host,Port},From,State) -> - open(Host,Port,?OPEN_TIMEOUT,State); - -handle_call({user, User, Pass}, _From, State) -> - #state{csock = CSock} = State, - case ctrl_cmd(CSock, "USER ~s", [User]) of - pos_interm -> - case ctrl_cmd(CSock, "PASS ~s", [Pass]) of - pos_compl -> - set_type(binary, CSock), - {reply, ok, State#state{type = binary}}; - {error,enotconn} -> - ?STOP_RET(econn); - _ -> - {reply, {error, euser}, State} - end; - pos_compl -> - set_type(binary, CSock), - {reply, ok, State#state{type = binary}}; - {error, enotconn} -> - ?STOP_RET(econn); - _ -> - {reply, {error, euser}, State} - end; - -handle_call({user, User, Pass,Acc}, _From, State) -> - #state{csock = CSock} = State, - case ctrl_cmd(CSock, "USER ~s", [User]) of - pos_interm -> - case ctrl_cmd(CSock, "PASS ~s", [Pass]) of - pos_compl -> - set_type(binary, CSock), - {reply, ok, State#state{type = binary}}; - pos_interm_acct-> - case ctrl_cmd(CSock,"ACCT ~s",[Acc]) of - pos_compl-> - set_type(binary, CSock), - {reply, ok, State#state{type = binary}}; - {error,enotconn}-> - ?STOP_RET(econn); - _ -> - {reply, {error, eacct}, State} - end; - {error,enotconn} -> - ?STOP_RET(econn); - _ -> - {reply, {error, euser}, State} - end; - pos_compl -> - set_type(binary, CSock), - {reply, ok, State#state{type = binary}}; - {error, enotconn} -> - ?STOP_RET(econn); - _ -> - {reply, {error, euser}, State} - end; - -%%set_account(Acc,State)->Reply -%%Reply={reply, {error, euser}, State} | {error,enotconn}-> -handle_call({account,Acc},_From,State)-> - #state{csock = CSock} = State, - case ctrl_cmd(CSock,"ACCT ~s",[Acc]) of - pos_compl-> - {reply, ok,State}; - {error,enotconn}-> - ?STOP_RET(econn); - Error -> - debug(" error: ~p",[Error]), - {reply, {error, eacct}, State} - end; - -handle_call(pwd, _From, State) when State#state.chunk == false -> - #state{csock = CSock} = State, - %% - %% NOTE: The directory string comes over the control connection. - case sock_write(CSock, mk_cmd("PWD", [])) of - ok -> - {_, Line} = result_line(CSock), - {_, Cs} = split($", Line), % XXX Ugly - {Dir0, _} = split($", Cs), - Dir = lists:delete($", Dir0), - {reply, {ok, Dir}, State}; - {error, enotconn} -> - ?STOP_RET(econn) - end; - -handle_call(lpwd, _From, State) -> - #state{csock = CSock, ldir = LDir} = State, - {reply, {ok, LDir}, State}; - -handle_call({cd, Dir}, _From, State) when State#state.chunk == false -> - #state{csock = CSock} = State, - case ctrl_cmd(CSock, "CWD ~s", [Dir]) of - pos_compl -> - {reply, ok, State}; - {error, enotconn} -> - ?STOP_RET(econn); - _ -> - {reply, {error, epath}, State} - end; - -handle_call({lcd, Dir}, _From, State) -> - #state{csock = CSock, ldir = LDir0} = State, - LDir = absname(LDir0, Dir), - case file:read_file_info(LDir) of - {ok, _ } -> - {reply, ok, State#state{ldir = LDir}}; - _ -> - {reply, {error, epath}, State} - end; - -handle_call({dir, Len, Dir}, _From, State) when State#state.chunk == false -> - debug(" dir : ~p: ~s~n",[Len,Dir]), - #state{csock = CSock, type = Type} = State, - set_type(ascii, Type, CSock), - LSock = listen_data(CSock, raw), - Cmd = case Len of - short -> "NLST"; - long -> "LIST" - end, - Result = case Dir of - "" -> - ctrl_cmd(CSock, Cmd, ""); - _ -> - ctrl_cmd(CSock, Cmd ++ " ~s", [Dir]) - end, - debug(" ctrl : command result: ~p~n",[Result]), - case Result of - pos_prel -> - debug(" dbg : await the data connection", []), - DSock = accept_data(LSock), - debug(" dbg : await the data", []), - Reply0 = - case recv_data(DSock) of - {ok, DirData} -> - debug(" data : DirData: ~p~n",[DirData]), - case result(CSock) of - pos_compl -> - {ok, DirData}; - _ -> - {error, epath} - end; - {error, Reason} -> - sock_close(DSock), - verbose(" data : error: ~p, ~p~n",[Reason, result(CSock)]), - {error, epath} - end, - - debug(" ctrl : reply: ~p~n",[Reply0]), - reset_type(ascii, Type, CSock), - {reply, Reply0, State}; - {closed, _Why} -> - ?STOP_RET(econn); - _ -> - sock_close(LSock), - {reply, {error, epath}, State} - end; - - -handle_call({rename, CurrFile, NewFile}, _From, State) when State#state.chunk == false -> - #state{csock = CSock} = State, - case ctrl_cmd(CSock, "RNFR ~s", [CurrFile]) of - pos_interm -> - case ctrl_cmd(CSock, "RNTO ~s", [NewFile]) of - pos_compl -> - {reply, ok, State}; - _ -> - {reply, {error, epath}, State} - end; - {error, enotconn} -> - ?STOP_RET(econn); - _ -> - {reply, {error, epath}, State} - end; - -handle_call({delete, File}, _From, State) when State#state.chunk == false -> - #state{csock = CSock} = State, - case ctrl_cmd(CSock, "DELE ~s", [File]) of - pos_compl -> - {reply, ok, State}; - {error, enotconn} -> - ?STOP_RET(econn); - _ -> - {reply, {error, epath}, State} - end; - -handle_call({mkdir, Dir}, _From, State) when State#state.chunk == false -> - #state{csock = CSock} = State, - case ctrl_cmd(CSock, "MKD ~s", [Dir]) of - pos_compl -> - {reply, ok, State}; - {error, enotconn} -> - ?STOP_RET(econn); - _ -> - {reply, {error, epath}, State} - end; - -handle_call({rmdir, Dir}, _From, State) when State#state.chunk == false -> - #state{csock = CSock} = State, - case ctrl_cmd(CSock, "RMD ~s", [Dir]) of - pos_compl -> - {reply, ok, State}; - {error, enotconn} -> - ?STOP_RET(econn); - _ -> - {reply, {error, epath}, State} - end; - -handle_call({type, Type}, _From, State) when State#state.chunk == false -> - #state{csock = CSock} = State, - case Type of - ascii -> - set_type(ascii, CSock), - {reply, ok, State#state{type = ascii}}; - binary -> - set_type(binary, CSock), - {reply, ok, State#state{type = binary}}; - _ -> - {reply, {error, etype}, State} - end; - -handle_call({recv, RFile, LFile}, _From, State) when State#state.chunk == false -> - #state{csock = CSock, ldir = LDir} = State, - ALFile = case LFile of - "" -> - absname(LDir, RFile); - _ -> - absname(LDir, LFile) - end, - case file_open(ALFile, write) of - {ok, Fd} -> - LSock = listen_data(CSock, binary), - Ret = case ctrl_cmd(CSock, "RETR ~s", [RFile]) of - pos_prel -> - DSock = accept_data(LSock), - recv_file(DSock, Fd), - Reply0 = case result(CSock) of - pos_compl -> - ok; - _ -> - {error, epath} - end, - sock_close(DSock), - {reply, Reply0, State}; - {error, enotconn} -> - ?STOP_RET(econn); - _ -> - {reply, {error, epath}, State} - end, - file_close(Fd), - Ret; - {error, _What} -> - {reply, {error, epath}, State} - end; - -handle_call({recv_bin, RFile}, _From, State) when State#state.chunk == false -> - #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_binary(DSock,CSock), - sock_close(DSock), - {reply, Reply, State}; - {error, enotconn} -> - ?STOP_RET(econn); - _ -> - {reply, {error, epath}, State} - end; - - -handle_call({recv_chunk_start, RFile}, _From, State) - when State#state.chunk == false -> - start_chunk_transfer("RETR",RFile,State); - -handle_call(recv_chunk, _From, State) - when State#state.chunk == true -> - do_recv_chunk(State); - - -handle_call({send, LFile, RFile}, _From, State) - when State#state.chunk == false -> - transfer_file("STOR",LFile,RFile,State); - -handle_call({append, LFile, RFile}, _From, State) - when State#state.chunk == false -> - transfer_file("APPE",LFile,RFile,State); - - -handle_call({send_bin, Bin, RFile}, _From, State) - when State#state.chunk == false -> - transfer_data("STOR",Bin,RFile,State); - -handle_call({append_bin, Bin, RFile}, _From, State) - when State#state.chunk == false -> - transfer_data("APPE",Bin,RFile,State); - - - -handle_call({send_chunk_start, RFile}, _From, State) - when State#state.chunk == false -> - start_chunk_transfer("STOR",RFile,State); - -handle_call({append_chunk_start,RFile},_From,State) - when State#state.chunk==false-> - start_chunk_transfer("APPE",RFile,State); - -handle_call({send_chunk, Bin}, _From, State) - when State#state.chunk == true -> - chunk_transfer(Bin,State); - -handle_call({append_chunk, Bin}, _From, State) - when State#state.chunk == true -> - chunk_transfer(Bin,State); - -handle_call(append_chunk_end, _From, State) - when State#state.chunk == true -> - end_chunk_transfer(State); - -handle_call(send_chunk_end, _From, State) - when State#state.chunk == true -> - end_chunk_transfer(State); - - - -handle_call(close, _From, State) when State#state.chunk == false -> - #state{csock = CSock} = State, - ctrl_cmd(CSock, "QUIT", []), - sock_close(CSock), - {stop, normal, ok, State}; - -handle_call(_, _From, State) when State#state.chunk == true -> - {reply, {error, echunk}, State}. - - -handle_cast(Msg, State) -> - {noreply, State}. - - -handle_info({Sock, {fromsocket, Bytes}}, State) when Sock == State#state.csock -> - put(leftovers, Bytes ++ leftovers()), - {noreply, State}; - -%% Data connection closed (during chunk sending) -handle_info({Sock, {socket_closed, _Reason}}, State) when Sock == State#state.dsock -> - {noreply, State#state{dsock = undefined}}; - -%% Control connection closed. -handle_info({Sock, {socket_closed, _Reason}}, State) when Sock == State#state.csock -> - debug(" sc : ~s~n",[leftovers()]), - {stop, ftp_server_close, State#state{csock = undefined}}; - -handle_info(Info, State) -> - error_logger:info_msg("ftp : ~w : Unexpected message: ~w\n", [self(),Info]), - {noreply, State}. - -code_change(OldVsn,State,Extra)-> - {ok,State}. - -terminate(Reason, State) -> - ok. -%% -%% OPEN CONNECTION -%% -open(Host,Port,Timeout,State)-> - case sock_connect(Host,Port,Timeout) of - {error, What} -> - {stop, normal, {error, What}, State}; - CSock -> - case result(CSock, State#state.flags) of - {error,Reason} -> - sock_close(CSock), - {stop,normal,{error,Reason},State}; - _ -> % We should really check this... - {reply, {ok, self()}, State#state{csock = CSock}} - end - end. - - - -%% -%% CONTROL CONNECTION -%% - -ctrl_cmd(CSock, Fmt, Args) -> - Cmd = mk_cmd(Fmt, Args), - case sock_write(CSock, Cmd) of - ok -> - debug(" cmd : ~s",[Cmd]), - result(CSock); - {error, enotconn} -> - {error, enotconn}; - Other -> - Other - end. - -mk_cmd(Fmt, Args) -> - [io_lib:format(Fmt, Args)| "\r\n"]. % Deep list ok. - -%% -%% TRANSFER TYPE -%% - -%% -%% set_type(NewType, CurrType, CSock) -%% reset_type(NewType, CurrType, CSock) -%% -set_type(Type, Type, CSock) -> - ok; -set_type(NewType, _OldType, CSock) -> - set_type(NewType, CSock). - -reset_type(Type, Type, CSock) -> - ok; -reset_type(_NewType, OldType, CSock) -> - set_type(OldType, CSock). - -set_type(ascii, CSock) -> - ctrl_cmd(CSock, "TYPE A", []); -set_type(binary, CSock) -> - ctrl_cmd(CSock, "TYPE I", []). - -%% -%% DATA CONNECTION -%% - -%% Create a listen socket for a data connection and send a PORT command -%% containing the IP address and port number. Mode is binary or raw. -%% -listen_data(CSock, Mode) -> - {IP, _} = sock_name(CSock), % IP address of control conn. - LSock = sock_listen(Mode, IP), - Port = sock_listen_port(LSock), - {A1, A2, A3, A4} = IP, - {P1, P2} = {Port div 256, Port rem 256}, - ctrl_cmd(CSock, "PORT ~w,~w,~w,~w,~w,~w", [A1, A2, A3, A4, P1, P2]), - LSock. - -%% -%% Accept the data connection and close the listen socket. -%% -accept_data(LSock) -> - Sock = sock_accept(LSock), - sock_close(LSock), - Sock. - -%% -%% DATA COLLECTION (ls, dir) -%% -%% Socket is a byte stream in ASCII mode. -%% - -%% Receive data (from data connection). -recv_data(Sock) -> - recv_data(Sock, [], 0). -recv_data(Sock, Sofar, ?OPER_TIMEOUT) -> - sock_close(Sock), - {ok, lists:flatten(lists:reverse(Sofar))}; -recv_data(Sock, Sofar, Retry) -> - case sock_read(Sock) of - {ok, Data} -> - debug(" dbg : received some data: ~n~s", [Data]), - recv_data(Sock, [Data| Sofar], 0); - {error, timeout} -> - %% Retry.. - recv_data(Sock, Sofar, Retry+1); - {error, Reason} -> - SoFar1 = lists:flatten(lists:reverse(Sofar)), - {error, {socket_error, Reason, SoFar1, Retry}}; - {closed, _} -> - {ok, lists:flatten(lists:reverse(Sofar))} - end. - -%% -%% BINARY TRANSFER -%% - -%% -------------------------------------------------- - -%% recv_binary(DSock,CSock) = {ok,Bin} | {error,Reason} -%% -recv_binary(DSock,CSock) -> - recv_binary1(recv_binary2(DSock,[],0),CSock). - -recv_binary1(Reply,Sock) -> - case result(Sock) of - pos_compl -> Reply; - _ -> {error, epath} - end. - -recv_binary2(Sock, _Bs, ?OPER_TIMEOUT) -> - sock_close(Sock), - {error,eclosed}; -recv_binary2(Sock, Bs, Retry) -> - case sock_read(Sock) of - {ok, Bin} -> - recv_binary2(Sock, [Bs, Bin], 0); - {error, timeout} -> - recv_binary2(Sock, Bs, Retry+1); - {closed, _Why} -> - {ok,list_to_binary(Bs)} - end. - -%% -------------------------------------------------- - -%% -%% recv_chunk -%% - -do_recv_chunk(#state{dsock = undefined} = State) -> - {reply, {error,econn}, State}; -do_recv_chunk(State) -> - recv_chunk1(recv_chunk2(State, 0), State). - -recv_chunk1({ok, _Bin} = Reply, State) -> - {reply, Reply, State}; -%% Reply = ok | {error, Reason} -recv_chunk1(Reply, #state{csock = CSock} = State) -> - State1 = State#state{dsock = undefined, chunk = false}, - case result(CSock) of - pos_compl -> - {reply, Reply, State1}; - _ -> - {reply, {error, epath}, State1} - end. - -recv_chunk2(#state{dsock = DSock} = State, ?OPER_TIMEOUT) -> - sock_close(DSock), - {error, eclosed}; -recv_chunk2(#state{dsock = DSock} = State, Retry) -> - case sock_read(DSock) of - {ok, Bin} -> - {ok, Bin}; - {error, timeout} -> - recv_chunk2(State, Retry+1); - {closed, Reason} -> - debug(" dbg : socket closed: ~p", [Reason]), - ok - end. - - -%% -------------------------------------------------- - -%% -%% FILE TRANSFER -%% - -recv_file(Sock, Fd) -> - recv_file(Sock, Fd, 0). - -recv_file(Sock, Fd, ?OPER_TIMEOUT) -> - sock_close(Sock), - {closed, timeout}; -recv_file(Sock, Fd, Retry) -> - case sock_read(Sock) of - {ok, Bin} -> - file_write(Fd, Bin), - recv_file(Sock, Fd); - {error, timeout} -> - recv_file(Sock, Fd, Retry+1); -% {error, Reason} -> -% SoFar1 = lists:flatten(lists:reverse(Sofar)), -% exit({socket_error, Reason, Sock, SoFar1, Retry}); - {closed, How} -> - {closed, How} - end. - -%% -%% send_file(Fd, Sock) = ok | {error, Why} -%% - -send_file(Fd, Sock) -> - {N, Bin} = file_read(Fd), - if - N > 0 -> - case sock_write(Sock, Bin) of - ok -> - send_file(Fd, Sock); - {error, Reason} -> - {error, Reason} - end; - true -> - ok - end. - - - -%% -%% PARSING OF RESULT LINES -%% - -%% Excerpt from RFC 959: -%% -%% "A reply is defined to contain the 3-digit code, followed by Space -%% <SP>, followed by one line of text (where some maximum line length -%% has been specified), and terminated by the Telnet end-of-line -%% code. There will be cases however, where the text is longer than -%% a single line. In these cases the complete text must be bracketed -%% so the User-process knows when it may stop reading the reply (i.e. -%% stop processing input on the control connection) and go do other -%% things. This requires a special format on the first line to -%% indicate that more than one line is coming, and another on the -%% last line to designate it as the last. At least one of these must -%% contain the appropriate reply code to indicate the state of the -%% transaction. To satisfy all factions, it was decided that both -%% the first and last line codes should be the same. -%% -%% Thus the format for multi-line replies is that the first line -%% will begin with the exact required reply code, followed -%% immediately by a Hyphen, "-" (also known as Minus), followed by -%% text. The last line will begin with the same code, followed -%% immediately by Space <SP>, optionally some text, and the Telnet -%% end-of-line code. -%% -%% For example: -%% 123-First line -%% Second line -%% 234 A line beginning with numbers -%% 123 The last line -%% -%% The user-process then simply needs to search for the second -%% occurrence of the same reply code, followed by <SP> (Space), at -%% the beginning of a line, and ignore all intermediary lines. If -%% an intermediary line begins with a 3-digit number, the Server -%% must pad the front to avoid confusion. -%% -%% This scheme allows standard system routines to be used for -%% reply information (such as for the STAT reply), with -%% "artificial" first and last lines tacked on. In rare cases -%% where these routines are able to generate three digits and a -%% Space at the beginning of any line, the beginning of each -%% text line should be offset by some neutral text, like Space. -%% -%% This scheme assumes that multi-line replies may not be nested." - -%% We have to collect the stream of result characters into lines (ending -%% in "\r\n"; we check for "\n"). When a line is assembled, left-over -%% characters are saved in the process dictionary. -%% - -%% result(Sock) = rescode() -%% -result(Sock) -> - result(Sock, false). - -result_line(Sock) -> - result(Sock, true). - -%% result(Sock, Bool) = {error,Reason} | rescode() | {rescode(), Lines} -%% Printout if Bool = true. -%% -result(Sock, RetForm) -> - case getline(Sock) of - Line when length(Line) > 3 -> - [D1, D2, D3| Tail] = Line, - case Tail of - [$-| _] -> - parse_to_end(Sock, [D1, D2, D3, $ ]); % 3 digits + space - _ -> - ok - end, - result(D1,D2,D3,Line,RetForm); - _ -> - retform(rescode(?PERM_NEG_COMPL,-1,-1),[],RetForm) - end. - -result(D1,_D2,_D3,Line,_RetForm) when D1 - $0 > 10 -> - {error,{invalid_server_response,Line}}; -result(D1,_D2,_D3,Line,_RetForm) when D1 - $0 < 0 -> - {error,{invalid_server_response,Line}}; -result(D1,D2,D3,Line,RetForm) -> - Res1 = D1 - $0, - Res2 = D2 - $0, - Res3 = D3 - $0, - verbose(" ~w : ~s", [Res1, Line]), - retform(rescode(Res1,Res2,Res3),Line,RetForm). - -retform(ResCode,Line,true) -> - {ResCode,Line}; -retform(ResCode,_,_) -> - ResCode. - -leftovers() -> - case get(leftovers) of - undefined -> []; - X -> X - end. - -%% getline(Sock) = Line -%% -getline(Sock) -> - getline(Sock, leftovers()). - -getline(Sock, Rest) -> - getline1(Sock, split($\n, Rest), 0). - -getline1(Sock, {[], Rest}, ?OPER_TIMEOUT) -> - sock_close(Sock), - put(leftovers, Rest), - []; -getline1(Sock, {[], Rest}, Retry) -> - case sock_read(Sock) of - {ok, More} -> - debug(" read : ~s~n",[More]), - getline(Sock, Rest ++ More); - {error, timeout} -> - %% Retry.. - getline1(Sock, {[], Rest}, Retry+1); - Error -> - put(leftovers, Rest), - [] - end; -getline1(Sock, {Line, Rest}, Retry) -> - put(leftovers, Rest), - Line. - -parse_to_end(Sock, Prefix) -> - Line = getline(Sock), - case lists:prefix(Prefix, Line) of - false -> - parse_to_end(Sock, Prefix); - true -> - ok - end. - - -%% Split list after first occurence of S. -%% Returns {Prefix, Suffix} ({[], Cs} if S not found). -split(S, Cs) -> - split(S, Cs, []). - -split(S, [S| Cs], As) -> - {lists:reverse([S|As]), Cs}; -split(S, [C| Cs], As) -> - split(S, Cs, [C| As]); -split(_, [], As) -> - {[], lists:reverse(As)}. - -%% -%% FILE INTERFACE -%% -%% All files are opened raw in binary mode. -%% --define(BUFSIZE, 4096). - -file_open(File, Option) -> - file:open(File, [raw, binary, Option]). - -file_close(Fd) -> - file:close(Fd). - - -file_read(Fd) -> % Compatible with pre R2A. - case file:read(Fd, ?BUFSIZE) of - {ok, {N, Bytes}} -> - {N, Bytes}; - {ok, Bytes} -> - {size(Bytes), Bytes}; - eof -> - {0, []} - end. - -file_write(Fd, Bytes) -> - file:write(Fd, Bytes). - -absname(Dir, File) -> % Args swapped. - filename:absname(File, Dir). - - - -%% sock_start() -%% - -%% -%% USE GEN_TCP -%% - -sock_start() -> - inet_db:start(). - -%% -%% Connect to FTP server at Host (default is TCP port 21) in raw mode, -%% in order to establish a control connection. -%% - -sock_connect(Host,Port,TimeOut) -> - debug(" info : connect to server on ~p:~p~n",[Host,Port]), - Opts = [{packet, 0}, {active, false}], - case (catch gen_tcp:connect(Host, Port, Opts,TimeOut)) of - {'EXIT', R1} -> % XXX Probably no longer needed. - debug(" error: socket connectionn failed with exit reason:" - "~n ~p",[R1]), - {error, ehost}; - {error, R2} -> - debug(" error: socket connectionn failed with exit reason:" - "~n ~p",[R2]), - {error, ehost}; - {ok, Sock} -> - Sock - end. - -%% -%% Create a listen socket (any port) in binary or raw non-packet mode for -%% data connection. -%% -sock_listen(Mode, IP) -> - Opts = case Mode of - binary -> - [binary, {packet, 0}]; - raw -> - [{packet, 0}] - end, - {ok, Sock} = gen_tcp:listen(0, [{ip, IP}, {active, false} | Opts]), - Sock. - -sock_accept(LSock) -> - {ok, Sock} = gen_tcp:accept(LSock), - Sock. - -sock_close(undefined) -> - ok; -sock_close(Sock) -> - gen_tcp:close(Sock). - -sock_read(Sock) -> - case gen_tcp:recv(Sock, 0, ?BYTE_TIMEOUT) of - {ok, Bytes} -> - {ok, Bytes}; - - {error, closed} -> - {closed, closed}; % Yes - - %% --- OTP-4770 begin --- - %% - %% This seems to happen on windows - %% "Someone" tried to close an already closed socket... - %% - - {error, enotsock} -> - {closed, enotsock}; - - %% - %% --- OTP-4770 end --- - - {error, etimedout} -> - {error, timeout}; - - Other -> - Other - end. - -%% receive -%% {tcp, Sock, Bytes} -> -%% {ok, Bytes}; -%% {tcp_closed, Sock} -> -%% {closed, closed} -%% end. - -sock_write(Sock, Bytes) -> - gen_tcp:send(Sock, Bytes). - -sock_name(Sock) -> - {ok, {IP, Port}} = inet:sockname(Sock), - {IP, Port}. - -sock_listen_port(LSock) -> - {ok, Port} = inet:port(LSock), - Port. - - -%% -%% ERROR STRINGS -%% -errstr({error, Reason}) -> - errstr(Reason); - -errstr(echunk) -> "Synchronisation error during chung sending."; -errstr(eclosed) -> "Session has been closed."; -errstr(econn) -> "Connection to remote server prematurely closed."; -errstr(eexists) ->"File or directory already exists."; -errstr(ehost) -> "Host not found, FTP server not found, " -"or connection rejected."; -errstr(elogin) -> "User not logged in."; -errstr(enotbinary) -> "Term is not a binary."; -errstr(epath) -> "No such file or directory, already exists, " -"or permission denied."; -errstr(etype) -> "No such type."; -errstr(euser) -> "User name or password not valid."; -errstr(etnospc) -> "Insufficient storage space in system."; -errstr(epnospc) -> "Exceeded storage allocation " -"(for current directory or dataset)."; -errstr(efnamena) -> "File name not allowed."; -errstr(Reason) -> - lists:flatten(io_lib:format("Unknown error: ~w", [Reason])). - - - -%% ---------------------------------------------------------- - -get_verbose(Params) -> check_param(verbose,Params). - -get_debug(Flags) -> check_param(debug,Flags). - -check_param(P,Ps) -> lists:member(P,Ps). - - -%% verbose -> ok -%% -%% Prints the string if the Flags list is non-epmty -%% -%% Params: F Format string -%% A Arguments to the format string -%% -verbose(F,A) -> verbose(get(verbose),F,A). - -verbose(true,F,A) -> print(F,A); -verbose(_,_F,_A) -> ok. - - - - -%% debug -> ok -%% -%% Prints the string if debug enabled -%% -%% Params: F Format string -%% A Arguments to the format string -%% -debug(F,A) -> debug(get(debug),F,A). - -debug(true,F,A) -> print(F,A); -debug(_,_F,_A) -> ok. - - -print(F,A) -> io:format(F,A). - - - -transfer_file(Cmd,LFile,RFile,State)-> - #state{csock = CSock, ldir = LDir} = State, - ARFile = case RFile of - "" -> - LFile; - _ -> - RFile - end, - ALFile = absname(LDir, LFile), - case file_open(ALFile, read) of - {ok, Fd} -> - LSock = listen_data(CSock, binary), - case ctrl_cmd(CSock, "~s ~s", [Cmd,ARFile]) of - pos_prel -> - DSock = accept_data(LSock), - SFreply = send_file(Fd, DSock), - file_close(Fd), - sock_close(DSock), - case {SFreply,result(CSock)} of - {ok,pos_compl} -> - {reply, ok, State}; - {ok,Other} -> - debug(" error: unknown reply: ~p~n",[Other]), - {reply, {error, epath}, State}; - {{error,Why},Result} -> - ?STOP_RET(retcode(Result,econn)) - end; - {error, enotconn} -> - ?STOP_RET(econn); - Other -> - debug(" error: ctrl failed: ~p~n",[Other]), - {reply, {error, epath}, State} - end; - {error, Reason} -> - debug(" error: file open: ~p~n",[Reason]), - {reply, {error, epath}, State} - end. - -transfer_data(Cmd,Bin,RFile,State)-> - #state{csock = CSock, ldir = LDir} = State, - LSock = listen_data(CSock, binary), - case ctrl_cmd(CSock, "~s ~s", [Cmd,RFile]) of - pos_prel -> - DSock = accept_data(LSock), - SReply = sock_write(DSock, Bin), - sock_close(DSock), - case {SReply,result(CSock)} of - {ok,pos_compl} -> - {reply, ok, State}; - {ok,trans_no_space} -> - ?STOP_RET(etnospc); - {ok,perm_no_space} -> - ?STOP_RET(epnospc); - {ok,perm_fname_not_allowed} -> - ?STOP_RET(efnamena); - {ok,Other} -> - debug(" error: unknown reply: ~p~n",[Other]), - {reply, {error, epath}, State}; - {{error,Why},Result} -> - ?STOP_RET(retcode(Result,econn)) - %% {{error,_Why},_Result} -> - %% ?STOP_RET(econn) - end; - - {error, enotconn} -> - ?STOP_RET(econn); - - Other -> - debug(" error: ctrl failed: ~p~n",[Other]), - {reply, {error, epath}, State} - end. - - -start_chunk_transfer(Cmd, RFile, #state{csock = CSock} = State) -> - LSock = listen_data(CSock, binary), - case ctrl_cmd(CSock, "~s ~s", [Cmd,RFile]) of - pos_prel -> - DSock = accept_data(LSock), - {reply, ok, State#state{dsock = DSock, chunk = true}}; - {error, enotconn} -> - ?STOP_RET(econn); - Otherwise -> - debug(" error: ctrl failed: ~p~n",[Otherwise]), - {reply, {error, epath}, State} - end. - - -chunk_transfer(Bin,State)-> - #state{dsock = DSock, csock = CSock} = State, - case DSock of - undefined -> - {reply,{error,econn},State}; - _ -> - case sock_write(DSock, Bin) of - ok -> - {reply, ok, State}; - Other -> - debug(" error: chunk write error: ~p~n",[Other]), - {reply, {error, econn}, State#state{dsock = undefined}} - end - end. - - - -end_chunk_transfer(State)-> - #state{csock = CSock, dsock = DSock} = State, - case DSock of - undefined -> - Result = result(CSock), - case Result of - pos_compl -> - {reply,ok,State#state{dsock = undefined, - chunk = false}}; - trans_no_space -> - ?STOP_RET(etnospc); - perm_no_space -> - ?STOP_RET(epnospc); - perm_fname_not_allowed -> - ?STOP_RET(efnamena); - Result -> - debug(" error: send chunk end (1): ~p~n", - [Result]), - {reply,{error,epath},State#state{dsock = undefined, - chunk = false}} - end; - _ -> - sock_close(DSock), - Result = result(CSock), - case Result of - pos_compl -> - {reply,ok,State#state{dsock = undefined, - chunk = false}}; - trans_no_space -> - sock_close(CSock), - ?STOP_RET(etnospc); - perm_no_space -> - sock_close(CSock), - ?STOP_RET(epnospc); - perm_fname_not_allowed -> - sock_close(CSock), - ?STOP_RET(efnamena); - Result -> - debug(" error: send chunk end (2): ~p~n", - [Result]), - {reply,{error,epath},State#state{dsock = undefined, - chunk = false}} - end - end. - -get_key1(Key,List,Default)-> - case lists:keysearch(Key,1,List)of - {value,{_,Val}}-> - Val; - false-> - Default - end. |