📄 filesys.c
字号:
{
FSROOTBLOCK_t *rb;
FSDIRBLOCK_t *dbl;
FSFILE_t *f;
sint_t file;
u32_t d;
sint_t img;
char *fn;
fn = fs_validateFileName(filename);
if (*fn == 0)
return -1;
/* allocate a file descriptor */
for (file = 0; (file < FS_MAXFILES) &&
(fsFileList_g[file].flags & FSFILE_F_USED); file++);
if (file >= FS_MAXFILES)
return -1;
f = &fsFileList_g[file];
if (mode & (FSO_CREAT | FSO_TRUNC))
{
/* FSO_CREAT: create a new file, FSO_TRUNC: overwrite existing file */
d = 0;
img = 0;
if (((mode & FSO_TRUNC) && fs_isFileOpened(fn, 0)) ||
fs_isFileOpened(fn, 1))
return -1; /* error: can't truncate a yet opened file, and can't
write to a file that is just opened for writing */
if (!(mode & FSO_TRUNC))
{
d = fs_findFile(&img, fn);
if ((mode & FSO_EXCL) && (d != 0))
return -1; /* error, file exist */
}
if (!(mode & FSO_CREAT))
{
if (!(mode & FSO_RDONLY))
d = fs_findFile(&img, fn);
if (d == 0)
return -1; /* error: rdonly is set or file does not exist */
d = 0;
}
if (d == 0)
d = fs_newFile(&img, fn, (mode & FSO_TRUNC) ? 1 : 0);
if ((d == 0) || ISREADONLY(img))
return -1;
rb = FSROOTBLOCK(img);
}
else
{
/* open an existing file */
if (!(mode & FSO_RDONLY))
{
/* may do a write access, but
this is not allowed while someone else
is writing to the file */
if (fs_isFileOpened(fn, 1))
return -1;
}
d = fs_findFile(&img, fn);
if (d == 0)
return -1; /* file not found */
if (!(mode & FSO_RDONLY) && ISREADONLY(img))
return -1; /* image not writeable */
rb = FSROOTBLOCK(img);
}
dbl = fs_getDirBlock(rb, d);
if (dbl->flags & FSDIR_F_SUBDIR)
return -1;
f->mode = mode;
f->flags = FSFILE_F_USED;
f->image = img;
f->dirblock = d;
f->curBlock = 0;
f->curDataPtr = 0;
f->curPosition = 0;
f->dblockptr = dbl;
fs_incRefCount(img, d);
return file;
}
static sint_t fs_getWriteableImage(void)
{
sint_t i;
for (i=0; i < FS_MAXIMAGES; i++)
{
if ((fsimages_g[i].rootblock != NULL) &&
((fsimages_g[i].flags & FSIMG_F_READONLY) == 0))
{
return i;
}
}
return -1;
}
static u32_t fs_newFile(sint_t *img, const char *filename, sint_t overwrite)
{
FSROOTBLOCK_t *rb;
FSDIRBLOCK_t *dbl;
u32_t n, pb, b;
sint_t i, i2;
/* find writeable image */
i = fs_getWriteableImage();
if (i < 0)
return 0;
rb = FSROOTBLOCK(i);
if (sysStrlen(filename) >= rb->maxFilenameLength)
return -1;
*img = i;
n = fs_findFile(&i2, filename);
if (n != 0)
{
if ((overwrite == 0) || (i != i2))
return 0;
dbl = fs_getDirBlock(rb, n);
if (dbl->flags & FSDIR_F_SUBDIR)
return 0;
/* overwrite an existing file */
fs_freeBlockChain(rb, dbl->firstFileBlock);
}
else
{
/* create a new file */
n = fs_allocDirBlock(rb);
if (n == 0)
return 0;
pb = 0;
for (b = rb->firstDirBlock; b != 0; b = fs_getDirBlock(rb, b)->nextBlock)
pb = b;
if (pb == 0)
{
rb->firstDirBlock = n;
}
else
{
fs_getDirBlock(rb, pb)->nextBlock = n;
}
dbl = fs_getDirBlock(rb, n);
dbl->prevBlock = pb;
sysStrcpy(dbl->filename, filename);
}
/* initialize directory entry */
dbl->firstFileBlock = 0;
dbl->filesize = 0;
fs_getCurrentTime(&dbl->time);
return n;
}
/* create a temporary file name */
static void fs_tempFilename(char *fname)
{
struct fsys_time fstime;
u32_t d, n;
fs_getCurrentTime(&fstime);
n = (((u32_t) fstime.min) << 6) | (u32_t) fstime.sec;
do
{
sprintf(fname, "TEMP%04x", n++);
d = fs_findFile(NULL, fname);
}
while (d > 0);
}
/*-------------------------------------------------------------------------*/
static u32_t fs_allocBlock(FSROOTBLOCK_t *rb)
{
FSBLOCK_t *bl;
u32_t n;
if (rb->freeBlocksList == 0)
return 0;
n = rb->freeBlocksList;
bl = fs_getBlock(rb, n);
rb->freeBlocksList = bl->nextBlock;
bl->nextBlock = 0;
return n;
}
static void fs_freeBlock(FSROOTBLOCK_t *rb, u32_t blockNmbr)
{
fs_getBlock(rb, blockNmbr)->nextBlock = rb->freeBlocksList;
rb->freeBlocksList = blockNmbr;
}
static void fs_freeBlockChain(FSROOTBLOCK_t *rb, u32_t firstBlockNmbr)
{
FSBLOCK_t *bl;
u32_t n, b;
b = firstBlockNmbr;
while (b != 0)
{
bl = fs_getBlock(rb, b);
n = bl->nextBlock;
fs_freeBlock(rb, b);
b = n;
}
}
static void fs_blockrestToDirblock(FSROOTBLOCK_t *rb, u32_t block)
{
FSDIRBLOCK_t *dbl;
u32_t db;
u16_t i;
db = block * rb->dirBlocksPerBlock + 1;
for (i = rb->dirBlocksPerBlock; i > 1; i--)
{
dbl = fs_getDirBlock(rb, db);
dbl->nextBlock = rb->freeDirBlocksList;
rb->freeDirBlocksList = db;
++db;
}
}
static u32_t fs_allocDirBlock(FSROOTBLOCK_t *rb)
{
FSDIRBLOCK_t *dbl;
u32_t n;
n = rb->freeDirBlocksList;
if (n == 0)
{
n = fs_allocBlock(rb);
if (n == 0)
return 0;
fs_blockrestToDirblock(rb, n);
n *= rb->dirBlocksPerBlock;
dbl = fs_getDirBlock(rb, n);
}
else
{
dbl = fs_getDirBlock(rb, n);
rb->freeDirBlocksList = dbl->nextBlock;
}
dbl->nextBlock = 0;
dbl->flags = 0;
return n;
}
static void fs_freeDirBlock(FSROOTBLOCK_t *rb, u32_t blockNmbr)
{
FSDIRBLOCK_t *dbl;
dbl = fs_getDirBlock(rb, blockNmbr);
dbl->flags = FSDIR_F_DELETED;
dbl->firstFileBlock = dbl->nextBlock;
dbl->nextBlock = rb->freeDirBlocksList;
rb->freeDirBlocksList = blockNmbr;
}
static void fs_removeDirEntry(FSROOTBLOCK_t *rb, u32_t dirblock)
{
FSDIRBLOCK_t *dbl;
dbl = fs_getDirBlock(rb, dirblock);
/* free data area of the file */
fs_freeBlockChain(rb, dbl->firstFileBlock);
/* remove the directory entry */
if (dbl->nextBlock != 0)
fs_getDirBlock(rb, dbl->nextBlock)->prevBlock = dbl->prevBlock;
if (dbl->prevBlock == 0)
{
rb->firstDirBlock = dbl->nextBlock;
}
else
{
fs_getDirBlock(rb, dbl->prevBlock)->nextBlock = dbl->nextBlock;
}
fs_freeDirBlock(rb, dirblock);
}
static void fs_closeAllFiles(void)
{
sint_t i;
for (i = 0; i < FS_MAXFILES; i++)
{
fsFileList_g[i].flags = 0;
fsRefList_g[i].refcount = 0;
fsSearchList_g[i].image = -1;
}
}
static sint_t fs_formatImage(sint_t img, u32_t blocksize,
u32_t maxFilenameLength)
{
FSROOTBLOCK_t *rb;
u32_t bpb, bpd, blocks, b;
if (fsimages_g[img].flags & FSIMG_F_READONLY)
return -1;
if (blocksize == 0)
blocksize = 512;
if (maxFilenameLength == 0)
maxFilenameLength = (blocksize/2) - SIZEOF_DIRBLOCK(0);
maxFilenameLength = maxFilenameLength & ~(sizeof(u32_t)-1);
if (maxFilenameLength > FS_MAXFNAMELEN)
maxFilenameLength = FS_MAXFNAMELEN;
bpb = FSALIGN32(blocksize);
bpd = FSALIGN32(SIZEOF_DIRBLOCK(maxFilenameLength));
if ((maxFilenameLength < 2) || (bpd > bpb))
return -1;
rb = fsimages_g[img].rootblock;
blocks = rb->driveSize / bpb;
if (blocks < 3)
return -1;
sysMemCopy(rb->driveId, FS_DRIVE_ID, FS_DRIVE_IDLEN);
rb->bytesPerBlock = (u16_t) bpb;
rb->dirBlocksPerBlock = (u16_t) (bpb / bpd);
rb->maxFilenameLength = (u16_t) ((maxFilenameLength +
((bpb/rb->dirBlocksPerBlock) - SIZEOF_DIRBLOCK(maxFilenameLength))) &
~(sizeof(u32_t)-1));
if (rb->maxFilenameLength > FS_MAXFNAMELEN)
rb->maxFilenameLength = FS_MAXFNAMELEN;
rb->bytesPerDirBlock =
FSALIGN32(SIZEOF_DIRBLOCK(rb->maxFilenameLength));
rb->firstDirBlock = 0;
rb->freeBlocksList = 1;
rb->freeDirBlocksList = 0;
for (b = 1; b < (blocks - 1); b++)
{
fs_getBlock(rb, b)->nextBlock = b + 1;
}
fs_getBlock(rb, b)->nextBlock = 0;
if (sizeof(FSROOTBLOCK_t) <= rb->bytesPerDirBlock)
{
fs_blockrestToDirblock(rb, 0);
}
return 0;
}
/*-------------------------------------------------------------------------*/
/* This function returns a pointer to the RAM based image in memory.
* The image is locked after this operation, so no file operation will
* change the image. After processing the image, the function
* fsys_unlockImage must be called.
*/
void* fsys_lockAndGetImage(u32_t *size)
{
FSROOTBLOCK_t *rb;
FSBLOCK_t *bl;
u32_t b;
sint_t i;
SYS_MTASK_LOCK(fsTaskLock_g);
/* find writeable image in RAM */
i = fs_getWriteableImage();
if (i < 0)
{
SYS_MTASK_LOCK(fsTaskLock_g);
return NULL;
}
/* clear all unused blocks */
rb = FSROOTBLOCK(i);
b = rb->freeBlocksList;
while (b != 0)
{
bl = fs_getBlock(rb, b);
sysMemSet(bl->data, 0, FS_DATABYTESPERBLOCK(rb));
b = bl->nextBlock;
}
if (size != NULL)
*size = rb->driveSize;
return (void*)rb;
}
/* Unlock an image that was previously locked
* by a call to the function fsys_lockAndGetImage().
*/
void fsys_unlockImage(void)
{
SYS_MTASK_UNLOCK(fsTaskLock_g);
}
/*-------------------------------------------------------------------------*/
/* Add an filesystem image to the filesystem.
* The image can be marked as readonly when the image resides in
* a non writable (Flash-) ROM.
*/
sint_t fsys_addDriveImage(void *img, sint_t readonly)
{
FSROOTBLOCK_t *rb = (FSROOTBLOCK_t*) img;
sint_t i;
if (img == NULL)
return -1;
if (sysStrncmp(rb->driveId, FS_DRIVE_ID, FS_DRIVE_IDLEN) != 0)
return -1;
if (rb->maxFilenameLength > FS_MAXFNAMELEN)
return -1;
SYS_MTASK_LOCK(fsTaskLock_g);
for (i=0; (i<FS_MAXIMAGES) && (fsimages_g[i].rootblock != NULL); i++);
if (i >= FS_MAXIMAGES)
{
SYS_MTASK_UNLOCK(fsTaskLock_g);
return -1;
}
fsimages_g[i].rootblock = rb;
fsimages_g[i].flags = FSIMG_F_EXTERNALIMG |
((readonly != 0) ? FSIMG_F_READONLY : 0);
SYS_MTASK_UNLOCK(fsTaskLock_g);
return 0;
}
/* Initialize the file system.
* This function must be called before all others.
*/
sint_t fsys_init(u32_t size, u32_t blocksize, u32_t maxFilenameLength)
{
FSROOTBLOCK_t *rb;
sint_t i;
SYS_MTASK_CREATELOCK(fsTaskLock_g);
for (i = 0; i < FS_MAXIMAGES; i++)
{
fsimages_g[i].rootblock = NULL;
}
fs_closeAllFiles();
if (size != 0)
{
rb = NULL;
if (size > sizeof(FSROOTBLOCK_t))
rb = (FSROOTBLOCK_t*) sysMemAlloc(size);
if (rb == NULL)
{
SYS_MTASK_DESTROYLOCK(fsTaskLock_g);
return -1;
}
sysMemSet(rb, 0, size);
fsimages_g[0].rootblock = rb;
fsimages_g[0].flags = 0;
rb->driveSize = size;
if (fs_formatImage(0, blocksize, maxFilenameLength) != 0)
{
sysMemFree(rb);
SYS_MTASK_DESTROYLOCK(fsTaskLock_g);
return -1;
}
}
fsInitialized_g = 1;
return 0;
}
/* Terminate the filesystem.
*/
sint_t fsys_term(void)
{
sint_t i;
fsInitialized_g = 0;
for (i=0; i<FS_MAXIMAGES; i++)
{
if ((fsimages_g[i].rootblock != NULL) &&
((fsimages_g[i].flags & FSIMG_F_EXTERNALIMG) == 0))
{
sysMemFree(fsimages_g[i].rootblock);
}
fsimages_g[i].rootblock = NULL;
}
SYS_MTASK_DESTROYLOCK(fsTaskLock_g);
return 0;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -