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*fd108c3eSJens Wiklander TEE_Result tee_fs_dirfile_open(const struct tee_fs_dirfile_operations *fops, 133d7767217SJens Wiklander struct tee_fs_dirfile_dirh **dirh_ret) 134d7767217SJens Wiklander { 135d7767217SJens Wiklander TEE_Result res; 136d7767217SJens Wiklander struct tee_fs_dirfile_dirh *dirh = calloc(1, sizeof(*dirh)); 137d7767217SJens Wiklander size_t n; 138d7767217SJens Wiklander 139d7767217SJens Wiklander if (!dirh) 140d7767217SJens Wiklander return TEE_ERROR_OUT_OF_MEMORY; 141d7767217SJens Wiklander 142d7767217SJens Wiklander dirh->fops = fops; 143d7767217SJens Wiklander res = fops->open(false, NULL, NULL, &dirh->fh); 144d7767217SJens Wiklander if (res) { 145d7767217SJens Wiklander res = fops->open(true, NULL, NULL, &dirh->fh); 146d7767217SJens Wiklander if (res) 147d7767217SJens Wiklander goto out; 148d7767217SJens Wiklander } 149d7767217SJens Wiklander 150d7767217SJens Wiklander for (n = 0;; n++) { 151d7767217SJens Wiklander struct dirfile_entry dent; 152d7767217SJens Wiklander 153d7767217SJens Wiklander res = read_dent(dirh, n, &dent); 154d7767217SJens Wiklander if (res) { 155d7767217SJens Wiklander if (res == TEE_ERROR_ITEM_NOT_FOUND) 156d7767217SJens Wiklander res = TEE_SUCCESS; 157d7767217SJens Wiklander goto out; 158d7767217SJens Wiklander } 159d7767217SJens Wiklander 160d7767217SJens Wiklander if (!dent.oidlen) 161d7767217SJens Wiklander continue; 162d7767217SJens Wiklander 163d7767217SJens Wiklander if (test_file(dirh, dent.file_number)) { 164d7767217SJens Wiklander DMSG("clearing duplicate file number %" PRIu32, 165d7767217SJens Wiklander dent.file_number); 166d7767217SJens Wiklander memset(&dent, 0, sizeof(dent)); 167d7767217SJens Wiklander res = write_dent(dirh, n, &dent); 168d7767217SJens Wiklander if (res) 169d7767217SJens Wiklander goto out; 170d7767217SJens Wiklander continue; 171d7767217SJens Wiklander } 172d7767217SJens Wiklander 173d7767217SJens Wiklander res = set_file(dirh, dent.file_number); 174d7767217SJens Wiklander if (res != TEE_SUCCESS) 175d7767217SJens Wiklander goto out; 176d7767217SJens Wiklander } 177d7767217SJens Wiklander out: 178d7767217SJens Wiklander if (!res) { 179d7767217SJens Wiklander dirh->ndents = n; 180d7767217SJens Wiklander *dirh_ret = dirh; 181d7767217SJens Wiklander } else { 182d7767217SJens Wiklander tee_fs_dirfile_close(dirh); 183d7767217SJens Wiklander } 184d7767217SJens Wiklander return res; 185d7767217SJens Wiklander } 186d7767217SJens Wiklander 187d7767217SJens Wiklander void tee_fs_dirfile_close(struct tee_fs_dirfile_dirh *dirh) 188d7767217SJens Wiklander { 189d7767217SJens Wiklander if (dirh) { 190d7767217SJens Wiklander dirh->fops->close(dirh->fh); 191d7767217SJens Wiklander free(dirh->files); 192d7767217SJens Wiklander free(dirh); 193d7767217SJens Wiklander } 194d7767217SJens Wiklander } 195d7767217SJens Wiklander 196d7767217SJens Wiklander TEE_Result tee_fs_dirfile_commit_writes(struct tee_fs_dirfile_dirh *dirh) 197d7767217SJens Wiklander { 198d7767217SJens Wiklander return dirh->fops->commit_writes(dirh->fh, NULL); 199d7767217SJens Wiklander } 200d7767217SJens Wiklander 201d7767217SJens Wiklander TEE_Result tee_fs_dirfile_get_tmp(struct tee_fs_dirfile_dirh *dirh, 202d7767217SJens Wiklander struct tee_fs_dirfile_fileh *dfh) 203d7767217SJens Wiklander { 204d7767217SJens Wiklander TEE_Result res; 205d7767217SJens Wiklander int i = 0; 206d7767217SJens Wiklander 207d7767217SJens Wiklander if (dirh->files) { 208d7767217SJens Wiklander bit_ffc(dirh->files, dirh->nbits, &i); 209d7767217SJens Wiklander if (i == -1) 210d7767217SJens Wiklander i = dirh->nbits; 211d7767217SJens Wiklander } 212d7767217SJens Wiklander 213d7767217SJens Wiklander res = set_file(dirh, i); 214d7767217SJens Wiklander if (!res) 215d7767217SJens Wiklander dfh->file_number = i; 216d7767217SJens Wiklander 217d7767217SJens Wiklander return res; 218d7767217SJens Wiklander } 219d7767217SJens Wiklander 220d7767217SJens Wiklander TEE_Result tee_fs_dirfile_find(struct tee_fs_dirfile_dirh *dirh, 221*fd108c3eSJens Wiklander const TEE_UUID *uuid, const void *oid, 222*fd108c3eSJens Wiklander size_t oidlen, struct tee_fs_dirfile_fileh *dfh) 223d7767217SJens Wiklander { 224d7767217SJens Wiklander TEE_Result res; 225d7767217SJens Wiklander struct dirfile_entry dent; 226d7767217SJens Wiklander int n; 227d7767217SJens Wiklander int first_free = -1; 228d7767217SJens Wiklander 229d7767217SJens Wiklander for (n = 0;; n++) { 230d7767217SJens Wiklander res = read_dent(dirh, n, &dent); 231d7767217SJens Wiklander if (res == TEE_ERROR_ITEM_NOT_FOUND && !oidlen) { 232d7767217SJens Wiklander memset(&dent, 0, sizeof(dent)); 233d7767217SJens Wiklander if (first_free != -1) 234d7767217SJens Wiklander n = first_free; 235d7767217SJens Wiklander break; 236d7767217SJens Wiklander } 237d7767217SJens Wiklander if (res) 238d7767217SJens Wiklander return res; 239d7767217SJens Wiklander 240*fd108c3eSJens Wiklander /* TODO check this loop when oidlen == 0 */ 241*fd108c3eSJens Wiklander 242d7767217SJens Wiklander if (!dent.oidlen && first_free == -1) 243d7767217SJens Wiklander first_free = n; 244d7767217SJens Wiklander if (dent.oidlen != oidlen) 245d7767217SJens Wiklander continue; 246d7767217SJens Wiklander 247d7767217SJens Wiklander assert(!oidlen || !dent.oidlen || 248d7767217SJens Wiklander test_file(dirh, dent.file_number)); 249d7767217SJens Wiklander 250*fd108c3eSJens Wiklander if (!memcmp(&dent.uuid, uuid, sizeof(dent.uuid)) && 251d7767217SJens Wiklander !memcmp(&dent.oid, oid, oidlen)) 252d7767217SJens Wiklander break; 253d7767217SJens Wiklander } 254d7767217SJens Wiklander 255d7767217SJens Wiklander if (dfh) { 256d7767217SJens Wiklander dfh->idx = n; 257d7767217SJens Wiklander dfh->file_number = dent.file_number; 258d7767217SJens Wiklander memcpy(dfh->hash, dent.hash, sizeof(dent.hash)); 259d7767217SJens Wiklander } 260d7767217SJens Wiklander 261d7767217SJens Wiklander return TEE_SUCCESS; 262d7767217SJens Wiklander } 263d7767217SJens Wiklander 264d7767217SJens Wiklander TEE_Result tee_fs_dirfile_fileh_to_fname(const struct tee_fs_dirfile_fileh *dfh, 265d7767217SJens Wiklander char *fname, size_t *fnlen) 266d7767217SJens Wiklander { 267d7767217SJens Wiklander int r; 268d7767217SJens Wiklander size_t l = *fnlen; 269d7767217SJens Wiklander 270d7767217SJens Wiklander if (dfh) 271d7767217SJens Wiklander r = snprintf(fname, l, "%" PRIx32, dfh->file_number); 272d7767217SJens Wiklander else 273d7767217SJens Wiklander r = snprintf(fname, l, "dirf.db"); 274d7767217SJens Wiklander 275d7767217SJens Wiklander if (r < 0) 276d7767217SJens Wiklander return TEE_ERROR_GENERIC; 277d7767217SJens Wiklander 278d7767217SJens Wiklander *fnlen = r + 1; 279d7767217SJens Wiklander if ((size_t)r >= l) 280d7767217SJens Wiklander return TEE_ERROR_SHORT_BUFFER; 281d7767217SJens Wiklander 282d7767217SJens Wiklander return TEE_SUCCESS; 283d7767217SJens Wiklander } 284d7767217SJens Wiklander 285d7767217SJens Wiklander TEE_Result tee_fs_dirfile_rename(struct tee_fs_dirfile_dirh *dirh, 286*fd108c3eSJens Wiklander const TEE_UUID *uuid, 287d7767217SJens Wiklander struct tee_fs_dirfile_fileh *dfh, 288d7767217SJens Wiklander const void *oid, size_t oidlen) 289d7767217SJens Wiklander { 290d7767217SJens Wiklander TEE_Result res; 291d7767217SJens Wiklander struct dirfile_entry dent; 292d7767217SJens Wiklander 293d7767217SJens Wiklander if (!oidlen || oidlen > sizeof(dent.oid)) 294d7767217SJens Wiklander return TEE_ERROR_BAD_PARAMETERS; 295d7767217SJens Wiklander memset(&dent, 0, sizeof(dent)); 296*fd108c3eSJens Wiklander dent.uuid = *uuid; 297d7767217SJens Wiklander memcpy(dent.oid, oid, oidlen); 298d7767217SJens Wiklander dent.oidlen = oidlen; 299d7767217SJens Wiklander memcpy(dent.hash, dfh->hash, sizeof(dent.hash)); 300d7767217SJens Wiklander dent.file_number = dfh->file_number; 301d7767217SJens Wiklander 302d7767217SJens Wiklander if (dfh->idx < 0) { 303d7767217SJens Wiklander struct tee_fs_dirfile_fileh dfh2; 304d7767217SJens Wiklander 305*fd108c3eSJens Wiklander res = tee_fs_dirfile_find(dirh, uuid, oid, oidlen, &dfh2); 306d7767217SJens Wiklander if (res) { 307d7767217SJens Wiklander if (res == TEE_ERROR_ITEM_NOT_FOUND) 308*fd108c3eSJens Wiklander res = tee_fs_dirfile_find(dirh, uuid, NULL, 0, 309*fd108c3eSJens Wiklander &dfh2); 310d7767217SJens Wiklander if (res) 311d7767217SJens Wiklander return res; 312d7767217SJens Wiklander } 313d7767217SJens Wiklander dfh->idx = dfh2.idx; 314d7767217SJens Wiklander } 315d7767217SJens Wiklander 316d7767217SJens Wiklander return write_dent(dirh, dfh->idx, &dent); 317d7767217SJens Wiklander } 318d7767217SJens Wiklander 319d7767217SJens Wiklander TEE_Result tee_fs_dirfile_remove(struct tee_fs_dirfile_dirh *dirh, 320d7767217SJens Wiklander const struct tee_fs_dirfile_fileh *dfh) 321d7767217SJens Wiklander { 322d7767217SJens Wiklander TEE_Result res; 323d7767217SJens Wiklander struct dirfile_entry dent; 324d7767217SJens Wiklander uint32_t file_number; 325d7767217SJens Wiklander 326d7767217SJens Wiklander res = read_dent(dirh, dfh->idx, &dent); 327d7767217SJens Wiklander if (res) 328d7767217SJens Wiklander return res; 329d7767217SJens Wiklander 330d7767217SJens Wiklander if (!dent.oidlen) 331d7767217SJens Wiklander return TEE_SUCCESS; 332d7767217SJens Wiklander 333d7767217SJens Wiklander file_number = dent.file_number; 334d7767217SJens Wiklander assert(dfh->file_number == file_number); 335d7767217SJens Wiklander assert(test_file(dirh, file_number)); 336d7767217SJens Wiklander 337d7767217SJens Wiklander memset(&dent, 0, sizeof(dent)); 338d7767217SJens Wiklander res = write_dent(dirh, dfh->idx, &dent); 339d7767217SJens Wiklander if (!res) 340d7767217SJens Wiklander clear_file(dirh, file_number); 341d7767217SJens Wiklander 342d7767217SJens Wiklander return res; 343d7767217SJens Wiklander } 344d7767217SJens Wiklander 345d7767217SJens Wiklander TEE_Result tee_fs_dirfile_update_hash(struct tee_fs_dirfile_dirh *dirh, 346d7767217SJens Wiklander const struct tee_fs_dirfile_fileh *dfh) 347d7767217SJens Wiklander { 348d7767217SJens Wiklander TEE_Result res; 349d7767217SJens Wiklander struct dirfile_entry dent; 350d7767217SJens Wiklander 351d7767217SJens Wiklander res = read_dent(dirh, dfh->idx, &dent); 352d7767217SJens Wiklander if (res) 353d7767217SJens Wiklander return res; 354d7767217SJens Wiklander assert(dent.file_number == dfh->file_number); 355d7767217SJens Wiklander assert(test_file(dirh, dent.file_number)); 356d7767217SJens Wiklander 357d7767217SJens Wiklander memcpy(&dent.hash, dfh->hash, sizeof(dent.hash)); 358d7767217SJens Wiklander 359d7767217SJens Wiklander return write_dent(dirh, dfh->idx, &dent); 360d7767217SJens Wiklander } 361d7767217SJens Wiklander 362d7767217SJens Wiklander TEE_Result tee_fs_dirfile_get_next(struct tee_fs_dirfile_dirh *dirh, 363*fd108c3eSJens Wiklander const TEE_UUID *uuid, int *idx, void *oid, 364*fd108c3eSJens Wiklander size_t *oidlen) 365d7767217SJens Wiklander { 366d7767217SJens Wiklander TEE_Result res; 367d7767217SJens Wiklander int i = *idx + 1; 368d7767217SJens Wiklander struct dirfile_entry dent; 369d7767217SJens Wiklander 370d7767217SJens Wiklander if (i < 0) 371d7767217SJens Wiklander i = 0; 372d7767217SJens Wiklander 373d7767217SJens Wiklander for (;; i++) { 374d7767217SJens Wiklander res = read_dent(dirh, i, &dent); 375d7767217SJens Wiklander if (res) 376d7767217SJens Wiklander return res; 377*fd108c3eSJens Wiklander if (!memcmp(&dent.uuid, uuid, sizeof(dent.uuid)) && 378d7767217SJens Wiklander dent.oidlen) 379d7767217SJens Wiklander break; 380d7767217SJens Wiklander } 381d7767217SJens Wiklander 382d7767217SJens Wiklander if (*oidlen < dent.oidlen) 383d7767217SJens Wiklander return TEE_ERROR_SHORT_BUFFER; 384d7767217SJens Wiklander 385d7767217SJens Wiklander memcpy(oid, dent.oid, dent.oidlen); 386d7767217SJens Wiklander *oidlen = dent.oidlen; 387d7767217SJens Wiklander *idx = i; 388d7767217SJens Wiklander 389d7767217SJens Wiklander return TEE_SUCCESS; 390d7767217SJens Wiklander } 391