diff --git a/src/internal.c b/src/internal.c index b225dc8f..b6ac358d 100644 --- a/src/internal.c +++ b/src/internal.c @@ -7093,6 +7093,7 @@ void clean_path(char* path) #ifdef WOLFSSL_NUCLEUS sz = WSTRLEN(path); + if (path[sz - 1] == ':') { path[sz] = WS_DELIM; path[sz + 1] = '\0'; @@ -7115,6 +7116,14 @@ void clean_path(char* path) } } } + + /* remove leading '/' for nucleus. Preserve case of single "/" */ + sz = WSTRLEN(path); + while (sz > 2 && path[0] == WS_DELIM) { + sz--; + WMEMMOVE(path, path + 1, sz); + path[sz] = '\0'; + } #endif /* remove trailing delimiter */ if (sz > 3 && path[sz - 1] == WS_DELIM) { diff --git a/src/wolfsftp.c b/src/wolfsftp.c index 5793e128..6b5a634e 100644 --- a/src/wolfsftp.c +++ b/src/wolfsftp.c @@ -945,11 +945,39 @@ static int wolfSSH_SFTPNAME_readdir(WOLFSSH* ssh, WDIR* dir, WS_SFTPNAME* out, char* dirName) { int sz; + byte special = 0; + int ret = WS_SUCCESS; if (dir == NULL || ssh == NULL || out == NULL) { return WS_BAD_ARGUMENT; } + /* special case of getting drives at "/" */ + if (WSTRLEN(dirName) < 3 && dirName[0] == WS_DELIM) { + unsigned int idx = dir->fsize; /* index of current drive */ + MNT_LIST_S* list = NU_NULL; + + if (NU_List_Mount(&list) != NU_SUCCESS) { + return WS_FATAL_ERROR; + } + + for (; idx > 0 && list != NU_NULL; idx--) list = list->next; + if (list == NULL) { + return WS_FATAL_ERROR; + } + + if (list->next == NULL) { + ret = WS_NEXT_ERROR; + } + + dir->lfname[0] = list->mnt_name[0]; + dir->lfname[1] = ':'; + dir->lfname[2] = '/'; + dir->lfname[3] = '\0'; + dir->fsize++; + special = 1; + } + /* use long name on Nucleus because sfname has only the file name and in all * caps */ sz = (int)WSTRLEN(dir->lfname); @@ -981,13 +1009,16 @@ static int wolfSSH_SFTPNAME_readdir(WOLFSSH* ssh, WDIR* dir, WS_SFTPNAME* out, return WS_MEMORY_E; } buf[0] = '\0'; - WSTRNCAT(buf, dirName, bufSz); - tmpSz = WSTRLEN(buf); + if (!special) { /* do not add dir name in special case */ + WSTRNCAT(buf, dirName, bufSz); + tmpSz = WSTRLEN(buf); + + /* add delimiter between path and file/dir name */ + if (tmpSz + 1 < bufSz) { + buf[tmpSz] = WS_DELIM; + buf[tmpSz+1] = '\0'; + } - /* add delimiter between path and file/dir name */ - if (tmpSz + 1 < bufSz) { - buf[tmpSz] = WS_DELIM; - buf[tmpSz+1] = '\0'; } WSTRNCAT(buf, out->fName, bufSz); @@ -998,11 +1029,11 @@ static int wolfSSH_SFTPNAME_readdir(WOLFSSH* ssh, WDIR* dir, WS_SFTPNAME* out, WFREE(buf, out->heap, DYNTYPE_SFTP); } - if ((WREADDIR(dir)) == NULL) { - return WS_NEXT_ERROR; + if (!special && (WREADDIR(dir)) == NULL) { + ret = WS_NEXT_ERROR; } - return WS_SUCCESS; + return ret; } #else /* helper function that gets file information from reading directory @@ -1836,6 +1867,13 @@ int SFTP_GetAttributes(const char* fileName, WS_SFTP_FILEATRB* atr, byte link) return WS_SUCCESS; } + /* handle case of "/" */ + if (sz < 3 && fileName[0] == WS_DELIM && ret == NUF_NOFILE) { + atr->flags |= WOLFSSH_FILEATRB_PERM; + atr->per |= 0x4000; + return WS_SUCCESS; + } + if (ret != NU_SUCCESS) { return WS_BAD_FILE_E; } diff --git a/wolfssh/port.h b/wolfssh/port.h index 7205c750..4800eacc 100644 --- a/wolfssh/port.h +++ b/wolfssh/port.h @@ -206,7 +206,71 @@ extern "C" { #define WSTAT(p,b) NU_Get_First((b),(p)) #define WLSTAT(p,b) NU_Get_First((b),(p)) #define WREMOVE(d) NU_Delete((d)) - #define WRENAME(o,n) NU_Rename((o),(n)) + +#ifndef WS_MAX_RENAME_BUF +#define WS_MAX_RENAME_BUF 256 +#endif + + static inline int wRename(char* o, char* n) + { + int ret; + + if (o == NULL || n == NULL) { + return NUF_BADPARM; + } + + ret = NU_Rename(o, n); + + /* try to handle case of from one drive to another */ + if (ret == NUF_BADPARM && o[0] != n[0]) { + WFILE* fOld; + WFILE* fNew; + unsigned char buf[WS_MAX_RENAME_BUF]; + + if ((ret = WFOPEN(&fOld, o, "rb")) != 0) { + return ret; + } + + if ((ret = WFOPEN(&fNew, n, "rwb")) != 0) { + WFCLOSE(fOld); + return ret; + } + + /* read from the file in chunks and write chunks to new file */ + do { + ret = WFREAD(buf, 1, WS_MAX_RENAME_BUF, fOld); + if (ret > 0) { + if ((WFWRITE(buf, 1, ret, fNew)) != ret) { + WFCLOSE(fOld); + WFCLOSE(fNew); + WREMOVE(n); + return NUF_BADPARM; + } + } + } while (ret > 0); + + if (WFTELL(fOld) == WFSEEK(fOld, 0, WSEEK_END)) { + /* wrote everything from file */ + WFCLOSE(fOld); + WREMOVE(o); + WFCLOSE(fNew); + } + else { + /* unable to write everything to file */ + WFCLOSE(fNew); + WREMOVE(n); + WFCLOSE(fOld); + return NUF_BADPARM; + } + + return 0; + } + + /* not special case so just return value from NU_Rename */ + return ret; + } + + #define WRENAME(o,n) wRename((o),(n)) #define WFD int #ifndef WGETCWD @@ -287,6 +351,12 @@ extern "C" { int idx = WSTRLEN(dir); char tmp[256]; /* default max file name size */ + /* handle special case at "/" to list all drives */ + if (idx < 3 && dir[0] == WS_DELIM) { + d->fsize = 0; /* used to count number of drives */ + return NU_SUCCESS; + } + if (idx < 3) { return -1; }