From ca71f22816e701dc5c16e22ca86dfb0d81ad3c20 Mon Sep 17 00:00:00 2001 From: Damien George Date: Fri, 23 Dec 2016 20:39:09 +1100 Subject: [PATCH 01/32] src: Remove diskio.c, it should be provided by user of the library. --- src/diskio.c | 229 --------------------------------------------------- 1 file changed, 229 deletions(-) delete mode 100644 src/diskio.c diff --git a/src/diskio.c b/src/diskio.c deleted file mode 100644 index 6413419..0000000 --- a/src/diskio.c +++ /dev/null @@ -1,229 +0,0 @@ -/*-----------------------------------------------------------------------*/ -/* Low level disk I/O module skeleton for FatFs (C)ChaN, 2016 */ -/*-----------------------------------------------------------------------*/ -/* If a working storage control module is available, it should be */ -/* attached to the FatFs via a glue function rather than modifying it. */ -/* This is an example of glue functions to attach various exsisting */ -/* storage control modules to the FatFs module with a defined API. */ -/*-----------------------------------------------------------------------*/ - -#include "ff.h" /* Obtains integer types */ -#include "diskio.h" /* Declarations of disk functions */ - -/* Definitions of physical drive number for each drive */ -#define DEV_RAM 0 /* Example: Map Ramdisk to physical drive 0 */ -#define DEV_MMC 1 /* Example: Map MMC/SD card to physical drive 1 */ -#define DEV_USB 2 /* Example: Map USB MSD to physical drive 2 */ - - -/*-----------------------------------------------------------------------*/ -/* Get Drive Status */ -/*-----------------------------------------------------------------------*/ - -DSTATUS disk_status ( - BYTE pdrv /* Physical drive nmuber to identify the drive */ -) -{ - DSTATUS stat; - int result; - - switch (pdrv) { - case DEV_RAM : - result = RAM_disk_status(); - - // translate the reslut code here - - return stat; - - case DEV_MMC : - result = MMC_disk_status(); - - // translate the reslut code here - - return stat; - - case DEV_USB : - result = USB_disk_status(); - - // translate the reslut code here - - return stat; - } - return STA_NOINIT; -} - - - -/*-----------------------------------------------------------------------*/ -/* Inidialize a Drive */ -/*-----------------------------------------------------------------------*/ - -DSTATUS disk_initialize ( - BYTE pdrv /* Physical drive nmuber to identify the drive */ -) -{ - DSTATUS stat; - int result; - - switch (pdrv) { - case DEV_RAM : - result = RAM_disk_initialize(); - - // translate the reslut code here - - return stat; - - case DEV_MMC : - result = MMC_disk_initialize(); - - // translate the reslut code here - - return stat; - - case DEV_USB : - result = USB_disk_initialize(); - - // translate the reslut code here - - return stat; - } - return STA_NOINIT; -} - - - -/*-----------------------------------------------------------------------*/ -/* Read Sector(s) */ -/*-----------------------------------------------------------------------*/ - -DRESULT disk_read ( - BYTE pdrv, /* Physical drive nmuber to identify the drive */ - BYTE *buff, /* Data buffer to store read data */ - DWORD sector, /* Start sector in LBA */ - UINT count /* Number of sectors to read */ -) -{ - DRESULT res; - int result; - - switch (pdrv) { - case DEV_RAM : - // translate the arguments here - - result = RAM_disk_read(buff, sector, count); - - // translate the reslut code here - - return res; - - case DEV_MMC : - // translate the arguments here - - result = MMC_disk_read(buff, sector, count); - - // translate the reslut code here - - return res; - - case DEV_USB : - // translate the arguments here - - result = USB_disk_read(buff, sector, count); - - // translate the reslut code here - - return res; - } - - return RES_PARERR; -} - - - -/*-----------------------------------------------------------------------*/ -/* Write Sector(s) */ -/*-----------------------------------------------------------------------*/ - -#if FF_FS_READONLY == 0 - -DRESULT disk_write ( - BYTE pdrv, /* Physical drive nmuber to identify the drive */ - const BYTE *buff, /* Data to be written */ - DWORD sector, /* Start sector in LBA */ - UINT count /* Number of sectors to write */ -) -{ - DRESULT res; - int result; - - switch (pdrv) { - case DEV_RAM : - // translate the arguments here - - result = RAM_disk_write(buff, sector, count); - - // translate the reslut code here - - return res; - - case DEV_MMC : - // translate the arguments here - - result = MMC_disk_write(buff, sector, count); - - // translate the reslut code here - - return res; - - case DEV_USB : - // translate the arguments here - - result = USB_disk_write(buff, sector, count); - - // translate the reslut code here - - return res; - } - - return RES_PARERR; -} - -#endif - - -/*-----------------------------------------------------------------------*/ -/* Miscellaneous Functions */ -/*-----------------------------------------------------------------------*/ - -DRESULT disk_ioctl ( - BYTE pdrv, /* Physical drive nmuber (0..) */ - BYTE cmd, /* Control code */ - void *buff /* Buffer to send/receive control data */ -) -{ - DRESULT res; - int result; - - switch (pdrv) { - case DEV_RAM : - - // Process of the command for the RAM drive - - return res; - - case DEV_MMC : - - // Process of the command for the MMC/SD card - - return res; - - case DEV_USB : - - // Process of the command the USB drive - - return res; - } - - return RES_PARERR; -} - From f46717fb2ef7caf7e80671e4704c6755130aadfb Mon Sep 17 00:00:00 2001 From: Damien George Date: Fri, 4 Mar 2016 22:43:29 +0000 Subject: [PATCH 02/32] src: Allow ffconf.h to be configurable, via FFCONF_H. --- src/ff.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ff.h b/src/ff.h index aa40bb4..718fcf4 100644 --- a/src/ff.h +++ b/src/ff.h @@ -26,7 +26,7 @@ extern "C" { #endif -#include "ffconf.h" /* FatFs configuration options */ +#include FFCONF_H /* FatFs configuration options */ #if FF_DEFINED != FFCONF_DEF #error Wrong configuration file (ffconf.h). From e30dd3324a5ae5f3e2103efd4b5f7780bbaed8e8 Mon Sep 17 00:00:00 2001 From: Damien George Date: Fri, 4 Mar 2016 22:54:02 +0000 Subject: [PATCH 03/32] src: Remove STRFUNC functions. --- src/ff.c | 458 ------------------------------------------------------- src/ff.h | 4 - 2 files changed, 462 deletions(-) diff --git a/src/ff.c b/src/ff.c index a9215e1..711059f 100644 --- a/src/ff.c +++ b/src/ff.c @@ -6065,464 +6065,6 @@ FRESULT f_fdisk ( - -#if FF_USE_STRFUNC -#if FF_USE_LFN && FF_LFN_UNICODE && (FF_STRF_ENCODE < 0 || FF_STRF_ENCODE > 3) -#error Wrong FF_STRF_ENCODE setting -#endif -/*-----------------------------------------------------------------------*/ -/* Get a String from the File */ -/*-----------------------------------------------------------------------*/ - -TCHAR* f_gets ( - TCHAR* buff, /* Pointer to the string buffer to read */ - int len, /* Size of string buffer (items) */ - FIL* fp /* Pointer to the file object */ -) -{ - int nc = 0; - TCHAR *p = buff; - BYTE s[4]; - UINT rc; - DWORD dc; -#if FF_USE_LFN && FF_LFN_UNICODE && FF_STRF_ENCODE <= 2 - WCHAR wc; -#endif -#if FF_USE_LFN && FF_LFN_UNICODE && FF_STRF_ENCODE == 3 - UINT ct; -#endif - -#if FF_USE_LFN && FF_LFN_UNICODE /* With code conversion (Unicode API) */ - /* Make a room for the character and terminator */ - if (FF_LFN_UNICODE == 1) len -= (FF_STRF_ENCODE == 0) ? 1 : 2; - if (FF_LFN_UNICODE == 2) len -= (FF_STRF_ENCODE == 0) ? 3 : 4; - if (FF_LFN_UNICODE == 3) len -= 1; - while (nc < len) { -#if FF_STRF_ENCODE == 0 /* Read a character in ANSI/OEM */ - f_read(fp, s, 1, &rc); - if (rc != 1) break; - wc = s[0]; - if (dbc_1st((BYTE)wc)) { - f_read(fp, s, 1, &rc); - if (rc != 1 || !dbc_2nd(s[0])) continue; - wc = wc << 8 | s[0]; - } - dc = ff_oem2uni(wc, CODEPAGE); - if (dc == 0) continue; -#elif FF_STRF_ENCODE == 1 || FF_STRF_ENCODE == 2 /* Read a character in UTF-16LE/BE */ - f_read(fp, s, 2, &rc); - if (rc != 2) break; - dc = (FF_STRF_ENCODE == 1) ? ld_word(s) : s[0] << 8 | s[1]; - if (IsSurrogateL(dc)) continue; - if (IsSurrogateH(dc)) { - f_read(fp, s, 2, &rc); - if (rc != 2) break; - wc = (FF_STRF_ENCODE == 1) ? ld_word(s) : s[0] << 8 | s[1]; - if (!IsSurrogateL(wc)) continue; - dc = ((dc & 0x3FF) + 0x40) << 10 | (wc & 0x3FF); - } -#else /* Read a character in UTF-8 */ - f_read(fp, s, 1, &rc); - if (rc != 1) break; - dc = s[0]; - if (dc >= 0x80) { /* Multi-byte character? */ - ct = 0; - if ((dc & 0xE0) == 0xC0) { dc &= 0x1F; ct = 1; } /* 2-byte? */ - if ((dc & 0xF0) == 0xE0) { dc &= 0x0F; ct = 2; } /* 3-byte? */ - if ((dc & 0xF8) == 0xF0) { dc &= 0x07; ct = 3; } /* 4-byte? */ - if (ct == 0) continue; - f_read(fp, s, ct, &rc); /* Get trailing bytes */ - if (rc != ct) break; - rc = 0; - do { /* Merge trailing bytes */ - if ((s[rc] & 0xC0) != 0x80) break; - dc = dc << 6 | (s[rc] & 0x3F); - } while (++rc < ct); - if (rc != ct || dc < 0x80 || IsSurrogate(dc) || dc >= 0x110000) continue; /* Wrong encoding? */ - } -#endif - if (FF_USE_STRFUNC == 2 && dc == '\r') continue; /* Strip \r off if needed */ -#if FF_LFN_UNICODE == 1 || FF_LFN_UNICODE == 3 /* Output it in UTF-16/32 encoding */ - if (FF_LFN_UNICODE == 1 && dc >= 0x10000) { /* Out of BMP at UTF-16? */ - *p++ = (TCHAR)(0xD800 | ((dc >> 10) - 0x40)); nc++; /* Make and output high surrogate */ - dc = 0xDC00 | (dc & 0x3FF); /* Make low surrogate */ - } - *p++ = (TCHAR)dc; nc++; - if (dc == '\n') break; /* End of line? */ -#elif FF_LFN_UNICODE == 2 /* Output it in UTF-8 encoding */ - if (dc < 0x80) { /* 1-byte */ - *p++ = (TCHAR)dc; - nc++; - if (dc == '\n') break; /* End of line? */ - } else { - if (dc < 0x800) { /* 2-byte */ - *p++ = (TCHAR)(0xC0 | (dc >> 6 & 0x1F)); - *p++ = (TCHAR)(0x80 | (dc >> 0 & 0x3F)); - nc += 2; - } else { - if (dc < 0x10000) { /* 3-byte */ - *p++ = (TCHAR)(0xE0 | (dc >> 12 & 0x0F)); - *p++ = (TCHAR)(0x80 | (dc >> 6 & 0x3F)); - *p++ = (TCHAR)(0x80 | (dc >> 0 & 0x3F)); - nc += 3; - } else { /* 4-byte */ - *p++ = (TCHAR)(0xF0 | (dc >> 18 & 0x07)); - *p++ = (TCHAR)(0x80 | (dc >> 12 & 0x3F)); - *p++ = (TCHAR)(0x80 | (dc >> 6 & 0x3F)); - *p++ = (TCHAR)(0x80 | (dc >> 0 & 0x3F)); - nc += 4; - } - } - } -#endif - } - -#else /* Byte-by-byte without any conversion (ANSI/OEM API) */ - len -= 1; /* Make a room for the terminator */ - while (nc < len) { - f_read(fp, s, 1, &rc); - if (rc != 1) break; - dc = s[0]; - if (FF_USE_STRFUNC == 2 && dc == '\r') continue; - *p++ = (TCHAR)dc; nc++; - if (dc == '\n') break; - } -#endif - - *p = 0; /* Terminate the string */ - return nc ? buff : 0; /* When no data read due to EOF or error, return with error. */ -} - - - - -#if !FF_FS_READONLY -#include -/*-----------------------------------------------------------------------*/ -/* Put a Character to the File */ -/*-----------------------------------------------------------------------*/ - -typedef struct { /* Putchar output buffer and work area */ - FIL *fp; /* Ptr to the writing file */ - int idx, nchr; /* Write index of buf[] (-1:error), number of encoding units written */ -#if FF_USE_LFN && FF_LFN_UNICODE == 1 - WCHAR hs; -#elif FF_USE_LFN && FF_LFN_UNICODE == 2 - BYTE bs[4]; - UINT wi, ct; -#endif - BYTE buf[64]; /* Write buffer */ -} putbuff; - - -static void putc_bfd ( /* Buffered write with code conversion */ - putbuff* pb, - TCHAR c -) -{ - UINT n; - int i, nc; -#if FF_USE_LFN && FF_LFN_UNICODE - WCHAR hs, wc; -#if FF_LFN_UNICODE == 2 - DWORD dc; - TCHAR *tp; -#endif -#endif - - if (FF_USE_STRFUNC == 2 && c == '\n') { /* LF -> CRLF conversion */ - putc_bfd(pb, '\r'); - } - - i = pb->idx; /* Write index of pb->buf[] */ - if (i < 0) return; - nc = pb->nchr; /* Write unit counter */ - -#if FF_USE_LFN && FF_LFN_UNICODE -#if FF_LFN_UNICODE == 1 /* UTF-16 input */ - if (IsSurrogateH(c)) { - pb->hs = c; return; - } - hs = pb->hs; pb->hs = 0; - if (hs != 0) { - if (!IsSurrogateL(c)) hs = 0; - } else { - if (IsSurrogateL(c)) return; - } - wc = c; -#elif FF_LFN_UNICODE == 2 /* UTF-8 input */ - for (;;) { - if (pb->ct == 0) { /* Out of multi-byte sequence? */ - pb->bs[pb->wi = 0] = (BYTE)c; /* Save 1st byte */ - if ((BYTE)c < 0x80) break; /* 1-byte? */ - if (((BYTE)c & 0xE0) == 0xC0) pb->ct = 1; /* 2-byte? */ - if (((BYTE)c & 0xF0) == 0xE0) pb->ct = 2; /* 3-byte? */ - if (((BYTE)c & 0xF1) == 0xF0) pb->ct = 3; /* 4-byte? */ - return; - } else { /* In the multi-byte sequence */ - if (((BYTE)c & 0xC0) != 0x80) { /* Broken sequence? */ - pb->ct = 0; continue; - } - pb->bs[++pb->wi] = (BYTE)c; /* Save the trailing byte */ - if (--pb->ct == 0) break; /* End of multi-byte sequence? */ - return; - } - } - tp = (TCHAR*)pb->bs; - dc = tchar2uni(&tp); /* UTF-8 ==> UTF-16 */ - if (dc == 0xFFFFFFFF) return; - wc = (WCHAR)dc; - hs = (WCHAR)(dc >> 16); -#elif FF_LFN_UNICODE == 3 /* UTF-32 input */ - if (IsSurrogate(c) || c >= 0x110000) return; - if (c >= 0x10000) { - hs = (WCHAR)(0xD800 | ((c >> 10) - 0x40)); /* Make high surrogate */ - wc = 0xDC00 | (c & 0x3FF); /* Make low surrogate */ - } else { - hs = 0; - wc = (WCHAR)c; - } -#endif - -#if FF_STRF_ENCODE == 1 /* Write a character in UTF-16LE */ - if (hs != 0) { - st_word(&pb->buf[i], hs); - i += 2; - nc++; - } - st_word(&pb->buf[i], wc); - i += 2; -#elif FF_STRF_ENCODE == 2 /* Write a character in UTF-16BE */ - if (hs != 0) { - pb->buf[i++] = (BYTE)(hs >> 8); - pb->buf[i++] = (BYTE)hs; - nc++; - } - pb->buf[i++] = (BYTE)(wc >> 8); - pb->buf[i++] = (BYTE)wc; -#elif FF_STRF_ENCODE == 3 /* Write it in UTF-8 */ - if (hs != 0) { /* 4-byte */ - nc += 3; - hs = (hs & 0x3FF) + 0x40; - pb->buf[i++] = (BYTE)(0xF0 | hs >> 8); - pb->buf[i++] = (BYTE)(0x80 | (hs >> 2 & 0x3F)); - pb->buf[i++] = (BYTE)(0x80 | (hs & 3) << 4 | (wc >> 6 & 0x0F)); - pb->buf[i++] = (BYTE)(0x80 | (wc & 0x3F)); - } else { - if (wc < 0x80) { /* 1-byte */ - pb->buf[i++] = (BYTE)wc; - } else { - if (wc < 0x800) { /* 2-byte */ - nc += 1; - pb->buf[i++] = (BYTE)(0xC0 | wc >> 6); - } else { /* 3-byte */ - nc += 2; - pb->buf[i++] = (BYTE)(0xE0 | wc >> 12); - pb->buf[i++] = (BYTE)(0x80 | (wc >> 6 & 0x3F)); - } - pb->buf[i++] = (BYTE)(0x80 | (wc & 0x3F)); - } - } -#else /* Write it in ANSI/OEM */ - if (hs != 0) return; - wc = ff_uni2oem(wc, CODEPAGE); /* UTF-16 ==> ANSI/OEM */ - if (wc == 0) return; - if (wc >= 0x100) { - pb->buf[i++] = (BYTE)(wc >> 8); nc++; - } - pb->buf[i++] = (BYTE)wc; -#endif - -#else /* ANSI/OEM input (without re-encode) */ - pb->buf[i++] = (BYTE)c; -#endif - - if (i >= (int)(sizeof pb->buf) - 4) { /* Write buffered characters to the file */ - f_write(pb->fp, pb->buf, (UINT)i, &n); - i = (n == (UINT)i) ? 0 : -1; - } - pb->idx = i; - pb->nchr = nc + 1; -} - - -static int putc_flush ( /* Flush left characters in the buffer */ - putbuff* pb -) -{ - UINT nw; - - if ( pb->idx >= 0 /* Flush buffered characters to the file */ - && f_write(pb->fp, pb->buf, (UINT)pb->idx, &nw) == FR_OK - && (UINT)pb->idx == nw) return pb->nchr; - return EOF; -} - - -static void putc_init ( /* Initialize write buffer */ - putbuff* pb, - FIL* fp -) -{ - mem_set(pb, 0, sizeof (putbuff)); - pb->fp = fp; -} - - - -int f_putc ( - TCHAR c, /* A character to be output */ - FIL* fp /* Pointer to the file object */ -) -{ - putbuff pb; - - - putc_init(&pb, fp); - putc_bfd(&pb, c); /* Put the character */ - return putc_flush(&pb); -} - - - - -/*-----------------------------------------------------------------------*/ -/* Put a String to the File */ -/*-----------------------------------------------------------------------*/ - -int f_puts ( - const TCHAR* str, /* Pointer to the string to be output */ - FIL* fp /* Pointer to the file object */ -) -{ - putbuff pb; - - - putc_init(&pb, fp); - while (*str) putc_bfd(&pb, *str++); /* Put the string */ - return putc_flush(&pb); -} - - - - -/*-----------------------------------------------------------------------*/ -/* Put a Formatted String to the File */ -/*-----------------------------------------------------------------------*/ - -int f_printf ( - FIL* fp, /* Pointer to the file object */ - const TCHAR* fmt, /* Pointer to the format string */ - ... /* Optional arguments... */ -) -{ - va_list arp; - putbuff pb; - BYTE f, r; - UINT i, j, w; - DWORD v; - TCHAR c, d, str[32], *p; - - - putc_init(&pb, fp); - - va_start(arp, fmt); - - for (;;) { - c = *fmt++; - if (c == 0) break; /* End of string */ - if (c != '%') { /* Non escape character */ - putc_bfd(&pb, c); - continue; - } - w = f = 0; - c = *fmt++; - if (c == '0') { /* Flag: '0' padding */ - f = 1; c = *fmt++; - } else { - if (c == '-') { /* Flag: left justified */ - f = 2; c = *fmt++; - } - } - if (c == '*') { /* Minimum width by argument */ - w = va_arg(arp, int); - c = *fmt++; - } else { - while (IsDigit(c)) { /* Minimum width */ - w = w * 10 + c - '0'; - c = *fmt++; - } - } - if (c == 'l' || c == 'L') { /* Type prefix: Size is long int */ - f |= 4; c = *fmt++; - } - if (c == 0) break; - d = c; - if (IsLower(d)) d -= 0x20; - switch (d) { /* Atgument type is... */ - case 'S' : /* String */ - p = va_arg(arp, TCHAR*); - for (j = 0; p[j]; j++) ; - if (!(f & 2)) { /* Right padded */ - while (j++ < w) putc_bfd(&pb, ' ') ; - } - while (*p) putc_bfd(&pb, *p++) ; /* String body */ - while (j++ < w) putc_bfd(&pb, ' ') ; /* Left padded */ - continue; - - case 'C' : /* Character */ - putc_bfd(&pb, (TCHAR)va_arg(arp, int)); continue; - - case 'B' : /* Unsigned binary */ - r = 2; break; - - case 'O' : /* Unsigned octal */ - r = 8; break; - - case 'D' : /* Signed decimal */ - case 'U' : /* Unsigned decimal */ - r = 10; break; - - case 'X' : /* Unsigned hexdecimal */ - r = 16; break; - - default: /* Unknown type (pass-through) */ - putc_bfd(&pb, c); continue; - } - - /* Get an argument and put it in numeral */ - v = (f & 4) ? (DWORD)va_arg(arp, long) : ((d == 'D') ? (DWORD)(long)va_arg(arp, int) : (DWORD)va_arg(arp, unsigned int)); - if (d == 'D' && (v & 0x80000000)) { - v = 0 - v; - f |= 8; - } - i = 0; - do { - d = (TCHAR)(v % r); v /= r; - if (d > 9) d += (c == 'x') ? 0x27 : 0x07; - str[i++] = d + '0'; - } while (v && i < sizeof str / sizeof *str); - if (f & 8) str[i++] = '-'; - j = i; d = (f & 1) ? '0' : ' '; - if (!(f & 2)) { - while (j++ < w) putc_bfd(&pb, d); /* Right pad */ - } - do { - putc_bfd(&pb, str[--i]); /* Number body */ - } while (i); - while (j++ < w) putc_bfd(&pb, d); /* Left pad */ - } - - va_end(arp); - - return putc_flush(&pb); -} - -#endif /* !FF_FS_READONLY */ -#endif /* FF_USE_STRFUNC */ - - - #if FF_CODE_PAGE == 0 /*-----------------------------------------------------------------------*/ /* Set Active Codepage for the Path Name */ diff --git a/src/ff.h b/src/ff.h index 718fcf4..0f7918e 100644 --- a/src/ff.h +++ b/src/ff.h @@ -310,10 +310,6 @@ FRESULT f_mount (FATFS* fs, const TCHAR* path, BYTE opt); /* Mount/Unm FRESULT f_mkfs (const TCHAR* path, BYTE opt, DWORD au, void* work, UINT len); /* Create a FAT volume */ FRESULT f_fdisk (BYTE pdrv, const DWORD* szt, void* work); /* Divide a physical drive into some partitions */ FRESULT f_setcp (WORD cp); /* Set current code page */ -int f_putc (TCHAR c, FIL* fp); /* Put a character to the file */ -int f_puts (const TCHAR* str, FIL* cp); /* Put a string to the file */ -int f_printf (FIL* fp, const TCHAR* str, ...); /* Put a formatted string to the file */ -TCHAR* f_gets (TCHAR* buff, int len, FIL* fp); /* Get a string from the file */ #define f_eof(fp) ((int)((fp)->fptr == (fp)->obj.objsize)) #define f_error(fp) ((fp)->err) From 5388dbfa43f2f0358491c8615e7bd42d6bd73ea5 Mon Sep 17 00:00:00 2001 From: Damien George Date: Fri, 4 Mar 2016 23:19:49 +0000 Subject: [PATCH 04/32] src: Make disk_XXX functions take a block device as first argument. --- src/diskio.h | 10 ++++----- src/ff.c | 57 +++++++++++++++++++++++++--------------------------- src/ff.h | 4 ++-- 3 files changed, 34 insertions(+), 37 deletions(-) diff --git a/src/diskio.h b/src/diskio.h index 8bf054a..9c13099 100644 --- a/src/diskio.h +++ b/src/diskio.h @@ -26,11 +26,11 @@ typedef enum { /* Prototypes for disk control functions */ -DSTATUS disk_initialize (BYTE pdrv); -DSTATUS disk_status (BYTE pdrv); -DRESULT disk_read (BYTE pdrv, BYTE* buff, DWORD sector, UINT count); -DRESULT disk_write (BYTE pdrv, const BYTE* buff, DWORD sector, UINT count); -DRESULT disk_ioctl (BYTE pdrv, BYTE cmd, void* buff); +DSTATUS disk_initialize (void *drv); +DSTATUS disk_status (void *drv); +DRESULT disk_read (void *drv, BYTE* buff, DWORD sector, UINT count); +DRESULT disk_write (void *drv, const BYTE* buff, DWORD sector, UINT count); +DRESULT disk_ioctl (void *drv, BYTE cmd, void* buff); /* Disk Status Bits (DSTATUS) */ diff --git a/src/ff.c b/src/ff.c index 711059f..74c76fa 100644 --- a/src/ff.c +++ b/src/ff.c @@ -222,10 +222,8 @@ /* Definitions of volume - physical location conversion */ #if FF_MULTI_PARTITION -#define LD2PD(vol) VolToPart[vol].pd /* Get physical drive number */ #define LD2PT(vol) VolToPart[vol].pt /* Get partition index */ #else -#define LD2PD(vol) (BYTE)(vol) /* Each logical drive is bound to the same physical drive number */ #define LD2PT(vol) 0 /* Find first valid partition or in SFD */ #endif @@ -1047,10 +1045,10 @@ static FRESULT sync_window ( /* Returns FR_OK or FR_DISK_ERR */ if (fs->wflag) { /* Is the disk access window dirty */ - if (disk_write(fs->pdrv, fs->win, fs->winsect, 1) == RES_OK) { /* Write back the window */ + if (disk_write(fs->drv, fs->win, fs->winsect, 1) == RES_OK) { /* Write back the window */ fs->wflag = 0; /* Clear window dirty flag */ if (fs->winsect - fs->fatbase < fs->fsize) { /* Is it in the 1st FAT? */ - if (fs->n_fats == 2) disk_write(fs->pdrv, fs->win, fs->winsect + fs->fsize, 1); /* Reflect it to 2nd FAT if needed */ + if (fs->n_fats == 2) disk_write(fs->drv, fs->win, fs->winsect + fs->fsize, 1); /* Reflect it to 2nd FAT if needed */ } } else { res = FR_DISK_ERR; @@ -1074,7 +1072,7 @@ static FRESULT move_window ( /* Returns FR_OK or FR_DISK_ERR */ res = sync_window(fs); /* Write-back changes */ #endif if (res == FR_OK) { /* Fill sector window with new data */ - if (disk_read(fs->pdrv, fs->win, sector, 1) != RES_OK) { + if (disk_read(fs->drv, fs->win, sector, 1) != RES_OK) { sector = 0xFFFFFFFF; /* Invalidate window if read data is not valid */ res = FR_DISK_ERR; } @@ -1111,11 +1109,11 @@ static FRESULT sync_fs ( /* Returns FR_OK or FR_DISK_ERR */ st_dword(fs->win + FSI_Nxt_Free, fs->last_clst); /* Write it into the FSInfo sector */ fs->winsect = fs->volbase + 1; - disk_write(fs->pdrv, fs->win, fs->winsect, 1); + disk_write(fs->drv, fs->win, fs->winsect, 1); fs->fsi_flag = 0; } /* Make sure that no pending write process in the lower layer */ - if (disk_ioctl(fs->pdrv, CTRL_SYNC, 0) != RES_OK) res = FR_DISK_ERR; + if (disk_ioctl(fs->drv, CTRL_SYNC, 0) != RES_OK) res = FR_DISK_ERR; } return res; @@ -1464,7 +1462,7 @@ static FRESULT remove_chain ( /* FR_OK(0):succeeded, !=0:error */ #if FF_USE_TRIM rt[0] = clst2sect(fs, scl); /* Start of data area freed */ rt[1] = clst2sect(fs, ecl) + fs->csize - 1; /* End of data area freed */ - disk_ioctl(fs->pdrv, CTRL_TRIM, rt); /* Inform device the data in the block is no longer needed */ + disk_ioctl(fs->drv, CTRL_TRIM, rt); /* Inform device the data in the block is no longer needed */ #endif scl = ecl = nxt; } @@ -1661,13 +1659,13 @@ static FRESULT dir_clear ( /* Returns FR_OK or FR_DISK_ERR */ if (szb > SS(fs)) { /* Buffer allocated? */ mem_set(ibuf, 0, szb); szb /= SS(fs); /* Bytes -> Sectors */ - for (n = 0; n < fs->csize && disk_write(fs->pdrv, ibuf, sect + n, szb) == RES_OK; n += szb) ; /* Fill the cluster with 0 */ + for (n = 0; n < fs->csize && disk_write(fs->drv, ibuf, sect + n, szb) == RES_OK; n += szb) ; /* Fill the cluster with 0 */ ff_memfree(ibuf); } else #endif { ibuf = fs->win; szb = 1; /* Use window buffer (many single-sector writes may take a time) */ - for (n = 0; n < fs->csize && disk_write(fs->pdrv, ibuf, sect + n, szb) == RES_OK; n += szb) ; /* Fill the cluster with 0 */ + for (n = 0; n < fs->csize && disk_write(fs->drv, ibuf, sect + n, szb) == RES_OK; n += szb) ; /* Fill the cluster with 0 */ } return (n == fs->csize) ? FR_OK : FR_DISK_ERR; } @@ -3252,7 +3250,6 @@ static FRESULT find_volume ( /* FR_OK(0): successful, !=0: an error occurred /* Following code attempts to mount the volume. (analyze BPB and initialize the filesystem object) */ fs->fs_type = 0; /* Clear the filesystem object */ - fs->pdrv = LD2PD(vol); /* Bind the logical drive and a physical drive */ stat = disk_initialize(fs->pdrv); /* Initialize the physical drive */ if (stat & STA_NOINIT) { /* Check if the initialization succeeded */ return FR_NOT_READY; /* Failed to initialize due to no medium or hard error */ @@ -3261,7 +3258,7 @@ static FRESULT find_volume ( /* FR_OK(0): successful, !=0: an error occurred return FR_WRITE_PROTECTED; } #if FF_MAX_SS != FF_MIN_SS /* Get sector size (multiple sector size cfg only) */ - if (disk_ioctl(fs->pdrv, GET_SECTOR_SIZE, &SS(fs)) != RES_OK) return FR_DISK_ERR; + if (disk_ioctl(fs->drv, GET_SECTOR_SIZE, &SS(fs)) != RES_OK) return FR_DISK_ERR; if (SS(fs) > FF_MAX_SS || SS(fs) < FF_MIN_SS || (SS(fs) & (SS(fs) - 1))) return FR_DISK_ERR; #endif @@ -3709,7 +3706,7 @@ FRESULT f_open ( } else { fp->sect = sc + (DWORD)(ofs / SS(fs)); #if !FF_FS_TINY - if (disk_read(fs->pdrv, fp->buf, fp->sect, 1) != RES_OK) res = FR_DISK_ERR; + if (disk_read(fs->drv, fp->buf, fp->sect, 1) != RES_OK) res = FR_DISK_ERR; #endif } } @@ -3783,7 +3780,7 @@ FRESULT f_read ( if (csect + cc > fs->csize) { /* Clip at cluster boundary */ cc = fs->csize - csect; } - if (disk_read(fs->pdrv, rbuff, sect, cc) != RES_OK) ABORT(fs, FR_DISK_ERR); + if (disk_read(fs->drv, rbuff, sect, cc) != RES_OK) ABORT(fs, FR_DISK_ERR); #if !FF_FS_READONLY && FF_FS_MINIMIZE <= 2 /* Replace one of the read sectors with cached data if it contains a dirty sector */ #if FF_FS_TINY if (fs->wflag && fs->winsect - sect < cc) { @@ -3802,11 +3799,11 @@ FRESULT f_read ( if (fp->sect != sect) { /* Load data sector if not in cache */ #if !FF_FS_READONLY if (fp->flag & FA_DIRTY) { /* Write-back dirty sector cache */ - if (disk_write(fs->pdrv, fp->buf, fp->sect, 1) != RES_OK) ABORT(fs, FR_DISK_ERR); + if (disk_write(fs->drv, fp->buf, fp->sect, 1) != RES_OK) ABORT(fs, FR_DISK_ERR); fp->flag &= (BYTE)~FA_DIRTY; } #endif - if (disk_read(fs->pdrv, fp->buf, sect, 1) != RES_OK) ABORT(fs, FR_DISK_ERR); /* Fill sector cache */ + if (disk_read(fs->drv, fp->buf, sect, 1) != RES_OK) ABORT(fs, FR_DISK_ERR); /* Fill sector cache */ } #endif fp->sect = sect; @@ -3886,7 +3883,7 @@ FRESULT f_write ( if (fs->winsect == fp->sect && sync_window(fs) != FR_OK) ABORT(fs, FR_DISK_ERR); /* Write-back sector cache */ #else if (fp->flag & FA_DIRTY) { /* Write-back sector cache */ - if (disk_write(fs->pdrv, fp->buf, fp->sect, 1) != RES_OK) ABORT(fs, FR_DISK_ERR); + if (disk_write(fs->drv, fp->buf, fp->sect, 1) != RES_OK) ABORT(fs, FR_DISK_ERR); fp->flag &= (BYTE)~FA_DIRTY; } #endif @@ -3898,7 +3895,7 @@ FRESULT f_write ( if (csect + cc > fs->csize) { /* Clip at cluster boundary */ cc = fs->csize - csect; } - if (disk_write(fs->pdrv, wbuff, sect, cc) != RES_OK) ABORT(fs, FR_DISK_ERR); + if (disk_write(fs->drv, wbuff, sect, cc) != RES_OK) ABORT(fs, FR_DISK_ERR); #if FF_FS_MINIMIZE <= 2 #if FF_FS_TINY if (fs->winsect - sect < cc) { /* Refill sector cache if it gets invalidated by the direct write */ @@ -3923,7 +3920,7 @@ FRESULT f_write ( #else if (fp->sect != sect && /* Fill sector cache with file data */ fp->fptr < fp->obj.objsize && - disk_read(fs->pdrv, fp->buf, sect, 1) != RES_OK) { + disk_read(fs->drv, fp->buf, sect, 1) != RES_OK) { ABORT(fs, FR_DISK_ERR); } #endif @@ -3968,7 +3965,7 @@ FRESULT f_sync ( if (fp->flag & FA_MODIFIED) { /* Is there any change to the file? */ #if !FF_FS_TINY if (fp->flag & FA_DIRTY) { /* Write-back cached data if needed */ - if (disk_write(fs->pdrv, fp->buf, fp->sect, 1) != RES_OK) LEAVE_FF(fs, FR_DISK_ERR); + if (disk_write(fs->drv, fp->buf, fp->sect, 1) != RES_OK) LEAVE_FF(fs, FR_DISK_ERR); fp->flag &= (BYTE)~FA_DIRTY; } #endif @@ -4310,11 +4307,11 @@ FRESULT f_lseek ( #if !FF_FS_TINY #if !FF_FS_READONLY if (fp->flag & FA_DIRTY) { /* Write-back dirty sector cache */ - if (disk_write(fs->pdrv, fp->buf, fp->sect, 1) != RES_OK) ABORT(fs, FR_DISK_ERR); + if (disk_write(fs->drv, fp->buf, fp->sect, 1) != RES_OK) ABORT(fs, FR_DISK_ERR); fp->flag &= (BYTE)~FA_DIRTY; } #endif - if (disk_read(fs->pdrv, fp->buf, dsc, 1) != RES_OK) ABORT(fs, FR_DISK_ERR); /* Load current sector */ + if (disk_read(fs->drv, fp->buf, dsc, 1) != RES_OK) ABORT(fs, FR_DISK_ERR); /* Load current sector */ #endif fp->sect = dsc; } @@ -4390,11 +4387,11 @@ FRESULT f_lseek ( #if !FF_FS_TINY #if !FF_FS_READONLY if (fp->flag & FA_DIRTY) { /* Write-back dirty sector cache */ - if (disk_write(fs->pdrv, fp->buf, fp->sect, 1) != RES_OK) ABORT(fs, FR_DISK_ERR); + if (disk_write(fs->drv, fp->buf, fp->sect, 1) != RES_OK) ABORT(fs, FR_DISK_ERR); fp->flag &= (BYTE)~FA_DIRTY; } #endif - if (disk_read(fs->pdrv, fp->buf, nsect, 1) != RES_OK) ABORT(fs, FR_DISK_ERR); /* Fill sector cache */ + if (disk_read(fs->drv, fp->buf, nsect, 1) != RES_OK) ABORT(fs, FR_DISK_ERR); /* Fill sector cache */ #endif fp->sect = nsect; } @@ -4748,7 +4745,7 @@ FRESULT f_truncate ( fp->flag |= FA_MODIFIED; #if !FF_FS_TINY if (res == FR_OK && (fp->flag & FA_DIRTY)) { - if (disk_write(fs->pdrv, fp->buf, fp->sect, 1) != RES_OK) { + if (disk_write(fs->drv, fp->buf, fp->sect, 1) != RES_OK) { res = FR_DISK_ERR; } else { fp->flag &= (BYTE)~FA_DIRTY; @@ -5500,11 +5497,11 @@ FRESULT f_forward ( if (fp->sect != sect) { /* Fill sector cache with file data */ #if !FF_FS_READONLY if (fp->flag & FA_DIRTY) { /* Write-back dirty sector cache */ - if (disk_write(fs->pdrv, fp->buf, fp->sect, 1) != RES_OK) ABORT(fs, FR_DISK_ERR); + if (disk_write(fs->drv, fp->buf, fp->sect, 1) != RES_OK) ABORT(fs, FR_DISK_ERR); fp->flag &= (BYTE)~FA_DIRTY; } #endif - if (disk_read(fs->pdrv, fp->buf, sect, 1) != RES_OK) ABORT(fs, FR_DISK_ERR); + if (disk_read(fs->drv, fp->buf, sect, 1) != RES_OK) ABORT(fs, FR_DISK_ERR); } dbuf = fp->buf; #endif @@ -5538,7 +5535,7 @@ FRESULT f_mkfs ( const UINT n_rootdir = 512; /* Number of root directory entries for FAT volume */ static const WORD cst[] = {1, 4, 16, 64, 256, 512, 0}; /* Cluster size boundary for FAT volume (4Ks unit) */ static const WORD cst32[] = {1, 2, 4, 8, 16, 32, 0}; /* Cluster size boundary for FAT32 volume (128Ks unit) */ - BYTE fmt, sys, *buf, *pte, pdrv, part; + BYTE fmt, sys, *buf, *pte, part; void *pdrv; WORD ss; /* Sector size */ DWORD szb_buf, sz_buf, sz_blk, n_clst, pau, sect, nsect, n; DWORD b_vol, b_fat, b_data; /* Base LBA for volume, fat, data */ @@ -5555,7 +5552,7 @@ FRESULT f_mkfs ( vol = get_ldnumber(&path); /* Get target logical drive */ if (vol < 0) return FR_INVALID_DRIVE; if (FatFs[vol]) FatFs[vol]->fs_type = 0; /* Clear the volume if mounted */ - pdrv = LD2PD(vol); /* Physical drive */ + pdrv = fs->drv; /* Physical drive */ part = LD2PT(vol); /* Partition (0:create as new, 1-4:get from partition table) */ /* Check physical drive status */ @@ -5992,7 +5989,7 @@ FRESULT f_mkfs ( /*-----------------------------------------------------------------------*/ FRESULT f_fdisk ( - BYTE pdrv, /* Physical drive number */ + void *pdrv, /* Physical drive number */ const DWORD* szt, /* Pointer to the size table for each partitions */ void* work /* Pointer to the working buffer (null: use heap memory) */ ) diff --git a/src/ff.h b/src/ff.h index 0f7918e..5e09b76 100644 --- a/src/ff.h +++ b/src/ff.h @@ -121,8 +121,8 @@ typedef DWORD FSIZE_t; /* Filesystem object structure (FATFS) */ typedef struct { + void *drv; // block device underlying this filesystem BYTE fs_type; /* Filesystem type (0:not mounted) */ - BYTE pdrv; /* Associated physical drive */ BYTE n_fats; /* Number of FATs (1 or 2) */ BYTE wflag; /* win[] flag (b0:dirty) */ BYTE fsi_flag; /* FSINFO flags (b7:disabled, b0:dirty) */ @@ -308,7 +308,7 @@ FRESULT f_forward (FIL* fp, UINT(*func)(const BYTE*,UINT), UINT btf, UINT* bf); FRESULT f_expand (FIL* fp, FSIZE_t szf, BYTE opt); /* Allocate a contiguous block to the file */ FRESULT f_mount (FATFS* fs, const TCHAR* path, BYTE opt); /* Mount/Unmount a logical drive */ FRESULT f_mkfs (const TCHAR* path, BYTE opt, DWORD au, void* work, UINT len); /* Create a FAT volume */ -FRESULT f_fdisk (BYTE pdrv, const DWORD* szt, void* work); /* Divide a physical drive into some partitions */ +FRESULT f_fdisk (void *pdrv, const DWORD* szt, void* work); /* Divide a physical drive into some partitions */ FRESULT f_setcp (WORD cp); /* Set current code page */ #define f_eof(fp) ((int)((fp)->fptr == (fp)->obj.objsize)) From ef6c4222830bbb00dcdacadf2cd6a47901449251 Mon Sep 17 00:00:00 2001 From: Damien George Date: Fri, 4 Mar 2016 23:58:27 +0000 Subject: [PATCH 05/32] src: Replace disk_initialize and disk_status with ioctl commands. --- src/diskio.h | 4 ++-- src/ff.c | 13 +++++++------ 2 files changed, 9 insertions(+), 8 deletions(-) diff --git a/src/diskio.h b/src/diskio.h index 9c13099..608937f 100644 --- a/src/diskio.h +++ b/src/diskio.h @@ -26,8 +26,6 @@ typedef enum { /* Prototypes for disk control functions */ -DSTATUS disk_initialize (void *drv); -DSTATUS disk_status (void *drv); DRESULT disk_read (void *drv, BYTE* buff, DWORD sector, UINT count); DRESULT disk_write (void *drv, const BYTE* buff, DWORD sector, UINT count); DRESULT disk_ioctl (void *drv, BYTE cmd, void* buff); @@ -48,6 +46,8 @@ DRESULT disk_ioctl (void *drv, BYTE cmd, void* buff); #define GET_SECTOR_SIZE 2 /* Get sector size (needed at FF_MAX_SS != FF_MIN_SS) */ #define GET_BLOCK_SIZE 3 /* Get erase block size (needed at FF_USE_MKFS == 1) */ #define CTRL_TRIM 4 /* Inform device that the data on the block of sectors is no longer used (needed at FF_USE_TRIM == 1) */ +#define IOCTL_INIT 5 +#define IOCTL_STATUS 6 /* Generic command (Not used by FatFs) */ #define CTRL_POWER 5 /* Get/Set power status */ diff --git a/src/ff.c b/src/ff.c index 74c76fa..4ecc899 100644 --- a/src/ff.c +++ b/src/ff.c @@ -3237,7 +3237,7 @@ static FRESULT find_volume ( /* FR_OK(0): successful, !=0: an error occurred mode &= (BYTE)~FA_READ; /* Desired access mode, write access or not */ if (fs->fs_type != 0) { /* If the volume has been mounted */ - stat = disk_status(fs->pdrv); + disk_ioctl(fs->drv, IOCTL_STATUS, &stat); if (!(stat & STA_NOINIT)) { /* and the physical drive is kept initialized */ if (!FF_FS_READONLY && mode && (stat & STA_PROTECT)) { /* Check write protection if needed */ return FR_WRITE_PROTECTED; @@ -3250,7 +3250,7 @@ static FRESULT find_volume ( /* FR_OK(0): successful, !=0: an error occurred /* Following code attempts to mount the volume. (analyze BPB and initialize the filesystem object) */ fs->fs_type = 0; /* Clear the filesystem object */ - stat = disk_initialize(fs->pdrv); /* Initialize the physical drive */ + disk_ioctl(fs->drv, IOCTL_INIT, &stat); /* Initialize the physical drive */ if (stat & STA_NOINIT) { /* Check if the initialization succeeded */ return FR_NOT_READY; /* Failed to initialize due to no medium or hard error */ } @@ -3453,12 +3453,13 @@ static FRESULT validate ( /* Returns FR_OK or FR_INVALID_OBJECT */ ) { FRESULT res = FR_INVALID_OBJECT; + DSTATUS stat; if (obj && obj->fs && obj->fs->fs_type && obj->id == obj->fs->id) { /* Test if the object is valid */ #if FF_FS_REENTRANT if (lock_fs(obj->fs)) { /* Obtain the filesystem object */ - if (!(disk_status(obj->fs->pdrv) & STA_NOINIT)) { /* Test if the phsical drive is kept initialized */ + if (disk_ioctl(obj->fs->drv, IOCTL_STATUS, &stat) == RES_OK && !(stat & STA_NOINIT)) { /* Test if the phsical drive is kept initialized */ res = FR_OK; } else { unlock_fs(obj->fs, FR_OK); @@ -3467,7 +3468,7 @@ static FRESULT validate ( /* Returns FR_OK or FR_INVALID_OBJECT */ res = FR_TIMEOUT; } #else - if (!(disk_status(obj->fs->pdrv) & STA_NOINIT)) { /* Test if the phsical drive is kept initialized */ + if (disk_ioctl(obj->fs->drv, IOCTL_STATUS, &stat) == RES_OK && (!stat & STA_NOINIT)) { /* Test if the phsical drive is kept initialized */ res = FR_OK; } #endif @@ -5556,7 +5557,7 @@ FRESULT f_mkfs ( part = LD2PT(vol); /* Partition (0:create as new, 1-4:get from partition table) */ /* Check physical drive status */ - stat = disk_initialize(pdrv); + disk_ioctl(pdrv, IOCTL_INIT, &stat); if (stat & STA_NOINIT) return FR_NOT_READY; if (stat & STA_PROTECT) return FR_WRITE_PROTECTED; if (disk_ioctl(pdrv, GET_BLOCK_SIZE, &sz_blk) != RES_OK || !sz_blk || sz_blk > 32768 || (sz_blk & (sz_blk - 1))) sz_blk = 1; /* Erase block to align data area */ @@ -6001,7 +6002,7 @@ FRESULT f_fdisk ( FRESULT res; - stat = disk_initialize(pdrv); + disk_ioctl(pdrv, IOCTL_INIT, &stat); if (stat & STA_NOINIT) return FR_NOT_READY; if (stat & STA_PROTECT) return FR_WRITE_PROTECTED; if (disk_ioctl(pdrv, GET_SECTOR_COUNT, &sz_disk)) return FR_DISK_ERR; From f6bd1b96bbfbf8fb573048e18e1db272c3929536 Mon Sep 17 00:00:00 2001 From: Damien George Date: Sat, 5 Mar 2016 00:14:19 +0000 Subject: [PATCH 06/32] src: Make f_mkfs take a FATFS as argument instead of a path. --- src/ff.c | 19 ++++++++----------- src/ff.h | 13 ++++--------- 2 files changed, 12 insertions(+), 20 deletions(-) diff --git a/src/ff.c b/src/ff.c index 4ecc899..957fac6 100644 --- a/src/ff.c +++ b/src/ff.c @@ -222,9 +222,9 @@ /* Definitions of volume - physical location conversion */ #if FF_MULTI_PARTITION -#define LD2PT(vol) VolToPart[vol].pt /* Get partition index */ +#define LD2PT(fs) (fs->part) /* Get partition index */ #else -#define LD2PT(vol) 0 /* Find first valid partition or in SFD */ +#define LD2PT(fs) 0 /* Find first valid partition or in SFD */ #endif @@ -3265,17 +3265,17 @@ static FRESULT find_volume ( /* FR_OK(0): successful, !=0: an error occurred /* Find an FAT partition on the drive. Supports only generic partitioning rules, FDISK (MBR) and SFD (w/o partition). */ bsect = 0; fmt = check_fs(fs, bsect); /* Load sector 0 and check if it is an FAT-VBR as SFD */ - if (fmt == 2 || (fmt < 2 && LD2PT(vol) != 0)) { /* Not an FAT-VBR or forced partition number */ + if (fmt == 2 || (fmt < 2 && LD2PT(fs) != 0)) { /* Not an FAT-VBR or forced partition number */ for (i = 0; i < 4; i++) { /* Get partition offset */ pt = fs->win + (MBR_Table + i * SZ_PTE); br[i] = pt[PTE_System] ? ld_dword(pt + PTE_StLba) : 0; } - i = LD2PT(vol); /* Partition number: 0:auto, 1-4:forced */ + i = LD2PT(fs); /* Partition number: 0:auto, 1-4:forced */ if (i != 0) i--; do { /* Find an FAT volume */ bsect = br[i]; fmt = bsect ? check_fs(fs, bsect) : 3; /* Check the partition */ - } while (LD2PT(vol) == 0 && fmt >= 2 && ++i < 4); + } while (LD2PT(fs) == 0 && fmt >= 2 && ++i < 4); } if (fmt == 4) return FR_DISK_ERR; /* An error occured in the disk I/O layer */ if (fmt >= 2) return FR_NO_FILESYSTEM; /* No FAT volume is found */ @@ -5525,7 +5525,7 @@ FRESULT f_forward ( /*-----------------------------------------------------------------------*/ FRESULT f_mkfs ( - const TCHAR* path, /* Logical drive number */ + FATFS *fs, BYTE opt, /* Format option */ DWORD au, /* Size of allocation unit (cluster) [byte] */ void* work, /* Pointer to working buffer (null: use heap memory) */ @@ -5542,7 +5542,6 @@ FRESULT f_mkfs ( DWORD b_vol, b_fat, b_data; /* Base LBA for volume, fat, data */ DWORD sz_vol, sz_rsv, sz_fat, sz_dir; /* Size for volume, fat, dir, data */ UINT i; - int vol; DSTATUS stat; #if FF_USE_TRIM || FF_FS_EXFAT DWORD tbl[3]; @@ -5550,11 +5549,9 @@ FRESULT f_mkfs ( /* Check mounted drive and clear work area */ - vol = get_ldnumber(&path); /* Get target logical drive */ - if (vol < 0) return FR_INVALID_DRIVE; - if (FatFs[vol]) FatFs[vol]->fs_type = 0; /* Clear the volume if mounted */ + fs->fs_type = 0; /* Clear mounted volume */ pdrv = fs->drv; /* Physical drive */ - part = LD2PT(vol); /* Partition (0:create as new, 1-4:get from partition table) */ + part = LD2PT(fs); /* Partition (0:create as new, 1-4:get from partition table) */ /* Check physical drive status */ disk_ioctl(pdrv, IOCTL_INIT, &stat); diff --git a/src/ff.h b/src/ff.h index 5e09b76..062a9a4 100644 --- a/src/ff.h +++ b/src/ff.h @@ -60,14 +60,6 @@ typedef unsigned long DWORD; /* 32-bit unsigned integer */ /* Definitions of volume management */ -#if FF_MULTI_PARTITION /* Multiple partition configuration */ -typedef struct { - BYTE pd; /* Physical drive number */ - BYTE pt; /* Partition: 0:Auto detect, 1-4:Forced partition) */ -} PARTITION; -extern PARTITION VolToPart[]; /* Volume - Partition resolution table */ -#endif - #if FF_STR_VOLUME_ID #ifndef FF_VOLUME_STRS extern const char* VolumeStr[FF_VOLUMES]; /* User defied volume ID */ @@ -122,6 +114,9 @@ typedef DWORD FSIZE_t; typedef struct { void *drv; // block device underlying this filesystem +#if FF_MULTI_PARTITION /* Multiple partition configuration */ + BYTE part; // Partition: 0:Auto detect, 1-4:Forced partition +#endif BYTE fs_type; /* Filesystem type (0:not mounted) */ BYTE n_fats; /* Number of FATs (1 or 2) */ BYTE wflag; /* win[] flag (b0:dirty) */ @@ -307,7 +302,7 @@ FRESULT f_setlabel (const TCHAR* label); /* Set volum FRESULT f_forward (FIL* fp, UINT(*func)(const BYTE*,UINT), UINT btf, UINT* bf); /* Forward data to the stream */ FRESULT f_expand (FIL* fp, FSIZE_t szf, BYTE opt); /* Allocate a contiguous block to the file */ FRESULT f_mount (FATFS* fs, const TCHAR* path, BYTE opt); /* Mount/Unmount a logical drive */ -FRESULT f_mkfs (const TCHAR* path, BYTE opt, DWORD au, void* work, UINT len); /* Create a FAT volume */ +FRESULT f_mkfs (FATFS *fs, BYTE opt, DWORD au, void* work, UINT len); /* Create a FAT volume */ FRESULT f_fdisk (void *pdrv, const DWORD* szt, void* work); /* Divide a physical drive into some partitions */ FRESULT f_setcp (WORD cp); /* Set current code page */ From 330e81cc2d22f6590650c2ce961a40e174898f18 Mon Sep 17 00:00:00 2001 From: Damien George Date: Mon, 7 Mar 2016 13:41:20 +0000 Subject: [PATCH 07/32] src: Split out umount functionality from f_mount to new f_umount. --- src/ff.c | 22 +++++++++++++++++----- src/ff.h | 1 + 2 files changed, 18 insertions(+), 5 deletions(-) diff --git a/src/ff.c b/src/ff.c index 957fac6..f1f5d6d 100644 --- a/src/ff.c +++ b/src/ff.c @@ -3493,7 +3493,7 @@ static FRESULT validate ( /* Returns FR_OK or FR_INVALID_OBJECT */ /*-----------------------------------------------------------------------*/ FRESULT f_mount ( - FATFS* fs, /* Pointer to the filesystem object (NULL:unmount)*/ + FATFS* fs, /* Pointer to the file system object to mount */ const TCHAR* path, /* Logical drive number to be mounted/unmounted */ BYTE opt /* Mode option 0:Do not mount (delayed mount), 1:Mount immediately */ ) @@ -3519,12 +3519,10 @@ FRESULT f_mount ( cfs->fs_type = 0; /* Clear old fs object */ } - if (fs) { - fs->fs_type = 0; /* Clear new fs object */ + fs->fs_type = 0; /* Clear new fs object */ #if FF_FS_REENTRANT /* Create sync object for the new volume */ - if (!ff_cre_syncobj((BYTE)vol, &fs->sobj)) return FR_INT_ERR; + if (!ff_cre_syncobj((BYTE)vol, &fs->sobj)) return FR_INT_ERR; #endif - } FatFs[vol] = fs; /* Register new fs object */ if (opt == 0) return FR_OK; /* Do not mount now, it will be mounted later */ @@ -3534,6 +3532,20 @@ FRESULT f_mount ( } +FRESULT f_umount ( + FATFS* fs /* Pointer to the file system object to unmount */ +) +{ +#if FF_FS_LOCK + clear_lock(fs); +#endif +#if FF_FS_REENTRANT /* Discard sync object of the current volume */ + if (!ff_del_syncobj(fs->sobj)) return FR_INT_ERR; +#endif + fs->fs_type = 0; /* Clear old fs object */ + + return FR_OK; +} /*-----------------------------------------------------------------------*/ diff --git a/src/ff.h b/src/ff.h index 062a9a4..19f1bc7 100644 --- a/src/ff.h +++ b/src/ff.h @@ -302,6 +302,7 @@ FRESULT f_setlabel (const TCHAR* label); /* Set volum FRESULT f_forward (FIL* fp, UINT(*func)(const BYTE*,UINT), UINT btf, UINT* bf); /* Forward data to the stream */ FRESULT f_expand (FIL* fp, FSIZE_t szf, BYTE opt); /* Allocate a contiguous block to the file */ FRESULT f_mount (FATFS* fs, const TCHAR* path, BYTE opt); /* Mount/Unmount a logical drive */ +FRESULT f_umount (FATFS* fs); /* Unmount a logical drive */ FRESULT f_mkfs (FATFS *fs, BYTE opt, DWORD au, void* work, UINT len); /* Create a FAT volume */ FRESULT f_fdisk (void *pdrv, const DWORD* szt, void* work); /* Divide a physical drive into some partitions */ FRESULT f_setcp (WORD cp); /* Set current code page */ From a2cc913afffe1c0a7c6bb062396507589d87d61e Mon Sep 17 00:00:00 2001 From: Damien George Date: Mon, 7 Mar 2016 14:04:30 +0000 Subject: [PATCH 08/32] src: Make all necessary functions take FATFS* as first argument. This removes the global FatFs[] structure, being the list of mounted filesystems. Instead, just pass the desired FS to the function. --- src/ff.c | 102 +++++++++++++++++-------------------------------------- src/ff.h | 28 +++++++-------- 2 files changed, 45 insertions(+), 85 deletions(-) diff --git a/src/ff.c b/src/ff.c index f1f5d6d..c488481 100644 --- a/src/ff.c +++ b/src/ff.c @@ -433,7 +433,6 @@ typedef struct { #if FF_VOLUMES < 1 || FF_VOLUMES > 10 #error Wrong FF_VOLUMES setting #endif -static FATFS* FatFs[FF_VOLUMES]; /* Pointer to the filesystem objects (logical drives) */ static WORD Fsid; /* Filesystem mount ID */ #if FF_FS_RPATH != 0 @@ -3208,32 +3207,20 @@ static BYTE check_fs ( /* 0:FAT, 1:exFAT, 2:Valid BS but not FAT, 3:Not a BS, 4 /*-----------------------------------------------------------------------*/ static FRESULT find_volume ( /* FR_OK(0): successful, !=0: an error occurred */ - const TCHAR** path, /* Pointer to pointer to the path name (drive number) */ - FATFS** rfs, /* Pointer to pointer to the found filesystem object */ + FATFS *fs, /* Pointer to the file system object */ BYTE mode /* !=0: Check write protection for write access */ ) { BYTE fmt, *pt; - int vol; DSTATUS stat; DWORD bsect, fasize, tsect, sysect, nclst, szbfat, br[4]; WORD nrsv; - FATFS *fs; UINT i; - /* Get logical drive number */ - *rfs = 0; - vol = get_ldnumber(path); - if (vol < 0) return FR_INVALID_DRIVE; - - /* Check if the filesystem object is valid or not */ - fs = FatFs[vol]; /* Get pointer to the filesystem object */ - if (!fs) return FR_NOT_ENABLED; /* Is the filesystem object available? */ #if FF_FS_REENTRANT if (!lock_fs(fs)) return FR_TIMEOUT; /* Lock the volume */ #endif - *rfs = fs; /* Return pointer to the filesystem object */ mode &= (BYTE)~FA_READ; /* Desired access mode, write access or not */ if (fs->fs_type != 0) { /* If the volume has been mounted */ @@ -3493,41 +3480,17 @@ static FRESULT validate ( /* Returns FR_OK or FR_INVALID_OBJECT */ /*-----------------------------------------------------------------------*/ FRESULT f_mount ( - FATFS* fs, /* Pointer to the file system object to mount */ - const TCHAR* path, /* Logical drive number to be mounted/unmounted */ - BYTE opt /* Mode option 0:Do not mount (delayed mount), 1:Mount immediately */ + FATFS* fs /* Pointer to the file system object to mount */ ) { - FATFS *cfs; - int vol; FRESULT res; - const TCHAR *rp = path; - - - /* Get logical drive number */ - vol = get_ldnumber(&rp); - if (vol < 0) return FR_INVALID_DRIVE; - cfs = FatFs[vol]; /* Pointer to fs object */ - - if (cfs) { -#if FF_FS_LOCK != 0 - clear_lock(cfs); -#endif -#if FF_FS_REENTRANT /* Discard sync object of the current volume */ - if (!ff_del_syncobj(cfs->sobj)) return FR_INT_ERR; -#endif - cfs->fs_type = 0; /* Clear old fs object */ - } fs->fs_type = 0; /* Clear new fs object */ #if FF_FS_REENTRANT /* Create sync object for the new volume */ if (!ff_cre_syncobj((BYTE)vol, &fs->sobj)) return FR_INT_ERR; #endif - FatFs[vol] = fs; /* Register new fs object */ - - if (opt == 0) return FR_OK; /* Do not mount now, it will be mounted later */ - res = find_volume(&path, &fs, 0); /* Force mounted the volume */ + res = find_volume(fs, 0); /* Force mounted the volume */ LEAVE_FF(fs, res); } @@ -3553,6 +3516,7 @@ FRESULT f_umount ( /*-----------------------------------------------------------------------*/ FRESULT f_open ( + FATFS *fs, FIL* fp, /* Pointer to the blank file object */ const TCHAR* path, /* Pointer to the file name */ BYTE mode /* Access mode and file open mode flags */ @@ -3560,7 +3524,6 @@ FRESULT f_open ( { FRESULT res; DIR dj; - FATFS *fs; #if !FF_FS_READONLY DWORD dw, cl, bcs, clst, sc; FSIZE_t ofs; @@ -3572,7 +3535,7 @@ FRESULT f_open ( /* Get logical drive number */ mode &= FF_FS_READONLY ? FA_READ : FA_READ | FA_WRITE | FA_CREATE_ALWAYS | FA_CREATE_NEW | FA_OPEN_ALWAYS | FA_OPEN_APPEND; - res = find_volume(&path, &fs, mode); + res = find_volume(fs, mode); if (res == FR_OK) { dj.obj.fs = fs; INIT_NAMBUF(fs); @@ -4098,6 +4061,7 @@ FRESULT f_chdrive ( FRESULT f_chdir ( + FATFS *fs, const TCHAR* path /* Pointer to the directory path */ ) { @@ -4106,12 +4070,11 @@ FRESULT f_chdir ( #endif FRESULT res; DIR dj; - FATFS *fs; DEF_NAMBUF /* Get logical drive */ - res = find_volume(&path, &fs, 0); + res = find_volume(fs, 0); if (res == FR_OK) { dj.obj.fs = fs; INIT_NAMBUF(fs); @@ -4160,13 +4123,13 @@ FRESULT f_chdir ( #if FF_FS_RPATH >= 2 FRESULT f_getcwd ( + FATFS *fs, TCHAR* buff, /* Pointer to the directory path */ UINT len /* Size of buff in unit of TCHAR */ ) { FRESULT res; DIR dj; - FATFS *fs; UINT i, n; DWORD ccl; TCHAR *tp = buff; @@ -4182,7 +4145,7 @@ FRESULT f_getcwd ( /* Get logical drive */ buff[0] = 0; /* Set null string to get current volume */ - res = find_volume((const TCHAR**)&buff, &fs, 0); /* Get current volume */ + res = find_volume(fs, 0); /* Get current volume */ if (res == FR_OK) { dj.obj.fs = fs; INIT_NAMBUF(fs); @@ -4421,19 +4384,19 @@ FRESULT f_lseek ( /*-----------------------------------------------------------------------*/ FRESULT f_opendir ( + FATFS *fs, DIR* dp, /* Pointer to directory object to create */ const TCHAR* path /* Pointer to the directory path */ ) { FRESULT res; - FATFS *fs; DEF_NAMBUF if (!dp) return FR_INVALID_OBJECT; /* Get logical drive */ - res = find_volume(&path, &fs, 0); + res = find_volume(fs, 0); if (res == FR_OK) { dp->obj.fs = fs; INIT_NAMBUF(fs); @@ -4605,6 +4568,7 @@ FRESULT f_findfirst ( /*-----------------------------------------------------------------------*/ FRESULT f_stat ( + FATFS *fs, const TCHAR* path, /* Pointer to the file path */ FILINFO* fno /* Pointer to file information to return */ ) @@ -4615,7 +4579,8 @@ FRESULT f_stat ( /* Get logical drive */ - res = find_volume(&path, &dj.obj.fs, 0); + res = find_volume(fs, 0); + dj.obj.fs = fs; if (res == FR_OK) { INIT_NAMBUF(dj.obj.fs); res = follow_path(&dj, path); /* Follow the file path */ @@ -4640,22 +4605,19 @@ FRESULT f_stat ( /*-----------------------------------------------------------------------*/ FRESULT f_getfree ( - const TCHAR* path, /* Logical drive number */ - DWORD* nclst, /* Pointer to a variable to return number of free clusters */ - FATFS** fatfs /* Pointer to return pointer to corresponding filesystem object */ + FATFS *fs, + DWORD* nclst /* Pointer to a variable to return number of free clusters */ ) { FRESULT res; - FATFS *fs; DWORD nfree, clst, sect, stat; UINT i; FFOBJID obj; /* Get logical drive */ - res = find_volume(&path, &fs, 0); + res = find_volume(fs, 0); if (res == FR_OK) { - *fatfs = fs; /* Return ptr to the fs object */ /* If free_clst is valid, return it without full FAT scan */ if (fs->free_clst <= fs->n_fatent - 2) { *nclst = fs->free_clst; @@ -4779,13 +4741,13 @@ FRESULT f_truncate ( /*-----------------------------------------------------------------------*/ FRESULT f_unlink ( + FATFS *fs, const TCHAR* path /* Pointer to the file or directory path */ ) { FRESULT res; DIR dj, sdj; DWORD dclst = 0; - FATFS *fs; #if FF_FS_EXFAT FFOBJID obj; #endif @@ -4793,7 +4755,7 @@ FRESULT f_unlink ( /* Get logical drive */ - res = find_volume(&path, &fs, FA_WRITE); + res = find_volume(fs, FA_WRITE); if (res == FR_OK) { dj.obj.fs = fs; INIT_NAMBUF(fs); @@ -4873,18 +4835,18 @@ FRESULT f_unlink ( /*-----------------------------------------------------------------------*/ FRESULT f_mkdir ( + FATFS *fs, const TCHAR* path /* Pointer to the directory path */ ) { FRESULT res; DIR dj; FFOBJID sobj; - FATFS *fs; DWORD dcl, pcl, tm; DEF_NAMBUF - res = find_volume(&path, &fs, FA_WRITE); /* Get logical drive */ + res = find_volume(fs, FA_WRITE); /* Get logical drive */ if (res == FR_OK) { dj.obj.fs = fs; INIT_NAMBUF(fs); @@ -4957,20 +4919,19 @@ FRESULT f_mkdir ( /*-----------------------------------------------------------------------*/ FRESULT f_rename ( + FATFS *fs, const TCHAR* path_old, /* Pointer to the object name to be renamed */ const TCHAR* path_new /* Pointer to the new name */ ) { FRESULT res; DIR djo, djn; - FATFS *fs; BYTE buf[FF_FS_EXFAT ? SZDIRE * 2 : SZDIRE], *dir; DWORD dw; DEF_NAMBUF - get_ldnumber(&path_new); /* Snip the drive number of new name off */ - res = find_volume(&path_old, &fs, FA_WRITE); /* Get logical drive of the old object */ + res = find_volume(fs, FA_WRITE); /* Get logical drive of the old object */ if (res == FR_OK) { djo.obj.fs = fs; INIT_NAMBUF(fs); @@ -5067,6 +5028,7 @@ FRESULT f_rename ( /*-----------------------------------------------------------------------*/ FRESULT f_chmod ( + FATFS *fs, const TCHAR* path, /* Pointer to the file path */ BYTE attr, /* Attribute bits */ BYTE mask /* Attribute mask to change */ @@ -5074,11 +5036,10 @@ FRESULT f_chmod ( { FRESULT res; DIR dj; - FATFS *fs; DEF_NAMBUF - res = find_volume(&path, &fs, FA_WRITE); /* Get logical drive */ + res = find_volume(fs, FA_WRITE); /* Get logical drive */ if (res == FR_OK) { dj.obj.fs = fs; INIT_NAMBUF(fs); @@ -5114,17 +5075,17 @@ FRESULT f_chmod ( /*-----------------------------------------------------------------------*/ FRESULT f_utime ( + FATFS *fs, const TCHAR* path, /* Pointer to the file/directory name */ const FILINFO* fno /* Pointer to the timestamp to be set */ ) { FRESULT res; DIR dj; - FATFS *fs; DEF_NAMBUF - res = find_volume(&path, &fs, FA_WRITE); /* Get logical drive */ + res = find_volume(fs, FA_WRITE); /* Get logical drive */ if (res == FR_OK) { dj.obj.fs = fs; INIT_NAMBUF(fs); @@ -5161,19 +5122,18 @@ FRESULT f_utime ( /*-----------------------------------------------------------------------*/ FRESULT f_getlabel ( - const TCHAR* path, /* Logical drive number */ + FATFS *fs, TCHAR* label, /* Buffer to store the volume label */ DWORD* vsn /* Variable to store the volume serial number */ ) { FRESULT res; DIR dj; - FATFS *fs; UINT si, di; WCHAR wc; /* Get logical drive */ - res = find_volume(&path, &fs, 0); + res = find_volume(fs, 0); /* Get volume label */ if (res == FR_OK && label) { @@ -5256,12 +5216,12 @@ FRESULT f_getlabel ( /*-----------------------------------------------------------------------*/ FRESULT f_setlabel ( + FATFS *fs, const TCHAR* label /* Volume label to set with heading logical drive number */ ) { FRESULT res; DIR dj; - FATFS *fs; BYTE dirvn[22]; UINT di; WCHAR wc; @@ -5271,7 +5231,7 @@ FRESULT f_setlabel ( #endif /* Get logical drive */ - res = find_volume(&label, &fs, FA_WRITE); + res = find_volume(fs, FA_WRITE); if (res != FR_OK) LEAVE_FF(fs, res); #if FF_FS_EXFAT diff --git a/src/ff.h b/src/ff.h index 19f1bc7..b403f3a 100644 --- a/src/ff.h +++ b/src/ff.h @@ -275,33 +275,33 @@ typedef enum { /*--------------------------------------------------------------*/ /* FatFs module application interface */ -FRESULT f_open (FIL* fp, const TCHAR* path, BYTE mode); /* Open or create a file */ +FRESULT f_open (FATFS *fs, FIL* fp, const TCHAR* path, BYTE mode); /* Open or create a file */ FRESULT f_close (FIL* fp); /* Close an open file object */ FRESULT f_read (FIL* fp, void* buff, UINT btr, UINT* br); /* Read data from the file */ FRESULT f_write (FIL* fp, const void* buff, UINT btw, UINT* bw); /* Write data to the file */ FRESULT f_lseek (FIL* fp, FSIZE_t ofs); /* Move file pointer of the file object */ FRESULT f_truncate (FIL* fp); /* Truncate the file */ FRESULT f_sync (FIL* fp); /* Flush cached data of the writing file */ -FRESULT f_opendir (DIR* dp, const TCHAR* path); /* Open a directory */ +FRESULT f_opendir (FATFS *fs, DIR* dp, const TCHAR* path); /* Open a directory */ FRESULT f_closedir (DIR* dp); /* Close an open directory */ FRESULT f_readdir (DIR* dp, FILINFO* fno); /* Read a directory item */ FRESULT f_findfirst (DIR* dp, FILINFO* fno, const TCHAR* path, const TCHAR* pattern); /* Find first file */ FRESULT f_findnext (DIR* dp, FILINFO* fno); /* Find next file */ -FRESULT f_mkdir (const TCHAR* path); /* Create a sub directory */ -FRESULT f_unlink (const TCHAR* path); /* Delete an existing file or directory */ -FRESULT f_rename (const TCHAR* path_old, const TCHAR* path_new); /* Rename/Move a file or directory */ -FRESULT f_stat (const TCHAR* path, FILINFO* fno); /* Get file status */ -FRESULT f_chmod (const TCHAR* path, BYTE attr, BYTE mask); /* Change attribute of a file/dir */ -FRESULT f_utime (const TCHAR* path, const FILINFO* fno); /* Change timestamp of a file/dir */ -FRESULT f_chdir (const TCHAR* path); /* Change current directory */ +FRESULT f_mkdir (FATFS *fs, const TCHAR* path); /* Create a sub directory */ +FRESULT f_unlink (FATFS *fs, const TCHAR* path); /* Delete an existing file or directory */ +FRESULT f_rename (FATFS *fs, const TCHAR* path_old, const TCHAR* path_new); /* Rename/Move a file or directory */ +FRESULT f_stat (FATFS *fs, const TCHAR* path, FILINFO* fno); /* Get file status */ +FRESULT f_chmod (FATFS *fs, const TCHAR* path, BYTE attr, BYTE mask); /* Change attribute of a file/dir */ +FRESULT f_utime (FATFS *fs, const TCHAR* path, const FILINFO* fno); /* Change timestamp of a file/dir */ +FRESULT f_chdir (FATFS *fs, const TCHAR* path); /* Change current directory */ FRESULT f_chdrive (const TCHAR* path); /* Change current drive */ -FRESULT f_getcwd (TCHAR* buff, UINT len); /* Get current directory */ -FRESULT f_getfree (const TCHAR* path, DWORD* nclst, FATFS** fatfs); /* Get number of free clusters on the drive */ -FRESULT f_getlabel (const TCHAR* path, TCHAR* label, DWORD* vsn); /* Get volume label */ -FRESULT f_setlabel (const TCHAR* label); /* Set volume label */ +FRESULT f_getcwd (FATFS *fs, TCHAR* buff, UINT len); /* Get current directory */ +FRESULT f_getfree (FATFS *fs, DWORD* nclst); /* Get number of free clusters on the drive */ +FRESULT f_getlabel (FATFS *fs, TCHAR* label, DWORD* vsn); /* Get volume label */ +FRESULT f_setlabel (FATFS *fs, const TCHAR* label); /* Set volume label */ FRESULT f_forward (FIL* fp, UINT(*func)(const BYTE*,UINT), UINT btf, UINT* bf); /* Forward data to the stream */ FRESULT f_expand (FIL* fp, FSIZE_t szf, BYTE opt); /* Allocate a contiguous block to the file */ -FRESULT f_mount (FATFS* fs, const TCHAR* path, BYTE opt); /* Mount/Unmount a logical drive */ +FRESULT f_mount (FATFS* fs); /* Mount/Unmount a logical drive */ FRESULT f_umount (FATFS* fs); /* Unmount a logical drive */ FRESULT f_mkfs (FATFS *fs, BYTE opt, DWORD au, void* work, UINT len); /* Create a FAT volume */ FRESULT f_fdisk (void *pdrv, const DWORD* szt, void* work); /* Divide a physical drive into some partitions */ From 7571bf6a85241524aa784e30efcc23ed888607fc Mon Sep 17 00:00:00 2001 From: Damien George Date: Mon, 7 Mar 2016 14:10:14 +0000 Subject: [PATCH 09/32] src: Remove get_ldnumber, CurrVol and f_chdrive. --- src/ff.c | 95 -------------------------------------------------------- src/ff.h | 1 - 2 files changed, 96 deletions(-) diff --git a/src/ff.c b/src/ff.c index c488481..c4d1441 100644 --- a/src/ff.c +++ b/src/ff.c @@ -435,10 +435,6 @@ typedef struct { #endif static WORD Fsid; /* Filesystem mount ID */ -#if FF_FS_RPATH != 0 -static BYTE CurrVol; /* Current drive */ -#endif - #if FF_FS_LOCK != 0 static FILESEM Files[FF_FS_LOCK]; /* Open object lock semaphores */ #endif @@ -3101,80 +3097,6 @@ static FRESULT follow_path ( /* FR_OK(0): successful, !=0: error code */ -/*-----------------------------------------------------------------------*/ -/* Get logical drive number from path name */ -/*-----------------------------------------------------------------------*/ - -static int get_ldnumber ( /* Returns logical drive number (-1:invalid drive number or null pointer) */ - const TCHAR** path /* Pointer to pointer to the path name */ -) -{ - const TCHAR *tp, *tt; - TCHAR tc; - int i, vol = -1; -#if FF_STR_VOLUME_ID /* Find string volume ID */ - const char *sp; - char c; -#endif - - tt = tp = *path; - if (!tp) return vol; /* Invalid path name? */ - do tc = *tt++; while ((UINT)tc >= (FF_USE_LFN ? ' ' : '!') && tc != ':'); /* Find a colon in the path */ - - if (tc == ':') { /* DOS/Windows style volume ID? */ - i = FF_VOLUMES; - if (IsDigit(*tp) && tp + 2 == tt) { /* Is there a numeric volume ID + colon? */ - i = (int)*tp - '0'; /* Get the LD number */ - } -#if FF_STR_VOLUME_ID == 1 /* Arbitrary string is enabled */ - else { - i = 0; - do { - sp = VolumeStr[i]; tp = *path; /* This string volume ID and path name */ - do { /* Compare the volume ID with path name */ - c = *sp++; tc = *tp++; - if (IsLower(c)) c -= 0x20; - if (IsLower(tc)) tc -= 0x20; - } while (c && (TCHAR)c == tc); - } while ((c || tp != tt) && ++i < FF_VOLUMES); /* Repeat for each id until pattern match */ - } -#endif - if (i < FF_VOLUMES) { /* If a volume ID is found, get the drive number and strip it */ - vol = i; /* Drive number */ - *path = tt; /* Snip the drive prefix off */ - } - return vol; - } -#if FF_STR_VOLUME_ID == 2 /* Unix style volume ID is enabled */ - if (*tp == '/') { - i = 0; - do { - sp = VolumeStr[i]; tp = *path; /* This string volume ID and path name */ - do { /* Compare the volume ID with path name */ - c = *sp++; tc = *(++tp); - if (IsLower(c)) c -= 0x20; - if (IsLower(tc)) tc -= 0x20; - } while (c && (TCHAR)c == tc); - } while ((c || (tc != '/' && (UINT)tc >= (FF_USE_LFN ? ' ' : '!'))) && ++i < FF_VOLUMES); /* Repeat for each ID until pattern match */ - if (i < FF_VOLUMES) { /* If a volume ID is found, get the drive number and strip it */ - vol = i; /* Drive number */ - *path = tp; /* Snip the drive prefix off */ - return vol; - } - } -#endif - /* No drive prefix is found */ -#if FF_FS_RPATH != 0 - vol = CurrVol; /* Default drive is current drive */ -#else - vol = 0; /* Default drive is 0 */ -#endif - return vol; /* Return the default drive */ -} - - - - /*-----------------------------------------------------------------------*/ /* Load a sector and check if it is an FAT VBR */ /*-----------------------------------------------------------------------*/ @@ -4043,23 +3965,6 @@ FRESULT f_close ( /* Change Current Directory or Current Drive, Get Current Directory */ /*-----------------------------------------------------------------------*/ -FRESULT f_chdrive ( - const TCHAR* path /* Drive number to set */ -) -{ - int vol; - - - /* Get logical drive number */ - vol = get_ldnumber(&path); - if (vol < 0) return FR_INVALID_DRIVE; - CurrVol = (BYTE)vol; /* Set it as current volume */ - - return FR_OK; -} - - - FRESULT f_chdir ( FATFS *fs, const TCHAR* path /* Pointer to the directory path */ diff --git a/src/ff.h b/src/ff.h index b403f3a..f54cf30 100644 --- a/src/ff.h +++ b/src/ff.h @@ -294,7 +294,6 @@ FRESULT f_stat (FATFS *fs, const TCHAR* path, FILINFO* fno); /* Get file FRESULT f_chmod (FATFS *fs, const TCHAR* path, BYTE attr, BYTE mask); /* Change attribute of a file/dir */ FRESULT f_utime (FATFS *fs, const TCHAR* path, const FILINFO* fno); /* Change timestamp of a file/dir */ FRESULT f_chdir (FATFS *fs, const TCHAR* path); /* Change current directory */ -FRESULT f_chdrive (const TCHAR* path); /* Change current drive */ FRESULT f_getcwd (FATFS *fs, TCHAR* buff, UINT len); /* Get current directory */ FRESULT f_getfree (FATFS *fs, DWORD* nclst); /* Get number of free clusters on the drive */ FRESULT f_getlabel (FATFS *fs, TCHAR* label, DWORD* vsn); /* Get volume label */ From b333a45aae597486e4218988fd5ff3d8d49fd71d Mon Sep 17 00:00:00 2001 From: Damien George Date: Wed, 28 Dec 2016 16:29:40 +1100 Subject: [PATCH 10/32] tests: Add functional test for fatfs functions. --- tests/.gitignore | 1 + tests/Makefile | 7 ++ tests/fatfs1.c | 226 ++++++++++++++++++++++++++++++++++++++++++++ tests/fatfs1.exp | 196 ++++++++++++++++++++++++++++++++++++++ tests/fatfs1_conf.h | 33 +++++++ tests/util.c | 50 ++++++++++ tests/util.h | 5 + 7 files changed, 518 insertions(+) create mode 100644 tests/.gitignore create mode 100644 tests/Makefile create mode 100644 tests/fatfs1.c create mode 100644 tests/fatfs1.exp create mode 100644 tests/fatfs1_conf.h create mode 100644 tests/util.c create mode 100644 tests/util.h diff --git a/tests/.gitignore b/tests/.gitignore new file mode 100644 index 0000000..9f4f72b --- /dev/null +++ b/tests/.gitignore @@ -0,0 +1 @@ +fatfs1 diff --git a/tests/Makefile b/tests/Makefile new file mode 100644 index 0000000..e1b9f58 --- /dev/null +++ b/tests/Makefile @@ -0,0 +1,7 @@ +all: fatfs1 + +fatfs1: ../src/ff.c ../src/option/ccsbcs.c util.c fatfs1.c + gcc -g -I.. -std=c99 -DFFCONF_H='"tests/fatfs1_conf.h"' $^ -o $@ + +test: fatfs1 + ./fatfs1 | diff - fatfs1.exp diff --git a/tests/fatfs1.c b/tests/fatfs1.c new file mode 100644 index 0000000..8db9098 --- /dev/null +++ b/tests/fatfs1.c @@ -0,0 +1,226 @@ +#include +#include +#include +#include + +#include "tests/util.h" +#include "src/ff.h" +#include "src/diskio.h" + +#define NSEC (128) +#define SEC_SIZE (512) +static uint8_t ram_bdev[NSEC * SEC_SIZE]; + +struct _bdev_t { + int pdrv; +}; + +DRESULT disk_read(void *bdev_in, BYTE *buff, DWORD sector, UINT count) { + struct _bdev_t *bdev = bdev_in; + printf("disk_read(%d, %u, %u)\n", bdev->pdrv, sector, count); + memcpy(buff, ram_bdev + sector * SEC_SIZE, count * SEC_SIZE); + return RES_OK; +} + +static DWORD sector_no_hash = -1; +DRESULT disk_write(void *bdev_in, const BYTE *buff, DWORD sector, UINT count) { + struct _bdev_t *bdev = bdev_in; + printf("disk_write(%d, %u, %u, ", bdev->pdrv, sector, count); + if (sector == sector_no_hash) { + // some sectors have non-deterministic data + printf(""); + } else { + printf("0x%08x", hash_djb2(buff, count * SEC_SIZE)); + } + printf(")\n"); + memcpy(ram_bdev + sector * SEC_SIZE, buff, count * SEC_SIZE); + return RES_OK; +} + +DRESULT disk_ioctl(void *bdev_in, BYTE cmd, void *buff) { + struct _bdev_t *bdev = bdev_in; + printf("disk_ioctl(%d, %u)\n", bdev->pdrv, cmd); + switch (cmd) { + case CTRL_SYNC: break; + case GET_SECTOR_COUNT: *((DWORD*)buff) = NSEC; break; + case GET_SECTOR_SIZE: *((WORD*)buff) = SEC_SIZE; break; + case GET_BLOCK_SIZE: *((DWORD*)buff) = 1; break; + case IOCTL_INIT: *((DSTATUS*)buff) = 0; break; + case IOCTL_STATUS: *((DSTATUS*)buff) = 0; break; + default: assert(0); + } + return RES_OK; +} + +DWORD get_fattime(void) { + printf("get_fattime()\n"); + return 0; +} + +int main() { + struct _bdev_t bdev = {0}; + FATFS fatfs; + fatfs.drv = &bdev; + + printf("== MKFS ==\n"); + { + FRESULT res = f_mkfs(&fatfs, 1, 0); + printf("mkfs res=%d\n", res); + } + + printf("== MOUNT ==\n"); + { + FRESULT res = f_mount(&fatfs); + printf("mount res=%d\n", res); + } + + printf("== SET LABEL ==\n"); + { + FRESULT res = f_setlabel(&fatfs, "LABEL"); + printf("setlabel res=%d\n", res); + } + + printf("== GET LABEL ==\n"); + { + uint8_t buf[256]; + DWORD vsn; + FRESULT res = f_getlabel(&fatfs, (TCHAR*)buf, &vsn); + printf("getlabel res=%d label=%.12s vsn=%u\n", res, buf, vsn); + } + + printf("== FILE CREATION ==\n"); + { + FIL fp; + FRESULT res = f_open(&fatfs, &fp, "/test.txt", FA_WRITE | FA_CREATE_ALWAYS); + printf("open res=%d\n", res); + UINT n; + res = f_write(&fp, "test file\n", 10, &n); + printf("write res=%d n=%u\n", res, n); + sector_no_hash = 34; + res = f_close(&fp); + sector_no_hash = -1; + printf("close res=%d\n", res); + } + + printf("== FILE READ ==\n"); + { + FIL fp; + FRESULT res = f_open(&fatfs, &fp, "/test.txt", FA_READ); + printf("open res=%d\n", res); + uint8_t buf[100]; + UINT n; + res = f_read(&fp, buf, 100, &n); + printf("read res=%d n=%u\n", res, n); + hexdump(buf, n, 16); + res = f_close(&fp); + printf("close res=%d\n", res); + } + + printf("== STAT ==\n"); + { + FILINFO fno; + #if _USE_LFN + fno.lfname = NULL; + fno.lfsize = 0; + #endif + FRESULT res = f_stat(&fatfs, "/test.txt", &fno); + printf("stat res=%d size=%u date=%u time=%u attrib=%u\n", res, fno.fsize, fno.fdate, fno.ftime, fno.fattrib); + } + + printf("== FILE CREATION, LONG NAME AND LOTS OF DATA ==\n"); + { + FIL fp; + FRESULT res = f_open(&fatfs, &fp, "/filename-that-is-long.txt", FA_WRITE | FA_CREATE_ALWAYS); + printf("open res=%d\n", res); + UINT n; + for (int i = 0; i < 10; ++i) { + res = f_write(&fp, "More data for the test file. Need to have enough characters to fill more than one 512-byte sector.\n", 100, &n); + printf("write res=%d n=%u\n", res, n); + } + res = f_close(&fp); + printf("close res=%d\n", res); + } + + printf("== FILE SEEK AND READ ==\n"); + { + FIL fp; + FRESULT res = f_open(&fatfs, &fp, "/filename-that-is-long.txt", FA_READ); + printf("open res=%d\n", res); + res = f_lseek(&fp, 800); + printf("lseek res=%d\n", res); + printf("tell %d\n", f_tell(&fp)); + uint8_t buf[100]; + UINT n; + res = f_read(&fp, buf, 100, &n); + printf("read res=%d n=%u\n", res, n); + hexdump(buf, n, 16); + res = f_close(&fp); + printf("close res=%d\n", res); + } + + printf("== MKDIR ==\n"); + { + FRESULT res = f_mkdir(&fatfs, "/dir"); + printf("mkdir res=%d\n", res); + } + + printf("== DIRECTORY LISTING ==\n"); + { + DIR dp; + FRESULT res = f_opendir(&fatfs, &dp, "/"); + printf("opendir res=%d\n", res); + FILINFO fno; + #if _USE_LFN + char lfn[_MAX_LFN + 1]; + fno.lfname = lfn; + fno.lfsize = sizeof(lfn); + #endif + for (;;){ + res = f_readdir(&dp, &fno); + if (res != FR_OK || fno.fname[0] == 0) { + break; + } + #if _USE_LFN + // note: lfname is empty string if it fits in 12 chars in fname + printf("readdir res=%d size=%u name=/%s/ lname=/%s/\n", res, fno.fsize, fno.fname, fno.lfname); + #else + printf("readdir res=%d size=%u name=/%s/\n", res, fno.fsize, fno.fname); + #endif + } + res = f_closedir(&dp); + printf("closedir res=%d\n", res); + } + + printf("== RENAME FILE ==\n"); + { + FRESULT res = f_rename(&fatfs, "/test.txt", "/test2.txt"); + printf("unlink res=%d\n", res); + } + + printf("== UNLINK FILE ==\n"); + { + FRESULT res = f_unlink(&fatfs, "/test2.txt"); + printf("unlink res=%d\n", res); + } + + printf("== RENAME DIR ==\n"); + { + FRESULT res = f_rename(&fatfs, "/dir", "/dir2"); + printf("unlink res=%d\n", res); + } + + printf("== UNLINK DIR ==\n"); + { + FRESULT res = f_unlink(&fatfs, "/dir2"); + printf("unlink res=%d\n", res); + } + + printf("== FREE SPACE ==\n"); + { + DWORD nclst; + FRESULT res = f_getfree(&fatfs, &nclst); + printf("getfree res=%d nclst=%u\n", res, nclst); + } + + return 0; +} diff --git a/tests/fatfs1.exp b/tests/fatfs1.exp new file mode 100644 index 0000000..c74649c --- /dev/null +++ b/tests/fatfs1.exp @@ -0,0 +1,196 @@ +== MKFS == +disk_ioctl(0, 5) +disk_ioctl(0, 1) +disk_ioctl(0, 3) +get_fattime() +disk_write(0, 0, 1, 0x56c0aabe) +disk_write(0, 1, 1, 0x9ca634d5) +disk_write(0, 2, 1, 0x082d5505) +disk_write(0, 3, 1, 0x082d5505) +disk_write(0, 4, 1, 0x082d5505) +disk_write(0, 5, 1, 0x082d5505) +disk_write(0, 6, 1, 0x082d5505) +disk_write(0, 7, 1, 0x082d5505) +disk_write(0, 8, 1, 0x082d5505) +disk_write(0, 9, 1, 0x082d5505) +disk_write(0, 10, 1, 0x082d5505) +disk_write(0, 11, 1, 0x082d5505) +disk_write(0, 12, 1, 0x082d5505) +disk_write(0, 13, 1, 0x082d5505) +disk_write(0, 14, 1, 0x082d5505) +disk_write(0, 15, 1, 0x082d5505) +disk_write(0, 16, 1, 0x082d5505) +disk_write(0, 17, 1, 0x082d5505) +disk_write(0, 18, 1, 0x082d5505) +disk_write(0, 19, 1, 0x082d5505) +disk_write(0, 20, 1, 0x082d5505) +disk_write(0, 21, 1, 0x082d5505) +disk_write(0, 22, 1, 0x082d5505) +disk_write(0, 23, 1, 0x082d5505) +disk_write(0, 24, 1, 0x082d5505) +disk_write(0, 25, 1, 0x082d5505) +disk_write(0, 26, 1, 0x082d5505) +disk_write(0, 27, 1, 0x082d5505) +disk_write(0, 28, 1, 0x082d5505) +disk_write(0, 29, 1, 0x082d5505) +disk_write(0, 30, 1, 0x082d5505) +disk_write(0, 31, 1, 0x082d5505) +disk_write(0, 32, 1, 0x082d5505) +disk_write(0, 33, 1, 0x082d5505) +disk_ioctl(0, 0) +mkfs res=0 +== MOUNT == +disk_ioctl(0, 5) +disk_read(0, 0, 1) +mount res=0 +== SET LABEL == +disk_ioctl(0, 6) +disk_read(0, 2, 1) +get_fattime() +disk_write(0, 2, 1, 0x0d96b58b) +disk_ioctl(0, 0) +setlabel res=0 +== GET LABEL == +disk_ioctl(0, 6) +disk_read(0, 0, 1) +getlabel res=0 label=LABEL vsn=0 +== FILE CREATION == +disk_ioctl(0, 6) +disk_read(0, 2, 1) +get_fattime() +open res=0 +disk_ioctl(0, 6) +disk_write(0, 2, 1, 0x236a437d) +disk_read(0, 1, 1) +write res=0 n=10 +disk_ioctl(0, 6) +disk_write(0, 34, 1, ) +disk_write(0, 1, 1, 0x5343a9c5) +disk_read(0, 2, 1) +get_fattime() +disk_write(0, 2, 1, 0x6ae708d5) +disk_ioctl(0, 0) +disk_ioctl(0, 6) +close res=0 +== FILE READ == +disk_ioctl(0, 6) +open res=0 +disk_ioctl(0, 6) +disk_read(0, 34, 1) +read res=0 n=10 +0000 74 65 73 74 20 66 69 6c 65 0a test file. +disk_ioctl(0, 6) +disk_ioctl(0, 6) +close res=0 +== STAT == +disk_ioctl(0, 6) +stat res=0 size=10 date=0 time=0 attrib=32 +== FILE CREATION, LONG NAME AND LOTS OF DATA == +disk_ioctl(0, 6) +get_fattime() +open res=0 +disk_ioctl(0, 6) +disk_write(0, 2, 1, 0xf3dd04eb) +disk_read(0, 1, 1) +write res=0 n=100 +disk_ioctl(0, 6) +write res=0 n=100 +disk_ioctl(0, 6) +write res=0 n=100 +disk_ioctl(0, 6) +write res=0 n=100 +disk_ioctl(0, 6) +write res=0 n=100 +disk_ioctl(0, 6) +disk_write(0, 35, 1, 0x4049ed30) +write res=0 n=100 +disk_ioctl(0, 6) +write res=0 n=100 +disk_ioctl(0, 6) +write res=0 n=100 +disk_ioctl(0, 6) +write res=0 n=100 +disk_ioctl(0, 6) +write res=0 n=100 +disk_ioctl(0, 6) +disk_write(0, 36, 1, 0x37a6ca6c) +disk_write(0, 1, 1, 0x7f57e755) +disk_read(0, 2, 1) +get_fattime() +disk_write(0, 2, 1, 0xdd0a2fc3) +disk_ioctl(0, 0) +disk_ioctl(0, 6) +close res=0 +== FILE SEEK AND READ == +disk_ioctl(0, 6) +open res=0 +disk_ioctl(0, 6) +disk_read(0, 1, 1) +disk_read(0, 36, 1) +lseek res=0 +tell 800 +disk_ioctl(0, 6) +read res=0 n=100 +0000 4d 6f 72 65 20 64 61 74 61 20 66 6f 72 20 74 68 More data for th +0010 65 20 74 65 73 74 20 66 69 6c 65 2e 20 20 4e 65 e test file. Ne +0020 65 64 20 74 6f 20 68 61 76 65 20 65 6e 6f 75 67 ed to have enoug +0030 68 20 63 68 61 72 61 63 74 65 72 73 20 74 6f 20 h characters to +0040 66 69 6c 6c 20 6d 6f 72 65 20 74 68 61 6e 20 6f fill more than o +0050 6e 65 20 35 31 32 2d 62 79 74 65 20 73 65 63 74 ne 512-byte sect +0060 6f 72 2e 0a or.. +disk_ioctl(0, 6) +disk_ioctl(0, 6) +close res=0 +== MKDIR == +get_fattime() +disk_ioctl(0, 6) +disk_read(0, 2, 1) +disk_read(0, 1, 1) +disk_write(0, 1, 1, 0xa5c7187a) +disk_write(0, 37, 1, 0x2953772e) +disk_read(0, 2, 1) +disk_write(0, 2, 1, 0x55944b21) +disk_ioctl(0, 0) +mkdir res=0 +== DIRECTORY LISTING == +disk_ioctl(0, 6) +opendir res=0 +disk_ioctl(0, 6) +readdir res=0 size=10 name=/test.txt/ lname=// +disk_ioctl(0, 6) +readdir res=0 size=1000 name=/FILENA~1.TXT/ lname=/filename-that-is-long.txt/ +disk_ioctl(0, 6) +readdir res=0 size=0 name=/dir/ lname=// +disk_ioctl(0, 6) +disk_ioctl(0, 6) +closedir res=0 +== RENAME FILE == +disk_ioctl(0, 6) +disk_write(0, 2, 1, 0xccafbc76) +disk_ioctl(0, 0) +unlink res=0 +== UNLINK FILE == +disk_ioctl(0, 6) +disk_write(0, 2, 1, 0x76e9bdff) +disk_read(0, 1, 1) +disk_write(0, 1, 1, 0xd19f436a) +disk_ioctl(0, 0) +unlink res=0 +== RENAME DIR == +disk_ioctl(0, 6) +disk_read(0, 2, 1) +disk_write(0, 2, 1, 0x1ff9ac0d) +disk_ioctl(0, 0) +unlink res=0 +== UNLINK DIR == +disk_ioctl(0, 6) +disk_read(0, 37, 1) +disk_read(0, 2, 1) +disk_write(0, 2, 1, 0x6ae11ad8) +disk_read(0, 1, 1) +disk_write(0, 1, 1, 0x61648e45) +disk_ioctl(0, 0) +unlink res=0 +== FREE SPACE == +disk_ioctl(0, 6) +getfree res=0 nclst=92 diff --git a/tests/fatfs1_conf.h b/tests/fatfs1_conf.h new file mode 100644 index 0000000..b408e76 --- /dev/null +++ b/tests/fatfs1_conf.h @@ -0,0 +1,33 @@ +#define _FFCONF 64180 +#define _FS_READONLY 0 +#define _FS_MINIMIZE 0 +#define _USE_STRFUNC 0 +#define _USE_FIND 0 +#define _USE_MKFS 1 +#define _USE_FASTSEEK 0 +#define _USE_LABEL 1 +#define _USE_FORWARD 0 +#define _CODE_PAGE 437 +#define _USE_LFN 1 +#define _MAX_LFN 255 +#define _LFN_UNICODE 0 +#define _STRF_ENCODE 3 +#define _FS_RPATH 0 +#define _VOLUMES 1 +#define _STR_VOLUME_ID 0 +#define _VOLUME_STRS "RAM","NAND","CF","SD1","SD2","USB1","USB2","USB3" +#define _MULTI_PARTITION 0 +#define _MIN_SS 512 +#define _MAX_SS 512 +#define _USE_TRIM 0 +#define _FS_NOFSINFO 0 +#define _FS_TINY 0 +#define _FS_NORTC 0 +#define _NORTC_MON 1 +#define _NORTC_MDAY 1 +#define _NORTC_YEAR 2015 +#define _FS_LOCK 0 +#define _FS_REENTRANT 0 +#define _FS_TIMEOUT 1000 +#define _SYNC_t HANDLE +#define _WORD_ACCESS 0 diff --git a/tests/util.c b/tests/util.c new file mode 100644 index 0000000..c90db10 --- /dev/null +++ b/tests/util.c @@ -0,0 +1,50 @@ +#include +#include + +#include "util.h" + +void hexdump(const uint8_t *buf, size_t len, size_t width) { + for (size_t i = 0; i < len; i += width) { + printf("%04x ", i); + size_t j; + for (j = i; j < len && j < i + width; ++j) { + printf("%02x ", buf[j]); + } + for (; j < i + width; ++j) { + printf(" "); + } + for (j = i; j < len && j < i + width; ++j) { + int c = buf[j]; + if (c < 32 || c > 126) { + c = '.'; + } + printf("%c", c); + } + printf("\n"); + } +} + +uint32_t hash_djb2(const uint8_t *data, size_t len) { + // djb2 algorithm; see http://www.cse.yorku.ca/~oz/hash.html + uint32_t hash = 5381; + for (const uint8_t *top = data + len; data < top; data++) { + hash = ((hash << 5) + hash) ^ (*data); // hash * 33 ^ data + } + return hash; +} + +void hashdump(const uint8_t *data, size_t len, size_t block_size, size_t width) { + const uint8_t *top = data + len; + for (size_t i = 0; data < top;) { + size_t n = top - data; + if (n > block_size) { + n = block_size; + } + printf("%08x ", hash_djb2(data, n)); + i += 1; + data += n; + if (i % width == 0 || data >= top) { + printf("\n"); + } + } +} diff --git a/tests/util.h b/tests/util.h new file mode 100644 index 0000000..5226bfc --- /dev/null +++ b/tests/util.h @@ -0,0 +1,5 @@ +#pragma once + +void hexdump(const uint8_t *buf, size_t len, size_t width); +uint32_t hash_djb2(const uint8_t *data, size_t len); +void hashdump(const uint8_t *data, size_t len, size_t block_size, size_t width); From 0cbebf9517373052ac94ee9500d0ae17d8673fa5 Mon Sep 17 00:00:00 2001 From: Damien George Date: Wed, 28 Dec 2016 16:35:29 +1100 Subject: [PATCH 11/32] tests: Update fatfs1 test. --- tests/fatfs1.c | 11 +---------- tests/fatfs1.exp | 23 +++++++++++------------ tests/fatfs1_conf.h | 6 ++++-- 3 files changed, 16 insertions(+), 24 deletions(-) diff --git a/tests/fatfs1.c b/tests/fatfs1.c index 8db9098..7350b96 100644 --- a/tests/fatfs1.c +++ b/tests/fatfs1.c @@ -119,10 +119,6 @@ int main() { printf("== STAT ==\n"); { FILINFO fno; - #if _USE_LFN - fno.lfname = NULL; - fno.lfsize = 0; - #endif FRESULT res = f_stat(&fatfs, "/test.txt", &fno); printf("stat res=%d size=%u date=%u time=%u attrib=%u\n", res, fno.fsize, fno.fdate, fno.ftime, fno.fattrib); } @@ -170,11 +166,6 @@ int main() { FRESULT res = f_opendir(&fatfs, &dp, "/"); printf("opendir res=%d\n", res); FILINFO fno; - #if _USE_LFN - char lfn[_MAX_LFN + 1]; - fno.lfname = lfn; - fno.lfsize = sizeof(lfn); - #endif for (;;){ res = f_readdir(&dp, &fno); if (res != FR_OK || fno.fname[0] == 0) { @@ -182,7 +173,7 @@ int main() { } #if _USE_LFN // note: lfname is empty string if it fits in 12 chars in fname - printf("readdir res=%d size=%u name=/%s/ lname=/%s/\n", res, fno.fsize, fno.fname, fno.lfname); + printf("readdir res=%d size=%u name=/%s/ lname=/%s/\n", res, fno.fsize, fno.altname, fno.fname); #else printf("readdir res=%d size=%u name=/%s/\n", res, fno.fsize, fno.fname); #endif diff --git a/tests/fatfs1.exp b/tests/fatfs1.exp index c74649c..c539ee2 100644 --- a/tests/fatfs1.exp +++ b/tests/fatfs1.exp @@ -46,7 +46,6 @@ mount res=0 == SET LABEL == disk_ioctl(0, 6) disk_read(0, 2, 1) -get_fattime() disk_write(0, 2, 1, 0x0d96b58b) disk_ioctl(0, 0) setlabel res=0 @@ -60,14 +59,14 @@ disk_read(0, 2, 1) get_fattime() open res=0 disk_ioctl(0, 6) -disk_write(0, 2, 1, 0x236a437d) +disk_write(0, 2, 1, 0xa8b3f35d) disk_read(0, 1, 1) write res=0 n=10 disk_ioctl(0, 6) disk_write(0, 34, 1, ) +get_fattime() disk_write(0, 1, 1, 0x5343a9c5) disk_read(0, 2, 1) -get_fattime() disk_write(0, 2, 1, 0x6ae708d5) disk_ioctl(0, 0) disk_ioctl(0, 6) @@ -90,7 +89,7 @@ disk_ioctl(0, 6) get_fattime() open res=0 disk_ioctl(0, 6) -disk_write(0, 2, 1, 0xf3dd04eb) +disk_write(0, 2, 1, 0xb1d034cb) disk_read(0, 1, 1) write res=0 n=100 disk_ioctl(0, 6) @@ -114,9 +113,9 @@ disk_ioctl(0, 6) write res=0 n=100 disk_ioctl(0, 6) disk_write(0, 36, 1, 0x37a6ca6c) +get_fattime() disk_write(0, 1, 1, 0x7f57e755) disk_read(0, 2, 1) -get_fattime() disk_write(0, 2, 1, 0xdd0a2fc3) disk_ioctl(0, 0) disk_ioctl(0, 6) @@ -142,11 +141,11 @@ disk_ioctl(0, 6) disk_ioctl(0, 6) close res=0 == MKDIR == -get_fattime() disk_ioctl(0, 6) disk_read(0, 2, 1) disk_read(0, 1, 1) disk_write(0, 1, 1, 0xa5c7187a) +get_fattime() disk_write(0, 37, 1, 0x2953772e) disk_read(0, 2, 1) disk_write(0, 2, 1, 0x55944b21) @@ -156,22 +155,22 @@ mkdir res=0 disk_ioctl(0, 6) opendir res=0 disk_ioctl(0, 6) -readdir res=0 size=10 name=/test.txt/ lname=// +readdir res=0 size=10 name=/TEST.TXT/ lname=/test.txt/ disk_ioctl(0, 6) readdir res=0 size=1000 name=/FILENA~1.TXT/ lname=/filename-that-is-long.txt/ disk_ioctl(0, 6) -readdir res=0 size=0 name=/dir/ lname=// +readdir res=0 size=0 name=/DIR/ lname=/dir/ disk_ioctl(0, 6) disk_ioctl(0, 6) closedir res=0 == RENAME FILE == disk_ioctl(0, 6) -disk_write(0, 2, 1, 0xccafbc76) +disk_write(0, 2, 1, 0xcdb1e73c) disk_ioctl(0, 0) unlink res=0 == UNLINK FILE == disk_ioctl(0, 6) -disk_write(0, 2, 1, 0x76e9bdff) +disk_write(0, 2, 1, 0x12c8992d) disk_read(0, 1, 1) disk_write(0, 1, 1, 0xd19f436a) disk_ioctl(0, 0) @@ -179,14 +178,14 @@ unlink res=0 == RENAME DIR == disk_ioctl(0, 6) disk_read(0, 2, 1) -disk_write(0, 2, 1, 0x1ff9ac0d) +disk_write(0, 2, 1, 0x2b759c33) disk_ioctl(0, 0) unlink res=0 == UNLINK DIR == disk_ioctl(0, 6) disk_read(0, 37, 1) disk_read(0, 2, 1) -disk_write(0, 2, 1, 0x6ae11ad8) +disk_write(0, 2, 1, 0x09922d72) disk_read(0, 1, 1) disk_write(0, 1, 1, 0x61648e45) disk_ioctl(0, 0) diff --git a/tests/fatfs1_conf.h b/tests/fatfs1_conf.h index b408e76..5c1ccc2 100644 --- a/tests/fatfs1_conf.h +++ b/tests/fatfs1_conf.h @@ -1,10 +1,12 @@ -#define _FFCONF 64180 +#define _FFCONF 88100 #define _FS_READONLY 0 #define _FS_MINIMIZE 0 #define _USE_STRFUNC 0 #define _USE_FIND 0 #define _USE_MKFS 1 #define _USE_FASTSEEK 0 +#define _USE_EXPAND 0 +#define _USE_CHMOD 1 #define _USE_LABEL 1 #define _USE_FORWARD 0 #define _CODE_PAGE 437 @@ -22,6 +24,7 @@ #define _USE_TRIM 0 #define _FS_NOFSINFO 0 #define _FS_TINY 0 +#define _FS_EXFAT 1 #define _FS_NORTC 0 #define _NORTC_MON 1 #define _NORTC_MDAY 1 @@ -30,4 +33,3 @@ #define _FS_REENTRANT 0 #define _FS_TIMEOUT 1000 #define _SYNC_t HANDLE -#define _WORD_ACCESS 0 From 69e1568cebb6ebedc4246863715824781827c30f Mon Sep 17 00:00:00 2001 From: Damien George Date: Wed, 28 Dec 2016 16:40:31 +1100 Subject: [PATCH 12/32] tests: Update fatfs1 test. --- tests/fatfs1.c | 3 ++- tests/fatfs1.exp | 16 ++++++++-------- tests/fatfs1_conf.h | 2 +- 3 files changed, 11 insertions(+), 10 deletions(-) diff --git a/tests/fatfs1.c b/tests/fatfs1.c index 7350b96..a8a8e29 100644 --- a/tests/fatfs1.c +++ b/tests/fatfs1.c @@ -64,7 +64,8 @@ int main() { printf("== MKFS ==\n"); { - FRESULT res = f_mkfs(&fatfs, 1, 0); + uint8_t buf[SEC_SIZE]; + FRESULT res = f_mkfs(&fatfs, FM_FAT | FM_SFD, 0, buf, sizeof(buf)); printf("mkfs res=%d\n", res); } diff --git a/tests/fatfs1.exp b/tests/fatfs1.exp index c539ee2..f70bd9c 100644 --- a/tests/fatfs1.exp +++ b/tests/fatfs1.exp @@ -1,10 +1,10 @@ == MKFS == disk_ioctl(0, 5) -disk_ioctl(0, 1) disk_ioctl(0, 3) +disk_ioctl(0, 1) get_fattime() -disk_write(0, 0, 1, 0x56c0aabe) -disk_write(0, 1, 1, 0x9ca634d5) +disk_write(0, 0, 1, 0x01c410b6) +disk_write(0, 1, 1, 0xd21511dd) disk_write(0, 2, 1, 0x082d5505) disk_write(0, 3, 1, 0x082d5505) disk_write(0, 4, 1, 0x082d5505) @@ -65,7 +65,7 @@ write res=0 n=10 disk_ioctl(0, 6) disk_write(0, 34, 1, ) get_fattime() -disk_write(0, 1, 1, 0x5343a9c5) +disk_write(0, 1, 1, 0x42bbc4cd) disk_read(0, 2, 1) disk_write(0, 2, 1, 0x6ae708d5) disk_ioctl(0, 0) @@ -114,7 +114,7 @@ write res=0 n=100 disk_ioctl(0, 6) disk_write(0, 36, 1, 0x37a6ca6c) get_fattime() -disk_write(0, 1, 1, 0x7f57e755) +disk_write(0, 1, 1, 0x2d32005d) disk_read(0, 2, 1) disk_write(0, 2, 1, 0xdd0a2fc3) disk_ioctl(0, 0) @@ -144,7 +144,7 @@ close res=0 disk_ioctl(0, 6) disk_read(0, 2, 1) disk_read(0, 1, 1) -disk_write(0, 1, 1, 0xa5c7187a) +disk_write(0, 1, 1, 0x867a0372) get_fattime() disk_write(0, 37, 1, 0x2953772e) disk_read(0, 2, 1) @@ -172,7 +172,7 @@ unlink res=0 disk_ioctl(0, 6) disk_write(0, 2, 1, 0x12c8992d) disk_read(0, 1, 1) -disk_write(0, 1, 1, 0xd19f436a) +disk_write(0, 1, 1, 0xf848f062) disk_ioctl(0, 0) unlink res=0 == RENAME DIR == @@ -187,7 +187,7 @@ disk_read(0, 37, 1) disk_read(0, 2, 1) disk_write(0, 2, 1, 0x09922d72) disk_read(0, 1, 1) -disk_write(0, 1, 1, 0x61648e45) +disk_write(0, 1, 1, 0x5535694d) disk_ioctl(0, 0) unlink res=0 == FREE SPACE == diff --git a/tests/fatfs1_conf.h b/tests/fatfs1_conf.h index 5c1ccc2..62ce3c3 100644 --- a/tests/fatfs1_conf.h +++ b/tests/fatfs1_conf.h @@ -1,4 +1,4 @@ -#define _FFCONF 88100 +#define _FFCONF 80186 #define _FS_READONLY 0 #define _FS_MINIMIZE 0 #define _USE_STRFUNC 0 From 198f6505b13a73ac0dd621ffde2529b8147c75c1 Mon Sep 17 00:00:00 2001 From: Damien George Date: Tue, 24 Jan 2017 17:40:20 +1100 Subject: [PATCH 13/32] src: Decrease minimum volume size down to 50 sectors. This seems to be the minimum that holds a FAT12 filesystem. --- src/ff.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ff.c b/src/ff.c index c4d1441..db60ebe 100644 --- a/src/ff.c +++ b/src/ff.c @@ -5474,7 +5474,7 @@ FRESULT f_mkfs ( if (sz_vol < b_vol) LEAVE_MKFS(FR_MKFS_ABORTED); sz_vol -= b_vol; /* Volume size */ } - if (sz_vol < 128) LEAVE_MKFS(FR_MKFS_ABORTED); /* Check if volume size is >=128s */ + if (sz_vol < 50) LEAVE_MKFS(FR_MKFS_ABORTED); /* Check if volume size is >=50s */ /* Pre-determine the FAT type */ do { From 6f354ce967b582ad71efa4a18c2420a03b31c8a2 Mon Sep 17 00:00:00 2001 From: Damien George Date: Tue, 24 Jan 2017 23:19:50 +1100 Subject: [PATCH 14/32] tests: Update fatfs1 test. --- tests/fatfs1_conf.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/fatfs1_conf.h b/tests/fatfs1_conf.h index 62ce3c3..569d943 100644 --- a/tests/fatfs1_conf.h +++ b/tests/fatfs1_conf.h @@ -1,4 +1,4 @@ -#define _FFCONF 80186 +#define _FFCONF 68020 #define _FS_READONLY 0 #define _FS_MINIMIZE 0 #define _USE_STRFUNC 0 From be42beb060c60323633679d304dbabd12a071b43 Mon Sep 17 00:00:00 2001 From: Damien George Date: Fri, 27 Jan 2017 12:46:07 +1100 Subject: [PATCH 15/32] src: Add short header to source files to describe and point to git repo. --- src/diskio.h | 4 ++++ src/ff.c | 4 ++++ src/ff.h | 4 ++++ src/ffconf.h | 4 ++++ 4 files changed, 16 insertions(+) diff --git a/src/diskio.h b/src/diskio.h index 608937f..d886bdd 100644 --- a/src/diskio.h +++ b/src/diskio.h @@ -1,3 +1,7 @@ +/* This file is part of ooFatFs, a customised version of FatFs + * See https://github.com/micropython/oofatfs for details + */ + /*-----------------------------------------------------------------------/ / Low level disk interface modlue include file (C)ChaN, 2014 / /-----------------------------------------------------------------------*/ diff --git a/src/ff.c b/src/ff.c index db60ebe..7ac534d 100644 --- a/src/ff.c +++ b/src/ff.c @@ -1,3 +1,7 @@ +/* This file is part of ooFatFs, a customised version of FatFs + * See https://github.com/micropython/oofatfs for details + */ + /*----------------------------------------------------------------------------/ / FatFs - Generic FAT Filesystem Module R0.13c / /-----------------------------------------------------------------------------/ diff --git a/src/ff.h b/src/ff.h index f54cf30..ec5d46b 100644 --- a/src/ff.h +++ b/src/ff.h @@ -1,3 +1,7 @@ +/* This file is part of ooFatFs, a customised version of FatFs + * See https://github.com/micropython/oofatfs for details + */ + /*----------------------------------------------------------------------------/ / FatFs - Generic FAT Filesystem module R0.13c / /-----------------------------------------------------------------------------/ diff --git a/src/ffconf.h b/src/ffconf.h index 045b3dc..edd052b 100644 --- a/src/ffconf.h +++ b/src/ffconf.h @@ -1,3 +1,7 @@ +/* This file is part of ooFatFs, a customised version of FatFs + * See https://github.com/micropython/oofatfs for details + */ + /*---------------------------------------------------------------------------/ / FatFs Functional Configurations /---------------------------------------------------------------------------*/ From 3ceb3dc2332ed72d3ca994245f2d9db607e60dc1 Mon Sep 17 00:00:00 2001 From: Damien George Date: Fri, 27 Jan 2017 12:54:38 +1100 Subject: [PATCH 16/32] src: Use standrd, external memcpy/memset/memcmp functions. --- src/ff.c | 45 ++++++++------------------------------------- 1 file changed, 8 insertions(+), 37 deletions(-) diff --git a/src/ff.c b/src/ff.c index 7ac534d..74cd5b6 100644 --- a/src/ff.c +++ b/src/ff.c @@ -23,6 +23,8 @@ /----------------------------------------------------------------------------*/ +#include + #include "ff.h" /* Declarations of FatFs API */ #include "diskio.h" /* Declarations of device I/O functions */ @@ -647,43 +649,12 @@ static void st_qword (BYTE* ptr, QWORD val) /* Store an 8-byte word in little-en /* String functions */ /*-----------------------------------------------------------------------*/ -/* Copy memory to memory */ -static void mem_cpy (void* dst, const void* src, UINT cnt) -{ - BYTE *d = (BYTE*)dst; - const BYTE *s = (const BYTE*)src; - - if (cnt != 0) { - do { - *d++ = *s++; - } while (--cnt); - } -} - - -/* Fill memory block */ -static void mem_set (void* dst, int val, UINT cnt) -{ - BYTE *d = (BYTE*)dst; - - do { - *d++ = (BYTE)val; - } while (--cnt); -} - - -/* Compare memory block */ -static int mem_cmp (const void* dst, const void* src, UINT cnt) /* ZR:same, NZ:different */ -{ - const BYTE *d = (const BYTE *)dst, *s = (const BYTE *)src; - int r = 0; - - do { - r = *d++ - *s++; - } while (--cnt && r == 0); - - return r; -} +// These were originally provided by the FatFs library but we use externally +// provided versions from C stdlib to (hopefully) reduce code size and use +// more efficient versions. +#define mem_cpy memcpy +#define mem_set memset +#define mem_cmp memcmp /* Check if chr is contained in the string */ From a556c2d9451bf71439e86539455d12a62a435934 Mon Sep 17 00:00:00 2001 From: Damien George Date: Mon, 30 Jan 2017 12:01:30 +1100 Subject: [PATCH 17/32] src: Make f_mount compile when _FS_REENTRANT is enabled. --- src/ff.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ff.c b/src/ff.c index 74cd5b6..2333bbd 100644 --- a/src/ff.c +++ b/src/ff.c @@ -3384,7 +3384,7 @@ FRESULT f_mount ( fs->fs_type = 0; /* Clear new fs object */ #if FF_FS_REENTRANT /* Create sync object for the new volume */ - if (!ff_cre_syncobj((BYTE)vol, &fs->sobj)) return FR_INT_ERR; + if (!ff_cre_syncobj(fs, &fs->sobj)) return FR_INT_ERR; #endif res = find_volume(fs, 0); /* Force mounted the volume */ From 7196748e36f8c697457f3082e037fad2df6e2312 Mon Sep 17 00:00:00 2001 From: Damien George Date: Mon, 30 Jan 2017 12:03:54 +1100 Subject: [PATCH 18/32] src: Make ff_cre_syncobj take a FATFS* as first arg, instead of BYTE. --- src/ff.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ff.h b/src/ff.h index ec5d46b..0b73b37 100644 --- a/src/ff.h +++ b/src/ff.h @@ -347,7 +347,7 @@ void ff_memfree (void* mblock); /* Free memory block */ /* Sync functions */ #if FF_FS_REENTRANT -int ff_cre_syncobj (BYTE vol, FF_SYNC_t* sobj); /* Create a sync object */ +int ff_cre_syncobj (FATFS *fatfs, FF_SYNC_t* sobj); /* Create a sync object */ int ff_req_grant (FF_SYNC_t sobj); /* Lock sync object */ void ff_rel_grant (FF_SYNC_t sobj); /* Unlock sync object */ int ff_del_syncobj (FF_SYNC_t sobj); /* Delete a sync object */ From e47c6fb19743a220173dc24b29e633354f18f046 Mon Sep 17 00:00:00 2001 From: Damien George Date: Mon, 30 Jan 2017 12:04:13 +1100 Subject: [PATCH 19/32] src: Rename DIR to FF_DIR, to not clash with POSIX declaration. --- src/ff.c | 2 ++ src/ff.h | 14 +++++++------- 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/src/ff.c b/src/ff.c index 2333bbd..2161338 100644 --- a/src/ff.c +++ b/src/ff.c @@ -28,6 +28,8 @@ #include "ff.h" /* Declarations of FatFs API */ #include "diskio.h" /* Declarations of device I/O functions */ +// DIR has been renamed FF_DIR in the public API so it doesn't clash with POSIX +#define DIR FF_DIR /*-------------------------------------------------------------------------- diff --git a/src/ff.h b/src/ff.h index 0b73b37..a8aa00e 100644 --- a/src/ff.h +++ b/src/ff.h @@ -213,7 +213,7 @@ typedef struct { -/* Directory object structure (DIR) */ +/* Directory object structure (FF_DIR) */ typedef struct { FFOBJID obj; /* Object identifier */ @@ -228,7 +228,7 @@ typedef struct { #if FF_USE_FIND const TCHAR* pat; /* Pointer to the name matching pattern */ #endif -} DIR; +} FF_DIR; @@ -286,11 +286,11 @@ FRESULT f_write (FIL* fp, const void* buff, UINT btw, UINT* bw); /* Write dat FRESULT f_lseek (FIL* fp, FSIZE_t ofs); /* Move file pointer of the file object */ FRESULT f_truncate (FIL* fp); /* Truncate the file */ FRESULT f_sync (FIL* fp); /* Flush cached data of the writing file */ -FRESULT f_opendir (FATFS *fs, DIR* dp, const TCHAR* path); /* Open a directory */ -FRESULT f_closedir (DIR* dp); /* Close an open directory */ -FRESULT f_readdir (DIR* dp, FILINFO* fno); /* Read a directory item */ -FRESULT f_findfirst (DIR* dp, FILINFO* fno, const TCHAR* path, const TCHAR* pattern); /* Find first file */ -FRESULT f_findnext (DIR* dp, FILINFO* fno); /* Find next file */ +FRESULT f_opendir (FATFS *fs, FF_DIR* dp, const TCHAR* path); /* Open a directory */ +FRESULT f_closedir (FF_DIR* dp); /* Close an open directory */ +FRESULT f_readdir (FF_DIR* dp, FILINFO* fno); /* Read a directory item */ +FRESULT f_findfirst (FF_DIR* dp, FILINFO* fno, const TCHAR* path, const TCHAR* pattern); /* Find first file */ +FRESULT f_findnext (FF_DIR* dp, FILINFO* fno); /* Find next file */ FRESULT f_mkdir (FATFS *fs, const TCHAR* path); /* Create a sub directory */ FRESULT f_unlink (FATFS *fs, const TCHAR* path); /* Delete an existing file or directory */ FRESULT f_rename (FATFS *fs, const TCHAR* path_old, const TCHAR* path_new); /* Rename/Move a file or directory */ From 2fcf3cdd24f8ab4f926c4e3d98da388f922aa22d Mon Sep 17 00:00:00 2001 From: Damien George Date: Mon, 30 Jan 2017 12:04:49 +1100 Subject: [PATCH 20/32] tests: Fix fatfs1 test to work with new FF_DIR type. --- tests/fatfs1.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/fatfs1.c b/tests/fatfs1.c index a8a8e29..bf14ceb 100644 --- a/tests/fatfs1.c +++ b/tests/fatfs1.c @@ -163,7 +163,7 @@ int main() { printf("== DIRECTORY LISTING ==\n"); { - DIR dp; + FF_DIR dp; FRESULT res = f_opendir(&fatfs, &dp, "/"); printf("opendir res=%d\n", res); FILINFO fno; From f0c6195221a37a1752b8dd35239220636eebb22b Mon Sep 17 00:00:00 2001 From: Damien George Date: Tue, 19 Feb 2019 22:55:14 +1100 Subject: [PATCH 21/32] tests: Update fatfs1 test for new library version. --- tests/Makefile | 2 +- tests/fatfs1.c | 2 +- tests/fatfs1_conf.h | 72 +++++++++++++++++++++++---------------------- 3 files changed, 39 insertions(+), 37 deletions(-) diff --git a/tests/Makefile b/tests/Makefile index e1b9f58..5fb9104 100644 --- a/tests/Makefile +++ b/tests/Makefile @@ -1,6 +1,6 @@ all: fatfs1 -fatfs1: ../src/ff.c ../src/option/ccsbcs.c util.c fatfs1.c +fatfs1: ../src/ff.c ../src/ffunicode.c util.c fatfs1.c gcc -g -I.. -std=c99 -DFFCONF_H='"tests/fatfs1_conf.h"' $^ -o $@ test: fatfs1 diff --git a/tests/fatfs1.c b/tests/fatfs1.c index bf14ceb..d327017 100644 --- a/tests/fatfs1.c +++ b/tests/fatfs1.c @@ -172,7 +172,7 @@ int main() { if (res != FR_OK || fno.fname[0] == 0) { break; } - #if _USE_LFN + #if FF_USE_LFN // note: lfname is empty string if it fits in 12 chars in fname printf("readdir res=%d size=%u name=/%s/ lname=/%s/\n", res, fno.fsize, fno.altname, fno.fname); #else diff --git a/tests/fatfs1_conf.h b/tests/fatfs1_conf.h index 569d943..67d2207 100644 --- a/tests/fatfs1_conf.h +++ b/tests/fatfs1_conf.h @@ -1,35 +1,37 @@ -#define _FFCONF 68020 -#define _FS_READONLY 0 -#define _FS_MINIMIZE 0 -#define _USE_STRFUNC 0 -#define _USE_FIND 0 -#define _USE_MKFS 1 -#define _USE_FASTSEEK 0 -#define _USE_EXPAND 0 -#define _USE_CHMOD 1 -#define _USE_LABEL 1 -#define _USE_FORWARD 0 -#define _CODE_PAGE 437 -#define _USE_LFN 1 -#define _MAX_LFN 255 -#define _LFN_UNICODE 0 -#define _STRF_ENCODE 3 -#define _FS_RPATH 0 -#define _VOLUMES 1 -#define _STR_VOLUME_ID 0 -#define _VOLUME_STRS "RAM","NAND","CF","SD1","SD2","USB1","USB2","USB3" -#define _MULTI_PARTITION 0 -#define _MIN_SS 512 -#define _MAX_SS 512 -#define _USE_TRIM 0 -#define _FS_NOFSINFO 0 -#define _FS_TINY 0 -#define _FS_EXFAT 1 -#define _FS_NORTC 0 -#define _NORTC_MON 1 -#define _NORTC_MDAY 1 -#define _NORTC_YEAR 2015 -#define _FS_LOCK 0 -#define _FS_REENTRANT 0 -#define _FS_TIMEOUT 1000 -#define _SYNC_t HANDLE +#define FFCONF_DEF 86604 +#define FF_FS_READONLY 0 +#define FF_FS_MINIMIZE 0 +#define FF_USE_STRFUNC 0 +#define FF_USE_FIND 0 +#define FF_USE_MKFS 1 +#define FF_USE_FASTSEEK 0 +#define FF_USE_EXPAND 0 +#define FF_USE_CHMOD 1 +#define FF_USE_LABEL 1 +#define FF_USE_FORWARD 0 +#define FF_CODE_PAGE 437 +#define FF_USE_LFN 1 +#define FF_MAX_LFN 255 +#define FF_LFN_UNICODE 0 +#define FF_LFN_BUF 255 +#define FF_SFN_BUF 12 +#define FF_STRF_ENCODE 3 +#define FF_FS_RPATH 0 +#define FF_VOLUMES 1 +#define FF_STR_VOLUME_ID 0 +#define FF_VOLUME_STRS "RAM","NAND","CF","SD1","SD2","USB1","USB2","USB3" +#define FF_MULTI_PARTITION 0 +#define FF_MIN_SS 512 +#define FF_MAX_SS 512 +#define FF_USE_TRIM 0 +#define FF_FS_NOFSINFO 0 +#define FF_FS_TINY 0 +#define FF_FS_EXFAT 1 +#define FF_FS_NORTC 0 +#define FF_NORTC_MON 1 +#define FF_NORTC_MDAY 1 +#define FF_NORTC_YEAR 2015 +#define FF_FS_LOCK 0 +#define FF_FS_REENTRANT 0 +#define FF_FS_TIMEOUT 1000 +#define FF_SYNC_t HANDLE From a77c9709e1dfe2f7ed756735b4115ed84c66e76b Mon Sep 17 00:00:00 2001 From: Damien George Date: Mon, 25 Feb 2019 10:47:54 +1100 Subject: [PATCH 22/32] src: Apply upstream patch ff13c_p1.diff. December 22, 2018: f_mkfs() function can fail with FR_MKFS_ABORTED if the FAT type is exFAT and the volume is located not at the first partition. --- src/ff.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ff.c b/src/ff.c index 2161338..93a8f01 100644 --- a/src/ff.c +++ b/src/ff.c @@ -5491,7 +5491,7 @@ FRESULT f_mkfs ( b_fat = b_vol + 32; /* FAT start at offset 32 */ sz_fat = ((sz_vol / au + 2) * 4 + ss - 1) / ss; /* Number of FAT sectors */ b_data = (b_fat + sz_fat + sz_blk - 1) & ~(sz_blk - 1); /* Align data area to the erase block boundary */ - if (b_data >= sz_vol / 2) LEAVE_MKFS(FR_MKFS_ABORTED); /* Too small volume? */ + if (b_data - b_vol >= sz_vol / 2) LEAVE_MKFS(FR_MKFS_ABORTED); /* Too small volume? */ n_clst = (sz_vol - (b_data - b_vol)) / au; /* Number of clusters */ if (n_clst <16) LEAVE_MKFS(FR_MKFS_ABORTED); /* Too few clusters? */ if (n_clst > MAX_EXFAT) LEAVE_MKFS(FR_MKFS_ABORTED); /* Too many clusters? */ From c1953a31e9fa902f3982c15d4e313913acf7ec67 Mon Sep 17 00:00:00 2001 From: Damien George Date: Mon, 25 Feb 2019 10:50:32 +1100 Subject: [PATCH 23/32] src: Apply upstream patch ff13c_p2.diff. January 9, 2019: f_readdir() function returns file names with wrong case conversion. When the directory item to be read has a file name within 8.3 format and only name body or name extension is in lower case, the file name returned in fname[] can be in wrong case conversion. --- src/ff.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/ff.c b/src/ff.c index 93a8f01..b4b730b 100644 --- a/src/ff.c +++ b/src/ff.c @@ -2619,6 +2619,7 @@ static void get_fileinfo ( { UINT si, di; #if FF_USE_LFN + BYTE lcf; WCHAR wc, hs; FATFS *fs = dp->obj.fs; #else @@ -2679,9 +2680,10 @@ static void get_fileinfo ( if (di == 0) { /* If LFN and SFN both are invalid, this object is inaccesible */ fno->fname[di++] = '?'; } else { - for (si = di = 0; fno->altname[si]; si++, di++) { /* Copy altname[] to fname[] with case information */ + for (si = di = 0, lcf = NS_BODY; fno->altname[si]; si++, di++) { /* Copy altname[] to fname[] with case information */ wc = (WCHAR)fno->altname[si]; - if (IsUpper(wc) && (dp->dir[DIR_NTres] & ((si >= 9) ? NS_EXT : NS_BODY))) wc += 0x20; + if (wc == '.') lcf = NS_EXT; + if (IsUpper(wc) && (dp->dir[DIR_NTres] & lcf)) wc += 0x20; fno->fname[di] = (TCHAR)wc; } } From 042a8bd9e44169f51d64040bf213498569dbb81d Mon Sep 17 00:00:00 2001 From: Damien George Date: Mon, 25 Feb 2019 10:53:57 +1100 Subject: [PATCH 24/32] src: Apply upstream patch ff13c_p3.diff. February 14, 2019: f_readdir() function cannot retrieve long file names in length of FF_MAX_LFN - 1 characters. f_open() function cannot find the file with file name in length of FF_MAX_LFN characters. --- src/ff.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/ff.c b/src/ff.c index b4b730b..3226c6e 100644 --- a/src/ff.c +++ b/src/ff.c @@ -1854,7 +1854,7 @@ static int cmp_lfn ( /* 1:matched, 0:not matched */ for (wc = 1, s = 0; s < 13; s++) { /* Process all characters in the entry */ uc = ld_word(dir + LfnOfs[s]); /* Pick an LFN character */ if (wc != 0) { - if (i >= FF_MAX_LFN || ff_wtoupper(uc) != ff_wtoupper(lfnbuf[i++])) { /* Compare it */ + if (i >= FF_MAX_LFN + 1 || ff_wtoupper(uc) != ff_wtoupper(lfnbuf[i++])) { /* Compare it */ return 0; /* Not matched */ } wc = uc; @@ -1890,15 +1890,15 @@ static int pick_lfn ( /* 1:succeeded, 0:buffer overflow or invalid LFN entry * for (wc = 1, s = 0; s < 13; s++) { /* Process all characters in the entry */ uc = ld_word(dir + LfnOfs[s]); /* Pick an LFN character */ if (wc != 0) { - if (i >= FF_MAX_LFN) return 0; /* Buffer overflow? */ + if (i >= FF_MAX_LFN + 1) return 0; /* Buffer overflow? */ lfnbuf[i++] = wc = uc; /* Store it */ } else { if (uc != 0xFFFF) return 0; /* Check filler */ } } - if (dir[LDIR_Ord] & LLEF) { /* Put terminator if it is the last LFN part */ - if (i >= FF_MAX_LFN) return 0; /* Buffer overflow? */ + if (dir[LDIR_Ord] & LLEF && wc != 0) { /* Put terminator if it is the last LFN part and not terminated */ + if (i >= FF_MAX_LFN + 1) return 0; /* Buffer overflow? */ lfnbuf[i] = 0; } From f23a30a1da57e791aeb4e175fdd6b9d86c47c2f6 Mon Sep 17 00:00:00 2001 From: Damien George Date: Tue, 5 Mar 2019 10:12:10 +1100 Subject: [PATCH 25/32] src: Decrease minimum volume size down to 22 sectors. This seems to be the minimum that holds a FAT12 filesystem with a sector size of 4096 bytes. Smaller sector sizes require more sectors for the minimum, but that bound is checked later on in the f_mkfs function. --- src/ff.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ff.c b/src/ff.c index 3226c6e..c7c79a1 100644 --- a/src/ff.c +++ b/src/ff.c @@ -5453,7 +5453,7 @@ FRESULT f_mkfs ( if (sz_vol < b_vol) LEAVE_MKFS(FR_MKFS_ABORTED); sz_vol -= b_vol; /* Volume size */ } - if (sz_vol < 50) LEAVE_MKFS(FR_MKFS_ABORTED); /* Check if volume size is >=50s */ + if (sz_vol < 22) LEAVE_MKFS(FR_MKFS_ABORTED); /* Check if volume size is >=22s (minimum for ss=4096) */ /* Pre-determine the FAT type */ do { From bc3007c89a2f84b3998fbb61d80f84179218684f Mon Sep 17 00:00:00 2001 From: Damien George Date: Tue, 5 Mar 2019 10:15:19 +1100 Subject: [PATCH 26/32] tests: Update expected output of fatfs1 test due to new ff behaviour. --- tests/fatfs1.exp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/tests/fatfs1.exp b/tests/fatfs1.exp index f70bd9c..2bfb6e3 100644 --- a/tests/fatfs1.exp +++ b/tests/fatfs1.exp @@ -144,8 +144,9 @@ close res=0 disk_ioctl(0, 6) disk_read(0, 2, 1) disk_read(0, 1, 1) -disk_write(0, 1, 1, 0x867a0372) get_fattime() +disk_write(0, 1, 1, 0x867a0372) +disk_write(0, 37, 1, 0x082d5505) disk_write(0, 37, 1, 0x2953772e) disk_read(0, 2, 1) disk_write(0, 2, 1, 0x55944b21) @@ -178,14 +179,14 @@ unlink res=0 == RENAME DIR == disk_ioctl(0, 6) disk_read(0, 2, 1) -disk_write(0, 2, 1, 0x2b759c33) +disk_write(0, 2, 1, 0x2c8e8693) disk_ioctl(0, 0) unlink res=0 == UNLINK DIR == disk_ioctl(0, 6) disk_read(0, 37, 1) disk_read(0, 2, 1) -disk_write(0, 2, 1, 0x09922d72) +disk_write(0, 2, 1, 0x1ab013d2) disk_read(0, 1, 1) disk_write(0, 1, 1, 0x5535694d) disk_ioctl(0, 0) From cb05c9486d3b48ffd6bd7542d8dbbab4b1caf790 Mon Sep 17 00:00:00 2001 From: Damien George Date: Tue, 5 Mar 2019 10:22:36 +1100 Subject: [PATCH 27/32] tests: Add fatfs2 to test filesystem with different sector sizes. --- tests/.gitignore | 2 +- tests/Makefile | 8 +- tests/fatfs2.c | 121 ++++++++++++++++++++++++ tests/fatfs2.exp | 220 ++++++++++++++++++++++++++++++++++++++++++++ tests/fatfs2_conf.h | 37 ++++++++ 5 files changed, 385 insertions(+), 3 deletions(-) create mode 100644 tests/fatfs2.c create mode 100644 tests/fatfs2.exp create mode 100644 tests/fatfs2_conf.h diff --git a/tests/.gitignore b/tests/.gitignore index 9f4f72b..3586ab0 100644 --- a/tests/.gitignore +++ b/tests/.gitignore @@ -1 +1 @@ -fatfs1 +fatfs[1-2] diff --git a/tests/Makefile b/tests/Makefile index 5fb9104..262d9d6 100644 --- a/tests/Makefile +++ b/tests/Makefile @@ -1,7 +1,11 @@ -all: fatfs1 +all: fatfs1 fatfs2 fatfs1: ../src/ff.c ../src/ffunicode.c util.c fatfs1.c gcc -g -I.. -std=c99 -DFFCONF_H='"tests/fatfs1_conf.h"' $^ -o $@ -test: fatfs1 +fatfs2: ../src/ff.c ../src/ffunicode.c util.c fatfs2.c + gcc -g -I.. -std=c99 -DFFCONF_H='"tests/fatfs2_conf.h"' $^ -o $@ + +test: fatfs1 fatfs2 ./fatfs1 | diff - fatfs1.exp + ./fatfs2 | diff - fatfs2.exp diff --git a/tests/fatfs2.c b/tests/fatfs2.c new file mode 100644 index 0000000..5c30ecc --- /dev/null +++ b/tests/fatfs2.c @@ -0,0 +1,121 @@ +// Test behaviour with different sector sizes + +#include +#include +#include +#include +#include + +#include "tests/util.h" +#include "src/ff.h" +#include "src/diskio.h" + +struct _bdev_t { + size_t nsec, sec_size; + uint8_t *blocks; +}; + +DRESULT disk_read(void *bdev_in, BYTE *buff, DWORD sector, UINT count) { + struct _bdev_t *bdev = bdev_in; + printf("disk_read(%u, %u)\n", sector, count); + memcpy(buff, bdev->blocks + sector * bdev->sec_size, count * bdev->sec_size); + return RES_OK; +} + +DRESULT disk_write(void *bdev_in, const BYTE *buff, DWORD sector, UINT count) { + struct _bdev_t *bdev = bdev_in; + printf("disk_write(%u, %u, 0x%08x)\n", sector, count, hash_djb2(buff, count * bdev->sec_size)); + memcpy(bdev->blocks + sector * bdev->sec_size, buff, count * bdev->sec_size); + return RES_OK; +} + +DRESULT disk_ioctl(void *bdev_in, BYTE cmd, void *buff) { + struct _bdev_t *bdev = bdev_in; + printf("disk_ioctl(%u)\n", cmd); + switch (cmd) { + case CTRL_SYNC: break; + case GET_SECTOR_COUNT: *((DWORD*)buff) = bdev->nsec; break; + case GET_SECTOR_SIZE: *((WORD*)buff) = bdev->sec_size; break; + case GET_BLOCK_SIZE: *((DWORD*)buff) = 1; break; + case IOCTL_INIT: *((DSTATUS*)buff) = 0; break; + case IOCTL_STATUS: *((DSTATUS*)buff) = 0; break; + default: assert(0); + } + return RES_OK; +} + +DWORD get_fattime(void) { + printf("get_fattime()\n"); + return 0; +} + +void run_single_test(size_t nsec, size_t sec_size) { + printf("======== BDEV nsec=%u sec_size=%u ========\n", nsec, sec_size); + + struct _bdev_t bdev = {nsec, sec_size, malloc(nsec * sec_size)}; + if (bdev.blocks == NULL) { + printf("malloc failed\n"); + return; + } + + FATFS fatfs; + fatfs.drv = &bdev; + + printf("== MKFS ==\n"); + { + uint8_t buf[FF_MAX_SS]; + FRESULT res = f_mkfs(&fatfs, FM_FAT | FM_SFD, 0, buf, sizeof(buf)); + printf("mkfs res=%d\n", res); + if (res != FR_OK) { + goto finished; + } + } + + printf("== MOUNT ==\n"); + { + FRESULT res = f_mount(&fatfs); + printf("mount res=%d\n", res); + } + + printf("== FILE CREATION ==\n"); + { + FIL fp; + FRESULT res = f_open(&fatfs, &fp, "/test.txt", FA_WRITE | FA_CREATE_ALWAYS); + printf("open res=%d\n", res); + UINT n; + res = f_write(&fp, "test file\n", 10, &n); + printf("write res=%d n=%u\n", res, n); + res = f_close(&fp); + printf("close res=%d\n", res); + } + + printf("== FILE READ ==\n"); + { + FIL fp; + FRESULT res = f_open(&fatfs, &fp, "/test.txt", FA_READ); + printf("open res=%d\n", res); + uint8_t buf[100]; + UINT n; + res = f_read(&fp, buf, 100, &n); + printf("read res=%d n=%u\n", res, n); + hexdump(buf, n, 16); + res = f_close(&fp); + printf("close res=%d\n", res); + } + +finished: + free(bdev.blocks); +} + +int main() { + // Run tests at the limit of minimum number of sectors for a valid filesystem + run_single_test(49, 512); + run_single_test(50, 512); + run_single_test(33, 1024); + run_single_test(34, 1024); + run_single_test(25, 2048); + run_single_test(26, 2048); + run_single_test(21, 4096); + run_single_test(22, 4096); + return 0; +} diff --git a/tests/fatfs2.exp b/tests/fatfs2.exp new file mode 100644 index 0000000..c106e6a --- /dev/null +++ b/tests/fatfs2.exp @@ -0,0 +1,220 @@ +======== BDEV nsec=49 sec_size=512 ======== +== MKFS == +disk_ioctl(5) +disk_ioctl(3) +disk_ioctl(2) +disk_ioctl(1) +mkfs res=14 +======== BDEV nsec=50 sec_size=512 ======== +== MKFS == +disk_ioctl(5) +disk_ioctl(3) +disk_ioctl(2) +disk_ioctl(1) +get_fattime() +disk_write(0, 1, 0xba3b6c44) +disk_write(1, 1, 0xd21511dd) +disk_write(2, 8, 0x016a1505) +disk_write(10, 8, 0x016a1505) +disk_write(18, 8, 0x016a1505) +disk_write(26, 8, 0x016a1505) +disk_ioctl(0) +mkfs res=0 +== MOUNT == +disk_ioctl(5) +disk_ioctl(2) +disk_read(0, 1) +mount res=0 +== FILE CREATION == +disk_ioctl(6) +disk_read(2, 1) +get_fattime() +open res=0 +disk_ioctl(6) +disk_write(2, 1, 0x89186453) +disk_read(1, 1) +write res=0 n=10 +disk_ioctl(6) +disk_write(34, 1, 0xe20a18df) +get_fattime() +disk_write(1, 1, 0x42bbc4cd) +disk_read(2, 1) +disk_write(2, 1, 0x15ad6edb) +disk_ioctl(0) +disk_ioctl(6) +close res=0 +== FILE READ == +disk_ioctl(6) +open res=0 +disk_ioctl(6) +disk_read(34, 1) +read res=0 n=10 +0000 74 65 73 74 20 66 69 6c 65 0a test file. +disk_ioctl(6) +disk_ioctl(6) +close res=0 +======== BDEV nsec=33 sec_size=1024 ======== +== MKFS == +disk_ioctl(5) +disk_ioctl(3) +disk_ioctl(2) +disk_ioctl(1) +mkfs res=14 +======== BDEV nsec=34 sec_size=1024 ======== +== MKFS == +disk_ioctl(5) +disk_ioctl(3) +disk_ioctl(2) +disk_ioctl(1) +get_fattime() +disk_write(0, 1, 0x902ad392) +disk_write(1, 1, 0x6e1851dd) +disk_write(2, 4, 0x016a1505) +disk_write(6, 4, 0x016a1505) +disk_write(10, 4, 0x016a1505) +disk_write(14, 4, 0x016a1505) +disk_ioctl(0) +mkfs res=0 +== MOUNT == +disk_ioctl(5) +disk_ioctl(2) +disk_read(0, 1) +mount res=0 +== FILE CREATION == +disk_ioctl(6) +disk_read(2, 1) +get_fattime() +open res=0 +disk_ioctl(6) +disk_write(2, 1, 0x81e12453) +disk_read(1, 1) +write res=0 n=10 +disk_ioctl(6) +disk_write(18, 1, 0xf9c5d8df) +get_fattime() +disk_write(1, 1, 0x0fbb04cd) +disk_read(2, 1) +disk_write(2, 1, 0xfef82edb) +disk_ioctl(0) +disk_ioctl(6) +close res=0 +== FILE READ == +disk_ioctl(6) +open res=0 +disk_ioctl(6) +disk_read(18, 1) +read res=0 n=10 +0000 74 65 73 74 20 66 69 6c 65 0a test file. +disk_ioctl(6) +disk_ioctl(6) +close res=0 +======== BDEV nsec=25 sec_size=2048 ======== +== MKFS == +disk_ioctl(5) +disk_ioctl(3) +disk_ioctl(2) +disk_ioctl(1) +mkfs res=14 +======== BDEV nsec=26 sec_size=2048 ======== +== MKFS == +disk_ioctl(5) +disk_ioctl(3) +disk_ioctl(2) +disk_ioctl(1) +get_fattime() +disk_write(0, 1, 0xee6e7fe6) +disk_write(1, 1, 0x161ed1dd) +disk_write(2, 2, 0x016a1505) +disk_write(4, 2, 0x016a1505) +disk_write(6, 2, 0x016a1505) +disk_write(8, 2, 0x016a1505) +disk_ioctl(0) +mkfs res=0 +== MOUNT == +disk_ioctl(5) +disk_ioctl(2) +disk_read(0, 1) +mount res=0 +== FILE CREATION == +disk_ioctl(6) +disk_read(2, 1) +get_fattime() +open res=0 +disk_ioctl(6) +disk_write(2, 1, 0x0372a453) +disk_read(1, 1) +write res=0 n=10 +disk_ioctl(6) +disk_write(10, 1, 0xf93d58df) +get_fattime() +disk_write(1, 1, 0x19b984cd) +disk_read(2, 1) +disk_write(2, 1, 0xe18daedb) +disk_ioctl(0) +disk_ioctl(6) +close res=0 +== FILE READ == +disk_ioctl(6) +open res=0 +disk_ioctl(6) +disk_read(10, 1) +read res=0 n=10 +0000 74 65 73 74 20 66 69 6c 65 0a test file. +disk_ioctl(6) +disk_ioctl(6) +close res=0 +======== BDEV nsec=21 sec_size=4096 ======== +== MKFS == +disk_ioctl(5) +disk_ioctl(3) +disk_ioctl(2) +disk_ioctl(1) +mkfs res=14 +======== BDEV nsec=22 sec_size=4096 ======== +== MKFS == +disk_ioctl(5) +disk_ioctl(3) +disk_ioctl(2) +disk_ioctl(1) +get_fattime() +disk_write(0, 1, 0xa88c80f2) +disk_write(1, 1, 0x262bd1dd) +disk_write(2, 1, 0x016a1505) +disk_write(3, 1, 0x016a1505) +disk_write(4, 1, 0x016a1505) +disk_write(5, 1, 0x016a1505) +disk_ioctl(0) +mkfs res=0 +== MOUNT == +disk_ioctl(5) +disk_ioctl(2) +disk_read(0, 1) +mount res=0 +== FILE CREATION == +disk_ioctl(6) +disk_read(2, 1) +get_fattime() +open res=0 +disk_ioctl(6) +disk_write(2, 1, 0x4695a453) +disk_read(1, 1) +write res=0 n=10 +disk_ioctl(6) +disk_write(6, 1, 0x382c58df) +get_fattime() +disk_write(1, 1, 0xedb684cd) +disk_read(2, 1) +disk_write(2, 1, 0xe6b8aedb) +disk_ioctl(0) +disk_ioctl(6) +close res=0 +== FILE READ == +disk_ioctl(6) +open res=0 +disk_ioctl(6) +disk_read(6, 1) +read res=0 n=10 +0000 74 65 73 74 20 66 69 6c 65 0a test file. +disk_ioctl(6) +disk_ioctl(6) +close res=0 diff --git a/tests/fatfs2_conf.h b/tests/fatfs2_conf.h new file mode 100644 index 0000000..725d2dc --- /dev/null +++ b/tests/fatfs2_conf.h @@ -0,0 +1,37 @@ +#define FFCONF_DEF 86604 +#define FF_FS_READONLY 0 +#define FF_FS_MINIMIZE 0 +#define FF_USE_STRFUNC 0 +#define FF_USE_FIND 0 +#define FF_USE_MKFS 1 +#define FF_USE_FASTSEEK 0 +#define FF_USE_EXPAND 0 +#define FF_USE_CHMOD 1 +#define FF_USE_LABEL 1 +#define FF_USE_FORWARD 0 +#define FF_CODE_PAGE 437 +#define FF_USE_LFN 1 +#define FF_MAX_LFN 255 +#define FF_LFN_UNICODE 0 +#define FF_LFN_BUF 255 +#define FF_SFN_BUF 12 +#define FF_STRF_ENCODE 3 +#define FF_FS_RPATH 0 +#define FF_VOLUMES 1 +#define FF_STR_VOLUME_ID 0 +#define FF_VOLUME_STRS "RAM","NAND","CF","SD1","SD2","USB1","USB2","USB3" +#define FF_MULTI_PARTITION 0 +#define FF_MIN_SS 512 +#define FF_MAX_SS 4096 +#define FF_USE_TRIM 0 +#define FF_FS_NOFSINFO 0 +#define FF_FS_TINY 0 +#define FF_FS_EXFAT 1 +#define FF_FS_NORTC 0 +#define FF_NORTC_MON 1 +#define FF_NORTC_MDAY 1 +#define FF_NORTC_YEAR 2015 +#define FF_FS_LOCK 0 +#define FF_FS_REENTRANT 0 +#define FF_FS_TIMEOUT 1000 +#define FF_SYNC_t HANDLE From 3b4ee5a646af2769b3dddfe17d5d866233c1e45b Mon Sep 17 00:00:00 2001 From: Damien George Date: Thu, 7 Mar 2019 14:58:10 +1100 Subject: [PATCH 28/32] src: Fix typo with ! applied inside parenthesis on ioctl check. --- src/ff.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ff.c b/src/ff.c index c7c79a1..0c9d04f 100644 --- a/src/ff.c +++ b/src/ff.c @@ -3356,7 +3356,7 @@ static FRESULT validate ( /* Returns FR_OK or FR_INVALID_OBJECT */ res = FR_TIMEOUT; } #else - if (disk_ioctl(obj->fs->drv, IOCTL_STATUS, &stat) == RES_OK && (!stat & STA_NOINIT)) { /* Test if the phsical drive is kept initialized */ + if (disk_ioctl(obj->fs->drv, IOCTL_STATUS, &stat) == RES_OK && !(stat & STA_NOINIT)) { /* Test if the phsical drive is kept initialized */ res = FR_OK; } #endif From de6123238e81dc702678ec03f1463f1a6815ad2d Mon Sep 17 00:00:00 2001 From: Jim Mussared Date: Thu, 25 Apr 2019 17:06:26 +1000 Subject: [PATCH 29/32] src: Add f_repair(FATFS*) function. Running this function on a mounted filesystem will: - Clear the dirty flag (avoiding the "This volume was not cleanly unmounted" error) - Clean up any unreferenced clusters (potentially left behind from conflicting host/device writes). - Update file sizes to match cluster chain length (or truncate cluster chain to match smaller file size). --- src/ff.c | 201 +++++++++++++++++++++++++++++++++++++++++++++++++++ src/ff.h | 1 + src/ffconf.h | 4 + 3 files changed, 206 insertions(+) diff --git a/src/ff.c b/src/ff.c index 0c9d04f..4189668 100644 --- a/src/ff.c +++ b/src/ff.c @@ -5915,6 +5915,207 @@ FRESULT f_fdisk ( #endif /* FF_USE_MKFS && !FF_FS_READONLY */ +#if FF_USE_REPAIR && !FF_FS_READONLY +/*-----------------------------------------------------------------------*/ +/* Repair an FAT/exFAT volume by reclaiming unreferenced clusters. */ +/*-----------------------------------------------------------------------*/ + +/* Marks all clusters in this object's chain as "referenced" in the bitmap. */ +static FRESULT repair_mark_chain (BYTE* bitmap, UINT lcpb, FFOBJID* obj, int* fixed) { + DWORD clst = obj->sclust; + DWORD nclst = 0; + *fixed = 0; + + /* Follow the chain. */ + while (clst >= 2 && clst < obj->fs->n_fatent) { + ++nclst; + DWORD idx = clst >> lcpb; /* Adjust precision based on how big the bitmap is (lcpb = log2(clusters per bit). */ + bitmap[idx / 8] |= 1 << (idx % 8); + + DWORD next = get_fat(obj, clst); + if (!(obj->attr & AM_DIR) && (next >= 2 && next < obj->fs->n_fatent) && nclst * obj->fs->csize * SS(obj->fs) >= obj->objsize) { + /* More clusters than expected for this file's size, truncate the chain. */ + put_fat(obj->fs, clst, 0xFFFFFFFF); + *fixed = 1; + break; + } + + if (next == 0xFFFFFFFF) return FR_DISK_ERR; + clst = next; + } + + /* Truncate file size to the size of the cluster chain. */ + DWORD cb = nclst * obj->fs->csize * SS(obj->fs); + if (cb < obj->objsize) { + obj->objsize = cb; + *fixed = 1; + } + + return FR_OK; +} + +/* Recursively mark all objects in this directory in the bitmap. */ +static FRESULT repair_mark_dir (BYTE* bitmap, UINT lcpb, DIR* dp) { + FRESULT res = FR_OK; + + for (;;) { + /* Advance to the next file/directory (i.e. the SFN entry). */ + res = DIR_READ_FILE(dp); + if (res == FR_NO_FILE) { + /* End of directory. */ + res = FR_OK; + break; + } + + if (res != FR_OK) break; + + FFOBJID obj; + obj.fs = dp->obj.fs; + obj.sclust = ld_clust(dp->obj.fs, dp->dir); + obj.objsize = ld_dword(dp->dir + DIR_FileSize); + obj.attr = dp->obj.attr; + if (!(dp->obj.attr & AM_DIR) && obj.objsize == 0) { + /* Note: Directories always have their size set to zero, + so can't apply this check. */ + if (obj.sclust != 0) { + /* File is zero-length, shouldn't have a cluster chain. */ + obj.sclust = 0; + st_clust(dp->obj.fs, dp->dir, 0); + dp->obj.fs->wflag = 1; + } + } else { + /* Mark this child file (or directory)'s' clusters, + then move the window back to the parent. */ + int fixed; + repair_mark_chain(bitmap, lcpb, &obj, &fixed); + res = move_window(dp->obj.fs, dp->sect); + if (res != FR_OK) break; + + if (fixed) { + /* Chain was shorter than expected. + Update the directory entry with truncated file size. */ + st_dword(dp->dir + DIR_FileSize, obj.objsize); + dp->obj.fs->wflag = 1; + } + } + + /* If the child is a directory, recurse into it. + Note: Confusingly, obj.attr represents the current file, not the directory + represented by dp itself! */ + if (dp->obj.attr & AM_DIR) { + /* dptr and obj.sclust can be used to resume the directory scan. */ + DWORD ofs = dp->dptr; + DWORD clst = dp->obj.sclust; + + /* Move dp to the start of the child directory and scan it. */ + dp->obj.sclust = ld_clust(dp->obj.fs, dp->obj.fs->win + dp->dptr % SS(dp->obj.fs)); + res = dir_sdi(dp, 0); + if (res != FR_OK) break; + res = repair_mark_dir(bitmap, lcpb, dp); + if (res != FR_OK) break; + + /* Restore the state of the parent scan. */ + dp->obj.sclust = clst; + res = dir_sdi(dp, ofs); + if (res != FR_OK) break; + } + + res = dir_next(dp, 0); + if (res == FR_NO_FILE) { + res = FR_OK; + break; + } + } + + return res; +} + +FRESULT f_repair (FATFS* fs, void* work, UINT len) { + if (FF_FS_EXFAT && fs->fs_type == FS_EXFAT) { + /* f_repair is unsupported on EXFAT. */ + return FR_INVALID_PARAMETER; + } + + /* Figure out how many clusters can be represented by each bit in the bitmap (log2 for faster division later). + Ideally this is 0 (i.e. 1 bit per cluster), but it might not be possible to provide a bitmap big enough. */ + UINT lcpb = 0; + while (fs->n_fatent >> lcpb >= len * 8) { + lcpb += 1; + } + + /* Initialize bitmap. */ + BYTE* bitmap = work; + mem_set(bitmap, 0, len); + + /* Open the root directory and mark all referenced clusters. */ + DIR dir; + dir.obj.fs = fs; + dir.obj.sclust = 0; /* Root directory. */ + dir_sdi(&dir, 0); + FRESULT res = repair_mark_dir(bitmap, lcpb, &dir); + if (res != FR_OK) return res; + + /* Don't count bad clusters as "used". */ + DWORD badclst = 0; + if (fs->fs_type == FS_FAT12) { + badclst = 0xFF7; + } else if (fs->fs_type == FS_FAT16) { + badclst = 0xFFF7; + } else if (fs->fs_type == FS_FAT32) { + badclst = 0xFFFFFFF7; + } + + /* Clear any FAT entries that aren't referenced in the bitmap. */ + DWORD free = 0; + DWORD modified = 0; + for (DWORD clst = 2; clst < fs->n_fatent; ++clst) { + DWORD actual = get_fat(&dir.obj, clst); + + DWORD idx = clst >> lcpb; /* Adjust precision. */ + if (actual == badclst) { + continue; + } else if (actual == 0) { + ++free; + } else if (((bitmap[idx / 8] >> (idx % 8)) & 1) == 0) { + res = put_fat(fs, clst, 0); + if (res != FR_OK) return res; + + modified = 1; + ++free; + } + } + + /* Update free_clst (used by f_getfree, and stored in FSINFO for FAT32). */ + if (fs->free_clst != free) { + fs->free_clst = free; + fs->fsi_flag |= 1; + fs->wflag = 1; + modified = 1; + } + + /* Check if the volume was not cleanly unmounted (and clear flag if necessary). */ + res = move_window(fs, fs->volbase); + if (res != FR_OK) return res; + if (fs->fs_type < FS_FAT32 && fs->win[BS_NTres]) { + fs->win[BS_NTres] = 0; + fs->wflag = 1; + modified = 1; + } else if (fs->fs_type == FS_FAT32 && fs->win[BS_NTres32]) { + fs->win[BS_NTres32] = 0; + fs->wflag = 1; + modified = 1; + } + + /* Write out changes to the bootsector. */ + if (modified) { + res = sync_fs(fs); + if (res != FR_OK) return res; + } + + return FR_OK; +} +#endif /* FF_USE_REPAIR && !FF_FS_READONLY */ + #if FF_CODE_PAGE == 0 /*-----------------------------------------------------------------------*/ diff --git a/src/ff.h b/src/ff.h index a8aa00e..198063a 100644 --- a/src/ff.h +++ b/src/ff.h @@ -309,6 +309,7 @@ FRESULT f_umount (FATFS* fs); /* Unmount a FRESULT f_mkfs (FATFS *fs, BYTE opt, DWORD au, void* work, UINT len); /* Create a FAT volume */ FRESULT f_fdisk (void *pdrv, const DWORD* szt, void* work); /* Divide a physical drive into some partitions */ FRESULT f_setcp (WORD cp); /* Set current code page */ +FRESULT f_repair (FATFS* fs, void* work, UINT len); /* Free unreferenced clusters from the FAT */ #define f_eof(fp) ((int)((fp)->fptr == (fp)->obj.objsize)) #define f_error(fp) ((fp)->err) diff --git a/src/ffconf.h b/src/ffconf.h index edd052b..036b6f0 100644 --- a/src/ffconf.h +++ b/src/ffconf.h @@ -68,6 +68,10 @@ /* This option switches f_forward() function. (0:Disable or 1:Enable) */ +#define FF_USE_REPAIR 0 +/* This option switches f_repair() function. (0:Disable or 1:Enable) */ + + /*---------------------------------------------------------------------------/ / Locale and Namespace Configurations /---------------------------------------------------------------------------*/ From e2e5b56a73f8e99e734d011a2108f147083fcb18 Mon Sep 17 00:00:00 2001 From: Jim Mussared Date: Thu, 25 Apr 2019 17:07:21 +1000 Subject: [PATCH 30/32] tests: Add tests for f_repair() function. The two tests are: - fatfs_repair creates an in-memory filesystem and corrupts it, then repairs it. - fatfs_repair_img will repair an image file (test.full.img is a filesystem with 100% usage due to mostly unreferenced clusters). --- tests/.gitignore | 3 + tests/Makefile | 13 +++ tests/fatfs1_conf.h | 1 + tests/fatfs2_conf.h | 1 + tests/fatfs_repair.c | 228 ++++++++++++++++++++++++++++++++++++++ tests/fatfs_repair_conf.h | 38 +++++++ tests/fatfs_repair_img.c | 98 ++++++++++++++++ tests/test.full.img.gz | Bin 0 -> 7533 bytes 8 files changed, 382 insertions(+) create mode 100644 tests/fatfs_repair.c create mode 100644 tests/fatfs_repair_conf.h create mode 100644 tests/fatfs_repair_img.c create mode 100644 tests/test.full.img.gz diff --git a/tests/.gitignore b/tests/.gitignore index 3586ab0..a449aaf 100644 --- a/tests/.gitignore +++ b/tests/.gitignore @@ -1 +1,4 @@ fatfs[1-2] +fatfs_repair +fatfs_repair_img +test.*.img diff --git a/tests/Makefile b/tests/Makefile index 262d9d6..28380b3 100644 --- a/tests/Makefile +++ b/tests/Makefile @@ -6,6 +6,19 @@ fatfs1: ../src/ff.c ../src/ffunicode.c util.c fatfs1.c fatfs2: ../src/ff.c ../src/ffunicode.c util.c fatfs2.c gcc -g -I.. -std=c99 -DFFCONF_H='"tests/fatfs2_conf.h"' $^ -o $@ +fatfs_repair: ../src/ff.c ../src/ffunicode.c util.c fatfs_repair.c + gcc -g -I.. -std=c99 -Werror -DFFCONF_H='"tests/fatfs_repair_conf.h"' $^ -o $@ + ./fatfs_repair + +fatfs_repair_img: ../src/ff.c ../src/ffunicode.c util.c fatfs_repair_img.c + gcc -g -I.. -std=c99 -Werror -DFFCONF_H='"tests/fatfs_repair_conf.h"' $^ -o $@ + + zcat test.full.img.gz > /tmp/test.img + fsck.vfat -n -l /tmp/test.img || true + ./fatfs_repair_img /tmp/test.img + fsck.vfat -n -l /tmp/test.img || true + rm /tmp/test.img + test: fatfs1 fatfs2 ./fatfs1 | diff - fatfs1.exp ./fatfs2 | diff - fatfs2.exp diff --git a/tests/fatfs1_conf.h b/tests/fatfs1_conf.h index 67d2207..5d3f9c7 100644 --- a/tests/fatfs1_conf.h +++ b/tests/fatfs1_conf.h @@ -9,6 +9,7 @@ #define FF_USE_CHMOD 1 #define FF_USE_LABEL 1 #define FF_USE_FORWARD 0 +#define FF_USE_REPAIR 0 #define FF_CODE_PAGE 437 #define FF_USE_LFN 1 #define FF_MAX_LFN 255 diff --git a/tests/fatfs2_conf.h b/tests/fatfs2_conf.h index 725d2dc..b73d5b9 100644 --- a/tests/fatfs2_conf.h +++ b/tests/fatfs2_conf.h @@ -9,6 +9,7 @@ #define FF_USE_CHMOD 1 #define FF_USE_LABEL 1 #define FF_USE_FORWARD 0 +#define FF_USE_REPAIR 0 #define FF_CODE_PAGE 437 #define FF_USE_LFN 1 #define FF_MAX_LFN 255 diff --git a/tests/fatfs_repair.c b/tests/fatfs_repair.c new file mode 100644 index 0000000..d3d668e --- /dev/null +++ b/tests/fatfs_repair.c @@ -0,0 +1,228 @@ +#include +#include +#include +#include +#include + +#include "tests/util.h" +#include "src/ff.h" +#include "src/diskio.h" + +// Test with 12/16/32. +#define FAT_TYPE (FS_FAT12) + +#if FAT_TYPE == FS_FAT12 +#define NSEC (1024) +#define NSEC_RAM (NSEC) +#define FAT_FORMAT FM_FAT +#elif FAT_TYPE == FS_FAT16 +#define NSEC (10240) +#define NSEC_RAM (1000) +#define FAT_FORMAT FM_FAT +#else +#define NSEC (512000) +#define NSEC_RAM (10000) +#define FAT_FORMAT FM_FAT32 +#endif +#define SEC_SIZE (512) + +static uint8_t ram_bdev[SEC_SIZE * NSEC_RAM]; + +struct _bdev_t { + int pdrv; +}; + +DRESULT disk_read(void *bdev_in, BYTE *buff, DWORD sector, UINT count) { + struct _bdev_t *bdev = bdev_in; + if (sector * SEC_SIZE > sizeof(ram_bdev)) { + printf("ram_bdev too small\n"); + return FR_DISK_ERR; + } + // printf("disk_read(%d, %u, %u)\n", bdev->pdrv, sector, count); + memcpy(buff, ram_bdev + sector * SEC_SIZE, count * SEC_SIZE); + return RES_OK; +} + +DRESULT disk_write(void *bdev_in, const BYTE *buff, DWORD sector, UINT count) { + struct _bdev_t *bdev = bdev_in; + if (sector * SEC_SIZE > sizeof(ram_bdev)) { + printf("ram_bdev too small\n"); + return FR_DISK_ERR; + } + // printf("disk_write(%d, %u, %u)\n", bdev->pdrv, sector, count); + memcpy(ram_bdev + sector * SEC_SIZE, buff, count * SEC_SIZE); + return RES_OK; +} + +DRESULT disk_ioctl(void *bdev_in, BYTE cmd, void *buff) { + struct _bdev_t *bdev = bdev_in; + // printf("disk_ioctl(%d, %u)\n", bdev->pdrv, cmd); + switch (cmd) { + case CTRL_SYNC: break; + case GET_SECTOR_COUNT: *((DWORD*)buff) = NSEC; break; + case GET_SECTOR_SIZE: *((WORD*)buff) = SEC_SIZE; break; + case GET_BLOCK_SIZE: *((DWORD*)buff) = 1; break; + case IOCTL_INIT: *((DSTATUS*)buff) = 0; break; + case IOCTL_STATUS: *((DSTATUS*)buff) = 0; break; + default: assert(0); + } + return RES_OK; +} + +DWORD get_fattime(void) { + return 0; +} + +FRESULT create_file(FATFS* fs, const TCHAR* path, UINT size) { + uint8_t buf[16] = {0}; + for (uint8_t i = 0; i < sizeof(buf); ++i) { + buf[i] = i; + } + FIL fp; + FRESULT res = f_open(fs, &fp, path, FA_CREATE_ALWAYS | FA_WRITE); + for (int i = 0; i < size / sizeof(buf); ++i) { + UINT written = 0; + f_write(&fp, buf, sizeof(buf), &written); + } + f_close(&fp); +} + +FRESULT abandon_chain(FATFS* fs, const TCHAR* path) { + FIL fp; + FRESULT res = f_open(fs, &fp, path, FA_READ); + + fp.obj.sclust = 0; + fp.flag |= 0x40; // FA_MODIFIED + f_sync(&fp); + + f_close(&fp); +} + +FRESULT truncate_without_removing_chain(FATFS* fs, const TCHAR* path, FSIZE_t size) { + FIL fp; + FRESULT res = f_open(fs, &fp, path, FA_READ); + + fp.obj.objsize = size; + fp.flag |= 0x40; // FA_MODIFIED + f_sync(&fp); + + f_close(&fp); +} + +FRESULT corrupt_chain(FATFS* fs, const TCHAR* path) { + FIL fp; + uint8_t buf[16] = {0}; + FRESULT res = f_open(fs, &fp, path, FA_WRITE | FA_OPEN_APPEND); + + uint8_t* fat_copy = malloc(fs->fsize * SEC_SIZE); + memcpy(fat_copy, ram_bdev + fs->fatbase * SEC_SIZE, fs->fsize * SEC_SIZE); + + for (int i = 0; i < 10 * fs->csize * SEC_SIZE / sizeof(buf); ++i) { + UINT written = 0; + f_write(&fp, buf, sizeof(buf), &written); + } + + f_close(&fp); + + f_umount(fs); + memcpy(ram_bdev + fs->fatbase * SEC_SIZE, fat_copy, fs->fsize * SEC_SIZE); + free(fat_copy); + f_mount(fs); +} + +int main() { + struct _bdev_t bdev = {0}; + FATFS fs; + fs.drv = &bdev; + + uint8_t buf[SEC_SIZE]; + FRESULT res = f_mkfs(&fs, FAT_FORMAT | FM_SFD, 0, buf, sizeof(buf)); + res = f_mount(&fs); + + printf("Cluster size: %d sectors (%d)\n", fs.csize, fs.fs_type); + + DWORD nclst; + res = f_getfree(&fs, &nclst); + printf("Free clusters: %u\n", nclst); + + FILINFO fi; + + res = f_mkdir(&fs, "/a"); + res = f_mkdir(&fs, "/a/aa"); + res = f_mkdir(&fs, "/b"); + res = f_mkdir(&fs, "/b/ba"); + res = f_mkdir(&fs, "/c"); + res = f_mkdir(&fs, "/c/ca"); + res = f_mkdir(&fs, "/d"); + res = f_mkdir(&fs, "/d/da"); + create_file(&fs, "/a/aa/aaa.txt", 121); + create_file(&fs, "/a/aa.txt", 812); + create_file(&fs, "/a/ab.txt", 38712); + create_file(&fs, "/a/ac.txt", 0); + create_file(&fs, "/a/data1.txt", 21171); + create_file(&fs, "/b/ba/bba.txt", 281); + create_file(&fs, "/b/ba.txt", 4782); + create_file(&fs, "/b/bb.txt", 728); + create_file(&fs, "/b/data2.txt", 23917); + create_file(&fs, "/c/ca/cca.txt", 24); + create_file(&fs, "/c/ca.txt", 2971); + create_file(&fs, "/c/cb.txt", 0); + create_file(&fs, "/c/data3.txt", fs.csize * SEC_SIZE * 10); + create_file(&fs, "/d/da/dda.txt", 21); + create_file(&fs, "/d/da.txt", 3102); + create_file(&fs, "/d/db.txt", 0); + create_file(&fs, "/d/data4.txt", 26712); + + printf("\nBefore corruption:\n"); + res = f_getfree(&fs, &nclst); + printf("Free clusters: %u\n", nclst); + f_stat(&fs, "/a/data1.txt", &fi); + printf("/a/data1.txt: %u bytes\n", fi.fsize); + f_stat(&fs, "/b/data2.txt", &fi); + printf("/b/data2.txt: %u bytes\n", fi.fsize); + f_stat(&fs, "/c/data3.txt", &fi); + printf("/c/data3.txt: %u bytes\n", fi.fsize); + f_stat(&fs, "/d/data4.txt", &fi); + printf("/d/data4.txt: %u bytes\n", fi.fsize); + + abandon_chain(&fs, "/a/data1.txt"); + truncate_without_removing_chain(&fs, "/b/data2.txt", 0); + truncate_without_removing_chain(&fs, "/c/data3.txt", fs.csize * SEC_SIZE * 5); + corrupt_chain(&fs, "/d/data4.txt"); + + printf("\nBefore repair:\n"); + res = f_getfree(&fs, &nclst); + printf("Free clusters: %u\n", nclst); + f_stat(&fs, "/a/data1.txt", &fi); + printf("/a/data1.txt: %u bytes\n", fi.fsize); + f_stat(&fs, "/b/data2.txt", &fi); + printf("/b/data2.txt: %u bytes\n", fi.fsize); + f_stat(&fs, "/c/data3.txt", &fi); + printf("/c/data3.txt: %u bytes\n", fi.fsize); + f_stat(&fs, "/d/data4.txt", &fi); + printf("/d/data4.txt: %u bytes\n", fi.fsize); + + printf("\nRepairing...\n"); + uint8_t bitmap[20]; + res = f_repair(&fs, bitmap, sizeof(bitmap)); + if (res != FR_OK) { + printf("Repair failed: %d\n", res); + return 1; + } + + printf("\nAfter repair:\n"); + res = f_getfree(&fs, &nclst); + printf("Free clusters: %u\n", nclst); + f_stat(&fs, "/a/data1.txt", &fi); + printf("/a/data1.txt: %u bytes\n", fi.fsize); + f_stat(&fs, "/b/data2.txt", &fi); + printf("/b/data2.txt: %u bytes\n", fi.fsize); + f_stat(&fs, "/c/data3.txt", &fi); + printf("/c/data3.txt: %u bytes\n", fi.fsize); + f_stat(&fs, "/d/data4.txt", &fi); + printf("/d/data4.txt: %u bytes\n", fi.fsize); + + f_umount(&fs); + + return 0; +} diff --git a/tests/fatfs_repair_conf.h b/tests/fatfs_repair_conf.h new file mode 100644 index 0000000..e5af414 --- /dev/null +++ b/tests/fatfs_repair_conf.h @@ -0,0 +1,38 @@ +#define FFCONF_DEF 86604 +#define FF_FS_READONLY 0 +#define FF_FS_MINIMIZE 0 +#define FF_USE_STRFUNC 0 +#define FF_USE_FIND 0 +#define FF_USE_MKFS 1 +#define FF_USE_FASTSEEK 0 +#define FF_USE_EXPAND 0 +#define FF_USE_CHMOD 1 +#define FF_USE_LABEL 1 +#define FF_USE_FORWARD 0 +#define FF_USE_REPAIR 1 +#define FF_CODE_PAGE 437 +#define FF_USE_LFN 1 +#define FF_MAX_LFN 255 +#define FF_LFN_UNICODE 0 +#define FF_LFN_BUF 255 +#define FF_SFN_BUF 12 +#define FF_STRF_ENCODE 3 +#define FF_FS_RPATH 0 +#define FF_VOLUMES 1 +#define FF_STR_VOLUME_ID 0 +#define FF_VOLUME_STRS "RAM","NAND","CF","SD1","SD2","USB1","USB2","USB3" +#define FF_MULTI_PARTITION 0 +#define FF_MIN_SS 512 +#define FF_MAX_SS 512 +#define FF_USE_TRIM 0 +#define FF_FS_NOFSINFO 0 +#define FF_FS_TINY 0 +#define FF_FS_EXFAT 1 +#define FF_FS_NORTC 0 +#define FF_NORTC_MON 1 +#define FF_NORTC_MDAY 1 +#define FF_NORTC_YEAR 2015 +#define FF_FS_LOCK 0 +#define FF_FS_REENTRANT 0 +#define FF_FS_TIMEOUT 1000 +#define FF_SYNC_t HANDLE diff --git a/tests/fatfs_repair_img.c b/tests/fatfs_repair_img.c new file mode 100644 index 0000000..a4c5209 --- /dev/null +++ b/tests/fatfs_repair_img.c @@ -0,0 +1,98 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "tests/util.h" +#include "src/ff.h" +#include "src/diskio.h" + +#define SEC_SIZE (512) + +int fd; + +struct _bdev_t { + int pdrv; +}; + +DRESULT disk_read(void *bdev_in, BYTE *buff, DWORD sector, UINT count) { + struct _bdev_t *bdev = bdev_in; + lseek(fd, sector * SEC_SIZE, SEEK_SET); + read(fd, buff, SEC_SIZE * count); + return RES_OK; +} + +DRESULT disk_write(void *bdev_in, const BYTE *buff, DWORD sector, UINT count) { + struct _bdev_t *bdev = bdev_in; + lseek(fd, sector * SEC_SIZE, SEEK_SET); + write(fd, buff, SEC_SIZE * count); + return RES_OK; +} + +DRESULT disk_ioctl(void *bdev_in, BYTE cmd, void *buff) { + struct _bdev_t *bdev = bdev_in; + switch (cmd) { + case CTRL_SYNC: + fsync(fd); + break; + case GET_SECTOR_COUNT: + *((DWORD*)buff) = lseek(fd, 0, SEEK_END); + break; + case GET_SECTOR_SIZE: *((WORD*)buff) = SEC_SIZE; break; + case GET_BLOCK_SIZE: *((DWORD*)buff) = 1; break; + case IOCTL_INIT: *((DSTATUS*)buff) = 0; break; + case IOCTL_STATUS: *((DSTATUS*)buff) = 0; break; + default: assert(0); + } + return RES_OK; +} + +DWORD get_fattime(void) { + return 0; +} + +int main(int argc, char** argv) { + struct _bdev_t bdev = {0}; + FATFS fs; + fs.drv = &bdev; + + fd = open(argv[1], O_RDWR); + + FRESULT res = f_mount(&fs); + if (res != FR_OK) { + printf("Failed to mount fs: %d.\n", res); + return 1; + } + + printf("Cluster size: %d sectors (%d)\n", fs.csize, fs.fs_type); + + printf("\nBefore repair:\n"); + DWORD nclst; + res = f_getfree(&fs, &nclst); + printf("Free clusters: %u\n", nclst); + + printf("\nRepairing...\n"); + // Experiment with the size of the bitmap to see how many reclaimable clusters + // are left behind for fsck.vfat to find. + uint8_t bitmap[20]; + res = f_repair(&fs, bitmap, sizeof(bitmap)); + if (res != FR_OK) { + printf("Repair failed: %d\n", res); + return 1; + } + + printf("\nAfter repair:\n"); + res = f_getfree(&fs, &nclst); + printf("Free clusters: %u\n", nclst); + + f_umount(&fs); + + close(fd); + + return 0; +} diff --git a/tests/test.full.img.gz b/tests/test.full.img.gz new file mode 100644 index 0000000000000000000000000000000000000000..d434fd752fc8108bb4de723c6665206994984685 GIT binary patch literal 7533 zcmeI#YdjNt|G@FCJDo1lZLZWRs%4Z=k{qKG6;aBFIV3U6Fw7y1>mpoE6S8HQUCxJL z4U3IUg~<7=Im~e}V{_bM4*%=AAKwq|r~lW>=gIf=`n|s2C+}y!)A0unGVMOw@7WvR z>K~x)hVt@K_dvk*%#XnD{WijETB7Nt|0hk%)Qfz#zta=7{U=}(@`~m^U7CvebN0^P zVWy%i{+V|$gYq)}6mk*_0)d8P7K9ZNV#32=OJ7X^?10?D|Jk@ZM zGgj`m#-hbiNc%vskIww|r^K>RtAs~{Q$!tH&g4*AoDrfG>(l!JI9;dV8Ms}VEV+0| zO)$2z$@9r|`=i8md=$J0{P$0cTiiRQjBmW(J~^$9Z24UWWuKw+#(f&#KyP@4eTN4F z9a7qUxj#^?2tCuDZ06sa7vkm-R#EwvnVrrVwG%iw$y!yvOK>`_ecshas3KS{KE7Cd zN>mJJF6NZu18hretp`;}f)p*O<`Ye><`KGT%et6V-Gv{zgm!<6pmtr&%QN#oGyMN0 zSn(4`a@oh)**HAoQc#E!aFMCUN1I6DzYt@l43i{QMwUZvb5~5-R=(nAuJiGt7th$eOCg;S%uWvTQV-e* zk9N`$Gx^JC&2e$yh=}lP`}M1BtBqGlA=_Rnn<9r5BdN9>9mAc}PlAdOff;?wredth ztxn(&X0(4Z3?tqGsQz0;?oTbrT^^qKK12RKrmW=V>+S7dclIQP|J7(z*l6^f zdwNoMgs^x-R^95noQjqt1RFJnjk4^B>gGpj$VyJV{$(ldcM0`Xn@Q<= zgoF2F)qBp%aj(WpVU6>##=s8abiT2zYJ+9OAKAgD)#d9N6<7zX}SzN?P%7FhBfaEYOarcbN7p@cVqe4_HvolathWp ziO`x^jk`{GDtvH!!(L|Nmh46kV51nkO4VFV)L&h=Gpj$be5i5xLc3p*>$+F#vZ#Y| zdZg9JLUl(`N?dYKoP9{_c}P3}5RL+c_3}c0&^+#ux)d&+>gN$_KcFJwW5rS}Xk|_q zC@Q=fbc1wI)l!105>a#XY-C*5edBlM?PV0o`l3muU;0ZYEJr80BPTRcCy*f5SJhW; zk{+m9Dp6HZYtk-6w)EY1#hth?#wG)3j|}u{)V1teUo4ayDvSqP;_PzNgYG&26X<$C zlzC+jklB;xz=D>S*P%FT{50+THtY=h5VPOV`UV@AYa8D8R~ZAd;?eFS`*TiPm>2;{ z{bI-`ddf~*u+##z}tBIciNE}KFTia*yqY$ zTnZ{FnJM2{1K&lXl+*iNj4Zx}0UFWLN#g88u^m8Es>Kft8cF(GO-x1B-62J_^gkc< zEJ9J+C_}^4A(%T=(C2A{tgX9Zc;nb<_rxQ94F_r_Z%0qwE|{!ufdAH_WjcBy4V5@V zQEH(oy>vHk>%;3HZ`EEodlUD@-Ta=PqGAo;aWvp@0idS=uGK=-8?}o>m42gKtEXP` zcSj8L4S6A-W3Fh};NHQ^+kzD3ssWNQfcShsd?Qb_1!X;|_Z~$UrId|O%bvSCaQf&f z$j8(xMJ6~axOuU^Vt-A_iRhFQ1u6Ij9`r3wp1!s)utvbF6*%xZrAm$TsoNPk>$O+b zBh=TkwboP4t(RY1Z+W!bUo;J$JZ!<)kMq7wM%}J+sYeY)pS*q2+X7JywxE?hpyim+ z;O4ZMdo+P*$mO@ozABvL;2bCod9MoDKu5MwmMHM4)U3pZ1=kE^3k+@YnO%9z%6z6@ zE;BHX2{c9Pr)^l&dfcLUm{xsr8NJH;zRIR@>$~!kp1e1V?KQmE%be|D+VwJZdzdvn zVN!Wp8Kz>e#W9oI_%&`%Pk=3y9`umj=}Q*`(1~}ZPG=qJg8$1*>m~v}u3+B$K`Fpa zR;gPBRB6hvh7?1pJaS%EcGnNR^FUEU%mbcDj~i4R%sLyuH7>_7?DjBabs$|_)M zXu{F@uPq)fX$@BL&c)sDJ7K#rctF44R{1G|P7So%aqzE0AfyS&t@0wO&s0j2(#oD*Ufr4Hr@qT&c z-4~257(=!FWj}U}uFPxq9T?`81f?KkWrp)thYj+E-G)Ch1T3L*@Ng3sK~!WB&z0BB zR@7nL!r`sk?9?q69q~+n@Y1)yEYF(n9~?Y~)!}3O(V9`%iyAVlhIqBfDNXiS^Px(P z1a(G2^y78H^y`;?Uvl+-E0#B{mrg^((9w6T1en=md5uhYWY0)2#5>}wb~pBYU*`Lf z_wTQyyr27Kp33hl44jkFKm3u9FC+jN`kHqG-9iH0%vSuYLTJ&o22jVaP{*4-juZDB zla8;sAu3GcutU%UqP@0Hee4GX0vLN7gvNdP$_%a-^j#^k>W2_%Ox1N}}sl?^W z^?S!S2h|{gU}AnRqoy-q-jK&aTiE$JLVQ0z^6j?vEn6Npz;@POI*}T$ONN6{YovnS&*yp;jAXltpCC--;8+=4pEQr}6 zzW8#vAO|+4?6CxcEFHVOWCLBQ5>5&jjYcMM;V$aNahQYeEzjX^``GF8L6R2al zT3x+$7wqCG>e2S^af}w#WLImK^wN?xwxu=O##+P9TK9=H$CZq!96Y{2brsU3L(xQr zb01sB#bwU74cPC5Fl}Pi+(m;|lp;S6m-m)<1y!l-# z;kmhvbCz3ovzsstZ3?le{S72I;DJ`G5TDzDpWep5rQrKm_^T|-#Ers^fWBu&o^uBH z?(nPr^X>!l-Cni`4E@@m)q5DZT~MMnOIABYQp1<3VdX0dlWfhKyo4^o4j0Z=lgd{N zq(gy}(hni=JRhK_LOQ*JzOhY@rqI8#=t`_5xiw@AH@Idi7&f!iyVca0AaA4}x|vb3 zT}$7NDB8|uY(Iu=ake)ux~$p2c;s&uI{nJ_`LYb5>=r?}Ohl~K2%P*e9}6vy9-fQV z&yTJVMu!p(i^L}t60{655W$N2Tx;T~D}+-N;whfNdiBn9Dkb$H?4e<*mZ6O{^RgDR zQkyyF^=fqNr(4O=g4dKjtLV^L(S_a%Nn3qhGex4U0>cEthEC{QY6-W3&W$hPk{I0K zDyN+-#-1G~uS;DgsyzL)cLLLiD^47!X65ou Date: Tue, 3 Sep 2019 15:55:57 +0200 Subject: [PATCH 31/32] src: Apply upstream patch ff13c_p4.diff. April 13, 2019: Some compiler warns about unused variable and something. --- src/ff.c | 2 +- src/ff.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/ff.c b/src/ff.c index 4189668..1d26ed3 100644 --- a/src/ff.c +++ b/src/ff.c @@ -4019,9 +4019,9 @@ FRESULT f_getcwd ( TCHAR *tp = buff; #if FF_VOLUMES >= 2 UINT vl; -#endif #if FF_STR_VOLUME_ID const char *vp; +#endif #endif FILINFO fno; DEF_NAMBUF diff --git a/src/ff.h b/src/ff.h index 198063a..1cb8cb2 100644 --- a/src/ff.h +++ b/src/ff.h @@ -303,7 +303,7 @@ FRESULT f_getfree (FATFS *fs, DWORD* nclst); /* Get numbe FRESULT f_getlabel (FATFS *fs, TCHAR* label, DWORD* vsn); /* Get volume label */ FRESULT f_setlabel (FATFS *fs, const TCHAR* label); /* Set volume label */ FRESULT f_forward (FIL* fp, UINT(*func)(const BYTE*,UINT), UINT btf, UINT* bf); /* Forward data to the stream */ -FRESULT f_expand (FIL* fp, FSIZE_t szf, BYTE opt); /* Allocate a contiguous block to the file */ +FRESULT f_expand (FIL* fp, FSIZE_t fsz, BYTE opt); /* Allocate a contiguous block to the file */ FRESULT f_mount (FATFS* fs); /* Mount/Unmount a logical drive */ FRESULT f_umount (FATFS* fs); /* Unmount a logical drive */ FRESULT f_mkfs (FATFS *fs, BYTE opt, DWORD au, void* work, UINT len); /* Create a FAT volume */ From 83b75167a40425ba21592b2203b99b7d7d51d979 Mon Sep 17 00:00:00 2001 From: Ondrej Mikle Date: Tue, 3 Sep 2019 15:55:57 +0200 Subject: [PATCH 32/32] src: Apply upstream patch ff13c_p5.diff. August 30, 2019: Wrong memory read one or more characters beyond end of the input path name. If the memory area following the string terminator is filled by / or \, it can cause memory protection fault or bus fault. --- src/ff.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/ff.c b/src/ff.c index 1d26ed3..171b599 100644 --- a/src/ff.c +++ b/src/ff.c @@ -2821,9 +2821,13 @@ static FRESULT create_name ( /* FR_OK: successful, FR_INVALID_NAME: could not if (di >= FF_MAX_LFN) return FR_INVALID_NAME; /* Reject too long name */ lfn[di++] = wc; /* Store the Unicode character */ } - while (*p == '/' || *p == '\\') p++; /* Skip duplicated separators if exist */ - *path = p; /* Return pointer to the next segment */ - cf = (wc < ' ') ? NS_LAST : 0; /* Set last segment flag if end of the path */ + if (wc < ' ') { /* End of path? */ + cf = NS_LAST; /* Set last segment flag */ + } else { + cf = 0; /* Next segment follows */ + while (*p == '/' || *p == '\\') p++; /* Skip duplicated separators if exist */ + } + *path = p; /* Return pointer to the next segment */ #if FF_FS_RPATH != 0 if ((di == 1 && lfn[di - 1] == '.') ||