diff --git a/src/browser.c b/src/browser.c
index fc27abc46f0ec1a9bf18b9be17824b2e6905f889..77bc4d64c9e87fb334adb23ef30574bf122f3e19 100644
--- a/src/browser.c
+++ b/src/browser.c
@@ -176,7 +176,7 @@ void browse_draw_item(struct dir *n, int row, off_t max, int ispar) {
         n->flags & FF_ERR ? '!' :
        n->flags & FF_SERR ? '.' :
       n->flags & FF_OTHFS ? '>' :
-       n->flags & FF_HLNK ? 'H' :
+      n->flags & FF_HLNKC ? 'H' :
      !(n->flags & FF_FILE
     || n->flags & FF_DIR) ? '@' :
         n->flags & FF_DIR
diff --git a/src/calc.c b/src/calc.c
index 5f959e93a9926bcc0d63e7edb84a2a7267ebbeca..5af2437ad07e15424ac02cfbdcb1e1fca459dd10 100644
--- a/src/calc.c
+++ b/src/calc.c
@@ -55,6 +55,9 @@ dev_t curdev;            /* current device we're calculating on */
 int anpos;               /* position of the animation string */
 int curpathl = 0, lasterrl = 0;
 
+struct dir **links = NULL;
+int linksl, linkst;
+
 
 
 /* adds name to curpath */
@@ -84,6 +87,63 @@ void calc_leavepath() {
 }
 
 
+/* looks in the links list and adds the file when not found */
+int calc_hlink_add(struct dir *d) {
+  int i;
+  /* check the list */
+  for(i=0; i<linkst; i++)
+    if(links[i]->dev == d->dev && links[i]->ino == d->ino)
+      break;
+  /* found, do nothing and return the index */
+  if(i != linkst)
+    return i;
+  /* otherwise, add to list and return -1 */
+  if(++linkst > linksl) {
+    linksl *= 2;
+    if(!linksl) {
+      linksl = 64;
+      links = malloc(linksl*sizeof(struct dir *));
+    } else
+      links = realloc(links, linksl*sizeof(struct dir *));
+  }
+  links[linkst-1] = d;
+  return -1;
+}
+
+
+/* recursively checks a dir structure for hard links and fills the lookup array */
+void calc_hlink_init(struct dir *d) {
+  struct dir *t;
+
+  for(t=d->sub; t!=NULL; t=t->next)
+    calc_hlink_init(t);
+
+  if(!(d->flags & FF_HLNKC))
+    return;
+  calc_hlink_add(d);
+}
+
+
+/* checks an individual file and updates the flags and cicrular linked list */
+void calc_hlink_check(struct dir *d) {
+  struct dir *t;
+  int i;
+
+  d->flags |= FF_HLNKC;
+  i = calc_hlink_add(d);
+
+  /* found in the list? update hlnk */
+  if(i >= 0) {
+    t = d->hlnk = links[i];
+    if(t->hlnk != NULL)
+      for(t=t->hlnk; t->hlnk!=d->hlnk; t=t->hlnk)
+        ;
+    t->hlnk = d;
+    return;
+  }
+}
+
+
 int calc_item(struct dir *par, char *name) {
   struct dir *t, *d;
   struct stat fs;
@@ -131,11 +191,11 @@ int calc_item(struct dir *par, char *name) {
     for(t=d->parent; t!=NULL; t=t->parent)
       t->items++;
 
-  /* Provide the necessary information for hard link checking */
+  /* Hard link checking */
   d->ino = fs.st_ino;
   d->dev = fs.st_dev;
   if(!S_ISDIR(fs.st_mode) && fs.st_nlink > 1)
-    d->flags |= FF_HLNKC;
+    calc_hlink_check(d);
 
   /* count the size */
   if(!(d->flags & FF_EXL || d->flags & FF_OTHFS)) {
@@ -309,6 +369,14 @@ int calc_process() {
   struct dir *t;
   int n;
 
+  /* create initial links array */
+  linksl = linkst = 0;
+  if(orig) {
+    for(t=orig; t->parent!=NULL; t=t->parent)
+      ;
+    calc_hlink_init(t);
+  }
+
   /* check root directory */
   if((path = path_real(curpath)) == NULL) {
     failed = 1;
@@ -384,6 +452,9 @@ int calc_process() {
     free(name);
   free(path);
 
+  if(links != NULL)
+    free(links);
+
   /* success */
   if(!n && !failed) {
     if(root->sub == NULL) {
@@ -414,8 +485,6 @@ int calc_process() {
       }
       freedir(orig);
     }
-
-    link_del(root);
     browse_init(root->sub);
     return 0;
   }
@@ -436,8 +505,7 @@ calc_fail:
 
 void calc_init(char *dir, struct dir *org) {
   failed = anpos = 0;
-  if((orig = org) != NULL)
-    link_add(orig);
+  orig = org;
   if(curpathl == 0) {
     curpathl = strlen(dir)+1;
     curpath = malloc(curpathl);
diff --git a/src/delete.c b/src/delete.c
index 55265130feb2dae4a5fcf1ac3eea10e19c6dd627..cc44d2401066d9d2441ac5c3120762dd82098dfc 100644
--- a/src/delete.c
+++ b/src/delete.c
@@ -222,19 +222,13 @@ void delete_process() {
       return;
     }
 
-  /* temporarily re-add hard links, so we won't lose sizes in case we delete
-     a file of which another file outside this directory was marked as duplicate */
-  link_add(root);
-
   /* chdir */
   if(path_chdir(getpath(root->parent)) < 0) {
     state = DS_FAILED;
     lasterrno = errno;
     while(state == DS_FAILED)
-      if(input_handle(0)) {
-        link_del(root);
+      if(input_handle(0))
         return;
-      }
   }
 
   /* delete */
@@ -247,8 +241,6 @@ void delete_process() {
       nextsel->flags |= FF_BSEL;
     browse_init(n);
   }
-  if(n != NULL)
-    link_del(n);
 }
 
 
diff --git a/src/global.h b/src/global.h
index f58ccb57954c26fe935f3236746c1b007a97d67e..47dcbe3902bf9a8dce92baad023c2c381c8a5636 100644
--- a/src/global.h
+++ b/src/global.h
@@ -38,9 +38,8 @@
 #define FF_OTHFS  0x08 /* excluded because it was an other filesystem */
 #define FF_EXL    0x10 /* excluded using exlude patterns */
 #define FF_SERR   0x20 /* error in subdirectory */
-#define FF_HLNK   0x40 /* hard link (same file already encountered before) */
-#define FF_HLNKC  0x80 /* hard link candidate (file with st_nlink > 1) */
-#define FF_BSEL  0x100 /* selected */
+#define FF_HLNKC  0x40 /* hard link candidate (file with st_nlink > 1) */
+#define FF_BSEL   0x80 /* selected */
 
 /* Program states */
 #define ST_CALC   0
@@ -51,11 +50,11 @@
 
 /* structure representing a file or directory */
 struct dir {
-  struct dir *parent, *next, *sub;
+  struct dir *parent, *next, *sub, *hlnk;
   char *name;
   off_t size, asize;
   unsigned long items;
-  unsigned short flags;
+  unsigned char flags;
   dev_t dev;
   ino_t ino;
 }; 
diff --git a/src/util.c b/src/util.c
index 9c9a6c1004503e53c7ddd368f0ceacdce01b006e..8980c2fb174a2d23371af57188da66e3550e4403 100644
--- a/src/util.c
+++ b/src/util.c
@@ -169,10 +169,23 @@ void ncprint(int r, int c, char *fmt, ...) {
 }
 
 
+/* removes item from the hlnk circular linked list */
+void freedir_hlnk(struct dir *d) {
+  struct dir *t;
+  if(!d->hlnk)
+    return;
+  for(t=d->hlnk; t->hlnk!=d; t=t->hlnk)
+    ;
+  t->hlnk = d->hlnk;
+}
+
+
 void freedir_rec(struct dir *dr) {
   struct dir *tmp, *tmp2;
   tmp2 = dr;
   while((tmp = tmp2) != NULL) {
+    freedir_hlnk(tmp);
+    /* remove item */
     if(tmp->sub) freedir_rec(tmp->sub);
     free(tmp->name);
     tmp2 = tmp->next;
@@ -208,6 +221,7 @@ void freedir(struct dir *dr) {
           tmp->next = dr->next;
   }
 
+  freedir_hlnk(dr);
   free(dr->name);
   free(dr);
 }
@@ -249,81 +263,3 @@ char *getpath(struct dir *cur) {
   return getpathdat;
 }
 
-
-/* act =  0  -> just fill the links array
-   act =  1  -> fill array and remove duplicates
-   act = -1  -> use array to re-add duplicates */
-void link_list_rec(struct dir *d, int act) {
-  struct dir *t;
-  int i;
-
-  /* recursion, check sub directories */
-  for(t=d->sub; t!=NULL; t=t->next)
-    link_list_rec(t, act);
-
-  /* not a link candidate? ignore */
-  if(!(d->flags & FF_HLNKC))
-    return;
-
-  /* check against what we've found so far */
-  for(i=0; i<linkst; i++)
-    if(links[i]->dev == d->dev && links[i]->ino == d->ino)
-      break;
-
-  /* found in the list, set link flag and set size to zero */
-  if(act == 1 && i != linkst) {
-    d->flags |= FF_HLNK;
-    for(t=d->parent; t!=NULL; t=t->parent) {
-      t->size -= d->size;
-      t->asize -= d->asize;
-    }
-    d->size = d->asize = 0;
-    return;
-  }
-
-  /* found in the list, reset flag and re-add size */
-  if(act == -1 && i != linkst && d->flags & FF_HLNK) {
-    d->flags -= FF_HLNK;
-    d->size = links[i]->size;
-    d->asize = links[i]->asize;
-    for(t=d->parent; t!=NULL; t=t->parent) {
-      t->size += d->size;
-      t->asize += d->asize;
-    }
-  }
-
-  /* not found, add to the list */
-  if(act == 1 || (act == 0 && !(d->flags & FF_HLNK))) {
-    if(++linkst > linksl) {
-      linksl *= 2;
-      if(!linksl) {
-        linksl = 64;
-        links = malloc(linksl*sizeof(struct dir *));
-      } else
-        links = realloc(links, linksl*sizeof(struct dir *));
-    }
-    links[i] = d;
-  }
-}
-
-
-void link_del(struct dir *par) {
-  while(par->parent != NULL)
-    par = par->parent;
-  link_list_rec(par, 1);
-  linkst = 0;
-}
-
-
-void link_add(struct dir *par) {
-  while(par->parent != NULL)
-    par = par->parent;
-  /* In order to correctly re-add the duplicates, we'll have to pass the entire
-     tree twice, one time to get a list of all links, second time to re-add them */
-  link_list_rec(par, 0);
-  link_list_rec(par, -1);
-  linkst = 0;
-}
-
-
-
diff --git a/src/util.h b/src/util.h
index 152a08ad72e4895ee4f9e8e0bf6a07f1390d9892..fc7e29b985e3f621e0dc3f7e5f36a8e20042d449 100644
--- a/src/util.h
+++ b/src/util.h
@@ -78,11 +78,5 @@ void freedir(struct dir *);
    returned pointer will be overwritten with a subsequent call */
 char *getpath(struct dir *);
 
-/* removes all hard links from a tree */
-void link_del(struct dir *);
-
-/* re-adds all hard links in a tree */
-void link_add(struct dir *);
-
 #endif