From fdd9ab4098124d94967e7fede7d885ab59e1a09b Mon Sep 17 00:00:00 2001 From: Andrew Borodin Date: Tue, 8 Nov 2016 10:59:55 +0300 Subject: [PATCH] Ticket #3666: Improper use of IEC and SI prefixes for size in size_trunc(). (size_trunc_len): return statically allocated buffer. Signed-off-by: Andrew Borodin --- lib/util.c | 32 +++++++++++++++++++++----------- lib/util.h | 8 ++++---- src/filemanager/chown.c | 4 ++-- src/filemanager/filegui.c | 27 ++++++++++++++++----------- src/filemanager/info.c | 14 +++++++++----- src/filemanager/panel.c | 19 +++++++++++-------- src/viewer/display.c | 11 ++++++----- 7 files changed, 69 insertions(+), 46 deletions(-) diff --git a/lib/util.c b/lib/util.c index 6b4b5c8f1..795fb2920 100644 --- a/lib/util.c +++ b/lib/util.c @@ -405,18 +405,24 @@ size_trunc_sep (uintmax_t size, gboolean use_si) /* --------------------------------------------------------------------------------------------- */ /** - * Print file SIZE to BUFFER, but don't exceed LEN characters, - * not including trailing 0. BUFFER should be at least LEN+1 long. - * This function is called for every file on panels, so avoid - * floating point by any means. + * Represent some numeric value as string of required length. * - * Units: size units (filesystem sizes are 1K blocks) - * 0=bytes, 1=Kbytes, 2=Mbytes, etc. + * @param len number of characters to represent @size + * @param size value to represent + * @param units @size units: 0=bytes, 1=Kbytes, 2=Mbytes, etc. + * @param use_si use SI or IEC units (10- or 2-based respectively) + * + * @return static buffer */ -void -size_trunc_len (char *buffer, unsigned int len, uintmax_t size, int units, gboolean use_si) +const char * +size_trunc_len (unsigned int len, uintmax_t size, int units, gboolean use_si) { + /* This function is called for every file on panels, so avoid floating point by any means. */ + + /* Enough space to represent uintmax_t value with units */ + static char buffer[BUF_TINY]; + /* Avoid taking power for every file. */ /* *INDENT-OFF* */ static const uintmax_t power10[] = { @@ -452,6 +458,7 @@ size_trunc_len (char *buffer, unsigned int len, uintmax_t size, int units, gbool #endif }; /* *INDENT-ON* */ + static const char *const suffix[] = { "", "K", "M", "G", "T", "P", "E", "Z", "Y", NULL }; static const char *const suffix_lc[] = { "", "k", "m", "g", "t", "p", "e", "z", "y", NULL }; @@ -493,19 +500,20 @@ size_trunc_len (char *buffer, unsigned int len, uintmax_t size, int units, gbool if (j == units) { /* Empty files will print "0" even with minimal width. */ - g_snprintf (buffer, len + 1, "%s", "0"); + g_snprintf (buffer, sizeof (buffer), "%s", "0"); } else { /* Use "~K" or just "K" if len is 1. Use "B" for bytes. */ - g_snprintf (buffer, len + 1, (len > 1) ? "~%s" : "%s", (j > 1) ? sfx[j - 1] : "B"); + g_snprintf (buffer, sizeof (buffer), (len > 1) ? "~%s" : "%s", + (j > 1) ? sfx[j - 1] : "B"); } break; } if (size < power10[len - (j > 0 ? 1 : 0)]) { - g_snprintf (buffer, len + 1, "%" PRIuMAX "%s", size, sfx[j]); + g_snprintf (buffer, sizeof (buffer), "%" PRIuMAX "%s", size, sfx[j]); break; } @@ -515,6 +523,8 @@ size_trunc_len (char *buffer, unsigned int len, uintmax_t size, int units, gbool else size = (size + 512) >> 10; } + + return buffer; } /* --------------------------------------------------------------------------------------------- */ diff --git a/lib/util.h b/lib/util.h index 46ac1f0b4..8fe7f2120 100644 --- a/lib/util.h +++ b/lib/util.h @@ -150,11 +150,11 @@ const char *size_trunc (uintmax_t size, gboolean use_si); * NOTE: uses the same static buffer as size_trunc. */ const char *size_trunc_sep (uintmax_t size, gboolean use_si); -/* Print file SIZE to BUFFER, but don't exceed LEN characters, - * not including trailing 0. BUFFER should be at least LEN+1 long. - * +/* Return a static string representing size, appending "K" or "M" for + * big sizes. but don't exceed LEN characters, * Units: size units (0=bytes, 1=Kbytes, 2=Mbytes, etc.) */ -void size_trunc_len (char *buffer, unsigned int len, uintmax_t size, int units, gboolean use_si); +const char *size_trunc_len (unsigned int len, uintmax_t size, int units, gboolean use_si); + const char *string_perm (mode_t mode_bits); const char *extension (const char *); diff --git a/src/filemanager/chown.c b/src/filemanager/chown.c index 72478eff5..2d91179cd 100644 --- a/src/filemanager/chown.c +++ b/src/filemanager/chown.c @@ -407,7 +407,7 @@ chown_cmd (void) struct stat sf_stat; const char *fname; int result; - char buffer[BUF_TINY]; + const char *buffer; uid_t new_user = (uid_t) (-1); gid_t new_group = (gid_t) (-1); @@ -438,7 +438,7 @@ chown_cmd (void) chown_label (0, str_trunc (fname, GW - 4)); chown_label (1, str_trunc (get_owner (sf_stat.st_uid), GW - 4)); chown_label (2, str_trunc (get_group (sf_stat.st_gid), GW - 4)); - size_trunc_len (buffer, GW - 4, sf_stat.st_size, 0, panels_options.kilobyte_si); + buffer = size_trunc_len (GW - 4, sf_stat.st_size, 0, panels_options.kilobyte_si); chown_label (3, buffer); chown_label (4, string_perm (sf_stat.st_mode)); diff --git a/src/filemanager/filegui.c b/src/filemanager/filegui.c index 5e3e41822..dd672b908 100644 --- a/src/filemanager/filegui.c +++ b/src/filemanager/filegui.c @@ -491,7 +491,7 @@ overwrite_query_dialog (file_op_context_t * ctx, enum OperationMode mode) vfs_path_t *p; char *s1; - char s2[BUF_SMALL]; + const char *s2; int w, bw1, bw2; unsigned short i; @@ -524,7 +524,7 @@ overwrite_query_dialog (file_op_context_t * ctx, enum OperationMode mode) vfs_path_free (p); g_free (s1); /* new file size */ - size_trunc_len (s2, sizeof (s2), ui->src_stat->st_size, 0, panels_options.kilobyte_si); + s2 = size_trunc_len (BUF_SMALL - 1, ui->src_stat->st_size, 0, panels_options.kilobyte_si); NEW_LABEL (2, s2); /* new file modification date & time */ s1 = (char *) file_date (ui->src_stat->st_mtime); @@ -539,7 +539,7 @@ overwrite_query_dialog (file_op_context_t * ctx, enum OperationMode mode) vfs_path_free (p); g_free (s1); /* existing file size */ - size_trunc_len (s2, sizeof (s2), ui->dst_stat->st_size, 0, panels_options.kilobyte_si); + s2 = size_trunc_len (BUF_SMALL - 1, ui->dst_stat->st_size, 0, panels_options.kilobyte_si); NEW_LABEL (6, s2); /* existing file modification date & time */ s1 = (char *) file_date (ui->dst_stat->st_mtime); @@ -1030,8 +1030,6 @@ file_progress_show_total (file_op_total_context_t * tctx, file_op_context_t * ct uintmax_t copied_bytes, gboolean show_summary) { char buffer[BUF_TINY]; - char buffer2[BUF_TINY]; - char buffer3[BUF_TINY]; file_op_context_ui_t *ui; if (ctx == NULL || ctx->ui == NULL) @@ -1057,7 +1055,7 @@ file_progress_show_total (file_op_total_context_t * tctx, file_op_context_t * ct if (ui->time_label != NULL) { struct timeval tv_current; - char buffer4[BUF_TINY]; + char buffer2[BUF_TINY], buffer3[BUF_TINY]; gettimeofday (&tv_current, NULL); file_frmt_time (buffer2, tv_current.tv_sec - tctx->transfer_start.tv_sec); @@ -1069,6 +1067,8 @@ file_progress_show_total (file_op_total_context_t * tctx, file_op_context_t * ct g_snprintf (buffer, sizeof (buffer), _("Time: %s %s"), buffer2, buffer3); else { + char buffer4[BUF_TINY]; + file_bps_prepare_for_show (buffer4, (long) tctx->bps); g_snprintf (buffer, sizeof (buffer), _("Time: %s %s (%s)"), buffer2, buffer3, buffer4); @@ -1080,8 +1080,8 @@ file_progress_show_total (file_op_total_context_t * tctx, file_op_context_t * ct g_snprintf (buffer, sizeof (buffer), _("Time: %s"), buffer2); else { - file_bps_prepare_for_show (buffer4, (long) tctx->bps); - g_snprintf (buffer, sizeof (buffer), _("Time: %s (%s)"), buffer2, buffer4); + file_bps_prepare_for_show (buffer3, (long) tctx->bps); + g_snprintf (buffer, sizeof (buffer), _("Time: %s (%s)"), buffer2, buffer3); } } @@ -1090,14 +1090,19 @@ file_progress_show_total (file_op_total_context_t * tctx, file_op_context_t * ct if (ui->total_bytes_label != NULL) { - size_trunc_len (buffer2, 5, tctx->copied_bytes, 0, panels_options.kilobyte_si); + const char *buffer2, *buffer3; + buffer2 = size_trunc_len (5, tctx->copied_bytes, 0, panels_options.kilobyte_si); if (!ctx->progress_totals_computed) g_snprintf (buffer, sizeof (buffer), _(" Total: %s "), buffer2); else { - size_trunc_len (buffer3, 5, ctx->progress_bytes, 0, panels_options.kilobyte_si); - g_snprintf (buffer, sizeof (buffer), _(" Total: %s/%s "), buffer2, buffer3); + char *b2; + + b2 = g_strdup (buffer2); + buffer3 = size_trunc_len (5, ctx->progress_bytes, 0, panels_options.kilobyte_si); + g_snprintf (buffer, sizeof (buffer), _(" Total: %s/%s "), b2, buffer3); + g_free (b2); } hline_set_text (ui->total_bytes_label, buffer); diff --git a/src/filemanager/info.c b/src/filemanager/info.c index 1703881f9..2b74f24f1 100644 --- a/src/filemanager/info.c +++ b/src/filemanager/info.c @@ -176,13 +176,16 @@ info_show_info (WInfo * info) tty_print_string (_("No space information")); else { - char buffer1[6], buffer2[6]; + char *buffer1; + const char *buffer2; - size_trunc_len (buffer1, 5, myfs_stats.avail, 1, panels_options.kilobyte_si); - size_trunc_len (buffer2, 5, myfs_stats.total, 1, panels_options.kilobyte_si); + buffer1 = + g_strdup (size_trunc_len (5, myfs_stats.avail, 1, panels_options.kilobyte_si)); + buffer2 = size_trunc_len (5, myfs_stats.total, 1, panels_options.kilobyte_si); tty_printf (_("Free space: %s/%s (%d%%)"), buffer1, buffer2, myfs_stats.total == 0 ? 0 : (int) (100 * (long double) myfs_stats.avail / myfs_stats.total)); + g_free (buffer1); } MC_FALLTHROUGH; case 14: @@ -236,8 +239,9 @@ info_show_info (WInfo * info) else #endif { - char buffer[10]; - size_trunc_len (buffer, 9, st.st_size, 0, panels_options.kilobyte_si); + const char *buffer; + + buffer = size_trunc_len (9, st.st_size, 0, panels_options.kilobyte_si); tty_printf (_("Size: %s"), buffer); #ifdef HAVE_STRUCT_STAT_ST_BLOCKS tty_printf (ngettext (" (%lu block)", " (%lu blocks)", diff --git a/src/filemanager/panel.c b/src/filemanager/panel.c index 4f01e9a50..1ddf232df 100644 --- a/src/filemanager/panel.c +++ b/src/filemanager/panel.c @@ -512,12 +512,13 @@ string_file_size (file_entry_t * fe, int len) #ifdef HAVE_STRUCT_STAT_ST_RDEV if (S_ISBLK (fe->st.st_mode) || S_ISCHR (fe->st.st_mode)) + { format_device_number (buffer, len + 1, fe->st.st_rdev); - else + return buffer; + } #endif - size_trunc_len (buffer, (unsigned int) len, fe->st.st_size, 0, panels_options.kilobyte_si); - return buffer; + return size_trunc_len ((unsigned int) len, fe->st.st_size, 0, panels_options.kilobyte_si); } /* --------------------------------------------------------------------------------------------- */ @@ -1154,15 +1155,17 @@ show_free_space (const WPanel * panel) if (myfs_stats.avail != 0 || myfs_stats.total != 0) { const Widget *w = CONST_WIDGET (panel); - char buffer1[6], buffer2[6], tmp[BUF_SMALL]; + char *buffer1; + const char *buffer2; + char tmp[BUF_SMALL]; - size_trunc_len (buffer1, sizeof (buffer1) - 1, myfs_stats.avail, 1, - panels_options.kilobyte_si); - size_trunc_len (buffer2, sizeof (buffer2) - 1, myfs_stats.total, 1, - panels_options.kilobyte_si); + buffer1 = g_strdup (size_trunc_len (5, myfs_stats.avail, 1, panels_options.kilobyte_si)); + buffer2 = size_trunc_len (5, myfs_stats.total, 1, panels_options.kilobyte_si); g_snprintf (tmp, sizeof (tmp), " %s/%s (%d%%) ", buffer1, buffer2, myfs_stats.total == 0 ? 0 : (int) (100 * (long double) myfs_stats.avail / myfs_stats.total)); + g_free (buffer1); + /* FIX LEGACY: use str_term_width1() instead of strlen() here */ widget_move (w, w->lines - 1, w->cols - 2 - (int) strlen (tmp)); tty_setcolor (NORMAL_COLOR); tty_print_string (tmp); diff --git a/src/viewer/display.c b/src/viewer/display.c index 665e20fe4..e09442931 100644 --- a/src/viewer/display.c +++ b/src/viewer/display.c @@ -169,12 +169,13 @@ mcview_display_status (WView * view) tty_printf ("0x%08" PRIxMAX, (uintmax_t) view->hex_cursor); else { - char buffer[BUF_TRUNC_LEN + 1]; + const char *buffer; - size_trunc_len (buffer, BUF_TRUNC_LEN, mcview_get_filesize (view), 0, - panels_options.kilobyte_si); - tty_printf ("%9" PRIuMAX "/%s%s %s", (uintmax_t) view->dpy_end, - buffer, mcview_may_still_grow (view) ? "+" : " ", + buffer = + size_trunc_len (BUF_TRUNC_LEN, mcview_get_filesize (view), 0, + panels_options.kilobyte_si); + tty_printf ("%9" PRIuMAX "/%s%s %s", (uintmax_t) view->dpy_end, buffer, + mcview_may_still_grow (view) ? "+" : " ", #ifdef HAVE_CHARSET mc_global.source_codepage >= 0 ? get_codepage_id (mc_global.source_codepage) :