HelenOS sources

root/uspace/srv/fs/exfat/exfat_bitmap.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. exfat_bitmap_is_free
  2. exfat_bitmap_set_cluster
  3. exfat_bitmap_clear_cluster
  4. exfat_bitmap_set_clusters
  5. exfat_bitmap_clear_clusters
  6. exfat_bitmap_alloc_clusters
  7. exfat_bitmap_append_clusters
  8. exfat_bitmap_free_clusters
  9. exfat_bitmap_replicate_clusters

/*
 * Copyright (c) 2011 Oleg Romanenko
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * - Redistributions of source code must retain the above copyright
 *   notice, this list of conditions and the following disclaimer.
 * - Redistributions in binary form must reproduce the above copyright
 *   notice, this list of conditions and the following disclaimer in the
 *   documentation and/or other materials provided with the distribution.
 * - The name of the author may not be used to endorse or promote products
 *   derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

/** @addtogroup exfat
 * @{
 */

/**
 * @file        exfat_bitmap.c
 * @brief       Functions that manipulate the Bitmap Table.
 */

#include "exfat_bitmap.h"
#include "../../vfs/vfs.h"
#include <libfs.h>
#include <block.h>
#include <errno.h>
#include <byteorder.h>
#include <align.h>
#include <assert.h>
#include <fibril_synch.h>
#include <mem.h>

errno_t exfat_bitmap_is_free(exfat_bs_t *bs, service_id_t service_id,
    exfat_cluster_t clst)
{
        fs_node_t *fn;
        block_t *b = NULL;
        exfat_node_t *bitmapp;
        uint8_t *bitmap;
        errno_t rc;
        bool alloc;

        clst -= EXFAT_CLST_FIRST;

        rc = exfat_bitmap_get(&fn, service_id);
        if (rc != EOK)
                return rc;
        bitmapp = EXFAT_NODE(fn);

        aoff64_t offset = clst / 8;
        rc = exfat_block_get(&b, bs, bitmapp, offset / BPS(bs), BLOCK_FLAGS_NONE);
        if (rc != EOK) {
                (void) exfat_node_put(fn);
                return rc;
        }
        bitmap = (uint8_t *)b->data;
        alloc = bitmap[offset % BPS(bs)] & (1 << (clst % 8));

        rc = block_put(b);
        if (rc != EOK) {
                (void) exfat_node_put(fn);
                return rc;
        }
        rc = exfat_node_put(fn);
        if (rc != EOK)
                return rc;

        if (alloc)
                return ENOENT;

        return EOK;
}

errno_t exfat_bitmap_set_cluster(exfat_bs_t *bs, service_id_t service_id,
    exfat_cluster_t clst)
{
        fs_node_t *fn;
        block_t *b = NULL;
        exfat_node_t *bitmapp;
        uint8_t *bitmap;
        errno_t rc;

        clst -= EXFAT_CLST_FIRST;

        rc = exfat_bitmap_get(&fn, service_id);
        if (rc != EOK)
                return rc;
        bitmapp = EXFAT_NODE(fn);

        aoff64_t offset = clst / 8;
        rc = exfat_block_get(&b, bs, bitmapp, offset / BPS(bs), BLOCK_FLAGS_NONE);
        if (rc != EOK) {
                (void) exfat_node_put(fn);
                return rc;
        }
        bitmap = (uint8_t *)b->data;
        bitmap[offset % BPS(bs)] |= (1 << (clst % 8));

        b->dirty = true;
        rc = block_put(b);
        if (rc != EOK) {
                (void) exfat_node_put(fn);
                return rc;
        }

        return exfat_node_put(fn);
}

errno_t exfat_bitmap_clear_cluster(exfat_bs_t *bs, service_id_t service_id,
    exfat_cluster_t clst)
{
        fs_node_t *fn;
        block_t *b = NULL;
        exfat_node_t *bitmapp;
        uint8_t *bitmap;
        errno_t rc;

        clst -= EXFAT_CLST_FIRST;

        rc = exfat_bitmap_get(&fn, service_id);
        if (rc != EOK)
                return rc;
        bitmapp = EXFAT_NODE(fn);

        aoff64_t offset = clst / 8;
        rc = exfat_block_get(&b, bs, bitmapp, offset / BPS(bs),
            BLOCK_FLAGS_NONE);
        if (rc != EOK) {
                (void) exfat_node_put(fn);
                return rc;
        }
        bitmap = (uint8_t *)b->data;
        bitmap[offset % BPS(bs)] &= ~(1 << (clst % 8));

        b->dirty = true;
        rc = block_put(b);
        if (rc != EOK) {
                (void) exfat_node_put(fn);
                return rc;
        }

        return exfat_node_put(fn);
}

