diff --git a/.github/workflows/test-fatfs.yml b/.github/workflows/test-fatfs.yml new file mode 100644 index 000000000..5431351ba --- /dev/null +++ b/.github/workflows/test-fatfs.yml @@ -0,0 +1,178 @@ +name: Test FATFS Support + +on: + push: + branches: [ master ] + pull_request: + branches: [ master ] + workflow_dispatch: + +jobs: + get-fatfs: + runs-on: ubuntu-latest + steps: + - name: Set up cache key + id: cache-key + run: echo "CACHE_KEY=ff15a-cache" >> $GITHUB_ENV + + - name: Download FF15a.zip + id: download + run: | + wget http://elm-chan.org/fsw/ff/arc/ff15a.zip -O ff15a.zip + + - name: Cache the downloaded ZIP file + uses: actions/cache@v4 + with: + path: ./ff15a.zip + key: ${{ env.CACHE_KEY }} + restore-keys: | + ${{ env.CACHE_KEY }} + + test-fatfs: + needs: get-fatfs + runs-on: ubuntu-latest + steps: + - name: Checkout code + uses: actions/checkout@v3 + + - name: Checking cache for FATFS + uses: actions/cache@v4 + with: + path: ./ff15a.zip + key: ff15a-cache + fail-on-cache-miss: true + + - name: Install dependencies + run: | + sudo apt-get update + sudo apt-get install -y build-essential autoconf automake libtool pkg-config openssh-server dosfstools + + - name: Clone wolfSSL + run: | + cd .. + git clone https://github.com/wolfSSL/wolfssl.git + cd wolfssl + ./autogen.sh + + - name: Configure and build wolfSSL + run: | + cd ../wolfssl + ./configure --enable-wolfssh --enable-intelasm --disable-crl --disable-examples --disable-filesystem CFLAGS="-DNO_WOLFSSL_DIR" + make + sudo make install + sudo ldconfig + + - name: Compile FATFS library + run: | + cd ide/Linux-FATFS + unzip ../../ff15a.zip + cp ffconf.h source/ + make + + - name: Configure and build wolfSSH with FATFS + run: | + ./autogen.sh + export LD_LIBRARY_PATH=$(pwd)/ide/Linux-FATFS + ./configure --enable-sftp CFLAGS="-DWOLFSSH_FATFS -Iide/Linux-FATFS/source -DSTDIN_FILENO=0 -DPRINTF=printf" LDFLAGS="-Lide/Linux-FATFS -lfatfs" + make + + + + - name: Create test file + run: | + dd if=/dev/urandom of=test_file.bin bs=1M count=1 + + - name: Setup SSH server + run: | + sudo mkdir -p /run/sshd + sudo /usr/sbin/sshd + mkdir -p ~/.ssh + ssh-keygen -t rsa -f ~/.ssh/id_rsa -N "" + cat ~/.ssh/id_rsa.pub >> ~/.ssh/authorized_keys + chmod 600 ~/.ssh/authorized_keys + echo "Host localhost" > ~/.ssh/config + echo " StrictHostKeyChecking no" >> ~/.ssh/config + echo " UserKnownHostsFile=/dev/null" >> ~/.ssh/config + chmod 600 ~/.ssh/config + + - name: Install expect + run: | + sudo apt-get update + sudo apt-get install -y expect + + - name: Run wolfsftp client to get file + run: | + # Export the library path + export LD_LIBRARY_PATH=$(pwd)/ide/Linux-FATFS + + # Get the full path to the test file + TEST_FILE_PATH=$(pwd)/test_file.bin + + # Change to the sftpclient directory + cd examples/sftpclient + + # Create the FATFS image file directly in the sftpclient directory + dd if=/dev/zero of=fatfs_image.img bs=1M count=32 + mkdosfs fatfs_image.img + + # Create a test user with a known password and add to the same group as the runner + sudo useradd -m testuser + echo "testuser:password123" | sudo chpasswd + sudo usermod -aG $(id -gn) testuser + + # Make the test file accessible to testuser + chmod 644 ${TEST_FILE_PATH} + sudo chown testuser:$(id -gn) ${TEST_FILE_PATH} + + # Configure SSH server to allow SFTP access + sudo sed -i 's/^#Subsystem\s\+sftp.*/Subsystem sftp \/usr\/lib\/openssh\/sftp-server/' /etc/ssh/sshd_config + sudo service ssh restart || sudo /etc/init.d/ssh restart || sudo /usr/sbin/sshd -t && sudo kill -HUP $(pgrep -f sshd) + + # Create expect script to automate the wolfsftp client interaction + cat > /tmp/sftp_test.exp << EOF + #!/usr/bin/expect -f + set timeout 60 + spawn ./wolfsftp -N -h localhost -p 22 -u testuser + expect "Password:" + send "password123\r" + expect "wolfSSH sftp>" + send "get ${TEST_FILE_PATH} test_file.bin\r" + expect "wolfSSH sftp>" + send "exit\r" + expect eof + EOF + chmod +x /tmp/sftp_test.exp + + # Run the expect script + /tmp/sftp_test.exp + + - name: Verify file in FATFS image + run: | + cd examples/sftpclient + sudo mkdir -p /mnt/fatfs + LOOPDEV=$(sudo losetup -f) + sudo losetup $LOOPDEV fatfs_image.img + sudo mount $LOOPDEV /mnt/fatfs + if [ -f /mnt/fatfs/test_file.bin ]; then + echo "File exists in FATFS image!" + ls -la /mnt/fatfs/ + + # Verify file contents match + if cmp -s ../../test_file.bin /mnt/fatfs/test_file.bin; then + echo "File contents match! FATFS test PASSED." + sudo umount /mnt/fatfs + sudo losetup -d $LOOPDEV + exit 0 + else + echo "File contents do not match! FATFS test FAILED." + sudo umount /mnt/fatfs + sudo losetup -d $LOOPDEV + exit 1 + fi + else + echo "File does not exist in FATFS image! FATFS test FAILED." + ls -la /mnt/fatfs/ + sudo umount /mnt/fatfs + sudo losetup -d $LOOPDEV + exit 1 + fi diff --git a/examples/sftpclient/sftpclient.c b/examples/sftpclient/sftpclient.c index 12fb7ecd5..744c79b7a 100644 --- a/examples/sftpclient/sftpclient.c +++ b/examples/sftpclient/sftpclient.c @@ -1476,6 +1476,9 @@ THREAD_RETURN WOLFSSH_THREAD sftpclient_test(void* args) int main(int argc, char** argv) { + #ifdef WOLFSSH_FATFS + FATFS fs; + #endif func_args args; args.argc = argc; @@ -1486,6 +1489,13 @@ THREAD_RETURN WOLFSSH_THREAD sftpclient_test(void* args) args.sftp_cb = NULL; #endif + #ifdef WOLFSSH_FATFS + if (f_mount(&fs, "0:", 1) != FR_OK) { + fprintf(stderr, "Failed to mount filesystem\n"); + return 1; + } + #endif + WSTARTTCP(); #ifdef DEBUG_WOLFSSH @@ -1499,6 +1509,10 @@ THREAD_RETURN WOLFSSH_THREAD sftpclient_test(void* args) wolfSSH_Cleanup(); + #ifdef WOLFSSH_FATFS + f_mount(NULL, "0:", 1); + #endif + #if defined(WOLFSSH_SFTP) && !defined(NO_WOLFSSH_CLIENT) return args.return_code; #else diff --git a/ide/Linux-FATFS/.gitignore b/ide/Linux-FATFS/.gitignore new file mode 100644 index 000000000..37fbe18b1 --- /dev/null +++ b/ide/Linux-FATFS/.gitignore @@ -0,0 +1 @@ +fatfs_image.img diff --git a/ide/Linux-FATFS/Makefile b/ide/Linux-FATFS/Makefile new file mode 100644 index 000000000..6c20d3457 --- /dev/null +++ b/ide/Linux-FATFS/Makefile @@ -0,0 +1,26 @@ +# Compiler and flags +CC = gcc +CFLAGS = -g -Wall -O2 -fPIC -Isource +LDFLAGS = -shared + +# Source files +SRCS = source/ff.c source/ffunicode.c fatfs_example.c + +# Object files +OBJS = $(SRCS:.c=.o) + +# Target library +TARGET = libfatfs.so + +all: $(TARGET) + +$(TARGET): $(OBJS) + $(CC) $(LDFLAGS) -o $@ $^ + +%.o: %.c + $(CC) $(CFLAGS) -c $< -o $@ + +clean: + rm -f $(OBJS) $(TARGET) + +.PHONY: all clean diff --git a/ide/Linux-FATFS/README.md b/ide/Linux-FATFS/README.md new file mode 100644 index 000000000..d3994a6cf --- /dev/null +++ b/ide/Linux-FATFS/README.md @@ -0,0 +1,49 @@ +# FATFS Linux Example + +This is a FATFS example that uses a single file on the Linux filesystem as the +FATFS file system. + +## Obtaining FATFS + +You can download the source code from +[The FATFS download site](http://elm-chan.org/fsw/ff/archives.html). Extract it +into this directory. + +The example has been tested against FATFS 0.15a + +## Compiling Library + +First copy the config file into the correct place: + +```sh +cp ffconf.h source/ +``` + +Then to compile the FATFS library simply run `make`. + +## Setup filesystem + +The single file used for FATFS should be generated using: + +```sh +dd if=/dev/zero of=fatfs_image.img bs=1M count=32 +mkdosfs fatfs_image.img +``` + +Note that this file will need to be local to wherever you execute anything using +the library. + +## Compiling wolfSSH and wolfSSL + +### wolfSSL + +```sh +./configure --enable-wolfssh --enable-intelasm --disable-crl --disable-examples --disable-filesystem CFLAGS="-DNO_WOLFSSL_DIR" +``` + +### wolfSSH + +```sh +LD_LIBRARY_PATH=ide/Linux-FATFS ./configure --enable-sftp CFLAGS="-DWOLFSSH_FATFS -Iide/Linux-FATFS/source -DSTDIN_FILENO=0 -DPRINTF=printf" LDFLAGS="-Lide/Linux-FATFS -lfatfs" +``` + diff --git a/ide/Linux-FATFS/fatfs_example.c b/ide/Linux-FATFS/fatfs_example.c new file mode 100644 index 000000000..7da8f36b6 --- /dev/null +++ b/ide/Linux-FATFS/fatfs_example.c @@ -0,0 +1,135 @@ +/* sftpclient.c + * + * Copyright (C) 2025 wolfSSL Inc. + * + * This file is part of wolfSSH. + * + * wolfSSH is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * wolfSSH is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with wolfSSH. If not, see . + */ + +#include +#include +#include +#include +#include "ff.h" +#include "diskio.h" + +#define STORAGE_FILE_PATH "fatfs_image.img" + +static FILE *storage_file = NULL; + +/* Initialize the storage file */ +DSTATUS disk_initialize(BYTE pdrv) { + if (pdrv != 0) return STA_NOINIT; /* Only support one drive (0) */ + + /* Open the storage file in read/write binary mode */ + storage_file = fopen(STORAGE_FILE_PATH, "r+b"); + if (!storage_file) { + perror("Failed to open storage file"); + return STA_NODISK | STA_NOINIT; + } + + return 0; /* Initialization successful */ +} + +/* Get the status of the storage file */ +DSTATUS disk_status(BYTE pdrv) { + if (pdrv != 0) return STA_NOINIT; /* Only support one drive (0) */ + if (!storage_file) return STA_NODISK; + return 0; +} + +/* Read sectors from the storage file */ +DRESULT disk_read(BYTE pdrv, BYTE* buff, LBA_t sector, UINT count) { + if (pdrv != 0) return RES_PARERR; /* Only support one drive (0) */ + if (!storage_file) return RES_NOTRDY; + + off_t offset = sector * FF_MIN_SS; /* Calculate the byte offset */ + if (fseek(storage_file, offset, SEEK_SET) != 0) { + perror("Failed to seek in storage file"); + return RES_ERROR; + } + + size_t bytes_read = fread(buff, FF_MIN_SS, count, storage_file); + if (bytes_read != count) { + perror("Failed to read from storage file"); + return RES_ERROR; + } + + return RES_OK; +} + +/* Write sectors to the storage file */ +DRESULT disk_write(BYTE pdrv, const BYTE* buff, LBA_t sector, UINT count) { + if (pdrv != 0) return RES_PARERR; /* Only support one drive (0) */ + if (!storage_file) return RES_NOTRDY; + + off_t offset = sector * FF_MIN_SS; /* Calculate the byte offset */ + if (fseek(storage_file, offset, SEEK_SET) != 0) { + perror("Failed to seek in storage file"); + return RES_ERROR; + } + + size_t bytes_written = fwrite(buff, FF_MIN_SS, count, storage_file); + if (bytes_written != count) { + perror("Failed to write to storage file"); + return RES_ERROR; + } + + fflush(storage_file); /* Ensure data is written to disk */ + return RES_OK; +} + +/* Control the device */ +DRESULT disk_ioctl(BYTE pdrv, BYTE cmd, void* buff) { + if (pdrv != 0) return RES_PARERR; /* Only support one drive (0) */ + + switch (cmd) { + case CTRL_SYNC: + /* Ensure all data is written to disk */ + fflush(storage_file); + break; + + case GET_SECTOR_SIZE: + *(WORD*)buff = FF_MIN_SS; + break; + + case GET_BLOCK_SIZE: + *(DWORD*)buff = 1; /* One sector per block (minimum) */ + break; + + default: + return RES_PARERR; + } + + return RES_OK; +} + +/* Function to deinitialize the storage file */ +DSTATUS disk_deinitialize(BYTE pdrv) { + if (pdrv != 0) return STA_NOINIT; /* Only support one drive (0) */ + + if (storage_file) { + fclose(storage_file); + storage_file = NULL; + } + + return 0; /* Deinitialization successful */ +} + +/* FatFs disk I/O driver interface */ +DSTATUS disk_status_(BYTE pdrv) { return disk_status(pdrv); } +DRESULT disk_read_(BYTE pdrv, BYTE* buff, LBA_t sector, UINT count) { return disk_read(pdrv, buff, sector, count); } +DRESULT disk_write_(BYTE pdrv, const BYTE* buff, LBA_t sector, UINT count) { return disk_write(pdrv, buff, sector, count); } +DRESULT disk_ioctl_(BYTE pdrv, BYTE cmd, void* buff) { return disk_ioctl(pdrv, cmd, buff); } diff --git a/ide/Linux-FATFS/ffconf.h b/ide/Linux-FATFS/ffconf.h new file mode 100644 index 000000000..eef441e2e --- /dev/null +++ b/ide/Linux-FATFS/ffconf.h @@ -0,0 +1,296 @@ +/*---------------------------------------------------------------------------/ +/ Configurations of FatFs Module +/---------------------------------------------------------------------------*/ + +#define FFCONF_DEF 5380 /* Revision ID */ + +/*---------------------------------------------------------------------------/ +/ Function Configurations +/---------------------------------------------------------------------------*/ + +#define FF_FS_READONLY 0 +/* This option switches read-only configuration. (0:Read/Write or 1:Read-only) +/ Read-only configuration removes writing API functions, f_write(), f_sync(), +/ f_unlink(), f_mkdir(), f_chmod(), f_rename(), f_truncate(), f_getfree() +/ and optional writing functions as well. */ + + +#define FF_FS_MINIMIZE 0 +/* This option defines minimization level to remove some basic API functions. +/ +/ 0: Basic functions are fully enabled. +/ 1: f_stat(), f_getfree(), f_unlink(), f_mkdir(), f_truncate() and f_rename() +/ are removed. +/ 2: f_opendir(), f_readdir() and f_closedir() are removed in addition to 1. +/ 3: f_lseek() function is removed in addition to 2. */ + + +#define FF_USE_FIND 0 +/* This option switches filtered directory read functions, f_findfirst() and +/ f_findnext(). (0:Disable, 1:Enable 2:Enable with matching altname[] too) */ + + +#define FF_USE_MKFS 0 +/* This option switches f_mkfs(). (0:Disable or 1:Enable) */ + + +#define FF_USE_FASTSEEK 0 +/* This option switches fast seek feature. (0:Disable or 1:Enable) */ + + +#define FF_USE_EXPAND 0 +/* This option switches f_expand(). (0:Disable or 1:Enable) */ + + +#define FF_USE_CHMOD 0 +/* This option switches attribute control API functions, f_chmod() and f_utime(). +/ (0:Disable or 1:Enable) Also FF_FS_READONLY needs to be 0 to enable this option. */ + + +#define FF_USE_LABEL 0 +/* This option switches volume label API functions, f_getlabel() and f_setlabel(). +/ (0:Disable or 1:Enable) */ + + +#define FF_USE_FORWARD 0 +/* This option switches f_forward(). (0:Disable or 1:Enable) */ + + +#define FF_USE_STRFUNC 0 +#define FF_PRINT_LLI 0 +#define FF_PRINT_FLOAT 0 +#define FF_STRF_ENCODE 3 +/* FF_USE_STRFUNC switches the string API functions, f_gets(), f_putc(), f_puts() +/ and f_printf(). +/ +/ 0: Disable. FF_PRINT_LLI, FF_PRINT_FLOAT and FF_STRF_ENCODE have no effect. +/ 1: Enable without LF - CRLF conversion. +/ 2: Enable with LF - CRLF conversion. +/ +/ FF_PRINT_LLI = 1 makes f_printf() support long long argument and FF_PRINT_FLOAT = 1/2 +/ makes f_printf() support floating point argument. These features want C99 or later. +/ When FF_LFN_UNICODE >= 1 with LFN enabled, string API functions convert the character +/ encoding in it. FF_STRF_ENCODE selects assumption of character encoding ON THE FILE +/ to be read/written via those functions. +/ +/ 0: ANSI/OEM in current CP +/ 1: Unicode in UTF-16LE +/ 2: Unicode in UTF-16BE +/ 3: Unicode in UTF-8 +*/ + + +/*---------------------------------------------------------------------------/ +/ Locale and Namespace Configurations +/---------------------------------------------------------------------------*/ + +#define FF_CODE_PAGE 932 +/* This option specifies the OEM code page to be used on the target system. +/ Incorrect code page setting can cause a file open failure. +/ +/ 437 - U.S. +/ 720 - Arabic +/ 737 - Greek +/ 771 - KBL +/ 775 - Baltic +/ 850 - Latin 1 +/ 852 - Latin 2 +/ 855 - Cyrillic +/ 857 - Turkish +/ 860 - Portuguese +/ 861 - Icelandic +/ 862 - Hebrew +/ 863 - Canadian French +/ 864 - Arabic +/ 865 - Nordic +/ 866 - Russian +/ 869 - Greek 2 +/ 932 - Japanese (DBCS) +/ 936 - Simplified Chinese (DBCS) +/ 949 - Korean (DBCS) +/ 950 - Traditional Chinese (DBCS) +/ 0 - Include all code pages above and configured by f_setcp() +*/ + + +#define FF_USE_LFN 2 +#define FF_MAX_LFN 255 +/* The FF_USE_LFN switches the support for LFN (long file name). +/ +/ 0: Disable LFN. FF_MAX_LFN has no effect. +/ 1: Enable LFN with static working buffer on the BSS. Always NOT thread-safe. +/ 2: Enable LFN with dynamic working buffer on the STACK. +/ 3: Enable LFN with dynamic working buffer on the HEAP. +/ +/ To enable the LFN, ffunicode.c needs to be added to the project. The LFN feature +/ requiers certain internal working buffer occupies (FF_MAX_LFN + 1) * 2 bytes and +/ additional (FF_MAX_LFN + 44) / 15 * 32 bytes when exFAT is enabled. +/ The FF_MAX_LFN defines size of the working buffer in UTF-16 code unit and it can +/ be in range of 12 to 255. It is recommended to be set 255 to fully support the LFN +/ specification. +/ When use stack for the working buffer, take care on stack overflow. When use heap +/ memory for the working buffer, memory management functions, ff_memalloc() and +/ ff_memfree() exemplified in ffsystem.c, need to be added to the project. */ + + +#define FF_LFN_UNICODE 0 +/* This option switches the character encoding on the API when LFN is enabled. +/ +/ 0: ANSI/OEM in current CP (TCHAR = char) +/ 1: Unicode in UTF-16 (TCHAR = WCHAR) +/ 2: Unicode in UTF-8 (TCHAR = char) +/ 3: Unicode in UTF-32 (TCHAR = DWORD) +/ +/ Also behavior of string I/O functions will be affected by this option. +/ When LFN is not enabled, this option has no effect. */ + + +#define FF_LFN_BUF 255 +#define FF_SFN_BUF 12 +/* This set of options defines size of file name members in the FILINFO structure +/ which is used to read out directory items. These values should be suffcient for +/ the file names to read. The maximum possible length of the read file name depends +/ on character encoding. When LFN is not enabled, these options have no effect. */ + + +#define FF_FS_RPATH 2 +/* This option configures support for relative path. +/ +/ 0: Disable relative path and remove related API functions. +/ 1: Enable relative path. f_chdir() and f_chdrive() are available. +/ 2: f_getcwd() is available in addition to 1. +*/ + + +/*---------------------------------------------------------------------------/ +/ Drive/Volume Configurations +/---------------------------------------------------------------------------*/ + +#define FF_VOLUMES 1 +/* Number of volumes (logical drives) to be used. (1-10) */ + + +#define FF_STR_VOLUME_ID 0 +#define FF_VOLUME_STRS "RAM","NAND","CF","SD","SD2","USB","USB2","USB3" +/* FF_STR_VOLUME_ID switches support for volume ID in arbitrary strings. +/ When FF_STR_VOLUME_ID is set to 1 or 2, arbitrary strings can be used as drive +/ number in the path name. FF_VOLUME_STRS defines the volume ID strings for each +/ logical drive. Number of items must not be less than FF_VOLUMES. Valid +/ characters for the volume ID strings are A-Z, a-z and 0-9, however, they are +/ compared in case-insensitive. If FF_STR_VOLUME_ID >= 1 and FF_VOLUME_STRS is +/ not defined, a user defined volume string table is needed as: +/ +/ const char* VolumeStr[FF_VOLUMES] = {"ram","flash","sd","usb",... +*/ + + +#define FF_MULTI_PARTITION 0 +/* This option switches support for multiple volumes on the physical drive. +/ By default (0), each logical drive number is bound to the same physical drive +/ number and only an FAT volume found on the physical drive will be mounted. +/ When this feature is enabled (1), each logical drive number can be bound to +/ arbitrary physical drive and partition listed in the VolToPart[]. Also f_fdisk() +/ will be available. */ + + +#define FF_MIN_SS 512 +#define FF_MAX_SS 512 +/* This set of options configures the range of sector size to be supported. (512, +/ 1024, 2048 or 4096) Always set both 512 for most systems, generic memory card and +/ harddisk, but a larger value may be required for on-board flash memory and some +/ type of optical media. When FF_MAX_SS is larger than FF_MIN_SS, FatFs is +/ configured for variable sector size mode and disk_ioctl() needs to implement +/ GET_SECTOR_SIZE command. */ + + +#define FF_LBA64 0 +/* This option switches support for 64-bit LBA. (0:Disable or 1:Enable) +/ To enable the 64-bit LBA, also exFAT needs to be enabled. (FF_FS_EXFAT == 1) */ + + +#define FF_MIN_GPT 0x10000000 +/* Minimum number of sectors to switch GPT as partitioning format in f_mkfs() and +/ f_fdisk(). 2^32 sectors maximum. This option has no effect when FF_LBA64 == 0. */ + + +#define FF_USE_TRIM 0 +/* This option switches support for ATA-TRIM. (0:Disable or 1:Enable) +/ To enable this feature, also CTRL_TRIM command should be implemented to +/ the disk_ioctl(). */ + + + +/*---------------------------------------------------------------------------/ +/ System Configurations +/---------------------------------------------------------------------------*/ + +#define FF_FS_TINY 0 +/* This option switches tiny buffer configuration. (0:Normal or 1:Tiny) +/ At the tiny configuration, size of file object (FIL) is shrinked FF_MAX_SS bytes. +/ Instead of private sector buffer eliminated from the file object, common sector +/ buffer in the filesystem object (FATFS) is used for the file data transfer. */ + + +#define FF_FS_EXFAT 0 +/* This option switches support for exFAT filesystem. (0:Disable or 1:Enable) +/ To enable exFAT, also LFN needs to be enabled. (FF_USE_LFN >= 1) +/ Note that enabling exFAT discards ANSI C (C89) compatibility. */ + + +#define FF_FS_NORTC 1 +#define FF_NORTC_MON 11 +#define FF_NORTC_MDAY 1 +#define FF_NORTC_YEAR 2024 +/* The option FF_FS_NORTC switches timestamp feature. If the system does not have +/ an RTC or valid timestamp is not needed, set FF_FS_NORTC = 1 to disable the +/ timestamp feature. Every object modified by FatFs will have a fixed timestamp +/ defined by FF_NORTC_MON, FF_NORTC_MDAY and FF_NORTC_YEAR in local time. +/ To enable timestamp function (FF_FS_NORTC = 0), get_fattime() need to be added +/ to the project to read current time form real-time clock. FF_NORTC_MON, +/ FF_NORTC_MDAY and FF_NORTC_YEAR have no effect. +/ These options have no effect in read-only configuration (FF_FS_READONLY = 1). */ + + +#define FF_FS_NOFSINFO 0 +/* If you need to know correct free space on the FAT32 volume, set bit 0 of this +/ option, and f_getfree() at the first time after volume mount will force +/ a full FAT scan. Bit 1 controls the use of last allocated cluster number. +/ +/ bit0=0: Use free cluster count in the FSINFO if available. +/ bit0=1: Do not trust free cluster count in the FSINFO. +/ bit1=0: Use last allocated cluster number in the FSINFO if available. +/ bit1=1: Do not trust last allocated cluster number in the FSINFO. +*/ + + +#define FF_FS_LOCK 0 +/* The option FF_FS_LOCK switches file lock function to control duplicated file open +/ and illegal operation to open objects. This option must be 0 when FF_FS_READONLY +/ is 1. +/ +/ 0: Disable file lock function. To avoid volume corruption, application program +/ should avoid illegal open, remove and rename to the open objects. +/ >0: Enable file lock function. The value defines how many files/sub-directories +/ can be opened simultaneously under file lock control. Note that the file +/ lock control is independent of re-entrancy. */ + + +#define FF_FS_REENTRANT 0 +#define FF_FS_TIMEOUT 1000 +/* The option FF_FS_REENTRANT switches the re-entrancy (thread safe) of the FatFs +/ module itself. Note that regardless of this option, file access to different +/ volume is always re-entrant and volume control functions, f_mount(), f_mkfs() +/ and f_fdisk(), are always not re-entrant. Only file/directory access to +/ the same volume is under control of this featuer. +/ +/ 0: Disable re-entrancy. FF_FS_TIMEOUT have no effect. +/ 1: Enable re-entrancy. Also user provided synchronization handlers, +/ ff_mutex_create(), ff_mutex_delete(), ff_mutex_take() and ff_mutex_give(), +/ must be added to the project. Samples are available in ffsystem.c. +/ +/ The FF_FS_TIMEOUT defines timeout period in unit of O/S time tick. +*/ + + + +/*--- End of configuration options ---*/ diff --git a/src/wolfsftp.c b/src/wolfsftp.c index 24a35329e..d228ccffa 100644 --- a/src/wolfsftp.c +++ b/src/wolfsftp.c @@ -1479,7 +1479,8 @@ int wolfSSH_SFTP_read(WOLFSSH* ssh) wolfSSH_SFTP_buffer_data(&state->buffer), wolfSSH_SFTP_buffer_size(&state->buffer)); break; - #if !defined(_WIN32_WCE) && !defined(WOLFSSH_ZEPHYR) + #if !defined(_WIN32_WCE) && !defined(WOLFSSH_ZEPHYR) && \ + !defined(WOLFSSH_FATFS) case WOLFSSH_FTP_SETSTAT: ret = wolfSSH_SFTP_RecvSetSTAT(ssh, state->reqId, wolfSSH_SFTP_buffer_data(&state->buffer), @@ -4689,6 +4690,10 @@ static int SFTP_GetAttributes(void* fs, const char* fileName, FRESULT ret; int sz = (int)WSTRLEN(fileName); + (void) fs; + (void) noFollow; + (void) heap; + ret = f_stat(fileName, &info); if (ret != FR_OK) return -1; @@ -5191,7 +5196,7 @@ int wolfSSH_SFTP_RecvLSTAT(WOLFSSH* ssh, int reqId, byte* data, word32 maxSz) } #if !defined(USE_WINDOWS_API) && !defined(WOLFSSH_ZEPHYR) \ - && !defined(WOLFSSH_SFTP_SETMODE) + && !defined(WOLFSSH_SFTP_SETMODE) && !defined(WOLFSSH_FATFS) /* Set the files mode * return WS_SUCCESS on success */ static int SFTP_SetMode(void* fs, char* name, word32 mode) { @@ -5204,7 +5209,7 @@ static int SFTP_SetMode(void* fs, char* name, word32 mode) { #endif #if !defined(USE_WINDOWS_API) && !defined(WOLFSSH_ZEPHYR) \ - && !defined(WOLFSSH_SFTP_SETMODEHANDLE) + && !defined(WOLFSSH_SFTP_SETMODEHANDLE) && !defined(WOLFSSH_FATFS) /* Set the files mode * return WS_SUCCESS on success */ static int SFTP_SetModeHandle(void* fs, WFD handle, word32 mode) { @@ -5216,7 +5221,7 @@ static int SFTP_SetModeHandle(void* fs, WFD handle, word32 mode) { } #endif -#if !defined(_WIN32_WCE) && !defined(WOLFSSH_ZEPHYR) +#if !defined(_WIN32_WCE) && !defined(WOLFSSH_ZEPHYR) && !defined(WOLFSSH_FATFS) /* sets a files attributes * returns WS_SUCCESS on success */ diff --git a/wolfssh/port.h b/wolfssh/port.h index dbd0de9b9..375bef72b 100644 --- a/wolfssh/port.h +++ b/wolfssh/port.h @@ -101,7 +101,7 @@ extern "C" { #endif #endif /* !WOLFSSH_HANDLE */ -#ifdef NO_FILESYSTEM +#if defined(NO_FILESYSTEM) && !defined(WOLFSSH_FATFS) #define WS_DELIM '/' #elif defined(WOLFSSL_NUCLEUS) #include "storage/nu_storage.h" @@ -255,6 +255,7 @@ extern "C" { #define WSEEK_SET 0 #define WSEEK_CUR 1 #define WSEEK_END 2 + #define WFFLUSH(s) ((void)(s)) static inline int ff_fopen(WFILE** f, const char* filename, const char* mode) { @@ -264,11 +265,12 @@ extern "C" { if (!f) { return -1; } -#ifdef WOLFSSH_XILFATFS - m = FA_CREATE_ALWAYS; + if (*f == 0) { *f = WMALLOC(sizeof(FIL), NULL, 0); } +#ifdef WOLFSSH_XILFATFS + m = FA_CREATE_ALWAYS; #else m = FA_CREATE_NEW; #endif @@ -585,7 +587,8 @@ extern "C" { #if (defined(WOLFSSH_SFTP) || \ defined(WOLFSSH_SCP) || defined(WOLFSSH_SSHD)) && \ - !defined(NO_WOLFSSH_SERVER) && !defined(NO_FILESYSTEM) + !defined(NO_WOLFSSH_SERVER) && \ + (!defined(NO_FILESYSTEM) || defined(WOLFSSH_FATFS)) #ifndef SIZEOF_OFF_T /* if not using autoconf then make a guess on off_t size based on sizeof @@ -1192,7 +1195,7 @@ extern "C" { #define WSTAT(fs,p,b) f_stat(p,b) #define WLSTAT(fs,p,b) f_stat(p,b) #define WREMOVE(fs,d) f_unlink((d)) - #define WRENAME(fs,fd,o,n) f_rename((o),(n)) + #define WRENAME(fs,o,n) f_rename((o),(n)) #define WMKDIR(fs, p, m) f_mkdir(p) #define WFD int diff --git a/wolfssh/settings.h b/wolfssh/settings.h index 70ada34c9..75db751ad 100644 --- a/wolfssh/settings.h +++ b/wolfssh/settings.h @@ -52,6 +52,10 @@ extern "C" { #define USE_WOLFSSH_MEMORY /* default memory handlers */ #endif /* WMALLOC_USER */ +/* SFTP requires storehandle when fatfs is in use */ +#ifdef WOLFSSH_FATFS + #define WOLFSSH_STOREHANDLE +#endif #if defined (_WIN32) #define USE_WINDOWS_API