From b0adf65d94a260334d4cd906cef1e774731f748b Mon Sep 17 00:00:00 2001 From: Scott Shawcroft Date: Mon, 13 Sep 2021 14:44:05 -0700 Subject: [PATCH] Bump to v4 with move and dir path tweaks --- supervisor/shared/bluetooth/file_transfer.c | 111 ++++++++++++++++-- .../shared/bluetooth/file_transfer_protocol.h | 18 +++ 2 files changed, 122 insertions(+), 7 deletions(-) diff --git a/supervisor/shared/bluetooth/file_transfer.c b/supervisor/shared/bluetooth/file_transfer.c index eaebb3fbcb..342e69c66e 100644 --- a/supervisor/shared/bluetooth/file_transfer.c +++ b/supervisor/shared/bluetooth/file_transfer.c @@ -100,7 +100,7 @@ void supervisor_start_bluetooth_file_transfer(void) { NULL, // no initial value NULL); // no description - uint32_t version = 3; + uint32_t version = 4; mp_buffer_info_t bufinfo; bufinfo.buf = &version; bufinfo.len = sizeof(version); @@ -269,7 +269,7 @@ STATIC uint8_t _process_write(const uint8_t *raw_buf, size_t command_len) { // Check to see if USB has already been mounted. If not, then we "eject" from USB until we're done. #if CIRCUITPY_USB && CIRCUITPY_USB_MSC if (storage_usb_enabled() && !usb_msc_lock()) { - response.status = STATUS_ERROR; + response.status = STATUS_ERROR_READONLY; common_hal_bleio_packet_buffer_write(&_transfer_packet_buffer, (const uint8_t *)&response, sizeof(struct write_pacing), NULL, 0); return ANY_COMMAND; } @@ -421,6 +421,14 @@ STATIC uint8_t _process_delete(const uint8_t *raw_buf, size_t command_len) { common_hal_bleio_packet_buffer_write(&_transfer_packet_buffer, (const uint8_t *)&response, sizeof(struct delete_status), NULL, 0); return ANY_COMMAND; } + // Check to see if USB has already been mounted. If not, then we "eject" from USB until we're done. + #if CIRCUITPY_USB && CIRCUITPY_USB_MSC + if (storage_usb_enabled() && !usb_msc_lock()) { + response.status = STATUS_ERROR_READONLY; + common_hal_bleio_packet_buffer_write(&_transfer_packet_buffer, (const uint8_t *)&response, sizeof(struct delete_status), NULL, 0); + return ANY_COMMAND; + } + #endif // We need to receive another packet to have the full path. if (command_len < header_size + command->path_length) { return THIS_COMMAND; @@ -428,9 +436,9 @@ STATIC uint8_t _process_delete(const uint8_t *raw_buf, size_t command_len) { FATFS *fs = &((fs_user_mount_t *)MP_STATE_VM(vfs_mount_table)->obj)->fatfs; char *path = (char *)((uint8_t *)command) + header_size; path[command->path_length] = '\0'; - FRESULT result = FR_OK; FILINFO file; - if (f_stat(fs, path, &file) == FR_OK) { + FRESULT result = f_stat(fs, path, &file); + if (result == FR_OK) { if ((file.fattrib & AM_DIR) != 0) { result = _delete_directory_contents(fs, path); } @@ -438,10 +446,19 @@ STATIC uint8_t _process_delete(const uint8_t *raw_buf, size_t command_len) { result = f_unlink(fs, path); } } + #if CIRCUITPY_USB_MSC + usb_msc_unlock(); + #endif if (result != FR_OK) { response.status = STATUS_ERROR; } common_hal_bleio_packet_buffer_write(&_transfer_packet_buffer, (const uint8_t *)&response, sizeof(struct delete_status), NULL, 0); + if (result == FR_OK) { + // Don't reload until everything is written out of the packet buffer. + common_hal_bleio_packet_buffer_flush(&_transfer_packet_buffer); + // Trigger an autoreload + autoreload_start(); + } return ANY_COMMAND; } @@ -457,23 +474,44 @@ STATIC uint8_t _process_mkdir(const uint8_t *raw_buf, size_t command_len) { common_hal_bleio_packet_buffer_write(&_transfer_packet_buffer, (const uint8_t *)&response, sizeof(struct mkdir_status), NULL, 0); return ANY_COMMAND; } + // Check to see if USB has already been mounted. If not, then we "eject" from USB until we're done. + #if CIRCUITPY_USB && CIRCUITPY_USB_MSC + if (storage_usb_enabled() && !usb_msc_lock()) { + response.status = STATUS_ERROR_READONLY; + common_hal_bleio_packet_buffer_write(&_transfer_packet_buffer, (const uint8_t *)&response, sizeof(struct mkdir_status), NULL, 0); + return ANY_COMMAND; + } + #endif // We need to receive another packet to have the full path. if (command_len < header_size + command->path_length) { return THIS_COMMAND; } FATFS *fs = &((fs_user_mount_t *)MP_STATE_VM(vfs_mount_table)->obj)->fatfs; char *path = (char *)command->path; - // TODO: Check that the final character is a `/` - path[command->path_length - 1] = '\0'; + // -1 because fatfs doesn't want a trailing / + if (path[command->path_length - 1] == '/') { + path[command->path_length - 1] = '\0'; + } else { + path[command->path_length] = '\0'; + } DWORD fattime; response.truncated_time = truncate_time(command->modification_time, &fattime); override_fattime(fattime); FRESULT result = f_mkdir(fs, path); override_fattime(0); + #if CIRCUITPY_USB_MSC + usb_msc_unlock(); + #endif if (result != FR_OK) { response.status = STATUS_ERROR; } common_hal_bleio_packet_buffer_write(&_transfer_packet_buffer, (const uint8_t *)&response, sizeof(struct mkdir_status), NULL, 0); + if (result == FR_OK) { + // Don't reload until everything is written out of the packet buffer. + common_hal_bleio_packet_buffer_flush(&_transfer_packet_buffer); + // Trigger an autoreload + autoreload_start(); + } return ANY_COMMAND; } @@ -499,7 +537,11 @@ STATIC uint8_t _process_listdir(uint8_t *raw_buf, size_t command_len) { FATFS *fs = &((fs_user_mount_t *)MP_STATE_VM(vfs_mount_table)->obj)->fatfs; char *path = (char *)&command->path; // -1 because fatfs doesn't want a trailing / - path[command->path_length - 1] = '\0'; + if (path[command->path_length - 1] == '/') { + path[command->path_length - 1] = '\0'; + } else { + path[command->path_length] = '\0'; + } // mp_printf(&mp_plat_print, "list %s\n", path); FF_DIR dir; FRESULT res = f_opendir(fs, &dir, path); @@ -564,6 +606,58 @@ STATIC uint8_t _process_listdir(uint8_t *raw_buf, size_t command_len) { return ANY_COMMAND; } +STATIC uint8_t _process_move(const uint8_t *raw_buf, size_t command_len) { + const struct move_command *command = (struct move_command *)raw_buf; + size_t header_size = sizeof(struct move_command); + struct move_status response; + response.command = MOVE_STATUS; + response.status = STATUS_OK; + // +2 for null terminators. + uint32_t total_path_length = command->old_path_length + command->new_path_length + 1; + if (total_path_length > (COMMAND_SIZE - header_size - 1)) { + // TODO: throw away any more packets of path. + response.status = STATUS_ERROR; + common_hal_bleio_packet_buffer_write(&_transfer_packet_buffer, (const uint8_t *)&response, sizeof(struct move_status), NULL, 0); + return ANY_COMMAND; + } + // Check to see if USB has already been mounted. If not, then we "eject" from USB until we're done. + #if CIRCUITPY_USB && CIRCUITPY_USB_MSC + if (storage_usb_enabled() && !usb_msc_lock()) { + response.status = STATUS_ERROR_READONLY; + common_hal_bleio_packet_buffer_write(&_transfer_packet_buffer, (const uint8_t *)&response, sizeof(struct move_status), NULL, 0); + return ANY_COMMAND; + } + #endif + // We need to receive another packet to have the full path. + if (command_len < header_size + total_path_length) { + return THIS_COMMAND; + } + FATFS *fs = &((fs_user_mount_t *)MP_STATE_VM(vfs_mount_table)->obj)->fatfs; + char *old_path = (char *)command->paths; + old_path[command->old_path_length] = '\0'; + + char *new_path = old_path + command->old_path_length + 1; + new_path[command->new_path_length] = '\0'; + + // mp_printf(&mp_plat_print, "move %s to %s\n", old_path, new_path); + + FRESULT result = f_rename(fs, old_path, new_path); + #if CIRCUITPY_USB_MSC + usb_msc_unlock(); + #endif + if (result != FR_OK) { + response.status = STATUS_ERROR; + } + common_hal_bleio_packet_buffer_write(&_transfer_packet_buffer, (const uint8_t *)&response, sizeof(struct move_status), NULL, 0); + if (result == FR_OK) { + // Don't reload until everything is written out of the packet buffer. + common_hal_bleio_packet_buffer_flush(&_transfer_packet_buffer); + // Trigger an autoreload + autoreload_start(); + } + return ANY_COMMAND; +} + // Background state that must live across background calls. After the _process // helpers to force them to not use them. STATIC uint8_t current_command[COMMAND_SIZE] __attribute__ ((aligned(4))); @@ -625,6 +719,9 @@ void supervisor_bluetooth_file_transfer_background(void) { case LISTDIR: next_command = _process_listdir(current_command, current_offset); break; + case MOVE: + next_command = _process_move(current_command, current_offset); + break; } // Preserve the offset if we are waiting for more from this command. if (next_command != THIS_COMMAND) { diff --git a/supervisor/shared/bluetooth/file_transfer_protocol.h b/supervisor/shared/bluetooth/file_transfer_protocol.h index 3de8716c3b..3bc1f611c5 100644 --- a/supervisor/shared/bluetooth/file_transfer_protocol.h +++ b/supervisor/shared/bluetooth/file_transfer_protocol.h @@ -153,10 +153,28 @@ struct listdir_entry { uint8_t path[]; } __attribute__((packed)); +#define MOVE 0x60 +struct move_command { + uint8_t command; + uint8_t reserved; + uint16_t old_path_length; + uint16_t new_path_length; + // paths is two strings. The first is old_path and then a reserved byte. + // The last path is new_path. + uint8_t paths[]; +} __attribute__((packed)); + +#define MOVE_STATUS 0x61 +struct move_status { + uint8_t command; + uint8_t status; +} __attribute__((packed)); + #define STATUS_OK 0x01 #define STATUS_ERROR 0x02 #define STATUS_ERROR_NO_FILE 0x03 #define STATUS_ERROR_PROTOCOL 0x04 +#define STATUS_ERROR_READONLY 0x05 #endif // MICROPY_INCLUDED_SUPERVISOR_SHARED_BLUETOOTH_FILE_TRANSFER_PROTOCOL_H