diff options
| author | Dan Halbert <halbert@halwitz.org> | 2018-07-11 16:45:30 -0400 |
|---|---|---|
| committer | Dan Halbert <halbert@halwitz.org> | 2018-07-11 16:45:30 -0400 |
| commit | 7c219600a246d8956d0b23ea3f5d125a820e6b6a (patch) | |
| tree | 4cf793a66284322d48a8f430815c31cd1c9ffa1d /extmod | |
| parent | 4962468ffffac9ec4e36b2b1fc3f132516df3127 (diff) | |
| parent | 25ae98f07cb3c4488cb955403dfe56b8bb8db6f0 (diff) | |
WIP: after merge; before testing
Diffstat (limited to 'extmod')
| -rw-r--r-- | extmod/machine_signal.c | 4 | ||||
| -rw-r--r-- | extmod/machine_spi.c | 116 | ||||
| -rw-r--r-- | extmod/machine_spi.h | 11 | ||||
| -rw-r--r-- | extmod/modbtree.c | 2 | ||||
| -rw-r--r-- | extmod/modframebuf.c | 54 | ||||
| -rw-r--r-- | extmod/modlwip.c | 180 | ||||
| -rw-r--r-- | extmod/moduhashlib.c | 190 | ||||
| -rw-r--r-- | extmod/modujson.c | 11 | ||||
| -rw-r--r-- | extmod/modure.c | 4 | ||||
| -rw-r--r-- | extmod/modussl_axtls.c | 64 | ||||
| -rw-r--r-- | extmod/modussl_mbedtls.c | 84 | ||||
| -rw-r--r-- | extmod/moduzlib.c | 3 | ||||
| -rw-r--r-- | extmod/modwebrepl.c | 34 | ||||
| -rw-r--r-- | extmod/modwebsocket.c | 18 | ||||
| -rw-r--r-- | extmod/re1.5/compilecode.c | 4 | ||||
| -rw-r--r-- | extmod/uos_dupterm.c | 43 | ||||
| -rw-r--r-- | extmod/vfs.c | 46 | ||||
| -rw-r--r-- | extmod/vfs.h | 5 | ||||
| -rw-r--r-- | extmod/vfs_fat.c | 116 | ||||
| -rw-r--r-- | extmod/vfs_fat_file.c | 43 | ||||
| -rw-r--r-- | extmod/vfs_fat_misc.c | 108 | ||||
| -rw-r--r-- | extmod/vfs_posix.c | 363 | ||||
| -rw-r--r-- | extmod/vfs_posix.h | 38 | ||||
| -rw-r--r-- | extmod/vfs_posix_file.c | 261 | ||||
| -rw-r--r-- | extmod/vfs_reader.c | 2 |
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); |
