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