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

📄 core.c

📁 是一个手机功能的模拟程序
💻 C
📖 第 1 页 / 共 5 页
字号:
effs_t is_fd_valid(fd_t fdi)
{
    if (fdi >= fs.fd_max || fdi < 0 || fs.fd[fdi].options == 0)
        return 0;  // Not valid!
    return 1;
}

effs_t is_offset_in_buf(int offset, fd_t fdi)
{
    if (fs.fd[fdi].dirty == 1)
        if (offset >= fs.fd[fdi].wfp && 
            offset < fs.fd[fdi].wfp + fs.chunk_size_max)
        return 1;
    return 0;
}

/******************************************************************************
 * Chunk Operations
 ******************************************************************************/

iref_t segment_create(const char *buf, int size, iref_t dir)
{
    iref_t i;
    struct inode_s *ip;
    int realsize;
    offset_t offset;
    char *dataaddr;

    ttw(ttr(TTrObj, "segc(%d, %d){" NL, size, dir));
    tw(tr(TR_BEGIN, TrObject, "segment_create( ?, %d, %d) {\n", size, dir));

    fs.journal.size = realsize = atomalign(size + 1);

    // Init journal.diri before chunk_alloc() because it might trigger a
    // data_reclaim() which can relocate the dir inode
    fs.journal.diri = dir;

    if ((i = chunk_alloc(realsize, 0, &offset)) < 0)
        return i;

    ip = inode_addr(i);
    dataaddr = offset2addr(offset);

    // 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. 
    ffsdrv.write(dataaddr, buf, size);
    dataaddr += size;
    ffsdrv_write_byte(dataaddr, 0);
   
    // Segments is linked together by the child link(create) or by the
    // sibling link(update or relocate). A negativ dir indicate that it is a
    // update or relocate and the sign must be reversed so the journal
    // system will use the sibling link to link the inode together. 
    if (dir > 0)
        fs.journal.diri = chunk_traverse(fs.journal.diri);
    
    fs.journal.diri = -fs.journal.diri;
   
    tw(tr(TR_END, TrObject, "} %d\n", i));
    ttw(ttr(TTrObj, "} %d" NL,i));

    return i;
}


int segment_read(iref_t i, char *buf, int size, int offset)
{
    struct inode_s *ip;
    char *p;
    int chunk_size;

    tw(tr(TR_BEGIN, TrObject, "segment_read(%d, 0x%x, %d, %d) {\n",
       i, buf, offset, size));

    if (buf == NULL) {
        tw(tr(TR_END, TrObject, "} %d\n", EFFS_INVALID));
        return EFFS_INVALID;
    }

    ip = inode_addr(i);
    
    chunk_size = segment_datasize(ip);
    
    // Saturate read buffer
    if (size > chunk_size - offset)
        size = chunk_size - offset;
   
    p = offset2addr(location2offset(ip->location));    
    p = addr2data(p, ip);

    memcpy(buf, &p[offset], size);

    tw(tr(TR_END, TrObject, "} %d\n", size));
    return size;
}

// Find next valid chunk
iref_t segment_next(iref_t i)
{
    struct inode_s *ip = inode_addr(i);
    
    tw(tr(TR_BEGIN, TrDirHigh, "ffs_segment_next(%d) {\n", i));

    // Dir is not allowed to contain data
    if (is_object(ip, OT_DIR)) {
        tw(tr(TR_END, TrDirHigh, "} 0\n"));
        return 0;
    }

    // Is this the last/only segment
    if ((i = ip->child) == (iref_t) IREF_NULL) {
        tw(tr(TR_END, TrDirHigh, "} 0\n"));
        return 0;
    }

    // Get child (is valid?), search though segment by sibling link(is
    // valid?), and again..
    do {
        i = ip->child;
        ip = inode_addr(i);
        if (is_object_valid(ip)) {
            tw(tr(TR_END, TrDirHigh,"} %d\n", i));
            return i;
        }

        while (ip->sibling != (iref_t) IREF_NULL) {  
            i = ip->sibling;
            ip = inode_addr(i);
            if (is_object_valid(ip)) {
                tw(tr(TR_END, TrDirHigh,"} %d\n", i));
                return i;
            }
        }
    } while (ip->child != (iref_t) IREF_NULL); 

    // No segment found
    tw(tr(TR_END, TrDirHigh,"} %d\n", i));
    return 0;
}

