/*
 * Copyright (c) 2016 Samsung Electronics Co., Ltd. All rights reserved.
 *
 * Created in Samsung Ukraine R&D Center (SRK) under a contract between
 * LLC "Samsung Electronics Ukraine Company" (Kiev, Ukraine)
 * and "Samsung Electronics Co", Ltd (Seoul, Republic of Korea)
 */

/**
 * @file TigerCounterDataStore.c
 * @brief Implements functionality of TEE internal and background synchronization counter.
 * @author Konstyantyn Volobuyev <k.volobuyev@samsung.com>
 * @date Created Jul 26, 2016
 */

#include "TigerCounterDataStore.h"

#include <stdio.h>
#include <limits.h>

#include "TigerKeyDataStore.h"
#include "TigerLogging.h"
#include "TigerMacroses.h"
#include "TigerStorageUtils.h"
#include "TzwString.h"

TEE_Result tigerSetCounter(TigerCounter_t val) {
    LOG_FUNC_BEGIN;
    TzwSfsObject_t objHandle = TEE_HANDLE_NULL;
    TEE_Result status = TEE_SUCCESS;
    do {
        status = tzwOpenSfsObject((void*) TIGER_REGISTRATION_INFO_ALIAS, strlen(TIGER_REGISTRATION_INFO_ALIAS),
                TEE_DATA_FLAG_ACCESS_WRITE, &objHandle);
        TIGER_CHECK_TEE_STATUS_SUCCESS_BREAK("Open device id object");

        int32_t counterOffset = getOffsetTo(COUNTER);
        TIGER_ASSERT(counterOffset != -1);

        // seek to counter field in device info file
        status = tzwSeekIntoSfsObject(objHandle, counterOffset, TEE_DATA_SEEK_SET);
        TIGER_CHECK_TEE_STATUS_SUCCESS_BREAK("Seek to counter field.");

        status = tzwWriteToSfsObject(objHandle, &val, sizeof(val));
        TIGER_CHECK_TEE_STATUS_SUCCESS_BREAK("tzwWriteToSfsObject");
    } while(0);

    tzwCloseSfsObject(objHandle);
    LOG_FUNC_END;

    return status;
}

TEE_Result tigerGetCounter(TigerCounter_t* val) {
    LOG_FUNC_BEGIN;
    TIGER_ASSERT(val != NULL);

    TzwSfsObject_t objHandle = TEE_HANDLE_NULL;
    TEE_Result status = TEE_SUCCESS;
    do {
        status = tzwOpenSfsObject((void*) TIGER_REGISTRATION_INFO_ALIAS, strlen(TIGER_REGISTRATION_INFO_ALIAS),
                                    TEE_DATA_FLAG_ACCESS_READ, &objHandle);
        TIGER_CHECK_TEE_STATUS_SUCCESS_BREAK("Open device id object");

        int32_t counterOffset = getOffsetTo(COUNTER);
        TIGER_ASSERT(counterOffset != -1);

        // seek to counter field in device info file
        status = tzwSeekIntoSfsObject(objHandle, counterOffset, TEE_DATA_SEEK_SET);
        TIGER_CHECK_TEE_STATUS_SUCCESS_BREAK("Seek to counter field.");

        TigerCounter_t counterVal = 0;
        uint32_t count = 0;
        status = tzwReadFromSfsObject(objHandle, &counterVal, sizeof(counterVal), &count);
        TIGER_CHECK_TEE_STATUS_SUCCESS_BREAK("tzwReadFromSfsObject");
        TIGER_CHECK_CONDITION_BREAK(count == sizeof(counterVal));

        *val = counterVal;
        LOG_D("get counter value is : %d", counterVal);
    } while(0);

    tzwCloseSfsObject(objHandle);
    LOG_FUNC_END;

    return status;
}

