📄 filesys.c
字号:
/*
* Copyright (c) 2004, Dennis Kuschel.
* All rights reserved.
*
* 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.
* 3. The name of the author may not be used to endorse or promote
* products derived from this software without specific prior written
* permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.
*
*/
/**
* @file filesys.c
* @author Dennis Kuschel
* @brief Simple file system for embedded devices
*
* This software is from http://mycpu.mikrocontroller.net.
* Please send questions and bug reports to dennis_k@freenet.de.
*/
#include "filesys.h"
/*---------------------------------------------------------------------------
* DEFINES
*-------------------------------------------------------------------------*/
#define FS_DRIVE_ID "RamDrive"
#define FS_DRIVE_IDLEN 8
#define FS_MAXIMAGES 2
#ifndef FS_MAXFILES
#define FS_MAXFILES 10
#endif
#ifndef SYS_MTASK_LOCK
#define SYS_MTASK_DECLARELOCK(lock)
#define SYS_MTASK_CREATELOCK(lock) do { } while(0)
#define SYS_MTASK_DESTROYLOCK(lock) do { } while(0)
#define SYS_MTASK_LOCK(lock) do { } while(0)
#define SYS_MTASK_UNLOCK(lock) do { } while(0)
#endif
/*---------------------------------------------------------------------------
* TYPEDEFS
*-------------------------------------------------------------------------*/
typedef struct {
u32_t nextBlock;
u32_t data[1];
} FSBLOCK_t;
typedef struct {
u32_t nextBlock;
u32_t prevBlock;
u32_t flags;
u32_t firstFileBlock; /* or last nextBlock */
u32_t filesize;
struct fsys_time time;
char filename[1]; /* must be the last element */
} FSDIRBLOCK_t;
#define SIZEOF_DIRBLOCK(fnsize) (sizeof(FSDIRBLOCK_t)-1 + (fnsize))
#define FSDIR_F_DELETED 0x00000001
#define FSDIR_F_IGNORE 0x00000002
#define FSDIR_F_DELONCLOSE 0x00000004
#define FSDIR_F_SUBDIR 0x00000008
typedef struct {
char driveId[(FS_DRIVE_IDLEN+3)&~3];
u32_t driveSize;
u32_t freeBlocksList;
u32_t freeDirBlocksList;
u32_t firstDirBlock;
u16_t bytesPerBlock;
u16_t bytesPerDirBlock;
u16_t dirBlocksPerBlock;
u16_t maxFilenameLength;
} FSROOTBLOCK_t;
typedef struct {
u32_t flags;
FSROOTBLOCK_t *rootblock;
} FSIMAGE_t;
#define FSIMG_F_EXTERNALIMG 0x00000001
#define FSIMG_F_READONLY 0x00000002
typedef struct {
sint_t mode;
u32_t flags;
u32_t image;
u32_t dirblock;
u32_t curBlock;
u32_t curDataPtr;
u32_t curPosition;
FSDIRBLOCK_t *dblockptr;
} FSFILE_t;
#define FSFILE_F_USED 0x00000001
typedef struct {
sint_t image;
u32_t dirblock;
u32_t refcount;
} FSFILEREF_t;
typedef struct {
sint_t image;
u32_t dirblock;
char mask[FS_MAXFNAMELEN];
} FSSEARCH_t;
/*---------------------------------------------------------------------------
* MACROS
*-------------------------------------------------------------------------*/
#define FSROOTBLOCK(img) fsimages_g[img].rootblock
#define ISREADONLY(img) ((fsimages_g[img].flags & FSIMG_F_READONLY) != 0)
#define FSALIGN32(val) (((val) + sizeof(u32_t)-1) & ~(sizeof(u32_t)-1))
#define FS_DATABYTESPERBLOCK(rb) ((rb)->bytesPerBlock - sizeof(u32_t))
/*---------------------------------------------------------------------------
* GLOBAL VARIABLES
*-------------------------------------------------------------------------*/
static sint_t fsInitialized_g = 0;
char fnbuffer_g[FS_MAXFNAMELEN];
FSIMAGE_t fsimages_g[FS_MAXIMAGES];
#define FS_RAMIMAGE 0
#define FS_EXTIMAGE 1
static FSFILE_t fsFileList_g[FS_MAXFILES];
static FSFILEREF_t fsRefList_g[FS_MAXFILES];
static FSSEARCH_t fsSearchList_g[FS_MAXFILES];
#if FS_SUBDIRECTORIES
static struct fsys_finddata finfo_g;
static FSSEARCH_t fsearch_g;
#endif
SYS_MTASK_DECLARELOCK(fsTaskLock_g)
/*---------------------------------------------------------------------------
* FUNCTION PROTOTYPES
*-------------------------------------------------------------------------*/
static void fs_getCurrentTime(struct fsys_time *time);
static u32_t fs_allocBlock(FSROOTBLOCK_t *rb);
static void fs_freeBlock(FSROOTBLOCK_t *rb, u32_t blockNmbr);
static void fs_freeBlockChain(FSROOTBLOCK_t *rb, u32_t firstBlockNmbr);
static u32_t fs_findFile(sint_t *img, const char *filename);
static u32_t fs_newFile(sint_t *img,const char *filename,sint_t overwrite);
static char* fs_validateFileName(const char* filename);
static sint_t fs_containWildcard(const char* filename);
static sint_t fs_isFileOpened(const char* filename, sint_t forWriting);
static void fs_incRefCount(sint_t img, u32_t dirblock);
static void fs_decRefCount(sint_t img, u32_t dirblock);
static u32_t fs_allocDirBlock(FSROOTBLOCK_t *rb);
static void fs_freeDirBlock(FSROOTBLOCK_t *rb, u32_t blockNmbr);
static u32_t fs_lastBlock(FSROOTBLOCK_t *rb,u32_t dirblock,u32_t *blocks);
static sint_t fs_open(const char *filename, const sint_t mode);
static sint_t fs_seek(const sint_t file, const sint_t position,
const sint_t origin);
static void fs_closeAllFiles(void);
static sint_t fs_formatImage(sint_t img, u32_t blocksize,
u32_t maxFilenameLength);
static void fs_tempFilename(char *fname);
static void fs_removeDirEntry(FSROOTBLOCK_t *rb, u32_t dirblock);
static s32_t fs_findnext(FSSEARCH_t *fs, struct fsys_finddata *fileinfo);
static sint_t fs_getWriteableImage(void);
static void fs_blockrestToDirblock(FSROOTBLOCK_t *rb, u32_t block);
static FSBLOCK_t* fs_getBlock(FSROOTBLOCK_t *rb, u32_t blocknbr);
static FSDIRBLOCK_t* fs_getDirBlock(FSROOTBLOCK_t *rb, u32_t blocknbr);
#if FS_SUBDIRECTORIES
static sint_t fs_isDirEmpty(const char *pathname, char **fnout);
#endif
/*---------------------------------------------------------------------------
* FUNCTION IMPLEMENTATION
*-------------------------------------------------------------------------*/
/* Open a file for read or write access.
*/
sint_t fsys_open(const char *filename, const sint_t mode)
{
sint_t fh;
if (fsInitialized_g == 0)
return -1;
if (fs_containWildcard(filename))
return -1;
SYS_MTASK_LOCK(fsTaskLock_g);
fh = fs_open(filename, mode);
SYS_MTASK_UNLOCK(fsTaskLock_g);
return fh;
}
/* Create and open a temporary file.
*/
sint_t fsys_opent(char *filename, const sint_t mode)
{
sint_t fh;
if ((fsInitialized_g == 0) || (filename == NULL))
return -1;
SYS_MTASK_LOCK(fsTaskLock_g);
fs_tempFilename(filename);
fh = fs_open(filename, mode | FSO_CREAT | FSO_EXCL);
SYS_MTASK_UNLOCK(fsTaskLock_g);
return fh;
}
/* Close a file again.
*/
void fsys_close(const sint_t file)
{
if ((fsInitialized_g == 0) || ((uint_t)file >= FS_MAXFILES))
return;
SYS_MTASK_LOCK(fsTaskLock_g);
if (fsFileList_g[file].flags & FSFILE_F_USED)
{
fsFileList_g[file].flags = 0;
fs_decRefCount(fsFileList_g[file].image, fsFileList_g[file].dirblock);
}
SYS_MTASK_UNLOCK(fsTaskLock_g);
}
/* Write a block of data to a file.
*/
sint_t fsys_write(const sint_t file, const char *buf, const sint_t count)
{
FSROOTBLOCK_t *rb;
FSFILE_t *f;
u32_t c, b, d, s, w;
if ((fsInitialized_g == 0) ||
((uint_t)file >= FS_MAXFILES) ||
(count < 0))
return -1;
SYS_MTASK_LOCK(fsTaskLock_g);
f = &fsFileList_g[file];
if (!(f->flags & FSFILE_F_USED) ||
(f->mode & FSO_RDONLY))
{
SYS_MTASK_UNLOCK(fsTaskLock_g);
return -1;
}
if ((f->mode & FSO_APPEND) &&
(f->curPosition < f->dblockptr->filesize))
{
if (fs_seek(file, 0, FSSEEK_END) < 0)
{
SYS_MTASK_UNLOCK(fsTaskLock_g);
return -1;
}
}
rb = FSROOTBLOCK(f->image);
b = f->curBlock;
d = f->curDataPtr;
c = (u32_t) count;
w = 0;
while (c != 0)
{
/* if curDataPtr == 0 we need to go to the next block */
if (d == 0)
{
if (b == 0)
{
b = f->dblockptr->firstFileBlock;
}
else
{
b = fs_getBlock(rb, b)->nextBlock;
}
if (b == 0)
{
b = fs_allocBlock(rb);
if (b == 0)
{
SYS_MTASK_UNLOCK(fsTaskLock_g);
return (sint_t) w; /* error: disk full */
}
if (f->curBlock == 0)
{
f->dblockptr->firstFileBlock = b;
}
else
{
fs_getBlock(rb, f->curBlock)->nextBlock = b;
}
}
f->curBlock = b;
}
/* copy data */
s = FS_DATABYTESPERBLOCK(rb) - d;
if (s > c)
s = c;
sysMemCopy(((u8_t*)(fs_getBlock(rb, b)->data)) + d, buf + w, s);
d += s;
if (d >= FS_DATABYTESPERBLOCK(rb))
d = 0;
f->curDataPtr = d;
f->curPosition += s;
if (f->curPosition > f->dblockptr->filesize)
f->dblockptr->filesize = f->curPosition;
w += s;
c -= s;
}
SYS_MTASK_UNLOCK(fsTaskLock_g);
return w;
}
/* Read a block of data from a file.
*/
sint_t fsys_read(const sint_t file, const char *buf, const sint_t count)
{
FSROOTBLOCK_t *rb;
FSFILE_t *f;
u32_t b, c, d, r, s, l;
if ((fsInitialized_g == 0) || ((uint_t)file >= FS_MAXFILES))
return -1;
SYS_MTASK_LOCK(fsTaskLock_g);
f = &fsFileList_g[file];
if (!(f->flags & FSFILE_F_USED) ||
(f->mode & FSO_WRONLY))
{
SYS_MTASK_UNLOCK(fsTaskLock_g);
return -1;
}
rb = FSROOTBLOCK(f->image);
b = f->curBlock;
d = f->curDataPtr;
c = (u32_t) count;
r = 0;
while ((c != 0) && (f->curPosition < f->dblockptr->filesize))
{
/* if curDataPtr == 0 we need to go to the next block */
if (d == 0)
{
if (b == 0)
{
b = f->dblockptr->firstFileBlock;
}
else
{
b = fs_getBlock(rb, b)->nextBlock;
}
if (b == 0)
{
SYS_MTASK_UNLOCK(fsTaskLock_g);
return (sint_t) r; /* reached end of file */
}
f->curBlock = b;
}
/* copy data */
s = FS_DATABYTESPERBLOCK(rb) - d;
if (s > c)
s = c;
l = f->dblockptr->filesize - f->curPosition;
if (s > l)
s = l;
sysMemCopy((u8_t*)buf + r,
((u8_t*)(fs_getBlock(rb, b)->data)) + d, s);
d += s;
if (d >= FS_DATABYTESPERBLOCK(rb))
d = 0;
f->curDataPtr = d;
f->curPosition += s;
r += s;
c -= s;
}
SYS_MTASK_UNLOCK(fsTaskLock_g);
return (sint_t) r;
}
/* Tests if the file pointer has reached the end of the file.
*/
sint_t fsys_eof(const sint_t file)
{
FSFILE_t *f;
sint_t rc;
if ((fsInitialized_g == 0) ||
((uint_t)file >= FS_MAXFILES))
return -1;
SYS_MTASK_LOCK(fsTaskLock_g);
f = &fsFileList_g[file];
if (!(f->flags & FSFILE_F_USED))
{
rc = -1;
}
else
{
rc = (f->curPosition >= f->dblockptr->filesize) ? 1 : 0;
}
SYS_MTASK_UNLOCK(fsTaskLock_g);
return rc;
}
/* Set the file pointer to a new position.
*/
sint_t fsys_seek(const sint_t file, const sint_t position,
const sint_t origin)
{
sint_t rc;
if ((fsInitialized_g == 0) ||
((uint_t)file >= FS_MAXFILES))
return -1;
SYS_MTASK_LOCK(fsTaskLock_g);
rc = fs_seek(file, position, origin);
SYS_MTASK_UNLOCK(fsTaskLock_g);
return rc;
}
/* Get current file pointer position.
*/
sint_t fsys_tell(const sint_t file)
{
FSFILE_t *f;
sint_t rc;
if ((fsInitialized_g == 0) ||
((uint_t)file >= FS_MAXFILES))
return -1;
SYS_MTASK_LOCK(fsTaskLock_g);
f = &fsFileList_g[file];
if (f->flags & FSFILE_F_USED)
{
rc = (sint_t) f->curPosition;
}
else
{
rc = -1;
}
SYS_MTASK_UNLOCK(fsTaskLock_g);
return rc;
}
/* Delete a file from a writeable RAM-Drive.
*/
sint_t fsys_remove(const char *filename)
{
FSROOTBLOCK_t *rb;
FSDIRBLOCK_t *dbl;
u32_t b;
sint_t img;
char *fn;
if ((fsInitialized_g == 0) ||
fs_containWildcard(filename))
return -1;
SYS_MTASK_LOCK(fsTaskLock_g);
fn = fs_validateFileName(filename);
b = fs_findFile(&img, fn);
if (b == 0)
{
SYS_MTASK_UNLOCK(fsTaskLock_g);
return -1; /* file not found */
}
rb = FSROOTBLOCK(img);
dbl = fs_getDirBlock(rb, b);
if (ISREADONLY(img) ||
fs_isFileOpened(fn, 0) ||
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -