1/*
2 * Copyright (c) 2013-2019 Huawei Technologies Co., Ltd. All rights reserved.
3 * Copyright (c) 2020-2022 Huawei Device Co., Ltd. All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without modification,
6 * are permitted provided that the following conditions are met:
7 *
8 * 1. Redistributions of source code must retain the above copyright notice, this list of
9 *    conditions and the following disclaimer.
10 *
11 * 2. Redistributions in binary form must reproduce the above copyright notice, this list
12 *    of conditions and the following disclaimer in the documentation and/or other materials
13 *    provided with the distribution.
14 *
15 * 3. Neither the name of the copyright holder nor the names of its contributors may be used
16 *    to endorse or promote products derived from this software without specific prior written
17 *    permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
21 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
23 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
24 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
25 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
26 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
27 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
28 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
29 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 */
31
32#define _GNU_SOURCE 1
33#include "lfs_adapter.h"
34#include "los_config.h"
35#include "vfs_files.h"
36#include "vfs_operations.h"
37#include "vfs_partition.h"
38#include "vfs_maps.h"
39#include "vfs_mount.h"
40#include "securec.h"
41#include "los_fs.h"
42
43static struct PartitionCfg g_partitionCfg;
44static struct DeviceDesc *g_lfsDevice = NULL;
45
46static uint32_t LfsGetStartAddr(int partition)
47{
48    if (g_lfsDevice == NULL) {
49        struct DeviceDesc *device = NULL;
50        for (device = getDeviceList(); device != NULL; device = device->dNext) {
51            if (strcmp(device->dFsType, "littlefs") == 0) {
52                g_lfsDevice = device;
53                break;
54            }
55        }
56    }
57
58    if ((g_lfsDevice == NULL) || (partition >= g_lfsDevice->dPartNum)) {
59        return INVALID_DEVICE_ADDR;
60    }
61
62    return (uint32_t)g_lfsDevice->dAddrArray[partition];
63}
64
65WEAK int littlefs_block_read(const struct lfs_config *c, lfs_block_t block,
66                             lfs_off_t off, void *dst, lfs_size_t size)
67{
68    UINT32 addr = c->block_size * block + off;
69    UINT32 startaddr = LfsGetStartAddr((int)c->context);
70    if (startaddr == INVALID_DEVICE_ADDR) {
71        return -1;
72    }
73    addr += startaddr;
74
75    return (g_partitionCfg.readFunc)((int)c->context, &addr, dst, size);
76}
77
78WEAK int littlefs_block_write(const struct lfs_config *c, lfs_block_t block,
79                              lfs_off_t off, const void *dst, lfs_size_t size)
80{
81    UINT32 addr = c->block_size * block + off;
82    UINT32 startaddr = LfsGetStartAddr((int)c->context);
83    if (startaddr == INVALID_DEVICE_ADDR) {
84        return -1;
85    }
86
87    addr += startaddr;
88
89    return (g_partitionCfg.writeFunc)((int)c->context, &addr, dst, size);
90}
91
92WEAK int littlefs_block_erase(const struct lfs_config *c, lfs_block_t block)
93{
94    UINT32 addr = c->block_size * block;
95    UINT32 startaddr = LfsGetStartAddr((int)c->context);
96    if (startaddr == INVALID_DEVICE_ADDR) {
97        return -1;
98    }
99
100    addr += startaddr;
101
102    return (g_partitionCfg.eraseFunc)((int)c->context, addr, c->block_size);
103}
104
105WEAK int littlefs_block_sync(const struct lfs_config *c)
106{
107    (void)c;
108    return 0;
109}
110
111static int ConvertFlagToLfsOpenFlag (int oflags)
112{
113    int lfsOpenFlag = 0;
114
115    if (oflags & O_CREAT) {
116        lfsOpenFlag |= LFS_O_CREAT;
117    }
118
119    if (oflags & O_EXCL) {
120        lfsOpenFlag |= LFS_O_EXCL;
121    }
122
123    if (oflags & O_TRUNC) {
124        lfsOpenFlag |= LFS_O_TRUNC;
125    }
126
127    if (oflags & O_APPEND) {
128        lfsOpenFlag |= LFS_O_APPEND;
129    }
130
131    if (oflags & O_RDWR) {
132        lfsOpenFlag |= LFS_O_RDWR;
133    }
134
135    if (oflags & O_WRONLY) {
136        lfsOpenFlag |= LFS_O_WRONLY;
137    }
138
139    if (oflags == O_RDONLY) {
140        lfsOpenFlag |= LFS_O_RDONLY;
141    }
142
143    return lfsOpenFlag;
144}
145
146static int LittlefsErrno(int result)
147{
148    return (result < 0) ? -result : result;
149}
150
151void LfsConfigAdapter(struct PartitionCfg *pCfg, struct lfs_config *lfsCfg)
152{
153    lfsCfg->context = (void *)pCfg->partNo;
154
155    lfsCfg->read_size = pCfg->readSize;
156    lfsCfg->prog_size = pCfg->writeSize;
157    lfsCfg->cache_size = pCfg->cacheSize;
158    lfsCfg->block_cycles = pCfg->blockCycles;
159    lfsCfg->lookahead_size = pCfg->lookaheadSize;
160    lfsCfg->block_size = pCfg->blockSize;
161    lfsCfg->block_count = pCfg->blockCount;
162
163    lfsCfg->read = littlefs_block_read;
164    lfsCfg->prog = littlefs_block_write;
165    lfsCfg->erase = littlefs_block_erase;
166    lfsCfg->sync = littlefs_block_sync;
167
168    g_partitionCfg.readFunc = pCfg->readFunc;
169    g_partitionCfg.writeFunc = pCfg->writeFunc;
170    g_partitionCfg.eraseFunc = pCfg->eraseFunc;
171}
172
173int LfsMount(struct MountPoint *mp, unsigned long mountflags, const void *data)
174{
175    int ret;
176    lfs_t *mountHdl = NULL;
177    struct lfs_config *cfg = NULL;
178
179    if ((mp == NULL) || (mp->mPath == NULL) || (data == NULL)) {
180        errno = EFAULT;
181        ret = (int)LOS_NOK;
182        goto errout;
183    }
184
185    if (mountflags & MS_REMOUNT) {
186        errno = ENOSYS;
187        ret = (int)LOS_NOK;
188        goto errout;
189    }
190
191    mountHdl = (lfs_t *)LOSCFG_FS_MALLOC_HOOK(sizeof(lfs_t) + sizeof(struct lfs_config));
192    if (mountHdl == NULL) {
193        errno = ENODEV;
194        ret = (int)LOS_NOK;
195        goto errout;
196    }
197    (void)memset_s(mountHdl, sizeof(lfs_t) + sizeof(struct lfs_config), 0, sizeof(lfs_t) + sizeof(struct lfs_config));
198    mp->mData = (void *)mountHdl;
199    cfg = (void *)((UINTPTR)mountHdl + sizeof(lfs_t));
200
201    LfsConfigAdapter((struct PartitionCfg *)data, cfg);
202
203    ret = lfs_mount((lfs_t *)mp->mData, cfg);
204    if (ret != 0) {
205        ret = lfs_format((lfs_t *)mp->mData, cfg);
206        if (ret == 0) {
207            ret = lfs_mount((lfs_t *)mp->mData, cfg);
208        }
209    }
210    if (ret != 0) {
211        LOSCFG_FS_FREE_HOOK(mountHdl);
212        errno = LittlefsErrno(ret);
213        ret = (int)LOS_NOK;
214    }
215
216errout:
217    return ret;
218}
219
220int LfsUmount(struct MountPoint *mp)
221{
222    int ret;
223
224    if (mp == NULL) {
225        errno = EFAULT;
226        return (int)LOS_NOK;
227    }
228
229    if (mp->mData == NULL) {
230        errno = ENOENT;
231        return (int)LOS_NOK;
232    }
233
234    ret = lfs_unmount((lfs_t *)mp->mData);
235    if (ret != 0) {
236        errno = LittlefsErrno(ret);
237        ret = (int)LOS_NOK;
238    }
239
240    LOSCFG_FS_FREE_HOOK(mp->mData);
241    mp->mData = NULL;
242    return ret;
243}
244
245int LfsUnlink(struct MountPoint *mp, const char *fileName)
246{
247    int ret;
248
249    if ((mp == NULL) || (fileName == NULL)) {
250        errno = EFAULT;
251        return (int)LOS_NOK;
252    }
253
254    if (mp->mData == NULL) {
255        errno = ENOENT;
256        return (int)LOS_NOK;
257    }
258
259    ret = lfs_remove((lfs_t *)mp->mData, fileName);
260    if (ret != 0) {
261        errno = LittlefsErrno(ret);
262        ret = (int)LOS_NOK;
263    }
264
265    return ret;
266}
267
268int LfsMkdir(struct MountPoint *mp, const char *dirName)
269{
270    int ret;
271
272    if ((dirName == NULL) || (mp == NULL)) {
273        errno = EFAULT;
274        return (int)LOS_NOK;
275    }
276
277    if (mp->mData == NULL) {
278        errno = ENOENT;
279        return (int)LOS_NOK;
280    }
281
282    lfs_t *lfs = (lfs_t *)mp->mData;
283
284    ret = lfs_mkdir(lfs, dirName);
285    if (ret != 0) {
286        errno = LittlefsErrno(ret);
287        ret = (int)LOS_NOK;
288    }
289
290    return ret;
291}
292
293int LfsRmdir(struct MountPoint *mp, const char *dirName)
294{
295    int ret;
296    lfs_t *lfs = NULL;
297
298    if (mp == NULL) {
299        errno = EFAULT;
300        return (int)LOS_NOK;
301    }
302
303    if (mp->mData == NULL) {
304        errno = ENOENT;
305        return (int)LOS_NOK;
306    }
307
308    lfs = (lfs_t *)mp->mData;
309
310    if (dirName == NULL) {
311        errno = EFAULT;
312        return (int)LOS_NOK;
313    }
314
315    ret = lfs_remove(lfs, dirName);
316    if (ret != 0) {
317        errno = LittlefsErrno(ret);
318        ret = (int)LOS_NOK;
319    }
320
321    return ret;
322}
323
324int LfsOpendir(struct Dir *dir, const char *dirName)
325{
326    int ret;
327
328    if ((dir == NULL) || (dir->dMp == NULL) || (dir->dMp->mData == NULL)) {
329        errno = EFAULT;
330        return (int)LOS_NOK;
331    }
332
333    lfs_t *lfs = (lfs_t *)dir->dMp->mData;
334    lfs_dir_t *dirInfo = (lfs_dir_t *)LOSCFG_FS_MALLOC_HOOK(sizeof(lfs_dir_t));
335    if (dirInfo == NULL) {
336        errno = ENOMEM;
337        return (int)LOS_NOK;
338    }
339
340    (void)memset_s(dirInfo, sizeof(lfs_dir_t), 0, sizeof(lfs_dir_t));
341    ret = lfs_dir_open(lfs, dirInfo, dirName);
342    if (ret != 0) {
343        LOSCFG_FS_FREE_HOOK(dirInfo);
344        errno = LittlefsErrno(ret);
345        goto errout;
346    }
347
348    dir->dData = dirInfo;
349    dir->dOffset = 0;
350
351    return LOS_OK;
352
353errout:
354    return (int)LOS_NOK;
355}
356
357int LfsReaddir(struct Dir *dir, struct dirent *dent)
358{
359    int ret;
360    struct lfs_info lfsInfo;
361
362    if ((dir == NULL) || (dir->dMp == NULL) || (dir->dMp->mData == NULL) ||
363        (dent == NULL)) {
364        errno = EFAULT;
365        return (int)LOS_NOK;
366    }
367
368    if (dir->dData == NULL) {
369        errno = EBADF;
370        return (int)LOS_NOK;
371    }
372
373    lfs_t *lfs = (lfs_t *)dir->dMp->mData;
374    lfs_dir_t *dirInfo = (lfs_dir_t *)dir->dData;
375
376    ret = lfs_dir_read(lfs, dirInfo, &lfsInfo);
377    if (ret == TRUE) {
378        (void)strncpy_s(dent->d_name, sizeof(dent->d_name), lfsInfo.name, strlen(lfsInfo.name) + 1);
379        if (lfsInfo.type == LFS_TYPE_DIR) {
380            dent->d_type = DT_DIR;
381        } else if (lfsInfo.type == LFS_TYPE_REG) {
382            dent->d_type = DT_REG;
383        }
384
385        dent->d_reclen = lfsInfo.size;
386
387        return LOS_OK;
388    }
389
390    if (ret != 0) {
391        errno = LittlefsErrno(ret);
392    }
393
394    return (int)LOS_NOK;
395}
396
397int LfsClosedir(struct Dir *dir)
398{
399    int ret;
400
401    if ((dir == NULL) || (dir->dMp == NULL) || (dir->dMp->mData == NULL)) {
402        errno = EFAULT;
403        return (int)LOS_NOK;
404    }
405
406    if (dir->dData == NULL) {
407        errno = EBADF;
408        return (int)LOS_NOK;
409    }
410
411    lfs_t *lfs = (lfs_t *)dir->dMp->mData;
412    lfs_dir_t *dirInfo = (lfs_dir_t *)dir->dData;
413
414    ret = lfs_dir_close(lfs, dirInfo);
415    if (ret != 0) {
416        errno = LittlefsErrno(ret);
417        ret = (int)LOS_NOK;
418    }
419
420    LOSCFG_FS_FREE_HOOK(dirInfo);
421    dir->dData = NULL;
422
423    return ret;
424}
425
426int LfsOpen(struct File *file, const char *pathName, int openFlag)
427{
428    int ret;
429    lfs_file_t *lfsHandle = NULL;
430
431    if ((pathName == NULL) || (file == NULL) || (file->fMp == NULL) ||
432        (file->fMp->mData == NULL)) {
433        errno = EFAULT;
434        return (int)LOS_NOK;
435    }
436
437    lfsHandle = (lfs_file_t *)LOSCFG_FS_MALLOC_HOOK(sizeof(lfs_file_t));
438    if (lfsHandle == NULL) {
439        errno = ENOMEM;
440        return (int)LOS_NOK;
441    }
442
443    int lfsOpenFlag = ConvertFlagToLfsOpenFlag(openFlag);
444    ret = lfs_file_open((lfs_t *)file->fMp->mData, lfsHandle, pathName, lfsOpenFlag);
445    if (ret != 0) {
446        LOSCFG_FS_FREE_HOOK(lfsHandle);
447        errno = LittlefsErrno(ret);
448        goto errout;
449    }
450
451    file->fData = (void *)lfsHandle;
452    return ret;
453
454errout:
455    return INVALID_FD;
456}
457
458int LfsRead(struct File *file, char *buf, size_t len)
459{
460    int ret;
461    struct MountPoint *mp = NULL;
462    lfs_file_t *lfsHandle = NULL;
463
464    if (buf == NULL) {
465        errno = EFAULT;
466        return (int)LOS_NOK;
467    }
468
469    if ((file == NULL) || (file->fData == NULL)) {
470        errno = EBADF;
471        return (int)LOS_NOK;
472    }
473
474    lfsHandle = (lfs_file_t *)file->fData;
475    mp = file->fMp;
476    if ((mp == NULL) || (mp->mData == NULL)) {
477        errno = EFAULT;
478        return (int)LOS_NOK;
479    }
480
481    ret = lfs_file_read((lfs_t *)mp->mData, lfsHandle, buf, len);
482    if (ret < 0) {
483        errno = LittlefsErrno(ret);
484        ret = (int)LOS_NOK;
485    }
486    return ret;
487}
488
489int LfsWrite(struct File *file, const char *buf, size_t len)
490{
491    int ret;
492    struct MountPoint *mp = NULL;
493    lfs_file_t *lfsHandle = NULL;
494
495    if (buf == NULL) {
496        errno = EFAULT;
497        return (int)LOS_NOK;
498    }
499
500    if ((file == NULL) || (file->fData == NULL)) {
501        errno = EBADF;
502        return (int)LOS_NOK;
503    }
504
505    lfsHandle = (lfs_file_t *)file->fData;
506    mp = file->fMp;
507    if ((mp == NULL) || (mp->mData == NULL)) {
508        errno = EFAULT;
509        return (int)LOS_NOK;
510    }
511
512    ret = lfs_file_write((lfs_t *)mp->mData, lfsHandle, buf, len);
513    if (ret < 0) {
514        errno = LittlefsErrno(ret);
515        ret = (int)LOS_NOK;
516    }
517    return ret;
518}
519
520off_t LfsSeek(struct File *file, off_t offset, int whence)
521{
522    off_t ret;
523    struct MountPoint *mp = NULL;
524    lfs_file_t *lfsHandle = NULL;
525
526    if ((file == NULL) || (file->fData == NULL)) {
527        errno = EBADF;
528        return (off_t)LOS_NOK;
529    }
530
531    lfsHandle = (lfs_file_t *)file->fData;
532    mp = file->fMp;
533    if ((mp == NULL) || (mp->mData == NULL)) {
534        errno = EFAULT;
535        return (off_t)LOS_NOK;
536    }
537
538    ret = (off_t)lfs_file_seek((lfs_t *)mp->mData, lfsHandle, offset, whence);
539    if (ret < 0) {
540        errno = LittlefsErrno(ret);
541        ret = (off_t)LOS_NOK;
542    }
543
544    return ret;
545}
546
547int LfsClose(struct File *file)
548{
549    int ret;
550    struct MountPoint *mp = NULL;
551    lfs_file_t *lfsHandle = NULL;
552
553    if ((file == NULL) || (file->fData == NULL)) {
554        errno = EBADF;
555        return (int)LOS_NOK;
556    }
557
558    lfsHandle = (lfs_file_t *)file->fData;
559    mp = file->fMp;
560    if ((mp == NULL) || (mp->mData == NULL)) {
561        errno = EFAULT;
562        return (int)LOS_NOK;
563    }
564
565    ret = lfs_file_close((lfs_t *)mp->mData, lfsHandle);
566    if (ret != 0) {
567        errno = LittlefsErrno(ret);
568        ret = (int)LOS_NOK;
569    }
570
571    LOSCFG_FS_FREE_HOOK(file->fData);
572    file->fData = NULL;
573    return ret;
574}
575
576int LfsRename(struct MountPoint *mp, const char *oldName, const char *newName)
577{
578    int ret;
579
580    if ((mp == NULL) || (oldName == NULL) || (newName == NULL)) {
581        errno = EFAULT;
582        return (int)LOS_NOK;
583    }
584
585    if (mp->mData == NULL) {
586        errno = ENOENT;
587        return (int)LOS_NOK;
588    }
589
590    ret = lfs_rename((lfs_t *)mp->mData, oldName, newName);
591    if (ret != 0) {
592        errno = LittlefsErrno(ret);
593        ret = (int)LOS_NOK;
594    }
595
596    return ret;
597}
598
599int LfsStat(struct MountPoint *mp, const char *path, struct stat *buf)
600{
601    int ret;
602    struct lfs_info info;
603
604    if ((mp == NULL) || (path == NULL) || (buf == NULL)) {
605        errno = EFAULT;
606        return (int)LOS_NOK;
607    }
608
609    if (mp->mData == NULL) {
610        errno = ENOENT;
611        return (int)LOS_NOK;
612    }
613
614    ret = lfs_stat((lfs_t *)mp->mData, path, &info);
615    if (ret == 0) {
616        buf->st_size = info.size;
617        if (info.type == LFS_TYPE_REG) {
618            buf->st_mode = S_IFREG;
619        } else {
620            buf->st_mode = S_IFDIR;
621        }
622    } else {
623        errno = LittlefsErrno(ret);
624        ret = (int)LOS_NOK;
625    }
626
627    return ret;
628}
629
630int LfsSync(struct File *file)
631{
632    int ret;
633    struct MountPoint *mp = NULL;
634
635    if ((file == NULL) || (file->fData == NULL)) {
636        errno = EBADF;
637        return (int)LOS_NOK;
638    }
639
640    if ((file->fMp == NULL) || (file->fMp->mData == NULL)) {
641        errno = EFAULT;
642        return (int)LOS_NOK;
643    }
644
645    mp = file->fMp;
646    ret = lfs_file_sync((lfs_t *)mp->mData, (lfs_file_t *)file->fData);
647    if (ret != 0) {
648        errno = LittlefsErrno(ret);
649        ret = (int)LOS_NOK;
650    }
651    return ret;
652}
653
654int LfsFormat(const char *partName, void *privData)
655{
656    int ret;
657    lfs_t lfs = {0};
658    struct lfs_config cfg = {0};
659
660    (void)partName;
661
662    LfsConfigAdapter((struct PartitionCfg *)privData, &cfg);
663
664    ret = lfs_format(&lfs, &cfg);
665    if (ret != 0) {
666        errno = LittlefsErrno(ret);
667        ret = (int)LOS_NOK;
668    }
669    return ret;
670}
671
672static struct MountOps g_lfsMnt = {
673    .mount = LfsMount,
674    .umount = LfsUmount,
675    .umount2 = NULL,
676    .statfs = NULL,
677};
678
679static struct FileOps g_lfsFops = {
680    .open = LfsOpen,
681    .close = LfsClose,
682    .read = LfsRead,
683    .write = LfsWrite,
684    .lseek = LfsSeek,
685    .stat = LfsStat,
686    .truncate = NULL,
687    .unlink = LfsUnlink,
688    .rename = LfsRename,
689    .ioctl = NULL, /* not support */
690    .sync = LfsSync,
691    .rmdir = LfsRmdir,
692    .opendir = LfsOpendir,
693    .readdir = LfsReaddir,
694    .closedir = LfsClosedir,
695    .mkdir = LfsMkdir,
696};
697
698static struct FsManagement g_lfsMgt = {
699    .fdisk = NULL,
700    .format = LfsFormat,
701};
702
703void LfsInit(void)
704{
705    (void)OsFsRegister("littlefs", &g_lfsMnt, &g_lfsFops, &g_lfsMgt);
706}
707