void fsw_dnode_release(struct fsw_dnode *dno)
{
    struct fsw_volume *vol = dno->vol;
    struct fsw_dnode *parent_dno;

    dno->refcount--;

    if (dno->refcount == 0) {
        parent_dno = dno->parent;

        // de-register from volume's list
        if (dno->next)
            dno->next->prev = dno->prev;
        if (dno->prev)
            dno->prev->next = dno->next;
        if (vol->dnode_head == dno)
            vol->dnode_head = dno->next;

        // run fstype-specific cleanup
        vol->fstype_table->dnode_free(vol, dno);

        fsw_strfree(&dno->name);
        fsw_free(dno);

        // release our pointer to the parent, possibly deallocating it, too
        if (parent_dno)
            fsw_dnode_release(parent_dno);
    }
}
void fsw_unmount(struct fsw_volume *vol)
{
    if (vol->root)
        fsw_dnode_release(vol->root);
    /// @todo check that no other dnodes are still around

    vol->fstype_table->volume_free(vol);

    fsw_blockcache_free(vol);
    fsw_strfree(&vol->label);
    fsw_free(vol);
}
Beispiel #3
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;
}