HelenOS sources

root/uspace/lib/label/src/empty.c

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

DEFINITIONS

This source file includes following definitions.
  1. mem_is_zero
  2. calc_num_check_blocks
  3. label_bd_is_empty
  4. label_bd_empty
  5. label_part_empty

/*
 * Copyright (c) 2015 Jiri Svoboda
 * 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 liblabel
 * @{
 */
/**
 * @file Empty partition handling
 * @brief
 */

#include <errno.h>
#include <io/log.h>
#include <label/empty.h>
#include <loc.h>
#include <stdlib.h>

/*
 * The partition will be considered empty if at least a minimum number of
 * bytes *and* blocks (whichever is larger) at the beginning and end of
 * the partition is zero.
 */
enum {
        min_empty_bytes = 16384,
        /*
         * First block in ISO 9660 that cannot be empty is the first
         * volume descriptor at LBA 16
         */
        min_empty_blocks = 17
};

static bool mem_is_zero(void *buf, size_t size)
{
        uint8_t *bp;
        size_t i;

        bp = (uint8_t *)buf;
        for (i = 0; i < size; i++) {
                if (bp[i] != 0)
                        return false;
        }

        return true;
}

/** Calculate number of blocks to check.
 *
 * Will store to @a *ncb the number of blocks that should be checked
 * at the beginning and end of device each.
 *
 * @param nblocks Total number of blocks on block device
 * @param block_size Block size
 * @param ncb Place to store number of blocks to check.
 */
static void calc_num_check_blocks(aoff64_t nblocks, size_t block_size,
    aoff64_t *ncb)
{
        aoff64_t n;

        /* Check first 16 kiB / 16 blocks, whichever is more */
        n = (min_empty_bytes + block_size - 1) / block_size;
        if (n < min_empty_blocks)
                n = min_empty_blocks;
        /*
         * Limit to half of the device so we do not process the same blocks
         * twice
         */
        if (n > (nblocks + 1) / 2)
                n = (nblocks + 1) / 2;

        *ncb = n;
}

errno_t label_bd_is_empty(label_bd_t *bd, bool *rempty)
{
        errno_t rc;
        void *buf = NULL;
        aoff64_t nblocks;
        aoff64_t n;
        aoff64_t i;
        size_t block_size;
        bool empty;

        rc = bd->ops->get_bsize(bd->arg, &block_size);
        if (rc != EOK) {
                log_msg(LOG_DEFAULT, LVL_ERROR, "Error getting "
                    "block size.");
                rc = EIO;
                goto error;
        }

        rc = bd->ops->get_nblocks(bd->arg, &nblocks);
        if (rc != EOK) {
                log_msg(LOG_DEFAULT, LVL_ERROR, "Error getting "
                    "number of blocks.");
                rc = EIO;
                goto error;
        }

        calc_num_check_blocks(nblocks, block_size, &n);

        buf = calloc(block_size, 1);
        if (buf == NULL) {
                log_msg(LOG_DEFAULT, LVL_ERROR, "Error allocating buffer.");
                rc = ENOMEM;
                goto error;
        }

        empty = true;

        for (i = 0; i < n; i++) {
                rc = bd->ops->read(bd->arg, i, 1, buf);
                if (rc != EOK) {
                        log_msg(LOG_DEFAULT, LVL_ERROR, "Error "
                            "reading blocks.");
                        rc = EIO;
                        goto error;
                }

                if (!mem_is_zero(buf, block_size)) {
                        empty = false;
                        goto done;
                }
        }

        for (i = 0; i < n; i++) {
                rc = bd->ops->read(bd->arg, nblocks - n + i, 1, buf);
                if (rc != EOK) {
                        log_msg(LOG_DEFAULT, LVL_ERROR, "Error "
                            "reading blocks.");
                        rc = EIO;
                        goto error;
                }

                if (!mem_is_zero(buf, block_size)) {
                        empty = false;
                        goto done;
                }
        }

done:
        free(buf);
        *rempty = empty;
        return EOK;
error:
        if (buf != NULL)
                free(buf);
        return rc;
}

errno_t label_bd_empty(label_bd_t *bd)
{
        errno_t rc;
        void *buf = NULL;
        aoff64_t nblocks;
        aoff64_t n;
        aoff64_t i;
        size_t block_size;

        rc = bd->ops->get_bsize(bd->arg, &block_size);
        if (rc != EOK) {
                log_msg(LOG_DEFAULT, LVL_ERROR, "Error getting "
                    "block size.");
                rc = EIO;
                goto error;
        }

        rc = bd->ops->get_nblocks(bd->arg, &nblocks);
        if (rc != EOK) {
                log_msg(LOG_DEFAULT, LVL_ERROR, "Error getting "
                    "number of blocks.");
                rc = EIO;
                goto error;
        }

        calc_num_check_blocks(nblocks, block_size, &n);

        buf = calloc(block_size, 1);
        if (buf == NULL) {
                log_msg(LOG_DEFAULT, LVL_ERROR, "Error allocating buffer.");
                rc = ENOMEM;
                goto error;
        }

        for (i = 0; i < n; i++) {
                rc = bd->ops->write(bd->arg, i, 1, buf);
                if (rc != EOK) {
                        log_msg(LOG_DEFAULT, LVL_ERROR, "Error "
                            "reading blocks.");
                        rc = EIO;
                        goto error;
                }
        }

        for (i = 0; i < n; i++) {
                rc = bd->ops->write(bd->arg, nblocks - n + i, 1, buf);
                if (rc != EOK) {
                        log_msg(LOG_DEFAULT, LVL_ERROR, "Error "
                            "reading blocks.");
                        rc = EIO;
                        goto error;
                }
        }

        free(buf);
        return EOK;
error:
        if (buf != NULL)
                free(buf);
        return rc;
}

errno_t label_part_empty(label_part_t *part)
{
        errno_t rc;
        void *buf = NULL;
        aoff64_t block0;
        aoff64_t nblocks;
        aoff64_t n;
        aoff64_t i;
        size_t block_size;
        label_bd_t *bd;

        bd = &part->label->bd;

        block_size = part->label->block_size;
        block0 = part->block0;
        nblocks = part->nblocks;

        calc_num_check_blocks(nblocks, block_size, &n);

        buf = calloc(block_size, 1);
        if (buf == NULL) {
                log_msg(LOG_DEFAULT, LVL_ERROR, "Error allocating buffer.");
                rc = ENOMEM;
                goto error;
        }

        for (i = 0; i < n; i++) {
                rc = bd->ops->write(bd->arg, block0 + i, 1, buf);
                if (rc != EOK) {
                        log_msg(LOG_DEFAULT, LVL_ERROR, "Error "
                            "reading blocks.");
                        rc = EIO;
                        goto error;
                }
        }

        for (i = 0; i < n; i++) {
                rc = bd->ops->write(bd->arg, block0 + nblocks - n + i, 1, buf);
                if (rc != EOK) {
                        log_msg(LOG_DEFAULT, LVL_ERROR, "Error "
                            "reading blocks.");
                        rc = EIO;
                        goto error;
                }
        }

        free(buf);
        return EOK;
error:
        if (buf != NULL)
                free(buf);
        return rc;
}

/** @}
 */

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