Update wolfSSH_SFTP_Put() and wolfSSH_SFTP_SendWritePacket() for non-blocking.

pull/134/head
John Safranek 2019-01-04 09:57:43 -08:00
parent 3f1ebe292c
commit 157b71be7c
4 changed files with 409 additions and 138 deletions

View File

@ -248,6 +248,15 @@ const char* GetErrorString(int err)
case WS_CHAN_PENDING: case WS_CHAN_PENDING:
return "channel open pending"; return "channel open pending";
case WS_SFTP_BAD_REQ_ID:
return "sftp bad request id";
case WS_SFTP_BAD_REQ_TYPE:
return "sftp bad request response type";
case WS_SFTP_STATUS_NOT_OK:
return "sftp status not OK";
default: default:
return "Unknown error code"; return "Unknown error code";
} }

View File

@ -51,6 +51,8 @@ enum WS_SFTP_STATE_ID {
STATE_ID_SEND = 0x80, STATE_ID_SEND = 0x80,
STATE_ID_LS = 0x100, STATE_ID_LS = 0x100,
STATE_ID_READDIR = 0x200, STATE_ID_READDIR = 0x200,
STATE_ID_PUT = 0x0400,
STATE_ID_SEND_WRITE = 0x0800
}; };
enum WS_SFTP_NAME_STATE_ID { enum WS_SFTP_NAME_STATE_ID {
@ -133,6 +135,7 @@ typedef struct WS_SFTP_SEND_STATE {
word32 idx; word32 idx;
} WS_SFTP_SEND_STATE; } WS_SFTP_SEND_STATE;
/* similar to open state, could refactor */ /* similar to open state, could refactor */
typedef struct WS_SFTP_READDIR_STATE { typedef struct WS_SFTP_READDIR_STATE {
enum WS_SFTP_READDIR_STATE_ID state; enum WS_SFTP_READDIR_STATE_ID state;
@ -148,6 +151,7 @@ typedef struct WS_SFTP_LS_STATE {
WS_SFTPNAME* name; WS_SFTPNAME* name;
} WS_SFTP_LS_STATE; } WS_SFTP_LS_STATE;
enum WS_SFTP_GET_STATE_ID { enum WS_SFTP_GET_STATE_ID {
STATE_GET_INIT, STATE_GET_INIT,
STATE_GET_LSTAT, STATE_GET_LSTAT,
@ -163,14 +167,36 @@ enum WS_SFTP_GET_STATE_ID {
typedef struct WS_SFTP_GET_STATE { typedef struct WS_SFTP_GET_STATE {
enum WS_SFTP_GET_STATE_ID state; enum WS_SFTP_GET_STATE_ID state;
WS_SFTP_FILEATRB attrib; WS_SFTP_FILEATRB attrib;
byte handle[WOLFSSH_MAX_HANDLE];
WFILE* fl; WFILE* fl;
long gOfst; long gOfst;
word32 handleSz; word32 handleSz;
byte handle[WOLFSSH_MAX_HANDLE];
byte r[WOLFSSH_MAX_SFTP_RW]; byte r[WOLFSSH_MAX_SFTP_RW];
} WS_SFTP_GET_STATE; } WS_SFTP_GET_STATE;
enum WS_SFTP_PUT_STATE_ID {
STATE_PUT_INIT,
STATE_PUT_LOOKUP_OFFSET,
STATE_PUT_OPEN_REMOTE,
STATE_PUT_OPEN_LOCAL,
STATE_PUT_WRITE,
STATE_PUT_CLOSE_LOCAL,
STATE_PUT_CLOSE_REMOTE,
STATE_PUT_CLEANUP
};
typedef struct WS_SFTP_PUT_STATE {
enum WS_SFTP_PUT_STATE_ID state;
WFILE* fl;
long pOfst;
word32 handleSz;
int rSz;
byte handle[WOLFSSH_MAX_HANDLE];
byte r[WOLFSSH_MAX_SFTP_RW];
} WS_SFTP_PUT_STATE;
enum WS_SFTP_SEND_READ_STATE_ID { enum WS_SFTP_SEND_READ_STATE_ID {
STATE_SEND_READ_INIT, STATE_SEND_READ_INIT,
STATE_SEND_READ_SEND_REQ, STATE_SEND_READ_SEND_REQ,
@ -192,6 +218,26 @@ typedef struct WS_SFTP_SEND_READ_STATE {
} WS_SFTP_SEND_READ_STATE; } WS_SFTP_SEND_READ_STATE;
enum WS_SFTP_SEND_WRITE_STATE_ID {
STATE_SEND_WRITE_INIT,
STATE_SEND_WRITE_SEND_HEADER,
STATE_SEND_WRITE_SEND_BODY,
STATE_SEND_WRITE_GET_HEADER,
STATE_SEND_WRITE_READ_STATUS,
STATE_SEND_WRITE_DO_STATUS,
STATE_SEND_WRITE_CLEANUP
};
typedef struct WS_SFTP_SEND_WRITE_STATE {
enum WS_SFTP_SEND_WRITE_STATE_ID state;
byte* data;
word32 reqId;
word32 idx;
word32 maxSz;
word32 sentSz;
} WS_SFTP_SEND_WRITE_STATE;
enum WS_SFTP_CLOSE_STATE_ID { enum WS_SFTP_CLOSE_STATE_ID {
STATE_CLOSE_INIT, STATE_CLOSE_INIT,
STATE_CLOSE_SEND, STATE_CLOSE_SEND,
@ -312,6 +358,16 @@ static void wolfSSH_SFTP_ClearState(WOLFSSH* ssh, enum WS_SFTP_STATE_ID state)
ssh->readDirState = NULL; ssh->readDirState = NULL;
} }
} }
if (state & STATE_ID_PUT) {
XFREE(ssh->putState, ssh->ctx->heap, DYNTYPE_SFTP_STATE);
ssh->putState = NULL;
}
if (state & STATE_ID_SEND_WRITE) {
XFREE(ssh->sendWriteState, ssh->ctx->heap, DYNTYPE_SFTP_STATE);
ssh->sendWriteState = NULL;
}
} }
} }
@ -4409,90 +4465,199 @@ int wolfSSH_SFTP_Open(WOLFSSH* ssh, char* dir, word32 reason,
int wolfSSH_SFTP_SendWritePacket(WOLFSSH* ssh, byte* handle, word32 handleSz, int wolfSSH_SFTP_SendWritePacket(WOLFSSH* ssh, byte* handle, word32 handleSz,
word64 ofst, byte* in, word32 inSz) word64 ofst, byte* in, word32 inSz)
{ {
WS_SFTP_SEND_WRITE_STATE* state = NULL;
int ret; int ret;
int status; int status;
byte* data;
byte type; byte type;
word32 reqId;
word32 idx;
word32 maxSz;
WLOG(WS_LOG_SFTP, "Entering wolfSSH_SFTP_SendWritePacket()"); WLOG(WS_LOG_SFTP, "Entering wolfSSH_SFTP_SendWritePacket()");
if (ssh == NULL || handle == NULL || in == NULL) { if (ssh == NULL || handle == NULL || in == NULL) {
return WS_BAD_ARGUMENT; return WS_BAD_ARGUMENT;
} }
data = (byte*)WMALLOC(handleSz + WOLFSSH_SFTP_HEADER + UINT32_SZ * 4, state = ssh->sendWriteState;
ssh->ctx->heap, DYNTYPE_BUFFER); if (state == NULL) {
if (data == NULL) { state = (WS_SFTP_SEND_WRITE_STATE*)WMALLOC(
return WS_MEMORY_E; sizeof(WS_SFTP_SEND_WRITE_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_SEND_WRITE_STATE));
ssh->sendWriteState = state;
state->state = STATE_SEND_WRITE_INIT;
} }
if (SFTP_SetHeader(ssh, ssh->reqId, WOLFSSH_FTP_WRITE, for (;;) {
handleSz + UINT32_SZ * 4 + inSz, data) != WS_SUCCESS) { switch (state->state) {
case STATE_SEND_WRITE_INIT:
WLOG(WS_LOG_SFTP, "SFTP SEND_WRITE STATE: INIT");
state->sentSz = 0;
state->data = (byte*)WMALLOC(
handleSz + WOLFSSH_SFTP_HEADER + UINT32_SZ * 4,
ssh->ctx->heap, DYNTYPE_BUFFER);
if (state->data == NULL) {
ssh->error = WS_MEMORY_E;
return WS_FATAL_ERROR; return WS_FATAL_ERROR;
} }
idx = WOLFSSH_SFTP_HEADER; ret = SFTP_SetHeader(ssh, ssh->reqId, WOLFSSH_FTP_WRITE,
c32toa(handleSz, data + idx); idx += UINT32_SZ; handleSz + UINT32_SZ * 4 + inSz, state->data);
WMEMCPY(data + idx, (byte*)handle, handleSz); idx += handleSz; if (ret != WS_SUCCESS) {
state->state = STATE_SEND_WRITE_CLEANUP;
continue;
}
state->idx = WOLFSSH_SFTP_HEADER;
c32toa(handleSz, state->data + state->idx);
state->idx += UINT32_SZ;
WMEMCPY(state->data + state->idx, (byte*)handle, handleSz);
state->idx += handleSz;
/* offset to start reading from */ /* offset to start reading from */
c32toa((word32)(ofst >> 32), data + idx); idx += UINT32_SZ; c32toa((word32)(ofst >> 32), state->data + state->idx);
c32toa((word32)ofst, data + idx); idx += UINT32_SZ; state->idx += UINT32_SZ;
c32toa((word32)ofst, state->data + state->idx);
state->idx += UINT32_SZ;
/* data to be written */ /* data to be written */
c32toa(inSz, data + idx); idx += UINT32_SZ; c32toa(inSz, state->data + state->idx);
state->idx += UINT32_SZ;
state->state = STATE_SEND_WRITE_SEND_HEADER;
FALL_THROUGH;
case STATE_SEND_WRITE_SEND_HEADER:
WLOG(WS_LOG_SFTP, "SFTP SEND_WRITE STATE: SEND_HEADER");
/* send header and type specific data */ /* send header and type specific data */
ret = wolfSSH_stream_send(ssh, data, idx); ret = wolfSSH_stream_send(ssh, state->data, state->idx);
if (ret < 0) { if (ret < 0) {
WFREE(data, NULL, DYNTYPE_BUFFER); if (ssh->error == WS_WANT_READ ||
return ret; ssh->error == WS_WANT_WRITE) {
return WS_FATAL_ERROR;
} }
state->state = STATE_SEND_WRITE_CLEANUP;
ret = wolfSSH_stream_send(ssh, in, inSz); continue;
if (ret < 0) {
WFREE(data, NULL, DYNTYPE_BUFFER);
return ret;
} }
WFREE(data, NULL, DYNTYPE_BUFFER); state->state = STATE_SEND_WRITE_SEND_BODY;
FALL_THROUGH;
case STATE_SEND_WRITE_SEND_BODY:
WLOG(WS_LOG_SFTP, "SFTP SEND_WRITE STATE: SEND_BODY");
state->sentSz = wolfSSH_stream_send(ssh, in, inSz);
if (state->sentSz <= 0) {
if (ssh->error == WS_WANT_READ ||
ssh->error == WS_WANT_WRITE) {
return WS_FATAL_ERROR;
}
state->state = STATE_SEND_WRITE_CLEANUP;
continue;
}
WFREE(state->data, ssh->ctx->heap, DYNTYPE_BUFFER);
state->data = NULL;
state->state = STATE_SEND_WRITE_GET_HEADER;
FALL_THROUGH;
case STATE_SEND_WRITE_GET_HEADER:
WLOG(WS_LOG_SFTP, "SFTP SEND_WRITE STATE: GET_HEADER");
/* Get response */ /* Get response */
if ((maxSz = SFTP_GetHeader(ssh, &reqId, &type)) <= 0) { state->maxSz = SFTP_GetHeader(ssh, &state->reqId, &type);
if (state->maxSz <= 0) {
if (ssh->error == WS_WANT_READ ||
ssh->error == WS_WANT_WRITE) {
fprintf(stderr, "WS_WANT_something\n");
return WS_FATAL_ERROR; return WS_FATAL_ERROR;
} }
state->state = STATE_SEND_WRITE_CLEANUP;
continue;
}
/* check request ID */ /* check request ID */
if (reqId != ssh->reqId) { if (state->reqId != ssh->reqId) {
WLOG(WS_LOG_SFTP, "Bad request ID received"); WLOG(WS_LOG_SFTP, "Bad request ID received");
return WS_FATAL_ERROR; ret = WS_FATAL_ERROR;
} ssh->error = WS_SFTP_BAD_REQ_ID;
else { state->state = STATE_SEND_WRITE_CLEANUP;
ssh->reqId++; continue;
} }
if (type == WOLFSSH_FTP_STATUS) { ssh->reqId++;
idx = 0;
data = (byte*)WMALLOC(maxSz, ssh->ctx->heap, DYNTYPE_BUFFER); if (type != WOLFSSH_FTP_STATUS) {
wolfSSH_stream_read(ssh, data, maxSz); WLOG(WS_LOG_SFTP, "Unexpected packet type");
status = wolfSSH_SFTP_DoStatus(ssh, reqId, data, &idx, maxSz); ret = WS_FATAL_ERROR;
WFREE(data, ssh->ctx->heap, DYNTYPE_BUFFER); ssh->error = WS_SFTP_BAD_REQ_TYPE;
if (status == WOLFSSH_FTP_OK) { state->state = STATE_SEND_WRITE_CLEANUP;
/* a okay */ continue;
} }
else {
/* @TODO better error value description i.e permissions... */ state->idx = 0;
state->data = (byte*)WMALLOC(state->maxSz,
ssh->ctx->heap, DYNTYPE_BUFFER);
if (state->data == NULL) {
ssh->error = WS_MEMORY_E;
ret = WS_FATAL_ERROR;
state->state = STATE_SEND_WRITE_CLEANUP;
continue;
}
state->state = STATE_SEND_WRITE_READ_STATUS;
FALL_THROUGH;
case STATE_SEND_WRITE_READ_STATUS:
WLOG(WS_LOG_SFTP, "SFTP SEND_WRITE STATE: READ_STATUS");
ret = wolfSSH_stream_read(ssh, state->data, state->maxSz);
if (ret <= 0) {
if (ssh->error == WS_WANT_READ ||
ssh->error == WS_WANT_WRITE) {
return WS_FATAL_ERROR;
}
state->state = STATE_SEND_WRITE_CLEANUP;
continue;
}
state->state = STATE_SEND_WRITE_DO_STATUS;
FALL_THROUGH;
case STATE_SEND_WRITE_DO_STATUS:
WLOG(WS_LOG_SFTP, "SFTP SEND_WRITE STATE: DO_STATUS");
status = wolfSSH_SFTP_DoStatus(ssh, state->reqId, state->data,
&state->idx, state->maxSz);
if (status < 0) {
ret = WS_FATAL_ERROR; ret = WS_FATAL_ERROR;
} }
else if (status != WOLFSSH_FTP_OK) {
/* @TODO better error value description i.e permissions */
ssh->error = WS_SFTP_STATUS_NOT_OK;
ret = WS_FATAL_ERROR;
} }
else { if (ret >= WS_SUCCESS)
WLOG(WS_LOG_SFTP, "Unexpected packet type"); ret = state->sentSz;
state->state = STATE_SEND_WRITE_CLEANUP;
FALL_THROUGH;
case STATE_SEND_WRITE_CLEANUP:
WLOG(WS_LOG_SFTP, "SFTP SEND_WRITE STATE: CLEANUP");
if (ssh->sendWriteState != NULL) {
if (ssh->sendWriteState->data != NULL) {
WFREE(ssh->sendWriteState->data,
ssh->ctx->heap, DYNTYPE_SFTP_STATE);
ssh->sendWriteState->data = NULL;
}
WFREE(ssh->sendWriteState,
ssh->ctx->heap, DYNTYPE_SFTP_STATE);
ssh->sendWriteState = NULL;
}
return ret;
default:
WLOG(WS_LOG_DEBUG, "Bad SFTP Send Write Packet state, "
"program error");
ssh->error = WS_INPUT_CASE_E;
return WS_FATAL_ERROR; return WS_FATAL_ERROR;
} }
}
return WS_SUCCESS;
return ret;
} }
@ -4545,8 +4710,10 @@ int wolfSSH_SFTP_SendReadPacket(WOLFSSH* ssh, byte* handle, word32 handleSz,
ret = SFTP_SetHeader(ssh, ssh->reqId, WOLFSSH_FTP_READ, ret = SFTP_SetHeader(ssh, ssh->reqId, WOLFSSH_FTP_READ,
handleSz + UINT32_SZ * 4, state->data); handleSz + UINT32_SZ * 4, state->data);
if (ret != WS_SUCCESS) if (ret != WS_SUCCESS) {
return WS_FATAL_ERROR; state->state = STATE_SEND_READ_CLEANUP;
continue;
}
state->idx = WOLFSSH_SFTP_HEADER; state->idx = WOLFSSH_SFTP_HEADER;
c32toa(handleSz, state->data + state->idx); c32toa(handleSz, state->data + state->idx);
@ -4669,11 +4836,12 @@ int wolfSSH_SFTP_SendReadPacket(WOLFSSH* ssh, byte* handle, word32 handleSz,
default: default:
WLOG(WS_LOG_DEBUG, "Bad SFTP Send Read Packet state, " WLOG(WS_LOG_DEBUG, "Bad SFTP Send Read Packet state, "
"program error"); "program error");
return WS_INPUT_CASE_E; ssh->error = WS_INPUT_CASE_E;
return WS_FATAL_ERROR;
} }
} }
return ret; return WS_SUCCESS;
} }
@ -5381,9 +5549,14 @@ int wolfSSH_SFTP_Get(WOLFSSH* ssh, char* from,
ret = wolfSSH_SFTP_Open(ssh, from, WOLFSSH_FXF_READ, NULL, ret = wolfSSH_SFTP_Open(ssh, from, WOLFSSH_FXF_READ, NULL,
state->handle, &state->handleSz); state->handle, &state->handleSz);
if (ret != WS_SUCCESS) { if (ret != WS_SUCCESS) {
WLOG(WS_LOG_SFTP, "Error getting handle"); if (ssh->error == WS_WANT_READ ||
ssh->error == WS_WANT_WRITE) {
return WS_FATAL_ERROR; return WS_FATAL_ERROR;
} }
WLOG(WS_LOG_SFTP, "Error getting handle");
state->state = STATE_GET_CLEANUP;
continue;
}
state->state = STATE_GET_LOOKUP_OFFSET; state->state = STATE_GET_LOOKUP_OFFSET;
FALL_THROUGH; FALL_THROUGH;
@ -5418,15 +5591,23 @@ int wolfSSH_SFTP_Get(WOLFSSH* ssh, char* from,
state->handle, state->handleSz, state->handle, state->handleSz,
state->gOfst, state->r, state->gOfst, state->r,
WOLFSSH_MAX_SFTP_RW); WOLFSSH_MAX_SFTP_RW);
if (wolfSSH_get_error(ssh) == WS_WANT_READ) { if (sz <= 0) {
if (ssh->error == WS_WANT_READ ||
ssh->error == WS_WANT_WRITE) {
return WS_FATAL_ERROR; return WS_FATAL_ERROR;
} }
WLOG(WS_LOG_SFTP, "Error reading packet");
if (sz > 0) { ret = WS_FATAL_ERROR;
state->state = STATE_GET_CLEANUP;
break;
}
else {
if ((long)WFWRITE(state->r, 1, if ((long)WFWRITE(state->r, 1,
sz, state->fl) != sz) { sz, state->fl) != sz) {
WLOG(WS_LOG_SFTP, "Error writing to file"); WLOG(WS_LOG_SFTP, "Error writing to file");
ssh->error = WS_BAD_FILE_E;
ret = WS_FATAL_ERROR; ret = WS_FATAL_ERROR;
state->state = STATE_GET_CLEANUP;
break; break;
} }
state->gOfst += sz; state->gOfst += sz;
@ -5435,10 +5616,8 @@ int wolfSSH_SFTP_Get(WOLFSSH* ssh, char* from,
} }
} }
} while (sz > 0 && ssh->sftpInt == 0); } while (sz > 0 && ssh->sftpInt == 0);
if (sz < 0) { if (ret != WS_SUCCESS)
state->state = STATE_GET_CLEANUP;
continue; continue;
}
if (ssh->sftpInt) { if (ssh->sftpInt) {
WLOG(WS_LOG_SFTP, "Interrupted, trying to save offset"); WLOG(WS_LOG_SFTP, "Interrupted, trying to save offset");
wolfSSH_SFTP_SaveOfst(ssh, from, to, state->gOfst); wolfSSH_SFTP_SaveOfst(ssh, from, to, state->gOfst);
@ -5494,67 +5673,142 @@ int wolfSSH_SFTP_Get(WOLFSSH* ssh, char* from,
int wolfSSH_SFTP_Put(WOLFSSH* ssh, char* from, char* to, byte resume, int wolfSSH_SFTP_Put(WOLFSSH* ssh, char* from, char* to, byte resume,
WS_STATUS_CB* statusCb) WS_STATUS_CB* statusCb)
{ {
byte handle[WOLFSSH_MAX_HANDLE]; WS_SFTP_PUT_STATE* state = NULL;
WFILE* fl; int ret = WS_SUCCESS;
long pOfst = 0; int sz;
word32 handleSz;
int ret;
if (ssh == NULL || from == NULL || to == NULL) { if (ssh == NULL || from == NULL || to == NULL) {
return WS_BAD_ARGUMENT; return WS_BAD_ARGUMENT;
} }
if (ssh->error == WS_WANT_READ || ssh->error == WS_WANT_WRITE)
ssh->error = WS_SUCCESS;
state = ssh->putState;
if (state == NULL) {
state = (WS_SFTP_PUT_STATE*)WMALLOC(sizeof(WS_SFTP_PUT_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_PUT_STATE));
ssh->putState = state;
state->state = STATE_PUT_INIT;
}
for (;;) {
switch (state->state) {
case STATE_PUT_INIT:
WLOG(WS_LOG_SFTP, "SFTP PUT STATE: INIT");
state->pOfst = 0;
state->state = STATE_PUT_LOOKUP_OFFSET;
FALL_THROUGH;
case STATE_PUT_LOOKUP_OFFSET:
WLOG(WS_LOG_SFTP, "SFTP PUT STATE: LOOKUP OFFSET");
if (resume) { if (resume) {
/* check if offset was stored */ /* check if offset was stored */
pOfst = (long)wolfSSH_SFTP_GetOfst(ssh, from, to); state->pOfst = (long)wolfSSH_SFTP_GetOfst(ssh, from, to);
} }
state->handleSz = WOLFSSH_MAX_HANDLE;
state->state = STATE_PUT_OPEN_LOCAL;
FALL_THROUGH;
case STATE_PUT_OPEN_REMOTE:
WLOG(WS_LOG_SFTP, "SFTP PUT STATE: OPEN REMOTE");
/* open file and get handle */ /* open file and get handle */
handleSz = WOLFSSH_MAX_HANDLE; ret = wolfSSH_SFTP_Open(ssh, to, (WOLFSSH_FXF_WRITE |
if ((ret = wolfSSH_SFTP_Open(ssh, to, (WOLFSSH_FXF_WRITE |
WOLFSSH_FXF_CREAT | WOLFSSH_FXF_TRUNC), NULL, WOLFSSH_FXF_CREAT | WOLFSSH_FXF_TRUNC), NULL,
handle, &handleSz)) != WS_SUCCESS) { state->handle, &state->handleSz);
if (ret != WS_SUCCESS) {
if (ssh->error == WS_WANT_READ ||
ssh->error == WS_WANT_WRITE) {
return WS_FATAL_ERROR;
}
WLOG(WS_LOG_SFTP, "Error getting handle"); WLOG(WS_LOG_SFTP, "Error getting handle");
return ret; state->state = STATE_PUT_CLEANUP;
continue;
} }
state->state = STATE_PUT_OPEN_LOCAL;
FALL_THROUGH;
ret = WFOPEN(&fl, from, "rb"); case STATE_PUT_OPEN_LOCAL:
WLOG(WS_LOG_SFTP, "SFTP PUT STATE: OPEN LOCAL");
ret = WFOPEN(&state->fl, from, "rb");
if (ret != 0) { if (ret != 0) {
WLOG(WS_LOG_SFTP, "Unable to open file"); WLOG(WS_LOG_SFTP, "Unable to open input file");
ssh->error = WS_BAD_FILE_E;
ret = WS_FATAL_ERROR; ret = WS_FATAL_ERROR;
continue;
} }
else { state->rSz = 0;
byte r[WOLFSSH_MAX_SFTP_RW]; state->state = STATE_PUT_WRITE;
int rSz; FALL_THROUGH;
int sz;
ret = WS_SUCCESS; case STATE_PUT_WRITE:
WLOG(WS_LOG_SFTP, "SFTP PUT STATE: WRITE");
do { do {
rSz = (int)WFREAD(r, 1, WOLFSSH_MAX_SFTP_RW, fl); if (state->rSz == 0) {
if (rSz <= 0 ) { state->rSz = (int)WFREAD(state->r,
1, WOLFSSH_MAX_SFTP_RW, state->fl);
if (state->rSz <= 0) {
break; /* either at end of file or error */ break; /* either at end of file or error */
} }
sz = wolfSSH_SFTP_SendWritePacket(ssh, handle, handleSz, pOfst, }
r, rSz); sz = wolfSSH_SFTP_SendWritePacket(ssh,
state->handle, state->handleSz, state->pOfst,
state->r, state->rSz);
if (sz > 0) { if (sz > 0) {
pOfst += sz; state->pOfst += sz;
state->rSz -= sz;
if (statusCb != NULL) { if (statusCb != NULL) {
statusCb(ssh, pOfst, from); statusCb(ssh, state->pOfst, from);
} }
} }
wolfSSH_CheckReceivePending(ssh); /* check for adjust window packet */ /* check for adjust window packet */
wolfSSH_CheckReceivePending(ssh);
} while (sz > 0 && ssh->sftpInt == 0); } while (sz > 0 && ssh->sftpInt == 0);
if (ssh->sftpInt) {
wolfSSH_SFTP_SaveOfst(ssh, from, to, pOfst);
}
ssh->sftpInt = 0;
WFCLOSE(fl);
}
if (wolfSSH_SFTP_Close(ssh, handle, handleSz) != WS_SUCCESS) { if (ssh->sftpInt) {
wolfSSH_SFTP_SaveOfst(ssh, from, to, state->pOfst);
ssh->sftpInt = 0;
}
FALL_THROUGH;
case STATE_PUT_CLOSE_LOCAL:
WLOG(WS_LOG_SFTP, "SFTP PUT STATE: CLOSE LOCAL");
WFCLOSE(state->fl);
state->state = STATE_PUT_CLOSE_REMOTE;
FALL_THROUGH;
case STATE_PUT_CLOSE_REMOTE:
WLOG(WS_LOG_SFTP, "SFTP PUT STATE: CLOSE REMOTE");
ret = wolfSSH_SFTP_Close(ssh, state->handle, state->handleSz);
if (ret != WS_SUCCESS) {
if (ssh->error == WS_WANT_READ ||
ssh->error == WS_WANT_WRITE) {
return WS_FATAL_ERROR;
}
WLOG(WS_LOG_SFTP, "Error closing handle"); WLOG(WS_LOG_SFTP, "Error closing handle");
if (ret == WS_SUCCESS) ret = WS_FATAL_ERROR; /* Fall through to cleanup. */
}
state->state = STATE_PUT_CLEANUP;
FALL_THROUGH;
case STATE_PUT_CLEANUP:
WLOG(WS_LOG_SFTP, "SFTP PUT STATE: CLEANUP");
if (ssh->putState != NULL) {
WFREE(ssh->putState, ssh->ctx->heap, DYNTYPE_SFTP_STATE);
ssh->putState = NULL;
}
return ret;
default:
WLOG(WS_LOG_DEBUG, "Bad SFTP Put state, program error");
return WS_INPUT_CASE_E;
}
} }
return ret; return ret;

View File

@ -97,8 +97,11 @@ enum WS_ErrorCodes {
WS_CHAN_RXD = -57, /* Status that channel data received. */ WS_CHAN_RXD = -57, /* Status that channel data received. */
WS_INVALID_EXTDATA = -58, /* invalid Channel Extended Data Type */ WS_INVALID_EXTDATA = -58, /* invalid Channel Extended Data Type */
WS_CHAN_PENDING = -59, /* peer hasn't confirmed channel open */ WS_CHAN_PENDING = -59, /* peer hasn't confirmed channel open */
WS_SFTP_BAD_REQ_ID = -60, /* SFTP Bad request ID */
WS_SFTP_BAD_REQ_TYPE = -61, /* SFTP Bad request ID */
WS_SFTP_STATUS_NOT_OK = -62, /* SFTP Status not OK */
WS_LAST_E = -59 /* Update this to indicate last error */ WS_LAST_E = -62 /* Update this to indicate last error */
}; };

View File

@ -258,11 +258,14 @@ typedef struct SFTP_OFST {
struct WS_SFTP_GET_STATE; struct WS_SFTP_GET_STATE;
struct WS_SFTP_PUT_STATE;
struct WS_SFTP_LSTAT_STATE; struct WS_SFTP_LSTAT_STATE;
struct WS_SFTP_OPEN_STATE; struct WS_SFTP_OPEN_STATE;
struct WS_SFTP_CLOSE_STATE; struct WS_SFTP_CLOSE_STATE;
struct WS_SFTP_SEND_READ_STATE; struct WS_SFTP_SEND_READ_STATE;
struct WS_SFTP_SEND_WRITE_STATE;
struct WS_SFTP_GET_HANDLE_STATE; struct WS_SFTP_GET_HANDLE_STATE;
struct WS_SFTP_PUT_STATE;
#endif /* WOLFSSH_SFTP */ #endif /* WOLFSSH_SFTP */
@ -399,10 +402,12 @@ struct WOLFSSH {
struct WS_SFTP_SEND_STATE* sendState; struct WS_SFTP_SEND_STATE* sendState;
struct WS_SFTP_NAME_STATE* nameState; struct WS_SFTP_NAME_STATE* nameState;
struct WS_SFTP_GET_STATE* getState; struct WS_SFTP_GET_STATE* getState;
struct WS_SFTP_PUT_STATE* putState;
struct WS_SFTP_LSTAT_STATE* lstatState; struct WS_SFTP_LSTAT_STATE* lstatState;
struct WS_SFTP_OPEN_STATE* openState; struct WS_SFTP_OPEN_STATE* openState;
struct WS_SFTP_CLOSE_STATE* closeState; struct WS_SFTP_CLOSE_STATE* closeState;
struct WS_SFTP_SEND_READ_STATE* sendReadState; struct WS_SFTP_SEND_READ_STATE* sendReadState;
struct WS_SFTP_SEND_WRITE_STATE* sendWriteState;
struct WS_SFTP_GET_HANDLE_STATE* getHandleState; struct WS_SFTP_GET_HANDLE_STATE* getHandleState;
#endif #endif
}; };