errno_t exfat_bitmap_set_clusters(exfat_bs_t *bs, service_id_t service_id,
    exfat_cluster_t firstc, exfat_cluster_t count)
{
        errno_t rc;
        exfat_cluster_t clst;
        clst = firstc;

        while (clst < firstc + count) {
                rc = exfat_bitmap_set_cluster(bs, service_id, clst);
                if (rc != EOK) {
                        if (clst - firstc > 0)
                                (void) exfat_bitmap_clear_clusters(bs, service_id,
                                    firstc, clst - firstc);
                        return rc;
                }
                clst++;
        }
        return EOK;
}

errno_t exfat_bitmap_clear_clusters(exfat_bs_t *bs, service_id_t service_id,
    exfat_cluster_t firstc, exfat_cluster_t count)
{
        errno_t rc;
        exfat_cluster_t clst;
        clst = firstc;

        while (clst < firstc + count) {
                rc = exfat_bitmap_clear_cluster(bs, service_id, clst);
                if (rc != EOK)
                        return rc;
                clst++;
        }
        return EOK;
}

errno_t exfat_bitmap_alloc_clusters(exfat_bs_t *bs, service_id_t service_id,
    exfat_cluster_t *firstc, exfat_cluster_t count)
{
        exfat_cluster_t startc, endc;
        startc = EXFAT_CLST_FIRST;

        while (startc < DATA_CNT(bs) + 2) {
                endc = startc;
                while (exfat_bitmap_is_free(bs, service_id, endc) == EOK) {
                        if ((endc - startc) + 1 == count) {
                                *firstc = startc;
                                return exfat_bitmap_set_clusters(bs, service_id, startc, count);
                        } else
                                endc++;
                }
                startc = endc + 1;
        }
        return ENOSPC;
}

errno_t exfat_bitmap_append_clusters(exfat_bs_t *bs, exfat_node_t *nodep,
    exfat_cluster_t count)
{
        if (nodep->firstc == 0) {
                return exfat_bitmap_alloc_clusters(bs, nodep->idx->service_id,
                    &nodep->firstc, count);
        } else {
                exfat_cluster_t lastc, clst;
                lastc = nodep->firstc + ROUND_UP(nodep->size, BPC(bs)) / BPC(bs) - 1;

                clst = lastc + 1;
                while (exfat_bitmap_is_free(bs, nodep->idx->service_id, clst) == EOK) {
                        if (clst - lastc == count) {
                                return exfat_bitmap_set_clusters(bs, nodep->idx->service_id,
                                    lastc + 1, count);
                        } else
                                clst++;
                }
                return ENOSPC;
        }
}

errno_t exfat_bitmap_free_clusters(exfat_bs_t *bs, exfat_node_t *nodep,
    exfat_cluster_t count)
{
        exfat_cluster_t lastc;
        lastc = nodep->firstc + ROUND_UP(nodep->size, BPC(bs)) / BPC(bs) - 1;
        lastc -= count;

        return exfat_bitmap_clear_clusters(bs, nodep->idx->service_id, lastc + 1, count);
}

errno_t exfat_bitmap_replicate_clusters(exfat_bs_t *bs, exfat_node_t *nodep)
{
        errno_t rc;
        exfat_cluster_t lastc, clst;
        service_id_t service_id = nodep->idx->service_id;
        lastc = nodep->firstc + ROUND_UP(nodep->size, BPC(bs)) / BPC(bs) - 1;

        for (clst = nodep->firstc; clst < lastc; clst++) {
                rc = exfat_set_cluster(bs, service_id, clst, clst + 1);
                if (rc != EOK)
                        return rc;
        }

        return exfat_set_cluster(bs, service_id, lastc, EXFAT_CLST_EOF);
}

/**
 * @}
 */

/* [<][>][^][v][top][bottom][index][help] */
HelenOS homepage, sources at GitHub