diff --git a/src/calc.c b/src/calc.c
index 8e8209b26b516ab0e5a150c34a0a31b2e599973a..5f6c9cc9dd3d0af319248b182fb7c3d4fcf95872 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->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 47dcbe3902bf9a8dce92baad023c2c381c8a5636..0ca5d437b7b49071b22f7620f4d9f510f49c4b53 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 8980c2fb174a2d23371af57188da66e3550e4403..ce09fbb7fcb143e8eb2ca07a853b869b811eda19 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;