// The output "inode" will be the inode that contains the requested data or
// the last inode in the segmentfile. The segmenthead will be skiped if it
// don't contains any data. inode_offset is the offset in the found inode
// pointed to by target_offset. If target_offset point past the last segment
// will inode_offset be the size of the last inode. The return value will be
// the same as target_offset but maximum the total size of the object.
int segfile_seek(iref_t seghead, int target_offset, 
                     iref_t *inode, int *inode_offset)
{
    int priv_count = 0, count_size = 0;
    iref_t i = seghead;
    struct inode_s *ip;

    tw(tr(TR_BEGIN, TrObject, "segfile_seek(%d, %d, ?, ?) {\n", 
          seghead, target_offset));
    
    if (!is_object_valid(inode_addr(seghead))) {
        tw(tr(TR_END, TrAll, "FATAL: Invalid seghead!\n"));
        return 0;
    }
    *inode = seghead;

    while (1)
    {
        ip = inode_addr(i);
        count_size += segment_datasize(ip);
        
        // Seghead will be skiped if it don't contain any data  
        if (count_size > target_offset && count_size != 0) {

            if (inode_offset != 0)
                *inode_offset = target_offset - priv_count;

            tw(tr(TR_END, TrObject, "} %d\n", target_offset));
            return target_offset;
        }

        if ((i = segment_next(i)) == 0) {
            tw(tr(TR_END, TrObject, "} (eof!?) %d\n", count_size));
            if (inode_offset != 0)
                *inode_offset = count_size - priv_count;
            // *inode = 0;
            return count_size; // No more segments
        }
        priv_count = count_size;

        *inode = i;
    }
}

// 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 segment_datasize(const struct inode_s *ip)
{
    char *p, *q;
    int size;

    p = offset2addr(location2offset(ip->location));
    q = p + ip->size - 1;

    // Segments is not allowed to contain any name
    if (!is_object(ip, OT_SEGMENT)) {
        // skip filename at start of data
        while (*p)
            p++;
    }
    else 
        // If it contained a name would p pointe to the null terminator of
        // the name but because chunks don't have a name decrement we p to get
        // the size correct
        p--;
    
    // skip padding at end of data
    while (*q)
        q--;
    
    // If there are data, there is also a null-terminator. Otherwise
    // there is no null-terminator
    size = q - p;
    if (size > 0)
        size--;

    tw(tr(TR_FUNC, TrObject, "segment_datasize(0x%x) %d\n", ip, size));
    return size;
}


