📄 core.c
字号:
/******************************************************************************
* Flash File System (ffs)
* Idea, design and coding by Mads Meisner-Jensen, mmj@ti.com
*
* FFS core functions (not public)
*
* $Id: core.c,v 1.1.1.1 2004/06/19 06:00:30 root Exp $
*
******************************************************************************/
#ifndef TARGET
#include "ffs.cfg"
#endif
#include <string.h>
#include "ffs.h"
#include "core.h"
#include "drv.h"
#include "ffstrace.h"
#include "tmffs.h"
#include <string.h>
#include <limits.h>
/******************************************************************************
* Globals
******************************************************************************/
struct fs_s fs;
struct block_stat_s bstat[FFS_BLOCKS_MAX];
struct ffs_stats_s stats;
// The following line is automatically expanded by the revision control
// system to make a unique ffs revision. The revision can be retrieved by
// ffs_query().
//$Format: "static const uint16 ffs_revision = ($ProjectMajorVersion$<<12)|(0x$ProjectMinorVersion$);"$
static const uint16 ffs_revision = (5<<12)|(0x53);
/******************************************************************************
* Main Functions
******************************************************************************/
// Create a new ffs object (object type is undefined)
iref_t object_create(const char *name, const char *buf, int size, iref_t dir)
{
iref_t i;
struct inode_s *ip;
int realsize, namelength;
offset_t offset;
char *dataaddr;
char is_journal;
char name_copy[FFS_FILENAME_MAX + 1]; // NOTEME: make dynamic?
ttw(ttr(TTrObj, "ocr(%s){" NL, name));
tw(tr(TR_BEGIN, TrObject, "object_create('%s', ?, %d, %d) {\n",
name, size, dir));
// NOTEME: special case just for format()!?
if (dir == 0)
namelength = ffs_strlen(name);
else
namelength = is_filename(name);
if (namelength < 0) {
tw(tr(TR_END, TrObject, "} %d\n", namelength));
ttw(ttr(TTrObj, "} %d" NL, namelength));
return namelength;
}
is_journal = (name[0] == '.' && ffs_strcmp(name, FFS_JOURNAL_NAME) == 0);
if (is_journal)
tw(tr(TR_FUNC, TrObject, "Journal file creation!\n"));
else
if (buf == NULL && size > 0) {
tw(tr(TR_END, TrObject, "} %d\n", EFFS_INVALID));
ttw(ttr(TTrObj, "} %d" NL, EFFS_INVALID));
return EFFS_INVALID;
}
// We don't write the data null_terminator if no data exists
realsize = namelength + 1 + size + (size > 0 ? 1 : 0);
fs.journal.size = realsize = atomalign(realsize);
// We save the diri in the ram journal because this will be updated if
// chunk_alloc trigger a data_reclaim
fs.journal.diri = dir;
// We have to make a local copy of name because name can be destroyed if
// it points into an object that is relocated by an ffs_data_reclaim.
memcpy(name_copy, name, ffs_strlen(name) + 1);
if ((i = chunk_alloc(realsize, is_journal, &offset)) < 0)
return i;
ip = inode_addr(i);
// Write filename including null-terminator
ffsdrv.write(addr2name(offset2addr(offset)), name_copy, namelength + 1);
// Write data and null terminator. We null-terminate the data block,
// such that blocks_fsck() can determine the amount of used data block
// space correctly. Note that we don't write null-terminator for objects
// with no data, e.g. empty files and directories.
if (size > 0) {
dataaddr = addr2name(offset2addr(offset)) + namelength + 1;
// Do NOT write data if we are creating the journal file --- it must
// be created as empty!
if (!is_journal)
ffsdrv.write(dataaddr, buf, size);
ffsdrv_write_byte(dataaddr + size, 0);
}
// Insert object in parent directory if this is not the root dir
if (dir != 0)
fs.journal.diri = dir_traverse(fs.journal.diri, 0);
else
fs.journal.diri = 0;
tw(tr(TR_END, TrObject, "} %d\n", i));
ttw(ttr(TTrObj, "} %d" NL,i));
return i;
}
int file_read(const char *name, void *addr, int size)
{
int size_read, object_size, total_read = 0;
iref_t i, dir;
char *not_used;
fd_t fdi;
if (size < 0)
return EFFS_INVALID;
if ((i = object_lookup(name, ¬_used, &dir)) < 0)
return i;
if ((fdi = get_fdi(i)) >= 0)
if (is_open_option(fs.fd[fdi].options, FFS_O_WRONLY))
return EFFS_LOCKED;
object_size = object_datasize(i);
do {
size_read = segment_read(i, (char*)addr + total_read,
size - total_read, 0);
total_read += size_read;
} while ((i = segment_next(i)) != 0 && size > total_read);
// Did we read the comlete object?
if (object_size > size)
return EFFS_FILETOOBIG;
return total_read; // number of bytes read
}
int stream_read(fd_t fdi, void *src, int size)
{
int offset, size_read = 0, copied = 0;
iref_t i;
if (!is_fd_valid(fdi))
return EFFS_BADFD;
if (!is_open_option(fs.fd[fdi].options, FFS_O_RDONLY))
return EFFS_INVALID;
if (src == NULL || size < 0)
return EFFS_INVALID;
// NOTEME: do this in another way?
// No data to read because fp is ad eof.
if (fs.fd[fdi].fp >= fs.fd[fdi].size) {
tw(tr(TR_FUNC, TrObject, "eof(no data read)\n"));
return 0;
}
segfile_seek(fs.fd[fdi].seghead, fs.fd[fdi].fp, &i, &offset);
// Read data from chunks or buffer until all data is read or eof is reach.
do {
if (is_offset_in_buf(fs.fd[fdi].fp, fdi)) {
offset = fs.fd[fdi].fp - fs.fd[fdi].wfp;
size_read = size - copied; // requested data that is left
// Saturate size to max left in buf or max left to eof
if (size_read > (fs.chunk_size_max - offset))
size_read = fs.chunk_size_max - offset;
if (size_read > (fs.fd[fdi].size - fs.fd[fdi].fp))
size_read = fs.fd[fdi].size - fs.fd[fdi].fp;
memcpy((char*)src + copied, fs.fd[fdi].buf + offset, size_read);
}
else {
// Data is only in the chunk
size_read = segment_read(i, (char*) src + copied,
size - copied, offset);
}
offset = 0;
fs.fd[fdi].fp += size_read;
copied += size_read;
if ((i = segment_next(i)) < 0)
return i;
} while (copied != size && fs.fd[fdi].fp < fs.fd[fdi].size);
if (copied == size) {
tw(tr(TR_FUNC, TrObject, "All requested data has been read\n"));
}
if (fs.fd[fdi].fp >= fs.fd[fdi].size) {
tw(tr(TR_FUNC, TrObject, "eof\n"));
}
return copied; // number of bytes read
}
int object_read(const char *name, char *buf, int size, int linkflag)
{
iref_t i;
struct inode_s *ip;
struct xstat_s stat;
char *p;
tw(tr(TR_BEGIN, TrObject, "object_read('%s', 0x%x, %d, %d) {\n",
name, buf, size, linkflag));
if (buf == NULL || size < 0) {
tw(tr(TR_END, TrObject, "} %d\n", EFFS_INVALID));
return EFFS_INVALID;
}
i = object_stat(name, &stat, linkflag, 0, 0);
if (i < 0) {
tw(tr(TR_END, TrObject, "} %d\n", EFFS_NOTFOUND));
return i;
}
ip = inode_addr(i);
if (stat.size > size) {
tw(tr(TR_END, TrObject, "} %d\n", EFFS_FILETOOBIG));
return EFFS_FILETOOBIG;
}
// return error if called as readlink() and object is not a link
if (!is_object(ip, OT_LINK) && linkflag) {
tw(tr(TR_END, TrObject, "} %d\n", EFFS_INVALID));
return EFFS_INVALID;
}
// 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(ip, OT_DIR) && !(fs.flags & FS_DIR_DATA)) {
tw(tr(TR_END, TrObject, "} %d\n", EFFS_NOTAFILE));
return EFFS_NOTAFILE;
}
p = offset2addr(location2offset(ip->location));
size = stat.size;
p = addr2data(p, ip);
// Copy data. NOTEME: Should be optimized!
while (size--)
*buf++ = *p++;
tw(tr(TR_END, TrObject, "} %d\n", stat.size));
return stat.size;
}
// Convert an object data addres to pure data address
char *addr2data(const char *addr, const struct inode_s *ip)
{
// OT_SEGMENT is pure data so it do not have any name to skip
if (!is_object(ip, OT_SEGMENT)) {
while (*addr++)
;
}
return (char *) addr;
}
// Calculate exact size of file data; without filename and null terminator
// and without data null terminator and succeeding alignment padding.
// NOTEME: Does this also work for empty files and directories?
int object_datasize(iref_t i)
{
iref_t not_used;
return segfile_seek(i, INT_MAX, ¬_used, 0);
}
iref_t object_stat(const char *name, struct xstat_s *stat,
int linkflag, int fdi, int extended)
{
iref_t i;
fd_t other_fdi;
struct inode_s *ip;
tw(tr(TR_BEGIN, TrObject, "object_stat('%s', ?, %x, %d, %d) {\n",
name, linkflag, fdi, extended));
if (stat == NULL) {
tw(tr(TR_END, TrObject, "} %d\n", EFFS_INVALID));
return EFFS_INVALID;
}
if (linkflag)
i = object_lookup_once(name, 0, 0);
else if (name == 0) {
fdi -= FFS_FD_OFFSET;
if (!is_fd_valid(fdi)) {
tw(tr(TR_END, TrObject, "} %d\n", EFFS_BADFD));
return EFFS_BADFD;
}
i = fs.fd[fdi].seghead;
}
else
i = object_lookup(name, 0, 0);
if (i > 0) {
ip = inode_addr(i);
stat->type = ip->flags & OT_MASK;;
stat->flags = ~ip->flags & OF_MASK;
stat->inode = i;
// If the file is open so get the size from the file descriptor
if ((other_fdi = get_fdi(i)) >= 0) {
if (i == fs.fd[other_fdi].seghead) {
stat->size = fs.fd[other_fdi].size;
}
}
else
stat->size = object_datasize(i);
if (extended) {
stat->location = ip->location;
stat->block = offset2block(location2offset(stat->location));
stat->space = ip->size;
while ((i = segment_next(i)) > 0) {
ip = inode_addr(i);
stat->space += ip->size;
}
stat->reserved = 0;
stat->sequence = ip->sequence;
stat->updates = ip->updates;
}
}
tw(tr(TR_END, TrObject, "} %d\n", i));
return i;
}
/******************************************************************************
* Remove and Rename
******************************************************************************/
// Delete a ffs object
effs_t object_remove(iref_t i)
{
struct inode_s *ip = inode_addr(i);
iref_t entries;
tw(tr(TR_BEGIN, TrObject, "object_remove(%d) {\n", i));
// if object is a dir, ensure it is empty
if (is_object(ip, OT_DIR)) {
dir_traverse(-i, &entries);
if (entries) {
tw(tr(TR_END, TrObject, "} %d\n", EFFS_DIRNOTEMPTY));
return EFFS_DIRNOTEMPTY;
}
}
// We don't actually journal deletions, this is why we call
// journal_commit() instead of journal_end(). We have to set
// journal.location to something else, otherwise journal_commit() will
// not discount the number of bytes lost by this delete.
if (is_object(ip, OT_DIR)) {
journal_begin(i);
fs.journal.location = 0;
journal_commit(0);
}
else {
// NOTE: This is not nice if we get a break down however the
// remaning chunks will be removed later by a block reclaim.
do {
journal_begin(i);
fs.journal.location = 0;
journal_commit(0);
} while ((i = segment_next(i)) != 0);
}
tw(tr(TR_END, TrObject, "} %d\n", EFFS_OK));
return EFFS_OK;
}
// Rename an object. <newname> is the new name.
iref_t object_rename(iref_t oldi, const char *newname, iref_t newdir)
{
iref_t newi;
struct inode_s *oldip;
char *olddata;
int oldsize, namelength, realsize, offset;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -