/**
 * Retrieves the number of the installed components belonging
 * to the given midlet suite.
 *
 * @param suiteId          [in]  ID of the MIDlet suite the information about
 *                               whose components must be retrieved
 * @param pNumOfComponents [out] pointer to variable to accept the number
 *                               of components
 *
 * @returns error code (ALL_OK if no errors)
 */
MIDPError
midp_get_number_of_components(SuiteIdType suiteId, int* pNumOfComponents) {
    MIDPError status;
    char* pszError;
    MidletSuiteData* pData;
    int n = 0;

    do {
        if (midpInit(LIST_LEVEL) != 0) {
            status = OUT_OF_MEMORY;
            break;
        }

        /* load _suites.dat */
        status = read_suites_data(&pszError);
        if (status != ALL_OK) {
            storageFreeError(pszError);
            break;
        }

        pData = g_pSuitesData;

        /* walk through the linked list */
        while (pData != NULL) {
            if (pData->suiteId == suiteId && pData->type == COMPONENT_DYNAMIC) {
                n++;
            }
            pData = pData->nextEntry;
        }

        *pNumOfComponents = n;
    } while(0);

    return status;
}
Esempio n. 2
0
static void loadSuiteIds() {
    int i;
    MIDPError status;

    /*
     * 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;
    }

    status = midp_get_suite_ids(&pSuiteIds, &numberOfSuiteIds);
    if (status != ALL_OK) {
        REPORT_ERROR(LC_AMS, "Can't load suite IDs.");
        fprintf(stderr, "Can't load suite IDs: error %d.\n", status);
        return;
    }

    pSuiteRunState = (jint*)midpMalloc(numberOfSuiteIds*sizeof(jint));
    if (pSuiteRunState == NULL) {
        REPORT_ERROR(LC_AMS, "Out of Memory");
        fprintf(stderr, "Out Of Memory\n");
        return;
    }

    for (i = 0; i < numberOfSuiteIds; i++) {
        pSuiteRunState[i] = MIDP_MIDLET_STATE_DESTROYED;
    }
}
/**
 * Gets the properties of a MIDlet suite to persistent storage.
 * <pre>
 * The format of the properties file will be:
 * <number of strings as int (2 strings per property)>
 *    {repeated for each property}
 *    <length of a property key as int>
 *    <property key as jchars>
 *    <length of property value as int>
 *    <property value as jchars>
 * </pre>
 *
 *
 * Note that memory for the strings inside the returned MidpProperties
 * structure is allocated by the callee, and the caller is
 * responsible for freeing it using midp_free_properties().
 *
 * @param suiteId ID of the suite
 *
 * @return properties in a pair pattern of key and value,
 * use the status macros to check the result. A SUITE_CORRUPTED_ERROR
 * is returned as a status of MidpProperties when suite is corrupted
 */
MidpProperties
midp_get_suite_properties(SuiteIdType suiteId) {
    pcsl_string filename;
    MidpProperties result = { 0, ALL_OK, NULL };
    int len;
    char* pszError;
    MIDPError status;

    /*
     * 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) {
        result.numberOfProperties = 0;
        result.status =  OUT_OF_MEMORY;
        return result;
    }

    /*
    if (check_for_corrupted_suite(suiteId) == SUITE_CORRUPTED_ERROR) {
        result.numberOfProperties = 0;
        result.status = SUITE_CORRUPTED_ERROR;
        return result;
    }
    */

    if (get_property_file(suiteId, KNI_TRUE, &filename) != ALL_OK) {
        result.numberOfProperties = 0;
        result.status = NOT_FOUND;
        return result;
    }

    status = get_string_list(&pszError, &filename, &result.pStringArr, &len);
    pcsl_string_free(&filename);
    if (status != ALL_OK) {
        result.numberOfProperties = 0;
        result.status = status;
        storageFreeError(pszError);
        return result;
    }

    if (len < 0) {
        /* error */
        result.numberOfProperties = 0;
        result.status = GENERAL_ERROR;
    } else {
        /* each property is 2 strings (key and value) */
        result.numberOfProperties = len / 2;
    }

    return result;
}
Esempio n. 4
0
/**
 * Remove all the Record Stores for a suite.
 *
 * @param filenameBase filenameBase of the suite
 * @param id ID of the suite
 * Only one of the parameters will be used by a given implementation.  In the
 * case where the implementation might store data outside of the MIDlet storage,
 * the filenameBase will be ignored and only the suite id will be pertinent.
 *
 * @return false if out of memory else true
 */
int
rmsdb_remove_record_stores_for_suite(pcsl_string* filenameBase, SuiteIdType id) {
    int numberOfNames;
    pcsl_string* pNames;
    int i;
    int result = 1;
    char* pszError;
    (void)id; /* avoid a compiler warning */

    /*
     * 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 0;
    }

    numberOfNames = rmsdb_get_record_store_list(filenameBase, &pNames);
    if (numberOfNames == OUT_OF_MEM_LEN) {
        return 0;
    }

    if (numberOfNames <= 0) {
        return 1;
    }

    for (i = 0; i < numberOfNames; i++) {
        if (rmsdb_record_store_delete(&pszError, filenameBase, &pNames[i], 
            DB_EXTENSION_INDEX) <= 0) {
            result = 0;
            break;
        }
        if (rmsdb_record_store_delete(&pszError, filenameBase, &pNames[i], 
            IDX_EXTENSION_INDEX) <= 0) {
            /*
         * Since index file is optional, ignore error here.
         *
        result = 0;
            break;
        */
        }
    }

    recordStoreFreeError(pszError);
    free_pcsl_string_list(pNames, numberOfNames);

    return result;
}
Esempio n. 5
0
/**
 * Returns true if the suite has created at least one record store.
 *
 * @param filenameBase filenameBase of the suite
 *
 * @return true if the suite has at least one record store
 */
