mirror of https://github.com/wolfSSL/wolfssh.git
Added support for FatFs
parent
a6e4d46c75
commit
338d3ba219
296
src/wolfsftp.c
296
src/wolfsftp.c
|
@ -395,6 +395,7 @@ static int SendPacketType(WOLFSSH* ssh, byte type, byte* buf, word32 bufSz);
|
|||
static int SFTP_ParseAtributes_buffer(WOLFSSH* ssh, WS_SFTP_FILEATRB* atr,
|
||||
byte* buf, word32* idx, word32 maxIdx);
|
||||
static WS_SFTPNAME* wolfSSH_SFTPNAME_new(void* heap);
|
||||
static int SFTP_CreateLongName(WS_SFTPNAME* name);
|
||||
|
||||
|
||||
static byte* wolfSSH_SFTP_buffer_data(WS_SFTP_BUFFER* buffer)
|
||||
|
@ -1755,6 +1756,105 @@ int wolfSSH_SFTP_RecvMKDIR(WOLFSSH* ssh, int reqId, byte* data, word32 maxSz)
|
|||
}
|
||||
|
||||
|
||||
#ifdef WOLFSSH_FATFS
|
||||
#ifndef WOLFSSH_FATFS_MAX_FILES
|
||||
#define WOLFSSH_FATFS_MAX_FILES 32
|
||||
#endif
|
||||
|
||||
|
||||
struct fd_entry {
|
||||
FIL f;
|
||||
int used;
|
||||
};
|
||||
|
||||
static struct fd_entry fd_pool[WOLFSSH_FATFS_MAX_FILES] = { };
|
||||
|
||||
int ff_open(const char *fname, int flag, int perm)
|
||||
{
|
||||
int i;
|
||||
BYTE mode;
|
||||
(void)perm;
|
||||
PRINTF("\r\nfatFS open: %s", fname);
|
||||
|
||||
if (flag & WOLFSSH_O_RDONLY) {
|
||||
mode = FA_READ;
|
||||
|
||||
} else if (flag & WOLFSSH_O_RDWR) {
|
||||
if ((flag & WOLFSSH_O_CREAT) &&
|
||||
(flag & WOLFSSH_O_TRUNC)) {
|
||||
mode = FA_READ | FA_WRITE | FA_CREATE_ALWAYS;
|
||||
|
||||
} else if ((flag & WOLFSSH_O_CREAT) &&
|
||||
(flag & WOLFSSH_O_APPEND)) {
|
||||
mode = FA_READ | FA_WRITE | FA_CREATE_NEW | FA_OPEN_APPEND;
|
||||
|
||||
} else {
|
||||
mode = AM_ARC;
|
||||
}
|
||||
} else if (flag & WOLFSSH_O_WRONLY) {
|
||||
if ((flag & WOLFSSH_O_CREAT) &&
|
||||
(flag & WOLFSSH_O_TRUNC)) {
|
||||
mode = FA_READ | FA_CREATE_ALWAYS | FA_WRITE;
|
||||
} else if ((flag & WOLFSSH_O_CREAT) &&
|
||||
(flag & WOLFSSH_O_APPEND)) {
|
||||
mode = FA_READ | FA_WRITE | FA_CREATE_NEW | FA_OPEN_APPEND;
|
||||
}
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
for (i = 0; i < WOLFSSH_FATFS_MAX_FILES; i++) {
|
||||
if (fd_pool[i].used == 0) {
|
||||
if (f_open(&(fd_pool[i].f), fname, mode) == FR_OK) {
|
||||
fd_pool[i].used = 1;
|
||||
PRINTF("\r\nfatFS open success: %d", i);
|
||||
return i;
|
||||
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
int ff_close(int fd)
|
||||
{
|
||||
f_close(&fd_pool[fd].f);
|
||||
if (fd_pool[fd].used)
|
||||
fd_pool[fd].used = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ff_pwrite(int fd, const byte *buffer, int sz)
|
||||
{
|
||||
FIL *f = &fd_pool[fd].f;
|
||||
FRESULT ret;
|
||||
unsigned int rsz;
|
||||
if (fd_pool[fd].used == 0)
|
||||
return -1;
|
||||
ret = f_write(f, buffer, sz, &rsz);
|
||||
if (ret != FR_OK)
|
||||
return -1;
|
||||
return rsz;
|
||||
}
|
||||
int ff_pread(int fd, byte *buffer, int sz)
|
||||
{
|
||||
FIL *f = &fd_pool[fd].f;
|
||||
FRESULT ret;
|
||||
unsigned int rsz;
|
||||
if (fd_pool[fd].used == 0)
|
||||
return -1;
|
||||
ret = f_read(f, buffer, sz, &rsz);
|
||||
if (ret != FR_OK)
|
||||
return -1;
|
||||
return rsz;
|
||||
}
|
||||
|
||||
|
||||
#endif /* WOLFSSH_FATFS */
|
||||
|
||||
/* Handles packet to open a file
|
||||
*
|
||||
* returns WS_SUCCESS on success
|
||||
|
@ -2678,6 +2778,87 @@ static int wolfSSH_SFTPNAME_readdir(WOLFSSH* ssh, WDIR* dir, WS_SFTPNAME* out,
|
|||
return WS_SUCCESS;
|
||||
}
|
||||
|
||||
#elif defined(WOLFSSH_FATFS)
|
||||
|
||||
/* helper function that gets file information from reading directory
|
||||
*
|
||||
* returns WS_SUCCESS on success
|
||||
*/
|
||||
static int wolfSSH_SFTPNAME_readdir(WOLFSSH* ssh, WDIR* dir, WS_SFTPNAME* out,
|
||||
char* dirName)
|
||||
{
|
||||
FILINFO f;
|
||||
FILINFO *dp;
|
||||
int sz;
|
||||
|
||||
if (dir == NULL || ssh == NULL || out == NULL) {
|
||||
return WS_BAD_ARGUMENT;
|
||||
}
|
||||
dp = &f;
|
||||
|
||||
if (f_readdir(dir, dp) != FR_OK) {
|
||||
return WS_FATAL_ERROR;
|
||||
}
|
||||
sz = (int)WSTRLEN(dp->fname);
|
||||
out->fName = (char*)WMALLOC(sz + 1, out->heap, DYNTYPE_SFTP);
|
||||
if (out->fName == NULL) {
|
||||
return WS_MEMORY_E;
|
||||
}
|
||||
|
||||
WMEMCPY(out->fName, dp->fname, sz);
|
||||
out->fName[sz] = '\0';
|
||||
out->fSz = sz;
|
||||
|
||||
/* attempt to get file attributes. Could be directory or have none */
|
||||
{
|
||||
char* buf;
|
||||
int bufSz;
|
||||
int tmpSz;
|
||||
|
||||
bufSz = out->fSz + (int)WSTRLEN(dirName) + sizeof(WS_DELIM);
|
||||
buf = (char*)WMALLOC(bufSz + 1, out->heap, DYNTYPE_SFTP);
|
||||
if (buf == NULL) {
|
||||
WFREE(out->fName, out->heap, DYNTYPE_SFTP);
|
||||
return WS_MEMORY_E;
|
||||
}
|
||||
buf[0] = '\0';
|
||||
WSTRNCAT(buf, dirName, bufSz + 1);
|
||||
tmpSz = (int)WSTRLEN(buf);
|
||||
|
||||
/* 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 + 1);
|
||||
if (XSTRLEN(out->fName) == 0) {
|
||||
WFREE(buf, out->heap, DYNTYPE_SFTP);
|
||||
return WS_EOF;
|
||||
}
|
||||
if (wolfSSH_CleanPath(ssh, buf) < 0) {
|
||||
WFREE(buf, out->heap, DYNTYPE_SFTP);
|
||||
return WS_FATAL_ERROR;
|
||||
}
|
||||
|
||||
if (SFTP_GetAttributes(ssh->fs, buf, &out->atrb, 0, ssh->ctx->heap)
|
||||
!= WS_SUCCESS) {
|
||||
WLOG(WS_LOG_SFTP, "Unable to get attribute values for %s",
|
||||
out->fName);
|
||||
WFREE(buf, out->heap, DYNTYPE_SFTP);
|
||||
return WS_FATAL_ERROR;
|
||||
}
|
||||
WFREE(buf, out->heap, DYNTYPE_SFTP);
|
||||
}
|
||||
|
||||
/* Use attributes and fName to create long name */
|
||||
if (SFTP_CreateLongName(out) != WS_SUCCESS) {
|
||||
WLOG(WS_LOG_DEBUG, "Error creating long name for %s", out->fName);
|
||||
WFREE(out->fName, out->heap, DYNTYPE_SFTP);
|
||||
return WS_FATAL_ERROR;
|
||||
}
|
||||
return WS_SUCCESS;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
/* helper function that gets file information from reading directory
|
||||
|
@ -4200,6 +4381,121 @@ int SFTP_GetAttributes_Handle(WOLFSSH* ssh, byte* handle, int handleSz,
|
|||
return WS_SUCCESS;
|
||||
}
|
||||
|
||||
#elif defined(WOLFSSH_FATFS)
|
||||
|
||||
/* FatFs has its own structure for file attributes */
|
||||
|
||||
static int SFTP_GetAttributes(void* fs, const char* fileName,
|
||||
WS_SFTP_FILEATRB* atr, byte link, void* heap)
|
||||
{
|
||||
FILINFO info;
|
||||
FRESULT ret;
|
||||
int sz = (int)WSTRLEN(fileName);
|
||||
|
||||
ret = f_stat(fileName, &info);
|
||||
if (ret != FR_OK)
|
||||
return -1;
|
||||
WMEMSET(atr, 0, sizeof(WS_SFTP_FILEATRB));
|
||||
if (sz > 2 && fileName[sz - 2] == ':') {
|
||||
atr->flags |= WOLFSSH_FILEATRB_PERM;
|
||||
atr->per |= 0x4000;
|
||||
return WS_SUCCESS;
|
||||
}
|
||||
|
||||
/* handle case of "/" */
|
||||
if (sz < 3 && fileName[0] == WS_DELIM) {
|
||||
atr->flags |= WOLFSSH_FILEATRB_PERM;
|
||||
atr->per |= 0x4000;
|
||||
return WS_SUCCESS;
|
||||
}
|
||||
|
||||
if (ret != FR_OK) {
|
||||
return WS_BAD_FILE_E;
|
||||
}
|
||||
|
||||
atr->flags |= WOLFSSH_FILEATRB_SIZE;
|
||||
atr->sz[0] = (word32)(info.fsize);
|
||||
atr->sz[1] = (word32)(0);
|
||||
|
||||
/* get additional attributes */
|
||||
{
|
||||
byte atrib = info.fattrib;
|
||||
atr->flags |= WOLFSSH_FILEATRB_PERM;
|
||||
if (atrib & AM_DIR) {
|
||||
atr->per |= 0x41ED; /* 755 with directory */
|
||||
}
|
||||
else {
|
||||
atr->per |= 0x8000;
|
||||
}
|
||||
if ((atrib & AM_ARC) == AM_ARC) {
|
||||
atr->per |= 0x1ED; /* octal 755 */
|
||||
}
|
||||
if ((atrib & AM_SYS) || (atrib & AM_RDO)) {
|
||||
atr->per |= 0x124; /* octal 444 */
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef NO_WOLFSSH_MKTIME
|
||||
/* get file times */
|
||||
atr->flags |= WOLFSSH_FILEATRB_TIME;
|
||||
atr->atime = info.fdate;
|
||||
atr->mtime = info.fdate;
|
||||
#endif /* NO_WOLFSSH_MKTIME */
|
||||
return WS_SUCCESS;
|
||||
}
|
||||
|
||||
static int SFTP_GetAttributes_Handle(WOLFSSH* ssh, byte* handle, int handleSz,
|
||||
WS_SFTP_FILEATRB* atr)
|
||||
{
|
||||
FILINFO info;
|
||||
WS_HANDLE_LIST *cur;
|
||||
|
||||
if (handle == NULL || atr == NULL) {
|
||||
return WS_FATAL_ERROR;
|
||||
}
|
||||
|
||||
cur = SFTP_GetHandleNode(ssh, handle, handleSz);
|
||||
if (cur == NULL) {
|
||||
WLOG(WS_LOG_SFTP, "Unknown handle");
|
||||
return WS_BAD_FILE_E;
|
||||
}
|
||||
|
||||
if (f_stat(cur->name, &info) != FR_OK) {
|
||||
return WS_FATAL_ERROR;
|
||||
}
|
||||
|
||||
WMEMSET(atr, 0, sizeof(WS_SFTP_FILEATRB));
|
||||
|
||||
atr->flags |= WOLFSSH_FILEATRB_SIZE;
|
||||
atr->sz[0] = (word32)(info.fsize);
|
||||
atr->sz[1] = (word32)(0);
|
||||
|
||||
{
|
||||
byte atrib = info.fattrib;
|
||||
atr->flags |= WOLFSSH_FILEATRB_PERM;
|
||||
if (atrib & AM_DIR) {
|
||||
atr->per |= 0x41ED; /* 755 with directory */
|
||||
}
|
||||
else {
|
||||
atr->per |= 0x8000;
|
||||
}
|
||||
if ((atrib & AM_ARC) == AM_ARC) {
|
||||
atr->per |= 0x1ED; /* octal 755 */
|
||||
}
|
||||
if ((atrib & AM_RDO) || (atrib & AM_SYS)) {
|
||||
atr->per |= 0x124; /* octal 444 */
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef NO_WOLFSSH_MKTIME
|
||||
/* get file times */
|
||||
atr->flags |= WOLFSSH_FILEATRB_TIME;
|
||||
atr->atime = info.ftime;
|
||||
atr->mtime = info.ftime;
|
||||
#endif /* NO_WOLFSSH_MKTIME */
|
||||
return WS_SUCCESS;
|
||||
}
|
||||
|
||||
#elif defined(WOLFSSH_USER_FILESYSTEM)
|
||||
/* User-defined I/O support */
|
||||
|
||||
|
|
144
wolfssh/port.h
144
wolfssh/port.h
|
@ -208,6 +208,94 @@ extern "C" {
|
|||
return 0;
|
||||
}
|
||||
#define WCHMOD(fs,f,m) wChmod((fs),(f),(m))
|
||||
|
||||
#elif defined(WOLFSSH_FATFS)
|
||||
#include <ff.h>
|
||||
#define WFILE FIL
|
||||
#define WS_DELIM '/'
|
||||
#define WOLFSSH_O_CREAT (FA_CREATE_NEW | FA_OPEN_ALWAYS)
|
||||
#define WOLFSSH_O_RDWR (FA_READ | FA_WRITE)
|
||||
#define WOLFSSH_O_RDONLY FA_READ
|
||||
#define WOLFSSH_O_WRONLY FA_WRITE
|
||||
#define WOLFSSH_O_TRUNC FA_CREATE_ALWAYS
|
||||
#define WOLFSSH_O_APPEND FA_OPEN_APPEND
|
||||
#define WOLFSSH_O_EXCL FA_OPEN_EXISTING
|
||||
#define WSEEK_SET 0
|
||||
#define WSEEK_CUR 1
|
||||
#define WSEEK_END 2
|
||||
static inline int ff_fopen(WFILE** f, const char* filename,
|
||||
const char* mode)
|
||||
{
|
||||
FRESULT ret;
|
||||
BYTE m = FA_CREATE_NEW;
|
||||
if (!f) {
|
||||
return -1;
|
||||
}
|
||||
if (XSTRSTR(mode, "r") && XSTRSTR(mode, "w")) {
|
||||
m |= WOLFSSH_O_RDWR;
|
||||
}
|
||||
else {
|
||||
if (XSTRSTR(mode, "r")) {
|
||||
m |= WOLFSSH_O_RDONLY;
|
||||
}
|
||||
if (XSTRSTR(mode, "w")) {
|
||||
m |= WOLFSSH_O_WRONLY;
|
||||
}
|
||||
}
|
||||
ret = f_open(*f, filename, m);
|
||||
return (int)ret;
|
||||
}
|
||||
#define WFOPEN(f, fn, m) ff_fopen((f),(fn),(m))
|
||||
#define WFCLOSE(f) f_close(f)
|
||||
|
||||
static inline int ff_read(void *ptr, size_t size, size_t nmemb, WFILE *f)
|
||||
{
|
||||
FRESULT ret;
|
||||
UINT n_bytes;
|
||||
UINT btr = size * nmemb;
|
||||
|
||||
ret = f_read(f, ptr, btr, &n_bytes);
|
||||
if (ret != FR_OK) {
|
||||
return 0;
|
||||
}
|
||||
return (n_bytes / size);
|
||||
}
|
||||
#define WFREAD(b,s,a,f) ff_read(b,s,a,f)
|
||||
static inline int ff_write(const void *ptr, size_t size, size_t nmemb, WFILE *f)
|
||||
{
|
||||
FRESULT ret;
|
||||
UINT n_bytes;
|
||||
UINT btr = size * nmemb;
|
||||
|
||||
ret = f_write(f, ptr, btr, &n_bytes);
|
||||
if (ret != FR_OK) {
|
||||
return 0;
|
||||
}
|
||||
return (n_bytes / size);
|
||||
}
|
||||
#define WFWRITE(b,s,a,f) ff_write(b,s,a,f)
|
||||
|
||||
#define WFTELL(s) f_tell((s))
|
||||
static inline int ff_seek(WFILE *fp, long off, int whence)
|
||||
{
|
||||
switch(whence) {
|
||||
case WSEEK_SET:
|
||||
return f_lseek(fp, off);
|
||||
case WSEEK_CUR:
|
||||
return f_lseek(fp, off + f_tell(fp));
|
||||
case WSEEK_END:
|
||||
return f_lseek(fp, off + f_size(fp));
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
#define WFSEEK(s,o,w) ff_seek((s),(o),(w))
|
||||
#define WREWIND(s) f_rewind(s)
|
||||
#define WBADFILE (-1)
|
||||
#ifndef NO_WOLFSSH_DIR
|
||||
#define WDIR DIR
|
||||
#define WOPENDIR(fs,h,c,d) f_opendir((c),(d))
|
||||
#define WCLOSEDIR(d) f_closedir(d)
|
||||
#endif
|
||||
#elif defined(WOLFSSH_USER_FILESYSTEM)
|
||||
/* User-defined I/O support */
|
||||
#else
|
||||
|
@ -971,6 +1059,62 @@ extern "C" {
|
|||
#endif /* WCLOSEDIR */
|
||||
#endif /* NO_WOLFSSH_DIR */
|
||||
|
||||
#elif defined(WOLFSSH_FATFS)
|
||||
#define WSTAT_T FILINFO
|
||||
|
||||
#define WRMDIR(fs, d) f_unlink((d))
|
||||
#define WSTAT(p,b) f_stat(p,b)
|
||||
#define WLSTAT(p,b) f_stat(p,b)
|
||||
#define WREMOVE(fs,d) f_unlink((d))
|
||||
#define WRENAME(fd,o,n) f_rename((o),(n))
|
||||
#define WMKDIR(fs, p, m) f_mkdir(p)
|
||||
#define WFD int
|
||||
|
||||
int ff_open(const char *fname, int mode, int perm);
|
||||
int ff_close(int fd);
|
||||
int ff_pwrite(int fd, const byte *buffer, int sz);
|
||||
int ff_pread(int fd, byte *buffer, int sz);
|
||||
#define WOPEN(f,m,p) ff_open(f,m,p)
|
||||
#define WPWRITE(fd,b,s,o) ff_pwrite(fd,b,s)
|
||||
#define WPREAD(fd,b,s,o) ff_pread(fd,b,s)
|
||||
#define WCLOSE(fd) ff_close(fd)
|
||||
|
||||
static inline int ff_chmod(const char *fname, int mode)
|
||||
{
|
||||
unsigned char atr = 0, mask = AM_RDO | AM_ARC;
|
||||
FILINFO info;
|
||||
if (fname == NULL) {
|
||||
return -1;
|
||||
}
|
||||
if (f_stat(fname, &info) != FR_OK) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Set attribute value */
|
||||
atr = atr & 0xF0; /* clear first byte */
|
||||
if (mode == 0x124) {
|
||||
atr |= AM_RDO; /* set read only value */
|
||||
}
|
||||
else {
|
||||
/* if not setting read only set to normal */
|
||||
atr |= AM_ARC;
|
||||
}
|
||||
if (f_chmod(fname, atr, mask) != FR_OK)
|
||||
return -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define WCHMOD(fs,f,m) ff_chmod(f,m)
|
||||
static inline char *ff_getcwd(char *r, int rSz)
|
||||
{
|
||||
FRESULT ret;
|
||||
ret = f_getcwd(r, rSz);
|
||||
if (ret != FR_OK) {
|
||||
return NULL;
|
||||
}
|
||||
return r;
|
||||
}
|
||||
#define WGETCWD(fs,r,rSz) ff_getcwd(r,(rSz))
|
||||
#elif defined(USE_WINDOWS_API)
|
||||
|
||||
#include <windows.h>
|
||||
|
|
Loading…
Reference in New Issue