⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 core.c

📁 是一个手机功能的模拟程序
💻 C
📖 第 1 页 / 共 5 页
字号:
/******************************************************************************
 * 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, &not_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, &not_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 + -