From 5152040c17eef73134b5417d3f8ae53d7bc9f06d Mon Sep 17 00:00:00 2001 From: Arnavion Date: Sat, 6 Dec 2014 14:02:45 -0800 Subject: [PATCH] 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 --- src/common/dcc.c | 474 +++++++++++++++++++++++++++++--------------- src/common/dcc.h | 27 +-- src/common/plugin.c | 9 +- src/fe-gtk/dccgui.c | 13 +- 4 files changed, 331 insertions(+), 192 deletions(-) diff --git a/src/common/dcc.c b/src/common/dcc.c index 169a0f76..41d93be8 100644 --- a/src/common/dcc.c +++ b/src/common/dcc.c @@ -23,8 +23,9 @@ * 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 + #include #include #include @@ -45,6 +46,8 @@ #include #endif +#include + #include "hexchat.h" #include "util.h" #include "fe.h" @@ -57,13 +60,9 @@ #include "url.h" #include "hexchatc.h" -#ifdef USE_DCC64 -#define BIG_STR_TO_INT(x) strtoull(x,NULL,10) +/* Setting _FILE_OFFSET_BITS to 64 doesn't change lseek to use off64_t on Windows, so override lseek to the version that does */ #ifdef WIN32 -#define stat _stat64 -#endif -#else -#define BIG_STR_TO_INT(x) strtoul(x,NULL,10) +#define lseek _lseeki64 #endif 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_sendcpssum, dcc_getcpssum; +static gint64 dcc_sendcpssum, dcc_getcpssum; static struct DCC *new_dcc (void); static void dcc_close (struct DCC *dcc, int dccstat, int destroy); @@ -127,11 +126,12 @@ static void dcc_calc_cps (struct DCC *dcc) { GTimeVal now; - int oldcps; + gint64 oldcps; double timediff, startdiff; int glob_throttle_bit, wasthrottled; - int *cpssum, glob_limit; - DCC_SIZE pos, posdiff; + gint64 *cpssum; + int glob_limit; + goffset pos, posdiff; g_get_current_time (&now); @@ -169,8 +169,7 @@ dcc_calc_cps (struct DCC *dcc) posdiff = pos - dcc->lastcpspos; oldcps = dcc->cps; - dcc->cps = ((double) posdiff / timediff) * (timediff / startdiff) + - (double) dcc->cps * (1.0 - (timediff / startdiff)); + dcc->cps = (gint64) ((posdiff / timediff) * (timediff / startdiff) + dcc->cps * (1.0 - (timediff / startdiff))); *cpssum += dcc->cps - oldcps; } @@ -420,7 +419,7 @@ dcc_close (struct DCC *dcc, int dccstat, int destroy) if (dcc->proxy) free (dcc->proxy); if (dcc->file) - free (dcc->file); + g_free (dcc->file); if (dcc->destfile) g_free (dcc->destfile); free (dcc->nick); @@ -700,11 +699,17 @@ dcc_read (GIOChannel *source, GIOCondition condition, struct DCC *dcc) 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->ack = dcc->resumable; - } else + } + else { + gchar *filename_fs; + if (g_access (dcc->destfile, F_OK) == 0) { n = 0; @@ -713,7 +718,7 @@ dcc_read (GIOChannel *source, GIOCondition condition, struct DCC *dcc) 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; dcc->destfile = g_strdup (buf); @@ -722,9 +727,10 @@ dcc_read (GIOChannel *source, GIOCondition condition, struct DCC *dcc) old, dcc->destfile, NULL, NULL, 0); g_free (old); } - dcc->fp = - g_open (dcc->destfile, OFLAGS | O_TRUNC | O_WRONLY | O_CREAT, - prefs.hex_dcc_permissions); + + filename_fs = g_filename_from_utf8 (dcc->destfile, -1, NULL, NULL, NULL); + 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) @@ -792,7 +798,7 @@ dcc_read (GIOChannel *source, GIOCondition condition, struct DCC *dcc) 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 */ /* cppcheck-suppress deallocuse */ - sprintf (buf, "%d", dcc->cps); + sprintf (buf, "%" G_GINT64_FORMAT, dcc->cps); EMIT_SIGNAL (XP_TE_DCCRECVCOMP, dcc->serv->front_session, dcc->file, dcc->destfile, dcc->nick, buf, 0); return TRUE; @@ -1416,8 +1422,8 @@ dcc_connect (struct DCC *dcc) /* possible problems with filenames containing spaces? */ if (dcc->type == TYPE_RECV) snprintf (tbuf, sizeof (tbuf), strchr (dcc->file, ' ') ? - "DCC SEND \"%s\" %u %d %"DCC_SFMT" %d" : - "DCC SEND %s %u %d %"DCC_SFMT" %d", dcc->file, + "DCC SEND \"%s\" %u %d %" G_GUINT64_FORMAT " %d" : + "DCC SEND %s %u %d %" G_GUINT64_FORMAT " %d", dcc->file, dcc->addr, dcc->port, dcc->size, dcc->pasvid); else 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->ack < dcc->pos) + if (dcc->ack < (dcc->pos & 0xFFFFFFFF)) return TRUE; } else if (!dcc->wiotag) @@ -1538,7 +1544,7 @@ dcc_handle_new_ack (struct DCC *dcc) 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 */ /* cppcheck-suppress deallocuse */ - sprintf (buf, "%d", dcc->cps); + sprintf (buf, "%" G_GINT64_FORMAT, dcc->cps); EMIT_SIGNAL (XP_TE_DCCSENDCOMP, dcc->serv->front_session, file_part (dcc->file), dcc->nick, buf, NULL, 0); done = TRUE; @@ -1548,12 +1554,10 @@ dcc_handle_new_ack (struct DCC *dcc) dcc_send_data (NULL, 0, (gpointer)dcc); } -#ifdef USE_DCC64 /* take the top 32 of "bytes send" and bottom 32 of "ack" */ dcc->ack = (dcc->pos & G_GINT64_CONSTANT (0xffffffff00000000)) | (dcc->ack & 0xffffffff); /* dcc->ack is only used for CPS and PERCENTAGE calcs from now on... */ -#endif return done; } @@ -1762,7 +1766,7 @@ dcc_listen_init (struct DCC *dcc, session *sess) static struct session *dccsess; static char *dccto; /* lame!! */ -static int dccmaxcps; +static gint64 dccmaxcps; static int recursive = FALSE; static void @@ -1772,21 +1776,25 @@ dcc_send_wild (char *file) } 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]; - GStatBuf st; + GFileInfo *file_info; + GFile *file; 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 wild[256]; - safe_strcpy (wild, file_part (file), sizeof (wild)); - path_part (file, path, sizeof (path)); + safe_strcpy (wild, file_part (filename), sizeof (wild)); + path_part (filename, path, sizeof (path)); if (path[0] != '/' || path[1] != '\0') 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; dccmaxcps = maxcps; - free (file); + g_free (filename); recursive = TRUE; 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 (); if (!dcc) { - free (file); + g_free (filename); return; } - dcc->file = file; + + dcc->file = filename; 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 - if (sizeof (st.st_size) > 4 && st.st_size > 4294967295U) - { - PrintText (sess, "Cannot send files larger than 4 GB.\n"); - goto xit; - } -#endif + dcc_close(dcc, 0, TRUE); /* dcc_close will free dcc->file */ - if (!(*file_part (file)) || S_ISDIR (st.st_mode) || st.st_size < 1) - { - PrintText (sess, "Cannot send directories or empty files.\n"); - goto xit; - } - - dcc->starttime = dcc->offertime = time (0); - dcc->serv = sess->server; - dcc->dccstat = STAT_QUEUED; - dcc->size = st.st_size; - dcc->type = TYPE_SEND; - dcc->fp = g_open (file, OFLAGS | O_RDONLY, 0); - if (dcc->fp != -1) - { - if (passive || dcc_listen_init (dcc, sess)) - { - char havespaces = 0; - while (*file) - { - if (*file == ' ') - { - if (prefs.hex_dcc_send_fillspaces) - *file = '_'; - else - havespaces = 1; - } - file++; - } - 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 %" DCC_SFMT " %d" : - "DCC SEND %s 199 0 %" DCC_SFMT " %d", - file_part (dcc->file), - dcc->size, dcc->pasvid); - } - else - { - snprintf (outbuf, sizeof (outbuf), (havespaces) ? - "DCC SEND \"%s\" %u %d %"DCC_SFMT : - "DCC SEND %s %u %d %"DCC_SFMT, - 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); - } - return; - } + return; + } + + file = g_file_new_for_path (filename_fs); + if (file == NULL) + { + return; + } + + file_info = g_file_query_info (file, G_FILE_ATTRIBUTE_STANDARD_SIZE "," G_FILE_ATTRIBUTE_STANDARD_TYPE, G_FILE_QUERY_INFO_NONE, NULL, NULL); + + g_object_unref (file); + + if (file_info == NULL) + { + PrintTextf (sess, _("Cannot access %s\n"), dcc->file); + PrintTextf (sess, "%s %d: %s\n", _("Error"), errno, errorstring (errno)); + + dcc_close (dcc, 0, TRUE); /* dcc_close will free dcc->file */ + + return; + } + + file_type = g_file_info_get_file_type (file_info); + file_size = g_file_info_get_size (file_info); + + g_object_unref (file_info); + + if (*file_part (filename) == '\0' || file_type == G_FILE_TYPE_DIRECTORY || file_size <= 0) + { + PrintText (sess, "Cannot send directories or empty files.\n"); + + dcc_close (dcc, 0, TRUE); /* dcc_close will free dcc->file */ + + return; + } + + dcc->starttime = dcc->offertime = time (0); + dcc->serv = sess->server; + dcc->dccstat = STAT_QUEUED; + dcc->size = file_size; + dcc->type = TYPE_SEND; + dcc->fp = g_open (filename_fs, OFLAGS | O_RDONLY, 0); + + g_free (filename_fs); + + if (dcc->fp == -1) + { + PrintText (sess, "Cannot send directories or empty files.\n"); + + g_object_unref (file_info); + dcc_close (dcc, 0, TRUE); /* dcc_close will free dcc->file */ + } + + if (passive || dcc_listen_init (dcc, sess)) + { + char havespaces = 0; + while (*filename) + { + if (*filename == ' ') + { + 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 * @@ -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 */ -static int +static gboolean is_same_file (struct DCC *dcc, struct DCC *new_dcc) { -#ifndef WIN32 - GStatBuf st_a, st_b; -#endif + gboolean result = FALSE; + gchar *filename_fs = NULL, *new_filename_fs = NULL; + 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 (strcmp (dcc->destfile, new_dcc->destfile) == 0) + { return TRUE; + } - /* now handle case-insensitive Filesystems: HFS+, FAT */ -#ifdef WIN32 - /* warning no win32 implementation - behaviour may be unreliable */ -#else - /* 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; + filename_fs = g_filename_from_utf8 (dcc->file, -1, NULL, NULL, NULL); + if (filename_fs == NULL) + { + goto exit; + } - /* same inode, same device, same file! */ - if (st_a.st_ino == st_b.st_ino && - st_a.st_dev == st_b.st_dev) - return TRUE; -#endif + new_filename_fs = g_filename_from_utf8 (new_dcc->file, -1, NULL, NULL, NULL); + if (new_filename_fs == NULL) + { + goto exit; + } - 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 -is_resumable (struct DCC *dcc) +static void +update_is_resumable (struct DCC *dcc) { + gchar *filename_fs = g_filename_from_utf8 (dcc->destfile, -1, NULL, NULL, NULL); + dcc->resumable = 0; /* 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; - - if (g_stat (dcc->destfile, &st) != -1) + GFile *file = g_file_new_for_path (filename_fs); + if (file != NULL) { - 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; - dcc->pos = st.st_size; + goffset file_size_offset = g_file_info_get_size (file_info); + 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 - dcc->resume_error = 2; - } else + { + dcc->resume_errno = errno; + dcc->resume_error = 1; + } + + g_object_unref(file); + } + else { dcc->resume_errno = errno; dcc->resume_error = 1; } - } else + } + else { dcc->resume_errno = errno; dcc->resume_error = 1; } /* Now verify that this DCC is not already in progress from someone else */ - if (dcc->resumable) { GSList *list = dcc_list; @@ -2059,8 +2206,6 @@ is_resumable (struct DCC *dcc) list = list->next; } } - - return dcc->resumable; } void @@ -2100,7 +2245,7 @@ dcc_get_with_destfile (struct DCC *dcc, char *file) dcc->destfile = g_strdup (file); /* utf-8 */ /* since destfile changed, must check resumability again */ - is_resumable (dcc); + update_is_resumable (dcc); dcc_get (dcc); } @@ -2133,14 +2278,13 @@ dcc_get_nick (struct session *sess, char *nick) static struct DCC * new_dcc (void) { - struct DCC *dcc = malloc (sizeof (struct DCC)); + struct DCC *dcc = calloc (1, sizeof (struct DCC)); if (!dcc) return 0; - memset (dcc, 0, sizeof (struct DCC)); dcc->sok = -1; dcc->fp = -1; dcc_list = g_slist_prepend (dcc_list, dcc); - return (dcc); + return dcc; } void @@ -2231,8 +2375,8 @@ dcc_resume (struct DCC *dcc) dcc->resume_sent = 1; /* filename contains spaces? Quote them! */ snprintf (tbuf, sizeof (tbuf) - 10, strchr (dcc->file, ' ') ? - "DCC RESUME \"%s\" %d %"DCC_SFMT : - "DCC RESUME %s %d %"DCC_SFMT, + "DCC RESUME \"%s\" %d %" G_GUINT64_FORMAT : + "DCC RESUME %s %d %" G_GUINT64_FORMAT, dcc->file, dcc->port, dcc->resumable); if (dcc->pasvid) @@ -2316,7 +2460,7 @@ dcc_add_chat (session *sess, char *nick, int port, guint32 addr, int pasvid) } 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; 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 (); if (dcc) { - dcc->file = strdup (file); + dcc->file = g_strdup (file); dcc->destfile = g_malloc (strlen (prefs.hex_dcc_dir) + strlen (nick) + 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->maxcps = prefs.hex_dcc_max_get_cps; - is_resumable (dcc); + update_is_resumable (dcc); 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 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); EMIT_SIGNAL (XP_TE_DCCSENDOFFER, sess->server->front_session, nick, 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]; int port, pasvid = 0; guint32 addr; - DCC_SIZE size; + guint64 size; int psend = 0; 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); if (dcc) { - size = BIG_STR_TO_INT (word[8]); + size = g_ascii_strtoull (word[8], NULL, 10); dcc->resumable = 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 */ if (dcc->pasvid) snprintf (tbuf, sizeof (tbuf), strchr (file_part (dcc->file), ' ') ? - "DCC ACCEPT \"%s\" %d %"DCC_SFMT" %d" : - "DCC ACCEPT %s %d %"DCC_SFMT" %d", + "DCC ACCEPT \"%s\" %d %" G_GUINT64_FORMAT " %d" : + "DCC ACCEPT %s %d %" G_GUINT64_FORMAT " %d", file_part (dcc->file), port, dcc->resumable, dcc->pasvid); else snprintf (tbuf, sizeof (tbuf), strchr (file_part (dcc->file), ' ') ? - "DCC ACCEPT \"%s\" %d %"DCC_SFMT : - "DCC ACCEPT %s %d %"DCC_SFMT, + "DCC ACCEPT \"%s\" %d %" G_GUINT64_FORMAT : + "DCC ACCEPT %s %d %" G_GUINT64_FORMAT, file_part (dcc->file), port, dcc->resumable); 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, file_part (dcc->file), tbuf, NULL, 0, tags_data->timestamp); @@ -2508,7 +2652,7 @@ handle_dcc (struct session *sess, char *nick, char *word[], char *word_eol[], port = atoi (word[8]); 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 */ pasvid = atoi (word[10]); @@ -2576,7 +2720,7 @@ dcc_show_list (struct session *sess) { dcc = (struct DCC *) list->data; 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, _(dccstat[dcc->dccstat].name), dcc->size, dcc->pos, file_part (dcc->file)); diff --git a/src/common/dcc.h b/src/common/dcc.h index ade1dae7..e7115b32 100644 --- a/src/common/dcc.h +++ b/src/common/dcc.h @@ -39,17 +39,6 @@ #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 server *serv; @@ -62,21 +51,21 @@ struct DCC int wiotag; /* writing/sending io tag */ int port; int pasvid; /* mIRC's passive DCC id */ - int cps; + gint64 cps; int resume_error; int resume_errno; GTimeVal lastcpstv, firstcpstv; - DCC_SIZE lastcpspos; - int maxcps; + goffset lastcpspos; + gint64 maxcps; unsigned char ack_buf[4]; /* buffer for reading 4-byte ack */ int ack_pos; - DCC_SIZE size; - DCC_SIZE resumable; - DCC_SIZE ack; - DCC_SIZE pos; + guint64 size; + guint64 resumable; + guint64 ack; + guint64 pos; time_t starttime; time_t offertime; time_t lasttime; @@ -125,7 +114,7 @@ void dcc_check_timeouts (void); void dcc_change_nick (server *serv, char *oldnick, char *newnick); void dcc_notify_kill (struct server *serv); 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); void dcc_get_nick (struct session *sess, char *nick); void dcc_chat (session *sess, char *nick, int passive); diff --git a/src/common/plugin.c b/src/common/plugin.c index d83b69ff..f386346e 100644 --- a/src/common/plugin.c +++ b/src/common/plugin.c @@ -1531,7 +1531,14 @@ hexchat_list_int (hexchat_plugin *ph, hexchat_list *xlist, const char *name) case 0x34207553: /* address32 */ return ((struct DCC *)data)->addr; 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 */ return ((struct DCC *)data)->port; case 0x1b254: /* pos */ diff --git a/src/fe-gtk/dccgui.c b/src/fe-gtk/dccgui.c index 10ec8388..9f5226bc 100644 --- a/src/fe-gtk/dccgui.c +++ b/src/fe-gtk/dccgui.c @@ -88,7 +88,7 @@ struct my_dcc_send { struct session *sess; char *nick; - int maxcps; + gint64 maxcps; int passive; }; @@ -105,7 +105,7 @@ static short view_mode; /* 1=download 2=upload 3=both */ 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; 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; #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_free (formatted_str); @@ -155,20 +155,20 @@ static void dcc_prepare_row_chat (struct DCC *dcc, GtkListStore *store, GtkTreeIter *iter, gboolean update_only) { - static char pos[16], siz[16]; + static char pos[16], size[16]; char *date; date = ctime (&dcc->starttime); date[strlen (date) - 1] = 0; /* remove the \n */ 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, CCOL_STATUS, _(dccstat[dcc->dccstat].name), CCOL_NICK, dcc->nick, CCOL_RECV, pos, - CCOL_SENT, siz, + CCOL_SENT, size, CCOL_START, date, CCOL_DCC, dcc, 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->pos, pos, sizeof (pos)); snprintf (kbs, sizeof (kbs), "%.1f", ((float)dcc->cps) / 1024); -/* proper_unit (dcc->ack, ack, sizeof (ack));*/ snprintf (perc, sizeof (perc), "%.0f%%", per); if (dcc->cps != 0) {