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