1 /**
2  * @file lv_fs_uefi.c
3  *
4  */
5 
6 /*********************
7  *      INCLUDES
8  *********************/
9 #include "../../../lvgl.h"
10 
11 #if LV_USE_FS_UEFI && LV_USE_UEFI
12 
13 #include "../../drivers/uefi/lv_uefi_private.h"
14 
15 #include "../../core/lv_global.h"
16 
17 /*********************
18  *      DEFINES
19  *********************/
20 #if LV_FS_UEFI_LETTER == '\0'
21     #error "LV_FS_UEFI_LETTER must be set to a valid value"
22 #else
23     #if (LV_FS_UEFI_LETTER < 'A') || (LV_FS_UEFI_LETTER > 'Z')
24         #if LV_FS_DEFAULT_DRIVE_LETTER != '\0' /*When using default drive letter, strict format (X:) is mandatory*/
25             #error "LV_FS_UEFI_LETTER must be an upper case ASCII letter"
26         #else /*Lean rules for backward compatibility*/
27             #warning LV_FS_UEFI_LETTER should be an upper case ASCII letter. \
28             Using a slash symbol as drive letter should be replaced with LV_FS_DEFAULT_DRIVE_LETTER mechanism
29         #endif
30     #endif
31 #endif
32 
33 /**********************
34  *      TYPEDEFS
35  **********************/
36 
37 typedef struct _lv_uefi_fs_file_context_t {
38     EFI_FILE_PROTOCOL * interface;
39 } lv_uefi_fs_file_context_t;
40 
41 /**********************
42  *  STATIC PROTOTYPES
43  **********************/
44 
45 static void lv_fs_drv_uefi_init(lv_fs_drv_t * drv, char fs_drive_letter, EFI_HANDLE fs_handle);
46 static void lv_fs_drv_uefi_deinit(lv_fs_drv_t * drv);
47 
48 static void lv_fs_uefi_lvgl_path_to_uefi_path(CHAR16 * path);
49 static void lv_fs_uefi_uefi_path_to_lvgl_path(CHAR16 * path);
50 static bool lv_fs_uefi_is_dot_path(CONST CHAR16 * path);
51 static bool lv_fs_uefi_is_dir(EFI_FILE_PROTOCOL * dir);
52 static bool lv_fs_uefi_is_file(EFI_FILE_PROTOCOL * file);
53 static EFI_FILE_INFO * lv_fs_uefi_get_info(EFI_FILE_PROTOCOL * file);
54 
55 static bool lv_fs_uefi_ready_cb(lv_fs_drv_t * drv);
56 
57 static void * lv_fs_uefi_open_cb(lv_fs_drv_t * drv, const char * path, lv_fs_mode_t mode);
58 static lv_fs_res_t lv_fs_uefi_close_cb(lv_fs_drv_t * drv, void * file_p);
59 static lv_fs_res_t lv_fs_uefi_read_cb(lv_fs_drv_t * drv, void * file_p, void * buf, uint32_t btr, uint32_t * br);
60 static lv_fs_res_t lv_fs_uefi_write_cb(lv_fs_drv_t * drv, void * file_p, const void * buf, uint32_t btw, uint32_t * bw);
61 static lv_fs_res_t lv_fs_uefi_seek_cb(lv_fs_drv_t * drv, void * file_p, uint32_t pos, lv_fs_whence_t whence);
62 static lv_fs_res_t lv_fs_uefi_tell_cb(lv_fs_drv_t * drv, void * file_p, uint32_t * pos_p);
63 
64 static void * lv_fs_uefi_dir_open_cb(lv_fs_drv_t * drv, const char * path);
65 static lv_fs_res_t lv_fs_uefi_dir_read_cb(lv_fs_drv_t * drv, void * rddir_p, char * fn, uint32_t fn_len);
66 static lv_fs_res_t lv_fs_uefi_dir_close_cb(lv_fs_drv_t * drv, void * rddir_p);
67 
68 /**********************
69  *  STATIC VARIABLES
70  **********************/
71 
72 static EFI_GUID _uefi_guid_simple_file_system = EFI_SIMPLE_FILE_SYSTEM_PROTOCOL_GUID;
73 static EFI_GUID _uefi_guid_loaded_image = EFI_LOADED_IMAGE_PROTOCOL_GUID;
74 static EFI_GUID _uefi_guid_file_info = EFI_FILE_INFO_ID;
75 
76 /**********************
77  *      MACROS
78  **********************/
79 
80 /**********************
81  *   GLOBAL FUNCTIONS
82  **********************/
83 
84 /**
85  * Register a driver for the File system interface
86  */
lv_fs_uefi_init(void)87 void lv_fs_uefi_init(void)
88 {
89     EFI_LOADED_IMAGE_PROTOCOL * interface_loaded_image = NULL;
90     EFI_HANDLE fs_handle = NULL;
91 
92     /*---------------------------------------------------
93      * Register the file system interface in LVGL
94      *--------------------------------------------------*/
95 
96     interface_loaded_image = lv_uefi_protocol_open(gLvEfiImageHandle, &_uefi_guid_loaded_image);
97     LV_ASSERT_NULL(interface_loaded_image);
98 
99     fs_handle = interface_loaded_image->DeviceHandle;
100 
101     if(fs_handle == NULL) return;
102 
103     lv_uefi_protocol_close(gLvEfiImageHandle, &_uefi_guid_loaded_image);
104 
105     /*Add a simple driver to open images*/
106     lv_fs_drv_t * fs_drv_p = &(LV_GLOBAL_DEFAULT()->uefi_fs_drv);
107     lv_fs_drv_uefi_init(fs_drv_p, LV_FS_UEFI_LETTER, fs_handle);
108 
109     lv_fs_drv_register(fs_drv_p);
110 }
111 
112 /**********************
113  *   STATIC FUNCTIONS
114  **********************/
115 
lv_fs_uefi_ready_cb(lv_fs_drv_t * drv)116 static bool lv_fs_uefi_ready_cb(lv_fs_drv_t * drv)
117 {
118     EFI_HANDLE fs_handle = (EFI_HANDLE)drv->user_data;
119 
120     return fs_handle != NULL;
121 }
122 
lv_fs_uefi_open_cb(lv_fs_drv_t * drv,const char * path,lv_fs_mode_t mode)123 static void * lv_fs_uefi_open_cb(lv_fs_drv_t * drv, const char * path, lv_fs_mode_t mode)
124 {
125     EFI_STATUS status;
126     EFI_FILE_PROTOCOL * fs_root = NULL;
127     EFI_SIMPLE_FILE_SYSTEM_PROTOCOL * fs_interface = NULL;
128     CHAR16 path_ucs2[LV_FS_MAX_PATH_LENGTH + 1];
129     lv_uefi_fs_file_context_t * file_ctx = NULL;
130     UINT64 uefi_mode = 0;
131 
132     EFI_HANDLE fs_handle = (EFI_HANDLE)drv->user_data;
133 
134     fs_interface = lv_uefi_protocol_open(fs_handle, &_uefi_guid_simple_file_system);
135     if(fs_interface == NULL) {
136         LV_LOG_WARN("[lv_uefi] Unable to open file system protocol.");
137         goto error;
138     }
139 
140     status = fs_interface->OpenVolume(fs_interface, &fs_root);
141     if(status != EFI_SUCCESS) {
142         LV_LOG_WARN("[lv_uefi] Unable to open file system root.");
143         goto error;
144     }
145 
146     if(lv_uefi_ascii_to_ucs2(path, path_ucs2, LV_FS_MAX_PATH_LENGTH + 1) == 0) {
147         LV_LOG_WARN("[lv_uefi] Unable to convert the ASCII path into an UCS-2 path.");
148         goto error;
149     }
150 
151     lv_fs_uefi_lvgl_path_to_uefi_path(path_ucs2);
152 
153     file_ctx = lv_calloc(1, sizeof(lv_uefi_fs_file_context_t));
154     LV_ASSERT_MALLOC(file_ctx);
155 
156     if(mode == LV_FS_MODE_WR) {
157         uefi_mode = EFI_FILE_MODE_CREATE | EFI_FILE_MODE_READ | EFI_FILE_MODE_WRITE;
158     }
159     else {
160         uefi_mode = EFI_FILE_MODE_READ;
161     }
162 
163     status = fs_root->Open(
164                  fs_root,
165                  &file_ctx->interface,
166                  path_ucs2,
167                  uefi_mode,
168                  0);
169     if(status != EFI_SUCCESS) {
170         LV_LOG_WARN("[lv_uefi] Unable to open file '%s'.", path);
171         goto error;
172     }
173 
174     if(!lv_fs_uefi_is_file(file_ctx->interface)) {
175         goto error;
176     }
177 
178     goto finish;
179 
180 error:
181     if(file_ctx != NULL) {
182         if(file_ctx->interface != NULL) file_ctx->interface->Close(file_ctx->interface);
183         lv_free(file_ctx);
184         file_ctx = NULL;
185     }
186 
187 finish:
188     if(fs_interface != NULL) lv_uefi_protocol_close(fs_handle, &_uefi_guid_simple_file_system);
189     if(fs_root != NULL) fs_root->Close(fs_root);
190 
191     return file_ctx;
192 }
193 
lv_fs_uefi_close_cb(lv_fs_drv_t * drv,void * file_p)194 static lv_fs_res_t lv_fs_uefi_close_cb(lv_fs_drv_t * drv, void * file_p)
195 {
196     EFI_STATUS status;
197     lv_uefi_fs_file_context_t * file_ctx = (lv_uefi_fs_file_context_t *)file_p;
198 
199     if(file_ctx == NULL || file_ctx->interface == NULL) return LV_FS_RES_INV_PARAM;
200 
201     status = file_ctx->interface->Close(file_ctx->interface);
202     if(status != EFI_SUCCESS) return LV_FS_RES_HW_ERR;
203 
204     lv_free(file_ctx);
205 
206     return LV_FS_RES_OK;
207 }
208 
lv_fs_uefi_read_cb(lv_fs_drv_t * drv,void * file_p,void * buf,uint32_t btr,uint32_t * br)209 static lv_fs_res_t lv_fs_uefi_read_cb(lv_fs_drv_t * drv, void * file_p, void * buf, uint32_t btr, uint32_t * br)
210 {
211     EFI_STATUS status;
212     lv_uefi_fs_file_context_t * file_ctx = (lv_uefi_fs_file_context_t *)file_p;
213     UINTN buf_size = btr;
214 
215     if(file_ctx == NULL || file_ctx->interface == NULL) return LV_FS_RES_INV_PARAM;
216 
217     status = file_ctx->interface->Read(
218                      file_ctx->interface,
219                      &buf_size,
220                      buf);
221     if(status != EFI_SUCCESS) return LV_FS_RES_HW_ERR;
222 
223     *br = (uint32_t) buf_size;
224 
225     return LV_FS_RES_OK;
226 }
227 
lv_fs_uefi_write_cb(lv_fs_drv_t * drv,void * file_p,const void * buf,uint32_t btw,uint32_t * bw)228 static lv_fs_res_t lv_fs_uefi_write_cb(lv_fs_drv_t * drv, void * file_p, const void * buf, uint32_t btw, uint32_t * bw)
229 {
230     EFI_STATUS status;
231     lv_uefi_fs_file_context_t * file_ctx = (lv_uefi_fs_file_context_t *)file_p;
232     UINTN buf_size = btw;
233 
234     if(file_ctx == NULL || file_ctx->interface == NULL) return LV_FS_RES_INV_PARAM;
235 
236     status = file_ctx->interface->Write(
237                      file_ctx->interface,
238                      &buf_size,
239                      (VOID *)buf);
240     if(status != EFI_SUCCESS) return LV_FS_RES_HW_ERR;
241 
242     file_ctx->interface->Flush(file_ctx->interface);
243 
244     *bw = (uint32_t) buf_size;
245 
246     return LV_FS_RES_OK;
247 }
248 
lv_fs_uefi_seek_cb(lv_fs_drv_t * drv,void * file_p,uint32_t pos,lv_fs_whence_t whence)249 static lv_fs_res_t lv_fs_uefi_seek_cb(lv_fs_drv_t * drv, void * file_p, uint32_t pos, lv_fs_whence_t whence)
250 {
251     EFI_STATUS status;
252     lv_uefi_fs_file_context_t * file_ctx = (lv_uefi_fs_file_context_t *)file_p;
253     UINT64 new_pos;
254 
255     if(file_ctx == NULL || file_ctx->interface == NULL) return LV_FS_RES_INV_PARAM;
256 
257     if(whence == LV_FS_SEEK_END) {
258         status = file_ctx->interface->SetPosition(
259                          file_ctx->interface,
260                          UINT64_MAX);
261         if(status != EFI_SUCCESS) return LV_FS_RES_HW_ERR;
262 
263         status = file_ctx->interface->GetPosition(
264                          file_ctx->interface,
265                          &new_pos);
266         if(status != EFI_SUCCESS) return LV_FS_RES_HW_ERR;
267 
268         if(new_pos < pos) {
269             new_pos = 0;
270         }
271         else {
272             new_pos -= pos;
273         }
274     }
275     else if(whence == LV_FS_SEEK_SET) {
276         new_pos = pos;
277     }
278     else if(whence == LV_FS_SEEK_CUR) {
279         status = file_ctx->interface->GetPosition(
280                          file_ctx->interface,
281                          &new_pos);
282         if(status != EFI_SUCCESS) return LV_FS_RES_HW_ERR;
283 
284         new_pos += pos;
285     }
286     else {
287         return LV_FS_RES_INV_PARAM;
288     }
289 
290     status = file_ctx->interface->SetPosition(
291                      file_ctx->interface,
292                      new_pos);
293     if(status != EFI_SUCCESS) return LV_FS_RES_HW_ERR;
294 
295     return LV_FS_RES_OK;
296 }
297 
lv_fs_uefi_tell_cb(lv_fs_drv_t * drv,void * file_p,uint32_t * pos_p)298 static lv_fs_res_t lv_fs_uefi_tell_cb(lv_fs_drv_t * drv, void * file_p, uint32_t * pos_p)
299 {
300     EFI_STATUS status;
301     lv_uefi_fs_file_context_t * file_ctx = (lv_uefi_fs_file_context_t *)file_p;
302     UINT64 pos;
303 
304     if(file_ctx == NULL || file_ctx->interface == NULL) return LV_FS_RES_INV_PARAM;
305 
306     status = file_ctx->interface->GetPosition(
307                      file_ctx->interface,
308                      &pos);
309     if(status != EFI_SUCCESS) return LV_FS_RES_HW_ERR;
310 
311     if(pos > UINT32_MAX) return LV_FS_RES_UNKNOWN;
312 
313     *pos_p = (uint32_t) pos;
314 
315     return LV_FS_RES_OK;
316 }
317 
lv_fs_uefi_dir_open_cb(lv_fs_drv_t * drv,const char * path)318 static void * lv_fs_uefi_dir_open_cb(lv_fs_drv_t * drv, const char * path)
319 {
320     EFI_STATUS status;
321     EFI_FILE_PROTOCOL * fs_root = NULL;
322     EFI_SIMPLE_FILE_SYSTEM_PROTOCOL * fs_interface = NULL;
323     CHAR16 path_ucs2[LV_FS_MAX_PATH_LENGTH + 1];
324     lv_uefi_fs_file_context_t * file_ctx = NULL;
325     UINT64 mode = 0;
326     UINT64 attributes = 0;
327 
328     EFI_HANDLE fs_handle = (EFI_HANDLE)drv->user_data;
329 
330     fs_interface = lv_uefi_protocol_open(fs_handle, &_uefi_guid_simple_file_system);
331     if(fs_interface == NULL) {
332         LV_LOG_WARN("[lv_uefi] Unable to open file system protocol.");
333         goto error;
334     }
335 
336     status = fs_interface->OpenVolume(fs_interface, &fs_root);
337     if(status != EFI_SUCCESS) {
338         LV_LOG_WARN("[lv_uefi] Unable to open file system root.");
339         goto error;
340     }
341 
342     if(path != NULL && path[0] != '\0') {
343         if(lv_uefi_ascii_to_ucs2(path, path_ucs2, LV_FS_MAX_PATH_LENGTH + 1) == 0) {
344             LV_LOG_WARN("[lv_uefi] Unable to convert the ASCII path into an UCS-2 path.");
345             goto error;
346         }
347     }
348     else {
349         path_ucs2[0] = '\\';
350         path_ucs2[1] = '\0';
351     }
352 
353     lv_fs_uefi_lvgl_path_to_uefi_path(path_ucs2);
354 
355     file_ctx = lv_calloc(1, sizeof(lv_uefi_fs_file_context_t));
356     LV_ASSERT_MALLOC(file_ctx);
357 
358     mode = EFI_FILE_MODE_CREATE | EFI_FILE_MODE_READ | EFI_FILE_MODE_WRITE;
359     attributes = EFI_FILE_DIRECTORY;
360 
361     status = fs_root->Open(
362                  fs_root,
363                  &file_ctx->interface,
364                  path_ucs2,
365                  mode,
366                  attributes);
367     if(status != EFI_SUCCESS) {
368         LV_LOG_WARN("[lv_uefi] Unable to open directory '%s'.", path);
369         goto error;
370     }
371 
372     if(!lv_fs_uefi_is_dir(file_ctx->interface)) {
373         goto error;
374     }
375 
376     goto finish;
377 
378 error:
379     if(file_ctx != NULL) {
380         if(file_ctx->interface != NULL) {
381             file_ctx->interface->Close(file_ctx->interface);
382         }
383         lv_free(file_ctx);
384         file_ctx = NULL;
385     }
386 
387 finish:
388     if(fs_interface != NULL) lv_uefi_protocol_close(fs_handle, &_uefi_guid_simple_file_system);
389     if(fs_root != NULL) fs_root->Close(fs_root);
390 
391     return file_ctx;
392 }
393 
lv_fs_uefi_dir_read_cb(lv_fs_drv_t * drv,void * rddir_p,char * fn,uint32_t fn_len)394 static lv_fs_res_t lv_fs_uefi_dir_read_cb(lv_fs_drv_t * drv, void * rddir_p, char * fn, uint32_t fn_len)
395 {
396     lv_fs_res_t return_code;
397     EFI_STATUS status;
398     lv_uefi_fs_file_context_t * file_ctx = (lv_uefi_fs_file_context_t *)rddir_p;
399 
400     EFI_FILE_INFO * info = NULL;
401     UINTN size;
402 
403     CONST CHAR16 * fn_ucs2;
404 
405     if(fn == NULL || fn_len == 0) return LV_FS_RES_INV_PARAM;
406     if(file_ctx == NULL || file_ctx->interface == NULL) return LV_FS_RES_INV_PARAM;
407 
408     // skip . and ..
409     do {
410         if(info != NULL) lv_free(info);
411         info = NULL;
412         size = 0;
413         status = file_ctx->interface->Read(
414                          file_ctx->interface,
415                          &size,
416                          info);
417         if(status == EFI_SUCCESS && size == 0) {
418             return_code = LV_FS_RES_OK;
419             *fn = '\0';
420             goto finish;
421         }
422         else if(status != EFI_BUFFER_TOO_SMALL) {
423             return_code = LV_FS_RES_NOT_EX;
424             goto error;
425         }
426 
427         info = lv_calloc(1, size);
428         LV_ASSERT_MALLOC(info);
429 
430         status = file_ctx->interface->Read(
431                          file_ctx->interface,
432                          &size,
433                          info);
434         if(status != EFI_SUCCESS) {
435             return_code = LV_FS_RES_HW_ERR;
436             goto error;
437         }
438     } while(lv_fs_uefi_is_dot_path(info->FileName));
439 
440     lv_fs_uefi_uefi_path_to_lvgl_path(info->FileName);
441 
442     // skip leading \ and /
443     for(fn_ucs2 = info->FileName; *fn_ucs2 != L'\0'; fn_ucs2++) {
444         if(*fn_ucs2 != L'\\' && *fn_ucs2 != L'/') {
445             break;
446         }
447     }
448 
449     if((info->Attribute & EFI_FILE_DIRECTORY) != 0) {
450         if(fn_len == 0) {
451             return_code = LV_FS_RES_UNKNOWN;
452             goto error;
453         }
454         fn[0] = '/';
455         fn++;
456         fn_len--;
457     }
458 
459     if(lv_uefi_ucs2_to_ascii(fn_ucs2, fn, fn_len) == 0) {
460         LV_LOG_WARN("[lv_uefi] Unable to convert the UCS-2 path into an ascii path.");
461         return_code = LV_FS_RES_UNKNOWN;
462         goto error;
463     }
464 
465     return_code = LV_FS_RES_OK;
466     goto finish;
467 
468 error:
469 
470 finish:
471     if(info) lv_free(info);
472 
473     return return_code;
474 }
475 
lv_fs_uefi_dir_close_cb(lv_fs_drv_t * drv,void * rddir_p)476 static lv_fs_res_t lv_fs_uefi_dir_close_cb(lv_fs_drv_t * drv, void * rddir_p)
477 {
478     EFI_STATUS status;
479     lv_uefi_fs_file_context_t * file_ctx = (lv_uefi_fs_file_context_t *)rddir_p;
480 
481     if(file_ctx == NULL || file_ctx->interface == NULL) return LV_FS_RES_INV_PARAM;
482 
483     status = file_ctx->interface->Close(file_ctx->interface);
484     if(status != EFI_SUCCESS) return LV_FS_RES_HW_ERR;
485 
486     lv_free(file_ctx);
487 
488     return LV_FS_RES_OK;
489 }
490 
lv_fs_drv_uefi_init(lv_fs_drv_t * drv,char fs_drive_letter,EFI_HANDLE fs_handle)491 static void lv_fs_drv_uefi_init(lv_fs_drv_t * drv, char fs_drive_letter, EFI_HANDLE fs_handle)
492 {
493     LV_ASSERT_NULL(drv);
494     LV_ASSERT_NULL(fs_handle);
495 
496     lv_fs_drv_init(drv);
497 
498     drv->letter = fs_drive_letter;
499     drv->cache_size = 0;
500 
501     drv->ready_cb = lv_fs_uefi_ready_cb;
502     drv->open_cb = lv_fs_uefi_open_cb;
503     drv->close_cb = lv_fs_uefi_close_cb;
504     drv->read_cb = lv_fs_uefi_read_cb;
505     drv->write_cb = lv_fs_uefi_write_cb;
506     drv->seek_cb = lv_fs_uefi_seek_cb;
507     drv->tell_cb = lv_fs_uefi_tell_cb;
508 
509     drv->dir_open_cb = lv_fs_uefi_dir_open_cb;
510     drv->dir_read_cb = lv_fs_uefi_dir_read_cb;
511     drv->dir_close_cb = lv_fs_uefi_dir_close_cb;
512 
513     drv->user_data = (void *) fs_handle;
514 }
515 
lv_fs_drv_uefi_deinit(lv_fs_drv_t * drv)516 static void lv_fs_drv_uefi_deinit(lv_fs_drv_t * drv)
517 {
518     LV_ASSERT_NULL(drv);
519     drv->user_data = NULL;
520 }
521 
lv_fs_uefi_lvgl_path_to_uefi_path(CHAR16 * path)522 static void lv_fs_uefi_lvgl_path_to_uefi_path(CHAR16 * path)
523 {
524     if(path == NULL) return;
525 
526     for(; *path != '\0'; path++) {
527         if(*path == L'/') *path = L'\\';
528     }
529 }
530 
lv_fs_uefi_uefi_path_to_lvgl_path(CHAR16 * path)531 static void lv_fs_uefi_uefi_path_to_lvgl_path(CHAR16 * path)
532 {
533     if(path == NULL) return;
534 
535     for(; *path != '\0'; path++) {
536         if(*path == L'\\') *path = L'/';
537     }
538 }
539 
lv_fs_uefi_is_dot_path(CONST CHAR16 * path)540 static bool lv_fs_uefi_is_dot_path(CONST CHAR16 * path)
541 {
542     if(path == NULL) return FALSE;
543 
544     if(path[0] == L'.' && path[1] == L'\0') return TRUE;
545     if(path[0] == L'.' && path[1] == L'.' && path[2] == L'\0') return TRUE;
546 
547     return FALSE;
548 }
549 
lv_fs_uefi_is_dir(EFI_FILE_PROTOCOL * dir)550 static bool lv_fs_uefi_is_dir(EFI_FILE_PROTOCOL * dir)
551 {
552     UINT64 attributes;
553 
554     if(dir == NULL) return FALSE;
555 
556     EFI_FILE_INFO * info = lv_fs_uefi_get_info(dir);
557     if(info == NULL) return FALSE;
558 
559     attributes = info->Attribute;
560     lv_free(info);
561 
562     return (attributes & EFI_FILE_DIRECTORY) != 0;
563 }
564 
lv_fs_uefi_is_file(EFI_FILE_PROTOCOL * file)565 static bool lv_fs_uefi_is_file(EFI_FILE_PROTOCOL * file)
566 {
567     UINT64 attributes;
568 
569     if(file == NULL) return FALSE;
570 
571     EFI_FILE_INFO * info = lv_fs_uefi_get_info(file);
572     if(info == NULL) return FALSE;
573 
574     attributes = info->Attribute;
575     lv_free(info);
576 
577     return (attributes & EFI_FILE_DIRECTORY) == 0;
578 }
579 
lv_fs_uefi_get_info(EFI_FILE_PROTOCOL * file)580 static EFI_FILE_INFO * lv_fs_uefi_get_info(EFI_FILE_PROTOCOL * file)
581 {
582     EFI_STATUS status;
583     EFI_FILE_INFO * info = NULL;
584     UINTN size = 0;
585 
586     status = file->GetInfo(file, &_uefi_guid_file_info, &size, info);
587     if(status != EFI_BUFFER_TOO_SMALL) return NULL;
588 
589     info = lv_calloc(1, size);
590     LV_ASSERT_MALLOC(info);
591 
592     status = file->GetInfo(file, &_uefi_guid_file_info, &size, info);
593     if(status != EFI_SUCCESS) {
594         lv_free(info);
595         return NULL;
596     }
597 
598     return info;
599 }
600 
601 #else /* LV_FS_UEFI_LETTER == 0*/
602 
603 #if defined(LV_FS_UEFI_LETTER) && LV_FS_UEFI_LETTER != '\0'
604     #warning "LV_FS_UEFI is not enabled but LV_FS_UEFI_LETTER is set"
605 #endif
606 
607 #endif
608