diff --git a/ChangeLog b/ChangeLog index 61f701e..3e61191 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,9 @@ +2007-07-15 James Housley + * Add libssh2_sftp_readdir_ex(), this function if passed the + extra parameters will be used to store the full directory + entry as provided by the server. Updated LIBSSH2_APINO to + 200706151200 for this change. + 2007-07-12 James Housley * libssh2_publickey_shutdown(), libssh2_session_free() changed diff --git a/NEWS b/NEWS index 23ec0f7..aa50a7c 100644 --- a/NEWS +++ b/NEWS @@ -1,5 +1,8 @@ Version ------------ + Added libssh2_sftp_readdir_ex() and updated LIBSSH2_APINO to + 200706151200 (James Housley) + Converted all of the libssh2 code to be able to work in non-blocking mode. This included some public API changes, listed below (James Housley) Changed function return values: diff --git a/docs/libssh2_sftp_readdir.3 b/docs/libssh2_sftp_readdir.3 index 9aa0a52..aace61d 100644 --- a/docs/libssh2_sftp_readdir.3 +++ b/docs/libssh2_sftp_readdir.3 @@ -1,12 +1,15 @@ -.\" $Id: libssh2_sftp_readdir.3,v 1.8 2007/06/13 16:41:33 jehousley Exp $ +.\" $Id: libssh2_sftp_readdir.3,v 1.9 2007/06/15 17:22:49 jehousley Exp $ .\" -.TH libssh2_sftp_readdir 3 "1 Jun 2007" "libssh2 0.15" "libssh2 manual" +.TH libssh2_sftp_readdir_ex 3 "1 Jun 2007" "libssh2 0.15" "libssh2 manual" .SH NAME -libssh2_sftp_readdir - read directory data from an SFTP handle +libssh2_sftp_readdir_ex - read directory data from an SFTP handle .SH SYNOPSIS #include #include +int +libssh2_sftp_readdir_ex(LIBSSH2_SFTP_HANDLE *handle, char *buffer, size_t buffer_maxlen, char *longentry, size_t longentry_maxlen, LIBSSH2_SFTP_ATTRIBUTES *attrs); + int libssh2_sftp_readdir(LIBSSH2_SFTP_HANDLE *handle, char *buffer, size_t buffer_maxlen, LIBSSH2_SFTP_ATTRIBUTES *attrs); @@ -21,6 +24,13 @@ libssh2_sftp_readdir(LIBSSH2_SFTP_HANDLE *handle, char *buffer, size_t buffer_ma filename is longer than the space provided by buffer_maxlen it will be truncated to fit. +\fIlongentry\fP - is a pointer to a pre-allocated buffer of at least +\fIlongentry_maxlen\fP bytes to read data into. + +\fIlongentry_maxlen\fP - is the length of longentry in bytes. If the length +of the full directory entry is longer than the space provided by +longentry_maxlen it will be truncated to fit. + \fIattrs\fP - is a pointer to LIBSSH2_SFTP_ATTRIBUTES storage to populate statbuf style data into. diff --git a/example/simple/sftpdir.c b/example/simple/sftpdir.c index b4b4a39..068a666 100644 --- a/example/simple/sftpdir.c +++ b/example/simple/sftpdir.c @@ -1,5 +1,5 @@ /* - * $Id: sftpdir.c,v 1.5 2007/06/06 12:34:09 jehousley Exp $ + * $Id: sftpdir.c,v 1.6 2007/06/15 17:22:49 jehousley Exp $ * * Sample doing an SFTP directory listing. * @@ -37,177 +37,182 @@ int main(int argc, char *argv[]) { - unsigned long hostaddr; - int sock, i, auth_pw = 1; - struct sockaddr_in sin; - const char *fingerprint; - LIBSSH2_SESSION *session; - char *username=(char *)"username"; - char *password=(char *)"password"; - char *sftppath=(char *)"/tmp/secretdir"; - int rc; - LIBSSH2_SFTP *sftp_session; - LIBSSH2_SFTP_HANDLE *sftp_handle; + unsigned long hostaddr; + int sock, i, auth_pw = 1; + struct sockaddr_in sin; + const char *fingerprint; + LIBSSH2_SESSION *session; + char *username=(char *)"username"; + char *password=(char *)"password"; + char *sftppath=(char *)"/tmp/secretdir"; + int rc; + LIBSSH2_SFTP *sftp_session; + LIBSSH2_SFTP_HANDLE *sftp_handle; #ifdef WIN32 - WSADATA wsadata; + WSADATA wsadata; - WSAStartup(WINSOCK_VERSION, &wsadata); + WSAStartup(WINSOCK_VERSION, &wsadata); #endif - if (argc > 1) { - hostaddr = inet_addr(argv[1]); - } else { - hostaddr = htonl(0x7F000001); - } + if (argc > 1) { + hostaddr = inet_addr(argv[1]); + } else { + hostaddr = htonl(0x7F000001); + } - if(argc > 2) { - username = argv[2]; - } - if(argc > 3) { - password = argv[3]; - } - if(argc > 4) { - sftppath = argv[4]; - } - /* - * The application code is responsible for creating the socket - * and establishing the connection - */ - sock = socket(AF_INET, SOCK_STREAM, 0); + if(argc > 2) { + username = argv[2]; + } + if(argc > 3) { + password = argv[3]; + } + if(argc > 4) { + sftppath = argv[4]; + } + /* + * The application code is responsible for creating the socket + * and establishing the connection + */ + sock = socket(AF_INET, SOCK_STREAM, 0); - sin.sin_family = AF_INET; - sin.sin_port = htons(22); - sin.sin_addr.s_addr = hostaddr; - if (connect(sock, (struct sockaddr*)(&sin), - sizeof(struct sockaddr_in)) != 0) { - fprintf(stderr, "failed to connect!\n"); - return -1; - } + sin.sin_family = AF_INET; + sin.sin_port = htons(22); + sin.sin_addr.s_addr = hostaddr; + if (connect(sock, (struct sockaddr*)(&sin), + sizeof(struct sockaddr_in)) != 0) { + fprintf(stderr, "failed to connect!\n"); + return -1; + } - /* Create a session instance - */ - session = libssh2_session_init(); - if(!session) - return -1; + /* Create a session instance + */ + session = libssh2_session_init(); + if(!session) + return -1; - /* ... start it up. This will trade welcome banners, exchange keys, - * and setup crypto, compression, and MAC layers - */ - rc = libssh2_session_startup(session, sock); - if(rc) { - fprintf(stderr, "Failure establishing SSH session: %d\n", rc); - return -1; - } + /* ... start it up. This will trade welcome banners, exchange keys, + * and setup crypto, compression, and MAC layers + */ + rc = libssh2_session_startup(session, sock); + if(rc) { + fprintf(stderr, "Failure establishing SSH session: %d\n", rc); + return -1; + } - /* At this point we havn't yet authenticated. The first thing to do - * is check the hostkey's fingerprint against our known hosts Your app - * may have it hard coded, may go to a file, may present it to the - * user, that's your call - */ - fingerprint = libssh2_hostkey_hash(session, LIBSSH2_HOSTKEY_HASH_MD5); - printf("Fingerprint: "); - for(i = 0; i < 16; i++) { - printf("%02X ", (unsigned char)fingerprint[i]); - } - printf("\n"); + /* At this point we havn't yet authenticated. The first thing to do + * is check the hostkey's fingerprint against our known hosts Your app + * may have it hard coded, may go to a file, may present it to the + * user, that's your call + */ + fingerprint = libssh2_hostkey_hash(session, LIBSSH2_HOSTKEY_HASH_MD5); + printf("Fingerprint: "); + for(i = 0; i < 16; i++) { + printf("%02X ", (unsigned char)fingerprint[i]); + } + printf("\n"); - if (auth_pw) { - /* We could authenticate via password */ - if (libssh2_userauth_password(session, username, password)) { - printf("Authentication by password failed.\n"); - goto shutdown; - } - } else { - /* Or by public key */ - if (libssh2_userauth_publickey_fromfile(session, username, - "/home/username/.ssh/id_rsa.pub", - "/home/username/.ssh/id_rsa", - password)) { - printf("\tAuthentication by public key failed\n"); - goto shutdown; - } - } + if (auth_pw) { + /* We could authenticate via password */ + if ((i = libssh2_userauth_password(session, username, password))) { + printf("Authentication by password failed.\n"); + goto shutdown; + } + } else { + /* Or by public key */ + if (libssh2_userauth_publickey_fromfile(session, username, + "/home/username/.ssh/id_rsa.pub", + "/home/username/.ssh/id_rsa", + password)) { + printf("\tAuthentication by public key failed\n"); + goto shutdown; + } + } - fprintf(stderr, "libssh2_sftp_init()!\n"); - sftp_session = libssh2_sftp_init(session); + fprintf(stderr, "libssh2_sftp_init()!\n"); + sftp_session = libssh2_sftp_init(session); - if (!sftp_session) { - fprintf(stderr, "Unable to init SFTP session\n"); - goto shutdown; - } + if (!sftp_session) { + fprintf(stderr, "Unable to init SFTP session\n"); + goto shutdown; + } - /* Since we have not set non-blocking, tell libssh2 we are blocking */ - libssh2_session_set_blocking(session, 1); + /* Since we have not set non-blocking, tell libssh2 we are blocking */ + libssh2_session_set_blocking(session, 1); - fprintf(stderr, "libssh2_sftp_opendir()!\n"); - /* Request a dir listing via SFTP */ - sftp_handle = libssh2_sftp_opendir(sftp_session, sftppath); + fprintf(stderr, "libssh2_sftp_opendir()!\n"); + /* Request a dir listing via SFTP */ + sftp_handle = libssh2_sftp_opendir(sftp_session, sftppath); - if (!sftp_handle) { - fprintf(stderr, "Unable to open dir with SFTP\n"); - goto shutdown; - } - fprintf(stderr, "libssh2_sftp_opendir() is done, now receive listing!\n"); - do { - char mem[512]; - LIBSSH2_SFTP_ATTRIBUTES attrs; + if (!sftp_handle) { + fprintf(stderr, "Unable to open dir with SFTP\n"); + goto shutdown; + } + fprintf(stderr, "libssh2_sftp_opendir() is done, now receive listing!\n"); + do { + char mem[512]; + char longentry[512]; + LIBSSH2_SFTP_ATTRIBUTES attrs; - /* loop until we fail */ - rc = libssh2_sftp_readdir(sftp_handle, mem, sizeof(mem), - &attrs); - if(rc > 0) { - /* rc is the length of the file name in the mem - buffer */ + /* loop until we fail */ + rc = libssh2_sftp_readdir_ex(sftp_handle, mem, sizeof(mem), + longentry, sizeof(longentry), &attrs); + if(rc > 0) { + /* rc is the length of the file name in the mem + buffer */ - if(attrs.flags & LIBSSH2_SFTP_ATTR_PERMISSIONS) { - /* this should check what permissions it - is and print the output accordingly */ - printf("--fix----- "); - } - else { - printf("---------- "); - } + if (longentry[0] != '\0') { + printf("%s\n", longentry); + } else { + if(attrs.flags & LIBSSH2_SFTP_ATTR_PERMISSIONS) { + /* this should check what permissions it + is and print the output accordingly */ + printf("--fix----- "); + } + else { + printf("---------- "); + } - if(attrs.flags & LIBSSH2_SFTP_ATTR_UIDGID) { - printf("%4ld %4ld ", attrs.uid, attrs.gid); - } - else { - printf(" - - "); - } + if(attrs.flags & LIBSSH2_SFTP_ATTR_UIDGID) { + printf("%4ld %4ld ", attrs.uid, attrs.gid); + } + else { + printf(" - - "); + } - if(attrs.flags & LIBSSH2_SFTP_ATTR_SIZE) { - /* attrs.filesize is an uint64_t according to - the docs but there is no really good and - portable 64bit type for C before C99, and - correspondingly there was no good printf() - option for it... */ + if(attrs.flags & LIBSSH2_SFTP_ATTR_SIZE) { + /* attrs.filesize is an uint64_t according to + the docs but there is no really good and + portable 64bit type for C before C99, and + correspondingly there was no good printf() + option for it... */ - printf("%8lld ", attrs.filesize); - } + printf("%8lld ", attrs.filesize); + } - printf("%s\n", mem); - } - else - break; + printf("%s\n", mem); + } + } + else + break; - } while (1); + } while (1); - libssh2_sftp_closedir(sftp_handle); - libssh2_sftp_shutdown(sftp_session); + libssh2_sftp_closedir(sftp_handle); + libssh2_sftp_shutdown(sftp_session); shutdown: - libssh2_session_disconnect(session, "Normal Shutdown, Thank you for playing"); - libssh2_session_free(session); + libssh2_session_disconnect(session, "Normal Shutdown, Thank you for playing"); + libssh2_session_free(session); #ifdef WIN32 - Sleep(1000); - closesocket(sock); + Sleep(1000); + closesocket(sock); #else - sleep(1); - close(sock); + sleep(1); + close(sock); #endif printf("all done\n"); - return 0; + return 0; } diff --git a/include/libssh2.h b/include/libssh2.h index df27c4a..7f9bfb6 100644 --- a/include/libssh2.h +++ b/include/libssh2.h @@ -77,7 +77,7 @@ typedef long long libssh2_int64_t; #endif #define LIBSSH2_VERSION "0.15-CVS" -#define LIBSSH2_APINO 200706012030 +#define LIBSSH2_APINO 200706151200 /* Part of every banner, user specified or not */ #define LIBSSH2_SSH_BANNER "SSH-2.0-libssh2_" LIBSSH2_VERSION diff --git a/include/libssh2_sftp.h b/include/libssh2_sftp.h index 537e479..596eb0b 100644 --- a/include/libssh2_sftp.h +++ b/include/libssh2_sftp.h @@ -193,8 +193,11 @@ LIBSSH2_API LIBSSH2_SFTP_HANDLE *libssh2_sftp_open_ex(LIBSSH2_SFTP *sftp, const LIBSSH2_API ssize_t libssh2_sftp_read(LIBSSH2_SFTP_HANDLE *handle, char *buffer, size_t buffer_maxlen); -LIBSSH2_API int libssh2_sftp_readdir(LIBSSH2_SFTP_HANDLE *handle, char *buffer, - size_t buffer_maxlen, LIBSSH2_SFTP_ATTRIBUTES *attrs); +LIBSSH2_API int libssh2_sftp_readdir_ex(LIBSSH2_SFTP_HANDLE *handle, char *buffer, size_t buffer_maxlen, + char *longentry, size_t longentry_maxlen, + LIBSSH2_SFTP_ATTRIBUTES *attrs); +#define libssh2_sftp_readdir(handle, buffer, buffer_maxlen, attrs) \ + libssh2_sftp_readdir_ex((handle), (buffer), (buffer_maxlen), NULL, 0, (attrs)) LIBSSH2_API ssize_t libssh2_sftp_write(LIBSSH2_SFTP_HANDLE *handle, const char *buffer, size_t count); diff --git a/src/sftp.c b/src/sftp.c index 4261576..32707ea 100644 --- a/src/sftp.c +++ b/src/sftp.c @@ -995,14 +995,15 @@ LIBSSH2_API ssize_t libssh2_sftp_read(LIBSSH2_SFTP_HANDLE *handle, char *buffer, /* {{{ libssh2_sftp_readdir * Read from an SFTP directory handle */ -LIBSSH2_API int libssh2_sftp_readdir(LIBSSH2_SFTP_HANDLE *handle, char *buffer, size_t buffer_maxlen, - LIBSSH2_SFTP_ATTRIBUTES *attrs) +LIBSSH2_API int libssh2_sftp_readdir_ex(LIBSSH2_SFTP_HANDLE *handle, char *buffer, size_t buffer_maxlen, + char *longentry, size_t longentry_maxlen, + LIBSSH2_SFTP_ATTRIBUTES *attrs) { LIBSSH2_SFTP *sftp = handle->sftp; LIBSSH2_CHANNEL *channel = sftp->channel; LIBSSH2_SESSION *session = channel->session; LIBSSH2_SFTP_ATTRIBUTES attrs_dummy; - unsigned long data_len, request_id, filename_len, num_names; + unsigned long data_len, request_id, filename_len, longentry_len, num_names; /* 13 = packet_len(4) + packet_type(1) + request_id(4) + handle_len(4) */ ssize_t packet_len = handle->handle_len + 13; unsigned char *packet, *s, *data; @@ -1031,8 +1032,25 @@ LIBSSH2_API int libssh2_sftp_readdir(LIBSSH2_SFTP_HANDLE *handle, char *buffer, buffer[filename_len] = '\0'; } - /* Skip longname */ - s += 4 + libssh2_ntohu32(s); + if ((longentry == NULL) || (longentry_maxlen == 0)) { + /* Skip longname */ + s += 4 + libssh2_ntohu32(s); + } else { + unsigned long real_longentry_len = libssh2_ntohu32(s); + + longentry_len = real_longentry_len; + s += 4; + if (longentry_len > longentry_maxlen) { + longentry_len = longentry_maxlen; + } + memcpy(longentry, s, longentry_len); + s += real_longentry_len; + + /* The longentry is not null terminated, make it so if possible */ + if (longentry_len < longentry_maxlen) { + longentry[longentry_len] = '\0'; + } + } if (attrs) { memset(attrs, 0, sizeof(LIBSSH2_SFTP_ATTRIBUTES)); @@ -1044,7 +1062,7 @@ LIBSSH2_API int libssh2_sftp_readdir(LIBSSH2_SFTP_HANDLE *handle, char *buffer, LIBSSH2_FREE(session, handle->u.dir.names_packet); } - _libssh2_debug(session, LIBSSH2_DBG_SFTP, "libssh2_sftp_readdir() return %d", filename_len); + _libssh2_debug(session, LIBSSH2_DBG_SFTP, "libssh2_sftp_readdir_ex() return %d", filename_len); return filename_len; } @@ -1159,7 +1177,7 @@ LIBSSH2_API int libssh2_sftp_readdir(LIBSSH2_SFTP_HANDLE *handle, char *buffer, sftp->readdir_state = libssh2_NB_state_idle; /* Be lazy, just use the name popping mechanism from the start of the function */ - return libssh2_sftp_readdir(handle, buffer, buffer_maxlen, attrs); + return libssh2_sftp_readdir_ex(handle, buffer, buffer_maxlen, longentry, longentry_maxlen, attrs); } /* }}} */