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