Always use 64-bit filesize and file offsets in DCC.

Based on LRN's commit for replacing stat with GFileInfo https://github.com/hexchat/hexchat/commit/32008bb

Fixes #382
This commit is contained in:
Arnavion 2014-12-06 14:02:45 -08:00
parent 985ea610e6
commit 5152040c17
4 changed files with 331 additions and 192 deletions

View File

@ -23,8 +23,9 @@
* Jim Seymour (jseymour@LinxNet.com) * Jim Seymour (jseymour@LinxNet.com)
*/ */
/* we only use 32 bits, but without this define, you get only 31! */ /* Required to make lseek use off64_t, but doesn't work on Windows */
#define _FILE_OFFSET_BITS 64 #define _FILE_OFFSET_BITS 64
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
@ -45,6 +46,8 @@
#include <unistd.h> #include <unistd.h>
#endif #endif
#include <gio/gio.h>
#include "hexchat.h" #include "hexchat.h"
#include "util.h" #include "util.h"
#include "fe.h" #include "fe.h"
@ -57,13 +60,9 @@
#include "url.h" #include "url.h"
#include "hexchatc.h" #include "hexchatc.h"
#ifdef USE_DCC64 /* Setting _FILE_OFFSET_BITS to 64 doesn't change lseek to use off64_t on Windows, so override lseek to the version that does */
#define BIG_STR_TO_INT(x) strtoull(x,NULL,10)
#ifdef WIN32 #ifdef WIN32
#define stat _stat64 #define lseek _lseeki64
#endif
#else
#define BIG_STR_TO_INT(x) strtoul(x,NULL,10)
#endif #endif
static char *dcctypes[] = { "SEND", "RECV", "CHAT", "CHAT" }; static char *dcctypes[] = { "SEND", "RECV", "CHAT", "CHAT" };
@ -78,7 +77,7 @@ struct dccstat_info dccstat[] = {
}; };
static int dcc_global_throttle; /* 0x1 = sends, 0x2 = gets */ static int dcc_global_throttle; /* 0x1 = sends, 0x2 = gets */
/*static*/ int dcc_sendcpssum, dcc_getcpssum; static gint64 dcc_sendcpssum, dcc_getcpssum;
static struct DCC *new_dcc (void); static struct DCC *new_dcc (void);
static void dcc_close (struct DCC *dcc, int dccstat, int destroy); static void dcc_close (struct DCC *dcc, int dccstat, int destroy);
@ -127,11 +126,12 @@ static void
dcc_calc_cps (struct DCC *dcc) dcc_calc_cps (struct DCC *dcc)
{ {
GTimeVal now; GTimeVal now;
int oldcps; gint64 oldcps;
double timediff, startdiff; double timediff, startdiff;
int glob_throttle_bit, wasthrottled; int glob_throttle_bit, wasthrottled;
int *cpssum, glob_limit; gint64 *cpssum;
DCC_SIZE pos, posdiff; int glob_limit;
goffset pos, posdiff;
g_get_current_time (&now); g_get_current_time (&now);
@ -169,8 +169,7 @@ dcc_calc_cps (struct DCC *dcc)
posdiff = pos - dcc->lastcpspos; posdiff = pos - dcc->lastcpspos;
oldcps = dcc->cps; oldcps = dcc->cps;
dcc->cps = ((double) posdiff / timediff) * (timediff / startdiff) + dcc->cps = (gint64) ((posdiff / timediff) * (timediff / startdiff) + dcc->cps * (1.0 - (timediff / startdiff)));
(double) dcc->cps * (1.0 - (timediff / startdiff));
*cpssum += dcc->cps - oldcps; *cpssum += dcc->cps - oldcps;
} }
@ -420,7 +419,7 @@ dcc_close (struct DCC *dcc, int dccstat, int destroy)
if (dcc->proxy) if (dcc->proxy)
free (dcc->proxy); free (dcc->proxy);
if (dcc->file) if (dcc->file)
free (dcc->file); g_free (dcc->file);
if (dcc->destfile) if (dcc->destfile)
g_free (dcc->destfile); g_free (dcc->destfile);
free (dcc->nick); free (dcc->nick);
@ -700,11 +699,17 @@ dcc_read (GIOChannel *source, GIOCondition condition, struct DCC *dcc)
if (dcc->resumable) if (dcc->resumable)
{ {
dcc->fp = g_open (dcc->destfile, O_WRONLY | O_APPEND | OFLAGS, 0); gchar *filename_fs = g_filename_from_utf8(dcc->destfile, -1, NULL, NULL, NULL);
dcc->fp = g_open(dcc->destfile, O_WRONLY | O_APPEND | OFLAGS, 0);
g_free (filename_fs);
dcc->pos = dcc->resumable; dcc->pos = dcc->resumable;
dcc->ack = dcc->resumable; dcc->ack = dcc->resumable;
} else }
else
{ {
gchar *filename_fs;
if (g_access (dcc->destfile, F_OK) == 0) if (g_access (dcc->destfile, F_OK) == 0)
{ {
n = 0; n = 0;
@ -713,7 +718,7 @@ dcc_read (GIOChannel *source, GIOCondition condition, struct DCC *dcc)
n++; n++;
snprintf (buf, sizeof (buf), "%s.%d", dcc->destfile, n); snprintf (buf, sizeof (buf), "%s.%d", dcc->destfile, n);
} }
while (access (buf, F_OK) == 0); while (g_access (buf, F_OK) == 0);
old = dcc->destfile; old = dcc->destfile;
dcc->destfile = g_strdup (buf); dcc->destfile = g_strdup (buf);
@ -722,9 +727,10 @@ dcc_read (GIOChannel *source, GIOCondition condition, struct DCC *dcc)
old, dcc->destfile, NULL, NULL, 0); old, dcc->destfile, NULL, NULL, 0);
g_free (old); g_free (old);
} }
dcc->fp =
g_open (dcc->destfile, OFLAGS | O_TRUNC | O_WRONLY | O_CREAT, filename_fs = g_filename_from_utf8 (dcc->destfile, -1, NULL, NULL, NULL);
prefs.hex_dcc_permissions); dcc->fp = g_open (filename_fs, OFLAGS | O_TRUNC | O_WRONLY | O_CREAT, prefs.hex_dcc_permissions);
g_free (filename_fs);
} }
} }
if (dcc->fp == -1) if (dcc->fp == -1)
@ -792,7 +798,7 @@ dcc_read (GIOChannel *source, GIOCondition condition, struct DCC *dcc)
dcc_close (dcc, STAT_DONE, FALSE); dcc_close (dcc, STAT_DONE, FALSE);
dcc_calc_average_cps (dcc); /* this must be done _after_ dcc_close, or dcc_remove_from_sum will see the wrong value in dcc->cps */ dcc_calc_average_cps (dcc); /* this must be done _after_ dcc_close, or dcc_remove_from_sum will see the wrong value in dcc->cps */
/* cppcheck-suppress deallocuse */ /* cppcheck-suppress deallocuse */
sprintf (buf, "%d", dcc->cps); sprintf (buf, "%" G_GINT64_FORMAT, dcc->cps);
EMIT_SIGNAL (XP_TE_DCCRECVCOMP, dcc->serv->front_session, EMIT_SIGNAL (XP_TE_DCCRECVCOMP, dcc->serv->front_session,
dcc->file, dcc->destfile, dcc->nick, buf, 0); dcc->file, dcc->destfile, dcc->nick, buf, 0);
return TRUE; return TRUE;
@ -1416,8 +1422,8 @@ dcc_connect (struct DCC *dcc)
/* possible problems with filenames containing spaces? */ /* possible problems with filenames containing spaces? */
if (dcc->type == TYPE_RECV) if (dcc->type == TYPE_RECV)
snprintf (tbuf, sizeof (tbuf), strchr (dcc->file, ' ') ? snprintf (tbuf, sizeof (tbuf), strchr (dcc->file, ' ') ?
"DCC SEND \"%s\" %u %d %"DCC_SFMT" %d" : "DCC SEND \"%s\" %u %d %" G_GUINT64_FORMAT " %d" :
"DCC SEND %s %u %d %"DCC_SFMT" %d", dcc->file, "DCC SEND %s %u %d %" G_GUINT64_FORMAT " %d", dcc->file,
dcc->addr, dcc->port, dcc->size, dcc->pasvid); dcc->addr, dcc->port, dcc->size, dcc->pasvid);
else else
snprintf (tbuf, sizeof (tbuf), "DCC CHAT chat %u %d %d", snprintf (tbuf, sizeof (tbuf), "DCC CHAT chat %u %d %d",
@ -1463,7 +1469,7 @@ dcc_send_data (GIOChannel *source, GIOCondition condition, struct DCC *dcc)
if (!dcc->fastsend) if (!dcc->fastsend)
{ {
if (dcc->ack < dcc->pos) if (dcc->ack < (dcc->pos & 0xFFFFFFFF))
return TRUE; return TRUE;
} }
else if (!dcc->wiotag) else if (!dcc->wiotag)
@ -1538,7 +1544,7 @@ dcc_handle_new_ack (struct DCC *dcc)
dcc_close (dcc, STAT_DONE, FALSE); dcc_close (dcc, STAT_DONE, FALSE);
dcc_calc_average_cps (dcc); /* this must be done _after_ dcc_close, or dcc_remove_from_sum will see the wrong value in dcc->cps */ dcc_calc_average_cps (dcc); /* this must be done _after_ dcc_close, or dcc_remove_from_sum will see the wrong value in dcc->cps */
/* cppcheck-suppress deallocuse */ /* cppcheck-suppress deallocuse */
sprintf (buf, "%d", dcc->cps); sprintf (buf, "%" G_GINT64_FORMAT, dcc->cps);
EMIT_SIGNAL (XP_TE_DCCSENDCOMP, dcc->serv->front_session, EMIT_SIGNAL (XP_TE_DCCSENDCOMP, dcc->serv->front_session,
file_part (dcc->file), dcc->nick, buf, NULL, 0); file_part (dcc->file), dcc->nick, buf, NULL, 0);
done = TRUE; done = TRUE;
@ -1548,12 +1554,10 @@ dcc_handle_new_ack (struct DCC *dcc)
dcc_send_data (NULL, 0, (gpointer)dcc); dcc_send_data (NULL, 0, (gpointer)dcc);
} }
#ifdef USE_DCC64
/* take the top 32 of "bytes send" and bottom 32 of "ack" */ /* take the top 32 of "bytes send" and bottom 32 of "ack" */
dcc->ack = (dcc->pos & G_GINT64_CONSTANT (0xffffffff00000000)) | dcc->ack = (dcc->pos & G_GINT64_CONSTANT (0xffffffff00000000)) |
(dcc->ack & 0xffffffff); (dcc->ack & 0xffffffff);
/* dcc->ack is only used for CPS and PERCENTAGE calcs from now on... */ /* dcc->ack is only used for CPS and PERCENTAGE calcs from now on... */
#endif
return done; return done;
} }
@ -1762,7 +1766,7 @@ dcc_listen_init (struct DCC *dcc, session *sess)
static struct session *dccsess; static struct session *dccsess;
static char *dccto; /* lame!! */ static char *dccto; /* lame!! */
static int dccmaxcps; static gint64 dccmaxcps;
static int recursive = FALSE; static int recursive = FALSE;
static void static void
@ -1772,21 +1776,25 @@ dcc_send_wild (char *file)
} }
void void
dcc_send (struct session *sess, char *to, char *file, int maxcps, int passive) dcc_send (struct session *sess, char *to, char *filename, gint64 maxcps, int passive)
{ {
char outbuf[512]; char outbuf[512];
GStatBuf st; GFileInfo *file_info;
GFile *file;
struct DCC *dcc; struct DCC *dcc;
gchar *filename_fs;
GFileType file_type;
goffset file_size;
file = expand_homedir (file); filename = expand_homedir (filename);
if (!recursive && (strchr (file, '*') || strchr (file, '?'))) if (!recursive && (strchr (filename, '*') || strchr (filename, '?')))
{ {
char path[256]; char path[256];
char wild[256]; char wild[256];
safe_strcpy (wild, file_part (file), sizeof (wild)); safe_strcpy (wild, file_part (filename), sizeof (wild));
path_part (file, path, sizeof (path)); path_part (filename, path, sizeof (path));
if (path[0] != '/' || path[1] != '\0') if (path[0] != '/' || path[1] != '\0')
path[strlen (path) - 1] = 0; /* remove trailing slash */ path[strlen (path) - 1] = 0; /* remove trailing slash */
@ -1794,7 +1802,7 @@ dcc_send (struct session *sess, char *to, char *file, int maxcps, int passive)
dccto = to; dccto = to;
dccmaxcps = maxcps; dccmaxcps = maxcps;
free (file); g_free (filename);
recursive = TRUE; recursive = TRUE;
for_files (path, wild, dcc_send_wild); for_files (path, wild, dcc_send_wild);
@ -1806,91 +1814,123 @@ dcc_send (struct session *sess, char *to, char *file, int maxcps, int passive)
dcc = new_dcc (); dcc = new_dcc ();
if (!dcc) if (!dcc)
{ {
free (file); g_free (filename);
return; return;
} }
dcc->file = file;
dcc->file = filename;
dcc->maxcps = maxcps; dcc->maxcps = maxcps;
if (g_stat (file, &st) != -1) filename_fs = g_filename_from_utf8 (filename, -1, NULL, NULL, NULL);
if (filename_fs == NULL)
{ {
PrintTextf(sess, _("Cannot access %s\n"), dcc->file);
PrintTextf(sess, "%s %d: %s\n", _("Error"), errno, errorstring(errno));
#ifndef USE_DCC64 dcc_close(dcc, 0, TRUE); /* dcc_close will free dcc->file */
if (sizeof (st.st_size) > 4 && st.st_size > 4294967295U)
{
PrintText (sess, "Cannot send files larger than 4 GB.\n");
goto xit;
}
#endif
if (!(*file_part (file)) || S_ISDIR (st.st_mode) || st.st_size < 1) return;
{ }
PrintText (sess, "Cannot send directories or empty files.\n");
goto xit; file = g_file_new_for_path (filename_fs);
} if (file == NULL)
{
dcc->starttime = dcc->offertime = time (0); return;
dcc->serv = sess->server; }
dcc->dccstat = STAT_QUEUED;
dcc->size = st.st_size; file_info = g_file_query_info (file, G_FILE_ATTRIBUTE_STANDARD_SIZE "," G_FILE_ATTRIBUTE_STANDARD_TYPE, G_FILE_QUERY_INFO_NONE, NULL, NULL);
dcc->type = TYPE_SEND;
dcc->fp = g_open (file, OFLAGS | O_RDONLY, 0); g_object_unref (file);
if (dcc->fp != -1)
{ if (file_info == NULL)
if (passive || dcc_listen_init (dcc, sess)) {
{ PrintTextf (sess, _("Cannot access %s\n"), dcc->file);
char havespaces = 0; PrintTextf (sess, "%s %d: %s\n", _("Error"), errno, errorstring (errno));
while (*file)
{ dcc_close (dcc, 0, TRUE); /* dcc_close will free dcc->file */
if (*file == ' ')
{ return;
if (prefs.hex_dcc_send_fillspaces) }
*file = '_';
else file_type = g_file_info_get_file_type (file_info);
havespaces = 1; file_size = g_file_info_get_size (file_info);
}
file++; g_object_unref (file_info);
}
dcc->nick = strdup (to); if (*file_part (filename) == '\0' || file_type == G_FILE_TYPE_DIRECTORY || file_size <= 0)
if (prefs.hex_gui_autoopen_send) {
{ PrintText (sess, "Cannot send directories or empty files.\n");
if (fe_dcc_open_send_win (TRUE)) /* already open? add */
fe_dcc_add (dcc); dcc_close (dcc, 0, TRUE); /* dcc_close will free dcc->file */
} else
fe_dcc_add (dcc); return;
}
if (passive)
{ dcc->starttime = dcc->offertime = time (0);
dcc->pasvid = new_id(); dcc->serv = sess->server;
snprintf (outbuf, sizeof (outbuf), (havespaces) ? dcc->dccstat = STAT_QUEUED;
"DCC SEND \"%s\" 199 0 %" DCC_SFMT " %d" : dcc->size = file_size;
"DCC SEND %s 199 0 %" DCC_SFMT " %d", dcc->type = TYPE_SEND;
file_part (dcc->file), dcc->fp = g_open (filename_fs, OFLAGS | O_RDONLY, 0);
dcc->size, dcc->pasvid);
} g_free (filename_fs);
else
{ if (dcc->fp == -1)
snprintf (outbuf, sizeof (outbuf), (havespaces) ? {
"DCC SEND \"%s\" %u %d %"DCC_SFMT : PrintText (sess, "Cannot send directories or empty files.\n");
"DCC SEND %s %u %d %"DCC_SFMT,
file_part (dcc->file), dcc->addr, g_object_unref (file_info);
dcc->port, dcc->size); dcc_close (dcc, 0, TRUE); /* dcc_close will free dcc->file */
} }
sess->server->p_ctcp (sess->server, to, outbuf);
if (passive || dcc_listen_init (dcc, sess))
EMIT_SIGNAL (XP_TE_DCCOFFER, sess, file_part (dcc->file), {
to, dcc->file, NULL, 0); char havespaces = 0;
} else while (*filename)
{ {
dcc_close (dcc, 0, TRUE); if (*filename == ' ')
} {
return; if (prefs.hex_dcc_send_fillspaces)
} *filename = '_';
else
havespaces = 1;
}
filename++;
}
dcc->nick = strdup (to);
if (prefs.hex_gui_autoopen_send)
{
if (fe_dcc_open_send_win (TRUE)) /* already open? add */
fe_dcc_add (dcc);
} else
fe_dcc_add (dcc);
if (passive)
{
dcc->pasvid = new_id();
snprintf (outbuf, sizeof (outbuf), (havespaces) ?
"DCC SEND \"%s\" 199 0 %" G_GUINT64_FORMAT " %d" :
"DCC SEND %s 199 0 %" G_GUINT64_FORMAT " %d",
file_part (dcc->file),
dcc->size, dcc->pasvid);
}
else
{
snprintf (outbuf, sizeof (outbuf), (havespaces) ?
"DCC SEND \"%s\" %u %d %" G_GUINT64_FORMAT :
"DCC SEND %s %u %d %" G_GUINT64_FORMAT,
file_part (dcc->file), dcc->addr,
dcc->port, dcc->size);
}
sess->server->p_ctcp (sess->server, to, outbuf);
EMIT_SIGNAL (XP_TE_DCCOFFER, sess, file_part (dcc->file),
to, dcc->file, NULL, 0);
}
else
{
dcc_close (dcc, 0, TRUE);
} }
PrintTextf (sess, _("Cannot access %s\n"), dcc->file);
PrintTextf (sess, "%s %d: %s\n", _("Error"), errno, errorstring (errno));
xit:
dcc_close (dcc, 0, TRUE); /* dcc_close will free dcc->file */
} }
static struct DCC * static struct DCC *
@ -1976,68 +2016,175 @@ dcc_change_nick (struct server *serv, char *oldnick, char *newnick)
/* is the destination file the same? new_dcc is not opened yet */ /* is the destination file the same? new_dcc is not opened yet */
static int static gboolean
is_same_file (struct DCC *dcc, struct DCC *new_dcc) is_same_file (struct DCC *dcc, struct DCC *new_dcc)
{ {
#ifndef WIN32 gboolean result = FALSE;
GStatBuf st_a, st_b; gchar *filename_fs = NULL, *new_filename_fs = NULL;
#endif GFile *file = NULL, *new_file = NULL;
GFileInfo *file_info = NULL, *new_file_info = NULL;
char *file_id = NULL, *new_file_id = NULL;
char *filesystem_id = NULL, *new_filesystem_id = NULL;
/* if it's the same filename, must be same */ /* if it's the same filename, must be same */
if (strcmp (dcc->destfile, new_dcc->destfile) == 0) if (strcmp (dcc->destfile, new_dcc->destfile) == 0)
{
return TRUE; return TRUE;
}
/* now handle case-insensitive Filesystems: HFS+, FAT */ filename_fs = g_filename_from_utf8 (dcc->file, -1, NULL, NULL, NULL);
#ifdef WIN32 if (filename_fs == NULL)
/* warning no win32 implementation - behaviour may be unreliable */ {
#else goto exit;
/* this fstat() shouldn't really fail */ }
if ((dcc->fp == -1 ? g_stat (dcc->destfile, &st_a) : fstat (dcc->fp, &st_a)) == -1)
return FALSE;
if (g_stat (new_dcc->destfile, &st_b) == -1)
return FALSE;
/* same inode, same device, same file! */ new_filename_fs = g_filename_from_utf8 (new_dcc->file, -1, NULL, NULL, NULL);
if (st_a.st_ino == st_b.st_ino && if (new_filename_fs == NULL)
st_a.st_dev == st_b.st_dev) {
return TRUE; goto exit;
#endif }
return FALSE; file = g_file_new_for_path (filename_fs);
if (file == NULL)
{
goto exit;
}
new_file = g_file_new_for_path (new_filename_fs);
if (new_file == NULL)
{
goto exit;
}
file_info = g_file_query_info (file, G_FILE_ATTRIBUTE_ID_FILE "," G_FILE_ATTRIBUTE_ID_FILESYSTEM, G_FILE_QUERY_INFO_NONE, NULL, NULL);
if (file_info == NULL)
{
goto exit;
}
new_file_info = g_file_query_info (new_file, G_FILE_ATTRIBUTE_ID_FILE "," G_FILE_ATTRIBUTE_ID_FILESYSTEM, G_FILE_QUERY_INFO_NONE, NULL, NULL);
if (file_info == NULL)
{
goto exit;
}
file_id = g_file_info_get_attribute_as_string (file_info, G_FILE_ATTRIBUTE_ID_FILE);
new_file_id = g_file_info_get_attribute_as_string (new_file_info, G_FILE_ATTRIBUTE_ID_FILE);
filesystem_id = g_file_info_get_attribute_as_string (file_info, G_FILE_ATTRIBUTE_ID_FILE);
new_filesystem_id = g_file_info_get_attribute_as_string (new_file_info, G_FILE_ATTRIBUTE_ID_FILE);
if (file_id != NULL && new_file_id != NULL && filesystem_id != NULL && new_filesystem_id != NULL && strcmp (file_id, new_file_id) == 0 && strcmp (filesystem_id, new_filesystem_id) == 0)
{
result = TRUE;
}
exit:
if (filename_fs != NULL)
{
g_free (filename_fs);
}
if (new_filename_fs != NULL)
{
g_free (new_filename_fs);
}
if (file != NULL)
{
g_object_unref (file);
}
if (new_file != NULL)
{
g_object_unref (new_file);
}
if (file_info != NULL)
{
g_object_unref (file_info);
}
if (new_file_info != NULL)
{
g_object_unref (new_file_info);
}
if (file_id != NULL)
{
g_free (file_id);
}
if (new_file_id != NULL)
{
g_free (new_file_id);
}
if (filesystem_id != NULL)
{
g_free(filesystem_id);
}
if (new_filesystem_id != NULL)
{
g_free(new_filesystem_id);
}
return result;
} }
static int static void
is_resumable (struct DCC *dcc) update_is_resumable (struct DCC *dcc)
{ {
gchar *filename_fs = g_filename_from_utf8 (dcc->destfile, -1, NULL, NULL, NULL);
dcc->resumable = 0; dcc->resumable = 0;
/* Check the file size */ /* Check the file size */
if (g_access (dcc->destfile, W_OK) == 0) if (filename_fs != NULL && g_access(filename_fs, W_OK) == 0)
{ {
GStatBuf st; GFile *file = g_file_new_for_path (filename_fs);
if (file != NULL)
if (g_stat (dcc->destfile, &st) != -1)
{ {
if (st.st_size < dcc->size) GFileInfo *file_info = g_file_query_info (file, G_FILE_ATTRIBUTE_STANDARD_SIZE "," G_FILE_ATTRIBUTE_STANDARD_TYPE, G_FILE_QUERY_INFO_NONE, NULL, NULL);
if (file_info != NULL)
{ {
dcc->resumable = st.st_size; goffset file_size_offset = g_file_info_get_size (file_info);
dcc->pos = st.st_size; guint64 file_size = (file_size_offset >= 0) ? (guint64) file_size_offset : 0;
if (file_size < dcc->size)
{
dcc->resumable = file_size;
dcc->pos = file_size;
}
else
{
dcc->resume_error = 2;
}
g_object_unref (file_info);
} }
else else
dcc->resume_error = 2; {
} else dcc->resume_errno = errno;
dcc->resume_error = 1;
}
g_object_unref(file);
}
else
{ {
dcc->resume_errno = errno; dcc->resume_errno = errno;
dcc->resume_error = 1; dcc->resume_error = 1;
} }
} else }
else
{ {
dcc->resume_errno = errno; dcc->resume_errno = errno;
dcc->resume_error = 1; dcc->resume_error = 1;
} }
/* Now verify that this DCC is not already in progress from someone else */ /* Now verify that this DCC is not already in progress from someone else */
if (dcc->resumable) if (dcc->resumable)
{ {
GSList *list = dcc_list; GSList *list = dcc_list;
@ -2059,8 +2206,6 @@ is_resumable (struct DCC *dcc)
list = list->next; list = list->next;
} }
} }
return dcc->resumable;
} }
void void
@ -2100,7 +2245,7 @@ dcc_get_with_destfile (struct DCC *dcc, char *file)
dcc->destfile = g_strdup (file); /* utf-8 */ dcc->destfile = g_strdup (file); /* utf-8 */
/* since destfile changed, must check resumability again */ /* since destfile changed, must check resumability again */
is_resumable (dcc); update_is_resumable (dcc);
dcc_get (dcc); dcc_get (dcc);
} }
@ -2133,14 +2278,13 @@ dcc_get_nick (struct session *sess, char *nick)
static struct DCC * static struct DCC *
new_dcc (void) new_dcc (void)
{ {
struct DCC *dcc = malloc (sizeof (struct DCC)); struct DCC *dcc = calloc (1, sizeof (struct DCC));
if (!dcc) if (!dcc)
return 0; return 0;
memset (dcc, 0, sizeof (struct DCC));
dcc->sok = -1; dcc->sok = -1;
dcc->fp = -1; dcc->fp = -1;
dcc_list = g_slist_prepend (dcc_list, dcc); dcc_list = g_slist_prepend (dcc_list, dcc);
return (dcc); return dcc;
} }
void void
@ -2231,8 +2375,8 @@ dcc_resume (struct DCC *dcc)
dcc->resume_sent = 1; dcc->resume_sent = 1;
/* filename contains spaces? Quote them! */ /* filename contains spaces? Quote them! */
snprintf (tbuf, sizeof (tbuf) - 10, strchr (dcc->file, ' ') ? snprintf (tbuf, sizeof (tbuf) - 10, strchr (dcc->file, ' ') ?
"DCC RESUME \"%s\" %d %"DCC_SFMT : "DCC RESUME \"%s\" %d %" G_GUINT64_FORMAT :
"DCC RESUME %s %d %"DCC_SFMT, "DCC RESUME %s %d %" G_GUINT64_FORMAT,
dcc->file, dcc->port, dcc->resumable); dcc->file, dcc->port, dcc->resumable);
if (dcc->pasvid) if (dcc->pasvid)
@ -2316,7 +2460,7 @@ dcc_add_chat (session *sess, char *nick, int port, guint32 addr, int pasvid)
} }
static struct DCC * static struct DCC *
dcc_add_file (session *sess, char *file, DCC_SIZE size, int port, char *nick, guint32 addr, int pasvid) dcc_add_file (session *sess, char *file, guint64 size, int port, char *nick, guint32 addr, int pasvid)
{ {
struct DCC *dcc; struct DCC *dcc;
char tbuf[512]; char tbuf[512];
@ -2324,7 +2468,7 @@ dcc_add_file (session *sess, char *file, DCC_SIZE size, int port, char *nick, gu
dcc = new_dcc (); dcc = new_dcc ();
if (dcc) if (dcc)
{ {
dcc->file = strdup (file); dcc->file = g_strdup (file);
dcc->destfile = g_malloc (strlen (prefs.hex_dcc_dir) + strlen (nick) + dcc->destfile = g_malloc (strlen (prefs.hex_dcc_dir) + strlen (nick) +
strlen (file) + 4); strlen (file) + 4);
@ -2362,7 +2506,7 @@ dcc_add_file (session *sess, char *file, DCC_SIZE size, int port, char *nick, gu
dcc->nick = strdup (nick); dcc->nick = strdup (nick);
dcc->maxcps = prefs.hex_dcc_max_get_cps; dcc->maxcps = prefs.hex_dcc_max_get_cps;
is_resumable (dcc); update_is_resumable (dcc);
if (prefs.hex_dcc_auto_recv == 1) if (prefs.hex_dcc_auto_recv == 1)
{ {
@ -2380,7 +2524,7 @@ dcc_add_file (session *sess, char *file, DCC_SIZE size, int port, char *nick, gu
} else } else
fe_dcc_add (dcc); fe_dcc_add (dcc);
} }
sprintf (tbuf, "%"DCC_SFMT, size); sprintf (tbuf, "%" G_GUINT64_FORMAT, size);
snprintf (tbuf + 24, 300, "%s:%d", net_ip (addr), port); snprintf (tbuf + 24, 300, "%s:%d", net_ip (addr), port);
EMIT_SIGNAL (XP_TE_DCCSENDOFFER, sess->server->front_session, nick, EMIT_SIGNAL (XP_TE_DCCSENDOFFER, sess->server->front_session, nick,
file, tbuf, tbuf + 24, 0); file, tbuf, tbuf + 24, 0);
@ -2397,7 +2541,7 @@ handle_dcc (struct session *sess, char *nick, char *word[], char *word_eol[],
char *type = word[5]; char *type = word[5];
int port, pasvid = 0; int port, pasvid = 0;
guint32 addr; guint32 addr;
DCC_SIZE size; guint64 size;
int psend = 0; int psend = 0;
if (!g_ascii_strcasecmp (type, "CHAT")) if (!g_ascii_strcasecmp (type, "CHAT"))
@ -2463,7 +2607,7 @@ handle_dcc (struct session *sess, char *nick, char *word[], char *word_eol[],
dcc = find_dcc (nick, word[6], TYPE_SEND); dcc = find_dcc (nick, word[6], TYPE_SEND);
if (dcc) if (dcc)
{ {
size = BIG_STR_TO_INT (word[8]); size = g_ascii_strtoull (word[8], NULL, 10);
dcc->resumable = size; dcc->resumable = size;
if (dcc->resumable < dcc->size) if (dcc->resumable < dcc->size)
{ {
@ -2474,18 +2618,18 @@ handle_dcc (struct session *sess, char *nick, char *word[], char *word_eol[],
/* Checking if dcc is passive and if filename contains spaces */ /* Checking if dcc is passive and if filename contains spaces */
if (dcc->pasvid) if (dcc->pasvid)
snprintf (tbuf, sizeof (tbuf), strchr (file_part (dcc->file), ' ') ? snprintf (tbuf, sizeof (tbuf), strchr (file_part (dcc->file), ' ') ?
"DCC ACCEPT \"%s\" %d %"DCC_SFMT" %d" : "DCC ACCEPT \"%s\" %d %" G_GUINT64_FORMAT " %d" :
"DCC ACCEPT %s %d %"DCC_SFMT" %d", "DCC ACCEPT %s %d %" G_GUINT64_FORMAT " %d",
file_part (dcc->file), port, dcc->resumable, dcc->pasvid); file_part (dcc->file), port, dcc->resumable, dcc->pasvid);
else else
snprintf (tbuf, sizeof (tbuf), strchr (file_part (dcc->file), ' ') ? snprintf (tbuf, sizeof (tbuf), strchr (file_part (dcc->file), ' ') ?
"DCC ACCEPT \"%s\" %d %"DCC_SFMT : "DCC ACCEPT \"%s\" %d %" G_GUINT64_FORMAT :
"DCC ACCEPT %s %d %"DCC_SFMT, "DCC ACCEPT %s %d %" G_GUINT64_FORMAT,
file_part (dcc->file), port, dcc->resumable); file_part (dcc->file), port, dcc->resumable);
dcc->serv->p_ctcp (dcc->serv, dcc->nick, tbuf); dcc->serv->p_ctcp (dcc->serv, dcc->nick, tbuf);
} }
sprintf (tbuf, "%"DCC_SFMT, dcc->pos); sprintf (tbuf, "%" G_GUINT64_FORMAT, dcc->pos);
EMIT_SIGNAL_TIMESTAMP (XP_TE_DCCRESUMEREQUEST, sess, nick, EMIT_SIGNAL_TIMESTAMP (XP_TE_DCCRESUMEREQUEST, sess, nick,
file_part (dcc->file), tbuf, NULL, 0, file_part (dcc->file), tbuf, NULL, 0,
tags_data->timestamp); tags_data->timestamp);
@ -2508,7 +2652,7 @@ handle_dcc (struct session *sess, char *nick, char *word[], char *word_eol[],
port = atoi (word[8]); port = atoi (word[8]);
addr = strtoul (word[7], NULL, 10); addr = strtoul (word[7], NULL, 10);
size = BIG_STR_TO_INT (word[9]); size = g_ascii_strtoull (word[9], NULL, 10);
if (port == 0) /* Passive dcc requested */ if (port == 0) /* Passive dcc requested */
pasvid = atoi (word[10]); pasvid = atoi (word[10]);
@ -2576,7 +2720,7 @@ dcc_show_list (struct session *sess)
{ {
dcc = (struct DCC *) list->data; dcc = (struct DCC *) list->data;
i++; i++;
PrintTextf (sess, " %s %-10.10s %-7.7s %-7"DCC_SFMT" %-7"DCC_SFMT" %s\n", PrintTextf (sess, " %s %-10.10s %-7.7s %-7" G_GUINT64_FORMAT " %-7" G_GUINT64_FORMAT " %s\n",
dcctypes[dcc->type], dcc->nick, dcctypes[dcc->type], dcc->nick,
_(dccstat[dcc->dccstat].name), dcc->size, dcc->pos, _(dccstat[dcc->dccstat].name), dcc->size, dcc->pos,
file_part (dcc->file)); file_part (dcc->file));

View File

@ -39,17 +39,6 @@
#define CPS_AVG_WINDOW 10 #define CPS_AVG_WINDOW 10
/* can we do 64-bit dcc? */
#if defined(G_GINT64_FORMAT) && defined(HAVE_STRTOULL)
#define USE_DCC64
/* we really get only 63 bits, since st_size is signed */
#define DCC_SIZE gint64
#define DCC_SFMT G_GINT64_FORMAT
#else
#define DCC_SIZE unsigned int
#define DCC_SFMT "u"
#endif
struct DCC struct DCC
{ {
struct server *serv; struct server *serv;
@ -62,21 +51,21 @@ struct DCC
int wiotag; /* writing/sending io tag */ int wiotag; /* writing/sending io tag */
int port; int port;
int pasvid; /* mIRC's passive DCC id */ int pasvid; /* mIRC's passive DCC id */
int cps; gint64 cps;
int resume_error; int resume_error;
int resume_errno; int resume_errno;
GTimeVal lastcpstv, firstcpstv; GTimeVal lastcpstv, firstcpstv;
DCC_SIZE lastcpspos; goffset lastcpspos;
int maxcps; gint64 maxcps;
unsigned char ack_buf[4]; /* buffer for reading 4-byte ack */ unsigned char ack_buf[4]; /* buffer for reading 4-byte ack */
int ack_pos; int ack_pos;
DCC_SIZE size; guint64 size;
DCC_SIZE resumable; guint64 resumable;
DCC_SIZE ack; guint64 ack;
DCC_SIZE pos; guint64 pos;
time_t starttime; time_t starttime;
time_t offertime; time_t offertime;
time_t lasttime; time_t lasttime;
@ -125,7 +114,7 @@ void dcc_check_timeouts (void);
void dcc_change_nick (server *serv, char *oldnick, char *newnick); void dcc_change_nick (server *serv, char *oldnick, char *newnick);
void dcc_notify_kill (struct server *serv); void dcc_notify_kill (struct server *serv);
struct DCC *dcc_write_chat (char *nick, char *text); struct DCC *dcc_write_chat (char *nick, char *text);
void dcc_send (struct session *sess, char *to, char *file, int maxcps, int passive); void dcc_send (struct session *sess, char *to, char *file, gint64 maxcps, int passive);
struct DCC *find_dcc (char *nick, char *file, int type); struct DCC *find_dcc (char *nick, char *file, int type);
void dcc_get_nick (struct session *sess, char *nick); void dcc_get_nick (struct session *sess, char *nick);
void dcc_chat (session *sess, char *nick, int passive); void dcc_chat (session *sess, char *nick, int passive);

View File

@ -1531,7 +1531,14 @@ hexchat_list_int (hexchat_plugin *ph, hexchat_list *xlist, const char *name)
case 0x34207553: /* address32 */ case 0x34207553: /* address32 */
return ((struct DCC *)data)->addr; return ((struct DCC *)data)->addr;
case 0x181a6: /* cps */ case 0x181a6: /* cps */
return ((struct DCC *)data)->cps; {
gint64 cps = ((struct DCC *)data)->cps;
if (cps <= INT_MAX)
{
return (int) cps;
}
return INT_MAX;
}
case 0x349881: /* port */ case 0x349881: /* port */
return ((struct DCC *)data)->port; return ((struct DCC *)data)->port;
case 0x1b254: /* pos */ case 0x1b254: /* pos */

View File

@ -88,7 +88,7 @@ struct my_dcc_send
{ {
struct session *sess; struct session *sess;
char *nick; char *nick;
int maxcps; gint64 maxcps;
int passive; int passive;
}; };
@ -105,7 +105,7 @@ static short view_mode; /* 1=download 2=upload 3=both */
static void static void
proper_unit (DCC_SIZE size, char *buf, int buf_len) proper_unit (guint64 size, char *buf, size_t buf_len)
{ {
gchar *formatted_str; gchar *formatted_str;
GFormatSizeFlags format_flags = G_FORMAT_SIZE_DEFAULT; GFormatSizeFlags format_flags = G_FORMAT_SIZE_DEFAULT;
@ -117,7 +117,7 @@ proper_unit (DCC_SIZE size, char *buf, int buf_len)
format_flags = G_FORMAT_SIZE_IEC_UNITS; format_flags = G_FORMAT_SIZE_IEC_UNITS;
#endif #endif
formatted_str = g_format_size_full ((guint64)size, format_flags); formatted_str = g_format_size_full (size, format_flags);
g_strlcpy (buf, formatted_str, buf_len); g_strlcpy (buf, formatted_str, buf_len);
g_free (formatted_str); g_free (formatted_str);
@ -155,20 +155,20 @@ static void
dcc_prepare_row_chat (struct DCC *dcc, GtkListStore *store, GtkTreeIter *iter, dcc_prepare_row_chat (struct DCC *dcc, GtkListStore *store, GtkTreeIter *iter,
gboolean update_only) gboolean update_only)
{ {
static char pos[16], siz[16]; static char pos[16], size[16];
char *date; char *date;
date = ctime (&dcc->starttime); date = ctime (&dcc->starttime);
date[strlen (date) - 1] = 0; /* remove the \n */ date[strlen (date) - 1] = 0; /* remove the \n */
proper_unit (dcc->pos, pos, sizeof (pos)); proper_unit (dcc->pos, pos, sizeof (pos));
proper_unit (dcc->size, siz, sizeof (siz)); proper_unit (dcc->size, size, sizeof (size));
gtk_list_store_set (store, iter, gtk_list_store_set (store, iter,
CCOL_STATUS, _(dccstat[dcc->dccstat].name), CCOL_STATUS, _(dccstat[dcc->dccstat].name),
CCOL_NICK, dcc->nick, CCOL_NICK, dcc->nick,
CCOL_RECV, pos, CCOL_RECV, pos,
CCOL_SENT, siz, CCOL_SENT, size,
CCOL_START, date, CCOL_START, date,
CCOL_DCC, dcc, CCOL_DCC, dcc,
CCOL_COLOR, CCOL_COLOR,
@ -195,7 +195,6 @@ dcc_prepare_row_send (struct DCC *dcc, GtkListStore *store, GtkTreeIter *iter,
proper_unit (dcc->size, size, sizeof (size)); proper_unit (dcc->size, size, sizeof (size));
proper_unit (dcc->pos, pos, sizeof (pos)); proper_unit (dcc->pos, pos, sizeof (pos));
snprintf (kbs, sizeof (kbs), "%.1f", ((float)dcc->cps) / 1024); snprintf (kbs, sizeof (kbs), "%.1f", ((float)dcc->cps) / 1024);
/* proper_unit (dcc->ack, ack, sizeof (ack));*/
snprintf (perc, sizeof (perc), "%.0f%%", per); snprintf (perc, sizeof (perc), "%.0f%%", per);
if (dcc->cps != 0) if (dcc->cps != 0)
{ {