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