/**
 * Check if the suite is corrupted
 * @param suiteId ID of a suite
 *
 * @return ALL_OK if the suite is not corrupted,
 *         SUITE_CORRUPTED_ERROR is suite is corrupted,
 *         OUT_OF_MEMORY if out of memory,
 *         IO_ERROR if I/O error
 */
MIDPError
check_for_corrupted_suite(SuiteIdType suiteId) {
    pcsl_string filename[NUM_SUITE_FILES];
    int arc[NUM_SUITE_FILES];
    int i;
    StorageIdType storageId;
    MIDPError status = ALL_OK; /* Default to no error */
    MidletSuiteData *pData = get_suite_data(suiteId);

    if (!pData) {
        return SUITE_CORRUPTED_ERROR;
    }

    /* if this suite was already checked, just return "OK" status */
    if (pData->isChecked) {
        return status;
    }

    /* get an id of the storage where the suite is located */
    status = midp_suite_get_suite_storage(suiteId, &storageId);
    if (status != ALL_OK) {
        return status;
    }

    arc[0] = get_suite_filename(suiteId, &INSTALL_INFO_FILENAME, &filename[0]);
    arc[1] = get_suite_filename(suiteId, &SETTINGS_FILENAME, &filename[1]);
    arc[2] = midp_suite_get_class_path(suiteId, storageId,
                                       KNI_FALSE, &filename[2]);
    arc[3] = get_property_file(suiteId, KNI_FALSE, &filename[3]);

    for (i = 0; i < NUM_SUITE_FILES; i++) {
        if (arc[i] != ALL_OK) {
            status = (MIDPError)arc[i];
            break;
        }

        if (!storage_file_exists(&filename[i])) {
            /* File does not exist; suite must be corrupted */
            status = SUITE_CORRUPTED_ERROR;
            break;
        }
    }

    if (status == ALL_OK) {
        /* if the suite is not currupted, mark it as "checked" */
        pData->isChecked = 1;
    }

    pcsl_string_free(&filename[0]);
    pcsl_string_free(&filename[1]);
    pcsl_string_free(&filename[2]);
    pcsl_string_free(&filename[3]);

    return status;
}
/**
 * Gets the amount of storage on the device that this suite is using.
 * This includes the JAD, JAR, management data, and RMS.
 *
 * @param suiteId  ID of the suite
 *
 * @return number of bytes of storage the suite is using or less than
 * OUT_OF_MEM_LEN if out of memory
 */
long
midp_get_suite_storage_size(SuiteIdType suiteId) {
    long used = 0;
    long rms = 0;
    pcsl_string filename[NUM_SUITE_FILES];
    int i;
    char* pszError;
    StorageIdType storageId;
    MIDPError status;
    MidletSuiteData* pData;
    pcsl_string filenameBase;

    // get the filename base from the suite id
    status = build_suite_filename(suiteId, &PCSL_STRING_EMPTY, 
                                            &filenameBase);
    
    if (status != ALL_OK) {
        return status;
    }
    pData = get_suite_data(suiteId);
    if (pData) {
        used = (jint)pData->suiteSize;
    }

    if (used <= 0) {
        /* Suite size is not cached (should not happen!), calculate it. */
        for (i = 0; i < NUM_SUITE_FILES; i++) {
            filename[i] = PCSL_STRING_NULL;
        }

        /*
         * This is a public API which can be called without the VM running
         * so we need automatically init anything needed, to make the
         * caller's code less complex.
         *
         * Initialization is performed in steps so that we do use any
         * extra resources such as the VM for the operation being performed.
         */
        if (midpInit(LIST_LEVEL) != 0) {
            return OUT_OF_MEM_LEN;
        }

        status = midp_suite_get_suite_storage(suiteId, &storageId);
        if (status != ALL_OK) {
            return OUT_OF_MEM_LEN;
        }

        status = build_suite_filename(suiteId, &INSTALL_INFO_FILENAME, &filename[0]);
        if (status != ALL_OK) {
            return status;
        }
        status = build_suite_filename(suiteId, &SETTINGS_FILENAME, &filename[1]);
        if (status != ALL_OK) {
            return status;
        }
        midp_suite_get_class_path(suiteId, storageId, KNI_TRUE, &filename[2]);
        get_property_file(suiteId, KNI_TRUE, &filename[3]);

        for (i = 0; i < NUM_SUITE_FILES; i++) {
            long tmp;

            if (pcsl_string_is_null(&filename[i])) {
                continue;
            }

            tmp = storage_size_of_file_by_name(&pszError, &filename[i]);
            pcsl_string_free(&filename[i]);

            if (pszError != NULL) {
                storageFreeError(pszError);
                continue;
            }

            used += tmp;
        }

        if (pData) {
            /* cache the calculated size */
            pData->suiteSize = (jint)used;
            status = write_suites_data(&pszError);
            if (status != ALL_OK) {
                storageFreeError(pszError);
                return OUT_OF_MEM_LEN;
            }
        }
    }

    rms = rmsdb_get_rms_storage_size(&filenameBase, suiteId);
    if (rms == OUT_OF_MEM_LEN) {
        return OUT_OF_MEM_LEN;
    }

    return used + rms;
}
/**
 * Moves a software package with given suite ID to the specified storage.
 *
 * @param suiteId suite ID for the installed package
 * @param storageId new storage ID
 *
 * @return SUITE_LOCKED if the
 * suite is locked, NOT_FOUND if the suite cannot be found or
 * invalid storage ID specified, BAD_PARAMS if attempt is made
 * to move suite to the external storage, GENERAL_ERROR if
 * VERIFY_ONCE is not enabled and if MONET is enabled
 */
