summaryrefslogtreecommitdiff
path: root/src/plugins/xfer
diff options
context:
space:
mode:
authorSébastien Helleu <flashcode@flashtux.org>2019-10-05 18:11:39 +0200
committerSébastien Helleu <flashcode@flashtux.org>2019-10-05 18:11:39 +0200
commit3c0bdc18f3f99386f57be4cd8e84f99d465a0b20 (patch)
tree997f196c8f3cae2c00746e3710180aeb18f089a5 /src/plugins/xfer
parent6c23f632b12de9f43026b72626ccbc57cbbd9aa5 (diff)
downloadweechat-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.c9
-rw-r--r--src/plugins/xfer/xfer-config.h1
-rw-r--r--src/plugins/xfer/xfer-dcc.c2
-rw-r--r--src/plugins/xfer/xfer-file.c176
-rw-r--r--src/plugins/xfer/xfer-network.c8
-rw-r--r--src/plugins/xfer/xfer.c21
-rw-r--r--src/plugins/xfer/xfer.h3
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 */