summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorYorhel <git@yorhel.nl>2010-02-28 16:50:43 +0100
committerYorhel <git@yorhel.nl>2010-02-28 16:56:45 +0100
commit1cc0e5a50fef5f0754c37701133f4cb31a99101e (patch)
tree3d0b70eab548c66e4fc02006c38b3a2cf6b132ff
parent82ec5b9fa81a9c7f0d6e8d04d60dc8d92b737112 (diff)
Only count the size of each hard link once for each directory
The displayed directory sizes are now fully correct, although in its current state it's not all that intuitive because: directory size != sum(size of all files and subdirectories) This should probably be fixed later on by splitting the sizes into a shared and non-shared part. Also, the sizes displayed after a recalculation or deletion are incorrect, I'll fix this later on.
-rw-r--r--src/calc.c62
-rw-r--r--src/global.h4
-rw-r--r--src/util.c3
3 files changed, 46 insertions, 23 deletions
diff --git a/src/calc.c b/src/calc.c
index 8e8209b..5f6c9cc 100644
--- a/src/calc.c
+++ b/src/calc.c
@@ -124,9 +124,10 @@ void calc_hlink_init(struct dir *d) {
}
-/* checks an individual file and updates the flags and cicrular linked list */
+/* checks an individual file and updates the flags and cicrular linked list,
+ * also updates the sizes of the parent dirs */
void calc_hlink_check(struct dir *d) {
- struct dir *t;
+ struct dir *t, *pt, *par;
int i;
d->flags |= FF_HLNKC;
@@ -139,7 +140,22 @@ void calc_hlink_check(struct dir *d) {
for(t=t->hlnk; t->hlnk!=d->hlnk; t=t->hlnk)
;
t->hlnk = d;
- return;
+ }
+
+ /* now update the sizes of the parent directories,
+ * This works by only counting this file in the parent directories where this
+ * file hasn't been counted yet, which can be determined from the hlnk list.
+ * XXX: This may not be the most efficient algorithm to do this */
+ for(i=1,par=d->parent; i&&par; par=par->parent) {
+ if(d->hlnk)
+ for(t=d->hlnk; i&&t!=d; t=t->hlnk)
+ for(pt=t->parent; i&&pt; pt=pt->parent)
+ if(pt==par)
+ i=0;
+ if(i) {
+ par->size += d->size;
+ par->asize += d->asize;
+ }
}
}
@@ -186,27 +202,29 @@ int calc_item(struct dir *par, char *name) {
else if(S_ISDIR(fs.st_mode))
d->flags |= FF_DIR;
- /* update parent dirs */
+ /* update the items count of the parent dirs */
if(!(d->flags & FF_EXL))
for(t=d->parent; t!=NULL; t=t->parent)
t->items++;
- /* Hard link checking */
- d->ino = fs.st_ino;
- d->dev = fs.st_dev;
- if(!S_ISDIR(fs.st_mode) && fs.st_nlink > 1)
- calc_hlink_check(d);
-
/* count the size */
if(!(d->flags & FF_EXL || d->flags & FF_OTHFS)) {
d->size = fs.st_blocks * S_BLKSIZE;
d->asize = fs.st_size;
- for(t=d->parent; t!=NULL; t=t->parent) {
- t->size += d->size;
- t->asize += d->asize;
- }
+ /* only update the sizes of the parents if it's not a hard link */
+ if(S_ISDIR(fs.st_mode) || fs.st_nlink <= 1)
+ for(t=d->parent; t!=NULL; t=t->parent) {
+ t->size += d->size;
+ t->asize += d->asize;
+ }
}
+ /* Hard link checking (also takes care of updating the sizes of the parents) */
+ d->ino = fs.st_ino;
+ d->dev = fs.st_dev;
+ if(!S_ISDIR(fs.st_mode) && fs.st_nlink > 1)
+ calc_hlink_check(d);
+
return 0;
}
@@ -421,6 +439,7 @@ int calc_process() {
if(orig) {
t->name = malloc(strlen(orig->name)+1);
strcpy(t->name, orig->name);
+ t->parent = orig->parent;
} else {
t->name = malloc(strlen(path)+strlen(name)+2);
t->name[0] = 0;
@@ -434,6 +453,14 @@ int calc_process() {
root = t;
curdev = fs.st_dev;
+ /* make sure to count this directory entry in its parents at this point */
+ if(orig)
+ for(t=root->parent; t!=NULL; t=t->parent) {
+ t->size += root->size;
+ t->asize += root->asize;
+ t->items += 1;
+ }
+
/* update curpath */
if(strcmp(name, ".")) {
if((int)strlen(path)+1 > curpathl) {
@@ -468,14 +495,7 @@ int calc_process() {
/* update references and free original item */
if(orig) {
- root->parent = orig->parent;
root->next = orig->next;
- for(t=root->parent; t!=NULL; t=t->parent) {
- t->size += root->size;
- t->asize += root->asize;
- t->items += root->items+1;
- }
-
if(orig->parent) {
t = orig->parent->sub;
if(t == orig)
diff --git a/src/global.h b/src/global.h
index 47dcbe3..0ca5d43 100644
--- a/src/global.h
+++ b/src/global.h
@@ -48,7 +48,9 @@
#define ST_HELP 3
-/* structure representing a file or directory */
+/* structure representing a file or directory
+ * XXX: probably a good idea to get rid of the custom _t types and use
+ * fixed-size integers instead, which are much more predictable */
struct dir {
struct dir *parent, *next, *sub, *hlnk;
char *name;
diff --git a/src/util.c b/src/util.c
index 8980c2f..ce09fbb 100644
--- a/src/util.c
+++ b/src/util.c
@@ -197,7 +197,8 @@ void freedir_rec(struct dir *dr) {
void freedir(struct dir *dr) {
struct dir *tmp;
- /* update sizes of parent directories */
+ /* update sizes of parent directories
+ * XXX: This breaks when the dir contains hard linked files */
tmp = dr;
while((tmp = tmp->parent) != NULL) {
tmp->size -= dr->size;