diff options
author | Sébastien Helleu <flashcode@flashtux.org> | 2019-10-05 18:11:39 +0200 |
---|---|---|
committer | Sébastien Helleu <flashcode@flashtux.org> | 2019-10-05 18:11:39 +0200 |
commit | 3c0bdc18f3f99386f57be4cd8e84f99d465a0b20 (patch) | |
tree | 997f196c8f3cae2c00746e3710180aeb18f089a5 /src/plugins/xfer | |
parent | 6c23f632b12de9f43026b72626ccbc57cbbd9aa5 (diff) | |
download | weechat-3c0bdc18f3f99386f57be4cd8e84f99d465a0b20.zip |
xfer: add option xfer.file.download_temporary_suffix with default value ".part" (closes #1237)
Diffstat (limited to 'src/plugins/xfer')
-rw-r--r-- | src/plugins/xfer/xfer-config.c | 9 | ||||
-rw-r--r-- | src/plugins/xfer/xfer-config.h | 1 | ||||
-rw-r--r-- | src/plugins/xfer/xfer-dcc.c | 2 | ||||
-rw-r--r-- | src/plugins/xfer/xfer-file.c | 176 | ||||
-rw-r--r-- | src/plugins/xfer/xfer-network.c | 8 | ||||
-rw-r--r-- | src/plugins/xfer/xfer.c | 21 | ||||
-rw-r--r-- | src/plugins/xfer/xfer.h | 3 |
7 files changed, 169 insertions, 51 deletions
diff --git a/src/plugins/xfer/xfer-config.c b/src/plugins/xfer/xfer-config.c index ddab21d82..f36fb2d46 100644 --- a/src/plugins/xfer/xfer-config.c +++ b/src/plugins/xfer/xfer-config.c @@ -64,6 +64,7 @@ struct t_config_option *xfer_config_file_auto_rename; struct t_config_option *xfer_config_file_auto_resume; struct t_config_option *xfer_config_file_convert_spaces; struct t_config_option *xfer_config_file_download_path; +struct t_config_option *xfer_config_file_download_temporary_suffix; struct t_config_option *xfer_config_file_upload_path; struct t_config_option *xfer_config_file_use_nick_in_filename; @@ -385,6 +386,14 @@ xfer_config_init () "(note: content is evaluated, see /help eval)"), NULL, 0, 0, "%h/xfer", NULL, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL); + xfer_config_file_download_temporary_suffix = weechat_config_new_option ( + xfer_config_file, ptr_section, + "download_temporary_suffix", "string", + N_("temporary filename suffix used during the transfer for a file " + "received, it is removed after successful transfer; " + "if empty string, no filename suffix is used during the transfer"), + NULL, 0, 0, ".part", NULL, 0, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL); xfer_config_file_upload_path = weechat_config_new_option ( xfer_config_file, ptr_section, "upload_path", "string", diff --git a/src/plugins/xfer/xfer-config.h b/src/plugins/xfer/xfer-config.h index 2a31f0408..edda24985 100644 --- a/src/plugins/xfer/xfer-config.h +++ b/src/plugins/xfer/xfer-config.h @@ -52,6 +52,7 @@ extern struct t_config_option *xfer_config_file_auto_resume; extern struct t_config_option *xfer_config_file_auto_check_crc32; extern struct t_config_option *xfer_config_file_convert_spaces; extern struct t_config_option *xfer_config_file_download_path; +extern struct t_config_option *xfer_config_file_download_temporary_suffix; extern struct t_config_option *xfer_config_file_upload_path; extern struct t_config_option *xfer_config_file_use_nick_in_filename; diff --git a/src/plugins/xfer/xfer-dcc.c b/src/plugins/xfer/xfer-dcc.c index 13306c96d..593235d6a 100644 --- a/src/plugins/xfer/xfer-dcc.c +++ b/src/plugins/xfer/xfer-dcc.c @@ -255,7 +255,7 @@ xfer_dcc_resume_hash (struct t_xfer *xfer) while (fd <= 0) { - fd = open (xfer->local_filename, O_RDONLY); + fd = open (xfer->temp_local_filename, O_RDONLY); if (fd < 0) { if (errno == EINTR) diff --git a/src/plugins/xfer/xfer-file.c b/src/plugins/xfer/xfer-file.c index ebed633f9..e9b7b0f26 100644 --- a/src/plugins/xfer/xfer-file.c +++ b/src/plugins/xfer/xfer-file.c @@ -71,6 +71,135 @@ xfer_file_resume (struct t_xfer *xfer, const char *filename) } /* + * Checks if file can be downloaded with a given suffix index (if 0 the + * filename is unchanged, otherwise .1, .2, etc. are added to the filename). + * + * Returns 1 if the file can be downloaded with this suffix, 0 if it can not. + */ + +int +xfer_file_check_suffix (struct t_xfer *xfer, int suffix) +{ + char *new_filename, *new_temp_filename; + const char *ptr_suffix; + int rc, length_suffix, length, filename_exists, temp_filename_exists; + int same_files; + + rc = 0; + new_filename = NULL; + new_temp_filename = NULL; + + ptr_suffix = weechat_config_string ( + xfer_config_file_download_temporary_suffix); + length_suffix = (ptr_suffix) ? strlen (ptr_suffix) : 0; + + /* build filename with suffix */ + if (suffix == 0) + { + new_filename = strdup (xfer->local_filename); + } + else + { + length = strlen (xfer->local_filename) + 16 + 1; + new_filename = malloc (length); + if (new_filename) + { + snprintf (new_filename, length, "%s.%d", + xfer->local_filename, + suffix); + } + } + if (!new_filename) + goto error; + + /* build temp filename with suffix */ + length = strlen (new_filename) + length_suffix + 1; + new_temp_filename = malloc (length); + if (!new_temp_filename) + goto error; + snprintf (new_temp_filename, length, + "%s%s", + new_filename, + (ptr_suffix) ? ptr_suffix : ""); + + filename_exists = (access (new_filename, F_OK) == 0); + temp_filename_exists = (access (new_temp_filename, F_OK) == 0); + same_files = (length_suffix == 0); + + /* if both filenames don't exist, we can use this prefix */ + if (!filename_exists && !temp_filename_exists) + goto use_prefix; + + /* + * we try to resume if one of this condition is true: + * - filename == temp filename and it exists + * - filename != temp filename and only the temp filename exists + * in any other case, we skip this suffix index + */ + + if ((same_files && filename_exists) + || (!same_files && !filename_exists && temp_filename_exists)) + { + if (xfer_file_resume (xfer, new_temp_filename)) + goto use_prefix; + } + + /* we skip this suffix index */ + goto end; + +use_prefix: + free (xfer->local_filename); + xfer->local_filename = new_filename; + xfer->temp_local_filename = new_temp_filename; + return 1; + +error: + /* + * in case of error, we remove the local filename and return 1 to stop the + * infinite loop used to find a suffix index + */ + free (xfer->local_filename); + xfer->local_filename = NULL; + rc = 1; + +end: + if (new_filename) + free (new_filename); + if (new_temp_filename) + free (new_temp_filename); + return rc; +} + +/* + * Finds the suffix needed for a file, if the file already exists. + * + * If no suffix is needed, nothing is changed in the xfer. + * If a suffix is needed, temp_local_filename and local_filename are changed + * and filename_suffix is set with the suffix number (starts to 1). + */ + +void +xfer_file_find_suffix (struct t_xfer *xfer) +{ + if (xfer_file_check_suffix (xfer, 0)) + return; + + /* if auto rename is not set, then abort xfer */ + if (!xfer_config_file_auto_rename) + { + xfer_close (xfer, XFER_STATUS_FAILED); + xfer_buffer_refresh (WEECHAT_HOTLIST_MESSAGE); + return; + } + + /* loop until we find a suffix we can use, starting with suffix == 1 */ + xfer->filename_suffix = 0; + while (!xfer_file_check_suffix (xfer, ++xfer->filename_suffix)) + { + } +} + +/* * Searches for local filename for a xfer. * * If type is file/recv, adds a suffix (like .1) if needed. @@ -80,8 +209,7 @@ xfer_file_resume (struct t_xfer *xfer, const char *filename) void xfer_file_find_filename (struct t_xfer *xfer) { - char *dir_separator, *path, *filename2; - int length; + char *dir_separator, *path; if (!XFER_IS_FILE(xfer->type)) return; @@ -119,49 +247,7 @@ xfer_file_find_filename (struct t_xfer *xfer) free (path); - /* file already exists? */ - if (access (xfer->local_filename, F_OK) == 0) - { - if (xfer_file_resume (xfer, xfer->local_filename)) - return; - - /* if auto rename is not set, then abort xfer */ - if (!xfer_config_file_auto_rename) - { - xfer_close (xfer, XFER_STATUS_FAILED); - xfer_buffer_refresh (WEECHAT_HOTLIST_MESSAGE); - return; - } - - length = strlen (xfer->local_filename) + 16; - filename2 = malloc (length); - if (!filename2) - { - xfer_close (xfer, XFER_STATUS_FAILED); - xfer_buffer_refresh (WEECHAT_HOTLIST_MESSAGE); - return; - } - xfer->filename_suffix = 0; - do - { - xfer->filename_suffix++; - snprintf (filename2, length, "%s.%d", - xfer->local_filename, - xfer->filename_suffix); - if (access (filename2, F_OK) == 0) - { - if (xfer_file_resume (xfer, filename2)) - break; - } - else - break; - } - while (1); - - free (xfer->local_filename); - xfer->local_filename = strdup (filename2); - free (filename2); - } + xfer_file_find_suffix (xfer); } /* diff --git a/src/plugins/xfer/xfer-network.c b/src/plugins/xfer/xfer-network.c index ac23ac619..c19f0cd1a 100644 --- a/src/plugins/xfer/xfer-network.c +++ b/src/plugins/xfer/xfer-network.c @@ -290,12 +290,16 @@ xfer_network_recv_file_fork (struct t_xfer *xfer) return; if (xfer->start_resume > 0) - xfer->file = open (xfer->local_filename, + { + xfer->file = open (xfer->temp_local_filename, O_APPEND | O_WRONLY | O_NONBLOCK); + } else - xfer->file = open (xfer->local_filename, + { + xfer->file = open (xfer->temp_local_filename, O_CREAT | O_TRUNC | O_WRONLY | O_NONBLOCK, 0644); + } switch (pid = fork ()) { diff --git a/src/plugins/xfer/xfer.c b/src/plugins/xfer/xfer.c index 680806318..1ab27ea90 100644 --- a/src/plugins/xfer/xfer.c +++ b/src/plugins/xfer/xfer.c @@ -346,17 +346,26 @@ xfer_close (struct t_xfer *xfer, enum t_xfer_status status) || (xfer->status == XFER_STATUS_ABORTED)) && XFER_IS_FILE(xfer->type) && XFER_IS_RECV(xfer->type) - && xfer->local_filename + && xfer->temp_local_filename && xfer->pos == 0) { /* erase file only if really empty on disk */ - if (stat (xfer->local_filename, &st) != -1) + if (stat (xfer->temp_local_filename, &st) != -1) { if ((unsigned long long) st.st_size == 0) - unlink (xfer->local_filename); + unlink (xfer->temp_local_filename); } } + /* rename received file if it has a suffix */ + if ((xfer->status == XFER_STATUS_DONE) + && XFER_IS_FILE(xfer->type) + && XFER_IS_RECV(xfer->type) + && (strcmp (xfer->local_filename, xfer->temp_local_filename) != 0)) + { + rename (xfer->temp_local_filename, xfer->local_filename); + } + if (XFER_IS_FILE(xfer->type)) xfer_file_calculate_speed (xfer, 1); @@ -500,6 +509,7 @@ xfer_alloc () new_xfer->unterminated_message = NULL; new_xfer->file = -1; new_xfer->local_filename = NULL; + new_xfer->temp_local_filename = NULL; new_xfer->filename_suffix = -1; new_xfer->pos = 0; new_xfer->ack = 0; @@ -955,6 +965,8 @@ xfer_free (struct t_xfer *xfer) free (xfer->unterminated_message); if (xfer->local_filename) free (xfer->local_filename); + if (xfer->temp_local_filename) + free (xfer->temp_local_filename); if (xfer->hash_handle) { gcry_md_close (*xfer->hash_handle); @@ -1688,6 +1700,8 @@ xfer_add_to_infolist (struct t_infolist *infolist, struct t_xfer *xfer) return 0; if (!weechat_infolist_new_var_string (ptr_item, "local_filename", xfer->local_filename)) return 0; + if (!weechat_infolist_new_var_string (ptr_item, "temp_local_filename", xfer->temp_local_filename)) + return 0; if (!weechat_infolist_new_var_integer (ptr_item, "filename_suffix", xfer->filename_suffix)) return 0; snprintf (value, sizeof (value), "%llu", xfer->pos); @@ -1776,6 +1790,7 @@ xfer_print_log () weechat_log_printf (" unterminated_message. . : '%s'", ptr_xfer->unterminated_message); weechat_log_printf (" file. . . . . . . . . . : %d", ptr_xfer->file); weechat_log_printf (" local_filename. . . . . : '%s'", ptr_xfer->local_filename); + weechat_log_printf (" temp_local_filename . . : '%s'", ptr_xfer->temp_local_filename); weechat_log_printf (" filename_suffix . . . . : %d", ptr_xfer->filename_suffix); weechat_log_printf (" pos . . . . . . . . . . : %llu", ptr_xfer->pos); weechat_log_printf (" ack . . . . . . . . . . : %llu", ptr_xfer->ack); diff --git a/src/plugins/xfer/xfer.h b/src/plugins/xfer/xfer.h index 263b885ff..ce984c458 100644 --- a/src/plugins/xfer/xfer.h +++ b/src/plugins/xfer/xfer.h @@ -170,6 +170,9 @@ struct t_xfer char *unterminated_message; /* beginning of a message */ int file; /* local file (read or write) */ char *local_filename; /* local filename (with path) */ + char *temp_local_filename; /* local filename filename with */ + /* temp. suffix (during transfer, */ + /* for receive file only) */ int filename_suffix; /* suffix (like .1) if renaming file */ unsigned long long pos; /* number of bytes received/sent */ unsigned long long ack; /* number of bytes received OK */ |