📄 ffs.c
字号:
/******************************************************************************
* Flash File System (ffs)
* Idea, design and coding by Mads Meisner-Jensen, mmj@ti.com
*
* ffs public API functions
*
* $Id: ffs.c,v 1.1.1.1 2004/06/19 06:00:30 root Exp $
*
f ******************************************************************************/
#ifndef TARGET
#include "ffs.cfg"
#endif
#if (TARGET == 1)
#include "task.h"
#else
#include <stdlib.h>
#endif
#include <string.h>
#include <limits.h>
#include "ffs.h"
#include "core.h"
#include "ffstrace.h"
/******************************************************************************
*
******************************************************************************/
extern struct fs_s fs; // defined in core.c
// These dummy defines and struct are only use to simulate FFS on the
// PC. The ones that is used in target are located in task.h
#if (TARGET == 0)
#define FFS_BLOCKING_CALL_BEGIN()
int result; \
struct ffs_blocking_s fb;
#define FFS_BLOCKING_CALL_END()
struct ffs_blocking_s { };
#endif
/******************************************************************************
* Create, Read and Write
******************************************************************************/
req_id_t ffs_file_write_b(const char *pathname, void *src, int size,
ffs_options_t option, T_RV_RETURN *cp,
struct ffs_blocking_s *fb)
{
iref_t i, dir;
char *name;
effs_t error;
int chunk_size, size_remaining, bytes_free;
tw(tr(TR_FUNC, TrApi, "ffs_file_write('%s', 0x%x, %d, %d) ?\n",
pathname, (int) src, size, option));
ttw(ttr(TTrApi, "ffs_file_write('%s', 0x%x, %d, %d) ?" NL,
pathname, (int) src, size, option));
// TASKBEGIN effs_t FILE_WRITE(path=pathname, src=src, size=size, value16=option) iref_t i, dir; char *name; effs_t error; int chunk_size, size_remaining, bytes_free;
if (fs.initerror)
return fs.initerror;
if (size < 0)
return EFFS_INVALID;
ffs_query(Q_BYTES_FREE, &bytes_free);
if (bytes_free < size)
return EFFS_NOSPACE;
chunk_size = (size > fs.chunk_size_max ? fs.chunk_size_max : size);
if ((i = object_lookup(pathname, &name, &dir)) < 0) {
// Object not found, continue like fcreate()
if (i != EFFS_NOTFOUND)
return i;
if (!is_open_option(option, FFS_O_CREATE))
return EFFS_NOTFOUND;
journal_begin(0);
if ((dir = object_create(name, src, chunk_size, -dir)) < 0)
return dir;
journal_end(OT_FILE);
}
else {
// Object found, continue like fupdate()
if (is_open_option(option, (FFS_O_CREATE))
&& is_open_option(option, (FFS_O_EXCL)))
return EFFS_EXISTS;
if (get_fdi(i) >= 0)
return EFFS_LOCKED;
// Even though the ffs architecture allows to have data in
// directory objects, we don't want to complicate matters, so we
// return an error
if (is_object(inode_addr(i), OT_DIR) && !(fs.flags & FS_DIR_DATA)) {
return EFFS_NOTAFILE;
}
if ((i = is_readonly(i, pathname)) < 0)
return i;
// Save the segment (if any) in the global variable because this
// global variable will be updated if the inode is going to be
// relocated if an inode_reclaim() is triggeret by the object_create()
fs.i_backup = segment_next(i);
journal_begin(i);
if ((dir = object_create(name, src, chunk_size, -dir)) < 0)
return dir;
// Do not link child - we are replacing the complete file!
fs.link_child = 0;
journal_end(0);
// If any other segments exist then remove them FIXME: If we get a
// power failure here then the remaining segments wil not be removed
// before inode_reclaim() has been executed
if (fs.i_backup > 0)
if ((error = object_remove(fs.i_backup)) < 0)
return error;
}
// Save dir in fs.i_backup because this will be updated if some of the
// chunks below trigger a inode reclaim!
fs.i_backup = dir;
size_remaining = size - chunk_size;
while (size_remaining > 0) {
chunk_size = (size_remaining > fs.chunk_size_max ?
fs.chunk_size_max : size_remaining);
journal_begin(0);
if ((i = segment_create((char*) src + size - size_remaining,
chunk_size, fs.i_backup)) < 0)
return i;
journal_end(OT_SEGMENT);
size_remaining -= chunk_size;
}
tw(tr_bstat());
return EFFS_OK;
// TASKEND
}
// Note: ffs_fcreate() is deprecated and should not be used. Use
// ffs_file_write(..., FFS_O_CREATE | FFS_O_EXCL) instead.
effs_t ffs_fcreate(const char *pathname, void *src, int size)
{
FFS_BLOCKING_CALL_BEGIN();
result = ffs_file_write_b(pathname, src, size, FFS_O_CREATE | FFS_O_EXCL,
0, &fb);
FFS_BLOCKING_CALL_END();
return result;
}
req_id_t ffs_fcreate_nb(const char *pathname, void *src, int size,
T_RV_RETURN *cp)
{
return ffs_file_write_b(pathname, src, size, FFS_O_CREATE | FFS_O_EXCL,
cp, 0);
}
// Note: ffs_fupdate() is deprecated and should not be used. Use
// ffs_file_write(...,FFS_O_TRUNC) instead.
effs_t ffs_fupdate(const char *pathname, void *src, int size)
{
FFS_BLOCKING_CALL_BEGIN();
result = ffs_file_write_b(pathname, src, size, FFS_O_TRUNC, 0, &fb);
FFS_BLOCKING_CALL_END();
return result;
}
req_id_t ffs_fupdate_nb(const char *pathname, void *src, int size,
T_RV_RETURN *cp)
{
return ffs_file_write_b(pathname, src, size, FFS_O_TRUNC, cp, 0);
}
// Note: ffs_fwrite() is deprecated and should not be used. Use
// ffs_file_write(...,FFS_O_CREATE | FFS_O_TRUNC) instead.
effs_t ffs_fwrite(const char *pathname, void *src, int size)
{
FFS_BLOCKING_CALL_BEGIN();
result = ffs_file_write_b(pathname, src, size,
FFS_O_CREATE | FFS_O_TRUNC, 0, &fb);
FFS_BLOCKING_CALL_END();
return result;
}
req_id_t ffs_fwrite_nb(const char *pathname, void *src, int size,
T_RV_RETURN *cp)
{
return ffs_file_write_b(pathname, src, size,
FFS_O_CREATE | FFS_O_TRUNC, cp, 0);
}
effs_t ffs_file_write(const char *pathname, void *src, int size,
ffs_options_t option)
{
FFS_BLOCKING_CALL_BEGIN();
result = ffs_file_write_b(pathname, src, size, option, 0, &fb);
FFS_BLOCKING_CALL_END();
return result;
}
req_id_t ffs_file_write_nb(const char *pathname, void *src, int size,
ffs_options_t option,
T_RV_RETURN *cp)
{
return ffs_file_write_b(pathname, src, size, option, cp, 0);
}
// Note important: ffs_fread() is deprecated and should not be used. Use
// ffs_file_read() instead.
int ffs_fread(const char *name, void *addr, int size)
{
return ffs_file_read(name, addr, size);
}
int ffs_file_read(const char *name, void *addr, int size)
{
int error;
tw(tr(TR_BEGIN, TrApi, "file_read('%s', 0x%x, %d) {\n",
name, (int) addr, size));
if ((error = ffs_begin()) == EFFS_OK)
{
error = file_read(name, addr, size);
}
tw(tr(TR_END, TrApi, "} %d\n", error));
return ffs_end(error); // number of bytes read
}
/******************************************************************************
* Stat, Symlink, Remove and Rename
******************************************************************************/
effs_t ffs_stat(const char *name, struct stat_s *stat)
{
iref_t i;
tw(tr(TR_FUNC, TrApi, "ffs_stat('%s', ?) ?\n", name));
ttw(ttr(TTrApi, "ffs_stat('%s', ?) ?" NL, name));
if (name == NULL)
return EFFS_BADNAME;
if ((i = ffs_begin()) == EFFS_OK)
{
if ((i = object_stat(name, (struct xstat_s*) stat, 0, 0, 0)) > 0)
i = EFFS_OK;
}
return ffs_end(i);
}
// Note: ffs_linkstat() is deprecated and should not be used. Use
// ffs_lstat() instead.
effs_t ffs_linkstat(const char *name, struct stat_s *stat)
{
return ffs_lstat(name, stat);
}
effs_t ffs_lstat(const char *name, struct stat_s *stat)
{
iref_t i;
tw(tr(TR_FUNC, TrApi, "ffs_lstat('%s', ?) ?\n", name));
ttw(ttr(TTrApi, "ffs_lstat('%s', ?) ?" NL, name));
if ((i = ffs_begin()) == EFFS_OK) {
if ((i = object_stat(name, (struct xstat_s*)stat, 1, 0, 0)) > 0)
i = EFFS_OK;
}
return ffs_end(i);
}
effs_t ffs_xlstat(const char *name, struct xstat_s *stat)
{
iref_t i;
tw(tr(TR_FUNC, TrApi, "ffs_xlstat('%s', ?) ?\n", name));
ttw(ttr(TTrApi, "ffs_xlstat('%s', ?) ?" NL, name));
if ((i = ffs_begin()) == EFFS_OK) {
if ((i = object_stat(name, stat, 1, 0, 1)) > 0)
i = EFFS_OK;
}
return ffs_end(i);
}
effs_t ffs_fstat(fd_t fdi, struct stat_s *stat)
{
iref_t i;
tw(tr(TR_FUNC, TrApi, "ffs_fstat('%d', ?) ?\n", fdi));
ttw(ttr(TTrApi, "ffs_fstat('%d', ?) ?" NL, fdi));
if ((i = ffs_begin()) == EFFS_OK) {
if ((i = object_stat( 0, (struct xstat_s*) stat, 0, fdi, 0)) > 0)
i = EFFS_OK;
}
return ffs_end(i);
}
req_id_t ffs_symlink_b(const char *pathname, const char *src,
T_RV_RETURN *cp, struct ffs_blocking_s *fb)
{
iref_t i, dir;
char *name;
int size;
tw(tr(TR_FUNC, TrApi, "ffs_symlink('%s', '%s') ?\n", pathname, src));
ttw(ttr(TTrApi, "ffs_symlink('%s', '%s') ?" NL, pathname, src));
// TASKBEGIN effs_t SYMLINK(path=pathname, src=src) iref_t i, dir; int size; char *name;
if (fs.initerror)
return fs.initerror;
if (src == NULL)
return EFFS_BADNAME;
i = object_lookup(pathname, &name, &dir);
if (i > 0)
return EFFS_EXISTS;
if (i != EFFS_NOTFOUND)
return i;
size = ffs_strlen(src) + 1; // include null-terminator
journal_begin(0);
if ((i = object_create(name, src, size, -dir)) < 0)
return i;
journal_end(OT_LINK);
tw(tr_bstat());
return EFFS_OK;
// TASKEND
}
effs_t ffs_symlink(const char *pathname, const char *actualpath)
{
FFS_BLOCKING_CALL_BEGIN();
result = ffs_symlink_b(pathname, actualpath, 0, &fb);
FFS_BLOCKING_CALL_END();
return result;
}
req_id_t ffs_symlink_nb(const char *pathname, const char *src,
T_RV_RETURN *cp)
{
return ffs_symlink_b(pathname, src, cp, 0);
}
int ffs_readlink(const char *name, char *addr, int size)
{
int error;
tw(tr(TR_FUNC, TrApi, "ffs_readlink('%s')\n", name));
if ((error = ffs_begin()) == EFFS_OK)
{
error = object_read(name, addr, size, 1);
}
return ffs_end(error);
}
req_id_t ffs_remove_b(const char *pathname, T_RV_RETURN *cp,
struct ffs_blocking_s *fb)
{
iref_t i;
tw(tr(TR_FUNC, TrApi, "ffs_remove('%s')\n", pathname));
ttw(ttr(TTrApi, "ffs_remove('%s') ?" NL, pathname));
// TASKBEGIN effs_t REMOVE(path=pathname) iref_t i;
if (fs.initerror)
return fs.initerror;
if ((i = object_lookup_once(pathname, 0, 0)) < 0)
return i;
if (get_fdi(i) >= 0)
return EFFS_LOCKED;
if ((i = is_readonly(i, pathname)) < 0)
return i;
if ((i = object_remove(i)) < 0)
return i;
tw(tr_bstat());
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -