cscg24-guacamole

CSCG 2024 Challenge 'Guacamole Mashup'
git clone https://git.sinitax.com/sinitax/cscg24-guacamole
Log | Files | Refs | sfeed.txt

fs.h (19396B)


      1/*
      2 * Licensed to the Apache Software Foundation (ASF) under one
      3 * or more contributor license agreements.  See the NOTICE file
      4 * distributed with this work for additional information
      5 * regarding copyright ownership.  The ASF licenses this file
      6 * to you under the Apache License, Version 2.0 (the
      7 * "License"); you may not use this file except in compliance
      8 * with the License.  You may obtain a copy of the License at
      9 *
     10 *   http://www.apache.org/licenses/LICENSE-2.0
     11 *
     12 * Unless required by applicable law or agreed to in writing,
     13 * software distributed under the License is distributed on an
     14 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
     15 * KIND, either express or implied.  See the License for the
     16 * specific language governing permissions and limitations
     17 * under the License.
     18 */
     19
     20#ifndef GUAC_RDP_FS_H
     21#define GUAC_RDP_FS_H
     22
     23/**
     24 * Functions and macros specific to filesystem handling and initialization
     25 * independent of RDP. The functions here may deal with the filesystem device
     26 * directly, but their semantics must not deal with RDP protocol messaging.
     27 * Functions here represent a virtual Windows-style filesystem on top of UNIX
     28 * system calls and structures, using the guac_rdp_fs structure as a home
     29 * for common data.
     30 *
     31 * @file fs.h 
     32 */
     33
     34#include <guacamole/client.h>
     35#include <guacamole/object.h>
     36#include <guacamole/pool.h>
     37#include <guacamole/user.h>
     38
     39#include <dirent.h>
     40#include <stdint.h>
     41
     42/**
     43 * The maximum number of file IDs to provide.
     44 */
     45#define GUAC_RDP_FS_MAX_FILES 128
     46
     47/**
     48 * The maximum number of bytes in a path string.
     49 */
     50#define GUAC_RDP_FS_MAX_PATH 4096
     51
     52/**
     53 * The maximum number of directories a path may contain.
     54 */
     55#define GUAC_RDP_MAX_PATH_DEPTH 64
     56
     57/**
     58 * Error code returned when no more file IDs can be allocated.
     59 */
     60#define GUAC_RDP_FS_ENFILE -1
     61
     62/**
     63 * Error code returned when no such file exists.
     64 */
     65#define GUAC_RDP_FS_ENOENT -2
     66
     67/**
     68 * Error code returned when the operation required a directory
     69 * but the file was not a directory.
     70 */
     71#define GUAC_RDP_FS_ENOTDIR -3
     72
     73/**
     74 * Error code returned when insufficient space exists to complete
     75 * the operation.
     76 */
     77#define GUAC_RDP_FS_ENOSPC -4
     78
     79/**
     80 * Error code returned when the operation requires a normal file but
     81 * a directory was given.
     82 */
     83#define GUAC_RDP_FS_EISDIR -5
     84
     85/**
     86 * Error code returned when permission is denied.
     87 */
     88#define GUAC_RDP_FS_EACCES -6
     89
     90/**
     91 * Error code returned when the operation cannot be completed because the
     92 * file already exists.
     93 */
     94#define GUAC_RDP_FS_EEXIST -7
     95
     96/**
     97 * Error code returned when invalid parameters were given.
     98 */
     99#define GUAC_RDP_FS_EINVAL -8
    100
    101/**
    102 * Error code returned when the operation is not implemented.
    103 */
    104#define GUAC_RDP_FS_ENOSYS -9
    105
    106/**
    107 * Error code returned when the operation is not supported.
    108 */
    109#define GUAC_RDP_FS_ENOTSUP -10
    110
    111/**
    112 * Converts a UNIX timestamp (seconds since Jan 1, 1970 UTC) to Windows
    113 * timestamp (100 nanosecond intervals since Jan 1, 1601 UTC).
    114 */
    115#define WINDOWS_TIME(t) ((t + ((uint64_t) 11644473600)) * 10000000)
    116
    117/**
    118 * An arbitrary file on the virtual filesystem of the Guacamole drive.
    119 */
    120typedef struct guac_rdp_fs_file {
    121
    122    /**
    123     * The ID of this file.
    124     */
    125    int id;
    126
    127    /**
    128     * The absolute path, including filename, of this file.
    129     */
    130    char* absolute_path;
    131
    132    /**
    133     * The real path of this file on the local filesystem.
    134     */
    135    char* real_path;
    136
    137    /**
    138     * Associated local file descriptor.
    139     */
    140    int fd;
    141
    142    /**
    143     * Associated directory stream, if any. This field only applies
    144     * if the file is being used as a directory.
    145     */
    146    DIR* dir;
    147
    148    /**
    149     * The pattern the check directory contents against, if any.
    150     */
    151    char dir_pattern[GUAC_RDP_FS_MAX_PATH];
    152
    153    /**
    154     * Bitwise OR of all associated Windows file attributes.
    155     */
    156    int attributes;
    157
    158    /**
    159     * The size of this file, in bytes.
    160     */
    161    uint64_t size;
    162
    163    /**
    164     * The time this file was created, as a Windows timestamp.
    165     */
    166    uint64_t ctime;
    167
    168    /**
    169     * The time this file was last modified, as a Windows timestamp.
    170     */
    171    uint64_t mtime;
    172
    173    /**
    174     * The time this file was last accessed, as a Windows timestamp.
    175     */
    176    uint64_t atime;
    177
    178    /**
    179     * The number of bytes written to the file.
    180     */
    181    uint64_t bytes_written;
    182
    183} guac_rdp_fs_file;
    184
    185/**
    186 * A virtual filesystem implementing RDP-style operations.
    187 */
    188typedef struct guac_rdp_fs {
    189
    190    /**
    191     * The Guacamole client associated with the RDP session.
    192     */
    193    guac_client* client;
    194
    195    /**
    196     * The root of the filesystem.
    197     */
    198    char* drive_path;
    199
    200    /**
    201     * The number of currently open files.
    202     */
    203    int open_files;
    204
    205    /**
    206     * Pool of file IDs.
    207     */
    208    guac_pool* file_id_pool;
    209
    210    /**
    211     * All available file structures.
    212     */
    213    guac_rdp_fs_file files[GUAC_RDP_FS_MAX_FILES];
    214    
    215    /**
    216     * If downloads from the remote server to the browser should be disabled.
    217     */
    218    int disable_download;
    219    
    220    /**
    221     * If uploads from the browser to the remote server should be disabled.
    222     */
    223    int disable_upload;
    224
    225} guac_rdp_fs;
    226
    227/**
    228 * Filesystem information structure.
    229 */
    230typedef struct guac_rdp_fs_info {
    231
    232    /**
    233     * The number of free blocks available.
    234     */
    235    int blocks_available;
    236
    237    /**
    238     * The number of blocks in the filesystem.
    239     */
    240    int blocks_total;
    241
    242    /**
    243     * The number of bytes per block.
    244     */
    245    int block_size;
    246
    247} guac_rdp_fs_info;
    248
    249/**
    250 * Allocates a new filesystem given a root path. This filesystem will behave
    251 * as if it were a network drive.
    252 *
    253 * @param client
    254 *     The guac_client associated with the current RDP session.
    255 *
    256 * @param drive_path
    257 *     The local directory to use as the root directory of the emulated
    258 *     network drive.
    259 *
    260 * @param create_drive_path
    261 *     Non-zero if the drive path specified should be automatically created if
    262 *     it does not yet exist, zero otherwise.
    263 * 
    264 * @param disable_download
    265 *     Non-zero if downloads from the remote server to the local browser should
    266 *     be disabled.
    267 * 
    268 * @param disable_upload
    269 *     Non-zero if uploads from the browser to the remote server should be
    270 *     disabled.
    271 *
    272 * @return
    273 *     The newly-allocated filesystem.
    274 */
    275guac_rdp_fs* guac_rdp_fs_alloc(guac_client* client, const char* drive_path,
    276        int create_drive_path, int disable_download, int disable_upload);
    277
    278/**
    279 * Frees the given filesystem.
    280 *
    281 * @param fs
    282 *     The filesystem to free.
    283 */
    284void guac_rdp_fs_free(guac_rdp_fs* fs);
    285
    286/**
    287 * Creates and exposes a new filesystem guac_object to the given user,
    288 * providing access to the files within the given RDP filesystem. The
    289 * allocated guac_object must eventually be freed via guac_user_free_object().
    290 *
    291 * @param fs
    292 *     The RDP filesystem object to expose.
    293 *
    294 * @param user
    295 *     The user that the RDP filesystem should be exposed to.
    296 *
    297 * @return
    298 *     A new Guacamole filesystem object, configured to use RDP for uploading
    299 *     and downloading files.
    300 */
    301guac_object* guac_rdp_fs_alloc_object(guac_rdp_fs* fs, guac_user* user);
    302
    303/**
    304 * Allocates a new filesystem guac_object for the given user, returning the
    305 * resulting guac_object. This function is provided for convenience, as it is
    306 * can be used as the callback for guac_client_foreach_user() or
    307 * guac_client_for_owner(). Note that this guac_object will be tracked
    308 * internally by libguac, will be provided to us in the parameters of handlers
    309 * related to that guac_object, and will automatically be freed when the
    310 * associated guac_user is freed, so the return value of this function can
    311 * safely be ignored.
    312 *
    313 * If either the given user or the given filesystem are NULL, then this
    314 * function has no effect.
    315 *
    316 * @param user
    317 *     The use to expose the filesystem to, or NULL if nothing should be
    318 *     exposed.
    319 *
    320 * @param data
    321 *     A pointer to the guac_rdp_fs instance to expose to the given user, or
    322 *     NULL if nothing should be exposed.
    323 *
    324 * @return
    325 *     The guac_object allocated for the newly-exposed filesystem, or NULL if
    326 *     no filesystem object could be allocated.
    327 */
    328void* guac_rdp_fs_expose(guac_user* user, void* data);
    329
    330/**
    331 * Converts the given relative path to an absolute path based on the given
    332 * parent path. If the path cannot be converted, non-zero is returned.
    333 *
    334 * @param parent
    335 *     The parent directory of the relative path.
    336 *
    337 * @param rel_path
    338 *     The relative path to convert.
    339 *
    340 * @return
    341 *     Zero if the path was converted successfully, non-zero otherwise.
    342 */
    343int guac_rdp_fs_convert_path(const char* parent, const char* rel_path,
    344        char* abs_path);
    345
    346/**
    347 * Translates the given errno error code to a GUAC_RDP_FS error code.
    348 *
    349 * @param err
    350 *     The error code, as returned within errno by a system call.
    351 *
    352 * @return
    353 *     A GUAC_RDP_FS error code, such as GUAC_RDP_FS_ENFILE,
    354 *     GUAC_RDP_FS_ENOENT, etc.
    355 */
    356int guac_rdp_fs_get_errorcode(int err);
    357
    358/**
    359 * Translates the given GUAC_RDP_FS error code to an RDPDR status code.
    360 *
    361 * @param err
    362 *     A GUAC_RDP_FS error code, such as GUAC_RDP_FS_ENFILE,
    363 *     GUAC_RDP_FS_ENOENT, etc.
    364 *
    365 * @return
    366 *     A status code corresponding to the given error code that an
    367 *     implementation of the RDPDR channel can understand.
    368 */
    369int guac_rdp_fs_get_status(int err);
    370
    371/**
    372 * Opens the given file, returning the a new file ID, or an error code less
    373 * than zero if an error occurs. The given path MUST be absolute, and will be
    374 * translated to be relative to the drive path of the simulated filesystem.
    375 *
    376 * @param fs
    377 *     The filesystem to use when opening the file.
    378 *
    379 * @param path
    380 *     The absolute path to the file within the simulated filesystem.
    381 *
    382 * @param access
    383 *     A bitwise-OR of various RDPDR access flags, such as GENERIC_ALL or
    384 *     GENERIC_WRITE. This value will ultimately be translated to a standard
    385 *     O_RDWR, O_WRONLY, etc. value when opening the real file on the local
    386 *     filesystem.
    387 *
    388 * @param file_attributes
    389 *     The attributes to apply to the file, if created. This parameter is
    390 *     currently ignored, and has no effect.
    391 *
    392 * @param create_disposition
    393 *     Any one of several RDPDR file creation dispositions, such as
    394 *     FILE_CREATE, FILE_OPEN_IF, etc. The creation disposition dictates
    395 *     whether a new file should be created, whether the file can already
    396 *     exist, whether existing contents should be truncated, etc.
    397 *
    398 * @param create_options
    399 *     A bitwise-OR of various RDPDR options dictating how a file is to be
    400 *     created. Currently only one option is implemented, FILE_DIRECTORY_FILE,
    401 *     which specifies that the new file must be a directory.
    402 *
    403 * @return
    404 *     A new file ID, which will always be a positive value, or an error code
    405 *     if an error occurs. All error codes are negative values and correspond
    406 *     to GUAC_RDP_FS constants, such as GUAC_RDP_FS_ENOENT.
    407 */
    408int guac_rdp_fs_open(guac_rdp_fs* fs, const char* path,
    409        int access, int file_attributes, int create_disposition,
    410        int create_options);
    411
    412/**
    413 * Reads up to the given length of bytes from the given offset within the
    414 * file having the given ID. Returns the number of bytes read, zero on EOF,
    415 * and an error code if an error occurs.
    416 *
    417 * @param fs
    418 *     The filesystem containing the file from which data is to be read.
    419 *
    420 * @param file_id
    421 *     The ID of the file to read data from, as returned by guac_rdp_fs_open().
    422 *
    423 * @param offset
    424 *     The byte offset within the file to start reading from.
    425 *
    426 * @param buffer
    427 *     The buffer to fill with data from the file.
    428 *
    429 * @param length
    430 *     The maximum number of bytes to read from the file.
    431 *
    432 * @return
    433 *     The number of bytes actually read, zero on EOF, or an error code if an
    434 *     error occurs. All error codes are negative values and correspond to
    435 *     GUAC_RDP_FS constants, such as GUAC_RDP_FS_ENOENT.
    436 */
    437int guac_rdp_fs_read(guac_rdp_fs* fs, int file_id, uint64_t offset,
    438        void* buffer, int length);
    439
    440/**
    441 * Writes up to the given length of bytes from the given offset within the
    442 * file having the given ID. Returns the number of bytes written, and an
    443 * error code if an error occurs.
    444 *
    445 * @param fs
    446 *     The filesystem containing the file to which data is to be written.
    447 *
    448 * @param file_id
    449 *     The ID of the file to write data to, as returned by guac_rdp_fs_open().
    450 *
    451 * @param offset
    452 *     The byte offset within the file to start writinging at.
    453 *
    454 * @param buffer
    455 *     The buffer containing the data to write.
    456 *
    457 * @param length
    458 *     The maximum number of bytes to write to the file.
    459 *
    460 * @return
    461 *     The number of bytes actually written, or an error code if an error
    462 *     occurs. All error codes are negative values and correspond to
    463 *     GUAC_RDP_FS constants, such as GUAC_RDP_FS_ENOENT.
    464 */
    465int guac_rdp_fs_write(guac_rdp_fs* fs, int file_id, uint64_t offset,
    466        void* buffer, int length);
    467
    468/**
    469 * Renames (moves) the file with the given ID to the new path specified.
    470 * Returns zero on success, or an error code if an error occurs.
    471 *
    472 * @param fs
    473 *     The filesystem containing the file to rename.
    474 *
    475 * @param file_id
    476 *     The ID of the file to rename, as returned by guac_rdp_fs_open().
    477 *
    478 * @param new_path
    479 *     The absolute path to move the file to.
    480 *
    481 * @return
    482 *     Zero if the rename succeeded, or an error code if an error occurs. All
    483 *     error codes are negative values and correspond to GUAC_RDP_FS constants,
    484 *     such as GUAC_RDP_FS_ENOENT.
    485 */
    486int guac_rdp_fs_rename(guac_rdp_fs* fs, int file_id,
    487        const char* new_path);
    488
    489/**
    490 * Deletes the file with the given ID.
    491 *
    492 * @param fs
    493 *     The filesystem containing the file to delete.
    494 *
    495 * @param file_id
    496 *     The ID of the file to delete, as returned by guac_rdp_fs_open().
    497 *
    498 * @return
    499 *     Zero if deletion succeeded, or an error code if an error occurs. All
    500 *     error codes are negative values and correspond to GUAC_RDP_FS constants,
    501 *     such as GUAC_RDP_FS_ENOENT.
    502 */
    503int guac_rdp_fs_delete(guac_rdp_fs* fs, int file_id);
    504
    505/**
    506 * Truncates the file with the given ID to the given length (in bytes), which
    507 * may be larger.
    508 *
    509 * @param fs
    510 *     The filesystem containing the file to truncate.
    511 *
    512 * @param file_id
    513 *     The ID of the file to truncate, as returned by guac_rdp_fs_open().
    514 *
    515 * @param length
    516 *     The new length of the file, in bytes. Despite being named "truncate",
    517 *     this new length may be larger.
    518 *
    519 * @return
    520 *     Zero if truncation succeeded, or an error code if an error occurs. All
    521 *     error codes are negative values and correspond to GUAC_RDP_FS constants,
    522 *     such as GUAC_RDP_FS_ENOENT.
    523 */
    524int guac_rdp_fs_truncate(guac_rdp_fs* fs, int file_id, int length);
    525
    526/**
    527 * Frees the given file ID, allowing future open operations to reuse it.
    528 *
    529 * @param fs
    530 *     The filesystem containing the file to close.
    531 *
    532 * @param file_id
    533 *     The ID of the file to close, as returned by guac_rdp_fs_open().
    534 */
    535void guac_rdp_fs_close(guac_rdp_fs* fs, int file_id);
    536
    537/**
    538 * Given an arbitrary path, returns a pointer to the first character following
    539 * the last path separator in the path (the basename of the path). For example,
    540 * given "/foo/bar/baz" or "\foo\bar\baz", this function would return a pointer
    541 * to "baz".
    542 *
    543 * @param path
    544 *     The path to determine the basename of.
    545 *
    546 * @return
    547 *     A pointer to the first character of the basename within the path.
    548 */
    549const char* guac_rdp_fs_basename(const char* path);
    550
    551/**
    552 * Given an arbitrary path, which may contain ".." and ".", creates an
    553 * absolute path which does NOT contain ".." or ".". The given path MUST
    554 * be absolute.
    555 *
    556 * @param path
    557 *     The absolute path to normalize.
    558 *
    559 * @param abs_path
    560 *     The buffer to populate with the normalized path. The normalized path
    561 *     will not contain relative path components like ".." or ".".
    562 *
    563 * @return
    564 *     Zero if normalization succeeded, non-zero otherwise.
    565 */
    566int guac_rdp_fs_normalize_path(const char* path, char* abs_path);
    567
    568/**
    569 * Given a parent path and a relative path, produces a normalized absolute
    570 * path.
    571 *
    572 * @param parent 
    573 *     The absolute path of the parent directory of the relative path.
    574 *
    575 * @param rel_path
    576 *     The relative path to convert.
    577 *
    578 * @param abs_path
    579 *     The buffer to populate with the absolute, normalized path. The
    580 *     normalized path will not contain relative path components like ".." or
    581 *     ".".
    582 *
    583 * @return
    584 *     Zero if conversion succeeded, non-zero otherwise.
    585 */
    586int guac_rdp_fs_convert_path(const char* parent, const char* rel_path,
    587        char* abs_path);
    588
    589/**
    590 * Returns the next filename within the directory having the given file ID,
    591 * or NULL if no more files.
    592 *
    593 * @param fs
    594 *     The filesystem containing the file to read directory entries from.
    595 *
    596 * @param file_id
    597 *     The ID of the file to read directory entries from, as returned by
    598 *     guac_rdp_fs_open().
    599 *
    600 * @return
    601 *     The name of the next filename within the directory, or NULL if the last
    602 *     file in the directory has already been returned by a previous call.
    603 */
    604const char* guac_rdp_fs_read_dir(guac_rdp_fs* fs, int file_id);
    605
    606/**
    607 * Returns the file having the given ID, or NULL if no such file exists.
    608 *
    609 * @param fs
    610 *     The filesystem containing the desired file.
    611 *
    612 * @param file_id
    613 *     The ID of the desired, as returned by guac_rdp_fs_open().
    614 *
    615 * @return
    616 *     The file having the given ID, or NULL is no such file exists.
    617 */
    618guac_rdp_fs_file* guac_rdp_fs_get_file(guac_rdp_fs* fs, int file_id);
    619
    620/**
    621 * Returns whether the given filename matches the given pattern. The pattern
    622 * given is a shell wildcard pattern as accepted by the POSIX fnmatch()
    623 * function. Backslashes will be interpreted as literal backslashes, not
    624 * escape characters.
    625 *
    626 * @param filename
    627 *     The filename to check
    628 *
    629 * @param pattern
    630 *     The pattern to check the filename against.
    631 *
    632 * @return
    633 *     Non-zero if the pattern matches, zero otherwise.
    634 */
    635int guac_rdp_fs_matches(const char* filename, const char* pattern);
    636
    637/**
    638 * Populates the given structure with information about the filesystem,
    639 * particularly the amount of space available.
    640 *
    641 * @param fs
    642 *     The filesystem to obtain information from.
    643 *
    644 * @param info
    645 *     The guac_rdp_fs_info structure to populate.
    646 *
    647 * @return 
    648 *     Zero if information retrieval succeeded, or an error code if an error
    649 *     occurs. All error codes are negative values and correspond to
    650 *     GUAC_RDP_FS constants, such as GUAC_RDP_FS_ENOENT.
    651 */
    652int guac_rdp_fs_get_info(guac_rdp_fs* fs, guac_rdp_fs_info* info);
    653
    654/**
    655 * Concatenates the given filename with the given path, separating the two
    656 * with a single forward slash. The full result must be no more than
    657 * GUAC_RDP_FS_MAX_PATH bytes long, counting null terminator.
    658 *
    659 * @param fullpath
    660 *     The buffer to store the result within. This buffer must be at least
    661 *     GUAC_RDP_FS_MAX_PATH bytes long.
    662 *
    663 * @param path
    664 *     The path to append the filename to.
    665 *
    666 * @param filename
    667 *     The filename to append to the path.
    668 *
    669 * @return
    670 *     Non-zero if the filename is valid and was successfully appended to the
    671 *     path, zero otherwise.
    672 */
    673int guac_rdp_fs_append_filename(char* fullpath, const char* path,
    674        const char* filename);
    675
    676#endif
    677