diff --git a/src/wolfsftp.c b/src/wolfsftp.c index 54486f0..be76289 100644 --- a/src/wolfsftp.c +++ b/src/wolfsftp.c @@ -55,7 +55,14 @@ enum WS_SFTP_STATE_ID { STATE_ID_SEND_WRITE = 0x0800, STATE_ID_RM = 0x1000, STATE_ID_MKDIR = 0x2000, - STATE_ID_RENAME = 0x4000, + STATE_ID_RMDIR = 0x4000, + STATE_ID_RENAME = 0x8000, +}; + +enum WS_SFTP_RMDIR_STATE_ID { + STATE_RMDIR_SEND, + STATE_RMDIR_GET, + STATE_RMDIR_STATUS }; enum WS_SFTP_MKDIR_STATE_ID { @@ -176,6 +183,14 @@ typedef struct WS_SFTP_MKDIR_STATE { word32 idx; } WS_SFTP_MKDIR_STATE; +/* similar to open state, could refactor */ +typedef struct WS_SFTP_RMDIR_STATE { + enum WS_SFTP_RMDIR_STATE_ID state; + byte* data; + int sz; + word32 idx; +} WS_SFTP_RMDIR_STATE; + typedef struct WS_SFTP_LS_STATE { enum WS_SFTP_LS_STATE_ID state; byte handle[WOLFSSH_MAX_HANDLE]; @@ -435,6 +450,13 @@ static void wolfSSH_SFTP_ClearState(WOLFSSH* ssh, enum WS_SFTP_STATE_ID state) ssh->mkdirState = NULL; } + if (state & STATE_ID_RMDIR) { + if (ssh->rmdirState != NULL) + XFREE(ssh->rmdirState->data, ssh->ctx->heap, DYNTYPE_BUFFER); + XFREE(ssh->rmdirState, ssh->ctx->heap, DYNTYPE_SFTP_STATE); + ssh->rmdirState = NULL; + } + if (state & STATE_ID_RENAME) { if (ssh->renameState != NULL) XFREE(ssh->renameState->data, ssh->ctx->heap, DYNTYPE_BUFFER); @@ -5614,45 +5636,86 @@ int wolfSSH_SFTP_Remove(WOLFSSH* ssh, char* f) */ int wolfSSH_SFTP_RMDIR(WOLFSSH* ssh, char* dir) { + struct WS_SFTP_RMDIR_STATE* state = NULL; int ret; word32 reqId; byte type; + word32 idx = 0; WLOG(WS_LOG_SFTP, "Sending WOLFSSH_FTP_RMDIR"); if (ssh == NULL || dir == NULL) { return WS_BAD_ARGUMENT; } - ret = SendPacketType(ssh, WOLFSSH_FTP_RMDIR, (byte*)dir, - (word32)WSTRLEN(dir)); - if (ret != WS_SUCCESS) { - return ret; + state = ssh->rmdirState; + if (state == NULL) { + state = (WS_SFTP_RMDIR_STATE*)WMALLOC(sizeof(WS_SFTP_RMDIR_STATE), + ssh->ctx->heap, DYNTYPE_SFTP_STATE); + if (state == NULL) { + ssh->error = WS_MEMORY_E; + return WS_FATAL_ERROR; + } + WMEMSET(state, 0, sizeof(WS_SFTP_RMDIR_STATE)); + ssh->rmdirState = state; + state->state = STATE_RMDIR_SEND; } - ret = SFTP_GetHeader(ssh, &reqId, &type); - if (ret <= 0 || type != WOLFSSH_FTP_STATUS) { - WLOG(WS_LOG_SFTP, "Unexpected packet type"); - return WS_FATAL_ERROR; - } + switch (state->state) { + case STATE_RMDIR_SEND: + ret = SendPacketType(ssh, WOLFSSH_FTP_RMDIR, (byte*)dir, + (word32)WSTRLEN(dir)); + if (ret != WS_SUCCESS) { + if (ssh->error != WS_WANT_READ && ssh->error != WS_WANT_WRITE) { + wolfSSH_SFTP_ClearState(ssh, STATE_ID_RMDIR); + } + return ret; + } + state->state = STATE_RMDIR_GET; + FALL_THROUGH; + /* no break */ - word32 maxSz = ret; - word32 idx = 0; + case STATE_RMDIR_GET: + ret = SFTP_GetHeader(ssh, &reqId, &type); + if (ret <= 0 || type != WOLFSSH_FTP_STATUS) { + if (ssh->error != WS_WANT_READ) { + wolfSSH_SFTP_ClearState(ssh, STATE_ID_RMDIR); + WLOG(WS_LOG_SFTP, "Unexpected packet type"); + } + return WS_FATAL_ERROR; + } + state->sz = ret; + state->data = (byte*)WMALLOC(state->sz, ssh->ctx->heap, + DYNTYPE_BUFFER); + if (state->data == NULL) { + wolfSSH_SFTP_ClearState(ssh, STATE_ID_RMDIR); + return WS_MEMORY_E; + } + state->state = STATE_RMDIR_STATUS; + FALL_THROUGH; + /* no break */ - byte* data = (byte*)WMALLOC(maxSz, ssh->ctx->heap, DYNTYPE_BUFFER); - if ((ret = wolfSSH_stream_read(ssh, data, maxSz)) < 0) { - WFREE(data, ssh->ctx->heap, DYNTYPE_BUFFER); - return WS_FATAL_ERROR; - } + case STATE_RMDIR_STATUS: + if ((ret = wolfSSH_stream_read(ssh, state->data, state->sz)) < 0) { + if (ssh->error != WS_WANT_READ) + wolfSSH_SFTP_ClearState(ssh, STATE_ID_RMDIR); + return WS_FATAL_ERROR; + } - ret = wolfSSH_SFTP_DoStatus(ssh, reqId, data, &idx, maxSz); - WFREE(data, ssh->ctx->heap, DYNTYPE_BUFFER); - if (ret == WOLFSSH_FTP_OK) { - return WS_SUCCESS; - } - else { - /* @TODO can return better error value i.e. permissions */ - ssh->error = ret; - return WS_FATAL_ERROR; + ret = wolfSSH_SFTP_DoStatus(ssh, reqId, state->data, &idx, + state->sz); + wolfSSH_SFTP_ClearState(ssh, STATE_ID_RMDIR); + if (ret == WOLFSSH_FTP_OK) { + return WS_SUCCESS; + } + else { + /* @TODO can return better error value i.e. permissions */ + ssh->error = ret; + return WS_FATAL_ERROR; + } + + default: + wolfSSH_SFTP_ClearState(ssh, STATE_ID_RMDIR); + return WS_FATAL_ERROR; } } diff --git a/wolfssh/internal.h b/wolfssh/internal.h index 30d58aa..2cdc564 100644 --- a/wolfssh/internal.h +++ b/wolfssh/internal.h @@ -398,6 +398,7 @@ struct WOLFSSH { #ifdef WOLFSSH_STOREHANDLE WS_HANDLE_LIST* handleList; #endif + struct WS_SFTP_RMDIR_STATE* rmdirState; struct WS_SFTP_MKDIR_STATE* mkdirState; struct WS_SFTP_RM_STATE* rmState; struct WS_SFTP_READDIR_STATE* readDirState;