ftp.erl
来自「OTP是开放电信平台的简称」· ERL 代码 · 共 1,598 行 · 第 1/4 页
ERL
1,598 行
%% ``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$%%%% Description: This module implements an ftp client, RFC 959. %% It also supports ipv6 RFC 2428.-module(ftp).-behaviour(gen_server).%% 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, 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, 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]).%% gen_server callbacks-export([init/1, handle_call/3, handle_cast/2, handle_info/2, terminate/2, code_change/3]).%% supervisor callbacks-export([start_link_sup/1]).-include("ftp_internal.hrl").%% Constante used in internal state definition-define(CONNECTION_TIMEOUT, 60*1000).-define(DEFAULT_MODE, passive).%% Internal Constants-define(FTP_PORT, 21).-define(FILE_BUFSIZE, 4096).%% Internal state-record(state, { csock = undefined, % socket() - Control connection socket dsock = undefined, % socket() - Data connection socket verbose = false, % boolean() ldir = undefined, % string() - Current local directory type = ftp_server_default, % atom() - binary | ascii chunk = false, % boolean() - Receiving data chunks mode = ?DEFAULT_MODE, % passive | active timeout = ?CONNECTION_TIMEOUT, % integer() %% Data received so far on the data connection data = <<>>, % binary() %% Data received so far on the control connection %% {BinStream, AccLines}. If a binary sequence %% ends with ?CR then keep it in the binary to %% be able to detect if the next received byte is ?LF %% and hence the end of the response is reached! ctrl_data = {<<>>, [], start}, % {binary(), [bytes()], LineStatus} %% pid() - Client pid (note not the same as "From") owner = undefined, client = undefined, % "From" to be used in gen_server:reply/2 %% Function that activated a connection and maybe some %% data needed further on. caller = undefined, % term() ip_v6_disabled, % boolean() progress = ignore % ignore | pid() }).%%%=========================================================================%%% API - CLIENT FUNCTIONS%%%=========================================================================%%--------------------------------------------------------------------------%% open(Host, <Port>, <Flags>) -> {ok, Pid} | {error, ehost}%% Host = string(), %% Port = integer(), %% Flags = [Flag], %% Flag = verbose | debug | trace%%%% Description: Start an ftp client and connect to a host.%%--------------------------------------------------------------------------%% The only option was the host in textual formopen({option_list, Options})-> ensure_started(), Flags = key_search(flags, Options, []), {ok, Pid} = ftp_sup:start_child([[[{client, self()}, Flags], []]]), call(Pid, {open, ip_comm, Options}, pid); %% The only option was the tuple form of the ip-numberopen(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) -> ensure_started(), {ok, Pid} = ftp_sup:start_child([[[{client, self()}, Flags], []]]), Opts = [{host, Host}, {port, Port}| Flags], call(Pid, {open, ip_comm, Opts}, pid).%%--------------------------------------------------------------------------%% user(Pid, User, Pass, <Acc>) -> ok | {error, euser} | {error, econn} %% | {error, eacct}%% Pid = pid(), %% User = Pass = Acc = string()%%%% Description: Login with or without a supplied account name.%%--------------------------------------------------------------------------user(Pid, User, Pass) -> call(Pid, {user, User, Pass}, atom).user(Pid, User, Pass, Acc) -> call(Pid, {user, User, Pass, Acc}, atom).%%--------------------------------------------------------------------------%% account(Pid, Acc) -> ok | {error, eacct}%% Pid = pid()%% Acc= string()%%%% Description: Set a user Account.%%--------------------------------------------------------------------------account(Pid, Acc) -> call(Pid, {account, Acc}, atom).%%--------------------------------------------------------------------------%% pwd(Pid) -> {ok, Dir} | {error, elogin} | {error, econn} %% Pid = pid()%% Dir = string()%%%% Description: Get the current working directory at remote server.%%--------------------------------------------------------------------------pwd(Pid) -> call(Pid, pwd, ctrl).%%--------------------------------------------------------------------------%% lpwd(Pid) -> {ok, Dir} | {error, elogin} %% Pid = pid()%% Dir = string()%%%% Description: Get the current working directory at local server.%%--------------------------------------------------------------------------lpwd(Pid) -> call(Pid, lpwd, string).%%--------------------------------------------------------------------------%% cd(Pid, Dir) -> ok | {error, epath} | {error, elogin} | {error, econn}%% Pid = pid()%% Dir = string()%%%% Description: Change current working directory at remote server.%%--------------------------------------------------------------------------cd(Pid, Dir) -> call(Pid, {cd, Dir}, atom).%%--------------------------------------------------------------------------%% lcd(Pid, Dir) -> ok | {error, epath}%% Pid = pid()%% Dir = string()%%%% Description: Change current working directory for the local client.%%--------------------------------------------------------------------------lcd(Pid, Dir) -> call(Pid, {lcd, Dir}, string).%%--------------------------------------------------------------------------%% ls(Pid, <Dir>) -> {ok, Listing} | {error, epath} | {error, elogin} | %% {error, econn}%% Pid = pid()%% Dir = string()%% Listing = string()%%%% Description: List the contents of current directory (ls/1) or%% directory Dir (ls/2) at remote server.%%--------------------------------------------------------------------------ls(Pid) -> ls(Pid, "").ls(Pid, Dir) -> call(Pid, {dir, long, Dir}, string).%%--------------------------------------------------------------------------%% nlist(Pid, <Dir>) -> {ok, Listing} | {error, epath} | {error, elogin} | %% {error, econn}%% Pid = pid()%% Dir = string()%%%% Description: 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.%%--------------------------------------------------------------------------nlist(Pid) -> nlist(Pid, "").nlist(Pid, Dir) -> call(Pid, {dir, short, Dir}, string).%%--------------------------------------------------------------------------%% rename(Pid, CurrFile, NewFile) -> ok | {error, epath} | {error, elogin} %% | {error, econn}%% Pid = pid()%% CurrFile = NewFile = string()%%%% Description: Rename a file at remote server.%%--------------------------------------------------------------------------rename(Pid, CurrFile, NewFile) -> call(Pid, {rename, CurrFile, NewFile}, string).%%--------------------------------------------------------------------------%% delete(Pid, File) -> ok | {error, epath} | {error, elogin} | %% {error, econn}%% Pid = pid()%% File = string()%%%% Description: Remove file at remote server.%%--------------------------------------------------------------------------delete(Pid, File) -> call(Pid, {delete, File}, string).%%--------------------------------------------------------------------------%% mkdir(Pid, Dir) -> ok | {error, epath} | {error, elogin} | {error, econn}%% Pid = pid(), %% Dir = string()%%%% Description: Make directory at remote server.%%--------------------------------------------------------------------------mkdir(Pid, Dir) -> call(Pid, {mkdir, Dir}, atom).%%--------------------------------------------------------------------------%% rmdir(Pid, Dir) -> ok | {error, epath} | {error, elogin} | {error, econn}%% Pid = pid(), %% Dir = string()%%%% Description: Remove directory at remote server.%%--------------------------------------------------------------------------rmdir(Pid, Dir) -> call(Pid, {rmdir, Dir}, atom).%%--------------------------------------------------------------------------%% type(Pid, Type) -> ok | {error, etype} | {error, elogin} | {error, econn}%% Pid = pid() %% Type = ascii | binary%%%% Description: Set transfer type.%%--------------------------------------------------------------------------type(Pid, Type) -> call(Pid, {type, Type}, atom).%%--------------------------------------------------------------------------%% recv(Pid, RemoteFileName <LocalFileName>) -> ok | {error, epath} |%% {error, elogin} | {error, econn}%% Pid = pid()%% RemoteFileName = LocalFileName = string()%%%% Description: Transfer file from remote server.%%--------------------------------------------------------------------------recv(Pid, RemotFileName) -> recv(Pid, RemotFileName, RemotFileName).recv(Pid, RemotFileName, LocalFileName) -> call(Pid, {recv, RemotFileName, LocalFileName}, atom).%%--------------------------------------------------------------------------%% recv_bin(Pid, RemoteFile) -> {ok, Bin} | {error, epath} | {error, elogin} %% | {error, econn}%% Pid = pid()%% RemoteFile = string()%% Bin = binary()%%%% Description: Transfer file from remote server into binary.%%--------------------------------------------------------------------------recv_bin(Pid, RemoteFile) -> call(Pid, {recv_bin, RemoteFile}, bin).%%--------------------------------------------------------------------------%% recv_chunk_start(Pid, RemoteFile) -> ok | {error, elogin} | {error, epath} %% | {error, econn}%% Pid = pid()%% RemoteFile = string()%%%% Description: Start receive of chunks of remote file.%%--------------------------------------------------------------------------recv_chunk_start(Pid, RemoteFile) -> call(Pid, {recv_chunk_start, RemoteFile}, atom).%%--------------------------------------------------------------------------%% recv_chunk(Pid, RemoteFile) -> ok | {ok, Bin} | {error, Reason}%% Pid = pid()%% RemoteFile = string()%%%% Description: Transfer file from remote server into binary in chunks%%--------------------------------------------------------------------------recv_chunk(Pid) -> call(Pid, recv_chunk, atom).%%--------------------------------------------------------------------------%% send(Pid, LocalFileName <RemotFileName>) -> ok | {error, epath} %% | {error, elogin} %% | {error, econn}%% Pid = pid()%% LocalFileName = RemotFileName = string()%%%% Description: Transfer file to remote server.%%--------------------------------------------------------------------------send(Pid, LocalFileName) -> send(Pid, LocalFileName, LocalFileName).send(Pid, LocalFileName, RemotFileName) -> call(Pid, {send, LocalFileName, RemotFileName}, atom).%%--------------------------------------------------------------------------%% send_bin(Pid, Bin, RemoteFile) -> ok | {error, epath} | {error, elogin} %% | {error, enotbinary} | {error, econn}%% Pid = pid()%% Bin = binary()%% RemoteFile = string()%%%% Description: Transfer a binary to a remote file.%%--------------------------------------------------------------------------send_bin(Pid, Bin, RemoteFile) when binary(Bin) -> call(Pid, {send_bin, Bin, RemoteFile}, atom);send_bin(_Pid, _Bin, _RemoteFile) -> {error, enotbinary}.%%--------------------------------------------------------------------------%% send_chunk_start(Pid, RemoteFile) -> ok | {error, elogin} | {error, epath} %% | {error, econn}%% Pid = pid()%% RemoteFile = string()%%%% Description: Start transfer of chunks to remote file.%%--------------------------------------------------------------------------send_chunk_start(Pid, RemoteFile) -> call(Pid, {send_chunk_start, RemoteFile}, atom).%%--------------------------------------------------------------------------%% append_chunk_start(Pid, RemoteFile) -> ok | {error, elogin} | %% {error, epath} | {error, econn}%% Pid = pid()%% RemoteFile = string()%%%% Description: Start append chunks of data to remote file.%%--------------------------------------------------------------------------append_chunk_start(Pid, RemoteFile) -> call(Pid, {append_chunk_start, RemoteFile}, atom).%%--------------------------------------------------------------------------%% send_chunk(Pid, Bin) -> ok | {error, elogin} | {error, enotbinary} %% | {error, echunk} | {error, econn}%% Pid = pid()%% Bin = binary().%%%% Purpose: Send chunk to remote file.%%--------------------------------------------------------------------------send_chunk(Pid, Bin) when binary(Bin) -> call(Pid, {transfer_chunk, Bin}, atom);send_chunk(_Pid, _Bin) -> {error, enotbinary}.%%--------------------------------------------------------------------------%% append_chunk(Pid, Bin) -> ok | {error, elogin} | {error, enotbinary} %% | {error, echunk} | {error, econn}%% Pid = pid()%% Bin = binary()%%%% Description: Append chunk to remote file.%%--------------------------------------------------------------------------append_chunk(Pid, Bin) when binary(Bin) -> call(Pid, {transfer_chunk, Bin}, atom);append_chunk(_Pid, _Bin) -> {error, enotbinary}.%%--------------------------------------------------------------------------%% send_chunk_end(Pid) -> ok | {error, elogin} | {error, echunk} %% | {error, econn}%% Pid = pid()%%%% Description: End sending of chunks to remote file.%%--------------------------------------------------------------------------
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?