11bb92983SJerome Forissier // SPDX-License-Identifier: BSD-2-Clause 2d7767217SJens Wiklander /* 3d7767217SJens Wiklander * Copyright (c) 2017, Linaro Limited 4d7767217SJens Wiklander */ 5d7767217SJens Wiklander 6d7767217SJens Wiklander #include <assert.h> 7d7767217SJens Wiklander #include <bitstring.h> 8d7767217SJens Wiklander #include <stdio.h> 9d7767217SJens Wiklander #include <stdlib.h> 10d7767217SJens Wiklander #include <string.h> 11d7767217SJens Wiklander #include <tee/fs_dirfile.h> 12d7767217SJens Wiklander #include <types_ext.h> 13d7767217SJens Wiklander 14d7767217SJens Wiklander struct tee_fs_dirfile_dirh { 15d7767217SJens Wiklander const struct tee_fs_dirfile_operations *fops; 16d7767217SJens Wiklander struct tee_file_handle *fh; 17d7767217SJens Wiklander int nbits; 18d7767217SJens Wiklander bitstr_t *files; 19d7767217SJens Wiklander size_t ndents; 20d7767217SJens Wiklander }; 21d7767217SJens Wiklander 22d7767217SJens Wiklander struct dirfile_entry { 23d7767217SJens Wiklander TEE_UUID uuid; 24d7767217SJens Wiklander uint8_t oid[TEE_OBJECT_ID_MAX_LEN]; 25d7767217SJens Wiklander uint32_t oidlen; 26d7767217SJens Wiklander uint8_t hash[TEE_FS_HTREE_HASH_SIZE]; 27d7767217SJens Wiklander uint32_t file_number; 28d7767217SJens Wiklander }; 29d7767217SJens Wiklander 3063740eacSJerome Forissier #define OID_EMPTY_NAME 1 3163740eacSJerome Forissier 3263740eacSJerome Forissier /* 3363740eacSJerome Forissier * An object can have an ID of size zero. This object is represented by 3463740eacSJerome Forissier * oidlen == 0 and oid[0] == OID_EMPTY_NAME. When both are zero, the entry is 3563740eacSJerome Forissier * not a valid object. 3663740eacSJerome Forissier */ 3763740eacSJerome Forissier static bool is_free(struct dirfile_entry *dent) 3863740eacSJerome Forissier { 3963740eacSJerome Forissier assert(dent->oidlen || !dent->oid[0] || dent->oid[0] == OID_EMPTY_NAME); 4063740eacSJerome Forissier 4163740eacSJerome Forissier return !dent->oidlen && !dent->oid[0]; 4263740eacSJerome Forissier } 4363740eacSJerome Forissier 44d7767217SJens Wiklander /* 45d7767217SJens Wiklander * File layout 46d7767217SJens Wiklander * 47d7767217SJens Wiklander * dirfile_entry.0 48d7767217SJens Wiklander * ... 49d7767217SJens Wiklander * dirfile_entry.n 50d7767217SJens Wiklander * 51d7767217SJens Wiklander * where n the index is disconnected from file_number in struct dirfile_entry 52d7767217SJens Wiklander */ 53d7767217SJens Wiklander 54d7767217SJens Wiklander static TEE_Result maybe_grow_files(struct tee_fs_dirfile_dirh *dirh, int idx) 55d7767217SJens Wiklander { 56d7767217SJens Wiklander void *p; 57d7767217SJens Wiklander 58d7767217SJens Wiklander if (idx < dirh->nbits) 59d7767217SJens Wiklander return TEE_SUCCESS; 60d7767217SJens Wiklander 61d7767217SJens Wiklander p = realloc(dirh->files, bitstr_size(idx + 1)); 62d7767217SJens Wiklander if (!p) 63d7767217SJens Wiklander return TEE_ERROR_OUT_OF_MEMORY; 64d7767217SJens Wiklander dirh->files = p; 65d7767217SJens Wiklander 66d7767217SJens Wiklander bit_nclear(dirh->files, dirh->nbits, idx); 67d7767217SJens Wiklander dirh->nbits = idx + 1; 68d7767217SJens Wiklander 69d7767217SJens Wiklander return TEE_SUCCESS; 70d7767217SJens Wiklander } 71d7767217SJens Wiklander 72d7767217SJens Wiklander static TEE_Result set_file(struct tee_fs_dirfile_dirh *dirh, int idx) 73d7767217SJens Wiklander { 74d7767217SJens Wiklander TEE_Result res = maybe_grow_files(dirh, idx); 75d7767217SJens Wiklander 76d7767217SJens Wiklander if (!res) 77d7767217SJens Wiklander bit_set(dirh->files, idx); 78d7767217SJens Wiklander 79d7767217SJens Wiklander return res; 80d7767217SJens Wiklander } 81d7767217SJens Wiklander 82d7767217SJens Wiklander static void clear_file(struct tee_fs_dirfile_dirh *dirh, int idx) 83d7767217SJens Wiklander { 84d7767217SJens Wiklander if (idx < dirh->nbits) 85d7767217SJens Wiklander bit_clear(dirh->files, idx); 86d7767217SJens Wiklander } 87d7767217SJens Wiklander 88d7767217SJens Wiklander static bool test_file(struct tee_fs_dirfile_dirh *dirh, int idx) 89d7767217SJens Wiklander { 90d7767217SJens Wiklander if (idx < dirh->nbits) 91d7767217SJens Wiklander return bit_test(dirh->files, idx); 92d7767217SJens Wiklander 93d7767217SJens Wiklander return false; 94d7767217SJens Wiklander } 95d7767217SJens Wiklander 96d7767217SJens Wiklander static TEE_Result read_dent(struct tee_fs_dirfile_dirh *dirh, int idx, 97d7767217SJens Wiklander struct dirfile_entry *dent) 98d7767217SJens Wiklander { 99d7767217SJens Wiklander TEE_Result res; 100d7767217SJens Wiklander size_t l; 101d7767217SJens Wiklander 102d7767217SJens Wiklander l = sizeof(*dent); 103d7767217SJens Wiklander res = dirh->fops->read(dirh->fh, sizeof(struct dirfile_entry) * idx, 104d7767217SJens Wiklander dent, &l); 105d7767217SJens Wiklander if (!res && l != sizeof(*dent)) 106d7767217SJens Wiklander res = TEE_ERROR_ITEM_NOT_FOUND; 107d7767217SJens Wiklander 108d7767217SJens Wiklander return res; 109d7767217SJens Wiklander } 110d7767217SJens Wiklander 111d7767217SJens Wiklander static TEE_Result write_dent(struct tee_fs_dirfile_dirh *dirh, size_t n, 112d7767217SJens Wiklander struct dirfile_entry *dent) 113d7767217SJens Wiklander { 114d7767217SJens Wiklander TEE_Result res; 115d7767217SJens Wiklander 116*b2284b11SJens Wiklander res = dirh->fops->write(dirh->fh, sizeof(*dent) * n, dent, 117*b2284b11SJens Wiklander sizeof(*dent)); 118d7767217SJens Wiklander if (!res && n >= dirh->ndents) 119d7767217SJens Wiklander dirh->ndents = n + 1; 120d7767217SJens Wiklander 121d7767217SJens Wiklander return res; 122d7767217SJens Wiklander } 123d7767217SJens Wiklander 124a4ed7bafSJens Wiklander TEE_Result tee_fs_dirfile_open(bool create, uint8_t *hash, 125a4ed7bafSJens Wiklander const struct tee_fs_dirfile_operations *fops, 126d7767217SJens Wiklander struct tee_fs_dirfile_dirh **dirh_ret) 127d7767217SJens Wiklander { 128d7767217SJens Wiklander TEE_Result res; 129d7767217SJens Wiklander struct tee_fs_dirfile_dirh *dirh = calloc(1, sizeof(*dirh)); 130d7767217SJens Wiklander size_t n; 131d7767217SJens Wiklander 132d7767217SJens Wiklander if (!dirh) 133d7767217SJens Wiklander return TEE_ERROR_OUT_OF_MEMORY; 134d7767217SJens Wiklander 135d7767217SJens Wiklander dirh->fops = fops; 136a4ed7bafSJens Wiklander res = fops->open(create, hash, NULL, NULL, &dirh->fh); 137d7767217SJens Wiklander if (res) 138d7767217SJens Wiklander goto out; 139d7767217SJens Wiklander 140d7767217SJens Wiklander for (n = 0;; n++) { 141d7767217SJens Wiklander struct dirfile_entry dent; 142d7767217SJens Wiklander 143d7767217SJens Wiklander res = read_dent(dirh, n, &dent); 144d7767217SJens Wiklander if (res) { 145d7767217SJens Wiklander if (res == TEE_ERROR_ITEM_NOT_FOUND) 146d7767217SJens Wiklander res = TEE_SUCCESS; 147d7767217SJens Wiklander goto out; 148d7767217SJens Wiklander } 149d7767217SJens Wiklander 15063740eacSJerome Forissier if (is_free(&dent)) 151d7767217SJens Wiklander continue; 152d7767217SJens Wiklander 153d7767217SJens Wiklander if (test_file(dirh, dent.file_number)) { 154d7767217SJens Wiklander DMSG("clearing duplicate file number %" PRIu32, 155d7767217SJens Wiklander dent.file_number); 156d7767217SJens Wiklander memset(&dent, 0, sizeof(dent)); 157d7767217SJens Wiklander res = write_dent(dirh, n, &dent); 158d7767217SJens Wiklander if (res) 159d7767217SJens Wiklander goto out; 160d7767217SJens Wiklander continue; 161d7767217SJens Wiklander } 162d7767217SJens Wiklander 163d7767217SJens Wiklander res = set_file(dirh, dent.file_number); 164d7767217SJens Wiklander if (res != TEE_SUCCESS) 165d7767217SJens Wiklander goto out; 166d7767217SJens Wiklander } 167d7767217SJens Wiklander out: 168d7767217SJens Wiklander if (!res) { 169d7767217SJens Wiklander dirh->ndents = n; 170d7767217SJens Wiklander *dirh_ret = dirh; 171d7767217SJens Wiklander } else { 172d7767217SJens Wiklander tee_fs_dirfile_close(dirh); 173d7767217SJens Wiklander } 174d7767217SJens Wiklander return res; 175d7767217SJens Wiklander } 176d7767217SJens Wiklander 177d7767217SJens Wiklander void tee_fs_dirfile_close(struct tee_fs_dirfile_dirh *dirh) 178d7767217SJens Wiklander { 179d7767217SJens Wiklander if (dirh) { 180d7767217SJens Wiklander dirh->fops->close(dirh->fh); 181d7767217SJens Wiklander free(dirh->files); 182d7767217SJens Wiklander free(dirh); 183d7767217SJens Wiklander } 184d7767217SJens Wiklander } 185d7767217SJens Wiklander 186a4ed7bafSJens Wiklander TEE_Result tee_fs_dirfile_commit_writes(struct tee_fs_dirfile_dirh *dirh, 187a4ed7bafSJens Wiklander uint8_t *hash) 188d7767217SJens Wiklander { 189a4ed7bafSJens Wiklander return dirh->fops->commit_writes(dirh->fh, hash); 190d7767217SJens Wiklander } 191d7767217SJens Wiklander 192d7767217SJens Wiklander TEE_Result tee_fs_dirfile_get_tmp(struct tee_fs_dirfile_dirh *dirh, 193d7767217SJens Wiklander struct tee_fs_dirfile_fileh *dfh) 194d7767217SJens Wiklander { 195d7767217SJens Wiklander TEE_Result res; 196d7767217SJens Wiklander int i = 0; 197d7767217SJens Wiklander 19868697bf5SJens Wiklander if (dirh->nbits) { 199d7767217SJens Wiklander bit_ffc(dirh->files, dirh->nbits, &i); 200d7767217SJens Wiklander if (i == -1) 201d7767217SJens Wiklander i = dirh->nbits; 202d7767217SJens Wiklander } 203d7767217SJens Wiklander 204d7767217SJens Wiklander res = set_file(dirh, i); 205d7767217SJens Wiklander if (!res) 206d7767217SJens Wiklander dfh->file_number = i; 207d7767217SJens Wiklander 208d7767217SJens Wiklander return res; 209d7767217SJens Wiklander } 210d7767217SJens Wiklander 211d7767217SJens Wiklander TEE_Result tee_fs_dirfile_find(struct tee_fs_dirfile_dirh *dirh, 212fd108c3eSJens Wiklander const TEE_UUID *uuid, const void *oid, 213fd108c3eSJens Wiklander size_t oidlen, struct tee_fs_dirfile_fileh *dfh) 214d7767217SJens Wiklander { 21563740eacSJerome Forissier TEE_Result res = TEE_SUCCESS; 21663740eacSJerome Forissier struct dirfile_entry dent = { }; 21763740eacSJerome Forissier int n = 0; 218d7767217SJens Wiklander 219d7767217SJens Wiklander for (n = 0;; n++) { 220d7767217SJens Wiklander res = read_dent(dirh, n, &dent); 221d7767217SJens Wiklander if (res) 222d7767217SJens Wiklander return res; 223d7767217SJens Wiklander 22463740eacSJerome Forissier if (is_free(&dent)) 22563740eacSJerome Forissier continue; 226d7767217SJens Wiklander if (dent.oidlen != oidlen) 227d7767217SJens Wiklander continue; 228d7767217SJens Wiklander 22963740eacSJerome Forissier assert(test_file(dirh, dent.file_number)); 230d7767217SJens Wiklander 231fd108c3eSJens Wiklander if (!memcmp(&dent.uuid, uuid, sizeof(dent.uuid)) && 232d7767217SJens Wiklander !memcmp(&dent.oid, oid, oidlen)) 233d7767217SJens Wiklander break; 234d7767217SJens Wiklander } 235d7767217SJens Wiklander 236d7767217SJens Wiklander if (dfh) { 237d7767217SJens Wiklander dfh->idx = n; 238d7767217SJens Wiklander dfh->file_number = dent.file_number; 239d7767217SJens Wiklander memcpy(dfh->hash, dent.hash, sizeof(dent.hash)); 240d7767217SJens Wiklander } 241d7767217SJens Wiklander 242d7767217SJens Wiklander return TEE_SUCCESS; 243d7767217SJens Wiklander } 244d7767217SJens Wiklander 24563740eacSJerome Forissier static TEE_Result find_empty_idx(struct tee_fs_dirfile_dirh *dh, int *idx) 24663740eacSJerome Forissier { 24763740eacSJerome Forissier struct dirfile_entry dent = { }; 24863740eacSJerome Forissier TEE_Result res = TEE_SUCCESS; 24963740eacSJerome Forissier int n = 0; 25063740eacSJerome Forissier 25163740eacSJerome Forissier for (n = 0;; n++) { 25263740eacSJerome Forissier res = read_dent(dh, n, &dent); 25363740eacSJerome Forissier if (res == TEE_ERROR_ITEM_NOT_FOUND) 25463740eacSJerome Forissier break; 25563740eacSJerome Forissier if (res) 25663740eacSJerome Forissier return res; 25763740eacSJerome Forissier if (is_free(&dent)) 25863740eacSJerome Forissier break; 25963740eacSJerome Forissier } 26063740eacSJerome Forissier 26163740eacSJerome Forissier *idx = n; 26263740eacSJerome Forissier return TEE_SUCCESS; 26363740eacSJerome Forissier } 26463740eacSJerome Forissier 265d7767217SJens Wiklander TEE_Result tee_fs_dirfile_fileh_to_fname(const struct tee_fs_dirfile_fileh *dfh, 266d7767217SJens Wiklander char *fname, size_t *fnlen) 267d7767217SJens Wiklander { 268d7767217SJens Wiklander int r; 269d7767217SJens Wiklander size_t l = *fnlen; 270d7767217SJens Wiklander 271d7767217SJens Wiklander if (dfh) 272d7767217SJens Wiklander r = snprintf(fname, l, "%" PRIx32, dfh->file_number); 273d7767217SJens Wiklander else 274d7767217SJens Wiklander r = snprintf(fname, l, "dirf.db"); 275d7767217SJens Wiklander 276d7767217SJens Wiklander if (r < 0) 277d7767217SJens Wiklander return TEE_ERROR_GENERIC; 278d7767217SJens Wiklander 279d7767217SJens Wiklander *fnlen = r + 1; 280d7767217SJens Wiklander if ((size_t)r >= l) 281d7767217SJens Wiklander return TEE_ERROR_SHORT_BUFFER; 282d7767217SJens Wiklander 283d7767217SJens Wiklander return TEE_SUCCESS; 284d7767217SJens Wiklander } 285d7767217SJens Wiklander 286d7767217SJens Wiklander TEE_Result tee_fs_dirfile_rename(struct tee_fs_dirfile_dirh *dirh, 287fd108c3eSJens Wiklander const TEE_UUID *uuid, 288d7767217SJens Wiklander struct tee_fs_dirfile_fileh *dfh, 289d7767217SJens Wiklander const void *oid, size_t oidlen) 290d7767217SJens Wiklander { 291d7767217SJens Wiklander TEE_Result res; 292d7767217SJens Wiklander struct dirfile_entry dent; 293d7767217SJens Wiklander 29463740eacSJerome Forissier if (oidlen > sizeof(dent.oid)) 295d7767217SJens Wiklander return TEE_ERROR_BAD_PARAMETERS; 296d7767217SJens Wiklander memset(&dent, 0, sizeof(dent)); 297fd108c3eSJens Wiklander dent.uuid = *uuid; 29863740eacSJerome Forissier if (oidlen) 299d7767217SJens Wiklander memcpy(dent.oid, oid, oidlen); 30063740eacSJerome Forissier else 30163740eacSJerome Forissier dent.oid[0] = OID_EMPTY_NAME; 30263740eacSJerome Forissier 303d7767217SJens Wiklander dent.oidlen = oidlen; 304d7767217SJens Wiklander memcpy(dent.hash, dfh->hash, sizeof(dent.hash)); 305d7767217SJens Wiklander dent.file_number = dfh->file_number; 306d7767217SJens Wiklander 307d7767217SJens Wiklander if (dfh->idx < 0) { 308d7767217SJens Wiklander struct tee_fs_dirfile_fileh dfh2; 309d7767217SJens Wiklander 310fd108c3eSJens Wiklander res = tee_fs_dirfile_find(dirh, uuid, oid, oidlen, &dfh2); 311d7767217SJens Wiklander if (res) { 312d7767217SJens Wiklander if (res == TEE_ERROR_ITEM_NOT_FOUND) 31363740eacSJerome Forissier res = find_empty_idx(dirh, &dfh2.idx); 314d7767217SJens Wiklander if (res) 315d7767217SJens Wiklander return res; 316d7767217SJens Wiklander } 317d7767217SJens Wiklander dfh->idx = dfh2.idx; 318d7767217SJens Wiklander } 319d7767217SJens Wiklander 320d7767217SJens Wiklander return write_dent(dirh, dfh->idx, &dent); 321d7767217SJens Wiklander } 322d7767217SJens Wiklander 323d7767217SJens Wiklander TEE_Result tee_fs_dirfile_remove(struct tee_fs_dirfile_dirh *dirh, 324d7767217SJens Wiklander const struct tee_fs_dirfile_fileh *dfh) 325d7767217SJens Wiklander { 326d7767217SJens Wiklander TEE_Result res; 327d7767217SJens Wiklander struct dirfile_entry dent; 328d7767217SJens Wiklander uint32_t file_number; 329d7767217SJens Wiklander 330d7767217SJens Wiklander res = read_dent(dirh, dfh->idx, &dent); 331d7767217SJens Wiklander if (res) 332d7767217SJens Wiklander return res; 333d7767217SJens Wiklander 33463740eacSJerome Forissier if (is_free(&dent)) 335d7767217SJens Wiklander return TEE_SUCCESS; 336d7767217SJens Wiklander 337d7767217SJens Wiklander file_number = dent.file_number; 338d7767217SJens Wiklander assert(dfh->file_number == file_number); 339d7767217SJens Wiklander assert(test_file(dirh, file_number)); 340d7767217SJens Wiklander 341d7767217SJens Wiklander memset(&dent, 0, sizeof(dent)); 342d7767217SJens Wiklander res = write_dent(dirh, dfh->idx, &dent); 343d7767217SJens Wiklander if (!res) 344d7767217SJens Wiklander clear_file(dirh, file_number); 345d7767217SJens Wiklander 346d7767217SJens Wiklander return res; 347d7767217SJens Wiklander } 348d7767217SJens Wiklander 349d7767217SJens Wiklander TEE_Result tee_fs_dirfile_update_hash(struct tee_fs_dirfile_dirh *dirh, 350d7767217SJens Wiklander const struct tee_fs_dirfile_fileh *dfh) 351d7767217SJens Wiklander { 352d7767217SJens Wiklander TEE_Result res; 353d7767217SJens Wiklander struct dirfile_entry dent; 354d7767217SJens Wiklander 355d7767217SJens Wiklander res = read_dent(dirh, dfh->idx, &dent); 356d7767217SJens Wiklander if (res) 357d7767217SJens Wiklander return res; 358d7767217SJens Wiklander assert(dent.file_number == dfh->file_number); 359d7767217SJens Wiklander assert(test_file(dirh, dent.file_number)); 360d7767217SJens Wiklander 361d7767217SJens Wiklander memcpy(&dent.hash, dfh->hash, sizeof(dent.hash)); 362d7767217SJens Wiklander 363d7767217SJens Wiklander return write_dent(dirh, dfh->idx, &dent); 364d7767217SJens Wiklander } 365d7767217SJens Wiklander 366d7767217SJens Wiklander TEE_Result tee_fs_dirfile_get_next(struct tee_fs_dirfile_dirh *dirh, 367fd108c3eSJens Wiklander const TEE_UUID *uuid, int *idx, void *oid, 368fd108c3eSJens Wiklander size_t *oidlen) 369d7767217SJens Wiklander { 370d7767217SJens Wiklander TEE_Result res; 371d7767217SJens Wiklander int i = *idx + 1; 372d7767217SJens Wiklander struct dirfile_entry dent; 373d7767217SJens Wiklander 374d7767217SJens Wiklander if (i < 0) 375d7767217SJens Wiklander i = 0; 376d7767217SJens Wiklander 377d7767217SJens Wiklander for (;; i++) { 378d7767217SJens Wiklander res = read_dent(dirh, i, &dent); 379d7767217SJens Wiklander if (res) 380d7767217SJens Wiklander return res; 381fd108c3eSJens Wiklander if (!memcmp(&dent.uuid, uuid, sizeof(dent.uuid)) && 38263740eacSJerome Forissier !is_free(&dent)) 383d7767217SJens Wiklander break; 384d7767217SJens Wiklander } 385d7767217SJens Wiklander 386d7767217SJens Wiklander if (*oidlen < dent.oidlen) 387d7767217SJens Wiklander return TEE_ERROR_SHORT_BUFFER; 388d7767217SJens Wiklander 389d7767217SJens Wiklander memcpy(oid, dent.oid, dent.oidlen); 390d7767217SJens Wiklander *oidlen = dent.oidlen; 391d7767217SJens Wiklander *idx = i; 392d7767217SJens Wiklander 393d7767217SJens Wiklander return TEE_SUCCESS; 394d7767217SJens Wiklander } 395