From 4a91df950b26660a9d6918cf97ab3f1f9cf7b97b Mon Sep 17 00:00:00 2001 From: Arun Prakash Jana Date: Sat, 22 Feb 2020 08:44:28 +0530 Subject: [PATCH] Ignore hard links on du --- src/nnn.c | 78 ++++++++++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 66 insertions(+), 12 deletions(-) diff --git a/src/nnn.c b/src/nnn.c index e8b52093..8fa1c8f6 100644 --- a/src/nnn.c +++ b/src/nnn.c @@ -164,6 +164,10 @@ #define ARCHIVE_CMD_LEN 16 #define BLK_SHIFT_512 9 +/* Detect hardlinks in du */ +#define HASH_BITS (0xFFFFFF) +#define HASH_OCTETS (HASH_BITS >> 6) /* 2^6 = 64 */ + /* Program return codes */ #define _SUCCESS 0 #define _FAILURE !_SUCCESS @@ -206,6 +210,7 @@ typedef unsigned int uint; typedef unsigned char uchar; typedef unsigned short ushort; typedef long long ll; +typedef unsigned long long ull; /* STRUCTURES */ @@ -348,6 +353,7 @@ static char *g_prefixpath; static char *plugindir; static char *sessiondir; static char *pnamebuf, *pselbuf; +static ull *ihashbmp; static struct entry *dents; static blkcnt_t ent_blocks; static blkcnt_t dir_blocks; @@ -690,6 +696,44 @@ static char *xitoa(uint val) return &ascbuf[++i]; } +/* + * Source: https://elixir.bootlin.com/linux/latest/source/arch/alpha/include/asm/bitops.h + */ +static bool test_set_bit(ull nr) +{ + ull *m = ((ull *)ihashbmp) + (nr >> 6); + + if (*m & (1 << (nr & 63))) + return FALSE; + + *m |= 1 << (nr & 63); + + return TRUE; +} + +#if 0 +static bool test_clear_bit(ull nr) +{ + ull *m = ((ull *) ihashbmp) + (nr >> 6); + + if (!(*m & (1 << (nr & 63)))) + return FALSE; + + *m &= ~(1 << (nr & 63)); + return TRUE; +} +#endif + +static void clear_hash() +{ + ulong i = 0; + ull *addr = ihashbmp; + + for (; i < HASH_OCTETS; ++i, ++addr) + if (*addr) + *addr = 0; +} + static void clearinfoln(void) { move(xlines - 2, 0); @@ -4146,7 +4190,8 @@ static void launch_app(const char *path, char *newpath) static int sum_bsize(const char *UNUSED(fpath), const struct stat *sb, int typeflag, struct FTW *UNUSED(ftwbuf)) { - if (sb->st_blocks && (typeflag == FTW_F || typeflag == FTW_D)) + if (sb->st_blocks && (typeflag == FTW_F || typeflag == FTW_D) + && (sb->st_nlink <= 1 || test_set_bit((ull)sb->st_ino))) ent_blocks += sb->st_blocks; ++num_files; @@ -4155,7 +4200,8 @@ static int sum_bsize(const char *UNUSED(fpath), const struct stat *sb, int typef static int sum_asize(const char *UNUSED(fpath), const struct stat *sb, int typeflag, struct FTW *UNUSED(ftwbuf)) { - if (sb->st_size && (typeflag == FTW_F || typeflag == FTW_D)) + if (sb->st_size && (typeflag == FTW_F || typeflag == FTW_D) + && (sb->st_nlink <= 1 || test_set_bit((ull)sb->st_ino))) ent_blocks += sb->st_size; ++num_files; @@ -4222,6 +4268,13 @@ static int dentfill(char *path, struct entry **dents) printwarn(NULL); return 0; } + + if (!ihashbmp) { + ihashbmp = calloc(1, HASH_OCTETS << 3); + if (!ihashbmp) + return 0; + } else + clear_hash(); } #if _POSIX_C_SOURCE >= 200112L @@ -4266,13 +4319,13 @@ static int dentfill(char *path, struct entry **dents) dir_blocks += dirwalk(buf, &sb); - if (g_states & STATE_INTERRUPTED) { - closedir(dirp); - return n; - } + if (g_states & STATE_INTERRUPTED) + goto exit; } } else { - dir_blocks += (cfg.apparentsz ? sb.st_size : sb.st_blocks); + /* Do not recount hard links */ + if (sb.st_nlink <= 1 || test_set_bit((ull)sb.st_ino)) + dir_blocks += (cfg.apparentsz ? sb.st_size : sb.st_blocks); ++num_files; } @@ -4363,13 +4416,13 @@ static int dentfill(char *path, struct entry **dents) else num_files = num_saved; - if (g_states & STATE_INTERRUPTED) { - closedir(dirp); - return n; - } + if (g_states & STATE_INTERRUPTED) + goto exit; } else { dentp->blocks = (cfg.apparentsz ? sb.st_size : sb.st_blocks); - dir_blocks += dentp->blocks; + /* Do not recount hard links */ + if (sb.st_nlink <= 1 || test_set_bit((ull)sb.st_ino)) + dir_blocks += dentp->blocks; ++num_files; } } @@ -6446,6 +6499,7 @@ static void cleanup(void) free(bmstr); free(pluginstr); free(g_prefixpath); + free(ihashbmp); unlink(g_pipepath);