static efi_status_t EFIAPI efi_file_write(struct efi_file_handle *file, efi_uintn_t *buffer_size, void *buffer) { struct file_handle *fh = to_fh(file); efi_status_t ret = EFI_SUCCESS; loff_t actwrite; EFI_ENTRY("%p, %p, %p", file, buffer_size, buffer); if (set_blk_dev(fh)) { ret = EFI_DEVICE_ERROR; goto error; } if (fs_write(fh->path, (ulong)buffer, fh->offset, *buffer_size, &actwrite)) { ret = EFI_DEVICE_ERROR; goto error; } *buffer_size = actwrite; fh->offset += actwrite; error: return EFI_EXIT(ret); }
static efi_status_t EFIAPI efi_file_read(struct efi_file_handle *file, efi_uintn_t *buffer_size, void *buffer) { struct file_handle *fh = to_fh(file); efi_status_t ret = EFI_SUCCESS; u64 bs; EFI_ENTRY("%p, %p, %p", file, buffer_size, buffer); if (!buffer_size || !buffer) { ret = EFI_INVALID_PARAMETER; goto error; } if (set_blk_dev(fh)) { ret = EFI_DEVICE_ERROR; goto error; } bs = *buffer_size; if (fh->isdir) ret = dir_read(fh, &bs, buffer); else ret = file_read(fh, &bs, buffer); if (bs <= SIZE_MAX) *buffer_size = bs; else *buffer_size = SIZE_MAX; error: return EFI_EXIT(ret); }
/* NOTE: despite what you would expect, 'file_name' is actually a path. * With windoze style backlashes, ofc. */ static struct efi_file_handle *file_open(struct file_system *fs, struct file_handle *parent, s16 *file_name, u64 mode) { struct file_handle *fh; char f0[MAX_UTF8_PER_UTF16] = {0}; int plen = 0; int flen = 0; if (file_name) { utf16_to_utf8((u8 *)f0, (u16 *)file_name, 1); flen = utf16_strlen((u16 *)file_name); } /* we could have a parent, but also an absolute path: */ if (f0[0] == '\\') { plen = 0; } else if (parent) { plen = strlen(parent->path) + 1; } /* +2 is for null and '/' */ fh = calloc(1, sizeof(*fh) + plen + (flen * MAX_UTF8_PER_UTF16) + 2); fh->base = efi_file_handle_protocol; fh->fs = fs; if (parent) { char *p = fh->path; if (plen > 0) { strcpy(p, parent->path); p += plen - 1; *p++ = '/'; } utf16_to_utf8((u8 *)p, (u16 *)file_name, flen); if (sanitize_path(fh->path)) goto error; /* check if file exists: */ if (set_blk_dev(fh)) goto error; if (!((mode & EFI_FILE_MODE_CREATE) || fs_exists(fh->path))) goto error; /* figure out if file is a directory: */ fh->isdir = is_dir(fh); } else { fh->isdir = 1; strcpy(fh->path, ""); } return &fh->base; error: free(fh); return NULL; }
static int is_dir(struct file_handle *fh) { struct fs_dir_stream *dirs; set_blk_dev(fh); dirs = fs_opendir(fh->path); if (!dirs) return 0; fs_closedir(dirs); return 1; }
static efi_status_t EFIAPI efi_file_delete(struct efi_file_handle *file) { struct file_handle *fh = to_fh(file); efi_status_t ret = EFI_SUCCESS; EFI_ENTRY("%p", file); if (set_blk_dev(fh)) { ret = EFI_DEVICE_ERROR; goto error; } if (fs_unlink(fh->path)) ret = EFI_DEVICE_ERROR; file_close(fh); error: return EFI_EXIT(ret); }
static efi_status_t EFIAPI efi_file_setpos(struct efi_file_handle *file, efi_uintn_t pos) { struct file_handle *fh = to_fh(file); efi_status_t ret = EFI_SUCCESS; EFI_ENTRY("%p, %zu", file, pos); if (fh->isdir) { if (pos != 0) { ret = EFI_UNSUPPORTED; goto error; } fs_closedir(fh->dirs); fh->dirs = NULL; } if (pos == ~0ULL) { loff_t file_size; if (set_blk_dev(fh)) { ret = EFI_DEVICE_ERROR; goto error; } if (fs_size(fh->path, &file_size)) { ret = EFI_DEVICE_ERROR; goto error; } pos = file_size; } fh->offset = pos; error: return EFI_EXIT(ret); }
static efi_status_t EFIAPI efi_file_getinfo(struct efi_file_handle *file, const efi_guid_t *info_type, efi_uintn_t *buffer_size, void *buffer) { struct file_handle *fh = to_fh(file); efi_status_t ret = EFI_SUCCESS; EFI_ENTRY("%p, %p, %p, %p", file, info_type, buffer_size, buffer); if (!guidcmp(info_type, &efi_file_info_guid)) { struct efi_file_info *info = buffer; char *filename = basename(fh); unsigned int required_size; loff_t file_size; /* check buffer size: */ required_size = sizeof(*info) + 2 * (strlen(filename) + 1); if (*buffer_size < required_size) { *buffer_size = required_size; ret = EFI_BUFFER_TOO_SMALL; goto error; } if (set_blk_dev(fh)) { ret = EFI_DEVICE_ERROR; goto error; } if (fs_size(fh->path, &file_size)) { ret = EFI_DEVICE_ERROR; goto error; } memset(info, 0, required_size); info->size = required_size; info->file_size = file_size; info->physical_size = file_size; if (fh->isdir) info->attribute |= EFI_FILE_DIRECTORY; ascii2unicode((u16 *)info->file_name, filename); } else if (!guidcmp(info_type, &efi_file_system_info_guid)) { struct efi_file_system_info *info = buffer; disk_partition_t part; efi_uintn_t required_size; int r; if (fh->fs->part >= 1) r = part_get_info(fh->fs->desc, fh->fs->part, &part); else r = part_get_info_whole_disk(fh->fs->desc, &part); if (r < 0) { ret = EFI_DEVICE_ERROR; goto error; } required_size = sizeof(info) + 2 * (strlen((const char *)part.name) + 1); if (*buffer_size < required_size) { *buffer_size = required_size; ret = EFI_BUFFER_TOO_SMALL; goto error; } memset(info, 0, required_size); info->size = required_size; info->read_only = true; info->volume_size = part.size * part.blksz; info->free_space = 0; info->block_size = part.blksz; /* * TODO: The volume label is not available in U-Boot. * Use the partition name as substitute. */ ascii2unicode((u16 *)info->volume_label, (const char *)part.name); } else { ret = EFI_UNSUPPORTED; } error: return EFI_EXIT(ret); }