uboot/lib/efi_loader/efi_file.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0+
   2/*
   3 * EFI_FILE_PROTOCOL
   4 *
   5 * Copyright (c) 2017 Rob Clark
   6 */
   7
   8#include <common.h>
   9#include <charset.h>
  10#include <efi_loader.h>
  11#include <log.h>
  12#include <malloc.h>
  13#include <mapmem.h>
  14#include <fs.h>
  15#include <part.h>
  16
  17/* GUID for file system information */
  18const efi_guid_t efi_file_system_info_guid = EFI_FILE_SYSTEM_INFO_GUID;
  19
  20/* GUID to obtain the volume label */
  21const efi_guid_t efi_system_volume_label_id = EFI_FILE_SYSTEM_VOLUME_LABEL_ID;
  22
  23struct file_system {
  24        struct efi_simple_file_system_protocol base;
  25        struct efi_device_path *dp;
  26        struct blk_desc *desc;
  27        int part;
  28};
  29#define to_fs(x) container_of(x, struct file_system, base)
  30
  31struct file_handle {
  32        struct efi_file_handle base;
  33        struct file_system *fs;
  34        loff_t offset;       /* current file position/cursor */
  35        int isdir;
  36        u64 open_mode;
  37
  38        /* for reading a directory: */
  39        struct fs_dir_stream *dirs;
  40        struct fs_dirent *dent;
  41
  42        char path[0];
  43};
  44#define to_fh(x) container_of(x, struct file_handle, base)
  45
  46static const struct efi_file_handle efi_file_handle_protocol;
  47
  48static char *basename(struct file_handle *fh)
  49{
  50        char *s = strrchr(fh->path, '/');
  51        if (s)
  52                return s + 1;
  53        return fh->path;
  54}
  55
  56static int set_blk_dev(struct file_handle *fh)
  57{
  58        return fs_set_blk_dev_with_part(fh->fs->desc, fh->fs->part);
  59}
  60
  61/**
  62 * is_dir() - check if file handle points to directory
  63 *
  64 * We assume that set_blk_dev(fh) has been called already.
  65 *
  66 * @fh:         file handle
  67 * Return:      true if file handle points to a directory
  68 */
  69static int is_dir(struct file_handle *fh)
  70{
  71        struct fs_dir_stream *dirs;
  72
  73        dirs = fs_opendir(fh->path);
  74        if (!dirs)
  75                return 0;
  76
  77        fs_closedir(dirs);
  78
  79        return 1;
  80}
  81
  82/*
  83 * Normalize a path which may include either back or fwd slashes,
  84 * double slashes, . or .. entries in the path, etc.
  85 */
  86static int sanitize_path(char *path)
  87{
  88        char *p;
  89
  90        /* backslash to slash: */
  91        p = path;
  92        while ((p = strchr(p, '\\')))
  93                *p++ = '/';
  94
  95        /* handle double-slashes: */
  96        p = path;
  97        while ((p = strstr(p, "//"))) {
  98                char *src = p + 1;
  99                memmove(p, src, strlen(src) + 1);
 100        }
 101
 102        /* handle extra /.'s */
 103        p = path;
 104        while ((p = strstr(p, "/."))) {
 105                /*
 106                 * You'd be tempted to do this *after* handling ".."s
 107                 * below to avoid having to check if "/." is start of
 108                 * a "/..", but that won't have the correct results..
 109                 * for example, "/foo/./../bar" would get resolved to
 110                 * "/foo/bar" if you did these two passes in the other
 111                 * order
 112                 */
 113                if (p[2] == '.') {
 114                        p += 2;
 115                        continue;
 116                }
 117                char *src = p + 2;
 118                memmove(p, src, strlen(src) + 1);
 119        }
 120
 121        /* handle extra /..'s: */
 122        p = path;
 123        while ((p = strstr(p, "/.."))) {
 124                char *src = p + 3;
 125
 126                p--;
 127
 128                /* find beginning of previous path entry: */
 129                while (true) {
 130                        if (p < path)
 131                                return -1;
 132                        if (*p == '/')
 133                                break;
 134                        p--;
 135                }
 136
 137                memmove(p, src, strlen(src) + 1);
 138        }
 139
 140        return 0;
 141}
 142
 143/**
 144 * efi_create_file() - create file or directory
 145 *
 146 * @fh:                 file handle
 147 * @attributes:         attributes for newly created file
 148 * Returns:             0 for success
 149 */
 150static int efi_create_file(struct file_handle *fh, u64 attributes)
 151{
 152        loff_t actwrite;
 153        void *buffer = &actwrite;
 154
 155        if (attributes & EFI_FILE_DIRECTORY)
 156                return fs_mkdir(fh->path);
 157        else
 158                return fs_write(fh->path, map_to_sysmem(buffer), 0, 0,
 159                                &actwrite);
 160}
 161
 162/**
 163 * file_open() - open a file handle
 164 *
 165 * @fs:                 file system
 166 * @parent:             directory relative to which the file is to be opened
 167 * @file_name:          path of the file to be opened. '\', '.', or '..' may
 168 *                      be used as modifiers. A leading backslash indicates an
 169 *                      absolute path.
 170 * @open_mode:          bit mask indicating the access mode (read, write,
 171 *                      create)
 172 * @attributes:         attributes for newly created file
 173 * Returns:             handle to the opened file or NULL
 174 */
 175static struct efi_file_handle *file_open(struct file_system *fs,
 176                struct file_handle *parent, u16 *file_name, u64 open_mode,
 177                u64 attributes)
 178{
 179        struct file_handle *fh;
 180        char f0[MAX_UTF8_PER_UTF16] = {0};
 181        int plen = 0;
 182        int flen = 0;
 183
 184        if (file_name) {
 185                utf16_to_utf8((u8 *)f0, file_name, 1);
 186                flen = u16_strlen(file_name);
 187        }
 188
 189        /* we could have a parent, but also an absolute path: */
 190        if (f0[0] == '\\') {
 191                plen = 0;
 192        } else if (parent) {
 193                plen = strlen(parent->path) + 1;
 194        }
 195
 196        /* +2 is for null and '/' */
 197        fh = calloc(1, sizeof(*fh) + plen + (flen * MAX_UTF8_PER_UTF16) + 2);
 198
 199        fh->open_mode = open_mode;
 200        fh->base = efi_file_handle_protocol;
 201        fh->fs = fs;
 202
 203        if (parent) {
 204                char *p = fh->path;
 205                int exists;
 206
 207                if (plen > 0) {
 208                        strcpy(p, parent->path);
 209                        p += plen - 1;
 210                        *p++ = '/';
 211                }
 212
 213                utf16_to_utf8((u8 *)p, file_name, flen);
 214
 215                if (sanitize_path(fh->path))
 216                        goto error;
 217
 218                /* check if file exists: */
 219                if (set_blk_dev(fh))
 220                        goto error;
 221
 222                exists = fs_exists(fh->path);
 223                /* fs_exists() calls fs_close(), so open file system again */
 224                if (set_blk_dev(fh))
 225                        goto error;
 226
 227                if (!exists) {
 228                        if (!(open_mode & EFI_FILE_MODE_CREATE) ||
 229                            efi_create_file(fh, attributes))
 230                                goto error;
 231                        if (set_blk_dev(fh))
 232                                goto error;
 233                }
 234
 235                /* figure out if file is a directory: */
 236                fh->isdir = is_dir(fh);
 237        } else {
 238                fh->isdir = 1;
 239                strcpy(fh->path, "");
 240        }
 241
 242        return &fh->base;
 243
 244error:
 245        free(fh);
 246        return NULL;
 247}
 248
 249static efi_status_t EFIAPI efi_file_open(struct efi_file_handle *file,
 250                struct efi_file_handle **new_handle,
 251                u16 *file_name, u64 open_mode, u64 attributes)
 252{
 253        struct file_handle *fh = to_fh(file);
 254        efi_status_t ret;
 255
 256        EFI_ENTRY("%p, %p, \"%ls\", %llx, %llu", file, new_handle,
 257                  file_name, open_mode, attributes);
 258
 259        /* Check parameters */
 260        if (!file || !new_handle || !file_name) {
 261                ret = EFI_INVALID_PARAMETER;
 262                goto out;
 263        }
 264        if (open_mode != EFI_FILE_MODE_READ &&
 265            open_mode != (EFI_FILE_MODE_READ | EFI_FILE_MODE_WRITE) &&
 266            open_mode != (EFI_FILE_MODE_READ | EFI_FILE_MODE_WRITE |
 267                         EFI_FILE_MODE_CREATE)) {
 268                ret = EFI_INVALID_PARAMETER;
 269                goto out;
 270        }
 271        /*
 272         * The UEFI spec requires that attributes are only set in create mode.
 273         * The SCT does not care about this and sets EFI_FILE_DIRECTORY in
 274         * read mode. EDK2 does not check that attributes are zero if not in
 275         * create mode.
 276         *
 277         * So here we only check attributes in create mode and do not check
 278         * that they are zero otherwise.
 279         */
 280        if ((open_mode & EFI_FILE_MODE_CREATE) &&
 281            (attributes & (EFI_FILE_READ_ONLY | ~EFI_FILE_VALID_ATTR))) {
 282                ret = EFI_INVALID_PARAMETER;
 283                goto out;
 284        }
 285
 286        /* Open file */
 287        *new_handle = file_open(fh->fs, fh, file_name, open_mode, attributes);
 288        if (*new_handle) {
 289                EFI_PRINT("file handle %p\n", *new_handle);
 290                ret = EFI_SUCCESS;
 291        } else {
 292                ret = EFI_NOT_FOUND;
 293        }
 294out:
 295        return EFI_EXIT(ret);
 296}
 297
 298static efi_status_t file_close(struct file_handle *fh)
 299{
 300        fs_closedir(fh->dirs);
 301        free(fh);
 302        return EFI_SUCCESS;
 303}
 304
 305static efi_status_t EFIAPI efi_file_close(struct efi_file_handle *file)
 306{
 307        struct file_handle *fh = to_fh(file);
 308        EFI_ENTRY("%p", file);
 309        return EFI_EXIT(file_close(fh));
 310}
 311
 312static efi_status_t EFIAPI efi_file_delete(struct efi_file_handle *file)
 313{
 314        struct file_handle *fh = to_fh(file);
 315        efi_status_t ret = EFI_SUCCESS;
 316
 317        EFI_ENTRY("%p", file);
 318
 319        if (set_blk_dev(fh) || fs_unlink(fh->path))
 320                ret = EFI_WARN_DELETE_FAILURE;
 321
 322        file_close(fh);
 323        return EFI_EXIT(ret);
 324}
 325
 326/**
 327 * efi_get_file_size() - determine the size of a file
 328 *
 329 * @fh:         file handle
 330 * @file_size:  pointer to receive file size
 331 * Return:      status code
 332 */
 333static efi_status_t efi_get_file_size(struct file_handle *fh,
 334                                      loff_t *file_size)
 335{
 336        if (set_blk_dev(fh))
 337                return EFI_DEVICE_ERROR;
 338
 339        if (fs_size(fh->path, file_size))
 340                return EFI_DEVICE_ERROR;
 341
 342        return EFI_SUCCESS;
 343}
 344
 345static efi_status_t file_read(struct file_handle *fh, u64 *buffer_size,
 346                void *buffer)
 347{
 348        loff_t actread;
 349        efi_status_t ret;
 350        loff_t file_size;
 351
 352        if (!buffer) {
 353                ret = EFI_INVALID_PARAMETER;
 354                return ret;
 355        }
 356
 357        ret = efi_get_file_size(fh, &file_size);
 358        if (ret != EFI_SUCCESS)
 359                return ret;
 360        if (file_size < fh->offset) {
 361                ret = EFI_DEVICE_ERROR;
 362                return ret;
 363        }
 364
 365        if (set_blk_dev(fh))
 366                return EFI_DEVICE_ERROR;
 367        if (fs_read(fh->path, map_to_sysmem(buffer), fh->offset,
 368                    *buffer_size, &actread))
 369                return EFI_DEVICE_ERROR;
 370
 371        *buffer_size = actread;
 372        fh->offset += actread;
 373
 374        return EFI_SUCCESS;
 375}
 376
 377static efi_status_t dir_read(struct file_handle *fh, u64 *buffer_size,
 378                void *buffer)
 379{
 380        struct efi_file_info *info = buffer;
 381        struct fs_dirent *dent;
 382        u64 required_size;
 383        u16 *dst;
 384
 385        if (set_blk_dev(fh))
 386                return EFI_DEVICE_ERROR;
 387
 388        if (!fh->dirs) {
 389                assert(fh->offset == 0);
 390                fh->dirs = fs_opendir(fh->path);
 391                if (!fh->dirs)
 392                        return EFI_DEVICE_ERROR;
 393                fh->dent = NULL;
 394        }
 395
 396        /*
 397         * So this is a bit awkward.  Since fs layer is stateful and we
 398         * can't rewind an entry, in the EFI_BUFFER_TOO_SMALL case below
 399         * we might have to return without consuming the dent.. so we
 400         * have to stash it for next call.
 401         */
 402        if (fh->dent) {
 403                dent = fh->dent;
 404        } else {
 405                dent = fs_readdir(fh->dirs);
 406        }
 407
 408        if (!dent) {
 409                /* no more files in directory */
 410                *buffer_size = 0;
 411                return EFI_SUCCESS;
 412        }
 413
 414        /* check buffer size: */
 415        required_size = sizeof(*info) +
 416                        2 * (utf8_utf16_strlen(dent->name) + 1);
 417        if (*buffer_size < required_size) {
 418                *buffer_size = required_size;
 419                fh->dent = dent;
 420                return EFI_BUFFER_TOO_SMALL;
 421        }
 422        if (!buffer)
 423                return EFI_INVALID_PARAMETER;
 424        fh->dent = NULL;
 425
 426        *buffer_size = required_size;
 427        memset(info, 0, required_size);
 428
 429        info->size = required_size;
 430        info->file_size = dent->size;
 431        info->physical_size = dent->size;
 432
 433        if (dent->type == FS_DT_DIR)
 434                info->attribute |= EFI_FILE_DIRECTORY;
 435
 436        dst = info->file_name;
 437        utf8_utf16_strcpy(&dst, dent->name);
 438
 439        fh->offset++;
 440
 441        return EFI_SUCCESS;
 442}
 443
 444static efi_status_t EFIAPI efi_file_read(struct efi_file_handle *file,
 445                                         efi_uintn_t *buffer_size, void *buffer)
 446{
 447        struct file_handle *fh = to_fh(file);
 448        efi_status_t ret = EFI_SUCCESS;
 449        u64 bs;
 450
 451        EFI_ENTRY("%p, %p, %p", file, buffer_size, buffer);
 452
 453        if (!buffer_size) {
 454                ret = EFI_INVALID_PARAMETER;
 455                goto error;
 456        }
 457
 458        bs = *buffer_size;
 459        if (fh->isdir)
 460                ret = dir_read(fh, &bs, buffer);
 461        else
 462                ret = file_read(fh, &bs, buffer);
 463        if (bs <= SIZE_MAX)
 464                *buffer_size = bs;
 465        else
 466                *buffer_size = SIZE_MAX;
 467
 468error:
 469        return EFI_EXIT(ret);
 470}
 471
 472/**
 473 * efi_file_write() - write to file
 474 *
 475 * This function implements the Write() service of the EFI_FILE_PROTOCOL.
 476 *
 477 * See the Unified Extensible Firmware Interface (UEFI) specification for
 478 * details.
 479 *
 480 * @file:               file handle
 481 * @buffer_size:        number of bytes to write
 482 * @buffer:             buffer with the bytes to write
 483 * Return:              status code
 484 */
 485static efi_status_t EFIAPI efi_file_write(struct efi_file_handle *file,
 486                                          efi_uintn_t *buffer_size,
 487                                          void *buffer)
 488{
 489        struct file_handle *fh = to_fh(file);
 490        efi_status_t ret = EFI_SUCCESS;
 491        loff_t actwrite;
 492
 493        EFI_ENTRY("%p, %p, %p", file, buffer_size, buffer);
 494
 495        if (!file || !buffer_size || !buffer) {
 496                ret = EFI_INVALID_PARAMETER;
 497                goto out;
 498        }
 499        if (fh->isdir) {
 500                ret = EFI_UNSUPPORTED;
 501                goto out;
 502        }
 503        if (!(fh->open_mode & EFI_FILE_MODE_WRITE)) {
 504                ret = EFI_ACCESS_DENIED;
 505                goto out;
 506        }
 507
 508        if (!*buffer_size)
 509                goto out;
 510
 511        if (set_blk_dev(fh)) {
 512                ret = EFI_DEVICE_ERROR;
 513                goto out;
 514        }
 515        if (fs_write(fh->path, map_to_sysmem(buffer), fh->offset, *buffer_size,
 516                     &actwrite)) {
 517                ret = EFI_DEVICE_ERROR;
 518                goto out;
 519        }
 520        *buffer_size = actwrite;
 521        fh->offset += actwrite;
 522
 523out:
 524        return EFI_EXIT(ret);
 525}
 526
 527/**
 528 * efi_file_getpos() - get current position in file
 529 *
 530 * This function implements the GetPosition service of the EFI file protocol.
 531 * See the UEFI spec for details.
 532 *
 533 * @file:       file handle
 534 * @pos:        pointer to file position
 535 * Return:      status code
 536 */
 537static efi_status_t EFIAPI efi_file_getpos(struct efi_file_handle *file,
 538                                           u64 *pos)
 539{
 540        efi_status_t ret = EFI_SUCCESS;
 541        struct file_handle *fh = to_fh(file);
 542
 543        EFI_ENTRY("%p, %p", file, pos);
 544
 545        if (fh->isdir) {
 546                ret = EFI_UNSUPPORTED;
 547                goto out;
 548        }
 549
 550        *pos = fh->offset;
 551out:
 552        return EFI_EXIT(ret);
 553}
 554
 555/**
 556 * efi_file_setpos() - set current position in file
 557 *
 558 * This function implements the SetPosition service of the EFI file protocol.
 559 * See the UEFI spec for details.
 560 *
 561 * @file:       file handle
 562 * @pos:        new file position
 563 * Return:      status code
 564 */
 565static efi_status_t EFIAPI efi_file_setpos(struct efi_file_handle *file,
 566                                           u64 pos)
 567{
 568        struct file_handle *fh = to_fh(file);
 569        efi_status_t ret = EFI_SUCCESS;
 570
 571        EFI_ENTRY("%p, %llu", file, pos);
 572
 573        if (fh->isdir) {
 574                if (pos != 0) {
 575                        ret = EFI_UNSUPPORTED;
 576                        goto error;
 577                }
 578                fs_closedir(fh->dirs);
 579                fh->dirs = NULL;
 580        }
 581
 582        if (pos == ~0ULL) {
 583                loff_t file_size;
 584
 585                ret = efi_get_file_size(fh, &file_size);
 586                if (ret != EFI_SUCCESS)
 587                        goto error;
 588                pos = file_size;
 589        }
 590
 591        fh->offset = pos;
 592
 593error:
 594        return EFI_EXIT(ret);
 595}
 596
 597static efi_status_t EFIAPI efi_file_getinfo(struct efi_file_handle *file,
 598                                            const efi_guid_t *info_type,
 599                                            efi_uintn_t *buffer_size,
 600                                            void *buffer)
 601{
 602        struct file_handle *fh = to_fh(file);
 603        efi_status_t ret = EFI_SUCCESS;
 604        u16 *dst;
 605
 606        EFI_ENTRY("%p, %pUl, %p, %p", file, info_type, buffer_size, buffer);
 607
 608        if (!file || !info_type || !buffer_size ||
 609            (*buffer_size && !buffer)) {
 610                ret = EFI_INVALID_PARAMETER;
 611                goto error;
 612        }
 613
 614        if (!guidcmp(info_type, &efi_file_info_guid)) {
 615                struct efi_file_info *info = buffer;
 616                char *filename = basename(fh);
 617                unsigned int required_size;
 618                loff_t file_size;
 619
 620                /* check buffer size: */
 621                required_size = sizeof(*info) +
 622                                2 * (utf8_utf16_strlen(filename) + 1);
 623                if (*buffer_size < required_size) {
 624                        *buffer_size = required_size;
 625                        ret = EFI_BUFFER_TOO_SMALL;
 626                        goto error;
 627                }
 628
 629                ret = efi_get_file_size(fh, &file_size);
 630                if (ret != EFI_SUCCESS)
 631                        goto error;
 632
 633                memset(info, 0, required_size);
 634
 635                info->size = required_size;
 636                info->file_size = file_size;
 637                info->physical_size = file_size;
 638
 639                if (fh->isdir)
 640                        info->attribute |= EFI_FILE_DIRECTORY;
 641
 642                dst = info->file_name;
 643                utf8_utf16_strcpy(&dst, filename);
 644        } else if (!guidcmp(info_type, &efi_file_system_info_guid)) {
 645                struct efi_file_system_info *info = buffer;
 646                struct disk_partition part;
 647                efi_uintn_t required_size;
 648                int r;
 649
 650                if (fh->fs->part >= 1)
 651                        r = part_get_info(fh->fs->desc, fh->fs->part, &part);
 652                else
 653                        r = part_get_info_whole_disk(fh->fs->desc, &part);
 654                if (r < 0) {
 655                        ret = EFI_DEVICE_ERROR;
 656                        goto error;
 657                }
 658                required_size = sizeof(*info) + 2;
 659                if (*buffer_size < required_size) {
 660                        *buffer_size = required_size;
 661                        ret = EFI_BUFFER_TOO_SMALL;
 662                        goto error;
 663                }
 664
 665                memset(info, 0, required_size);
 666
 667                info->size = required_size;
 668                /*
 669                 * TODO: We cannot determine if the volume can be written to.
 670                 */
 671                info->read_only = false;
 672                info->volume_size = part.size * part.blksz;
 673                /*
 674                 * TODO: We currently have no function to determine the free
 675                 * space. The volume size is the best upper bound we have.
 676                 */
 677                info->free_space = info->volume_size;
 678                info->block_size = part.blksz;
 679                /*
 680                 * TODO: The volume label is not available in U-Boot.
 681                 */
 682                info->volume_label[0] = 0;
 683        } else if (!guidcmp(info_type, &efi_system_volume_label_id)) {
 684                if (*buffer_size < 2) {
 685                        *buffer_size = 2;
 686                        ret = EFI_BUFFER_TOO_SMALL;
 687                        goto error;
 688                }
 689                *(u16 *)buffer = 0;
 690        } else {
 691                ret = EFI_UNSUPPORTED;
 692        }
 693
 694error:
 695        return EFI_EXIT(ret);
 696}
 697
 698static efi_status_t EFIAPI efi_file_setinfo(struct efi_file_handle *file,
 699                                            const efi_guid_t *info_type,
 700                                            efi_uintn_t buffer_size,
 701                                            void *buffer)
 702{
 703        struct file_handle *fh = to_fh(file);
 704        efi_status_t ret = EFI_UNSUPPORTED;
 705
 706        EFI_ENTRY("%p, %pUl, %zu, %p", file, info_type, buffer_size, buffer);
 707
 708        if (!guidcmp(info_type, &efi_file_info_guid)) {
 709                struct efi_file_info *info = (struct efi_file_info *)buffer;
 710                char *filename = basename(fh);
 711                char *new_file_name, *pos;
 712                loff_t file_size;
 713
 714                /* The buffer will always contain a file name. */
 715                if (buffer_size < sizeof(struct efi_file_info) + 2 ||
 716                    buffer_size < info->size) {
 717                        ret = EFI_BAD_BUFFER_SIZE;
 718                        goto out;
 719                }
 720                /* We cannot change the directory attribute */
 721                if (!fh->isdir != !(info->attribute & EFI_FILE_DIRECTORY)) {
 722                        ret = EFI_ACCESS_DENIED;
 723                        goto out;
 724                }
 725                /* Check for renaming */
 726                new_file_name = malloc(utf16_utf8_strlen(info->file_name) + 1);
 727                if (!new_file_name) {
 728                        ret = EFI_OUT_OF_RESOURCES;
 729                        goto out;
 730                }
 731                pos = new_file_name;
 732                utf16_utf8_strcpy(&pos, info->file_name);
 733                if (strcmp(new_file_name, filename)) {
 734                        /* TODO: we do not support renaming */
 735                        EFI_PRINT("Renaming not supported\n");
 736                        free(new_file_name);
 737                        ret = EFI_ACCESS_DENIED;
 738                        goto out;
 739                }
 740                free(new_file_name);
 741                /* Check for truncation */
 742                ret = efi_get_file_size(fh, &file_size);
 743                if (ret != EFI_SUCCESS)
 744                        goto out;
 745                if (file_size != info->file_size) {
 746                        /* TODO: we do not support truncation */
 747                        EFI_PRINT("Truncation not supported\n");
 748                        ret = EFI_ACCESS_DENIED;
 749                        goto out;
 750                }
 751                /*
 752                 * We do not care for the other attributes
 753                 * TODO: Support read only
 754                 */
 755                ret = EFI_SUCCESS;
 756        } else {
 757                /* TODO: We do not support changing the volume label */
 758                ret = EFI_UNSUPPORTED;
 759        }
 760out:
 761        return EFI_EXIT(ret);
 762}
 763
 764static efi_status_t EFIAPI efi_file_flush(struct efi_file_handle *file)
 765{
 766        EFI_ENTRY("%p", file);
 767        return EFI_EXIT(EFI_SUCCESS);
 768}
 769
 770static efi_status_t EFIAPI efi_file_open_ex(struct efi_file_handle *file,
 771                        struct efi_file_handle **new_handle,
 772                        u16 *file_name, u64 open_mode, u64 attributes,
 773                        struct efi_file_io_token *token)
 774{
 775        return EFI_UNSUPPORTED;
 776}
 777
 778static efi_status_t EFIAPI efi_file_read_ex(struct efi_file_handle *file,
 779                        struct efi_file_io_token *token)
 780{
 781        return EFI_UNSUPPORTED;
 782}
 783
 784static efi_status_t EFIAPI efi_file_write_ex(struct efi_file_handle *file,
 785                        struct efi_file_io_token *token)
 786{
 787        return EFI_UNSUPPORTED;
 788}
 789
 790static efi_status_t EFIAPI efi_file_flush_ex(struct efi_file_handle *file,
 791                        struct efi_file_io_token *token)
 792{
 793        return EFI_UNSUPPORTED;
 794}
 795
 796static const struct efi_file_handle efi_file_handle_protocol = {
 797        .rev = EFI_FILE_PROTOCOL_REVISION2,
 798        .open = efi_file_open,
 799        .close = efi_file_close,
 800        .delete = efi_file_delete,
 801        .read = efi_file_read,
 802        .write = efi_file_write,
 803        .getpos = efi_file_getpos,
 804        .setpos = efi_file_setpos,
 805        .getinfo = efi_file_getinfo,
 806        .setinfo = efi_file_setinfo,
 807        .flush = efi_file_flush,
 808        .open_ex = efi_file_open_ex,
 809        .read_ex = efi_file_read_ex,
 810        .write_ex = efi_file_write_ex,
 811        .flush_ex = efi_file_flush_ex,
 812};
 813
 814/**
 815 * efi_file_from_path() - open file via device path
 816 *
 817 * @fp:         device path
 818 * @return:     EFI_FILE_PROTOCOL for the file or NULL
 819 */
 820struct efi_file_handle *efi_file_from_path(struct efi_device_path *fp)
 821{
 822        struct efi_simple_file_system_protocol *v;
 823        struct efi_file_handle *f;
 824        efi_status_t ret;
 825
 826        v = efi_fs_from_path(fp);
 827        if (!v)
 828                return NULL;
 829
 830        EFI_CALL(ret = v->open_volume(v, &f));
 831        if (ret != EFI_SUCCESS)
 832                return NULL;
 833
 834        /* Skip over device-path nodes before the file path. */
 835        while (fp && !EFI_DP_TYPE(fp, MEDIA_DEVICE, FILE_PATH))
 836                fp = efi_dp_next(fp);
 837
 838        /*
 839         * Step through the nodes of the directory path until the actual file
 840         * node is reached which is the final node in the device path.
 841         */
 842        while (fp) {
 843                struct efi_device_path_file_path *fdp =
 844                        container_of(fp, struct efi_device_path_file_path, dp);
 845                struct efi_file_handle *f2;
 846                u16 *filename;
 847
 848                if (!EFI_DP_TYPE(fp, MEDIA_DEVICE, FILE_PATH)) {
 849                        printf("bad file path!\n");
 850                        f->close(f);
 851                        return NULL;
 852                }
 853
 854                filename = u16_strdup(fdp->str);
 855                if (!filename)
 856                        return NULL;
 857                EFI_CALL(ret = f->open(f, &f2, filename,
 858                                       EFI_FILE_MODE_READ, 0));
 859                free(filename);
 860                if (ret != EFI_SUCCESS)
 861                        return NULL;
 862
 863                fp = efi_dp_next(fp);
 864
 865                EFI_CALL(f->close(f));
 866                f = f2;
 867        }
 868
 869        return f;
 870}
 871
 872static efi_status_t EFIAPI
 873efi_open_volume(struct efi_simple_file_system_protocol *this,
 874                struct efi_file_handle **root)
 875{
 876        struct file_system *fs = to_fs(this);
 877
 878        EFI_ENTRY("%p, %p", this, root);
 879
 880        *root = file_open(fs, NULL, NULL, 0, 0);
 881
 882        return EFI_EXIT(EFI_SUCCESS);
 883}
 884
 885struct efi_simple_file_system_protocol *
 886efi_simple_file_system(struct blk_desc *desc, int part,
 887                       struct efi_device_path *dp)
 888{
 889        struct file_system *fs;
 890
 891        fs = calloc(1, sizeof(*fs));
 892        fs->base.rev = EFI_SIMPLE_FILE_SYSTEM_PROTOCOL_REVISION;
 893        fs->base.open_volume = efi_open_volume;
 894        fs->desc = desc;
 895        fs->part = part;
 896        fs->dp = dp;
 897
 898        return &fs->base;
 899}
 900