1d7767217SJens Wiklander /* 2d7767217SJens Wiklander * Copyright (c) 2017, Linaro Limited 3d7767217SJens Wiklander * All rights reserved. 4d7767217SJens Wiklander * 5d7767217SJens Wiklander * Redistribution and use in source and binary forms, with or without 6d7767217SJens Wiklander * modification, are permitted provided that the following conditions are met: 7d7767217SJens Wiklander * 8d7767217SJens Wiklander * 1. Redistributions of source code must retain the above copyright notice, 9d7767217SJens Wiklander * this list of conditions and the following disclaimer. 10d7767217SJens Wiklander * 11d7767217SJens Wiklander * 2. Redistributions in binary form must reproduce the above copyright notice, 12d7767217SJens Wiklander * this list of conditions and the following disclaimer in the documentation 13d7767217SJens Wiklander * and/or other materials provided with the distribution. 14d7767217SJens Wiklander * 15d7767217SJens Wiklander * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 16d7767217SJens Wiklander * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17d7767217SJens Wiklander * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18d7767217SJens Wiklander * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 19d7767217SJens Wiklander * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 20d7767217SJens Wiklander * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 21d7767217SJens Wiklander * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 22d7767217SJens Wiklander * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 23d7767217SJens Wiklander * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 24d7767217SJens Wiklander * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 25d7767217SJens Wiklander * POSSIBILITY OF SUCH DAMAGE. 26d7767217SJens Wiklander */ 27d7767217SJens Wiklander 28d7767217SJens Wiklander #include <assert.h> 29d7767217SJens Wiklander #include <bitstring.h> 30d7767217SJens Wiklander #include <stdio.h> 31d7767217SJens Wiklander #include <stdlib.h> 32d7767217SJens Wiklander #include <string.h> 33d7767217SJens Wiklander #include <tee/fs_dirfile.h> 34d7767217SJens Wiklander #include <types_ext.h> 35d7767217SJens Wiklander 36d7767217SJens Wiklander struct tee_fs_dirfile_dirh { 37d7767217SJens Wiklander const struct tee_fs_dirfile_operations *fops; 38d7767217SJens Wiklander struct tee_file_handle *fh; 39d7767217SJens Wiklander int nbits; 40d7767217SJens Wiklander bitstr_t *files; 41d7767217SJens Wiklander size_t ndents; 42d7767217SJens Wiklander }; 43d7767217SJens Wiklander 44d7767217SJens Wiklander struct dirfile_entry { 45d7767217SJens Wiklander TEE_UUID uuid; 46d7767217SJens Wiklander uint8_t oid[TEE_OBJECT_ID_MAX_LEN]; 47d7767217SJens Wiklander uint32_t oidlen; 48d7767217SJens Wiklander uint8_t hash[TEE_FS_HTREE_HASH_SIZE]; 49d7767217SJens Wiklander uint32_t file_number; 50d7767217SJens Wiklander }; 51d7767217SJens Wiklander 52d7767217SJens Wiklander /* 53d7767217SJens Wiklander * File layout 54d7767217SJens Wiklander * 55d7767217SJens Wiklander * dirfile_entry.0 56d7767217SJens Wiklander * ... 57d7767217SJens Wiklander * dirfile_entry.n 58d7767217SJens Wiklander * 59d7767217SJens Wiklander * where n the index is disconnected from file_number in struct dirfile_entry 60d7767217SJens Wiklander */ 61d7767217SJens Wiklander 62d7767217SJens Wiklander static TEE_Result maybe_grow_files(struct tee_fs_dirfile_dirh *dirh, int idx) 63d7767217SJens Wiklander { 64d7767217SJens Wiklander void *p; 65d7767217SJens Wiklander 66d7767217SJens Wiklander if (idx < dirh->nbits) 67d7767217SJens Wiklander return TEE_SUCCESS; 68d7767217SJens Wiklander 69d7767217SJens Wiklander p = realloc(dirh->files, bitstr_size(idx + 1)); 70d7767217SJens Wiklander if (!p) 71d7767217SJens Wiklander return TEE_ERROR_OUT_OF_MEMORY; 72d7767217SJens Wiklander dirh->files = p; 73d7767217SJens Wiklander 74d7767217SJens Wiklander bit_nclear(dirh->files, dirh->nbits, idx); 75d7767217SJens Wiklander dirh->nbits = idx + 1; 76d7767217SJens Wiklander 77d7767217SJens Wiklander return TEE_SUCCESS; 78d7767217SJens Wiklander } 79d7767217SJens Wiklander 80d7767217SJens Wiklander static TEE_Result set_file(struct tee_fs_dirfile_dirh *dirh, int idx) 81d7767217SJens Wiklander { 82d7767217SJens Wiklander TEE_Result res = maybe_grow_files(dirh, idx); 83d7767217SJens Wiklander 84d7767217SJens Wiklander if (!res) 85d7767217SJens Wiklander bit_set(dirh->files, idx); 86d7767217SJens Wiklander 87d7767217SJens Wiklander return res; 88d7767217SJens Wiklander } 89d7767217SJens Wiklander 90d7767217SJens Wiklander static void clear_file(struct tee_fs_dirfile_dirh *dirh, int idx) 91d7767217SJens Wiklander { 92d7767217SJens Wiklander if (idx < dirh->nbits) 93d7767217SJens Wiklander bit_clear(dirh->files, idx); 94d7767217SJens Wiklander } 95d7767217SJens Wiklander 96d7767217SJens Wiklander static bool test_file(struct tee_fs_dirfile_dirh *dirh, int idx) 97d7767217SJens Wiklander { 98d7767217SJens Wiklander if (idx < dirh->nbits) 99d7767217SJens Wiklander return bit_test(dirh->files, idx); 100d7767217SJens Wiklander 101d7767217SJens Wiklander return false; 102d7767217SJens Wiklander } 103d7767217SJens Wiklander 104d7767217SJens Wiklander static TEE_Result read_dent(struct tee_fs_dirfile_dirh *dirh, int idx, 105d7767217SJens Wiklander struct dirfile_entry *dent) 106d7767217SJens Wiklander { 107d7767217SJens Wiklander TEE_Result res; 108d7767217SJens Wiklander size_t l; 109d7767217SJens Wiklander 110d7767217SJens Wiklander l = sizeof(*dent); 111d7767217SJens Wiklander res = dirh->fops->read(dirh->fh, sizeof(struct dirfile_entry) * idx, 112d7767217SJens Wiklander dent, &l); 113d7767217SJens Wiklander if (!res && l != sizeof(*dent)) 114d7767217SJens Wiklander res = TEE_ERROR_ITEM_NOT_FOUND; 115d7767217SJens Wiklander 116d7767217SJens Wiklander return res; 117d7767217SJens Wiklander } 118d7767217SJens Wiklander 119d7767217SJens Wiklander static TEE_Result write_dent(struct tee_fs_dirfile_dirh *dirh, size_t n, 120d7767217SJens Wiklander struct dirfile_entry *dent) 121d7767217SJens Wiklander { 122d7767217SJens Wiklander TEE_Result res; 123d7767217SJens Wiklander 124d7767217SJens Wiklander res = dirh->fops->write(dirh->fh, sizeof(*dent) * n, 125d7767217SJens Wiklander dent, sizeof(*dent)); 126d7767217SJens Wiklander if (!res && n >= dirh->ndents) 127d7767217SJens Wiklander dirh->ndents = n + 1; 128d7767217SJens Wiklander 129d7767217SJens Wiklander return res; 130d7767217SJens Wiklander } 131d7767217SJens Wiklander 132*a4ed7bafSJens Wiklander TEE_Result tee_fs_dirfile_open(bool create, uint8_t *hash, 133*a4ed7bafSJens Wiklander const struct tee_fs_dirfile_operations *fops, 134d7767217SJens Wiklander struct tee_fs_dirfile_dirh **dirh_ret) 135d7767217SJens Wiklander { 136d7767217SJens Wiklander TEE_Result res; 137d7767217SJens Wiklander struct tee_fs_dirfile_dirh *dirh = calloc(1, sizeof(*dirh)); 138d7767217SJens Wiklander size_t n; 139d7767217SJens Wiklander 140d7767217SJens Wiklander if (!dirh) 141d7767217SJens Wiklander return TEE_ERROR_OUT_OF_MEMORY; 142d7767217SJens Wiklander 143d7767217SJens Wiklander dirh->fops = fops; 144*a4ed7bafSJens Wiklander res = fops->open(create, hash, NULL, NULL, &dirh->fh); 145d7767217SJens Wiklander if (res) 146d7767217SJens Wiklander goto out; 147d7767217SJens Wiklander 148d7767217SJens Wiklander for (n = 0;; n++) { 149d7767217SJens Wiklander struct dirfile_entry dent; 150d7767217SJens Wiklander 151d7767217SJens Wiklander res = read_dent(dirh, n, &dent); 152d7767217SJens Wiklander if (res) { 153d7767217SJens Wiklander if (res == TEE_ERROR_ITEM_NOT_FOUND) 154d7767217SJens Wiklander res = TEE_SUCCESS; 155d7767217SJens Wiklander goto out; 156d7767217SJens Wiklander } 157d7767217SJens Wiklander 158d7767217SJens Wiklander if (!dent.oidlen) 159d7767217SJens Wiklander continue; 160d7767217SJens Wiklander 161d7767217SJens Wiklander if (test_file(dirh, dent.file_number)) { 162d7767217SJens Wiklander DMSG("clearing duplicate file number %" PRIu32, 163d7767217SJens Wiklander dent.file_number); 164d7767217SJens Wiklander memset(&dent, 0, sizeof(dent)); 165d7767217SJens Wiklander res = write_dent(dirh, n, &dent); 166d7767217SJens Wiklander if (res) 167d7767217SJens Wiklander goto out; 168d7767217SJens Wiklander continue; 169d7767217SJens Wiklander } 170d7767217SJens Wiklander 171d7767217SJens Wiklander res = set_file(dirh, dent.file_number); 172d7767217SJens Wiklander if (res != TEE_SUCCESS) 173d7767217SJens Wiklander goto out; 174d7767217SJens Wiklander } 175d7767217SJens Wiklander out: 176d7767217SJens Wiklander if (!res) { 177d7767217SJens Wiklander dirh->ndents = n; 178d7767217SJens Wiklander *dirh_ret = dirh; 179d7767217SJens Wiklander } else { 180d7767217SJens Wiklander tee_fs_dirfile_close(dirh); 181d7767217SJens Wiklander } 182d7767217SJens Wiklander return res; 183d7767217SJens Wiklander } 184d7767217SJens Wiklander 185d7767217SJens Wiklander void tee_fs_dirfile_close(struct tee_fs_dirfile_dirh *dirh) 186d7767217SJens Wiklander { 187d7767217SJens Wiklander if (dirh) { 188d7767217SJens Wiklander dirh->fops->close(dirh->fh); 189d7767217SJens Wiklander free(dirh->files); 190d7767217SJens Wiklander free(dirh); 191d7767217SJens Wiklander } 192d7767217SJens Wiklander } 193d7767217SJens Wiklander 194*a4ed7bafSJens Wiklander TEE_Result tee_fs_dirfile_commit_writes(struct tee_fs_dirfile_dirh *dirh, 195*a4ed7bafSJens Wiklander uint8_t *hash) 196d7767217SJens Wiklander { 197*a4ed7bafSJens Wiklander return dirh->fops->commit_writes(dirh->fh, hash); 198d7767217SJens Wiklander } 199d7767217SJens Wiklander 200d7767217SJens Wiklander TEE_Result tee_fs_dirfile_get_tmp(struct tee_fs_dirfile_dirh *dirh, 201d7767217SJens Wiklander struct tee_fs_dirfile_fileh *dfh) 202d7767217SJens Wiklander { 203d7767217SJens Wiklander TEE_Result res; 204d7767217SJens Wiklander int i = 0; 205d7767217SJens Wiklander 206d7767217SJens Wiklander if (dirh->files) { 207d7767217SJens Wiklander bit_ffc(dirh->files, dirh->nbits, &i); 208d7767217SJens Wiklander if (i == -1) 209d7767217SJens Wiklander i = dirh->nbits; 210d7767217SJens Wiklander } 211d7767217SJens Wiklander 212d7767217SJens Wiklander res = set_file(dirh, i); 213d7767217SJens Wiklander if (!res) 214d7767217SJens Wiklander dfh->file_number = i; 215d7767217SJens Wiklander 216d7767217SJens Wiklander return res; 217d7767217SJens Wiklander } 218d7767217SJens Wiklander 219d7767217SJens Wiklander TEE_Result tee_fs_dirfile_find(struct tee_fs_dirfile_dirh *dirh, 220fd108c3eSJens Wiklander const TEE_UUID *uuid, const void *oid, 221fd108c3eSJens Wiklander size_t oidlen, struct tee_fs_dirfile_fileh *dfh) 222d7767217SJens Wiklander { 223d7767217SJens Wiklander TEE_Result res; 224d7767217SJens Wiklander struct dirfile_entry dent; 225d7767217SJens Wiklander int n; 226d7767217SJens Wiklander int first_free = -1; 227d7767217SJens Wiklander 228d7767217SJens Wiklander for (n = 0;; n++) { 229d7767217SJens Wiklander res = read_dent(dirh, n, &dent); 230d7767217SJens Wiklander if (res == TEE_ERROR_ITEM_NOT_FOUND && !oidlen) { 231d7767217SJens Wiklander memset(&dent, 0, sizeof(dent)); 232d7767217SJens Wiklander if (first_free != -1) 233d7767217SJens Wiklander n = first_free; 234d7767217SJens Wiklander break; 235d7767217SJens Wiklander } 236d7767217SJens Wiklander if (res) 237d7767217SJens Wiklander return res; 238d7767217SJens Wiklander 239fd108c3eSJens Wiklander /* TODO check this loop when oidlen == 0 */ 240fd108c3eSJens Wiklander 241d7767217SJens Wiklander if (!dent.oidlen && first_free == -1) 242d7767217SJens Wiklander first_free = n; 243d7767217SJens Wiklander if (dent.oidlen != oidlen) 244d7767217SJens Wiklander continue; 245d7767217SJens Wiklander 246d7767217SJens Wiklander assert(!oidlen || !dent.oidlen || 247d7767217SJens Wiklander test_file(dirh, dent.file_number)); 248d7767217SJens Wiklander 249fd108c3eSJens Wiklander if (!memcmp(&dent.uuid, uuid, sizeof(dent.uuid)) && 250d7767217SJens Wiklander !memcmp(&dent.oid, oid, oidlen)) 251d7767217SJens Wiklander break; 252d7767217SJens Wiklander } 253d7767217SJens Wiklander 254d7767217SJens Wiklander if (dfh) { 255d7767217SJens Wiklander dfh->idx = n; 256d7767217SJens Wiklander dfh->file_number = dent.file_number; 257d7767217SJens Wiklander memcpy(dfh->hash, dent.hash, sizeof(dent.hash)); 258d7767217SJens Wiklander } 259d7767217SJens Wiklander 260d7767217SJens Wiklander return TEE_SUCCESS; 261d7767217SJens Wiklander } 262d7767217SJens Wiklander 263d7767217SJens Wiklander TEE_Result tee_fs_dirfile_fileh_to_fname(const struct tee_fs_dirfile_fileh *dfh, 264d7767217SJens Wiklander char *fname, size_t *fnlen) 265d7767217SJens Wiklander { 266d7767217SJens Wiklander int r; 267d7767217SJens Wiklander size_t l = *fnlen; 268d7767217SJens Wiklander 269d7767217SJens Wiklander if (dfh) 270d7767217SJens Wiklander r = snprintf(fname, l, "%" PRIx32, dfh->file_number); 271d7767217SJens Wiklander else 272d7767217SJens Wiklander r = snprintf(fname, l, "dirf.db"); 273d7767217SJens Wiklander 274d7767217SJens Wiklander if (r < 0) 275d7767217SJens Wiklander return TEE_ERROR_GENERIC; 276d7767217SJens Wiklander 277d7767217SJens Wiklander *fnlen = r + 1; 278d7767217SJens Wiklander if ((size_t)r >= l) 279d7767217SJens Wiklander return TEE_ERROR_SHORT_BUFFER; 280d7767217SJens Wiklander 281d7767217SJens Wiklander return TEE_SUCCESS; 282d7767217SJens Wiklander } 283d7767217SJens Wiklander 284d7767217SJens Wiklander TEE_Result tee_fs_dirfile_rename(struct tee_fs_dirfile_dirh *dirh, 285fd108c3eSJens Wiklander const TEE_UUID *uuid, 286d7767217SJens Wiklander struct tee_fs_dirfile_fileh *dfh, 287d7767217SJens Wiklander const void *oid, size_t oidlen) 288d7767217SJens Wiklander { 289d7767217SJens Wiklander TEE_Result res; 290d7767217SJens Wiklander struct dirfile_entry dent; 291d7767217SJens Wiklander 292d7767217SJens Wiklander if (!oidlen || oidlen > sizeof(dent.oid)) 293d7767217SJens Wiklander return TEE_ERROR_BAD_PARAMETERS; 294d7767217SJens Wiklander memset(&dent, 0, sizeof(dent)); 295fd108c3eSJens Wiklander dent.uuid = *uuid; 296d7767217SJens Wiklander memcpy(dent.oid, oid, oidlen); 297d7767217SJens Wiklander dent.oidlen = oidlen; 298d7767217SJens Wiklander memcpy(dent.hash, dfh->hash, sizeof(dent.hash)); 299d7767217SJens Wiklander dent.file_number = dfh->file_number; 300d7767217SJens Wiklander 301d7767217SJens Wiklander if (dfh->idx < 0) { 302d7767217SJens Wiklander struct tee_fs_dirfile_fileh dfh2; 303d7767217SJens Wiklander 304fd108c3eSJens Wiklander res = tee_fs_dirfile_find(dirh, uuid, oid, oidlen, &dfh2); 305d7767217SJens Wiklander if (res) { 306d7767217SJens Wiklander if (res == TEE_ERROR_ITEM_NOT_FOUND) 307fd108c3eSJens Wiklander res = tee_fs_dirfile_find(dirh, uuid, NULL, 0, 308fd108c3eSJens Wiklander &dfh2); 309d7767217SJens Wiklander if (res) 310d7767217SJens Wiklander return res; 311d7767217SJens Wiklander } 312d7767217SJens Wiklander dfh->idx = dfh2.idx; 313d7767217SJens Wiklander } 314d7767217SJens Wiklander 315d7767217SJens Wiklander return write_dent(dirh, dfh->idx, &dent); 316d7767217SJens Wiklander } 317d7767217SJens Wiklander 318d7767217SJens Wiklander TEE_Result tee_fs_dirfile_remove(struct tee_fs_dirfile_dirh *dirh, 319d7767217SJens Wiklander const struct tee_fs_dirfile_fileh *dfh) 320d7767217SJens Wiklander { 321d7767217SJens Wiklander TEE_Result res; 322d7767217SJens Wiklander struct dirfile_entry dent; 323d7767217SJens Wiklander uint32_t file_number; 324d7767217SJens Wiklander 325d7767217SJens Wiklander res = read_dent(dirh, dfh->idx, &dent); 326d7767217SJens Wiklander if (res) 327d7767217SJens Wiklander return res; 328d7767217SJens Wiklander 329d7767217SJens Wiklander if (!dent.oidlen) 330d7767217SJens Wiklander return TEE_SUCCESS; 331d7767217SJens Wiklander 332d7767217SJens Wiklander file_number = dent.file_number; 333d7767217SJens Wiklander assert(dfh->file_number == file_number); 334d7767217SJens Wiklander assert(test_file(dirh, file_number)); 335d7767217SJens Wiklander 336d7767217SJens Wiklander memset(&dent, 0, sizeof(dent)); 337d7767217SJens Wiklander res = write_dent(dirh, dfh->idx, &dent); 338d7767217SJens Wiklander if (!res) 339d7767217SJens Wiklander clear_file(dirh, file_number); 340d7767217SJens Wiklander 341d7767217SJens Wiklander return res; 342d7767217SJens Wiklander } 343d7767217SJens Wiklander 344d7767217SJens Wiklander TEE_Result tee_fs_dirfile_update_hash(struct tee_fs_dirfile_dirh *dirh, 345d7767217SJens Wiklander const struct tee_fs_dirfile_fileh *dfh) 346d7767217SJens Wiklander { 347d7767217SJens Wiklander TEE_Result res; 348d7767217SJens Wiklander struct dirfile_entry dent; 349d7767217SJens Wiklander 350d7767217SJens Wiklander res = read_dent(dirh, dfh->idx, &dent); 351d7767217SJens Wiklander if (res) 352d7767217SJens Wiklander return res; 353d7767217SJens Wiklander assert(dent.file_number == dfh->file_number); 354d7767217SJens Wiklander assert(test_file(dirh, dent.file_number)); 355d7767217SJens Wiklander 356d7767217SJens Wiklander memcpy(&dent.hash, dfh->hash, sizeof(dent.hash)); 357d7767217SJens Wiklander 358d7767217SJens Wiklander return write_dent(dirh, dfh->idx, &dent); 359d7767217SJens Wiklander } 360d7767217SJens Wiklander 361d7767217SJens Wiklander TEE_Result tee_fs_dirfile_get_next(struct tee_fs_dirfile_dirh *dirh, 362fd108c3eSJens Wiklander const TEE_UUID *uuid, int *idx, void *oid, 363fd108c3eSJens Wiklander size_t *oidlen) 364d7767217SJens Wiklander { 365d7767217SJens Wiklander TEE_Result res; 366d7767217SJens Wiklander int i = *idx + 1; 367d7767217SJens Wiklander struct dirfile_entry dent; 368d7767217SJens Wiklander 369d7767217SJens Wiklander if (i < 0) 370d7767217SJens Wiklander i = 0; 371d7767217SJens Wiklander 372d7767217SJens Wiklander for (;; i++) { 373d7767217SJens Wiklander res = read_dent(dirh, i, &dent); 374d7767217SJens Wiklander if (res) 375d7767217SJens Wiklander return res; 376fd108c3eSJens Wiklander if (!memcmp(&dent.uuid, uuid, sizeof(dent.uuid)) && 377d7767217SJens Wiklander dent.oidlen) 378d7767217SJens Wiklander break; 379d7767217SJens Wiklander } 380d7767217SJens Wiklander 381d7767217SJens Wiklander if (*oidlen < dent.oidlen) 382d7767217SJens Wiklander return TEE_ERROR_SHORT_BUFFER; 383d7767217SJens Wiklander 384d7767217SJens Wiklander memcpy(oid, dent.oid, dent.oidlen); 385d7767217SJens Wiklander *oidlen = dent.oidlen; 386d7767217SJens Wiklander *idx = i; 387d7767217SJens Wiklander 388d7767217SJens Wiklander return TEE_SUCCESS; 389d7767217SJens Wiklander } 390