ssh_xfer.erl

来自「OTP是开放电信平台的简称」· ERL 代码 · 共 1,026 行 · 第 1/3 页

ERL
1,026
字号
%% ``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: SFTP functions-module(ssh_xfer).-export([attach/2, connect/3]).-export([open/6, opendir/3, readdir/3, close/3, read/5, write/5,	 rename/5, remove/3, mkdir/4, rmdir/3, realpath/3, extended/4,	 stat/4, fstat/4, lstat/4, setstat/4,	 readlink/3, fsetstat/4, symlink/4,	 xf_reply/2,	 xf_send_reply/3, xf_send_names/3, xf_send_name/4,	 xf_send_status/3, xf_send_status/4, xf_send_status/5,	 xf_send_handle/3, xf_send_attr/3, xf_send_data/3,	 encode_erlang_status/1,	 decode_open_flags/2, encode_open_flags/1,	 decode_ATTR/2, encode_ATTR/2]).-include("ssh.hrl").-include("ssh_xfer.hrl").-import(lists, [foldl/3, reverse/1]).-define(is_set(F, Bits),	((F) band (Bits)) == (F)).-define(XFER_PACKET_SIZE, 32768).-define(XFER_WINDOW_SIZE, 4*?XFER_PACKET_SIZE).-define(DEFAULT_TIMEOUT, 5000).attach(CM, Opts) ->    case ssh_cm:attach(CM, connect_timeout(Opts)) of	{ok,CMPid} ->  open_xfer(CMPid, Opts);	Error ->  Error    end.connect(Host, Port, Opts) ->    case ssh_cm:connect(Host, Port, Opts) of	{ok, CM} -> open_xfer(CM, Opts);	Error -> Error    end.%% xfer_channel(XF, Channel) ->%%     XF#ssh_xfer{channel = Channel}.open_xfer(CM, Opts) ->    TMO = connect_timeout(Opts),    case ssh_cm:session_open(CM, ?XFER_WINDOW_SIZE, ?XFER_PACKET_SIZE, TMO) of	{ok, Channel} ->	    case ssh_cm:subsystem(CM, Channel, "sftp", TMO) of		success ->		    case init(CM, Channel) of			{ok, {Vsn,Ext}, Rest} ->			    ?dbg(true, "open_xfer: Vsn=~p Ext=~p\n", [Vsn,Ext]),			    {ok, #ssh_xfer{vsn = Vsn,					   ext = Ext,					   cm  = CM,					   channel = Channel}, Rest};			Error -> Error		    end;		Error -> Error	    end;	Error -> Error    end.init(CM, Channel) ->    XF = #ssh_xfer { cm = CM, channel = Channel},    xf_request(XF, ?SSH_FXP_INIT, <<?UINT32(?SSH_SFTP_PROTOCOL_VERSION)>>),    case reply(CM, Channel) of	{ok, <<?SSH_FXP_VERSION, ?UINT32(Version), Ext/binary>>, Rest} ->	    ?dbg(true, "init: Version=~p\n", [Version]),	    {ok, {Version, decode_ext(Ext)}, Rest};	Error ->	    Error    end.reply(CM,Channel) ->    reply(CM,Channel,<<>>).reply(CM,Channel,RBuf) ->    receive	{ssh_cm, CM, {data, Channel, 0, Data}} ->	    case <<RBuf/binary, Data/binary>> of		<<?UINT32(Len),Reply:Len/binary,Rest/binary>> ->		    {ok, Reply, Rest};		RBuf2 ->		    reply(CM,Channel,RBuf2)	    end;	{ssh_cm, CM, {data, Channel, _, Data}} ->	    error_logger:format("ssh: STDERR: ~s\n", [binary_to_list(Data)]),	    reply(CM,Channel,RBuf);	{ssh_cm, CM, {exit_signal,Channel,_SIG,Err,_Lang}} ->	    ssh_cm:close(CM, Channel),	    {error, Err};	{ssh_cm, CM, {exit_status,Channel,_Status}} ->	    ssh_cm:close(CM, Channel),	    eof;	{ssh_cm, CM, {eof, Channel}} ->	    eof;	{ssh_cm, CM, {closed, Channel}} ->	    {error, closed};	{ssh_cm, CM, Msg} ->	    error_logger:format("GOT: ssh_cm ~p\n", [Msg]);	Msg ->	    error_logger:format("GOT: ~p\n", [Msg])    end.open(XF, ReqID, FileName, Access, Flags, Attrs) ->     Vsn = XF#ssh_xfer.vsn,    FileName1 = list_to_binary(FileName),    MBits = if Vsn >= 5 -> 		    M = encode_ace_mask(Access),		    ?uint32(M);	       true ->		    (<<>>)	    end,    F = encode_open_flags(Flags),    xf_request(XF,?SSH_FXP_OPEN, 	       [?uint32(ReqID),		?binary(FileName1),		MBits,		?uint32(F),		encode_ATTR(Vsn,Attrs)]).        opendir(XF, ReqID, DirName) ->    xf_request(XF, ?SSH_FXP_OPENDIR, 	       [?uint32(ReqID),		?string(DirName)]).close(XF, ReqID, Handle) ->    xf_request(XF, ?SSH_FXP_CLOSE,	       [?uint32(ReqID),		?binary(Handle)]).read(XF, ReqID, Handle, Offset, Length) ->    xf_request(XF, ?SSH_FXP_READ,	       [?uint32(ReqID),		?binary(Handle),		?uint64(Offset),		?uint32(Length)]).readdir(XF, ReqID, Handle) ->    xf_request(XF, ?SSH_FXP_READDIR,	       [?uint32(ReqID),		?binary(Handle)]).    write(XF,ReqID, Handle, Offset, Data) ->    Data1 = if binary(Data) -> Data;	       list(Data) -> list_to_binary(Data)	    end,    xf_request(XF,?SSH_FXP_WRITE,	       [?uint32(ReqID),		?binary(Handle),		?uint64(Offset),		?binary(Data1)]).%% Remove a fileremove(XF, ReqID, File) ->    xf_request(XF, ?SSH_FXP_REMOVE, 	       [?uint32(ReqID),		?string(File)]).%% Rename a file/directoryrename(XF, ReqID, Old, New, Flags) ->    Vsn = XF#ssh_xfer.vsn,    OldPath = list_to_binary(Old),    NewPath = list_to_binary(New),    FlagBits	= if Vsn >= 5 ->		  F0 = encode_rename_flags(Flags),		  ?uint32(F0);	     true ->		  (<<>>)	  end,    xf_request(XF, ?SSH_FXP_RENAME, 	       [?uint32(ReqID),		?binary(OldPath),		?binary(NewPath),		FlagBits]).%% Create directorymkdir(XF, ReqID, Path, Attrs) ->    Path1 = list_to_binary(Path),    xf_request(XF, ?SSH_FXP_MKDIR, 	       [?uint32(ReqID),		?binary(Path1),		encode_ATTR(XF#ssh_xfer.vsn, Attrs)]).%% Remove a directoryrmdir(XF, ReqID, Dir) ->    Dir1 = list_to_binary(Dir),    xf_request(XF, ?SSH_FXP_RMDIR,	       [?uint32(ReqID),		?binary(Dir1)]).%% Stat filestat(XF, ReqID, Path, Flags) ->    Path1 = list_to_binary(Path),    Vsn = XF#ssh_xfer.vsn,    AttrFlags = if Vsn >= 5 ->			F = encode_attr_flags(Vsn, Flags),			?uint32(F);		   true ->			[]		end,    xf_request(XF, ?SSH_FXP_STAT, 	       [?uint32(ReqID),		?binary(Path1),		AttrFlags]).%% Stat file - follow symbolic linkslstat(XF, ReqID, Path, Flags) ->    Path1 = list_to_binary(Path),    Vsn = XF#ssh_xfer.vsn,    AttrFlags = if Vsn >= 5 ->			F = encode_attr_flags(Vsn, Flags),			?uint32(F);		   true ->			[]		end,    xf_request(XF, ?SSH_FXP_LSTAT, 	     [?uint32(ReqID),	      ?binary(Path1),	      AttrFlags]).%% Stat open filefstat(XF, ReqID, Handle, Flags) ->    Vsn = XF#ssh_xfer.vsn,    AttrFlags = if Vsn >= 5 ->			F = encode_attr_flags(Vsn, Flags),			?uint32(F);		   true ->			[]		end,    xf_request(XF, ?SSH_FXP_FSTAT, 	       [?uint32(ReqID),		?binary(Handle),		AttrFlags]).%% Modify file attributessetstat(XF, ReqID, Path, Attrs) ->    Path1 = list_to_binary(Path),    xf_request(XF, ?SSH_FXP_SETSTAT, 	       [?uint32(ReqID),		?binary(Path1),		encode_ATTR(XF#ssh_xfer.vsn, Attrs)]).%% Modify file attributesfsetstat(XF, ReqID, Handle, Attrs) ->    xf_request(XF, ?SSH_FXP_FSETSTAT, 	       [?uint32(ReqID),		?binary(Handle),		encode_ATTR(XF#ssh_xfer.vsn, Attrs)]).    %% Read a symbolic linkreadlink(XF, ReqID, Path) ->    Path1 = list_to_binary(Path),    xf_request(XF, ?SSH_FXP_READLINK, 	       [?uint32(ReqID),		?binary(Path1)]).%% Create a symbolic link    symlink(XF, ReqID, LinkPath, TargetPath) ->    LinkPath1 = list_to_binary(LinkPath),    TargetPath1 = list_to_binary(TargetPath),    xf_request(XF, ?SSH_FXP_SYMLINK, 	       [?uint32(ReqID),		?binary(LinkPath1),		?binary(TargetPath1)]).%% Convert a path into a 'canonical' formrealpath(XF, ReqID, Path) ->    Path1 = list_to_binary(Path),    xf_request(XF, ?SSH_FXP_REALPATH,     	       [?uint32(ReqID),		?binary(Path1)]).extended(XF, ReqID, Request, Data) ->    xf_request(XF, ?SSH_FXP_EXTENDED,	       [?uint32(ReqID),		?string(Request),		?binary(Data)]).%% Send xfer request to connection managerxf_request(XF, Op, Arg) ->    CM = XF#ssh_xfer.cm,    Channel = XF#ssh_xfer.channel,    Data = if binary(Arg) -> Arg;	      list(Arg) -> list_to_binary(Arg)	   end,    Size = 1+size(Data),    ssh_cm:send(CM, Channel, <<?UINT32(Size), Op, Data/binary>>).xf_send_reply(#ssh_xfer{cm = CM, channel = Channel}, Op, Arg) ->        Data = if binary(Arg) -> Arg;	      list(Arg) -> list_to_binary(Arg)	   end,    Size = 1 + size(Data),    ssh_cm:send(CM, Channel, <<?UINT32(Size), Op, Data/binary>>).xf_send_name(XF, ReqId, Name, Attr) ->    xf_send_names(XF, ReqId, [{Name, Attr}]).					    %%     ?dbg(true, "xf_send_name: ReqId=~p Name=~p\n", [ReqId, Name]),    %%     Count%%     NameLen = length(Name),%%     EncAttr = encode_ATTR(Vsn, Attr),%%     Size = 1 + 4 + 4 + 4 + NameLen + bsize(EncAttr),% op reqid count namelen name attr%%     ToSend = [<<?UINT32(Size),%% 	       ?SSH_FXP_NAME, ?UINT32(ReqId), ?UINT32(1), ?UINT32(NameLen)>>,%% 	      Name, EncAttr],%%     ssh_cm:send(CM, Channel, ToSend).xf_send_handle(#ssh_xfer{cm = CM, channel = Channel},	       ReqId, Handle) ->

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?