summaryrefslogtreecommitdiff
path: root/extmod
diff options
context:
space:
mode:
authorDan Halbert <halbert@halwitz.org>2018-07-11 16:45:30 -0400
committerDan Halbert <halbert@halwitz.org>2018-07-11 16:45:30 -0400
commit7c219600a246d8956d0b23ea3f5d125a820e6b6a (patch)
tree4cf793a66284322d48a8f430815c31cd1c9ffa1d /extmod
parent4962468ffffac9ec4e36b2b1fc3f132516df3127 (diff)
parent25ae98f07cb3c4488cb955403dfe56b8bb8db6f0 (diff)
WIP: after merge; before testing
Diffstat (limited to 'extmod')
-rw-r--r--extmod/machine_signal.c4
-rw-r--r--extmod/machine_spi.c116
-rw-r--r--extmod/machine_spi.h11
-rw-r--r--extmod/modbtree.c2
-rw-r--r--extmod/modframebuf.c54
-rw-r--r--extmod/modlwip.c180
-rw-r--r--extmod/moduhashlib.c190
-rw-r--r--extmod/modujson.c11
-rw-r--r--extmod/modure.c4
-rw-r--r--extmod/modussl_axtls.c64
-rw-r--r--extmod/modussl_mbedtls.c84
-rw-r--r--extmod/moduzlib.c3
-rw-r--r--extmod/modwebrepl.c34
-rw-r--r--extmod/modwebsocket.c18
-rw-r--r--extmod/re1.5/compilecode.c4
-rw-r--r--extmod/uos_dupterm.c43
-rw-r--r--extmod/vfs.c46
-rw-r--r--extmod/vfs.h5
-rw-r--r--extmod/vfs_fat.c116
-rw-r--r--extmod/vfs_fat_file.c43
-rw-r--r--extmod/vfs_fat_misc.c108
-rw-r--r--extmod/vfs_posix.c363
-rw-r--r--extmod/vfs_posix.h38
-rw-r--r--extmod/vfs_posix_file.c261
-rw-r--r--extmod/vfs_reader.c2
25 files changed, 1343 insertions, 461 deletions
diff --git a/extmod/machine_signal.c b/extmod/machine_signal.c
index 78d0c3fee..3f9f5af94 100644
--- a/extmod/machine_signal.c
+++ b/extmod/machine_signal.c
@@ -58,7 +58,7 @@ STATIC mp_obj_t signal_make_new(const mp_obj_type_t *type, size_t n_args, size_t
// If first argument isn't a Pin-like object, we filter out "invert"
// from keyword arguments and pass them all to the exported Pin
// constructor to create one.
- mp_obj_t pin_args[n_args + n_kw * 2];
+ mp_obj_t *pin_args = mp_local_alloc((n_args + n_kw * 2) * sizeof(mp_obj_t));
memcpy(pin_args, args, n_args * sizeof(mp_obj_t));
const mp_obj_t *src = args + n_args;
mp_obj_t *dst = pin_args + n_args;
@@ -88,6 +88,8 @@ STATIC mp_obj_t signal_make_new(const mp_obj_type_t *type, size_t n_args, size_t
// will just ignore it as set a concrete type. If not, we'd need
// to expose port's "default" pin type too.
pin = MICROPY_PY_MACHINE_PIN_MAKE_NEW(NULL, n_args, n_kw, pin_args);
+
+ mp_local_free(pin_args);
}
else
#endif
diff --git a/extmod/machine_spi.c b/extmod/machine_spi.c
index a67d294ba..f0c4896c2 100644
--- a/extmod/machine_spi.c
+++ b/extmod/machine_spi.c
@@ -38,61 +38,6 @@
#define MICROPY_PY_MACHINE_SPI_LSB (1)
#endif
-void mp_machine_soft_spi_transfer(mp_obj_base_t *self_in, size_t len, const uint8_t *src, uint8_t *dest) {
- mp_machine_soft_spi_obj_t *self = (mp_machine_soft_spi_obj_t*)self_in;
- uint32_t delay_half = self->delay_half;
-
- // only MSB transfer is implemented
-
- // If a port defines MICROPY_PY_MACHINE_SPI_MIN_DELAY, and the configured
- // delay_half is equal to this value, then the software SPI implementation
- // will run as fast as possible, limited only by CPU speed and GPIO time.
- #ifdef MICROPY_PY_MACHINE_SPI_MIN_DELAY
- if (delay_half == MICROPY_PY_MACHINE_SPI_MIN_DELAY) {
- for (size_t i = 0; i < len; ++i) {
- uint8_t data_out = src[i];
- uint8_t data_in = 0;
- for (int j = 0; j < 8; ++j, data_out <<= 1) {
- mp_hal_pin_write(self->mosi, (data_out >> 7) & 1);
- mp_hal_pin_write(self->sck, 1 - self->polarity);
- data_in = (data_in << 1) | mp_hal_pin_read(self->miso);
- mp_hal_pin_write(self->sck, self->polarity);
- }
- if (dest != NULL) {
- dest[i] = data_in;
- }
- }
- return;
- }
- #endif
-
- for (size_t i = 0; i < len; ++i) {
- uint8_t data_out = src[i];
- uint8_t data_in = 0;
- for (int j = 0; j < 8; ++j, data_out <<= 1) {
- mp_hal_pin_write(self->mosi, (data_out >> 7) & 1);
- if (self->phase == 0) {
- mp_hal_delay_us_fast(delay_half);
- mp_hal_pin_write(self->sck, 1 - self->polarity);
- } else {
- mp_hal_pin_write(self->sck, 1 - self->polarity);
- mp_hal_delay_us_fast(delay_half);
- }
- data_in = (data_in << 1) | mp_hal_pin_read(self->miso);
- if (self->phase == 0) {
- mp_hal_delay_us_fast(delay_half);
- mp_hal_pin_write(self->sck, self->polarity);
- } else {
- mp_hal_pin_write(self->sck, self->polarity);
- mp_hal_delay_us_fast(delay_half);
- }
- }
- if (dest != NULL) {
- dest[i] = data_in;
- }
- }
-}
-
/******************************************************************************/
// MicroPython bindings for generic machine.SPI
@@ -199,9 +144,9 @@ MP_DEFINE_CONST_DICT(mp_machine_spi_locals_dict, machine_spi_locals_dict_table);
// Implementation of soft SPI
STATIC uint32_t baudrate_from_delay_half(uint32_t delay_half) {
- #ifdef MICROPY_PY_MACHINE_SPI_MIN_DELAY
- if (delay_half == MICROPY_PY_MACHINE_SPI_MIN_DELAY) {
- return MICROPY_PY_MACHINE_SPI_MAX_BAUDRATE;
+ #ifdef MICROPY_HW_SOFTSPI_MIN_DELAY
+ if (delay_half == MICROPY_HW_SOFTSPI_MIN_DELAY) {
+ return MICROPY_HW_SOFTSPI_MAX_BAUDRATE;
} else
#endif
{
@@ -210,9 +155,9 @@ STATIC uint32_t baudrate_from_delay_half(uint32_t delay_half) {
}
STATIC uint32_t baudrate_to_delay_half(uint32_t baudrate) {
- #ifdef MICROPY_PY_MACHINE_SPI_MIN_DELAY
- if (baudrate >= MICROPY_PY_MACHINE_SPI_MAX_BAUDRATE) {
- return MICROPY_PY_MACHINE_SPI_MIN_DELAY;
+ #ifdef MICROPY_HW_SOFTSPI_MIN_DELAY
+ if (baudrate >= MICROPY_HW_SOFTSPI_MAX_BAUDRATE) {
+ return MICROPY_HW_SOFTSPI_MIN_DELAY;
} else
#endif
{
@@ -229,8 +174,8 @@ STATIC void mp_machine_soft_spi_print(const mp_print_t *print, mp_obj_t self_in,
mp_machine_soft_spi_obj_t *self = MP_OBJ_TO_PTR(self_in);
mp_printf(print, "SoftSPI(baudrate=%u, polarity=%u, phase=%u,"
" sck=" MP_HAL_PIN_FMT ", mosi=" MP_HAL_PIN_FMT ", miso=" MP_HAL_PIN_FMT ")",
- baudrate_from_delay_half(self->delay_half), self->polarity, self->phase,
- mp_hal_pin_name(self->sck), mp_hal_pin_name(self->mosi), mp_hal_pin_name(self->miso));
+ baudrate_from_delay_half(self->spi.delay_half), self->spi.polarity, self->spi.phase,
+ mp_hal_pin_name(self->spi.sck), mp_hal_pin_name(self->spi.mosi), mp_hal_pin_name(self->spi.miso));
}
STATIC mp_obj_t mp_machine_soft_spi_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) {
@@ -253,9 +198,9 @@ STATIC mp_obj_t mp_machine_soft_spi_make_new(const mp_obj_type_t *type, size_t n
self->base.type = &mp_machine_soft_spi_type;
// set parameters
- self->delay_half = baudrate_to_delay_half(args[ARG_baudrate].u_int);
- self->polarity = args[ARG_polarity].u_int;
- self->phase = args[ARG_phase].u_int;
+ self->spi.delay_half = baudrate_to_delay_half(args[ARG_baudrate].u_int);
+ self->spi.polarity = args[ARG_polarity].u_int;
+ self->spi.phase = args[ARG_phase].u_int;
if (args[ARG_bits].u_int != 8) {
mp_raise_ValueError("bits must be 8");
}
@@ -267,15 +212,12 @@ STATIC mp_obj_t mp_machine_soft_spi_make_new(const mp_obj_type_t *type, size_t n
|| args[ARG_miso].u_obj == MP_OBJ_NULL) {
mp_raise_ValueError("must specify all of sck/mosi/miso");
}
- self->sck = mp_hal_get_pin_obj(args[ARG_sck].u_obj);
- self->mosi = mp_hal_get_pin_obj(args[ARG_mosi].u_obj);
- self->miso = mp_hal_get_pin_obj(args[ARG_miso].u_obj);
+ self->spi.sck = mp_hal_get_pin_obj(args[ARG_sck].u_obj);
+ self->spi.mosi = mp_hal_get_pin_obj(args[ARG_mosi].u_obj);
+ self->spi.miso = mp_hal_get_pin_obj(args[ARG_miso].u_obj);
- // configure pins
- mp_hal_pin_write(self->sck, self->polarity);
- mp_hal_pin_output(self->sck);
- mp_hal_pin_output(self->mosi);
- mp_hal_pin_input(self->miso);
+ // configure bus
+ mp_soft_spi_ioctl(&self->spi, MP_SPI_IOCTL_INIT);
return MP_OBJ_FROM_PTR(self);
}
@@ -296,32 +238,34 @@ STATIC void mp_machine_soft_spi_init(mp_obj_base_t *self_in, size_t n_args, cons
mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
if (args[ARG_baudrate].u_int != -1) {
- self->delay_half = baudrate_to_delay_half(args[ARG_baudrate].u_int);
+ self->spi.delay_half = baudrate_to_delay_half(args[ARG_baudrate].u_int);
}
if (args[ARG_polarity].u_int != -1) {
- self->polarity = args[ARG_polarity].u_int;
+ self->spi.polarity = args[ARG_polarity].u_int;
}
if (args[ARG_phase].u_int != -1) {
- self->phase = args[ARG_phase].u_int;
+ self->spi.phase = args[ARG_phase].u_int;
}
if (args[ARG_sck].u_obj != MP_OBJ_NULL) {
- self->sck = mp_hal_get_pin_obj(args[ARG_sck].u_obj);
+ self->spi.sck = mp_hal_get_pin_obj(args[ARG_sck].u_obj);
}
if (args[ARG_mosi].u_obj != MP_OBJ_NULL) {
- self->mosi = mp_hal_get_pin_obj(args[ARG_mosi].u_obj);
+ self->spi.mosi = mp_hal_get_pin_obj(args[ARG_mosi].u_obj);
}
if (args[ARG_miso].u_obj != MP_OBJ_NULL) {
- self->miso = mp_hal_get_pin_obj(args[ARG_miso].u_obj);
+ self->spi.miso = mp_hal_get_pin_obj(args[ARG_miso].u_obj);
}
- // configure pins
- mp_hal_pin_write(self->sck, self->polarity);
- mp_hal_pin_output(self->sck);
- mp_hal_pin_output(self->mosi);
- mp_hal_pin_input(self->miso);
+ // configure bus
+ mp_soft_spi_ioctl(&self->spi, MP_SPI_IOCTL_INIT);
+}
+
+STATIC void mp_machine_soft_spi_transfer(mp_obj_base_t *self_in, size_t len, const uint8_t *src, uint8_t *dest) {
+ mp_machine_soft_spi_obj_t *self = (mp_machine_soft_spi_obj_t*)self_in;
+ mp_soft_spi_transfer(&self->spi, len, src, dest);
}
-STATIC const mp_machine_spi_p_t mp_machine_soft_spi_p = {
+const mp_machine_spi_p_t mp_machine_soft_spi_p = {
.init = mp_machine_soft_spi_init,
.deinit = NULL,
.transfer = mp_machine_soft_spi_transfer,
diff --git a/extmod/machine_spi.h b/extmod/machine_spi.h
index e24e41eb3..db21e1cd3 100644
--- a/extmod/machine_spi.h
+++ b/extmod/machine_spi.h
@@ -28,6 +28,7 @@
#include "py/obj.h"
#include "py/mphal.h"
+#include "drivers/bus/spi.h"
// SPI protocol
typedef struct _mp_machine_spi_p_t {
@@ -38,19 +39,13 @@ typedef struct _mp_machine_spi_p_t {
typedef struct _mp_machine_soft_spi_obj_t {
mp_obj_base_t base;
- uint32_t delay_half; // microsecond delay for half SCK period
- uint8_t polarity;
- uint8_t phase;
- mp_hal_pin_obj_t sck;
- mp_hal_pin_obj_t mosi;
- mp_hal_pin_obj_t miso;
+ mp_soft_spi_obj_t spi;
} mp_machine_soft_spi_obj_t;
+extern const mp_machine_spi_p_t mp_machine_soft_spi_p;
extern const mp_obj_type_t mp_machine_soft_spi_type;
extern const mp_obj_dict_t mp_machine_spi_locals_dict;
-void mp_machine_soft_spi_transfer(mp_obj_base_t *self, size_t len, const uint8_t *src, uint8_t *dest);
-
mp_obj_t mp_machine_spi_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args);
MP_DECLARE_CONST_FUN_OBJ_VAR_BETWEEN(mp_machine_spi_read_obj);
diff --git a/extmod/modbtree.c b/extmod/modbtree.c
index 5c1311532..8b7688580 100644
--- a/extmod/modbtree.c
+++ b/extmod/modbtree.c
@@ -282,7 +282,7 @@ STATIC mp_obj_t btree_subscr(mp_obj_t self_in, mp_obj_t index, mp_obj_t value) {
STATIC mp_obj_t btree_binary_op(mp_binary_op_t op, mp_obj_t lhs_in, mp_obj_t rhs_in) {
mp_obj_btree_t *self = MP_OBJ_TO_PTR(lhs_in);
switch (op) {
- case MP_BINARY_OP_IN: {
+ case MP_BINARY_OP_CONTAINS: {
DBT key, val;
key.data = (void*)mp_obj_str_get_data(rhs_in, &key.size);
int res = __bt_get(self->db, &key, &val, 0);
diff --git a/extmod/modframebuf.c b/extmod/modframebuf.c
index 20e40d579..a7f6ba905 100644
--- a/extmod/modframebuf.c
+++ b/extmod/modframebuf.c
@@ -54,7 +54,9 @@ typedef struct _mp_framebuf_p_t {
// constants for formats
#define FRAMEBUF_MVLSB (0)
#define FRAMEBUF_RGB565 (1)
+#define FRAMEBUF_GS2_HMSB (5)
#define FRAMEBUF_GS4_HMSB (2)
+#define FRAMEBUF_GS8 (6)
#define FRAMEBUF_MHLSB (3)
#define FRAMEBUF_MHMSB (4)
@@ -130,6 +132,30 @@ STATIC void rgb565_fill_rect(const mp_obj_framebuf_t *fb, int x, int y, int w, i
}
}
+// Functions for GS2_HMSB format
+
+STATIC void gs2_hmsb_setpixel(const mp_obj_framebuf_t *fb, int x, int y, uint32_t col) {
+ uint8_t *pixel = &((uint8_t*)fb->buf)[(x + y * fb->stride) >> 2];
+ uint8_t shift = (x & 0x3) << 1;
+ uint8_t mask = 0x3 << shift;
+ uint8_t color = (col & 0x3) << shift;
+ *pixel = color | (*pixel & (~mask));
+}
+
+STATIC uint32_t gs2_hmsb_getpixel(const mp_obj_framebuf_t *fb, int x, int y) {
+ uint8_t pixel = ((uint8_t*)fb->buf)[(x + y * fb->stride) >> 2];
+ uint8_t shift = (x & 0x3) << 1;
+ return (pixel >> shift) & 0x3;
+}
+
+STATIC void gs2_hmsb_fill_rect(const mp_obj_framebuf_t *fb, int x, int y, int w, int h, uint32_t col) {
+ for (int xx=x; xx < x+w; xx++) {
+ for (int yy=y; yy < y+h; yy++) {
+ gs2_hmsb_setpixel(fb, xx, yy, col);
+ }
+ }
+}
+
// Functions for GS4_HMSB format
STATIC void gs4_hmsb_setpixel(const mp_obj_framebuf_t *fb, int x, int y, uint32_t col) {
@@ -181,10 +207,31 @@ STATIC void gs4_hmsb_fill_rect(const mp_obj_framebuf_t *fb, int x, int y, int w,
}
}
+// Functions for GS8 format
+
+STATIC void gs8_setpixel(const mp_obj_framebuf_t *fb, int x, int y, uint32_t col) {
+ uint8_t *pixel = &((uint8_t*)fb->buf)[(x + y * fb->stride)];
+ *pixel = col & 0xff;
+}
+
+STATIC uint32_t gs8_getpixel(const mp_obj_framebuf_t *fb, int x, int y) {
+ return ((uint8_t*)fb->buf)[(x + y * fb->stride)];
+}
+
+STATIC void gs8_fill_rect(const mp_obj_framebuf_t *fb, int x, int y, int w, int h, uint32_t col) {
+ uint8_t *pixel = &((uint8_t*)fb->buf)[(x + y * fb->stride)];
+ while (h--) {
+ memset(pixel, col, w);
+ pixel += fb->stride;
+ }
+}
+
STATIC mp_framebuf_p_t formats[] = {
[FRAMEBUF_MVLSB] = {mvlsb_setpixel, mvlsb_getpixel, mvlsb_fill_rect},
[FRAMEBUF_RGB565] = {rgb565_setpixel, rgb565_getpixel, rgb565_fill_rect},
+ [FRAMEBUF_GS2_HMSB] = {gs2_hmsb_setpixel, gs2_hmsb_getpixel, gs2_hmsb_fill_rect},
[FRAMEBUF_GS4_HMSB] = {gs4_hmsb_setpixel, gs4_hmsb_getpixel, gs4_hmsb_fill_rect},
+ [FRAMEBUF_GS8] = {gs8_setpixel, gs8_getpixel, gs8_fill_rect},
[FRAMEBUF_MHLSB] = {mono_horiz_setpixel, mono_horiz_getpixel, mono_horiz_fill_rect},
[FRAMEBUF_MHMSB] = {mono_horiz_setpixel, mono_horiz_getpixel, mono_horiz_fill_rect},
};
@@ -240,9 +287,14 @@ STATIC mp_obj_t framebuf_make_new(const mp_obj_type_t *type, size_t n_args, size
case FRAMEBUF_MHMSB:
o->stride = (o->stride + 7) & ~7;
break;
+ case FRAMEBUF_GS2_HMSB:
+ o->stride = (o->stride + 3) & ~3;
+ break;
case FRAMEBUF_GS4_HMSB:
o->stride = (o->stride + 1) & ~1;
break;
+ case FRAMEBUF_GS8:
+ break;
default:
mp_raise_ValueError("invalid format");
}
@@ -579,7 +631,9 @@ STATIC const mp_rom_map_elem_t framebuf_module_globals_table[] = {
{ MP_ROM_QSTR(MP_QSTR_MVLSB), MP_ROM_INT(FRAMEBUF_MVLSB) },
{ MP_ROM_QSTR(MP_QSTR_MONO_VLSB), MP_ROM_INT(FRAMEBUF_MVLSB) },
{ MP_ROM_QSTR(MP_QSTR_RGB565), MP_ROM_INT(FRAMEBUF_RGB565) },
+ { MP_ROM_QSTR(MP_QSTR_GS2_HMSB), MP_ROM_INT(FRAMEBUF_GS2_HMSB) },
{ MP_ROM_QSTR(MP_QSTR_GS4_HMSB), MP_ROM_INT(FRAMEBUF_GS4_HMSB) },
+ { MP_ROM_QSTR(MP_QSTR_GS8), MP_ROM_INT(FRAMEBUF_GS8) },
{ MP_ROM_QSTR(MP_QSTR_MONO_HLSB), MP_ROM_INT(FRAMEBUF_MHLSB) },
{ MP_ROM_QSTR(MP_QSTR_MONO_HMSB), MP_ROM_INT(FRAMEBUF_MHMSB) },
};
diff --git a/extmod/modlwip.c b/extmod/modlwip.c
index bbb01b5d7..dfb5de9e4 100644
--- a/extmod/modlwip.c
+++ b/extmod/modlwip.c
@@ -38,13 +38,18 @@
#include "lib/netutils/netutils.h"
#include "lwip/init.h"
-#include "lwip/timers.h"
#include "lwip/tcp.h"
#include "lwip/udp.h"
//#include "lwip/raw.h"
#include "lwip/dns.h"
-#include "lwip/tcp_impl.h"
#include "lwip/igmp.h"
+#if LWIP_VERSION_MAJOR < 2
+#include "lwip/timers.h"
+#include "lwip/tcp_impl.h"
+#else
+#include "lwip/timeouts.h"
+#include "lwip/priv/tcp_priv.h"
+#endif
#if 0 // print debugging info
#define DEBUG_printf DEBUG_printf
@@ -171,11 +176,16 @@ STATIC const mp_obj_type_t lwip_slip_type = {
// Table to convert lwIP err_t codes to socket errno codes, from the lwIP
// socket API.
+// lwIP 2 changed LWIP_VERSION and it can no longer be used in macros,
+// so we define our own equivalent version that can.
+#define LWIP_VERSION_MACRO (LWIP_VERSION_MAJOR << 24 | LWIP_VERSION_MINOR << 16 \
+ | LWIP_VERSION_REVISION << 8 | LWIP_VERSION_RC)
+
// Extension to lwIP error codes
#define _ERR_BADF -16
// TODO: We just know that change happened somewhere between 1.4.0 and 1.4.1,
// investigate in more detail.
-#if LWIP_VERSION < 0x01040100
+#if LWIP_VERSION_MACRO < 0x01040100
static const int error_lookup_table[] = {
0, /* ERR_OK 0 No error, everything OK. */
MP_ENOMEM, /* ERR_MEM -1 Out of memory error. */
@@ -196,7 +206,7 @@ static const int error_lookup_table[] = {
MP_EALREADY, /* ERR_ISCONN -15 Already connected. */
MP_EBADF, /* _ERR_BADF -16 Closed socket (null pcb) */
};
-#else
+#elif LWIP_VERSION_MACRO < 0x02000000
static const int error_lookup_table[] = {
0, /* ERR_OK 0 No error, everything OK. */
MP_ENOMEM, /* ERR_MEM -1 Out of memory error. */
@@ -217,6 +227,30 @@ static const int error_lookup_table[] = {
-1, /* ERR_IF -15 Low-level netif error */
MP_EBADF, /* _ERR_BADF -16 Closed socket (null pcb) */
};
+#else
+// Matches lwIP 2.0.3
+#undef _ERR_BADF
+#define _ERR_BADF -17
+static const int error_lookup_table[] = {
+ 0, /* ERR_OK 0 No error, everything OK */
+ MP_ENOMEM, /* ERR_MEM -1 Out of memory error */
+ MP_ENOBUFS, /* ERR_BUF -2 Buffer error */
+ MP_EWOULDBLOCK, /* ERR_TIMEOUT -3 Timeout */
+ MP_EHOSTUNREACH, /* ERR_RTE -4 Routing problem */
+ MP_EINPROGRESS, /* ERR_INPROGRESS -5 Operation in progress */
+ MP_EINVAL, /* ERR_VAL -6 Illegal value */
+ MP_EWOULDBLOCK, /* ERR_WOULDBLOCK -7 Operation would block */
+ MP_EADDRINUSE, /* ERR_USE -8 Address in use */
+ MP_EALREADY, /* ERR_ALREADY -9 Already connecting */
+ MP_EALREADY, /* ERR_ISCONN -10 Conn already established */
+ MP_ENOTCONN, /* ERR_CONN -11 Not connected */
+ -1, /* ERR_IF -12 Low-level netif error */
+ MP_ECONNABORTED, /* ERR_ABRT -13 Connection aborted */
+ MP_ECONNRESET, /* ERR_RST -14 Connection reset */
+ MP_ENOTCONN, /* ERR_CLSD -15 Connection closed */
+ MP_EIO, /* ERR_ARG -16 Illegal argument. */
+ MP_EBADF, /* _ERR_BADF -17 Closed socket (null pcb) */
+};
#endif
/*******************************************************************************/
@@ -276,7 +310,12 @@ static inline void exec_user_callback(lwip_socket_obj_t *socket) {
// Callback for incoming UDP packets. We simply stash the packet and the source address,
// in case we need it for recvfrom.
-STATIC void _lwip_udp_incoming(void *arg, struct udp_pcb *upcb, struct pbuf *p, ip_addr_t *addr, u16_t port) {
+#if LWIP_VERSION_MAJOR < 2
+STATIC void _lwip_udp_incoming(void *arg, struct udp_pcb *upcb, struct pbuf *p, ip_addr_t *addr, u16_t port)
+#else
+STATIC void _lwip_udp_incoming(void *arg, struct udp_pcb *upcb, struct pbuf *p, const ip_addr_t *addr, u16_t port)
+#endif
+{
lwip_socket_obj_t *socket = (lwip_socket_obj_t*)arg;
if (socket->incoming.pbuf != NULL) {
@@ -498,6 +537,11 @@ STATIC mp_uint_t lwip_tcp_send(lwip_socket_obj_t *socket, const byte *buf, mp_ui
err_t err = tcp_write(socket->pcb.tcp, buf, write_len, TCP_WRITE_FLAG_COPY);
+ // If the output buffer is getting full then send the data to the lower layers
+ if (err == ERR_OK && tcp_sndbuf(socket->pcb.tcp) < TCP_SND_BUF / 4) {
+ err = tcp_output(socket->pcb.tcp);
+ }
+
if (err != ERR_OK) {
*_errno = error_lookup_table[-err];
return MP_STREAM_ERROR;
@@ -632,42 +676,6 @@ STATIC mp_obj_t lwip_socket_make_new(const mp_obj_type_t *type, size_t n_args, s
return socket;
}
-STATIC mp_obj_t lwip_socket_close(mp_obj_t self_in) {
- lwip_socket_obj_t *socket = self_in;
- bool socket_is_listener = false;
-
- if (socket->pcb.tcp == NULL) {
- return mp_const_none;
- }
- switch (socket->type) {
- case MOD_NETWORK_SOCK_STREAM: {
- if (socket->pcb.tcp->state == LISTEN) {
- socket_is_listener = true;
- }
- if (tcp_close(socket->pcb.tcp) != ERR_OK) {
- DEBUG_printf("lwip_close: had to call tcp_abort()\n");
- tcp_abort(socket->pcb.tcp);
- }
- break;
- }
- case MOD_NETWORK_SOCK_DGRAM: udp_remove(socket->pcb.udp); break;
- //case MOD_NETWORK_SOCK_RAW: raw_remove(socket->pcb.raw); break;
- }
- socket->pcb.tcp = NULL;
- socket->state = _ERR_BADF;
- if (socket->incoming.pbuf != NULL) {
- if (!socket_is_listener) {
- pbuf_free(socket->incoming.pbuf);
- } else {
- tcp_abort(socket->incoming.connection);
- }
- socket->incoming.pbuf = NULL;
- }
-
- return mp_const_none;
-}
-STATIC MP_DEFINE_CONST_FUN_OBJ_1(lwip_socket_close_obj, lwip_socket_close);
-
STATIC mp_obj_t lwip_socket_bind(mp_obj_t self_in, mp_obj_t addr_in) {
lwip_socket_obj_t *socket = self_in;
@@ -715,6 +723,9 @@ STATIC mp_obj_t lwip_socket_listen(mp_obj_t self_in, mp_obj_t backlog_in) {
socket->pcb.tcp = new_pcb;
tcp_accept(new_pcb, _lwip_tcp_accept);
+ // Socket is no longer considered "new" for purposes of polling
+ socket->state = STATE_CONNECTING;
+
return mp_const_none;
}
STATIC MP_DEFINE_CONST_FUN_OBJ_2(lwip_socket_listen_obj, lwip_socket_listen);
@@ -1163,17 +1174,60 @@ STATIC mp_uint_t lwip_socket_ioctl(mp_obj_t self_in, mp_uint_t request, uintptr_
ret |= MP_STREAM_POLL_RD;
}
- if (flags & MP_STREAM_POLL_WR && tcp_sndbuf(socket->pcb.tcp) > 0) {
+ // Note: pcb.tcp==NULL if state<0, and in this case we can't call tcp_sndbuf
+ if (flags & MP_STREAM_POLL_WR && socket->pcb.tcp != NULL && tcp_sndbuf(socket->pcb.tcp) > 0) {
ret |= MP_STREAM_POLL_WR;
}
- if (socket->state == STATE_PEER_CLOSED) {
+ if (socket->state == STATE_NEW) {
+ // New sockets are not connected so set HUP
+ ret |= flags & MP_STREAM_POLL_HUP;
+ } else if (socket->state == STATE_PEER_CLOSED) {
// Peer-closed socket is both readable and writable: read will
// return EOF, write - error. Without this poll will hang on a
// socket which was closed by peer.
ret |= flags & (MP_STREAM_POLL_RD | MP_STREAM_POLL_WR);
+ } else if (socket->state == ERR_RST) {
+ // Socket was reset by peer, a write will return an error
+ ret |= flags & (MP_STREAM_POLL_WR | MP_STREAM_POLL_HUP);
+ } else if (socket->state < 0) {
+ // Socket in some other error state, use catch-all ERR flag
+ // TODO: may need to set other return flags here
+ ret |= flags & MP_STREAM_POLL_ERR;
}
+ } else if (request == MP_STREAM_CLOSE) {
+ bool socket_is_listener = false;
+
+ if (socket->pcb.tcp == NULL) {
+ return 0;
+ }
+ switch (socket->type) {
+ case MOD_NETWORK_SOCK_STREAM: {
+ if (socket->pcb.tcp->state == LISTEN) {
+ socket_is_listener = true;
+ }
+ if (tcp_close(socket->pcb.tcp) != ERR_OK) {
+ DEBUG_printf("lwip_close: had to call tcp_abort()\n");
+ tcp_abort(socket->pcb.tcp);
+ }
+ break;
+ }
+ case MOD_NETWORK_SOCK_DGRAM: udp_remove(socket->pcb.udp); break;
+ //case MOD_NETWORK_SOCK_RAW: raw_remove(socket->pcb.raw); break;
+ }
+ socket->pcb.tcp = NULL;
+ socket->state = _ERR_BADF;
+ if (socket->incoming.pbuf != NULL) {
+ if (!socket_is_listener) {
+ pbuf_free(socket->incoming.pbuf);
+ } else {
+ tcp_abort(socket->incoming.connection);
+ }
+ socket->incoming.pbuf = NULL;
+ }
+ ret = 0;
+
} else {
*errcode = MP_EINVAL;
ret = MP_STREAM_ERROR;
@@ -1183,8 +1237,8 @@ STATIC mp_uint_t lwip_socket_ioctl(mp_obj_t self_in, mp_uint_t request, uintptr_
}
STATIC const mp_rom_map_elem_t lwip_socket_locals_dict_table[] = {
- { MP_ROM_QSTR(MP_QSTR___del__), MP_ROM_PTR(&lwip_socket_close_obj) },
- { MP_ROM_QSTR(MP_QSTR_close), MP_ROM_PTR(&lwip_socket_close_obj) },
+ { MP_ROM_QSTR(MP_QSTR___del__), MP_ROM_PTR(&mp_stream_close_obj) },
+ { MP_ROM_QSTR(MP_QSTR_close), MP_ROM_PTR(&mp_stream_close_obj) },
{ MP_ROM_QSTR(MP_QSTR_bind), MP_ROM_PTR(&lwip_socket_bind_obj) },
{ MP_ROM_QSTR(MP_QSTR_listen), MP_ROM_PTR(&lwip_socket_listen_obj) },
{ MP_ROM_QSTR(MP_QSTR_accept), MP_ROM_PTR(&lwip_socket_accept_obj) },
@@ -1278,7 +1332,12 @@ typedef struct _getaddrinfo_state_t {
} getaddrinfo_state_t;
// Callback for incoming DNS requests.
-STATIC void lwip_getaddrinfo_cb(const char *name, ip_addr_t *ipaddr, void *arg) {
+#if LWIP_VERSION_MAJOR < 2
+STATIC void lwip_getaddrinfo_cb(const char *name, ip_addr_t *ipaddr, void *arg)
+#else
+STATIC void lwip_getaddrinfo_cb(const char *name, const ip_addr_t *ipaddr, void *arg)
+#endif
+{
getaddrinfo_state_t *state = arg;
if (ipaddr != NULL) {
state->status = 1;
@@ -1291,14 +1350,33 @@ STATIC void lwip_getaddrinfo_cb(const char *name, ip_addr_t *ipaddr, void *arg)
// lwip.getaddrinfo
STATIC mp_obj_t lwip_getaddrinfo(size_t n_args, const mp_obj_t *args) {
- if (n_args > 2) {
- mp_warning("getaddrinfo constraints not supported");
- }
-
mp_obj_t host_in = args[0], port_in = args[1];
const char *host = mp_obj_str_get_str(host_in);
mp_int_t port = mp_obj_get_int(port_in);
+ // If constraints were passed then check they are compatible with the supported params
+ if (n_args > 2) {
+ mp_int_t family = mp_obj_get_int(args[2]);
+ mp_int_t type = 0;
+ mp_int_t proto = 0;
+ mp_int_t flags = 0;
+ if (n_args > 3) {
+ type = mp_obj_get_int(args[3]);
+ if (n_args > 4) {
+ proto = mp_obj_get_int(args[4]);
+ if (n_args > 5) {
+ flags = mp_obj_get_int(args[5]);
+ }
+ }
+ }
+ if (!((family == 0 || family == MOD_NETWORK_AF_INET)
+ && (type == 0 || type == MOD_NETWORK_SOCK_STREAM)
+ && proto == 0
+ && flags == 0)) {
+ mp_warning("unsupported getaddrinfo constraints");
+ }
+ }
+
getaddrinfo_state_t state;
state.status = 0;
@@ -1331,7 +1409,7 @@ STATIC mp_obj_t lwip_getaddrinfo(size_t n_args, const mp_obj_t *args) {
tuple->items[4] = netutils_format_inet_addr((uint8_t*)&state.ipaddr, port, NETUTILS_BIG);
return mp_obj_new_list(1, (mp_obj_t*)&tuple);
}
-STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(lwip_getaddrinfo_obj, 2, 6, lwip_getaddrinfo);
+MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(lwip_getaddrinfo_obj, 2, 6, lwip_getaddrinfo);
// Debug functions
diff --git a/extmod/moduhashlib.c b/extmod/moduhashlib.c
index 7ae42a15f..d062271bb 100644
--- a/extmod/moduhashlib.c
+++ b/extmod/moduhashlib.c
@@ -31,8 +31,19 @@
#if MICROPY_PY_UHASHLIB
+#if MICROPY_PY_UHASHLIB_SHA256
+
+#if MICROPY_SSL_MBEDTLS
+#include "mbedtls/sha256.h"
+#else
#include "crypto-algorithms/sha256.h"
+#endif
+
+#endif
+
#if MICROPY_PY_UHASHLIB_SHA1
+
+#if MICROPY_SSL_AXTLS
#include "lib/axtls/crypto/crypto.h"
#endif
@@ -42,6 +53,13 @@ static void check_not_unicode(const mp_obj_t arg) {
mp_raise_TypeError("a bytes-like object is required");
}
#endif
+
+#if MICROPY_SSL_MBEDTLS
+#include "mbedtls/sha1.h"
+#endif
+
+#endif
+
}
typedef struct _mp_obj_hash_t {
@@ -49,35 +67,53 @@ typedef struct _mp_obj_hash_t {
char state[0];
} mp_obj_hash_t;
-STATIC mp_obj_t hash_update(mp_obj_t self_in, mp_obj_t arg);
+#if MICROPY_PY_UHASHLIB_SHA256
+STATIC mp_obj_t uhashlib_sha256_update(mp_obj_t self_in, mp_obj_t arg);
+
+#if MICROPY_SSL_MBEDTLS
-STATIC mp_obj_t hash_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) {
+STATIC mp_obj_t uhashlib_sha256_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) {
mp_arg_check_num(n_args, n_kw, 0, 1, false);
- mp_obj_hash_t *o = m_new_obj_var(mp_obj_hash_t, char, sizeof(CRYAL_SHA256_CTX));
+ mp_obj_hash_t *o = m_new_obj_var(mp_obj_hash_t, char, sizeof(mbedtls_sha256_context));
o->base.type = type;
- sha256_init((CRYAL_SHA256_CTX*)o->state);
+ mbedtls_sha256_init((mbedtls_sha256_context*)&o->state);
+ mbedtls_sha256_starts((mbedtls_sha256_context*)&o->state, 0);
if (n_args == 1) {
- hash_update(MP_OBJ_FROM_PTR(o), args[0]);
+ uhashlib_sha256_update(MP_OBJ_FROM_PTR(o), args[0]);
}
return MP_OBJ_FROM_PTR(o);
}
-#if MICROPY_PY_UHASHLIB_SHA1
-STATIC mp_obj_t sha1_update(mp_obj_t self_in, mp_obj_t arg);
+STATIC mp_obj_t uhashlib_sha256_update(mp_obj_t self_in, mp_obj_t arg) {
+ mp_obj_hash_t *self = MP_OBJ_TO_PTR(self_in);
+ mp_buffer_info_t bufinfo;
+ mp_get_buffer_raise(arg, &bufinfo, MP_BUFFER_READ);
+ mbedtls_sha256_update((mbedtls_sha256_context*)&self->state, bufinfo.buf, bufinfo.len);
+ return mp_const_none;
+}
-STATIC mp_obj_t sha1_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) {
+STATIC mp_obj_t uhashlib_sha256_digest(mp_obj_t self_in) {
+ mp_obj_hash_t *self = MP_OBJ_TO_PTR(self_in);
+ vstr_t vstr;
+ vstr_init_len(&vstr, 32);
+ mbedtls_sha256_finish((mbedtls_sha256_context*)&self->state, (unsigned char *)vstr.buf);
+ return mp_obj_new_str_from_vstr(&mp_type_bytes, &vstr);
+}
+
+#else
+
+STATIC mp_obj_t uhashlib_sha256_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) {
mp_arg_check_num(n_args, n_kw, 0, 1, false);
- mp_obj_hash_t *o = m_new_obj_var(mp_obj_hash_t, char, sizeof(SHA1_CTX));
+ mp_obj_hash_t *o = m_new_obj_var(mp_obj_hash_t, char, sizeof(CRYAL_SHA256_CTX));
o->base.type = type;
- SHA1_Init((SHA1_CTX*)o->state);
+ sha256_init((CRYAL_SHA256_CTX*)o->state);
if (n_args == 1) {
- sha1_update(MP_OBJ_FROM_PTR(o), args[0]);
+ uhashlib_sha256_update(MP_OBJ_FROM_PTR(o), args[0]);
}
return MP_OBJ_FROM_PTR(o);
}
-#endif
-STATIC mp_obj_t hash_update(mp_obj_t self_in, mp_obj_t arg) {
+STATIC mp_obj_t uhashlib_sha256_update(mp_obj_t self_in, mp_obj_t arg) {
check_not_unicode(arg);
mp_obj_hash_t *self = MP_OBJ_TO_PTR(self_in);
mp_buffer_info_t bufinfo;
@@ -85,10 +121,50 @@ STATIC mp_obj_t hash_update(mp_obj_t self_in, mp_obj_t arg) {
sha256_update((CRYAL_SHA256_CTX*)self->state, bufinfo.buf, bufinfo.len);
return mp_const_none;
}
-MP_DEFINE_CONST_FUN_OBJ_2(hash_update_obj, hash_update);
+
+STATIC mp_obj_t uhashlib_sha256_digest(mp_obj_t self_in) {
+ mp_obj_hash_t *self = MP_OBJ_TO_PTR(self_in);
+ vstr_t vstr;
+ vstr_init_len(&vstr, SHA256_BLOCK_SIZE);
+ sha256_final((CRYAL_SHA256_CTX*)self->state, (byte*)vstr.buf);
+ return mp_obj_new_str_from_vstr(&mp_type_bytes, &vstr);
+}
+#endif
+
+STATIC MP_DEFINE_CONST_FUN_OBJ_2(uhashlib_sha256_update_obj, uhashlib_sha256_update);
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(uhashlib_sha256_digest_obj, uhashlib_sha256_digest);
+
+STATIC const mp_rom_map_elem_t uhashlib_sha256_locals_dict_table[] = {
+ { MP_ROM_QSTR(MP_QSTR_update), MP_ROM_PTR(&uhashlib_sha256_update_obj) },
+ { MP_ROM_QSTR(MP_QSTR_digest), MP_ROM_PTR(&uhashlib_sha256_digest_obj) },
+};
+
+STATIC MP_DEFINE_CONST_DICT(uhashlib_sha256_locals_dict, uhashlib_sha256_locals_dict_table);
+
+STATIC const mp_obj_type_t uhashlib_sha256_type = {
+ { &mp_type_type },
+ .name = MP_QSTR_sha256,
+ .make_new = uhashlib_sha256_make_new,
+ .locals_dict = (void*)&uhashlib_sha256_locals_dict,
+};
+#endif
#if MICROPY_PY_UHASHLIB_SHA1
-STATIC mp_obj_t sha1_update(mp_obj_t self_in, mp_obj_t arg) {
+STATIC mp_obj_t uhashlib_sha1_update(mp_obj_t self_in, mp_obj_t arg);
+
+#if MICROPY_SSL_AXTLS
+STATIC mp_obj_t uhashlib_sha1_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) {
+ mp_arg_check_num(n_args, n_kw, 0, 1, false);
+ mp_obj_hash_t *o = m_new_obj_var(mp_obj_hash_t, char, sizeof(SHA1_CTX));
+ o->base.type = type;
+ SHA1_Init((SHA1_CTX*)o->state);
+ if (n_args == 1) {
+ uhashlib_sha1_update(MP_OBJ_FROM_PTR(o), args[0]);
+ }
+ return MP_OBJ_FROM_PTR(o);
+}
+
+STATIC mp_obj_t uhashlib_sha1_update(mp_obj_t self_in, mp_obj_t arg) {
check_not_unicode(arg);
mp_obj_hash_t *self = MP_OBJ_TO_PTR(self_in);
mp_buffer_info_t bufinfo;
@@ -96,73 +172,83 @@ STATIC mp_obj_t sha1_update(mp_obj_t self_in, mp_obj_t arg) {
SHA1_Update((SHA1_CTX*)self->state, bufinfo.buf, bufinfo.len);
return mp_const_none;
}
-MP_DEFINE_CONST_FUN_OBJ_2(sha1_update_obj, sha1_update);
-#endif
-STATIC mp_obj_t hash_digest(mp_obj_t self_in) {
+STATIC mp_obj_t uhashlib_sha1_digest(mp_obj_t self_in) {
mp_obj_hash_t *self = MP_OBJ_TO_PTR(self_in);
vstr_t vstr;
- vstr_init_len(&vstr, SHA256_BLOCK_SIZE);
- sha256_final((CRYAL_SHA256_CTX*)self->state, (byte*)vstr.buf);
+ vstr_init_len(&vstr, SHA1_SIZE);
+ SHA1_Final((byte*)vstr.buf, (SHA1_CTX*)self->state);
return mp_obj_new_str_from_vstr(&mp_type_bytes, &vstr);
}
-MP_DEFINE_CONST_FUN_OBJ_1(hash_digest_obj, hash_digest);
+#endif
-#if MICROPY_PY_UHASHLIB_SHA1
-STATIC mp_obj_t sha1_digest(mp_obj_t self_in) {
+#if MICROPY_SSL_MBEDTLS
+STATIC mp_obj_t uhashlib_sha1_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) {
+ mp_arg_check_num(n_args, n_kw, 0, 1, false);
+ mp_obj_hash_t *o = m_new_obj_var(mp_obj_hash_t, char, sizeof(mbedtls_sha1_context));
+ o->base.type = type;
+ mbedtls_sha1_init((mbedtls_sha1_context*)o->state);
+ mbedtls_sha1_starts((mbedtls_sha1_context*)o->state);
+ if (n_args == 1) {
+ uhashlib_sha1_update(MP_OBJ_FROM_PTR(o), args[0]);
+ }
+ return MP_OBJ_FROM_PTR(o);
+}
+
+STATIC mp_obj_t uhashlib_sha1_update(mp_obj_t self_in, mp_obj_t arg) {
+ mp_obj_hash_t *self = MP_OBJ_TO_PTR(self_in);
+ mp_buffer_info_t bufinfo;
+ mp_get_buffer_raise(arg, &bufinfo, MP_BUFFER_READ);
+ mbedtls_sha1_update((mbedtls_sha1_context*)self->state, bufinfo.buf, bufinfo.len);
+ return mp_const_none;
+}
+
+STATIC mp_obj_t uhashlib_sha1_digest(mp_obj_t self_in) {
mp_obj_hash_t *self = MP_OBJ_TO_PTR(self_in);
vstr_t vstr;
- vstr_init_len(&vstr, SHA1_SIZE);
- SHA1_Final((byte*)vstr.buf, (SHA1_CTX*)self->state);
+ vstr_init_len(&vstr, 20);
+ mbedtls_sha1_finish((mbedtls_sha1_context*)self->state, (byte*)vstr.buf);
+ mbedtls_sha1_free((mbedtls_sha1_context*)self->state);
return mp_obj_new_str_from_vstr(&mp_type_bytes, &vstr);
}
-MP_DEFINE_CONST_FUN_OBJ_1(sha1_digest_obj, sha1_digest);
#endif
-STATIC const mp_rom_map_elem_t hash_locals_dict_table[] = {
- { MP_ROM_QSTR(MP_QSTR_update), MP_ROM_PTR(&hash_update_obj) },
- { MP_ROM_QSTR(MP_QSTR_digest), MP_ROM_PTR(&hash_digest_obj) },
-};
-
-STATIC MP_DEFINE_CONST_DICT(hash_locals_dict, hash_locals_dict_table);
+STATIC MP_DEFINE_CONST_FUN_OBJ_2(uhashlib_sha1_update_obj, uhashlib_sha1_update);
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(uhashlib_sha1_digest_obj, uhashlib_sha1_digest);
-STATIC const mp_obj_type_t sha256_type = {
- { &mp_type_type },
- .name = MP_QSTR_sha256,
- .make_new = hash_make_new,
- .locals_dict = (void*)&hash_locals_dict,
+STATIC const mp_rom_map_elem_t uhashlib_sha1_locals_dict_table[] = {
+ { MP_ROM_QSTR(MP_QSTR_update), MP_ROM_PTR(&uhashlib_sha1_update_obj) },
+ { MP_ROM_QSTR(MP_QSTR_digest), MP_ROM_PTR(&uhashlib_sha1_digest_obj) },
};
+STATIC MP_DEFINE_CONST_DICT(uhashlib_sha1_locals_dict, uhashlib_sha1_locals_dict_table);
-#if MICROPY_PY_UHASHLIB_SHA1
-STATIC const mp_rom_map_elem_t sha1_locals_dict_table[] = {
- { MP_ROM_QSTR(MP_QSTR_update), MP_ROM_PTR(&sha1_update_obj) },
- { MP_ROM_QSTR(MP_QSTR_digest), MP_ROM_PTR(&sha1_digest_obj) },
-};
-STATIC MP_DEFINE_CONST_DICT(sha1_locals_dict, sha1_locals_dict_table);
-
-STATIC const mp_obj_type_t sha1_type = {
+STATIC const mp_obj_type_t uhashlib_sha1_type = {
{ &mp_type_type },
.name = MP_QSTR_sha1,
- .make_new = sha1_make_new,
- .locals_dict = (void*)&sha1_locals_dict,
+ .make_new = uhashlib_sha1_make_new,
+ .locals_dict = (void*)&uhashlib_sha1_locals_dict,
};
#endif
-STATIC const mp_rom_map_elem_t mp_module_hashlib_globals_table[] = {
+STATIC const mp_rom_map_elem_t mp_module_uhashlib_globals_table[] = {
{ MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_hashlib) },
- { MP_ROM_QSTR(MP_QSTR_sha256), MP_ROM_PTR(&sha256_type) },
+ #if MICROPY_PY_UHASHLIB_SHA256
+ { MP_ROM_QSTR(MP_QSTR_sha256), MP_ROM_PTR(&uhashlib_sha256_type) },
+ #endif
#if MICROPY_PY_UHASHLIB_SHA1
- { MP_ROM_QSTR(MP_QSTR_sha1), MP_ROM_PTR(&sha1_type) },
+ { MP_ROM_QSTR(MP_QSTR_sha1), MP_ROM_PTR(&uhashlib_sha1_type) },
#endif
};
-STATIC MP_DEFINE_CONST_DICT(mp_module_hashlib_globals, mp_module_hashlib_globals_table);
+STATIC MP_DEFINE_CONST_DICT(mp_module_uhashlib_globals, mp_module_uhashlib_globals_table);
const mp_obj_module_t mp_module_uhashlib = {
.base = { &mp_type_module },
- .globals = (mp_obj_dict_t*)&mp_module_hashlib_globals,
+ .globals = (mp_obj_dict_t*)&mp_module_uhashlib_globals,
};
+#if MICROPY_PY_UHASHLIB_SHA256
#include "crypto-algorithms/sha256.c"
+#endif
#endif //MICROPY_PY_UHASHLIB
diff --git a/extmod/modujson.c b/extmod/modujson.c
index f14682d26..830b588fd 100644
--- a/extmod/modujson.c
+++ b/extmod/modujson.c
@@ -34,6 +34,14 @@
#if MICROPY_PY_UJSON
+STATIC mp_obj_t mod_ujson_dump(mp_obj_t obj, mp_obj_t stream) {
+ mp_get_stream_raise(stream, MP_STREAM_OP_WRITE);
+ mp_print_t print = {MP_OBJ_TO_PTR(stream), mp_stream_write_adaptor};
+ mp_obj_print_helper(&print, obj, PRINT_JSON);
+ return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_2(mod_ujson_dump_obj, mod_ujson_dump);
+
STATIC mp_obj_t mod_ujson_dumps(mp_obj_t obj) {
vstr_t vstr;
mp_print_t print;
@@ -166,7 +174,7 @@ STATIC mp_obj_t mod_ujson_load(mp_obj_t stream_obj) {
goto fail;
}
S_NEXT(s);
- next = mp_obj_new_str(vstr.buf, vstr.len, false);
+ next = mp_obj_new_str(vstr.buf, vstr.len);
break;
case '-':
case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': {
@@ -283,6 +291,7 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_1(mod_ujson_loads_obj, mod_ujson_loads);
STATIC const mp_rom_map_elem_t mp_module_ujson_globals_table[] = {
{ MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_ujson) },
+ { MP_ROM_QSTR(MP_QSTR_dump), MP_ROM_PTR(&mod_ujson_dump_obj) },
{ MP_ROM_QSTR(MP_QSTR_dumps), MP_ROM_PTR(&mod_ujson_dumps_obj) },
{ MP_ROM_QSTR(MP_QSTR_load), MP_ROM_PTR(&mod_ujson_load_obj) },
{ MP_ROM_QSTR(MP_QSTR_loads), MP_ROM_PTR(&mod_ujson_loads_obj) },
diff --git a/extmod/modure.c b/extmod/modure.c
index 78de4706d..31c2b9864 100644
--- a/extmod/modure.c
+++ b/extmod/modure.c
@@ -144,7 +144,7 @@ STATIC mp_obj_t re_split(size_t n_args, const mp_obj_t *args) {
}
mp_obj_t retval = mp_obj_new_list(0, NULL);
- const char **caps = alloca(caps_num * sizeof(char*));
+ const char **caps = mp_local_alloc(caps_num * sizeof(char*));
while (true) {
// cast is a workaround for a bug in msvc: it treats const char** as a const pointer instead of a pointer to pointer to const char
memset((char**)caps, 0, caps_num * sizeof(char*));
@@ -165,6 +165,8 @@ STATIC mp_obj_t re_split(size_t n_args, const mp_obj_t *args) {
break;
}
}
+ // cast is a workaround for a bug in msvc (see above)
+ mp_local_free((char**)caps);
mp_obj_t s = mp_obj_new_str_of_type(str_type, (const byte*)subj.begin, subj.end - subj.begin);
mp_obj_list_append(retval, s);
diff --git a/extmod/modussl_axtls.c b/extmod/modussl_axtls.c
index 3ad65ebf3..475d3f0ea 100644
--- a/extmod/modussl_axtls.c
+++ b/extmod/modussl_axtls.c
@@ -44,6 +44,8 @@ typedef struct _mp_obj_ssl_socket_t {
} mp_obj_ssl_socket_t;
struct ssl_args {
+ mp_arg_val_t key;
+ mp_arg_val_t cert;
mp_arg_val_t server_side;
mp_arg_val_t server_hostname;
};
@@ -62,10 +64,28 @@ STATIC mp_obj_ssl_socket_t *socket_new(mp_obj_t sock, struct ssl_args *args) {
o->sock = sock;
uint32_t options = SSL_SERVER_VERIFY_LATER;
+ if (args->key.u_obj != mp_const_none) {
+ options |= SSL_NO_DEFAULT_KEY;
+ }
if ((o->ssl_ctx = ssl_ctx_new(options, SSL_DEFAULT_CLNT_SESS)) == NULL) {
mp_raise_OSError(MP_EINVAL);
}
+ if (args->key.u_obj != mp_const_none) {
+ size_t len;
+ const byte *data = (const byte*)mp_obj_str_get_data(args->key.u_obj, &len);
+ int res = ssl_obj_memory_load(o->ssl_ctx, SSL_OBJ_RSA_KEY, data, len, NULL);
+ if (res != SSL_OK) {
+ mp_raise_ValueError("invalid key");
+ }
+
+ data = (const byte*)mp_obj_str_get_data(args->cert.u_obj, &len);
+ res = ssl_obj_memory_load(o->ssl_ctx, SSL_OBJ_X509_CERT, data, len, NULL);
+ if (res != SSL_OK) {
+ mp_raise_ValueError("invalid cert");
+ }
+ }
+
if (args->server_side.u_bool) {
o->ssl_sock = ssl_server_new(o->ssl_ctx, (long)sock);
} else {
@@ -113,7 +133,7 @@ STATIC mp_uint_t socket_read(mp_obj_t o_in, void *buf, mp_uint_t size, int *errc
mp_int_t r = ssl_read(o->ssl_sock, &o->buf);
if (r == SSL_OK) {
// SSL_OK from ssl_read() means "everything is ok, but there's
- // not user data yet. So, we just keep reading.
+ // no user data yet". So, we just keep reading.
continue;
}
if (r < 0) {
@@ -121,6 +141,9 @@ STATIC mp_uint_t socket_read(mp_obj_t o_in, void *buf, mp_uint_t size, int *errc
// EOF
return 0;
}
+ if (r == SSL_EAGAIN) {
+ r = MP_EAGAIN;
+ }
*errcode = r;
return MP_STREAM_ERROR;
}
@@ -152,6 +175,25 @@ STATIC mp_uint_t socket_write(mp_obj_t o_in, const void *buf, mp_uint_t size, in
return r;
}
+STATIC mp_uint_t socket_ioctl(mp_obj_t o_in, mp_uint_t request, uintptr_t arg, int *errcode) {
+ mp_obj_ssl_socket_t *self = MP_OBJ_TO_PTR(o_in);
+ (void)arg;
+ switch (request) {
+ case MP_STREAM_CLOSE:
+ if (self->ssl_sock != NULL) {
+ ssl_free(self->ssl_sock);
+ ssl_ctx_free(self->ssl_ctx);
+ self->ssl_sock = NULL;
+ mp_stream_close(self->sock);
+ }
+ return 0;
+
+ default:
+ *errcode = MP_EINVAL;
+ return MP_STREAM_ERROR;
+ }
+}
+
STATIC mp_obj_t socket_setblocking(mp_obj_t self_in, mp_obj_t flag_in) {
// Currently supports only blocking mode
(void)self_in;
@@ -162,28 +204,15 @@ STATIC mp_obj_t socket_setblocking(mp_obj_t self_in, mp_obj_t flag_in) {
}
STATIC MP_DEFINE_CONST_FUN_OBJ_2(socket_setblocking_obj, socket_setblocking);
-STATIC mp_obj_t socket_close(mp_obj_t self_in) {
- mp_obj_ssl_socket_t *self = MP_OBJ_TO_PTR(self_in);
- if (self->ssl_sock != NULL) {
- ssl_free(self->ssl_sock);
- ssl_ctx_free(self->ssl_ctx);
- self->ssl_sock = NULL;
- return mp_stream_close(self->sock);
- }
-
- return mp_const_none;
-}
-STATIC MP_DEFINE_CONST_FUN_OBJ_1(socket_close_obj, socket_close);
-
STATIC const mp_rom_map_elem_t ussl_socket_locals_dict_table[] = {
{ MP_ROM_QSTR(MP_QSTR_read), MP_ROM_PTR(&mp_stream_read_obj) },
{ MP_ROM_QSTR(MP_QSTR_readinto), MP_ROM_PTR(&mp_stream_readinto_obj) },
{ MP_ROM_QSTR(MP_QSTR_readline), MP_ROM_PTR(&mp_stream_unbuffered_readline_obj) },
{ MP_ROM_QSTR(MP_QSTR_write), MP_ROM_PTR(&mp_stream_write_obj) },
{ MP_ROM_QSTR(MP_QSTR_setblocking), MP_ROM_PTR(&socket_setblocking_obj) },
- { MP_ROM_QSTR(MP_QSTR_close), MP_ROM_PTR(&socket_close_obj) },
+ { MP_ROM_QSTR(MP_QSTR_close), MP_ROM_PTR(&mp_stream_close_obj) },
#if MICROPY_PY_USSL_FINALISER
- { MP_ROM_QSTR(MP_QSTR___del__), MP_ROM_PTR(&socket_close_obj) },
+ { MP_ROM_QSTR(MP_QSTR___del__), MP_ROM_PTR(&mp_stream_close_obj) },
#endif
};
@@ -192,6 +221,7 @@ STATIC MP_DEFINE_CONST_DICT(ussl_socket_locals_dict, ussl_socket_locals_dict_tab
STATIC const mp_stream_p_t ussl_socket_stream_p = {
.read = socket_read,
.write = socket_write,
+ .ioctl = socket_ioctl,
};
STATIC const mp_obj_type_t ussl_socket_type = {
@@ -208,6 +238,8 @@ STATIC const mp_obj_type_t ussl_socket_type = {
STATIC mp_obj_t mod_ssl_wrap_socket(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
// TODO: Implement more args
static const mp_arg_t allowed_args[] = {
+ { MP_QSTR_key, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none} },
+ { MP_QSTR_cert, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none} },
{ MP_QSTR_server_side, MP_ARG_KW_ONLY | MP_ARG_BOOL, {.u_bool = false} },
{ MP_QSTR_server_hostname, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none} },
};
diff --git a/extmod/modussl_mbedtls.c b/extmod/modussl_mbedtls.c
index 69a64d2f7..08807d20b 100644
--- a/extmod/modussl_mbedtls.c
+++ b/extmod/modussl_mbedtls.c
@@ -73,19 +73,10 @@ STATIC void mbedtls_debug(void *ctx, int level, const char *file, int line, cons
}
#endif
-// TODO: FIXME!
-STATIC int null_entropy_func(void *data, unsigned char *output, size_t len) {
- (void)data;
- (void)output;
- (void)len;
- // enjoy random bytes
- return 0;
-}
-
STATIC int _mbedtls_ssl_send(void *ctx, const byte *buf, size_t len) {
mp_obj_t sock = *(mp_obj_t*)ctx;
- const mp_stream_p_t *sock_stream = mp_get_stream_raise(sock, MP_STREAM_OP_WRITE);
+ const mp_stream_p_t *sock_stream = mp_get_stream(sock);
int err;
mp_uint_t out_sz = sock_stream->write(sock, buf, len, &err);
@@ -102,7 +93,7 @@ STATIC int _mbedtls_ssl_send(void *ctx, const byte *buf, size_t len) {
STATIC int _mbedtls_ssl_recv(void *ctx, byte *buf, size_t len) {
mp_obj_t sock = *(mp_obj_t*)ctx;
- const mp_stream_p_t *sock_stream = mp_get_stream_raise(sock, MP_STREAM_OP_READ);
+ const mp_stream_p_t *sock_stream = mp_get_stream(sock);
int err;
mp_uint_t out_sz = sock_stream->read(sock, buf, len, &err);
@@ -118,12 +109,16 @@ STATIC int _mbedtls_ssl_recv(void *ctx, byte *buf, size_t len) {
STATIC mp_obj_ssl_socket_t *socket_new(mp_obj_t sock, struct ssl_args *args) {
+ // Verify the socket object has the full stream protocol
+ mp_get_stream_raise(sock, MP_STREAM_OP_READ | MP_STREAM_OP_WRITE | MP_STREAM_OP_IOCTL);
+
#if MICROPY_PY_USSL_FINALISER
mp_obj_ssl_socket_t *o = m_new_obj_with_finaliser(mp_obj_ssl_socket_t);
#else
mp_obj_ssl_socket_t *o = m_new_obj(mp_obj_ssl_socket_t);
#endif
o->base.type = &ussl_socket_type;
+ o->sock = sock;
int ret;
mbedtls_ssl_init(&o->ssl);
@@ -139,10 +134,9 @@ STATIC mp_obj_ssl_socket_t *socket_new(mp_obj_t sock, struct ssl_args *args) {
mbedtls_entropy_init(&o->entropy);
const byte seed[] = "upy";
- ret = mbedtls_ctr_drbg_seed(&o->ctr_drbg, null_entropy_func/*mbedtls_entropy_func*/, &o->entropy, seed, sizeof(seed));
+ ret = mbedtls_ctr_drbg_seed(&o->ctr_drbg, mbedtls_entropy_func, &o->entropy, seed, sizeof(seed));
if (ret != 0) {
- printf("ret=%d\n", ret);
- assert(0);
+ goto cleanup;
}
ret = mbedtls_ssl_config_defaults(&o->conf,
@@ -150,7 +144,7 @@ STATIC mp_obj_ssl_socket_t *socket_new(mp_obj_t sock, struct ssl_args *args) {
MBEDTLS_SSL_TRANSPORT_STREAM,
MBEDTLS_SSL_PRESET_DEFAULT);
if (ret != 0) {
- assert(0);
+ goto cleanup;
}
mbedtls_ssl_conf_authmode(&o->conf, MBEDTLS_SSL_VERIFY_NONE);
@@ -161,18 +155,17 @@ STATIC mp_obj_ssl_socket_t *socket_new(mp_obj_t sock, struct ssl_args *args) {
ret = mbedtls_ssl_setup(&o->ssl, &o->conf);
if (ret != 0) {
- assert(0);
+ goto cleanup;
}
if (args->server_hostname.u_obj != mp_const_none) {
const char *sni = mp_obj_str_get_str(args->server_hostname.u_obj);
ret = mbedtls_ssl_set_hostname(&o->ssl, sni);
if (ret != 0) {
- assert(0);
+ goto cleanup;
}
}
- o->sock = sock;
mbedtls_ssl_set_bio(&o->ssl, &o->sock, _mbedtls_ssl_send, _mbedtls_ssl_recv, NULL);
if (args->key.u_obj != MP_OBJ_NULL) {
@@ -194,13 +187,27 @@ STATIC mp_obj_ssl_socket_t *socket_new(mp_obj_t sock, struct ssl_args *args) {
while ((ret = mbedtls_ssl_handshake(&o->ssl)) != 0) {
if (ret != MBEDTLS_ERR_SSL_WANT_READ && ret != MBEDTLS_ERR_SSL_WANT_WRITE) {
- //assert(0);
printf("mbedtls_ssl_handshake error: -%x\n", -ret);
- mp_raise_OSError(MP_EIO);
+ goto cleanup;
}
}
return o;
+
+cleanup:
+ mbedtls_pk_free(&o->pkey);
+ mbedtls_x509_crt_free(&o->cert);
+ mbedtls_x509_crt_free(&o->cacert);
+ mbedtls_ssl_free(&o->ssl);
+ mbedtls_ssl_config_free(&o->conf);
+ mbedtls_ctr_drbg_free(&o->ctr_drbg);
+ mbedtls_entropy_free(&o->entropy);
+
+ if (ret == MBEDTLS_ERR_SSL_ALLOC_FAILED) {
+ mp_raise_OSError(MP_ENOMEM);
+ } else {
+ mp_raise_OSError(MP_EIO);
+ }
}
STATIC mp_obj_t mod_ssl_getpeercert(mp_obj_t o_in, mp_obj_t binary_form) {
@@ -261,20 +268,26 @@ STATIC mp_obj_t socket_setblocking(mp_obj_t self_in, mp_obj_t flag_in) {
}
STATIC MP_DEFINE_CONST_FUN_OBJ_2(socket_setblocking_obj, socket_setblocking);
-STATIC mp_obj_t socket_close(mp_obj_t self_in) {
- mp_obj_ssl_socket_t *self = MP_OBJ_TO_PTR(self_in);
-
- mbedtls_pk_free(&self->pkey);
- mbedtls_x509_crt_free(&self->cert);
- mbedtls_x509_crt_free(&self->cacert);
- mbedtls_ssl_free(&self->ssl);
- mbedtls_ssl_config_free(&self->conf);
- mbedtls_ctr_drbg_free(&self->ctr_drbg);
- mbedtls_entropy_free(&self->entropy);
-
- return mp_stream_close(self->sock);
+STATIC mp_uint_t socket_ioctl(mp_obj_t o_in, mp_uint_t request, uintptr_t arg, int *errcode) {
+ mp_obj_ssl_socket_t *self = MP_OBJ_TO_PTR(o_in);
+ (void)arg;
+ switch (request) {
+ case MP_STREAM_CLOSE:
+ mbedtls_pk_free(&self->pkey);
+ mbedtls_x509_crt_free(&self->cert);
+ mbedtls_x509_crt_free(&self->cacert);
+ mbedtls_ssl_free(&self->ssl);
+ mbedtls_ssl_config_free(&self->conf);
+ mbedtls_ctr_drbg_free(&self->ctr_drbg);
+ mbedtls_entropy_free(&self->entropy);
+ mp_stream_close(self->sock);
+ return 0;
+
+ default:
+ *errcode = MP_EINVAL;
+ return MP_STREAM_ERROR;
+ }
}
-STATIC MP_DEFINE_CONST_FUN_OBJ_1(socket_close_obj, socket_close);
STATIC const mp_rom_map_elem_t ussl_socket_locals_dict_table[] = {
{ MP_ROM_QSTR(MP_QSTR_read), MP_ROM_PTR(&mp_stream_read_obj) },
@@ -282,9 +295,9 @@ STATIC const mp_rom_map_elem_t ussl_socket_locals_dict_table[] = {
{ MP_ROM_QSTR(MP_QSTR_readline), MP_ROM_PTR(&mp_stream_unbuffered_readline_obj) },
{ MP_ROM_QSTR(MP_QSTR_write), MP_ROM_PTR(&mp_stream_write_obj) },
{ MP_ROM_QSTR(MP_QSTR_setblocking), MP_ROM_PTR(&socket_setblocking_obj) },
- { MP_ROM_QSTR(MP_QSTR_close), MP_ROM_PTR(&socket_close_obj) },
+ { MP_ROM_QSTR(MP_QSTR_close), MP_ROM_PTR(&mp_stream_close_obj) },
#if MICROPY_PY_USSL_FINALISER
- { MP_ROM_QSTR(MP_QSTR___del__), MP_ROM_PTR(&socket_close_obj) },
+ { MP_ROM_QSTR(MP_QSTR___del__), MP_ROM_PTR(&mp_stream_close_obj) },
#endif
{ MP_ROM_QSTR(MP_QSTR_getpeercert), MP_ROM_PTR(&mod_ssl_getpeercert_obj) },
};
@@ -294,6 +307,7 @@ STATIC MP_DEFINE_CONST_DICT(ussl_socket_locals_dict, ussl_socket_locals_dict_tab
STATIC const mp_stream_p_t ussl_socket_stream_p = {
.read = socket_read,
.write = socket_write,
+ .ioctl = socket_ioctl,
};
STATIC const mp_obj_type_t ussl_socket_type = {
diff --git a/extmod/moduzlib.c b/extmod/moduzlib.c
index 3d2ab88af..0d2366bea 100644
--- a/extmod/moduzlib.c
+++ b/extmod/moduzlib.c
@@ -53,7 +53,7 @@ STATIC unsigned char read_src_stream(TINF_DATA *data) {
p -= offsetof(mp_obj_decompio_t, decomp);
mp_obj_decompio_t *self = (mp_obj_decompio_t*)p;
- const mp_stream_p_t *stream = mp_get_stream_raise(self->src_stream, MP_STREAM_OP_READ);
+ const mp_stream_p_t *stream = mp_get_stream(self->src_stream);
int err;
byte c;
mp_uint_t out_sz = stream->read(self->src_stream, &c, 1, &err);
@@ -68,6 +68,7 @@ STATIC unsigned char read_src_stream(TINF_DATA *data) {
STATIC mp_obj_t decompio_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) {
mp_arg_check_num(n_args, n_kw, 1, 2, false);
+ mp_get_stream_raise(args[0], MP_STREAM_OP_READ);
mp_obj_decompio_t *o = m_new_obj(mp_obj_decompio_t);
o->base.type = type;
memset(&o->decomp, 0, sizeof(o->decomp));
diff --git a/extmod/modwebrepl.c b/extmod/modwebrepl.c
index 38b88821b..48b49bfc4 100644
--- a/extmod/modwebrepl.c
+++ b/extmod/modwebrepl.c
@@ -76,7 +76,7 @@ STATIC char denied_prompt[] = "\r\nAccess denied\r\n";
STATIC char webrepl_passwd[10];
STATIC void write_webrepl(mp_obj_t websock, const void *buf, size_t len) {
- const mp_stream_p_t *sock_stream = mp_get_stream_raise(websock, MP_STREAM_OP_WRITE | MP_STREAM_OP_IOCTL);
+ const mp_stream_p_t *sock_stream = mp_get_stream(websock);
int err;
int old_opts = sock_stream->ioctl(websock, MP_STREAM_SET_DATA_OPTS, FRAME_BIN, &err);
sock_stream->write(websock, buf, len, &err);
@@ -86,7 +86,7 @@ STATIC void write_webrepl(mp_obj_t websock, const void *buf, size_t len) {
#define SSTR(s) s, sizeof(s) - 1
STATIC void write_webrepl_str(mp_obj_t websock, const char *str, int sz) {
int err;
- const mp_stream_p_t *sock_stream = mp_get_stream_raise(websock, MP_STREAM_OP_WRITE | MP_STREAM_OP_IOCTL);
+ const mp_stream_p_t *sock_stream = mp_get_stream(websock);
sock_stream->write(websock, str, sz, &err);
}
@@ -110,8 +110,7 @@ STATIC mp_obj_t webrepl_make_new(const mp_obj_type_t *type, size_t n_args, size_
}
STATIC int write_file_chunk(mp_obj_webrepl_t *self) {
- const mp_stream_p_t *file_stream =
- mp_get_stream_raise(self->cur_file, MP_STREAM_OP_READ | MP_STREAM_OP_WRITE | MP_STREAM_OP_IOCTL);
+ const mp_stream_p_t *file_stream = mp_get_stream(self->cur_file);
byte readbuf[2 + 256];
int err;
mp_uint_t out_sz = file_stream->read(self->cur_file, readbuf + 2, sizeof(readbuf) - 2, &err);
@@ -141,7 +140,7 @@ STATIC void handle_op(mp_obj_webrepl_t *self) {
// Handle operations requiring opened file
mp_obj_t open_args[2] = {
- mp_obj_new_str(self->hdr.fname, strlen(self->hdr.fname), false),
+ mp_obj_new_str(self->hdr.fname, strlen(self->hdr.fname)),
MP_OBJ_NEW_QSTR(MP_QSTR_rb)
};
@@ -181,7 +180,7 @@ STATIC mp_uint_t _webrepl_read(mp_obj_t self_in, void *buf, mp_uint_t size, int
// We know that os.dupterm always calls with size = 1
assert(size == 1);
mp_obj_webrepl_t *self = self_in;
- const mp_stream_p_t *sock_stream = mp_get_stream_raise(self->sock, MP_STREAM_OP_READ);
+ const mp_stream_p_t *sock_stream = mp_get_stream(self->sock);
mp_uint_t out_sz = sock_stream->read(self->sock, buf, size, errcode);
//DEBUG_printf("webrepl: Read %d initial bytes from websocket\n", out_sz);
if (out_sz == 0 || out_sz == MP_STREAM_ERROR) {
@@ -293,16 +292,24 @@ STATIC mp_uint_t webrepl_write(mp_obj_t self_in, const void *buf, mp_uint_t size
// Don't forward output until passwd is entered
return size;
}
- const mp_stream_p_t *stream_p = mp_get_stream_raise(self->sock, MP_STREAM_OP_WRITE);
+ const mp_stream_p_t *stream_p = mp_get_stream(self->sock);
return stream_p->write(self->sock, buf, size, errcode);
}
-STATIC mp_obj_t webrepl_close(mp_obj_t self_in) {
- mp_obj_webrepl_t *self = MP_OBJ_TO_PTR(self_in);
- // TODO: This is a place to do cleanup
- return mp_stream_close(self->sock);
+STATIC mp_uint_t webrepl_ioctl(mp_obj_t o_in, mp_uint_t request, uintptr_t arg, int *errcode) {
+ mp_obj_webrepl_t *self = MP_OBJ_TO_PTR(o_in);
+ (void)arg;
+ switch (request) {
+ case MP_STREAM_CLOSE:
+ // TODO: This is a place to do cleanup
+ mp_stream_close(self->sock);
+ return 0;
+
+ default:
+ *errcode = MP_EINVAL;
+ return MP_STREAM_ERROR;
+ }
}
-STATIC MP_DEFINE_CONST_FUN_OBJ_1(webrepl_close_obj, webrepl_close);
STATIC mp_obj_t webrepl_set_password(mp_obj_t passwd_in) {
size_t len;
@@ -319,13 +326,14 @@ STATIC const mp_rom_map_elem_t webrepl_locals_dict_table[] = {
{ MP_ROM_QSTR(MP_QSTR_read), MP_ROM_PTR(&mp_stream_read_obj) },
{ MP_ROM_QSTR(MP_QSTR_readinto), MP_ROM_PTR(&mp_stream_readinto_obj) },
{ MP_ROM_QSTR(MP_QSTR_write), MP_ROM_PTR(&mp_stream_write_obj) },
- { MP_ROM_QSTR(MP_QSTR_close), MP_ROM_PTR(&webrepl_close_obj) },
+ { MP_ROM_QSTR(MP_QSTR_close), MP_ROM_PTR(&mp_stream_close_obj) },
};
STATIC MP_DEFINE_CONST_DICT(webrepl_locals_dict, webrepl_locals_dict_table);
STATIC const mp_stream_p_t webrepl_stream_p = {
.read = webrepl_read,
.write = webrepl_write,
+ .ioctl = webrepl_ioctl,
};
STATIC const mp_obj_type_t webrepl_type = {
diff --git a/extmod/modwebsocket.c b/extmod/modwebsocket.c
index a651164b2..c556f2b77 100644
--- a/extmod/modwebsocket.c
+++ b/extmod/modwebsocket.c
@@ -59,6 +59,7 @@ STATIC mp_uint_t websocket_write(mp_obj_t self_in, const void *buf, mp_uint_t si
STATIC mp_obj_t websocket_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) {
mp_arg_check_num(n_args, n_kw, 1, 2, false);
+ mp_get_stream_raise(args[0], MP_STREAM_OP_READ | MP_STREAM_OP_WRITE | MP_STREAM_OP_IOCTL);
mp_obj_websocket_t *o = m_new_obj(mp_obj_websocket_t);
o->base.type = type;
o->sock = args[0];
@@ -75,7 +76,7 @@ STATIC mp_obj_t websocket_make_new(const mp_obj_type_t *type, size_t n_args, siz
STATIC mp_uint_t websocket_read(mp_obj_t self_in, void *buf, mp_uint_t size, int *errcode) {
mp_obj_websocket_t *self = MP_OBJ_TO_PTR(self_in);
- const mp_stream_p_t *stream_p = mp_get_stream_raise(self->sock, MP_STREAM_OP_READ);
+ const mp_stream_p_t *stream_p = mp_get_stream(self->sock);
while (1) {
if (self->to_recv != 0) {
mp_uint_t out_sz = stream_p->read(self->sock, self->buf + self->buf_pos, self->to_recv, errcode);
@@ -256,6 +257,11 @@ STATIC mp_uint_t websocket_write(mp_obj_t self_in, const void *buf, mp_uint_t si
STATIC mp_uint_t websocket_ioctl(mp_obj_t self_in, mp_uint_t request, uintptr_t arg, int *errcode) {
mp_obj_websocket_t *self = MP_OBJ_TO_PTR(self_in);
switch (request) {
+ case MP_STREAM_CLOSE:
+ // TODO: Send close signaling to the other side, otherwise it's
+ // abrupt close (connection abort).
+ mp_stream_close(self->sock);
+ return 0;
case MP_STREAM_GET_DATA_OPTS:
return self->ws_flags & FRAME_OPCODE_MASK;
case MP_STREAM_SET_DATA_OPTS: {
@@ -269,21 +275,13 @@ STATIC mp_uint_t websocket_ioctl(mp_obj_t self_in, mp_uint_t request, uintptr_t
}
}
-STATIC mp_obj_t websocket_close(mp_obj_t self_in) {
- mp_obj_websocket_t *self = MP_OBJ_TO_PTR(self_in);
- // TODO: Send close signaling to the other side, otherwise it's
- // abrupt close (connection abort).
- return mp_stream_close(self->sock);
-}
-STATIC MP_DEFINE_CONST_FUN_OBJ_1(websocket_close_obj, websocket_close);
-
STATIC const mp_rom_map_elem_t websocket_locals_dict_table[] = {
{ MP_ROM_QSTR(MP_QSTR_read), MP_ROM_PTR(&mp_stream_read_obj) },
{ MP_ROM_QSTR(MP_QSTR_readinto), MP_ROM_PTR(&mp_stream_readinto_obj) },
{ MP_ROM_QSTR(MP_QSTR_readline), MP_ROM_PTR(&mp_stream_unbuffered_readline_obj) },
{ MP_ROM_QSTR(MP_QSTR_write), MP_ROM_PTR(&mp_stream_write_obj) },
{ MP_ROM_QSTR(MP_QSTR_ioctl), MP_ROM_PTR(&mp_stream_ioctl_obj) },
- { MP_ROM_QSTR(MP_QSTR_close), MP_ROM_PTR(&websocket_close_obj) },
+ { MP_ROM_QSTR(MP_QSTR_close), MP_ROM_PTR(&mp_stream_close_obj) },
};
STATIC MP_DEFINE_CONST_DICT(websocket_locals_dict, websocket_locals_dict_table);
diff --git a/extmod/re1.5/compilecode.c b/extmod/re1.5/compilecode.c
index 3267a4190..a685a508a 100644
--- a/extmod/re1.5/compilecode.c
+++ b/extmod/re1.5/compilecode.c
@@ -5,9 +5,9 @@
#include "re1.5.h"
#define INSERT_CODE(at, num, pc) \
- ((code ? memmove(code + at + num, code + at, pc - at) : (void)0), pc += num)
+ ((code ? memmove(code + at + num, code + at, pc - at) : 0), pc += num)
#define REL(at, to) (to - at - 2)
-#define EMIT(at, byte) (code ? (code[at] = byte) : (void)(at))
+#define EMIT(at, byte) (code ? (code[at] = byte) : (at))
#define PC (prog->bytelen)
static const char *_compilecode(const char *re, ByteProg *prog, int sizecode)
diff --git a/extmod/uos_dupterm.c b/extmod/uos_dupterm.c
index e5e6663b0..0de26cbdd 100644
--- a/extmod/uos_dupterm.c
+++ b/extmod/uos_dupterm.c
@@ -60,25 +60,29 @@ int mp_uos_dupterm_rx_chr(void) {
nlr_buf_t nlr;
if (nlr_push(&nlr) == 0) {
- mp_obj_t readinto_m[3];
- mp_load_method(MP_STATE_VM(dupterm_objs[idx]), MP_QSTR_readinto, readinto_m);
- readinto_m[2] = MP_STATE_VM(dupterm_arr_obj);
- mp_obj_t res = mp_call_method_n_kw(1, 0, readinto_m);
- if (res == mp_const_none) {
- nlr_pop();
- } else if (res == MP_OBJ_NEW_SMALL_INT(0)) {
+ byte buf[1];
+ int errcode;
+ const mp_stream_p_t *stream_p = mp_get_stream(MP_STATE_VM(dupterm_objs[idx]));
+ mp_uint_t out_sz = stream_p->read(MP_STATE_VM(dupterm_objs[idx]), buf, 1, &errcode);
+ if (out_sz == 0) {
nlr_pop();
mp_uos_deactivate(idx, "dupterm: EOF received, deactivating\n", MP_OBJ_NULL);
+ } else if (out_sz == MP_STREAM_ERROR) {
+ // errcode is valid
+ if (mp_is_nonblocking_error(errcode)) {
+ nlr_pop();
+ } else {
+ mp_raise_OSError(errcode);
+ }
} else {
- mp_buffer_info_t bufinfo;
- mp_get_buffer_raise(MP_STATE_VM(dupterm_arr_obj), &bufinfo, MP_BUFFER_READ);
+ // read 1 byte
nlr_pop();
- if (*(byte*)bufinfo.buf == mp_interrupt_char) {
+ if (buf[0] == mp_interrupt_char) {
// Signal keyboard interrupt to be raised as soon as the VM resumes
mp_keyboard_interrupt();
return -2;
}
- return *(byte*)bufinfo.buf;
+ return buf[0];
}
} else {
mp_uos_deactivate(idx, "dupterm: Exception in read() method, deactivating: ", nlr.ret_val);
@@ -96,18 +100,7 @@ void mp_uos_dupterm_tx_strn(const char *str, size_t len) {
}
nlr_buf_t nlr;
if (nlr_push(&nlr) == 0) {
- mp_obj_t write_m[3];
- mp_load_method(MP_STATE_VM(dupterm_objs[idx]), MP_QSTR_write, write_m);
-
- mp_obj_array_t *arr = MP_OBJ_TO_PTR(MP_STATE_VM(dupterm_arr_obj));
- void *org_items = arr->items;
- arr->items = (void*)str;
- arr->len = len;
- write_m[2] = MP_STATE_VM(dupterm_arr_obj);
- mp_call_method_n_kw(1, 0, write_m);
- arr = MP_OBJ_TO_PTR(MP_STATE_VM(dupterm_arr_obj));
- arr->items = org_items;
- arr->len = 1;
+ mp_stream_write(MP_STATE_VM(dupterm_objs[idx]), str, len, MP_STREAM_RW_WRITE);
nlr_pop();
} else {
mp_uos_deactivate(idx, "dupterm: Exception in write() method, deactivating: ", nlr.ret_val);
@@ -132,10 +125,8 @@ STATIC mp_obj_t mp_uos_dupterm(size_t n_args, const mp_obj_t *args) {
if (args[0] == mp_const_none) {
MP_STATE_VM(dupterm_objs[idx]) = MP_OBJ_NULL;
} else {
+ mp_get_stream_raise(args[0], MP_STREAM_OP_READ | MP_STREAM_OP_WRITE | MP_STREAM_OP_IOCTL);
MP_STATE_VM(dupterm_objs[idx]) = args[0];
- if (MP_STATE_VM(dupterm_arr_obj) == MP_OBJ_NULL) {
- MP_STATE_VM(dupterm_arr_obj) = mp_obj_new_bytearray(1, "");
- }
}
return previous_obj;
diff --git a/extmod/vfs.c b/extmod/vfs.c
index e83646d8d..cc794aad5 100644
--- a/extmod/vfs.c
+++ b/extmod/vfs.c
@@ -124,21 +124,39 @@ mp_import_stat_t mp_vfs_import_stat(const char *path) {
if (vfs == MP_VFS_NONE || vfs == MP_VFS_ROOT) {
return MP_IMPORT_STAT_NO_EXIST;
}
- #if MICROPY_VFS_FAT
- // fast paths for known VFS types
- if (mp_obj_get_type(vfs->obj) == &mp_fat_vfs_type) {
- return fat_vfs_import_stat(MP_OBJ_TO_PTR(vfs->obj), path_out);
+
+ // If the mounted object has the VFS protocol, call its import_stat helper
+ const mp_vfs_proto_t *proto = mp_obj_get_type(vfs->obj)->protocol;
+ if (proto != NULL) {
+ return proto->import_stat(MP_OBJ_TO_PTR(vfs->obj), path_out);
+ }
+
+ // delegate to vfs.stat() method
+ mp_obj_t path_o = mp_obj_new_str(path_out, strlen(path_out));
+ mp_obj_t stat;
+ nlr_buf_t nlr;
+ if (nlr_push(&nlr) == 0) {
+ stat = mp_vfs_proxy_call(vfs, MP_QSTR_stat, 1, &path_o);
+ nlr_pop();
+ } else {
+ // assume an exception means that the path is not found
+ return MP_IMPORT_STAT_NO_EXIST;
+ }
+ mp_obj_t *items;
+ mp_obj_get_array_fixed_n(stat, 10, &items);
+ mp_int_t st_mode = mp_obj_get_int(items[0]);
+ if (st_mode & MP_S_IFDIR) {
+ return MP_IMPORT_STAT_DIR;
+ } else {
+ return MP_IMPORT_STAT_FILE;
}
- #endif
- // TODO delegate to vfs.stat() method
- return MP_IMPORT_STAT_NO_EXIST;
}
mp_obj_t mp_vfs_mount(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
enum { ARG_readonly, ARG_mkfs };
static const mp_arg_t allowed_args[] = {
- { MP_QSTR_readonly, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_false} },
- { MP_QSTR_mkfs, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_false} },
+ { MP_QSTR_readonly, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_rom_obj = MP_ROM_PTR(&mp_const_false_obj)} },
+ { MP_QSTR_mkfs, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_rom_obj = MP_ROM_PTR(&mp_const_false_obj)} },
};
// parse args
@@ -246,7 +264,7 @@ mp_obj_t mp_vfs_open(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args)
mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
- mp_vfs_mount_t *vfs = lookup_path((mp_obj_t)args[ARG_file].u_rom_obj, &args[ARG_file].u_obj);
+ mp_vfs_mount_t *vfs = lookup_path(args[ARG_file].u_obj, &args[ARG_file].u_obj);
return mp_vfs_proxy_call(vfs, MP_QSTR_open, 2, (mp_obj_t*)&args);
}
MP_DEFINE_CONST_FUN_OBJ_KW(mp_vfs_open_obj, 0, mp_vfs_open);
@@ -261,7 +279,7 @@ mp_obj_t mp_vfs_chdir(mp_obj_t path_in) {
// subsequent relative paths begin at the root of that VFS.
for (vfs = MP_STATE_VM(vfs_mount_table); vfs != NULL; vfs = vfs->next) {
if (vfs->len == 1) {
- mp_obj_t root = mp_obj_new_str("/", 1, false);
+ mp_obj_t root = MP_OBJ_NEW_QSTR(MP_QSTR__slash_);
mp_vfs_proxy_call(vfs, MP_QSTR_chdir, 1, &root);
break;
}
@@ -307,7 +325,7 @@ mp_obj_t mp_vfs_ilistdir_it_iternext(mp_obj_t self_in) {
self->cur.vfs = vfs->next;
if (vfs->len == 1) {
// vfs is mounted at root dir, delegate to it
- mp_obj_t root = mp_obj_new_str("/", 1, false);
+ mp_obj_t root = MP_OBJ_NEW_QSTR(MP_QSTR__slash_);
self->is_iter = true;
self->cur.iter = mp_vfs_proxy_call(vfs, MP_QSTR_ilistdir, 1, &root);
return mp_iternext(self->cur.iter);
@@ -355,9 +373,7 @@ mp_obj_t mp_vfs_listdir(size_t n_args, const mp_obj_t *args) {
mp_obj_t dir_list = mp_obj_new_list(0, NULL);
mp_obj_t next;
while ((next = mp_iternext(iter)) != MP_OBJ_STOP_ITERATION) {
- mp_obj_t *items;
- mp_obj_get_array_fixed_n(next, 3, &items);
- mp_obj_list_append(dir_list, items[0]);
+ mp_obj_list_append(dir_list, mp_obj_subscr(next, MP_OBJ_NEW_SMALL_INT(0), MP_OBJ_SENTINEL));
}
return dir_list;
}
diff --git a/extmod/vfs.h b/extmod/vfs.h
index c20d6dcd4..5ab2067e5 100644
--- a/extmod/vfs.h
+++ b/extmod/vfs.h
@@ -45,6 +45,11 @@
#define BP_IOCTL_SEC_COUNT (4)
#define BP_IOCTL_SEC_SIZE (5)
+// At the moment the VFS protocol just has import_stat, but could be extended to other methods
+typedef struct _mp_vfs_proto_t {
+ mp_import_stat_t (*import_stat)(void *self, const char *path);
+} mp_vfs_proto_t;
+
typedef struct _mp_vfs_mount_t {
const char *str; // mount point with leading /
size_t len;
diff --git a/extmod/vfs_fat.c b/extmod/vfs_fat.c
index 81ca1e23d..633c04389 100644
--- a/extmod/vfs_fat.c
+++ b/extmod/vfs_fat.c
@@ -48,6 +48,21 @@
#define mp_obj_fat_vfs_t fs_user_mount_t
+STATIC mp_import_stat_t fat_vfs_import_stat(void *vfs_in, const char *path) {
+ fs_user_mount_t *vfs = vfs_in;
+ FILINFO fno;
+ assert(vfs != NULL);
+ FRESULT res = f_stat(&vfs->fatfs, path, &fno);
+ if (res == FR_OK) {
+ if ((fno.fattrib & AM_DIR) != 0) {
+ return MP_IMPORT_STAT_DIR;
+ } else {
+ return MP_IMPORT_STAT_FILE;
+ }
+ }
+ return MP_IMPORT_STAT_NO_EXIST;
+}
+
STATIC mp_obj_t fat_vfs_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) {
mp_arg_check_num(n_args, n_kw, 1, 1, false);
@@ -70,9 +85,28 @@ STATIC mp_obj_t fat_vfs_make_new(const mp_obj_type_t *type, size_t n_args, size_
mp_load_method(args[0], MP_QSTR_count, vfs->u.old.count);
}
+ // mount the block device so the VFS methods can be used
+ FRESULT res = f_mount(&vfs->fatfs);
+ if (res == FR_NO_FILESYSTEM) {
+ // don't error out if no filesystem, to let mkfs()/mount() create one if wanted
+ vfs->flags |= FSUSER_NO_FILESYSTEM;
+ } else if (res != FR_OK) {
+ mp_raise_OSError(fresult_to_errno_table[res]);
+ }
+
return MP_OBJ_FROM_PTR(vfs);
}
+#if _FS_REENTRANT
+STATIC mp_obj_t fat_vfs_del(mp_obj_t self_in) {
+ mp_obj_fat_vfs_t *self = MP_OBJ_TO_PTR(self_in);
+ // f_umount only needs to be called to release the sync object
+ f_umount(&self->fatfs);
+ return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(fat_vfs_del_obj, fat_vfs_del);
+#endif
+
STATIC mp_obj_t fat_vfs_mkfs(mp_obj_t bdev_in) {
// create new object
fs_user_mount_t *vfs = MP_OBJ_TO_PTR(fat_vfs_make_new(&mp_fat_vfs_type, 1, 0, &bdev_in));
@@ -89,7 +123,52 @@ STATIC mp_obj_t fat_vfs_mkfs(mp_obj_t bdev_in) {
STATIC MP_DEFINE_CONST_FUN_OBJ_1(fat_vfs_mkfs_fun_obj, fat_vfs_mkfs);
STATIC MP_DEFINE_CONST_STATICMETHOD_OBJ(fat_vfs_mkfs_obj, MP_ROM_PTR(&fat_vfs_mkfs_fun_obj));
-STATIC MP_DEFINE_CONST_FUN_OBJ_3(fat_vfs_open_obj, fatfs_builtin_open_self);
+typedef struct _mp_vfs_fat_ilistdir_it_t {
+ mp_obj_base_t base;
+ mp_fun_1_t iternext;
+ bool is_str;
+ FF_DIR dir;
+} mp_vfs_fat_ilistdir_it_t;
+
+STATIC mp_obj_t mp_vfs_fat_ilistdir_it_iternext(mp_obj_t self_in) {
+ mp_vfs_fat_ilistdir_it_t *self = MP_OBJ_TO_PTR(self_in);
+
+ for (;;) {
+ FILINFO fno;
+ FRESULT res = f_readdir(&self->dir, &fno);
+ char *fn = fno.fname;
+ if (res != FR_OK || fn[0] == 0) {
+ // stop on error or end of dir
+ break;
+ }
+
+ // Note that FatFS already filters . and .., so we don't need to
+
+ // make 4-tuple with info about this entry
+ mp_obj_tuple_t *t = MP_OBJ_TO_PTR(mp_obj_new_tuple(4, NULL));
+ if (self->is_str) {
+ t->items[0] = mp_obj_new_str(fn, strlen(fn));
+ } else {
+ t->items[0] = mp_obj_new_bytes((const byte*)fn, strlen(fn));
+ }
+ if (fno.fattrib & AM_DIR) {
+ // dir
+ t->items[1] = MP_OBJ_NEW_SMALL_INT(MP_S_IFDIR);
+ } else {
+ // file
+ t->items[1] = MP_OBJ_NEW_SMALL_INT(MP_S_IFREG);
+ }
+ t->items[2] = MP_OBJ_NEW_SMALL_INT(0); // no inode number
+ t->items[3] = mp_obj_new_int_from_uint(fno.fsize);
+
+ return MP_OBJ_FROM_PTR(t);
+ }
+
+ // ignore error because we may be closing a second time
+ f_closedir(&self->dir);
+
+ return MP_OBJ_STOP_ITERATION;
+}
STATIC mp_obj_t fat_vfs_ilistdir_func(size_t n_args, const mp_obj_t *args) {
mp_obj_fat_vfs_t *self = MP_OBJ_TO_PTR(args[0]);
@@ -104,7 +183,17 @@ STATIC mp_obj_t fat_vfs_ilistdir_func(size_t n_args, const mp_obj_t *args) {
path = "";
}
- return fat_vfs_ilistdir2(self, path, is_str_type);
+ // Create a new iterator object to list the dir
+ mp_vfs_fat_ilistdir_it_t *iter = m_new_obj(mp_vfs_fat_ilistdir_it_t);
+ iter->base.type = &mp_type_polymorph_iter;
+ iter->iternext = mp_vfs_fat_ilistdir_it_iternext;
+ iter->is_str = is_str_type;
+ FRESULT res = f_opendir(&self->fatfs, &iter->dir, path);
+ if (res != FR_OK) {
+ mp_raise_OSError(fresult_to_errno_table[res]);
+ }
+
+ return MP_OBJ_FROM_PTR(iter);
}
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(fat_vfs_ilistdir_obj, 1, 2, fat_vfs_ilistdir_func);
@@ -198,7 +287,7 @@ STATIC mp_obj_t fat_vfs_getcwd(mp_obj_t vfs_in) {
if (res != FR_OK) {
mp_raise_OSError(fresult_to_errno_table[res]);
}
- return mp_obj_new_str(buf, strlen(buf), false);
+ return mp_obj_new_str(buf, strlen(buf));
}
STATIC MP_DEFINE_CONST_FUN_OBJ_1(fat_vfs_getcwd_obj, fat_vfs_getcwd);
@@ -292,10 +381,8 @@ STATIC mp_obj_t vfs_fat_mount(mp_obj_t self_in, mp_obj_t readonly, mp_obj_t mkfs
self->writeblocks[0] = MP_OBJ_NULL;
}
- // mount the block device
- FRESULT res = f_mount(&self->fatfs);
-
// check if we need to make the filesystem
+ FRESULT res = (self->flags & FSUSER_NO_FILESYSTEM) ? FR_NO_FILESYSTEM : FR_OK;
if (res == FR_NO_FILESYSTEM && mp_obj_is_true(mkfs)) {
uint8_t working_buf[_MAX_SS];
res = f_mkfs(&self->fatfs, FM_FAT | FM_SFD, 0, working_buf, sizeof(working_buf));
@@ -303,17 +390,15 @@ STATIC mp_obj_t vfs_fat_mount(mp_obj_t self_in, mp_obj_t readonly, mp_obj_t mkfs
if (res != FR_OK) {
mp_raise_OSError(fresult_to_errno_table[res]);
}
+ self->flags &= ~FSUSER_NO_FILESYSTEM;
return mp_const_none;
}
STATIC MP_DEFINE_CONST_FUN_OBJ_3(vfs_fat_mount_obj, vfs_fat_mount);
STATIC mp_obj_t vfs_fat_umount(mp_obj_t self_in) {
- fs_user_mount_t *self = MP_OBJ_TO_PTR(self_in);
- FRESULT res = f_umount(&self->fatfs);
- if (res != FR_OK) {
- mp_raise_OSError(fresult_to_errno_table[res]);
- }
+ (void)self_in;
+ // keep the FAT filesystem mounted internally so the VFS methods can still be used
return mp_const_none;
}
STATIC MP_DEFINE_CONST_FUN_OBJ_1(fat_vfs_umount_obj, vfs_fat_umount);
@@ -352,6 +437,9 @@ STATIC const mp_obj_property_t fat_vfs_label_obj = {
#endif
STATIC const mp_rom_map_elem_t fat_vfs_locals_dict_table[] = {
+ #if _FS_REENTRANT
+ { MP_ROM_QSTR(MP_QSTR___del__), MP_ROM_PTR(&fat_vfs_del_obj) },
+ #endif
{ MP_ROM_QSTR(MP_QSTR_mkfs), MP_ROM_PTR(&fat_vfs_mkfs_obj) },
{ MP_ROM_QSTR(MP_QSTR_open), MP_ROM_PTR(&fat_vfs_open_obj) },
{ MP_ROM_QSTR(MP_QSTR_ilistdir), MP_ROM_PTR(&fat_vfs_ilistdir_obj) },
@@ -371,11 +459,17 @@ STATIC const mp_rom_map_elem_t fat_vfs_locals_dict_table[] = {
};
STATIC MP_DEFINE_CONST_DICT(fat_vfs_locals_dict, fat_vfs_locals_dict_table);
+STATIC const mp_vfs_proto_t fat_vfs_proto = {
+ .import_stat = fat_vfs_import_stat,
+};
+
const mp_obj_type_t mp_fat_vfs_type = {
{ &mp_type_type },
.name = MP_QSTR_VfsFat,
.make_new = fat_vfs_make_new,
+ .protocol = &fat_vfs_proto,
.locals_dict = (mp_obj_dict_t*)&fat_vfs_locals_dict,
+
};
#endif // MICROPY_VFS_FAT
diff --git a/extmod/vfs_fat_file.c b/extmod/vfs_fat_file.c
index be9c8c792..86ae65aef 100644
--- a/extmod/vfs_fat_file.c
+++ b/extmod/vfs_fat_file.c
@@ -94,22 +94,9 @@ STATIC mp_uint_t file_obj_write(mp_obj_t self_in, const void *buf, mp_uint_t siz
}
-STATIC mp_obj_t file_obj_close(mp_obj_t self_in) {
- pyb_file_obj_t *self = MP_OBJ_TO_PTR(self_in);
- // if fs==NULL then the file is closed and in that case this method is a no-op
- if (self->fp.obj.fs != NULL) {
- FRESULT res = f_close(&self->fp);
- if (res != FR_OK) {
- mp_raise_OSError(fresult_to_errno_table[res]);
- }
- }
- return mp_const_none;
-}
-STATIC MP_DEFINE_CONST_FUN_OBJ_1(file_obj_close_obj, file_obj_close);
-
STATIC mp_obj_t file_obj___exit__(size_t n_args, const mp_obj_t *args) {
(void)n_args;
- return file_obj_close(args[0]);
+ return mp_stream_close(args[0]);
}
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(file_obj___exit___obj, 4, 4, file_obj___exit__);
@@ -144,6 +131,17 @@ STATIC mp_uint_t file_obj_ioctl(mp_obj_t o_in, mp_uint_t request, uintptr_t arg,
}
return 0;
+ } else if (request == MP_STREAM_CLOSE) {
+ // if fs==NULL then the file is closed and in that case this method is a no-op
+ if (self->fp.obj.fs != NULL) {
+ FRESULT res = f_close(&self->fp);
+ if (res != FR_OK) {
+ *errcode = fresult_to_errno_table[res];
+ return MP_STREAM_ERROR;
+ }
+ }
+ return 0;
+
} else {
*errcode = MP_EINVAL;
return MP_STREAM_ERROR;
@@ -182,11 +180,11 @@ STATIC mp_obj_t file_open(fs_user_mount_t *vfs, const mp_obj_type_t *type, mp_ar
break;
#if MICROPY_PY_IO_FILEIO
case 'b':
- type = &mp_type_fileio;
+ type = &mp_type_vfs_fat_fileio;
break;
#endif
case 't':
- type = &mp_type_textio;
+ type = &mp_type_vfs_fat_textio;
break;
}
}
@@ -225,10 +223,10 @@ STATIC const mp_rom_map_elem_t rawfile_locals_dict_table[] = {
{ MP_ROM_QSTR(MP_QSTR_readlines), MP_ROM_PTR(&mp_stream_unbuffered_readlines_obj) },
{ MP_ROM_QSTR(MP_QSTR_write), MP_ROM_PTR(&mp_stream_write_obj) },
{ MP_ROM_QSTR(MP_QSTR_flush), MP_ROM_PTR(&mp_stream_flush_obj) },
- { MP_ROM_QSTR(MP_QSTR_close), MP_ROM_PTR(&file_obj_close_obj) },
+ { MP_ROM_QSTR(MP_QSTR_close), MP_ROM_PTR(&mp_stream_close_obj) },
{ MP_ROM_QSTR(MP_QSTR_seek), MP_ROM_PTR(&mp_stream_seek_obj) },
{ MP_ROM_QSTR(MP_QSTR_tell), MP_ROM_PTR(&mp_stream_tell_obj) },
- { MP_ROM_QSTR(MP_QSTR___del__), MP_ROM_PTR(&file_obj_close_obj) },
+ { MP_ROM_QSTR(MP_QSTR___del__), MP_ROM_PTR(&mp_stream_close_obj) },
{ MP_ROM_QSTR(MP_QSTR___enter__), MP_ROM_PTR(&mp_identity_obj) },
{ MP_ROM_QSTR(MP_QSTR___exit__), MP_ROM_PTR(&file_obj___exit___obj) },
};
@@ -242,7 +240,7 @@ STATIC const mp_stream_p_t fileio_stream_p = {
.ioctl = file_obj_ioctl,
};
-const mp_obj_type_t mp_type_fileio = {
+const mp_obj_type_t mp_type_vfs_fat_fileio = {
{ &mp_type_type },
.name = MP_QSTR_FileIO,
.print = file_obj_print,
@@ -261,7 +259,7 @@ STATIC const mp_stream_p_t textio_stream_p = {
.is_text = true,
};
-const mp_obj_type_t mp_type_textio = {
+const mp_obj_type_t mp_type_vfs_fat_textio = {
{ &mp_type_type },
.name = MP_QSTR_TextIOWrapper,
.print = file_obj_print,
@@ -273,14 +271,15 @@ const mp_obj_type_t mp_type_textio = {
};
// Factory function for I/O stream classes
-mp_obj_t fatfs_builtin_open_self(mp_obj_t self_in, mp_obj_t path, mp_obj_t mode) {
+STATIC mp_obj_t fatfs_builtin_open_self(mp_obj_t self_in, mp_obj_t path, mp_obj_t mode) {
// TODO: analyze buffering args and instantiate appropriate type
fs_user_mount_t *self = MP_OBJ_TO_PTR(self_in);
mp_arg_val_t arg_vals[FILE_OPEN_NUM_ARGS];
arg_vals[0].u_obj = path;
arg_vals[1].u_obj = mode;
arg_vals[2].u_obj = mp_const_none;
- return file_open(self, &mp_type_textio, arg_vals);
+ return file_open(self, &mp_type_vfs_fat_textio, arg_vals);
}
+MP_DEFINE_CONST_FUN_OBJ_3(fat_vfs_open_obj, fatfs_builtin_open_self);
#endif // MICROPY_VFS && MICROPY_VFS_FAT
diff --git a/extmod/vfs_fat_misc.c b/extmod/vfs_fat_misc.c
deleted file mode 100644
index 9a26b4a2f..000000000
--- a/extmod/vfs_fat_misc.c
+++ /dev/null
@@ -1,108 +0,0 @@
-/*
- * This file is part of the MicroPython project, http://micropython.org/
- *
- * The MIT License (MIT)
- *
- * Copyright (c) 2014 Damien P. George
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- */
-
-#include "py/mpconfig.h"
-#if MICROPY_VFS_FAT
-
-#include <string.h>
-#include "py/runtime.h"
-#include "lib/oofatfs/ff.h"
-#include "extmod/vfs_fat.h"
-#include "py/lexer.h"
-
-typedef struct _mp_vfs_fat_ilistdir_it_t {
- mp_obj_base_t base;
- mp_fun_1_t iternext;
- bool is_str;
- FF_DIR dir;
-} mp_vfs_fat_ilistdir_it_t;
-
-STATIC mp_obj_t mp_vfs_fat_ilistdir_it_iternext(mp_obj_t self_in) {
- mp_vfs_fat_ilistdir_it_t *self = MP_OBJ_TO_PTR(self_in);
-
- for (;;) {
- FILINFO fno;
- FRESULT res = f_readdir(&self->dir, &fno);
- char *fn = fno.fname;
- if (res != FR_OK || fn[0] == 0) {
- // stop on error or end of dir
- break;
- }
-
- // Note that FatFS already filters . and .., so we don't need to
-
- // make 3-tuple with info about this entry
- mp_obj_tuple_t *t = MP_OBJ_TO_PTR(mp_obj_new_tuple(3, NULL));
- if (self->is_str) {
- t->items[0] = mp_obj_new_str(fn, strlen(fn), false);
- } else {
- t->items[0] = mp_obj_new_bytes((const byte*)fn, strlen(fn));
- }
- if (fno.fattrib & AM_DIR) {
- // dir
- t->items[1] = MP_OBJ_NEW_SMALL_INT(MP_S_IFDIR);
- } else {
- // file
- t->items[1] = MP_OBJ_NEW_SMALL_INT(MP_S_IFREG);
- }
- t->items[2] = MP_OBJ_NEW_SMALL_INT(0); // no inode number
-
- return MP_OBJ_FROM_PTR(t);
- }
-
- // ignore error because we may be closing a second time
- f_closedir(&self->dir);
-
- return MP_OBJ_STOP_ITERATION;
-}
-
-mp_obj_t fat_vfs_ilistdir2(fs_user_mount_t *vfs, const char *path, bool is_str_type) {
- mp_vfs_fat_ilistdir_it_t *iter = m_new_obj(mp_vfs_fat_ilistdir_it_t);
- iter->base.type = &mp_type_polymorph_iter;
- iter->iternext = mp_vfs_fat_ilistdir_it_iternext;
- iter->is_str = is_str_type;
- FRESULT res = f_opendir(&vfs->fatfs, &iter->dir, path);
- if (res != FR_OK) {
- mp_raise_OSError(fresult_to_errno_table[res]);
- }
- return MP_OBJ_FROM_PTR(iter);
-}
-
-mp_import_stat_t fat_vfs_import_stat(fs_user_mount_t *vfs, const char *path) {
- FILINFO fno;
- assert(vfs != NULL);
- FRESULT res = f_stat(&vfs->fatfs, path, &fno);
- if (res == FR_OK) {
- if ((fno.fattrib & AM_DIR) != 0) {
- return MP_IMPORT_STAT_DIR;
- } else {
- return MP_IMPORT_STAT_FILE;
- }
- }
- return MP_IMPORT_STAT_NO_EXIST;
-}
-
-#endif // MICROPY_VFS_FAT
diff --git a/extmod/vfs_posix.c b/extmod/vfs_posix.c
new file mode 100644
index 000000000..6e3bb2c5b
--- /dev/null
+++ b/extmod/vfs_posix.c
@@ -0,0 +1,363 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2017-2018 Damien P. George
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "py/runtime.h"
+#include "py/mperrno.h"
+#include "extmod/vfs.h"
+#include "extmod/vfs_posix.h"
+
+#if MICROPY_VFS_POSIX
+
+#include <string.h>
+#include <sys/stat.h>
+#include <dirent.h>
+
+typedef struct _mp_obj_vfs_posix_t {
+ mp_obj_base_t base;
+ vstr_t root;
+ size_t root_len;
+ bool readonly;
+} mp_obj_vfs_posix_t;
+
+STATIC const char *vfs_posix_get_path_str(mp_obj_vfs_posix_t *self, mp_obj_t path) {
+ if (self->root_len == 0) {
+ return mp_obj_str_get_str(path);
+ } else {
+ self->root.len = self->root_len;
+ vstr_add_str(&self->root, mp_obj_str_get_str(path));
+ return vstr_null_terminated_str(&self->root);
+ }
+}
+
+STATIC mp_obj_t vfs_posix_get_path_obj(mp_obj_vfs_posix_t *self, mp_obj_t path) {
+ if (self->root_len == 0) {
+ return path;
+ } else {
+ self->root.len = self->root_len;
+ vstr_add_str(&self->root, mp_obj_str_get_str(path));
+ return mp_obj_new_str(self->root.buf, self->root.len);
+ }
+}
+
+STATIC mp_obj_t vfs_posix_fun1_helper(mp_obj_t self_in, mp_obj_t path_in, int (*f)(const char*)) {
+ mp_obj_vfs_posix_t *self = MP_OBJ_TO_PTR(self_in);
+ int ret = f(vfs_posix_get_path_str(self, path_in));
+ if (ret != 0) {
+ mp_raise_OSError(errno);
+ }
+ return mp_const_none;
+}
+
+STATIC mp_import_stat_t mp_vfs_posix_import_stat(void *self_in, const char *path) {
+ mp_obj_vfs_posix_t *self = self_in;
+ if (self->root_len != 0) {
+ self->root.len = self->root_len;
+ vstr_add_str(&self->root, path);
+ path = vstr_null_terminated_str(&self->root);
+ }
+ struct stat st;
+ if (stat(path, &st) == 0) {
+ if (S_ISDIR(st.st_mode)) {
+ return MP_IMPORT_STAT_DIR;
+ } else if (S_ISREG(st.st_mode)) {
+ return MP_IMPORT_STAT_FILE;
+ }
+ }
+ return MP_IMPORT_STAT_NO_EXIST;
+}
+
+STATIC mp_obj_t vfs_posix_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) {
+ mp_arg_check_num(n_args, n_kw, 0, 1, false);
+
+ mp_obj_vfs_posix_t *vfs = m_new_obj(mp_obj_vfs_posix_t);
+ vfs->base.type = type;
+ vstr_init(&vfs->root, 0);
+ if (n_args == 1) {
+ vstr_add_str(&vfs->root, mp_obj_str_get_str(args[0]));
+ vstr_add_char(&vfs->root, '/');
+ }
+ vfs->root_len = vfs->root.len;
+ vfs->readonly = false;
+
+ return MP_OBJ_FROM_PTR(vfs);
+}
+
+STATIC mp_obj_t vfs_posix_mount(mp_obj_t self_in, mp_obj_t readonly, mp_obj_t mkfs) {
+ mp_obj_vfs_posix_t *self = MP_OBJ_TO_PTR(self_in);
+ if (mp_obj_is_true(readonly)) {
+ self->readonly = true;
+ }
+ if (mp_obj_is_true(mkfs)) {
+ mp_raise_OSError(MP_EPERM);
+ }
+ return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_3(vfs_posix_mount_obj, vfs_posix_mount);
+
+STATIC mp_obj_t vfs_posix_umount(mp_obj_t self_in) {
+ (void)self_in;
+ return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(vfs_posix_umount_obj, vfs_posix_umount);
+
+STATIC mp_obj_t vfs_posix_open(mp_obj_t self_in, mp_obj_t path_in, mp_obj_t mode_in) {
+ mp_obj_vfs_posix_t *self = MP_OBJ_TO_PTR(self_in);
+ const char *mode = mp_obj_str_get_str(mode_in);
+ if (self->readonly
+ && (strchr(mode, 'w') != NULL || strchr(mode, 'a') != NULL || strchr(mode, '+') != NULL)) {
+ mp_raise_OSError(MP_EROFS);
+ }
+ if (!MP_OBJ_IS_SMALL_INT(path_in)) {
+ path_in = vfs_posix_get_path_obj(self, path_in);
+ }
+ return mp_vfs_posix_file_open(&mp_type_textio, path_in, mode_in);
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_3(vfs_posix_open_obj, vfs_posix_open);
+
+STATIC mp_obj_t vfs_posix_chdir(mp_obj_t self_in, mp_obj_t path_in) {
+ return vfs_posix_fun1_helper(self_in, path_in, chdir);
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_2(vfs_posix_chdir_obj, vfs_posix_chdir);
+
+STATIC mp_obj_t vfs_posix_getcwd(mp_obj_t self_in) {
+ mp_obj_vfs_posix_t *self = MP_OBJ_TO_PTR(self_in);
+ char buf[MICROPY_ALLOC_PATH_MAX + 1];
+ const char *ret = getcwd(buf, sizeof(buf));
+ if (ret == NULL) {
+ mp_raise_OSError(errno);
+ }
+ ret += self->root_len;
+ return mp_obj_new_str(ret, strlen(ret));
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(vfs_posix_getcwd_obj, vfs_posix_getcwd);
+
+typedef struct _vfs_posix_ilistdir_it_t {
+ mp_obj_base_t base;
+ mp_fun_1_t iternext;
+ bool is_str;
+ DIR *dir;
+} vfs_posix_ilistdir_it_t;
+
+STATIC mp_obj_t vfs_posix_ilistdir_it_iternext(mp_obj_t self_in) {
+ vfs_posix_ilistdir_it_t *self = MP_OBJ_TO_PTR(self_in);
+
+ if (self->dir == NULL) {
+ return MP_OBJ_STOP_ITERATION;
+ }
+
+ for (;;) {
+ struct dirent *dirent = readdir(self->dir);
+ if (dirent == NULL) {
+ closedir(self->dir);
+ self->dir = NULL;
+ return MP_OBJ_STOP_ITERATION;
+ }
+ const char *fn = dirent->d_name;
+
+ if (fn[0] == '.' && (fn[1] == 0 || fn[1] == '.')) {
+ // skip . and ..
+ continue;
+ }
+
+ // make 3-tuple with info about this entry
+ mp_obj_tuple_t *t = MP_OBJ_TO_PTR(mp_obj_new_tuple(3, NULL));
+
+ if (self->is_str) {
+ t->items[0] = mp_obj_new_str(fn, strlen(fn));
+ } else {
+ t->items[0] = mp_obj_new_bytes((const byte*)fn, strlen(fn));
+ }
+
+ #ifdef _DIRENT_HAVE_D_TYPE
+ if (dirent->d_type == DT_DIR) {
+ t->items[1] = MP_OBJ_NEW_SMALL_INT(MP_S_IFDIR);
+ } else if (dirent->d_type == DT_REG) {
+ t->items[1] = MP_OBJ_NEW_SMALL_INT(MP_S_IFREG);
+ } else {
+ t->items[1] = MP_OBJ_NEW_SMALL_INT(dirent->d_type);
+ }
+ #else
+ // DT_UNKNOWN should have 0 value on any reasonable system
+ t->items[1] = MP_OBJ_NEW_SMALL_INT(0);
+ #endif
+ #ifdef _DIRENT_HAVE_D_INO
+ t->items[2] = MP_OBJ_NEW_SMALL_INT(dirent->d_ino);
+ #else
+ t->items[2] = MP_OBJ_NEW_SMALL_INT(0);
+ #endif
+
+ return MP_OBJ_FROM_PTR(t);
+ }
+}
+
+STATIC mp_obj_t vfs_posix_ilistdir(mp_obj_t self_in, mp_obj_t path_in) {
+ mp_obj_vfs_posix_t *self = MP_OBJ_TO_PTR(self_in);
+ vfs_posix_ilistdir_it_t *iter = m_new_obj(vfs_posix_ilistdir_it_t);
+ iter->base.type = &mp_type_polymorph_iter;
+ iter->iternext = vfs_posix_ilistdir_it_iternext;
+ iter->is_str = mp_obj_get_type(path_in) == &mp_type_str;
+ const char *path = vfs_posix_get_path_str(self, path_in);
+ iter->dir = opendir(path);
+ if (iter->dir == NULL) {
+ mp_raise_OSError(errno);
+ }
+ return MP_OBJ_FROM_PTR(iter);
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_2(vfs_posix_ilistdir_obj, vfs_posix_ilistdir);
+
+typedef struct _mp_obj_listdir_t {
+ mp_obj_base_t base;
+ mp_fun_1_t iternext;
+ DIR *dir;
+} mp_obj_listdir_t;
+
+STATIC mp_obj_t vfs_posix_mkdir(mp_obj_t self_in, mp_obj_t path_in) {
+ mp_obj_vfs_posix_t *self = MP_OBJ_TO_PTR(self_in);
+ int ret = mkdir(vfs_posix_get_path_str(self, path_in), 0777);
+ if (ret != 0) {
+ mp_raise_OSError(errno);
+ }
+ return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_2(vfs_posix_mkdir_obj, vfs_posix_mkdir);
+
+STATIC mp_obj_t vfs_posix_remove(mp_obj_t self_in, mp_obj_t path_in) {
+ return vfs_posix_fun1_helper(self_in, path_in, unlink);
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_2(vfs_posix_remove_obj, vfs_posix_remove);
+
+STATIC mp_obj_t vfs_posix_rename(mp_obj_t self_in, mp_obj_t old_path_in, mp_obj_t new_path_in) {
+ mp_obj_vfs_posix_t *self = MP_OBJ_TO_PTR(self_in);
+ const char *old_path = vfs_posix_get_path_str(self, old_path_in);
+ const char *new_path = vfs_posix_get_path_str(self, new_path_in);
+ int ret = rename(old_path, new_path);
+ if (ret != 0) {
+ mp_raise_OSError(errno);
+ }
+ return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_3(vfs_posix_rename_obj, vfs_posix_rename);
+
+STATIC mp_obj_t vfs_posix_rmdir(mp_obj_t self_in, mp_obj_t path_in) {
+ return vfs_posix_fun1_helper(self_in, path_in, rmdir);
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_2(vfs_posix_rmdir_obj, vfs_posix_rmdir);
+
+STATIC mp_obj_t vfs_posix_stat(mp_obj_t self_in, mp_obj_t path_in) {
+ mp_obj_vfs_posix_t *self = MP_OBJ_TO_PTR(self_in);
+ struct stat sb;
+ int ret = stat(vfs_posix_get_path_str(self, path_in), &sb);
+ if (ret != 0) {
+ mp_raise_OSError(errno);
+ }
+ mp_obj_tuple_t *t = MP_OBJ_TO_PTR(mp_obj_new_tuple(10, NULL));
+ t->items[0] = MP_OBJ_NEW_SMALL_INT(sb.st_mode);
+ t->items[1] = MP_OBJ_NEW_SMALL_INT(sb.st_ino);
+ t->items[2] = MP_OBJ_NEW_SMALL_INT(sb.st_dev);
+ t->items[3] = MP_OBJ_NEW_SMALL_INT(sb.st_nlink);
+ t->items[4] = MP_OBJ_NEW_SMALL_INT(sb.st_uid);
+ t->items[5] = MP_OBJ_NEW_SMALL_INT(sb.st_gid);
+ t->items[6] = MP_OBJ_NEW_SMALL_INT(sb.st_size);
+ t->items[7] = MP_OBJ_NEW_SMALL_INT(sb.st_atime);
+ t->items[8] = MP_OBJ_NEW_SMALL_INT(sb.st_mtime);
+ t->items[9] = MP_OBJ_NEW_SMALL_INT(sb.st_ctime);
+ return MP_OBJ_FROM_PTR(t);
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_2(vfs_posix_stat_obj, vfs_posix_stat);
+
+#ifdef __ANDROID__
+#define USE_STATFS 1
+#endif
+
+#if USE_STATFS
+#include <sys/vfs.h>
+#define STRUCT_STATVFS struct statfs
+#define STATVFS statfs
+#define F_FAVAIL sb.f_ffree
+#define F_NAMEMAX sb.f_namelen
+#define F_FLAG sb.f_flags
+#else
+#include <sys/statvfs.h>
+#define STRUCT_STATVFS struct statvfs
+#define STATVFS statvfs
+#define F_FAVAIL sb.f_favail
+#define F_NAMEMAX sb.f_namemax
+#define F_FLAG sb.f_flag
+#endif
+
+STATIC mp_obj_t vfs_posix_statvfs(mp_obj_t self_in, mp_obj_t path_in) {
+ mp_obj_vfs_posix_t *self = MP_OBJ_TO_PTR(self_in);
+ STRUCT_STATVFS sb;
+ const char *path = vfs_posix_get_path_str(self, path_in);
+ int ret = STATVFS(path, &sb);
+ if (ret != 0) {
+ mp_raise_OSError(errno);
+ }
+ mp_obj_tuple_t *t = MP_OBJ_TO_PTR(mp_obj_new_tuple(10, NULL));
+ t->items[0] = MP_OBJ_NEW_SMALL_INT(sb.f_bsize);
+ t->items[1] = MP_OBJ_NEW_SMALL_INT(sb.f_frsize);
+ t->items[2] = MP_OBJ_NEW_SMALL_INT(sb.f_blocks);
+ t->items[3] = MP_OBJ_NEW_SMALL_INT(sb.f_bfree);
+ t->items[4] = MP_OBJ_NEW_SMALL_INT(sb.f_bavail);
+ t->items[5] = MP_OBJ_NEW_SMALL_INT(sb.f_files);
+ t->items[6] = MP_OBJ_NEW_SMALL_INT(sb.f_ffree);
+ t->items[7] = MP_OBJ_NEW_SMALL_INT(F_FAVAIL);
+ t->items[8] = MP_OBJ_NEW_SMALL_INT(F_FLAG);
+ t->items[9] = MP_OBJ_NEW_SMALL_INT(F_NAMEMAX);
+ return MP_OBJ_FROM_PTR(t);
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_2(vfs_posix_statvfs_obj, vfs_posix_statvfs);
+
+STATIC const mp_rom_map_elem_t vfs_posix_locals_dict_table[] = {
+ { MP_ROM_QSTR(MP_QSTR_mount), MP_ROM_PTR(&vfs_posix_mount_obj) },
+ { MP_ROM_QSTR(MP_QSTR_umount), MP_ROM_PTR(&vfs_posix_umount_obj) },
+ { MP_ROM_QSTR(MP_QSTR_open), MP_ROM_PTR(&vfs_posix_open_obj) },
+
+ { MP_ROM_QSTR(MP_QSTR_chdir), MP_ROM_PTR(&vfs_posix_chdir_obj) },
+ { MP_ROM_QSTR(MP_QSTR_getcwd), MP_ROM_PTR(&vfs_posix_getcwd_obj) },
+ { MP_ROM_QSTR(MP_QSTR_ilistdir), MP_ROM_PTR(&vfs_posix_ilistdir_obj) },
+ { MP_ROM_QSTR(MP_QSTR_mkdir), MP_ROM_PTR(&vfs_posix_mkdir_obj) },
+ { MP_ROM_QSTR(MP_QSTR_remove), MP_ROM_PTR(&vfs_posix_remove_obj) },
+ { MP_ROM_QSTR(MP_QSTR_rename), MP_ROM_PTR(&vfs_posix_rename_obj) },
+ { MP_ROM_QSTR(MP_QSTR_rmdir), MP_ROM_PTR(&vfs_posix_rmdir_obj) },
+ { MP_ROM_QSTR(MP_QSTR_stat), MP_ROM_PTR(&vfs_posix_stat_obj) },
+ { MP_ROM_QSTR(MP_QSTR_statvfs), MP_ROM_PTR(&vfs_posix_statvfs_obj) },
+};
+STATIC MP_DEFINE_CONST_DICT(vfs_posix_locals_dict, vfs_posix_locals_dict_table);
+
+STATIC const mp_vfs_proto_t vfs_posix_proto = {
+ .import_stat = mp_vfs_posix_import_stat,
+};
+
+const mp_obj_type_t mp_type_vfs_posix = {
+ { &mp_type_type },
+ .name = MP_QSTR_VfsPosix,
+ .make_new = vfs_posix_make_new,
+ .protocol = &vfs_posix_proto,
+ .locals_dict = (mp_obj_dict_t*)&vfs_posix_locals_dict,
+};
+
+#endif // MICROPY_VFS_POSIX
diff --git a/extmod/vfs_posix.h b/extmod/vfs_posix.h
new file mode 100644
index 000000000..00756b4c9
--- /dev/null
+++ b/extmod/vfs_posix.h
@@ -0,0 +1,38 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2018 Damien P. George
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+#ifndef MICROPY_INCLUDED_EXTMOD_VFS_POSIX_H
+#define MICROPY_INCLUDED_EXTMOD_VFS_POSIX_H
+
+#include "py/lexer.h"
+#include "py/obj.h"
+
+extern const mp_obj_type_t mp_type_vfs_posix;
+extern const mp_obj_type_t mp_type_vfs_posix_fileio;
+extern const mp_obj_type_t mp_type_vfs_posix_textio;
+
+mp_obj_t mp_vfs_posix_file_open(const mp_obj_type_t *type, mp_obj_t file_in, mp_obj_t mode_in);
+
+#endif // MICROPY_INCLUDED_EXTMOD_VFS_POSIX_H
diff --git a/extmod/vfs_posix_file.c b/extmod/vfs_posix_file.c
new file mode 100644
index 000000000..435ac65cd
--- /dev/null
+++ b/extmod/vfs_posix_file.c
@@ -0,0 +1,261 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2013-2018 Damien P. George
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "py/runtime.h"
+#include "py/stream.h"
+#include "extmod/vfs_posix.h"
+
+#if MICROPY_VFS_POSIX
+
+#include <fcntl.h>
+
+#ifdef _WIN32
+#define fsync _commit
+#endif
+
+typedef struct _mp_obj_vfs_posix_file_t {
+ mp_obj_base_t base;
+ int fd;
+} mp_obj_vfs_posix_file_t;
+
+#ifdef MICROPY_CPYTHON_COMPAT
+STATIC void check_fd_is_open(const mp_obj_vfs_posix_file_t *o) {
+ if (o->fd < 0) {
+ nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, "I/O operation on closed file"));
+ }
+}
+#else
+#define check_fd_is_open(o)
+#endif
+
+STATIC void vfs_posix_file_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) {
+ (void)kind;
+ mp_obj_vfs_posix_file_t *self = MP_OBJ_TO_PTR(self_in);
+ mp_printf(print, "<io.%s %d>", mp_obj_get_type_str(self_in), self->fd);
+}
+
+mp_obj_t mp_vfs_posix_file_open(const mp_obj_type_t *type, mp_obj_t file_in, mp_obj_t mode_in) {
+ mp_obj_vfs_posix_file_t *o = m_new_obj(mp_obj_vfs_posix_file_t);
+ const char *mode_s = mp_obj_str_get_str(mode_in);
+
+ int mode_rw = 0, mode_x = 0;
+ while (*mode_s) {
+ switch (*mode_s++) {
+ case 'r':
+ mode_rw = O_RDONLY;
+ break;
+ case 'w':
+ mode_rw = O_WRONLY;
+ mode_x = O_CREAT | O_TRUNC;
+ break;
+ case 'a':
+ mode_rw = O_WRONLY;
+ mode_x = O_CREAT | O_APPEND;
+ break;
+ case '+':
+ mode_rw = O_RDWR;
+ break;
+ #if MICROPY_PY_IO_FILEIO
+ // If we don't have io.FileIO, then files are in text mode implicitly
+ case 'b':
+ type = &mp_type_vfs_posix_fileio;
+ break;
+ case 't':
+ type = &mp_type_vfs_posix_textio;
+ break;
+ #endif
+ }
+ }
+
+ o->base.type = type;
+
+ mp_obj_t fid = file_in;
+
+ if (MP_OBJ_IS_SMALL_INT(fid)) {
+ o->fd = MP_OBJ_SMALL_INT_VALUE(fid);
+ return MP_OBJ_FROM_PTR(o);
+ }
+
+ const char *fname = mp_obj_str_get_str(fid);
+ int fd = open(fname, mode_x | mode_rw, 0644);
+ if (fd == -1) {
+ mp_raise_OSError(errno);
+ }
+ o->fd = fd;
+ return MP_OBJ_FROM_PTR(o);
+}
+
+STATIC mp_obj_t vfs_posix_file_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) {
+ static const mp_arg_t allowed_args[] = {
+ { MP_QSTR_file, MP_ARG_OBJ | MP_ARG_REQUIRED, {.u_rom_obj = MP_ROM_PTR(&mp_const_none_obj)} },
+ { MP_QSTR_mode, MP_ARG_OBJ, {.u_rom_obj = MP_ROM_QSTR(MP_QSTR_r)} },
+ };
+
+ mp_arg_val_t arg_vals[MP_ARRAY_SIZE(allowed_args)];
+ mp_arg_parse_all_kw_array(n_args, n_kw, args, MP_ARRAY_SIZE(allowed_args), allowed_args, arg_vals);
+ return mp_vfs_posix_file_open(type, arg_vals[0].u_obj, arg_vals[1].u_obj);
+}
+
+STATIC mp_obj_t vfs_posix_file_fileno(mp_obj_t self_in) {
+ mp_obj_vfs_posix_file_t *self = MP_OBJ_TO_PTR(self_in);
+ check_fd_is_open(self);
+ return MP_OBJ_NEW_SMALL_INT(self->fd);
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(vfs_posix_file_fileno_obj, vfs_posix_file_fileno);
+
+STATIC mp_obj_t vfs_posix_file___exit__(size_t n_args, const mp_obj_t *args) {
+ (void)n_args;
+ return mp_stream_close(args[0]);
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(vfs_posix_file___exit___obj, 4, 4, vfs_posix_file___exit__);
+
+STATIC mp_uint_t vfs_posix_file_read(mp_obj_t o_in, void *buf, mp_uint_t size, int *errcode) {
+ mp_obj_vfs_posix_file_t *o = MP_OBJ_TO_PTR(o_in);
+ check_fd_is_open(o);
+ mp_int_t r = read(o->fd, buf, size);
+ if (r == -1) {
+ *errcode = errno;
+ return MP_STREAM_ERROR;
+ }
+ return r;
+}
+
+STATIC mp_uint_t vfs_posix_file_write(mp_obj_t o_in, const void *buf, mp_uint_t size, int *errcode) {
+ mp_obj_vfs_posix_file_t *o = MP_OBJ_TO_PTR(o_in);
+ check_fd_is_open(o);
+ #if MICROPY_PY_OS_DUPTERM
+ if (o->fd <= STDERR_FILENO) {
+ mp_hal_stdout_tx_strn(buf, size);
+ return size;
+ }
+ #endif
+ mp_int_t r = write(o->fd, buf, size);
+ while (r == -1 && errno == EINTR) {
+ if (MP_STATE_VM(mp_pending_exception) != MP_OBJ_NULL) {
+ mp_obj_t obj = MP_STATE_VM(mp_pending_exception);
+ MP_STATE_VM(mp_pending_exception) = MP_OBJ_NULL;
+ nlr_raise(obj);
+ }
+ r = write(o->fd, buf, size);
+ }
+ if (r == -1) {
+ *errcode = errno;
+ return MP_STREAM_ERROR;
+ }
+ return r;
+}
+
+STATIC mp_uint_t vfs_posix_file_ioctl(mp_obj_t o_in, mp_uint_t request, uintptr_t arg, int *errcode) {
+ mp_obj_vfs_posix_file_t *o = MP_OBJ_TO_PTR(o_in);
+ check_fd_is_open(o);
+ switch (request) {
+ case MP_STREAM_FLUSH:
+ if (fsync(o->fd) < 0) {
+ *errcode = errno;
+ return MP_STREAM_ERROR;
+ }
+ return 0;
+ case MP_STREAM_SEEK: {
+ struct mp_stream_seek_t *s = (struct mp_stream_seek_t*)arg;
+ off_t off = lseek(o->fd, s->offset, s->whence);
+ if (off == (off_t)-1) {
+ *errcode = errno;
+ return MP_STREAM_ERROR;
+ }
+ s->offset = off;
+ return 0;
+ }
+ case MP_STREAM_CLOSE:
+ close(o->fd);
+ #ifdef MICROPY_CPYTHON_COMPAT
+ o->fd = -1;
+ #endif
+ return 0;
+ default:
+ *errcode = EINVAL;
+ return MP_STREAM_ERROR;
+ }
+}
+
+STATIC const mp_rom_map_elem_t rawfile_locals_dict_table[] = {
+ { MP_ROM_QSTR(MP_QSTR_fileno), MP_ROM_PTR(&vfs_posix_file_fileno_obj) },
+ { MP_ROM_QSTR(MP_QSTR_read), MP_ROM_PTR(&mp_stream_read_obj) },
+ { MP_ROM_QSTR(MP_QSTR_readinto), MP_ROM_PTR(&mp_stream_readinto_obj) },
+ { MP_ROM_QSTR(MP_QSTR_readline), MP_ROM_PTR(&mp_stream_unbuffered_readline_obj) },
+ { MP_ROM_QSTR(MP_QSTR_readlines), MP_ROM_PTR(&mp_stream_unbuffered_readlines_obj) },
+ { MP_ROM_QSTR(MP_QSTR_write), MP_ROM_PTR(&mp_stream_write_obj) },
+ { MP_ROM_QSTR(MP_QSTR_seek), MP_ROM_PTR(&mp_stream_seek_obj) },
+ { MP_ROM_QSTR(MP_QSTR_tell), MP_ROM_PTR(&mp_stream_tell_obj) },
+ { MP_ROM_QSTR(MP_QSTR_flush), MP_ROM_PTR(&mp_stream_flush_obj) },
+ { MP_ROM_QSTR(MP_QSTR_close), MP_ROM_PTR(&mp_stream_close_obj) },
+ { MP_ROM_QSTR(MP_QSTR___enter__), MP_ROM_PTR(&mp_identity_obj) },
+ { MP_ROM_QSTR(MP_QSTR___exit__), MP_ROM_PTR(&vfs_posix_file___exit___obj) },
+};
+
+STATIC MP_DEFINE_CONST_DICT(rawfile_locals_dict, rawfile_locals_dict_table);
+
+#if MICROPY_PY_IO_FILEIO
+STATIC const mp_stream_p_t fileio_stream_p = {
+ .read = vfs_posix_file_read,
+ .write = vfs_posix_file_write,
+ .ioctl = vfs_posix_file_ioctl,
+};
+
+const mp_obj_type_t mp_type_vfs_posix_fileio = {
+ { &mp_type_type },
+ .name = MP_QSTR_FileIO,
+ .print = vfs_posix_file_print,
+ .make_new = vfs_posix_file_make_new,
+ .getiter = mp_identity_getiter,
+ .iternext = mp_stream_unbuffered_iter,
+ .protocol = &fileio_stream_p,
+ .locals_dict = (mp_obj_dict_t*)&rawfile_locals_dict,
+};
+#endif
+
+STATIC const mp_stream_p_t textio_stream_p = {
+ .read = vfs_posix_file_read,
+ .write = vfs_posix_file_write,
+ .ioctl = vfs_posix_file_ioctl,
+ .is_text = true,
+};
+
+const mp_obj_type_t mp_type_vfs_posix_textio = {
+ { &mp_type_type },
+ .name = MP_QSTR_TextIOWrapper,
+ .print = vfs_posix_file_print,
+ .make_new = vfs_posix_file_make_new,
+ .getiter = mp_identity_getiter,
+ .iternext = mp_stream_unbuffered_iter,
+ .protocol = &textio_stream_p,
+ .locals_dict = (mp_obj_dict_t*)&rawfile_locals_dict,
+};
+
+const mp_obj_vfs_posix_file_t mp_sys_stdin_obj = {{&mp_type_textio}, STDIN_FILENO};
+const mp_obj_vfs_posix_file_t mp_sys_stdout_obj = {{&mp_type_textio}, STDOUT_FILENO};
+const mp_obj_vfs_posix_file_t mp_sys_stderr_obj = {{&mp_type_textio}, STDERR_FILENO};
+
+#endif // MICROPY_VFS_POSIX
diff --git a/extmod/vfs_reader.c b/extmod/vfs_reader.c
index 891098aa1..e1ee45a3c 100644
--- a/extmod/vfs_reader.c
+++ b/extmod/vfs_reader.c
@@ -71,7 +71,7 @@ STATIC void mp_reader_vfs_close(void *data) {
void mp_reader_new_file(mp_reader_t *reader, const char *filename) {
mp_reader_vfs_t *rf = m_new_obj(mp_reader_vfs_t);
- mp_obj_t arg = mp_obj_new_str(filename, strlen(filename), false);
+ mp_obj_t arg = mp_obj_new_str(filename, strlen(filename));
rf->file = mp_vfs_open(1, &arg, (mp_map_t*)&mp_const_empty_map);
int errcode;
rf->len = mp_stream_rw(rf->file, rf->buf, sizeof(rf->buf), &errcode, MP_STREAM_RW_READ | MP_STREAM_RW_ONCE);