/* * Copyright (C) 2018 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include #include #include #include #include #define FILE_BUFFER_MAX 1000000 #define TEST_FILE_MAX 100 #define TEST_HANDLER_MAX 1000 #define MAX_CHUNK_SIZE 4040 #define MAX_PARAMETER_SIZE 10 /* File info structure representing a file on secure storage. */ struct FileInfo { char name[STORAGE_MAX_NAME_LENGTH_BYTES]; size_t size; /* For test we just use a static buffer for file content. */ uint8_t buf[FILE_BUFFER_MAX]; }; struct FileHandler { char name[STORAGE_MAX_NAME_LENGTH_BYTES]; uint64_t file_handler; struct FileInfo* file_info; }; static struct FileInfo* storage_mock_files[TEST_FILE_MAX]; static struct FileHandler* storage_mock_handlers[TEST_HANDLER_MAX]; static uint64_t storage_mock_handlers_count; static uint64_t storage_mock_files_count; static uint64_t storage_handler_num = 1; static uint64_t storage_session_num = 1; static bool storage_session_opened; static struct FileHandler* get_file_handler(file_handle_t fh) { for (int i = 0; i < TEST_HANDLER_MAX; i++) { if (storage_mock_handlers[i] == NULL) { continue; } if (storage_mock_handlers[i]->file_handler == fh) { return storage_mock_handlers[i]; } } return NULL; } static int not_implemented_handler(const char* operation) { fprintf(stderr, "%s is not supported in fake secure storage implementation.\n", operation); return ERR_NOT_IMPLEMENTED; } /* * Copied from client_tipc.c. */ static int is_valid_name(const char* name, size_t name_len) { size_t i; if (!name_len) return 0; for (i = 0; i < name_len; i++) { if ((name[i] >= 'a') && (name[i] <= 'z')) continue; if ((name[i] >= 'A') && (name[i] <= 'Z')) continue; if ((name[i] >= '0') && (name[i] <= '9')) continue; if ((name[i] == '.') || (name[i] == '-') || (name[i] == '_')) continue; /* not a legal character so reject this name */ return 0; } return 1; } int storage_open_session(storage_session_t* session_p, const char* type) { if (storage_session_opened) { return not_implemented_handler("Using more than one session"); } storage_session_opened = true; *session_p = storage_session_num; storage_session_num++; return NO_ERROR; } void storage_close_session(storage_session_t session) { storage_session_opened = false; return; } int storage_open_file(storage_session_t session, file_handle_t* handle_p, const char* name, uint32_t flags, uint32_t opflags) { if (strlen(name) >= STORAGE_MAX_NAME_LENGTH_BYTES) { return ERR_NOT_VALID; } if (!is_valid_name(name, strlen(name))) { return ERR_NOT_VALID; } if (storage_mock_handlers_count >= TEST_HANDLER_MAX) { return ERR_GENERIC; } struct FileInfo* file_info_p = NULL; for (int i = 0; i < TEST_FILE_MAX; i++) { if (storage_mock_files[i] == NULL) { continue; } if (!strcmp(storage_mock_files[i]->name, name)) { file_info_p = storage_mock_files[i]; } } if (file_info_p == NULL) { /* File not found. */ if (!(flags & STORAGE_FILE_OPEN_CREATE)) { return ERR_NOT_FOUND; } else { /* Create new file. */ storage_mock_files[storage_mock_files_count] = malloc(sizeof(struct FileInfo)); memset(storage_mock_files[storage_mock_files_count], 0, sizeof(struct FileInfo)); strncpy(storage_mock_files[storage_mock_files_count]->name, name, STORAGE_MAX_NAME_LENGTH_BYTES); file_info_p = storage_mock_files[storage_mock_files_count]; storage_mock_files_count++; } } else { if ((flags & STORAGE_FILE_OPEN_CREATE) && (flags & STORAGE_FILE_OPEN_CREATE_EXCLUSIVE)) { /* When CREATE_EXCLUSIVE is specified, opening existing file would * fail. */ return ERR_ALREADY_EXISTS; } for (int i = 0; i < TEST_HANDLER_MAX; i++) { if (storage_mock_handlers[i] == NULL) { continue; } if (!strcmp(storage_mock_handlers[i]->name, name)) { /* open a same file second time is not allowed. */ return ERR_NOT_ALLOWED; } } if (flags & STORAGE_FILE_OPEN_TRUNCATE) { /* Discard existing contents. */ file_info_p->size = 0; memset(file_info_p->buf, 0, FILE_BUFFER_MAX); } } storage_mock_handlers[storage_mock_handlers_count] = malloc(sizeof(struct FileHandler)); memset(storage_mock_handlers[storage_mock_handlers_count], 0, sizeof(struct FileHandler)); strncpy(storage_mock_handlers[storage_mock_handlers_count]->name, name, STORAGE_MAX_NAME_LENGTH_BYTES); storage_mock_handlers[storage_mock_handlers_count]->file_handler = storage_handler_num; storage_mock_handlers[storage_mock_handlers_count]->file_info = file_info_p; *handle_p = storage_handler_num; storage_handler_num++; storage_mock_handlers_count++; return NO_ERROR; } void storage_close_file(file_handle_t fh) { for (int i = 0; i < TEST_HANDLER_MAX; i++) { if (storage_mock_handlers[i] == NULL) { continue; } if (storage_mock_handlers[i]->file_handler == fh) { free(storage_mock_handlers[i]); for (int j = i; j < TEST_HANDLER_MAX - 1; j++) { storage_mock_handlers[j] = storage_mock_handlers[j + 1]; } return; } } } int storage_move_file(storage_session_t session, file_handle_t handle, const char* old_name, const char* new_name, uint32_t flags, uint32_t opflags) { return not_implemented_handler("Moving file"); } int storage_delete_file(storage_session_t session, const char* name, uint32_t opflags) { for (int i = 0; i < TEST_FILE_MAX; i++) { if (storage_mock_files[i] == NULL) { continue; } if (!strcmp(storage_mock_files[i]->name, name)) { free(storage_mock_files[i]); for (int j = i; j < TEST_FILE_MAX - 1; j++) { storage_mock_files[j] = storage_mock_files[j + 1]; } /* Invalid all the handlers pointing to the non existing file. */ for (int j = 0; j < TEST_HANDLER_MAX; j++) { if (storage_mock_handlers[j] == NULL) { continue; } if (strcmp(storage_mock_handlers[j]->name, name)) { storage_mock_handlers[j]->file_info = NULL; } } return NO_ERROR; } } return ERR_NOT_FOUND; } struct storage_open_dir_state { uint8_t buf[MAX_CHUNK_SIZE]; size_t buf_size; size_t buf_last_read; size_t buf_read; }; int storage_open_dir(storage_session_t session, const char* path, struct storage_open_dir_state** state) { return not_implemented_handler("Opening directory"); } void storage_close_dir(storage_session_t session, struct storage_open_dir_state* state) { not_implemented_handler("Closing directory"); return; } int storage_read_dir(storage_session_t session, struct storage_open_dir_state* state, uint8_t* flags, char* name, size_t name_out_size) { return not_implemented_handler("Reading directory"); } ssize_t storage_read(file_handle_t fh, storage_off_t off, void* buf, size_t size) { struct FileHandler* file_handler_p = get_file_handler(fh); if (file_handler_p == NULL) { return ERR_NOT_VALID; } struct FileInfo* file_info = file_handler_p->file_info; if (file_info == NULL) { return ERR_NOT_VALID; } if (off > file_info->size) { return ERR_NOT_VALID; } size_t copy_size = size; if (off + copy_size > file_info->size) { copy_size = file_info->size - off; } memcpy(buf, file_info->buf + off, copy_size); return copy_size; } ssize_t storage_write(file_handle_t fh, storage_off_t off, const void* buf, size_t size, uint32_t opflags) { struct FileHandler* file_handler_p = get_file_handler(fh); if (file_handler_p == NULL) { return ERR_NOT_VALID; } struct FileInfo* file_info = file_handler_p->file_info; if (file_info == NULL) { return ERR_NOT_VALID; } if (off + size > FILE_BUFFER_MAX) { return ERR_GENERIC; } if (off > file_info->size) { // Write beyond EOF, pad with 0 first. size_t padding_size = off - file_info->size; memset(file_info->buf + file_info->size, 0, padding_size); } if (off + size > file_info->size) { file_info->size = off + size; } memcpy(file_info->buf + off, buf, size); return size; } int storage_set_file_size(file_handle_t fh, storage_off_t file_size, uint32_t opflags) { if (file_size > FILE_BUFFER_MAX) { return ERR_GENERIC; } struct FileHandler* file_handler_p = get_file_handler(fh); if (file_handler_p == NULL) { return ERR_NOT_VALID; } struct FileInfo* file_info = file_handler_p->file_info; if (file_info == NULL) { return ERR_NOT_VALID; } if (file_size > file_info->size) { // Write beyond EOF, pad with 0. size_t padding_size = file_size - file_info->size; memset(file_info->buf + file_info->size, 0, padding_size); } file_info->size = file_size; return NO_ERROR; } int storage_get_file_size(file_handle_t fh, storage_off_t* size_p) { struct FileHandler* file_handler_p = get_file_handler(fh); if (file_handler_p == NULL) { return ERR_NOT_VALID; } struct FileInfo* file_info = file_handler_p->file_info; if (file_info == NULL) { /* File has been deleted, return NO_ERROR. */ size_p = 0; return NO_ERROR; } *size_p = file_info->size; return NO_ERROR; } int storage_end_transaction(storage_session_t session, bool complete) { if (!complete) { return not_implemented_handler("Discard transaction"); } return NO_ERROR; }