int
rmsdb_suite_has_rms_data(pcsl_string* filenameBase) {
    /*
     * 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 0;
    }

    return (rmsdb_get_number_of_record_stores(filenameBase) > 0);
}
/**
 * Retrieves the number of installed midlet suites.
 *
 * @param pNumOfSuites [out] pointer to variable to accept the number of suites
 *
 * @returns error code (ALL_OK if no errors)
 */
MIDPError
midp_get_number_of_suites(int* pNumOfSuites) {
    MIDPError status;
    char* pszError;

    do {
        /*
         * 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) {
            status = OUT_OF_MEMORY;
            break;
        }

        /* load _suites.dat */
        status = read_suites_data(&pszError);
        if (status == ALL_OK) {
#if ENABLE_DYNAMIC_COMPONENTS
            MidletSuiteData* pData = g_pSuitesData;
            int num = 0;

            /* walk through the linked list */
            while (pData != NULL) {
                if (pData->type == COMPONENT_REGULAR_SUITE) {
                    num++;
                }
                pData = pData->nextEntry;
            }

            *pNumOfSuites = num;
#else
            *pNumOfSuites = g_numberOfSuites;
#endif /* ENABLE_DYNAMIC_COMPONENTS */
        } else {
            storageFreeError(pszError);
        }
    } while(0);

    return status;
}
/**
 * Reads the file with information about the installed suites.
 *
 * Note that if the value of the global variable g_numberOfSuites
 * is zero, this function does nothing.
 *
 * @param ppszError pointer to character string pointer to accept an error
 *
 * @return status code: ALL_OK if no errors,
 *         OUT_OF_MEMORY if malloc failed
 *         IO_ERROR if an IO_ERROR,
 *         SUITE_CORRUPTED_ERROR if the suite database is corrupted
 */
MIDPError
read_suites_data(char** ppszError) {
    MIDPError status;
    int i;
    long bufferLen, pos;
    char* buffer = NULL;
    pcsl_string_status rc;
    pcsl_string suitesDataFile;
    MidletSuiteData *pSuitesData = g_pSuitesData;
    MidletSuiteData *pData, *pPrevData = NULL;
    int numOfSuites = 0;

    *ppszError = NULL;

    if (g_isSuitesDataLoaded) {
        return ALL_OK;
    }

    if (midpInit(LIST_LEVEL) != 0) {
        return OUT_OF_MEMORY;
    }

    /* get a full path to the _suites.dat */
    rc = pcsl_string_cat(storage_get_root(INTERNAL_STORAGE_ID),
                         &SUITE_DATA_FILENAME, &suitesDataFile);
    if (rc != PCSL_STRING_OK) {
        return OUT_OF_MEMORY;
    }

    /* read the file */
    status = read_file(ppszError, &suitesDataFile, &buffer, &bufferLen);
    pcsl_string_free(&suitesDataFile);

    if (status == NOT_FOUND || (status == ALL_OK && bufferLen == 0)) {
        /* _suites.dat is absent or empty, it's a normal situation */
        g_pSuitesData        = NULL;
        g_numberOfSuites     = 0;
        g_isSuitesDataLoaded = 1;
        return ALL_OK;
    }

    if (status == ALL_OK && bufferLen < (long) sizeof(int)) {
        pcsl_mem_free(buffer);
        status = SUITE_CORRUPTED_ERROR; /* _suites.dat is corrupted */
    }
    if (status != ALL_OK) {
        return status;
    }

    /* parse contents of the suite database */
    pos = 0;
    numOfSuites = *(int*)&buffer[pos];
    ADJUST_POS_IN_BUF(pos, bufferLen, sizeof(int));

    for (i = 0; i < numOfSuites; i++) {
        pData = (MidletSuiteData*) pcsl_mem_malloc(sizeof(MidletSuiteData));
        if (!pData) {
            status = OUT_OF_MEMORY;
            break;
        }

        if (pPrevData) {
            pPrevData->nextEntry = pData;
        } else {
            pSuitesData = pData;
        }

        /* IMPL_NOTE: introduce pcsl_mem_copy() */
        if (bufferLen < (long)MIDLET_SUITE_DATA_SIZE) {
            status = IO_ERROR;
            break;
        }
        memcpy((char*)pData, (char*)&buffer[pos], MIDLET_SUITE_DATA_SIZE);
        ADJUST_POS_IN_BUF(pos, bufferLen, MIDLET_SUITE_DATA_SIZE);

        pData->nextEntry = NULL;

        /* this suite was not checked if it is corrupted */
        pData->isChecked = 0;

        /* setup pJarHash */
        if (pData->jarHashLen > 0) {
            pData->varSuiteData.pJarHash = (unsigned char*)pcsl_mem_malloc(pData->jarHashLen);
            if (pData->varSuiteData.pJarHash == NULL) {
                status = OUT_OF_MEMORY;
                break;
            }
            memcpy(pData->varSuiteData.pJarHash, (char*)&buffer[pos],
                pData->jarHashLen);
            ADJUST_POS_IN_BUF(pos, bufferLen, pData->jarHashLen);
        } else {
            pData->varSuiteData.pJarHash = NULL;
        }

        /* setup string fields */
        {
            int i;
            jint strLen;
            pcsl_string* pStrings[] = {
                &pData->varSuiteData.midletClassName,
                &pData->varSuiteData.displayName,
                &pData->varSuiteData.iconName,
                &pData->varSuiteData.suiteVendor,
                &pData->varSuiteData.suiteName,
                &pData->varSuiteData.pathToJar,
                &pData->varSuiteData.pathToSettings
            };

            status = ALL_OK;

            for (i = 0; i < (int) (sizeof(pStrings) / sizeof(pStrings[0]));
                    i++) {
                if (bufferLen < (long)sizeof(jint)) {
                    status = IO_ERROR; /* _suites.dat is corrupted */
                    break;
                }

                /*
                 * We have to guarantee 4 - bytes alignment to use this:
                 *     strLen = *(jint*)&buffer[pos];
                 * on RISC CPUs.
                 */
                pos = SUITESTORE_ALIGN_4(pos);
                strLen = *(jint*)&buffer[pos];
                ADJUST_POS_IN_BUF(pos, bufferLen, sizeof(jint));

                if (bufferLen < (long)strLen) {
                    status = IO_ERROR; /* _suites.dat is corrupted */
                    break;
                }

                if (strLen > 0) {
                    rc = pcsl_string_convert_from_utf16(
                        (jchar*)&buffer[pos], strLen, pStrings[i]);

                    if (rc != PCSL_STRING_OK) {
                        status = OUT_OF_MEMORY;
                        break;
                    }
                    ADJUST_POS_IN_BUF(pos, bufferLen, strLen * sizeof(jchar));
                } else {
                    *pStrings[i] = strLen ?
                        PCSL_STRING_NULL : PCSL_STRING_EMPTY;
                }
            }
        }

        if (status != ALL_OK) {
            break;
        }

        pData->nextEntry = NULL;
        pPrevData = pData;
    } /* end for (numOfSuites) */

    pcsl_mem_free(buffer);

    if (status == ALL_OK) {
        g_numberOfSuites = numOfSuites;
        g_pSuitesData = pSuitesData;
        g_isSuitesDataLoaded = 1;
    } else {
        free_suites_data();
    }

    return status;
}
/**
 * Change the enabled state of a suite.
 *
 * @param suiteId ID of the suite
 * @param enabled true if the suite is be enabled
 *
 * @return an error code (ALL_OK if no errors)
 */
static MIDPError
change_enabled_state(SuiteIdType suiteId, jboolean enabled) {
    char* pszError;
    MIDPError status;
    jbyte* pPermissions;
    int numberOfPermissions;
    jbyte pushInterrupt;
    jint pushOptions;
    jboolean temp;
    lockStorageList* node;
    MidletSuiteData* pData;

    /*
     * 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_MEMORY;
    }

    status = midp_suite_exists(suiteId);

    if ((status != ALL_OK) && (status != SUITE_CORRUPTED_ERROR)) {
        return status;
    }

    node = find_storage_lock(suiteId);
    if (node != NULL) {
        if (node->update == KNI_TRUE) {
            /* Suite is being updated currently. */
            return SUITE_LOCKED;
        }
    }

    status = read_settings(&pszError, suiteId, &temp, &pushInterrupt,
                           &pushOptions, &pPermissions, &numberOfPermissions);
    if (status != ALL_OK) {
        storageFreeError(pszError);
        return status;
    }

    status = begin_transaction(TRANSACTION_ENABLE_SUITE, suiteId, NULL);
    if (status != ALL_OK) {
        return status;
    }

    status = write_settings(&pszError, suiteId, enabled, pushInterrupt,
                            pushOptions, pPermissions, numberOfPermissions,
                            NULL);
    pcsl_mem_free(pPermissions);
    if (status != ALL_OK) {
        storageFreeError(pszError);
        /* nothing was written, so nothing to rollback, just finish */
        (void)finish_transaction();
        return status;
    }

    /* synchronize the settings in the list of MidletSuiteData structures */
    pData = get_suite_data(suiteId);

    /*
     * We can assert that pData is not NULL because midp_suite_exists()
     * was called above to ensure that the suite with the given ID exists.
     */
    if (pData != NULL) {
        int status;
        char* pszError;
        pData->isEnabled = enabled;

        /* IMPL_NOTE: these settings must be cached and saved on AMS exit. */
        status = write_suites_data(&pszError);
        storageFreeError(pszError);
        if (status != ALL_OK) {
            (void)rollback_transaction();
            return IO_ERROR;
        }
    }

    (void)finish_transaction();

    return ALL_OK;
}
/**
 * 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 the given midlet suite to another folder.
 *
 * @param suiteId ID of the suite
 * @param newFolderId ID of the folder where the suite must be moved
 *
 * @return ALL_OK if no errors or an error code
 */
