Prepare v2024.10
[platform/kernel/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 <charset.h>
9 #include <efi_loader.h>
10 #include <log.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         if (!fh)
198                 return NULL;
199
200         fh->open_mode = open_mode;
201         fh->base = efi_file_handle_protocol;
202         fh->fs = fs;
203
204         if (parent) {
205                 char *p = fh->path;
206                 int exists;
207
208                 if (plen > 0) {
209                         strcpy(p, parent->path);
210                         p += plen - 1;
211                         *p++ = '/';
212                 }
213
214                 utf16_to_utf8((u8 *)p, file_name, flen);
215
216                 if (sanitize_path(fh->path))
217                         goto error;
218
219                 /* check if file exists: */
220                 if (set_blk_dev(fh))
221                         goto error;
222
223                 exists = fs_exists(fh->path);
224                 /* fs_exists() calls fs_close(), so open file system again */
225                 if (set_blk_dev(fh))
226                         goto error;
227
228                 if (!exists) {
229                         if (!(open_mode & EFI_FILE_MODE_CREATE) ||
230                             efi_create_file(fh, attributes))
231                                 goto error;
232                         if (set_blk_dev(fh))
233                                 goto error;
234                 }
235
236                 /* figure out if file is a directory: */
237                 fh->isdir = is_dir(fh);
238         } else {
239                 fh->isdir = 1;
240                 strcpy(fh->path, "");
241         }
242
243         return &fh->base;
244
245 error:
246         free(fh);
247         return NULL;
248 }
249
250 efi_status_t efi_file_open_int(struct efi_file_handle *this,
251                                struct efi_file_handle **new_handle,
252                                u16 *file_name, u64 open_mode,
253                                u64 attributes)
254 {
255         struct file_handle *fh = to_fh(this);
256         efi_status_t ret;
257
258         /* Check parameters */
259         if (!this || !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 ret;
295 }
296
297 /**
298  * efi_file_open() - open file synchronously
299  *
300  * This function implements the Open service of the File Protocol.
301  * See the UEFI spec for details.
302  *
303  * @this:       EFI_FILE_PROTOCOL instance
304  * @new_handle: on return pointer to file handle
305  * @file_name:  file name
306  * @open_mode:  mode to open the file (read, read/write, create/read/write)
307  * @attributes: attributes for newly created file
308  */
309 static efi_status_t EFIAPI efi_file_open(struct efi_file_handle *this,
310                                          struct efi_file_handle **new_handle,
311                                          u16 *file_name, u64 open_mode,
312                                          u64 attributes)
313 {
314         efi_status_t ret;
315
316         EFI_ENTRY("%p, %p, \"%ls\", %llx, %llu", this, new_handle,
317                   file_name, open_mode, attributes);
318
319         ret = efi_file_open_int(this, new_handle, file_name, open_mode,
320                                 attributes);
321
322         return EFI_EXIT(ret);
323 }
324
325 /**
326  * efi_file_open_ex() - open file asynchronously
327  *
328  * This function implements the OpenEx service of the File Protocol.
329  * See the UEFI spec for details.
330  *
331  * @this:       EFI_FILE_PROTOCOL instance
332  * @new_handle: on return pointer to file handle
333  * @file_name:  file name
334  * @open_mode:  mode to open the file (read, read/write, create/read/write)
335  * @attributes: attributes for newly created file
336  * @token:      transaction token
337  */
338 static efi_status_t EFIAPI efi_file_open_ex(struct efi_file_handle *this,
339                                             struct efi_file_handle **new_handle,
340                                             u16 *file_name, u64 open_mode,
341                                             u64 attributes,
342                                             struct efi_file_io_token *token)
343 {
344         efi_status_t ret;
345
346         EFI_ENTRY("%p, %p, \"%ls\", %llx, %llu, %p", this, new_handle,
347                   file_name, open_mode, attributes, token);
348
349         if (!token) {
350                 ret = EFI_INVALID_PARAMETER;
351                 goto out;
352         }
353
354         ret = efi_file_open_int(this, new_handle, file_name, open_mode,
355                                 attributes);
356
357         if (ret == EFI_SUCCESS && token->event) {
358                 token->status = EFI_SUCCESS;
359                 efi_signal_event(token->event);
360         }
361
362 out:
363         return EFI_EXIT(ret);
364 }
365
366 static efi_status_t file_close(struct file_handle *fh)
367 {
368         fs_closedir(fh->dirs);
369         free(fh);
370         return EFI_SUCCESS;
371 }
372
373 efi_status_t efi_file_close_int(struct efi_file_handle *file)
374 {
375         struct file_handle *fh = to_fh(file);
376
377         return file_close(fh);
378 }
379
380 static efi_status_t EFIAPI efi_file_close(struct efi_file_handle *file)
381 {
382         EFI_ENTRY("%p", file);
383         return EFI_EXIT(efi_file_close_int(file));
384 }
385
386 static efi_status_t EFIAPI efi_file_delete(struct efi_file_handle *file)
387 {
388         struct file_handle *fh = to_fh(file);
389         efi_status_t ret = EFI_SUCCESS;
390
391         EFI_ENTRY("%p", file);
392
393         if (set_blk_dev(fh) || fs_unlink(fh->path))
394                 ret = EFI_WARN_DELETE_FAILURE;
395
396         file_close(fh);
397         return EFI_EXIT(ret);
398 }
399
400 /**
401  * efi_get_file_size() - determine the size of a file
402  *
403  * @fh:         file handle
404  * @file_size:  pointer to receive file size
405  * Return:      status code
406  */
407 static efi_status_t efi_get_file_size(struct file_handle *fh,
408                                       loff_t *file_size)
409 {
410         if (set_blk_dev(fh))
411                 return EFI_DEVICE_ERROR;
412
413         if (fs_size(fh->path, file_size))
414                 return EFI_DEVICE_ERROR;
415
416         return EFI_SUCCESS;
417 }
418
419 /**
420  * efi_file_size() - Get the size of a file using an EFI file handle
421  *
422  * @fh:         EFI file handle
423  * @size:       buffer to fill in the discovered size
424  *
425  * Return:      size of the file
426  */
427 efi_status_t efi_file_size(struct efi_file_handle *fh, efi_uintn_t *size)
428 {
429         struct efi_file_info *info = NULL;
430         efi_uintn_t bs = 0;
431         efi_status_t ret;
432
433         *size = 0;
434         ret = EFI_CALL(fh->getinfo(fh, (efi_guid_t *)&efi_file_info_guid, &bs,
435                                    info));
436         if (ret != EFI_BUFFER_TOO_SMALL) {
437                 ret = EFI_DEVICE_ERROR;
438                 goto out;
439         }
440
441         info = malloc(bs);
442         if (!info) {
443                 ret = EFI_OUT_OF_RESOURCES;
444                 goto out;
445         }
446         ret = EFI_CALL(fh->getinfo(fh, (efi_guid_t *)&efi_file_info_guid, &bs,
447                                    info));
448         if (ret != EFI_SUCCESS)
449                 goto out;
450
451         *size = info->file_size;
452
453 out:
454         free(info);
455         return ret;
456 }
457
458 static efi_status_t file_read(struct file_handle *fh, u64 *buffer_size,
459                 void *buffer)
460 {
461         loff_t actread;
462         efi_status_t ret;
463         loff_t file_size;
464
465         if (!buffer) {
466                 ret = EFI_INVALID_PARAMETER;
467                 return ret;
468         }
469
470         ret = efi_get_file_size(fh, &file_size);
471         if (ret != EFI_SUCCESS)
472                 return ret;
473         if (file_size < fh->offset) {
474                 ret = EFI_DEVICE_ERROR;
475                 return ret;
476         }
477
478         if (set_blk_dev(fh))
479                 return EFI_DEVICE_ERROR;
480         if (fs_read(fh->path, map_to_sysmem(buffer), fh->offset,
481                     *buffer_size, &actread))
482                 return EFI_DEVICE_ERROR;
483
484         *buffer_size = actread;
485         fh->offset += actread;
486
487         return EFI_SUCCESS;
488 }
489
490 static void rtc2efi(struct efi_time *time, struct rtc_time *tm)
491 {
492         memset(time, 0, sizeof(struct efi_time));
493         time->year = tm->tm_year;
494         time->month = tm->tm_mon;
495         time->day = tm->tm_mday;
496         time->hour = tm->tm_hour;
497         time->minute = tm->tm_min;
498         time->second = tm->tm_sec;
499 }
500
501 static efi_status_t dir_read(struct file_handle *fh, u64 *buffer_size,
502                 void *buffer)
503 {
504         struct efi_file_info *info = buffer;
505         struct fs_dirent *dent;
506         u64 required_size;
507         u16 *dst;
508
509         if (set_blk_dev(fh))
510                 return EFI_DEVICE_ERROR;
511
512         if (!fh->dirs) {
513                 assert(fh->offset == 0);
514                 fh->dirs = fs_opendir(fh->path);
515                 if (!fh->dirs)
516                         return EFI_DEVICE_ERROR;
517                 fh->dent = NULL;
518         }
519
520         /*
521          * So this is a bit awkward.  Since fs layer is stateful and we
522          * can't rewind an entry, in the EFI_BUFFER_TOO_SMALL case below
523          * we might have to return without consuming the dent.. so we
524          * have to stash it for next call.
525          */
526         if (fh->dent) {
527                 dent = fh->dent;
528         } else {
529                 dent = fs_readdir(fh->dirs);
530         }
531
532         if (!dent) {
533                 /* no more files in directory */
534                 *buffer_size = 0;
535                 return EFI_SUCCESS;
536         }
537
538         /* check buffer size: */
539         required_size = sizeof(*info) +
540                         2 * (utf8_utf16_strlen(dent->name) + 1);
541         if (*buffer_size < required_size) {
542                 *buffer_size = required_size;
543                 fh->dent = dent;
544                 return EFI_BUFFER_TOO_SMALL;
545         }
546         if (!buffer)
547                 return EFI_INVALID_PARAMETER;
548         fh->dent = NULL;
549
550         *buffer_size = required_size;
551         memset(info, 0, required_size);
552
553         info->size = required_size;
554         info->file_size = dent->size;
555         info->physical_size = dent->size;
556         info->attribute = dent->attr;
557         rtc2efi(&info->create_time, &dent->create_time);
558         rtc2efi(&info->modification_time, &dent->change_time);
559         rtc2efi(&info->last_access_time, &dent->access_time);
560
561         if (dent->type == FS_DT_DIR)
562                 info->attribute |= EFI_FILE_DIRECTORY;
563
564         dst = info->file_name;
565         utf8_utf16_strcpy(&dst, dent->name);
566
567         fh->offset++;
568
569         return EFI_SUCCESS;
570 }
571
572 efi_status_t efi_file_read_int(struct efi_file_handle *this,
573                                efi_uintn_t *buffer_size, void *buffer)
574 {
575         struct file_handle *fh = to_fh(this);
576         efi_status_t ret = EFI_SUCCESS;
577         u64 bs;
578
579         if (!this || !buffer_size)
580                 return EFI_INVALID_PARAMETER;
581
582         bs = *buffer_size;
583         if (fh->isdir)
584                 ret = dir_read(fh, &bs, buffer);
585         else
586                 ret = file_read(fh, &bs, buffer);
587         if (bs <= SIZE_MAX)
588                 *buffer_size = bs;
589         else
590                 *buffer_size = SIZE_MAX;
591
592         return ret;
593 }
594
595 /**
596  * efi_file_read() - read file
597  *
598  * This function implements the Read() service of the EFI_FILE_PROTOCOL.
599  *
600  * See the Unified Extensible Firmware Interface (UEFI) specification for
601  * details.
602  *
603  * @this:               file protocol instance
604  * @buffer_size:        number of bytes to read
605  * @buffer:             read buffer
606  * Return:              status code
607  */
608 static efi_status_t EFIAPI efi_file_read(struct efi_file_handle *this,
609                                          efi_uintn_t *buffer_size, void *buffer)
610 {
611         efi_status_t ret;
612
613         EFI_ENTRY("%p, %p, %p", this, buffer_size, buffer);
614
615         ret = efi_file_read_int(this, buffer_size, buffer);
616
617         return EFI_EXIT(ret);
618 }
619
620 /**
621  * efi_file_read_ex() - read file asynchonously
622  *
623  * This function implements the ReadEx() service of the EFI_FILE_PROTOCOL.
624  *
625  * See the Unified Extensible Firmware Interface (UEFI) specification for
626  * details.
627  *
628  * @this:               file protocol instance
629  * @token:              transaction token
630  * Return:              status code
631  */
632 static efi_status_t EFIAPI efi_file_read_ex(struct efi_file_handle *this,
633                                             struct efi_file_io_token *token)
634 {
635         efi_status_t ret;
636
637         EFI_ENTRY("%p, %p", this, token);
638
639         if (!token) {
640                 ret = EFI_INVALID_PARAMETER;
641                 goto out;
642         }
643
644         ret = efi_file_read_int(this, &token->buffer_size, token->buffer);
645
646         if (ret == EFI_SUCCESS && token->event) {
647                 token->status = EFI_SUCCESS;
648                 efi_signal_event(token->event);
649         }
650
651 out:
652         return EFI_EXIT(ret);
653 }
654
655 static efi_status_t efi_file_write_int(struct efi_file_handle *this,
656                                        efi_uintn_t *buffer_size, void *buffer)
657 {
658         struct file_handle *fh = to_fh(this);
659         efi_status_t ret = EFI_SUCCESS;
660         loff_t actwrite;
661
662         if (!this || !buffer_size || !buffer) {
663                 ret = EFI_INVALID_PARAMETER;
664                 goto out;
665         }
666         if (fh->isdir) {
667                 ret = EFI_UNSUPPORTED;
668                 goto out;
669         }
670         if (!(fh->open_mode & EFI_FILE_MODE_WRITE)) {
671                 ret = EFI_ACCESS_DENIED;
672                 goto out;
673         }
674
675         if (!*buffer_size)
676                 goto out;
677
678         if (set_blk_dev(fh)) {
679                 ret = EFI_DEVICE_ERROR;
680                 goto out;
681         }
682         if (fs_write(fh->path, map_to_sysmem(buffer), fh->offset, *buffer_size,
683                      &actwrite)) {
684                 ret = EFI_DEVICE_ERROR;
685                 goto out;
686         }
687         *buffer_size = actwrite;
688         fh->offset += actwrite;
689
690 out:
691         return ret;
692 }
693
694 /**
695  * efi_file_write() - write to file
696  *
697  * This function implements the Write() service of the EFI_FILE_PROTOCOL.
698  *
699  * See the Unified Extensible Firmware Interface (UEFI) specification for
700  * details.
701  *
702  * @this:               file protocol instance
703  * @buffer_size:        number of bytes to write
704  * @buffer:             buffer with the bytes to write
705  * Return:              status code
706  */
707 static efi_status_t EFIAPI efi_file_write(struct efi_file_handle *this,
708                                           efi_uintn_t *buffer_size,
709                                           void *buffer)
710 {
711         efi_status_t ret;
712
713         EFI_ENTRY("%p, %p, %p", this, buffer_size, buffer);
714
715         ret = efi_file_write_int(this, buffer_size, buffer);
716
717         return EFI_EXIT(ret);
718 }
719
720 /**
721  * efi_file_write_ex() - write to file
722  *
723  * This function implements the WriteEx() service of the EFI_FILE_PROTOCOL.
724  *
725  * See the Unified Extensible Firmware Interface (UEFI) specification for
726  * details.
727  *
728  * @this:               file protocol instance
729  * @token:              transaction token
730  * Return:              status code
731  */
732 static efi_status_t EFIAPI efi_file_write_ex(struct efi_file_handle *this,
733                                              struct efi_file_io_token *token)
734 {
735         efi_status_t ret;
736
737         EFI_ENTRY("%p, %p", this, token);
738
739         if (!token) {
740                 ret = EFI_INVALID_PARAMETER;
741                 goto out;
742         }
743
744         ret = efi_file_write_int(this, &token->buffer_size, token->buffer);
745
746         if (ret == EFI_SUCCESS && token->event) {
747                 token->status = EFI_SUCCESS;
748                 efi_signal_event(token->event);
749         }
750
751 out:
752         return EFI_EXIT(ret);
753 }
754
755 /**
756  * efi_file_getpos() - get current position in file
757  *
758  * This function implements the GetPosition service of the EFI file protocol.
759  * See the UEFI spec for details.
760  *
761  * @file:       file handle
762  * @pos:        pointer to file position
763  * Return:      status code
764  */
765 static efi_status_t EFIAPI efi_file_getpos(struct efi_file_handle *file,
766                                            u64 *pos)
767 {
768         efi_status_t ret = EFI_SUCCESS;
769         struct file_handle *fh = to_fh(file);
770
771         EFI_ENTRY("%p, %p", file, pos);
772
773         if (fh->isdir) {
774                 ret = EFI_UNSUPPORTED;
775                 goto out;
776         }
777
778         *pos = fh->offset;
779 out:
780         return EFI_EXIT(ret);
781 }
782
783 efi_status_t efi_file_setpos_int(struct efi_file_handle *file, u64 pos)
784 {
785         struct file_handle *fh = to_fh(file);
786         efi_status_t ret = EFI_SUCCESS;
787
788         if (fh->isdir) {
789                 if (pos != 0) {
790                         ret = EFI_UNSUPPORTED;
791                         goto error;
792                 }
793                 fs_closedir(fh->dirs);
794                 fh->dirs = NULL;
795         }
796
797         if (pos == ~0ULL) {
798                 loff_t file_size;
799
800                 ret = efi_get_file_size(fh, &file_size);
801                 if (ret != EFI_SUCCESS)
802                         goto error;
803                 pos = file_size;
804         }
805
806         fh->offset = pos;
807
808 error:
809         return ret;
810 }
811
812 /**
813  * efi_file_setpos() - set current position in file
814  *
815  * This function implements the SetPosition service of the EFI file protocol.
816  * See the UEFI spec for details.
817  *
818  * @file:       file handle
819  * @pos:        new file position
820  * Return:      status code
821  */
822 static efi_status_t EFIAPI efi_file_setpos(struct efi_file_handle *file,
823                                            u64 pos)
824 {
825         efi_status_t ret = EFI_SUCCESS;
826
827         EFI_ENTRY("%p, %llu", file, pos);
828
829         ret = efi_file_setpos_int(file, pos);
830
831         return EFI_EXIT(ret);
832 }
833
834 static efi_status_t EFIAPI efi_file_getinfo(struct efi_file_handle *file,
835                                             const efi_guid_t *info_type,
836                                             efi_uintn_t *buffer_size,
837                                             void *buffer)
838 {
839         struct file_handle *fh = to_fh(file);
840         efi_status_t ret = EFI_SUCCESS;
841         u16 *dst;
842
843         EFI_ENTRY("%p, %pUs, %p, %p", file, info_type, buffer_size, buffer);
844
845         if (!file || !info_type || !buffer_size ||
846             (*buffer_size && !buffer)) {
847                 ret = EFI_INVALID_PARAMETER;
848                 goto error;
849         }
850
851         if (!guidcmp(info_type, &efi_file_info_guid)) {
852                 struct efi_file_info *info = buffer;
853                 char *filename = basename(fh);
854                 unsigned int required_size;
855                 loff_t file_size;
856
857                 /* check buffer size: */
858                 required_size = sizeof(*info) +
859                                 2 * (utf8_utf16_strlen(filename) + 1);
860                 if (*buffer_size < required_size) {
861                         *buffer_size = required_size;
862                         ret = EFI_BUFFER_TOO_SMALL;
863                         goto error;
864                 }
865
866                 ret = efi_get_file_size(fh, &file_size);
867                 if (ret != EFI_SUCCESS)
868                         goto error;
869
870                 memset(info, 0, required_size);
871
872                 info->size = required_size;
873                 info->file_size = file_size;
874                 info->physical_size = file_size;
875
876                 if (fh->isdir)
877                         info->attribute |= EFI_FILE_DIRECTORY;
878
879                 dst = info->file_name;
880                 utf8_utf16_strcpy(&dst, filename);
881         } else if (!guidcmp(info_type, &efi_file_system_info_guid)) {
882                 struct efi_file_system_info *info = buffer;
883                 struct disk_partition part;
884                 efi_uintn_t required_size;
885                 int r;
886
887                 if (fh->fs->part >= 1)
888                         r = part_get_info(fh->fs->desc, fh->fs->part, &part);
889                 else
890                         r = part_get_info_whole_disk(fh->fs->desc, &part);
891                 if (r < 0) {
892                         ret = EFI_DEVICE_ERROR;
893                         goto error;
894                 }
895                 required_size = sizeof(*info) + 2;
896                 if (*buffer_size < required_size) {
897                         *buffer_size = required_size;
898                         ret = EFI_BUFFER_TOO_SMALL;
899                         goto error;
900                 }
901
902                 memset(info, 0, required_size);
903
904                 info->size = required_size;
905                 /*
906                  * TODO: We cannot determine if the volume can be written to.
907                  */
908                 info->read_only = false;
909                 info->volume_size = part.size * part.blksz;
910                 /*
911                  * TODO: We currently have no function to determine the free
912                  * space. The volume size is the best upper bound we have.
913                  */
914                 info->free_space = info->volume_size;
915                 info->block_size = part.blksz;
916                 /*
917                  * TODO: The volume label is not available in U-Boot.
918                  */
919                 info->volume_label[0] = 0;
920         } else if (!guidcmp(info_type, &efi_system_volume_label_id)) {
921                 if (*buffer_size < 2) {
922                         *buffer_size = 2;
923                         ret = EFI_BUFFER_TOO_SMALL;
924                         goto error;
925                 }
926                 *(u16 *)buffer = 0;
927         } else {
928                 ret = EFI_UNSUPPORTED;
929         }
930
931 error:
932         return EFI_EXIT(ret);
933 }
934
935 static efi_status_t EFIAPI efi_file_setinfo(struct efi_file_handle *file,
936                                             const efi_guid_t *info_type,
937                                             efi_uintn_t buffer_size,
938                                             void *buffer)
939 {
940         struct file_handle *fh = to_fh(file);
941         efi_status_t ret = EFI_UNSUPPORTED;
942
943         EFI_ENTRY("%p, %pUs, %zu, %p", file, info_type, buffer_size, buffer);
944
945         if (!guidcmp(info_type, &efi_file_info_guid)) {
946                 struct efi_file_info *info = (struct efi_file_info *)buffer;
947                 char *filename = basename(fh);
948                 char *new_file_name, *pos;
949                 loff_t file_size;
950
951                 /* The buffer will always contain a file name. */
952                 if (buffer_size < sizeof(struct efi_file_info) + 2 ||
953                     buffer_size < info->size) {
954                         ret = EFI_BAD_BUFFER_SIZE;
955                         goto out;
956                 }
957                 /* We cannot change the directory attribute */
958                 if (!fh->isdir != !(info->attribute & EFI_FILE_DIRECTORY)) {
959                         ret = EFI_ACCESS_DENIED;
960                         goto out;
961                 }
962                 /* Check for renaming */
963                 new_file_name = malloc(utf16_utf8_strlen(info->file_name) + 1);
964                 if (!new_file_name) {
965                         ret = EFI_OUT_OF_RESOURCES;
966                         goto out;
967                 }
968                 pos = new_file_name;
969                 utf16_utf8_strcpy(&pos, info->file_name);
970                 if (strcmp(new_file_name, filename)) {
971                         /* TODO: we do not support renaming */
972                         EFI_PRINT("Renaming not supported\n");
973                         free(new_file_name);
974                         ret = EFI_ACCESS_DENIED;
975                         goto out;
976                 }
977                 free(new_file_name);
978                 /* Check for truncation */
979                 ret = efi_get_file_size(fh, &file_size);
980                 if (ret != EFI_SUCCESS)
981                         goto out;
982                 if (file_size != info->file_size) {
983                         /* TODO: we do not support truncation */
984                         EFI_PRINT("Truncation not supported\n");
985                         ret = EFI_ACCESS_DENIED;
986                         goto out;
987                 }
988                 /*
989                  * We do not care for the other attributes
990                  * TODO: Support read only
991                  */
992                 ret = EFI_SUCCESS;
993         } else {
994                 /* TODO: We do not support changing the volume label */
995                 ret = EFI_UNSUPPORTED;
996         }
997 out:
998         return EFI_EXIT(ret);
999 }
1000
1001 /**
1002  * efi_file_flush_int() - flush file
1003  *
1004  * This is the internal implementation of the Flush() and FlushEx() services of
1005  * the EFI_FILE_PROTOCOL.
1006  *
1007  * @this:       file protocol instance
1008  * Return:      status code
1009  */
1010 static efi_status_t efi_file_flush_int(struct efi_file_handle *this)
1011 {
1012         struct file_handle *fh = to_fh(this);
1013
1014         if (!this)
1015                 return EFI_INVALID_PARAMETER;
1016
1017         if (!(fh->open_mode & EFI_FILE_MODE_WRITE))
1018                 return EFI_ACCESS_DENIED;
1019
1020         /* TODO: flush for file position after end of file */
1021         return EFI_SUCCESS;
1022 }
1023
1024 /**
1025  * efi_file_flush() - flush file
1026  *
1027  * This function implements the Flush() service of the EFI_FILE_PROTOCOL.
1028  *
1029  * See the Unified Extensible Firmware Interface (UEFI) specification for
1030  * details.
1031  *
1032  * @this:       file protocol instance
1033  * Return:      status code
1034  */
1035 static efi_status_t EFIAPI efi_file_flush(struct efi_file_handle *this)
1036 {
1037         efi_status_t ret;
1038
1039         EFI_ENTRY("%p", this);
1040
1041         ret = efi_file_flush_int(this);
1042
1043         return EFI_EXIT(ret);
1044 }
1045
1046 /**
1047  * efi_file_flush_ex() - flush file
1048  *
1049  * This function implements the FlushEx() service of the EFI_FILE_PROTOCOL.
1050  *
1051  * See the Unified Extensible Firmware Interface (UEFI) specification for
1052  * details.
1053  *
1054  * @this:       file protocol instance
1055  * @token:      transaction token
1056  * Return:      status code
1057  */
1058 static efi_status_t EFIAPI efi_file_flush_ex(struct efi_file_handle *this,
1059                                              struct efi_file_io_token *token)
1060 {
1061         efi_status_t ret;
1062
1063         EFI_ENTRY("%p, %p", this, token);
1064
1065         if (!token) {
1066                 ret = EFI_INVALID_PARAMETER;
1067                 goto out;
1068         }
1069
1070         ret = efi_file_flush_int(this);
1071
1072         if (ret == EFI_SUCCESS && token->event) {
1073                 token->status = EFI_SUCCESS;
1074                 efi_signal_event(token->event);
1075         }
1076
1077 out:
1078         return EFI_EXIT(ret);
1079 }
1080
1081 static const struct efi_file_handle efi_file_handle_protocol = {
1082         .rev = EFI_FILE_PROTOCOL_REVISION2,
1083         .open = efi_file_open,
1084         .close = efi_file_close,
1085         .delete = efi_file_delete,
1086         .read = efi_file_read,
1087         .write = efi_file_write,
1088         .getpos = efi_file_getpos,
1089         .setpos = efi_file_setpos,
1090         .getinfo = efi_file_getinfo,
1091         .setinfo = efi_file_setinfo,
1092         .flush = efi_file_flush,
1093         .open_ex = efi_file_open_ex,
1094         .read_ex = efi_file_read_ex,
1095         .write_ex = efi_file_write_ex,
1096         .flush_ex = efi_file_flush_ex,
1097 };
1098
1099 /**
1100  * efi_file_from_path() - open file via device path
1101  *
1102  * The device path @fp consists of the device path of the handle with the
1103  * simple file system protocol and one or more file path device path nodes.
1104  * The concatenation of all file path names provides the total file path.
1105  *
1106  * The code starts at the first file path node and tries to open that file or
1107  * directory. If there is a succeding file path node, the code opens it relative
1108  * to this directory and continues iterating until reaching the last file path
1109  * node.
1110  *
1111  * @fp:         device path
1112  * Return:      EFI_FILE_PROTOCOL for the file or NULL
1113  */
1114 struct efi_file_handle *efi_file_from_path(struct efi_device_path *fp)
1115 {
1116         struct efi_simple_file_system_protocol *v;
1117         struct efi_file_handle *f;
1118         efi_status_t ret;
1119
1120         v = efi_fs_from_path(fp);
1121         if (!v)
1122                 return NULL;
1123
1124         EFI_CALL(ret = v->open_volume(v, &f));
1125         if (ret != EFI_SUCCESS)
1126                 return NULL;
1127
1128         /* Skip over device-path nodes before the file path. */
1129         while (fp && !EFI_DP_TYPE(fp, MEDIA_DEVICE, FILE_PATH))
1130                 fp = efi_dp_next(fp);
1131
1132         /*
1133          * Step through the nodes of the directory path until the actual file
1134          * node is reached which is the final node in the device path.
1135          */
1136         while (fp) {
1137                 struct efi_device_path_file_path *fdp =
1138                         container_of(fp, struct efi_device_path_file_path, dp);
1139                 struct efi_file_handle *f2;
1140                 u16 *filename;
1141                 size_t filename_sz;
1142
1143                 if (!EFI_DP_TYPE(fp, MEDIA_DEVICE, FILE_PATH)) {
1144                         printf("bad file path!\n");
1145                         EFI_CALL(f->close(f));
1146                         return NULL;
1147                 }
1148
1149                 /*
1150                  * UEFI specification requires pointers that are passed to
1151                  * protocol member functions to be aligned.  So memcpy it
1152                  * unconditionally
1153                  */
1154                 if (fdp->dp.length <= offsetof(struct efi_device_path_file_path, str))
1155                         return NULL;
1156                 filename_sz = fdp->dp.length -
1157                         offsetof(struct efi_device_path_file_path, str);
1158                 filename = malloc(filename_sz);
1159                 if (!filename)
1160                         return NULL;
1161                 memcpy(filename, fdp->str, filename_sz);
1162                 EFI_CALL(ret = f->open(f, &f2, filename,
1163                                        EFI_FILE_MODE_READ, 0));
1164                 free(filename);
1165                 if (ret != EFI_SUCCESS)
1166                         return NULL;
1167
1168                 fp = efi_dp_next(fp);
1169
1170                 EFI_CALL(f->close(f));
1171                 f = f2;
1172         }
1173
1174         return f;
1175 }
1176
1177 efi_status_t efi_open_volume_int(struct efi_simple_file_system_protocol *this,
1178                                  struct efi_file_handle **root)
1179 {
1180         struct file_system *fs = to_fs(this);
1181
1182         *root = file_open(fs, NULL, NULL, 0, 0);
1183
1184         return EFI_SUCCESS;
1185 }
1186
1187 static efi_status_t EFIAPI
1188 efi_open_volume(struct efi_simple_file_system_protocol *this,
1189                 struct efi_file_handle **root)
1190 {
1191         EFI_ENTRY("%p, %p", this, root);
1192
1193         return EFI_EXIT(efi_open_volume_int(this, root));
1194 }
1195
1196 efi_status_t
1197 efi_create_simple_file_system(struct blk_desc *desc, int part,
1198                               struct efi_device_path *dp,
1199                               struct efi_simple_file_system_protocol **fsp)
1200 {
1201         struct file_system *fs;
1202
1203         fs = calloc(1, sizeof(*fs));
1204         if (!fs)
1205                 return EFI_OUT_OF_RESOURCES;
1206         fs->base.rev = EFI_SIMPLE_FILE_SYSTEM_PROTOCOL_REVISION;
1207         fs->base.open_volume = efi_open_volume;
1208         fs->desc = desc;
1209         fs->part = part;
1210         fs->dp = dp;
1211         *fsp = &fs->base;
1212
1213         return EFI_SUCCESS;
1214 }