xref: /kernel/uniproton/src/fs/littlefs/lfs_adapter.c (revision 54568cb3)
1/*
2 * Copyright (c) 2022-2022 Huawei Technologies Co., Ltd. All rights reserved.
3 *
4 * UniProton is licensed under Mulan PSL v2.
5 * You can use this software according to the terms and conditions of the Mulan PSL v2.
6 * You may obtain a copy of Mulan PSL v2 at:
7 *          http://license.coscl.org.cn/MulanPSL2
8 * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
9 * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
10 * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
11 * See the Mulan PSL v2 for more details.
12 * Create: 2022-09-21
13 * Description: littlefs适配层代码
14 */
15#define _GNU_SOURCE 1
16#include "lfs_adapter.h"
17#include "prt_fs.h"
18#include "vfs_files.h"
19#include "vfs_operations.h"
20#include "vfs_partition.h"
21#include "vfs_maps.h"
22#include "vfs_mount.h"
23#include "securec.h"
24
25static pthread_mutex_t g_fsLocalMutex = PTHREAD_MUTEX_INITIALIZER;
26
27static struct PartitionCfg g_partitionCfg;
28static struct TagDeviceDesc *g_lfsDevice;
29
30static uintptr_t OsLfsGetStartAddr(S32 partition)
31{
32    if (g_lfsDevice == NULL) {
33        struct TagDeviceDesc *device = NULL;
34        for (device = OsGetDeviceList(); device != NULL; device = device->dNext) {
35            if (strcmp(device->dFsType, "littlefs") == 0) {
36                g_lfsDevice = device;
37                break;
38            }
39        }
40    }
41
42    if ((g_lfsDevice == NULL) || (partition >= g_lfsDevice->dPartNum)) {
43        return INVALID_DEVICE_ADDR;
44    }
45
46    return g_lfsDevice->dAddrArray[partition];
47}
48
49static S32 OsLfsBlockRead(const struct lfs_config *c, lfs_block_t block,
50                                      lfs_off_t off, void *dst, lfs_size_t size)
51{
52    uintptr_t startAddr = OsLfsGetStartAddr((S32)c->context);
53    if (startAddr == INVALID_DEVICE_ADDR) {
54        return -1;
55    }
56    startAddr += (c->block_size * block + off);
57    return (g_partitionCfg.readFunc)((S32)c->context, startAddr, dst, size);
58}
59
60static S32 OsLfsBlockWrite(const struct lfs_config *c, lfs_block_t block,
61                                       lfs_off_t off, const void *dst, lfs_size_t size)
62{
63    uintptr_t startAddr = OsLfsGetStartAddr((S32)c->context);
64    if (startAddr == INVALID_DEVICE_ADDR) {
65        return -1;
66    }
67
68    startAddr += (c->block_size * block + off);
69    return (g_partitionCfg.writeFunc)((S32)c->context, startAddr, dst, size);
70}
71
72static S32 OsLfsBlockErase(const struct lfs_config *c, lfs_block_t block)
73{
74    uintptr_t startAddr = OsLfsGetStartAddr((S32)c->context);
75    if (startAddr == INVALID_DEVICE_ADDR) {
76        return -1;
77    }
78
79    startAddr += (c->block_size * block);
80    return (g_partitionCfg.eraseFunc)((S32)c->context, startAddr, c->block_size);
81}
82
83static S32 OsLfsBlockSync(const struct lfs_config *c)
84{
85    (void)c;
86    return 0;
87}
88
89static S32 OsConvertFlagToLfsOpenFlag(S32 oflags)
90{
91    S32 lfsOpenFlag = 0;
92
93    if (oflags & O_CREAT) {
94        lfsOpenFlag |= LFS_O_CREAT;
95    }
96
97    if (oflags & O_EXCL) {
98        lfsOpenFlag |= LFS_O_EXCL;
99    }
100
101    if (oflags & O_TRUNC) {
102        lfsOpenFlag |= LFS_O_TRUNC;
103    }
104
105    if (oflags & O_APPEND) {
106        lfsOpenFlag |= LFS_O_APPEND;
107    }
108
109    if (oflags & O_RDWR) {
110        lfsOpenFlag |= LFS_O_RDWR;
111    }
112
113    if (oflags & O_WRONLY) {
114        lfsOpenFlag |= LFS_O_WRONLY;
115    }
116
117    if (oflags == O_RDONLY) {
118        lfsOpenFlag |= LFS_O_RDONLY;
119    }
120
121    return lfsOpenFlag;
122}
123
124static S32 OsLfsErrno(S32 result)
125{
126    return (result < 0) ? -result : result;
127}
128
129static void OsLfsConfigAdapter(struct PartitionCfg *pCfg, struct lfs_config *lfsCfg)
130{
131    lfsCfg->context = (void *)pCfg->partNo;
132
133    lfsCfg->read_size = pCfg->readSize;
134    lfsCfg->prog_size = pCfg->writeSize;
135    lfsCfg->cache_size = pCfg->cacheSize;
136    lfsCfg->block_cycles = pCfg->blockCycles;
137    lfsCfg->lookahead_size = pCfg->lookaheadSize;
138    lfsCfg->block_size = pCfg->blockSize;
139    lfsCfg->block_count = pCfg->blockCount;
140
141    lfsCfg->read = OsLfsBlockRead;
142    lfsCfg->prog = OsLfsBlockWrite;
143    lfsCfg->erase = OsLfsBlockErase;
144    lfsCfg->sync = OsLfsBlockSync;
145
146    g_partitionCfg.readFunc = pCfg->readFunc;
147    g_partitionCfg.writeFunc = pCfg->writeFunc;
148    g_partitionCfg.eraseFunc = pCfg->eraseFunc;
149}
150
151static S32 OsLfsMount(struct TagMountPoint *mp, uintptr_t mountflags, const void *data)
152{
153    S32 ret;
154    S32 size;
155    lfs_t *mountHdl = NULL;
156    struct lfs_config *cfg = NULL;
157
158    if ((mp == NULL) || (mp->mPath == NULL) || (data == NULL)) {
159        errno = EFAULT;
160        return FS_NOK;
161    }
162
163    size = sizeof(lfs_t) + sizeof(struct lfs_config);
164    mountHdl = (lfs_t *)malloc(size);
165    if (mountHdl == NULL) {
166        errno = ENODEV;
167        return FS_NOK;
168    }
169    if (memset_s(mountHdl, size, 0, size) != EOK) {
170        free(mountHdl);
171        errno = EBADF;
172        return FS_NOK;
173    }
174    mp->mData = (void *)mountHdl;
175    cfg = (struct lfs_config *)((uintptr_t)mountHdl + sizeof(lfs_t));
176
177    OsLfsConfigAdapter((struct PartitionCfg *)data, cfg);
178
179    ret = lfs_mount((lfs_t *)mp->mData, cfg);
180    if (ret != 0) {
181        ret = lfs_format((lfs_t *)mp->mData, cfg);
182        if (ret == 0) {
183            ret = lfs_mount((lfs_t *)mp->mData, cfg);
184        }
185    }
186    if (ret != 0) {
187        free(mountHdl);
188        errno = OsLfsErrno(ret);
189        return FS_NOK;
190    }
191    return ret;
192}
193
194static S32 OsLfsUmount(struct TagMountPoint *mp)
195{
196    S32 ret;
197
198    if (mp == NULL) {
199        errno = EFAULT;
200        return FS_NOK;
201    }
202
203    if (mp->mData == NULL) {
204        errno = ENOENT;
205        return FS_NOK;
206    }
207
208    ret = lfs_unmount((lfs_t *)mp->mData);
209    if (ret != 0) {
210        errno = OsLfsErrno(ret);
211        ret = FS_NOK;
212    }
213
214    free(mp->mData);
215    mp->mData = NULL;
216    return ret;
217}
218
219static S32 OsLfsUnlink(struct TagMountPoint *mp, const char *fileName)
220{
221    S32 ret;
222
223    if ((mp == NULL) || (fileName == NULL)) {
224        errno = EFAULT;
225        return FS_NOK;
226    }
227
228    if (mp->mData == NULL) {
229        errno = ENOENT;
230        return FS_NOK;
231    }
232
233    ret = lfs_remove((lfs_t *)mp->mData, fileName);
234    if (ret != 0) {
235        errno = OsLfsErrno(ret);
236        ret = FS_NOK;
237    }
238
239    return ret;
240}
241
242static S32 OsLfsMkdir(struct TagMountPoint *mp, const char *dirName)
243{
244    S32 ret;
245
246    if ((dirName == NULL) || (mp == NULL)) {
247        errno = EFAULT;
248        return FS_NOK;
249    }
250
251    if (mp->mData == NULL) {
252        errno = ENOENT;
253        return FS_NOK;
254    }
255
256    lfs_t *lfs = (lfs_t *)mp->mData;
257
258    ret = lfs_mkdir(lfs, dirName);
259    if (ret != 0) {
260        errno = OsLfsErrno(ret);
261        ret = FS_NOK;
262    }
263
264    return ret;
265}
266
267static S32 OsLfsRmdir(struct TagMountPoint *mp, const char *dirName)
268{
269    S32 ret;
270    lfs_t *lfs = NULL;
271
272    if (mp == NULL) {
273        errno = EFAULT;
274        return FS_NOK;
275    }
276
277    if (mp->mData == NULL) {
278        errno = ENOENT;
279        return FS_NOK;
280    }
281
282    if (dirName == NULL) {
283        errno = EFAULT;
284        return FS_NOK;
285    }
286
287    lfs = (lfs_t *)mp->mData;
288    ret = lfs_remove(lfs, dirName);
289    if (ret != 0) {
290        errno = OsLfsErrno(ret);
291        ret = FS_NOK;
292    }
293    return ret;
294}
295
296static S32 OsLfsOpendir(struct TagDir *dir, const char *dirName)
297{
298    S32 ret;
299
300    if ((dir == NULL) || (dir->dMp == NULL) || (dir->dMp->mData == NULL)) {
301        errno = EFAULT;
302        return FS_NOK;
303    }
304
305    lfs_t *lfs = (lfs_t *)dir->dMp->mData;
306    lfs_dir_t *dirInfo = (lfs_dir_t *)malloc(sizeof(lfs_dir_t));
307    if (dirInfo == NULL) {
308        errno = ENOMEM;
309        return FS_NOK;
310    }
311    if (memset_s(dirInfo, sizeof(lfs_dir_t), 0, sizeof(lfs_dir_t)) != EOK) {
312        free(dirInfo);
313        errno = EBADF;
314        return FS_NOK;
315    }
316
317    ret = lfs_dir_open(lfs, dirInfo, dirName);
318    if (ret != 0) {
319        free(dirInfo);
320        errno = OsLfsErrno(ret);
321        return FS_NOK;
322    }
323
324    dir->dData = dirInfo;
325    dir->dOffset = 0;
326    return FS_OK;
327}
328
329static S32 OsLfsReaddir(struct TagDir *dir, struct dirent *dent)
330{
331    S32 ret;
332    struct lfs_info lfsInfo;
333
334    if ((dir == NULL) || (dir->dMp == NULL) || (dir->dMp->mData == NULL) ||
335        (dent == NULL)) {
336        errno = EFAULT;
337        return FS_NOK;
338    }
339
340    if (dir->dData == NULL) {
341        errno = EBADF;
342        return FS_NOK;
343    }
344
345    lfs_t *lfs = (lfs_t *)dir->dMp->mData;
346    lfs_dir_t *dirInfo = (lfs_dir_t *)dir->dData;
347
348    ret = lfs_dir_read(lfs, dirInfo, &lfsInfo);
349    if (ret == TRUE) {
350        pthread_mutex_lock(&g_fsLocalMutex);
351        (void)strncpy_s(dent->d_name, sizeof(dent->d_name), lfsInfo.name, strlen(lfsInfo.name) + 1);
352        if (lfsInfo.type == LFS_TYPE_DIR) {
353            dent->d_type = DT_DIR;
354        } else if (lfsInfo.type == LFS_TYPE_REG) {
355            dent->d_type = DT_REG;
356        }
357
358        dent->d_reclen = lfsInfo.size;
359        pthread_mutex_unlock(&g_fsLocalMutex);
360
361        return FS_OK;
362    }
363
364    if (ret != 0) {
365        errno = OsLfsErrno(ret);
366    }
367
368    return FS_NOK;
369}
370
371static S32 OsLfsClosedir(struct TagDir *dir)
372{
373    S32 ret;
374
375    if ((dir == NULL) || (dir->dMp == NULL) || (dir->dMp->mData == NULL)) {
376        errno = EFAULT;
377        return FS_NOK;
378    }
379
380    if (dir->dData == NULL) {
381        errno = EBADF;
382        return FS_NOK;
383    }
384
385    lfs_t *lfs = (lfs_t *)dir->dMp->mData;
386    lfs_dir_t *dirInfo = (lfs_dir_t *)dir->dData;
387
388    ret = lfs_dir_close(lfs, dirInfo);
389    if (ret != 0) {
390        errno = OsLfsErrno(ret);
391        ret = FS_NOK;
392    }
393
394    free(dirInfo);
395    dir->dData = NULL;
396
397    return ret;
398}
399
400static S32 OsLfsOpen(struct TagFile *file, const char *pathName, S32 openFlag)
401{
402    S32 ret;
403    lfs_file_t *lfsHandle = NULL;
404
405    if ((pathName == NULL) || (file == NULL) || (file->fMp == NULL) ||
406        (file->fMp->mData == NULL)) {
407        errno = EFAULT;
408        return FS_NOK;
409    }
410
411    lfsHandle = (lfs_file_t *)malloc(sizeof(lfs_file_t));
412    if (lfsHandle == NULL) {
413        errno = ENOMEM;
414        return FS_NOK;
415    }
416
417    S32 lfsOpenFlag = OsConvertFlagToLfsOpenFlag(openFlag);
418    ret = lfs_file_open((lfs_t *)file->fMp->mData, lfsHandle, pathName, lfsOpenFlag);
419    if (ret != 0) {
420        free(lfsHandle);
421        errno = OsLfsErrno(ret);
422        return INVALID_FD;
423    }
424
425    file->fData = (void *)lfsHandle;
426    return ret;
427}
428
429static S32 OsLfsRead(struct TagFile *file, char *buf, size_t len)
430{
431    S32 ret;
432    struct TagMountPoint *mp = NULL;
433    lfs_file_t *lfsHandle = NULL;
434
435    if (buf == NULL) {
436        errno = EFAULT;
437        return FS_NOK;
438    }
439
440    if ((file == NULL) || (file->fData == NULL)) {
441        errno = EBADF;
442        return FS_NOK;
443    }
444
445    lfsHandle = (lfs_file_t *)file->fData;
446    mp = file->fMp;
447    if ((mp == NULL) || (mp->mData == NULL)) {
448        errno = EFAULT;
449        return FS_NOK;
450    }
451
452    ret = lfs_file_read((lfs_t *)mp->mData, lfsHandle, buf, len);
453    if (ret < 0) {
454        errno = OsLfsErrno(ret);
455        ret = FS_NOK;
456    }
457    return ret;
458}
459
460static S32 OsLfsWrite(struct TagFile *file, const char *buf, size_t len)
461{
462    S32 ret;
463    struct TagMountPoint *mp = NULL;
464    lfs_file_t *lfsHandle = NULL;
465
466    if (buf == NULL) {
467        errno = EFAULT;
468        return FS_NOK;
469    }
470
471    if ((file == NULL) || (file->fData == NULL)) {
472        errno = EBADF;
473        return FS_NOK;
474    }
475
476    lfsHandle = (lfs_file_t *)file->fData;
477    mp = file->fMp;
478    if ((mp == NULL) || (mp->mData == NULL)) {
479        errno = EFAULT;
480        return FS_NOK;
481    }
482
483    ret = lfs_file_write((lfs_t *)mp->mData, lfsHandle, buf, len);
484    if (ret < 0) {
485        errno = OsLfsErrno(ret);
486        ret = FS_NOK;
487    }
488    return ret;
489}
490
491static off_t OsLfsSeek(struct TagFile *file, off_t offset, S32 whence)
492{
493    off_t ret;
494    struct TagMountPoint *mp = NULL;
495    lfs_file_t *lfsHandle = NULL;
496
497    if ((file == NULL) || (file->fData == NULL)) {
498        errno = EBADF;
499        return (off_t)FS_NOK;
500    }
501
502    lfsHandle = (lfs_file_t *)file->fData;
503    mp = file->fMp;
504    if ((mp == NULL) || (mp->mData == NULL)) {
505        errno = EFAULT;
506        return (off_t)FS_NOK;
507    }
508
509    ret = (off_t)lfs_file_seek((lfs_t *)mp->mData, lfsHandle, offset, whence);
510    if (ret < 0) {
511        errno = OsLfsErrno(ret);
512        ret = (off_t)FS_NOK;
513    }
514
515    return ret;
516}
517
518static S32 OsLfsClose(struct TagFile *file)
519{
520    S32 ret;
521    struct TagMountPoint *mp = NULL;
522    lfs_file_t *lfsHandle = NULL;
523
524    if ((file == NULL) || (file->fData == NULL)) {
525        errno = EBADF;
526        return FS_NOK;
527    }
528
529    lfsHandle = (lfs_file_t *)file->fData;
530    mp = file->fMp;
531    if ((mp == NULL) || (mp->mData == NULL)) {
532        errno = EFAULT;
533        return FS_NOK;
534    }
535
536    pthread_mutex_lock(&g_fsLocalMutex);
537    ret = lfs_file_close((lfs_t *)mp->mData, lfsHandle);
538    pthread_mutex_unlock(&g_fsLocalMutex);
539
540    if (ret != 0) {
541        errno = OsLfsErrno(ret);
542        ret = FS_NOK;
543    }
544
545    free(file->fData);
546    file->fData = NULL;
547    return ret;
548}
549
550static S32 OsLfsRename(struct TagMountPoint *mp, const char *oldName, const char *newName)
551{
552    S32 ret;
553
554    if ((mp == NULL) || (oldName == NULL) || (newName == NULL)) {
555        errno = EFAULT;
556        return FS_NOK;
557    }
558
559    if (mp->mData == NULL) {
560        errno = ENOENT;
561        return FS_NOK;
562    }
563
564    ret = lfs_rename((lfs_t *)mp->mData, oldName, newName);
565    if (ret != 0) {
566        errno = OsLfsErrno(ret);
567        ret = FS_NOK;
568    }
569
570    return ret;
571}
572
573static S32 OsLfsStat(struct TagMountPoint *mp, const char *path, struct stat *buf)
574{
575    S32 ret;
576    struct lfs_info info;
577
578    if ((mp == NULL) || (path == NULL) || (buf == NULL)) {
579        errno = EFAULT;
580        return FS_NOK;
581    }
582
583    if (mp->mData == NULL) {
584        errno = ENOENT;
585        return FS_NOK;
586    }
587
588    ret = lfs_stat((lfs_t *)mp->mData, path, &info);
589    if (ret == 0) {
590        buf->st_size = info.size;
591        if (info.type == LFS_TYPE_REG) {
592            buf->st_mode = S_IFREG;
593        } else {
594            buf->st_mode = S_IFDIR;
595        }
596    } else {
597        errno = OsLfsErrno(ret);
598        ret = FS_NOK;
599    }
600
601    return ret;
602}
603
604static S32 OsLfsSync(struct TagFile *file)
605{
606    S32 ret;
607    struct TagMountPoint *mp = NULL;
608
609    if ((file == NULL) || (file->fData == NULL)) {
610        errno = EBADF;
611        return FS_NOK;
612    }
613
614    if ((file->fMp == NULL) || (file->fMp->mData == NULL)) {
615        errno = EFAULT;
616        return FS_NOK;
617    }
618
619    mp = file->fMp;
620    ret = lfs_file_sync((lfs_t *)mp->mData, (lfs_file_t *)file->fData);
621    if (ret != 0) {
622        errno = OsLfsErrno(ret);
623        ret = FS_NOK;
624    }
625    return ret;
626}
627
628static S32 OsLfsFormat(const char *partName, void *privData)
629{
630    S32 ret;
631    lfs_t lfs = {0};
632    struct lfs_config cfg = {0};
633
634    (void)partName;
635
636    OsLfsConfigAdapter((struct PartitionCfg *)privData, &cfg);
637
638    ret = lfs_format(&lfs, &cfg);
639    if (ret != 0) {
640        errno = OsLfsErrno(ret);
641        ret = FS_NOK;
642    }
643    return ret;
644}
645
646static struct TagMountOps g_lfsMnt = {
647    .mount = OsLfsMount,
648    .umount = OsLfsUmount,
649    .umount2 = NULL,
650    .statfs = NULL,
651};
652
653static struct TagFileOps g_lfsFops = {
654    .open = OsLfsOpen,
655    .close = OsLfsClose,
656    .read = OsLfsRead,
657    .write = OsLfsWrite,
658    .lseek = OsLfsSeek,
659    .stat = OsLfsStat,
660    .truncate = NULL,
661    .unlink = OsLfsUnlink,
662    .rename = OsLfsRename,
663    .ioctl = NULL, /* 不支持 */
664    .sync = OsLfsSync,
665    .rmdir = OsLfsRmdir,
666    .opendir = OsLfsOpendir,
667    .readdir = OsLfsReaddir,
668    .closedir = OsLfsClosedir,
669    .mkdir = OsLfsMkdir,
670};
671
672static struct TagFsManagement g_lfsMgt = {
673    .fdisk = NULL,
674    .format = OsLfsFormat,
675};
676
677void OsLfsInit(void)
678{
679    (void)OsFsRegister("littlefs", &g_lfsMnt, &g_lfsFops, &g_lfsMgt);
680}
681