Skip to content

Commit 1a0596a

Browse files
committed
Add option to disable the concurrent write protection
This allows writing to the filesystem from the host computer and CircuitPython by increasing the risk of filesystem corruption.
1 parent b1e8c43 commit 1a0596a

File tree

12 files changed

+69
-41
lines changed

12 files changed

+69
-41
lines changed

extmod/vfs_fat.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,8 @@
3838
#define FSUSER_NO_FILESYSTEM (0x0008) // the block device has no filesystem on it
3939
// Device is writable over USB and read-only to MicroPython.
4040
#define FSUSER_USB_WRITABLE (0x0010)
41+
// Bit set when the above flag is checked before opening a file for write.
42+
#define FSUSER_CONCURRENT_WRITE_PROTECTED (0x0020)
4143

4244
typedef struct _fs_user_mount_t {
4345
mp_obj_base_t base;

extmod/vfs_fat_file.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@
3434
#include "py/mperrno.h"
3535
#include "lib/oofatfs/ff.h"
3636
#include "extmod/vfs_fat.h"
37+
#include "supervisor/filesystem.h"
3738

3839
// this table converts from FRESULT to POSIX errno
3940
const byte fresult_to_errno_table[20] = {
@@ -187,7 +188,7 @@ STATIC mp_obj_t file_open(fs_user_mount_t *vfs, const mp_obj_type_t *type, mp_ar
187188
}
188189
}
189190
assert(vfs != NULL);
190-
if ((vfs->flags & FSUSER_USB_WRITABLE) != 0 && (mode & FA_WRITE) != 0) {
191+
if ((mode & FA_WRITE) != 0 && !filesystem_is_writable_by_python(vfs)) {
191192
mp_raise_OSError(MP_EROFS);
192193
}
193194

lib/tinyusb

main.c

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -323,12 +323,12 @@ void __attribute__ ((noinline)) run_boot_py(safe_mode_t safe_mode) {
323323
mp_hal_delay_ms(1500);
324324

325325
// USB isn't up, so we can write the file.
326-
filesystem_writable_by_python(true);
326+
filesystem_set_internal_writable_by_usb(false);
327327
f_open(fs, boot_output_file, CIRCUITPY_BOOT_OUTPUT_FILE, FA_WRITE | FA_CREATE_ALWAYS);
328328

329329
// Switch the filesystem back to non-writable by Python now instead of later,
330330
// since boot.py might change it back to writable.
331-
filesystem_writable_by_python(false);
331+
filesystem_set_internal_writable_by_usb(true);
332332

333333
// Write version info to boot_out.txt.
334334
mp_hal_stdout_tx_str(MICROPY_FULL_VERSION_INFO);
@@ -416,7 +416,8 @@ int __attribute__((used)) main(void) {
416416

417417
// By default our internal flash is readonly to local python code and
418418
// writable over USB. Set it here so that boot.py can change it.
419-
filesystem_writable_by_python(false);
419+
filesystem_set_internal_concurrent_write_protection(true);
420+
filesystem_set_internal_writable_by_usb(true);
420421

421422
run_boot_py(safe_mode);
422423

shared-bindings/storage/__init__.c

Lines changed: 16 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -48,16 +48,18 @@
4848
//| directly.
4949
//|
5050

51-
//| .. function:: mount(filesystem, mount_path, \*, readonly=False)
51+
//| .. function:: mount(filesystem, mount_path, \*, readonly=False, disable_concurrent_write_protection=False)
5252
//|
5353
//| Mounts the given filesystem object at the given path.
5454
//|
5555
//| This is the CircuitPython analog to the UNIX ``mount`` command.
5656
//|
57+
//| :param bool readonly: True when the filesystem should be readonly to CircuitPython.
58+
//|
5759
mp_obj_t storage_mount(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
5860
enum { ARG_readonly };
5961
static const mp_arg_t allowed_args[] = {
60-
{ MP_QSTR_readonly, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_false} },
62+
{ MP_QSTR_readonly, MP_ARG_KW_ONLY | MP_ARG_BOOL, {.u_bool = false} },
6163
};
6264

6365
// parse args
@@ -77,7 +79,7 @@ mp_obj_t storage_mount(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_arg
7779
mp_raise_ValueError(translate("filesystem must provide mount method"));
7880
}
7981

80-
common_hal_storage_mount(vfs_obj, mnt_str, mp_obj_is_true(args[ARG_readonly].u_obj));
82+
common_hal_storage_mount(vfs_obj, mnt_str, args[ARG_readonly].u_bool);
8183

8284
return mp_const_none;
8385
}
@@ -101,14 +103,21 @@ mp_obj_t storage_umount(mp_obj_t mnt_in) {
101103
}
102104
MP_DEFINE_CONST_FUN_OBJ_1(storage_umount_obj, storage_umount);
103105

104-
//| .. function:: remount(mount_path, readonly=False)
106+
//| .. function:: remount(mount_path, readonly=False, *, disable_concurrent_write_protection=False)
105107
//|
106108
//| Remounts the given path with new parameters.
107109
//|
110+
//| :param bool readonly: True when the filesystem should be readonly to CircuitPython.
111+
//| :param bool disable_concurrent_write_protection: When True, the check that makes sure the
112+
//| underlying filesystem data is written by one computer is disabled. Disabling the protection
113+
//| allows CircuitPython and a host to write to the same filesystem with the risk that the
114+
//| filesystem will be corrupted.
115+
//|
108116
mp_obj_t storage_remount(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
109-
enum { ARG_readonly };
117+
enum { ARG_readonly, ARG_disable_concurrent_write_protection };
110118
static const mp_arg_t allowed_args[] = {
111-
{ MP_QSTR_readonly, MP_ARG_BOOL | MP_ARG_REQUIRED, {.u_bool = false} },
119+
{ MP_QSTR_readonly, MP_ARG_BOOL, {.u_bool = false} },
120+
{ MP_QSTR_disable_concurrent_write_protection, MP_ARG_KW_ONLY | MP_ARG_BOOL, {.u_bool = false} },
112121
};
113122

114123
// get the mount point
@@ -118,7 +127,7 @@ mp_obj_t storage_remount(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_a
118127
mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
119128
mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
120129

121-
common_hal_storage_remount(mnt_str, args[ARG_readonly].u_bool);
130+
common_hal_storage_remount(mnt_str, args[ARG_readonly].u_bool, args[ARG_disable_concurrent_write_protection].u_bool);
122131

123132
return mp_const_none;
124133
}

shared-bindings/storage/__init__.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@
3333
void common_hal_storage_mount(mp_obj_t vfs_obj, const char* path, bool readonly);
3434
void common_hal_storage_umount_path(const char* path);
3535
void common_hal_storage_umount_object(mp_obj_t vfs_obj);
36-
void common_hal_storage_remount(const char* path, bool readonly);
36+
void common_hal_storage_remount(const char* path, bool readonly, bool disable_concurrent_write_protection);
3737
mp_obj_t common_hal_storage_getmount(const char* path);
3838
void common_hal_storage_erase_filesystem(void);
3939

shared-module/storage/__init__.c

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -143,7 +143,7 @@ mp_obj_t common_hal_storage_getmount(const char *mount_path) {
143143
return storage_object_from_path(mount_path);
144144
}
145145

146-
void common_hal_storage_remount(const char *mount_path, bool readonly) {
146+
void common_hal_storage_remount(const char *mount_path, bool readonly, bool disable_concurrent_write_protection) {
147147
if (strcmp(mount_path, "/") != 0) {
148148
mp_raise_OSError(MP_EINVAL);
149149
}
@@ -156,7 +156,8 @@ void common_hal_storage_remount(const char *mount_path, bool readonly) {
156156
}
157157
#endif
158158

159-
supervisor_flash_set_usb_writable(readonly);
159+
filesystem_set_internal_writable_by_usb(readonly);
160+
filesystem_set_internal_concurrent_write_protection(!disable_concurrent_write_protection);
160161
}
161162

162163
void common_hal_storage_erase_filesystem(void) {

supervisor/filesystem.h

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,9 +29,16 @@
2929

3030
#include <stdbool.h>
3131

32+
#include "extmod/vfs_fat.h"
33+
3234
void filesystem_init(bool create_allowed, bool force_create);
3335
void filesystem_flush(void);
34-
void filesystem_writable_by_python(bool writable);
3536
bool filesystem_present(void);
37+
void filesystem_set_internal_writable_by_usb(bool usb_writable);
38+
void filesystem_set_internal_concurrent_write_protection(bool concurrent_write_protection);
39+
void filesystem_set_writable_by_usb(fs_user_mount_t *vfs, bool usb_writable);
40+
void filesystem_set_concurrent_write_protection(fs_user_mount_t *vfs, bool concurrent_write_protection);
41+
bool filesystem_is_writable_by_python(fs_user_mount_t *vfs);
42+
bool filesystem_is_writable_by_usb(fs_user_mount_t *vfs);
3643

3744
#endif // MICROPY_INCLUDED_SUPERVISOR_FILESYSTEM_H

supervisor/flash.h

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,6 @@
3737
#include "supervisor/internal_flash.h"
3838
#endif
3939

40-
void supervisor_flash_set_usb_writable(bool usb_writable);
4140
void supervisor_flash_init(void);
4241
uint32_t supervisor_flash_get_block_size(void);
4342
uint32_t supervisor_flash_get_block_count(void);

supervisor/shared/filesystem.c

Lines changed: 30 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,8 @@
2424
* THE SOFTWARE.
2525
*/
2626

27+
#include "supervisor/filesystem.h"
28+
2729
#include "extmod/vfs_fat.h"
2830
#include "lib/oofatfs/ff.h"
2931
#include "lib/oofatfs/diskio.h"
@@ -92,16 +94,42 @@ void filesystem_flush(void) {
9294
supervisor_flash_flush();
9395
}
9496

95-
void filesystem_writable_by_python(bool writable) {
97+
void filesystem_set_internal_writable_by_usb(bool writable) {
9698
fs_user_mount_t *vfs = &_internal_vfs;
9799

98-
if (!writable) {
100+
filesystem_set_writable_by_usb(vfs, writable);
101+
}
102+
103+
void filesystem_set_writable_by_usb(fs_user_mount_t *vfs, bool usb_writable) {
104+
if (usb_writable) {
99105
vfs->flags |= FSUSER_USB_WRITABLE;
100106
} else {
101107
vfs->flags &= ~FSUSER_USB_WRITABLE;
102108
}
103109
}
104110

111+
bool filesystem_is_writable_by_python(fs_user_mount_t *vfs) {
112+
return (vfs->flags & FSUSER_CONCURRENT_WRITE_PROTECTED) == 0 ||
113+
(vfs->flags & FSUSER_USB_WRITABLE) == 0;
114+
}
115+
116+
bool filesystem_is_writable_by_usb(fs_user_mount_t *vfs) {
117+
return (vfs->flags & FSUSER_CONCURRENT_WRITE_PROTECTED) == 0 ||
118+
(vfs->flags & FSUSER_USB_WRITABLE) != 0;
119+
}
120+
121+
void filesystem_set_internal_concurrent_write_protection(bool concurrent_write_protection) {
122+
filesystem_set_concurrent_write_protection(&_internal_vfs, concurrent_write_protection);
123+
}
124+
125+
void filesystem_set_concurrent_write_protection(fs_user_mount_t *vfs, bool concurrent_write_protection) {
126+
if (concurrent_write_protection) {
127+
vfs->flags |= FSUSER_CONCURRENT_WRITE_PROTECTED;
128+
} else {
129+
vfs->flags &= ~FSUSER_CONCURRENT_WRITE_PROTECTED;
130+
}
131+
}
132+
105133
bool filesystem_present(void) {
106134
return true;
107135
}

0 commit comments

Comments
 (0)