?? 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 1.156.1.13.1.1.1.50 Thu, 08 Jan 2004 15:05:23 +0100 tsj $
*
******************************************************************************/
#ifndef TARGET
#include "ffs.cfg"
#endif
#include <string.h>
#include "ffs/ffs.h"
#include "ffs/board/core.h"
#include "ffs/board/drv.h"
#include "ffs/board/ffstrace.h"
#include "ffs/board/tmffs.h"
#include <string.h>
#include <limits.h>
#if (TARGET == 0)
#include "ffs/board/tffs.h"
#endif
#include "swconfig.cfg"
/******************************************************************************
* 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)|(0x60);
/******************************************************************************
* 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;
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));
POWERFAIL_DOMAIN_BEGIN(PFM_CHUNK);
// 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_ram.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;
POWERFAIL_SET_ADDR((uint32)addr2name(offset2addr(offset)));
// 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 (LINEAR_FILE_SYSTEM)
if (!is_journal && (unsigned long)(buf) != 0xFFFFFFFFUL)
ffsdrv.write(dataaddr, buf, size);
#else
if (!is_journal)
ffsdrv.write(dataaddr, buf, size);
#endif
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;
POWERFAIL_DOMAIN_END();
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;
}
#if (FFS_SEEK_OPT == 1)
i =fs.fd[fdi].rch;
offset = fs.fd[fdi].roffset;
#else
segfile_seek(fs.fd[fdi].seghead, fs.fd[fdi].fp, &i, &offset);
#endif
// 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 {
#if (FFS_READ_CACHE_ENBALE == 1)
size_read = segment_read_cache(fdi, i, (char*)src+copied, size-copied, offset);
#else
// Data is only in the chunk
size_read = segment_read(i, (char*) src + copied,
size - copied, offset);
#endif
#if (FFS_SEEK_OPT == 1)
/* record the current chunk & offset */
fs.fd[fdi].rch = i;
fs.fd[fdi].roffset = (offset+size_read);
#endif
}
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, OTE_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, OTE_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, OTE_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);
switch (ip->flags & OT_MASK) {
case OTE_FILE: stat->type = OT_FILE; break;
case OTE_SEGMENT: stat->type = OT_SEGMENT; break;
case OTE_DIR: stat->type = OT_DIR; break;
case OTE_LINK: stat->type = OT_LINK; break;
default: stat->type = ip->flags & OT_MASK;
}
switch (~ip->flags & 0x1) {
case OFE_READONLY: stat->flags = OF_READONLY; break;
default: stat->flags = ~ip->flags & 0x1;
}
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, OTE_DIR)) {
dir_traverse(-i, &entries);
if (entries) {
tw(tr(TR_END, TrObject, "} %d\n", EFFS_DIRNOTEMPTY));
return EFFS_DIRNOTEMPTY;
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -