1 /* 2 * EFI utils 3 * 4 * Copyright (c) 2017 Rob Clark 5 * 6 * SPDX-License-Identifier: GPL-2.0+ 7 */ 8 9 #include <common.h> 10 #include <charset.h> 11 #include <efi_loader.h> 12 #include <malloc.h> 13 #include <fs.h> 14 15 /* GUID for file system information */ 16 const efi_guid_t efi_file_system_info_guid = EFI_FILE_SYSTEM_INFO_GUID; 17 18 struct file_system { 19 struct efi_simple_file_system_protocol base; 20 struct efi_device_path *dp; 21 struct blk_desc *desc; 22 int part; 23 }; 24 #define to_fs(x) container_of(x, struct file_system, base) 25 26 struct file_handle { 27 struct efi_file_handle base; 28 struct file_system *fs; 29 loff_t offset; /* current file position/cursor */ 30 int isdir; 31 32 /* for reading a directory: */ 33 struct fs_dir_stream *dirs; 34 struct fs_dirent *dent; 35 36 char path[0]; 37 }; 38 #define to_fh(x) container_of(x, struct file_handle, base) 39 40 static const struct efi_file_handle efi_file_handle_protocol; 41 42 static char *basename(struct file_handle *fh) 43 { 44 char *s = strrchr(fh->path, '/'); 45 if (s) 46 return s + 1; 47 return fh->path; 48 } 49 50 static int set_blk_dev(struct file_handle *fh) 51 { 52 return fs_set_blk_dev_with_part(fh->fs->desc, fh->fs->part); 53 } 54 55 static int is_dir(struct file_handle *fh) 56 { 57 struct fs_dir_stream *dirs; 58 59 set_blk_dev(fh); 60 dirs = fs_opendir(fh->path); 61 if (!dirs) 62 return 0; 63 64 fs_closedir(dirs); 65 66 return 1; 67 } 68 69 /* 70 * Normalize a path which may include either back or fwd slashes, 71 * double slashes, . or .. entries in the path, etc. 72 */ 73 static int sanitize_path(char *path) 74 { 75 char *p; 76 77 /* backslash to slash: */ 78 p = path; 79 while ((p = strchr(p, '\\'))) 80 *p++ = '/'; 81 82 /* handle double-slashes: */ 83 p = path; 84 while ((p = strstr(p, "//"))) { 85 char *src = p + 1; 86 memmove(p, src, strlen(src) + 1); 87 } 88 89 /* handle extra /.'s */ 90 p = path; 91 while ((p = strstr(p, "/."))) { 92 /* 93 * You'd be tempted to do this *after* handling ".."s 94 * below to avoid having to check if "/." is start of 95 * a "/..", but that won't have the correct results.. 96 * for example, "/foo/./../bar" would get resolved to 97 * "/foo/bar" if you did these two passes in the other 98 * order 99 */ 100 if (p[2] == '.') { 101 p += 2; 102 continue; 103 } 104 char *src = p + 2; 105 memmove(p, src, strlen(src) + 1); 106 } 107 108 /* handle extra /..'s: */ 109 p = path; 110 while ((p = strstr(p, "/.."))) { 111 char *src = p + 3; 112 113 p--; 114 115 /* find beginning of previous path entry: */ 116 while (true) { 117 if (p < path) 118 return -1; 119 if (*p == '/') 120 break; 121 p--; 122 } 123 124 memmove(p, src, strlen(src) + 1); 125 } 126 127 return 0; 128 } 129 130 /* NOTE: despite what you would expect, 'file_name' is actually a path. 131 * With windoze style backlashes, ofc. 132 */ 133 static struct efi_file_handle *file_open(struct file_system *fs, 134 struct file_handle *parent, s16 *file_name, u64 mode) 135 { 136 struct file_handle *fh; 137 char f0[MAX_UTF8_PER_UTF16] = {0}; 138 int plen = 0; 139 int flen = 0; 140 141 if (file_name) { 142 utf16_to_utf8((u8 *)f0, (u16 *)file_name, 1); 143 flen = utf16_strlen((u16 *)file_name); 144 } 145 146 /* we could have a parent, but also an absolute path: */ 147 if (f0[0] == '\\') { 148 plen = 0; 149 } else if (parent) { 150 plen = strlen(parent->path) + 1; 151 } 152 153 /* +2 is for null and '/' */ 154 fh = calloc(1, sizeof(*fh) + plen + (flen * MAX_UTF8_PER_UTF16) + 2); 155 156 fh->base = efi_file_handle_protocol; 157 fh->fs = fs; 158 159 if (parent) { 160 char *p = fh->path; 161 162 if (plen > 0) { 163 strcpy(p, parent->path); 164 p += plen - 1; 165 *p++ = '/'; 166 } 167 168 utf16_to_utf8((u8 *)p, (u16 *)file_name, flen); 169 170 if (sanitize_path(fh->path)) 171 goto error; 172 173 /* check if file exists: */ 174 if (set_blk_dev(fh)) 175 goto error; 176 177 if (!((mode & EFI_FILE_MODE_CREATE) || fs_exists(fh->path))) 178 goto error; 179 180 /* figure out if file is a directory: */ 181 fh->isdir = is_dir(fh); 182 } else { 183 fh->isdir = 1; 184 strcpy(fh->path, ""); 185 } 186 187 return &fh->base; 188 189 error: 190 free(fh); 191 return NULL; 192 } 193 194 static efi_status_t EFIAPI efi_file_open(struct efi_file_handle *file, 195 struct efi_file_handle **new_handle, 196 s16 *file_name, u64 open_mode, u64 attributes) 197 { 198 struct file_handle *fh = to_fh(file); 199 200 EFI_ENTRY("%p, %p, \"%ls\", %llx, %llu", file, new_handle, file_name, 201 open_mode, attributes); 202 203 *new_handle = file_open(fh->fs, fh, file_name, open_mode); 204 if (!*new_handle) 205 return EFI_EXIT(EFI_NOT_FOUND); 206 207 return EFI_EXIT(EFI_SUCCESS); 208 } 209 210 static efi_status_t file_close(struct file_handle *fh) 211 { 212 fs_closedir(fh->dirs); 213 free(fh); 214 return EFI_SUCCESS; 215 } 216 217 static efi_status_t EFIAPI efi_file_close(struct efi_file_handle *file) 218 { 219 struct file_handle *fh = to_fh(file); 220 EFI_ENTRY("%p", file); 221 return EFI_EXIT(file_close(fh)); 222 } 223 224 static efi_status_t EFIAPI efi_file_delete(struct efi_file_handle *file) 225 { 226 struct file_handle *fh = to_fh(file); 227 EFI_ENTRY("%p", file); 228 file_close(fh); 229 return EFI_EXIT(EFI_WARN_DELETE_FAILURE); 230 } 231 232 static efi_status_t file_read(struct file_handle *fh, u64 *buffer_size, 233 void *buffer) 234 { 235 loff_t actread; 236 237 if (fs_read(fh->path, (ulong)buffer, fh->offset, 238 *buffer_size, &actread)) 239 return EFI_DEVICE_ERROR; 240 241 *buffer_size = actread; 242 fh->offset += actread; 243 244 return EFI_SUCCESS; 245 } 246 247 static efi_status_t dir_read(struct file_handle *fh, u64 *buffer_size, 248 void *buffer) 249 { 250 struct efi_file_info *info = buffer; 251 struct fs_dirent *dent; 252 unsigned int required_size; 253 254 if (!fh->dirs) { 255 assert(fh->offset == 0); 256 fh->dirs = fs_opendir(fh->path); 257 if (!fh->dirs) 258 return EFI_DEVICE_ERROR; 259 } 260 261 /* 262 * So this is a bit awkward. Since fs layer is stateful and we 263 * can't rewind an entry, in the EFI_BUFFER_TOO_SMALL case below 264 * we might have to return without consuming the dent.. so we 265 * have to stash it for next call. 266 */ 267 if (fh->dent) { 268 dent = fh->dent; 269 fh->dent = NULL; 270 } else { 271 dent = fs_readdir(fh->dirs); 272 } 273 274 275 if (!dent) { 276 /* no more files in directory: */ 277 /* workaround shim.efi bug/quirk.. as find_boot_csv() 278 * loops through directory contents, it initially calls 279 * read w/ zero length buffer to find out how much mem 280 * to allocate for the EFI_FILE_INFO, then allocates, 281 * and then calls a 2nd time. If we return size of 282 * zero the first time, it happily passes that to 283 * AllocateZeroPool(), and when that returns NULL it 284 * thinks it is EFI_OUT_OF_RESOURCES. So on first 285 * call return a non-zero size: 286 */ 287 if (*buffer_size == 0) 288 *buffer_size = sizeof(*info); 289 else 290 *buffer_size = 0; 291 return EFI_SUCCESS; 292 } 293 294 /* check buffer size: */ 295 required_size = sizeof(*info) + 2 * (strlen(dent->name) + 1); 296 if (*buffer_size < required_size) { 297 *buffer_size = required_size; 298 fh->dent = dent; 299 return EFI_BUFFER_TOO_SMALL; 300 } 301 302 *buffer_size = required_size; 303 memset(info, 0, required_size); 304 305 info->size = required_size; 306 info->file_size = dent->size; 307 info->physical_size = dent->size; 308 309 if (dent->type == FS_DT_DIR) 310 info->attribute |= EFI_FILE_DIRECTORY; 311 312 ascii2unicode((u16 *)info->file_name, dent->name); 313 314 fh->offset++; 315 316 return EFI_SUCCESS; 317 } 318 319 static efi_status_t EFIAPI efi_file_read(struct efi_file_handle *file, 320 efi_uintn_t *buffer_size, void *buffer) 321 { 322 struct file_handle *fh = to_fh(file); 323 efi_status_t ret = EFI_SUCCESS; 324 u64 bs; 325 326 EFI_ENTRY("%p, %p, %p", file, buffer_size, buffer); 327 328 if (!buffer_size || !buffer) { 329 ret = EFI_INVALID_PARAMETER; 330 goto error; 331 } 332 333 if (set_blk_dev(fh)) { 334 ret = EFI_DEVICE_ERROR; 335 goto error; 336 } 337 338 bs = *buffer_size; 339 if (fh->isdir) 340 ret = dir_read(fh, &bs, buffer); 341 else 342 ret = file_read(fh, &bs, buffer); 343 if (bs <= SIZE_MAX) 344 *buffer_size = bs; 345 else 346 *buffer_size = SIZE_MAX; 347 348 error: 349 return EFI_EXIT(ret); 350 } 351 352 static efi_status_t EFIAPI efi_file_write(struct efi_file_handle *file, 353 efi_uintn_t *buffer_size, 354 void *buffer) 355 { 356 struct file_handle *fh = to_fh(file); 357 efi_status_t ret = EFI_SUCCESS; 358 loff_t actwrite; 359 360 EFI_ENTRY("%p, %p, %p", file, buffer_size, buffer); 361 362 if (set_blk_dev(fh)) { 363 ret = EFI_DEVICE_ERROR; 364 goto error; 365 } 366 367 if (fs_write(fh->path, (ulong)buffer, fh->offset, *buffer_size, 368 &actwrite)) { 369 ret = EFI_DEVICE_ERROR; 370 goto error; 371 } 372 373 *buffer_size = actwrite; 374 fh->offset += actwrite; 375 376 error: 377 return EFI_EXIT(ret); 378 } 379 380 static efi_status_t EFIAPI efi_file_getpos(struct efi_file_handle *file, 381 efi_uintn_t *pos) 382 { 383 struct file_handle *fh = to_fh(file); 384 385 EFI_ENTRY("%p, %p", file, pos); 386 387 if (fh->offset <= SIZE_MAX) { 388 *pos = fh->offset; 389 return EFI_EXIT(EFI_SUCCESS); 390 } else { 391 return EFI_EXIT(EFI_DEVICE_ERROR); 392 } 393 } 394 395 static efi_status_t EFIAPI efi_file_setpos(struct efi_file_handle *file, 396 efi_uintn_t pos) 397 { 398 struct file_handle *fh = to_fh(file); 399 efi_status_t ret = EFI_SUCCESS; 400 401 EFI_ENTRY("%p, %zu", file, pos); 402 403 if (fh->isdir) { 404 if (pos != 0) { 405 ret = EFI_UNSUPPORTED; 406 goto error; 407 } 408 fs_closedir(fh->dirs); 409 fh->dirs = NULL; 410 } 411 412 if (pos == ~0ULL) { 413 loff_t file_size; 414 415 if (set_blk_dev(fh)) { 416 ret = EFI_DEVICE_ERROR; 417 goto error; 418 } 419 420 if (fs_size(fh->path, &file_size)) { 421 ret = EFI_DEVICE_ERROR; 422 goto error; 423 } 424 425 pos = file_size; 426 } 427 428 fh->offset = pos; 429 430 error: 431 return EFI_EXIT(ret); 432 } 433 434 static efi_status_t EFIAPI efi_file_getinfo(struct efi_file_handle *file, 435 const efi_guid_t *info_type, 436 efi_uintn_t *buffer_size, 437 void *buffer) 438 { 439 struct file_handle *fh = to_fh(file); 440 efi_status_t ret = EFI_SUCCESS; 441 442 EFI_ENTRY("%p, %p, %p, %p", file, info_type, buffer_size, buffer); 443 444 if (!guidcmp(info_type, &efi_file_info_guid)) { 445 struct efi_file_info *info = buffer; 446 char *filename = basename(fh); 447 unsigned int required_size; 448 loff_t file_size; 449 450 /* check buffer size: */ 451 required_size = sizeof(*info) + 2 * (strlen(filename) + 1); 452 if (*buffer_size < required_size) { 453 *buffer_size = required_size; 454 ret = EFI_BUFFER_TOO_SMALL; 455 goto error; 456 } 457 458 if (set_blk_dev(fh)) { 459 ret = EFI_DEVICE_ERROR; 460 goto error; 461 } 462 463 if (fs_size(fh->path, &file_size)) { 464 ret = EFI_DEVICE_ERROR; 465 goto error; 466 } 467 468 memset(info, 0, required_size); 469 470 info->size = required_size; 471 info->file_size = file_size; 472 info->physical_size = file_size; 473 474 if (fh->isdir) 475 info->attribute |= EFI_FILE_DIRECTORY; 476 477 ascii2unicode((u16 *)info->file_name, filename); 478 } else if (!guidcmp(info_type, &efi_file_system_info_guid)) { 479 struct efi_file_system_info *info = buffer; 480 disk_partition_t part; 481 efi_uintn_t required_size; 482 int r; 483 484 if (fh->fs->part >= 1) 485 r = part_get_info(fh->fs->desc, fh->fs->part, &part); 486 else 487 r = part_get_info_whole_disk(fh->fs->desc, &part); 488 if (r < 0) { 489 ret = EFI_DEVICE_ERROR; 490 goto error; 491 } 492 required_size = sizeof(info) + 2 * 493 (strlen((const char *)part.name) + 1); 494 if (*buffer_size < required_size) { 495 *buffer_size = required_size; 496 ret = EFI_BUFFER_TOO_SMALL; 497 goto error; 498 } 499 500 memset(info, 0, required_size); 501 502 info->size = required_size; 503 info->read_only = true; 504 info->volume_size = part.size * part.blksz; 505 info->free_space = 0; 506 info->block_size = part.blksz; 507 /* 508 * TODO: The volume label is not available in U-Boot. 509 * Use the partition name as substitute. 510 */ 511 ascii2unicode((u16 *)info->volume_label, 512 (const char *)part.name); 513 } else { 514 ret = EFI_UNSUPPORTED; 515 } 516 517 error: 518 return EFI_EXIT(ret); 519 } 520 521 static efi_status_t EFIAPI efi_file_setinfo(struct efi_file_handle *file, 522 const efi_guid_t *info_type, 523 efi_uintn_t buffer_size, 524 void *buffer) 525 { 526 EFI_ENTRY("%p, %p, %zu, %p", file, info_type, buffer_size, buffer); 527 528 return EFI_EXIT(EFI_UNSUPPORTED); 529 } 530 531 static efi_status_t EFIAPI efi_file_flush(struct efi_file_handle *file) 532 { 533 EFI_ENTRY("%p", file); 534 return EFI_EXIT(EFI_SUCCESS); 535 } 536 537 static const struct efi_file_handle efi_file_handle_protocol = { 538 .rev = EFI_FILE_PROTOCOL_REVISION, 539 .open = efi_file_open, 540 .close = efi_file_close, 541 .delete = efi_file_delete, 542 .read = efi_file_read, 543 .write = efi_file_write, 544 .getpos = efi_file_getpos, 545 .setpos = efi_file_setpos, 546 .getinfo = efi_file_getinfo, 547 .setinfo = efi_file_setinfo, 548 .flush = efi_file_flush, 549 }; 550 551 struct efi_file_handle *efi_file_from_path(struct efi_device_path *fp) 552 { 553 struct efi_simple_file_system_protocol *v; 554 struct efi_file_handle *f; 555 efi_status_t ret; 556 557 v = efi_fs_from_path(fp); 558 if (!v) 559 return NULL; 560 561 EFI_CALL(ret = v->open_volume(v, &f)); 562 if (ret != EFI_SUCCESS) 563 return NULL; 564 565 /* skip over device-path nodes before the file path: */ 566 while (fp && !EFI_DP_TYPE(fp, MEDIA_DEVICE, FILE_PATH)) 567 fp = efi_dp_next(fp); 568 569 while (fp) { 570 struct efi_device_path_file_path *fdp = 571 container_of(fp, struct efi_device_path_file_path, dp); 572 struct efi_file_handle *f2; 573 574 if (!EFI_DP_TYPE(fp, MEDIA_DEVICE, FILE_PATH)) { 575 printf("bad file path!\n"); 576 f->close(f); 577 return NULL; 578 } 579 580 EFI_CALL(ret = f->open(f, &f2, (s16 *)fdp->str, 581 EFI_FILE_MODE_READ, 0)); 582 if (ret != EFI_SUCCESS) 583 return NULL; 584 585 fp = efi_dp_next(fp); 586 587 EFI_CALL(f->close(f)); 588 f = f2; 589 } 590 591 return f; 592 } 593 594 static efi_status_t EFIAPI 595 efi_open_volume(struct efi_simple_file_system_protocol *this, 596 struct efi_file_handle **root) 597 { 598 struct file_system *fs = to_fs(this); 599 600 EFI_ENTRY("%p, %p", this, root); 601 602 *root = file_open(fs, NULL, NULL, 0); 603 604 return EFI_EXIT(EFI_SUCCESS); 605 } 606 607 struct efi_simple_file_system_protocol * 608 efi_simple_file_system(struct blk_desc *desc, int part, 609 struct efi_device_path *dp) 610 { 611 struct file_system *fs; 612 613 fs = calloc(1, sizeof(*fs)); 614 fs->base.rev = EFI_SIMPLE_FILE_SYSTEM_PROTOCOL_REVISION; 615 fs->base.open_volume = efi_open_volume; 616 fs->desc = desc; 617 fs->part = part; 618 fs->dp = dp; 619 620 return &fs->base; 621 } 622