diff --git a/src/protocols/rdp/guac_rdpdr/rdpdr_fs.c b/src/protocols/rdp/guac_rdpdr/rdpdr_fs.c index 05401f97..3f958ad5 100644 --- a/src/protocols/rdp/guac_rdpdr/rdpdr_fs.c +++ b/src/protocols/rdp/guac_rdpdr/rdpdr_fs.c @@ -283,6 +283,7 @@ int guac_rdpdr_fs_open(guac_rdpdr_device* device, const char* path, file->dir = NULL; file->dir_pattern[0] = '\0'; file->absolute_path = strdup(normalized_path); + file->real_path = strdup(real_path); GUAC_RDP_DEBUG(2, "Opened \"%s\" as file_id=%i", normalized_path, file_id); @@ -325,14 +326,47 @@ int guac_rdpdr_fs_open(guac_rdpdr_device* device, const char* path, } +int guac_rdpdr_fs_rename(guac_rdpdr_device* device, int file_id, + const char* new_path) { + + char real_path[GUAC_RDPDR_FS_MAX_PATH]; + char normalized_path[GUAC_RDPDR_FS_MAX_PATH]; + + guac_rdpdr_fs_file* file = guac_rdpdr_fs_get_file(device, file_id); + if (file == NULL) { + GUAC_RDP_DEBUG(1, "Rename of bad file_id: %i", file_id); + return GUAC_RDPDR_FS_EINVAL; + } + + /* Normalize path, return no-such-file if invalid */ + if (guac_rdpdr_fs_normalize_path(new_path, normalized_path)) { + GUAC_RDP_DEBUG(1, "Normalization of path \"%s\" failed.", new_path); + return GUAC_RDPDR_FS_ENOENT; + } + + /* Translate normalized path to real path */ + __guac_rdpdr_fs_translate_path(device, normalized_path, real_path); + + GUAC_RDP_DEBUG(2, "Renaming \"%s\" -> \"%s\"", file->real_path, real_path); + + /* Perform rename */ + if (rename(file->real_path, real_path)) { + GUAC_RDP_DEBUG(1, "rename() failed: \"%s\" -> \"%s\"", + file->real_path, real_path); + return guac_rdpdr_fs_get_errorcode(errno); + } + + return 0; + +} + void guac_rdpdr_fs_close(guac_rdpdr_device* device, int file_id) { guac_rdpdr_fs_data* data = (guac_rdpdr_fs_data*) device->data; - guac_rdpdr_fs_file* file; - /* Only close if file ID is valid */ - if (file_id < 0 || file_id >= GUAC_RDPDR_FS_MAX_FILES) { - GUAC_RDP_DEBUG(2, "Ignoring close for out-of-range file_id: %i", + guac_rdpdr_fs_file* file = guac_rdpdr_fs_get_file(device, file_id); + if (file == NULL) { + GUAC_RDP_DEBUG(2, "Ignoring close for bad file_id: %i", file_id); return; } @@ -351,6 +385,7 @@ void guac_rdpdr_fs_close(guac_rdpdr_device* device, int file_id) { /* Free name */ free(file->absolute_path); + free(file->real_path); /* Free ID back to pool */ guac_pool_free_int(data->file_id_pool, file_id); diff --git a/src/protocols/rdp/guac_rdpdr/rdpdr_fs.h b/src/protocols/rdp/guac_rdpdr/rdpdr_fs.h index c551d2cd..a7ca2b58 100644 --- a/src/protocols/rdp/guac_rdpdr/rdpdr_fs.h +++ b/src/protocols/rdp/guac_rdpdr/rdpdr_fs.h @@ -208,6 +208,11 @@ typedef struct guac_rdpdr_fs_file { */ char* absolute_path; + /** + * The real path of this file on the local filesystem. + */ + char* real_path; + /** * Associated local file descriptor. */ @@ -309,6 +314,13 @@ int guac_rdpdr_fs_open(guac_rdpdr_device* device, const char* path, int access, int file_attributes, int create_disposition, int create_options); +/** + * Renames (moves) the file with the given ID to the new path specified. + * Returns zero on success, or an error code if an error occurs. + */ +int guac_rdpdr_fs_rename(guac_rdpdr_device* device, int file_id, + const char* new_path); + /** * Frees the given file ID, allowing future open operations to reuse it. */ diff --git a/src/protocols/rdp/guac_rdpdr/rdpdr_fs_messages_file_info.c b/src/protocols/rdp/guac_rdpdr/rdpdr_fs_messages_file_info.c index af28e118..b6604734 100644 --- a/src/protocols/rdp/guac_rdpdr/rdpdr_fs_messages_file_info.c +++ b/src/protocols/rdp/guac_rdpdr/rdpdr_fs_messages_file_info.c @@ -143,9 +143,33 @@ void guac_rdpdr_fs_process_query_attribute_tag_info(guac_rdpdr_device* device, void guac_rdpdr_fs_process_set_rename_info(guac_rdpdr_device* device, wStream* input_stream, int file_id, int completion_id, int length) { - /* STUB */ - guac_client_log_error(device->rdpdr->client, - "Unimplemented stub: %s", __func__); + + int result; + int filename_length; + wStream* output_stream; + char destination_path[GUAC_RDPDR_FS_MAX_PATH]; + + /* Read structure */ + Stream_Seek_UINT8(input_stream); /* ReplaceIfExists */ + Stream_Seek_UINT8(input_stream); /* RootDirectory */ + Stream_Read_UINT32(input_stream, filename_length); /* FileNameLength */ + + /* Convert name to UTF-8 */ + guac_rdp_utf16_to_utf8(Stream_Pointer(input_stream), + destination_path, filename_length/2); + + /* Perform rename */ + result = guac_rdpdr_fs_rename(device, file_id, destination_path); + if (result < 0) + output_stream = guac_rdpdr_new_io_completion(device, + completion_id, guac_rdpdr_fs_get_status(result), 4); + else + output_stream = guac_rdpdr_new_io_completion(device, + completion_id, STATUS_SUCCESS, 4); + + Stream_Write_UINT32(output_stream, length); + svc_plugin_send((rdpSvcPlugin*) device->rdpdr, output_stream); + } void guac_rdpdr_fs_process_set_allocation_info(guac_rdpdr_device* device,