示例#1
0
fsw_status_t fsw_dnode_create_with_tree(struct fsw_dnode *parent_dno, fsw_u64 tree_id, fsw_u64 dnode_id, int type,
                              struct fsw_string *name, struct fsw_dnode **dno_out)
{
    fsw_status_t    status;
    struct fsw_volume *vol = parent_dno->vol;
    struct fsw_dnode *dno;

    // check if we already have a dnode with the same id
    for (dno = vol->dnode_head; dno; dno = dno->next) {
        if (dno->dnode_id == dnode_id && dno->tree_id == tree_id) {
            fsw_dnode_retain(dno);
            *dno_out = dno;
            return FSW_SUCCESS;
        }
    }

    // allocate memory for the structure
    status = fsw_alloc_zero(vol->fstype_table->dnode_struct_size, (void **)&dno);
    if (status)
        return status;

    // fill the structure
    dno->vol = vol;
    dno->parent = parent_dno;
    fsw_dnode_retain(dno->parent);
    dno->tree_id = tree_id;
    dno->dnode_id = dnode_id;
    dno->type = type;
    dno->refcount = 1;
    status = fsw_strdup_coerce(&dno->name, vol->host_table->native_string_type, name);
    if (status) {
        fsw_free(dno);
        return status;
    }

    fsw_dnode_register(vol, dno);

    *dno_out = dno;
    return FSW_SUCCESS;
}
示例#2
0
fsw_status_t fsw_dnode_resolve(struct fsw_dnode *dno, struct fsw_dnode **target_dno_out)
{
    fsw_status_t    status;
    struct fsw_string target_name;
    struct fsw_dnode *target_dno;
    /* Linux kernel max link count is 40 */
    int link_count = 40;

    fsw_dnode_retain(dno);

    while (--link_count > 0) {
        // get full information
        status = fsw_dnode_fill(dno);
        if (status)
            goto errorexit;
        if (dno->type != FSW_DNODE_TYPE_SYMLINK) {
            // found a non-symlink target, return it
            *target_dno_out = dno;
            return FSW_SUCCESS;
        }
        if (dno->parent == NULL) {    // safety measure, cannot happen in theory
            status = FSW_NOT_FOUND;
            goto errorexit;
        }

        // read the link's target
        status = fsw_dnode_readlink(dno, &target_name);
        if (status)
            goto errorexit;

        // resolve it
        status = fsw_dnode_lookup_path(dno->parent, &target_name, '/', &target_dno);
        fsw_strfree(&target_name);
        if (status)
            goto errorexit;

        // target_dno becomes the new dno
        fsw_dnode_release(dno);
        dno = target_dno;   // is already retained
    }
    if(link_count == 0)
      status = FSW_NOT_FOUND;

errorexit:
    fsw_dnode_release(dno);
    return status;
}
fsw_status_t fsw_shandle_open(struct fsw_dnode *dno, struct fsw_shandle *shand)
{
    fsw_status_t    status;
    struct fsw_volume *vol = dno->vol;

    // read full dnode information into memory
    status = vol->fstype_table->dnode_fill(vol, dno);
    if (status)
        return status;

    // setup shandle
    fsw_dnode_retain(dno);

    shand->dnode = dno;
    shand->pos = 0;
    shand->extent.type = FSW_EXTENT_TYPE_INVALID;

    return FSW_SUCCESS;
}
fsw_status_t fsw_dnode_lookup_path(struct fsw_dnode *dno,
                                   struct fsw_string *lookup_path, char separator,
                                   struct fsw_dnode **child_dno_out)
{
    fsw_status_t    status;
    struct fsw_volume *vol = dno->vol;
    struct fsw_dnode *child_dno = NULL;
    struct fsw_string lookup_name;
    struct fsw_string remaining_path;
    int             root_if_empty;

    remaining_path = *lookup_path;
    fsw_dnode_retain(dno);

    // loop over the path
    for (root_if_empty = 1; fsw_strlen(&remaining_path) > 0; root_if_empty = 0) {
        // parse next path component
        fsw_strsplit(&lookup_name, &remaining_path, separator);

        FSW_MSG_DEBUG((FSW_MSGSTR("fsw_dnode_lookup_path: split into %d '%s' and %d '%s'\n"),
                       lookup_name.len, lookup_name.data,
                       remaining_path.len, remaining_path.data));

        if (fsw_strlen(&lookup_name) == 0) {        // empty path component
            if (root_if_empty)
                child_dno = vol->root;
            else
                child_dno = dno;
            fsw_dnode_retain(child_dno);

        } else {
            // do an actual directory lookup

            // ensure we have full information
            status = fsw_dnode_fill(dno);
            if (status)
                goto errorexit;

            // resolve symlink if necessary
            if (dno->type == FSW_DNODE_TYPE_SYMLINK) {
                status = fsw_dnode_resolve(dno, &child_dno);
                if (status)
                    goto errorexit;

                // symlink target becomes the new dno
                fsw_dnode_release(dno);
                dno = child_dno;   // is already retained
                child_dno = NULL;

                // ensure we have full information
                status = fsw_dnode_fill(dno);
                if (status)
                    goto errorexit;
            }

            // make sure we operate on a directory
            if (dno->type != FSW_DNODE_TYPE_DIR) {
                return FSW_UNSUPPORTED;
                goto errorexit;
            }

            // check special paths
            if (fsw_streq_cstr(&lookup_name, ".")) {    // self directory
                child_dno = dno;
                fsw_dnode_retain(child_dno);

            } else if (fsw_streq_cstr(&lookup_name, "..")) {   // parent directory
                if (dno->parent == NULL) {
                    // We cannot go up from the root directory. Caution: Certain apps like the EFI shell
                    // rely on this behaviour!
                    status = FSW_NOT_FOUND;
                    goto errorexit;
                }
                child_dno = dno->parent;
                fsw_dnode_retain(child_dno);

            } else {
                // do an actual lookup
                status = vol->fstype_table->dir_lookup(vol, dno, &lookup_name, &child_dno);
                if (status)
                    goto errorexit;
            }
        }

        // child_dno becomes the new dno
        fsw_dnode_release(dno);
        dno = child_dno;   // is already retained
        child_dno = NULL;

        FSW_MSG_DEBUG((FSW_MSGSTR("fsw_dnode_lookup_path: now at inode %d\n"), dno->dnode_id));
    }

    *child_dno_out = dno;
    return FSW_SUCCESS;

errorexit:
    FSW_MSG_DEBUG((FSW_MSGSTR("fsw_dnode_lookup_path: leaving with error %d\n"), status));
    fsw_dnode_release(dno);
    if (child_dno != NULL)
        fsw_dnode_release(child_dno);
    return status;
}