Code:
//============================================================================== // Copyright (c) 2013, Isaac Marino Bavaresco // All rights reserved // isaacbavaresco@yahoo.com.br //============================================================================== /*============================================================================*/ #include <asf.h> #include <stdio.h> #include <fcntl.h> #include <errno.h> #include <string.h> #include "FileIO.h" /*============================================================================*/ #define MAX_FILES 10 /*============================================================================*/ typedef struct { unsigned int Next; int Valid; FIL File; } files_t; /*============================================================================*/ #define HandleIsValid(h) ( (unsigned int)(h) < sizeof Files / sizeof Files[0] ) /*============================================================================*/ static files_t Files[MAX_FILES]; static unsigned int FreeList = 0; static unsigned int OpenFiles = -1; /*============================================================================*/ static int TranslateErrNo( FRESULT Result ) { switch( Result ) { default: case FR_INT_ERR: /* (2) Assertion failed */ case FR_NOT_READY: /* (3) The physical drive cannot work */ case FR_WRITE_PROTECTED: /* (10) The physical drive is write protected */ case FR_NOT_ENABLED: /* (12) The volume has no work area */ case FR_NO_FILESYSTEM: /* (13) There is no valid FAT volume */ case FR_MKFS_ABORTED: /* (14) The f_mkfs() aborted due to any parameter error */ case FR_TIMEOUT: /* (15) Could not get a grant to access the volume within defined period */ case FR_LOCKED: /* (16) The operation is rejected according to the file shareing policy */ case FR_NOT_ENOUGH_CORE: /* (17) LFN working buffer could not be allocated */ return ENOSPC; case FR_DISK_ERR: /* (1) A hard error occured in the low level disk I/O layer */ return EIO; case FR_NO_FILE: /* (4) Could not find the file */ case FR_NO_PATH: /* (5) Could not find the path */ return ENOENT; case FR_INVALID_NAME: /* (6) The path name format is invalid */ case FR_INVALID_OBJECT: /* (9) The file/directory object is invalid */ case FR_INVALID_DRIVE: /* (11) The logical drive number is invalid */ case FR_INVALID_PARAMETER: /* (19) Given parameter is invalid */ return EINVAL; case FR_DENIED: /* (7) Acces denied due to prohibited access or directory full */ return EACCES; case FR_EXIST: /* (8) Acces denied due to prohibited access */ return EEXIST; case FR_TOO_MANY_OPEN_FILES: /* (18) Number of open files > _FS_SHARE */ return ENFILE; } } /*============================================================================*/ int FileIOInit( void ) { int i; for( i = 0; i < sizeof Files / sizeof Files[0] - 1; i++ ) { memset( &Files[i], 0, sizeof Files[i] ); Files[i].Next = i + 1; } memset( &Files[i], 0, sizeof Files[i] ); Files[i].Next = -1; FreeList = 0; OpenFiles = -1; return 0; } /*============================================================================*/ int open( const char *path, int oflag, ... ) { FRESULT Result; int Handle, Flags = 0; if( !HandleIsValid( FreeList )) { errno = ENFILE; return EOF; } #if _FS_READONLY if( oflag & O_RDWR || oflag & O_WRONLY || oflag & O_CREAT ) { errno = EACCES; return EOF; } else Flags |= FA_READ; #else // _FS_READONLY if( oflag & O_RDWR ) Flags |= FA_READ | FA_WRITE; else if( oflag & O_WRONLY ) Flags |= FA_WRITE; else Flags |= FA_READ; if( oflag & O_CREAT ) if( oflag & O_EXCL ) Flags |= FA_CREATE_NEW; else Flags |= FA_CREATE_ALWAYS; #endif // _FS_READONLY Handle = FreeList; Result = f_open( &Files[Handle].File, path, Flags ); if( Result != FR_OK ) { errno = TranslateErrNo( Result ); return EOF; } FreeList = Files[FreeList].Next; Files[Handle].Next = OpenFiles; Files[Handle].Valid = 1; OpenFiles = Handle; errno = 0; return Handle; } /*============================================================================*/ int close( int fildes ) { FRESULT Result; int i, j; if( !HandleIsValid( fildes ) || !Files[fildes].Valid ) { errno = EBADF; return EOF; } Result = f_close( &Files[fildes].File ); if( OpenFiles == fildes ) OpenFiles = Files[fildes].Next; else { for( i = sizeof Files / sizeof Files[0], j = OpenFiles; i > 0 && Files[j].Next != fildes; i--, j = Files[j].Next ) {} /* Should always be true. Testing just for safety */ if( Files[j].Next == fildes ) Files[j].Next = Files[fildes].Next; } memset( &Files[fildes], 0, sizeof Files[fildes] ); Files[fildes].Next = FreeList; FreeList = fildes; if( Result != FR_OK ) { errno = TranslateErrNo( Result ); return EOF; } errno = 0; return 0; } /*============================================================================*/ ssize_t read( int fildes, void *buf, ssize_t nbyte ) { FRESULT Result; UINT BytesRead; if( !HandleIsValid( fildes ) || !Files[fildes].Valid ) { errno = EBADF; return EOF; } Result = f_read( &Files[fildes].File, buf, nbyte, &BytesRead ); if( Result != FR_OK ) { errno = TranslateErrNo( Result ); return EOF; } errno = 0; return BytesRead; } /*============================================================================*/ ssize_t write( int fildes, const void *buf, ssize_t nbyte ) { #if _FS_READONLY errno = EACCES; return EOF; #else // _FS_READONLY FRESULT Result; UINT BytesRead; if( !HandleIsValid( fildes ) || !Files[fildes].Valid ) { errno = EBADF; return EOF; } Result = f_write( &Files[fildes].File, buf, nbyte, &BytesRead ); if( Result != FR_OK ) { errno = TranslateErrNo( Result ); return EOF; } errno = 0; return BytesRead; #endif // _FS_READONLY } /*============================================================================*/ off_t lseek( int fildes, off_t offset, int whence ) { FRESULT Result; if( !HandleIsValid( fildes ) || !Files[fildes].Valid ) { errno = EBADF; return EOF; } if( whence == SEEK_SET ) { if( offset < 0 ) offset = 0; else if( offset > Files[fildes].File.fsize ) offset = Files[fildes].File.fsize; } else if( whence == SEEK_END ) { if( offset > 0 ) offset = Files[fildes].File.fsize; else if( offset < -(long)Files[fildes].File.fsize ) offset = 0; else offset = Files[fildes].File.fsize - offset; } else if( whence == SEEK_CUR ) { if( Files[fildes].File.fptr + offset < 0 ) offset = 0; else if( Files[fildes].File.fptr + offset > Files[fildes].File.fsize ) offset = Files[fildes].File.fsize; else offset = Files[fildes].File.fptr + offset; } else { errno = EINVAL; return EOF; } Result = f_lseek( &Files[fildes].File, offset ); if( Result != FR_OK ) { errno = EOVERFLOW; return EOF; } errno = 0; return Files[fildes].File.fptr; } /*============================================================================*/ int remove( const char *path ) { #if _FS_READONLY errno = EACCES; return EOF; #else // _FS_READONLY FRESULT Result; Result = f_unlink( path ); if( Result != FR_OK ) { errno = TranslateErrNo( Result ); return EOF; } errno = 0; return 0; #endif // _FS_READONLY } /*============================================================================*/ int rename( const char *old, const char *new ) { #if _FS_READONLY errno = EACCES; return EOF; #else // _FS_READONLY FRESULT Result; Result = f_rename( old, new ); if( Result != FR_OK ) { errno = TranslateErrNo( Result ); return EOF; } errno = 0; return 0; #endif // _FS_READONLY } /*============================================================================*/ int eof( int fildes ) { if( !HandleIsValid( fildes ) || !Files[fildes].Valid ) { errno = EBADF; return EOF; } errno = 0; return ( Files[fildes].File.fptr >= Files[fildes].File.fsize) ? 1 : 0; } /*============================================================================*/ #if 0 // Doesn't work yet because the way FatFS implements truncate is too different from the standard int truncate( const char *path, off_t length ) { FRESULT Result; DWORD CurrentPosition; if( !HandleIsValid( fildes ) || !Files[fildes].Valid ) { errno = EBADF; return EOF; } } #endif /*============================================================================*/ #if 0 // Needs some more work int fileno( FILE *stream ) { if(( (unsigned)stream & 0xfffffff0 ) != 0x015aac00 || ( (unsigned)stream & 0x000000ff ) >= sizeof Files / sizeof Files[0] ) { errno = EBADF; return EOF; } errno = 0; return (unsigned)stream & 0x000000ff; } /*============================================================================*/ FILE *fdopen( int fildes, const char *mode ) { if( !HandleIsValid( fildes )) { errno = EBADF; return NULL; } errno = 0; return (FILE*)( fildes | 0x015aac00 ); } #endif /*============================================================================*/