From 9fcb3e3678626626ede9958d2ec92f25018436b4 Mon Sep 17 00:00:00 2001 From: Michael Jumper Date: Mon, 29 Jul 2013 17:57:24 -0700 Subject: [PATCH] Actually resolve and open files. --- src/protocols/rdp/guac_rdpdr/rdpdr_fs.c | 137 +++++++++++++++++- src/protocols/rdp/guac_rdpdr/rdpdr_fs.h | 52 +++---- .../rdp/guac_rdpdr/rdpdr_fs_messages.c | 2 +- 3 files changed, 158 insertions(+), 33 deletions(-) diff --git a/src/protocols/rdp/guac_rdpdr/rdpdr_fs.c b/src/protocols/rdp/guac_rdpdr/rdpdr_fs.c index 3b5d2232..f3b45aad 100644 --- a/src/protocols/rdp/guac_rdpdr/rdpdr_fs.c +++ b/src/protocols/rdp/guac_rdpdr/rdpdr_fs.c @@ -35,6 +35,10 @@ * * ***** END LICENSE BLOCK ***** */ +#include +#include +#include + #ifdef ENABLE_WINPR #include #else @@ -51,27 +55,148 @@ #include -int guac_rdpdr_fs_open(guac_rdpdr_device* device, const char* path) { +/** + * Translates an absolute Windows path to an absolute path which is within the "drive path" + * specified in the connection settings. + */ +static char* __guac_rdpdr_fs_translate_path(guac_rdpdr_device* device, + const char* path, char* path_buffer) { + + /* Get drive path */ + rdp_guac_client_data* client_data = (rdp_guac_client_data*) device->rdpdr->client->data; + char* drive_path = client_data->settings.drive_path; + + int i; + + /* Start with path from settings */ + for (i=0; idata; + char path_buffer[GUAC_RDPDR_FS_MAX_PATH]; + int fd; int file_id; guac_rdpdr_fs_file* file; + mode_t mode; + int flags = 0; + /* If no files available, return too many open */ if (data->open_files >= GUAC_RDPDR_FS_MAX_FILES) return GUAC_RDPDR_FS_ENFILE; - /* If path is empty, the file does not exist */ - if (path[0] == '\0') + /* If path is empty or relative, the file does not exist */ + if (path[0] != '\\') return GUAC_RDPDR_FS_ENOENT; - file->type = GUAC_RDPDR_FS_FILE; - /* STUB */ + /* Translate access into mode */ + if (access & ACCESS_FILE_READ_DATA) { + if (access & (ACCESS_FILE_WRITE_DATA | ACCESS_FILE_APPEND_DATA)) + mode = O_RDWR; + else + mode = O_RDONLY; + } + else if (access & (ACCESS_FILE_WRITE_DATA | ACCESS_FILE_APPEND_DATA)) + mode = O_WRONLY; + else + return GUAC_RDPDR_FS_ENOENT; /* FIXME: Replace with real return value */ - /* Get file ID */ + /* If append access requested, add appropriate option */ + if (access & ACCESS_FILE_APPEND_DATA) + flags |= O_APPEND; + + switch (create_disposition) { + + /* Supersede (replace) if exists, otherwise create */ + case DISP_FILE_SUPERSEDE: + flags |= O_TRUNC | O_CREAT; + break; + + /* Open file if exists and do not overwrite, fail otherwise */ + case DISP_FILE_OPEN: + flags |= O_APPEND; + break; + + /* Create if not exist, fail otherwise */ + case DISP_FILE_CREATE: + flags |= O_EXCL; + break; + + /* Open if exists, create otherwise */ + case DISP_FILE_OPEN_IF: + flags |= O_APPEND | O_CREAT; + break; + + /* Overwrite if exists, fail otherwise */ + case DISP_FILE_OVERWRITE: + /* No flag necessary - default functionality of open */ + break; + + /* Overwrite if exists, create otherwise */ + case DISP_FILE_OVERWRITE_IF: + flags |= O_CREAT; + break; + + /* Unrecognised disposition */ + default: + return GUAC_RDPDR_FS_ENOENT; /* FIXME: Replace with real return value */ + + } + + /* If path invalid, return no such file */ + if (__guac_rdpdr_fs_translate_path(device, path, path_buffer) == NULL) + return GUAC_RDPDR_FS_ENOENT; + + guac_client_log_info(device->rdpdr->client, "Path translated to \"%s\"", path_buffer); + + /* Open file */ + fd = open(path_buffer, flags, mode); + if (fd == -1) + return GUAC_RDPDR_FS_ENOENT; + + /* Get file ID, init file */ file_id = guac_pool_next_int(data->file_id_pool); file = &(data->files[file_id]); + file->fd = fd; data->open_files++; diff --git a/src/protocols/rdp/guac_rdpdr/rdpdr_fs.h b/src/protocols/rdp/guac_rdpdr/rdpdr_fs.h index 019b6c92..1312a772 100644 --- a/src/protocols/rdp/guac_rdpdr/rdpdr_fs.h +++ b/src/protocols/rdp/guac_rdpdr/rdpdr_fs.h @@ -60,6 +60,11 @@ */ #define GUAC_RDPDR_FS_MAX_FILES 128 +/** + * The maximum number of bytes in a path string. + */ +#define GUAC_RDPDR_FS_MAX_PATH 4096 + /** * Error code returned when no more file IDs can be allocated. */ @@ -70,6 +75,25 @@ */ #define GUAC_RDPDR_FS_ENOENT -2 +/* + * Access constants. + */ +#define ACCESS_FILE_READ_DATA 0x00000001 +#define ACCESS_FILE_WRITE_DATA 0x00000002 +#define ACCESS_FILE_APPEND_DATA 0x00000004 +#define ACCESS_DELETE 0x00010000 + +/* + * Create disposition constants. + */ + +#define DISP_FILE_SUPERSEDE 0x00000000 +#define DISP_FILE_OPEN 0x00000001 +#define DISP_FILE_CREATE 0x00000002 +#define DISP_FILE_OPEN_IF 0x00000003 +#define DISP_FILE_OVERWRITE 0x00000004 +#define DISP_FILE_OVERWRITE_IF 0x00000005 + /* * Information constants. */ @@ -102,36 +126,11 @@ */ #define WINDOWS_TIME(t) ((t - ((uint64_t) 11644473600)) * 10000000) -/** - * Enumeration of all supported file types. - */ -typedef enum guac_rdpdr_fs_file_type { - - /** - * A regular file - either a file or directory. - */ - GUAC_RDPDR_FS_FILE, - - /** - * A disk device - here, this is always virtual, and always the containing - * volume (the Guacamole drive). - */ - GUAC_RDPDR_FS_VOLUME, - -} guac_rdpdr_fs_file_type; - /** * An arbitrary file on the virtual filesystem of the Guacamole drive. */ typedef struct guac_rdpdr_fs_file { - /** - * The type of this file - either a FILE (file or directory) or a - * VOLUME (virtual file, represents the virtual device represented by - * the Guacamole drive). - */ - guac_rdpdr_fs_file_type type; - /** * Associated local file descriptor. */ @@ -170,7 +169,8 @@ void guac_rdpdr_register_fs(guac_rdpdrPlugin* rdpdr); /** * Returns the next available file ID, or -1 if none available. */ -int guac_rdpdr_fs_open(guac_rdpdr_device* device, const char* path); +int guac_rdpdr_fs_open(guac_rdpdr_device* device, const char* path, + int access, int create_disposition); /** * Frees the given file ID, allowing future open operations to reuse it. diff --git a/src/protocols/rdp/guac_rdpdr/rdpdr_fs_messages.c b/src/protocols/rdp/guac_rdpdr/rdpdr_fs_messages.c index 2ba5f39d..9d21dd63 100644 --- a/src/protocols/rdp/guac_rdpdr/rdpdr_fs_messages.c +++ b/src/protocols/rdp/guac_rdpdr/rdpdr_fs_messages.c @@ -78,7 +78,7 @@ void guac_rdpdr_fs_process_create(guac_rdpdr_device* device, guac_rdp_utf16_to_utf8(Stream_Pointer(input_stream), path, path_length/2 - 1); /* Open file */ - file_id = guac_rdpdr_fs_open(device, path); + file_id = guac_rdpdr_fs_open(device, path, desired_access, create_disposition); /* Write header */ Stream_Write_UINT16(output_stream, RDPDR_CTYP_CORE);