mirror of
https://gitlab.rtems.org/rtems/rtos/rtems.git
synced 2025-11-16 12:34:45 +00:00
Compare commits
9 Commits
18b2ce8e81
...
4482d84c9b
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4482d84c9b | ||
|
|
bff18c05b9 | ||
|
|
e3592620d7 | ||
|
|
54de3ac479 | ||
|
|
7ab332d86f | ||
|
|
88bce4ee7f | ||
|
|
a4333a4361 | ||
|
|
38367143fe | ||
|
|
0e20f50870 |
@@ -668,7 +668,7 @@ rtems_device_driver console_open(
|
||||
};
|
||||
|
||||
/* open the port depending on the minor device number */
|
||||
if ( ( minor >= 0 ) && ( minor < MAX_UART_INFO ) )
|
||||
if ( minor < MAX_UART_INFO )
|
||||
{
|
||||
info = &IntUartInfo[minor];
|
||||
switch ( info->iomode )
|
||||
|
||||
@@ -212,7 +212,7 @@ MC68681_STATIC void mc68681_initialize_context(
|
||||
mc68681_context *pmc68681Context
|
||||
)
|
||||
{
|
||||
int port;
|
||||
unsigned long port;
|
||||
unsigned int pMC68681;
|
||||
unsigned int pMC68681_port;
|
||||
|
||||
@@ -432,7 +432,7 @@ MC68681_STATIC rtems_isr mc68681_isr(
|
||||
rtems_vector_number vector
|
||||
)
|
||||
{
|
||||
int minor;
|
||||
unsigned long minor;
|
||||
|
||||
for(minor=0 ; minor<Console_Port_Count ; minor++) {
|
||||
if(Console_Port_Tbl[minor]->ulIntVector == vector &&
|
||||
@@ -517,7 +517,7 @@ MC68681_STATIC ssize_t mc68681_write_support_polled(
|
||||
size_t len
|
||||
)
|
||||
{
|
||||
int nwrite = 0;
|
||||
size_t nwrite = 0;
|
||||
|
||||
/*
|
||||
* poll each byte in the string out of the port.
|
||||
|
||||
@@ -850,7 +850,7 @@ ssize_t ns16550_write_support_polled(
|
||||
size_t len
|
||||
)
|
||||
{
|
||||
int nwrite = 0;
|
||||
size_t nwrite = 0;
|
||||
|
||||
/*
|
||||
* poll each byte in the string out of the port.
|
||||
|
||||
@@ -662,7 +662,7 @@ Z85C30_STATIC rtems_isr z85c30_isr(
|
||||
rtems_vector_number vector
|
||||
)
|
||||
{
|
||||
int minor;
|
||||
unsigned long minor;
|
||||
uint32_t ulCtrlPort;
|
||||
volatile uint8_t ucIntPend;
|
||||
volatile uint8_t ucIntPendPort;
|
||||
@@ -847,7 +847,7 @@ Z85C30_STATIC ssize_t z85c30_write_support_polled(
|
||||
const char *buf,
|
||||
size_t len)
|
||||
{
|
||||
int nwrite=0;
|
||||
size_t nwrite=0;
|
||||
|
||||
/*
|
||||
* poll each byte in the string out of the port.
|
||||
|
||||
@@ -103,6 +103,28 @@ static int xqspi_page_count(
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int xqspi_sector_count(
|
||||
rtems_flashdev *flash,
|
||||
int *sector_count
|
||||
)
|
||||
{
|
||||
*sector_count = QspiPsu_NOR_Get_Device_Size(flash->driver) /
|
||||
QspiPsu_NOR_Get_Sector_Size(flash->driver);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int xqspi_sector_info_by_off(
|
||||
rtems_flashdev *flash,
|
||||
off_t search_offset,
|
||||
off_t *sector_offset,
|
||||
size_t *sector_size
|
||||
)
|
||||
{
|
||||
*sector_size = QspiPsu_NOR_Get_Sector_Size(flash->driver);
|
||||
*sector_offset = search_offset - (search_offset%((off_t)(*sector_size)));
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int xqspi_write_block_size(
|
||||
rtems_flashdev *flash,
|
||||
size_t *write_block_size
|
||||
@@ -181,6 +203,8 @@ rtems_flashdev* xqspi_flash_init(XQspiPsu *xQspiDev)
|
||||
flash->page_info_by_index = &xqspi_page_info_by_index;
|
||||
flash->page_count = &xqspi_page_count;
|
||||
flash->write_block_size = &xqspi_write_block_size;
|
||||
flash->sector_count = &xqspi_sector_count;
|
||||
flash->sector_info_by_offset = &xqspi_sector_info_by_off;
|
||||
flash->region_table = ftable;
|
||||
|
||||
return flash;
|
||||
|
||||
@@ -520,7 +520,7 @@ static int read_task(rtems_termios_device_context *base)
|
||||
rtems_interrupt_lock_context lock_context;
|
||||
struct apbuart_priv *uart = base_get_priv(base);
|
||||
apbuart *regs = uart->regs;
|
||||
int cnt;
|
||||
size_t cnt;
|
||||
char buf[33];
|
||||
struct rtems_termios_tty *tty;
|
||||
uint32_t ctrl;
|
||||
@@ -683,7 +683,7 @@ static void write_polled(
|
||||
)
|
||||
{
|
||||
struct apbuart_priv *uart = base_get_priv(base);
|
||||
int nwrite = 0;
|
||||
size_t nwrite = 0;
|
||||
|
||||
while (nwrite < len) {
|
||||
apbuart_outbyte_polled(uart->regs, *buf++);
|
||||
@@ -699,7 +699,7 @@ static void write_interrupt(
|
||||
{
|
||||
struct apbuart_priv *uart = base_get_priv(base);
|
||||
apbuart *regs = uart->regs;
|
||||
int sending;
|
||||
size_t sending;
|
||||
unsigned int ctrl;
|
||||
|
||||
ctrl = grlib_load_32(®s->ctrl);
|
||||
@@ -752,7 +752,7 @@ static void apbuart_cons_isr(void *arg)
|
||||
apbuart *regs = uart->regs;
|
||||
unsigned int status;
|
||||
char buf[33];
|
||||
int cnt;
|
||||
size_t cnt;
|
||||
|
||||
if (uart->mode == TERMIOS_TASK_DRIVEN) {
|
||||
if ((status = grlib_load_32(®s->status)) & APBUART_STATUS_DR) {
|
||||
|
||||
@@ -187,7 +187,7 @@ ssize_t rtems_ofw_get_prop(
|
||||
const void *prop;
|
||||
int offset;
|
||||
int len;
|
||||
int copy_len;
|
||||
size_t copy_len;
|
||||
uint32_t cpuid;
|
||||
|
||||
offset = rtems_fdt_phandle_to_offset(node);
|
||||
@@ -251,7 +251,7 @@ ssize_t rtems_ofw_get_enc_prop(
|
||||
return rv;
|
||||
}
|
||||
|
||||
for (int i = 0; i < (len / 4); i++) {
|
||||
for (size_t i = 0; i < (len / 4); i++) {
|
||||
buf[i] = fdt32_to_cpu(buf[i]);
|
||||
}
|
||||
|
||||
@@ -540,7 +540,8 @@ phandle_t rtems_ofw_node_from_xref( phandle_t xref )
|
||||
{
|
||||
phandle_t node;
|
||||
|
||||
if ((node = rtems_ofw_get_effective_phandle(rtems_ofw_peer(0), xref)) == -1)
|
||||
node = rtems_ofw_get_effective_phandle(rtems_ofw_peer(0), xref);
|
||||
if (node == (phandle_t)-1)
|
||||
return xref;
|
||||
|
||||
return node;
|
||||
|
||||
@@ -106,7 +106,7 @@ static uint32_t rtems_flashdev_ioctl_jedec_id(
|
||||
rtems_flashdev *flash
|
||||
);
|
||||
|
||||
static uint32_t rtems_flashdev_ioctl_flash_type(
|
||||
static int rtems_flashdev_ioctl_flash_type(
|
||||
rtems_flashdev *flash,
|
||||
void *arg
|
||||
);
|
||||
@@ -728,7 +728,7 @@ static int rtems_flashdev_ioctl_erase(
|
||||
int status;
|
||||
|
||||
if ( flash->erase == NULL ) {
|
||||
return 0;
|
||||
rtems_set_errno_and_return_minus_one( ENOSYS );
|
||||
}
|
||||
|
||||
erase_args_1 = (rtems_flashdev_region *) arg;
|
||||
@@ -884,14 +884,14 @@ static uint32_t rtems_flashdev_ioctl_jedec_id( rtems_flashdev *flash )
|
||||
}
|
||||
}
|
||||
|
||||
static uint32_t rtems_flashdev_ioctl_flash_type(
|
||||
static int rtems_flashdev_ioctl_flash_type(
|
||||
rtems_flashdev *flash,
|
||||
void *arg
|
||||
)
|
||||
{
|
||||
rtems_flashdev_flash_type *type = (rtems_flashdev_flash_type*)arg;
|
||||
if ( flash->flash_type == NULL ) {
|
||||
return 0;
|
||||
rtems_set_errno_and_return_minus_one( ENOSYS );
|
||||
} else {
|
||||
return ( *flash->flash_type )( flash, type );
|
||||
}
|
||||
@@ -908,7 +908,7 @@ static int rtems_flashdev_ioctl_pageinfo_offset(
|
||||
rtems_set_errno_and_return_minus_one( EINVAL );
|
||||
}
|
||||
if ( flash->page_info_by_offset == NULL ) {
|
||||
return 0;
|
||||
rtems_set_errno_and_return_minus_one( ENOSYS );
|
||||
} else {
|
||||
page_info = (rtems_flashdev_ioctl_page_info *) arg;
|
||||
return ( *flash->page_info_by_offset )( flash,
|
||||
@@ -927,7 +927,7 @@ static int rtems_flashdev_ioctl_pageinfo_index( rtems_flashdev *flash,
|
||||
rtems_set_errno_and_return_minus_one( EINVAL );
|
||||
}
|
||||
if ( flash->page_info_by_index == NULL ) {
|
||||
return 0;
|
||||
rtems_set_errno_and_return_minus_one( ENOSYS );
|
||||
} else {
|
||||
page_info = (rtems_flashdev_ioctl_page_info *) arg;
|
||||
return ( *flash->page_info_by_index )( flash,
|
||||
@@ -943,7 +943,7 @@ static int rtems_flashdev_ioctl_page_count( rtems_flashdev *flash, void *arg )
|
||||
rtems_set_errno_and_return_minus_one( EINVAL );
|
||||
}
|
||||
if ( flash->page_count == NULL ) {
|
||||
return 0;
|
||||
rtems_set_errno_and_return_minus_one( ENOSYS );
|
||||
} else {
|
||||
return ( *flash->page_count )( flash, ( (int *) arg ) );
|
||||
}
|
||||
@@ -958,7 +958,7 @@ static int rtems_flashdev_ioctl_write_block_size(
|
||||
rtems_set_errno_and_return_minus_one( EINVAL );
|
||||
}
|
||||
if ( flash->write_block_size == NULL ) {
|
||||
return 0;
|
||||
rtems_set_errno_and_return_minus_one( ENOSYS );
|
||||
} else {
|
||||
return ( *flash->write_block_size )( flash, ( (size_t *) arg ) );
|
||||
}
|
||||
@@ -975,7 +975,7 @@ static int rtems_flashdev_ioctl_sectorinfo_offset(
|
||||
rtems_set_errno_and_return_minus_one( EINVAL );
|
||||
}
|
||||
if ( flash->sector_info_by_offset == NULL ) {
|
||||
return 0;
|
||||
rtems_set_errno_and_return_minus_one( ENOSYS );
|
||||
} else {
|
||||
sector_info = (rtems_flashdev_ioctl_sector_info *) arg;
|
||||
return ( *flash->sector_info_by_offset )( flash,
|
||||
@@ -991,7 +991,7 @@ static int rtems_flashdev_ioctl_sector_count( rtems_flashdev *flash, void *arg )
|
||||
rtems_set_errno_and_return_minus_one( EINVAL );
|
||||
}
|
||||
if ( flash->sector_count == NULL ) {
|
||||
return 0;
|
||||
rtems_set_errno_and_return_minus_one( ENOSYS );
|
||||
} else {
|
||||
return ( *flash->sector_count )( flash, ( (int *) arg ) );
|
||||
}
|
||||
@@ -1042,7 +1042,7 @@ static int rtems_flashdev_ioctl_oob_bytes_per_page(
|
||||
rtems_set_errno_and_return_minus_one( EINVAL );
|
||||
}
|
||||
if ( flash->oob_bytes_per_page == NULL ) {
|
||||
return 0;
|
||||
rtems_set_errno_and_return_minus_one( ENOSYS );
|
||||
} else {
|
||||
return ( *flash->oob_bytes_per_page )( flash, ( (size_t *) arg ) );
|
||||
}
|
||||
@@ -1055,7 +1055,7 @@ static int rtems_flashdev_ioctl_oob_read( rtems_flashdev *flash, void *arg )
|
||||
rtems_set_errno_and_return_minus_one( EINVAL );
|
||||
}
|
||||
if ( flash->oob_read == NULL ) {
|
||||
return 0;
|
||||
rtems_set_errno_and_return_minus_one( ENOSYS );
|
||||
} else {
|
||||
rw_info = (rtems_flashdev_ioctl_oob_rw_info *) arg;
|
||||
return ( *flash->oob_read )(
|
||||
@@ -1154,7 +1154,7 @@ static int rtems_flashdev_ioctl_oob_write( rtems_flashdev *flash, void *arg )
|
||||
rtems_set_errno_and_return_minus_one( EINVAL );
|
||||
}
|
||||
if ( flash->oob_write == NULL ) {
|
||||
return 0;
|
||||
rtems_set_errno_and_return_minus_one( ENOSYS );
|
||||
} else {
|
||||
rw_info = (rtems_flashdev_ioctl_oob_rw_info *) arg;
|
||||
return ( *flash->oob_write )(
|
||||
@@ -1193,7 +1193,7 @@ static int rtems_flashdev_ioctl_sector_mark_bad(
|
||||
rtems_set_errno_and_return_minus_one( EINVAL );
|
||||
}
|
||||
if ( flash->sector_mark_bad == NULL ) {
|
||||
return 0;
|
||||
rtems_set_errno_and_return_minus_one( ENOSYS );
|
||||
} else {
|
||||
return ( *flash->sector_mark_bad)( flash, *(uintptr_t *) arg );
|
||||
}
|
||||
@@ -1229,7 +1229,7 @@ static int rtems_flashdev_ioctl_sectorhealth(
|
||||
rtems_set_errno_and_return_minus_one( EINVAL );
|
||||
}
|
||||
if ( flash->sector_health == NULL ) {
|
||||
return 0;
|
||||
rtems_set_errno_and_return_minus_one( ENOSYS );
|
||||
} else {
|
||||
sector_health = arg;
|
||||
return ( *flash->sector_health)( flash, sector_health->location, §or_health->sector_bad );
|
||||
|
||||
@@ -48,6 +48,7 @@
|
||||
|
||||
#ifdef CONFIGURE_FILESYSTEM_ALL
|
||||
#define CONFIGURE_FILESYSTEM_DOSFS
|
||||
#define CONFIGURE_FILESYSTEM_FATFS
|
||||
#define CONFIGURE_FILESYSTEM_FTPFS
|
||||
#define CONFIGURE_FILESYSTEM_IMFS
|
||||
#define CONFIGURE_FILESYSTEM_JFFS2
|
||||
@@ -108,6 +109,10 @@
|
||||
#error "CONFIGURE_APPLICATION_DISABLE_FILESYSTEM cannot be used together with CONFIGURE_FILESYSTEM_DOSFS"
|
||||
#endif
|
||||
|
||||
#ifdef CONFIGURE_FILESYSTEM_FATFS
|
||||
#error "CONFIGURE_APPLICATION_DISABLE_FILESYSTEM cannot be used together with CONFIGURE_FILESYSTEM_FATFS"
|
||||
#endif
|
||||
|
||||
#ifdef CONFIGURE_FILESYSTEM_FTPFS
|
||||
#error "CONFIGURE_APPLICATION_DISABLE_FILESYSTEM cannot be used together with CONFIGURE_FILESYSTEM_FTPFS"
|
||||
#endif
|
||||
@@ -139,6 +144,10 @@
|
||||
#include <rtems/dosfs.h>
|
||||
#endif
|
||||
|
||||
#ifdef CONFIGURE_FILESYSTEM_FATFS
|
||||
#include <rtems/fatfs.h>
|
||||
#endif
|
||||
|
||||
#ifdef CONFIGURE_FILESYSTEM_FTPFS
|
||||
#include <rtems/ftpfs.h>
|
||||
#endif
|
||||
@@ -297,6 +306,9 @@ const rtems_filesystem_table_t rtems_filesystem_table[] = {
|
||||
#ifdef CONFIGURE_FILESYSTEM_DOSFS
|
||||
{ RTEMS_FILESYSTEM_TYPE_DOSFS, rtems_dosfs_initialize },
|
||||
#endif
|
||||
#ifdef CONFIGURE_FILESYSTEM_FATFS
|
||||
{ RTEMS_FILESYSTEM_TYPE_FATFS, rtems_fatfs_initialize },
|
||||
#endif
|
||||
#ifdef CONFIGURE_FILESYSTEM_FTPFS
|
||||
{ RTEMS_FILESYSTEM_TYPE_FTPFS, rtems_ftpfs_initialize },
|
||||
#endif
|
||||
|
||||
60
cpukit/include/rtems/fatfs.h
Normal file
60
cpukit/include/rtems/fatfs.h
Normal file
@@ -0,0 +1,60 @@
|
||||
/**
|
||||
* @file
|
||||
*
|
||||
* @ingroup FatFS
|
||||
*
|
||||
* @brief RTEMS FatFS Filesystem Public API
|
||||
*/
|
||||
|
||||
/*
|
||||
Copyright (C) 2025 Sepehr Ganji <sepehrganji79@gmail.com>
|
||||
*/
|
||||
|
||||
#ifndef _RTEMS_FATFS_H
|
||||
#define _RTEMS_FATFS_H
|
||||
|
||||
#include <rtems.h>
|
||||
#include <rtems/libio.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @addtogroup FATFS
|
||||
*
|
||||
* @{
|
||||
*/
|
||||
|
||||
/**
|
||||
* @brief RTEMS FatFS filesystem mount options.
|
||||
*/
|
||||
typedef struct {
|
||||
/** Currently no options defined */
|
||||
int reserved;
|
||||
} rtems_fatfs_mount_options;
|
||||
|
||||
/**
|
||||
* @brief Initialize FatFS filesystem.
|
||||
*
|
||||
* This function is the mount handler for the FatFS filesystem. It is called
|
||||
* by the mount() system call when the filesystem type is
|
||||
* RTEMS_FILESYSTEM_TYPE_FATFS.
|
||||
*
|
||||
* @param[in] mt_entry The mount table entry.
|
||||
* @param[in] data Mount options (rtems_fatfs_mount_options or NULL).
|
||||
*
|
||||
* @return 0 on success, -1 on error with errno set.
|
||||
*/
|
||||
int rtems_fatfs_initialize(
|
||||
rtems_filesystem_mount_table_entry_t *mt_entry,
|
||||
const void *data
|
||||
);
|
||||
|
||||
/** @} */
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _RTEMS_FATFS_H */
|
||||
@@ -1649,6 +1649,7 @@ extern int rtems_mkdir(const char *path, mode_t mode);
|
||||
#define RTEMS_FILESYSTEM_TYPE_TFTPFS "tftpfs"
|
||||
#define RTEMS_FILESYSTEM_TYPE_NFS "nfs"
|
||||
#define RTEMS_FILESYSTEM_TYPE_DOSFS "dosfs"
|
||||
#define RTEMS_FILESYSTEM_TYPE_FATFS "fatfs"
|
||||
#define RTEMS_FILESYSTEM_TYPE_RFS "rfs"
|
||||
#define RTEMS_FILESYSTEM_TYPE_JFFS2 "jffs2"
|
||||
|
||||
|
||||
222
cpukit/libfs/src/fatfs/rtems-diskio.c
Normal file
222
cpukit/libfs/src/fatfs/rtems-diskio.c
Normal file
@@ -0,0 +1,222 @@
|
||||
/**
|
||||
* @file
|
||||
*
|
||||
* @ingroup FatFS
|
||||
*
|
||||
* @brief RTEMS Disk I/O Interface for FatFs
|
||||
*/
|
||||
|
||||
/*
|
||||
Copyright (C) 2025 Sepehr Ganji <sepehrganji79@gmail.com>
|
||||
*/
|
||||
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <rtems.h>
|
||||
#include <rtems/bdbuf.h>
|
||||
#include <rtems/libio_.h>
|
||||
|
||||
#include "ff.h"
|
||||
#include "diskio.h"
|
||||
#include "rtems-fatfs.h"
|
||||
|
||||
static fatfs_volume_t volumes[ FF_VOLUMES ];
|
||||
|
||||
/*
|
||||
* Compiler will change name to rtems_fatfs_disk_status
|
||||
*/
|
||||
DSTATUS disk_status( BYTE pdrv )
|
||||
{
|
||||
if ( pdrv >= FF_VOLUMES ) {
|
||||
return STA_NOINIT;
|
||||
}
|
||||
|
||||
if ( !volumes[ pdrv ].initialized ) {
|
||||
return STA_NOINIT;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Compiler will change name to rtems_fatfs_disk_initialize
|
||||
*/
|
||||
DSTATUS disk_initialize( BYTE pdrv )
|
||||
{
|
||||
if ( pdrv >= FF_VOLUMES ) {
|
||||
return STA_NOINIT;
|
||||
}
|
||||
bool is_initialized = volumes[ pdrv ].initialized;
|
||||
return is_initialized ? 0 : STA_NOINIT;
|
||||
}
|
||||
|
||||
/*
|
||||
* Compiler will change name to rtems_fatfs_disk_read
|
||||
*/
|
||||
DRESULT disk_read( BYTE pdrv, BYTE *buff, LBA_t sector, UINT count )
|
||||
{
|
||||
rtems_status_code sc;
|
||||
rtems_bdbuf_buffer *bd;
|
||||
uint32_t block_size;
|
||||
|
||||
if ( disk_status( pdrv ) != 0 ) {
|
||||
return RES_NOTRDY;
|
||||
}
|
||||
|
||||
rtems_disk_device *dd = volumes[ pdrv ].dd;
|
||||
block_size = dd->block_size;
|
||||
|
||||
for ( size_t i = 0; i < count; i++ ) {
|
||||
sc = rtems_bdbuf_read( dd, sector + i, &bd );
|
||||
if ( sc != RTEMS_SUCCESSFUL ) {
|
||||
return RES_ERROR;
|
||||
}
|
||||
|
||||
memcpy( buff + ( i * block_size ), bd->buffer, block_size );
|
||||
|
||||
sc = rtems_bdbuf_release( bd );
|
||||
if ( sc != RTEMS_SUCCESSFUL ) {
|
||||
return RES_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
return RES_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
* Compiler will change name to rtems_fatfs_disk_write
|
||||
*/
|
||||
DRESULT disk_write( BYTE pdrv, const BYTE *buff, LBA_t sector, UINT count )
|
||||
{
|
||||
rtems_status_code sc;
|
||||
rtems_bdbuf_buffer *bd;
|
||||
uint32_t block_size;
|
||||
|
||||
if ( disk_status( pdrv ) != 0 ) {
|
||||
return RES_NOTRDY;
|
||||
}
|
||||
|
||||
rtems_disk_device *dd = volumes[ pdrv ].dd;
|
||||
|
||||
block_size = dd->block_size;
|
||||
|
||||
for ( size_t i = 0; i < count; i++ ) {
|
||||
sc = rtems_bdbuf_get( dd, sector + i, &bd );
|
||||
if ( sc != RTEMS_SUCCESSFUL ) {
|
||||
return RES_ERROR;
|
||||
}
|
||||
|
||||
memcpy( bd->buffer, buff + ( i * block_size ), block_size );
|
||||
|
||||
sc = rtems_bdbuf_release_modified( bd );
|
||||
if ( sc != RTEMS_SUCCESSFUL ) {
|
||||
return RES_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
return RES_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
* Compiler will change name to rtems_fatfs_disk_ioctl
|
||||
*/
|
||||
DRESULT disk_ioctl( BYTE pdrv, BYTE cmd, void *buff )
|
||||
{
|
||||
if ( disk_status( pdrv ) != 0 ) {
|
||||
return RES_NOTRDY;
|
||||
}
|
||||
|
||||
rtems_disk_device *dd = volumes[ pdrv ].dd;
|
||||
|
||||
switch ( cmd ) {
|
||||
case CTRL_SYNC: {
|
||||
rtems_status_code sc = rtems_bdbuf_syncdev( dd );
|
||||
if ( sc != RTEMS_SUCCESSFUL ) {
|
||||
return RES_ERROR;
|
||||
}
|
||||
} break;
|
||||
|
||||
case GET_SECTOR_COUNT:
|
||||
*(rtems_blkdev_bnum *) buff = dd->size;
|
||||
break;
|
||||
|
||||
case GET_SECTOR_SIZE:
|
||||
*(uint32_t *) buff = dd->media_block_size;
|
||||
break;
|
||||
|
||||
case GET_BLOCK_SIZE:
|
||||
*(uint32_t *) buff = dd->block_size;
|
||||
break;
|
||||
|
||||
case CTRL_TRIM:
|
||||
break;
|
||||
|
||||
default:
|
||||
return RES_PARERR;
|
||||
}
|
||||
|
||||
return RES_OK;
|
||||
}
|
||||
|
||||
int fatfs_diskio_register_device( uint8_t pdrv, const char *device_path )
|
||||
{
|
||||
struct stat stat_buf;
|
||||
int fd;
|
||||
rtems_disk_device *dd;
|
||||
int rc;
|
||||
|
||||
if ( pdrv >= FF_VOLUMES ) {
|
||||
rtems_set_errno_and_return_minus_one( EINVAL );
|
||||
}
|
||||
|
||||
if ( volumes[ pdrv ].initialized ) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
fd = open( device_path, O_RDWR );
|
||||
if ( fd < 0 ) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
rc = fstat( fd, &stat_buf );
|
||||
if ( rc != 0 ) {
|
||||
close( fd );
|
||||
return -1;
|
||||
}
|
||||
|
||||
if ( !S_ISBLK( stat_buf.st_mode ) ) {
|
||||
close( fd );
|
||||
rtems_set_errno_and_return_minus_one( ENXIO );
|
||||
}
|
||||
|
||||
rc = rtems_disk_fd_get_disk_device( fd, &dd );
|
||||
if ( rc != 0 ) {
|
||||
close( fd );
|
||||
return -1;
|
||||
}
|
||||
|
||||
volumes[ pdrv ].fd = fd;
|
||||
volumes[ pdrv ].dd = dd;
|
||||
volumes[ pdrv ].initialized = true;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void fatfs_diskio_unregister_device( uint8_t pdrv )
|
||||
{
|
||||
if ( pdrv >= FF_VOLUMES || !volumes[ pdrv ].initialized ) {
|
||||
return;
|
||||
}
|
||||
|
||||
close( volumes[ pdrv ].fd );
|
||||
volumes[ pdrv ].fd = -1;
|
||||
volumes[ pdrv ].dd = NULL;
|
||||
volumes[ pdrv ].initialized = false;
|
||||
}
|
||||
207
cpukit/libfs/src/fatfs/rtems-fatfs-dir.c
Normal file
207
cpukit/libfs/src/fatfs/rtems-fatfs-dir.c
Normal file
@@ -0,0 +1,207 @@
|
||||
/**
|
||||
* @file
|
||||
*
|
||||
* @ingroup FatFS
|
||||
*
|
||||
* @brief RTEMS FATFS directory operations
|
||||
*/
|
||||
|
||||
/*
|
||||
Copyright (C) 2025 Sepehr Ganji <sepehrganji79@gmail.com>
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <stddef.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <rtems.h>
|
||||
#include <rtems/libio.h>
|
||||
#include <rtems/libio_.h>
|
||||
|
||||
#include "ff.h"
|
||||
#include "rtems-fatfs.h"
|
||||
|
||||
#define DIR POSIX_DIR
|
||||
#include <dirent.h>
|
||||
#undef DIR
|
||||
|
||||
ssize_t rtems_fatfs_dir_read( rtems_libio_t *iop, void *buffer, size_t count )
|
||||
{
|
||||
rtems_fatfs_node_t *node = (rtems_fatfs_node_t *) iop->pathinfo.node_access;
|
||||
struct dirent *dp = (struct dirent *) buffer;
|
||||
FILINFO fno;
|
||||
FRESULT fr;
|
||||
size_t bytes_transferred = 0;
|
||||
|
||||
if ( node == NULL || !node->is_directory ) {
|
||||
rtems_set_errno_and_return_minus_one( ENOTDIR );
|
||||
}
|
||||
|
||||
if ( count < sizeof( struct dirent ) ) {
|
||||
rtems_set_errno_and_return_minus_one( EINVAL );
|
||||
}
|
||||
|
||||
rtems_fatfs_lock( iop->pathinfo.mt_entry );
|
||||
|
||||
memset( &fno, 0, sizeof( fno ) );
|
||||
|
||||
fr = f_readdir( &node->handle.dir, &fno );
|
||||
if ( fr != FR_OK ) {
|
||||
rtems_fatfs_unlock( iop->pathinfo.mt_entry );
|
||||
errno = rtems_fatfs_fresult_to_errno( fr );
|
||||
return -1;
|
||||
}
|
||||
|
||||
if ( fno.fname[ 0 ] == '\0' ) {
|
||||
rtems_fatfs_unlock( iop->pathinfo.mt_entry );
|
||||
return 0;
|
||||
}
|
||||
|
||||
memset( dp, 0, sizeof( struct dirent ) );
|
||||
dp->d_ino = 1;
|
||||
dp->d_off = iop->offset;
|
||||
dp->d_reclen = sizeof( struct dirent );
|
||||
|
||||
size_t name_len = strlen( fno.fname );
|
||||
if ( name_len >= sizeof( dp->d_name ) ) {
|
||||
name_len = sizeof( dp->d_name ) - 1;
|
||||
}
|
||||
memcpy( dp->d_name, fno.fname, name_len );
|
||||
dp->d_name[ name_len ] = '\0';
|
||||
dp->d_namlen = name_len;
|
||||
|
||||
if ( fno.fattrib & AM_DIR ) {
|
||||
dp->d_type = DT_DIR;
|
||||
} else {
|
||||
dp->d_type = DT_REG;
|
||||
}
|
||||
|
||||
bytes_transferred = sizeof( struct dirent );
|
||||
iop->offset += sizeof( struct dirent );
|
||||
|
||||
rtems_fatfs_unlock( iop->pathinfo.mt_entry );
|
||||
|
||||
return (ssize_t) bytes_transferred;
|
||||
}
|
||||
|
||||
int rtems_fatfs_dir_fstat(
|
||||
const rtems_filesystem_location_info_t *loc,
|
||||
struct stat *buf
|
||||
)
|
||||
{
|
||||
rtems_fatfs_node_t *node = (rtems_fatfs_node_t *) loc->node_access;
|
||||
|
||||
if ( node == NULL ) {
|
||||
rtems_set_errno_and_return_minus_one( EBADF );
|
||||
}
|
||||
rtems_fatfs_fs_info_t *fs_info = (rtems_fatfs_fs_info_t *)
|
||||
loc->mt_entry->fs_info;
|
||||
rtems_fatfs_node_to_stat( node, buf, fs_info );
|
||||
return 0;
|
||||
}
|
||||
|
||||
int rtems_fatfs_opendir(
|
||||
rtems_libio_t *iop,
|
||||
const char *path,
|
||||
int oflag,
|
||||
mode_t mode
|
||||
)
|
||||
{
|
||||
(void) path;
|
||||
(void) oflag;
|
||||
(void) mode;
|
||||
|
||||
rtems_fatfs_node_t *node = (rtems_fatfs_node_t *) iop->pathinfo.node_access;
|
||||
rtems_fatfs_fs_info_t *fs_info = (rtems_fatfs_fs_info_t *)
|
||||
iop->pathinfo.mt_entry->fs_info;
|
||||
char full_path[ 256 ];
|
||||
FRESULT fr;
|
||||
int rc;
|
||||
|
||||
if ( node == NULL || !node->is_directory ) {
|
||||
rtems_set_errno_and_return_minus_one( ENOTDIR );
|
||||
}
|
||||
|
||||
if ( node->is_open ) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
rtems_fatfs_lock( iop->pathinfo.mt_entry );
|
||||
|
||||
rc = rtems_fatfs_resolve_node_path(
|
||||
fs_info,
|
||||
node,
|
||||
full_path,
|
||||
sizeof( full_path ),
|
||||
iop->pathinfo.mt_entry
|
||||
);
|
||||
if ( rc != 0 ) {
|
||||
return rc;
|
||||
}
|
||||
|
||||
fr = f_opendir( &node->handle.dir, full_path );
|
||||
if ( fr != FR_OK ) {
|
||||
rtems_fatfs_unlock( iop->pathinfo.mt_entry );
|
||||
errno = rtems_fatfs_fresult_to_errno( fr );
|
||||
return -1;
|
||||
}
|
||||
|
||||
node->is_open = true;
|
||||
rtems_fatfs_unlock( iop->pathinfo.mt_entry );
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int rtems_fatfs_closedir( rtems_libio_t *iop )
|
||||
{
|
||||
rtems_fatfs_node_t *node = (rtems_fatfs_node_t *) iop->pathinfo.node_access;
|
||||
FRESULT fr;
|
||||
|
||||
if ( node == NULL || !node->is_directory ) {
|
||||
rtems_set_errno_and_return_minus_one( ENOTDIR );
|
||||
}
|
||||
|
||||
if ( !node->is_open ) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
rtems_fatfs_lock( iop->pathinfo.mt_entry );
|
||||
|
||||
fr = f_closedir( &node->handle.dir );
|
||||
if ( fr != FR_OK ) {
|
||||
rtems_fatfs_unlock( iop->pathinfo.mt_entry );
|
||||
errno = rtems_fatfs_fresult_to_errno( fr );
|
||||
return -1;
|
||||
}
|
||||
|
||||
node->is_open = false;
|
||||
rtems_fatfs_unlock( iop->pathinfo.mt_entry );
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
const rtems_filesystem_file_handlers_r rtems_fatfs_dir_handlers = {
|
||||
.open_h = rtems_fatfs_opendir,
|
||||
.close_h = rtems_fatfs_closedir,
|
||||
.read_h = rtems_fatfs_dir_read,
|
||||
.write_h = rtems_filesystem_default_write,
|
||||
.ioctl_h = rtems_filesystem_default_ioctl,
|
||||
.lseek_h = rtems_filesystem_default_lseek_directory,
|
||||
.fstat_h = rtems_fatfs_dir_fstat,
|
||||
.ftruncate_h = rtems_filesystem_default_ftruncate_directory,
|
||||
.fsync_h = rtems_fatfs_file_fsync,
|
||||
.fdatasync_h = rtems_fatfs_file_fsync,
|
||||
.fcntl_h = rtems_filesystem_default_fcntl,
|
||||
.kqfilter_h = rtems_filesystem_default_kqfilter,
|
||||
.mmap_h = rtems_filesystem_default_mmap,
|
||||
.poll_h = rtems_filesystem_default_poll,
|
||||
.readv_h = rtems_filesystem_default_readv,
|
||||
.writev_h = rtems_filesystem_default_writev
|
||||
};
|
||||
451
cpukit/libfs/src/fatfs/rtems-fatfs-file.c
Normal file
451
cpukit/libfs/src/fatfs/rtems-fatfs-file.c
Normal file
@@ -0,0 +1,451 @@
|
||||
/**
|
||||
* @file
|
||||
*
|
||||
* @ingroup FatFS
|
||||
*
|
||||
* @brief RTEMS FATFS file operations
|
||||
*/
|
||||
|
||||
/*
|
||||
Copyright (C) 2025 Sepehr Ganji <sepehrganji79@gmail.com>
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <limits.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <rtems.h>
|
||||
#include <rtems/libio.h>
|
||||
#include <rtems/libio_.h>
|
||||
|
||||
#include "ff.h"
|
||||
#include "rtems-fatfs.h"
|
||||
|
||||
ssize_t rtems_fatfs_file_read( rtems_libio_t *iop, void *buffer, size_t count )
|
||||
{
|
||||
rtems_fatfs_node_t *node = (rtems_fatfs_node_t *) iop->pathinfo.node_access;
|
||||
FRESULT fr;
|
||||
UINT bytes_read = 0;
|
||||
|
||||
if ( node == NULL || node->is_directory ) {
|
||||
rtems_set_errno_and_return_minus_one( EBADF );
|
||||
}
|
||||
|
||||
rtems_fatfs_lock( iop->pathinfo.mt_entry );
|
||||
|
||||
fr = f_lseek( &node->handle.file, (FSIZE_t) iop->offset );
|
||||
if ( fr != FR_OK ) {
|
||||
rtems_fatfs_unlock( iop->pathinfo.mt_entry );
|
||||
errno = rtems_fatfs_fresult_to_errno( fr );
|
||||
return -1;
|
||||
}
|
||||
|
||||
fr = f_read( &node->handle.file, buffer, (UINT) count, &bytes_read );
|
||||
|
||||
rtems_fatfs_unlock( iop->pathinfo.mt_entry );
|
||||
|
||||
if ( fr != FR_OK ) {
|
||||
errno = rtems_fatfs_fresult_to_errno( fr );
|
||||
return -1;
|
||||
}
|
||||
|
||||
if ( bytes_read > 0 ) {
|
||||
iop->offset += bytes_read;
|
||||
}
|
||||
|
||||
return (ssize_t) bytes_read;
|
||||
}
|
||||
|
||||
ssize_t rtems_fatfs_file_write(
|
||||
rtems_libio_t *iop,
|
||||
const void *buffer,
|
||||
size_t count
|
||||
)
|
||||
{
|
||||
rtems_fatfs_node_t *node = (rtems_fatfs_node_t *) iop->pathinfo.node_access;
|
||||
FRESULT fr;
|
||||
UINT bytes_written = 0;
|
||||
|
||||
if ( node == NULL || node->is_directory ) {
|
||||
rtems_set_errno_and_return_minus_one( EBADF );
|
||||
}
|
||||
|
||||
rtems_fatfs_lock( iop->pathinfo.mt_entry );
|
||||
|
||||
if ( rtems_libio_iop_is_append( iop ) ) {
|
||||
fr = f_lseek( &node->handle.file, f_size( &node->handle.file ) );
|
||||
if ( fr != FR_OK ) {
|
||||
rtems_fatfs_unlock( iop->pathinfo.mt_entry );
|
||||
errno = rtems_fatfs_fresult_to_errno( fr );
|
||||
return -1;
|
||||
}
|
||||
iop->offset = f_tell( &node->handle.file );
|
||||
} else {
|
||||
FSIZE_t current_size = f_size( &node->handle.file );
|
||||
FSIZE_t target_pos = (FSIZE_t) iop->offset;
|
||||
|
||||
if ( target_pos > current_size ) {
|
||||
FSIZE_t gap_size = target_pos - current_size;
|
||||
char zero_buf[ 512 ];
|
||||
UINT bw;
|
||||
|
||||
memset( zero_buf, 0, sizeof( zero_buf ) );
|
||||
|
||||
fr = f_lseek( &node->handle.file, current_size );
|
||||
if ( fr != FR_OK ) {
|
||||
rtems_fatfs_unlock( iop->pathinfo.mt_entry );
|
||||
errno = rtems_fatfs_fresult_to_errno( fr );
|
||||
return -1;
|
||||
}
|
||||
|
||||
while ( gap_size > 0 && fr == FR_OK ) {
|
||||
UINT to_write = gap_size > sizeof( zero_buf ) ? sizeof( zero_buf ) :
|
||||
(UINT) gap_size;
|
||||
fr = f_write( &node->handle.file, zero_buf, to_write, &bw );
|
||||
if ( fr == FR_OK && bw == to_write ) {
|
||||
gap_size -= to_write;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if ( fr != FR_OK ) {
|
||||
rtems_fatfs_unlock( iop->pathinfo.mt_entry );
|
||||
errno = rtems_fatfs_fresult_to_errno( fr );
|
||||
return -1;
|
||||
}
|
||||
|
||||
if ( gap_size > 0 ) {
|
||||
rtems_fatfs_unlock( iop->pathinfo.mt_entry );
|
||||
errno = ENOSPC;
|
||||
return -1;
|
||||
}
|
||||
} else {
|
||||
fr = f_lseek( &node->handle.file, target_pos );
|
||||
if ( fr != FR_OK ) {
|
||||
rtems_fatfs_unlock( iop->pathinfo.mt_entry );
|
||||
errno = rtems_fatfs_fresult_to_errno( fr );
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fr = f_write( &node->handle.file, buffer, (UINT) count, &bytes_written );
|
||||
|
||||
rtems_fatfs_unlock( iop->pathinfo.mt_entry );
|
||||
|
||||
if ( fr != FR_OK ) {
|
||||
errno = rtems_fatfs_fresult_to_errno( fr );
|
||||
return -1;
|
||||
}
|
||||
|
||||
if ( bytes_written > 0 ) {
|
||||
iop->offset += bytes_written;
|
||||
node->info.fsize = f_size( &node->handle.file );
|
||||
|
||||
time_t current_time = time( NULL );
|
||||
node->posix_mtime = current_time;
|
||||
node->posix_ctime = current_time;
|
||||
node->posix_time_valid = true;
|
||||
} else if ( count > 0 && bytes_written == 0 ) {
|
||||
errno = ENOSPC;
|
||||
return -1;
|
||||
}
|
||||
|
||||
return (ssize_t) bytes_written;
|
||||
}
|
||||
|
||||
off_t rtems_fatfs_file_lseek( rtems_libio_t *iop, off_t offset, int whence )
|
||||
{
|
||||
rtems_fatfs_node_t *node = (rtems_fatfs_node_t *) iop->pathinfo.node_access;
|
||||
FSIZE_t new_pos;
|
||||
off_t result;
|
||||
|
||||
if ( node == NULL || node->is_directory ) {
|
||||
rtems_set_errno_and_return_minus_one( EBADF );
|
||||
}
|
||||
|
||||
switch ( whence ) {
|
||||
case SEEK_SET:
|
||||
if ( offset < 0 ) {
|
||||
rtems_set_errno_and_return_minus_one( EINVAL );
|
||||
}
|
||||
new_pos = (FSIZE_t) offset;
|
||||
break;
|
||||
case SEEK_CUR:
|
||||
if ( offset > 0 && iop->offset > LLONG_MAX - offset ) {
|
||||
rtems_set_errno_and_return_minus_one( EOVERFLOW );
|
||||
}
|
||||
result = iop->offset + offset;
|
||||
if ( result < 0 ) {
|
||||
rtems_set_errno_and_return_minus_one( EINVAL );
|
||||
}
|
||||
new_pos = (FSIZE_t) result;
|
||||
break;
|
||||
case SEEK_END:
|
||||
if ( offset > 0 && (off_t) node->info.fsize > LLONG_MAX - offset ) {
|
||||
rtems_set_errno_and_return_minus_one( EOVERFLOW );
|
||||
}
|
||||
result = (off_t) node->info.fsize + offset;
|
||||
if ( result < 0 ) {
|
||||
rtems_set_errno_and_return_minus_one( EINVAL );
|
||||
}
|
||||
new_pos = (FSIZE_t) result;
|
||||
break;
|
||||
default:
|
||||
rtems_set_errno_and_return_minus_one( EINVAL );
|
||||
}
|
||||
|
||||
iop->offset = (off_t) new_pos;
|
||||
return iop->offset;
|
||||
}
|
||||
|
||||
int rtems_fatfs_file_fstat(
|
||||
const rtems_filesystem_location_info_t *loc,
|
||||
struct stat *buf
|
||||
)
|
||||
{
|
||||
rtems_fatfs_node_t *node = (rtems_fatfs_node_t *) loc->node_access;
|
||||
|
||||
if ( node == NULL ) {
|
||||
rtems_set_errno_and_return_minus_one( EBADF );
|
||||
}
|
||||
|
||||
rtems_fatfs_fs_info_t *fs_info = (rtems_fatfs_fs_info_t *)
|
||||
loc->mt_entry->fs_info;
|
||||
rtems_fatfs_node_to_stat( node, buf, fs_info );
|
||||
return 0;
|
||||
}
|
||||
|
||||
int rtems_fatfs_file_ftruncate( rtems_libio_t *iop, off_t length )
|
||||
{
|
||||
rtems_fatfs_node_t *node = (rtems_fatfs_node_t *) iop->pathinfo.node_access;
|
||||
FRESULT fr;
|
||||
FSIZE_t old_size;
|
||||
|
||||
if ( node == NULL || node->is_directory ) {
|
||||
rtems_set_errno_and_return_minus_one( EBADF );
|
||||
}
|
||||
|
||||
rtems_fatfs_lock( iop->pathinfo.mt_entry );
|
||||
|
||||
old_size = f_size( &node->handle.file );
|
||||
|
||||
if ( (FSIZE_t) length > old_size ) {
|
||||
FSIZE_t current_pos = f_tell( &node->handle.file );
|
||||
FSIZE_t gap_size = (FSIZE_t) length - old_size;
|
||||
char zero_buf[ 512 ];
|
||||
UINT bw;
|
||||
|
||||
memset( zero_buf, 0, sizeof( zero_buf ) );
|
||||
|
||||
fr = f_lseek( &node->handle.file, old_size );
|
||||
if ( fr != FR_OK ) {
|
||||
rtems_fatfs_unlock( iop->pathinfo.mt_entry );
|
||||
errno = rtems_fatfs_fresult_to_errno( fr );
|
||||
return -1;
|
||||
}
|
||||
|
||||
while ( gap_size > 0 && fr == FR_OK ) {
|
||||
UINT to_write = gap_size > sizeof( zero_buf ) ? sizeof( zero_buf ) :
|
||||
(UINT) gap_size;
|
||||
fr = f_write( &node->handle.file, zero_buf, to_write, &bw );
|
||||
if ( fr == FR_OK && bw == to_write ) {
|
||||
gap_size -= to_write;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if ( fr == FR_OK ) {
|
||||
if ( gap_size > 0 ) {
|
||||
rtems_fatfs_unlock( iop->pathinfo.mt_entry );
|
||||
errno = ENOSPC;
|
||||
return -1;
|
||||
}
|
||||
fr = f_lseek( &node->handle.file, current_pos );
|
||||
}
|
||||
} else {
|
||||
fr = f_lseek( &node->handle.file, (FSIZE_t) length );
|
||||
if ( fr == FR_OK ) {
|
||||
fr = f_truncate( &node->handle.file );
|
||||
}
|
||||
}
|
||||
|
||||
rtems_fatfs_unlock( iop->pathinfo.mt_entry );
|
||||
|
||||
if ( fr != FR_OK ) {
|
||||
errno = rtems_fatfs_fresult_to_errno( fr );
|
||||
return -1;
|
||||
}
|
||||
|
||||
node->info.fsize = (FSIZE_t) length;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int rtems_fatfs_file_fsync( rtems_libio_t *iop )
|
||||
{
|
||||
rtems_fatfs_node_t *node = (rtems_fatfs_node_t *) iop->pathinfo.node_access;
|
||||
FRESULT fr;
|
||||
|
||||
if ( node == NULL || node->is_directory || !node->is_open ) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
rtems_fatfs_lock( iop->pathinfo.mt_entry );
|
||||
fr = f_sync( &node->handle.file );
|
||||
rtems_fatfs_unlock( iop->pathinfo.mt_entry );
|
||||
|
||||
if ( fr != FR_OK ) {
|
||||
errno = rtems_fatfs_fresult_to_errno( fr );
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int rtems_fatfs_openfile(
|
||||
rtems_libio_t *iop,
|
||||
const char *path,
|
||||
int oflag,
|
||||
mode_t mode
|
||||
)
|
||||
{
|
||||
(void) path;
|
||||
(void) mode;
|
||||
|
||||
rtems_fatfs_node_t *node = (rtems_fatfs_node_t *) iop->pathinfo.node_access;
|
||||
rtems_fatfs_fs_info_t *fs_info = (rtems_fatfs_fs_info_t *)
|
||||
iop->pathinfo.mt_entry->fs_info;
|
||||
char full_path[ 256 ];
|
||||
FRESULT fr;
|
||||
int rc;
|
||||
|
||||
if ( node == NULL || node->is_directory ) {
|
||||
rtems_set_errno_and_return_minus_one( EISDIR );
|
||||
}
|
||||
|
||||
if ( node->is_open ) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
rtems_fatfs_lock( iop->pathinfo.mt_entry );
|
||||
|
||||
rc = rtems_fatfs_resolve_node_path(
|
||||
fs_info,
|
||||
node,
|
||||
full_path,
|
||||
sizeof( full_path ),
|
||||
iop->pathinfo.mt_entry
|
||||
);
|
||||
if ( rc != 0 ) {
|
||||
return rc;
|
||||
}
|
||||
|
||||
BYTE fatfs_mode = FA_READ;
|
||||
|
||||
if ( oflag & O_WRONLY ) {
|
||||
fatfs_mode = FA_WRITE;
|
||||
} else if ( oflag & O_RDWR ) {
|
||||
fatfs_mode = FA_READ | FA_WRITE;
|
||||
}
|
||||
|
||||
if ( oflag & O_CREAT ) {
|
||||
if ( oflag & O_WRONLY ) {
|
||||
fatfs_mode = FA_WRITE | FA_OPEN_EXISTING;
|
||||
} else if ( oflag & O_RDWR ) {
|
||||
fatfs_mode = FA_READ | FA_WRITE | FA_OPEN_EXISTING;
|
||||
} else {
|
||||
fatfs_mode = FA_READ | FA_OPEN_EXISTING;
|
||||
}
|
||||
}
|
||||
|
||||
fr = f_open( &node->handle.file, full_path, fatfs_mode );
|
||||
if ( fr != FR_OK ) {
|
||||
rtems_fatfs_unlock( iop->pathinfo.mt_entry );
|
||||
errno = rtems_fatfs_fresult_to_errno( fr );
|
||||
return -1;
|
||||
}
|
||||
|
||||
if ( oflag & O_TRUNC ) {
|
||||
if ( f_size( &node->handle.file ) == 0 ) {
|
||||
UINT bw;
|
||||
char dummy = 0;
|
||||
fr = f_write( &node->handle.file, &dummy, 1, &bw );
|
||||
if ( fr == FR_OK ) {
|
||||
fr = f_truncate( &node->handle.file );
|
||||
}
|
||||
} else {
|
||||
fr = f_truncate( &node->handle.file );
|
||||
}
|
||||
|
||||
if ( fr != FR_OK ) {
|
||||
f_close( &node->handle.file );
|
||||
rtems_fatfs_unlock( iop->pathinfo.mt_entry );
|
||||
errno = rtems_fatfs_fresult_to_errno( fr );
|
||||
return -1;
|
||||
}
|
||||
|
||||
f_sync( &node->handle.file );
|
||||
}
|
||||
|
||||
node->is_open = true;
|
||||
rtems_fatfs_unlock( iop->pathinfo.mt_entry );
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int rtems_fatfs_closefile( rtems_libio_t *iop )
|
||||
{
|
||||
rtems_fatfs_node_t *node = (rtems_fatfs_node_t *) iop->pathinfo.node_access;
|
||||
FRESULT fr;
|
||||
|
||||
if ( node == NULL || node->is_directory ) {
|
||||
rtems_set_errno_and_return_minus_one( EISDIR );
|
||||
}
|
||||
|
||||
if ( !node->is_open ) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
rtems_fatfs_lock( iop->pathinfo.mt_entry );
|
||||
|
||||
fr = f_close( &node->handle.file );
|
||||
if ( fr != FR_OK ) {
|
||||
rtems_fatfs_unlock( iop->pathinfo.mt_entry );
|
||||
errno = rtems_fatfs_fresult_to_errno( fr );
|
||||
return -1;
|
||||
}
|
||||
|
||||
node->is_open = false;
|
||||
rtems_fatfs_unlock( iop->pathinfo.mt_entry );
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
const rtems_filesystem_file_handlers_r rtems_fatfs_file_handlers = {
|
||||
.open_h = rtems_fatfs_openfile,
|
||||
.close_h = rtems_fatfs_closefile,
|
||||
.read_h = rtems_fatfs_file_read,
|
||||
.write_h = rtems_fatfs_file_write,
|
||||
.ioctl_h = rtems_filesystem_default_ioctl,
|
||||
.lseek_h = rtems_fatfs_file_lseek,
|
||||
.fstat_h = rtems_fatfs_file_fstat,
|
||||
.ftruncate_h = rtems_fatfs_file_ftruncate,
|
||||
.fsync_h = rtems_fatfs_file_fsync,
|
||||
.fdatasync_h = rtems_fatfs_file_fsync,
|
||||
.fcntl_h = rtems_filesystem_default_fcntl,
|
||||
.kqfilter_h = rtems_filesystem_default_kqfilter,
|
||||
.mmap_h = rtems_filesystem_default_mmap,
|
||||
.poll_h = rtems_filesystem_default_poll,
|
||||
.readv_h = rtems_filesystem_default_readv,
|
||||
.writev_h = rtems_filesystem_default_writev
|
||||
};
|
||||
837
cpukit/libfs/src/fatfs/rtems-fatfs-init.c
Normal file
837
cpukit/libfs/src/fatfs/rtems-fatfs-init.c
Normal file
@@ -0,0 +1,837 @@
|
||||
/**
|
||||
* @file
|
||||
*
|
||||
* @ingroup FatFS
|
||||
*
|
||||
* @brief RTEMS FATFS initialization
|
||||
*/
|
||||
|
||||
/*
|
||||
Copyright (C) 2025 Sepehr Ganji <sepehrganji79@gmail.com>
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/statvfs.h>
|
||||
#include <time.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <rtems.h>
|
||||
#include <rtems/bdbuf.h>
|
||||
#include <rtems/diskdevs.h>
|
||||
#include <rtems/fatfs.h>
|
||||
#include <rtems/libio.h>
|
||||
#include <rtems/libio_.h>
|
||||
#include <rtems/score/chain.h>
|
||||
#include <rtems/seterr.h>
|
||||
|
||||
#include "ff.h"
|
||||
#include "rtems-fatfs.h"
|
||||
|
||||
static uint8_t next_drive_number = 0;
|
||||
|
||||
static int rtems_fatfs_build_full_path(
|
||||
const rtems_fatfs_fs_info_t *fs_info,
|
||||
const rtems_fatfs_node_t *parent_node,
|
||||
const char *name,
|
||||
size_t namelen,
|
||||
char *path,
|
||||
size_t path_size
|
||||
)
|
||||
{
|
||||
size_t mount_len = strlen( fs_info->mount_path );
|
||||
size_t total_len;
|
||||
char *write_pos = path;
|
||||
|
||||
if ( parent_node == NULL ) {
|
||||
total_len = mount_len + namelen;
|
||||
if ( total_len >= path_size ) {
|
||||
rtems_set_errno_and_return_minus_one( ENAMETOOLONG );
|
||||
}
|
||||
memcpy( write_pos, fs_info->mount_path, mount_len );
|
||||
write_pos += mount_len;
|
||||
memcpy( write_pos, name, namelen );
|
||||
write_pos += namelen;
|
||||
*write_pos = '\0';
|
||||
} else {
|
||||
size_t parent_len = strlen( parent_node->path );
|
||||
bool need_slash = ( strcmp( parent_node->path, "/" ) != 0 );
|
||||
total_len = mount_len + parent_len + ( need_slash ? 1 : 0 ) + namelen;
|
||||
|
||||
if ( total_len >= path_size ) {
|
||||
rtems_set_errno_and_return_minus_one( ENAMETOOLONG );
|
||||
}
|
||||
|
||||
memcpy( write_pos, fs_info->mount_path, mount_len );
|
||||
write_pos += mount_len;
|
||||
memcpy( write_pos, parent_node->path, parent_len );
|
||||
write_pos += parent_len;
|
||||
if ( need_slash ) {
|
||||
*write_pos = '/';
|
||||
write_pos++;
|
||||
}
|
||||
memcpy( write_pos, name, namelen );
|
||||
write_pos += namelen;
|
||||
*write_pos = '\0';
|
||||
}
|
||||
|
||||
char *dotdot;
|
||||
while ( ( dotdot = strstr( path, "/.." ) ) != NULL ) {
|
||||
if ( dotdot[ 3 ] == '\0' || dotdot[ 3 ] == '/' ) {
|
||||
char *start = dotdot - 1;
|
||||
while ( start > path && *start != '/' ) {
|
||||
start--;
|
||||
}
|
||||
if ( start >= path && *start == '/' ) {
|
||||
char *end = dotdot + 3;
|
||||
memmove( start, end, strlen( end ) + 1 );
|
||||
if ( start == path && *start == '\0' ) {
|
||||
strcpy( path, "/" );
|
||||
}
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
size_t len = strlen( path );
|
||||
if ( len > 0 && len <= 2 && path[ len - 1 ] == ':' ) {
|
||||
strcat( path, "/" );
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void rtems_fatfs_cache_posix_times(
|
||||
rtems_fatfs_fs_info_t *fs_info,
|
||||
const char *path,
|
||||
time_t mtime,
|
||||
time_t ctime
|
||||
)
|
||||
{
|
||||
int index = fs_info->posix_cache_next;
|
||||
size_t path_len = strlen( path );
|
||||
if ( path_len >= sizeof( fs_info->posix_cache[ index ].path ) ) {
|
||||
path_len = sizeof( fs_info->posix_cache[ index ].path ) - 1;
|
||||
}
|
||||
memcpy( fs_info->posix_cache[ index ].path, path, path_len );
|
||||
fs_info->posix_cache[ index ].path[ path_len ] = '\0';
|
||||
fs_info->posix_cache[ index ].mtime = mtime;
|
||||
fs_info->posix_cache[ index ].ctime = ctime;
|
||||
fs_info->posix_cache[ index ].valid = true;
|
||||
fs_info->posix_cache_next = ( fs_info->posix_cache_next + 1 ) %
|
||||
RTEMS_FATFS_POSIX_CACHE_SIZE;
|
||||
}
|
||||
|
||||
static void rtems_fatfs_set_parent_timestamps(
|
||||
const rtems_fatfs_node_t *parent_node
|
||||
)
|
||||
{
|
||||
if ( parent_node != NULL && parent_node->is_directory ) {
|
||||
rtems_fatfs_node_t *mutable_parent = (rtems_fatfs_node_t *) parent_node;
|
||||
time_t current_time = time( NULL );
|
||||
|
||||
mutable_parent->posix_mtime = current_time;
|
||||
mutable_parent->posix_ctime = current_time;
|
||||
mutable_parent->posix_time_valid = true;
|
||||
}
|
||||
}
|
||||
|
||||
int rtems_fatfs_initialize(
|
||||
rtems_filesystem_mount_table_entry_t *mt_entry,
|
||||
const void *data
|
||||
)
|
||||
{
|
||||
(void) data;
|
||||
|
||||
rtems_fatfs_fs_info_t *fs_info = NULL;
|
||||
rtems_fatfs_node_t *root_node = NULL;
|
||||
FRESULT fr;
|
||||
char drive_path[ 8 ];
|
||||
int rc = -1;
|
||||
|
||||
fs_info = calloc( 1, sizeof( *fs_info ) );
|
||||
if ( fs_info == NULL ) {
|
||||
rtems_set_errno_and_return_minus_one( ENOMEM );
|
||||
}
|
||||
|
||||
root_node = calloc( 1, sizeof( *root_node ) );
|
||||
if ( root_node == NULL ) {
|
||||
free( fs_info );
|
||||
rtems_set_errno_and_return_minus_one( ENOMEM );
|
||||
}
|
||||
|
||||
rtems_recursive_mutex_init(
|
||||
&fs_info->vol_mutex,
|
||||
RTEMS_FILESYSTEM_TYPE_FATFS
|
||||
);
|
||||
|
||||
fs_info->drive_number = next_drive_number++;
|
||||
if ( next_drive_number >= FF_VOLUMES ) {
|
||||
next_drive_number = 0;
|
||||
}
|
||||
|
||||
rc = fatfs_diskio_register_device( fs_info->drive_number, mt_entry->dev );
|
||||
if ( rc != 0 ) {
|
||||
rtems_recursive_mutex_destroy( &fs_info->vol_mutex );
|
||||
free( root_node );
|
||||
free( fs_info );
|
||||
return -1;
|
||||
}
|
||||
|
||||
drive_path[ 0 ] = '0' + fs_info->drive_number;
|
||||
drive_path[ 1 ] = ':';
|
||||
drive_path[ 2 ] = '\0';
|
||||
fr = f_mount( &fs_info->fatfs, drive_path, 1 );
|
||||
if ( fr != FR_OK ) {
|
||||
fatfs_diskio_unregister_device( fs_info->drive_number );
|
||||
rtems_recursive_mutex_destroy( &fs_info->vol_mutex );
|
||||
free( root_node );
|
||||
free( fs_info );
|
||||
errno = rtems_fatfs_fresult_to_errno( fr );
|
||||
return -1;
|
||||
}
|
||||
|
||||
fs_info->file_handlers = &rtems_fatfs_file_handlers;
|
||||
fs_info->dir_handlers = &rtems_fatfs_dir_handlers;
|
||||
|
||||
strncpy( fs_info->mount_path, drive_path, sizeof( fs_info->mount_path ) - 1 );
|
||||
fs_info->mount_path[ sizeof( fs_info->mount_path ) - 1 ] = '\0';
|
||||
|
||||
strcpy( fs_info->current_dir, "/" );
|
||||
|
||||
memset( fs_info->posix_cache, 0, sizeof( fs_info->posix_cache ) );
|
||||
fs_info->posix_cache_next = 0;
|
||||
|
||||
root_node->is_directory = true;
|
||||
root_node->is_open = false;
|
||||
root_node->is_root_node = true;
|
||||
root_node->ref_count = 1;
|
||||
strcpy( root_node->path, "/" );
|
||||
|
||||
memset( &root_node->info, 0, sizeof( root_node->info ) );
|
||||
root_node->info.fattrib = AM_DIR;
|
||||
root_node->info.fsize = 0;
|
||||
root_node->info.fdate = 0;
|
||||
root_node->info.ftime = 0;
|
||||
strcpy( root_node->info.fname, "/" );
|
||||
|
||||
mt_entry->fs_info = fs_info;
|
||||
mt_entry->ops = &rtems_fatfs_ops;
|
||||
mt_entry->mt_fs_root->location.node_access = root_node;
|
||||
mt_entry->mt_fs_root->location.handlers = fs_info->dir_handlers;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void rtems_fatfs_fsunmount_me( rtems_filesystem_mount_table_entry_t *mt_entry )
|
||||
{
|
||||
rtems_fatfs_fs_info_t *fs_info = (rtems_fatfs_fs_info_t *) mt_entry->fs_info;
|
||||
rtems_fatfs_node_t *root_node = NULL;
|
||||
|
||||
if ( fs_info != NULL ) {
|
||||
if ( mt_entry->mt_fs_root != NULL ) {
|
||||
root_node = (rtems_fatfs_node_t *)
|
||||
mt_entry->mt_fs_root->location.node_access;
|
||||
}
|
||||
|
||||
f_mount( NULL, fs_info->mount_path, 1 );
|
||||
|
||||
fatfs_diskio_unregister_device( fs_info->drive_number );
|
||||
|
||||
if ( root_node != NULL ) {
|
||||
free( root_node );
|
||||
}
|
||||
|
||||
rtems_recursive_mutex_destroy( &fs_info->vol_mutex );
|
||||
|
||||
free( fs_info );
|
||||
}
|
||||
}
|
||||
|
||||
static rtems_fatfs_node_t *rtems_fatfs_node_get( rtems_fatfs_node_t *node )
|
||||
{
|
||||
if ( node != NULL ) {
|
||||
node->ref_count++;
|
||||
}
|
||||
return node;
|
||||
}
|
||||
|
||||
static void rtems_fatfs_node_put( rtems_fatfs_node_t *node )
|
||||
{
|
||||
if ( node != NULL ) {
|
||||
if ( node->is_root_node ) {
|
||||
node->ref_count--;
|
||||
return;
|
||||
}
|
||||
|
||||
node->ref_count--;
|
||||
if ( node->ref_count <= 0 ) {
|
||||
if ( node->is_open ) {
|
||||
if ( node->is_directory ) {
|
||||
f_closedir( &node->handle.dir );
|
||||
} else {
|
||||
f_close( &node->handle.file );
|
||||
}
|
||||
}
|
||||
|
||||
free( node );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static int rtems_fatfs_find_name(
|
||||
rtems_filesystem_location_info_t *parentloc,
|
||||
const char *name,
|
||||
size_t name_len
|
||||
)
|
||||
{
|
||||
rtems_fatfs_fs_info_t *fs_info = parentloc->mt_entry->fs_info;
|
||||
rtems_fatfs_node_t *parent_node = parentloc->node_access;
|
||||
rtems_fatfs_node_t *new_node = NULL;
|
||||
FRESULT fr;
|
||||
FILINFO fno;
|
||||
char fatfs_path[ 256 ];
|
||||
int ret;
|
||||
|
||||
ret = rtems_fatfs_build_full_path(
|
||||
fs_info,
|
||||
parent_node,
|
||||
name,
|
||||
name_len,
|
||||
fatfs_path,
|
||||
sizeof( fatfs_path )
|
||||
);
|
||||
if ( ret != 0 ) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
if ( strlen( fatfs_path ) == 3 && fatfs_path[ 1 ] == ':' &&
|
||||
fatfs_path[ 2 ] == '/' ) {
|
||||
rtems_filesystem_mount_table_entry_t *mt_entry = parentloc->mt_entry;
|
||||
if ( mt_entry && mt_entry->mt_fs_root ) {
|
||||
new_node = (rtems_fatfs_node_t *)
|
||||
mt_entry->mt_fs_root->location.node_access;
|
||||
if ( new_node ) {
|
||||
rtems_fatfs_node_get( new_node );
|
||||
rtems_fatfs_node_put( parent_node );
|
||||
parentloc->node_access = new_node;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
rtems_set_errno_and_return_minus_one( ENOENT );
|
||||
}
|
||||
|
||||
fr = f_stat( fatfs_path, &fno );
|
||||
if ( fr != FR_OK ) {
|
||||
errno = rtems_fatfs_fresult_to_errno( fr );
|
||||
return -1;
|
||||
}
|
||||
|
||||
new_node = malloc( sizeof( *new_node ) );
|
||||
if ( new_node == NULL ) {
|
||||
rtems_set_errno_and_return_minus_one( ENOMEM );
|
||||
}
|
||||
memset( new_node, 0, sizeof( *new_node ) );
|
||||
|
||||
new_node->info = fno;
|
||||
new_node->is_directory = ( fno.fattrib & AM_DIR ) != 0;
|
||||
new_node->is_open = false;
|
||||
new_node->is_root_node = false;
|
||||
new_node->ref_count = 1;
|
||||
|
||||
size_t total_len;
|
||||
if ( strcmp( parent_node->path, "/" ) == 0 ) {
|
||||
total_len = 1 + name_len; // "/" + name
|
||||
if ( total_len >= sizeof( new_node->path ) ) {
|
||||
free( new_node );
|
||||
rtems_set_errno_and_return_minus_one( ENAMETOOLONG );
|
||||
}
|
||||
new_node->path[ 0 ] = '/';
|
||||
memcpy( new_node->path + 1, name, name_len );
|
||||
new_node->path[ total_len ] = '\0';
|
||||
} else {
|
||||
size_t parent_len = strlen( parent_node->path );
|
||||
total_len = parent_len + 1 + name_len; // parent + "/" + name
|
||||
if ( total_len >= sizeof( new_node->path ) ) {
|
||||
free( new_node );
|
||||
rtems_set_errno_and_return_minus_one( ENAMETOOLONG );
|
||||
}
|
||||
memcpy( new_node->path, parent_node->path, parent_len );
|
||||
new_node->path[ parent_len ] = '/';
|
||||
memcpy( new_node->path + parent_len + 1, name, name_len );
|
||||
new_node->path[ total_len ] = '\0';
|
||||
}
|
||||
|
||||
rtems_fatfs_node_put( parent_node );
|
||||
|
||||
parentloc->node_access = new_node;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void rtems_fatfs_set_handlers( rtems_filesystem_location_info_t *loc )
|
||||
{
|
||||
rtems_fatfs_fs_info_t *fs_info = loc->mt_entry->fs_info;
|
||||
rtems_fatfs_node_t *node = loc->node_access;
|
||||
|
||||
if ( node->is_directory ) {
|
||||
loc->handlers = fs_info->dir_handlers;
|
||||
} else {
|
||||
loc->handlers = fs_info->file_handlers;
|
||||
}
|
||||
}
|
||||
|
||||
static bool rtems_fatfs_eval_is_directory(
|
||||
rtems_filesystem_eval_path_context_t *ctx,
|
||||
void *arg
|
||||
)
|
||||
{
|
||||
(void) arg;
|
||||
|
||||
rtems_fatfs_node_t *node = (rtems_fatfs_node_t *) ctx->currentloc.node_access;
|
||||
return node != NULL && node->is_directory;
|
||||
}
|
||||
|
||||
static rtems_filesystem_eval_path_generic_status rtems_fatfs_eval_token(
|
||||
rtems_filesystem_eval_path_context_t *ctx,
|
||||
void *arg,
|
||||
const char *token,
|
||||
size_t tokenlen
|
||||
)
|
||||
{
|
||||
(void) arg;
|
||||
|
||||
rtems_filesystem_eval_path_generic_status
|
||||
status = RTEMS_FILESYSTEM_EVAL_PATH_GENERIC_DONE;
|
||||
|
||||
if ( rtems_filesystem_is_current_directory( token, tokenlen ) ) {
|
||||
rtems_filesystem_eval_path_clear_token( ctx );
|
||||
status = RTEMS_FILESYSTEM_EVAL_PATH_GENERIC_CONTINUE;
|
||||
} else {
|
||||
rtems_filesystem_location_info_t
|
||||
*currentloc = rtems_filesystem_eval_path_get_currentloc( ctx );
|
||||
|
||||
int rc = rtems_fatfs_find_name( currentloc, token, tokenlen );
|
||||
|
||||
if ( rc == 0 ) {
|
||||
rtems_filesystem_eval_path_clear_token( ctx );
|
||||
rtems_fatfs_set_handlers( currentloc );
|
||||
|
||||
if ( rtems_filesystem_eval_path_has_path( ctx ) ) {
|
||||
rtems_fatfs_node_t *node = (rtems_fatfs_node_t *)
|
||||
currentloc->node_access;
|
||||
if ( node != NULL && !node->is_directory ) {
|
||||
rtems_filesystem_eval_path_error( ctx, ENOTDIR );
|
||||
status = RTEMS_FILESYSTEM_EVAL_PATH_GENERIC_DONE;
|
||||
} else {
|
||||
status = RTEMS_FILESYSTEM_EVAL_PATH_GENERIC_CONTINUE;
|
||||
}
|
||||
} else {
|
||||
status = RTEMS_FILESYSTEM_EVAL_PATH_GENERIC_DONE;
|
||||
}
|
||||
} else {
|
||||
if ( errno == ENOENT ) {
|
||||
status = RTEMS_FILESYSTEM_EVAL_PATH_GENERIC_NO_ENTRY;
|
||||
} else {
|
||||
rtems_filesystem_eval_path_error( ctx, errno );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
static const rtems_filesystem_eval_path_generic_config rtems_fatfs_eval_config =
|
||||
{ .is_directory = rtems_fatfs_eval_is_directory,
|
||||
.eval_token = rtems_fatfs_eval_token };
|
||||
|
||||
void rtems_fatfs_eval_path( rtems_filesystem_eval_path_context_t *ctx )
|
||||
{
|
||||
rtems_filesystem_eval_path_generic( ctx, NULL, &rtems_fatfs_eval_config );
|
||||
}
|
||||
|
||||
int rtems_fatfs_mknod(
|
||||
const rtems_filesystem_location_info_t *parentloc,
|
||||
const char *name,
|
||||
size_t namelen,
|
||||
mode_t mode,
|
||||
dev_t dev
|
||||
)
|
||||
{
|
||||
char full_path[ 256 ];
|
||||
FRESULT fr;
|
||||
FIL fil;
|
||||
int rc;
|
||||
|
||||
(void) dev;
|
||||
|
||||
rtems_fatfs_fs_info_t *fs_info = (rtems_fatfs_fs_info_t *)
|
||||
parentloc->mt_entry->fs_info;
|
||||
rtems_fatfs_node_t *parent_node = (rtems_fatfs_node_t *)
|
||||
parentloc->node_access;
|
||||
|
||||
rc = rtems_fatfs_build_full_path(
|
||||
fs_info,
|
||||
parent_node,
|
||||
name,
|
||||
namelen,
|
||||
full_path,
|
||||
sizeof( full_path )
|
||||
);
|
||||
|
||||
if ( rc != 0 ) {
|
||||
return rc;
|
||||
}
|
||||
|
||||
rtems_fatfs_lock( parentloc->mt_entry );
|
||||
|
||||
if ( S_ISDIR( mode ) ) {
|
||||
fr = f_mkdir( full_path );
|
||||
if ( fr == FR_OK ) {
|
||||
rtems_fatfs_set_parent_timestamps( parent_node );
|
||||
}
|
||||
} else if ( S_ISREG( mode ) ) {
|
||||
fr = f_open( &fil, full_path, FA_CREATE_NEW | FA_WRITE );
|
||||
if ( fr == FR_OK ) {
|
||||
f_close( &fil );
|
||||
rtems_fatfs_set_parent_timestamps( parent_node );
|
||||
}
|
||||
} else {
|
||||
rtems_fatfs_unlock( parentloc->mt_entry );
|
||||
rtems_set_errno_and_return_minus_one( ENOTSUP );
|
||||
}
|
||||
|
||||
rtems_fatfs_unlock( parentloc->mt_entry );
|
||||
|
||||
if ( fr != FR_OK ) {
|
||||
errno = rtems_fatfs_fresult_to_errno( fr );
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int rtems_fatfs_rmnod(
|
||||
const rtems_filesystem_location_info_t *parentloc,
|
||||
const rtems_filesystem_location_info_t *loc
|
||||
)
|
||||
{
|
||||
rtems_fatfs_fs_info_t *fs_info = NULL;
|
||||
rtems_fatfs_node_t *node = NULL;
|
||||
char full_path[ 256 ];
|
||||
FRESULT fr;
|
||||
int rc;
|
||||
|
||||
fs_info = (rtems_fatfs_fs_info_t *) parentloc->mt_entry->fs_info;
|
||||
node = (rtems_fatfs_node_t *) loc->node_access;
|
||||
|
||||
if ( node == NULL ) {
|
||||
rtems_set_errno_and_return_minus_one( EINVAL );
|
||||
}
|
||||
|
||||
if ( node->is_open && !node->is_directory ) {
|
||||
f_close( &node->handle.file );
|
||||
node->is_open = false;
|
||||
}
|
||||
|
||||
rc = rtems_fatfs_resolve_node_path(
|
||||
fs_info,
|
||||
node,
|
||||
full_path,
|
||||
sizeof( full_path ),
|
||||
NULL
|
||||
);
|
||||
if ( rc != 0 ) {
|
||||
return rc;
|
||||
}
|
||||
|
||||
rtems_fatfs_lock( parentloc->mt_entry );
|
||||
|
||||
fr = f_unlink( full_path );
|
||||
|
||||
rtems_fatfs_unlock( parentloc->mt_entry );
|
||||
|
||||
if ( fr != FR_OK ) {
|
||||
if ( ( fr == FR_DENIED || fr == FR_INVALID_NAME ) && node->is_directory ) {
|
||||
errno = ENOTEMPTY;
|
||||
} else {
|
||||
errno = rtems_fatfs_fresult_to_errno( fr );
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool rtems_fatfs_are_nodes_equal(
|
||||
const rtems_filesystem_location_info_t *a,
|
||||
const rtems_filesystem_location_info_t *b
|
||||
)
|
||||
{
|
||||
rtems_fatfs_node_t *node_a = (rtems_fatfs_node_t *) a->node_access;
|
||||
rtems_fatfs_node_t *node_b = (rtems_fatfs_node_t *) b->node_access;
|
||||
|
||||
if ( node_a == NULL || node_b == NULL ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return strcmp( node_a->path, node_b->path ) == 0;
|
||||
}
|
||||
|
||||
int rtems_fatfs_clone_node( rtems_filesystem_location_info_t *loc )
|
||||
{
|
||||
rtems_fatfs_node_t *node = (rtems_fatfs_node_t *) loc->node_access;
|
||||
|
||||
if ( node != NULL ) {
|
||||
rtems_fatfs_node_get( node );
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void rtems_fatfs_free_node( const rtems_filesystem_location_info_t *loc )
|
||||
{
|
||||
rtems_fatfs_node_t *node = (rtems_fatfs_node_t *) loc->node_access;
|
||||
|
||||
if ( node != NULL ) {
|
||||
rtems_fatfs_node_put( node );
|
||||
}
|
||||
}
|
||||
|
||||
int rtems_fatfs_rename(
|
||||
const rtems_filesystem_location_info_t *old_parent_loc,
|
||||
const rtems_filesystem_location_info_t *old_loc,
|
||||
const rtems_filesystem_location_info_t *new_parent_loc,
|
||||
const char *new_name,
|
||||
size_t new_namelen
|
||||
)
|
||||
{
|
||||
rtems_fatfs_fs_info_t *fs_info = NULL;
|
||||
rtems_fatfs_node_t *old_node = NULL;
|
||||
char old_path[ 256 ];
|
||||
char new_path[ 256 ];
|
||||
FRESULT fr;
|
||||
int rc;
|
||||
|
||||
fs_info = (rtems_fatfs_fs_info_t *) old_parent_loc->mt_entry->fs_info;
|
||||
old_node = (rtems_fatfs_node_t *) old_loc->node_access;
|
||||
|
||||
if ( old_node == NULL ) {
|
||||
rtems_set_errno_and_return_minus_one( EINVAL );
|
||||
}
|
||||
|
||||
rc = rtems_fatfs_resolve_node_path(
|
||||
fs_info,
|
||||
old_node,
|
||||
old_path,
|
||||
sizeof( old_path ),
|
||||
NULL
|
||||
);
|
||||
if ( rc != 0 ) {
|
||||
return rc;
|
||||
}
|
||||
|
||||
rtems_fatfs_fs_info_t *new_fs_info = (rtems_fatfs_fs_info_t *)
|
||||
new_parent_loc->mt_entry->fs_info;
|
||||
rtems_fatfs_node_t *new_parent_node = (rtems_fatfs_node_t *)
|
||||
new_parent_loc->node_access;
|
||||
rc = rtems_fatfs_build_full_path(
|
||||
new_fs_info,
|
||||
new_parent_node,
|
||||
new_name,
|
||||
new_namelen,
|
||||
new_path,
|
||||
sizeof( new_path )
|
||||
);
|
||||
if ( rc != 0 ) {
|
||||
return rc;
|
||||
}
|
||||
|
||||
rtems_fatfs_lock( old_parent_loc->mt_entry );
|
||||
|
||||
fr = f_rename( old_path, new_path );
|
||||
|
||||
rtems_fatfs_unlock( old_parent_loc->mt_entry );
|
||||
|
||||
if ( fr != FR_OK ) {
|
||||
errno = rtems_fatfs_fresult_to_errno( fr );
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void rtems_fatfs_update_fat_timestamp(
|
||||
const char *path,
|
||||
time_t timestamp
|
||||
)
|
||||
{
|
||||
struct tm *tm_info = localtime( ×tamp );
|
||||
if ( tm_info != NULL ) {
|
||||
FILINFO fno;
|
||||
memset( &fno, 0, sizeof( fno ) );
|
||||
|
||||
fno.fdate = ( ( tm_info->tm_year + 1900 - 1980 ) << 9 ) |
|
||||
( ( tm_info->tm_mon + 1 ) << 5 ) | ( tm_info->tm_mday );
|
||||
fno.ftime = ( tm_info->tm_hour << 11 ) | ( tm_info->tm_min << 5 ) |
|
||||
( tm_info->tm_sec >> 1 );
|
||||
|
||||
f_utime( path, &fno );
|
||||
}
|
||||
}
|
||||
|
||||
int rtems_fatfs_utimens(
|
||||
const rtems_filesystem_location_info_t *loc,
|
||||
struct timespec times[ 2 ]
|
||||
)
|
||||
{
|
||||
rtems_fatfs_fs_info_t *fs_info = (rtems_fatfs_fs_info_t *)
|
||||
loc->mt_entry->fs_info;
|
||||
rtems_fatfs_node_t *node = (rtems_fatfs_node_t *) loc->node_access;
|
||||
char full_path[ 256 ];
|
||||
int rc;
|
||||
|
||||
if ( node == NULL ) {
|
||||
rtems_set_errno_and_return_minus_one( EINVAL );
|
||||
}
|
||||
|
||||
time_t mtime = times[ 1 ].tv_sec;
|
||||
time_t current_time = time( NULL );
|
||||
|
||||
rc = rtems_fatfs_resolve_node_path(
|
||||
fs_info,
|
||||
node,
|
||||
full_path,
|
||||
sizeof( full_path ),
|
||||
NULL
|
||||
);
|
||||
if ( rc != 0 ) {
|
||||
return rc;
|
||||
}
|
||||
|
||||
rtems_fatfs_lock( loc->mt_entry );
|
||||
rtems_fatfs_update_fat_timestamp( full_path, mtime );
|
||||
rtems_fatfs_unlock( loc->mt_entry );
|
||||
|
||||
rtems_fatfs_cache_posix_times( fs_info, node->path, mtime, current_time );
|
||||
|
||||
node->posix_mtime = mtime;
|
||||
node->posix_ctime = current_time;
|
||||
node->posix_time_valid = true;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Compiler will change name to rtems_fatfs_get_fattime
|
||||
*/
|
||||
DWORD get_fattime( void )
|
||||
{
|
||||
time_t current_time;
|
||||
struct tm *tm_info;
|
||||
DWORD fat_time = 0;
|
||||
|
||||
current_time = time( NULL );
|
||||
tm_info = localtime( ¤t_time );
|
||||
|
||||
if ( tm_info != NULL ) {
|
||||
fat_time = ( (DWORD) ( tm_info->tm_year + 1900 - 1980 ) << 25 ) |
|
||||
( (DWORD) ( tm_info->tm_mon + 1 ) << 21 ) |
|
||||
( (DWORD) tm_info->tm_mday << 16 ) |
|
||||
( (DWORD) tm_info->tm_hour << 11 ) |
|
||||
( (DWORD) tm_info->tm_min << 5 ) |
|
||||
( (DWORD) tm_info->tm_sec >> 1 );
|
||||
} else {
|
||||
fat_time = ( 0 << 25 ) | ( 1 << 21 ) | ( 1 << 16 );
|
||||
}
|
||||
|
||||
return fat_time;
|
||||
}
|
||||
|
||||
int rtems_fatfs_statvfs(
|
||||
const rtems_filesystem_location_info_t *root_loc,
|
||||
struct statvfs *sb
|
||||
)
|
||||
{
|
||||
rtems_fatfs_fs_info_t *fs_info = root_loc->mt_entry->fs_info;
|
||||
FATFS *fs = &fs_info->fatfs;
|
||||
FRESULT fr;
|
||||
DWORD free_clusters;
|
||||
FATFS *fatfs_ptr;
|
||||
char drive_path[ 8 ];
|
||||
|
||||
if ( fs_info == NULL || sb == NULL ) {
|
||||
rtems_set_errno_and_return_minus_one( EINVAL );
|
||||
}
|
||||
|
||||
rtems_fatfs_lock( root_loc->mt_entry );
|
||||
|
||||
drive_path[ 0 ] = '0' + fs_info->drive_number;
|
||||
drive_path[ 1 ] = ':';
|
||||
drive_path[ 2 ] = '\0';
|
||||
|
||||
fr = f_getfree( drive_path, &free_clusters, &fatfs_ptr );
|
||||
if ( fr != FR_OK ) {
|
||||
rtems_fatfs_unlock( root_loc->mt_entry );
|
||||
errno = rtems_fatfs_fresult_to_errno( fr );
|
||||
return -1;
|
||||
}
|
||||
|
||||
#if FF_MAX_SS != FF_MIN_SS
|
||||
WORD sector_size = fs->ssize;
|
||||
#else
|
||||
WORD sector_size = FF_MAX_SS;
|
||||
#endif
|
||||
|
||||
sb->f_bsize = sector_size;
|
||||
sb->f_frsize = fs->csize * sector_size;
|
||||
sb->f_blocks = fs->n_fatent - 2;
|
||||
sb->f_bfree = free_clusters;
|
||||
sb->f_bavail = free_clusters;
|
||||
sb->f_files = 0;
|
||||
sb->f_ffree = 0;
|
||||
sb->f_favail = 0;
|
||||
sb->f_flag = 0;
|
||||
|
||||
#if FF_USE_LFN
|
||||
sb->f_namemax = FF_LFN_BUF - 1;
|
||||
#else
|
||||
sb->f_namemax = 12;
|
||||
#endif
|
||||
|
||||
rtems_fatfs_unlock( root_loc->mt_entry );
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
const rtems_filesystem_operations_table rtems_fatfs_ops = {
|
||||
.lock_h = rtems_fatfs_lock,
|
||||
.unlock_h = rtems_fatfs_unlock,
|
||||
.eval_path_h = rtems_fatfs_eval_path,
|
||||
.link_h = rtems_filesystem_default_link,
|
||||
.are_nodes_equal_h = rtems_fatfs_are_nodes_equal,
|
||||
.mknod_h = rtems_fatfs_mknod,
|
||||
.rmnod_h = rtems_fatfs_rmnod,
|
||||
.fchmod_h = rtems_filesystem_default_fchmod,
|
||||
.chown_h = rtems_filesystem_default_chown,
|
||||
.clonenod_h = rtems_fatfs_clone_node,
|
||||
.freenod_h = rtems_fatfs_free_node,
|
||||
.mount_h = rtems_fatfs_initialize,
|
||||
.unmount_h = rtems_filesystem_default_unmount,
|
||||
.fsunmount_me_h = rtems_fatfs_fsunmount_me,
|
||||
.utimens_h = rtems_fatfs_utimens,
|
||||
.symlink_h = rtems_filesystem_default_symlink,
|
||||
.readlink_h = rtems_filesystem_default_readlink,
|
||||
.rename_h = rtems_fatfs_rename,
|
||||
.statvfs_h = rtems_fatfs_statvfs
|
||||
};
|
||||
372
cpukit/libfs/src/fatfs/rtems-fatfs.h
Normal file
372
cpukit/libfs/src/fatfs/rtems-fatfs.h
Normal file
@@ -0,0 +1,372 @@
|
||||
/**
|
||||
* @file
|
||||
*
|
||||
* @ingroup FatFS
|
||||
*
|
||||
* @brief RTEMS FatFS headers
|
||||
*/
|
||||
|
||||
/*
|
||||
Copyright (C) 2025 Sepehr Ganji <sepehrganji79@gmail.com>
|
||||
*/
|
||||
|
||||
#ifndef RTEMS_FATFS_H
|
||||
#define RTEMS_FATFS_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
#include <time.h>
|
||||
|
||||
#include <rtems/diskdevs.h>
|
||||
#include <rtems/libio.h>
|
||||
#include <rtems/seterr.h>
|
||||
|
||||
#include "ff.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define DT_REG 8
|
||||
#define DT_DIR 4
|
||||
|
||||
typedef struct {
|
||||
int fd;
|
||||
rtems_disk_device *dd;
|
||||
bool initialized;
|
||||
} fatfs_volume_t;
|
||||
|
||||
#define RTEMS_FATFS_POSIX_CACHE_SIZE 64
|
||||
|
||||
typedef struct {
|
||||
char path[ 256 ];
|
||||
time_t mtime;
|
||||
time_t ctime;
|
||||
bool valid;
|
||||
} rtems_fatfs_posix_cache_entry_t;
|
||||
|
||||
typedef struct {
|
||||
FATFS fatfs;
|
||||
rtems_recursive_mutex vol_mutex;
|
||||
const rtems_filesystem_file_handlers_r *file_handlers;
|
||||
const rtems_filesystem_file_handlers_r *dir_handlers;
|
||||
uint8_t drive_number;
|
||||
char mount_path[ 256 ];
|
||||
char current_dir[ 256 ];
|
||||
rtems_fatfs_posix_cache_entry_t posix_cache[ RTEMS_FATFS_POSIX_CACHE_SIZE ];
|
||||
int posix_cache_next;
|
||||
} rtems_fatfs_fs_info_t;
|
||||
|
||||
typedef struct {
|
||||
union {
|
||||
FIL file;
|
||||
DIR dir;
|
||||
} handle;
|
||||
FILINFO info;
|
||||
bool is_directory;
|
||||
bool is_open;
|
||||
char path[ 256 ];
|
||||
bool is_root_node;
|
||||
int ref_count;
|
||||
time_t posix_mtime;
|
||||
time_t posix_ctime;
|
||||
bool posix_time_valid;
|
||||
} rtems_fatfs_node_t;
|
||||
|
||||
/* Disk I/O interface */
|
||||
int fatfs_diskio_register_device( uint8_t pdrv, const char *device_path );
|
||||
void fatfs_diskio_unregister_device( uint8_t pdrv );
|
||||
|
||||
/* Utility functions */
|
||||
static inline int rtems_fatfs_get_full_path(
|
||||
const rtems_fatfs_fs_info_t *fs_info,
|
||||
const char *relative_path,
|
||||
char *full_path,
|
||||
size_t path_size
|
||||
)
|
||||
{
|
||||
size_t mount_len = strlen( fs_info->mount_path );
|
||||
size_t rel_len = strlen( relative_path );
|
||||
|
||||
if ( mount_len + rel_len >= path_size ) {
|
||||
rtems_set_errno_and_return_minus_one( ENAMETOOLONG );
|
||||
}
|
||||
|
||||
memcpy( full_path, fs_info->mount_path, mount_len );
|
||||
memcpy( full_path + mount_len, relative_path, rel_len + 1 );
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int rtems_fatfs_fresult_to_errno( FRESULT fr )
|
||||
{
|
||||
switch ( fr ) {
|
||||
case FR_OK:
|
||||
return 0;
|
||||
case FR_DISK_ERR:
|
||||
case FR_INT_ERR:
|
||||
case FR_NOT_READY:
|
||||
return EIO;
|
||||
case FR_NO_FILE:
|
||||
case FR_NO_PATH:
|
||||
return ENOENT;
|
||||
case FR_INVALID_NAME:
|
||||
return EINVAL;
|
||||
case FR_DENIED:
|
||||
return EACCES;
|
||||
case FR_EXIST:
|
||||
return EEXIST;
|
||||
case FR_INVALID_OBJECT:
|
||||
return EBADF;
|
||||
case FR_WRITE_PROTECTED:
|
||||
return EROFS;
|
||||
case FR_INVALID_DRIVE:
|
||||
case FR_NOT_ENABLED:
|
||||
case FR_NO_FILESYSTEM:
|
||||
return ENXIO;
|
||||
case FR_MKFS_ABORTED:
|
||||
return EINVAL;
|
||||
case FR_TIMEOUT:
|
||||
return ETIMEDOUT;
|
||||
case FR_LOCKED:
|
||||
return EBUSY;
|
||||
case FR_NOT_ENOUGH_CORE:
|
||||
return ENOMEM;
|
||||
case FR_TOO_MANY_OPEN_FILES:
|
||||
return EMFILE;
|
||||
case FR_INVALID_PARAMETER:
|
||||
return EINVAL;
|
||||
default:
|
||||
return EIO;
|
||||
}
|
||||
}
|
||||
|
||||
static inline void rtems_fatfs_unlock(
|
||||
const rtems_filesystem_mount_table_entry_t *mt_entry
|
||||
)
|
||||
{
|
||||
rtems_fatfs_fs_info_t *fs_info = (rtems_fatfs_fs_info_t *) mt_entry->fs_info;
|
||||
rtems_recursive_mutex_unlock( &fs_info->vol_mutex );
|
||||
}
|
||||
|
||||
static inline int rtems_fatfs_resolve_node_path(
|
||||
const rtems_fatfs_fs_info_t *fs_info,
|
||||
const rtems_fatfs_node_t *node,
|
||||
char *full_path,
|
||||
size_t path_size,
|
||||
const rtems_filesystem_mount_table_entry_t *mt_entry
|
||||
)
|
||||
{
|
||||
int
|
||||
rc = rtems_fatfs_get_full_path( fs_info, node->path, full_path, path_size );
|
||||
if ( rc != 0 && mt_entry != NULL ) {
|
||||
rtems_fatfs_unlock( mt_entry );
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
static inline void rtems_fatfs_filinfo_to_stat(
|
||||
const FILINFO *fno,
|
||||
struct stat *st
|
||||
)
|
||||
{
|
||||
const char *name = fno->fname;
|
||||
ino_t inode_hash = 1;
|
||||
|
||||
memset( st, 0, sizeof( *st ) );
|
||||
|
||||
while ( *name != '\0' ) {
|
||||
inode_hash = ( inode_hash * 33 ) + (unsigned char) *name;
|
||||
name++;
|
||||
}
|
||||
inode_hash ^= fno->fsize ^ ( fno->fdate << 16 ) ^ fno->ftime;
|
||||
|
||||
st->st_ino = ( inode_hash != 0 ) ? inode_hash : 1;
|
||||
st->st_dev = 1;
|
||||
st->st_size = (off_t) fno->fsize;
|
||||
st->st_blksize = 512;
|
||||
st->st_blocks = ( st->st_size + 511 ) / 512;
|
||||
|
||||
if ( fno->fdate != 0 || fno->ftime != 0 ) {
|
||||
struct tm tm;
|
||||
memset( &tm, 0, sizeof( tm ) );
|
||||
|
||||
tm.tm_year = ( ( fno->fdate >> 9 ) & 0x7F ) + 80;
|
||||
tm.tm_mon = ( ( fno->fdate >> 5 ) & 0x0F ) - 1;
|
||||
tm.tm_mday = fno->fdate & 0x1F;
|
||||
tm.tm_hour = ( fno->ftime >> 11 ) & 0x1F;
|
||||
tm.tm_min = ( fno->ftime >> 5 ) & 0x3F;
|
||||
tm.tm_sec = ( fno->ftime & 0x1F ) * 2;
|
||||
|
||||
st->st_mtime = mktime( &tm );
|
||||
st->st_ctime = st->st_mtime;
|
||||
st->st_atime = st->st_mtime;
|
||||
}
|
||||
|
||||
if ( fno->fattrib & AM_DIR ) {
|
||||
st->st_mode = S_IFDIR | 0755;
|
||||
} else {
|
||||
st->st_mode = S_IFREG | 0644;
|
||||
}
|
||||
|
||||
if ( fno->fattrib & AM_RDO ) {
|
||||
st->st_mode &= ~( S_IWUSR | S_IWGRP | S_IWOTH );
|
||||
}
|
||||
}
|
||||
|
||||
static inline void rtems_fatfs_node_to_stat_basic(
|
||||
const rtems_fatfs_node_t *node,
|
||||
struct stat *st
|
||||
)
|
||||
{
|
||||
rtems_fatfs_filinfo_to_stat( &node->info, st );
|
||||
}
|
||||
|
||||
static inline void rtems_fatfs_node_to_stat(
|
||||
const rtems_fatfs_node_t *node,
|
||||
struct stat *st,
|
||||
rtems_fatfs_fs_info_t *fs_info
|
||||
)
|
||||
{
|
||||
rtems_fatfs_filinfo_to_stat( &node->info, st );
|
||||
|
||||
if ( fs_info != NULL ) {
|
||||
blksize_t cluster_size = fs_info->fatfs.csize * 512;
|
||||
st->st_blksize = cluster_size;
|
||||
blkcnt_t clusters_used = ( st->st_size + cluster_size - 1 ) / cluster_size;
|
||||
st->st_blocks = clusters_used * fs_info->fatfs.csize;
|
||||
}
|
||||
|
||||
if ( node->posix_time_valid ) {
|
||||
st->st_mtime = node->posix_mtime;
|
||||
st->st_ctime = node->posix_ctime;
|
||||
st->st_atime = node->posix_mtime;
|
||||
} else if ( fs_info != NULL ) {
|
||||
for ( int i = 0; i < RTEMS_FATFS_POSIX_CACHE_SIZE; i++ ) {
|
||||
if ( fs_info->posix_cache[ i ].valid &&
|
||||
strcmp( fs_info->posix_cache[ i ].path, node->path ) == 0 ) {
|
||||
st->st_mtime = fs_info->posix_cache[ i ].mtime;
|
||||
st->st_ctime = fs_info->posix_cache[ i ].ctime;
|
||||
st->st_atime = fs_info->posix_cache[ i ].mtime;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static inline void rtems_fatfs_lock(
|
||||
const rtems_filesystem_mount_table_entry_t *mt_entry
|
||||
)
|
||||
{
|
||||
rtems_fatfs_fs_info_t *fs_info = (rtems_fatfs_fs_info_t *) mt_entry->fs_info;
|
||||
rtems_recursive_mutex_lock( &fs_info->vol_mutex );
|
||||
}
|
||||
|
||||
/* Filesystem operations - declared in rtems-fatfs-init.c */
|
||||
int rtems_fatfs_initialize(
|
||||
rtems_filesystem_mount_table_entry_t *mt_entry,
|
||||
const void *data
|
||||
);
|
||||
|
||||
void rtems_fatfs_fsunmount_me( rtems_filesystem_mount_table_entry_t *mt_entry );
|
||||
|
||||
void rtems_fatfs_eval_path( rtems_filesystem_eval_path_context_t *ctx );
|
||||
|
||||
int rtems_fatfs_mknod(
|
||||
const rtems_filesystem_location_info_t *parentloc,
|
||||
const char *name,
|
||||
size_t namelen,
|
||||
mode_t mode,
|
||||
dev_t dev
|
||||
);
|
||||
|
||||
int rtems_fatfs_rmnod(
|
||||
const rtems_filesystem_location_info_t *parentloc,
|
||||
const rtems_filesystem_location_info_t *loc
|
||||
);
|
||||
|
||||
int rtems_fatfs_rename(
|
||||
const rtems_filesystem_location_info_t *old_parent_loc,
|
||||
const rtems_filesystem_location_info_t *old_loc,
|
||||
const rtems_filesystem_location_info_t *new_parent_loc,
|
||||
const char *new_name,
|
||||
size_t new_namelen
|
||||
);
|
||||
|
||||
int rtems_fatfs_utimens(
|
||||
const rtems_filesystem_location_info_t *loc,
|
||||
struct timespec times[ 2 ]
|
||||
);
|
||||
|
||||
int rtems_fatfs_statvfs(
|
||||
const rtems_filesystem_location_info_t *root_loc,
|
||||
struct statvfs *sb
|
||||
);
|
||||
|
||||
bool rtems_fatfs_are_nodes_equal(
|
||||
const rtems_filesystem_location_info_t *a,
|
||||
const rtems_filesystem_location_info_t *b
|
||||
);
|
||||
|
||||
int rtems_fatfs_clone_node( rtems_filesystem_location_info_t *loc );
|
||||
|
||||
void rtems_fatfs_free_node( const rtems_filesystem_location_info_t *loc );
|
||||
|
||||
/* File operations - declared in rtems-fatfs-file.c */
|
||||
ssize_t rtems_fatfs_file_read( rtems_libio_t *iop, void *buffer, size_t count );
|
||||
|
||||
ssize_t rtems_fatfs_file_write(
|
||||
rtems_libio_t *iop,
|
||||
const void *buffer,
|
||||
size_t count
|
||||
);
|
||||
|
||||
off_t rtems_fatfs_file_lseek( rtems_libio_t *iop, off_t offset, int whence );
|
||||
|
||||
int rtems_fatfs_file_fstat(
|
||||
const rtems_filesystem_location_info_t *loc,
|
||||
struct stat *buf
|
||||
);
|
||||
|
||||
int rtems_fatfs_file_ftruncate( rtems_libio_t *iop, off_t length );
|
||||
|
||||
int rtems_fatfs_file_fsync( rtems_libio_t *iop );
|
||||
|
||||
/* Directory operations - declared in rtems-fatfs-dir.c */
|
||||
ssize_t rtems_fatfs_dir_read( rtems_libio_t *iop, void *buffer, size_t count );
|
||||
|
||||
int rtems_fatfs_dir_fstat(
|
||||
const rtems_filesystem_location_info_t *loc,
|
||||
struct stat *buf
|
||||
);
|
||||
|
||||
int rtems_fatfs_opendir(
|
||||
rtems_libio_t *iop,
|
||||
const char *path,
|
||||
int oflag,
|
||||
mode_t mode
|
||||
);
|
||||
|
||||
int rtems_fatfs_closedir( rtems_libio_t *iop );
|
||||
|
||||
int rtems_fatfs_openfile(
|
||||
rtems_libio_t *iop,
|
||||
const char *path,
|
||||
int oflag,
|
||||
mode_t mode
|
||||
);
|
||||
|
||||
int rtems_fatfs_closefile( rtems_libio_t *iop );
|
||||
|
||||
/* Handler tables */
|
||||
extern const rtems_filesystem_operations_table rtems_fatfs_ops;
|
||||
extern const rtems_filesystem_file_handlers_r rtems_fatfs_file_handlers;
|
||||
extern const rtems_filesystem_file_handlers_r rtems_fatfs_dir_handlers;
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* RTEMS_FATFS_H */
|
||||
@@ -4,7 +4,30 @@ cflags:
|
||||
- ${COVERAGE_COMPILER_FLAGS}
|
||||
copyrights:
|
||||
- Copyright (C) 2020 embedded brains GmbH & Co. KG
|
||||
cppflags: []
|
||||
cppflags:
|
||||
- -Ddisk_status=rtems_fatfs_disk_status
|
||||
- -Ddisk_initialize=rtems_fatfs_disk_initialize
|
||||
- -Ddisk_read=rtems_fatfs_disk_read
|
||||
- -Ddisk_write=rtems_fatfs_disk_write
|
||||
- -Ddisk_ioctl=rtems_fatfs_disk_ioctl
|
||||
- -Dget_fattime=rtems_fatfs_get_fattime
|
||||
- -DFFCONF_DEF=5385
|
||||
- -DFF_VOLUMES=1
|
||||
- -DFF_USE_MKFS=1
|
||||
- -DFF_USE_CHMOD=1
|
||||
- -DFF_USE_LFN=1
|
||||
- -DFF_FS_RPATH=2
|
||||
- -DFF_FS_EXFAT=1
|
||||
- -DFF_MAX_SS=512
|
||||
- -DFF_MIN_SS=512
|
||||
- -DFF_LFN_BUF=255
|
||||
- -DFF_SFN_BUF=12
|
||||
- -DFF_MAX_LFN=255
|
||||
- -DFF_USE_LABEL=0
|
||||
- -DFF_STR_VOLUME_ID=0
|
||||
- -DFF_MULTI_PARTITION=0
|
||||
- -DFF_FS_READONLY=0
|
||||
- -DFF_LBA64=0
|
||||
cxxflags:
|
||||
- ${COVERAGE_COMPILER_FLAGS}
|
||||
enabled-by: true
|
||||
@@ -118,6 +141,7 @@ install:
|
||||
- cpukit/include/rtems/devzero.h
|
||||
- cpukit/include/rtems/diskdevs.h
|
||||
- cpukit/include/rtems/dosfs.h
|
||||
- cpukit/include/rtems/fatfs.h
|
||||
- cpukit/include/rtems/dumpbuf.h
|
||||
- cpukit/include/rtems/endian.h
|
||||
- cpukit/include/rtems/error.h
|
||||
@@ -861,6 +885,13 @@ source:
|
||||
- cpukit/libfs/src/dosfs/msdos_rename.c
|
||||
- cpukit/libfs/src/dosfs/msdos_rmnod.c
|
||||
- cpukit/libfs/src/dosfs/msdos_statvfs.c
|
||||
- cpukit/libfs/src/fatfs/ff.c
|
||||
- cpukit/libfs/src/fatfs/ffunicode.c
|
||||
- cpukit/libfs/src/fatfs/ffsystem.c
|
||||
- cpukit/libfs/src/fatfs/rtems-diskio.c
|
||||
- cpukit/libfs/src/fatfs/rtems-fatfs-init.c
|
||||
- cpukit/libfs/src/fatfs/rtems-fatfs-file.c
|
||||
- cpukit/libfs/src/fatfs/rtems-fatfs-dir.c
|
||||
- cpukit/libfs/src/imfs/deviceio.c
|
||||
- cpukit/libfs/src/imfs/imfs_add_node.c
|
||||
- cpukit/libfs/src/imfs/imfs_chown.c
|
||||
|
||||
21
spec/build/testsuites/fstests/fatfsfsclose01.yml
Normal file
21
spec/build/testsuites/fstests/fatfsfsclose01.yml
Normal file
@@ -0,0 +1,21 @@
|
||||
SPDX-License-Identifier: CC-BY-SA-4.0 OR BSD-2-Clause
|
||||
build-type: test-program
|
||||
cflags: []
|
||||
copyrights:
|
||||
- Copyright (C) 2025 Sepehr Ganji <sepehrganji79@gmail.com>
|
||||
cppflags: []
|
||||
cxxflags: []
|
||||
enabled-by: true
|
||||
features: c cprogram
|
||||
includes:
|
||||
- testsuites/fstests/fatfs_support
|
||||
ldflags: []
|
||||
links: []
|
||||
source:
|
||||
- testsuites/fstests/fsclose01/init.c
|
||||
stlib: []
|
||||
target: testsuites/fstests/fatfs_fsclose01.exe
|
||||
type: build
|
||||
use-after: []
|
||||
use-before:
|
||||
- testfatfs
|
||||
21
spec/build/testsuites/fstests/fatfsfserror.yml
Normal file
21
spec/build/testsuites/fstests/fatfsfserror.yml
Normal file
@@ -0,0 +1,21 @@
|
||||
SPDX-License-Identifier: CC-BY-SA-4.0 OR BSD-2-Clause
|
||||
build-type: test-program
|
||||
cflags: []
|
||||
copyrights:
|
||||
- Copyright (C) 2025 Sepehr Ganji <sepehrganji79@gmail.com>
|
||||
cppflags: []
|
||||
cxxflags: []
|
||||
enabled-by: true
|
||||
features: c cprogram
|
||||
includes:
|
||||
- testsuites/fstests/fatfs_support
|
||||
ldflags: []
|
||||
links: []
|
||||
source:
|
||||
- testsuites/fstests/fserror/test.c
|
||||
stlib: []
|
||||
target: testsuites/fstests/fatfs_fserror.exe
|
||||
type: build
|
||||
use-after: []
|
||||
use-before:
|
||||
- testfatfs
|
||||
21
spec/build/testsuites/fstests/fatfsfspatheval.yml
Normal file
21
spec/build/testsuites/fstests/fatfsfspatheval.yml
Normal file
@@ -0,0 +1,21 @@
|
||||
SPDX-License-Identifier: CC-BY-SA-4.0 OR BSD-2-Clause
|
||||
build-type: test-program
|
||||
cflags: []
|
||||
copyrights:
|
||||
- Copyright (C) 2025 Sepehr Ganji <sepehrganji79@gmail.com>
|
||||
cppflags: []
|
||||
cxxflags: []
|
||||
enabled-by: true
|
||||
features: c cprogram
|
||||
includes:
|
||||
- testsuites/fstests/fatfs_support
|
||||
ldflags: []
|
||||
links: []
|
||||
source:
|
||||
- testsuites/fstests/fspatheval/test.c
|
||||
stlib: []
|
||||
target: testsuites/fstests/fatfs_fspatheval.exe
|
||||
type: build
|
||||
use-after: []
|
||||
use-before:
|
||||
- testfatfs
|
||||
21
spec/build/testsuites/fstests/fatfsfsrdwr.yml
Normal file
21
spec/build/testsuites/fstests/fatfsfsrdwr.yml
Normal file
@@ -0,0 +1,21 @@
|
||||
SPDX-License-Identifier: CC-BY-SA-4.0 OR BSD-2-Clause
|
||||
build-type: test-program
|
||||
cflags: []
|
||||
copyrights:
|
||||
- Copyright (C) 2025 Sepehr Ganji <sepehrganji79@gmail.com>
|
||||
cppflags: []
|
||||
cxxflags: []
|
||||
enabled-by: true
|
||||
features: c cprogram
|
||||
includes:
|
||||
- testsuites/fstests/fatfs_support
|
||||
ldflags: []
|
||||
links: []
|
||||
source:
|
||||
- testsuites/fstests/fsrdwr/init.c
|
||||
stlib: []
|
||||
target: testsuites/fstests/fatfs_fsrdwr.exe
|
||||
type: build
|
||||
use-after: []
|
||||
use-before:
|
||||
- testfatfs
|
||||
21
spec/build/testsuites/fstests/fatfsfsrename.yml
Normal file
21
spec/build/testsuites/fstests/fatfsfsrename.yml
Normal file
@@ -0,0 +1,21 @@
|
||||
SPDX-License-Identifier: CC-BY-SA-4.0 OR BSD-2-Clause
|
||||
build-type: test-program
|
||||
cflags: []
|
||||
copyrights:
|
||||
- Copyright (C) 2025 Sepehr Ganji <sepehrganji79@gmail.com>
|
||||
cppflags: []
|
||||
cxxflags: []
|
||||
enabled-by: true
|
||||
features: c cprogram
|
||||
includes:
|
||||
- testsuites/fstests/fatfs_support
|
||||
ldflags: []
|
||||
links: []
|
||||
source:
|
||||
- testsuites/fstests/fsrename/test.c
|
||||
stlib: []
|
||||
target: testsuites/fstests/fatfs_fsrename.exe
|
||||
type: build
|
||||
use-after: []
|
||||
use-before:
|
||||
- testfatfs
|
||||
22
spec/build/testsuites/fstests/fatfsfsrenameexisting.yml
Normal file
22
spec/build/testsuites/fstests/fatfsfsrenameexisting.yml
Normal file
@@ -0,0 +1,22 @@
|
||||
SPDX-License-Identifier: CC-BY-SA-4.0 OR BSD-2-Clause
|
||||
build-type: test-program
|
||||
cflags: []
|
||||
copyrights:
|
||||
- Copyright (C) 2025 Sepehr Ganji <sepehrganji79@gmail.com>
|
||||
cppflags:
|
||||
- -DTEST_STATE_EXPECTED_FAIL=1
|
||||
cxxflags: []
|
||||
enabled-by: true
|
||||
features: c cprogram
|
||||
includes:
|
||||
- testsuites/fstests/fatfs_support
|
||||
ldflags: []
|
||||
links: []
|
||||
source:
|
||||
- testsuites/fstests/fsrenameexisting/test.c
|
||||
stlib: []
|
||||
target: testsuites/fstests/fatfs_fsrenameexisting.exe
|
||||
type: build
|
||||
use-after: []
|
||||
use-before:
|
||||
- testfatfs
|
||||
21
spec/build/testsuites/fstests/fatfsfsrenamelongname.yml
Normal file
21
spec/build/testsuites/fstests/fatfsfsrenamelongname.yml
Normal file
@@ -0,0 +1,21 @@
|
||||
SPDX-License-Identifier: CC-BY-SA-4.0 OR BSD-2-Clause
|
||||
build-type: test-program
|
||||
cflags: []
|
||||
copyrights:
|
||||
- Copyright (C) 2025 Sepehr Ganji <sepehrganji79@gmail.com>
|
||||
cppflags: []
|
||||
cxxflags: []
|
||||
enabled-by: true
|
||||
features: c cprogram
|
||||
includes:
|
||||
- testsuites/fstests/fatfs_support
|
||||
ldflags: []
|
||||
links: []
|
||||
source:
|
||||
- testsuites/fstests/fsrenamelongname/test.c
|
||||
stlib: []
|
||||
target: testsuites/fstests/fatfs_fsrenamelongname.exe
|
||||
type: build
|
||||
use-after: []
|
||||
use-before:
|
||||
- testfatfs
|
||||
22
spec/build/testsuites/fstests/fatfsfsrenamemaxlinks.yml
Normal file
22
spec/build/testsuites/fstests/fatfsfsrenamemaxlinks.yml
Normal file
@@ -0,0 +1,22 @@
|
||||
SPDX-License-Identifier: CC-BY-SA-4.0 OR BSD-2-Clause
|
||||
build-type: test-program
|
||||
cflags: []
|
||||
copyrights:
|
||||
- Copyright (C) 2025 Sepehr Ganji <sepehrganji79@gmail.com>
|
||||
cppflags:
|
||||
- -DTEST_STATE_EXPECTED_FAIL=1
|
||||
cxxflags: []
|
||||
enabled-by: true
|
||||
features: c cprogram
|
||||
includes:
|
||||
- testsuites/fstests/fatfs_support
|
||||
ldflags: []
|
||||
links: []
|
||||
source:
|
||||
- testsuites/fstests/fsrenamemaxlinks/test.c
|
||||
stlib: []
|
||||
target: testsuites/fstests/fatfs_fsrenamemaxlinks.exe
|
||||
type: build
|
||||
use-after: []
|
||||
use-before:
|
||||
- testfatfs
|
||||
21
spec/build/testsuites/fstests/fatfsfsrmdirparent.yml
Normal file
21
spec/build/testsuites/fstests/fatfsfsrmdirparent.yml
Normal file
@@ -0,0 +1,21 @@
|
||||
SPDX-License-Identifier: CC-BY-SA-4.0 OR BSD-2-Clause
|
||||
build-type: test-program
|
||||
cflags: []
|
||||
copyrights:
|
||||
- Copyright (C) 2025 Sepehr Ganji <sepehrganji79@gmail.com>
|
||||
cppflags: []
|
||||
cxxflags: []
|
||||
enabled-by: true
|
||||
features: c cprogram
|
||||
includes:
|
||||
- testsuites/fstests/fatfs_support
|
||||
ldflags: []
|
||||
links: []
|
||||
source:
|
||||
- testsuites/fstests/fsrmdirparent/test.c
|
||||
stlib: []
|
||||
target: testsuites/fstests/fatfs_fsrmdirparent.exe
|
||||
type: build
|
||||
use-after: []
|
||||
use-before:
|
||||
- testfatfs
|
||||
21
spec/build/testsuites/fstests/fatfsfsscandir01.yml
Normal file
21
spec/build/testsuites/fstests/fatfsfsscandir01.yml
Normal file
@@ -0,0 +1,21 @@
|
||||
SPDX-License-Identifier: CC-BY-SA-4.0 OR BSD-2-Clause
|
||||
build-type: test-program
|
||||
cflags: []
|
||||
copyrights:
|
||||
- Copyright (C) 2025 Sepehr Ganji <sepehrganji79@gmail.com>
|
||||
cppflags: []
|
||||
cxxflags: []
|
||||
enabled-by: true
|
||||
features: c cprogram
|
||||
includes:
|
||||
- testsuites/fstests/fatfs_support
|
||||
ldflags: []
|
||||
links: []
|
||||
source:
|
||||
- testsuites/fstests/fsscandir01/init.c
|
||||
stlib: []
|
||||
target: testsuites/fstests/fatfs_fsscandir01.exe
|
||||
type: build
|
||||
use-after: []
|
||||
use-before:
|
||||
- testfatfs
|
||||
21
spec/build/testsuites/fstests/fatfsfsstatvfs.yml
Normal file
21
spec/build/testsuites/fstests/fatfsfsstatvfs.yml
Normal file
@@ -0,0 +1,21 @@
|
||||
SPDX-License-Identifier: CC-BY-SA-4.0 OR BSD-2-Clause
|
||||
build-type: test-program
|
||||
cflags: []
|
||||
copyrights:
|
||||
- Copyright (C) 2025 Sepehr Ganji <sepehrganji79@gmail.com>
|
||||
cppflags: []
|
||||
cxxflags: []
|
||||
enabled-by: true
|
||||
features: c cprogram
|
||||
includes:
|
||||
- testsuites/fstests/fatfs_support
|
||||
ldflags: []
|
||||
links: []
|
||||
source:
|
||||
- testsuites/fstests/fsstatvfs/test.c
|
||||
stlib: []
|
||||
target: testsuites/fstests/fatfs_fsstatvfs.exe
|
||||
type: build
|
||||
use-after: []
|
||||
use-before:
|
||||
- testfatfs
|
||||
21
spec/build/testsuites/fstests/fatfsfstime.yml
Normal file
21
spec/build/testsuites/fstests/fatfsfstime.yml
Normal file
@@ -0,0 +1,21 @@
|
||||
SPDX-License-Identifier: CC-BY-SA-4.0 OR BSD-2-Clause
|
||||
build-type: test-program
|
||||
cflags: []
|
||||
copyrights:
|
||||
- Copyright (C) 2025 Sepehr Ganji <sepehrganji79@gmail.com>
|
||||
cppflags: []
|
||||
cxxflags: []
|
||||
enabled-by: true
|
||||
features: c cprogram
|
||||
includes:
|
||||
- testsuites/fstests/fatfs_support
|
||||
ldflags: []
|
||||
links: []
|
||||
source:
|
||||
- testsuites/fstests/fstime/test.c
|
||||
stlib: []
|
||||
target: testsuites/fstests/fatfs_fstime.exe
|
||||
type: build
|
||||
use-after: []
|
||||
use-before:
|
||||
- testfatfs
|
||||
19
spec/build/testsuites/fstests/fsfatfsformat01.yml
Normal file
19
spec/build/testsuites/fstests/fsfatfsformat01.yml
Normal file
@@ -0,0 +1,19 @@
|
||||
SPDX-License-Identifier: CC-BY-SA-4.0 OR BSD-2-Clause
|
||||
build-type: test-program
|
||||
cflags: []
|
||||
copyrights:
|
||||
- Copyright (C) 2025 Sepehr Ganji <sepehrganji79@gmail.com>
|
||||
cppflags: []
|
||||
cxxflags: []
|
||||
enabled-by: true
|
||||
features: c cprogram
|
||||
includes: []
|
||||
ldflags: []
|
||||
links: []
|
||||
source:
|
||||
- testsuites/fstests/fsfatfsformat01/init.c
|
||||
stlib: []
|
||||
target: testsuites/fstests/fsfatfsformat01.exe
|
||||
type: build
|
||||
use-after: []
|
||||
use-before: []
|
||||
19
spec/build/testsuites/fstests/fsfatfssync01.yml
Normal file
19
spec/build/testsuites/fstests/fsfatfssync01.yml
Normal file
@@ -0,0 +1,19 @@
|
||||
SPDX-License-Identifier: CC-BY-SA-4.0 OR BSD-2-Clause
|
||||
build-type: test-program
|
||||
cflags: []
|
||||
copyrights:
|
||||
- Copyright (C) 2025 Sepehr Ganji <sepehrganji79@gmail.com>
|
||||
cppflags: []
|
||||
cxxflags: []
|
||||
enabled-by: true
|
||||
features: c cprogram
|
||||
includes: []
|
||||
ldflags: []
|
||||
links: []
|
||||
source:
|
||||
- testsuites/fstests/fsfatfssync01/init.c
|
||||
stlib: []
|
||||
target: testsuites/fstests/fsfatfssync01.exe
|
||||
type: build
|
||||
use-after: []
|
||||
use-before: []
|
||||
@@ -27,6 +27,8 @@ links:
|
||||
uid: libmimfs
|
||||
- role: build-dependency
|
||||
uid: librfs
|
||||
- role: build-dependency
|
||||
uid: libfatfs
|
||||
- role: build-dependency
|
||||
uid: fsbdpart01
|
||||
- role: build-dependency
|
||||
@@ -41,6 +43,8 @@ links:
|
||||
uid: fsdosfssync01
|
||||
- role: build-dependency
|
||||
uid: fsdosfswrite01
|
||||
- role: build-dependency
|
||||
uid: fsfatfssync01
|
||||
- role: build-dependency
|
||||
uid: fsfseeko01
|
||||
- role: build-dependency
|
||||
@@ -221,6 +225,32 @@ links:
|
||||
uid: mrfsfstime
|
||||
- role: build-dependency
|
||||
uid: tftpfs
|
||||
- role: build-dependency
|
||||
uid: fsfatfsformat01
|
||||
- role: build-dependency
|
||||
uid: fatfsfsrdwr
|
||||
- role: build-dependency
|
||||
uid: fatfsfserror
|
||||
- role: build-dependency
|
||||
uid: fatfsfspatheval
|
||||
- role: build-dependency
|
||||
uid: fatfsfsrename
|
||||
- role: build-dependency
|
||||
uid: fatfsfsrenameexisting
|
||||
- role: build-dependency
|
||||
uid: fatfsfsrenamelongname
|
||||
- role: build-dependency
|
||||
uid: fatfsfsrenamemaxlinks
|
||||
- role: build-dependency
|
||||
uid: fatfsfsrmdirparent
|
||||
- role: build-dependency
|
||||
uid: fatfsfsscandir01
|
||||
- role: build-dependency
|
||||
uid: fatfsfsstatvfs
|
||||
- role: build-dependency
|
||||
uid: fatfsfstime
|
||||
- role: build-dependency
|
||||
uid: fatfsfsclose01
|
||||
type: build
|
||||
use-after: []
|
||||
use-before:
|
||||
|
||||
19
spec/build/testsuites/fstests/libfatfs.yml
Normal file
19
spec/build/testsuites/fstests/libfatfs.yml
Normal file
@@ -0,0 +1,19 @@
|
||||
SPDX-License-Identifier: CC-BY-SA-4.0 OR BSD-2-Clause
|
||||
build-type: library
|
||||
cflags: []
|
||||
copyrights:
|
||||
- Copyright (C) 2025 Sepehr Ganji <sepehrganji79@gmail.com>
|
||||
cppflags: []
|
||||
cxxflags: []
|
||||
enabled-by: true
|
||||
includes:
|
||||
- testsuites/fstests/fatfs_support
|
||||
install: []
|
||||
install-path: null
|
||||
links: []
|
||||
source:
|
||||
- testsuites/fstests/fatfs_support/fs_support.c
|
||||
- testsuites/fstests/support/fstest_support.c
|
||||
- testsuites/fstests/support/ramdisk_support.c
|
||||
target: testfatfs
|
||||
type: build
|
||||
34
testsuites/fstests/fatfs_support/fs_config.h
Normal file
34
testsuites/fstests/fatfs_support/fs_config.h
Normal file
@@ -0,0 +1,34 @@
|
||||
/* SPDX-License-Identifier: BSD-2-Clause */
|
||||
|
||||
/*
|
||||
* COPYRIGHT (c) 2025 Sepehr Ganji <sepehrganji79@gmail.com>
|
||||
* On-Line Applications Research Corporation (OAR).
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef __FATFS_SUPPORT_h
|
||||
#define __FATFS_SUPPORT_h
|
||||
|
||||
#define FILESYSTEM "FATFS"
|
||||
|
||||
#endif
|
||||
183
testsuites/fstests/fatfs_support/fs_support.c
Normal file
183
testsuites/fstests/fatfs_support/fs_support.c
Normal file
@@ -0,0 +1,183 @@
|
||||
/* SPDX-License-Identifier: BSD-2-Clause */
|
||||
|
||||
/*
|
||||
* COPYRIGHT (c) 2025 Sepehr Ganji <sepehrganji79@gmail.com>
|
||||
* On-Line Applications Research Corporation (OAR).
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
#include <tmacros.h>
|
||||
|
||||
#include <rtems/fatfs.h>
|
||||
#include <rtems/libcsupport.h>
|
||||
#include <rtems/libio.h>
|
||||
|
||||
#include "fs_config.h"
|
||||
#include "fstest.h"
|
||||
#include "fstest_support.h"
|
||||
#include "ramdisk_support.h"
|
||||
|
||||
/* Include FatFS headers - these are internal to the FatFS implementation */
|
||||
extern int fatfs_diskio_register_device(
|
||||
unsigned char pdrv,
|
||||
const char *device_path
|
||||
);
|
||||
extern void fatfs_diskio_unregister_device( unsigned char pdrv );
|
||||
|
||||
/* FatFS constants and structures */
|
||||
#define FR_OK 0
|
||||
#define FM_FAT 0x01
|
||||
#define FM_FAT32 0x02
|
||||
|
||||
typedef struct {
|
||||
unsigned char fmt;
|
||||
unsigned char num_fat;
|
||||
unsigned int align;
|
||||
unsigned int n_root;
|
||||
unsigned long auto_cluster_size;
|
||||
} mkfs_parm;
|
||||
|
||||
typedef unsigned char FRESULT;
|
||||
|
||||
/* FatFS function declaration */
|
||||
extern FRESULT f_mkfs(
|
||||
const char *path,
|
||||
const mkfs_parm *opt,
|
||||
void *work,
|
||||
unsigned int len
|
||||
);
|
||||
|
||||
#define BLOCK_SIZE 512
|
||||
|
||||
static const mkfs_parm fatfs_format_options = {
|
||||
.fmt = FM_FAT, /* Format as FAT12/16 (auto-detect) */
|
||||
.num_fat = 2, /* Number of FAT copies */
|
||||
.align = 0, /* Auto data area alignment */
|
||||
.n_root = 512, /* Number of root directory entries for FAT12/16 */
|
||||
.auto_cluster_size = 0 /* Auto cluster size */
|
||||
};
|
||||
|
||||
static rtems_resource_snapshot before_mount;
|
||||
static unsigned char fatfs_work_buffer[ 4096 ]; /* Work buffer for f_mkfs() */
|
||||
|
||||
static int fatfs_format_disk( const char *device_path )
|
||||
{
|
||||
FRESULT fr;
|
||||
int rc;
|
||||
|
||||
rc = fatfs_diskio_register_device( 0, device_path );
|
||||
if ( rc != 0 ) {
|
||||
printf( "Device registration failed: %d\n", rc );
|
||||
return -1;
|
||||
}
|
||||
|
||||
fr = f_mkfs(
|
||||
"0:",
|
||||
&fatfs_format_options,
|
||||
fatfs_work_buffer,
|
||||
sizeof( fatfs_work_buffer )
|
||||
);
|
||||
if ( fr != FR_OK ) {
|
||||
printf( "FatFS formatting failed: %d\n", fr );
|
||||
fatfs_diskio_unregister_device( 0 );
|
||||
return -1;
|
||||
}
|
||||
|
||||
fatfs_diskio_unregister_device( 0 );
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void test_initialize_filesystem( void )
|
||||
{
|
||||
int rc = 0;
|
||||
|
||||
rc = mkdir( BASE_FOR_TEST, S_IRWXU | S_IRWXG | S_IRWXO );
|
||||
rtems_test_assert( rc == 0 );
|
||||
|
||||
init_ramdisk();
|
||||
|
||||
rc = fatfs_format_disk( RAMDISK_PATH );
|
||||
rtems_test_assert( rc == 0 );
|
||||
|
||||
rtems_resource_snapshot_take( &before_mount );
|
||||
|
||||
rc = mount(
|
||||
RAMDISK_PATH,
|
||||
BASE_FOR_TEST,
|
||||
"fatfs",
|
||||
RTEMS_FILESYSTEM_READ_WRITE,
|
||||
NULL
|
||||
);
|
||||
if ( rc != 0 ) {
|
||||
printf( "Mount failed with errno: %s\n", strerror( errno ) );
|
||||
}
|
||||
rtems_test_assert( rc == 0 );
|
||||
}
|
||||
|
||||
void test_shutdown_filesystem( void )
|
||||
{
|
||||
int rc = 0;
|
||||
rc = unmount( BASE_FOR_TEST );
|
||||
|
||||
if ( rc != 0 ) {
|
||||
printf( "Unmount failed with errno: %d (%s)\n", errno, strerror( errno ) );
|
||||
} else {
|
||||
printf( "Unmount successful!\n" );
|
||||
}
|
||||
rtems_test_assert( rc == 0 );
|
||||
rtems_test_assert( rtems_resource_snapshot_check( &before_mount ) );
|
||||
del_ramdisk();
|
||||
}
|
||||
|
||||
/* configuration information */
|
||||
|
||||
/* drivers */
|
||||
#define CONFIGURE_APPLICATION_NEEDS_CLOCK_DRIVER
|
||||
#define CONFIGURE_APPLICATION_NEEDS_SIMPLE_CONSOLE_DRIVER
|
||||
|
||||
/**
|
||||
* Configure base RTEMS resources.
|
||||
*/
|
||||
|
||||
#define CONFIGURE_INITIAL_EXTENSIONS RTEMS_TEST_INITIAL_EXTENSION
|
||||
|
||||
#define CONFIGURE_RTEMS_INIT_TASKS_TABLE
|
||||
|
||||
#define CONFIGURE_MAXIMUM_SEMAPHORES 10
|
||||
#define CONFIGURE_MAXIMUM_TASKS 10
|
||||
#define CONFIGURE_MAXIMUM_FILE_DESCRIPTORS 40
|
||||
#define CONFIGURE_INIT_TASK_STACK_SIZE ( 16 * 1024 )
|
||||
#define CONFIGURE_INIT_TASK_ATTRIBUTES RTEMS_FLOATING_POINT
|
||||
|
||||
#define CONFIGURE_APPLICATION_NEEDS_LIBBLOCK
|
||||
|
||||
#define CONFIGURE_FILESYSTEM_FATFS
|
||||
|
||||
#define CONFIGURE_INIT
|
||||
#include <rtems/confdefs.h>
|
||||
@@ -547,7 +547,7 @@ static void test_close(test_context *ctx)
|
||||
rtems_test_assert(rv == -1);
|
||||
rtems_test_assert(errno == EBADF);
|
||||
flags = rtems_libio_iop_flags(iop);
|
||||
expected_flags = LIBIO_FLAGS_READ_WRITE;
|
||||
expected_flags = LIBIO_FLAGS_REFERENCE_INC | LIBIO_FLAGS_READ_WRITE;
|
||||
rtems_test_assert(flags == expected_flags);
|
||||
rtems_test_assert((iops_free - 1) == free_iops());
|
||||
break;
|
||||
|
||||
445
testsuites/fstests/fsfatfsformat01/init.c
Normal file
445
testsuites/fstests/fsfatfsformat01/init.c
Normal file
@@ -0,0 +1,445 @@
|
||||
/* SPDX-License-Identifier: BSD-2-Clause */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2025 Sepehr Ganji <sepehrganji79@gmail.com>
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <inttypes.h>
|
||||
#include <stdio.h>
|
||||
#include <sys/statvfs.h>
|
||||
|
||||
#include <rtems/blkdev.h>
|
||||
#include <rtems/libio.h>
|
||||
#include <rtems/sparse-disk.h>
|
||||
|
||||
#include <bsp.h>
|
||||
|
||||
#include "tmacros.h"
|
||||
|
||||
const char rtems_test_name[] = "FSFATFSFORMAT 1";
|
||||
|
||||
#define MAX_PATH_LENGTH 100
|
||||
#define SECTOR_SIZE 512
|
||||
#define FAT12_MAX_CLN 4085
|
||||
#define FAT16_MAX_CLN 65525
|
||||
#define FAT12_DEFAULT_SECTORS_PER_CLUSTER 8
|
||||
#define FAT16_DEFAULT_SECTORS_PER_CLUSTER 32
|
||||
|
||||
/* FatFS constants and structures */
|
||||
#define FR_OK 0
|
||||
#define FR_INVALID_PARAMETER 19
|
||||
#define FM_FAT 0x01
|
||||
#define FM_FAT32 0x02
|
||||
#define FM_ANY 0x07
|
||||
|
||||
typedef struct {
|
||||
unsigned char fmt;
|
||||
unsigned char num_fat;
|
||||
unsigned int align;
|
||||
unsigned int n_root;
|
||||
unsigned long auto_cluster_size;
|
||||
} mkfs_parm;
|
||||
|
||||
/* FatFS MKFS_PARM structure for proper parameter passing */
|
||||
typedef struct {
|
||||
unsigned char fmt; /* Format option (FM_FAT, FM_FAT32, etc.) */
|
||||
unsigned char n_fat; /* Number of FATs */
|
||||
unsigned int align; /* Data area alignment (sector) */
|
||||
unsigned int n_root; /* Number of root directory entries */
|
||||
unsigned long au_size; /* Cluster size (byte) */
|
||||
} MKFS_PARM;
|
||||
|
||||
typedef unsigned char FRESULT;
|
||||
|
||||
extern int fatfs_diskio_register_device(
|
||||
unsigned char pdrv,
|
||||
const char *device_path
|
||||
);
|
||||
extern void fatfs_diskio_unregister_device( unsigned char pdrv );
|
||||
extern FRESULT f_mkfs(
|
||||
const char *path,
|
||||
const MKFS_PARM *opt,
|
||||
void *work,
|
||||
unsigned int len
|
||||
);
|
||||
|
||||
static unsigned char fatfs_work_buffer[ 4096 ];
|
||||
|
||||
static int fatfs_format_disk(
|
||||
const char *device_path,
|
||||
const mkfs_parm *format_options
|
||||
)
|
||||
{
|
||||
FRESULT fr;
|
||||
int rc;
|
||||
MKFS_PARM fatfs_opts;
|
||||
|
||||
rc = fatfs_diskio_register_device( 0, device_path );
|
||||
if ( rc != 0 ) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Convert test structure to FatFS structure */
|
||||
fatfs_opts.fmt = format_options->fmt;
|
||||
fatfs_opts.n_fat = format_options->num_fat;
|
||||
fatfs_opts.align = format_options->align;
|
||||
fatfs_opts.n_root = format_options->n_root;
|
||||
fatfs_opts.au_size = format_options->auto_cluster_size *
|
||||
512; /* Convert sectors to bytes */
|
||||
|
||||
fr = f_mkfs(
|
||||
"0:",
|
||||
&fatfs_opts,
|
||||
fatfs_work_buffer,
|
||||
sizeof( fatfs_work_buffer )
|
||||
);
|
||||
|
||||
fatfs_diskio_unregister_device( 0 );
|
||||
|
||||
return ( fr == FR_OK ) ? 0 : -1;
|
||||
}
|
||||
|
||||
static void test_disk_params(
|
||||
const char *dev_name,
|
||||
const char *mount_dir,
|
||||
const blksize_t sector_size,
|
||||
const blksize_t cluster_size,
|
||||
const blkcnt_t sectors_per_cluster
|
||||
)
|
||||
{
|
||||
int rv;
|
||||
int fildes;
|
||||
struct stat stat_buff;
|
||||
char file_name[ MAX_PATH_LENGTH + 1 ];
|
||||
ssize_t num_bytes;
|
||||
unsigned int value = (unsigned int) -1;
|
||||
|
||||
snprintf( file_name, MAX_PATH_LENGTH, "%s/file1.txt", mount_dir );
|
||||
memset( &stat_buff, 0, sizeof( stat_buff ) );
|
||||
|
||||
rv = mount( dev_name, mount_dir, "fatfs", RTEMS_FILESYSTEM_READ_WRITE, NULL );
|
||||
rtems_test_assert( 0 == rv );
|
||||
|
||||
fildes = open(
|
||||
file_name,
|
||||
O_RDWR | O_CREAT | O_TRUNC,
|
||||
S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH
|
||||
);
|
||||
rtems_test_assert( -1 != fildes );
|
||||
|
||||
num_bytes = write( fildes, &value, sizeof( value ) );
|
||||
rtems_test_assert( sizeof( value ) == num_bytes );
|
||||
|
||||
rv = fstat( fildes, &stat_buff );
|
||||
rtems_test_assert( 0 == rv );
|
||||
rtems_test_assert( S_ISREG( stat_buff.st_mode ) );
|
||||
rtems_test_assert( sizeof( value ) == stat_buff.st_size );
|
||||
rtems_test_assert( cluster_size == stat_buff.st_blksize );
|
||||
rtems_test_assert(
|
||||
sectors_per_cluster == ( stat_buff.st_blocks * sector_size / 512 )
|
||||
);
|
||||
rtems_test_assert(
|
||||
( ( ( stat_buff.st_size + cluster_size - 1 ) / cluster_size ) *
|
||||
cluster_size / 512 ) == stat_buff.st_blocks
|
||||
);
|
||||
rv = close( fildes );
|
||||
rtems_test_assert( 0 == rv );
|
||||
|
||||
rv = unmount( mount_dir );
|
||||
rtems_test_assert( 0 == rv );
|
||||
|
||||
rv = mount( dev_name, mount_dir, "fatfs", RTEMS_FILESYSTEM_READ_WRITE, NULL );
|
||||
rtems_test_assert( 0 == rv );
|
||||
|
||||
rv = unmount( mount_dir );
|
||||
rtems_test_assert( 0 == rv );
|
||||
}
|
||||
|
||||
static void test_create_file(
|
||||
const char *mount_dir,
|
||||
uint32_t file_idx,
|
||||
bool expect_ok
|
||||
)
|
||||
{
|
||||
char file_name[ MAX_PATH_LENGTH + 1 ];
|
||||
int fd;
|
||||
|
||||
snprintf(
|
||||
file_name,
|
||||
MAX_PATH_LENGTH,
|
||||
"%s/file%" PRIu32 ".txt",
|
||||
mount_dir,
|
||||
file_idx
|
||||
);
|
||||
fd = open(
|
||||
file_name,
|
||||
O_RDWR | O_CREAT | O_TRUNC,
|
||||
S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH
|
||||
);
|
||||
|
||||
if ( expect_ok ) {
|
||||
int rv;
|
||||
|
||||
rtems_test_assert( fd >= 0 );
|
||||
|
||||
rv = close( fd );
|
||||
rtems_test_assert( rv == 0 );
|
||||
} else {
|
||||
rtems_test_assert( fd == -1 );
|
||||
}
|
||||
}
|
||||
|
||||
static void test_file_creation(
|
||||
const char *dev_name,
|
||||
const char *mount_dir,
|
||||
const uint32_t number_of_files
|
||||
)
|
||||
{
|
||||
int rv;
|
||||
uint32_t file_idx;
|
||||
char file_name[ MAX_PATH_LENGTH + 1 ];
|
||||
|
||||
rv = mount( dev_name, mount_dir, "fatfs", RTEMS_FILESYSTEM_READ_WRITE, NULL );
|
||||
rtems_test_assert( 0 == rv );
|
||||
|
||||
for ( file_idx = 0; file_idx < number_of_files; ++file_idx ) {
|
||||
test_create_file( mount_dir, file_idx, true );
|
||||
}
|
||||
|
||||
test_create_file( mount_dir, file_idx, false );
|
||||
|
||||
for ( file_idx = 0; file_idx < number_of_files; ++file_idx ) {
|
||||
snprintf(
|
||||
file_name,
|
||||
MAX_PATH_LENGTH,
|
||||
"%s/file%" PRIu32 ".txt",
|
||||
mount_dir,
|
||||
file_idx
|
||||
);
|
||||
rv = unlink( file_name );
|
||||
rtems_test_assert( 0 == rv );
|
||||
}
|
||||
|
||||
rv = unmount( mount_dir );
|
||||
rtems_test_assert( 0 == rv );
|
||||
}
|
||||
|
||||
static void test( void )
|
||||
{
|
||||
rtems_status_code sc;
|
||||
int rv;
|
||||
const char dev_name[] = "/dev/rda";
|
||||
const char mount_dir[] = "/mnt";
|
||||
mkfs_parm rqdata;
|
||||
rtems_blkdev_bnum media_block_count;
|
||||
|
||||
memset( &rqdata, 0, sizeof( rqdata ) );
|
||||
|
||||
rv = mkdir( mount_dir, S_IRWXU | S_IRWXG | S_IRWXO );
|
||||
rtems_test_assert( 0 == rv );
|
||||
|
||||
/* FAT12 */
|
||||
/* For 1.44 MB disks */
|
||||
sc = rtems_sparse_disk_create_and_register(
|
||||
dev_name,
|
||||
SECTOR_SIZE,
|
||||
64,
|
||||
2880,
|
||||
0
|
||||
);
|
||||
rtems_test_assert( RTEMS_SUCCESSFUL == sc );
|
||||
|
||||
/* Optimized for disk space */
|
||||
rqdata.fmt = FM_FAT;
|
||||
rqdata.num_fat = 1;
|
||||
rqdata.align = 0;
|
||||
rqdata.n_root = 32;
|
||||
rqdata.auto_cluster_size = 1;
|
||||
rv = fatfs_format_disk( dev_name, &rqdata );
|
||||
rtems_test_assert( rv == 0 );
|
||||
test_disk_params( dev_name, mount_dir, SECTOR_SIZE, SECTOR_SIZE, 1 );
|
||||
test_file_creation( dev_name, mount_dir, rqdata.n_root );
|
||||
|
||||
/* FatFS silently clamps invalid parameters rather than returning errors,
|
||||
* so we skip this test as it doesn't match FatFS behavior */
|
||||
|
||||
/* Optimized for read/write speed */
|
||||
rqdata.fmt = FM_FAT;
|
||||
rqdata.num_fat = 2;
|
||||
rqdata.align = 0;
|
||||
rqdata.n_root = 0;
|
||||
rqdata.auto_cluster_size = 8;
|
||||
rv = fatfs_format_disk( dev_name, &rqdata );
|
||||
rtems_test_assert( rv == 0 );
|
||||
test_disk_params( dev_name, mount_dir, SECTOR_SIZE, SECTOR_SIZE * 8, 8 );
|
||||
|
||||
rv = unlink( dev_name );
|
||||
rtems_test_assert( rv == 0 );
|
||||
|
||||
/* Largest FAT12 disk */
|
||||
sc = rtems_sparse_disk_create_and_register(
|
||||
dev_name,
|
||||
SECTOR_SIZE,
|
||||
64,
|
||||
( FAT12_MAX_CLN * FAT12_DEFAULT_SECTORS_PER_CLUSTER ) - 1L,
|
||||
0
|
||||
);
|
||||
rtems_test_assert( RTEMS_SUCCESSFUL == sc );
|
||||
|
||||
/* Default parameters - let FatFS choose cluster size */
|
||||
rqdata.fmt = FM_FAT;
|
||||
rqdata.num_fat = 2;
|
||||
rqdata.align = 0;
|
||||
rqdata.n_root = 512;
|
||||
rqdata.auto_cluster_size = 0;
|
||||
rv = fatfs_format_disk( dev_name, &rqdata );
|
||||
rtems_test_assert( rv == 0 );
|
||||
/* FatFS chooses cluster size based on volume size, so test actual result */
|
||||
test_disk_params(
|
||||
dev_name,
|
||||
mount_dir,
|
||||
SECTOR_SIZE,
|
||||
SECTOR_SIZE * 4, /* FatFS actually chooses 4 sectors per cluster */
|
||||
4
|
||||
);
|
||||
|
||||
rv = unlink( dev_name );
|
||||
rtems_test_assert( rv == 0 );
|
||||
|
||||
/* FAT16 */
|
||||
sc = rtems_sparse_disk_create_and_register(
|
||||
dev_name,
|
||||
SECTOR_SIZE,
|
||||
1024,
|
||||
( FAT12_MAX_CLN * FAT12_DEFAULT_SECTORS_PER_CLUSTER ) + 1L,
|
||||
0
|
||||
);
|
||||
rtems_test_assert( RTEMS_SUCCESSFUL == sc );
|
||||
|
||||
/* Optimized for disk space */
|
||||
rqdata.fmt = FM_FAT;
|
||||
rqdata.num_fat = 1;
|
||||
rqdata.align = 0;
|
||||
rqdata.n_root = 32;
|
||||
rqdata.auto_cluster_size = 1;
|
||||
rv = fatfs_format_disk( dev_name, &rqdata );
|
||||
rtems_test_assert( rv == 0 );
|
||||
test_disk_params( dev_name, mount_dir, SECTOR_SIZE, SECTOR_SIZE, 1 );
|
||||
|
||||
rv = unlink( dev_name );
|
||||
rtems_test_assert( rv == 0 );
|
||||
|
||||
/* FAT32 */
|
||||
sc = rtems_sparse_disk_create_and_register(
|
||||
dev_name,
|
||||
SECTOR_SIZE,
|
||||
1024,
|
||||
( FAT16_MAX_CLN * FAT16_DEFAULT_SECTORS_PER_CLUSTER ) + 41L,
|
||||
0
|
||||
);
|
||||
rtems_test_assert( RTEMS_SUCCESSFUL == sc );
|
||||
|
||||
/* Default parameters - FAT32 chooses larger cluster sizes */
|
||||
rqdata.fmt = FM_FAT32;
|
||||
rqdata.num_fat = 2;
|
||||
rqdata.align = 0;
|
||||
rqdata.n_root = 0;
|
||||
rqdata.auto_cluster_size = 0;
|
||||
rv = fatfs_format_disk( dev_name, &rqdata );
|
||||
rtems_test_assert( rv == 0 );
|
||||
test_disk_params( dev_name, mount_dir, SECTOR_SIZE, SECTOR_SIZE * 16, 16 );
|
||||
|
||||
rv = unlink( dev_name );
|
||||
rtems_test_assert( rv == 0 );
|
||||
|
||||
/* Format some disks from 1MB up to 128GB - let FatFS choose appropriate FAT
|
||||
* type */
|
||||
rqdata.fmt = FM_ANY;
|
||||
rqdata.num_fat = 2;
|
||||
rqdata.align = 0;
|
||||
rqdata.n_root = 0;
|
||||
rqdata.auto_cluster_size = 64;
|
||||
for ( media_block_count = 1 * 1024 * ( 1024 / SECTOR_SIZE );
|
||||
media_block_count <= 128 * 1024 * 1024 * ( 1024 / SECTOR_SIZE );
|
||||
media_block_count *= 2 ) {
|
||||
sc = rtems_sparse_disk_create_and_register(
|
||||
dev_name,
|
||||
SECTOR_SIZE,
|
||||
64,
|
||||
media_block_count,
|
||||
0
|
||||
);
|
||||
rtems_test_assert( sc == RTEMS_SUCCESSFUL );
|
||||
|
||||
rv = fatfs_format_disk( dev_name, &rqdata );
|
||||
rtems_test_assert( rv == 0 );
|
||||
|
||||
test_disk_params( dev_name, mount_dir, SECTOR_SIZE, SECTOR_SIZE * 64, 64 );
|
||||
|
||||
rv = unlink( dev_name );
|
||||
rtems_test_assert( rv == 0 );
|
||||
}
|
||||
}
|
||||
|
||||
static void Init( rtems_task_argument arg )
|
||||
{
|
||||
(void) arg;
|
||||
|
||||
TEST_BEGIN();
|
||||
|
||||
test();
|
||||
|
||||
TEST_END();
|
||||
rtems_test_exit( 0 );
|
||||
}
|
||||
|
||||
#define CONFIGURE_APPLICATION_NEEDS_CLOCK_DRIVER
|
||||
#define CONFIGURE_APPLICATION_NEEDS_SIMPLE_CONSOLE_DRIVER
|
||||
#define CONFIGURE_APPLICATION_NEEDS_LIBBLOCK
|
||||
|
||||
#define CONFIGURE_MAXIMUM_FILE_DESCRIPTORS 5
|
||||
|
||||
#define CONFIGURE_FILESYSTEM_FATFS
|
||||
|
||||
#define CONFIGURE_MAXIMUM_TASKS 1
|
||||
#define CONFIGURE_MAXIMUM_SEMAPHORES 10
|
||||
|
||||
#define CONFIGURE_INIT_TASK_STACK_SIZE ( 32 * 1024 )
|
||||
|
||||
#define CONFIGURE_INITIAL_EXTENSIONS RTEMS_TEST_INITIAL_EXTENSION
|
||||
|
||||
#define CONFIGURE_RTEMS_INIT_TASKS_TABLE
|
||||
|
||||
#define CONFIGURE_INIT_TASK_ATTRIBUTES RTEMS_FLOATING_POINT
|
||||
|
||||
#define CONFIGURE_BDBUF_BUFFER_MAX_SIZE ( 32 * 1024 )
|
||||
|
||||
#define CONFIGURE_INIT
|
||||
|
||||
#include <rtems/confdefs.h>
|
||||
17
testsuites/fstests/fsfatfssync01/fsfatfssync01.doc
Normal file
17
testsuites/fstests/fsfatfssync01/fsfatfssync01.doc
Normal file
@@ -0,0 +1,17 @@
|
||||
This file documents the test fsfatfssync01.
|
||||
|
||||
test set name: fsfatfssync01
|
||||
|
||||
test purpose:
|
||||
Verify FatFS auto-sync behavior and explicit fsync() functionality.
|
||||
|
||||
test description:
|
||||
Tests FatFS's synchronization behavior by:
|
||||
- Creating a file and verifying it persists after disk cache purge
|
||||
- Writing data without explicit fsync() and verifying it persists after disk cache purge
|
||||
(demonstrates FatFS auto-syncs on file close)
|
||||
- Writing additional data with explicit fsync() and verifying it persists after disk cache purge
|
||||
|
||||
Note: Unlike traditional POSIX filesystems, FatFS automatically calls f_sync() during
|
||||
f_close(), ensuring all writes are immediately persisted to disk regardless of whether
|
||||
fsync() was explicitly called.
|
||||
237
testsuites/fstests/fsfatfssync01/init.c
Normal file
237
testsuites/fstests/fsfatfssync01/init.c
Normal file
@@ -0,0 +1,237 @@
|
||||
/* SPDX-License-Identifier: BSD-2-Clause */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2025 Sepehr Ganji <sepehrganji79@gmail.com>
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include <sys/stat.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <rtems/blkdev.h>
|
||||
#include <rtems/fatfs.h>
|
||||
#include <rtems/libio.h>
|
||||
#include <rtems/ramdisk.h>
|
||||
|
||||
#include "tmacros.h"
|
||||
|
||||
const char rtems_test_name[] = "FSFATFSSYNC 1";
|
||||
|
||||
/* FatFS constants and structures */
|
||||
#define FR_OK 0
|
||||
#define FM_FAT 0x01
|
||||
#define FM_FAT32 0x02
|
||||
|
||||
typedef struct {
|
||||
unsigned char fmt;
|
||||
unsigned char num_fat;
|
||||
unsigned int align;
|
||||
unsigned int n_root;
|
||||
unsigned long auto_cluster_size;
|
||||
} MKFS_PARM;
|
||||
|
||||
typedef unsigned char FRESULT;
|
||||
|
||||
/* External FatFS functions */
|
||||
extern int fatfs_diskio_register_device(
|
||||
unsigned char pdrv,
|
||||
const char *device_path
|
||||
);
|
||||
extern void fatfs_diskio_unregister_device( unsigned char pdrv );
|
||||
extern FRESULT f_mkfs(
|
||||
const char *path,
|
||||
const MKFS_PARM *opt,
|
||||
void *work,
|
||||
unsigned int len
|
||||
);
|
||||
|
||||
static unsigned char fatfs_work_buffer[ 4096 ];
|
||||
|
||||
static void create_file( const char *file )
|
||||
{
|
||||
int fd;
|
||||
int rv;
|
||||
|
||||
fd = creat( file, S_IRWXU | S_IRWXG | S_IRWXO );
|
||||
rtems_test_assert( fd >= 0 );
|
||||
|
||||
rv = fsync( fd );
|
||||
rtems_test_assert( rv == 0 );
|
||||
|
||||
rv = close( fd );
|
||||
rtems_test_assert( rv == 0 );
|
||||
}
|
||||
|
||||
static void write_to_file( const char *file, bool sync )
|
||||
{
|
||||
int fd;
|
||||
char buf[ 1 ] = { 'A' };
|
||||
ssize_t n;
|
||||
off_t pos_before, pos_after;
|
||||
int rv;
|
||||
|
||||
fd = open( file, O_RDWR );
|
||||
rtems_test_assert( fd >= 0 );
|
||||
|
||||
pos_before = lseek( fd, 0, SEEK_END );
|
||||
|
||||
n = write( fd, buf, sizeof( buf ) );
|
||||
rtems_test_assert( n == (ssize_t) sizeof( buf ) );
|
||||
|
||||
pos_after = lseek( fd, 0, SEEK_END );
|
||||
rtems_test_assert( pos_after == pos_before + sizeof( buf ) );
|
||||
|
||||
if ( sync ) {
|
||||
rv = fsync( fd );
|
||||
rtems_test_assert( rv == 0 );
|
||||
}
|
||||
|
||||
rv = close( fd );
|
||||
rtems_test_assert( rv == 0 );
|
||||
}
|
||||
|
||||
static void check_file_size( const char *file, off_t size )
|
||||
{
|
||||
int fd;
|
||||
off_t pos;
|
||||
int rv;
|
||||
|
||||
fd = open( file, O_RDWR );
|
||||
rtems_test_assert( fd >= 0 );
|
||||
|
||||
pos = lseek( fd, 0, SEEK_END );
|
||||
rtems_test_assert( pos == size );
|
||||
|
||||
rv = close( fd );
|
||||
rtems_test_assert( rv == 0 );
|
||||
}
|
||||
|
||||
static void test( const char *rda, const char *mnt, const char *file )
|
||||
{
|
||||
static const MKFS_PARM fatfs_format_options = {
|
||||
.fmt = FM_FAT,
|
||||
.num_fat = 2,
|
||||
.align = 0,
|
||||
.n_root = 512,
|
||||
.auto_cluster_size = 0
|
||||
};
|
||||
|
||||
int disk_fd;
|
||||
int rv;
|
||||
FRESULT fr;
|
||||
|
||||
disk_fd = open( rda, O_RDWR );
|
||||
rtems_test_assert( disk_fd >= 0 );
|
||||
|
||||
rv = fatfs_diskio_register_device( 0, rda );
|
||||
rtems_test_assert( rv == 0 );
|
||||
|
||||
/* Format using FatFS */
|
||||
fr = f_mkfs(
|
||||
"0:",
|
||||
&fatfs_format_options,
|
||||
fatfs_work_buffer,
|
||||
sizeof( fatfs_work_buffer )
|
||||
);
|
||||
rtems_test_assert( fr == FR_OK );
|
||||
|
||||
fatfs_diskio_unregister_device( 0 );
|
||||
|
||||
rv = mount_and_make_target_path(
|
||||
rda,
|
||||
mnt,
|
||||
"fatfs",
|
||||
RTEMS_FILESYSTEM_READ_WRITE,
|
||||
NULL
|
||||
);
|
||||
rtems_test_assert( rv == 0 );
|
||||
|
||||
create_file( file );
|
||||
rv = rtems_disk_fd_purge( disk_fd );
|
||||
rtems_test_assert( rv == 0 );
|
||||
|
||||
write_to_file( file, false );
|
||||
rv = rtems_disk_fd_purge( disk_fd );
|
||||
rtems_test_assert( rv == 0 );
|
||||
check_file_size( file, 1 );
|
||||
|
||||
write_to_file( file, true );
|
||||
rv = rtems_disk_fd_purge( disk_fd );
|
||||
rtems_test_assert( rv == 0 );
|
||||
check_file_size( file, 2 );
|
||||
|
||||
rv = unmount( mnt );
|
||||
rtems_test_assert( rv == 0 );
|
||||
|
||||
rv = close( disk_fd );
|
||||
rtems_test_assert( rv == 0 );
|
||||
}
|
||||
|
||||
static void Init( rtems_task_argument arg )
|
||||
{
|
||||
(void) arg;
|
||||
|
||||
TEST_BEGIN();
|
||||
|
||||
test( "/dev/rda", "/mnt", "/mnt/file" );
|
||||
|
||||
TEST_END();
|
||||
rtems_test_exit( 0 );
|
||||
}
|
||||
|
||||
rtems_ramdisk_config rtems_ramdisk_configuration[] = {
|
||||
{ .block_size = 512, .block_num = 1024 }
|
||||
};
|
||||
|
||||
size_t rtems_ramdisk_configuration_size = 1;
|
||||
|
||||
#define CONFIGURE_APPLICATION_NEEDS_CLOCK_DRIVER
|
||||
#define CONFIGURE_APPLICATION_NEEDS_SIMPLE_CONSOLE_DRIVER
|
||||
#define CONFIGURE_APPLICATION_EXTRA_DRIVERS RAMDISK_DRIVER_TABLE_ENTRY
|
||||
#define CONFIGURE_APPLICATION_NEEDS_LIBBLOCK
|
||||
|
||||
#define CONFIGURE_MAXIMUM_FILE_DESCRIPTORS 6
|
||||
|
||||
#define CONFIGURE_FILESYSTEM_FATFS
|
||||
|
||||
#define CONFIGURE_MAXIMUM_TASKS 2
|
||||
|
||||
#define CONFIGURE_EXTRA_TASK_STACKS ( 8 * 1024 )
|
||||
|
||||
#define CONFIGURE_INITIAL_EXTENSIONS RTEMS_TEST_INITIAL_EXTENSION
|
||||
|
||||
#define CONFIGURE_RTEMS_INIT_TASKS_TABLE
|
||||
|
||||
#define CONFIGURE_INIT_TASK_ATTRIBUTES RTEMS_FLOATING_POINT
|
||||
|
||||
#define CONFIGURE_INIT
|
||||
|
||||
#include <rtems/confdefs.h>
|
||||
Reference in New Issue
Block a user