mirror of https://github.com/wolfSSL/wolfssh.git
nonblocking chmod, add chmod sftp test
parent
854fb8d7e8
commit
aa7330f7fc
|
@ -1115,8 +1115,11 @@ THREAD_RETURN WOLFSSH_THREAD sftpclient_test(void* args)
|
|||
|
||||
ret = doCmds(args);
|
||||
XFREE(workingDir, NULL, DYNAMIC_TYPE_TMP_BUFFER);
|
||||
if (ret == WS_SUCCESS)
|
||||
ret = wolfSSH_shutdown(ssh);
|
||||
if (ret == WS_SUCCESS) {
|
||||
if (wolfSSH_shutdown(ssh) != WS_SUCCESS) {
|
||||
printf("error with wolfSSH_shutdown(), already disconnected?\n");
|
||||
}
|
||||
}
|
||||
WCLOSESOCKET(sockFd);
|
||||
wolfSSH_free(ssh);
|
||||
wolfSSH_CTX_free(ctx);
|
||||
|
|
|
@ -58,13 +58,13 @@ trap do_trap INT TERM
|
|||
|
||||
[ ! -x ./examples/sftpclient/wolfsftp ] && echo -e "\n\nClient doesn't exist" && exit 1
|
||||
|
||||
echo "Test basic connection"
|
||||
./examples/echoserver/echoserver -1 -R $ready_file &
|
||||
server_pid=$!
|
||||
create_port
|
||||
echo "ls\nexit" | ./examples/sftpclient/wolfsftp -u jill -P upthehill -p $port
|
||||
echo "exit" | ./examples/sftpclient/wolfsftp -u jill -P upthehill -p $port
|
||||
RESULT=$?
|
||||
remove_ready_file
|
||||
# if fail here then is a settings issue so return 0
|
||||
if [ $RESULT -ne 0 ]; then
|
||||
echo -e "\n\nfailed to connect"
|
||||
do_cleanup
|
||||
|
@ -72,13 +72,13 @@ if [ $RESULT -ne 0 ]; then
|
|||
fi
|
||||
|
||||
# Test non blocking connection
|
||||
echo "Test non blocking connection"
|
||||
./examples/echoserver/echoserver -N -1 -R $ready_file &
|
||||
server_pid=$!
|
||||
create_port
|
||||
echo "ls\nexit" | ./examples/sftpclient/wolfsftp -N -u jill -P upthehill -p $port
|
||||
echo "exit" | ./examples/sftpclient/wolfsftp -N -u jill -P upthehill -p $port
|
||||
RESULT=$?
|
||||
remove_ready_file
|
||||
# if fail here then is a settings issue so return 0
|
||||
if [ $RESULT -ne 0 ]; then
|
||||
echo -e "\n\nfailed to connect"
|
||||
do_cleanup
|
||||
|
@ -86,14 +86,14 @@ if [ $RESULT -ne 0 ]; then
|
|||
fi
|
||||
|
||||
# Test of setting directory
|
||||
echo "Test of setting directory"
|
||||
PWD=`pwd`
|
||||
./examples/echoserver/echoserver -d $PWD/examples -1 -R $ready_file &
|
||||
server_pid=$!
|
||||
create_port
|
||||
echo "ls\nexit" | ./examples/sftpclient/wolfsftp -N -u jill -P upthehill -p $port
|
||||
echo "exit" | ./examples/sftpclient/wolfsftp -N -u jill -P upthehill -p $port
|
||||
RESULT=$?
|
||||
remove_ready_file
|
||||
# if fail here then is a settings issue so return 0
|
||||
if [ $RESULT -ne 0 ]; then
|
||||
echo -e "\n\nfailed to connect"
|
||||
do_cleanup
|
||||
|
|
262
src/wolfsftp.c
262
src/wolfsftp.c
|
@ -58,6 +58,20 @@ enum WS_SFTP_STATE_ID {
|
|||
STATE_ID_RMDIR = 0x4000,
|
||||
STATE_ID_RENAME = 0x8000,
|
||||
STATE_ID_RECV = 0x10000,
|
||||
STATE_ID_CHMOD = 0x20000,
|
||||
STATE_ID_SETATR = 0x40000,
|
||||
};
|
||||
|
||||
enum WS_SFTP_CHMOD_STATE_ID {
|
||||
STATE_CHMOD_GET,
|
||||
STATE_CHMOD_SEND
|
||||
};
|
||||
|
||||
enum WS_SFTP_SETATR_STATE_ID {
|
||||
STATE_SET_ATR_INIT,
|
||||
STATE_SET_ATR_SEND,
|
||||
STATE_SET_ATR_GET,
|
||||
STATE_SET_ATR_STATUS
|
||||
};
|
||||
|
||||
enum WS_SFTP_RMDIR_STATE_ID {
|
||||
|
@ -123,6 +137,20 @@ enum WS_SFTP_LSTAT_STATE_ID {
|
|||
STATE_LSTAT_CLEANUP
|
||||
};
|
||||
|
||||
typedef struct WS_SFTP_CHMOD_STATE {
|
||||
enum WS_SFTP_CHMOD_STATE_ID state;
|
||||
WS_SFTP_FILEATRB atr;
|
||||
} WS_SFTP_CHMOD_STATE;
|
||||
|
||||
|
||||
typedef struct WS_SFTP_SETATR_STATE {
|
||||
enum WS_SFTP_SETATR_STATE_ID state;
|
||||
byte* data;
|
||||
word32 sz;
|
||||
word32 reqId;
|
||||
} WS_SFTP_SETATR_STATE;
|
||||
|
||||
|
||||
typedef struct WS_SFTP_LSTAT_STATE {
|
||||
enum WS_SFTP_LSTAT_STATE_ID state;
|
||||
word32 reqId;
|
||||
|
@ -497,6 +525,21 @@ static void wolfSSH_SFTP_ClearState(WOLFSSH* ssh, enum WS_SFTP_STATE_ID state)
|
|||
XFREE(ssh->recvState, ssh->ctx->heap, DYNTYPE_SFTP_STATE);
|
||||
ssh->recvState = NULL;
|
||||
}
|
||||
|
||||
if (state & STATE_ID_CHMOD) {
|
||||
if (ssh->chmodState) {
|
||||
XFREE(ssh->chmodState, ssh->ctx->heap, DYNTYPE_SFTP_STATE);
|
||||
ssh->chmodState = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
if (state & STATE_ID_SETATR) {
|
||||
if (ssh->setatrState) {
|
||||
XFREE(ssh->setatrState->data, ssh->ctx->heap, DYNTYPE_BUFFER);
|
||||
XFREE(ssh->setatrState, ssh->ctx->heap, DYNTYPE_SFTP_STATE);
|
||||
ssh->setatrState = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -5009,29 +5052,63 @@ WS_SFTPNAME* wolfSSH_SFTP_LS(WOLFSSH* ssh, char* dir)
|
|||
*/
|
||||
int wolfSSH_SFTP_CHMOD(WOLFSSH* ssh, char* n, char* oct)
|
||||
{
|
||||
int ret;
|
||||
struct WS_SFTP_CHMOD_STATE* state = NULL;
|
||||
int ret = WS_FATAL_ERROR;
|
||||
int mode;
|
||||
WS_SFTP_FILEATRB atr;
|
||||
|
||||
if (ssh == NULL || n == NULL || oct == NULL) {
|
||||
return WS_BAD_ARGUMENT;
|
||||
}
|
||||
|
||||
/* convert from octal to decimal */
|
||||
mode = wolfSSH_oct2dec(ssh, (byte*)oct, (word32)WSTRLEN(oct));
|
||||
if (mode < 0) {
|
||||
return mode;
|
||||
state = ssh->chmodState;
|
||||
if (state == NULL) {
|
||||
state = (WS_SFTP_CHMOD_STATE*)WMALLOC(sizeof(WS_SFTP_CHMOD_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_CHMOD_STATE));
|
||||
ssh->chmodState = state;
|
||||
state->state = STATE_CHMOD_GET;
|
||||
}
|
||||
|
||||
/* get current attributes of path */
|
||||
WMEMSET(&atr, 0, sizeof(WS_SFTP_FILEATRB));
|
||||
if ((ret = wolfSSH_SFTP_STAT(ssh, n, &atr)) != WS_SUCCESS) {
|
||||
return ret;
|
||||
}
|
||||
switch (state->state) {
|
||||
case STATE_CHMOD_GET:
|
||||
/* get current attributes of path */
|
||||
if ((ret = wolfSSH_SFTP_STAT(ssh, n, &state->atr)) != WS_SUCCESS) {
|
||||
if (ssh->error != WS_WANT_READ && ssh->error != WS_WANT_WRITE) {
|
||||
break;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* update permissions */
|
||||
atr.per = mode;
|
||||
return wolfSSH_SFTP_SetSTAT(ssh, n, &atr);
|
||||
/* convert from octal to decimal */
|
||||
mode = wolfSSH_oct2dec(ssh, (byte*)oct, (word32)WSTRLEN(oct));
|
||||
if (mode < 0) {
|
||||
ret = WS_FATAL_ERROR;
|
||||
break;
|
||||
}
|
||||
|
||||
/* update permissions */
|
||||
state->atr.per = mode;
|
||||
state->state = STATE_CHMOD_SEND;
|
||||
FALL_THROUGH;
|
||||
/* no break */
|
||||
|
||||
case STATE_CHMOD_SEND:
|
||||
ret = wolfSSH_SFTP_SetSTAT(ssh, n, &state->atr);
|
||||
if (ssh->error == WS_WANT_READ || ssh->error == WS_WANT_WRITE) {
|
||||
return ret;
|
||||
}
|
||||
break;
|
||||
|
||||
|
||||
default:
|
||||
WLOG(WS_LOG_SFTP, "Unknown CHMOD state");
|
||||
}
|
||||
wolfSSH_SFTP_ClearState(ssh, STATE_ID_CHMOD);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
|
@ -5223,10 +5300,9 @@ int wolfSSH_SFTP_LSTAT(WOLFSSH* ssh, char* dir, WS_SFTP_FILEATRB* atr)
|
|||
*/
|
||||
int wolfSSH_SFTP_SetSTAT(WOLFSSH* ssh, char* dir, WS_SFTP_FILEATRB* atr)
|
||||
{
|
||||
byte* data;
|
||||
struct WS_SFTP_SETATR_STATE* state = NULL;
|
||||
int dirSz, atrSz, status;
|
||||
int maxSz;
|
||||
word32 reqId;
|
||||
int maxSz, ret = WS_FATAL_ERROR;
|
||||
word32 idx;
|
||||
byte type;
|
||||
|
||||
|
@ -5235,54 +5311,116 @@ int wolfSSH_SFTP_SetSTAT(WOLFSSH* ssh, char* dir, WS_SFTP_FILEATRB* atr)
|
|||
return WS_BAD_ARGUMENT;
|
||||
}
|
||||
|
||||
dirSz = (int)WSTRLEN(dir);
|
||||
atrSz = SFTP_AtributesSz(ssh, atr);
|
||||
data = (byte*)WMALLOC(dirSz + atrSz + WOLFSSH_SFTP_HEADER + UINT32_SZ,
|
||||
ssh->ctx->heap, DYNTYPE_BUFFER);
|
||||
if (data == NULL) {
|
||||
return WS_MEMORY_E;
|
||||
}
|
||||
|
||||
if (SFTP_SetHeader(ssh, ssh->reqId, WOLFSSH_FTP_SETSTAT,
|
||||
dirSz + atrSz + UINT32_SZ, data) != WS_SUCCESS) {
|
||||
WFREE(data, NULL, DYNTYPE_BUFFER);
|
||||
return WS_FATAL_ERROR;
|
||||
}
|
||||
|
||||
idx = WOLFSSH_SFTP_HEADER;
|
||||
c32toa(dirSz, data + idx); idx += UINT32_SZ;
|
||||
WMEMCPY(data + idx, (byte*)dir, dirSz); idx += dirSz;
|
||||
SFTP_SetAttributes(ssh, data + idx, atrSz, atr); idx += atrSz;
|
||||
|
||||
/* send header and type specific data */
|
||||
if (wolfSSH_stream_send(ssh, data, idx) < 0) {
|
||||
WFREE(data, NULL, DYNTYPE_BUFFER);
|
||||
return WS_FATAL_ERROR;
|
||||
}
|
||||
WFREE(data, NULL, DYNTYPE_BUFFER);
|
||||
|
||||
maxSz = SFTP_GetHeader(ssh, &reqId, &type);
|
||||
if (maxSz <= 0) {
|
||||
return WS_FATAL_ERROR;
|
||||
}
|
||||
|
||||
if (type != WOLFSSH_FTP_STATUS) {
|
||||
WLOG(WS_LOG_SFTP, "Unexpected packet type %d", type);
|
||||
return WS_FATAL_ERROR;
|
||||
}
|
||||
else {
|
||||
idx = 0;
|
||||
data = (byte*)WMALLOC(maxSz, ssh->ctx->heap, DYNTYPE_BUFFER);
|
||||
wolfSSH_stream_read(ssh, data, maxSz);
|
||||
status = wolfSSH_SFTP_DoStatus(ssh, reqId, data, &idx, maxSz);
|
||||
WFREE(data, ssh->ctx->heap, DYNTYPE_BUFFER);
|
||||
if (status != WOLFSSH_FTP_OK) {
|
||||
return WS_BAD_FILE_E;
|
||||
state = ssh->setatrState;
|
||||
if (state == NULL) {
|
||||
state = (WS_SFTP_SETATR_STATE*)WMALLOC(sizeof(WS_SFTP_SETATR_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_SETATR_STATE));
|
||||
ssh->setatrState = state;
|
||||
state->state = STATE_SET_ATR_INIT;
|
||||
}
|
||||
(void)maxSz;
|
||||
|
||||
return WS_SUCCESS;
|
||||
|
||||
switch (state->state) {
|
||||
case STATE_SET_ATR_INIT:
|
||||
dirSz = (int)WSTRLEN(dir);
|
||||
atrSz = SFTP_AtributesSz(ssh, atr);
|
||||
state->data = (byte*)WMALLOC(dirSz + atrSz + WOLFSSH_SFTP_HEADER +
|
||||
UINT32_SZ, ssh->ctx->heap, DYNTYPE_BUFFER);
|
||||
if (state->data == NULL) {
|
||||
ret = WS_MEMORY_E;
|
||||
break;
|
||||
}
|
||||
|
||||
if (SFTP_SetHeader(ssh, ssh->reqId, WOLFSSH_FTP_SETSTAT,
|
||||
dirSz + atrSz + UINT32_SZ, state->data) != WS_SUCCESS) {
|
||||
ret = WS_FATAL_ERROR;
|
||||
break;
|
||||
}
|
||||
|
||||
idx = WOLFSSH_SFTP_HEADER;
|
||||
c32toa(dirSz, state->data + idx);
|
||||
idx += UINT32_SZ;
|
||||
WMEMCPY(state->data + idx, (byte*)dir, dirSz);
|
||||
idx += dirSz;
|
||||
SFTP_SetAttributes(ssh, state->data + idx, atrSz, atr);
|
||||
idx += atrSz;
|
||||
|
||||
state->sz = idx;
|
||||
state->state = STATE_SET_ATR_SEND;
|
||||
FALL_THROUGH;
|
||||
/* no break */
|
||||
|
||||
/* send header and type specific data */
|
||||
case STATE_SET_ATR_SEND:
|
||||
if (wolfSSH_stream_send(ssh, state->data, state->sz) < 0) {
|
||||
if (ssh->error != WS_WANT_READ && ssh->error != WS_WANT_WRITE) {
|
||||
ret = WS_FATAL_ERROR;
|
||||
break;
|
||||
}
|
||||
return WS_FATAL_ERROR;
|
||||
}
|
||||
state->state = STATE_SET_ATR_GET;
|
||||
FALL_THROUGH;
|
||||
/* no break */
|
||||
|
||||
|
||||
case STATE_SET_ATR_GET:
|
||||
maxSz = SFTP_GetHeader(ssh, &state->reqId, &type);
|
||||
if (maxSz <= 0) {
|
||||
if (ssh->error != WS_WANT_READ && ssh->error != WS_WANT_WRITE) {
|
||||
ret = WS_FATAL_ERROR;
|
||||
break;
|
||||
}
|
||||
return WS_FATAL_ERROR;
|
||||
}
|
||||
|
||||
if (type != WOLFSSH_FTP_STATUS) {
|
||||
WLOG(WS_LOG_SFTP, "Unexpected packet type %d", type);
|
||||
ret = WS_FATAL_ERROR;
|
||||
break;
|
||||
}
|
||||
XFREE(state->data, ssh->ctx->heap, DYNTYPE_BUFER);
|
||||
state->data = (byte*)WMALLOC(maxSz, ssh->ctx->heap, DYNTYPE_BUFFER);
|
||||
if (state->data == NULL) {
|
||||
ret = WS_MEMORY_E;
|
||||
break;
|
||||
}
|
||||
|
||||
state->sz = maxSz;
|
||||
state->state = STATE_SET_ATR_STATUS;
|
||||
FALL_THROUGH;
|
||||
/* no break */
|
||||
|
||||
|
||||
case STATE_SET_ATR_STATUS:
|
||||
idx = 0;
|
||||
ret = wolfSSH_stream_read(ssh, state->data, state->sz);
|
||||
if (ret < 0) {
|
||||
if (ssh->error != WS_WANT_READ && ssh->error != WS_WANT_WRITE) {
|
||||
ret = WS_FATAL_ERROR;
|
||||
break;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
status = wolfSSH_SFTP_DoStatus(ssh, state->reqId, state->data, &idx,
|
||||
state->sz);
|
||||
ret = WS_SUCCESS;
|
||||
if (status != WOLFSSH_FTP_OK) {
|
||||
ret = WS_BAD_FILE_E;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
WLOG(WS_LOG_SFTP, "Unknown set attribute state");
|
||||
}
|
||||
|
||||
wolfSSH_SFTP_ClearState(ssh, STATE_ID_SETATR);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -46,6 +46,7 @@ static const char* cmds[] = {
|
|||
"rename test-get test-get-2",
|
||||
"rmdir a",
|
||||
"ls",
|
||||
"chmod 600 test-get-2",
|
||||
"rm test-get-2",
|
||||
"exit"
|
||||
};
|
||||
|
|
|
@ -405,6 +405,8 @@ struct WOLFSSH {
|
|||
struct WS_SFTP_MKDIR_STATE* mkdirState;
|
||||
struct WS_SFTP_RM_STATE* rmState;
|
||||
struct WS_SFTP_READDIR_STATE* readDirState;
|
||||
struct WS_SFTP_SETATR_STATE* setatrState;
|
||||
struct WS_SFTP_CHMOD_STATE* chmodState;
|
||||
struct WS_SFTP_LS_STATE* lsState;
|
||||
struct WS_SFTP_SEND_STATE* sendState;
|
||||
struct WS_SFTP_NAME_STATE* nameState;
|
||||
|
|
Loading…
Reference in New Issue