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 : 1226 : static int MP_VFS_LFSx(dev_ioctl)(const struct LFSx_API (config) * c, int cmd, int arg, bool must_return_int) {
47 : 1226 : mp_obj_t ret = mp_vfs_blockdev_ioctl(c->context, cmd, arg);
48 : 1226 : int ret_i = 0;
49 [ + + ]: 1226 : if (must_return_int || ret != mp_const_none) {
50 : 622 : ret_i = mp_obj_get_int(ret);
51 : : }
52 : 1226 : return ret_i;
53 : : }
54 : :
55 : 17976 : 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 : 17976 : return mp_vfs_blockdev_read_ext(c->context, block, off, size, buffer);
57 : : }
58 : :
59 : 1194 : 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 : 1194 : return mp_vfs_blockdev_write_ext(c->context, block, off, size, buffer);
61 : : }
62 : :
63 : 398 : static int MP_VFS_LFSx(dev_erase)(const struct LFSx_API (config) * c, LFSx_API(block_t) block) {
64 : 398 : return MP_VFS_LFSx(dev_ioctl)(c, MP_BLOCKDEV_IOCTL_BLOCK_ERASE, block, true);
65 : : }
66 : :
67 : 492 : static int MP_VFS_LFSx(dev_sync)(const struct LFSx_API (config) * c) {
68 : 492 : return MP_VFS_LFSx(dev_ioctl)(c, MP_BLOCKDEV_IOCTL_SYNC, 0, false);
69 : : }
70 : :
71 : 112 : 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 : 112 : self->blockdev.flags = MP_BLOCKDEV_FLAG_FREE_OBJ;
73 : 112 : mp_vfs_blockdev_init(&self->blockdev, bdev);
74 : :
75 : 112 : struct LFSx_API (config) * config = &self->config;
76 : 112 : memset(config, 0, sizeof(*config));
77 : :
78 : 112 : config->context = &self->blockdev;
79 : :
80 : 112 : config->read = MP_VFS_LFSx(dev_read);
81 : 112 : config->prog = MP_VFS_LFSx(dev_prog);
82 : 112 : config->erase = MP_VFS_LFSx(dev_erase);
83 : 112 : config->sync = MP_VFS_LFSx(dev_sync);
84 : :
85 : 112 : MP_VFS_LFSx(dev_ioctl)(config, MP_BLOCKDEV_IOCTL_INIT, 1, false); // initialise block device
86 : 112 : int bs = MP_VFS_LFSx(dev_ioctl)(config, MP_BLOCKDEV_IOCTL_BLOCK_SIZE, 0, true); // get block size
87 : 112 : int bc = MP_VFS_LFSx(dev_ioctl)(config, MP_BLOCKDEV_IOCTL_BLOCK_COUNT, 0, true); // get block count
88 : 112 : self->blockdev.block_size = bs;
89 : :
90 : 112 : config->read_size = read_size;
91 : 112 : config->prog_size = prog_size;
92 : 112 : config->block_size = bs;
93 : 112 : 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 : 68 : config->block_cycles = 100;
102 : 68 : config->cache_size = MIN(config->block_size, (4 * MAX(read_size, prog_size)));
103 : 68 : config->lookahead_size = lookahead;
104 : 68 : config->read_buffer = m_new(uint8_t, config->cache_size);
105 : 68 : config->prog_buffer = m_new(uint8_t, config->cache_size);
106 : 68 : config->lookahead_buffer = m_new(uint8_t, config->lookahead_size);
107 : : #endif
108 : 112 : }
109 : :
110 : 550 : const char *MP_VFS_LFSx(make_path)(MP_OBJ_VFS_LFSx * self, mp_obj_t path_in) {
111 : 550 : const char *path = mp_obj_str_get_str(path_in);
112 [ + + ]: 550 : if (path[0] != '/') {
113 [ + - ]: 350 : size_t l = vstr_len(&self->cur_dir);
114 [ + - ]: 350 : if (l > 0) {
115 : 350 : vstr_add_str(&self->cur_dir, path);
116 : 350 : path = vstr_null_terminated_str(&self->cur_dir);
117 : 350 : self->cur_dir.len = l;
118 : : }
119 : : }
120 : 550 : return path;
121 : : }
122 : :
123 : 64 : 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 : 64 : mp_arg_val_t args[MP_ARRAY_SIZE(lfs_make_allowed_args)];
125 : 64 : 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 : 64 : MP_OBJ_VFS_LFSx *self = m_new0(MP_OBJ_VFS_LFSx, 1);
128 : 64 : self->base.type = type;
129 : 64 : vstr_init(&self->cur_dir, 16);
130 : 64 : vstr_add_byte(&self->cur_dir, '/');
131 : : #if LFS_BUILD_VERSION == 2
132 : 40 : self->enable_mtime = args[LFS_MAKE_ARG_mtime].u_bool;
133 : : #endif
134 : 64 : MP_VFS_LFSx(init_config)(self, args[LFS_MAKE_ARG_bdev].u_obj,
135 : 64 : args[LFS_MAKE_ARG_readsize].u_int, args[LFS_MAKE_ARG_progsize].u_int, args[LFS_MAKE_ARG_lookahead].u_int);
136 : 64 : int ret = LFSx_API(mount)(&self->lfs, &self->config);
137 [ + + ]: 64 : if (ret < 0) {
138 : 4 : mp_raise_OSError(-ret);
139 : : }
140 : 60 : return MP_OBJ_FROM_PTR(self);
141 : : }
142 : :
143 : 48 : static mp_obj_t MP_VFS_LFSx(mkfs)(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
144 : 48 : mp_arg_val_t args[MP_ARRAY_SIZE(lfs_make_allowed_args)];
145 : 48 : mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(lfs_make_allowed_args), lfs_make_allowed_args, args);
146 : :
147 : 48 : MP_OBJ_VFS_LFSx self;
148 : 48 : MP_VFS_LFSx(init_config)(&self, args[LFS_MAKE_ARG_bdev].u_obj,
149 : 48 : args[LFS_MAKE_ARG_readsize].u_int, args[LFS_MAKE_ARG_progsize].u_int, args[LFS_MAKE_ARG_lookahead].u_int);
150 : 48 : int ret = LFSx_API(format)(&self.lfs, &self.config);
151 [ + + ]: 48 : if (ret < 0) {
152 : 4 : mp_raise_OSError(-ret);
153 : : }
154 : 44 : 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_from_cstr(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)
|