int object_truncate(const char *pathname, fd_t fdi, offset_t length)
{
    int segment_offset, flength, realsize, offset;
    iref_t i, dir, next_i;
    char *name = 0, *olddata;
    struct inode_s *oldip;
    effs_t error; 
    
    tw(tr(TR_FUNC, TrObject, "ffs_object_truncate('%s', %d, %d) \n", 
          pathname, fdi, length));
    if (length < 0) return EFFS_INVALID;
    
    if (pathname == 0) {
        // File descriptor must be open and it have to be in write mode
        if (!is_fd_valid(fdi)) 
            return EFFS_BADFD;;
       
        if (!is_open_option(fs.fd[fdi].options, FFS_O_WRONLY))
            return EFFS_INVALID; 
          
        // It is not possible to truncate an open file to a size less than
        // the current file pointer
        if (length < fs.fd[fdi].fp)
            return EFFS_INVALID;

        i = fs.fd[fdi].seghead;
    }
    else {
        // File must exists and not be open
        if ((i = object_lookup(pathname, &name, &dir)) < 0)
            return i;

        if (get_fdi(i) >= 0) 
            return EFFS_LOCKED;

        oldip = inode_addr(i);
        // 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(oldip, OT_DIR) && !(fs.flags & FS_DIR_DATA)) 
            return EFFS_NOTAFILE;
        
        if ((i = is_readonly(i, pathname)) < 0) 
            return i;
    }
    // Find the segment which length points in to
    flength = segfile_seek(i, length, &i, &segment_offset);

    if (pathname == 0) {
        if (is_offset_in_buf(length, fdi) == 1) {
            fs.fd[fdi].size = (length > fs.fd[fdi].size ? 
                               fs.fd[fdi].size : length); // Truncate the buffer 
            
            if (i == fs.fd[fdi].wch) {
                next_i = segment_next(i);
                if (next_i > 0) 
                    if ((error = object_remove(next_i)) < 0)
                        return error;
            }
            return EFFS_OK;
        } 
    }
    
    if (flength < length)
        return EFFS_OK;
    
    journal_begin(i);
    
    // Realsize do not always need to include a name but we simplify it. 
    realsize = atomalign(segment_offset + 1 + fs.filename_max + 1); 

    // Make sure that there is enough space to make the rename without
    // object_create() trigger a data_reclaim() (awoid relocate oldi/data
    // source)
    if ((offset = data_prealloc(realsize)) <= 0)
        return EFFS_NOSPACE;

    // Find the next segment if any.
    next_i = segment_next(fs.journal.oldi);
    
    // Find old data source
    oldip = inode_addr(fs.journal.oldi);
    olddata = offset2addr(location2offset(oldip->location));
    name = addr2name(olddata);   // reinit name (maybe relocated)
    olddata = addr2data(olddata, oldip);
    
    if (is_object(oldip, OT_SEGMENT)) {
        if (segment_offset == 0)
            next_i = fs.journal.oldi; // Remove the found object
        else {
            if ((i = segment_create(olddata, segment_offset, 
                                        -fs.journal.oldi)) < 0)
                return i;
            
            fs.link_child = 0;  //Do not link child
            journal_end(0);
        }
    }
    else {
        if ((i = object_create(name, olddata, length, fs.journal.oldi)) < 0)
            return i;
        fs.link_child = 0;  //Do not link child
        journal_end(0);
        
        if (is_fd_valid(fdi))
            fs.fd[fdi].seghead = i;
    }

    if (is_fd_valid(fdi))
        fs.fd[fdi].size = length;

    // If any remaning segment exists then remove them 
    if (next_i > 0) 
        if ((error = object_remove(next_i)) < 0)
            return error;

    return EFFS_OK;
}


// Find the last segment valid or not valid
iref_t chunk_traverse(iref_t i)
{
    struct inode_s *ip = inode_addr(i);
    
    tw(tr(TR_BEGIN, TrDirHigh, "ffs_chunk_traverse(%d) {\n", i));
    // Is this the last/only segment?
    if (ip->child == (iref_t) IREF_NULL) {
        tw(tr(TR_END, TrDirHigh, "} %d\n", i));
        return i;
    }
        
    // Get child, find the last segment by sibling link, and again..
    do {
        i = ip->child;
        ip = inode_addr(i);

        while (ip->sibling != (iref_t) IREF_NULL) {  
            i = ip->sibling;
            ip = inode_addr(i);
        }
    } while (ip->child != (iref_t) IREF_NULL); 

    // FIXME: remove this 
    if (ip->child != (iref_t) IREF_NULL || ip->sibling != (iref_t) IREF_NULL) {
        tw(tr(TR_END, TrAll, 
              "FATAL: ffs_chunk_traverse() found invalid inode\n"));
        return 0;
    }

    tw(tr(TR_END, TrDirHigh, "} %d\n", i));

    return i;
}

// fdi include offset now but change this so core use pure fdi.
effs_t datasync(fd_t fdi) 
{
    int chunk_size;
    iref_t i;
    struct inode_s *ip;
    char *name;

    tw(tr(TR_FUNC, TrObject, "datasync(%d) \n", fdi));
    ttw(ttr(TTrApi, "datasync(%d) {" NL, fdi)); 

    // NOTEME: is this necessary?
    if (!is_fd_valid(fdi))
        return EFFS_BADFD;

    if (fs.fd[fdi].dirty == 0) 
        return EFFS_OK;

    // If size - wfp is more than max is the complete buffer valid or else
    // is it only a part of it that consist valid data
        chunk_size = fs.fd[fdi].size - fs.fd[fdi].wfp;
        if (chunk_size > fs.chunk_size_max)
            chunk_size = fs.chunk_size_max;

      ip = inode_addr(fs.fd[fdi].wch);        

    // Create new chunk or update a old one
    if (fs.fd[fdi].wch > 0) {
        // Update existing chunk
        // Negativ

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -