研究了一下libssh与libssh2,网上的例子除了官方的example,寥寥无几,share一下自己拙劣的C++封装。
ssh2.h
/* Objective C++ using libssh2 (http://www.libssh2.org/). LIBRARY NEEDED ssl crypto ssh2 ABOUT LIBSSH2 http://www.libssh2.org/docs.html http://www.libssh2.org/examples/ Date 2010-07-30 Author xiaohan */ #ifndef _SSH2_H_CLASS_ #define _SSH2_H_CLASS_ #include <libssh2.h> #include <libssh2_sftp.h> #include <sys/socket.h> #include <sys/poll.h> #include <netinet/in.h> #include <unistd.h> #include <arpa/inet.h> #include <sys/types.h> #include <fcntl.h> #include <errno.h> #include <stdio.h> #include <stdlib.h> #include <ctype.h> #include <sys/select.h> #include <string> #include <cstring> #include <cassert> #include <algorithm> #include <pwd.h> #include <grp.h> #include <dirent.h> /* 自定义的错误码 */ #define SSH2_ERRNO_INVALID_USING -200 #define SSH2_ERRNO_REMOTE_CHOWN_FAILID -201 class ssh2_t { public: ssh2_t() : m_sock(0), m_session(NULL), m_connected(0), m_sftp(NULL), m_buf(NULL), m_buflen(1024), m_errno(0), m_errmsg(NULL), m_errmsg_buflen(1024) { m_buf = new char[m_buflen]; assert(m_buf); m_errmsg = new char[m_errmsg_buflen]; assert(m_errmsg); } virtual ~ssh2_t() { disconnect(); delete[] m_buf; m_buf = NULL; delete[] m_errmsg; m_errmsg = NULL; } long tvdiff(struct timeval newer, struct timeval older); /********************************************************************************************************************** * @connect * DESCRIPTION * 建立到目标主机的ssh连接; 如果此前已连接到其他主机,将断开连接并连接到新的主机 * PARAMETER LIST * 1 ip std::string [in] * 2 port unsigned short [in] * 3 username std::string [in] * 4 password std::string [in] * RETURN VALUE * 0, 成功; * ERRNO * 该函数将重置实例的errno和errmsg * 0 无错误 * >0 系统错误 * <0,>-100 libssh2错误 **********************************************************************************************************************/ int connect(const std::string& ip, unsigned short port, const std::string& username, const std::string& password); /********************************************************************************************************************** * @connected * DESCRIPTION * 连接是否建立成功 * RETURN VALUE * 0, 无连接; 非0, 已连接 * ERRNO * INVALID **********************************************************************************************************************/ int connected()const{return m_connected;} int connected(){return m_connected;} /********************************************************************************************************************** * @disconnect * DESCRIPTION * 断开已建立的连接 * ERRNO * INVALID **********************************************************************************************************************/ void disconnect(); LIBSSH2_CHANNEL* channel_open(); int channel_close(LIBSSH2_CHANNEL* channel); int channel_exec(LIBSSH2_CHANNEL* channel, const std::string& cmdline); int channel_write(LIBSSH2_CHANNEL* channel, const char* buf, size_t len); int channel_read(LIBSSH2_CHANNEL* channel, char* buf, size_t len); /********************************************************************************************************************** * @exec * DESCRIPTION * 通过ssh连接执行命令, 并将执行过程的标准输出和标准出错写入指定的fd和内存buffer * PARAMETER LIST * 1 cmdline std::string [in] [required] 要执行的命令 * 2 stdout_buf char* [mod][optional] 标准输出的buffer; * 若NULL,stdout_buf stdout_buflen stdout_recvlen将被忽略; * 若!NULL,将写入已NULL结尾的字符串 * 3 stdout_buflen int [in] [optional] 标准输出的buffer长度; * 若stdout_buf!=NULL, stdout_buflen必须>0 * 4 stdout_recvlen int* [mod][optional] 若!NULL, *stdout_recvlen记录写入stdout_buf的实际长度(byte) * 5 stderr_buf char* [mod][optional] 标准错误的buffer; * 若NULL,stderr_buf stderr_buflen stderr_recvlen将被忽略 * 若!NULL,将写入已NULL结尾的字符串 * 6 stderr_buflen int [in] [optional] 标准错误的buffer长度; * 若stderr_buf非NULL, stdout_buflen必须>0 * 7 stderr_recvlen int* [mod][optional] 若NULL, *stderr_recvlen记录写入stderr_buf的实际长度(byte) * 8 stdout_fd int [in] [optional] 若>0, 标准输出将写入stdout_fd * 9 stderr_fd int [in] [optional] 若>0, 标准错误将写入stderr_fd * RETURN VALUE * 该函数将重置实例的errno和errmsg * 0, 成功; * 非零, 失败; * ERRNO **********************************************************************************************************************/ int exec(const std::string& cmdline, char* stdout_buf=NULL, int stdout_buflen=0, int* stdout_recvlen=NULL, char* stderr_buf=NULL, int stderr_buflen=0, int* stderr_recvlen=NULL, int stdout_fd=-1, int stder_fd=-1); LIBSSH2_SFTP* sftp_init(); int sftp_shutdown(); int sftp_close_handle(LIBSSH2_SFTP_HANDLE* sftp_handle); LIBSSH2_SFTP_HANDLE* sftp_open(const std::string& path, long flags, long mode); int sftp_close(LIBSSH2_SFTP_HANDLE* sftp_handle); int sftp_read(LIBSSH2_SFTP_HANDLE* sftp_handle, char* buf, size_t len); int sftp_write(LIBSSH2_SFTP_HANDLE* sftp_handle, const char* buf, size_t len); LIBSSH2_SFTP_HANDLE* sftp_opendir(const std::string& path); int sftp_closedir(LIBSSH2_SFTP_HANDLE* sftp_handle); int sftp_readdir(LIBSSH2_SFTP_HANDLE* sftp_handle, char* buf, size_t buflen, LIBSSH2_SFTP_ATTRIBUTES* attrs); int sftp_unlink(const std::string& path); int sftp_mkdir(const std::string& path, long mode); int sftp_rmdir(const std::string& path); int sftp_stat(const std::string& path, LIBSSH2_SFTP_ATTRIBUTES* attrs); int sftp_lstat(const std::string& path, LIBSSH2_SFTP_ATTRIBUTES* attrs); int sftp_setstat(const std::string& path, LIBSSH2_SFTP_ATTRIBUTES* attrs); int sftp_readlink(const std::string& path, char* buf, size_t buflen); int sftp_symlink(const std::string& path, const std::string& link); int sftp_realpath(const std::string& path, char* buf, size_t buflen); void init_attrs(LIBSSH2_SFTP_ATTRIBUTES* attrs, struct stat* st); int sftp_copy_file(const std::string& local, const std::string& remote, char* buf, size_t buflen); int sftp_copy_link(const std::string& local, const std::string& remote, char* buf, size_t buflen); int sftp_copy_dir(const std::string& local, const std::string& remote, char* buf, size_t buflen); int sftp_copy(const std::string& local, const std::string& remote, char* buf=NULL, size_t buflen=0); /********************************************************************************************************************** * @remote_chown * DESCRIPTION * 修改远程主机指定文件的属主和属组 * PARAMETER LIST * 1 remote std::string [in] * 2 user std::string [in] * 4 group std::string [in] * RETURN VALUE * 0, 成功; * ERRNO * 该函数将重置实例的errno和errmsg * 0 无错误 * >0 系统错误 * <0,>-100 libssh2错误 **********************************************************************************************************************/ int remote_chown(const std::string& remote, const std::string& user, const std::string& group); /********************************************************************************************************************** * @ sendfile * DESCRIPTION * 将本地文件scp到目标机器指定路径. 若目标主机文件已存在将被覆盖 WARNING! 不支持目录 * PARAMETER LIST * 1 lcoal std::string [in] [required] 要传输的本地文件 * 2 remote std::string [in] [required] 在目标机器上的全路径(包括名称) * 3 keep_owner int [in] [optional] 0,属主为连接使用的账户; else, 属主和属组与源文件相同 * RETURN VALUE * 0, 成功; * ERRNO * 该函数将重置实例的errno和errmsg * 0 无错误 * >0 系统错误 * <0,>-100 libssh2错误 **********************************************************************************************************************/ int sendfile(const std::string& local, const std::string& remote, int keep_owner=0); /********************************************************************************************************************** * @ recvfile * DESCRIPTION * 将目标机器指定路径文件scp到本地. 若本机文件已存在将被覆盖 WARNING! 不支持目录 * PARAMETER LIST * 1 lcoal std::string [in] [required] 要传输的文件在目标机器上的全路径 * 2 remote std::string [in] [required] 本地文件路径(包括名称) * RETURN VALUE * 0, 成功; * ERRNO * 该函数将重置实例的errno和errmsg * 0 无错误 * >0 系统错误 * <0,>-100 libssh2错误 **********************************************************************************************************************/ int recvfile(const std::string& local, const std::string& remote); void clear_error(){m_errno=0;snprintf(m_errmsg, m_errmsg_buflen, "%s", "success");} const char* last_error()const{return m_errmsg;} int last_errno()const{return m_errno;} protected: int waitsocket(int timeout=-1); void get_sys_error(){m_errno = errno; strerror_r(m_errno, m_errmsg, m_errmsg_buflen);} void get_lib_error() { m_errno = libssh2_session_last_errno(m_session); char* errmsg = NULL; int errmsg_len = 0; libssh2_session_last_error(m_session, &errmsg, &errmsg_len, 0); if (errmsg_len>0 && errmsg) { strncpy(m_errmsg, errmsg, m_errmsg_buflen); } } std::string uid_to_name(uid_t uid); std::string gid_to_name(gid_t gid); void set_nonblocking(int fd); private: /* forbidden copy */ ssh2_t(const ssh2_t& e); ssh2_t& operator=(const ssh2_t& e); std::string basename(const std::string& path); std::string dirname(const std::string& path); std::string fixpath(const std::string& path); protected: struct sockaddr_in m_sin; int m_sock; LIBSSH2_SESSION* m_session; int m_connected; LIBSSH2_SFTP* m_sftp; char* m_buf; size_t m_buflen; int m_errno; // m_errno>0的部分是等于系统errno, m_errno<0是libssh2的错误 char* m_errmsg; // NUL结尾的字符串 size_t m_errmsg_buflen; }; #endif //_SSH2_H_CLASS_
ssh2.cpp
#include "ssh2.h" #include <iostream> /* set a fd into nonblocking mod#include <grp.h>e. */ void ssh2_t::set_nonblocking(int fd) { int val; if ((val = fcntl(fd, F_GETFL)) == -1) return; if (!(val & O_NONBLOCK)) { val |= O_NONBLOCK; fcntl(fd, F_SETFL, val); } } int ssh2_t::waitsocket(int timeout/*=-1*/) { int rc; struct pollfd pfd; bzero(&pfd, sizeof(pfd)); pfd.events = 0; //POLLHUP | POLLERR; pfd.fd = m_sock; int dir = 0; // now make sure we wait in the correct direction dir = libssh2_session_block_directions(m_session); if(dir & LIBSSH2_SESSION_BLOCK_INBOUND) pfd.events |= POLLIN; if(dir & LIBSSH2_SESSION_BLOCK_OUTBOUND) pfd.events |= POLLOUT; rc = poll(&pfd, 1, timeout*1000); return rc; } long ssh2_t::tvdiff(struct timeval newer, struct timeval older) { return (newer.tv_sec-older.tv_sec)*1000 + (newer.tv_usec-older.tv_usec)/1000; } void ssh2_t::disconnect() { if (m_session) { libssh2_session_disconnect(m_session, "Normal Shutdown"); libssh2_session_free(m_session); m_session = NULL; } if (m_sock) { ::close(m_sock); m_sock = 0; } m_connected = 0; } int ssh2_t::connect(const std::string& ip, unsigned short port, const std::string& username, const std::string& password) { clear_error(); if (m_connected) { // 判断是否是重复connect, 否则先disconnect之 char ipaddr[INET_ADDRSTRLEN]; inet_ntop(AF_INET, &m_sin.sin_addr, ipaddr, INET_ADDRSTRLEN); if (ip==ipaddr && port==ntohs(m_sin.sin_port)) { return 0; } else { disconnect(); } } int rc = 0; // 返回结果的临时变量 /* 连接ssh端口 */ inet_pton(AF_INET, ip.c_str(), &m_sin.sin_addr); m_sin.sin_family = AF_INET; m_sin.sin_port = htons(port); m_sock = socket(AF_INET, SOCK_STREAM, 0); while ((m_connected=::connect(m_sock, (struct sockaddr*)(&m_sin), sizeof(struct sockaddr_in)))==-1 && EINTR==errno); if (m_sock<=0 || m_connected) { get_sys_error(); disconnect(); return -1; } // 建立session m_session = libssh2_session_init(); if (NULL==m_session) { get_lib_error(); disconnect(); return -1; } libssh2_session_set_blocking(m_session, 0); // 非阻塞socket while ((rc=libssh2_session_startup(m_session, m_sock))==LIBSSH2_ERROR_EAGAIN && waitsocket()>=0); if (rc) { get_lib_error(); disconnect(); return -1; } // 检查验证方法 : 仅使用password方式 char *userauthlist = NULL; while ( (userauthlist=libssh2_userauth_list(m_session, username.c_str(), username.size()))==NULL && libssh2_session_last_error(m_session,NULL,NULL,0)==LIBSSH2_ERROR_EAGAIN && waitsocket()>=0); if (NULL==userauthlist || strstr(userauthlist, "password") == NULL) { get_lib_error(); disconnect(); return -1; } // auth while ((rc=libssh2_userauth_password(m_session, username.c_str(), password.c_str()))==LIBSSH2_ERROR_EAGAIN && waitsocket()>=0); if (rc) { get_lib_error(); disconnect(); return -1; } m_connected = 1; return 0; } int ssh2_t::exec(const std::string& cmdline, char* stdout_buf/*=NULL*/, int stdout_buflen/*=0*/, int* stdout_recvlen/*=NULL*/, char* stderr_buf/*=NULL*/, int stderr_buflen/*=0*/, int* stderr_recvlen/*=NULL*/, int stdout_fd/*=-1*/, int stderr_fd/*=-1*/) { clear_error(); if (0==m_connected) { /// FIX ME : do connect snprintf(m_errmsg, m_errmsg_buflen, "%s", "None connection yet"); return -1; } int rc = 0; int ret = 0; LIBSSH2_CHANNEL* channel = NULL; while( (channel= libssh2_channel_open_session(m_session))==NULL && libssh2_session_last_error(m_session,NULL,NULL,0)==LIBSSH2_ERROR_EAGAIN && waitsocket()>=0 ); if( channel == NULL ) { get_sys_error(); return -1; } libssh2_channel_set_blocking(channel, 1); while ((rc=libssh2_channel_exec(channel, cmdline.c_str()))==LIBSSH2_ERROR_EAGAIN && waitsocket()>=0); if (rc) { ret = -1; get_lib_error(); goto clearup; } // 获取标准输出 if (stdout_recvlen) *stdout_recvlen = 0; if (stdout_buf) *stdout_buf = 0; if (0==rc && (stdout_fd>=0 || (stdout_buf&&stdout_buflen>0))) { while (1) { int nread = libssh2_channel_read(channel, m_buf, m_buflen); if (LIBSSH2_ERROR_EAGAIN==nread) { waitsocket(); continue; } if (nread > 0) { if (stdout_fd>=0) { write(stdout_fd, m_buf, nread); // FIX ME : 未检查错误 } int len = std::min(nread, stdout_buflen-1); // 尽量多的写入buf, 但至少留一个字节置为NUL if (stdout_buf && len>0) { memcpy(stdout_buf, m_buf, len); stdout_buf += len; stdout_buflen -= len; *stdout_buf = 0; // 以NUL结尾 if (stdout_recvlen) *stdout_recvlen += len; } } else { get_lib_error(); break; } } // end while (1) } // 获取标准错误 if (stderr_recvlen) *stderr_recvlen = 0; if (stderr_buf) *stderr_buf = 0; if (0==rc && (stderr_fd>=0 || (stderr_buf&&stderr_buflen>0))) { while (1) { int nread = libssh2_channel_read(channel, m_buf, m_buflen); if (LIBSSH2_ERROR_EAGAIN==nread) { waitsocket(); continue; } if (nread > 0) { if (stderr_fd>=0) { write(stderr_fd, m_buf, nread); // FIX ME : 未检查错误 } int len = std::min(nread, stderr_buflen-1); // 尽量多的写入buf, 但至少留一个字节置为NUL if (stderr_buf && len>0) { memcpy(stderr_buf, m_buf, len); stderr_buf += len; stderr_buflen -= len; *stderr_buf = 0; // 以NUL结尾 if (stderr_recvlen) *stderr_recvlen += len; } } else { get_lib_error(); break; } } // end while (1) } clearup: while( channel && (rc = libssh2_channel_close(channel)) == LIBSSH2_ERROR_EAGAIN && waitsocket()>=0); if(channel && rc== 0) { ret = libssh2_channel_get_exit_status( channel ); libssh2_channel_free(channel); channel = NULL; } return ret; } LIBSSH2_CHANNEL* ssh2_t::channel_open() { clear_error(); if (0==m_connected) { /// FIX ME : do connect snprintf(m_errmsg, m_errmsg_buflen, "%s", "None connection yet"); return NULL; } LIBSSH2_CHANNEL* channel = NULL; while( (channel= libssh2_channel_open_session(m_session))==NULL && libssh2_session_last_error(m_session,NULL,NULL,0)==LIBSSH2_ERROR_EAGAIN && waitsocket()>=0 ); if( channel == NULL ) { get_sys_error(); } else { libssh2_channel_set_blocking(channel, 1); } return channel; } int ssh2_t::channel_close(LIBSSH2_CHANNEL* channel) { int rc = 0, ret=0; while(channel && (rc=libssh2_channel_close(channel))==LIBSSH2_ERROR_EAGAIN && waitsocket()>=0); if(channel && rc== 0) { ret = libssh2_channel_get_exit_status( channel ); libssh2_channel_free(channel); } return ret; } int ssh2_t::channel_exec(LIBSSH2_CHANNEL* channel, const std::string& cmdline) { int rc = 0; while ((rc=libssh2_channel_exec(channel, cmdline.c_str()))==LIBSSH2_ERROR_EAGAIN && waitsocket()>=0); if (rc) { get_lib_error(); return -1; } return libssh2_channel_get_exit_status(channel); } int ssh2_t::channel_write(LIBSSH2_CHANNEL* channel, const char* buf, size_t len) { int ret = 0, rn=0; while (len) { while ((rn=libssh2_channel_write(channel, buf, len))==LIBSSH2_ERROR_EAGAIN && waitsocket()>=0); if (rn>0) { ret += rn; buf += rn; len -= rn; } else { break; } } get_lib_error(); return ret; } int ssh2_t::channel_read(LIBSSH2_CHANNEL* channel, char* buf, size_t len) { int ret = 0, rn=0; while (len) { while ((rn=libssh2_channel_read(channel, buf, len))==LIBSSH2_ERROR_EAGAIN && waitsocket()>=0); if (rn>0) { ret += rn; buf += rn; len -= rn; } else { break; } } get_lib_error(); return ret; } LIBSSH2_SFTP* ssh2_t::sftp_init() { if (NULL==m_sftp) { while ((m_sftp=libssh2_sftp_init(m_session))==NULL && libssh2_session_last_error(m_session, NULL, NULL, 0)==LIBSSH2_ERROR_EAGAIN && waitsocket()>=0); } get_lib_error(); return m_sftp; } int ssh2_t::sftp_shutdown() { if (NULL==m_sftp) { return 0; } int rc = 0; while ((rc=libssh2_sftp_shutdown(m_sftp))==LIBSSH2_ERROR_EAGAIN && waitsocket()>=0); return rc; } int ssh2_t::sftp_close_handle(LIBSSH2_SFTP_HANDLE* sftp_handle) { if (NULL==sftp_handle) { return 0; } int rc = 0; while ((rc=libssh2_sftp_close(sftp_handle))==LIBSSH2_ERROR_EAGAIN); return rc; } LIBSSH2_SFTP_HANDLE* ssh2_t::sftp_open(const std::string& path, long flags, long mode) { if (NULL==m_sftp) { if (NULL==sftp_init()) return NULL; return NULL; } LIBSSH2_SFTP_HANDLE* sftp_handle = NULL; while ((sftp_handle=libssh2_sftp_open(m_sftp, path.c_str(), flags, mode))==NULL && libssh2_session_last_errno(m_session)==LIBSSH2_ERROR_EAGAIN && waitsocket()>=0); get_lib_error(); return sftp_handle; } int ssh2_t::sftp_close(LIBSSH2_SFTP_HANDLE* sftp_handle) { return sftp_close_handle(sftp_handle); } int ssh2_t::sftp_read(LIBSSH2_SFTP_HANDLE* sftp_handle, char* buf, size_t len) { int ret = 0; while (len) { int rn = 0; while ((rn=libssh2_sftp_read(sftp_handle, buf, len))==LIBSSH2_ERROR_EAGAIN && waitsocket()>=0); if (rn<=0) { break; } buf += rn; len -= rn; ret += rn; } get_lib_error(); return ret; } int ssh2_t::sftp_write(LIBSSH2_SFTP_HANDLE* sftp_handle, const char* buf, size_t len) { int ret = 0; while (len) { int rn = 0; while ((rn=libssh2_sftp_write(sftp_handle, buf, len))==LIBSSH2_ERROR_EAGAIN && waitsocket()>=0); if (rn<=0) { break; } buf += rn; len -= rn; ret += rn; } get_lib_error(); return ret; } LIBSSH2_SFTP_HANDLE* ssh2_t::sftp_opendir(const std::string& path) { if (NULL==m_sftp) { return NULL; } LIBSSH2_SFTP_HANDLE* sftp_handle = NULL; while ((sftp_handle=libssh2_sftp_opendir(m_sftp, path.c_str()))==NULL && libssh2_session_last_errno(m_session)==LIBSSH2_ERROR_EAGAIN && waitsocket()>=0); get_lib_error(); return sftp_handle; } int ssh2_t::sftp_closedir(LIBSSH2_SFTP_HANDLE* sftp_handle) { return sftp_close_handle(sftp_handle); } int ssh2_t::sftp_readdir(LIBSSH2_SFTP_HANDLE* sftp_handle, char* buf, size_t buflen, LIBSSH2_SFTP_ATTRIBUTES* attrs) { int rc = 0; while ((rc=libssh2_sftp_readdir(sftp_handle, buf, buflen, attrs))==LIBSSH2_ERROR_EAGAIN && waitsocket()>=0); return rc; } int ssh2_t::sftp_unlink(const std::string& path) { int rc = 0; while ((rc=libssh2_sftp_unlink(m_sftp, path.c_str()))==LIBSSH2_ERROR_EAGAIN && waitsocket()>=0); return rc; } int ssh2_t::sftp_mkdir(const std::string& path, long mode) { int rc = 0; while ((rc=libssh2_sftp_mkdir(m_sftp, path.c_str(), mode))==LIBSSH2_ERROR_EAGAIN && waitsocket()>=0); return rc; } int ssh2_t::sftp_rmdir(const std::string& path) { int rc = 0; while ((rc=libssh2_sftp_rmdir(m_sftp, path.c_str()))==LIBSSH2_ERROR_EAGAIN && waitsocket()>=0); return rc; } int ssh2_t::sftp_stat(const std::string& path, LIBSSH2_SFTP_ATTRIBUTES* attrs) { int rc = 0; while ((rc=libssh2_sftp_stat(m_sftp, path.c_str(), attrs))==LIBSSH2_ERROR_EAGAIN && waitsocket()>=0); return rc; } int ssh2_t::sftp_lstat(const std::string& path, LIBSSH2_SFTP_ATTRIBUTES* attrs) { int rc = 0; while ((rc=libssh2_sftp_lstat(m_sftp, path.c_str(), attrs))==LIBSSH2_ERROR_EAGAIN && waitsocket()>=0); return rc; } int ssh2_t::sftp_setstat(const std::string& path, LIBSSH2_SFTP_ATTRIBUTES* attrs) { int rc = 0; while ((rc=libssh2_sftp_setstat(m_sftp, path.c_str(), attrs))==LIBSSH2_ERROR_EAGAIN && waitsocket()>=0); return rc; } int ssh2_t::sftp_readlink(const std::string& path, char* buf, size_t buflen) { int rc = 0; while ((rc=libssh2_sftp_readlink(m_sftp, path.c_str(), buf, buflen))==LIBSSH2_ERROR_EAGAIN && waitsocket()>=0); return rc; } int ssh2_t::sftp_symlink(const std::string& path, const std::string& link) { int rc = 0; while ((rc=libssh2_sftp_symlink(m_sftp, path.c_str(), (char*)link.c_str()))==LIBSSH2_ERROR_EAGAIN && waitsocket()>=0); return rc; } int ssh2_t::sftp_realpath(const std::string& path, char* buf, size_t buflen) { int rc = 0; while ((rc=libssh2_sftp_readlink(m_sftp, path.c_str(), buf, buflen))==LIBSSH2_ERROR_EAGAIN && waitsocket()>=0); return rc; } void ssh2_t::init_attrs(LIBSSH2_SFTP_ATTRIBUTES* attrs, struct stat* st) { bzero(attrs, sizeof(*attrs)); attrs->filesize = st->st_size; attrs->flags |= LIBSSH2_SFTP_ATTR_SIZE; attrs->permissions = st->st_mode; attrs->flags |= LIBSSH2_SFTP_ATTR_PERMISSIONS; attrs->atime = st->st_atime; attrs->mtime = st->st_mtime; attrs->flags |= LIBSSH2_SFTP_ATTR_ACMODTIME; } int ssh2_t::sftp_copy_file(const std::string& local, const std::string& remote, char* buf, size_t buflen) { struct stat st; bzero(&st, sizeof(st)); stat(local.c_str(), &st); if (!S_ISREG(st.st_mode) && !S_ISLNK(st.st_mode)) { return -1; } LIBSSH2_SFTP_ATTRIBUTES attrs; init_attrs(&attrs, &st); int fd = ::open(local.c_str(), O_RDONLY); if (fd<0) { return -1; } LIBSSH2_SFTP_HANDLE* handle = NULL; handle = sftp_open(remote, LIBSSH2_FXF_WRITE|LIBSSH2_FXF_CREAT|LIBSSH2_FXF_TRUNC, attrs.permissions&0777); if (NULL==handle) { ::close(fd); return -1; } int ret = 0; while (1) { int rn=0, wn=0; while ((rn=::read(fd, buf, buflen))==-1 && EAGAIN==errno); if (rn>0) { wn = sftp_write(handle, buf, rn); if (wn!=rn) { get_lib_error(); ret = -1; break; } } if (rn<=0) { if (rn<0) ret=-1; break; } }; sftp_close(handle); ::close(fd); sftp_setstat(remote, &attrs); return ret; } int ssh2_t::sftp_copy_link(const std::string& local, const std::string& remote, char* buf, size_t buflen) { if (::readlink(local.c_str(), buf, buflen)<0) { return -1; } return sftp_symlink(remote, buf); } int ssh2_t::sftp_copy_dir(const std::string& local, const std::string& remote, char* buf, size_t buflen) { int ret = 0; struct stat st; bzero(&st, sizeof(st)); stat(local.c_str(), &st); if (!S_ISDIR(st.st_mode)) { return -1; } DIR* dir = ::opendir(local.c_str()); if (NULL==dir) { return -1; } LIBSSH2_SFTP_ATTRIBUTES attrs; init_attrs(&attrs, &st); sftp_mkdir(remote, attrs.permissions&0777); if (sftp_stat(remote, &attrs)) { return -1; } struct dirent entry, *pentry; while (readdir_r(dir, &entry, &pentry)==0) { if (NULL==pentry) { break; } if (strncmp(entry.d_name, ".", 1)==0 || strncmp(entry.d_name, "..", 2)==0) { continue; } std::string this_local = local + "/" + entry.d_name; std::string this_remote = remote + "/" + entry.d_name; sftp_copy(this_local, this_remote, buf, buflen); } ::closedir(dir); dir = NULL; return ret; } int ssh2_t::sftp_copy(const std::string& local, const std::string& remote, char* buf/*=NULL*/, size_t buflen/*=0*/) { std::string local_fix = fixpath(local); std::string remote_fix = fixpath(remote); struct stat st; bzero(&st, sizeof(st)); if (::stat(local_fix.c_str(), &st)) { get_sys_error(); return -1; } LIBSSH2_SFTP_ATTRIBUTES attrs; bzero(&attrs, sizeof(attrs)); if (sftp_lstat(remote_fix, &attrs)==0 && attrs.flags&LIBSSH2_SFTP_ATTR_PERMISSIONS && LIBSSH2_SFTP_S_ISDIR(attrs.permissions)) { remote_fix = remote_fix + "/" + basename(local_fix); } int ret = 0; int alloc_buf = 0; if (NULL==buf) { buflen = 1024*2; buf = new char[buflen]; alloc_buf = 1; } if (S_ISREG(st.st_mode)) { ret = sftp_copy_file(local_fix, remote_fix, buf, buflen); } else if (S_ISLNK(st.st_mode)) { ret = sftp_copy_link(local_fix, remote_fix, buf, buflen); } else if (S_ISDIR(st.st_mode)) { ret = sftp_copy_dir(local_fix, remote_fix, buf, buflen); } else { ret = -1; } if (alloc_buf) { delete[] buf; } return ret; } int ssh2_t::remote_chown(const std::string& remote, const std::string& user, const std::string& group) { std::string cmdline = std::string("chown ") + user + ":" + group + " " + remote; int ret = exec(cmdline, NULL, 0, NULL, m_errmsg, m_errmsg_buflen); if (ret!=0) { m_errno = SSH2_ERRNO_REMOTE_CHOWN_FAILID; } return ret; } int ssh2_t::sendfile(const std::string& local, const std::string& remote, int keep_owner/*=0*/) { clear_error(); off_t total_send = 0; struct stat st; if (stat(local.c_str(), &st)) { get_sys_error(); return -2; } int ret = 0; int fd = 0; // local file fd LIBSSH2_SFTP *sftp_session = NULL; LIBSSH2_SFTP_HANDLE *sftp_handle = NULL; while ((sftp_session = libssh2_sftp_init(m_session))==NULL && libssh2_session_last_errno(m_session)==LIBSSH2_ERROR_EAGAIN /*&& waitsocket()>=0*/); if (NULL==sftp_session) { get_lib_error(); return -3; } while ((sftp_handle = libssh2_sftp_open(sftp_session, remote.c_str(), LIBSSH2_FXF_WRITE|LIBSSH2_FXF_CREAT|LIBSSH2_FXF_TRUNC, st.st_mode))==NULL && libssh2_session_last_errno(m_session) == LIBSSH2_ERROR_EAGAIN) ; if (NULL==sftp_handle) { ret = -1; get_lib_error(); goto clearup; } fd = open(local.c_str(), O_RDONLY); if (fd < 0) { ret = -1; get_sys_error(); goto clearup; } while (1) { int nread = ::read(fd, m_buf, m_buflen); if (nread <= 0) { if (nread<0) { // read出错 get_sys_error(); } break; } char *write_ptr = m_buf; while (nread>0) { int nwrite = libssh2_sftp_write(sftp_handle, write_ptr, nread); if (LIBSSH2_ERROR_EAGAIN == nwrite) { continue; } if (nwrite < 0) { break; } else { total_send += nwrite; nread -= nwrite; write_ptr += nwrite; } } // 仍有未写入的序列, 则出错推出循环 if (nread) { get_lib_error(); break; } } if (total_send<st.st_size) { ret = -1; } if (keep_owner) { remote_chown(remote, uid_to_name(st.st_uid), gid_to_name(st.st_gid)); } clearup: if (fd>0) ::close(fd); while (sftp_handle && libssh2_sftp_close(sftp_handle) == LIBSSH2_ERROR_EAGAIN); while (sftp_session && libssh2_sftp_shutdown(sftp_session) == LIBSSH2_ERROR_EAGAIN); sftp_handle = NULL; sftp_session = NULL; return ret; } int ssh2_t::recvfile(const std::string& local, const std::string& remote) { clear_error(); off_t total_recv = 0; LIBSSH2_SFTP_ATTRIBUTES attrs; struct stat st; LIBSSH2_SFTP *sftp_session = NULL; LIBSSH2_SFTP_HANDLE *sftp_handle = NULL; int rc = 0; int fd = 0; int ret = 0; while ((sftp_session = libssh2_sftp_init(m_session))==NULL && libssh2_session_last_errno(m_session)==LIBSSH2_ERROR_EAGAIN /*&& waitsocket()>=0*/); if (NULL==sftp_session) { get_lib_error(); return -1; } while ((sftp_handle = libssh2_sftp_open(sftp_session, remote.c_str(), LIBSSH2_FXF_READ, 0))==NULL && libssh2_session_last_errno(m_session) == LIBSSH2_ERROR_EAGAIN) ; if (NULL==sftp_handle) { ret = -1; get_lib_error(); goto clearup; } while ((rc=libssh2_sftp_stat(sftp_session, remote.c_str(), &attrs)==LIBSSH2_ERROR_EAGAIN)); if (rc) { ret = -1; get_lib_error(); goto clearup; } else { // FIX ME : 未检查是否为文件 st.st_size = attrs.flags & LIBSSH2_SFTP_ATTR_SIZE ? attrs.filesize : 0; st.st_mode = attrs.flags & LIBSSH2_SFTP_ATTR_PERMISSIONS ? attrs.permissions : 0644; st.st_atime = attrs.flags & LIBSSH2_SFTP_ATTR_ACMODTIME ? attrs.atime : time(NULL); st.st_mtime = attrs.flags & LIBSSH2_SFTP_ATTR_ACMODTIME ? attrs.mtime : time(NULL); fd = open(local.c_str(), O_RDWR|O_CREAT|O_TRUNC, st.st_mode); } if (fd < 0) { ret = -1; get_sys_error(); goto clearup; } while (1) { int nread = libssh2_sftp_read(sftp_handle, m_buf, m_buflen); if (LIBSSH2_ERROR_EAGAIN == nread) { waitsocket(); continue; } if (nread <= 0) { if (nread < 0) { // libssh2_channel_read错误 ret = -1; get_lib_error(); } break; } char *write_ptr = m_buf; while (nread>0) { int nwrite = ::write(fd, write_ptr, nread); if (nwrite < 0) { break; } else { total_recv += nwrite; nread -= nwrite; write_ptr += nwrite; } } if (nread) { ret = -1; get_sys_error(); break; } } if (attrs.flags & LIBSSH2_SFTP_ATTR_SIZE && total_recv<(off_t)attrs.filesize) { ret = -1; } clearup: if (fd>0) ::close(fd); while (sftp_handle && libssh2_sftp_close(sftp_handle) == LIBSSH2_ERROR_EAGAIN); while (sftp_session && libssh2_sftp_shutdown(sftp_session) == LIBSSH2_ERROR_EAGAIN); sftp_handle = NULL; sftp_session = NULL; return ret; } std::string ssh2_t::uid_to_name(uid_t uid) { std::string name; struct passwd pwd, *pret=NULL; if (getpwuid_r(uid, &pwd, m_buf, m_buflen, &pret)==0 && pret==&pwd && pwd.pw_name) { name = pwd.pw_name; } return name; } std::string ssh2_t::gid_to_name(gid_t gid) { std::string name; struct group grp, *pret = NULL; if (getgrgid_r(gid, &grp, m_buf, m_buflen, &pret)==0 && pret==&grp && grp.gr_name) { name = grp.gr_name; } return name; } std::string ssh2_t::basename(const std::string& path) { std::string p = fixpath(path); std::string::size_type pos = p.rfind('/'); return p.substr(pos+1); } std::string ssh2_t::dirname(const std::string& path) { std::string p = fixpath(path); std::string::size_type pos = p.rfind('/'); return p.substr(0, pos); } std::string ssh2_t::fixpath(const std::string& path) { std::string p = path; std::string::size_type pos_pre = 0, pos=0; while ((pos=p.find("//", pos_pre))!=std::string::npos) { p.replace(pos, 2, "/"); pos_pre = pos; } pos = p.rfind("/"); if (pos==p.size()-1) { p = p.substr(0, pos); } return p; }
6.6. 封装 一个对象的变量或者方法如果对调用方是不可见的话,一般就被定义为“封装”。封装有时候也被叫做信息隐藏,同时也是面向对象编程最关键的一个方面。 Go语言只有一种控制可见性的手段:大写首字母的标识符会从定义它们的包中被导出,小写字母的则不会。这种限制包内成员的方式同样适用于struct或者一个类型的方法。因而如果我们想要封装一个对象,我们必须将其定义为一个struct。 这也就是前面的小
prototype对象 构造函数的缺点 prototype属性的作用 原型链 constructor属性 Object.getPrototypeOf方法 Object.create方法 isPrototypeOf方法 prototype对象 构造函数的缺点 JavaScript通过构造函数生成新对象,因此构造函数可以视为对象的模板。实例对象的属性和方法,可以定义在构造函数内部。 function
主要内容:1、public,2、private,3、protected,4、internal,5、protected internalC# 是一门面向对象编程语言,面向对象编程语言有三大特性,分别是封装、 继承和 多态。所谓封装就是将一个或多个项目(函数)集合在一个单元中,这个单元称之为类,我们可以根据需要通过访问权限修饰符来设定类中成员的范围和可见性。C# 中的访问权限修饰符有以下几种: public:公共的,所有对象都可以访问,但是需要引用命名空间; private:私有的,类的内部才可以访
主要内容:Python 类如何进行封装?不光是 Python,大多数面向对象编程语言(诸如 C++、 Java 等)都具备 3 个典型特征,即封装、继承和多态。其中,本节重点讲解 Python 类的封装特性,继承和多态会在后续章节给大家做详细讲解。 简单的理解封装(Encapsulation),即在设计类时,刻意地将一些属性和方法隐藏在类的内部,这样在使用此类时,将无法直接以“类对象.属性名”(或者“类对象.方法名(参数)”)的形式调用
我实现了一个名为mobile eCall的类。我从这个类中创建了几个对象,并用来自XML的值填充该对象的String变量,该XML具有针对特定人员的多个mobile eCall。我需要对这个人发出的所有呼叫进行分组和计数(例如,国内呼叫:11分钟;国际呼叫:15分钟;数据:20 MB) 因此,我在类中实现了几个公共方法来检查调用的类型,以返回true或false。在主类中,我调用了这些方法来检查它
Encapsulation被定义为“将一个或多个项目封装在物理或逻辑包中的过程”。 在面向对象的编程方法中,封装阻止了对实现细节的访问。 抽象和封装是面向对象编程中的相关特征。 抽象允许使相关信息可见,封装使程序员能够implement the desired level of abstraction 。 使用access specifiers实现封装。 access specifier定义类成员
所有D程序都由以下两个基本要素组成 - Program statements (code) - 这是执行操作的程序的一部分,它们被称为函数。 Program data - 受程序功能影响的程序信息。 封装是一种面向对象的编程概念,它将数据和功能绑定在一起,将数据一起操作,并保护其免受外部干扰和误用。 数据封装导致了重要的OOP data hiding概念。 Data encapsulation是捆
Encapsulation是四个基本OOP概念之一。 其他三个是继承,多态和抽象。 Java中的封装是将数据(变量)和作用于数据(方法)的代码作为一个单元包装在一起的机制。 在封装中,类的变量将从其他类隐藏,并且只能通过其当前类的方法访问。 因此,它也被称为data hiding 。 在Java中实现封装 - 将类的变量声明为private。 提供公共setter和getter方法来修改和查看变量