LCOV - code coverage report
Current view: top level - extmod - vfs_lfsx.c (source / functions) Hit Total Coverage
Test: unix_coverage_v1.22.0-335-g9c7f0659e.info Lines: 263 263 100.0 %
Date: 2024-04-24 08:31:58 Functions: 48 48 100.0 %
Branches: 94 100 94.0 %

           Branch data     Line data    Source code
       1                 :            : /*
       2                 :            :  * This file is part of the MicroPython project, http://micropython.org/
       3                 :            :  *
       4                 :            :  * The MIT License (MIT)
       5                 :            :  *
       6                 :            :  * Copyright (c) 2019-2020 Damien P. George
       7                 :            :  *
       8                 :            :  * Permission is hereby granted, free of charge, to any person obtaining a copy
       9                 :            :  * of this software and associated documentation files (the "Software"), to deal
      10                 :            :  * in the Software without restriction, including without limitation the rights
      11                 :            :  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
      12                 :            :  * copies of the Software, and to permit persons to whom the Software is
      13                 :            :  * furnished to do so, subject to the following conditions:
      14                 :            :  *
      15                 :            :  * The above copyright notice and this permission notice shall be included in
      16                 :            :  * all copies or substantial portions of the Software.
      17                 :            :  *
      18                 :            :  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
      19                 :            :  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
      20                 :            :  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
      21                 :            :  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
      22                 :            :  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
      23                 :            :  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
      24                 :            :  * THE SOFTWARE.
      25                 :            :  */
      26                 :            : 
      27                 :            : // This file should be compiled when included from vfs_lfs.c.
      28                 :            : #if defined(LFS_BUILD_VERSION)
      29                 :            : 
      30                 :            : #include <stdio.h>
      31                 :            : #include <string.h>
      32                 :            : 
      33                 :            : #include "py/runtime.h"
      34                 :            : #include "py/stream.h"
      35                 :            : #include "py/binary.h"
      36                 :            : #include "py/objarray.h"
      37                 :            : #include "py/objstr.h"
      38                 :            : #include "py/mperrno.h"
      39                 :            : #include "extmod/vfs.h"
      40                 :            : #include "shared/timeutils/timeutils.h"
      41                 :            : 
      42                 :            : #if !MICROPY_ENABLE_FINALISER
      43                 :            : #error "MICROPY_VFS_LFS requires MICROPY_ENABLE_FINALISER"
      44                 :            : #endif
      45                 :            : 
      46                 :       1202 : static int MP_VFS_LFSx(dev_ioctl)(const struct LFSx_API (config) * c, int cmd, int arg, bool must_return_int) {
      47                 :       1202 :     mp_obj_t ret = mp_vfs_blockdev_ioctl(c->context, cmd, arg);
      48                 :       1202 :     int ret_i = 0;
      49         [ +  + ]:       1202 :     if (must_return_int || ret != mp_const_none) {
      50                 :        610 :         ret_i = mp_obj_get_int(ret);
      51                 :            :     }
      52                 :       1202 :     return ret_i;
      53                 :            : }
      54                 :            : 
      55                 :      17816 : static int MP_VFS_LFSx(dev_read)(const struct LFSx_API (config) * c, LFSx_API(block_t) block, LFSx_API(off_t) off, void *buffer, LFSx_API(size_t) size) {
      56                 :      17816 :     return mp_vfs_blockdev_read_ext(c->context, block, off, size, buffer);
      57                 :            : }
      58                 :            : 
      59                 :       1186 : static int MP_VFS_LFSx(dev_prog)(const struct LFSx_API (config) * c, LFSx_API(block_t) block, LFSx_API(off_t) off, const void *buffer, LFSx_API(size_t) size) {
      60                 :       1186 :     return mp_vfs_blockdev_write_ext(c->context, block, off, size, buffer);
      61                 :            : }
      62                 :            : 
      63                 :        394 : static int MP_VFS_LFSx(dev_erase)(const struct LFSx_API (config) * c, LFSx_API(block_t) block) {
      64                 :        394 :     return MP_VFS_LFSx(dev_ioctl)(c, MP_BLOCKDEV_IOCTL_BLOCK_ERASE, block, true);
      65                 :            : }
      66                 :            : 
      67                 :        484 : static int MP_VFS_LFSx(dev_sync)(const struct LFSx_API (config) * c) {
      68                 :        484 :     return MP_VFS_LFSx(dev_ioctl)(c, MP_BLOCKDEV_IOCTL_SYNC, 0, false);
      69                 :            : }
      70                 :            : 
      71                 :        108 : static void MP_VFS_LFSx(init_config)(MP_OBJ_VFS_LFSx * self, mp_obj_t bdev, size_t read_size, size_t prog_size, size_t lookahead) {
      72                 :        108 :     self->blockdev.flags = MP_BLOCKDEV_FLAG_FREE_OBJ;
      73                 :        108 :     mp_vfs_blockdev_init(&self->blockdev, bdev);
      74                 :            : 
      75                 :        108 :     struct LFSx_API (config) * config = &self->config;
      76                 :        108 :     memset(config, 0, sizeof(*config));
      77                 :            : 
      78                 :        108 :     config->context = &self->blockdev;
      79                 :            : 
      80                 :        108 :     config->read = MP_VFS_LFSx(dev_read);
      81                 :        108 :     config->prog = MP_VFS_LFSx(dev_prog);
      82                 :        108 :     config->erase = MP_VFS_LFSx(dev_erase);
      83                 :        108 :     config->sync = MP_VFS_LFSx(dev_sync);
      84                 :            : 
      85                 :        108 :     MP_VFS_LFSx(dev_ioctl)(config, MP_BLOCKDEV_IOCTL_INIT, 1, false); // initialise block device
      86                 :        108 :     int bs = MP_VFS_LFSx(dev_ioctl)(config, MP_BLOCKDEV_IOCTL_BLOCK_SIZE, 0, true); // get block size
      87                 :        108 :     int bc = MP_VFS_LFSx(dev_ioctl)(config, MP_BLOCKDEV_IOCTL_BLOCK_COUNT, 0, true); // get block count
      88                 :        108 :     self->blockdev.block_size = bs;
      89                 :            : 
      90                 :        108 :     config->read_size = read_size;
      91                 :        108 :     config->prog_size = prog_size;
      92                 :        108 :     config->block_size = bs;
      93                 :        108 :     config->block_count = bc;
      94                 :            : 
      95                 :            :     #if LFS_BUILD_VERSION == 1
      96                 :         44 :     config->lookahead = lookahead;
      97                 :         44 :     config->read_buffer = m_new(uint8_t, config->read_size);
      98                 :         44 :     config->prog_buffer = m_new(uint8_t, config->prog_size);
      99                 :         44 :     config->lookahead_buffer = m_new(uint8_t, config->lookahead / 8);
     100                 :            :     #else
     101                 :         64 :     config->block_cycles = 100;
     102                 :         64 :     config->cache_size = MIN(config->block_size, (4 * MAX(read_size, prog_size)));
     103                 :         64 :     config->lookahead_size = lookahead;
     104                 :         64 :     config->read_buffer = m_new(uint8_t, config->cache_size);
     105                 :         64 :     config->prog_buffer = m_new(uint8_t, config->cache_size);
     106                 :         64 :     config->lookahead_buffer = m_new(uint8_t, config->lookahead_size);
     107                 :            :     #endif
     108                 :        108 : }
     109                 :            : 
     110                 :        528 : const char *MP_VFS_LFSx(make_path)(MP_OBJ_VFS_LFSx * self, mp_obj_t path_in) {
     111                 :        528 :     const char *path = mp_obj_str_get_str(path_in);
     112         [ +  + ]:        528 :     if (path[0] != '/') {
     113         [ +  - ]:        328 :         size_t l = vstr_len(&self->cur_dir);
     114         [ +  - ]:        328 :         if (l > 0) {
     115                 :        328 :             vstr_add_str(&self->cur_dir, path);
     116                 :        328 :             path = vstr_null_terminated_str(&self->cur_dir);
     117                 :        328 :             self->cur_dir.len = l;
     118                 :            :         }
     119                 :            :     }
     120                 :        528 :     return path;
     121                 :            : }
     122                 :            : 
     123                 :         62 : static mp_obj_t MP_VFS_LFSx(make_new)(const mp_obj_type_t * type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) {
     124                 :         62 :     mp_arg_val_t args[MP_ARRAY_SIZE(lfs_make_allowed_args)];
     125                 :         62 :     mp_arg_parse_all_kw_array(n_args, n_kw, all_args, MP_ARRAY_SIZE(lfs_make_allowed_args), lfs_make_allowed_args, args);
     126                 :            : 
     127                 :         62 :     MP_OBJ_VFS_LFSx *self = m_new0(MP_OBJ_VFS_LFSx, 1);
     128                 :         62 :     self->base.type = type;
     129                 :         62 :     vstr_init(&self->cur_dir, 16);
     130                 :         62 :     vstr_add_byte(&self->cur_dir, '/');
     131                 :            :     #if LFS_BUILD_VERSION == 2
     132                 :         38 :     self->enable_mtime = args[LFS_MAKE_ARG_mtime].u_bool;
     133                 :            :     #endif
     134                 :         62 :     MP_VFS_LFSx(init_config)(self, args[LFS_MAKE_ARG_bdev].u_obj,
     135                 :         62 :         args[LFS_MAKE_ARG_readsize].u_int, args[LFS_MAKE_ARG_progsize].u_int, args[LFS_MAKE_ARG_lookahead].u_int);
     136                 :         62 :     int ret = LFSx_API(mount)(&self->lfs, &self->config);
     137         [ +  + ]:         62 :     if (ret < 0) {
     138                 :          4 :         mp_raise_OSError(-ret);
     139                 :            :     }
     140                 :         58 :     return MP_OBJ_FROM_PTR(self);
     141                 :            : }
     142                 :            : 
     143                 :         46 : static mp_obj_t MP_VFS_LFSx(mkfs)(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
     144                 :         46 :     mp_arg_val_t args[MP_ARRAY_SIZE(lfs_make_allowed_args)];
     145                 :         46 :     mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(lfs_make_allowed_args), lfs_make_allowed_args, args);
     146                 :            : 
     147                 :         46 :     MP_OBJ_VFS_LFSx self;
     148                 :         46 :     MP_VFS_LFSx(init_config)(&self, args[LFS_MAKE_ARG_bdev].u_obj,
     149                 :         46 :         args[LFS_MAKE_ARG_readsize].u_int, args[LFS_MAKE_ARG_progsize].u_int, args[LFS_MAKE_ARG_lookahead].u_int);
     150                 :         46 :     int ret = LFSx_API(format)(&self.lfs, &self.config);
     151         [ +  + ]:         46 :     if (ret < 0) {
     152                 :          4 :         mp_raise_OSError(-ret);
     153                 :            :     }
     154                 :         42 :     return mp_const_none;
     155                 :            : }
     156                 :            : static MP_DEFINE_CONST_FUN_OBJ_KW(MP_VFS_LFSx(mkfs_fun_obj), 0, MP_VFS_LFSx(mkfs));
     157                 :            : static MP_DEFINE_CONST_STATICMETHOD_OBJ(MP_VFS_LFSx(mkfs_obj), MP_ROM_PTR(&MP_VFS_LFSx(mkfs_fun_obj)));
     158                 :            : 
     159                 :            : // Implementation of mp_vfs_lfs_file_open is provided in vfs_lfsx_file.c
     160                 :            : static MP_DEFINE_CONST_FUN_OBJ_3(MP_VFS_LFSx(open_obj), MP_VFS_LFSx(file_open));
     161                 :            : 
     162                 :            : typedef struct MP_VFS_LFSx (_ilistdir_it_t) {
     163                 :            :     mp_obj_base_t base;
     164                 :            :     mp_fun_1_t iternext;
     165                 :            :     mp_fun_1_t finaliser;
     166                 :            :     bool is_str;
     167                 :            :     MP_OBJ_VFS_LFSx *vfs;
     168                 :            :     LFSx_API(dir_t) dir;
     169                 :            : } MP_VFS_LFSx(ilistdir_it_t);
     170                 :            : 
     171                 :        266 : static mp_obj_t MP_VFS_LFSx(ilistdir_it_iternext)(mp_obj_t self_in) {
     172                 :        266 :     MP_VFS_LFSx(ilistdir_it_t) * self = MP_OBJ_TO_PTR(self_in);
     173                 :            : 
     174         [ +  + ]:        266 :     if (self->vfs == NULL) {
     175                 :            :         return MP_OBJ_STOP_ITERATION;
     176                 :            :     }
     177                 :            : 
     178                 :        458 :     struct LFSx_API (info) info;
     179                 :        458 :     for (;;) {
     180                 :        458 :         int ret = LFSx_API(dir_read)(&self->vfs->lfs, &self->dir, &info);
     181         [ +  + ]:        458 :         if (ret == 0) {
     182                 :         66 :             LFSx_API(dir_close)(&self->vfs->lfs, &self->dir);
     183                 :         66 :             self->vfs = NULL;
     184                 :         66 :             return MP_OBJ_STOP_ITERATION;
     185                 :            :         }
     186   [ +  +  +  + ]:        392 :         if (!(info.name[0] == '.' && (info.name[1] == '\0'
     187         [ +  - ]:        106 :                                       || (info.name[1] == '.' && info.name[2] == '\0')))) {
     188                 :            :             break;
     189                 :            :         }
     190                 :            :     }
     191                 :            : 
     192                 :            :     // make 4-tuple with info about this entry
     193                 :        180 :     mp_obj_tuple_t *t = MP_OBJ_TO_PTR(mp_obj_new_tuple(4, NULL));
     194         [ +  + ]:        180 :     if (self->is_str) {
     195                 :        176 :         t->items[0] = mp_obj_new_str(info.name, strlen(info.name));
     196                 :            :     } else {
     197                 :          4 :         t->items[0] = mp_obj_new_bytes((const byte *)info.name, strlen(info.name));
     198                 :            :     }
     199         [ +  + ]:        180 :     t->items[1] = MP_OBJ_NEW_SMALL_INT(info.type == LFSx_MACRO(_TYPE_REG) ? MP_S_IFREG : MP_S_IFDIR);
     200                 :        180 :     t->items[2] = MP_OBJ_NEW_SMALL_INT(0); // no inode number
     201                 :        180 :     t->items[3] = MP_OBJ_NEW_SMALL_INT(info.size);
     202                 :            : 
     203                 :        180 :     return MP_OBJ_FROM_PTR(t);
     204                 :            : }
     205                 :            : 
     206                 :        110 : static mp_obj_t MP_VFS_LFSx(ilistdir_it_del)(mp_obj_t self_in) {
     207                 :        110 :     MP_VFS_LFSx(ilistdir_it_t) * self = MP_OBJ_TO_PTR(self_in);
     208         [ +  + ]:        110 :     if (self->vfs != NULL) {
     209                 :         40 :         LFSx_API(dir_close)(&self->vfs->lfs, &self->dir);
     210                 :            :     }
     211                 :        110 :     return mp_const_none;
     212                 :            : }
     213                 :            : 
     214                 :        110 : static mp_obj_t MP_VFS_LFSx(ilistdir_func)(size_t n_args, const mp_obj_t *args) {
     215                 :        110 :     MP_OBJ_VFS_LFSx *self = MP_OBJ_TO_PTR(args[0]);
     216                 :        110 :     bool is_str_type = true;
     217                 :        110 :     const char *path;
     218         [ +  + ]:        110 :     if (n_args == 2) {
     219         [ +  + ]:         78 :         if (mp_obj_get_type(args[1]) == &mp_type_bytes) {
     220                 :          4 :             is_str_type = false;
     221                 :            :         }
     222                 :         78 :         path = MP_VFS_LFSx(make_path)(self, args[1]);
     223                 :            :     } else {
     224                 :         32 :         path = vstr_null_terminated_str(&self->cur_dir);
     225                 :            :     }
     226                 :            : 
     227                 :        110 :     MP_VFS_LFSx(ilistdir_it_t) * iter = mp_obj_malloc_with_finaliser(MP_VFS_LFSx(ilistdir_it_t), &mp_type_polymorph_iter_with_finaliser);
     228                 :            : 
     229                 :        110 :     iter->iternext = MP_VFS_LFSx(ilistdir_it_iternext);
     230                 :        110 :     iter->finaliser = MP_VFS_LFSx(ilistdir_it_del);
     231                 :        110 :     iter->is_str = is_str_type;
     232                 :        110 :     int ret = LFSx_API(dir_open)(&self->lfs, &iter->dir, path);
     233         [ +  + ]:        110 :     if (ret < 0) {
     234                 :          4 :         mp_raise_OSError(-ret);
     235                 :            :     }
     236                 :        106 :     iter->vfs = self;
     237                 :        106 :     return MP_OBJ_FROM_PTR(iter);
     238                 :            : }
     239                 :            : static MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(MP_VFS_LFSx(ilistdir_obj), 1, 2, MP_VFS_LFSx(ilistdir_func));
     240                 :            : 
     241                 :         12 : static mp_obj_t MP_VFS_LFSx(remove)(mp_obj_t self_in, mp_obj_t path_in) {
     242                 :         12 :     MP_OBJ_VFS_LFSx *self = MP_OBJ_TO_PTR(self_in);
     243                 :         12 :     const char *path = MP_VFS_LFSx(make_path)(self, path_in);
     244                 :         12 :     int ret = LFSx_API(remove)(&self->lfs, path);
     245         [ +  + ]:         12 :     if (ret < 0) {
     246                 :          4 :         mp_raise_OSError(-ret);
     247                 :            :     }
     248                 :          8 :     return mp_const_none;
     249                 :            : }
     250                 :            : static MP_DEFINE_CONST_FUN_OBJ_2(MP_VFS_LFSx(remove_obj), MP_VFS_LFSx(remove));
     251                 :            : 
     252                 :         40 : static mp_obj_t MP_VFS_LFSx(rmdir)(mp_obj_t self_in, mp_obj_t path_in) {
     253                 :         40 :     MP_OBJ_VFS_LFSx *self = MP_OBJ_TO_PTR(self_in);
     254                 :         40 :     const char *path = MP_VFS_LFSx(make_path)(self, path_in);
     255                 :         40 :     int ret = LFSx_API(remove)(&self->lfs, path);
     256         [ +  + ]:         40 :     if (ret < 0) {
     257                 :          4 :         mp_raise_OSError(-ret);
     258                 :            :     }
     259                 :         36 :     return mp_const_none;
     260                 :            : }
     261                 :            : static MP_DEFINE_CONST_FUN_OBJ_2(MP_VFS_LFSx(rmdir_obj), MP_VFS_LFSx(rmdir));
     262                 :            : 
     263                 :         20 : static mp_obj_t MP_VFS_LFSx(rename)(mp_obj_t self_in, mp_obj_t path_old_in, mp_obj_t path_new_in) {
     264                 :         20 :     MP_OBJ_VFS_LFSx *self = MP_OBJ_TO_PTR(self_in);
     265                 :         20 :     const char *path_old = MP_VFS_LFSx(make_path)(self, path_old_in);
     266                 :         20 :     const char *path = mp_obj_str_get_str(path_new_in);
     267                 :         20 :     vstr_t path_new;
     268                 :         20 :     vstr_init(&path_new, vstr_len(&self->cur_dir));
     269         [ +  + ]:         20 :     if (path[0] != '/') {
     270                 :         12 :         vstr_add_strn(&path_new, vstr_str(&self->cur_dir), vstr_len(&self->cur_dir));
     271                 :            :     }
     272                 :         20 :     vstr_add_str(&path_new, path);
     273                 :         20 :     int ret = LFSx_API(rename)(&self->lfs, path_old, vstr_null_terminated_str(&path_new));
     274                 :         20 :     vstr_clear(&path_new);
     275         [ +  + ]:         20 :     if (ret < 0) {
     276                 :          4 :         mp_raise_OSError(-ret);
     277                 :            :     }
     278                 :         16 :     return mp_const_none;
     279                 :            : }
     280                 :            : static MP_DEFINE_CONST_FUN_OBJ_3(MP_VFS_LFSx(rename_obj), MP_VFS_LFSx(rename));
     281                 :            : 
     282                 :         58 : static mp_obj_t MP_VFS_LFSx(mkdir)(mp_obj_t self_in, mp_obj_t path_o) {
     283                 :         58 :     MP_OBJ_VFS_LFSx *self = MP_OBJ_TO_PTR(self_in);
     284                 :         58 :     const char *path = MP_VFS_LFSx(make_path)(self, path_o);
     285                 :         58 :     int ret = LFSx_API(mkdir)(&self->lfs, path);
     286         [ +  + ]:         58 :     if (ret < 0) {
     287                 :          4 :         mp_raise_OSError(-ret);
     288                 :            :     }
     289                 :         54 :     return mp_const_none;
     290                 :            : }
     291                 :            : static MP_DEFINE_CONST_FUN_OBJ_2(MP_VFS_LFSx(mkdir_obj), MP_VFS_LFSx(mkdir));
     292                 :            : 
     293                 :         68 : static mp_obj_t MP_VFS_LFSx(chdir)(mp_obj_t self_in, mp_obj_t path_in) {
     294                 :         68 :     MP_OBJ_VFS_LFSx *self = MP_OBJ_TO_PTR(self_in);
     295                 :            : 
     296                 :            :     // Check path exists
     297                 :         68 :     const char *path = MP_VFS_LFSx(make_path)(self, path_in);
     298         [ +  + ]:         68 :     if (path[1] != '\0') {
     299                 :            :         // Not at root, check it exists
     300                 :         56 :         struct LFSx_API (info) info;
     301                 :         56 :         int ret = LFSx_API(stat)(&self->lfs, path, &info);
     302   [ +  +  +  + ]:         56 :         if (ret < 0 || info.type != LFSx_MACRO(_TYPE_DIR)) {
     303                 :          8 :             mp_raise_OSError(-MP_ENOENT);
     304                 :            :         }
     305                 :            :     }
     306                 :            : 
     307                 :            :     // Update cur_dir with new path
     308         [ +  + ]:         60 :     if (path == vstr_str(&self->cur_dir)) {
     309                 :         36 :         self->cur_dir.len = strlen(path);
     310                 :            :     } else {
     311                 :         24 :         vstr_reset(&self->cur_dir);
     312                 :         24 :         vstr_add_str(&self->cur_dir, path);
     313                 :            :     }
     314                 :            : 
     315                 :            :     // If not at root add trailing / to make it easy to build paths
     316                 :            :     // and then normalise the path
     317         [ +  + ]:         60 :     if (vstr_len(&self->cur_dir) != 1) {
     318                 :         48 :         vstr_add_byte(&self->cur_dir, '/');
     319                 :            : 
     320                 :            :         #define CWD_LEN (vstr_len(&self->cur_dir))
     321                 :         48 :         size_t to = 1;
     322                 :         48 :         size_t from = 1;
     323                 :         48 :         char *cwd = vstr_str(&self->cur_dir);
     324         [ +  + ]:        152 :         while (from < CWD_LEN) {
     325   [ +  +  +  + ]:        112 :             for (; from < CWD_LEN && cwd[from] == '/'; ++from) {
     326                 :            :                 // Scan for the start
     327                 :          8 :             }
     328         [ +  + ]:        104 :             if (from > to) {
     329                 :            :                 // Found excessive slash chars, squeeze them out
     330                 :          8 :                 vstr_cut_out_bytes(&self->cur_dir, to, from - to);
     331                 :          8 :                 from = to;
     332                 :            :             }
     333   [ +  +  +  + ]:        604 :             for (; from < CWD_LEN && cwd[from] != '/'; ++from) {
     334                 :            :                 // Scan for the next /
     335                 :        500 :             }
     336   [ +  +  +  - ]:        104 :             if ((from - to) == 1 && cwd[to] == '.') {
     337                 :            :                 // './', ignore
     338                 :         12 :                 vstr_cut_out_bytes(&self->cur_dir, to, ++from - to);
     339                 :         12 :                 from = to;
     340   [ +  +  +  -  :         92 :             } else if ((from - to) == 2 && cwd[to] == '.' && cwd[to + 1] == '.') {
                   +  - ]
     341                 :            :                 // '../', skip back
     342         [ +  + ]:         24 :                 if (to > 1) {
     343                 :            :                     // Only skip back if not at the tip
     344   [ +  +  +  + ]:        160 :                     for (--to; to > 1 && cwd[to - 1] != '/'; --to) {
     345                 :            :                         // Skip back
     346                 :            :                     }
     347                 :            :                 }
     348                 :         24 :                 vstr_cut_out_bytes(&self->cur_dir, to, ++from - to);
     349                 :         24 :                 from = to;
     350                 :            :             } else {
     351                 :            :                 // Normal element, keep it and just move the offset
     352                 :         68 :                 to = ++from;
     353                 :            :             }
     354                 :            :         }
     355                 :            :     }
     356                 :            : 
     357                 :         60 :     return mp_const_none;
     358                 :            : }
     359                 :            : static MP_DEFINE_CONST_FUN_OBJ_2(MP_VFS_LFSx(chdir_obj), MP_VFS_LFSx(chdir));
     360                 :            : 
     361                 :         60 : static mp_obj_t MP_VFS_LFSx(getcwd)(mp_obj_t self_in) {
     362                 :         60 :     MP_OBJ_VFS_LFSx *self = MP_OBJ_TO_PTR(self_in);
     363         [ +  + ]:         60 :     if (vstr_len(&self->cur_dir) == 1) {
     364                 :            :         return MP_OBJ_NEW_QSTR(MP_QSTR__slash_);
     365                 :            :     } else {
     366                 :            :         // don't include trailing /
     367                 :         28 :         return mp_obj_new_str(self->cur_dir.buf, self->cur_dir.len - 1);
     368                 :            :     }
     369                 :            : }
     370                 :            : static MP_DEFINE_CONST_FUN_OBJ_1(MP_VFS_LFSx(getcwd_obj), MP_VFS_LFSx(getcwd));
     371                 :            : 
     372                 :         38 : static mp_obj_t MP_VFS_LFSx(stat)(mp_obj_t self_in, mp_obj_t path_in) {
     373                 :         38 :     MP_OBJ_VFS_LFSx *self = MP_OBJ_TO_PTR(self_in);
     374                 :         38 :     const char *path = MP_VFS_LFSx(make_path)(self, path_in);
     375                 :         38 :     struct LFSx_API (info) info;
     376                 :         38 :     int ret = LFSx_API(stat)(&self->lfs, path, &info);
     377         [ +  + ]:         38 :     if (ret < 0) {
     378                 :          4 :         mp_raise_OSError(-ret);
     379                 :            :     }
     380                 :            : 
     381                 :         34 :     mp_uint_t mtime = 0;
     382                 :            :     #if LFS_BUILD_VERSION == 2
     383                 :         26 :     uint8_t mtime_buf[8];
     384                 :         26 :     lfs2_ssize_t sz = lfs2_getattr(&self->lfs, path, LFS_ATTR_MTIME, &mtime_buf, sizeof(mtime_buf));
     385         [ +  + ]:         26 :     if (sz == sizeof(mtime_buf)) {
     386                 :            :         uint64_t ns = 0;
     387         [ +  + ]:        216 :         for (size_t i = sizeof(mtime_buf); i > 0; --i) {
     388                 :        192 :             ns = ns << 8 | mtime_buf[i - 1];
     389                 :            :         }
     390                 :            :         // On-disk storage of timestamps uses 1970 as the Epoch, so convert to host's Epoch.
     391                 :         24 :         mtime = timeutils_seconds_since_epoch_from_nanoseconds_since_1970(ns);
     392                 :            :     }
     393                 :            :     #endif
     394                 :            : 
     395                 :         34 :     mp_obj_tuple_t *t = MP_OBJ_TO_PTR(mp_obj_new_tuple(10, NULL));
     396         [ +  + ]:         34 :     t->items[0] = MP_OBJ_NEW_SMALL_INT(info.type == LFSx_MACRO(_TYPE_REG) ? MP_S_IFREG : MP_S_IFDIR); // st_mode
     397                 :         34 :     t->items[1] = MP_OBJ_NEW_SMALL_INT(0); // st_ino
     398                 :         34 :     t->items[2] = MP_OBJ_NEW_SMALL_INT(0); // st_dev
     399                 :         34 :     t->items[3] = MP_OBJ_NEW_SMALL_INT(0); // st_nlink
     400                 :         34 :     t->items[4] = MP_OBJ_NEW_SMALL_INT(0); // st_uid
     401                 :         34 :     t->items[5] = MP_OBJ_NEW_SMALL_INT(0); // st_gid
     402                 :         34 :     t->items[6] = mp_obj_new_int_from_uint(info.size); // st_size
     403                 :         34 :     t->items[7] = mp_obj_new_int_from_uint(mtime); // st_atime
     404                 :         34 :     t->items[8] = mp_obj_new_int_from_uint(mtime); // st_mtime
     405                 :         34 :     t->items[9] = mp_obj_new_int_from_uint(mtime); // st_ctime
     406                 :            : 
     407                 :         34 :     return MP_OBJ_FROM_PTR(t);
     408                 :            : }
     409                 :            : static MP_DEFINE_CONST_FUN_OBJ_2(MP_VFS_LFSx(stat_obj), MP_VFS_LFSx(stat));
     410                 :            : 
     411                 :        132 : static int LFSx_API(traverse_cb)(void *data, LFSx_API(block_t) bl) {
     412                 :        132 :     (void)bl;
     413                 :        132 :     uint32_t *n = (uint32_t *)data;
     414                 :        132 :     *n += 1;
     415                 :        132 :     return LFSx_MACRO(_ERR_OK);
     416                 :            : }
     417                 :            : 
     418                 :         18 : static mp_obj_t MP_VFS_LFSx(statvfs)(mp_obj_t self_in, mp_obj_t path_in) {
     419                 :         18 :     (void)path_in;
     420                 :         18 :     MP_OBJ_VFS_LFSx *self = MP_OBJ_TO_PTR(self_in);
     421                 :         18 :     uint32_t n_used_blocks = 0;
     422                 :            :     #if LFS_BUILD_VERSION == 1
     423                 :          8 :     int ret = LFSx_API(traverse)(&self->lfs, LFSx_API(traverse_cb), &n_used_blocks);
     424                 :            :     #else
     425                 :         10 :     int ret = LFSx_API(fs_traverse)(&self->lfs, LFSx_API(traverse_cb), &n_used_blocks);
     426                 :            :     #endif
     427         [ +  + ]:         18 :     if (ret < 0) {
     428                 :          4 :         mp_raise_OSError(-ret);
     429                 :            :     }
     430                 :            : 
     431                 :         14 :     mp_obj_tuple_t *t = MP_OBJ_TO_PTR(mp_obj_new_tuple(10, NULL));
     432                 :         14 :     t->items[0] = MP_OBJ_NEW_SMALL_INT(self->lfs.cfg->block_size); // f_bsize
     433                 :         14 :     t->items[1] = t->items[0]; // f_frsize
     434                 :         14 :     t->items[2] = MP_OBJ_NEW_SMALL_INT(self->lfs.cfg->block_count); // f_blocks
     435                 :         14 :     t->items[3] = MP_OBJ_NEW_SMALL_INT(self->lfs.cfg->block_count - n_used_blocks); // f_bfree
     436                 :         14 :     t->items[4] = t->items[3]; // f_bavail
     437                 :         14 :     t->items[5] = MP_OBJ_NEW_SMALL_INT(0); // f_files
     438                 :         14 :     t->items[6] = MP_OBJ_NEW_SMALL_INT(0); // f_ffree
     439                 :         14 :     t->items[7] = MP_OBJ_NEW_SMALL_INT(0); // f_favail
     440                 :         14 :     t->items[8] = MP_OBJ_NEW_SMALL_INT(0); // f_flags
     441                 :         14 :     t->items[9] = MP_OBJ_NEW_SMALL_INT(LFSx_MACRO(_NAME_MAX)); // f_namemax
     442                 :            : 
     443                 :         14 :     return MP_OBJ_FROM_PTR(t);
     444                 :            : }
     445                 :            : static MP_DEFINE_CONST_FUN_OBJ_2(MP_VFS_LFSx(statvfs_obj), MP_VFS_LFSx(statvfs));
     446                 :            : 
     447                 :         14 : static mp_obj_t MP_VFS_LFSx(mount)(mp_obj_t self_in, mp_obj_t readonly, mp_obj_t mkfs) {
     448                 :         14 :     MP_OBJ_VFS_LFSx *self = MP_OBJ_TO_PTR(self_in);
     449                 :         14 :     (void)mkfs;
     450                 :            : 
     451                 :            :     // Make block device read-only if requested.
     452         [ +  + ]:         14 :     if (mp_obj_is_true(readonly)) {
     453                 :          4 :         self->blockdev.writeblocks[0] = MP_OBJ_NULL;
     454                 :            :     }
     455                 :            : 
     456                 :            :     // Already called LFSx_API(mount) in MP_VFS_LFSx(make_new) so the filesystem is ready.
     457                 :            : 
     458                 :         14 :     return mp_const_none;
     459                 :            : }
     460                 :            : static MP_DEFINE_CONST_FUN_OBJ_3(MP_VFS_LFSx(mount_obj), MP_VFS_LFSx(mount));
     461                 :            : 
     462                 :         20 : static mp_obj_t MP_VFS_LFSx(umount)(mp_obj_t self_in) {
     463                 :         20 :     MP_OBJ_VFS_LFSx *self = MP_OBJ_TO_PTR(self_in);
     464                 :            :     // LFS unmount never fails
     465                 :         20 :     LFSx_API(unmount)(&self->lfs);
     466                 :         20 :     return mp_const_none;
     467                 :            : }
     468                 :            : static MP_DEFINE_CONST_FUN_OBJ_1(MP_VFS_LFSx(umount_obj), MP_VFS_LFSx(umount));
     469                 :            : 
     470                 :            : static const mp_rom_map_elem_t MP_VFS_LFSx(locals_dict_table)[] = {
     471                 :            :     { MP_ROM_QSTR(MP_QSTR_mkfs), MP_ROM_PTR(&MP_VFS_LFSx(mkfs_obj)) },
     472                 :            :     { MP_ROM_QSTR(MP_QSTR_open), MP_ROM_PTR(&MP_VFS_LFSx(open_obj)) },
     473                 :            :     { MP_ROM_QSTR(MP_QSTR_ilistdir), MP_ROM_PTR(&MP_VFS_LFSx(ilistdir_obj)) },
     474                 :            :     { MP_ROM_QSTR(MP_QSTR_mkdir), MP_ROM_PTR(&MP_VFS_LFSx(mkdir_obj)) },
     475                 :            :     { MP_ROM_QSTR(MP_QSTR_rmdir), MP_ROM_PTR(&MP_VFS_LFSx(rmdir_obj)) },
     476                 :            :     { MP_ROM_QSTR(MP_QSTR_chdir), MP_ROM_PTR(&MP_VFS_LFSx(chdir_obj)) },
     477                 :            :     { MP_ROM_QSTR(MP_QSTR_getcwd), MP_ROM_PTR(&MP_VFS_LFSx(getcwd_obj)) },
     478                 :            :     { MP_ROM_QSTR(MP_QSTR_remove), MP_ROM_PTR(&MP_VFS_LFSx(remove_obj)) },
     479                 :            :     { MP_ROM_QSTR(MP_QSTR_rename), MP_ROM_PTR(&MP_VFS_LFSx(rename_obj)) },
     480                 :            :     { MP_ROM_QSTR(MP_QSTR_stat), MP_ROM_PTR(&MP_VFS_LFSx(stat_obj)) },
     481                 :            :     { MP_ROM_QSTR(MP_QSTR_statvfs), MP_ROM_PTR(&MP_VFS_LFSx(statvfs_obj)) },
     482                 :            :     { MP_ROM_QSTR(MP_QSTR_mount), MP_ROM_PTR(&MP_VFS_LFSx(mount_obj)) },
     483                 :            :     { MP_ROM_QSTR(MP_QSTR_umount), MP_ROM_PTR(&MP_VFS_LFSx(umount_obj)) },
     484                 :            : };
     485                 :            : static MP_DEFINE_CONST_DICT(MP_VFS_LFSx(locals_dict), MP_VFS_LFSx(locals_dict_table));
     486                 :            : 
     487                 :         36 : static mp_import_stat_t MP_VFS_LFSx(import_stat)(void *self_in, const char *path) {
     488                 :         36 :     MP_OBJ_VFS_LFSx *self = self_in;
     489                 :         36 :     struct LFSx_API (info) info;
     490                 :         36 :     mp_obj_str_t path_obj = { { &mp_type_str }, 0, 0, (const byte *)path };
     491                 :         36 :     path = MP_VFS_LFSx(make_path)(self, MP_OBJ_FROM_PTR(&path_obj));
     492                 :         36 :     int ret = LFSx_API(stat)(&self->lfs, path, &info);
     493         [ +  + ]:         36 :     if (ret == 0) {
     494         [ +  + ]:         16 :         if (info.type == LFSx_MACRO(_TYPE_REG)) {
     495                 :            :             return MP_IMPORT_STAT_FILE;
     496                 :            :         } else {
     497                 :          4 :             return MP_IMPORT_STAT_DIR;
     498                 :            :         }
     499                 :            :     }
     500                 :            :     return MP_IMPORT_STAT_NO_EXIST;
     501                 :            : }
     502                 :            : 
     503                 :            : static const mp_vfs_proto_t MP_VFS_LFSx(proto) = {
     504                 :            :     .import_stat = MP_VFS_LFSx(import_stat),
     505                 :            : };
     506                 :            : 
     507                 :            : #if LFS_BUILD_VERSION == 1
     508                 :            : #define VFS_LFSx_QSTR MP_QSTR_VfsLfs1
     509                 :            : #else
     510                 :            : #define VFS_LFSx_QSTR MP_QSTR_VfsLfs2
     511                 :            : #endif
     512                 :            : 
     513                 :            : MP_DEFINE_CONST_OBJ_TYPE(
     514                 :            :     MP_TYPE_VFS_LFSx,
     515                 :            :     VFS_LFSx_QSTR,
     516                 :            :     MP_TYPE_FLAG_NONE,
     517                 :            :     make_new, MP_VFS_LFSx(make_new),
     518                 :            :     protocol, &MP_VFS_LFSx(proto),
     519                 :            :     locals_dict, &MP_VFS_LFSx(locals_dict)
     520                 :            :     );
     521                 :            : 
     522                 :            : #undef VFS_LFSx_QSTR
     523                 :            : 
     524                 :            : #endif // defined(LFS_BUILD_VERSION)

Generated by: LCOV version 1.15-5-g462f71d