From ad84603bee29574d64ada57cd97d8e2423577b96 Mon Sep 17 00:00:00 2001 From: Yorhel Date: Thu, 22 Nov 2012 13:33:32 +0100 Subject: [PATCH] Clip directory sizes to fit in a signed 64bit integer This mostly avoids the issue of getting negative sizes. It's still possible to get a negative size after refresh or deletion, I'll get to that in a bit. --- doc/ncdu.pod | 4 ++++ src/dir_mem.c | 4 ++-- src/global.h | 1 + src/util.c | 4 ++-- src/util.h | 6 ++++++ 5 files changed, 15 insertions(+), 4 deletions(-) diff --git a/doc/ncdu.pod b/doc/ncdu.pod index ef2d4b0..3d8df5b 100644 --- a/doc/ncdu.pod +++ b/doc/ncdu.pod @@ -276,6 +276,10 @@ links, and will thus be scanned and counted multiple times. Some minor glitches may appear when displaying filenames that contain multibyte or multicolumn characters. +All sizes are internally represented as a signed 64bit integer. If you have a +directory larger than 8 EiB minus one byte, ncdu will clip its size to 8 EiB +minus one byte. + Please report any other bugs you may find at the bug tracker, which can be found on the web site at http://dev.yorhel.nl/ncdu diff --git a/src/dir_mem.c b/src/dir_mem.c index 3001c01..d13ba24 100644 --- a/src/dir_mem.c +++ b/src/dir_mem.c @@ -84,8 +84,8 @@ static void hlink_check(struct dir *d) { if(pt==par) i=0; if(i) { - par->size += d->size; - par->asize += d->asize; + par->size = adds64(par->size, d->size); + par->asize = adds64(par->size, d->asize); } } } diff --git a/src/global.h b/src/global.h index 7249bcd..d6eb2cb 100644 --- a/src/global.h +++ b/src/global.h @@ -29,6 +29,7 @@ #include "config.h" #include #include +#include #include #include diff --git a/src/util.c b/src/util.c index d519581..ce000e6 100644 --- a/src/util.c +++ b/src/util.c @@ -287,8 +287,8 @@ struct dir *getroot(struct dir *d) { void addparentstats(struct dir *d, int64_t size, int64_t asize, int items) { while(d) { - d->size += size; - d->asize += asize; + d->size = adds64(d->size, size); + d->asize = adds64(d->asize, asize); d->items += items; d = d->parent; } diff --git a/src/util.h b/src/util.h index 8b1b959..5c63876 100644 --- a/src/util.h +++ b/src/util.h @@ -81,6 +81,12 @@ char *getpath(struct dir *); /* returns the root element of the given dir struct */ struct dir *getroot(struct dir *); +/* Add two positive signed 64-bit integers. Returns INT64_MAX if the result + * would overflow. + * I use uint64_t's to detect the overflow, as (a + b < 0) relies on undefined + * behaviour, and (INT64_MAX - b >= a) didn't work for some reason. */ +#define adds64(a, b) ((uint64_t)(a) + (uint64_t)(b) > (uint64_t)INT64_MAX ? INT64_MAX : (a)+(b)) + /* Adds a value to the size, asize and items fields of *d and its parents */ void addparentstats(struct dir *, int64_t, int64_t, int);