diff --git a/examples/sftpclient/sftpclient.c b/examples/sftpclient/sftpclient.c index 800b0ea85..576f1c894 100644 --- a/examples/sftpclient/sftpclient.c +++ b/examples/sftpclient/sftpclient.c @@ -358,6 +358,8 @@ static void ShowCommands(void) printf("\tcd change directory\n"); printf("\tchmod change mode\n"); printf("\tget pulls file(s) from server\n"); + printf("\tlcd change local directory\n"); + printf("\tlls list local directory\n"); printf("\tls list current directory\n"); printf("\tmkdir creates new directory on server\n"); printf("\tput push file(s) to server\n"); @@ -731,6 +733,30 @@ static int doCmds(func_args* args) continue; } + /* lcd must be checked before cd so that WSTRNSTR + * does not match "cd" inside "lcd" */ + #ifndef WOLFSSH_FATFS /* WCHDIR not yet defined for FatFS */ + if ((pt = WSTRNSTR(msg, "lcd", MAX_CMD_SZ)) != NULL) { + int sz; + + pt += sizeof("lcd"); + sz = (int)WSTRLEN(pt); + + if (sz > 0 && pt[sz - 1] == '\n') { + pt[sz - 1] = '\0'; + } + + if (WCHDIR(ssh->fs, pt) != 0) { + if (SFTP_FPUTS(args, + "Error changing local directory\n") < 0) { + err_msg("fputs error"); + return -1; + } + } + continue; + } + #endif /* !WOLFSSH_FATFS */ + if ((pt = WSTRNSTR(msg, "cd", MAX_CMD_SZ)) != NULL) { WS_SFTP_FILEATRB atrb; int sz; @@ -1071,6 +1097,114 @@ static int doCmds(func_args* args) } + #if !defined(NO_WOLFSSH_DIR) && !defined(WOLFSSH_FATFS) + /* lls must be checked before ls so that WSTRNSTR + * does not match "ls" inside "lls" */ + if (WSTRNSTR(msg, "lls", MAX_CMD_SZ) != NULL) { + char cwd[WOLFSSH_MAX_FILENAME]; + int llsErr = 0; + + #ifdef WOLFSSH_ZEPHYR + WSTRNCPY(cwd, CONFIG_WOLFSSH_SFTP_DEFAULT_DIR, + sizeof(cwd)); + #else + if (WGETCWD(ssh->fs, cwd, sizeof(cwd)) == NULL) { + if (SFTP_FPUTS(args, + "Error getting local directory\n") < 0) { + err_msg("fputs error"); + return -1; + } + continue; + } + #endif + + #ifdef USE_WINDOWS_API + { + WDIR findHandle; + char name[MAX_PATH]; + char fileName[MAX_PATH]; + + WSTRNCPY(name, cwd, MAX_PATH); + WSTRNCAT(name, "\\*", MAX_PATH); + findHandle = (HANDLE)WS_FindFirstFileA(name, + fileName, sizeof(fileName), NULL, NULL); + if (findHandle == INVALID_HANDLE_VALUE) { + if (SFTP_FPUTS(args, + "Error opening local directory\n") < 0) { + err_msg("fputs error"); + return -1; + } + continue; + } + + do { + if (SFTP_FPUTS(args, fileName) < 0 || + SFTP_FPUTS(args, "\n") < 0) { + err_msg("fputs error"); + llsErr = 1; + break; + } + } while (WS_FindNextFileA(findHandle, + fileName, sizeof(fileName))); + FindClose(findHandle); + } + #elif defined(WOLFSSH_ZEPHYR) + { + WDIR dir; + struct fs_dirent dp; + + if (WOPENDIR(ssh->fs, NULL, &dir, cwd) != 0) { + if (SFTP_FPUTS(args, + "Error opening local directory\n") < 0) { + err_msg("fputs error"); + return -1; + } + continue; + } + + while (fs_readdir(&dir, &dp) == 0 && + dp.name[0] != '\0') { + if (SFTP_FPUTS(args, dp.name) < 0 || + SFTP_FPUTS(args, "\n") < 0) { + err_msg("fputs error"); + llsErr = 1; + break; + } + } + WCLOSEDIR(ssh->fs, &dir); + } + #else + { + WDIR dir; + struct dirent* dp; + + if (WOPENDIR(ssh->fs, NULL, &dir, cwd) != 0) { + if (SFTP_FPUTS(args, + "Error opening local directory\n") < 0) { + err_msg("fputs error"); + return -1; + } + continue; + } + + while ((dp = WREADDIR(ssh->fs, &dir)) != NULL) { + if (SFTP_FPUTS(args, dp->d_name) < 0 || + SFTP_FPUTS(args, "\n") < 0) { + err_msg("fputs error"); + llsErr = 1; + break; + } + } + WCLOSEDIR(ssh->fs, &dir); + } + #endif + if (llsErr) { + return -1; + } + continue; + } + #endif /* !NO_WOLFSSH_DIR && !WOLFSSH_FATFS */ + if (WSTRNSTR(msg, "ls", MAX_CMD_SZ) != NULL) { WS_SFTPNAME* tmp; WS_SFTPNAME* current; @@ -1503,8 +1637,9 @@ THREAD_RETURN WOLFSSH_THREAD sftpclient_test(void* args) int err; ret = wolfSSH_shutdown(ssh); - /* peer hung up, stop trying to shutdown */ - if (ret == WS_SOCKET_ERROR_E) { + /* peer hung up or channel already closed, stop trying */ + if (ret == WS_SOCKET_ERROR_E || ret == WS_ERROR || + ret == WS_CHANNEL_CLOSED) { ret = 0; } @@ -1525,7 +1660,7 @@ THREAD_RETURN WOLFSSH_THREAD sftpclient_test(void* args) } /* peer hung up, stop shutdown */ - if (ret == WS_SOCKET_ERROR_E) { + if (ret == WS_SOCKET_ERROR_E || ret == WS_ERROR) { ret = 0; break; } diff --git a/tests/sftp.c b/tests/sftp.c index 0066c1776..781edb78c 100644 --- a/tests/sftp.c +++ b/tests/sftp.c @@ -136,6 +136,68 @@ static int checkLsSize(void) sizeof(inBuf)) == NULL) ? 1 : 0; } +static int checkCdNonexistent(void) +{ + if (WSTRNSTR(inBuf, "Error changing directory", + sizeof(inBuf)) == NULL) { + fprintf(stderr, + "cd: expected error not found in %s\n", inBuf); + return 1; + } + return 0; +} + +#if !defined(NO_WOLFSSH_DIR) && !defined(WOLFSSH_FATFS) +static int checkLlsHasConfigureAc(void) +{ + if (WSTRNSTR(inBuf, "configure.ac", + sizeof(inBuf)) == NULL) { + fprintf(stderr, + "lls: configure.ac not found in %s\n", inBuf); + return 1; + } + return 0; +} +#endif /* !NO_WOLFSSH_DIR && !WOLFSSH_FATFS */ + +static int checkLcdNonexistent(void) +{ + if (WSTRNSTR(inBuf, "Error changing local directory", + sizeof(inBuf)) == NULL) { + fprintf(stderr, + "lcd: expected error not found in %s\n", inBuf); + return 1; + } + return 0; +} + +#if !defined(NO_WOLFSSH_DIR) && !defined(WOLFSSH_FATFS) \ + && !defined(WOLFSSH_ZEPHYR) +/* after lcd into keys/, lls should show key files */ +static int checkLlsInKeys(void) +{ + if (WSTRNSTR(inBuf, ".pem", sizeof(inBuf)) == NULL && + WSTRNSTR(inBuf, ".der", sizeof(inBuf)) == NULL) { + fprintf(stderr, + "lls: expected key files not found in %s\n", inBuf); + return 1; + } + return 0; +} + +/* after lcd back to .., lls should show project root files */ +static int checkLlsBackToRoot(void) +{ + if (WSTRNSTR(inBuf, "configure.ac", + sizeof(inBuf)) == NULL) { + fprintf(stderr, + "lls: configure.ac not found after lcd ..\n"); + return 1; + } + return 0; +} +#endif /* !NO_WOLFSSH_DIR && !WOLFSSH_FATFS && !WOLFSSH_ZEPHYR */ + static const SftpTestCmd cmds[] = { /* If a prior run was interrupted, files and directories * created during the test may still exist in the working @@ -176,6 +238,21 @@ static const SftpTestCmd cmds[] = { { "chmod 600 test-get-2", NULL }, { "rm test-get-2", NULL }, { "ls -s", checkLsSize }, + { "cd /nonexistent_path_xyz", checkCdNonexistent }, +#if !defined(NO_WOLFSSH_DIR) && !defined(WOLFSSH_FATFS) + { "lls", checkLlsHasConfigureAc }, +#endif + { "lcd /nonexistent_path_xyz", checkLcdNonexistent }, +#if !defined(NO_WOLFSSH_DIR) && !defined(WOLFSSH_FATFS) \ + && !defined(WOLFSSH_ZEPHYR) + /* lcd into a subdirectory, verify with lls, then return. + * Skipped on Zephyr: lls always lists the default dir + * (no WGETCWD) and the keys/ tree is not on the RAM fs. */ + { "lcd keys", NULL }, + { "lls", checkLlsInKeys }, + { "lcd ..", NULL }, + { "lls", checkLlsBackToRoot }, +#endif /* empty arg tests: must not underflow on pt[sz-1] */ { "mkdir", NULL }, { "cd", NULL },