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