MIDPError midp_move_suite_to_folder(SuiteIdType suiteId,
                                    FolderIdType newFolderId) {
    MIDPError status = ALL_OK;
    char* pszError = NULL;
    lockStorageList *node = NULL;
    MidletSuiteData* pSuiteData;
    FolderIdType oldFolderId;

    /*
     * 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) {
        return OUT_OF_MEMORY;
    }

    /* load _suites.dat */
    status = read_suites_data(&pszError);
    storageFreeError(pszError);

    if (status != ALL_OK) {
        return status;
    }

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

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

    status = begin_transaction(TRANSACTION_MOVE_TO_FOLDER, suiteId, NULL);
    if (status != ALL_OK) {
        remove_storage_lock(suiteId);
        return status;
    }

    oldFolderId = pSuiteData->folderId;
    pSuiteData->folderId = newFolderId;

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

    if (status != ALL_OK) {
        pSuiteData->folderId = oldFolderId;
        (void)rollback_transaction();
    } else {
        (void)finish_transaction();
    }

    remove_storage_lock(suiteId);

    return status;
}
/**
 * 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 */
}
/**
 * Removes a software package given its suite ID
 * <p>
 * If the component is in use it must continue to be available
 * to the other components that are using it.  The resources it
 * consumes must not be released until it is not in use.
 *
 * @param suiteId ID of the suite
 *
 * @return ALL_OK if no errors,
 *         NOT_FOUND if the suite does not exist,
 *         SUITE_LOCKED if the suite is locked,
 *         BAD_PARAMS this suite cannot be removed
 */
