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

📄 core.c

📁 MMI层OBJ不能完全编译
💻 C
📖 第 1 页 / 共 5 页
字号:
        }
    }

    // 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, OTE_DIR)) {
        journal_begin(i);
        fs.journal_ram.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_ram.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;

    tw(tr(TR_BEGIN, TrObject, "object_rename(%d, '%s', %d) {\n",
          oldi, newname, newdir));

    oldip   = inode_addr(oldi);
    oldsize = segment_datasize(oldip);

    // Make sure that there is enough space to make the rename without
    // object_create() trigger a data_reclaim() (awoid relocate oldi/data
    // source)
    namelength = is_filename(newname);
    realsize = namelength + 1 + oldsize + (oldsize > 0 ? 1 : 0);
    realsize = atomalign(realsize);

    // Save newdir in fs.xx because it will be updated if it is relocated.
    fs.i_backup  = newdir;

    if ((offset = data_prealloc(realsize)) <= 0)
        return EFFS_NOSPACE;

    // Use fs.journal.oldi because i would have been updated if
    // data_reclaim() relocate oldi
    oldip   = inode_addr(fs.journal.oldi);
    olddata = offset2addr(location2offset(oldip->location));
    olddata = addr2data(olddata, oldip);

    newi = object_create(newname, olddata, oldsize, fs.i_backup);
    
    tw(tr(TR_END, TrObject, "} %d\n", newi));
    return newi;
}


/******************************************************************************
 * Object Lookup
 ******************************************************************************/

// Lookup an object. Symlinks are followed.
iref_t object_lookup(const char *path, char **leaf, iref_t *dir)
{
    iref_t i;
    struct inode_s *ip;

    tw(tr(TR_BEGIN, TrLookup, "object_lookup('%s', ?, ?) {\n", path));
    ttw(ttr(TTrInode, "olu(%s){" NL, path));

    i = object_lookup_once(path, leaf, dir);
    ip = inode_addr(i);

    if (i > 0 && is_object(ip, OTE_LINK)) {
        path = offset2addr(location2offset(ip->location));
        path += ffs_strlen(path) + 1;  // point to data portion
        i = object_lookup_once(path, leaf, dir);

        // Links may only point to regular files...
        ip = inode_addr(i);
        if (+i > 0 && !is_object(ip, OTE_FILE))
            i = EFFS_NOTAFILE;
    }
    else { 
        if (leaf) leaf = 0;  
        if (dir) dir = 0;
    }
    tw(tr(TR_END, TrLookup, "} (%d, '%s') %d\n",
          (dir ? *dir : 0), (leaf ? *leaf : ""), i));

    ttw(ttr(TTrInode, "} %d" NL, i));
    return i;
}

