515 lines
11 KiB
C
515 lines
11 KiB
C
/*
|
|
* Copyright (c) 2020 AIIT XUOS Lab
|
|
* XiUOS is licensed under Mulan PSL v2.
|
|
* You can use this software according to the terms and conditions of the Mulan PSL v2.
|
|
* You may obtain a copy of Mulan PSL v2 at:
|
|
* http://license.coscl.org.cn/MulanPSL2
|
|
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
|
|
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
|
|
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
|
|
* See the Mulan PSL v2 for more details.
|
|
*/
|
|
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
#include <stdlib.h>
|
|
#include <stdint.h>
|
|
#include <xiuos.h>
|
|
#include <iot-vfs.h>
|
|
#include <ff.h>
|
|
#include <ffconf.h>
|
|
#include <diskio.h>
|
|
|
|
/* copy from xs_base.h */
|
|
#define DK_UNKNOWN 0x00
|
|
#define DK_REG 0x01
|
|
#define DK_DIR 0x02
|
|
|
|
struct ff_disk ff_disks[FF_VOLUMES];
|
|
|
|
static int TranslateError(FRESULT error)
|
|
{
|
|
int status = EOK;
|
|
|
|
switch (error) {
|
|
case FR_OK:
|
|
break;
|
|
case FR_NO_FILE:
|
|
case FR_NO_PATH:
|
|
case FR_NO_FILESYSTEM:
|
|
status = -ENOENT;
|
|
break;
|
|
case FR_INVALID_NAME:
|
|
status = -EINVAL;
|
|
break;
|
|
case FR_EXIST:
|
|
case FR_INVALID_OBJECT:
|
|
status = -EEXIST;
|
|
break;
|
|
case FR_DISK_ERR:
|
|
case FR_NOT_READY:
|
|
case FR_INT_ERR:
|
|
status = -EIO;
|
|
break;
|
|
case FR_WRITE_PROTECTED:
|
|
case FR_DENIED:
|
|
status = -EROFS;
|
|
break;
|
|
case FR_MKFS_ABORTED:
|
|
status = -EINVAL;
|
|
break;
|
|
default:
|
|
status = -1;
|
|
break;
|
|
}
|
|
|
|
return status;
|
|
}
|
|
|
|
static int GetDisk(HardwareDevType dev)
|
|
{
|
|
for (int i = 0; i < FF_VOLUMES; i++)
|
|
if (ff_disks[i].dev == dev)
|
|
return i;
|
|
return -1;
|
|
}
|
|
|
|
static char *MakeFatfsPath(const struct MountPoint *mp,
|
|
const char *relpath)
|
|
{
|
|
int i = GetDisk(mp->dev);
|
|
char *ff_path = malloc(strlen(relpath) + 8);
|
|
|
|
sprintf(ff_path, "%d:/%s", i, relpath);
|
|
|
|
return ff_path;
|
|
}
|
|
|
|
static int FatfsOpen(struct FileDescriptor *fdp, const char *path)
|
|
{
|
|
FRESULT res;
|
|
uint8_t fs_mode;
|
|
FIL *file;
|
|
char *ff_path;
|
|
|
|
file = malloc(sizeof(FIL));
|
|
if (file == NULL)
|
|
return -ENOMEM;
|
|
memset(file, 0, sizeof(FIL));
|
|
fdp->data = file;
|
|
|
|
fs_mode = FA_READ | FA_WRITE | FA_OPEN_ALWAYS;
|
|
|
|
ff_path = MakeFatfsPath(fdp->mntp, path);
|
|
res = f_open(fdp->data, ff_path, fs_mode);
|
|
free(ff_path);
|
|
|
|
return TranslateError(res);
|
|
}
|
|
|
|
static int FatfsClose(struct FileDescriptor *fdp)
|
|
{
|
|
FRESULT res;
|
|
|
|
res = f_close(fdp->data);
|
|
|
|
/* Free file ptr memory */
|
|
if (res == FR_OK) {
|
|
free(fdp->data);
|
|
fdp->data = NULL;
|
|
}
|
|
|
|
return TranslateError(res);
|
|
}
|
|
|
|
static ssize_t FatfsRead(struct FileDescriptor *fdp, void *dst, size_t len)
|
|
{
|
|
FRESULT res;
|
|
unsigned int br;
|
|
|
|
res = f_read(fdp->data, dst, len, &br);
|
|
if (res != FR_OK)
|
|
return TranslateError(res);
|
|
|
|
return br;
|
|
}
|
|
|
|
static ssize_t FatfsWrite(struct FileDescriptor *fdp, const void *src, size_t len)
|
|
{
|
|
FRESULT res;
|
|
unsigned int bw;
|
|
|
|
res = f_write(fdp->data, src, len, &bw);
|
|
if (res != FR_OK)
|
|
return TranslateError(res);
|
|
|
|
return bw;
|
|
}
|
|
|
|
static int FatfsSeek(struct FileDescriptor *fdp, off_t offset, int whence,
|
|
off_t *new_offset)
|
|
{
|
|
FRESULT res = FR_OK;
|
|
off_t pos;
|
|
|
|
switch (whence) {
|
|
case SEEK_SET:
|
|
pos = offset;
|
|
break;
|
|
case SEEK_CUR:
|
|
pos = f_tell((FIL *)fdp->data) + offset;
|
|
break;
|
|
case SEEK_END:
|
|
pos = f_size((FIL *)fdp->data) + offset;
|
|
break;
|
|
default:
|
|
return -EINVAL;
|
|
}
|
|
|
|
if ((pos < 0) || (pos > f_size((FIL *)fdp->data)))
|
|
return -EINVAL;
|
|
|
|
res = f_lseek(fdp->data, pos);
|
|
*new_offset = (off_t)f_tell((FIL *)fdp->data);
|
|
|
|
return TranslateError(res);
|
|
}
|
|
|
|
static off_t FatfsTell(struct FileDescriptor *fdp)
|
|
{
|
|
return f_tell((FIL *)fdp->data);
|
|
}
|
|
|
|
static int FatfsTruncate(struct FileDescriptor *fdp, off_t length)
|
|
{
|
|
FRESULT res = FR_OK;
|
|
off_t curr_len = f_size((FIL *)fdp->data);
|
|
|
|
/* expand file if new position is larger than file size */
|
|
res = f_lseek(fdp->data, length);
|
|
if (res != FR_OK)
|
|
return TranslateError(res);
|
|
|
|
if (length < curr_len)
|
|
res = f_truncate(fdp->data);
|
|
else {
|
|
/* get actual length */
|
|
length = f_tell((FIL *)fdp->data);
|
|
|
|
res = f_lseek(fdp->data, curr_len);
|
|
if (res != FR_OK)
|
|
return TranslateError(res);
|
|
|
|
unsigned int bw;
|
|
uint8_t c = 0;
|
|
|
|
for (int i = curr_len; i < length; i++) {
|
|
res = f_write(fdp->data, &c, 1, &bw);
|
|
if (res != FR_OK)
|
|
break;
|
|
}
|
|
}
|
|
|
|
return TranslateError(res);
|
|
}
|
|
|
|
static int FatfsSync(struct FileDescriptor *fdp)
|
|
{
|
|
FRESULT res = FR_OK;
|
|
|
|
res = f_sync(fdp->data);
|
|
|
|
return TranslateError(res);
|
|
}
|
|
|
|
static int FatfsOpendir(struct FileDescriptor *fdp, const char *path)
|
|
{
|
|
FRESULT res;
|
|
DIR *dir;
|
|
char *ff_path;
|
|
|
|
dir = malloc(sizeof(DIR));
|
|
if (dir == NULL)
|
|
return -ENOMEM;
|
|
memset(dir, 0, sizeof(DIR));
|
|
fdp->data = dir;
|
|
|
|
ff_path = MakeFatfsPath(fdp->mntp, path);
|
|
res = f_opendir((DIR *)fdp->data, ff_path);
|
|
free(ff_path);
|
|
|
|
return TranslateError(res);
|
|
}
|
|
|
|
static int FatfsClosedir(struct FileDescriptor *fdp)
|
|
{
|
|
FRESULT res;
|
|
|
|
res = f_closedir(fdp->data);
|
|
|
|
if (res == FR_OK) {
|
|
free(fdp->data);
|
|
fdp->data = NULL;
|
|
}
|
|
|
|
return TranslateError(res);
|
|
}
|
|
|
|
static int FatfsReaddir(struct FileDescriptor *fdp, struct dirent *dirent)
|
|
{
|
|
FRESULT res;
|
|
FILINFO fno;
|
|
|
|
res = f_readdir(fdp->data, &fno);
|
|
if (res == FR_OK) {
|
|
dirent->d_kind = (fno.fattrib & AM_DIR) ? DK_DIR : DK_REG;
|
|
strcpy(dirent->d_name, fno.fname);
|
|
}
|
|
|
|
return TranslateError(res);
|
|
}
|
|
|
|
static int FatfsMount(struct MountPoint *mp)
|
|
{
|
|
FRESULT res;
|
|
char ff_mnt_point[16];
|
|
int i = GetDisk(NULL);
|
|
|
|
if (i < 0)
|
|
return -ENOENT;
|
|
ff_disks[i].dev = mp->dev;
|
|
sprintf(ff_mnt_point, "%d:", i);
|
|
|
|
mp->fs_data = malloc(sizeof(FATFS));
|
|
if (mp->fs_data == NULL)
|
|
return -ENOMEM;
|
|
|
|
res = f_mount((FATFS *)mp->fs_data, ff_mnt_point, 1);
|
|
|
|
if (res == FR_NO_FILESYSTEM) {
|
|
/* create filesystem if not found */
|
|
uint8_t work[FF_MAX_SS];
|
|
MKFS_PARM parm = {FM_FAT | FM_SFD, 0, 0, 0, 0};
|
|
|
|
res = f_mkfs(ff_mnt_point, &parm, work, sizeof(work));
|
|
if (res == FR_OK)
|
|
res = f_mount((FATFS *)mp->fs_data, ff_mnt_point, 1);
|
|
}
|
|
|
|
CHECK(res == FR_OK);
|
|
|
|
return TranslateError(res);
|
|
}
|
|
|
|
static int FatfsUnmount(struct MountPoint *mp)
|
|
{
|
|
FRESULT res;
|
|
char ff_mnt_point[16];
|
|
int i = GetDisk(mp->dev);
|
|
|
|
if (i < 0)
|
|
return -ENOENT;
|
|
sprintf(ff_mnt_point, "%d:", i);
|
|
|
|
res = f_mount(NULL, ff_mnt_point, 0);
|
|
if (res == 0) {
|
|
ff_disks[i].dev = NULL;
|
|
}
|
|
|
|
return TranslateError(res);
|
|
}
|
|
|
|
static int FatfsUnlink(struct MountPoint *mp, const char *path)
|
|
{
|
|
FRESULT res;
|
|
char *ff_path;
|
|
|
|
ff_path = MakeFatfsPath(mp, path);
|
|
res = f_unlink(ff_path);
|
|
free(ff_path);
|
|
|
|
return TranslateError(res);
|
|
}
|
|
|
|
static int FatfsRename(struct MountPoint *mp, const char *from,
|
|
const char *to)
|
|
{
|
|
FRESULT res;
|
|
FILINFO fno;
|
|
char *ff_path_from, *ff_path_to;
|
|
|
|
ff_path_from = MakeFatfsPath(mp, from);
|
|
ff_path_to = MakeFatfsPath(mp, to);
|
|
|
|
/* remove if "to" already exists */
|
|
res = f_stat(ff_path_to, &fno);
|
|
if (FR_OK == res) {
|
|
res = f_unlink(ff_path_to);
|
|
if (FR_OK != res)
|
|
goto err;
|
|
}
|
|
|
|
res = f_rename(ff_path_from, ff_path_to);
|
|
|
|
err:
|
|
free(ff_path_from);
|
|
free(ff_path_to);
|
|
|
|
return TranslateError(res);
|
|
}
|
|
|
|
static int FatfsMkdir(struct MountPoint *mp, const char *path)
|
|
{
|
|
FRESULT res;
|
|
char *ff_path;
|
|
|
|
ff_path = MakeFatfsPath(mp, path);
|
|
res = f_mkdir(ff_path);
|
|
free(ff_path);
|
|
|
|
return TranslateError(res);
|
|
}
|
|
|
|
static int FatfsStat(struct MountPoint *mp, const char *path,
|
|
struct FileStat *buf)
|
|
{
|
|
FRESULT res;
|
|
FILINFO fno;
|
|
char *ff_path;
|
|
struct tm tm;
|
|
int year, mon, day, hour, min, sec;
|
|
WORD tmp;
|
|
|
|
ff_path = MakeFatfsPath(mp, path);
|
|
res = f_stat(ff_path, &fno);
|
|
if (res != FR_OK)
|
|
goto err;
|
|
|
|
buf->type = (fno.fattrib & AM_DIR) ? FTYPE_DIR : FTYPE_FILE;
|
|
strcpy(buf->name, fno.fname);
|
|
buf->size = fno.fsize;
|
|
|
|
// tmp = fno.fdate;
|
|
// day = tmp & 0x1f;
|
|
// tmp >>= 5;
|
|
// mon = tmp & 0x0f;
|
|
// tmp >>= 4;
|
|
// year = (tmp & 0x7f) + 1980;
|
|
|
|
// tmp = fno.ftime;
|
|
// sec = (tmp & 0x1f) * 2;
|
|
// tmp >>= 5;
|
|
// min = tmp & 0x3f;
|
|
// tmp >>= 6;
|
|
// hour = tmp & 0x1f;
|
|
|
|
// memset(&tm, 0, sizeof(tm));
|
|
// tm.tm_year = year - 1900;
|
|
// tm.tm_mon = mon - 1;
|
|
// tm.tm_mday = day;
|
|
// tm.tm_hour = hour;
|
|
// tm.tm_min = min;
|
|
// tm.tm_sec = sec;
|
|
|
|
// buf->mtime = mktime(&tm);
|
|
buf->mtime = 1580486400; /* 2020/01/01 00:00:00 */
|
|
|
|
err:
|
|
free(ff_path);
|
|
|
|
return TranslateError(res);
|
|
}
|
|
|
|
static int FatfsStatvfs(struct MountPoint *mp, const char *path,
|
|
struct statfs *buf)
|
|
{
|
|
FATFS *fs;
|
|
FRESULT res;
|
|
char *ff_mnt_point;
|
|
DWORD fre_clust, fre_sect, tot_sect;
|
|
|
|
fs = mp->fs_data;
|
|
|
|
ff_mnt_point = MakeFatfsPath(mp, "");
|
|
res = f_getfree(ff_mnt_point, &fre_clust, &fs);
|
|
free(ff_mnt_point);
|
|
if (res != FR_OK)
|
|
return -EIO;
|
|
|
|
tot_sect = (fs->n_fatent - 2) * fs->csize;
|
|
fre_sect = fre_clust * fs->csize;
|
|
|
|
buf->f_bfree = fre_sect;
|
|
buf->f_blocks = tot_sect;
|
|
#if FF_MAX_SS != 512
|
|
buf->f_bsize = fs->ssize;
|
|
#else
|
|
buf->f_bsize = 512;
|
|
#endif
|
|
|
|
return TranslateError(res);
|
|
}
|
|
|
|
/* fatfs filesystem interface */
|
|
static struct Filesystem fatfs_fs = {
|
|
.open = FatfsOpen,
|
|
.close = FatfsClose,
|
|
.read = FatfsRead,
|
|
.write = FatfsWrite,
|
|
.seek = FatfsSeek,
|
|
.tell = FatfsTell,
|
|
.truncate = FatfsTruncate,
|
|
.sync = FatfsSync,
|
|
.ioctl = NULL,
|
|
.poll = NULL,
|
|
.opendir = FatfsOpendir,
|
|
.closedir = FatfsClosedir,
|
|
.readdir = FatfsReaddir,
|
|
.seekdir = NULL,
|
|
.mount = FatfsMount,
|
|
.unmount = FatfsUnmount,
|
|
.unlink = FatfsUnlink,
|
|
.rename = FatfsRename,
|
|
.mkdir = FatfsMkdir,
|
|
.stat = FatfsStat,
|
|
.statvfs = FatfsStatvfs,
|
|
};
|
|
|
|
int FatfsInit()
|
|
{
|
|
return RegisterFilesystem(FSTYPE_FATFS, &fatfs_fs);
|
|
}
|
|
|
|
DWORD GetFatTime(void)
|
|
{
|
|
DWORD fat_time = 0;
|
|
|
|
#ifdef LIB
|
|
time_t now;
|
|
struct tm *p_tm;
|
|
struct tm tm_now;
|
|
x_base lock;
|
|
|
|
/* get current time */
|
|
now = time(NONE);
|
|
|
|
/* lock scheduler. */
|
|
lock = CriticalAreaLock();
|
|
/* converts calendar time time into local time. */
|
|
p_tm = localtime(&now);
|
|
/* copy the statically located variable */
|
|
memcpy(&tm_now, p_tm, sizeof(struct tm));
|
|
/* unlock scheduler. */
|
|
CriticalAreaUnLock(lock);
|
|
|
|
fat_time = (DWORD)(tm_now.tm_year - 80) << 25 |
|
|
(DWORD)(tm_now.tm_mon + 1) << 21 |
|
|
(DWORD)tm_now.tm_mday << 16 |
|
|
(DWORD)tm_now.tm_hour << 11 |
|
|
(DWORD)tm_now.tm_min << 5 |
|
|
(DWORD)tm_now.tm_sec / 2 ;
|
|
#endif /* LIB */
|
|
|
|
return fat_time;
|
|
}
|