From dbaa6848539061c01db47d8f5665457cfcff5e64 Mon Sep 17 00:00:00 2001 From: Sergey Bugaev Date: Sat, 4 Mar 2023 20:18:51 +0300 Subject: [PATCH] Unlink the temp file sooner We only need the temp file to be present on the file system to run xdg-mime on it. Once we have done that, we can unlink it and simply use an fd to refer to it, seeking to the beginning each time. This makes us more robust against wl-copy crashing (or getting killed), in which case the file would be kept on the file system; this should no longer be the case with this patch. Related to https://github.com/bugaevc/wl-clipboard/pull/155 --- src/types/copy-action.c | 11 ++++++++-- src/types/copy-action.h | 3 ++- src/wl-copy.c | 45 +++++++++++++++++++++++------------------ 3 files changed, 36 insertions(+), 23 deletions(-) diff --git a/src/types/copy-action.c b/src/types/copy-action.c index 4b6a760..b3f8829 100644 --- a/src/types/copy-action.c +++ b/src/types/copy-action.c @@ -71,7 +71,7 @@ static void do_send(struct source *source, const char *mime_type, int fd) { /* Unset O_NONBLOCK */ fcntl(fd, F_SETFL, 0); - if (self->file_to_copy != NULL) { + if (self->fd_to_copy_from != -1) { /* Copy the file to the given file descriptor * by spawning an appropriate cat process. */ @@ -82,9 +82,11 @@ static void do_send(struct source *source, const char *mime_type, int fd) { return; } if (pid == 0) { + dup2(self->fd_to_copy_from, STDIN_FILENO); + close(self->fd_to_copy_from); dup2(fd, STDOUT_FILENO); close(fd); - execlp("cat", "cat", self->file_to_copy, NULL); + execlp("cat", "cat", NULL); perror("exec cat"); exit(1); } @@ -97,6 +99,11 @@ static void do_send(struct source *source, const char *mime_type, int fd) { * instead. */ waitpid(pid, NULL, 0); + /* Seek back to the beginning of the file */ + off_t rc = lseek(self->fd_to_copy_from, 0, SEEK_SET); + if (rc < 0) { + perror("lseek"); + } } else { /* We'll perform the copy ourselves */ FILE *f = fdopen(fd, "w"); diff --git a/src/types/copy-action.h b/src/types/copy-action.h index d7d3422..babe179 100644 --- a/src/types/copy-action.h +++ b/src/types/copy-action.h @@ -40,8 +40,9 @@ struct copy_action { /* Exactly one of these fields must be non-null if the source * is non-null, otherwise all these fields must be null. + * The null value for fd_to_copy_from is -1. */ - const char *file_to_copy; + int fd_to_copy_from; argv_t argv_to_copy; struct { const char *ptr; diff --git a/src/wl-copy.c b/src/wl-copy.c index 70ac45c..a9813da 100644 --- a/src/wl-copy.c +++ b/src/wl-copy.c @@ -81,29 +81,13 @@ static void did_set_selection_callback(struct copy_action *copy_action) { } } -static void cleanup_and_exit(struct copy_action *copy_action, int code) { - /* We're done copying! - * All that's left to do now is to - * clean up after ourselves and exit. - */ - char *temp_file = (char *) copy_action->file_to_copy; - if (temp_file != NULL) { - /* Clean up our temporary file */ - execlp("rm", "rm", "-r", dirname(temp_file), NULL); - perror("exec rm"); - exit(1); - } else { - exit(code); - } -} - static void cancelled_callback(struct copy_action *copy_action) { - cleanup_and_exit(copy_action, 0); + exit(0); } static void pasted_callback(struct copy_action *copy_action) { if (options.paste_once) { - cleanup_and_exit(copy_action, 0); + exit(0); } } @@ -244,6 +228,7 @@ int main(int argc, argv_t argv) { /* Create and initialize the copy action */ struct copy_action *copy_action = calloc(1, sizeof(struct copy_action)); + copy_action->fd_to_copy_from = -1; copy_action->device = device; copy_action->primary = options.primary; @@ -266,7 +251,28 @@ int main(int argc, argv_t argv) { if (options.mime_type == NULL) { options.mime_type = infer_mime_type_from_contents(temp_file); } - copy_action->file_to_copy = temp_file; + copy_action->fd_to_copy_from = open( + temp_file, + O_RDONLY | O_CLOEXEC + ); + if (copy_action->fd_to_copy_from < 0) { + perror("Failed to open temp file"); + return 1; + } + /* Now, remove the temp file and its + * containing directory. We still keep + * access to the file through our open + * file descriptor. + */ + int rc = unlink(temp_file); + if (rc < 0) { + perror("Failed to unlink temp file"); + } + rc = rmdir(dirname(temp_file)); + if (rc < 0) { + perror("Failed to remove temp file directory"); + } + free(temp_file); } /* Create the source */ @@ -300,6 +306,5 @@ int main(int argc, argv_t argv) { while (wl_display_dispatch(wl_display) >= 0); perror("wl_display_dispatch"); - cleanup_and_exit(copy_action, 1); return 1; }