// Lookup an object.  If object is found: Return iref of object and
// directory of object in <dir>. If object is not found: Return
// EFFS_NOTFOUND and last directory component of path in <dir> and leafname
// of pathname in <leaf>
iref_t object_lookup_once(const char *path, char **leaf, iref_t *dir)
{
    iref_t i, j, d;
    struct inode_s *ip;
    const char *p, *q;
    uint8 depth = 1;

    tw(tr(TR_FUNC, TrLookup, "object_lookup_once('%s', ?, ?) { ", path));

    if (path == NULL) 
        return EFFS_BADNAME;

    d = fs.root;
    if (*path == '/') {
        path++;  // silently ignore and skip prefix slash
        // root directory is a special case
        if (*path == 0) {
            j = d;
            if (leaf) *leaf = (char *) path;
            if (dir) *dir = 0;
            tw(tr(TR_NULL, TrLookup, "} ('%s', %d) %d\n", path, 0, j));
            return j;
        }
    }
    else
        return EFFS_BADNAME;

    // set default return value if root dir is completely empty
    // (child link empty) 
    j = EFFS_NOTFOUND;

    ip = inode_addr(d);

    while ((i = get_child(ip)) != (iref_t) IREF_NULL)
    {
        j = 0;  // default to not found
        do {
            tw(tr(TR_NULL, TrLookup, "i%d ", (int) i));

            p = path;
            ip = inode_addr(i);
            if (is_object_valid(ip) && !is_object(ip, OTE_SEGMENT)) {
                q = addr2name(offset2addr(location2offset(ip->location)));
                tw(tr(TR_NULL, TrLookup, "%s ", q));
                while (*p == *q && *p != 0 && *q != 0) {
                    p++;
                    q++;
                }
                if (*q == 0 && (*p == 0 || *p == '/')) {
                    j = i;
                    break;
                }
            }
        } while ((i = get_sibling(ip)) != (iref_t) IREF_NULL);


        if (j == 0) {
            // we did not find this component of the path. Let's
            // see if this was the leafname component or not...
            while (*p != 0 && *p != '/')
                p++;

            if (*p == 0)
                // The path component was indeed the leafname
                j = EFFS_NOTFOUND;
            else
                // The path component was not the last, so it
                // obviously contained an object that was not a
                // directory.
                j = EFFS_NOTADIR;
            break;
        }

        if (*p == '/') {
            // if there are more path components, the object found
            // must be a directory...
            if (!is_object(ip, OTE_DIR)) {
                j = EFFS_NOTADIR;
                break;
            }
            if (++depth > fs.path_depth_max) {
                j = EFFS_PATHTOODEEP;
                break;
            }
            path = p + 1;
            d = i;

            // if this dir inode has no children, we will leave the
            // while loop, so we preset the return error code. NOTEME:
            // Not strictly correct because if we still have a lot of
            // the pathname left, it should return the error
            // EFFS_NOTADIR
            j = EFFS_NOTFOUND;

            tw(tr(TR_NULL, TrLookup, "/ "));

        }
        else {
            // It is a fact that *p == 0. So we found the object!
            break;
        }
    }

    if (leaf) *leaf = (char *) path;
    if (dir) *dir = d;

    tw(tr(TR_NULL, TrLookup, "} (%d, '%s') %d\n", d, path, j));

    return j;
}

/******************************************************************************
 * Directory Operations
 ******************************************************************************/

// Open a directory, returning the iref of the directory's inode.
iref_t dir_open(const char *name)
{
    iref_t i;
    struct inode_s *ip;

    tw(tr(TR_BEGIN, TrDirHigh, "dir_open('%s') {\n", name));

    if ((i = object_lookup(name, 0, 0)) < 0) {
        tw(tr(TR_END, TrDirHigh, "} %d\n", i));
        return i;
    }

    ip = inode_addr(i);
    if (!is_object(ip, OTE_DIR))
        i = EFFS_NOTADIR;

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

    return i;
}

// Return name and iref of next entry in directory <dir>. <i> is the last
// entry we returned from this function. In case this is the first call
// after the initial call to dir_open(), <i> equals <dir>.
iref_t dir_next(iref_t dir, iref_t i, char *name, int8 size)
{
    struct inode_s *ip = inode_addr(i);
    char *p;

    tw(tr(TR_BEGIN, TrDirHigh, "dir_next(%d, %d, ?, %d) {\n", dir, i, size));

    i = (i == dir ? get_child(ip) : get_sibling(ip));

    while (i != (iref_t) IREF_NULL) {
        ip = inode_addr(i);
        if (is_object_valid(ip)) {
            p = offset2addr(location2offset(ip->location));
            while (size-- && (*name++ = *p++))
                ;
            break;
        }
        i = get_sibling(ip);
    }
    if (i == (iref_t) IREF_NULL)
        i = 0;

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

    return i;
}

