LCOV - code coverage report
Current view: top level - extmod - vfs_rom.c (source / functions) Hit Total Coverage
Test: unix_coverage_v1.25.0-32-g076e07197.info Lines: 197 197 100.0 %
Date: 2025-04-24 18:23:45 Functions: 13 13 100.0 %
Branches: 86 92 93.5 %

           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) 2022 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                 :            : // ROMFS filesystem format
      28                 :            : // =======================
      29                 :            : //
      30                 :            : // ROMFS is a flexible and extensible filesystem format designed to represent a
      31                 :            : // directory hierarchy with files, where those files are read-only and their data
      32                 :            : // can be memory mapped.
      33                 :            : //
      34                 :            : // Concepts:
      35                 :            : // - varuint: An unsigned integer that is encoded in a variable number of bytes. It is
      36                 :            : //   stored big-endian with the high bit of the byte set if there are following bytes.
      37                 :            : // - record: A variable sized element with a type.  It is stored as two varuint's and then
      38                 :            : //   a payload.  The first varuint is the record kind and the second varuint is the
      39                 :            : //   payload length (which may be zero bytes long).
      40                 :            : //
      41                 :            : // A ROMFS filesystem is a record with record kind 0x14a6b1, chosen so the encoded value
      42                 :            : // is 0xd2-0xcd-0x31 which is "RM1" with the first two bytes having their high bit set.
      43                 :            : // If the ROMFS record's payload is non-empty then it contains records.
      44                 :            : //
      45                 :            : // Record types:
      46                 :            : // - 0 = unused, can be used to detect corruption of the filesystem.
      47                 :            : // - 1 = padding/comments, can contain any data in their payload.
      48                 :            : // - 2 = verbatim data, used to store file data.
      49                 :            : // - 3 = indirect data, pointer to offset within the ROMFS payload.
      50                 :            : // - 4 = a directory: payload contains a varuint which is the length of the directory
      51                 :            : //       name in bytes, then the name, then optional nested records for the contents
      52                 :            : //       of the directory (including optional metadata).
      53                 :            : // - 5 = a file: payload contains a varuint which is the length of the filename in bytes
      54                 :            : //       then the name, then optional nested records.
      55                 :            : //
      56                 :            : // Remarks:
      57                 :            : // - A varuint can be padded if needed by prepending with one or more 0x80 bytes.  This
      58                 :            : //   padding does not change any semantics.
      59                 :            : // - The size of the ROMFS record (including kind and length and payload) must be a
      60                 :            : //   multiple of 2 (because it's not possible to add a padding record of one byte).
      61                 :            : // - File data can be optionally aligned using padding records and/or indirect data
      62                 :            : //   records.
      63                 :            : // - There is no limit to the size of directory/file names or file data.
      64                 :            : //
      65                 :            : // Unknown record types must be skipped over.  They may in the future add optional
      66                 :            : // features, while still retaining backwards compatibility.  Such features may be:
      67                 :            : // - Alignment requirements of the ROMFS record.
      68                 :            : // - Timestamps on directories/files.
      69                 :            : // - A precomputed hash of a file, or other metadata.
      70                 :            : // - An optimised lookup table indexing the directory hierarchy.
      71                 :            : 
      72                 :            : #include <string.h>
      73                 :            : 
      74                 :            : #include "py/bc.h"
      75                 :            : #include "py/runtime.h"
      76                 :            : #include "py/mperrno.h"
      77                 :            : #include "extmod/vfs.h"
      78                 :            : #include "extmod/vfs_rom.h"
      79                 :            : 
      80                 :            : #if MICROPY_VFS_ROM
      81                 :            : 
      82                 :            : #define ROMFS_SIZE_MIN (4)
      83                 :            : #define ROMFS_HEADER_BYTE0 (0x80 | 'R')
      84                 :            : #define ROMFS_HEADER_BYTE1 (0x80 | 'M')
      85                 :            : #define ROMFS_HEADER_BYTE2 (0x00 | '1')
      86                 :            : 
      87                 :            : // Values for `record_kind_t`.
      88                 :            : #define ROMFS_RECORD_KIND_UNUSED (0)
      89                 :            : #define ROMFS_RECORD_KIND_PADDING (1)
      90                 :            : #define ROMFS_RECORD_KIND_DATA_VERBATIM (2)
      91                 :            : #define ROMFS_RECORD_KIND_DATA_POINTER (3)
      92                 :            : #define ROMFS_RECORD_KIND_DIRECTORY (4)
      93                 :            : #define ROMFS_RECORD_KIND_FILE (5)
      94                 :            : #define ROMFS_RECORD_KIND_FILESYSTEM (0x14a6b1)
      95                 :            : 
      96                 :            : typedef mp_uint_t record_kind_t;
      97                 :            : 
      98                 :            : struct _mp_obj_vfs_rom_t {
      99                 :            :     mp_obj_base_t base;
     100                 :            :     mp_obj_t memory;
     101                 :            :     const uint8_t *filesystem;
     102                 :            :     const uint8_t *filesystem_end;
     103                 :            : };
     104                 :            : 
     105                 :            : // Returns 0 for success, -1 for failure.
     106                 :       8288 : static int mp_decode_uint_checked(const uint8_t **ptr, const uint8_t *ptr_max, mp_uint_t *value_out) {
     107                 :       8288 :     mp_uint_t unum = 0;
     108                 :       8288 :     byte val;
     109                 :       8288 :     const uint8_t *p = *ptr;
     110                 :      15522 :     do {
     111         [ +  + ]:      15522 :         if (p >= ptr_max) {
     112                 :            :             return -1;
     113                 :            :         }
     114                 :      15504 :         val = *p++;
     115                 :      15504 :         unum = (unum << 7) | (val & 0x7f);
     116         [ +  + ]:      15504 :     } while ((val & 0x80) != 0);
     117                 :       8270 :     *ptr = p;
     118                 :       8270 :     *value_out = unum;
     119                 :       8270 :     return 0;
     120                 :            : }
     121                 :            : 
     122                 :       3984 : static record_kind_t extract_record(const uint8_t **fs, const uint8_t **fs_next, const uint8_t *fs_max) {
     123                 :       3984 :     mp_uint_t record_kind;
     124         [ +  + ]:       3984 :     if (mp_decode_uint_checked(fs, fs_max, &record_kind) != 0) {
     125                 :            :         return ROMFS_RECORD_KIND_UNUSED;
     126                 :            :     }
     127                 :       3978 :     mp_uint_t record_len;
     128         [ +  + ]:       3978 :     if (mp_decode_uint_checked(fs, fs_max, &record_len) != 0) {
     129                 :            :         return ROMFS_RECORD_KIND_UNUSED;
     130                 :            :     }
     131                 :       3974 :     *fs_next = *fs + record_len;
     132                 :       3974 :     return record_kind;
     133                 :            : }
     134                 :            : 
     135                 :            : // Returns 0 for success, a negative integer for failure.
     136                 :         92 : static int extract_data(mp_obj_vfs_rom_t *self, const uint8_t *fs, const uint8_t *fs_top, size_t *size_out, const uint8_t **data_out) {
     137         [ +  + ]:        100 :     while (fs < fs_top) {
     138                 :         96 :         const uint8_t *fs_next;
     139                 :         96 :         record_kind_t record_kind = extract_record(&fs, &fs_next, fs_top);
     140         [ +  + ]:         96 :         if (record_kind == ROMFS_RECORD_KIND_UNUSED) {
     141                 :            :             // Corrupt filesystem.
     142                 :            :             break;
     143         [ +  + ]:         92 :         } else if (record_kind == ROMFS_RECORD_KIND_DATA_VERBATIM) {
     144                 :            :             // Verbatim data.
     145         [ +  + ]:         66 :             if (size_out != NULL) {
     146                 :         58 :                 *size_out = fs_next - fs;
     147                 :         58 :                 *data_out = fs;
     148                 :            :             }
     149                 :         80 :             return 0;
     150         [ +  + ]:         26 :         } else if (record_kind == ROMFS_RECORD_KIND_DATA_POINTER) {
     151                 :            :             // Pointer to data.
     152                 :         18 :             mp_uint_t size;
     153         [ +  + ]:         18 :             if (mp_decode_uint_checked(&fs, fs_next, &size) != 0) {
     154                 :            :                 break;
     155                 :            :             }
     156                 :         16 :             mp_uint_t offset;
     157         [ +  + ]:         16 :             if (mp_decode_uint_checked(&fs, fs_next, &offset) != 0) {
     158                 :            :                 break;
     159                 :            :             }
     160         [ +  - ]:         14 :             if (size_out != NULL) {
     161                 :         14 :                 *size_out = size;
     162                 :         14 :                 *data_out = self->filesystem + offset;
     163                 :            :             }
     164                 :         14 :             return 0;
     165                 :            :         } else {
     166                 :            :             // Skip this record.
     167                 :          8 :             fs = fs_next;
     168                 :            :         }
     169                 :            :     }
     170                 :            :     return -MP_EIO;
     171                 :            : }
     172                 :            : 
     173                 :            : // Searches for `path` in the filesystem.
     174                 :            : // `path` must be null-terminated.
     175                 :        122 : mp_import_stat_t mp_vfs_rom_search_filesystem(mp_obj_vfs_rom_t *self, const char *path, size_t *size_out, const uint8_t **data_out) {
     176                 :        122 :     const uint8_t *fs = self->filesystem;
     177                 :        122 :     const uint8_t *fs_top = self->filesystem_end;
     178                 :        122 :     size_t path_len = strlen(path);
     179         [ +  + ]:        122 :     if (*path == '/') {
     180                 :            :         // An optional slash at the start of the path enters the top-level filesystem.
     181                 :         84 :         ++path;
     182                 :         84 :         --path_len;
     183                 :            :     }
     184         [ +  + ]:        370 :     while (path_len > 0 && fs < fs_top) {
     185                 :        306 :         const uint8_t *fs_next;
     186                 :        306 :         record_kind_t record_kind = extract_record(&fs, &fs_next, fs_top);
     187         [ +  + ]:        306 :         if (record_kind == ROMFS_RECORD_KIND_UNUSED) {
     188                 :            :             // Corrupt filesystem.
     189                 :         58 :             return MP_IMPORT_STAT_NO_EXIST;
     190         [ +  + ]:        304 :         } else if (record_kind == ROMFS_RECORD_KIND_DIRECTORY || record_kind == ROMFS_RECORD_KIND_FILE) {
     191                 :            :             // A directory or file record.
     192                 :        240 :             mp_uint_t name_len;
     193         [ +  + ]:        240 :             if (mp_decode_uint_checked(&fs, fs_next, &name_len) != 0) {
     194                 :            :                 // Corrupt filesystem.
     195                 :         56 :                 return MP_IMPORT_STAT_NO_EXIST;
     196                 :            :             }
     197         [ +  + ]:        238 :             if ((name_len == path_len
     198   [ +  +  +  + ]:        126 :                  || (name_len < path_len && path[name_len] == '/'))
     199         [ +  + ]:        132 :                 && memcmp(path, fs, name_len) == 0) {
     200                 :            :                 // Name matches, so enter this record.
     201                 :         84 :                 fs += name_len;
     202                 :         84 :                 fs_top = fs_next;
     203                 :         84 :                 path += name_len;
     204                 :         84 :                 path_len -= name_len;
     205         [ +  + ]:         84 :                 if (record_kind == ROMFS_RECORD_KIND_DIRECTORY) {
     206                 :            :                     // Continue searching in this directory.
     207         [ +  + ]:         30 :                     if (*path == '/') {
     208                 :         20 :                         ++path;
     209                 :         20 :                         --path_len;
     210                 :            :                     }
     211                 :            :                 } else {
     212                 :            :                     // Return this file.
     213         [ +  - ]:         54 :                     if (path_len != 0) {
     214                 :            :                         return MP_IMPORT_STAT_NO_EXIST;
     215                 :            :                     }
     216         [ +  + ]:         54 :                     if (extract_data(self, fs, fs_top, size_out, data_out) != 0) {
     217                 :            :                         // Corrupt filesystem.
     218                 :            :                         return MP_IMPORT_STAT_NO_EXIST;
     219                 :            :                     }
     220                 :         44 :                     return MP_IMPORT_STAT_FILE;
     221                 :            :                 }
     222                 :            :             } else {
     223                 :            :                 // Skip this directory/file record.
     224                 :        154 :                 fs = fs_next;
     225                 :            :             }
     226                 :            :         } else {
     227                 :            :             // Skip this record.
     228                 :         64 :             fs = fs_next;
     229                 :            :         }
     230                 :            :     }
     231         [ +  + ]:         64 :     if (path_len == 0) {
     232         [ +  - ]:         44 :         if (size_out != NULL) {
     233                 :         44 :             *size_out = fs_top - fs;
     234                 :         44 :             *data_out = fs;
     235                 :            :         }
     236                 :         44 :         return MP_IMPORT_STAT_DIR;
     237                 :            :     }
     238                 :            :     return MP_IMPORT_STAT_NO_EXIST;
     239                 :            : }
     240                 :            : 
     241                 :       3522 : static mp_obj_t vfs_rom_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) {
     242                 :       3522 :     mp_arg_check_num(n_args, n_kw, 1, 1, false);
     243                 :            : 
     244                 :       3522 :     mp_obj_vfs_rom_t *self = m_new_obj(mp_obj_vfs_rom_t);
     245                 :       3522 :     self->base.type = type;
     246                 :       3522 :     self->memory = args[0];
     247                 :            : 
     248                 :            :     // Get the ROMFS memory region.
     249                 :       3522 :     mp_buffer_info_t bufinfo;
     250                 :       3522 :     mp_get_buffer_raise(self->memory, &bufinfo, MP_BUFFER_READ);
     251         [ +  + ]:       3520 :     if (bufinfo.len < ROMFS_SIZE_MIN) {
     252                 :          4 :         mp_raise_OSError(MP_ENODEV);
     253                 :            :     }
     254                 :       3516 :     self->filesystem = bufinfo.buf;
     255                 :            : 
     256                 :            :     // Verify it is a ROMFS.
     257         [ +  + ]:       3516 :     if (!(self->filesystem[0] == ROMFS_HEADER_BYTE0
     258         [ +  - ]:       3514 :           && self->filesystem[1] == ROMFS_HEADER_BYTE1
     259         [ -  + ]:       3514 :           && self->filesystem[2] == ROMFS_HEADER_BYTE2)) {
     260                 :          2 :         mp_raise_OSError(MP_ENODEV);
     261                 :            :     }
     262                 :            : 
     263                 :            :     // The ROMFS is a record itself, so enter into it and compute its limit.
     264                 :       3514 :     record_kind_t record_kind = extract_record(&self->filesystem, &self->filesystem_end, self->filesystem + bufinfo.len);
     265         [ +  + ]:       3514 :     if (record_kind != ROMFS_RECORD_KIND_FILESYSTEM) {
     266                 :          2 :         mp_raise_OSError(MP_ENODEV);
     267                 :            :     }
     268                 :            : 
     269                 :            :     // Check the filesystem is within the limits of the input buffer.
     270         [ +  + ]:       3512 :     if (self->filesystem_end > (const uint8_t *)bufinfo.buf + bufinfo.len) {
     271                 :          2 :         mp_raise_OSError(MP_ENODEV);
     272                 :            :     }
     273                 :            : 
     274                 :       3510 :     return MP_OBJ_FROM_PTR(self);
     275                 :            : }
     276                 :            : 
     277                 :       3478 : static mp_obj_t vfs_rom_mount(mp_obj_t self_in, mp_obj_t readonly, mp_obj_t mkfs) {
     278                 :       3478 :     (void)self_in;
     279                 :       3478 :     (void)readonly;
     280         [ +  + ]:       3478 :     if (mp_obj_is_true(mkfs)) {
     281                 :          2 :         mp_raise_OSError(MP_EPERM);
     282                 :            :     }
     283                 :       3476 :     return mp_const_none;
     284                 :            : }
     285                 :            : static MP_DEFINE_CONST_FUN_OBJ_3(vfs_rom_mount_obj, vfs_rom_mount);
     286                 :            : 
     287                 :            : // mp_vfs_rom_file_open is implemented in vfs_rom_file.c.
     288                 :            : static MP_DEFINE_CONST_FUN_OBJ_3(vfs_rom_open_obj, mp_vfs_rom_file_open);
     289                 :            : 
     290                 :          6 : static mp_obj_t vfs_rom_chdir(mp_obj_t self_in, mp_obj_t path_in) {
     291                 :          6 :     mp_obj_vfs_rom_t *self = MP_OBJ_TO_PTR(self_in);
     292                 :          6 :     const char *path = mp_vfs_rom_get_path_str(self, path_in);
     293   [ +  -  +  + ]:          6 :     if (path[0] == '/' && path[1] == '\0') {
     294                 :            :         // Allow chdir to the root of the filesystem.
     295                 :          4 :     } else {
     296                 :            :         // Don't allow chdir to any subdirectory (not currently implemented).
     297                 :          2 :         mp_raise_OSError(MP_EOPNOTSUPP);
     298                 :            :     }
     299                 :          4 :     return mp_const_none;
     300                 :            : }
     301                 :            : static MP_DEFINE_CONST_FUN_OBJ_2(vfs_rom_chdir_obj, vfs_rom_chdir);
     302                 :            : 
     303                 :          4 : static mp_obj_t vfs_rom_getcwd(mp_obj_t self_in) {
     304                 :          4 :     (void)self_in;
     305                 :            :     // The current directory is always the root of the ROMFS.
     306                 :          4 :     return MP_OBJ_NEW_QSTR(MP_QSTR_);
     307                 :            : }
     308                 :            : static MP_DEFINE_CONST_FUN_OBJ_1(vfs_rom_getcwd_obj, vfs_rom_getcwd);
     309                 :            : 
     310                 :            : typedef struct _vfs_rom_ilistdir_it_t {
     311                 :            :     mp_obj_base_t base;
     312                 :            :     mp_fun_1_t iternext;
     313                 :            :     mp_obj_vfs_rom_t *vfs_rom;
     314                 :            :     bool is_str;
     315                 :            :     const uint8_t *index;
     316                 :            :     const uint8_t *index_top;
     317                 :            : } vfs_rom_ilistdir_it_t;
     318                 :            : 
     319                 :         74 : static mp_obj_t vfs_rom_ilistdir_it_iternext(mp_obj_t self_in) {
     320                 :         74 :     vfs_rom_ilistdir_it_t *self = MP_OBJ_TO_PTR(self_in);
     321                 :            : 
     322         [ +  + ]:         88 :     while (self->index < self->index_top) {
     323                 :         68 :         const uint8_t *index_next;
     324                 :         68 :         record_kind_t record_kind = extract_record(&self->index, &index_next, self->index_top);
     325                 :         68 :         uint32_t type;
     326                 :         68 :         mp_uint_t name_len;
     327                 :         68 :         size_t data_len;
     328         [ +  + ]:         68 :         if (record_kind == ROMFS_RECORD_KIND_UNUSED) {
     329                 :            :             // Corrupt filesystem.
     330                 :          2 :             self->index = self->index_top;
     331                 :          6 :             break;
     332         [ +  + ]:         66 :         } else if (record_kind == ROMFS_RECORD_KIND_DIRECTORY || record_kind == ROMFS_RECORD_KIND_FILE) {
     333                 :            :             // A directory or file record.
     334         [ +  + ]:         52 :             if (mp_decode_uint_checked(&self->index, index_next, &name_len) != 0) {
     335                 :            :                 // Corrupt filesystem.
     336                 :          2 :                 self->index = self->index_top;
     337                 :          2 :                 break;
     338                 :            :             }
     339         [ +  + ]:         50 :             if (record_kind == ROMFS_RECORD_KIND_DIRECTORY) {
     340                 :            :                 // A directory.
     341                 :         12 :                 type = MP_S_IFDIR;
     342                 :         12 :                 data_len = index_next - self->index - name_len;
     343                 :            :             } else {
     344                 :            :                 // A file.
     345                 :         38 :                 type = MP_S_IFREG;
     346                 :         38 :                 const uint8_t *data_value;
     347         [ +  + ]:         38 :                 if (extract_data(self->vfs_rom, self->index + name_len, index_next, &data_len, &data_value) != 0) {
     348                 :            :                     // Corrupt filesystem.
     349                 :            :                     break;
     350                 :            :                 }
     351                 :            :             }
     352                 :            :         } else {
     353                 :            :             // Skip this record.
     354                 :         14 :             self->index = index_next;
     355                 :         14 :             continue;
     356                 :            :         }
     357                 :            : 
     358                 :         48 :         const uint8_t *name_str = self->index;
     359                 :         48 :         self->index = index_next;
     360                 :            : 
     361                 :            :         // Make 4-tuple with info about this entry: (name, attr, inode, size)
     362                 :         48 :         mp_obj_tuple_t *t = MP_OBJ_TO_PTR(mp_obj_new_tuple(4, NULL));
     363                 :            : 
     364         [ +  + ]:         48 :         if (self->is_str) {
     365                 :         42 :             t->items[0] = mp_obj_new_str((const char *)name_str, name_len);
     366                 :            :         } else {
     367                 :          6 :             t->items[0] = mp_obj_new_bytes(name_str, name_len);
     368                 :            :         }
     369                 :            : 
     370                 :         48 :         t->items[1] = MP_OBJ_NEW_SMALL_INT(type);
     371                 :         48 :         t->items[2] = MP_OBJ_NEW_SMALL_INT(0);
     372                 :         48 :         t->items[3] = mp_obj_new_int(data_len);
     373                 :            : 
     374                 :         48 :         return MP_OBJ_FROM_PTR(t);
     375                 :            :     }
     376                 :            : 
     377                 :            :     return MP_OBJ_STOP_ITERATION;
     378                 :            : }
     379                 :            : 
     380                 :         28 : static mp_obj_t vfs_rom_ilistdir(mp_obj_t self_in, mp_obj_t path_in) {
     381                 :         28 :     mp_obj_vfs_rom_t *self = MP_OBJ_TO_PTR(self_in);
     382                 :         28 :     vfs_rom_ilistdir_it_t *iter = m_new_obj(vfs_rom_ilistdir_it_t);
     383                 :         28 :     iter->base.type = &mp_type_polymorph_iter;
     384                 :         28 :     iter->iternext = vfs_rom_ilistdir_it_iternext;
     385                 :         28 :     iter->vfs_rom = self;
     386                 :         28 :     iter->is_str = mp_obj_get_type(path_in) == &mp_type_str;
     387                 :         28 :     const char *path = mp_vfs_rom_get_path_str(self, path_in);
     388                 :         28 :     size_t size;
     389         [ +  + ]:         28 :     if (mp_vfs_rom_search_filesystem(self, path, &size, &iter->index) != MP_IMPORT_STAT_DIR) {
     390                 :          2 :         mp_raise_OSError(MP_ENOENT);
     391                 :            :     }
     392                 :         26 :     iter->index_top = iter->index + size;
     393                 :         26 :     return MP_OBJ_FROM_PTR(iter);
     394                 :            : }
     395                 :            : static MP_DEFINE_CONST_FUN_OBJ_2(vfs_rom_ilistdir_obj, vfs_rom_ilistdir);
     396                 :            : 
     397                 :         36 : static mp_obj_t vfs_rom_stat(mp_obj_t self_in, mp_obj_t path_in) {
     398                 :         36 :     mp_obj_vfs_rom_t *self = MP_OBJ_TO_PTR(self_in);
     399                 :         36 :     const char *path = mp_vfs_rom_get_path_str(self, path_in);
     400                 :         36 :     size_t file_size;
     401                 :         36 :     const uint8_t *file_data;
     402                 :         36 :     mp_import_stat_t stat = mp_vfs_rom_search_filesystem(self, path, &file_size, &file_data);
     403         [ +  + ]:         36 :     if (stat == MP_IMPORT_STAT_NO_EXIST) {
     404                 :         18 :         mp_raise_OSError(MP_ENOENT);
     405                 :            :     }
     406                 :         18 :     mp_obj_tuple_t *t = MP_OBJ_TO_PTR(mp_obj_new_tuple(10, NULL));
     407         [ +  + ]:         18 :     t->items[0] = MP_OBJ_NEW_SMALL_INT(stat == MP_IMPORT_STAT_FILE ? MP_S_IFREG : MP_S_IFDIR); // st_mode
     408                 :         18 :     t->items[1] = MP_OBJ_NEW_SMALL_INT(0); // st_ino
     409                 :         18 :     t->items[2] = MP_OBJ_NEW_SMALL_INT(0); // st_dev
     410                 :         18 :     t->items[3] = MP_OBJ_NEW_SMALL_INT(0); // st_nlink
     411                 :         18 :     t->items[4] = MP_OBJ_NEW_SMALL_INT(0); // st_uid
     412                 :         18 :     t->items[5] = MP_OBJ_NEW_SMALL_INT(0); // st_gid
     413                 :         18 :     t->items[6] = MP_OBJ_NEW_SMALL_INT(file_size); // st_size
     414                 :         18 :     t->items[7] = MP_OBJ_NEW_SMALL_INT(0); // st_atime
     415                 :         18 :     t->items[8] = MP_OBJ_NEW_SMALL_INT(0); // st_mtime
     416                 :         18 :     t->items[9] = MP_OBJ_NEW_SMALL_INT(0); // st_ctime
     417                 :         18 :     return MP_OBJ_FROM_PTR(t);
     418                 :            : }
     419                 :            : static MP_DEFINE_CONST_FUN_OBJ_2(vfs_rom_stat_obj, vfs_rom_stat);
     420                 :            : 
     421                 :          4 : static mp_obj_t vfs_rom_statvfs(mp_obj_t self_in, mp_obj_t path_in) {
     422                 :          4 :     mp_obj_vfs_rom_t *self = MP_OBJ_TO_PTR(self_in);
     423                 :          4 :     (void)path_in;
     424                 :          4 :     size_t filesystem_len = self->filesystem_end - self->filesystem;
     425                 :          4 :     mp_obj_tuple_t *t = MP_OBJ_TO_PTR(mp_obj_new_tuple(10, NULL));
     426                 :          4 :     t->items[0] = MP_OBJ_NEW_SMALL_INT(1); // f_bsize
     427                 :          4 :     t->items[1] = MP_OBJ_NEW_SMALL_INT(0); // f_frsize
     428                 :          4 :     t->items[2] = mp_obj_new_int_from_uint(filesystem_len); // f_blocks
     429                 :          4 :     t->items[3] = MP_OBJ_NEW_SMALL_INT(0); // f_bfree
     430                 :          4 :     t->items[4] = MP_OBJ_NEW_SMALL_INT(0); // f_bavail
     431                 :          4 :     t->items[5] = MP_OBJ_NEW_SMALL_INT(0); // f_files
     432                 :          4 :     t->items[6] = MP_OBJ_NEW_SMALL_INT(0); // f_ffree
     433                 :          4 :     t->items[7] = MP_OBJ_NEW_SMALL_INT(0); // f_favail
     434                 :          4 :     t->items[8] = MP_OBJ_NEW_SMALL_INT(0); // f_flags
     435                 :          4 :     t->items[9] = MP_OBJ_NEW_SMALL_INT(32767); // f_namemax
     436                 :          4 :     return MP_OBJ_FROM_PTR(t);
     437                 :            : }
     438                 :            : static MP_DEFINE_CONST_FUN_OBJ_2(vfs_rom_statvfs_obj, vfs_rom_statvfs);
     439                 :            : 
     440                 :            : static const mp_rom_map_elem_t vfs_rom_locals_dict_table[] = {
     441                 :            :     { MP_ROM_QSTR(MP_QSTR_mount), MP_ROM_PTR(&vfs_rom_mount_obj) },
     442                 :            :     { MP_ROM_QSTR(MP_QSTR_umount), MP_ROM_PTR(&mp_identity_obj) },
     443                 :            :     { MP_ROM_QSTR(MP_QSTR_open), MP_ROM_PTR(&vfs_rom_open_obj) },
     444                 :            : 
     445                 :            :     { MP_ROM_QSTR(MP_QSTR_chdir), MP_ROM_PTR(&vfs_rom_chdir_obj) },
     446                 :            :     { MP_ROM_QSTR(MP_QSTR_getcwd), MP_ROM_PTR(&vfs_rom_getcwd_obj) },
     447                 :            :     { MP_ROM_QSTR(MP_QSTR_ilistdir), MP_ROM_PTR(&vfs_rom_ilistdir_obj) },
     448                 :            :     { MP_ROM_QSTR(MP_QSTR_stat), MP_ROM_PTR(&vfs_rom_stat_obj) },
     449                 :            :     { MP_ROM_QSTR(MP_QSTR_statvfs), MP_ROM_PTR(&vfs_rom_statvfs_obj) },
     450                 :            : };
     451                 :            : static MP_DEFINE_CONST_DICT(vfs_rom_locals_dict, vfs_rom_locals_dict_table);
     452                 :            : 
     453                 :         18 : static mp_import_stat_t mp_vfs_rom_import_stat(void *self_in, const char *path) {
     454                 :         18 :     mp_obj_vfs_rom_t *self = MP_OBJ_TO_PTR(self_in);
     455                 :         18 :     return mp_vfs_rom_search_filesystem(self, path, NULL, NULL);
     456                 :            : }
     457                 :            : 
     458                 :            : static const mp_vfs_proto_t vfs_rom_proto = {
     459                 :            :     .import_stat = mp_vfs_rom_import_stat,
     460                 :            : };
     461                 :            : 
     462                 :            : MP_DEFINE_CONST_OBJ_TYPE(
     463                 :            :     mp_type_vfs_rom,
     464                 :            :     MP_QSTR_VfsRom,
     465                 :            :     MP_TYPE_FLAG_NONE,
     466                 :            :     make_new, vfs_rom_make_new,
     467                 :            :     protocol, &vfs_rom_proto,
     468                 :            :     locals_dict, &vfs_rom_locals_dict
     469                 :            :     );
     470                 :            : 
     471                 :            : #endif // MICROPY_VFS_ROM

Generated by: LCOV version 1.15-5-g462f71d