mirror of https://github.com/wolfSSL/wolfssh.git
Merge pull request #436 from ejohnstown/sftp-list
commit
6f57587249
|
@ -2030,6 +2030,57 @@ static int wsUserAuth(byte authType,
|
|||
}
|
||||
|
||||
|
||||
#ifdef WOLFSSH_SFTP
|
||||
/*
|
||||
* Sets the WOLFSSH object's default SFTP path to the value provided by
|
||||
* defaultSftpPath, or uses the current working directory from where the
|
||||
* echoserver is run. The new default path is cleaned up with the real
|
||||
* path function.
|
||||
*
|
||||
* @param ssh WOLFSSH object to update
|
||||
* @param defaultSftpPath command line provided default SFTP path
|
||||
* @return 0 for success or error code
|
||||
*/
|
||||
static int SetDefaultSftpPath(WOLFSSH* ssh, const char* defaultSftpPath)
|
||||
{
|
||||
char path[WOLFSSH_MAX_FILENAME];
|
||||
char realPath[WOLFSSH_MAX_FILENAME];
|
||||
int ret = 0;
|
||||
|
||||
if (defaultSftpPath == NULL) {
|
||||
#ifdef USE_WINDOWS_API
|
||||
if (GetCurrentDirectoryA(sizeof(path)-1, path) == 0) {
|
||||
ret = WS_INVALID_PATH_E;
|
||||
}
|
||||
#else
|
||||
if (getcwd(path, sizeof(path)-1) == NULL) {
|
||||
ret = WS_INVALID_PATH_E;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
else {
|
||||
if (WSTRLEN(defaultSftpPath) >= sizeof(path)) {
|
||||
ret = WS_INVALID_PATH_E;
|
||||
}
|
||||
else {
|
||||
WSTRNCPY(path, defaultSftpPath, sizeof(path));
|
||||
}
|
||||
}
|
||||
|
||||
if (ret == 0) {
|
||||
path[sizeof(path) - 1] = 0;
|
||||
ret = wolfSSH_RealPath(NULL, path, realPath, sizeof(realPath));
|
||||
}
|
||||
|
||||
if (ret == WS_SUCCESS) {
|
||||
ret = wolfSSH_SFTP_SetDefaultPath(ssh, realPath);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
static void ShowUsage(void)
|
||||
{
|
||||
printf("echoserver %s\n", LIBWOLFSSH_VERSION_STRING);
|
||||
|
@ -2451,12 +2502,9 @@ THREAD_RETURN WOLFSSH_THREAD echoserver_test(void* args)
|
|||
}
|
||||
|
||||
#ifdef WOLFSSH_SFTP
|
||||
if (defaultSftpPath) {
|
||||
if (wolfSSH_SFTP_SetDefaultPath(ssh, defaultSftpPath)
|
||||
!= WS_SUCCESS) {
|
||||
fprintf(stderr, "Couldn't store default sftp path.\n");
|
||||
WEXIT(EXIT_FAILURE);
|
||||
}
|
||||
if (SetDefaultSftpPath(ssh, defaultSftpPath) != 0) {
|
||||
fprintf(stderr, "Couldn't store default sftp path.\n");
|
||||
WEXIT(EXIT_FAILURE);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
|
34
src/port.c
34
src/port.c
|
@ -166,6 +166,25 @@ int wfopen(WFILE** f, const char* filename, const char* mode)
|
|||
|
||||
#if defined(USE_WINDOWS_API) && (defined(WOLFSSH_SFTP) || defined(WOLFSSH_SCP))
|
||||
|
||||
/*
|
||||
* SFTP paths all start with a leading root "/". Most Windows file routines
|
||||
* expect a drive letter when dealing with an absolute path. If the provided
|
||||
* path, f, is of the form "/C:...", adjust the pointer f to point to the "C",
|
||||
* and decrement the file path size, fSz, by one.
|
||||
*
|
||||
* @param f pointer to a file name
|
||||
* @param fSz size of f in bytes
|
||||
* @return pointer to somewhere in f
|
||||
*/
|
||||
static const char* TrimFileName(const char* f, size_t* fSz)
|
||||
{
|
||||
if (f != NULL && fSz != NULL && *fSz >= 3 && f[0] == '/' && f[2] == ':') {
|
||||
f++;
|
||||
*fSz--;
|
||||
}
|
||||
return f;
|
||||
}
|
||||
|
||||
void* WS_CreateFileA(const char* fileName, unsigned long desiredAccess,
|
||||
unsigned long shareMode, unsigned long creationDisposition,
|
||||
unsigned long flags, void* heap)
|
||||
|
@ -178,6 +197,8 @@ void* WS_CreateFileA(const char* fileName, unsigned long desiredAccess,
|
|||
errno_t error;
|
||||
|
||||
fileNameSz = WSTRLEN(fileName);
|
||||
fileName = TrimFileName(fileName, &fileNameSz);
|
||||
|
||||
error = mbstowcs_s(&unicodeFileNameSz, NULL, 0, fileName, 0);
|
||||
if (error)
|
||||
return INVALID_HANDLE_VALUE;
|
||||
|
@ -211,6 +232,8 @@ void* WS_FindFirstFileA(const char* fileName,
|
|||
errno_t error;
|
||||
|
||||
fileNameSz = WSTRLEN(fileName);
|
||||
fileName = TrimFileName(fileName, &fileNameSz);
|
||||
|
||||
error = mbstowcs_s(&unicodeFileNameSz, NULL, 0, fileName, 0);
|
||||
if (error)
|
||||
return INVALID_HANDLE_VALUE;
|
||||
|
@ -268,6 +291,8 @@ int WS_GetFileAttributesExA(const char* fileName, void* fileInfo, void* heap)
|
|||
errno_t error;
|
||||
|
||||
fileNameSz = WSTRLEN(fileName);
|
||||
fileName = TrimFileName(fileName, &fileNameSz);
|
||||
|
||||
error = mbstowcs_s(&unicodeFileNameSz, NULL, 0, fileName, 0);
|
||||
if (error != 0)
|
||||
return 0;
|
||||
|
@ -301,6 +326,8 @@ int WS_RemoveDirectoryA(const char* dirName, void* heap)
|
|||
errno_t error;
|
||||
|
||||
dirNameSz = WSTRLEN(dirName);
|
||||
dirName = TrimFileName(dirName, &dirNameSz);
|
||||
|
||||
error = mbstowcs_s(&unicodeDirNameSz, NULL, 0, dirName, 0);
|
||||
if (error != 0)
|
||||
return 0;
|
||||
|
@ -333,6 +360,8 @@ int WS_CreateDirectoryA(const char* dirName, void* heap)
|
|||
errno_t error;
|
||||
|
||||
dirNameSz = WSTRLEN(dirName);
|
||||
dirName = TrimFileName(dirName, &dirNameSz);
|
||||
|
||||
error = mbstowcs_s(&unicodeDirNameSz, NULL, 0, dirName, 0);
|
||||
if (error != 0)
|
||||
return 0;
|
||||
|
@ -368,6 +397,7 @@ int WS_MoveFileA(const char* oldName, const char* newName, void* heap)
|
|||
errno_t error;
|
||||
|
||||
oldNameSz = WSTRLEN(oldName);
|
||||
oldName = TrimFileName(oldName, &oldNameSz);
|
||||
|
||||
error = mbstowcs_s(&unicodeOldNameSz, NULL, 0, oldName, 0);
|
||||
if (error != 0)
|
||||
|
@ -382,6 +412,8 @@ int WS_MoveFileA(const char* oldName, const char* newName, void* heap)
|
|||
oldName, oldNameSz);
|
||||
|
||||
newNameSz = WSTRLEN(newName);
|
||||
newName = TrimFileName(newName, &newNameSz);
|
||||
|
||||
error = mbstowcs_s(&unicodeNewNameSz, NULL, 0, newName, 0);
|
||||
if (error != 0)
|
||||
return 0;
|
||||
|
@ -417,6 +449,8 @@ int WS_DeleteFileA(const char* fileName, void* heap)
|
|||
errno_t error;
|
||||
|
||||
fileNameSz = WSTRLEN(fileName);
|
||||
fileName = TrimFileName(fileName, &fileNameSz);
|
||||
|
||||
error = mbstowcs_s(&unicodeFileNameSz, NULL, 0, fileName, 0);
|
||||
if (error != 0)
|
||||
return 0;
|
||||
|
|
49
src/ssh.c
49
src/ssh.c
|
@ -2274,9 +2274,14 @@ int wolfSSH_ChannelGetEof(WOLFSSH_CHANNEL* channel)
|
|||
|
||||
#if (defined(WOLFSSH_SFTP) || defined(WOLFSSH_SCP)) && \
|
||||
!defined(NO_WOLFSSH_SERVER)
|
||||
|
||||
#define DELIM "/\\"
|
||||
#define IS_DELIM(x) ((x) == '/' || (x) == '\\')
|
||||
#define IS_WINPATH(x,y) ((x) > 1 && (y)[1] == ':')
|
||||
|
||||
/*
|
||||
* Paths starting with a slash are absolute, rooted at root. Any path that
|
||||
* doesn't have a starting slash is assumed to be relative to the current
|
||||
* Paths starting with a slash are absolute, rooted at "/". Any path that
|
||||
* doesn't have a starting slash is assumed to be relative to the default
|
||||
* path. If the path is empty, return the default path.
|
||||
*
|
||||
* The path "/." is stripped out. The path "/.." strips out the previous
|
||||
|
@ -2284,7 +2289,7 @@ int wolfSSH_ChannelGetEof(WOLFSSH_CHANNEL* channel)
|
|||
*
|
||||
* Example: "/home/fred/frob/frizz/../../../barney/bar/baz/./././../.."
|
||||
* will return "/home/barney". "/../.." will return "/". "." will return
|
||||
* currentPath.
|
||||
* the default path.
|
||||
*
|
||||
* Note, this function does not care about OS and filesystem issues. The
|
||||
* SFTP protocol describes how paths are handled in SFTP. Specialized
|
||||
|
@ -2292,39 +2297,41 @@ int wolfSSH_ChannelGetEof(WOLFSSH_CHANNEL* channel)
|
|||
* are further massaged there. For example, the C: drive is treated as
|
||||
* the path "/C:", and is a directory like any other.
|
||||
*
|
||||
* @param currentPath RealPath of the current working directory
|
||||
* @param defaultPath RealPath of the default directory, usually user's
|
||||
* @param in requested new path
|
||||
* @param out output of real path cleanup
|
||||
* @param outSz size in bytes of buffer 'out'
|
||||
* @return WS_SUCCESS, WS_BAD_ARGUMENT, or WS_INVALID_PATH_E
|
||||
*/
|
||||
int wolfSSH_RealPath(const char* currentPath, const char* defaultPath,
|
||||
char* in, char* out, word32 outSz)
|
||||
int wolfSSH_RealPath(const char* defaultPath, char* in,
|
||||
char* out, word32 outSz)
|
||||
{
|
||||
char* tail = NULL;
|
||||
char* seg;
|
||||
word32 inSz, segSz, curSz;
|
||||
|
||||
if (currentPath == NULL || defaultPath == NULL ||
|
||||
in == NULL || out == NULL || outSz == 0)
|
||||
if (in == NULL || out == NULL || outSz == 0) {
|
||||
return WS_BAD_ARGUMENT;
|
||||
}
|
||||
|
||||
WMEMSET(out, 0, outSz);
|
||||
inSz = (word32)WSTRLEN(in);
|
||||
if (inSz == 0) {
|
||||
WSTRNCPY(out, defaultPath, outSz);
|
||||
out[0] = '/';
|
||||
curSz = 1;
|
||||
if (inSz == 0 || (!IS_DELIM(in[0]) && !IS_WINPATH(inSz, in))) {
|
||||
if (defaultPath != NULL) {
|
||||
curSz = (word32)WSTRLEN(defaultPath);
|
||||
if (curSz >= outSz) {
|
||||
return WS_INVALID_PATH_E;
|
||||
}
|
||||
WSTRNCPY(out, defaultPath, outSz);
|
||||
}
|
||||
}
|
||||
else if (in[0] == '/') {
|
||||
out[0] = '/';
|
||||
}
|
||||
else {
|
||||
WSTRNCPY(out, currentPath, outSz);
|
||||
}
|
||||
out[outSz - 1] = 0;
|
||||
curSz = (word32)WSTRLEN(out);
|
||||
out[curSz] = 0;
|
||||
|
||||
for (seg = WSTRTOK(in, "/", &tail); seg; seg = WSTRTOK(NULL, "/", &tail)) {
|
||||
for (seg = WSTRTOK(in, DELIM, &tail);
|
||||
seg;
|
||||
seg = WSTRTOK(NULL, DELIM, &tail)) {
|
||||
segSz = (word32)WSTRLEN(seg);
|
||||
|
||||
/* Try to match "." */
|
||||
|
@ -2349,6 +2356,10 @@ int wolfSSH_RealPath(const char* currentPath, const char* defaultPath,
|
|||
}
|
||||
/* Everything else is copied */
|
||||
else {
|
||||
if (curSz >= outSz - segSz) {
|
||||
return WS_INVALID_PATH_E;
|
||||
}
|
||||
|
||||
if (curSz != 1) {
|
||||
WSTRNCAT(out, "/", outSz - curSz);
|
||||
curSz++;
|
||||
|
|
595
src/wolfsftp.c
595
src/wolfsftp.c
File diff suppressed because it is too large
Load Diff
120
tests/api.c
120
tests/api.c
|
@ -1021,7 +1021,7 @@ struct RealPathTestCase {
|
|||
const char* exp;
|
||||
};
|
||||
|
||||
struct RealPathTestCase realPathTestCases[] = {
|
||||
struct RealPathTestCase realPathDefault[] = {
|
||||
{ ".", "/C:/Users/fred" },
|
||||
{ "", "/C:/Users/fred" },
|
||||
{ "/C:/Users/fred/..", "/C:/Users" },
|
||||
|
@ -1042,33 +1042,106 @@ struct RealPathTestCase realPathTestCases[] = {
|
|||
{ "/home/C:/ok", "/home/C:/ok" },
|
||||
{ "/home/fred/frob/frizz/../../../barney/bar/baz/./././../..",
|
||||
"/home/barney" },
|
||||
{ "/home/fred/sample.", "/home/fred/sample." },
|
||||
{ "/home/fred/sample.jpg", "/home/fred/sample.jpg" },
|
||||
{ "/home/fred/sample./other", "/home/fred/sample./other" },
|
||||
{ "/home/fred/sample.dir/other", "/home/fred/sample.dir/other" },
|
||||
{ "./sample.", "/C:/Users/fred/sample." },
|
||||
{ "./sample.jpg", "/C:/Users/fred/sample.jpg" },
|
||||
{ "./sample./other", "/C:/Users/fred/sample./other" },
|
||||
{ "./sample.dir/other", "/C:/Users/fred/sample.dir/other" },
|
||||
{ "\\C:\\Users\\fred\\Documents\\junk.txt",
|
||||
"/C:/Users/fred/Documents/junk.txt" },
|
||||
{ "C:\\Users\\fred\\Documents\\junk.txt",
|
||||
"/C:/Users/fred/Documents/junk.txt" },
|
||||
{ "/C:\\Users\\fred/Documents\\junk.txt",
|
||||
"/C:/Users/fred/Documents/junk.txt" },
|
||||
};
|
||||
const char* defaultPath = "/C:/Users/fred";
|
||||
|
||||
struct RealPathTestCase realPathNull[] = {
|
||||
{ ".", "/" },
|
||||
{ "", "/" },
|
||||
{ "..", "/" },
|
||||
{ "../barney", "/barney" },
|
||||
};
|
||||
|
||||
static void DoRealPathTestCase(const char* path, struct RealPathTestCase* tc)
|
||||
{
|
||||
char testPath[128];
|
||||
char checkPath[128];
|
||||
int err;
|
||||
|
||||
WSTRNCPY(testPath, tc->in, sizeof(testPath) - 1);
|
||||
testPath[sizeof(testPath) - 1] = 0;
|
||||
WMEMSET(checkPath, 0, sizeof checkPath);
|
||||
err = wolfSSH_RealPath(path, testPath,
|
||||
checkPath, sizeof checkPath);
|
||||
if (err || WSTRCMP(tc->exp, checkPath) != 0) {
|
||||
fprintf(stderr, "RealPath failure (%d)\n"
|
||||
" defaultPath: %s\n"
|
||||
" input: %s\n"
|
||||
" expected: %s\n"
|
||||
" output: %s\n", err,
|
||||
path, tc->in, tc->exp, checkPath);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
struct RealPathTestFailCase {
|
||||
const char* defaultPath;
|
||||
const char* in;
|
||||
word32 checkPathSz;
|
||||
int expErr;
|
||||
};
|
||||
struct RealPathTestFailCase realPathFail[] = {
|
||||
/* Output size less than default path length. */
|
||||
{ "12345678", "12345678", 4, WS_INVALID_PATH_E },
|
||||
/* Output size equal to default path length. */
|
||||
{ "12345678", "12345678", 8, WS_INVALID_PATH_E },
|
||||
/* Copy segment will not fit in output. */
|
||||
{ "1234567", "12345678", 8, WS_INVALID_PATH_E },
|
||||
};
|
||||
|
||||
static void DoRealPathTestFailCase(struct RealPathTestFailCase* tc)
|
||||
{
|
||||
char testPath[128];
|
||||
char checkPath[128];
|
||||
int err;
|
||||
|
||||
WSTRNCPY(testPath, tc->in, sizeof(testPath) - 1);
|
||||
testPath[sizeof(testPath) - 1] = 0;
|
||||
WMEMSET(checkPath, 0, sizeof checkPath);
|
||||
err = wolfSSH_RealPath(tc->defaultPath, testPath,
|
||||
checkPath, tc->checkPathSz);
|
||||
if (err != tc->expErr) {
|
||||
fprintf(stderr, "RealPath fail check failure (%d)\n"
|
||||
" defaultPath: %s\n"
|
||||
" input: %s\n"
|
||||
" checkPathSz: %u\n"
|
||||
" expected: %d\n", err,
|
||||
tc->defaultPath, tc->in, tc->checkPathSz, tc->expErr);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void test_wolfSSH_RealPath(void)
|
||||
{
|
||||
struct RealPathTestCase* tc;
|
||||
char testPath[128];
|
||||
char checkPath[128];
|
||||
word32 testCount =
|
||||
(sizeof realPathTestCases)/(sizeof(struct RealPathTestCase));
|
||||
word32 testCount;
|
||||
word32 i;
|
||||
int err;
|
||||
|
||||
for (i = 0, tc = realPathTestCases; i < testCount; i++, tc++) {
|
||||
WSTRNCPY(testPath, tc->in, sizeof(testPath) - 1);
|
||||
testPath[sizeof(testPath) - 1] = 0;
|
||||
WMEMSET(checkPath, 0, sizeof checkPath);
|
||||
err = wolfSSH_RealPath(defaultPath, defaultPath, testPath,
|
||||
checkPath, sizeof checkPath);
|
||||
if (err || WSTRCMP(tc->exp, checkPath) != 0) {
|
||||
printf("RealPath failure (case %u: %d)\n"
|
||||
" defaultPath: %s\n"
|
||||
" input: %s\n"
|
||||
" expected: %s\n"
|
||||
" output: %s\n", i, err,
|
||||
defaultPath, tc->in, tc->exp, checkPath);
|
||||
}
|
||||
testCount = (sizeof realPathDefault)/(sizeof(struct RealPathTestCase));
|
||||
for (i = 0; i < testCount; i++) {
|
||||
DoRealPathTestCase("/C:/Users/fred", realPathDefault + i);
|
||||
}
|
||||
|
||||
testCount = (sizeof realPathNull)/(sizeof(struct RealPathTestCase));
|
||||
for (i = 0; i < testCount; i++) {
|
||||
DoRealPathTestCase(NULL, realPathNull + i);
|
||||
}
|
||||
|
||||
testCount = (sizeof realPathFail)/(sizeof(struct RealPathTestFailCase));
|
||||
for (i = 0; i < testCount; i++) {
|
||||
DoRealPathTestFailCase(realPathFail + i);
|
||||
}
|
||||
}
|
||||
#else
|
||||
|
@ -1088,7 +1161,6 @@ int main(void)
|
|||
test_wolfSSH_SetUsername();
|
||||
test_wolfSSH_ConvertConsole();
|
||||
test_wolfSSH_CTX_UsePrivateKey_buffer();
|
||||
test_wolfSSH_RealPath();
|
||||
test_wolfSSH_CTX_UseCert_buffer();
|
||||
test_wolfSSH_CertMan();
|
||||
|
||||
|
@ -1098,6 +1170,8 @@ int main(void)
|
|||
/* SFTP tests */
|
||||
test_wolfSSH_SFTP_SendReadPacket();
|
||||
|
||||
/* Either SCP or SFTP */
|
||||
test_wolfSSH_RealPath();
|
||||
|
||||
AssertIntEQ(wolfSSH_Cleanup(), WS_SUCCESS);
|
||||
|
||||
|
|
|
@ -540,7 +540,11 @@ struct WS_SFTP_GET_HANDLE_STATE;
|
|||
struct WS_SFTP_PUT_STATE;
|
||||
struct WS_SFTP_RENAME_STATE;
|
||||
|
||||
#ifdef USE_WINDOWS_API
|
||||
#define MAX_DRIVE_LETTER 26
|
||||
#endif /* USE_WINDOWS_API */
|
||||
#endif /* WOLFSSH_SFTP */
|
||||
|
||||
#ifdef USE_WINDOWS_API
|
||||
#ifndef WOLFSSL_MAX_ESCBUF
|
||||
#define WOLFSSL_MAX_ESCBUF 19
|
||||
|
@ -717,6 +721,11 @@ struct WOLFSSH {
|
|||
struct WS_SFTP_SEND_WRITE_STATE* sendWriteState;
|
||||
struct WS_SFTP_GET_HANDLE_STATE* getHandleState;
|
||||
struct WS_SFTP_RENAME_STATE* renameState;
|
||||
#ifdef USE_WINDOWS_API
|
||||
char driveList[MAX_DRIVE_LETTER];
|
||||
word16 driveListCount;
|
||||
word16 driveIdx;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef WOLFSSH_AGENT
|
||||
|
|
|
@ -339,8 +339,8 @@ enum WS_DisconnectReasonCodes {
|
|||
};
|
||||
|
||||
|
||||
WOLFSSH_API int wolfSSH_RealPath(const char* currentPath,
|
||||
const char* defaultPath, char* in, char* out, word32 outSz);
|
||||
WOLFSSH_API int wolfSSH_RealPath(const char* defaultPath, char* in,
|
||||
char* out, word32 outSz);
|
||||
|
||||
|
||||
WOLFSSH_API void wolfSSH_ShowSizes(void);
|
||||
|
|
Loading…
Reference in New Issue