From 757bdff7ed3dc79b079f76011c38cc476ef6eb00 Mon Sep 17 00:00:00 2001 From: Yorhel <git@yorhel.nl> Date: Tue, 5 May 2009 19:13:52 +0200 Subject: [PATCH] Implemented hardlink detection --- src/calc.c | 56 +++++++++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 47 insertions(+), 9 deletions(-) diff --git a/src/calc.c b/src/calc.c index a8198bf..6fb02cc 100644 --- a/src/calc.c +++ b/src/calc.c @@ -53,7 +53,12 @@ struct dir *root; /* root directory struct we're calculating */ struct dir *orig; /* original directory, when recalculating */ dev_t curdev; /* current device we're calculating on */ int anpos; /* position of the animation string */ -int curpathl = 0, lasterrl = 0; +struct link_inode { /* list of all non-dirs with nlink > 1 */ + dev_t dev; + ino_t ino; +} *links = NULL; +int curpathl = 0, lasterrl = 0, linksl = 0, linkst = 0; + /* adds name to curpath */ @@ -86,6 +91,7 @@ void calc_leavepath() { int calc_item(struct dir *par, char *name) { struct dir *t, *d; struct stat fs; + int i; if(name[0] == '.' && (name[1] == '\0' || (name[1] == '.' && name[2] == '\0'))) return 0; @@ -130,6 +136,31 @@ int calc_item(struct dir *par, char *name) { for(t=d->parent; t!=NULL; t=t->parent) t->items++; + /* check for hard links. + An item is only considered a hard link if it's not a directory, + has st_nlink > 1, and is already present in the links array */ + if(!S_ISDIR(fs.st_mode) && fs.st_nlink > 1) { + for(i=0; i<linkst; i++) + if(links[i].dev == fs.st_dev && links[i].ino == fs.st_ino) + break; + /* found in the list, set size = 0 */ + if(i != linkst) + fs.st_blocks = fs.st_size = 0; + /* not found, add to the list */ + else { + if(++linkst > linksl) { + linksl *= 2; + if(!linksl) { + linksl = 64; + links = malloc(linksl); + } else + links = realloc(links, linksl); + } + links[i].dev = fs.st_dev; + links[i].ino = fs.st_ino; + } + } + /* count the size */ if(!(d->flags & FF_EXL || d->flags & FF_OTHFS)) { d->size = fs.st_blocks * S_BLKSIZE; @@ -297,6 +328,7 @@ void calc_process() { char *path, *name; struct stat fs; struct dir *t; + int n; /* check root directory */ if((path = path_real(curpath)) == NULL) { @@ -365,11 +397,20 @@ void calc_process() { } else curpath[0] = 0; - /* start calculating */ - if(!calc_dir(root, name) && !failed) { - if(!path[1] && strcmp(name, ".")) - free(name); - free(path); + /* calculate */ + n = calc_dir(root, name); + + /* free some resources */ + if(!path[1] && strcmp(name, ".")) + free(name); + free(path); + if(linksl) { + linksl = linkst = 0; + free(links); + } + + /* success */ + if(!n && !failed) { if(root->sub == NULL) { freedir(root); failed = 1; @@ -403,9 +444,6 @@ void calc_process() { } /* something went wrong... */ - if(!path[1] && strcmp(name, ".")) - free(name); - free(path); freedir(root); calc_fail: while(failed && !input_handle(0)) -- GitLab