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