1
0
mirror of https://github.com/libssh2/libssh2.git synced 2025-08-08 19:02:07 +03:00

Make _libssh2_sftp_mkdir_ex() fully non-blocking safe. This makes

libssh2_sftp_mkdirnb_ex() non-blocking safe and libssh2_sftp_mkdir_ex()
blocking safe
This commit is contained in:
James Housley
2007-04-22 19:51:24 +00:00
parent 510df9bf52
commit a66885c51c
2 changed files with 138 additions and 41 deletions

View File

@@ -228,6 +228,8 @@ LIBSSH2_API int libssh2_sftp_unlink_ex(LIBSSH2_SFTP *sftp, const char *filename,
LIBSSH2_API int libssh2_sftp_mkdir_ex(LIBSSH2_SFTP *sftp, const char *path, unsigned int path_len, long mode); LIBSSH2_API int libssh2_sftp_mkdir_ex(LIBSSH2_SFTP *sftp, const char *path, unsigned int path_len, long mode);
#define libssh2_sftp_mkdir(sftp, path, mode) libssh2_sftp_mkdir_ex((sftp), (path), strlen(path), (mode)) #define libssh2_sftp_mkdir(sftp, path, mode) libssh2_sftp_mkdir_ex((sftp), (path), strlen(path), (mode))
LIBSSH2_API int libssh2_sftp_mkdirnb_ex(LIBSSH2_SFTP *sftp, const char *path, unsigned int path_len, long mode);
#define libssh2_sftp_mkdirnb(sftp, path, mode) libssh2_sftp_mkdirnb_ex((sftp), (path), strlen(path), (mode))
LIBSSH2_API int libssh2_sftp_rmdir_ex(LIBSSH2_SFTP *sftp, const char *path, unsigned int path_len); LIBSSH2_API int libssh2_sftp_rmdir_ex(LIBSSH2_SFTP *sftp, const char *path, unsigned int path_len);
#define libssh2_sftp_rmdir(sftp, path) libssh2_sftp_rmdir_ex((sftp), (path), strlen(path)) #define libssh2_sftp_rmdir(sftp, path) libssh2_sftp_rmdir_ex((sftp), (path), strlen(path))

View File

@@ -93,6 +93,12 @@ typedef enum {
sftp_write_packet_sent sftp_write_packet_sent
} libssh2_sftp_write_state; } libssh2_sftp_write_state;
typedef enum {
sftp_mkdir_idle = 0,
sftp_mkdir_packet_created,
sftp_mkdir_packet_sent
} libssh2_sftp_mkdir_state;
struct _LIBSSH2_SFTP { struct _LIBSSH2_SFTP {
LIBSSH2_CHANNEL *channel; LIBSSH2_CHANNEL *channel;
@@ -128,6 +134,11 @@ struct _LIBSSH2_SFTP {
unsigned char *write_packet; unsigned char *write_packet;
unsigned long write_request_id; unsigned long write_request_id;
/* State variables used in _libssh2_sftp_mkdir() */
libssh2_sftp_mkdir_state mkdir_state;
unsigned char *mkdir_packet;
unsigned long mkdir_request_id;
}; };
#define LIBSSH2_SFTP_HANDLE_FILE 0 #define LIBSSH2_SFTP_HANDLE_FILE 0
@@ -1355,6 +1366,12 @@ LIBSSH2_API ssize_t libssh2_sftp_write(LIBSSH2_SFTP_HANDLE *handle,
/* restore state */ /* restore state */
libssh2_channel_set_blocking(ch, bl); libssh2_channel_set_blocking(ch, bl);
if(rc < 0) {
/* precent accidental returning of other return codes since
this API does not support/provide those */
return -1;
}
return rc; return rc;
} }
/* }}} */ /* }}} */
@@ -1692,67 +1709,145 @@ LIBSSH2_API int libssh2_sftp_rename_ex(LIBSSH2_SFTP *sftp, const char *source_f
} }
/* }}} */ /* }}} */
/* {{{ libssh2_sftp_mkdir_ex /* {{{ _libssh2_sftp_mkdir_ex
* Create a directory * Create an SFTP directory using blocking/non-blocking depending on state
*/ */
/* libssh2_sftp_mkdir_ex - NB-UNSAFE?? */ /* _libssh2_sftp_mkdir_ex - NB-SAFE */
LIBSSH2_API int libssh2_sftp_mkdir_ex(LIBSSH2_SFTP *sftp, const char *path, unsigned int path_len, long mode) static int _libssh2_sftp_mkdir_ex(LIBSSH2_SFTP *sftp, const char *path, unsigned int path_len, long mode)
{ {
LIBSSH2_CHANNEL *channel = sftp->channel; LIBSSH2_CHANNEL *channel = sftp->channel;
LIBSSH2_SESSION *session = channel->session; LIBSSH2_SESSION *session = channel->session;
LIBSSH2_SFTP_ATTRIBUTES attrs = { LIBSSH2_SFTP_ATTRIBUTES attrs = {
LIBSSH2_SFTP_ATTR_PERMISSIONS, 0, 0, 0, 0, 0, 0 LIBSSH2_SFTP_ATTR_PERMISSIONS, 0, 0, 0, 0, 0, 0
}; };
unsigned long data_len, retcode, request_id; unsigned long data_len, retcode, request_id;
ssize_t packet_len = path_len + 13 + libssh2_sftp_attrsize(&attrs); ssize_t packet_len = path_len + 13 + libssh2_sftp_attrsize(&attrs);
/* packet_len(4) + packet_type(1) + request_id(4) + path_len(4) */ /* packet_len(4) + packet_type(1) + request_id(4) + path_len(4) */
unsigned char *packet, *s, *data; unsigned char *packet, *s, *data;
int rc; int rc;
if (sftp->mkdir_state == sftp_mkdir_idle) {
_libssh2_debug(session, LIBSSH2_DBG_SFTP, "Creating directory %s with mode 0%lo", path, mode); _libssh2_debug(session, LIBSSH2_DBG_SFTP, "Creating directory %s with mode 0%lo", path, mode);
s = packet = LIBSSH2_ALLOC(session, packet_len); s = packet = LIBSSH2_ALLOC(session, packet_len);
if (!packet) { if (!packet) {
libssh2_error(session, LIBSSH2_ERROR_ALLOC, "Unable to allocate memory for FXP_MKDIR packet", 0); libssh2_error(session, LIBSSH2_ERROR_ALLOC, "Unable to allocate memory for FXP_MKDIR packet", 0);
return -1; return -1;
} }
/* Filetype in SFTP 3 and earlier */ /* Filetype in SFTP 3 and earlier */
attrs.permissions = mode | LIBSSH2_SFTP_ATTR_PFILETYPE_DIR; attrs.permissions = mode | LIBSSH2_SFTP_ATTR_PFILETYPE_DIR;
libssh2_htonu32(s, packet_len - 4); s += 4; libssh2_htonu32(s, packet_len - 4); s += 4;
*(s++) = SSH_FXP_MKDIR; *(s++) = SSH_FXP_MKDIR;
request_id = sftp->request_id++; request_id = sftp->request_id++;
libssh2_htonu32(s, request_id); s += 4; libssh2_htonu32(s, request_id); s += 4;
libssh2_htonu32(s, path_len); s += 4; libssh2_htonu32(s, path_len); s += 4;
memcpy(s, path, path_len); s += path_len; memcpy(s, path, path_len); s += path_len;
s += libssh2_sftp_attr2bin(s, &attrs); s += libssh2_sftp_attr2bin(s, &attrs);
if (packet_len != libssh2_channel_write(channel, (char *)packet, sftp->mkdir_state = sftp_mkdir_packet_created;
packet_len)) { } else {
libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND, "Unable to send FXP_MKDIR command", 0); packet = sftp->mkdir_packet;
request_id = sftp->mkdir_request_id;
}
if (sftp->mkdir_state != sftp_mkdir_packet_sent) {
if (libssh2_channel_get_blocking(channel)) {
if (packet_len != libssh2_channel_write(channel, (char *)packet, packet_len)) {
libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND, "Unable to send FXP_READ command", 0);
LIBSSH2_FREE(session, packet); LIBSSH2_FREE(session, packet);
sftp->mkdir_state = sftp_mkdir_idle;
return -1; return -1;
}
} else {
if ((rc = libssh2_channel_writenb(channel, (char *)packet, packet_len)) == PACKET_EAGAIN) {
sftp->mkdir_packet = packet;
sftp->mkdir_request_id = request_id;
return PACKET_EAGAIN;
}
if (packet_len != rc) {
libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND, "Unable to send FXP_READ command", 0);
LIBSSH2_FREE(session, packet);
sftp->mkdir_state = sftp_mkdir_idle;
return -1;
}
} }
LIBSSH2_FREE(session, packet); LIBSSH2_FREE(session, packet);
sftp->mkdir_state = sftp_mkdir_packet_sent;
sftp->mkdir_packet = NULL;
}
/* #warning "XXX - Looping on PACKET_EAGAIN (blocking) until fix is migrated up farther" */ rc = libssh2_sftp_packet_require(sftp, SSH_FXP_STATUS, request_id, &data, &data_len);
while ((rc = libssh2_sftp_packet_require(sftp, SSH_FXP_STATUS, request_id, &data, &data_len)) == PACKET_EAGAIN) { if (rc == PACKET_EAGAIN) {
; return PACKET_EAGAIN;
} }
if (rc) { else if (rc) {
libssh2_error(session, LIBSSH2_ERROR_SOCKET_TIMEOUT, "Timeout waiting for status message", 0); libssh2_error(session, LIBSSH2_ERROR_SOCKET_TIMEOUT, "Timeout waiting for status message", 0);
return -1; sftp->mkdir_state = sftp_mkdir_idle;
} return -1;
}
retcode = libssh2_ntohu32(data + 5); sftp->mkdir_state = sftp_mkdir_idle;
LIBSSH2_FREE(session, data);
if (retcode == LIBSSH2_FX_OK) { retcode = libssh2_ntohu32(data + 5);
return 0; LIBSSH2_FREE(session, data);
} else {
libssh2_error(session, LIBSSH2_ERROR_SFTP_PROTOCOL, "SFTP Protocol Error", 0); if (retcode == LIBSSH2_FX_OK) {
sftp->last_errno = retcode; return 0;
return -1; } else {
} libssh2_error(session, LIBSSH2_ERROR_SFTP_PROTOCOL, "SFTP Protocol Error", 0);
sftp->last_errno = retcode;
return -1;
}
}
/* }}} */
/* {{{ libssh2_sftp_mkdir_ex
* Create a directory
*/
/* libssh2_sftp_mkdir_ex - NB-UNSAFE */
LIBSSH2_API int libssh2_sftp_mkdir_ex(LIBSSH2_SFTP *sftp, const char *path, unsigned int path_len, long mode)
{
ssize_t rc;
LIBSSH2_CHANNEL *ch = sftp->channel;
int bl = libssh2_channel_get_blocking(ch);
/* set blocking */
libssh2_channel_set_blocking(ch, 1);
rc = _libssh2_sftp_mkdir_ex(sftp, path, path_len, mode);
/* restore state */
libssh2_channel_set_blocking(ch, bl);
if(rc < 0) {
/* precent accidental returning of other return codes since
this API does not support/provide those */
return -1;
}
return rc;
}
/* }}} */
/* {{{ libssh2_sftp_mkdirnb_ex
* Create a directory
*/
/* libssh2_sftp_mkdirnb_ex - NB-SAFE */
LIBSSH2_API int libssh2_sftp_mkdirnb_ex(LIBSSH2_SFTP *sftp, const char *path, unsigned int path_len, long mode)
{
ssize_t rc;
LIBSSH2_CHANNEL *ch = sftp->channel;
int bl = libssh2_channel_get_blocking(ch);
/* set non-blocking */
libssh2_channel_set_blocking(ch, 0);
rc = _libssh2_sftp_mkdir_ex(sftp, path, path_len, mode);
/* restore state */
libssh2_channel_set_blocking(ch, bl);
return rc;
} }
/* }}} */ /* }}} */