Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

GUACAMOLE-1931: Allow writing to existing typescript files. #500

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion src/protocols/kubernetes/kubernetes.c
Original file line number Diff line number Diff line change
Expand Up @@ -275,7 +275,8 @@ void* guac_kubernetes_client_thread(void* data) {
guac_terminal_create_typescript(kubernetes_client->term,
settings->typescript_path,
settings->typescript_name,
settings->create_typescript_path);
settings->create_typescript_path,
settings->typescript_write_existing);
}

/* Init libwebsockets context creation parameters */
Expand Down
12 changes: 12 additions & 0 deletions src/protocols/kubernetes/settings.c
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ const char* GUAC_KUBERNETES_CLIENT_ARGS[] = {
"typescript-path",
"typescript-name",
"create-typescript-path",
"typescript-write-existing",
"recording-path",
"recording-name",
"recording-exclude-output",
Expand Down Expand Up @@ -167,6 +168,12 @@ enum KUBERNETES_ARGS_IDX {
*/
IDX_CREATE_TYPESCRIPT_PATH,

/**
* Whether existing files should be appended to when creating a new
* typescript. Disabled by default.
*/
IDX_TYPESCRIPT_WRITE_EXISTING,

/**
* The full absolute path to the directory in which screen recordings
* should be written.
Expand Down Expand Up @@ -366,6 +373,11 @@ guac_kubernetes_settings* guac_kubernetes_parse_args(guac_user* user,
guac_user_parse_args_boolean(user, GUAC_KUBERNETES_CLIENT_ARGS, argv,
IDX_CREATE_TYPESCRIPT_PATH, false);

/* Parse allow write existing file flag */
settings->typescript_write_existing =
guac_user_parse_args_boolean(user, GUAC_KUBERNETES_CLIENT_ARGS, argv,
IDX_TYPESCRIPT_WRITE_EXISTING, false);

/* Read recording path */
settings->recording_path =
guac_user_parse_args_string(user, GUAC_KUBERNETES_CLIENT_ARGS, argv,
Expand Down
6 changes: 6 additions & 0 deletions src/protocols/kubernetes/settings.h
Original file line number Diff line number Diff line change
Expand Up @@ -191,6 +191,12 @@ typedef struct guac_kubernetes_settings {
*/
bool create_typescript_path;

/**
* Whether existing files should be appended to when creating a new
* typescript. Disabled by default.
*/
bool typescript_write_existing;

/**
* The path in which the screen recording should be saved, if enabled. If
* no screen recording should be saved, this will be NULL.
Expand Down
12 changes: 12 additions & 0 deletions src/protocols/ssh/settings.c
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ const char* GUAC_SSH_CLIENT_ARGS[] = {
"typescript-path",
"typescript-name",
"create-typescript-path",
"typescript-write-existing",
"recording-path",
"recording-name",
"recording-exclude-output",
Expand Down Expand Up @@ -198,6 +199,12 @@ enum SSH_ARGS_IDX {
*/
IDX_CREATE_TYPESCRIPT_PATH,

/**
* Whether existing files should be appended to when creating a new
* typescript. Disabled by default.
*/
IDX_TYPESCRIPT_WRITE_EXISTING,

/**
* The full absolute path to the directory in which screen recordings
* should be written.
Expand Down Expand Up @@ -472,6 +479,11 @@ guac_ssh_settings* guac_ssh_parse_args(guac_user* user,
guac_user_parse_args_boolean(user, GUAC_SSH_CLIENT_ARGS, argv,
IDX_CREATE_TYPESCRIPT_PATH, false);

/* Parse allow write existing file flag */
settings->typescript_write_existing =
guac_user_parse_args_boolean(user, GUAC_SSH_CLIENT_ARGS, argv,
IDX_TYPESCRIPT_WRITE_EXISTING, false);

/* Read recording path */
settings->recording_path =
guac_user_parse_args_string(user, GUAC_SSH_CLIENT_ARGS, argv,
Expand Down
6 changes: 6 additions & 0 deletions src/protocols/ssh/settings.h
Original file line number Diff line number Diff line change
Expand Up @@ -208,6 +208,12 @@ typedef struct guac_ssh_settings {
*/
bool create_typescript_path;

/**
* Whether existing files should be appended to when creating a new
* typescript. Disabled by default.
*/
bool typescript_write_existing;

/**
* The path in which the screen recording should be saved, if enabled. If
* no screen recording should be saved, this will be NULL.
Expand Down
3 changes: 2 additions & 1 deletion src/protocols/ssh/ssh.c
Original file line number Diff line number Diff line change
Expand Up @@ -301,7 +301,8 @@ void* ssh_client_thread(void* data) {
guac_terminal_create_typescript(ssh_client->term,
settings->typescript_path,
settings->typescript_name,
settings->create_typescript_path);
settings->create_typescript_path,
settings->typescript_write_existing);
}

/* Get user and credentials */
Expand Down
12 changes: 12 additions & 0 deletions src/protocols/telnet/settings.c
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ const char* GUAC_TELNET_CLIENT_ARGS[] = {
"typescript-path",
"typescript-name",
"create-typescript-path",
"typescript-write-existing",
"recording-path",
"recording-name",
"recording-exclude-output",
Expand Down Expand Up @@ -150,6 +151,12 @@ enum TELNET_ARGS_IDX {
*/
IDX_CREATE_TYPESCRIPT_PATH,

/**
* Whether existing files should be appended to when creating a new
* typescript. Disabled by default.
*/
IDX_TYPESCRIPT_WRITE_EXISTING,

/**
* The full absolute path to the directory in which screen recordings
* should be written.
Expand Down Expand Up @@ -463,6 +470,11 @@ guac_telnet_settings* guac_telnet_parse_args(guac_user* user,
guac_user_parse_args_boolean(user, GUAC_TELNET_CLIENT_ARGS, argv,
IDX_CREATE_TYPESCRIPT_PATH, false);

/* Parse allow write existing file flag */
settings->typescript_write_existing =
guac_user_parse_args_boolean(user, GUAC_TELNET_CLIENT_ARGS, argv,
IDX_TYPESCRIPT_WRITE_EXISTING, false);

/* Read recording path */
settings->recording_path =
guac_user_parse_args_string(user, GUAC_TELNET_CLIENT_ARGS, argv,
Expand Down
6 changes: 6 additions & 0 deletions src/protocols/telnet/settings.h
Original file line number Diff line number Diff line change
Expand Up @@ -196,6 +196,12 @@ typedef struct guac_telnet_settings {
*/
bool create_typescript_path;

/**
* Whether existing files should be appended to when creating a new
* typescript. Disabled by default.
*/
bool typescript_write_existing;

/**
* The path in which the screen recording should be saved, if enabled. If
* no screen recording should be saved, this will be NULL.
Expand Down
3 changes: 2 additions & 1 deletion src/protocols/telnet/telnet.c
Original file line number Diff line number Diff line change
Expand Up @@ -644,7 +644,8 @@ void* guac_telnet_client_thread(void* data) {
guac_terminal_create_typescript(telnet_client->term,
settings->typescript_path,
settings->typescript_name,
settings->create_typescript_path);
settings->create_typescript_path,
settings->typescript_write_existing);
}

/* Open telnet session */
Expand Down
5 changes: 3 additions & 2 deletions src/terminal/terminal.c
Original file line number Diff line number Diff line change
Expand Up @@ -2029,10 +2029,11 @@ void guac_terminal_pipe_stream_close(guac_terminal* term) {
}

int guac_terminal_create_typescript(guac_terminal* term, const char* path,
const char* name, int create_path) {
const char* name, int create_path, int allow_write_existing) {

/* Create typescript */
term->typescript = guac_terminal_typescript_alloc(path, name, create_path);
term->typescript = guac_terminal_typescript_alloc(
path, name, create_path, allow_write_existing);

/* Log failure */
if (term->typescript == NULL) {
Expand Down
25 changes: 17 additions & 8 deletions src/terminal/terminal/terminal.h
Original file line number Diff line number Diff line change
Expand Up @@ -747,13 +747,18 @@ void guac_terminal_clipboard_append(guac_terminal* terminal,
void guac_terminal_remove_user(guac_terminal* terminal, guac_user* user);

/**
* Requests that the terminal write all output to a new pair of typescript
* files within the given path and using the given base name. Terminal output
* will be written to these new files, along with timing information. If the
* create_path flag is non-zero, the given path will be created if it does not
* yet exist. If creation of the typescript files or path fails, error messages
* will automatically be logged, and no typescript will be written. The
* typescript will automatically be closed once the terminal is freed.
* Requests that the terminal write all output to a pair of typescript
* files within the given path and using the given base name. If
* allow_write_existing is non-zero, these may be existing files; otherwise,
* the existing files may not be written to, and a non-zero value will be
* returned.
*
* Terminal output will be written to the files, along with timing information.
* If the create_path flag is non-zero, the given path will be created if it
* does not yet exist. If creation of the typescript files or path fails,
* error messages will automatically be logged, and no typescript will be
* written. The typescript will automatically be closed once the terminal is
* freed.
*
* @param term
* The terminal whose output should be written to a typescript.
Expand All @@ -771,12 +776,16 @@ void guac_terminal_remove_user(guac_terminal* terminal, guac_user* user);
* written, or non-zero if the path should be created if it does not yet
* exist.
*
* @param allow_write_existing
* Non-zero if writing to existing files should be allowed, or zero
* otherwise.
*
* @return
* Zero if the typescript files have been successfully created and a
* typescript will be written, non-zero otherwise.
*/
int guac_terminal_create_typescript(guac_terminal* term, const char* path,
const char* name, int create_path);
const char* name, int create_path, int allow_write_existing);

/**
* Immediately applies the given color scheme to the given terminal, overriding
Expand Down
14 changes: 10 additions & 4 deletions src/terminal/terminal/typescript.h
Original file line number Diff line number Diff line change
Expand Up @@ -125,11 +125,13 @@ typedef struct guac_terminal_typescript {
} guac_terminal_typescript;

/**
* Creates a new pair of typescript files within the given path and using the
* Creates a pair of typescript files within the given path and using the
* given base name, returning an abstraction which represents those files.
* Terminal output will be written to these new files, along with timing
* Terminal output will be written to these files, along with timing
* information. If the create_path flag is non-zero, the given path will be
* created if it does not yet exist.
* created if it does not yet exist. If allow_write_existing is non-zero,
* these may be existing files; otherwise, any existing file will cause this
* function to fail, returning NULL.
*
* @param path
* The full absolute path to a directory in which the typescript files
Expand All @@ -144,12 +146,16 @@ typedef struct guac_terminal_typescript {
* written, or non-zero if the path should be created if it does not yet
* exist.
*
* @param allow_write_existing
* Non-zero if writing to existing files should be allowed, or zero
* otherwise.
*
* @return
* A new guac_terminal_typescript representing the typescript files
* requested, or NULL if creation of the typescript files failed.
*/
guac_terminal_typescript* guac_terminal_typescript_alloc(const char* path,
const char* name, int create_path);
const char* name, int create_path, int allow_write_existing);

/**
* Writes a single byte of terminal data to the typescript, flushing and
Expand Down
41 changes: 24 additions & 17 deletions src/terminal/typescript.c
Original file line number Diff line number Diff line change
Expand Up @@ -33,12 +33,12 @@
#include <fcntl.h>

/**
* Attempts to open a new typescript data file within the given path and having
* the given name. If such a file already exists, sequential numeric suffixes
* (.1, .2, .3, etc.) are appended until a filename is found which does not
* exist (or until the maximum number of numeric suffixes has been tried). If
* the file absolutely cannot be opened due to an error, -1 is returned and
* errno is set appropriately.
* Attempts to open a typescript data file within the given path and having
* the given name. If such a file already exists and allow_write_existing is
* zero, sequential numeric suffixes (.1, .2, .3, etc.) are appended until a
* filename is found which does not exist (or until the maximum number of
* numeric suffixes has been tried). If the file absolutely cannot be opened
* due to an error, -1 is returned and errno is set appropriately.
*
* @param path
* The full path to the directory in which the data file should be created.
Expand All @@ -55,12 +55,17 @@
* @param basename_size
* The number of bytes available within the provided basename buffer.
*
* @param allow_write_existing
* Non-zero if writing to an existing file should be allowed, or zero
* otherwise.
*
* @return
* The file descriptor of the open data file if open succeeded, or -1 on
* failure.
*/
static int guac_terminal_typescript_open_data_file(const char* path,
const char* name, char* basename, int basename_size) {
const char* name, char* basename, int basename_size,
int allow_write_existing) {

int i;

Expand All @@ -76,10 +81,11 @@ static int guac_terminal_typescript_open_data_file(const char* path,
return -1;
}

/* Require the file not exist already if allow_write_existing not set */
int file_flags = O_CREAT | O_WRONLY | (allow_write_existing ? 0 : O_EXCL);

/* Attempt to open typescript data file */
int data_fd = open(basename,
O_CREAT | O_EXCL | O_WRONLY,
S_IRUSR | S_IWUSR | S_IRGRP);
int data_fd = open(basename, file_flags, S_IRUSR | S_IWUSR | S_IRGRP);

/* Continuously retry with alternate names on failure */
if (data_fd == -1) {
Expand All @@ -96,9 +102,7 @@ static int guac_terminal_typescript_open_data_file(const char* path,
sprintf(suffix, "%i", i);

/* Retry with newly-suffixed filename */
data_fd = open(basename,
O_CREAT | O_EXCL | O_WRONLY,
S_IRUSR | S_IWUSR | S_IRGRP);
data_fd = open(basename, file_flags, S_IRUSR | S_IWUSR | S_IRGRP);

}

Expand All @@ -109,7 +113,7 @@ static int guac_terminal_typescript_open_data_file(const char* path,
}

guac_terminal_typescript* guac_terminal_typescript_alloc(const char* path,
const char* name, int create_path) {
const char* name, int create_path, int allow_write_existing) {

/* Create path if it does not exist, fail if impossible */
if (create_path && mkdir(path, S_IRWXU | S_IRGRP | S_IXGRP)
Expand All @@ -124,7 +128,8 @@ guac_terminal_typescript* guac_terminal_typescript_alloc(const char* path,
typescript->data_fd = guac_terminal_typescript_open_data_file(
path, name, typescript->data_filename,
sizeof(typescript->data_filename)
- sizeof(GUAC_TERMINAL_TYPESCRIPT_TIMING_SUFFIX));
- sizeof(GUAC_TERMINAL_TYPESCRIPT_TIMING_SUFFIX),
allow_write_existing);
if (typescript->data_fd == -1) {
guac_mem_free(typescript);
return NULL;
Expand All @@ -139,10 +144,12 @@ guac_terminal_typescript* guac_terminal_typescript_alloc(const char* path,
return NULL;
}

/* Require the file not exist already if allow_write_existing not set */
int file_flags = O_CREAT | O_WRONLY | (allow_write_existing ? 0 : O_EXCL);

/* Attempt to open typescript timing file */
typescript->timing_fd = open(typescript->timing_filename,
O_CREAT | O_EXCL | O_WRONLY,
S_IRUSR | S_IWUSR | S_IRGRP);
file_flags, S_IRUSR | S_IWUSR | S_IRGRP);
if (typescript->timing_fd == -1) {
close(typescript->data_fd);
guac_mem_free(typescript);
Expand Down
Loading