MIDPError
midp_remove_suite(SuiteIdType suiteId) {
    pcsl_string filename;
    char* pszError;
    pcsl_string suiteRoot;
    MIDPError status;
    int operationStarted = 0;
    void* fileIteratorHandle = NULL;
    MidpProperties properties;
    pcsl_string* pproperty;
    MidletSuiteData* pData = NULL;
    pcsl_string filenameBase;

    lockStorageList *node = NULL;

    /* get the filename base from the suite id */
    status = build_suite_filename(suiteId, &PCSL_STRING_EMPTY, 
                                          &filenameBase);
    if (status != ALL_OK) {
        return status;
    }
    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) {
        return OUT_OF_MEMORY;
    }

    do {
        int rc; /* return code for rmsdb_... and storage_... */

        /* load _suites.dat */
        status = read_suites_data(&pszError);
        storageFreeError(pszError);
        if (status != ALL_OK) {
            break;
        }

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

        if (pData == NULL) {
            status = NOT_FOUND;
            break;
        }

        /* notify the listeners that we starting to remove the suite */
        operationStarted = 1;
        suite_listeners_notify(SUITESTORE_LISTENER_TYPE_REMOVE,
            SUITESTORE_OPERATION_START, ALL_OK, pData);

        if (pData->type == COMPONENT_PREINSTALLED_SUITE) {
            status = BAD_PARAMS;
            break;
        }

        status = begin_transaction(TRANSACTION_REMOVE_SUITE, suiteId, NULL);
        if (status != ALL_OK) {
            return status;
        }

        /*
         * Remove the files
         * Call the native RMS method to remove the RMS data.
         * This function call is needed for portability
         */
        rc = rmsdb_remove_record_stores_for_suite(&filenameBase, suiteId);
        if (rc == KNI_FALSE) {
            status = SUITE_LOCKED;
            break;
        }

        pushdeletesuite(suiteId);

        /*
         * If there is a delete notify property, add the value to the delete
         * notify URL list.
         */
        properties = midp_get_suite_properties(suiteId);
        if (properties.numberOfProperties > 0) {
            pproperty = midp_find_property(&properties, &DELETE_NOTIFY_PROP);
            if (pcsl_string_length(pproperty) > 0) {
                midpAddDeleteNotification(suiteId, pproperty);
            }

            pproperty = midp_find_property(&properties, &INSTALL_NOTIFY_PROP);
            if (pcsl_string_length(pproperty) > 0) {
                /*
                 * Remove any pending install notifications since they are only
                 * retried when the suite is run.
                 */
                midpRemoveInstallNotification(suiteId);
            }

            midp_free_properties(&properties);
        }

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

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

#if ENABLE_ICON_CACHE
        midp_remove_suite_icons(suiteId);
#endif        

        for (;;) {
            rc = storage_get_next_file_in_iterator(&suiteRoot,
                fileIteratorHandle, &filename);
            if (0 != rc) {
                break;
            }
            storage_delete_file(&pszError, &filename);
            pcsl_string_free(&filename);
            if (pszError != NULL) {
                storageFreeError(pszError);
                break;
            }
        }

    } while (0);

    pcsl_string_free(&suiteRoot);
    storageCloseFileIterator(fileIteratorHandle);

    (void)finish_transaction();

    /*
     * Notify the listeners the we've finished removing the suite.
     * It should be done before remove_from_suite_list_and_save()
     * call because it frees pData structure.
     */
    if (operationStarted) {
        suite_listeners_notify(SUITESTORE_LISTENER_TYPE_REMOVE,
            SUITESTORE_OPERATION_END, status, pData);
    }

    if (status == ALL_OK) {
        (void)remove_from_suite_list_and_save(suiteId);
    }

    remove_storage_lock(suiteId);

    return status;
}
/**
 * Get the list installed of MIDlet suite IDs.
 *
 * Note that memory for the suite IDs is allocated by the callee,
 * and the caller is responsible for freeing it using midp_free_suite_ids().
 *
 * @param ppSuites empty array of jints to fill with suite IDs
 * @param pNumOfSuites [out] pointer to variable to accept the number
 * of suites in the returned array
 *
 * @returns error code: ALL_OK if no errors,
 *          OUT_OF_MEMORY if for out of memory,
 *          IO_ERROR if an IO error
 */
