mirror of
https://github.com/ShadauxCat/CATSFC.git
synced 2025-04-02 10:41:47 -04:00
452 lines
8.5 KiB
C
Executable file
452 lines
8.5 KiB
C
Executable file
//fs_api.c
|
|
|
|
#include <stdio.h>
|
|
#include <fcntl.h>
|
|
#include <errno.h>
|
|
#include <stdarg.h>
|
|
#include <string.h>
|
|
#include <sys/stat.h>
|
|
#include "fs_common.h"
|
|
#include "fatfile.h"
|
|
#include "fatdir.h"
|
|
|
|
typedef unsigned int size_t;
|
|
typedef unsigned int mode_t;
|
|
|
|
typedef struct {
|
|
const char* mode; /* mode string */
|
|
unsigned int flag; /* mode flag */
|
|
// unsigned char mode_r; /* READ */
|
|
// unsigned char mode_w; /* WRITE */
|
|
// unsigned char mode_a; /* APPEND */
|
|
// unsigned char mode_c; /* CREATE */
|
|
} _fat_mode_type;
|
|
|
|
static const _fat_mode_type _fat_valid_mode[] = {
|
|
{ "r" , O_RDONLY },
|
|
{ "w" , O_WRONLY | O_TRUNC | O_CREAT },
|
|
{ "a" , O_WRONLY | O_APPEND | O_CREAT },
|
|
{ "rb" , O_RDONLY },
|
|
{ "wb" , O_WRONLY | O_TRUNC | O_CREAT },
|
|
{ "ab" , O_WRONLY | O_APPEND | O_CREAT },
|
|
{ "r+" , O_RDWR },
|
|
{ "w+" , O_RDWR | O_TRUNC | O_CREAT },
|
|
{ "a+" , O_RDWR | O_APPEND | O_CREAT },
|
|
{ "r+b" , O_RDWR },
|
|
{ "rb+" , O_RDWR },
|
|
{ "w+b" , O_RDWR | O_TRUNC | O_CREAT },
|
|
{ "wb+" , O_RDWR | O_TRUNC | O_CREAT },
|
|
{ "a+b" , O_RDWR | O_APPEND | O_CREAT },
|
|
{ "ab+" , O_RDWR | O_APPEND | O_CREAT }
|
|
};
|
|
|
|
#define MAX_OPEN_FILE 16
|
|
#define MAX_OPEN_DIR 32
|
|
#define MAX_PWD_LEN 512
|
|
#define MAX_STDIO_BUF_SIZE 2048
|
|
|
|
#define FAT_VALID_MODE_NUM (sizeof(_fat_valid_mode)/sizeof(_fat_mode_type))
|
|
|
|
static FILE_STRUCT __FILEs[MAX_OPEN_FILE];
|
|
struct _reent __REENT;
|
|
static DIR_STATE_STRUCT __DIRs[MAX_OPEN_DIR];
|
|
static char __PWD[MAX_PWD_LEN];
|
|
|
|
int fat_init(void)
|
|
{
|
|
int i, flag;
|
|
|
|
for(i= 0; i < MAX_OPEN_FILE; i++)
|
|
__FILEs[i].inUse = false;
|
|
|
|
for(i= 0; i < MAX_OPEN_DIR; i++)
|
|
__DIRs[i].inUse = false;
|
|
|
|
flag = -1;
|
|
if(_FAT_Init() == true) //success
|
|
flag = 0;
|
|
|
|
return flag;
|
|
}
|
|
|
|
FILE_STRUCT* fat_fopen(const char *file, const char *mode)
|
|
{
|
|
int i, k;
|
|
int fd;
|
|
FILE_STRUCT* fp;
|
|
|
|
for(i= 0; i < MAX_OPEN_FILE; i++)
|
|
if(false == __FILEs[i].inUse) break;
|
|
|
|
if(i >= MAX_OPEN_FILE)
|
|
{
|
|
__REENT._errno = EMFILE; /* Too many open files */
|
|
return NULL;
|
|
}
|
|
|
|
for(k = 0; k < FAT_VALID_MODE_NUM; k++)
|
|
if(!strcasecmp(_fat_valid_mode[k].mode, mode)) break;
|
|
|
|
if(k >= FAT_VALID_MODE_NUM)
|
|
{
|
|
__REENT._errno = EINVAL;
|
|
return NULL;
|
|
}
|
|
|
|
fd = _FAT_open_r(&__REENT, (void*)&__FILEs[i], file, _fat_valid_mode[k].flag);
|
|
if(-1 == fd) return NULL;
|
|
|
|
fp = &__FILEs[i];
|
|
fp -> fd = fd;
|
|
|
|
return fp;
|
|
}
|
|
|
|
size_t fat_fread(void *buf, size_t size, size_t count, FILE_STRUCT *fp)
|
|
{
|
|
if(0 == size || 0 == count)
|
|
return 0;
|
|
|
|
int len = _FAT_read_r(&__REENT, fp->fd, (char*)buf, size*count);
|
|
len /= size;
|
|
return len;
|
|
}
|
|
|
|
size_t fat_fwrite(const void *buf, size_t size, size_t count, FILE_STRUCT *fp)
|
|
{
|
|
if(0 == size || 0 == count)
|
|
return 0;
|
|
|
|
int len = _FAT_write_r(&__REENT, fp->fd, (const char*)buf, size*count);
|
|
len /= size;
|
|
|
|
return len;
|
|
}
|
|
|
|
int fat_fclose(FILE_STRUCT *fp)
|
|
{
|
|
return( _FAT_close_r(&__REENT, fp->fd) );
|
|
}
|
|
|
|
int fat_fseek(FILE_STRUCT *fp, long offset, int whence)
|
|
{
|
|
int flag;
|
|
|
|
//When success, _FAT_seek_r return file position pointer
|
|
flag = _FAT_seek_r (&__REENT, fp->fd, (int)offset, whence);
|
|
if(flag > 0) flag = 0;
|
|
|
|
return flag;
|
|
}
|
|
|
|
long fat_ftell(FILE_STRUCT *fp)
|
|
{
|
|
return( (long)fp->currentPosition );
|
|
}
|
|
|
|
int fat_feof(FILE_STRUCT *fp)
|
|
{
|
|
int result;
|
|
|
|
result = 0;
|
|
if((fp->currentPosition +1) >= (fp->filesize))
|
|
result = -1;
|
|
|
|
return result;
|
|
}
|
|
|
|
int fat_ferror(FILE_STRUCT *fp)
|
|
{
|
|
return( __REENT._errno );
|
|
}
|
|
|
|
void fat_clearerr(FILE_STRUCT *fp)
|
|
{
|
|
fp = fp;
|
|
|
|
__REENT._errno = 0;
|
|
}
|
|
|
|
int fat_fflush(FILE_STRUCT *fp)
|
|
{
|
|
return(_FAT_cache_flush(fp->partition->cache));
|
|
}
|
|
|
|
int fat_fgetc(FILE_STRUCT *fp)
|
|
{
|
|
char ch;
|
|
int result;
|
|
|
|
result = _FAT_read_r(&__REENT, fp->fd, &ch, 1);
|
|
if(0 == result)
|
|
return EOF;
|
|
|
|
return ( (int)ch );
|
|
}
|
|
|
|
char* fat_fgets(char* buf, int n, FILE_STRUCT* fp)
|
|
{
|
|
int m;
|
|
char *s;
|
|
|
|
buf[0] = '\0';
|
|
if(n <= 1) return buf;
|
|
|
|
n -= 1;
|
|
m = _FAT_read_r(&__REENT, fp->fd, buf, n);
|
|
if(0 == m) return NULL;
|
|
|
|
buf[m] = '\0';
|
|
s = strchr((const char*)buf, 0x0A);
|
|
|
|
if(NULL != s)
|
|
{
|
|
*(++s)= '\0';
|
|
m -= s - buf;
|
|
|
|
//fix reading pointer
|
|
_FAT_seek_r (&__REENT, fp->fd, -m, SEEK_CUR);
|
|
}
|
|
else if(m == n)
|
|
{
|
|
if(0x0D == buf[n-1]) //0x0D,0x0A
|
|
{
|
|
buf[n-1] = '\0';
|
|
_FAT_seek_r (&__REENT, fp->fd, -1, SEEK_CUR);
|
|
}
|
|
}
|
|
|
|
return buf;
|
|
}
|
|
|
|
int fat_fputc(int ch, FILE_STRUCT *fp)
|
|
{
|
|
return( _FAT_write_r(&__REENT, fp->fd, (const char*)&ch, 1) );
|
|
}
|
|
|
|
int fat_fputs(const char *s, FILE_STRUCT *fp)
|
|
{
|
|
unsigned int len;
|
|
|
|
len = strlen(s);
|
|
return( _FAT_write_r(&__REENT, fp->fd, s, len) );
|
|
}
|
|
|
|
int fat_remove(const char *filename)
|
|
{
|
|
return( _FAT_unlink_r (&__REENT, (const char*)filename) );
|
|
}
|
|
|
|
int fat_rename(const char *oldName, const char *newName)
|
|
{
|
|
return( _FAT_rename_r(&__REENT, oldName, newName) );
|
|
}
|
|
|
|
int fat_setHidden(const char *name, unsigned char hide){
|
|
return(_FAT_hideAttrib_r (&__REENT, name, hide));
|
|
}
|
|
|
|
#define S_ISHID(st_mode) ((st_mode & S_IHIDDEN) != 0)
|
|
int fat_isHidden(struct stat *st){
|
|
return S_ISHID(st->st_mode);
|
|
}
|
|
|
|
int fat_getShortName(const char *fullName, char *outName){
|
|
return(_FAT_getshortname_r (&__REENT, fullName, outName));
|
|
}
|
|
|
|
|
|
void fat_rewind(FILE_STRUCT *fp)
|
|
{
|
|
_FAT_seek_r (&__REENT, fp->fd, 0, SEEK_SET);
|
|
}
|
|
|
|
int fat_fstat(int fildes, struct stat *buf)
|
|
{
|
|
return( _FAT_fstat_r (&__REENT, fildes, buf) );
|
|
}
|
|
|
|
//int fat_fprintf(FILE_STRUCT *fp, const char *format, ...)
|
|
int fat_fprintf(void* fp, const char *format, ...)
|
|
{
|
|
int ret;
|
|
va_list ap;
|
|
char buf[MAX_STDIO_BUF_SIZE];
|
|
|
|
if(NULL == fp)
|
|
{
|
|
__REENT._errno = EINVAL;
|
|
return -1;
|
|
}
|
|
|
|
//FIXME: stderr, stdout
|
|
if((void*)stderr == fp) return 0;
|
|
if((void*)stdout == fp) return 0;
|
|
|
|
memset(buf, 0, MAX_STDIO_BUF_SIZE);
|
|
|
|
va_start (ap, format);
|
|
ret = vsnprintf (buf, MAX_STDIO_BUF_SIZE, format, ap);
|
|
va_end (ap);
|
|
|
|
//if output string too long, it will not put out to file
|
|
if(ret >= MAX_STDIO_BUF_SIZE)
|
|
return -1;
|
|
|
|
return( _FAT_write_r(&__REENT, ((FILE_STRUCT*)fp)->fd, (const char*)buf, strlen(buf)) );
|
|
}
|
|
|
|
int fat_fscanf(FILE_STRUCT *fp, const char *format, ...)
|
|
{
|
|
int ret;
|
|
va_list ap;
|
|
char buf[MAX_STDIO_BUF_SIZE];
|
|
char *pt;
|
|
|
|
if(NULL == fp)
|
|
{
|
|
__REENT._errno = EINVAL;
|
|
return -1;
|
|
}
|
|
|
|
pt = fat_fgets(buf, MAX_STDIO_BUF_SIZE, fp);
|
|
if(NULL == pt)
|
|
return -1;
|
|
|
|
va_start (ap, format);
|
|
ret = vsscanf (buf, format, ap);
|
|
|
|
return ret;
|
|
}
|
|
|
|
DIR_STATE_STRUCT* fat_opendir(const char *name)
|
|
{
|
|
int i;
|
|
|
|
for(i = 0; i < MAX_OPEN_DIR; i++)
|
|
{
|
|
if(false == __DIRs[i].inUse) break;
|
|
}
|
|
|
|
if(i>= MAX_OPEN_DIR)
|
|
{
|
|
__REENT._errno = EMFILE; /* Too many open files */
|
|
return NULL;
|
|
}
|
|
|
|
return( _FAT_diropen_r(&__REENT, &__DIRs[i], name) );
|
|
}
|
|
|
|
DIR_ENTRY* fat_readdir(DIR_STATE_STRUCT *dirp)
|
|
{
|
|
int isValid;
|
|
|
|
isValid = _FAT_dirnext_r (&__REENT, dirp, NULL);
|
|
if(0 != isValid)
|
|
return NULL;
|
|
|
|
return( &(dirp->currentEntry) );
|
|
}
|
|
|
|
long int fat_telldir(DIR_STATE_STRUCT *dirp)
|
|
{
|
|
return( dirp->posEntry );
|
|
}
|
|
|
|
void fat_seekdir(DIR_STATE_STRUCT *dirp, long int loc)
|
|
{
|
|
if (!dirp->inUse) {
|
|
__REENT._errno = EBADF;
|
|
return;
|
|
}
|
|
|
|
if(0 == loc)
|
|
{
|
|
dirp->posEntry = 0;
|
|
}
|
|
else if(loc > 0)
|
|
{
|
|
while(dirp->posEntry < loc)
|
|
{
|
|
dirp->validEntry = _FAT_directory_getNextEntry (dirp->partition, &(dirp->currentEntry));
|
|
dirp->posEntry += 1;
|
|
|
|
if(!dirp->validEntry) break;
|
|
}
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
int fat_closedir(DIR_STATE_STRUCT *dirp)
|
|
{
|
|
return(_FAT_dirclose_r (&__REENT, dirp));
|
|
}
|
|
|
|
int fat_chdir(const char *path)
|
|
{
|
|
int ret;
|
|
char *pt;
|
|
|
|
ret = _FAT_chdir_r (&__REENT, path);
|
|
if(0 != ret) return -1;
|
|
|
|
pt = strchr(path, ':');
|
|
if(pt == NULL)
|
|
strcat(__PWD, path);
|
|
else
|
|
strcpy(__PWD, path);
|
|
|
|
pt = strchr(__PWD, '\0');
|
|
while(pt-- != __PWD)
|
|
{
|
|
if(pt[0] != DIR_SEPARATOR) break;
|
|
}
|
|
|
|
pt[1] = DIR_SEPARATOR;
|
|
pt[2] = '\0';
|
|
|
|
return 0;
|
|
}
|
|
|
|
char* fat_getcwd(char *buf, size_t size)
|
|
{
|
|
int len;
|
|
|
|
len = strlen(__PWD);
|
|
if(len >= size)
|
|
{
|
|
__REENT._errno = ERANGE;
|
|
return NULL;
|
|
}
|
|
|
|
strcpy(buf, __PWD);
|
|
return buf;
|
|
}
|
|
|
|
int fat_mkdir(const char *path, mode_t mode)
|
|
{
|
|
return( _FAT_mkdir_r(&__REENT, path, mode) );
|
|
}
|
|
|
|
int fat_rmdir(const char *path)
|
|
{
|
|
return( _FAT_unlink_r(&__REENT, path) );
|
|
}
|
|
|
|
int fat_lstat(const char *path, struct stat *buf)
|
|
{
|
|
return( _FAT_stat_r (&__REENT, path, buf) );
|
|
}
|
|
|
|
DIR_ENTRY* fat_readdir_ex(DIR_STATE_STRUCT *dirp, struct stat *statbuf)
|
|
{
|
|
int isValid;
|
|
|
|
isValid = _FAT_dirnext_r (&__REENT, dirp, statbuf);
|
|
if(0 != isValid)
|
|
return NULL;
|
|
|
|
return( &(dirp->currentEntry) );
|
|
}
|
|
|