MIDPError
midp_change_suite_storage(SuiteIdType suiteId, StorageIdType newStorageId) {

#ifndef VERIFY_ONCE
    (void)suiteId;
    (void)newStorageId;
    return GENERAL_ERROR;
#else

   /*
    * if VERIFY_ONCE is enabled then MONET is disabled
    * so we don't have to check ENABLE_MONET.
    */

    {
        pcsl_string suiteRoot;
        MidletSuiteData* pData = NULL;
        int status;
        void* fileIteratorHandle = NULL;
        lockStorageList *node = NULL;

        if ((UNUSED_STORAGE_ID == newStorageId) ||
            (newStorageId >= MAX_STORAGE_NUM)) {
            return BAD_PARAMS;
        }

        /*
         * IMPL_NOTE: for security reasons we allow to move suite
         * only to the internal storage.
         */
        if (newStorageId != INTERNAL_STORAGE_ID) {
            return BAD_PARAMS;
        }

        node = find_storage_lock(suiteId);
        if (node != NULL) {
            if (node->update != KNI_TRUE) {
                return SUITE_LOCKED;
            }
        }

        /*
         * This is a public API which can be called without the VM running
         * so we need automatically init anything needed, to make the
         * caller's code less complex.
         *
         * Initialization is performed in steps so that we do use any
         * extra resources such as the VM for the operation being performed.
         */
        if (midpInit(REMOVE_LEVEL) != 0) {
            remove_storage_lock(suiteId);
            return OUT_OF_MEMORY;
        }

        /* check that the suite exists and it is not a preloaded one */
        pData = get_suite_data(suiteId);

        if (pData == NULL) {
            remove_storage_lock(suiteId);
            return NOT_FOUND;
        }

        if (pData->storageId == newStorageId) {
            remove_storage_lock(suiteId);
            return BAD_PARAMS;
        }

        if (pData->type == COMPONENT_PREINSTALLED_SUITE) {
            remove_storage_lock(suiteId);
            return BAD_PARAMS;
        }

        do {
            jsize oldRootLength;
            jsize newRootLength;
            const pcsl_string* newRoot;
            const pcsl_string* oldRoot;
            char* pszError = NULL;
            pcsl_string filePath;
            pcsl_string newFilePath;


            status = begin_transaction(TRANSACTION_CHANGE_STORAGE, suiteId, NULL);
            if (status != ALL_OK) {
                break;
            }

            if ((status = get_suite_storage_root(suiteId, &suiteRoot)) != ALL_OK) {
                break;
            }

            fileIteratorHandle = storage_open_file_iterator(&suiteRoot);
            if (!fileIteratorHandle) {
                status = IO_ERROR;
                break;
            }

            newRoot = storage_get_root(newStorageId);
            oldRoot = storage_get_root(pData->storageId);
            newRootLength = pcsl_string_length(newRoot);
            oldRootLength = pcsl_string_length(oldRoot);

            status = ALL_OK;

            if ((status = midp_suite_get_class_path(suiteId,
                pData->storageId, KNI_FALSE, &filePath)) != ALL_OK) {
                break;
            }

            if ((status = midp_suite_get_class_path(suiteId,
                newStorageId, KNI_FALSE, &newFilePath)) != ALL_OK) {
                break;
            }

            storage_rename_file(&pszError, &filePath, &newFilePath);
            if (pszError != NULL) {
                status = IO_ERROR;
                storageFreeError(pszError);
                pcsl_string_free(&filePath);
                pcsl_string_free(&newFilePath);
                break;
            }

            pcsl_string_free(&filePath);
            pcsl_string_free(&newFilePath);

#if ENABLE_IMAGE_CACHE
            moveImageCache(suiteId, pData->storageId, newStorageId);
#endif

            pData->storageId = newStorageId;

            status = write_suites_data(&pszError);
            storageFreeError(pszError);

        } while (0);

        pcsl_string_free(&suiteRoot);
        storageCloseFileIterator(fileIteratorHandle);

        if (status != ALL_OK) {
            (void)rollback_transaction();
        } else {
            (void)finish_transaction();
        }

        remove_storage_lock(suiteId);

        return status;
    }

#endif /* VERIFY_ONCE */
}