X-Git-Url: https://git.librecmc.org/?a=blobdiff_plain;f=lib%2Fefi_loader%2Fefi_file.c;h=182d735e6bc28cadf6a83823cdb5d344020480e0;hb=e6023be41e94eb2bab4c93d343ac3deddfe12c7b;hp=9d709a8db026457480c8b79118423b45466004c7;hpb=c82f8f600a34d540f95a04e9cb3c49a9e6b3ae83;p=oweals%2Fu-boot.git diff --git a/lib/efi_loader/efi_file.c b/lib/efi_loader/efi_file.c index 9d709a8db0..182d735e6b 100644 --- a/lib/efi_loader/efi_file.c +++ b/lib/efi_loader/efi_file.c @@ -134,6 +134,25 @@ static int sanitize_path(char *path) return 0; } +/** + * efi_create_file() - create file or directory + * + * @fh: file handle + * @attributes: attributes for newly created file + * Returns: 0 for success + */ +static int efi_create_file(struct file_handle *fh, u64 attributes) +{ + loff_t actwrite; + void *buffer = &actwrite; + + if (attributes & EFI_FILE_DIRECTORY) + return fs_mkdir(fh->path); + else + return fs_write(fh->path, map_to_sysmem(buffer), 0, 0, + &actwrite); +} + /** * file_open() - open a file handle * @@ -176,6 +195,7 @@ static struct efi_file_handle *file_open(struct file_system *fs, if (parent) { char *p = fh->path; + int exists; if (plen > 0) { strcpy(p, parent->path); @@ -192,14 +212,17 @@ static struct efi_file_handle *file_open(struct file_system *fs, if (set_blk_dev(fh)) goto error; - if ((mode & EFI_FILE_MODE_CREATE) && - (attributes & EFI_FILE_DIRECTORY)) { - if (fs_mkdir(fh->path)) - goto error; - } else if (!((mode & EFI_FILE_MODE_CREATE) || - fs_exists(fh->path))) + exists = fs_exists(fh->path); + /* fs_exists() calls fs_close(), so open file system again */ + if (set_blk_dev(fh)) goto error; + if (!exists) { + if (!(mode & EFI_FILE_MODE_CREATE) || + efi_create_file(fh, attributes)) + goto error; + } + /* figure out if file is a directory: */ fh->isdir = is_dir(fh); } else { @@ -222,7 +245,7 @@ static efi_status_t EFIAPI efi_file_open(struct efi_file_handle *file, efi_status_t ret; EFI_ENTRY("%p, %p, \"%ls\", %llx, %llu", file, new_handle, - (wchar_t *)file_name, open_mode, attributes); + file_name, open_mode, attributes); /* Check parameters */ if (!file || !new_handle || !file_name) { @@ -253,10 +276,12 @@ static efi_status_t EFIAPI efi_file_open(struct efi_file_handle *file, /* Open file */ *new_handle = file_open(fh->fs, fh, file_name, open_mode, attributes); - if (*new_handle) + if (*new_handle) { + EFI_PRINT("file handle %p\n", *new_handle); ret = EFI_SUCCESS; - else + } else { ret = EFI_NOT_FOUND; + } out: return EFI_EXIT(ret); } @@ -612,9 +637,72 @@ static efi_status_t EFIAPI efi_file_setinfo(struct efi_file_handle *file, efi_uintn_t buffer_size, void *buffer) { - EFI_ENTRY("%p, %p, %zu, %p", file, info_type, buffer_size, buffer); + struct file_handle *fh = to_fh(file); + efi_status_t ret = EFI_UNSUPPORTED; + + EFI_ENTRY("%p, %pUl, %zu, %p", file, info_type, buffer_size, buffer); - return EFI_EXIT(EFI_UNSUPPORTED); + if (!guidcmp(info_type, &efi_file_info_guid)) { + struct efi_file_info *info = (struct efi_file_info *)buffer; + char *filename = basename(fh); + char *new_file_name, *pos; + loff_t file_size; + + if (buffer_size < sizeof(struct efi_file_info)) { + ret = EFI_BAD_BUFFER_SIZE; + goto out; + } + /* We cannot change the directory attribute */ + if (!fh->isdir != !(info->attribute & EFI_FILE_DIRECTORY)) { + ret = EFI_ACCESS_DENIED; + goto out; + } + /* Check for renaming */ + new_file_name = malloc(utf16_utf8_strlen(info->file_name)); + if (!new_file_name) { + ret = EFI_OUT_OF_RESOURCES; + goto out; + } + pos = new_file_name; + utf16_utf8_strcpy(&pos, info->file_name); + if (strcmp(new_file_name, filename)) { + /* TODO: we do not support renaming */ + EFI_PRINT("Renaming not supported\n"); + free(new_file_name); + ret = EFI_ACCESS_DENIED; + goto out; + } + free(new_file_name); + /* Check for truncation */ + if (set_blk_dev(fh)) { + ret = EFI_DEVICE_ERROR; + goto out; + } + if (fs_size(fh->path, &file_size)) { + ret = EFI_DEVICE_ERROR; + goto out; + } + if (file_size != info->file_size) { + /* TODO: we do not support truncation */ + EFI_PRINT("Truncation not supported\n"); + ret = EFI_ACCESS_DENIED; + goto out; + } + /* + * We do not care for the other attributes + * TODO: Support read only + */ + ret = EFI_SUCCESS; + } else if (!guidcmp(info_type, &efi_file_system_info_guid)) { + if (buffer_size < sizeof(struct efi_file_system_info)) { + ret = EFI_BAD_BUFFER_SIZE; + goto out; + } + } else { + ret = EFI_UNSUPPORTED; + } +out: + return EFI_EXIT(ret); } static efi_status_t EFIAPI efi_file_flush(struct efi_file_handle *file) @@ -624,6 +712,10 @@ static efi_status_t EFIAPI efi_file_flush(struct efi_file_handle *file) } static const struct efi_file_handle efi_file_handle_protocol = { + /* + * TODO: We currently only support EFI file protocol revision 0x00010000 + * while UEFI specs 2.4 - 2.7 prescribe revision 0x00020000. + */ .rev = EFI_FILE_PROTOCOL_REVISION, .open = efi_file_open, .close = efi_file_close, @@ -637,6 +729,12 @@ static const struct efi_file_handle efi_file_handle_protocol = { .flush = efi_file_flush, }; +/** + * efi_file_from_path() - open file via device path + * + * @fp: device path + * @return: EFI_FILE_PROTOCOL for the file or NULL + */ struct efi_file_handle *efi_file_from_path(struct efi_device_path *fp) { struct efi_simple_file_system_protocol *v; @@ -651,10 +749,14 @@ struct efi_file_handle *efi_file_from_path(struct efi_device_path *fp) if (ret != EFI_SUCCESS) return NULL; - /* skip over device-path nodes before the file path: */ + /* Skip over device-path nodes before the file path. */ while (fp && !EFI_DP_TYPE(fp, MEDIA_DEVICE, FILE_PATH)) fp = efi_dp_next(fp); + /* + * Step through the nodes of the directory path until the actual file + * node is reached which is the final node in the device path. + */ while (fp) { struct efi_device_path_file_path *fdp = container_of(fp, struct efi_device_path_file_path, dp);