1 // SPDX-License-Identifier: BSD-2-Clause 2 /* 3 * Copyright (c) 2017, Linaro Limited 4 * All rights reserved. 5 */ 6 7 #include <assert.h> 8 #include <bitstring.h> 9 #include <stdio.h> 10 #include <stdlib.h> 11 #include <string.h> 12 #include <tee/fs_dirfile.h> 13 #include <types_ext.h> 14 15 struct tee_fs_dirfile_dirh { 16 const struct tee_fs_dirfile_operations *fops; 17 struct tee_file_handle *fh; 18 int nbits; 19 bitstr_t *files; 20 size_t ndents; 21 }; 22 23 struct dirfile_entry { 24 TEE_UUID uuid; 25 uint8_t oid[TEE_OBJECT_ID_MAX_LEN]; 26 uint32_t oidlen; 27 uint8_t hash[TEE_FS_HTREE_HASH_SIZE]; 28 uint32_t file_number; 29 }; 30 31 /* 32 * File layout 33 * 34 * dirfile_entry.0 35 * ... 36 * dirfile_entry.n 37 * 38 * where n the index is disconnected from file_number in struct dirfile_entry 39 */ 40 41 static TEE_Result maybe_grow_files(struct tee_fs_dirfile_dirh *dirh, int idx) 42 { 43 void *p; 44 45 if (idx < dirh->nbits) 46 return TEE_SUCCESS; 47 48 p = realloc(dirh->files, bitstr_size(idx + 1)); 49 if (!p) 50 return TEE_ERROR_OUT_OF_MEMORY; 51 dirh->files = p; 52 53 bit_nclear(dirh->files, dirh->nbits, idx); 54 dirh->nbits = idx + 1; 55 56 return TEE_SUCCESS; 57 } 58 59 static TEE_Result set_file(struct tee_fs_dirfile_dirh *dirh, int idx) 60 { 61 TEE_Result res = maybe_grow_files(dirh, idx); 62 63 if (!res) 64 bit_set(dirh->files, idx); 65 66 return res; 67 } 68 69 static void clear_file(struct tee_fs_dirfile_dirh *dirh, int idx) 70 { 71 if (idx < dirh->nbits) 72 bit_clear(dirh->files, idx); 73 } 74 75 static bool test_file(struct tee_fs_dirfile_dirh *dirh, int idx) 76 { 77 if (idx < dirh->nbits) 78 return bit_test(dirh->files, idx); 79 80 return false; 81 } 82 83 static TEE_Result read_dent(struct tee_fs_dirfile_dirh *dirh, int idx, 84 struct dirfile_entry *dent) 85 { 86 TEE_Result res; 87 size_t l; 88 89 l = sizeof(*dent); 90 res = dirh->fops->read(dirh->fh, sizeof(struct dirfile_entry) * idx, 91 dent, &l); 92 if (!res && l != sizeof(*dent)) 93 res = TEE_ERROR_ITEM_NOT_FOUND; 94 95 return res; 96 } 97 98 static TEE_Result write_dent(struct tee_fs_dirfile_dirh *dirh, size_t n, 99 struct dirfile_entry *dent) 100 { 101 TEE_Result res; 102 103 res = dirh->fops->write(dirh->fh, sizeof(*dent) * n, 104 dent, sizeof(*dent)); 105 if (!res && n >= dirh->ndents) 106 dirh->ndents = n + 1; 107 108 return res; 109 } 110 111 TEE_Result tee_fs_dirfile_open(bool create, uint8_t *hash, 112 const struct tee_fs_dirfile_operations *fops, 113 struct tee_fs_dirfile_dirh **dirh_ret) 114 { 115 TEE_Result res; 116 struct tee_fs_dirfile_dirh *dirh = calloc(1, sizeof(*dirh)); 117 size_t n; 118 119 if (!dirh) 120 return TEE_ERROR_OUT_OF_MEMORY; 121 122 dirh->fops = fops; 123 res = fops->open(create, hash, NULL, NULL, &dirh->fh); 124 if (res) 125 goto out; 126 127 for (n = 0;; n++) { 128 struct dirfile_entry dent; 129 130 res = read_dent(dirh, n, &dent); 131 if (res) { 132 if (res == TEE_ERROR_ITEM_NOT_FOUND) 133 res = TEE_SUCCESS; 134 goto out; 135 } 136 137 if (!dent.oidlen) 138 continue; 139 140 if (test_file(dirh, dent.file_number)) { 141 DMSG("clearing duplicate file number %" PRIu32, 142 dent.file_number); 143 memset(&dent, 0, sizeof(dent)); 144 res = write_dent(dirh, n, &dent); 145 if (res) 146 goto out; 147 continue; 148 } 149 150 res = set_file(dirh, dent.file_number); 151 if (res != TEE_SUCCESS) 152 goto out; 153 } 154 out: 155 if (!res) { 156 dirh->ndents = n; 157 *dirh_ret = dirh; 158 } else { 159 tee_fs_dirfile_close(dirh); 160 } 161 return res; 162 } 163 164 void tee_fs_dirfile_close(struct tee_fs_dirfile_dirh *dirh) 165 { 166 if (dirh) { 167 dirh->fops->close(dirh->fh); 168 free(dirh->files); 169 free(dirh); 170 } 171 } 172 173 TEE_Result tee_fs_dirfile_commit_writes(struct tee_fs_dirfile_dirh *dirh, 174 uint8_t *hash) 175 { 176 return dirh->fops->commit_writes(dirh->fh, hash); 177 } 178 179 TEE_Result tee_fs_dirfile_get_tmp(struct tee_fs_dirfile_dirh *dirh, 180 struct tee_fs_dirfile_fileh *dfh) 181 { 182 TEE_Result res; 183 int i = 0; 184 185 if (dirh->files) { 186 bit_ffc(dirh->files, dirh->nbits, &i); 187 if (i == -1) 188 i = dirh->nbits; 189 } 190 191 res = set_file(dirh, i); 192 if (!res) 193 dfh->file_number = i; 194 195 return res; 196 } 197 198 TEE_Result tee_fs_dirfile_find(struct tee_fs_dirfile_dirh *dirh, 199 const TEE_UUID *uuid, const void *oid, 200 size_t oidlen, struct tee_fs_dirfile_fileh *dfh) 201 { 202 TEE_Result res; 203 struct dirfile_entry dent; 204 int n; 205 int first_free = -1; 206 207 for (n = 0;; n++) { 208 res = read_dent(dirh, n, &dent); 209 if (res == TEE_ERROR_ITEM_NOT_FOUND && !oidlen) { 210 memset(&dent, 0, sizeof(dent)); 211 if (first_free != -1) 212 n = first_free; 213 break; 214 } 215 if (res) 216 return res; 217 218 /* TODO check this loop when oidlen == 0 */ 219 220 if (!dent.oidlen && first_free == -1) 221 first_free = n; 222 if (dent.oidlen != oidlen) 223 continue; 224 225 assert(!oidlen || !dent.oidlen || 226 test_file(dirh, dent.file_number)); 227 228 if (!memcmp(&dent.uuid, uuid, sizeof(dent.uuid)) && 229 !memcmp(&dent.oid, oid, oidlen)) 230 break; 231 } 232 233 if (dfh) { 234 dfh->idx = n; 235 dfh->file_number = dent.file_number; 236 memcpy(dfh->hash, dent.hash, sizeof(dent.hash)); 237 } 238 239 return TEE_SUCCESS; 240 } 241 242 TEE_Result tee_fs_dirfile_fileh_to_fname(const struct tee_fs_dirfile_fileh *dfh, 243 char *fname, size_t *fnlen) 244 { 245 int r; 246 size_t l = *fnlen; 247 248 if (dfh) 249 r = snprintf(fname, l, "%" PRIx32, dfh->file_number); 250 else 251 r = snprintf(fname, l, "dirf.db"); 252 253 if (r < 0) 254 return TEE_ERROR_GENERIC; 255 256 *fnlen = r + 1; 257 if ((size_t)r >= l) 258 return TEE_ERROR_SHORT_BUFFER; 259 260 return TEE_SUCCESS; 261 } 262 263 TEE_Result tee_fs_dirfile_rename(struct tee_fs_dirfile_dirh *dirh, 264 const TEE_UUID *uuid, 265 struct tee_fs_dirfile_fileh *dfh, 266 const void *oid, size_t oidlen) 267 { 268 TEE_Result res; 269 struct dirfile_entry dent; 270 271 if (!oidlen || oidlen > sizeof(dent.oid)) 272 return TEE_ERROR_BAD_PARAMETERS; 273 memset(&dent, 0, sizeof(dent)); 274 dent.uuid = *uuid; 275 memcpy(dent.oid, oid, oidlen); 276 dent.oidlen = oidlen; 277 memcpy(dent.hash, dfh->hash, sizeof(dent.hash)); 278 dent.file_number = dfh->file_number; 279 280 if (dfh->idx < 0) { 281 struct tee_fs_dirfile_fileh dfh2; 282 283 res = tee_fs_dirfile_find(dirh, uuid, oid, oidlen, &dfh2); 284 if (res) { 285 if (res == TEE_ERROR_ITEM_NOT_FOUND) 286 res = tee_fs_dirfile_find(dirh, uuid, NULL, 0, 287 &dfh2); 288 if (res) 289 return res; 290 } 291 dfh->idx = dfh2.idx; 292 } 293 294 return write_dent(dirh, dfh->idx, &dent); 295 } 296 297 TEE_Result tee_fs_dirfile_remove(struct tee_fs_dirfile_dirh *dirh, 298 const struct tee_fs_dirfile_fileh *dfh) 299 { 300 TEE_Result res; 301 struct dirfile_entry dent; 302 uint32_t file_number; 303 304 res = read_dent(dirh, dfh->idx, &dent); 305 if (res) 306 return res; 307 308 if (!dent.oidlen) 309 return TEE_SUCCESS; 310 311 file_number = dent.file_number; 312 assert(dfh->file_number == file_number); 313 assert(test_file(dirh, file_number)); 314 315 memset(&dent, 0, sizeof(dent)); 316 res = write_dent(dirh, dfh->idx, &dent); 317 if (!res) 318 clear_file(dirh, file_number); 319 320 return res; 321 } 322 323 TEE_Result tee_fs_dirfile_update_hash(struct tee_fs_dirfile_dirh *dirh, 324 const struct tee_fs_dirfile_fileh *dfh) 325 { 326 TEE_Result res; 327 struct dirfile_entry dent; 328 329 res = read_dent(dirh, dfh->idx, &dent); 330 if (res) 331 return res; 332 assert(dent.file_number == dfh->file_number); 333 assert(test_file(dirh, dent.file_number)); 334 335 memcpy(&dent.hash, dfh->hash, sizeof(dent.hash)); 336 337 return write_dent(dirh, dfh->idx, &dent); 338 } 339 340 TEE_Result tee_fs_dirfile_get_next(struct tee_fs_dirfile_dirh *dirh, 341 const TEE_UUID *uuid, int *idx, void *oid, 342 size_t *oidlen) 343 { 344 TEE_Result res; 345 int i = *idx + 1; 346 struct dirfile_entry dent; 347 348 if (i < 0) 349 i = 0; 350 351 for (;; i++) { 352 res = read_dent(dirh, i, &dent); 353 if (res) 354 return res; 355 if (!memcmp(&dent.uuid, uuid, sizeof(dent.uuid)) && 356 dent.oidlen) 357 break; 358 } 359 360 if (*oidlen < dent.oidlen) 361 return TEE_ERROR_SHORT_BUFFER; 362 363 memcpy(oid, dent.oid, dent.oidlen); 364 *oidlen = dent.oidlen; 365 *idx = i; 366 367 return TEE_SUCCESS; 368 } 369