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 + -
显示快捷键?