12a92080dSRob Clark /* 22a92080dSRob Clark * EFI utils 32a92080dSRob Clark * 42a92080dSRob Clark * Copyright (c) 2017 Rob Clark 52a92080dSRob Clark * 62a92080dSRob Clark * SPDX-License-Identifier: GPL-2.0+ 72a92080dSRob Clark */ 82a92080dSRob Clark 92a92080dSRob Clark #include <common.h> 102a92080dSRob Clark #include <charset.h> 112a92080dSRob Clark #include <efi_loader.h> 122a92080dSRob Clark #include <malloc.h> 132a92080dSRob Clark #include <fs.h> 142a92080dSRob Clark 152a92080dSRob Clark struct file_system { 162a92080dSRob Clark struct efi_simple_file_system_protocol base; 172a92080dSRob Clark struct efi_device_path *dp; 182a92080dSRob Clark struct blk_desc *desc; 192a92080dSRob Clark int part; 202a92080dSRob Clark }; 212a92080dSRob Clark #define to_fs(x) container_of(x, struct file_system, base) 222a92080dSRob Clark 232a92080dSRob Clark struct file_handle { 242a92080dSRob Clark struct efi_file_handle base; 252a92080dSRob Clark struct file_system *fs; 262a92080dSRob Clark loff_t offset; /* current file position/cursor */ 272a92080dSRob Clark int isdir; 282a92080dSRob Clark 292a92080dSRob Clark /* for reading a directory: */ 302a92080dSRob Clark struct fs_dir_stream *dirs; 312a92080dSRob Clark struct fs_dirent *dent; 322a92080dSRob Clark 332a92080dSRob Clark char path[0]; 342a92080dSRob Clark }; 352a92080dSRob Clark #define to_fh(x) container_of(x, struct file_handle, base) 362a92080dSRob Clark 372a92080dSRob Clark static const struct efi_file_handle efi_file_handle_protocol; 382a92080dSRob Clark 392a92080dSRob Clark static char *basename(struct file_handle *fh) 402a92080dSRob Clark { 412a92080dSRob Clark char *s = strrchr(fh->path, '/'); 422a92080dSRob Clark if (s) 432a92080dSRob Clark return s + 1; 442a92080dSRob Clark return fh->path; 452a92080dSRob Clark } 462a92080dSRob Clark 472a92080dSRob Clark static int set_blk_dev(struct file_handle *fh) 482a92080dSRob Clark { 492a92080dSRob Clark return fs_set_blk_dev_with_part(fh->fs->desc, fh->fs->part); 502a92080dSRob Clark } 512a92080dSRob Clark 522a92080dSRob Clark static int is_dir(struct file_handle *fh) 532a92080dSRob Clark { 542a92080dSRob Clark struct fs_dir_stream *dirs; 552a92080dSRob Clark 562a92080dSRob Clark set_blk_dev(fh); 572a92080dSRob Clark dirs = fs_opendir(fh->path); 582a92080dSRob Clark if (!dirs) 592a92080dSRob Clark return 0; 602a92080dSRob Clark 612a92080dSRob Clark fs_closedir(dirs); 622a92080dSRob Clark 632a92080dSRob Clark return 1; 642a92080dSRob Clark } 652a92080dSRob Clark 662a92080dSRob Clark /* 672a92080dSRob Clark * Normalize a path which may include either back or fwd slashes, 682a92080dSRob Clark * double slashes, . or .. entries in the path, etc. 692a92080dSRob Clark */ 702a92080dSRob Clark static int sanitize_path(char *path) 712a92080dSRob Clark { 722a92080dSRob Clark char *p; 732a92080dSRob Clark 742a92080dSRob Clark /* backslash to slash: */ 752a92080dSRob Clark p = path; 762a92080dSRob Clark while ((p = strchr(p, '\\'))) 772a92080dSRob Clark *p++ = '/'; 782a92080dSRob Clark 792a92080dSRob Clark /* handle double-slashes: */ 802a92080dSRob Clark p = path; 812a92080dSRob Clark while ((p = strstr(p, "//"))) { 822a92080dSRob Clark char *src = p + 1; 832a92080dSRob Clark memmove(p, src, strlen(src) + 1); 842a92080dSRob Clark } 852a92080dSRob Clark 862a92080dSRob Clark /* handle extra /.'s */ 872a92080dSRob Clark p = path; 882a92080dSRob Clark while ((p = strstr(p, "/."))) { 892a92080dSRob Clark /* 902a92080dSRob Clark * You'd be tempted to do this *after* handling ".."s 912a92080dSRob Clark * below to avoid having to check if "/." is start of 922a92080dSRob Clark * a "/..", but that won't have the correct results.. 932a92080dSRob Clark * for example, "/foo/./../bar" would get resolved to 942a92080dSRob Clark * "/foo/bar" if you did these two passes in the other 952a92080dSRob Clark * order 962a92080dSRob Clark */ 972a92080dSRob Clark if (p[2] == '.') { 982a92080dSRob Clark p += 2; 992a92080dSRob Clark continue; 1002a92080dSRob Clark } 1012a92080dSRob Clark char *src = p + 2; 1022a92080dSRob Clark memmove(p, src, strlen(src) + 1); 1032a92080dSRob Clark } 1042a92080dSRob Clark 1052a92080dSRob Clark /* handle extra /..'s: */ 1062a92080dSRob Clark p = path; 1072a92080dSRob Clark while ((p = strstr(p, "/.."))) { 1082a92080dSRob Clark char *src = p + 3; 1092a92080dSRob Clark 1102a92080dSRob Clark p--; 1112a92080dSRob Clark 1122a92080dSRob Clark /* find beginning of previous path entry: */ 1132a92080dSRob Clark while (true) { 1142a92080dSRob Clark if (p < path) 1152a92080dSRob Clark return -1; 1162a92080dSRob Clark if (*p == '/') 1172a92080dSRob Clark break; 1182a92080dSRob Clark p--; 1192a92080dSRob Clark } 1202a92080dSRob Clark 1212a92080dSRob Clark memmove(p, src, strlen(src) + 1); 1222a92080dSRob Clark } 1232a92080dSRob Clark 1242a92080dSRob Clark return 0; 1252a92080dSRob Clark } 1262a92080dSRob Clark 1272a92080dSRob Clark /* NOTE: despite what you would expect, 'file_name' is actually a path. 1282a92080dSRob Clark * With windoze style backlashes, ofc. 1292a92080dSRob Clark */ 1302a92080dSRob Clark static struct efi_file_handle *file_open(struct file_system *fs, 1312a92080dSRob Clark struct file_handle *parent, s16 *file_name, u64 mode) 1322a92080dSRob Clark { 1332a92080dSRob Clark struct file_handle *fh; 1342a92080dSRob Clark char f0[MAX_UTF8_PER_UTF16] = {0}; 1352a92080dSRob Clark int plen = 0; 1362a92080dSRob Clark int flen = 0; 1372a92080dSRob Clark 1382a92080dSRob Clark if (file_name) { 1392a92080dSRob Clark utf16_to_utf8((u8 *)f0, (u16 *)file_name, 1); 1402a92080dSRob Clark flen = utf16_strlen((u16 *)file_name); 1412a92080dSRob Clark } 1422a92080dSRob Clark 1432a92080dSRob Clark /* we could have a parent, but also an absolute path: */ 1442a92080dSRob Clark if (f0[0] == '\\') { 1452a92080dSRob Clark plen = 0; 1462a92080dSRob Clark } else if (parent) { 1472a92080dSRob Clark plen = strlen(parent->path) + 1; 1482a92080dSRob Clark } 1492a92080dSRob Clark 1502a92080dSRob Clark /* +2 is for null and '/' */ 1512a92080dSRob Clark fh = calloc(1, sizeof(*fh) + plen + (flen * MAX_UTF8_PER_UTF16) + 2); 1522a92080dSRob Clark 1532a92080dSRob Clark fh->base = efi_file_handle_protocol; 1542a92080dSRob Clark fh->fs = fs; 1552a92080dSRob Clark 1562a92080dSRob Clark if (parent) { 1572a92080dSRob Clark char *p = fh->path; 1582a92080dSRob Clark 1592a92080dSRob Clark if (plen > 0) { 1602a92080dSRob Clark strcpy(p, parent->path); 1612a92080dSRob Clark p += plen - 1; 1622a92080dSRob Clark *p++ = '/'; 1632a92080dSRob Clark } 1642a92080dSRob Clark 1652a92080dSRob Clark utf16_to_utf8((u8 *)p, (u16 *)file_name, flen); 1662a92080dSRob Clark 1672a92080dSRob Clark if (sanitize_path(fh->path)) 1682a92080dSRob Clark goto error; 1692a92080dSRob Clark 1702a92080dSRob Clark /* check if file exists: */ 1712a92080dSRob Clark if (set_blk_dev(fh)) 1722a92080dSRob Clark goto error; 1732a92080dSRob Clark 1742a92080dSRob Clark if (!((mode & EFI_FILE_MODE_CREATE) || fs_exists(fh->path))) 1752a92080dSRob Clark goto error; 1762a92080dSRob Clark 1772a92080dSRob Clark /* figure out if file is a directory: */ 1782a92080dSRob Clark fh->isdir = is_dir(fh); 1792a92080dSRob Clark } else { 1802a92080dSRob Clark fh->isdir = 1; 1812a92080dSRob Clark strcpy(fh->path, ""); 1822a92080dSRob Clark } 1832a92080dSRob Clark 1842a92080dSRob Clark return &fh->base; 1852a92080dSRob Clark 1862a92080dSRob Clark error: 1872a92080dSRob Clark free(fh); 1882a92080dSRob Clark return NULL; 1892a92080dSRob Clark } 1902a92080dSRob Clark 1912a92080dSRob Clark static efi_status_t EFIAPI efi_file_open(struct efi_file_handle *file, 1922a92080dSRob Clark struct efi_file_handle **new_handle, 1932a92080dSRob Clark s16 *file_name, u64 open_mode, u64 attributes) 1942a92080dSRob Clark { 1952a92080dSRob Clark struct file_handle *fh = to_fh(file); 1962a92080dSRob Clark 1972a92080dSRob Clark EFI_ENTRY("%p, %p, \"%ls\", %llx, %llu", file, new_handle, file_name, 1982a92080dSRob Clark open_mode, attributes); 1992a92080dSRob Clark 2002a92080dSRob Clark *new_handle = file_open(fh->fs, fh, file_name, open_mode); 2012a92080dSRob Clark if (!*new_handle) 2022a92080dSRob Clark return EFI_EXIT(EFI_NOT_FOUND); 2032a92080dSRob Clark 2042a92080dSRob Clark return EFI_EXIT(EFI_SUCCESS); 2052a92080dSRob Clark } 2062a92080dSRob Clark 2072a92080dSRob Clark static efi_status_t file_close(struct file_handle *fh) 2082a92080dSRob Clark { 2092a92080dSRob Clark fs_closedir(fh->dirs); 2102a92080dSRob Clark free(fh); 2112a92080dSRob Clark return EFI_SUCCESS; 2122a92080dSRob Clark } 2132a92080dSRob Clark 2142a92080dSRob Clark static efi_status_t EFIAPI efi_file_close(struct efi_file_handle *file) 2152a92080dSRob Clark { 2162a92080dSRob Clark struct file_handle *fh = to_fh(file); 2172a92080dSRob Clark EFI_ENTRY("%p", file); 2182a92080dSRob Clark return EFI_EXIT(file_close(fh)); 2192a92080dSRob Clark } 2202a92080dSRob Clark 2212a92080dSRob Clark static efi_status_t EFIAPI efi_file_delete(struct efi_file_handle *file) 2222a92080dSRob Clark { 2232a92080dSRob Clark struct file_handle *fh = to_fh(file); 2242a92080dSRob Clark EFI_ENTRY("%p", file); 2252a92080dSRob Clark file_close(fh); 2262a92080dSRob Clark return EFI_EXIT(EFI_WARN_DELETE_FAILURE); 2272a92080dSRob Clark } 2282a92080dSRob Clark 2292a92080dSRob Clark static efi_status_t file_read(struct file_handle *fh, u64 *buffer_size, 2302a92080dSRob Clark void *buffer) 2312a92080dSRob Clark { 2322a92080dSRob Clark loff_t actread; 2332a92080dSRob Clark 2342a92080dSRob Clark if (fs_read(fh->path, (ulong)buffer, fh->offset, 2352a92080dSRob Clark *buffer_size, &actread)) 2362a92080dSRob Clark return EFI_DEVICE_ERROR; 2372a92080dSRob Clark 2382a92080dSRob Clark *buffer_size = actread; 2392a92080dSRob Clark fh->offset += actread; 2402a92080dSRob Clark 2412a92080dSRob Clark return EFI_SUCCESS; 2422a92080dSRob Clark } 2432a92080dSRob Clark 2442a92080dSRob Clark static efi_status_t dir_read(struct file_handle *fh, u64 *buffer_size, 2452a92080dSRob Clark void *buffer) 2462a92080dSRob Clark { 2472a92080dSRob Clark struct efi_file_info *info = buffer; 2482a92080dSRob Clark struct fs_dirent *dent; 2492a92080dSRob Clark unsigned int required_size; 2502a92080dSRob Clark 2512a92080dSRob Clark if (!fh->dirs) { 2522a92080dSRob Clark assert(fh->offset == 0); 2532a92080dSRob Clark fh->dirs = fs_opendir(fh->path); 2542a92080dSRob Clark if (!fh->dirs) 2552a92080dSRob Clark return EFI_DEVICE_ERROR; 2562a92080dSRob Clark } 2572a92080dSRob Clark 2582a92080dSRob Clark /* 2592a92080dSRob Clark * So this is a bit awkward. Since fs layer is stateful and we 2602a92080dSRob Clark * can't rewind an entry, in the EFI_BUFFER_TOO_SMALL case below 2612a92080dSRob Clark * we might have to return without consuming the dent.. so we 2622a92080dSRob Clark * have to stash it for next call. 2632a92080dSRob Clark */ 2642a92080dSRob Clark if (fh->dent) { 2652a92080dSRob Clark dent = fh->dent; 2662a92080dSRob Clark fh->dent = NULL; 2672a92080dSRob Clark } else { 2682a92080dSRob Clark dent = fs_readdir(fh->dirs); 2692a92080dSRob Clark } 2702a92080dSRob Clark 2712a92080dSRob Clark 2722a92080dSRob Clark if (!dent) { 2732a92080dSRob Clark /* no more files in directory: */ 2742a92080dSRob Clark /* workaround shim.efi bug/quirk.. as find_boot_csv() 2752a92080dSRob Clark * loops through directory contents, it initially calls 2762a92080dSRob Clark * read w/ zero length buffer to find out how much mem 2772a92080dSRob Clark * to allocate for the EFI_FILE_INFO, then allocates, 2782a92080dSRob Clark * and then calls a 2nd time. If we return size of 2792a92080dSRob Clark * zero the first time, it happily passes that to 2802a92080dSRob Clark * AllocateZeroPool(), and when that returns NULL it 2812a92080dSRob Clark * thinks it is EFI_OUT_OF_RESOURCES. So on first 2822a92080dSRob Clark * call return a non-zero size: 2832a92080dSRob Clark */ 2842a92080dSRob Clark if (*buffer_size == 0) 2852a92080dSRob Clark *buffer_size = sizeof(*info); 2862a92080dSRob Clark else 2872a92080dSRob Clark *buffer_size = 0; 2882a92080dSRob Clark return EFI_SUCCESS; 2892a92080dSRob Clark } 2902a92080dSRob Clark 2912a92080dSRob Clark /* check buffer size: */ 2922a92080dSRob Clark required_size = sizeof(*info) + 2 * (strlen(dent->name) + 1); 2932a92080dSRob Clark if (*buffer_size < required_size) { 2942a92080dSRob Clark *buffer_size = required_size; 2952a92080dSRob Clark fh->dent = dent; 2962a92080dSRob Clark return EFI_BUFFER_TOO_SMALL; 2972a92080dSRob Clark } 2982a92080dSRob Clark 2992a92080dSRob Clark *buffer_size = required_size; 3002a92080dSRob Clark memset(info, 0, required_size); 3012a92080dSRob Clark 3022a92080dSRob Clark info->size = required_size; 3032a92080dSRob Clark info->file_size = dent->size; 3042a92080dSRob Clark info->physical_size = dent->size; 3052a92080dSRob Clark 3062a92080dSRob Clark if (dent->type == FS_DT_DIR) 3072a92080dSRob Clark info->attribute |= EFI_FILE_DIRECTORY; 3082a92080dSRob Clark 3092a92080dSRob Clark ascii2unicode((u16 *)info->file_name, dent->name); 3102a92080dSRob Clark 3112a92080dSRob Clark fh->offset++; 3122a92080dSRob Clark 3132a92080dSRob Clark return EFI_SUCCESS; 3142a92080dSRob Clark } 3152a92080dSRob Clark 3162a92080dSRob Clark static efi_status_t EFIAPI efi_file_read(struct efi_file_handle *file, 317b6dd5777SHeinrich Schuchardt efi_uintn_t *buffer_size, void *buffer) 3182a92080dSRob Clark { 3192a92080dSRob Clark struct file_handle *fh = to_fh(file); 3202a92080dSRob Clark efi_status_t ret = EFI_SUCCESS; 321b6dd5777SHeinrich Schuchardt u64 bs; 3222a92080dSRob Clark 3232a92080dSRob Clark EFI_ENTRY("%p, %p, %p", file, buffer_size, buffer); 3242a92080dSRob Clark 325b6dd5777SHeinrich Schuchardt if (!buffer_size || !buffer) { 326b6dd5777SHeinrich Schuchardt ret = EFI_INVALID_PARAMETER; 327b6dd5777SHeinrich Schuchardt goto error; 328b6dd5777SHeinrich Schuchardt } 329b6dd5777SHeinrich Schuchardt 3302a92080dSRob Clark if (set_blk_dev(fh)) { 3312a92080dSRob Clark ret = EFI_DEVICE_ERROR; 3322a92080dSRob Clark goto error; 3332a92080dSRob Clark } 3342a92080dSRob Clark 335b6dd5777SHeinrich Schuchardt bs = *buffer_size; 3362a92080dSRob Clark if (fh->isdir) 337b6dd5777SHeinrich Schuchardt ret = dir_read(fh, &bs, buffer); 3382a92080dSRob Clark else 339b6dd5777SHeinrich Schuchardt ret = file_read(fh, &bs, buffer); 340b6dd5777SHeinrich Schuchardt if (bs <= SIZE_MAX) 341b6dd5777SHeinrich Schuchardt *buffer_size = bs; 342b6dd5777SHeinrich Schuchardt else 343b6dd5777SHeinrich Schuchardt *buffer_size = SIZE_MAX; 3442a92080dSRob Clark 3452a92080dSRob Clark error: 3462a92080dSRob Clark return EFI_EXIT(ret); 3472a92080dSRob Clark } 3482a92080dSRob Clark 3492a92080dSRob Clark static efi_status_t EFIAPI efi_file_write(struct efi_file_handle *file, 350b6dd5777SHeinrich Schuchardt efi_uintn_t *buffer_size, 351b6dd5777SHeinrich Schuchardt void *buffer) 3522a92080dSRob Clark { 3532a92080dSRob Clark struct file_handle *fh = to_fh(file); 3542a92080dSRob Clark efi_status_t ret = EFI_SUCCESS; 3552a92080dSRob Clark loff_t actwrite; 3562a92080dSRob Clark 3572a92080dSRob Clark EFI_ENTRY("%p, %p, %p", file, buffer_size, buffer); 3582a92080dSRob Clark 3592a92080dSRob Clark if (set_blk_dev(fh)) { 3602a92080dSRob Clark ret = EFI_DEVICE_ERROR; 3612a92080dSRob Clark goto error; 3622a92080dSRob Clark } 3632a92080dSRob Clark 3642a92080dSRob Clark if (fs_write(fh->path, (ulong)buffer, fh->offset, *buffer_size, 3652a92080dSRob Clark &actwrite)) { 3662a92080dSRob Clark ret = EFI_DEVICE_ERROR; 3672a92080dSRob Clark goto error; 3682a92080dSRob Clark } 3692a92080dSRob Clark 3702a92080dSRob Clark *buffer_size = actwrite; 3712a92080dSRob Clark fh->offset += actwrite; 3722a92080dSRob Clark 3732a92080dSRob Clark error: 3742a92080dSRob Clark return EFI_EXIT(ret); 3752a92080dSRob Clark } 3762a92080dSRob Clark 3772a92080dSRob Clark static efi_status_t EFIAPI efi_file_getpos(struct efi_file_handle *file, 378b6dd5777SHeinrich Schuchardt efi_uintn_t *pos) 3792a92080dSRob Clark { 3802a92080dSRob Clark struct file_handle *fh = to_fh(file); 381b6dd5777SHeinrich Schuchardt 3822a92080dSRob Clark EFI_ENTRY("%p, %p", file, pos); 383b6dd5777SHeinrich Schuchardt 384b6dd5777SHeinrich Schuchardt if (fh->offset <= SIZE_MAX) { 3852a92080dSRob Clark *pos = fh->offset; 3862a92080dSRob Clark return EFI_EXIT(EFI_SUCCESS); 387b6dd5777SHeinrich Schuchardt } else { 388b6dd5777SHeinrich Schuchardt return EFI_EXIT(EFI_DEVICE_ERROR); 389b6dd5777SHeinrich Schuchardt } 3902a92080dSRob Clark } 3912a92080dSRob Clark 3922a92080dSRob Clark static efi_status_t EFIAPI efi_file_setpos(struct efi_file_handle *file, 393b6dd5777SHeinrich Schuchardt efi_uintn_t pos) 3942a92080dSRob Clark { 3952a92080dSRob Clark struct file_handle *fh = to_fh(file); 3962a92080dSRob Clark efi_status_t ret = EFI_SUCCESS; 3972a92080dSRob Clark 398b6dd5777SHeinrich Schuchardt EFI_ENTRY("%p, %zu", file, pos); 3992a92080dSRob Clark 4002a92080dSRob Clark if (fh->isdir) { 4012a92080dSRob Clark if (pos != 0) { 4022a92080dSRob Clark ret = EFI_UNSUPPORTED; 4032a92080dSRob Clark goto error; 4042a92080dSRob Clark } 4052a92080dSRob Clark fs_closedir(fh->dirs); 4062a92080dSRob Clark fh->dirs = NULL; 4072a92080dSRob Clark } 4082a92080dSRob Clark 4092a92080dSRob Clark if (pos == ~0ULL) { 4102a92080dSRob Clark loff_t file_size; 4112a92080dSRob Clark 4122a92080dSRob Clark if (set_blk_dev(fh)) { 4132a92080dSRob Clark ret = EFI_DEVICE_ERROR; 4142a92080dSRob Clark goto error; 4152a92080dSRob Clark } 4162a92080dSRob Clark 4172a92080dSRob Clark if (fs_size(fh->path, &file_size)) { 4182a92080dSRob Clark ret = EFI_DEVICE_ERROR; 4192a92080dSRob Clark goto error; 4202a92080dSRob Clark } 4212a92080dSRob Clark 4222a92080dSRob Clark pos = file_size; 4232a92080dSRob Clark } 4242a92080dSRob Clark 4252a92080dSRob Clark fh->offset = pos; 4262a92080dSRob Clark 4272a92080dSRob Clark error: 4282a92080dSRob Clark return EFI_EXIT(ret); 4292a92080dSRob Clark } 4302a92080dSRob Clark 4312a92080dSRob Clark static efi_status_t EFIAPI efi_file_getinfo(struct efi_file_handle *file, 432*9c9021e2SHeinrich Schuchardt const efi_guid_t *info_type, 433b6dd5777SHeinrich Schuchardt efi_uintn_t *buffer_size, 434b6dd5777SHeinrich Schuchardt void *buffer) 4352a92080dSRob Clark { 4362a92080dSRob Clark struct file_handle *fh = to_fh(file); 4372a92080dSRob Clark efi_status_t ret = EFI_SUCCESS; 4382a92080dSRob Clark 4392a92080dSRob Clark EFI_ENTRY("%p, %p, %p, %p", file, info_type, buffer_size, buffer); 4402a92080dSRob Clark 4412a92080dSRob Clark if (!guidcmp(info_type, &efi_file_info_guid)) { 4422a92080dSRob Clark struct efi_file_info *info = buffer; 4432a92080dSRob Clark char *filename = basename(fh); 4442a92080dSRob Clark unsigned int required_size; 4452a92080dSRob Clark loff_t file_size; 4462a92080dSRob Clark 4472a92080dSRob Clark /* check buffer size: */ 4482a92080dSRob Clark required_size = sizeof(*info) + 2 * (strlen(filename) + 1); 4492a92080dSRob Clark if (*buffer_size < required_size) { 4502a92080dSRob Clark *buffer_size = required_size; 4512a92080dSRob Clark ret = EFI_BUFFER_TOO_SMALL; 4522a92080dSRob Clark goto error; 4532a92080dSRob Clark } 4542a92080dSRob Clark 4552a92080dSRob Clark if (set_blk_dev(fh)) { 4562a92080dSRob Clark ret = EFI_DEVICE_ERROR; 4572a92080dSRob Clark goto error; 4582a92080dSRob Clark } 4592a92080dSRob Clark 4602a92080dSRob Clark if (fs_size(fh->path, &file_size)) { 4612a92080dSRob Clark ret = EFI_DEVICE_ERROR; 4622a92080dSRob Clark goto error; 4632a92080dSRob Clark } 4642a92080dSRob Clark 4652a92080dSRob Clark memset(info, 0, required_size); 4662a92080dSRob Clark 4672a92080dSRob Clark info->size = required_size; 4682a92080dSRob Clark info->file_size = file_size; 4692a92080dSRob Clark info->physical_size = file_size; 4702a92080dSRob Clark 4712a92080dSRob Clark if (fh->isdir) 4722a92080dSRob Clark info->attribute |= EFI_FILE_DIRECTORY; 4732a92080dSRob Clark 4742a92080dSRob Clark ascii2unicode((u16 *)info->file_name, filename); 4752a92080dSRob Clark } else { 4762a92080dSRob Clark ret = EFI_UNSUPPORTED; 4772a92080dSRob Clark } 4782a92080dSRob Clark 4792a92080dSRob Clark error: 4802a92080dSRob Clark return EFI_EXIT(ret); 4812a92080dSRob Clark } 4822a92080dSRob Clark 4832a92080dSRob Clark static efi_status_t EFIAPI efi_file_setinfo(struct efi_file_handle *file, 484*9c9021e2SHeinrich Schuchardt const efi_guid_t *info_type, 485b6dd5777SHeinrich Schuchardt efi_uintn_t buffer_size, 486b6dd5777SHeinrich Schuchardt void *buffer) 4872a92080dSRob Clark { 488b6dd5777SHeinrich Schuchardt EFI_ENTRY("%p, %p, %zu, %p", file, info_type, buffer_size, buffer); 489b6dd5777SHeinrich Schuchardt 4902a92080dSRob Clark return EFI_EXIT(EFI_UNSUPPORTED); 4912a92080dSRob Clark } 4922a92080dSRob Clark 4932a92080dSRob Clark static efi_status_t EFIAPI efi_file_flush(struct efi_file_handle *file) 4942a92080dSRob Clark { 4952a92080dSRob Clark EFI_ENTRY("%p", file); 4962a92080dSRob Clark return EFI_EXIT(EFI_SUCCESS); 4972a92080dSRob Clark } 4982a92080dSRob Clark 4992a92080dSRob Clark static const struct efi_file_handle efi_file_handle_protocol = { 5002a92080dSRob Clark .rev = EFI_FILE_PROTOCOL_REVISION, 5012a92080dSRob Clark .open = efi_file_open, 5022a92080dSRob Clark .close = efi_file_close, 5032a92080dSRob Clark .delete = efi_file_delete, 5042a92080dSRob Clark .read = efi_file_read, 5052a92080dSRob Clark .write = efi_file_write, 5062a92080dSRob Clark .getpos = efi_file_getpos, 5072a92080dSRob Clark .setpos = efi_file_setpos, 5082a92080dSRob Clark .getinfo = efi_file_getinfo, 5092a92080dSRob Clark .setinfo = efi_file_setinfo, 5102a92080dSRob Clark .flush = efi_file_flush, 5112a92080dSRob Clark }; 5122a92080dSRob Clark 5132a92080dSRob Clark struct efi_file_handle *efi_file_from_path(struct efi_device_path *fp) 5142a92080dSRob Clark { 5152a92080dSRob Clark struct efi_simple_file_system_protocol *v; 5162a92080dSRob Clark struct efi_file_handle *f; 5172a92080dSRob Clark efi_status_t ret; 5182a92080dSRob Clark 5192a92080dSRob Clark v = efi_fs_from_path(fp); 5202a92080dSRob Clark if (!v) 5212a92080dSRob Clark return NULL; 5222a92080dSRob Clark 5232a92080dSRob Clark EFI_CALL(ret = v->open_volume(v, &f)); 5242a92080dSRob Clark if (ret != EFI_SUCCESS) 5252a92080dSRob Clark return NULL; 5262a92080dSRob Clark 5272a92080dSRob Clark /* skip over device-path nodes before the file path: */ 5282a92080dSRob Clark while (fp && !EFI_DP_TYPE(fp, MEDIA_DEVICE, FILE_PATH)) 5292a92080dSRob Clark fp = efi_dp_next(fp); 5302a92080dSRob Clark 5312a92080dSRob Clark while (fp) { 5322a92080dSRob Clark struct efi_device_path_file_path *fdp = 5332a92080dSRob Clark container_of(fp, struct efi_device_path_file_path, dp); 5342a92080dSRob Clark struct efi_file_handle *f2; 5352a92080dSRob Clark 5362a92080dSRob Clark if (!EFI_DP_TYPE(fp, MEDIA_DEVICE, FILE_PATH)) { 5372a92080dSRob Clark printf("bad file path!\n"); 5382a92080dSRob Clark f->close(f); 5392a92080dSRob Clark return NULL; 5402a92080dSRob Clark } 5412a92080dSRob Clark 5422a92080dSRob Clark EFI_CALL(ret = f->open(f, &f2, (s16 *)fdp->str, 5432a92080dSRob Clark EFI_FILE_MODE_READ, 0)); 5442a92080dSRob Clark if (ret != EFI_SUCCESS) 5452a92080dSRob Clark return NULL; 5462a92080dSRob Clark 5472a92080dSRob Clark fp = efi_dp_next(fp); 5482a92080dSRob Clark 5492a92080dSRob Clark EFI_CALL(f->close(f)); 5502a92080dSRob Clark f = f2; 5512a92080dSRob Clark } 5522a92080dSRob Clark 5532a92080dSRob Clark return f; 5542a92080dSRob Clark } 5552a92080dSRob Clark 5562a92080dSRob Clark static efi_status_t EFIAPI 5572a92080dSRob Clark efi_open_volume(struct efi_simple_file_system_protocol *this, 5582a92080dSRob Clark struct efi_file_handle **root) 5592a92080dSRob Clark { 5602a92080dSRob Clark struct file_system *fs = to_fs(this); 5612a92080dSRob Clark 5622a92080dSRob Clark EFI_ENTRY("%p, %p", this, root); 5632a92080dSRob Clark 5642a92080dSRob Clark *root = file_open(fs, NULL, NULL, 0); 5652a92080dSRob Clark 5662a92080dSRob Clark return EFI_EXIT(EFI_SUCCESS); 5672a92080dSRob Clark } 5682a92080dSRob Clark 5692a92080dSRob Clark struct efi_simple_file_system_protocol * 5702a92080dSRob Clark efi_simple_file_system(struct blk_desc *desc, int part, 5712a92080dSRob Clark struct efi_device_path *dp) 5722a92080dSRob Clark { 5732a92080dSRob Clark struct file_system *fs; 5742a92080dSRob Clark 5752a92080dSRob Clark fs = calloc(1, sizeof(*fs)); 5762a92080dSRob Clark fs->base.rev = EFI_SIMPLE_FILE_SYSTEM_PROTOCOL_REVISION; 5772a92080dSRob Clark fs->base.open_volume = efi_open_volume; 5782a92080dSRob Clark fs->desc = desc; 5792a92080dSRob Clark fs->part = part; 5802a92080dSRob Clark fs->dp = dp; 5812a92080dSRob Clark 5822a92080dSRob Clark return &fs->base; 5832a92080dSRob Clark } 584