// Traverse a directory given by inode reference <i>. If <i> is negative, it
// refers to the actual directory so we start by traversing the child link.
// Otherwise if <i> is positive, it refers to an entry within the directory
// and we only traverse sibling links. Returns iref of last object in
// directory (or negative iref of directory if the child link is empty).
// <entries> is number of non-deleted objects in the dir (only valid if
// traversed from the start, eg. with negative <i>).
iref_t dir_traverse(iref_t i, iref_t *entries)
{
    iref_t j = 0, valid = 0, erased = 0, invalid = 0;
    struct inode_s *ip;

    tw(tr(TR_FUNC, TrDirLow, "dir_traverse(%d, ?) { ", i));

    if (i < 0) {
        // If directory's child is empty, this is a virgin directory and we
        // return negative iref of the directory itself.
        j = i;
        i = -i;
        ip = inode_addr(i);
        i = get_child(ip);
    }
    if (i != (iref_t) IREF_NULL) {
        do {
            if (j == i) {
                tw(tr(TR_NULL, TrDirLow, "LOOP! "));
                return EFFS_SIBLINGLOOP;
            }
            
            j = i;
            ip = inode_addr(j);

            tw(tr(TR_NULL, TrDirLow, "%d/%x ", j, ip->flags));

            if (is_object_valid(ip))
                valid++;
            else if (is_object_erased(ip))
                erased++;
            else
                invalid++;

        } while ((i = get_sibling(ip)) != (iref_t) IREF_NULL);
    }

    if (entries != 0)
        *entries = valid;

    tw(tr(TR_NULL, TrDirLow, "} (valid = %d, erased = %d, invalid = %d) %d\n",
          valid, erased, invalid, j));

    return j;
}


/******************************************************************************
 * Block, Inode and Data Allocation
 ******************************************************************************/

// Find the youngest free block. Return block index on success. If the
// argument <priority> is zero, this is a normal alloc and it will leave at
// least fs.blocks_free_min spare blocks. Otherwise, if it is non-zero, it
// is a privileged alloc (initiated by a reclaim operation) and it will not
// necessarily leave any spare blocks.
bref_t block_alloc(bref_t priority, uint16 flags)
{
    bref_t i, b, b_min, b_max, blocks_free;
    struct block_header_s *bhp;
    age_t age, age_min, age_max;

    tw(tr(TR_BEGIN, TrBlock, "block_alloc(%d, 0x%x) {\n", priority, flags));
    ttw(ttr(TTrData, "ba(%d,0x%x) {" NL, priority, flags));

    age_min = BLOCK_AGE_MAX;
    age_max = 0;
    blocks_free = 0;
    b_min = b_max = -1;

    tw(tr(TR_FUNC, TrBlock, "blocks(age): "));
    for (i = dev.numblocks - 1; i >= 0; i--)
    {
        if (is_block(i, BF_IS_FREE))
        {
			blocks_free++;
            bhp = (struct block_header_s *) offset2addr(dev.binfo[i].offset);
			age = bhp->age;

            tw(tr(TR_NULL, TrBlock, "%d(%d) ", i, age));

            // Remember index of block found. We use '<=' and '>=' operators
            // (instead of '<' and '>') to ensure we have both limits
            // properly set on exit from this loop.
            if (age <= age_min) {
                b_min = i;
                age_min = age;
            }
            if (age >= age_max) {
                b_max = i;
                age_max = age;
            } 
        }
    }
    tw(tr(TR_NULL, TrBlock, "\n"));

    // Handle age wrap around
    b = b_min;
    if (b_min != -1) {
        // Either age_max really is max age, so b_min is youngest block OR
        // age_max really is min age, so b_max is youngest block
        b = (age_max - age_min) < 0x8000 ? b_min : b_max;
    }
    
    // Only privileged allocs will get the last free block
    if (blocks_free <= fs.blocks_free_min - priority) {
        b = -1;
        tw(tr(TR_FUNC, TrBlock, "Only %d block(s) left, required = %d\n",
              blocks_free, fs.blocks_free_min - priority));
    }
    else {
        // Prepare/format the block for holding data/inodes
        if (flags == BF_DATA) {
            bstat[b].used = BHEADER_SIZE;
            bstat[b].lost = 0; 
            bstat[b].objects = 0;
            block_flags_write(b, BF_DATA);
        }
        else if (flags == BF_COPYING) {
            // This code is used on a fresh format and when allocating a new
            // block for reclaiming inodes
            block_flags_write(b, BF_COPYING);
            bstat[b].used = 0;
            bstat[b].lost = 0;
            bstat[b].objects = 1;  // first inode to be allocated
        }
        else {
            tw(tr(TR_FUNC, TrBlock, "FATAL: Bad input (flags = 0x%X)\n", flags));
        }
    }

    tw(tr(TR_END, TrBlock, "} (%d) %d\n", blocks_free, b));
    ttw(ttr(TTrData, "} 0x%x" NL, b));

    return b;
}

// Free and schedule a block for erase.

⌨️ 快捷键说明

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