mirror of
https://github.com/weechat/weechat.git
synced 2026-07-04 08:43:13 +02:00
xfer: add option xfer.file.download_temporary_suffix with default value ".part" (closes #1237)
This commit is contained in:
@@ -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",
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
+131
-45
@@ -70,6 +70,135 @@ xfer_file_resume (struct t_xfer *xfer, const char *filename)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* 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.
|
||||
*
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
@@ -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 ())
|
||||
{
|
||||
|
||||
+18
-3
@@ -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);
|
||||
|
||||
@@ -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 */
|
||||
|
||||
Reference in New Issue
Block a user