TEE_Result tigerIncCounter() {
    LOG_FUNC_BEGIN;

    TzwSfsObject_t objHandle = TEE_HANDLE_NULL;
    TEE_Result status = TEE_SUCCESS;
    do {
        status = tzwOpenSfsObject((void*) TIGER_REGISTRATION_INFO_ALIAS, strlen(TIGER_REGISTRATION_INFO_ALIAS),
                                    TEE_DATA_FLAG_ACCESS_READ | TEE_DATA_FLAG_ACCESS_WRITE, &objHandle);
        TIGER_CHECK_TEE_STATUS_SUCCESS_BREAK("Open device id object");

        int32_t counterOffset = getOffsetTo(COUNTER);
        TIGER_ASSERT(counterOffset != -1);

        // seek to counter field in device info file
        status = tzwSeekIntoSfsObject(objHandle, counterOffset, TEE_DATA_SEEK_SET);
        TIGER_CHECK_TEE_STATUS_SUCCESS_BREAK("Seek to counter field.");

        TigerCounter_t counterVal = 0;
        uint32_t count = 0;
        status = tzwReadFromSfsObject(objHandle, &counterVal, sizeof(counterVal), &count);
        TIGER_CHECK_TEE_STATUS_SUCCESS_BREAK("tzwReadFromSfsObject");
        if(0 != count) {
            TIGER_CHECK_CONDITION_BREAK(count == sizeof(counterVal));
        }

        ++counterVal;

        status = tzwSeekIntoSfsObject(objHandle, counterOffset, TEE_DATA_SEEK_SET);
        TIGER_CHECK_TEE_STATUS_SUCCESS_BREAK("Seek to counter field.");

        status = tzwWriteToSfsObject(objHandle, &counterVal, sizeof(counterVal));
        TIGER_CHECK_TEE_STATUS_SUCCESS_BREAK("tzwWriteToSfsObject");

    } while(0);

    tzwCloseSfsObject(objHandle);
    LOG_FUNC_END;
    return status;
}

TEE_Result tigerGetIncCounter(TigerCounter_t* val) {
    LOG_FUNC_BEGIN;
    TIGER_ASSERT(val != NULL);

    TzwSfsObject_t objHandle = TEE_HANDLE_NULL;
    TEE_Result status = TEE_SUCCESS;
    do {
        status = tzwOpenSfsObject((void*) TIGER_REGISTRATION_INFO_ALIAS, strlen(TIGER_REGISTRATION_INFO_ALIAS),
                                    TEE_DATA_FLAG_ACCESS_READ | TEE_DATA_FLAG_ACCESS_WRITE, &objHandle);
        TIGER_CHECK_TEE_STATUS_SUCCESS_BREAK("Open device id object");

        int32_t counterOffset = getOffsetTo(COUNTER);
        TIGER_ASSERT(counterOffset != -1);

        // seek to counter field in device info file
        status = tzwSeekIntoSfsObject(objHandle, counterOffset, TEE_DATA_SEEK_SET);
        TIGER_CHECK_TEE_STATUS_SUCCESS_BREAK("Seek to counter field.");

        TigerCounter_t counterVal = 0;
        uint32_t count = 0;
        status = tzwReadFromSfsObject(objHandle, &counterVal, sizeof(counterVal), &count);
        TIGER_CHECK_TEE_STATUS_SUCCESS_BREAK("tzwReadFromSfsObject");
        if(0 != count) {
            TIGER_CHECK_CONDITION_BREAK(count == sizeof(counterVal));
        }

        ++counterVal;

        status = tzwSeekIntoSfsObject(objHandle, counterOffset, TEE_DATA_SEEK_SET);
        TIGER_CHECK_TEE_STATUS_SUCCESS_BREAK("Seek to counter field.");

        status = tzwWriteToSfsObject(objHandle, &counterVal, sizeof(counterVal));
        TIGER_CHECK_TEE_STATUS_SUCCESS_BREAK("tzwWriteToSfsObject");

        *val = counterVal;

    } while(0);

    tzwCloseSfsObject(objHandle);
    LOG_FUNC_END;
    return status;
}

