/** * Gets the storage root for a MIDlet suite by ID. * Free the data of the string returned with pcsl_string_free(). * * @param suiteId suite ID * @param sRoot receives storage root (gets set to NULL in the case of an error) * * @return status: ALL_OK if success, * OUT_OF_MEMORY if out-of-memory */ MIDPError get_suite_storage_root(SuiteIdType suiteId, pcsl_string* sRoot) { StorageIdType storageId; const pcsl_string* root; MIDPError status; *sRoot = PCSL_STRING_EMPTY; /* 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; } root = storage_get_root(storageId); pcsl_string_predict_size(sRoot, pcsl_string_length(root) + GET_SUITE_ID_LEN(suiteId)); if (PCSL_STRING_OK == pcsl_string_append(sRoot, root) && PCSL_STRING_OK == pcsl_string_append(sRoot, midp_suiteid2pcsl_string(suiteId))) { return ALL_OK; } pcsl_string_free(sRoot); *sRoot = PCSL_STRING_NULL; return OUT_OF_MEMORY; }
/** * Builds a full file name using the storage root and MIDlet suite by ID. * * @param suiteId suite ID * @param filename filename without a root path * @param sRoot receives full name of the file * * @return the status: ALL_OK if ok, OUT_OF_MEMORY if out of memory */ static MIDPError get_suite_filename(SuiteIdType suiteId, const pcsl_string* filename, pcsl_string* sRoot) { int sRoot_len; const pcsl_string* root; StorageIdType storageId; MIDPError 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; } root = storage_get_root(storageId); *sRoot = PCSL_STRING_EMPTY; sRoot_len = pcsl_string_length(root) + GET_SUITE_ID_LEN(suiteId) + pcsl_string_length(filename); pcsl_string_predict_size(sRoot, sRoot_len); if (PCSL_STRING_OK == pcsl_string_append(sRoot, root) && PCSL_STRING_OK == pcsl_string_append(sRoot, midp_suiteid2pcsl_string(suiteId)) && PCSL_STRING_OK == pcsl_string_append(sRoot, filename)) { return ALL_OK; } else { pcsl_string_free(sRoot); *sRoot = PCSL_STRING_NULL; return OUT_OF_MEMORY; } }
/** * Returns the number of record stores owned by the * MIDlet suite. * * @param suiteId ID of the MIDlet suite that owns the record store * * @return number of record stores or OUT_OF_MEM_LEN */ int rmsdb_get_number_of_record_stores(SuiteIdType suiteId) { pcsl_string root = PCSL_STRING_NULL; int numberOfStores; MIDPError status; StorageIdType storageId; /* * IMPL Note: here is assumed that the record store is located in the same * storage as the midlet suite. This may not be true. */ status = midp_suite_get_suite_storage(suiteId, &storageId); if (status != ALL_OK) { return OUT_OF_MEM_LEN; } status = midp_suite_get_rms_filename(suiteId, storageId, -1, &PCSL_STRING_EMPTY, &root); if (status != ALL_OK) { return OUT_OF_MEM_LEN; } if (root.data == NULL) { return 0; } numberOfStores = rmsdb_get_number_of_record_stores_int(&root); pcsl_string_free(&root); return numberOfStores; }
/** * Approximation of remaining RMS space in storage for a suite. * * Usage Warning: This may be a slow operation if * the platform has to look at the size of each file * stored in the MIDP memory space and include its size * in the total. * * @param handle handle to record store storage * @param id ID of the suite * * @return the approximate space available to grow the * record store in bytes. */ long rmsdb_get_record_store_space_available(int handle, SuiteIdType id) { /* Storage may have more then 2Gb space available so use 64-bit type */ jlong availSpace; long availSpaceUpTo2Gb; char* pszError; StorageIdType storageId; MIDPError status; (void)id; /* Avoid compiler warnings */ /* * IMPL_NOTE: here we introduce a limitation that the suite's RMS * must be located at the same storage as the midlet suite. * This is done because the public RecordStore API doesn't support * a storageId parameter. * There is a plan to get rid of such limitation by introducing a * function that will return a storage ID by the suite ID and RMS name. */ status = midp_suite_get_suite_storage(id, &storageId); if (status != ALL_OK) { return 0; /* Error: report that no space is available */ } availSpace = midp_file_cache_available_space(&pszError, handle, storageId); /* * Public RecordStore API uses Java int type for the available space * so here we trim the real space to 2Gb limit. */ availSpaceUpTo2Gb = (availSpace <= LONG_MAX) ? availSpace : LONG_MAX; return availSpaceUpTo2Gb; }
/** * Looks to see if the storage file for record store * identified by <code>uidPath</code> exists * * @param suiteId ID of the MIDlet suite that owns the record store * @param name name of the record store * @param extension extension number to add to the end of the file name * * @return true if the file exists, false if it does not. */ int rmsdb_record_store_exists(SuiteIdType suiteId, const pcsl_string* name, int extension) { pcsl_string filename; int intStatus; StorageIdType storageId; MIDPError status; /* * IMPL Note: here is assumed that the record store is located in the same * storage as the midlet suite. This may not be true. */ status = midp_suite_get_suite_storage(suiteId, &storageId); if (status != ALL_OK) { return 0; } if (MIDP_ERROR_NONE != rmsdb_get_unique_id_path(suiteId, storageId, name, extension, &filename)) { return 0; } if (pcsl_string_is_null(&filename)) { return 0; } intStatus = storage_file_exists(&filename); pcsl_string_free(&filename); return 0 != intStatus; }
int rmsdb_record_store_open(char** ppszError, SuiteIdType suiteId, const pcsl_string * name_str, int extension) { StorageIdType storageId; MIDPError status; pcsl_string filename_str; int handle; lockFileList* searchedNodePtr = NULL; int addflag = 0; *ppszError = NULL; if ((extension == DB_EXTENSION_INDEX) && (lockFileListPtr != NULL)) { /* linked list is already initialised for a db file */ searchedNodePtr = findLockById(suiteId, name_str); if (searchedNodePtr != NULL) { /* File is already opened by another isolate, return an error */ *ppszError = (char *)FILE_LOCK_ERROR; return -2; } else { /* remember to add a node */ addflag = 1; } } /* * IMPL Note: here is assumed that the record store is located in the same * storage as the midlet suite. This may not be true. */ status = midp_suite_get_suite_storage(suiteId, &storageId); if (status != ALL_OK) { return 0; } if (MIDP_ERROR_NONE != rmsdb_get_unique_id_path(suiteId, storageId, name_str, extension, &filename_str)) { return -1; } handle = midp_file_cache_open(ppszError, storageId, &filename_str, OPEN_READ_WRITE); pcsl_string_free(&filename_str); if (*ppszError != NULL) { return -1; } /* * Add the node only if it's a db file AND lockFileListPtr is NULL or * addflag is 1 */ if ((extension == DB_EXTENSION_INDEX)&& ( (lockFileListPtr == NULL) || (addflag == 1)) ) { if (recordStoreCreateLock(suiteId, name_str, handle) != 0) { return -1; } } return handle; }
/** * 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; }
/** * Removes the storage file for record store <code>filename</code> * if it exists. * * @param ppszError pointer to a string that will hold an error message * if there is a problem, or null if the function is * successful (This function sets <tt>ppszError</tt>'s value.) * @param suiteId ID of the MIDlet suite that owns the record store * @param name name of the record store * @param extension extension number to add to the end of the file name * * @return 1 if successful * 0 if an IOException occurred * -1 if file is locked by another isolate * -2 if out of memory error occurs * */ int rmsdb_record_store_delete(char** ppszError, SuiteIdType suiteId, const pcsl_string* name_str, int extension) { StorageIdType storageId; MIDPError status; pcsl_string filename_str; lockFileList* searchedNodePtr = NULL; *ppszError = NULL; if ((extension == DB_EXTENSION_INDEX)&&(lockFileListPtr != NULL)) { /* linked list is already initialised for a db file */ searchedNodePtr = findLockById(suiteId, name_str); if (searchedNodePtr != NULL) { /* File is in use by another isolate */ *ppszError = (char *)FILE_LOCK_ERROR; return -1; } } /* * IMPL Note: here is assumed that the record store is located in the same * storage as the midlet suite. This may not be true. */ status = midp_suite_get_suite_storage(suiteId, &storageId); if (status != ALL_OK) { return 0; } if (MIDP_ERROR_NONE != rmsdb_get_unique_id_path(suiteId, storageId, name_str, extension, &filename_str)) { return -2; } storage_delete_file(ppszError, &filename_str); pcsl_string_free(&filename_str); if (*ppszError != NULL) { return 0; } return 1; }
/** * Returns an array of the names of record stores owned by the * MIDlet suite. * * @param suiteId * @param ppNames pointer to pointer that will be filled in with names * * @return number of record store names or OUT_OF_MEM_LEN */ int rmsdb_get_record_store_list(SuiteIdType suiteId, pcsl_string* *const ppNames) { int numberOfStores; pcsl_string root; pcsl_string* pStores; pcsl_string filename; pcsl_string ascii_name = PCSL_STRING_NULL_INITIALIZER; int i; void* handle = NULL; MIDPError status; int f_errc; pcsl_string_status s_errc; StorageIdType storageId; /* IMPL_NOTE: how can we get it statically? */ const int dbext_len = pcsl_string_length(&DB_EXTENSION); *ppNames = NULL; /* * IMPL Note: here is assumed that the record store is located in the same * storage as the midlet suite. This may not be true. */ status = midp_suite_get_suite_storage(suiteId, &storageId); if (status != ALL_OK) { return OUT_OF_MEM_LEN; } status = midp_suite_get_rms_filename(suiteId, storageId, -1, &PCSL_STRING_EMPTY, &root); if (status != ALL_OK) { return OUT_OF_MEM_LEN; } if (pcsl_string_is_null(&root)) { return 0; } numberOfStores = rmsdb_get_number_of_record_stores_int(&root); if (numberOfStores <= 0) { pcsl_string_free(&root); return numberOfStores; } pStores = alloc_pcsl_string_list(numberOfStores); if (pStores == NULL) { pcsl_string_free(&root); return OUT_OF_MEM_LEN; } handle = storage_open_file_iterator(&root); if (!handle) { pcsl_string_free(&root); return OUT_OF_MEM_LEN; } /* the main loop */ for(i=0,f_errc=0,s_errc=0;;) { f_errc = storage_get_next_file_in_iterator(&root, handle, &filename); if (0 != f_errc) { f_errc = 0; break; } if (pcsl_string_ends_with(&filename, &DB_EXTENSION)) { s_errc = pcsl_string_substring(&filename, pcsl_string_length(&root), pcsl_string_length(&filename) - dbext_len, &ascii_name); pcsl_string_free(&filename); if (PCSL_STRING_OK != s_errc ) { break; } s_errc = escaped_ascii_to_unicode(&ascii_name, &pStores[i]); pcsl_string_free(&ascii_name); if (PCSL_STRING_OK != s_errc ) { break; } i++; } pcsl_string_free(&filename); /* IMPL_NOTE: do we need this one? isn't it useless? */ if (i == numberOfStores) { break; } } pcsl_string_free(&root); storageCloseFileIterator(handle); if (f_errc || s_errc) { /* The loop stopped because we ran out of memory. */ free_pcsl_string_list(pStores, i); return OUT_OF_MEM_LEN; } *ppNames = pStores; return numberOfStores; }
/** * 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; }