mirror of
https://github.com/doublecmd/doublecmd.git
synced 2026-06-21 09:58:13 +00:00
ADD: FTP - initial sftp support code
This commit is contained in:
parent
af50180865
commit
41a1d1b2ff
2 changed files with 920 additions and 0 deletions
457
plugins/wfx/ftp/src/sftp/libssh.pas
Normal file
457
plugins/wfx/ftp/src/sftp/libssh.pas
Normal file
|
|
@ -0,0 +1,457 @@
|
|||
unit libssh;
|
||||
|
||||
{$mode delphi}
|
||||
{$packrecords c}
|
||||
|
||||
interface
|
||||
|
||||
uses
|
||||
Classes, SysUtils, CTypes;
|
||||
|
||||
const
|
||||
//* Hash Types */
|
||||
LIBSSH2_HOSTKEY_HASH_MD5 = 1;
|
||||
LIBSSH2_HOSTKEY_HASH_SHA1 = 2;
|
||||
|
||||
//* Disconnect Codes (defined by SSH protocol) */
|
||||
SSH_DISCONNECT_HOST_NOT_ALLOWED_TO_CONNECT = 1;
|
||||
SSH_DISCONNECT_PROTOCOL_ERROR = 2;
|
||||
SSH_DISCONNECT_KEY_EXCHANGE_FAILED = 3;
|
||||
SSH_DISCONNECT_RESERVED = 4;
|
||||
SSH_DISCONNECT_MAC_ERROR = 5;
|
||||
SSH_DISCONNECT_COMPRESSION_ERROR = 6;
|
||||
SSH_DISCONNECT_SERVICE_NOT_AVAILABLE = 7;
|
||||
SSH_DISCONNECT_PROTOCOL_VERSION_NOT_SUPPORTED = 8;
|
||||
SSH_DISCONNECT_HOST_KEY_NOT_VERIFIABLE = 9;
|
||||
SSH_DISCONNECT_CONNECTION_LOST = 10;
|
||||
SSH_DISCONNECT_BY_APPLICATION = 11;
|
||||
SSH_DISCONNECT_TOO_MANY_CONNECTIONS = 12;
|
||||
SSH_DISCONNECT_AUTH_CANCELLED_BY_USER = 13;
|
||||
SSH_DISCONNECT_NO_MORE_AUTH_METHODS_AVAILABLE = 14;
|
||||
SSH_DISCONNECT_ILLEGAL_USER_NAME = 15;
|
||||
|
||||
{ Error Codes (defined by libssh2) }
|
||||
LIBSSH2_ERROR_NONE = 0;
|
||||
LIBSSH2_ERROR_SOCKET_NONE = -(1);
|
||||
LIBSSH2_ERROR_BANNER_RECV = -(2);
|
||||
LIBSSH2_ERROR_BANNER_SEND = -(3);
|
||||
LIBSSH2_ERROR_INVALID_MAC = -(4);
|
||||
LIBSSH2_ERROR_KEX_FAILURE = -(5);
|
||||
LIBSSH2_ERROR_ALLOC = -(6);
|
||||
LIBSSH2_ERROR_SOCKET_SEND = -(7);
|
||||
LIBSSH2_ERROR_KEY_EXCHANGE_FAILURE = -(8);
|
||||
LIBSSH2_ERROR_TIMEOUT = -(9);
|
||||
LIBSSH2_ERROR_HOSTKEY_INIT = -(10);
|
||||
LIBSSH2_ERROR_HOSTKEY_SIGN = -(11);
|
||||
LIBSSH2_ERROR_DECRYPT = -(12);
|
||||
LIBSSH2_ERROR_SOCKET_DISCONNECT = -(13);
|
||||
LIBSSH2_ERROR_PROTO = -(14);
|
||||
LIBSSH2_ERROR_PASSWORD_EXPIRED = -(15);
|
||||
LIBSSH2_ERROR_FILE = -(16);
|
||||
LIBSSH2_ERROR_METHOD_NONE = -(17);
|
||||
LIBSSH2_ERROR_AUTHENTICATION_FAILED = -(18);
|
||||
LIBSSH2_ERROR_PUBLICKEY_UNRECOGNIZED = LIBSSH2_ERROR_AUTHENTICATION_FAILED;
|
||||
LIBSSH2_ERROR_PUBLICKEY_UNVERIFIED = -(19);
|
||||
LIBSSH2_ERROR_CHANNEL_OUTOFORDER = -(20);
|
||||
LIBSSH2_ERROR_CHANNEL_FAILURE = -(21);
|
||||
LIBSSH2_ERROR_CHANNEL_REQUEST_DENIED = -(22);
|
||||
LIBSSH2_ERROR_CHANNEL_UNKNOWN = -(23);
|
||||
LIBSSH2_ERROR_CHANNEL_WINDOW_EXCEEDED = -(24);
|
||||
LIBSSH2_ERROR_CHANNEL_PACKET_EXCEEDED = -(25);
|
||||
LIBSSH2_ERROR_CHANNEL_CLOSED = -(26);
|
||||
LIBSSH2_ERROR_CHANNEL_EOF_SENT = -(27);
|
||||
LIBSSH2_ERROR_SCP_PROTOCOL = -(28);
|
||||
LIBSSH2_ERROR_ZLIB = -(29);
|
||||
LIBSSH2_ERROR_SOCKET_TIMEOUT = -(30);
|
||||
LIBSSH2_ERROR_SFTP_PROTOCOL = -(31);
|
||||
LIBSSH2_ERROR_REQUEST_DENIED = -(32);
|
||||
LIBSSH2_ERROR_METHOD_NOT_SUPPORTED = -(33);
|
||||
LIBSSH2_ERROR_INVAL = -(34);
|
||||
LIBSSH2_ERROR_INVALID_POLL_TYPE = -(35);
|
||||
LIBSSH2_ERROR_PUBLICKEY_PROTOCOL = -(36);
|
||||
LIBSSH2_ERROR_EAGAIN = -(37);
|
||||
LIBSSH2_ERROR_BUFFER_TOO_SMALL = -(38);
|
||||
LIBSSH2_ERROR_BAD_USE = -(39);
|
||||
LIBSSH2_ERROR_COMPRESS = -(40);
|
||||
LIBSSH2_ERROR_OUT_OF_BOUNDARY = -(41);
|
||||
LIBSSH2_ERROR_AGENT_PROTOCOL = -(42);
|
||||
LIBSSH2_ERROR_SOCKET_RECV = -(43);
|
||||
LIBSSH2_ERROR_ENCRYPT = -(44);
|
||||
LIBSSH2_ERROR_BAD_SOCKET = -(45);
|
||||
LIBSSH2_ERROR_KNOWN_HOSTS = -(46);
|
||||
|
||||
//* Flags for open_ex() */
|
||||
_LIBSSH2_SFTP_OPENFILE = 0;
|
||||
_LIBSSH2_SFTP_OPENDIR = 1;
|
||||
|
||||
//* Flags for rename_ex() */
|
||||
LIBSSH2_SFTP_RENAME_OVERWRITE = $00000001;
|
||||
LIBSSH2_SFTP_RENAME_ATOMIC = $00000002;
|
||||
LIBSSH2_SFTP_RENAME_NATIVE = $00000004;
|
||||
|
||||
//* Flags for stat_ex() */
|
||||
_LIBSSH2_SFTP_STAT = 0;
|
||||
_LIBSSH2_SFTP_LSTAT = 1;
|
||||
_LIBSSH2_SFTP_SETSTAT = 2;
|
||||
|
||||
//* Flags for symlink_ex() */
|
||||
_LIBSSH2_SFTP_SYMLINK = 0;
|
||||
_LIBSSH2_SFTP_READLINK = 1;
|
||||
_LIBSSH2_SFTP_REALPATH = 2;
|
||||
|
||||
//* SFTP attribute flag bits */
|
||||
LIBSSH2_SFTP_ATTR_SIZE = $00000001;
|
||||
LIBSSH2_SFTP_ATTR_UIDGID = $00000002;
|
||||
LIBSSH2_SFTP_ATTR_PERMISSIONS = $00000004;
|
||||
LIBSSH2_SFTP_ATTR_ACMODTIME = $00000008;
|
||||
LIBSSH2_SFTP_ATTR_EXTENDED = $80000000;
|
||||
|
||||
//* File mode */
|
||||
//* Read, write, execute/search by owner */
|
||||
LIBSSH2_SFTP_S_IRWXU = 448; //* RWX mask for owner */
|
||||
LIBSSH2_SFTP_S_IRUSR = 256; //* R for owner */
|
||||
LIBSSH2_SFTP_S_IWUSR = 128; //* W for owner */
|
||||
LIBSSH2_SFTP_S_IXUSR = 64; //* X for owner */
|
||||
//* Read, write, execute/search by group */
|
||||
LIBSSH2_SFTP_S_IRWXG = 56; //* RWX mask for group */
|
||||
LIBSSH2_SFTP_S_IRGRP = 32; //* R for group */
|
||||
LIBSSH2_SFTP_S_IWGRP = 16; //* W for group */
|
||||
LIBSSH2_SFTP_S_IXGRP = 8; //* X for group */
|
||||
//* Read, write, execute/search by others */
|
||||
LIBSSH2_SFTP_S_IRWXO = 7; //* RWX mask for other */
|
||||
LIBSSH2_SFTP_S_IROTH = 4; //* R for other */
|
||||
LIBSSH2_SFTP_S_IWOTH = 2; //* W for other */
|
||||
LIBSSH2_SFTP_S_IXOTH = 1; //* X for other */
|
||||
|
||||
//* SFTP File Transfer Flags -- (e.g. flags parameter to sftp_open()) */
|
||||
LIBSSH2_FXF_READ = $00000001;
|
||||
LIBSSH2_FXF_WRITE = $00000002;
|
||||
LIBSSH2_FXF_APPEND = $00000004;
|
||||
LIBSSH2_FXF_CREAT = $00000008;
|
||||
LIBSSH2_FXF_TRUNC = $00000010;
|
||||
LIBSSH2_FXF_EXCL = $00000020;
|
||||
|
||||
type
|
||||
//* Session API */
|
||||
PLIBSSH2_SESSION = type Pointer;
|
||||
//* SFTP API */
|
||||
PLIBSSH2_SFTP = type Pointer;
|
||||
PLIBSSH2_SFTP_HANDLE = type Pointer;
|
||||
PLIBSSH2_SFTP_ATTRIBUTES = ^LIBSSH2_SFTP_ATTRIBUTES;
|
||||
LIBSSH2_SFTP_ATTRIBUTES = record
|
||||
flags: culong;
|
||||
filesize: cuint64;
|
||||
uid, gid: culong;
|
||||
permissions: culong;
|
||||
atime, mtime: culong;
|
||||
end;
|
||||
PLIBSSH2_SFTP_STATVFS = ^_LIBSSH2_SFTP_STATVFS;
|
||||
_LIBSSH2_SFTP_STATVFS = record
|
||||
f_bsize: cuint64; //* file system block size */
|
||||
f_frsize: cuint64; //* fragment size */
|
||||
f_blocks: cuint64; //* size of fs in f_frsize units */
|
||||
f_bfree: cuint64; //* # free blocks */
|
||||
f_bavail: cuint64; //* # free blocks for non-root */
|
||||
f_files: cuint64; //* # inodes */
|
||||
f_ffree: cuint64; //* # free inodes */
|
||||
f_favail: cuint64; //* # free inodes for non-root */
|
||||
f_fsid: cuint64; //* file system ID */
|
||||
f_flag: cuint64; //* mount flags */
|
||||
f_namemax: cuint64; //* maximum filename length */
|
||||
end;
|
||||
PLIBSSH2_USERAUTH_KBDINT_PROMPT = ^LIBSSH2_USERAUTH_KBDINT_PROMPT;
|
||||
LIBSSH2_USERAUTH_KBDINT_PROMPT = record
|
||||
text: PAnsiChar;
|
||||
length: cuint;
|
||||
echo: cuchar;
|
||||
end;
|
||||
PLIBSSH2_USERAUTH_KBDINT_RESPONSE = ^LIBSSH2_USERAUTH_KBDINT_RESPONSE;
|
||||
LIBSSH2_USERAUTH_KBDINT_RESPONSE = record
|
||||
text: PAnsiChar;
|
||||
length: cuint;
|
||||
end;
|
||||
//* Malloc callbacks */
|
||||
LIBSSH2_ALLOC_FUNC = function(count: csize_t; abstract: Pointer): Pointer; cdecl;
|
||||
LIBSSH2_REALLOC_FUNC = function(ptr: Pointer; count: csize_t; abstract: Pointer): Pointer; cdecl;
|
||||
LIBSSH2_FREE_FUNC = procedure(ptr: Pointer; abstract: Pointer); cdecl;
|
||||
//* Callbacks for special SSH packets */
|
||||
LIBSSH2_PASSWD_CHANGEREQ_FUNC = procedure(session: PLIBSSH2_SESSION; var newpw: PAnsiChar;
|
||||
var newpw_len: cint; abstract: Pointer); cdecl;
|
||||
//* 'keyboard-interactive' authentication callback */
|
||||
LIBSSH2_USERAUTH_KBDINT_RESPONSE_FUNC = procedure(const name: PAnsiChar; name_len: cint;
|
||||
const instruction: PAnsiChar; instruction_len: cint;
|
||||
num_prompts: cint; const prompts: PLIBSSH2_USERAUTH_KBDINT_PROMPT;
|
||||
responses: PLIBSSH2_USERAUTH_KBDINT_RESPONSE; abstract: PPointer); cdecl;
|
||||
|
||||
var
|
||||
//* Session API */
|
||||
libssh2_session_init_ex: function(my_alloc: LIBSSH2_ALLOC_FUNC;
|
||||
my_free: LIBSSH2_FREE_FUNC;
|
||||
my_realloc: LIBSSH2_REALLOC_FUNC;
|
||||
abstract: Pointer): PLIBSSH2_SESSION; cdecl;
|
||||
libssh2_session_handshake: function(session: PLIBSSH2_SESSION; sock: cint): cint; cdecl;
|
||||
libssh2_hostkey_hash: function(session: PLIBSSH2_SESSION; hash_type: cint): PAnsiChar; cdecl;
|
||||
libssh2_session_disconnect_ex: function(session: PLIBSSH2_SESSION;
|
||||
reason: cint;
|
||||
const description: PAnsiChar;
|
||||
const lang: PAnsiChar): cint; cdecl;
|
||||
libssh2_session_free: function(session: PLIBSSH2_SESSION): cint; cdecl;
|
||||
libssh2_session_set_blocking: procedure(session: PLIBSSH2_SESSION; blocking: cint); cdecl;
|
||||
libssh2_session_last_errno: function(session: PLIBSSH2_SESSION): cint; cdecl;
|
||||
libssh2_session_set_timeout: procedure(session: PLIBSSH2_SESSION; timeout: clong); cdecl;
|
||||
//* Userauth API */
|
||||
libssh2_userauth_list: function(session: PLIBSSH2_SESSION;
|
||||
const username: PAnsiChar; username_len: cuint): PAnsiChar; cdecl;
|
||||
libssh2_userauth_password_ex: function(session: PLIBSSH2_SESSION;
|
||||
const username: PAnsiChar;
|
||||
username_len: cuint;
|
||||
const password: PAnsiChar;
|
||||
password_len: cuint;
|
||||
passwd_change_cb: LIBSSH2_PASSWD_CHANGEREQ_FUNC): cint; cdecl;
|
||||
libssh2_userauth_keyboard_interactive_ex: function(session: PLIBSSH2_SESSION;
|
||||
const username: PAnsiChar;
|
||||
username_len: cuint;
|
||||
response_callback: LIBSSH2_USERAUTH_KBDINT_RESPONSE_FUNC): cint; cdecl;
|
||||
//* SFTP API */
|
||||
libssh2_sftp_init: function(session: PLIBSSH2_SESSION): PLIBSSH2_SFTP; cdecl;
|
||||
libssh2_sftp_shutdown: function(sftp: PLIBSSH2_SFTP): cint; cdecl;
|
||||
libssh2_sftp_last_error: function(sftp: PLIBSSH2_SFTP): culong; cdecl;
|
||||
//* File / Directory Ops */
|
||||
libssh2_sftp_open_ex: function(sftp: PLIBSSH2_SFTP;
|
||||
const filename: PAnsiChar;
|
||||
filename_len: cint; flags: culong;
|
||||
mode: clong; open_type: cint): PLIBSSH2_SFTP_HANDLE; cdecl;
|
||||
libssh2_sftp_read: function(handle: PLIBSSH2_SFTP_HANDLE;
|
||||
buffer: PAnsiChar; buffer_maxlen: csize_t): ptrint; cdecl;
|
||||
libssh2_sftp_write: function(handle: PLIBSSH2_SFTP_HANDLE;
|
||||
buffer: PByte; count: csize_t): ptrint; cdecl;
|
||||
libssh2_sftp_readdir_ex: function(handle: PLIBSSH2_SFTP_HANDLE;
|
||||
buffer: PAnsiChar; buffer_maxlen: csize_t;
|
||||
longentry: PAnsiChar; longentry_maxlen: csize_t;
|
||||
attrs: PLIBSSH2_SFTP_ATTRIBUTES): cint; cdecl;
|
||||
libssh2_sftp_close_handle: function(handle: PLIBSSH2_SFTP_HANDLE): cint; cdecl;
|
||||
libssh2_sftp_seek64: procedure(handle: PLIBSSH2_SFTP_HANDLE; offset: cuint64); cdecl;
|
||||
//* Miscellaneous Ops */
|
||||
libssh2_sftp_rename_ex: function(sftp: PLIBSSH2_SFTP;
|
||||
const source_filename: PAnsiChar;
|
||||
srouce_filename_len: cuint;
|
||||
const dest_filename: PAnsiChar;
|
||||
dest_filename_len: cuint;
|
||||
flags: clong): cint; cdecl;
|
||||
libssh2_sftp_unlink_ex: function(sftp: PLIBSSH2_SFTP;
|
||||
const filename: PAnsiChar;
|
||||
filename_len: cuint): cint; cdecl;
|
||||
libssh2_sftp_statvfs: function(sftp: PLIBSSH2_SFTP;
|
||||
const path: PAnsiChar;
|
||||
path_len: csize_t;
|
||||
st: PLIBSSH2_SFTP_STATVFS): cint; cdecl;
|
||||
libssh2_sftp_mkdir_ex: function(sftp: PLIBSSH2_SFTP;
|
||||
const path: PAnsiChar;
|
||||
path_len: cuint; mode: clong): cint; cdecl;
|
||||
libssh2_sftp_rmdir_ex: function(sftp: PLIBSSH2_SFTP;
|
||||
const path: PAnsiChar;
|
||||
path_len: cuint): cint; cdecl;
|
||||
libssh2_sftp_stat_ex: function(sftp: PLIBSSH2_SFTP;
|
||||
const path: PAnsiChar;
|
||||
path_len: cuint;
|
||||
stat_type: cint;
|
||||
attrs: PLIBSSH2_SFTP_ATTRIBUTES): cint; cdecl;
|
||||
libssh2_sftp_symlink_ex: function(sftp: PLIBSSH2_SFTP;
|
||||
const path: PAnsiChar;
|
||||
path_len: cuint;
|
||||
target: PAnsiChar;
|
||||
target_len: cuint; link_type: cint): cint; cdecl;
|
||||
|
||||
//* Inline functions */
|
||||
function libssh2_session_init: PLIBSSH2_SESSION; inline;
|
||||
function libssh2_session_disconnect(session: PLIBSSH2_SESSION; const description: PAnsiChar): cint; inline;
|
||||
function libssh2_userauth_password(session: PLIBSSH2_SESSION; const username: PAnsiChar; const password: PAnsiChar): cint; inline;
|
||||
function libssh2_userauth_keyboard_interactive(session: PLIBSSH2_SESSION; const username: PAnsiChar; response_callback: LIBSSH2_USERAUTH_KBDINT_RESPONSE_FUNC): cint; inline;
|
||||
function libssh2_sftp_open(sftp: PLIBSSH2_SFTP; const filename: PAnsiChar; flags: culong; mode: clong): PLIBSSH2_SFTP_HANDLE; inline;
|
||||
function libssh2_sftp_opendir(sftp: PLIBSSH2_SFTP; const path: PAnsiChar): PLIBSSH2_SFTP_HANDLE; inline;
|
||||
function libssh2_sftp_close(handle: PLIBSSH2_SFTP_HANDLE): cint; inline;
|
||||
function libssh2_sftp_closedir(handle: PLIBSSH2_SFTP_HANDLE): cint; inline;
|
||||
function libssh2_sftp_rename(sftp: PLIBSSH2_SFTP; const sourcefile: PAnsiChar; const destfile: PAnsiChar): cint; inline;
|
||||
function libssh2_sftp_unlink(sftp: PLIBSSH2_SFTP; const filename: PAnsiChar): cint; inline;
|
||||
function libssh2_sftp_mkdir(sftp: PLIBSSH2_SFTP; const path: PAnsiChar; mode: clong): cint; inline;
|
||||
function libssh2_sftp_rmdir(sftp: PLIBSSH2_SFTP; const path: PAnsiChar): cint; inline;
|
||||
function libssh2_sftp_stat(sftp: PLIBSSH2_SFTP; const path: PAnsiChar; attrs: PLIBSSH2_SFTP_ATTRIBUTES): cint; inline;
|
||||
function libssh2_sftp_lstat(sftp: PLIBSSH2_SFTP; const path: PAnsiChar; attrs: PLIBSSH2_SFTP_ATTRIBUTES): cint; inline;
|
||||
function libssh2_sftp_setstat(sftp: PLIBSSH2_SFTP; const path: PAnsiChar; attrs: PLIBSSH2_SFTP_ATTRIBUTES): cint; inline;
|
||||
function libssh2_sftp_symlink(sftp: PLIBSSH2_SFTP; const orig: PAnsiChar; linkpath: PAnsiChar): cint; inline;
|
||||
function libssh2_sftp_readlink(sftp: PLIBSSH2_SFTP; const path: PAnsiChar; target: PAnsiChar; maxlen: cuint): cint; inline;
|
||||
function libssh2_sftp_realpath(sftp: PLIBSSH2_SFTP; const path: PAnsiChar; target: PAnsiChar; maxlen: cuint): cint; inline;
|
||||
|
||||
implementation
|
||||
|
||||
uses
|
||||
DynLibs;
|
||||
|
||||
function libssh2_session_init: PLIBSSH2_SESSION;
|
||||
begin
|
||||
Result:= libssh2_session_init_ex(nil, nil, nil, nil);
|
||||
end;
|
||||
|
||||
function libssh2_session_disconnect(session: PLIBSSH2_SESSION; const description: PAnsiChar): cint;
|
||||
begin
|
||||
Result:= libssh2_session_disconnect_ex(session, SSH_DISCONNECT_BY_APPLICATION,
|
||||
description, '');
|
||||
end;
|
||||
|
||||
function libssh2_userauth_password(session: PLIBSSH2_SESSION;
|
||||
const username: PAnsiChar; const password: PAnsiChar): cint;
|
||||
begin
|
||||
Result:= libssh2_userauth_password_ex(session, username, strlen(username),
|
||||
password, strlen(password), nil);
|
||||
end;
|
||||
|
||||
function libssh2_userauth_keyboard_interactive(session: PLIBSSH2_SESSION;
|
||||
const username: PAnsiChar;
|
||||
response_callback: LIBSSH2_USERAUTH_KBDINT_RESPONSE_FUNC): cint;
|
||||
begin
|
||||
Result:= libssh2_userauth_keyboard_interactive_ex(session, username, strlen(username), response_callback);
|
||||
end;
|
||||
|
||||
function libssh2_sftp_open(sftp: PLIBSSH2_SFTP; const filename: PAnsiChar;
|
||||
flags: culong; mode: clong): PLIBSSH2_SFTP_HANDLE;
|
||||
begin
|
||||
Result:= libssh2_sftp_open_ex(sftp, filename, strlen(filename), flags, mode, _LIBSSH2_SFTP_OPENFILE);
|
||||
end;
|
||||
|
||||
function libssh2_sftp_opendir(sftp: PLIBSSH2_SFTP; const path: PAnsiChar): PLIBSSH2_SFTP_HANDLE;
|
||||
begin
|
||||
Result:= libssh2_sftp_open_ex(sftp, path, strlen(path), 0, 0, _LIBSSH2_SFTP_OPENDIR);
|
||||
end;
|
||||
|
||||
function libssh2_sftp_close(handle: PLIBSSH2_SFTP_HANDLE): cint;
|
||||
begin
|
||||
Result:= libssh2_sftp_close_handle(handle);
|
||||
end;
|
||||
|
||||
function libssh2_sftp_closedir(handle: PLIBSSH2_SFTP_HANDLE): cint;
|
||||
begin
|
||||
Result:= libssh2_sftp_close_handle(handle);
|
||||
end;
|
||||
|
||||
function libssh2_sftp_rename(sftp: PLIBSSH2_SFTP; const sourcefile: PAnsiChar; const destfile: PAnsiChar): cint;
|
||||
begin
|
||||
Result:= libssh2_sftp_rename_ex(sftp, sourcefile, strlen(sourcefile),
|
||||
destfile, strlen(destfile),
|
||||
LIBSSH2_SFTP_RENAME_OVERWRITE or
|
||||
LIBSSH2_SFTP_RENAME_ATOMIC or
|
||||
LIBSSH2_SFTP_RENAME_NATIVE);
|
||||
end;
|
||||
|
||||
function libssh2_sftp_unlink(sftp: PLIBSSH2_SFTP; const filename: PAnsiChar): cint;
|
||||
begin
|
||||
Result:= libssh2_sftp_unlink_ex(sftp, filename, strlen(filename));
|
||||
end;
|
||||
|
||||
function libssh2_sftp_mkdir(sftp: PLIBSSH2_SFTP; const path: PAnsiChar; mode: clong): cint;
|
||||
begin
|
||||
Result:= libssh2_sftp_mkdir_ex(sftp, path, strlen(path), mode);
|
||||
end;
|
||||
|
||||
function libssh2_sftp_rmdir(sftp: PLIBSSH2_SFTP; const path: PAnsiChar): cint;
|
||||
begin
|
||||
Result:= libssh2_sftp_rmdir_ex(sftp, path, strlen(path));
|
||||
end;
|
||||
|
||||
function libssh2_sftp_stat(sftp: PLIBSSH2_SFTP; const path: PAnsiChar;
|
||||
attrs: PLIBSSH2_SFTP_ATTRIBUTES): cint;
|
||||
begin
|
||||
Result:= libssh2_sftp_stat_ex(sftp, path, strlen(path), _LIBSSH2_SFTP_STAT, attrs);
|
||||
end;
|
||||
|
||||
function libssh2_sftp_lstat(sftp: PLIBSSH2_SFTP; const path: PAnsiChar;
|
||||
attrs: PLIBSSH2_SFTP_ATTRIBUTES): cint;
|
||||
begin
|
||||
Result:= libssh2_sftp_stat_ex(sftp, path, strlen(path), _LIBSSH2_SFTP_LSTAT, attrs);
|
||||
end;
|
||||
|
||||
function libssh2_sftp_setstat(sftp: PLIBSSH2_SFTP; const path: PAnsiChar;
|
||||
attrs: PLIBSSH2_SFTP_ATTRIBUTES): cint;
|
||||
begin
|
||||
repeat
|
||||
Result:= libssh2_sftp_stat_ex(sftp, path, strlen(path), _LIBSSH2_SFTP_SETSTAT, attrs);
|
||||
Sleep(1);
|
||||
until Result <> LIBSSH2_ERROR_EAGAIN;
|
||||
end;
|
||||
|
||||
function libssh2_sftp_symlink(sftp: PLIBSSH2_SFTP; const orig: PAnsiChar;
|
||||
linkpath: PAnsiChar): cint;
|
||||
begin
|
||||
Result:= libssh2_sftp_symlink_ex(sftp, orig, strlen(orig), linkpath, strlen(linkpath), _LIBSSH2_SFTP_SYMLINK);
|
||||
end;
|
||||
|
||||
function libssh2_sftp_readlink(sftp: PLIBSSH2_SFTP; const path: PAnsiChar;
|
||||
target: PAnsiChar; maxlen: cuint): cint;
|
||||
begin
|
||||
Result:= libssh2_sftp_symlink_ex(sftp, path, strlen(path), target, maxlen, _LIBSSH2_SFTP_READLINK)
|
||||
end;
|
||||
|
||||
function libssh2_sftp_realpath(sftp: PLIBSSH2_SFTP; const path: PAnsiChar;
|
||||
target: PAnsiChar; maxlen: cuint): cint;
|
||||
begin
|
||||
Result:= libssh2_sftp_symlink_ex(sftp, path, strlen(path), target, maxlen, _LIBSSH2_SFTP_REALPATH);
|
||||
end;
|
||||
|
||||
var
|
||||
libssh2: TLibHandle = NilHandle;
|
||||
|
||||
function SafeGetProcAddress(Lib : TlibHandle; const ProcName : AnsiString) : Pointer;
|
||||
begin
|
||||
Result:= GetProcedureAddress(Lib, ProcName);
|
||||
if (Result = nil) then raise Exception.Create(EmptyStr);
|
||||
end;
|
||||
|
||||
procedure Initialize;
|
||||
begin
|
||||
libssh2:= LoadLibrary('libssh2.dll');
|
||||
if (libssh2 <> NilHandle) then
|
||||
try
|
||||
//* Session API */
|
||||
libssh2_session_init_ex:= SafeGetProcAddress(libssh2, 'libssh2_session_init_ex');
|
||||
libssh2_session_handshake:= SafeGetProcAddress(libssh2, 'libssh2_session_handshake');
|
||||
libssh2_hostkey_hash:= SafeGetProcAddress(libssh2, 'libssh2_hostkey_hash');
|
||||
libssh2_session_disconnect_ex:= SafeGetProcAddress(libssh2, 'libssh2_session_disconnect_ex');
|
||||
libssh2_session_free:= SafeGetProcAddress(libssh2, 'libssh2_session_free');
|
||||
libssh2_session_set_blocking:= SafeGetProcAddress(libssh2, 'libssh2_session_set_blocking');
|
||||
libssh2_session_last_errno:= SafeGetProcAddress(libssh2, 'libssh2_session_last_errno');
|
||||
libssh2_session_set_timeout:= SafeGetProcAddress(libssh2, 'libssh2_session_set_timeout');
|
||||
//* Userauth API */
|
||||
libssh2_userauth_list:= SafeGetProcAddress(libssh2, 'libssh2_userauth_list');
|
||||
libssh2_userauth_password_ex:= SafeGetProcAddress(libssh2, 'libssh2_userauth_password_ex');
|
||||
libssh2_userauth_keyboard_interactive_ex:= SafeGetProcAddress(libssh2, 'libssh2_userauth_keyboard_interactive_ex');
|
||||
//* SFTP API */
|
||||
libssh2_sftp_init:= SafeGetProcAddress(libssh2, 'libssh2_sftp_init');
|
||||
libssh2_sftp_shutdown:= SafeGetProcAddress(libssh2, 'libssh2_sftp_shutdown');
|
||||
libssh2_sftp_last_error:= SafeGetProcAddress(libssh2, 'libssh2_sftp_last_error');
|
||||
//* File / Directory Ops */
|
||||
libssh2_sftp_open_ex:= SafeGetProcAddress(libssh2, 'libssh2_sftp_open_ex');
|
||||
libssh2_sftp_read:= SafeGetProcAddress(libssh2, 'libssh2_sftp_read');
|
||||
libssh2_sftp_write:= SafeGetProcAddress(libssh2, 'libssh2_sftp_write');
|
||||
libssh2_sftp_readdir_ex:= SafeGetProcAddress(libssh2, 'libssh2_sftp_readdir_ex');
|
||||
libssh2_sftp_close_handle:= SafeGetProcAddress(libssh2, 'libssh2_sftp_close_handle');
|
||||
libssh2_sftp_seek64:= SafeGetProcAddress(libssh2, 'libssh2_sftp_seek64');
|
||||
//* Miscellaneous Ops */
|
||||
libssh2_sftp_rename_ex:= SafeGetProcAddress(libssh2, 'libssh2_sftp_rename_ex');
|
||||
libssh2_sftp_unlink_ex:= SafeGetProcAddress(libssh2, 'libssh2_sftp_unlink_ex');
|
||||
libssh2_sftp_statvfs:= SafeGetProcAddress(libssh2, 'libssh2_sftp_statvfs');
|
||||
libssh2_sftp_mkdir_ex:= SafeGetProcAddress(libssh2, 'libssh2_sftp_mkdir_ex');
|
||||
libssh2_sftp_rmdir_ex:= SafeGetProcAddress(libssh2, 'libssh2_sftp_rmdir_ex');
|
||||
libssh2_sftp_stat_ex:= SafeGetProcAddress(libssh2, 'libssh2_sftp_stat_ex');
|
||||
libssh2_sftp_symlink_ex:= SafeGetProcAddress(libssh2, 'libssh2_sftp_symlink_ex');
|
||||
|
||||
except
|
||||
end;
|
||||
end;
|
||||
|
||||
initialization
|
||||
Initialize;
|
||||
|
||||
finalization
|
||||
if (libssh2 <> NilHandle) then FreeLibrary(libssh2);
|
||||
|
||||
end.
|
||||
|
||||
463
plugins/wfx/ftp/src/sftp/sftpsend.pas
Normal file
463
plugins/wfx/ftp/src/sftp/sftpsend.pas
Normal file
|
|
@ -0,0 +1,463 @@
|
|||
unit SFtpSend;
|
||||
|
||||
{$mode delphi}
|
||||
|
||||
interface
|
||||
|
||||
uses
|
||||
Classes, SysUtils, WfxPlugin, ftpsend, libssh, FtpAdv;
|
||||
|
||||
type
|
||||
|
||||
{ TSFtpSend }
|
||||
|
||||
TSFtpSend = class(TFTPSendEx)
|
||||
private
|
||||
FLastError: Integer;
|
||||
SourceName, TargetName: PWideChar;
|
||||
procedure DoProgress(Percent: Int64);
|
||||
function FileClose(Handle: Pointer): Boolean;
|
||||
protected
|
||||
FCurrentDir: String;
|
||||
FSession: PLIBSSH2_SESSION;
|
||||
FSFTPSession: PLIBSSH2_SFTP;
|
||||
protected
|
||||
function Connect: Boolean; override;
|
||||
public
|
||||
constructor Create(const Encoding: String); override;
|
||||
function Login: Boolean; override;
|
||||
function Logout: Boolean; override;
|
||||
function GetCurrentDir: String; override;
|
||||
function FileSize(const FileName: String): Int64; override;
|
||||
function CreateDir(const Directory: string): Boolean; override;
|
||||
function DeleteDir(const Directory: string): Boolean; override;
|
||||
function DeleteFile(const FileName: string): Boolean; override;
|
||||
function ExecuteCommand(const Command: String): Boolean; override;
|
||||
function ChangeWorkingDir(const Directory: string): Boolean; override;
|
||||
function RenameFile(const OldName, NewName: string): Boolean; override;
|
||||
function ChangeMode(const FileName, Mode: String): Boolean; override;
|
||||
function StoreFile(const FileName: string; Restore: Boolean): Boolean; override;
|
||||
function RetrieveFile(const FileName: string; FileSize: Int64; Restore: Boolean): Boolean; override;
|
||||
public
|
||||
function FsFindFirstW(const Path: String; var FindData: TWin32FindDataW): Pointer; override;
|
||||
function FsFindNextW(Handle: Pointer; var FindData: TWin32FindDataW): BOOL; override;
|
||||
function FsFindClose(Handle: Pointer): Integer; override;
|
||||
function FsSetTime(const FileName: String; LastAccessTime, LastWriteTime: PFileTime): BOOL; override;
|
||||
end;
|
||||
|
||||
implementation
|
||||
|
||||
uses
|
||||
DCBasicTypes, DCDateTimeUtils, DCStrUtils, DCOSUtils, FtpFunc, CTypes, DCClassesUtf8;
|
||||
|
||||
const
|
||||
SMB_BUFFER_SIZE = 131072;
|
||||
|
||||
procedure userauth_kbdint(const name: PAnsiChar; name_len: cint;
|
||||
const instruction: PAnsiChar; instruction_len: cint;
|
||||
num_prompts: cint; const prompts: PLIBSSH2_USERAUTH_KBDINT_PROMPT;
|
||||
responses: PLIBSSH2_USERAUTH_KBDINT_RESPONSE; abstract: PPointer); cdecl;
|
||||
var
|
||||
I: Integer;
|
||||
Sender: TSFtpSend;
|
||||
begin
|
||||
Sender:= TSFtpSend(abstract^);
|
||||
for I:= 0 to num_prompts - 1 do
|
||||
begin
|
||||
if (I = 0) and (Length(Sender.FPassword) > 0) then
|
||||
begin
|
||||
responses^.text:= PAnsiChar(Sender.FPassword);
|
||||
responses^.length:= Length(Sender.FPassword);
|
||||
end;
|
||||
end;
|
||||
end;
|
||||
|
||||
{ TSFtpSend }
|
||||
|
||||
procedure TSFtpSend.DoProgress(Percent: Int64);
|
||||
begin
|
||||
if ProgressProc(PluginNumber, SourceName, TargetName, Percent) = 1 then
|
||||
raise EUserAbort.Create(EmptyStr);
|
||||
end;
|
||||
|
||||
function TSFtpSend.FileClose(Handle: Pointer): Boolean;
|
||||
begin
|
||||
if Assigned(Handle) then
|
||||
repeat
|
||||
FLastError:= libssh2_sftp_close(Handle);
|
||||
DoProgress(100);
|
||||
until FLastError <> LIBSSH2_ERROR_EAGAIN;
|
||||
Result:= (FLastError = 0);
|
||||
end;
|
||||
|
||||
function TSFtpSend.Connect: Boolean;
|
||||
const
|
||||
HOSTKEY_SIZE = 20;
|
||||
var
|
||||
I: Integer;
|
||||
S: String;
|
||||
userauthlist: PAnsiChar;
|
||||
FingerPrint: array [0..Pred(HOSTKEY_SIZE)] of AnsiChar;
|
||||
begin
|
||||
FSock.CloseSocket;
|
||||
DoStatus(False, 'Connecting to: ' + FTargetHost);
|
||||
FSock.Connect(FTargetHost, FTargetPort);
|
||||
|
||||
if FSock.LastError=0 then
|
||||
begin
|
||||
FSession := libssh2_session_init_ex(nil, nil, nil, Self);
|
||||
|
||||
libssh2_session_set_timeout(FSession, FTimeout);
|
||||
|
||||
//* Since we have not set non-blocking, tell libssh2 we are blocking */
|
||||
libssh2_session_set_blocking(FSession, 1);
|
||||
|
||||
if libssh2_session_handshake(FSession, FSock.Socket) <> 0 then
|
||||
begin
|
||||
DoStatus(False, 'Cannot establishing SSH session');
|
||||
Exit(False);
|
||||
end;
|
||||
DoStatus(False, 'Connection established');
|
||||
FingerPrint := libssh2_hostkey_hash(FSession, LIBSSH2_HOSTKEY_HASH_SHA1);
|
||||
S:= 'Server fingerprint:';
|
||||
i:=0;
|
||||
for I:= Low(FingerPrint) to High(FingerPrint) do
|
||||
begin
|
||||
S:= S + #32 + IntToHex(Ord(FingerPrint[i]), 2);
|
||||
end;
|
||||
DoStatus(False, S);
|
||||
|
||||
//* check what authentication methods are available */
|
||||
userauthlist := libssh2_userauth_list(FSession, PAnsiChar(FUserName), Length(FUserName));
|
||||
|
||||
if (strpos(userauthlist, 'password') <> nil) then
|
||||
begin
|
||||
I:= libssh2_userauth_password(FSession, PAnsiChar(FUserName), PAnsiChar(FPassword));
|
||||
if I <> 0 then
|
||||
begin
|
||||
DoStatus(False, 'Authentication by password failed');
|
||||
Exit(False);
|
||||
end;
|
||||
end
|
||||
else if (strpos(userauthlist, 'keyboard-interactive') <> nil) then
|
||||
begin
|
||||
I:= libssh2_userauth_keyboard_interactive(FSession, PAnsiChar(FUserName), @userauth_kbdint);
|
||||
if I <> 0 then
|
||||
begin
|
||||
DoStatus(False, 'Authentication by keyboard-interactive failed');
|
||||
Exit(False);
|
||||
end;
|
||||
end
|
||||
else if (strpos(userauthlist, 'publickey') <> nil) then
|
||||
begin
|
||||
DoStatus(False, 'Authentication by publickey is not supported!');
|
||||
Exit(False);
|
||||
end;
|
||||
|
||||
DoStatus(False, 'Authentication succeeded');
|
||||
FSFTPSession := libssh2_sftp_init(FSession);
|
||||
|
||||
end;
|
||||
Result:= Assigned(FSFTPSession);
|
||||
end;
|
||||
|
||||
constructor TSFtpSend.Create(const Encoding: String);
|
||||
begin
|
||||
FCurrentDir:= '/';
|
||||
inherited Create(Encoding);
|
||||
FTargetPort:= '22';
|
||||
FCanResume := True;
|
||||
end;
|
||||
|
||||
function TSFtpSend.Login: Boolean;
|
||||
begin
|
||||
Result:= Connect;
|
||||
end;
|
||||
|
||||
function TSFtpSend.Logout: Boolean;
|
||||
begin
|
||||
Result:= libssh2_sftp_shutdown(FSFTPSession) = 0;
|
||||
libssh2_session_disconnect(FSession, 'Thank you for using sshtest');
|
||||
libssh2_session_free(FSession);
|
||||
FSock.CloseSocket;
|
||||
end;
|
||||
|
||||
function TSFtpSend.GetCurrentDir: String;
|
||||
begin
|
||||
Result:= FCurrentDir;
|
||||
end;
|
||||
|
||||
function TSFtpSend.FileSize(const FileName: String): Int64;
|
||||
var
|
||||
Attributes: LIBSSH2_SFTP_ATTRIBUTES;
|
||||
begin
|
||||
if (libssh2_sftp_stat(FSFTPSession, PAnsiChar(FileName), @Attributes) = 0) then
|
||||
Result:= Attributes.filesize
|
||||
else begin
|
||||
Result:= -1;
|
||||
end;
|
||||
end;
|
||||
|
||||
function TSFtpSend.CreateDir(const Directory: string): Boolean;
|
||||
var
|
||||
Return: Integer;
|
||||
Attributes: LIBSSH2_SFTP_ATTRIBUTES;
|
||||
begin
|
||||
Return:= libssh2_sftp_mkdir(FSFTPSession,
|
||||
PAnsiChar(Directory),
|
||||
LIBSSH2_SFTP_S_IRWXU or
|
||||
LIBSSH2_SFTP_S_IRGRP or LIBSSH2_SFTP_S_IXGRP or
|
||||
LIBSSH2_SFTP_S_IROTH or LIBSSH2_SFTP_S_IXOTH);
|
||||
if (Return <> 0) then begin
|
||||
Return:= libssh2_sftp_stat(FSFTPSession, PAnsiChar(Directory), @Attributes);
|
||||
end;
|
||||
Result:= (Return = 0);
|
||||
end;
|
||||
|
||||
function TSFtpSend.DeleteDir(const Directory: string): Boolean;
|
||||
begin
|
||||
Result:= libssh2_sftp_rmdir(FSFTPSession, PAnsiChar(Directory)) = 0;
|
||||
end;
|
||||
|
||||
function TSFtpSend.DeleteFile(const FileName: string): Boolean;
|
||||
begin
|
||||
Result:= libssh2_sftp_unlink(FSFTPSession, PAnsiChar(FileName)) = 0;
|
||||
end;
|
||||
|
||||
function TSFtpSend.ExecuteCommand(const Command: String): Boolean;
|
||||
begin
|
||||
Result:= False;
|
||||
end;
|
||||
|
||||
function TSFtpSend.ChangeWorkingDir(const Directory: string): Boolean;
|
||||
var
|
||||
Attributes: LIBSSH2_SFTP_ATTRIBUTES;
|
||||
begin
|
||||
Result:= libssh2_sftp_stat(FSFTPSession, PAnsiChar(Directory), @Attributes) = 0;
|
||||
if Result then FCurrentDir:= Directory;
|
||||
end;
|
||||
|
||||
function TSFtpSend.RenameFile(const OldName, NewName: string): Boolean;
|
||||
begin
|
||||
Result:= libssh2_sftp_rename(FSFTPSession, PAnsiChar(OldName), PAnsiChar(NewName)) = 0;
|
||||
end;
|
||||
|
||||
function TSFtpSend.ChangeMode(const FileName, Mode: String): Boolean;
|
||||
var
|
||||
Attributes: LIBSSH2_SFTP_ATTRIBUTES;
|
||||
begin
|
||||
Attributes.permissions:= OctToDec(Mode);
|
||||
Attributes.flags:= LIBSSH2_SFTP_ATTR_PERMISSIONS;
|
||||
Result:= libssh2_sftp_setstat(FSFTPSession, PAnsiChar(FileName), @Attributes) = 0;
|
||||
end;
|
||||
|
||||
function TSFtpSend.StoreFile(const FileName: string; Restore: Boolean): Boolean;
|
||||
var
|
||||
Index: PtrInt;
|
||||
FBuffer: PByte;
|
||||
FileSize: Int64;
|
||||
BytesRead: Integer;
|
||||
BytesToRead: Integer;
|
||||
BytesWritten: PtrInt;
|
||||
BytesToWrite: Integer;
|
||||
SendStream: TFileStreamEx;
|
||||
TotalBytesToWrite: Int64 = 0;
|
||||
TargetHandle: PLIBSSH2_SFTP_HANDLE;
|
||||
Flags: cint = LIBSSH2_FXF_CREAT or LIBSSH2_FXF_WRITE;
|
||||
begin
|
||||
SendStream := TFileStreamEx.Create(FDirectFileName, fmOpenRead or fmShareDenyWrite);
|
||||
|
||||
TargetName:= PWideChar(ServerToClient(FileName));
|
||||
SourceName:= PWideChar(UTF8Decode(FDirectFileName));
|
||||
|
||||
FileSize:= SendStream.Size;
|
||||
FBuffer:= GetMem(SMB_BUFFER_SIZE);
|
||||
libssh2_session_set_blocking(FSession, 0);
|
||||
try
|
||||
if not Restore then
|
||||
begin
|
||||
TotalBytesToWrite:= FileSize;
|
||||
Flags:= Flags or LIBSSH2_FXF_TRUNC
|
||||
end
|
||||
else begin
|
||||
TotalBytesToWrite:= Self.FileSize(FileName);
|
||||
if (FileSize = TotalBytesToWrite) then Exit(True);
|
||||
if TotalBytesToWrite < 0 then TotalBytesToWrite:= 0;
|
||||
SendStream.Seek(TotalBytesToWrite, soBeginning);
|
||||
TotalBytesToWrite := FileSize - TotalBytesToWrite;
|
||||
Flags:= Flags or LIBSSH2_FXF_APPEND;
|
||||
end;
|
||||
|
||||
// Open remote file
|
||||
repeat
|
||||
TargetHandle:= libssh2_sftp_open(FSFTPSession,
|
||||
PAnsiChar(FileName),
|
||||
Flags, $1A0);
|
||||
if (TargetHandle = nil) then
|
||||
begin
|
||||
FLastError:= libssh2_session_last_errno(FSession);
|
||||
if (FLastError <> LIBSSH2_ERROR_EAGAIN) then Exit(False);
|
||||
DoProgress((FileSize - TotalBytesToWrite) * 100 div FileSize);
|
||||
end;
|
||||
until not ((TargetHandle = nil) and (FLastError = LIBSSH2_ERROR_EAGAIN));
|
||||
|
||||
BytesToRead:= SMB_BUFFER_SIZE;
|
||||
while (TotalBytesToWrite > 0) do
|
||||
begin
|
||||
if (BytesToRead > TotalBytesToWrite) then begin
|
||||
BytesToRead:= TotalBytesToWrite;
|
||||
end;
|
||||
BytesRead:= SendStream.Read(FBuffer^, BytesToRead);
|
||||
if (BytesRead = 0) then Exit(False);
|
||||
// Start write operation
|
||||
Index:= 0;
|
||||
BytesToWrite:= BytesRead;
|
||||
while (BytesToWrite > 0) do
|
||||
begin
|
||||
repeat
|
||||
BytesWritten:= libssh2_sftp_write(TargetHandle, FBuffer + Index, BytesToWrite);
|
||||
if BytesWritten = LIBSSH2_ERROR_EAGAIN then begin
|
||||
DoProgress((FileSize - TotalBytesToWrite) * 100 div FileSize);
|
||||
end;
|
||||
until BytesWritten <> LIBSSH2_ERROR_EAGAIN;
|
||||
if (BytesWritten < 0) then Exit(False);
|
||||
Dec(TotalBytesToWrite, BytesWritten);
|
||||
Dec(BytesToWrite, BytesWritten);
|
||||
Inc(Index, BytesWritten);
|
||||
end;
|
||||
DoProgress((FileSize - TotalBytesToWrite) * 100 div FileSize);
|
||||
end;
|
||||
Result:= True;
|
||||
finally
|
||||
SendStream.Free;
|
||||
FreeMem(FBuffer);
|
||||
Result:= FileClose(TargetHandle) and Result;
|
||||
libssh2_session_set_blocking(FSession, 1);
|
||||
end;
|
||||
end;
|
||||
|
||||
function TSFtpSend.RetrieveFile(const FileName: string; FileSize: Int64;
|
||||
Restore: Boolean): Boolean;
|
||||
var
|
||||
FBuffer: PByte;
|
||||
BytesRead: PtrInt;
|
||||
RetrStream: TFileStreamEx;
|
||||
TotalBytesToRead: Int64 = 0;
|
||||
SourceHandle: PLIBSSH2_SFTP_HANDLE;
|
||||
begin
|
||||
if Restore and mbFileExists(FDirectFileName) then
|
||||
RetrStream := TFileStreamEx.Create(FDirectFileName, fmOpenWrite or fmShareExclusive)
|
||||
else begin
|
||||
RetrStream := TFileStreamEx.Create(FDirectFileName, fmCreate or fmShareDenyWrite)
|
||||
end;
|
||||
|
||||
SourceName := PWideChar(ServerToClient(FileName));
|
||||
TargetName := PWideChar(UTF8Decode(FDirectFileName));
|
||||
|
||||
if Restore then TotalBytesToRead:= RetrStream.Seek(0, soEnd);
|
||||
|
||||
libssh2_session_set_blocking(FSession, 0);
|
||||
try
|
||||
repeat
|
||||
SourceHandle:= libssh2_sftp_open(FSFTPSession,
|
||||
PAnsiChar(FileName),
|
||||
LIBSSH2_FXF_READ, 0);
|
||||
if (SourceHandle = nil) then
|
||||
begin
|
||||
FLastError:= libssh2_session_last_errno(FSession);
|
||||
if (FLastError <> LIBSSH2_ERROR_EAGAIN) then Exit(False);
|
||||
DoProgress((FileSize - TotalBytesToRead) * 100 div FileSize);
|
||||
end;
|
||||
until not ((SourceHandle = nil) and (FLastError = LIBSSH2_ERROR_EAGAIN));
|
||||
|
||||
if Restore then begin
|
||||
libssh2_sftp_seek64(SourceHandle, TotalBytesToRead);
|
||||
end;
|
||||
|
||||
FBuffer:= GetMem(SMB_BUFFER_SIZE);
|
||||
TotalBytesToRead:= FileSize - TotalBytesToRead;
|
||||
try
|
||||
while TotalBytesToRead > 0 do
|
||||
begin
|
||||
repeat
|
||||
BytesRead := libssh2_sftp_read(SourceHandle, PAnsiChar(FBuffer), SMB_BUFFER_SIZE);
|
||||
if BytesRead = LIBSSH2_ERROR_EAGAIN then begin
|
||||
DoProgress((FileSize - TotalBytesToRead) * 100 div FileSize);
|
||||
end;
|
||||
until BytesRead <> LIBSSH2_ERROR_EAGAIN;
|
||||
|
||||
if (BytesRead < 0) then Exit(False);
|
||||
|
||||
if RetrStream.Write(FBuffer^, BytesRead) <> BytesRead then
|
||||
Exit(False);
|
||||
|
||||
Dec(TotalBytesToRead, BytesRead);
|
||||
DoProgress((FileSize - TotalBytesToRead) * 100 div FileSize);
|
||||
end;
|
||||
Result:= True;
|
||||
finally
|
||||
RetrStream.Free;
|
||||
FreeMem(FBuffer);
|
||||
Result:= FileClose(SourceHandle) and Result;
|
||||
end;
|
||||
finally
|
||||
libssh2_session_set_blocking(FSession, 1);
|
||||
end;
|
||||
end;
|
||||
|
||||
function TSFtpSend.FsFindFirstW(const Path: String; var FindData: TWin32FindDataW): Pointer;
|
||||
begin
|
||||
Result := libssh2_sftp_opendir(FSFTPSession, PAnsiChar(Path));
|
||||
if Assigned(Result) then FsFindNextW(Result, FindData);
|
||||
end;
|
||||
|
||||
function TSFtpSend.FsFindNextW(Handle: Pointer; var FindData: TWin32FindDataW): BOOL;
|
||||
var
|
||||
Return: Integer;
|
||||
Attributes: LIBSSH2_SFTP_ATTRIBUTES;
|
||||
AFileName: array[0..1023] of AnsiChar;
|
||||
AFullData: array[0..1023] of AnsiChar;
|
||||
begin
|
||||
Return:= libssh2_sftp_readdir_ex(Handle, AFileName, SizeOf(AFileName),
|
||||
AFullData, SizeOf(AFullData), @Attributes);
|
||||
Result:= (Return > 0);
|
||||
if Result then
|
||||
begin
|
||||
FillChar(FindData, SizeOf(FindData), 0);
|
||||
StrPCopy(FindData.cFileName, ServerToClient(AFileName));
|
||||
FindData.dwReserved0:= Attributes.permissions;
|
||||
FindData.dwFileAttributes:= FILE_ATTRIBUTE_UNIX_MODE;
|
||||
FindData.nFileSizeLow:= Int64Rec(Attributes.filesize).Lo;
|
||||
FindData.nFileSizeHigh:= Int64Rec(Attributes.filesize).Hi;
|
||||
FindData.ftLastAccessTime:= TWfxFileTime(UnixFileTimeToWinTime(Attributes.atime));
|
||||
FindData.ftLastWriteTime:= TWfxFileTime(UnixFileTimeToWinTime(Attributes.mtime));
|
||||
end;
|
||||
end;
|
||||
|
||||
function TSFtpSend.FsFindClose(Handle: Pointer): Integer;
|
||||
begin
|
||||
Result:= libssh2_sftp_closedir(Handle);
|
||||
end;
|
||||
|
||||
function TSFtpSend.FsSetTime(const FileName: String; LastAccessTime,
|
||||
LastWriteTime: WfxPlugin.PFileTime): BOOL;
|
||||
var
|
||||
Attributes: LIBSSH2_SFTP_ATTRIBUTES;
|
||||
begin
|
||||
if (LastAccessTime = nil) or (LastWriteTime = nil) then
|
||||
begin
|
||||
if libssh2_sftp_stat(FSFTPSession, PAnsiChar(FileName), @Attributes) <> 0 then
|
||||
Exit(False);
|
||||
end;
|
||||
if Assigned(LastAccessTime) then begin
|
||||
Attributes.atime:= WinFileTimeToUnixTime(TWinFileTime(LastAccessTime^));
|
||||
end;
|
||||
if Assigned(LastWriteTime) then begin
|
||||
Attributes.mtime:= WinFileTimeToUnixTime(TWinFileTime(LastWriteTime^));
|
||||
end;
|
||||
Attributes.flags:= LIBSSH2_SFTP_ATTR_ACMODTIME;
|
||||
Result:= libssh2_sftp_setstat(FSFTPSession, PAnsiChar(FileName), @Attributes) = 0;
|
||||
end;
|
||||
|
||||
end.
|
||||
|
||||
Loading…
Add table
Add a link
Reference in a new issue