MIDPError
midp_get_suite_ids(SuiteIdType** ppSuites, int* pNumOfSuites) {
    MIDPError status;
    char* pszError;
    SuiteIdType* pSuiteIds;
    MidletSuiteData* pData;
    int numberOfSuites = 0;
#if ENABLE_DYNAMIC_COMPONENTS
    int numberOfEntries = 0;
#endif

    *ppSuites = NULL;
    *pNumOfSuites = 0;

    /*
     * 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_MEMORY;
    }

    /* load _suites.dat */
    status = read_suites_data(&pszError);
    storageFreeError(pszError);

    if (status != ALL_OK) {
        return status;
    }

    if (!g_numberOfSuites) {
        /* there are no installed suites */
        return ALL_OK;
    }

    pData = g_pSuitesData;

    /* allocate a memory for the IDs */
    pSuiteIds = pcsl_mem_malloc(g_numberOfSuites * sizeof(SuiteIdType));
    if (pSuiteIds == NULL) {
        return OUT_OF_MEMORY;
    }

    /* walk through the linked list collecting suite IDs */
    while (pData != NULL) {
#if ENABLE_DYNAMIC_COMPONENTS
        if (pData->type == COMPONENT_REGULAR_SUITE) {
#endif
            pSuiteIds[numberOfSuites] = pData->suiteId;
            numberOfSuites++;
#if ENABLE_DYNAMIC_COMPONENTS
        }
        numberOfEntries++;
#endif
        pData = pData->nextEntry;
    }

#if ENABLE_DYNAMIC_COMPONENTS
    if (numberOfEntries != g_numberOfSuites) {
#else
    if (numberOfSuites != g_numberOfSuites) {
#endif
        /*
         * This should not happen: it means that something is wrong with
         * the list of structures containing the midlet suites information.
         */
        pcsl_mem_free(pSuiteIds);
        return IO_ERROR;
    }

    *ppSuites = pSuiteIds;
    *pNumOfSuites = numberOfSuites;

    return ALL_OK;
}

/**
 * Frees a list of suite IDs.
 *
 * @param pSuiteIds point to an array of suite IDs
 * @param numberOfSuites number of elements in pSuites
 */
void
midp_free_suite_ids(SuiteIdType* pSuiteIds, int numberOfSuites) {
    (void)numberOfSuites;
    pcsl_mem_free(pSuiteIds);
}