%% %% %CopyrightBegin% %% %% Copyright Ericsson AB 2006-2012. All Rights Reserved. %% %% 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 online 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. %% %% %CopyrightEnd% %% %% -module(ssh_sftpd_SUITE). %% Note: This directive should only be used in test suites. -compile(export_all). -include_lib("common_test/include/ct.hrl"). -include_lib("kernel/include/file.hrl"). -include("ssh_xfer.hrl"). -include("ssh.hrl"). -define(USER, "Alladin"). -define(PASSWD, "Sesame"). -define(XFER_PACKET_SIZE, 32768). -define(XFER_WINDOW_SIZE, 4*?XFER_PACKET_SIZE). -define(TIMEOUT, 10000). -define(REG_ATTERS, <<0,0,0,0,1>>). -define(UNIX_EPOCH, 62167219200). -define(is_set(F, Bits), ((F) band (Bits)) == (F)). %%-------------------------------------------------------------------- %% Common Test interface functions ----------------------------------- %%-------------------------------------------------------------------- all() -> [open_close_file, open_close_dir, read_file, read_dir, write_file, rename_file, mk_rm_dir, remove_file, real_path, retrieve_attributes, set_attributes, links, ver3_rename, relpath, sshd_read_file, ver6_basic]. groups() -> []. %%-------------------------------------------------------------------- init_per_suite(Config) -> case (catch crypto:start()) of ok -> DataDir = ?config(data_dir, Config), PrivDir = ?config(priv_dir, Config), ssh_test_lib:setup_dsa(DataDir, PrivDir), %% to make sure we don't use public-key-auth %% this should be tested by other test suites UserDir = filename:join(?config(priv_dir, Config), nopubkey), file:make_dir(UserDir), Config; _ -> {skip,"Could not start crypto!"} end. end_per_suite(Config) -> SysDir = ?config(priv_dir, Config), ssh_test_lib:clean_dsa(SysDir), UserDir = filename:join(?config(priv_dir, Config), nopubkey), file:del_dir(UserDir), ssh:stop(), crypto:stop(). %%-------------------------------------------------------------------- init_per_group(_GroupName, Config) -> Config. end_per_group(_GroupName, Config) -> Config. %%-------------------------------------------------------------------- init_per_testcase(TestCase, Config) -> ssh:start(), prep(Config), PrivDir = ?config(priv_dir, Config), ClientUserDir = filename:join(PrivDir, nopubkey), SystemDir = filename:join(?config(priv_dir, Config), system), Port = ssh_test_lib:inet_port(node()), {ok, Sftpd} = case TestCase of ver6_basic -> ssh_sftpd:listen(Port, [{system_dir, SystemDir}, {user_dir, PrivDir}, {user_passwords,[{?USER, ?PASSWD}]}, {pwdfun, fun(_,_) -> true end}, {sftpd_vsn, 6}]); _ -> ssh_sftpd:listen(Port, [{system_dir, SystemDir}, {user_dir, PrivDir}, {user_passwords,[{?USER, ?PASSWD}]}, {pwdfun, fun(_,_) -> true end}]) end, Cm = ssh_test_lib:connect(Port, [{user_dir, ClientUserDir}, {user, ?USER}, {password, ?PASSWD}, {user_interaction, false}, {silently_accept_hosts, true}, {pwdfun, fun(_,_) -> true end}]), {ok, Channel} = ssh_connection:session_channel(Cm, ?XFER_WINDOW_SIZE, ?XFER_PACKET_SIZE, ?TIMEOUT), success = ssh_connection:subsystem(Cm, Channel, "sftp", ?TIMEOUT), ProtocolVer = case atom_to_list(TestCase) of "ver3_" ++ _ -> 3; _ -> ?SSH_SFTP_PROTOCOL_VERSION end, Data = <> , Size = 1 + size(Data), ssh_connection:send(Cm, Channel, << ?UINT32(Size), ?SSH_FXP_INIT, Data/binary >>), {ok, <>, _} = reply(Cm, Channel), ct:pal("Client: ~p Server ~p~n", [ProtocolVer, Version]), [{sftp, {Cm, Channel}}, {sftpd, Sftpd }| Config]. end_per_testcase(_TestCase, Config) -> ssh_sftpd:stop(?config(sftpd, Config)), {Cm, Channel} = ?config(sftp, Config), ssh_connection:close(Cm, Channel), ssh:close(Cm), ssh:stop(). %%-------------------------------------------------------------------- %% Test Cases -------------------------------------------------------- %%-------------------------------------------------------------------- open_close_file(doc) -> ["Test SSH_FXP_OPEN and SSH_FXP_CLOSE commands"]; open_close_file(Config) when is_list(Config) -> PrivDir = ?config(priv_dir, Config), FileName = filename:join(PrivDir, "test.txt"), {Cm, Channel} = ?config(sftp, Config), ReqId = 0, {ok, <>, _} = open_file(FileName, Cm, Channel, ReqId, ?ACE4_READ_DATA bor ?ACE4_READ_ATTRIBUTES, ?SSH_FXF_OPEN_EXISTING), {ok, <>, _} = close(Handle, ReqId, Cm, Channel), NewReqId = ReqId + 1, {ok, <>, _} = close(Handle, ReqId, Cm, Channel), NewReqId1 = NewReqId + 1, %% {ok, <>, _} = {ok, <>, _} = open_file(PrivDir, Cm, Channel, NewReqId1, ?ACE4_READ_DATA bor ?ACE4_READ_ATTRIBUTES, ?SSH_FXF_OPEN_EXISTING). %%-------------------------------------------------------------------- open_close_dir(doc) -> ["Test SSH_FXP_OPENDIR and SSH_FXP_CLOSE commands"]; open_close_dir(Config) when is_list(Config) -> PrivDir = ?config(priv_dir, Config), {Cm, Channel} = ?config(sftp, Config), FileName = filename:join(PrivDir, "test.txt"), ReqId = 0, {ok, <>, _} = open_dir(PrivDir, Cm, Channel, ReqId), {ok, <>, _} = close(Handle, ReqId, Cm, Channel), NewReqId = 1, case open_dir(FileName, Cm, Channel, NewReqId) of {ok, <>, _} -> %% Only if server is using vsn > 5. ok; {ok, <>, _} -> ok end. %%-------------------------------------------------------------------- read_file(doc) -> ["Test SSH_FXP_READ command"]; read_file(Config) when is_list(Config) -> PrivDir = ?config(priv_dir, Config), FileName = filename:join(PrivDir, "test.txt"), ReqId = 0, {Cm, Channel} = ?config(sftp, Config), {ok, <>, _} = open_file(FileName, Cm, Channel, ReqId, ?ACE4_READ_DATA bor ?ACE4_READ_ATTRIBUTES, ?SSH_FXF_OPEN_EXISTING), NewReqId = 1, {ok, <>, _} = read_file(Handle, 100, 0, Cm, Channel, NewReqId), {ok, Data} = file:read_file(FileName). %%-------------------------------------------------------------------- read_dir(doc) -> ["Test SSH_FXP_READDIR command"]; read_dir(Config) when is_list(Config) -> PrivDir = ?config(priv_dir, Config), {Cm, Channel} = ?config(sftp, Config), ReqId = 0, {ok, <>, _} = open_dir(PrivDir, Cm, Channel, ReqId), ok = read_dir(Handle, Cm, Channel, ReqId). %%-------------------------------------------------------------------- write_file(doc) -> ["Test SSH_FXP_WRITE command"]; write_file(Config) when is_list(Config) -> PrivDir = ?config(priv_dir, Config), FileName = filename:join(PrivDir, "test.txt"), ReqId = 0, {Cm, Channel} = ?config(sftp, Config), {ok, <>, _} = open_file(FileName, Cm, Channel, ReqId, ?ACE4_WRITE_DATA bor ?ACE4_WRITE_ATTRIBUTES, ?SSH_FXF_OPEN_EXISTING), NewReqId = 1, Data = list_to_binary("Write file test"), {ok, <>, _} = write_file(Handle, Data, 0, Cm, Channel, NewReqId), {ok, Data} = file:read_file(FileName). %%-------------------------------------------------------------------- remove_file(doc) -> ["Test SSH_FXP_REMOVE command"]; remove_file(Config) when is_list(Config) -> PrivDir = ?config(priv_dir, Config), FileName = filename:join(PrivDir, "test.txt"), ReqId = 0, {Cm, Channel} = ?config(sftp, Config), {ok, <>, _} = remove(FileName, Cm, Channel, ReqId), NewReqId = 1, %% {ok, <>, _} = {ok, <>, _} = remove(PrivDir, Cm, Channel, NewReqId). %%-------------------------------------------------------------------- rename_file(doc) -> ["Test SSH_FXP_RENAME command"]; rename_file(Config) when is_list(Config) -> PrivDir = ?config(priv_dir, Config), FileName = filename:join(PrivDir, "test.txt"), NewFileName = filename:join(PrivDir, "test1.txt"), ReqId = 0, {Cm, Channel} = ?config(sftp, Config), {ok, <>, _} = rename(FileName, NewFileName, Cm, Channel, ReqId, 6, 0), NewReqId = ReqId + 1, {ok, <>, _} = rename(NewFileName, FileName, Cm, Channel, NewReqId, 6, ?SSH_FXP_RENAME_OVERWRITE), NewReqId1 = NewReqId + 1, file:copy(FileName, NewFileName), %% No owerwrite {ok, <>, _} = rename(FileName, NewFileName, Cm, Channel, NewReqId1, 6, ?SSH_FXP_RENAME_NATIVE), NewReqId2 = NewReqId1 + 1, {ok, <>, _} = rename(FileName, NewFileName, Cm, Channel, NewReqId2, 6, ?SSH_FXP_RENAME_ATOMIC). %%-------------------------------------------------------------------- mk_rm_dir(doc) -> ["Test SSH_FXP_MKDIR and SSH_FXP_RMDIR command"]; mk_rm_dir(Config) when is_list(Config) -> PrivDir = ?config(priv_dir, Config), {Cm, Channel} = ?config(sftp, Config), DirName = filename:join(PrivDir, "test"), ReqId = 0, {ok, <>, _} = mkdir(DirName, Cm, Channel, ReqId), NewReqId = 1, {ok, <>, _} = mkdir(DirName, Cm, Channel, NewReqId), NewReqId1 = 2, {ok, <>, _} = rmdir(DirName, Cm, Channel, NewReqId1), NewReqId2 = 3, {ok, <>, _} = rmdir(DirName, Cm, Channel, NewReqId2). %%-------------------------------------------------------------------- real_path(doc) -> ["Test SSH_FXP_REALPATH command"]; real_path(Config) when is_list(Config) -> case os:type() of {win32, _} -> {skip, "Not a relevant test on windows"}; _ -> ReqId = 0, {Cm, Channel} = ?config(sftp, Config), PrivDir = ?config(priv_dir, Config), TestDir = filename:join(PrivDir, "ssh_test"), ok = file:make_dir(TestDir), OrigPath = filename:join(TestDir, ".."), {ok, <>, _} = real_path(OrigPath, Cm, Channel, ReqId), RealPath = filename:absname(binary_to_list(Path)), AbsPrivDir = filename:absname(PrivDir), ct:pal("Path: ~p PrivDir: ~p~n", [RealPath, AbsPrivDir]), true = RealPath == AbsPrivDir end. %%-------------------------------------------------------------------- links(doc) -> []; links(Config) when is_list(Config) -> case os:type() of {win32, _} -> {skip, "Links are not fully supported by windows"}; _ -> ReqId = 0, {Cm, Channel} = ?config(sftp, Config), PrivDir = ?config(priv_dir, Config), FileName = filename:join(PrivDir, "test.txt"), LinkFileName = filename:join(PrivDir, "link_test.txt"), {ok, <>, _} = create_link(LinkFileName, FileName, Cm, Channel, ReqId), NewReqId = 1, {ok, <>, _} = read_link(LinkFileName, Cm, Channel, NewReqId), true = binary_to_list(Path) == FileName, ct:pal("Path: ~p~n", [binary_to_list(Path)]) end. %%-------------------------------------------------------------------- retrieve_attributes(doc) -> ["Test SSH_FXP_STAT, SSH_FXP_LSTAT AND SSH_FXP_FSTAT commands"]; retrieve_attributes(Config) when is_list(Config) -> PrivDir = ?config(priv_dir, Config), FileName = filename:join(PrivDir, "test.txt"), ReqId = 0, {Cm, Channel} = ?config(sftp, Config), {ok, FileInfo} = file:read_file_info(FileName), AttrValues = retrive_attributes(FileName, Cm, Channel, ReqId), Type = encode_file_type(FileInfo#file_info.type), Size = FileInfo#file_info.size, Owner = FileInfo#file_info.uid, Group = FileInfo#file_info.gid, Permissions = FileInfo#file_info.mode, Atime = calendar:datetime_to_gregorian_seconds( erlang:localtime_to_universaltime(FileInfo#file_info.atime)) - ?UNIX_EPOCH, Mtime = calendar:datetime_to_gregorian_seconds( erlang:localtime_to_universaltime(FileInfo#file_info.mtime)) - ?UNIX_EPOCH, Ctime = calendar:datetime_to_gregorian_seconds( erlang:localtime_to_universaltime(FileInfo#file_info.ctime)) - ?UNIX_EPOCH, lists:foreach(fun(Value) -> <> = Value, true = ?is_set(?SSH_FILEXFER_ATTR_SIZE, Flags), true = ?is_set(?SSH_FILEXFER_ATTR_PERMISSIONS, Flags), true = ?is_set(?SSH_FILEXFER_ATTR_ACCESSTIME, Flags), true = ?is_set(?SSH_FILEXFER_ATTR_CREATETIME, Flags), true = ?is_set(?SSH_FILEXFER_ATTR_MODIFYTIME, Flags), true = ?is_set(?SSH_FILEXFER_ATTR_OWNERGROUP, Flags), false = ?is_set(?SSH_FILEXFER_ATTR_ACL, Flags), false = ?is_set(?SSH_FILEXFER_ATTR_SUBSECOND_TIMES, Flags), false = ?is_set(?SSH_FILEXFER_ATTR_BITS, Flags), false = ?is_set(?SSH_FILEXFER_ATTR_EXTENDED, Flags), <> = Value, Owner = list_to_integer(binary_to_list(BinOwner)), Group = list_to_integer(binary_to_list(BinGroup)) end, AttrValues). %%-------------------------------------------------------------------- set_attributes(doc) -> ["Test SSH_FXP_SETSTAT AND SSH_FXP_FSETSTAT commands"]; set_attributes(Config) when is_list(Config) -> case os:type() of {win32, _} -> {skip, "Known error bug in erts file:read_file_info"}; _ -> PrivDir = ?config(priv_dir, Config), FileName = filename:join(PrivDir, "test.txt"), ReqId = 0, {Cm, Channel} = ?config(sftp, Config), {ok, FileInfo} = file:read_file_info(FileName), OrigPermissions = FileInfo#file_info.mode, Permissions = not_default_permissions(), Flags = ?SSH_FILEXFER_ATTR_PERMISSIONS, Atters = [?uint32(Flags), ?byte(?SSH_FILEXFER_TYPE_REGULAR), ?uint32(Permissions)], {ok, <>, _} = set_attributes_file(FileName, Atters, Cm, Channel, ReqId), {ok, NewFileInfo} = file:read_file_info(FileName), NewPermissions = NewFileInfo#file_info.mode, %% Can not test that NewPermissions = Permissions as %% on Unix platforms, other bits than those listed in the %% API may be set. ct:pal("Org: ~p New: ~p~n", [OrigPermissions, NewPermissions]), true = OrigPermissions =/= NewPermissions, ct:pal("Try to open the file"), NewReqId = 2, {ok, <>, _} = open_file(FileName, Cm, Channel, NewReqId, ?ACE4_READ_DATA bor ?ACE4_WRITE_ATTRIBUTES, ?SSH_FXF_OPEN_EXISTING), NewAtters = [?uint32(Flags), ?byte(?SSH_FILEXFER_TYPE_REGULAR), ?uint32(OrigPermissions)], NewReqId1 = 3, ct:pal("Set original permissions on the now open file"), {ok, <>, _} = set_attributes_open_file(Handle, NewAtters, Cm, Channel, NewReqId1), {ok, NewFileInfo1} = file:read_file_info(FileName), OrigPermissions = NewFileInfo1#file_info.mode end. %%-------------------------------------------------------------------- ver3_rename(doc) -> ["Test that ver3 rename message is handled OTP 6352"]; ver3_rename(Config) when is_list(Config) -> PrivDir = ?config(priv_dir, Config), FileName = filename:join(PrivDir, "test.txt"), NewFileName = filename:join(PrivDir, "test1.txt"), ReqId = 0, {Cm, Channel} = ?config(sftp, Config), {ok, <>, _} = rename(FileName, NewFileName, Cm, Channel, ReqId, 3, 0). %%-------------------------------------------------------------------- relpath(doc) -> ["Check that realpath works ok seq10670"]; relpath(Config) when is_list(Config) -> ReqId = 0, {Cm, Channel} = ?config(sftp, Config), case os:type() of {win32, _} -> {skip, "Not a relevant test on windows"}; _ -> {ok, <>, _} = real_path("/..", Cm, Channel, ReqId), <<"/">> = Root, {ok, <>, _} = real_path("/usr/bin/../..", Cm, Channel, ReqId), Root = Path end. %%-------------------------------------------------------------------- sshd_read_file(doc) -> ["Test SSH_FXP_READ command, using sshd-server"]; sshd_read_file(Config) when is_list(Config) -> PrivDir = ?config(priv_dir, Config), FileName = filename:join(PrivDir, "test.txt"), ReqId = 0, {Cm, Channel} = ?config(sftp, Config), {ok, <>, _} = open_file(FileName, Cm, Channel, ReqId, ?ACE4_READ_DATA bor ?ACE4_READ_ATTRIBUTES, ?SSH_FXF_OPEN_EXISTING), NewReqId = 1, {ok, <>, _} = read_file(Handle, 100, 0, Cm, Channel, NewReqId), {ok, Data} = file:read_file(FileName). ver6_basic(doc) -> ["Test SFTP Version 6"]; ver6_basic(Config) when is_list(Config) -> PrivDir = ?config(priv_dir, Config), %FileName = filename:join(PrivDir, "test.txt"), {Cm, Channel} = ?config(sftp, Config), ReqId = 0, {ok, <>, _} = open_file(PrivDir, Cm, Channel, ReqId, ?ACE4_READ_DATA bor ?ACE4_READ_ATTRIBUTES, ?SSH_FXF_OPEN_EXISTING). %%-------------------------------------------------------------------- %% Internal functions ------------------------------------------------ %%-------------------------------------------------------------------- prep(Config) -> PrivDir = ?config(priv_dir, Config), TestFile = filename:join(PrivDir, "test.txt"), TestFile1 = filename:join(PrivDir, "test1.txt"), file:delete(TestFile), file:delete(TestFile1), %% Initial config DataDir = ?config(data_dir, Config), FileName = filename:join(DataDir, "test.txt"), file:copy(FileName, TestFile), Mode = 8#00400 bor 8#00200 bor 8#00040, % read & write owner, read group {ok, FileInfo} = file:read_file_info(TestFile), ok = file:write_file_info(TestFile, FileInfo#file_info{mode = Mode}). reply(Cm, Channel) -> reply(Cm, Channel,<<>>). reply(Cm, Channel, RBuf) -> receive {ssh_cm, Cm, {data, Channel, 0, Data}} -> case <> of <> -> {ok, Reply, Rest}; RBuf2 -> reply(Cm, Channel, RBuf2) end; {ssh_cm, Cm, {eof, Channel}} -> eof; {ssh_cm, Cm, {closed, Channel}} -> closed; {ssh_cm, Cm, Msg} -> ct:fail(Msg) end. open_file(File, Cm, Channel, ReqId, Access, Flags) -> Data = list_to_binary([?uint32(ReqId), ?binary(list_to_binary(File)), ?uint32(Access), ?uint32(Flags), ?REG_ATTERS]), Size = 1 + size(Data), ssh_connection:send(Cm, Channel, <>), reply(Cm, Channel). close(Handle, ReqId, Cm , Channel) -> Data = list_to_binary([?uint32(ReqId), Handle]), Size = 1 + size(Data), ssh_connection:send(Cm, Channel, <>), reply(Cm, Channel). open_dir(Dir, Cm, Channel, ReqId) -> Data = list_to_binary([?uint32(ReqId), ?binary(list_to_binary(Dir))]), Size = 1 + size(Data), ssh_connection:send(Cm, Channel, <>), reply(Cm, Channel). rename(OldName, NewName, Cm, Channel, ReqId, Version, Flags) -> Data = case Version of 3 -> list_to_binary([?uint32(ReqId), ?binary(list_to_binary(OldName)), ?binary(list_to_binary(NewName))]); _ -> list_to_binary([?uint32(ReqId), ?binary(list_to_binary(OldName)), ?binary(list_to_binary(NewName)), ?uint32(Flags)]) end, Size = 1 + size(Data), ssh_connection:send(Cm, Channel, <>), reply(Cm, Channel). mkdir(Dir, Cm, Channel, ReqId)-> Data = list_to_binary([?uint32(ReqId), ?binary(list_to_binary(Dir)), ?REG_ATTERS]), Size = 1 + size(Data), ssh_connection:send(Cm, Channel, <>), reply(Cm, Channel). rmdir(Dir, Cm, Channel, ReqId) -> Data = list_to_binary([?uint32(ReqId), ?binary(list_to_binary(Dir))]), Size = 1 + size(Data), ssh_connection:send(Cm, Channel, <>), reply(Cm, Channel). remove(File, Cm, Channel, ReqId) -> Data = list_to_binary([?uint32(ReqId), ?binary(list_to_binary(File))]), Size = 1 + size(Data), ssh_connection:send(Cm, Channel, <>), reply(Cm, Channel). read_dir(Handle, Cm, Channel, ReqId) -> Data = list_to_binary([?uint32(ReqId), Handle]), Size = 1 + size(Data), ssh_connection:send(Cm, Channel, <>), case reply(Cm, Channel) of {ok, <>, _} -> ct:pal("Count: ~p Listing: ~p~n", [Count, binary_to_list(Listing)]), read_dir(Handle, Cm, Channel, ReqId); {ok, <>, _} -> ok end. read_file(Handle, MaxLength, OffSet, Cm, Channel, ReqId) -> Data = list_to_binary([?uint32(ReqId), Handle, ?uint64(OffSet), ?uint32(MaxLength)]), Size = 1 + size(Data), ssh_connection:send(Cm, Channel, <>), reply(Cm, Channel). write_file(Handle, FileData, OffSet, Cm, Channel, ReqId) -> Data = list_to_binary([?uint32(ReqId), Handle, ?uint64(OffSet), ?binary(FileData)]), Size = 1 + size(Data), ssh_connection:send(Cm, Channel, <>), reply(Cm, Channel). real_path(OrigPath, Cm, Channel, ReqId) -> Data = list_to_binary([?uint32(ReqId), ?binary(list_to_binary(OrigPath))]), Size = 1 + size(Data), ssh_connection:send(Cm, Channel, <>), reply(Cm, Channel). create_link(LinkPath, Path, Cm, Channel, ReqId) -> Data = list_to_binary([?uint32(ReqId), ?binary(list_to_binary(LinkPath)), ?binary(list_to_binary(Path))]), Size = 1 + size(Data), ssh_connection:send(Cm, Channel, <>), reply(Cm, Channel). read_link(Link, Cm, Channel, ReqId) -> Data = list_to_binary([?uint32(ReqId), ?binary(list_to_binary(Link))]), Size = 1 + size(Data), ssh_connection:send(Cm, Channel, <>), reply(Cm, Channel). retrive_attributes_file(FilePath, Flags, Cm, Channel, ReqId) -> Data = list_to_binary([?uint32(ReqId), ?binary(list_to_binary(FilePath)), ?uint32(Flags)]), Size = 1 + size(Data), ssh_connection:send(Cm, Channel, <>), reply(Cm, Channel). retrive_attributes_file_or_link(FilePath, Flags, Cm, Channel, ReqId) -> Data = list_to_binary([?uint32(ReqId), ?binary(list_to_binary(FilePath)), ?uint32(Flags)]), Size = 1 + size(Data), ssh_connection:send(Cm, Channel, <>), reply(Cm, Channel). retrive_attributes_open_file(Handle, Flags, Cm, Channel, ReqId) -> Data = list_to_binary([?uint32(ReqId), Handle, ?uint32(Flags)]), Size = 1 + size(Data), ssh_connection:send(Cm, Channel, <>), reply(Cm, Channel). retrive_attributes(FileName, Cm, Channel, ReqId) -> Attr = ?SSH_FILEXFER_ATTR_SIZE, {ok, <>, _} = retrive_attributes_file(FileName, Attr, Cm, Channel, ReqId), NewReqId = ReqId + 1, {ok, <>, _} = retrive_attributes_file_or_link(FileName, Attr, Cm, Channel, NewReqId), NewReqId1 = NewReqId + 1, {ok, <>, _} = open_file(FileName, Cm, Channel, NewReqId1, ?ACE4_READ_DATA bor ?ACE4_READ_ATTRIBUTES, ?SSH_FXF_OPEN_EXISTING), NewReqId2 = NewReqId1 + 1, {ok, <>, _} = retrive_attributes_open_file(Handle, Attr, Cm, Channel, NewReqId2), [Value, Value1, Value2]. set_attributes_file(FilePath, Atters, Cm, Channel, ReqId) -> Data = list_to_binary([?uint32(ReqId), ?binary(list_to_binary(FilePath)), Atters]), Size = 1 + size(Data), ssh_connection:send(Cm, Channel, <>), reply(Cm, Channel). set_attributes_open_file(Handle, Atters, Cm, Channel, ReqId) -> Data = list_to_binary([?uint32(ReqId), Handle, Atters]), Size = 1 + size(Data), ssh_connection:send(Cm, Channel, <>), reply(Cm, Channel). encode_file_type(Type) -> case Type of regular -> ?SSH_FILEXFER_TYPE_REGULAR; directory -> ?SSH_FILEXFER_TYPE_DIRECTORY; symlink -> ?SSH_FILEXFER_TYPE_SYMLINK; special -> ?SSH_FILEXFER_TYPE_SPECIAL; unknown -> ?SSH_FILEXFER_TYPE_UNKNOWN; other -> ?SSH_FILEXFER_TYPE_UNKNOWN; socket -> ?SSH_FILEXFER_TYPE_SOCKET; char_device -> ?SSH_FILEXFER_TYPE_CHAR_DEVICE; block_device -> ?SSH_FILEXFER_TYPE_BLOCK_DEVICE; fifo -> ?SSH_FILEXFER_TYPE_FIFO; undefined -> ?SSH_FILEXFER_TYPE_UNKNOWN end. not_default_permissions() -> 8#600. %% User read-write-only