Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
CTCaer
GitHub Repository: CTCaer/hekate
Path: blob/master/bdk/libs/lvgl/lv_misc/lv_fs.c
1476 views
1
/**
2
* @file lv_fs.c
3
*
4
*/
5
6
/*********************
7
* INCLUDES
8
*********************/
9
#include "lv_fs.h"
10
#if USE_LV_FILESYSTEM
11
12
#include "lv_ll.h"
13
#include <string.h>
14
#include "lv_gc.h"
15
16
#if defined(LV_GC_INCLUDE)
17
# include LV_GC_INCLUDE
18
#endif /* LV_ENABLE_GC */
19
20
/*********************
21
* DEFINES
22
*********************/
23
24
/* "free" is used as a function pointer (in lv_fs_drv_t).
25
* We must make sure "free" was not defined to a platform specific
26
* free function, otherwise compilation would fail.
27
*/
28
#ifdef free
29
#undef free
30
#endif
31
32
/**********************
33
* TYPEDEFS
34
**********************/
35
36
/**********************
37
* STATIC PROTOTYPES
38
**********************/
39
static const char * lv_fs_get_real_path(const char * path);
40
static lv_fs_drv_t * lv_fs_get_drv(char letter);
41
42
43
/**********************
44
* STATIC VARIABLES
45
**********************/
46
47
/**********************
48
* MACROS
49
**********************/
50
51
/**********************
52
* GLOBAL FUNCTIONS
53
**********************/
54
55
/**
56
* Initialize the File system interface
57
*/
58
void lv_fs_init(void)
59
{
60
lv_ll_init(&LV_GC_ROOT(_lv_drv_ll), sizeof(lv_fs_drv_t));
61
}
62
63
/**
64
* Test if a drive is rady or not. If the `ready` function was not initialized `true` will be returned.
65
* @param letter letter of the drive
66
* @return true: drive is ready; false: drive is not ready
67
*/
68
bool lv_fs_is_ready(char letter)
69
{
70
lv_fs_drv_t * drv = lv_fs_get_drv(letter);
71
72
if(drv == NULL) return false; /*An unknown driver in not ready*/
73
74
if(drv->ready == NULL) return true; /*Assume the driver is always ready if no handler provided*/
75
76
return drv->ready();
77
}
78
79
/**
80
* Open a file
81
* @param file_p pointer to a lv_fs_file_t variable
82
* @param path path to the file beginning with the driver letter (e.g. S:/folder/file.txt)
83
* @param mode read: FS_MODE_RD, write: FS_MODE_WR, both: FS_MODE_RD | FS_MODE_WR
84
* @return LV_FS_RES_OK or any error from lv_fs_res_t enum
85
*/
86
lv_fs_res_t lv_fs_open(lv_fs_file_t * file_p, const char * path, lv_fs_mode_t mode)
87
{
88
file_p->drv = NULL;
89
file_p->file_d = NULL;
90
91
if(path == NULL) return LV_FS_RES_INV_PARAM;
92
93
char letter = path[0];
94
95
file_p->drv = lv_fs_get_drv(letter);
96
97
if(file_p->drv == NULL) {
98
file_p->file_d = NULL;
99
return LV_FS_RES_NOT_EX;
100
}
101
102
if(file_p->drv->ready != NULL) {
103
if(file_p->drv->ready() == false) {
104
file_p->drv = NULL;
105
file_p->file_d = NULL;
106
return LV_FS_RES_HW_ERR;
107
}
108
}
109
110
file_p->file_d = lv_mem_alloc(file_p->drv->file_size);
111
lv_mem_assert(file_p->file_d);
112
if(file_p->file_d == NULL) {
113
file_p->drv = NULL;
114
return LV_FS_RES_OUT_OF_MEM; /* Out of memory */
115
}
116
117
if(file_p->drv->open == NULL) {
118
return LV_FS_RES_NOT_IMP;
119
}
120
121
const char * real_path = lv_fs_get_real_path(path);
122
lv_fs_res_t res = file_p->drv->open(file_p->file_d, real_path, mode);
123
124
if(res != LV_FS_RES_OK) {
125
lv_mem_free(file_p->file_d);
126
file_p->file_d = NULL;
127
file_p->drv = NULL;
128
}
129
130
return res;
131
}
132
133
/**
134
* Close an already opened file
135
* @param file_p pointer to a lv_fs_file_t variable
136
* @return LV_FS_RES_OK or any error from lv_fs_res_t enum
137
*/
138
lv_fs_res_t lv_fs_close(lv_fs_file_t * file_p)
139
{
140
if(file_p->drv == NULL) {
141
return LV_FS_RES_INV_PARAM;
142
}
143
144
if(file_p->drv->close == NULL) {
145
return LV_FS_RES_NOT_IMP;
146
}
147
148
lv_fs_res_t res = file_p->drv->close(file_p->file_d);
149
150
lv_mem_free(file_p->file_d); /*Clean up*/
151
file_p->file_d = NULL;
152
file_p->drv = NULL;
153
file_p->file_d = NULL;
154
155
return res;
156
}
157
158
/**
159
* Delete a file
160
* @param path path of the file to delete
161
* @return LV_FS_RES_OK or any error from lv_fs_res_t enum
162
*/
163
lv_fs_res_t lv_fs_remove(const char * path)
164
{
165
if(path == NULL) return LV_FS_RES_INV_PARAM;
166
lv_fs_drv_t * drv = NULL;
167
168
char letter = path[0];
169
170
drv = lv_fs_get_drv(letter);
171
if(drv == NULL) return LV_FS_RES_NOT_EX;
172
if(drv->ready != NULL) {
173
if(drv->ready() == false) return LV_FS_RES_HW_ERR;
174
}
175
176
if(drv->remove == NULL) return LV_FS_RES_NOT_IMP;
177
178
const char * real_path = lv_fs_get_real_path(path);
179
lv_fs_res_t res = drv->remove(real_path);
180
181
return res;
182
}
183
184
/**
185
* Read from a file
186
* @param file_p pointer to a lv_fs_file_t variable
187
* @param buf pointer to a buffer where the read bytes are stored
188
* @param btr Bytes To Read
189
* @param br the number of real read bytes (Bytes Read). NULL if unused.
190
* @return LV_FS_RES_OK or any error from lv_fs_res_t enum
191
*/
192
lv_fs_res_t lv_fs_read(lv_fs_file_t * file_p, void * buf, uint32_t btr, uint32_t * br)
193
{
194
if(br != NULL) *br = 0;
195
if(file_p->drv == NULL) return LV_FS_RES_INV_PARAM;
196
if(file_p->drv->read == NULL) return LV_FS_RES_NOT_IMP;
197
198
uint32_t br_tmp = 0;
199
lv_fs_res_t res = file_p->drv->read(file_p->file_d, buf, btr, &br_tmp);
200
if(br != NULL) *br = br_tmp;
201
202
return res;
203
}
204
205
/**
206
* Write into a file
207
* @param file_p pointer to a lv_fs_file_t variable
208
* @param buf pointer to a buffer with the bytes to write
209
* @param btr Bytes To Write
210
* @param br the number of real written bytes (Bytes Written). NULL if unused.
211
* @return LV_FS_RES_OK or any error from lv_fs_res_t enum
212
*/
213
lv_fs_res_t lv_fs_write(lv_fs_file_t * file_p, const void * buf, uint32_t btw, uint32_t * bw)
214
{
215
if(bw != NULL) *bw = 0;
216
217
if(file_p->drv == NULL) {
218
return LV_FS_RES_INV_PARAM;
219
}
220
221
if(file_p->drv->write == NULL) {
222
return LV_FS_RES_NOT_IMP;
223
}
224
225
uint32_t bw_tmp = 0;
226
lv_fs_res_t res = file_p->drv->write(file_p->file_d, buf, btw, &bw_tmp);
227
if(bw != NULL) *bw = bw_tmp;
228
229
return res;
230
}
231
232
/**
233
* Set the position of the 'cursor' (read write pointer) in a file
234
* @param file_p pointer to a lv_fs_file_t variable
235
* @param pos the new position expressed in bytes index (0: start of file)
236
* @return LV_FS_RES_OK or any error from lv_fs_res_t enum
237
*/
238
lv_fs_res_t lv_fs_seek(lv_fs_file_t * file_p, uint32_t pos)
239
{
240
if(file_p->drv == NULL) {
241
return LV_FS_RES_INV_PARAM;
242
}
243
244
if(file_p->drv->seek == NULL) {
245
return LV_FS_RES_NOT_IMP;
246
}
247
248
lv_fs_res_t res = file_p->drv->seek(file_p->file_d, pos);
249
250
return res;
251
}
252
253
/**
254
* Give the position of the read write pointer
255
* @param file_p pointer to a lv_fs_file_t variable
256
* @param pos_p pointer to store the position of the read write pointer
257
* @return LV_FS_RES_OK or any error from 'fs_res_t'
258
*/
259
lv_fs_res_t lv_fs_tell(lv_fs_file_t * file_p, uint32_t * pos)
260
{
261
if(file_p->drv == NULL) {
262
pos = 0;
263
return LV_FS_RES_INV_PARAM;
264
}
265
266
if(file_p->drv->tell == NULL) {
267
pos = 0;
268
return LV_FS_RES_NOT_IMP;
269
}
270
271
lv_fs_res_t res = file_p->drv->tell(file_p->file_d, pos);
272
273
return res;
274
}
275
276
/**
277
* Truncate the file size to the current position of the read write pointer
278
* @param file_p pointer to an 'ufs_file_t' variable. (opened with lv_fs_open )
279
* @return LV_FS_RES_OK: no error, the file is read
280
* any error from lv_fs_res_t enum
281
*/
282
lv_fs_res_t lv_fs_trunc(lv_fs_file_t * file_p)
283
{
284
if(file_p->drv == NULL) {
285
return LV_FS_RES_INV_PARAM;
286
}
287
288
if(file_p->drv->tell == NULL) {
289
return LV_FS_RES_NOT_IMP;
290
}
291
292
lv_fs_res_t res = file_p->drv->trunc(file_p->file_d);
293
294
return res;
295
}
296
/**
297
* Give the size of a file bytes
298
* @param file_p pointer to a lv_fs_file_t variable
299
* @param size pointer to a variable to store the size
300
* @return LV_FS_RES_OK or any error from lv_fs_res_t enum
301
*/
302
lv_fs_res_t lv_fs_size(lv_fs_file_t * file_p, uint32_t * size)
303
{
304
if(file_p->drv == NULL) {
305
return LV_FS_RES_INV_PARAM;
306
}
307
308
if(file_p->drv->size == NULL) return LV_FS_RES_NOT_IMP;
309
310
311
if(size == NULL) return LV_FS_RES_INV_PARAM;
312
313
lv_fs_res_t res = file_p->drv->size(file_p->file_d, size);
314
315
return res;
316
}
317
318
/**
319
* Rename a file
320
* @param oldname path to the file
321
* @param newname path with the new name
322
* @return LV_FS_RES_OK or any error from 'fs_res_t'
323
*/
324
lv_fs_res_t lv_fs_rename(const char * oldname, const char * newname)
325
{
326
if(!oldname || !newname) return LV_FS_RES_INV_PARAM;
327
328
char letter = oldname[0];
329
330
lv_fs_drv_t * drv = lv_fs_get_drv(letter);
331
332
if(!drv) {
333
return LV_FS_RES_NOT_EX;
334
}
335
336
if(drv->ready != NULL) {
337
if(drv->ready() == false) {
338
return LV_FS_RES_HW_ERR;
339
}
340
}
341
342
if(drv->rename == NULL) return LV_FS_RES_NOT_IMP;
343
344
const char * old_real = lv_fs_get_real_path(oldname);
345
const char * new_real = lv_fs_get_real_path(newname);
346
lv_fs_res_t res = drv->rename(old_real, new_real);
347
348
return res;
349
}
350
351
352
/**
353
* Initialize a 'fs_read_dir_t' variable for directory reading
354
* @param rddir_p pointer to a 'fs_read_dir_t' variable
355
* @param path path to a directory
356
* @return LV_FS_RES_OK or any error from lv_fs_res_t enum
357
*/
358
lv_fs_res_t lv_fs_dir_open(lv_fs_dir_t * rddir_p, const char * path)
359
{
360
if(path == NULL) return LV_FS_RES_INV_PARAM;
361
362
char letter = path[0];
363
364
rddir_p->drv = lv_fs_get_drv(letter);
365
366
if(rddir_p->drv == NULL) {
367
rddir_p->dir_d = NULL;
368
return LV_FS_RES_NOT_EX;
369
}
370
371
rddir_p->dir_d = lv_mem_alloc(rddir_p->drv->rddir_size);
372
lv_mem_assert(rddir_p->dir_d);
373
if(rddir_p->dir_d == NULL) {
374
rddir_p->dir_d = NULL;
375
return LV_FS_RES_OUT_OF_MEM; /* Out of memory */
376
}
377
378
if(rddir_p->drv->dir_open == NULL) {
379
return LV_FS_RES_NOT_IMP;
380
}
381
382
const char * real_path = lv_fs_get_real_path(path);
383
lv_fs_res_t res = rddir_p->drv->dir_open(rddir_p->dir_d, real_path);
384
385
return res;
386
}
387
388
/**
389
* Read the next filename form a directory.
390
* The name of the directories will begin with '/'
391
* @param rddir_p pointer to an initialized 'fs_read_dir_t' variable
392
* @param fn pointer to a buffer to store the filename
393
* @return LV_FS_RES_OK or any error from lv_fs_res_t enum
394
*/
395
lv_fs_res_t lv_fs_dir_read(lv_fs_dir_t * rddir_p, char * fn)
396
{
397
if(rddir_p->drv == NULL || rddir_p->dir_d == NULL) {
398
fn[0] = '\0';
399
return LV_FS_RES_INV_PARAM;
400
}
401
402
if(rddir_p->drv->dir_read == NULL) {
403
return LV_FS_RES_NOT_IMP;
404
}
405
406
lv_fs_res_t res = rddir_p->drv->dir_read(rddir_p->dir_d, fn);
407
408
return res;
409
}
410
411
/**
412
* Close the directory reading
413
* @param rddir_p pointer to an initialized 'fs_read_dir_t' variable
414
* @return LV_FS_RES_OK or any error from lv_fs_res_t enum
415
*/
416
lv_fs_res_t lv_fs_dir_close(lv_fs_dir_t * rddir_p)
417
{
418
if(rddir_p->drv == NULL || rddir_p->dir_d == NULL) {
419
return LV_FS_RES_INV_PARAM;
420
}
421
422
lv_fs_res_t res;
423
424
if(rddir_p->drv->dir_close == NULL) {
425
res = LV_FS_RES_NOT_IMP;
426
} else {
427
res = rddir_p->drv->dir_close(rddir_p->dir_d);
428
}
429
430
lv_mem_free(rddir_p->dir_d); /*Clean up*/
431
rddir_p->dir_d = NULL;
432
rddir_p->drv = NULL;
433
rddir_p->dir_d = NULL;
434
435
return res;
436
}
437
438
/**
439
* Get the free and total size of a driver in kB
440
* @param letter the driver letter
441
* @param total_p pointer to store the total size [kB]
442
* @param free_p pointer to store the free size [kB]
443
* @return LV_FS_RES_OK or any error from lv_fs_res_t enum
444
*/
445
lv_fs_res_t lv_fs_free(char letter, uint32_t * total_p, uint32_t * free_p)
446
{
447
lv_fs_drv_t * drv = lv_fs_get_drv(letter);
448
449
if(drv == NULL) {
450
return LV_FS_RES_INV_PARAM;
451
}
452
453
lv_fs_res_t res;
454
455
if(drv->free == NULL) {
456
res = LV_FS_RES_NOT_IMP;
457
} else {
458
uint32_t total_tmp = 0;
459
uint32_t free_tmp = 0;
460
res = drv->free(&total_tmp, &free_tmp);
461
462
if(total_p != NULL) *total_p = total_tmp;
463
if(free_p != NULL) *free_p = free_tmp;
464
}
465
466
return res;
467
}
468
469
/**
470
* Add a new drive
471
* @param drv_p pointer to an lv_fs_drv_t structure which is inited with the
472
* corresponding function pointers. The data will be copied so the variable can be local.
473
*/
474
void lv_fs_add_drv(lv_fs_drv_t * drv_p)
475
{
476
/*Save the new driver*/
477
lv_fs_drv_t * new_drv;
478
new_drv = lv_ll_ins_head(&LV_GC_ROOT(_lv_drv_ll));
479
lv_mem_assert(new_drv);
480
if(new_drv == NULL) return;
481
482
memcpy(new_drv, drv_p, sizeof(lv_fs_drv_t));
483
}
484
485
/**
486
* Fill a buffer with the letters of existing drivers
487
* @param buf buffer to store the letters ('\0' added after the last letter)
488
* @return the buffer
489
*/
490
char * lv_fs_get_letters(char * buf)
491
{
492
lv_fs_drv_t * drv;
493
uint8_t i = 0;
494
495
LL_READ(LV_GC_ROOT(_lv_drv_ll), drv) {
496
buf[i] = drv->letter;
497
i++;
498
}
499
500
buf[i] = '\0';
501
502
return buf;
503
}
504
505
506
/**
507
* Return with the extension of the filename
508
* @param fn string with a filename
509
* @return pointer to the beginning extension or empty string if no extension
510
*/
511
const char * lv_fs_get_ext(const char * fn)
512
{
513
uint16_t i;
514
for(i = strlen(fn); i > 0; i --) {
515
if(fn[i] == '.') {
516
return &fn[i + 1];
517
} else if(fn[i] == '/' || fn[i] == '\\') {
518
return ""; /*No extension if a '\' or '/' found*/
519
}
520
}
521
522
return ""; /*Empty string if no '.' in the file name. */
523
}
524
525
/**
526
* Step up one level
527
* @param path pointer to a file name
528
* @return the truncated file name
529
*/
530
char * lv_fs_up(char * path)
531
{
532
uint16_t len = strlen(path);
533
if(len == 0) return path;
534
535
len --; /*Go before the trailing '\0'*/
536
537
/*Ignore trailing '/' or '\'*/
538
while(path[len] == '/' || path[len] == '\\') {
539
path[len] = '\0';
540
if(len > 0) len --;
541
else return path;
542
}
543
544
uint16_t i;
545
for(i = len; i > 0; i --) {
546
if(path[i] == '/' || path[i] == '\\') break;
547
}
548
549
if(i > 0) path[i] = '\0';
550
551
return path;
552
}
553
554
/**
555
* Get the last element of a path (e.g. U:/folder/file -> file)
556
* @param path a character sting with the path to search in
557
* @return pointer to the beginning of the last element in the path
558
*/
559
const char * lv_fs_get_last(const char * path)
560
{
561
uint16_t len = strlen(path);
562
if(len == 0) return path;
563
564
len --; /*Go before the trailing '\0'*/
565
566
/*Ignore trailing '/' or '\'*/
567
while(path[len] == '/' || path[len] == '\\') {
568
if(len > 0) len --;
569
else return path;
570
}
571
572
uint16_t i;
573
for(i = len; i > 0; i --) {
574
if(path[i] == '/' || path[i] == '\\') break;
575
}
576
577
/*No '/' or '\' in the path so return with path itself*/
578
if(i == 0) return path;
579
580
return &path[i + 1];
581
}
582
/**********************
583
* STATIC FUNCTIONS
584
**********************/
585
586
/**
587
* Leave the driver letters and / or \ letters from beginning of the path
588
* @param path path string (E.g. S:/folder/file.txt)
589
* @return pointer to the beginning of the real path (E.g. folder/file.txt)
590
*/
591
static const char * lv_fs_get_real_path(const char * path)
592
{
593
/* Example path: "S:/folder/file.txt"
594
* Leave the letter and the : / \ characters*/
595
596
path ++; /*Ignore the driver letter*/
597
598
while(*path != '\0') {
599
if(*path == ':' || *path == '\\' || *path == '/') {
600
path ++;
601
} else {
602
break;
603
}
604
}
605
606
return path;
607
}
608
609
/**
610
* Give a pointer to a driver from its letter
611
* @param letter the driver letter
612
* @return pointer to a driver or NULL if not found
613
*/
614
static lv_fs_drv_t * lv_fs_get_drv(char letter)
615
{
616
lv_fs_drv_t * drv;
617
618
LL_READ(LV_GC_ROOT(_lv_drv_ll), drv) {
619
if(drv->letter == letter) {
620
return drv;
621
}
622
}
623
624
return NULL;
625
}
626
627
#endif /*USE_LV_FILESYSTEM*/
628
629