diff --git a/src/browser.c b/src/browser.c
index 29b40c7deff5e2d09825b8f30b5fe11b5bbc8c6a..596f29d5e2cc2a711847c716fb4dbdccfe70fb61 100644
--- a/src/browser.c
+++ b/src/browser.c
@@ -134,8 +134,6 @@ struct dir *browse_sort(struct dir *list) {
 
 
 void browse_draw_info(struct dir *dr) {
-  char path[PATH_MAX];
-
   nccreate(11, 60, "Item info");
 
   attron(A_BOLD);
@@ -147,7 +145,7 @@ void browse_draw_info(struct dir *dr) {
   attroff(A_BOLD);
 
   ncaddstr(2,  9, cropstr(dr->name, 49));
-  ncaddstr(3,  9, cropstr(getpath(dr, path), 49));
+  ncaddstr(3,  9, cropstr(getpath(dr), 49));
   ncaddstr(4,  9, dr->flags & FF_DIR ? "Directory"
       : dr->flags & FF_FILE ? "File" : "Other (link, device, socket, ..)");
   ncprint(6, 18, "%s (%s B)", formatsize(dr->size),  fullsize(dr->size));
@@ -226,7 +224,7 @@ void browse_draw_item(struct dir *n, int row, off_t max, int ispar) {
 
 int browse_draw() {
   struct dir *n, ref, *cur, *sel = NULL;
-  char tmp[PATH_MAX];
+  char tmp[PATH_MAX], *tmp2;
   int selected, i;
   off_t max = 1;
 
@@ -250,9 +248,9 @@ int browse_draw() {
   mvhline(1, 0, '-', wincols);
   if(cur) {
     mvaddch(1, 3, ' ');
-    getpath(cur, tmp);
-    mvaddstr(1, 4, cropstr(tmp, wincols-8));
-    mvaddch(1, 4+((int)strlen(tmp) > wincols-8 ? wincols-8 : (int)strlen(tmp)), ' ');
+    tmp2 = getpath(cur);
+    mvaddstr(1, 4, cropstr(tmp2, wincols-8));
+    mvaddch(1, 4+((int)strlen(tmp2) > wincols-8 ? wincols-8 : (int)strlen(tmp2)), ' ');
   }
 
   if(!cur)
@@ -339,7 +337,6 @@ void browse_key_sel(int change) {
 #define toggle(x,y) if(x & y) x -=y; else x |= y
 
 int browse_key(int ch) {
-  char tmp[PATH_MAX];
   char sort = 0, nonfo = 0;
   struct dir *n, *r;
 
@@ -419,7 +416,7 @@ int browse_key(int ch) {
 
    /* refresh */
     case 'r':
-      calc_init(getpath(browse_dir, tmp), browse_dir->parent);
+      calc_init(getpath(browse_dir), browse_dir->parent);
       nonfo++;
       sort++;
       break;
diff --git a/src/calc.c b/src/calc.c
index ee97de78d02cfde0ef73e239ab96f08e894719df..ae3eaecc07ddbc8aaffc8e2a272f3539ed0eb5c2 100644
--- a/src/calc.c
+++ b/src/calc.c
@@ -53,28 +53,25 @@ char calc_smfs  = 0;
 
 /* global vars for internal use */
 char failed;             /* 1 on fatal error */
-char curpath[PATH_MAX];  /* last lstat()'ed item */
-char lasterr[PATH_MAX];  /* last unreadable dir/item */
-char errmsg[128];        /* error message, when err=1 */
+char *curpath;           /* last lstat()'ed item */
+char *lasterr;           /* last unreadable dir/item */
+char errmsg[128];        /* error message, when failed=1 */
 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 */
 long lastupdate;         /* time of the last screen update */
 int anpos;               /* position of the animation string */
+int curpathl = 0, lasterrl = 0;
 
 
-int calc_item(struct dir *par, char *path, char *name) {
-  char tmp[PATH_MAX];
+int calc_item(struct dir *par, char *name) {
   struct dir *t, *d;
   struct stat fs;
+  char *tmp;
 
   if(name[0] == '.' && (name[1] == '\0' || (name[1] == '.' && name[2] == '\0')))
     return 0;
 
-  /* path too long - ignore file */
-  if(strlen(path)+strlen(name)+1 > PATH_MAX)
-    return 1;
-
   /* allocate dir and fix references */
   d = calloc(sizeof(struct dir), 1);
   d->parent = par;
@@ -96,17 +93,22 @@ int calc_item(struct dir *par, char *path, char *name) {
   }
 #endif
 
-  /* lstat */
-  strcpy(tmp, path);
-  strcat(tmp, name);
+  /* update curpath */
+  tmp = getpath(d);
+  if((int)strlen(tmp)+1 > curpathl) {
+    curpathl = strlen(tmp)+1;
+    curpath = realloc(curpath, curpathl);
+  }
   strcpy(curpath, tmp);
-  if(lstat(tmp, &fs)) {
+
+  /* lstat */
+  if(lstat(d->name, &fs)) {
     d->flags |= FF_ERR;
     return 0;
   }
 
   /* check for excludes and same filesystem */
-  if(exclude_match(tmp))
+  if(exclude_match(curpath))
     d->flags |= FF_EXL;
 
   if(calc_smfs && curdev != fs.st_dev)
@@ -136,20 +138,26 @@ int calc_item(struct dir *par, char *path, char *name) {
 }
 
 
-/* recursively walk through the directory tree */
-int calc_dir(struct dir *dest, char *path) {
+/* recursively walk through the directory tree,
+   assumes path resides in the cwd */
+int calc_dir(struct dir *dest) {
   struct dir *t;
   DIR *dir;
+  char *tmp;
   struct dirent *dr;
-  char tmp[PATH_MAX];
-  int len;
+  int ch;
 
   if(input_handle(1))
     return 1;
 
   /* open directory */
-  if((dir = opendir(path)) == NULL) {
-    strcpy(lasterr, path);
+  if((dir = opendir(dest->name)) == NULL) {
+    tmp = getpath(dest);
+    if(lasterrl < (int)strlen(tmp)+1) {
+      lasterrl = strlen(tmp)+1;
+      lasterr = realloc(lasterr, lasterrl);
+    }
+    strcpy(lasterr, tmp);
     dest->flags |= FF_ERR;
     t = dest;
     while((t = t->parent) != NULL)
@@ -157,16 +165,15 @@ int calc_dir(struct dir *dest, char *path) {
     return 0;
   }
 
-  /* add leading slash */
-  len = strlen(path);
-  if(path[len-1] != '/') {
-    path[len] = '/';
-    path[++len] = '\0';
+  /* chdir */
+  if(chdir(dest->name) < 0) {
+      dest->flags |= FF_ERR;
+    return 0;
   }
 
   /* read directory */
   while((dr = readdir(dir)) != NULL) {
-    if(calc_item(dest, path, dr->d_name))
+    if(calc_item(dest, dr->d_name))
       dest->flags |= FF_ERR;
     if(input_handle(1))
       return 1;
@@ -190,13 +197,18 @@ int calc_dir(struct dir *dest, char *path) {
   }
 
   /* calculate subdirectories */
+  ch = 0;
   for(t=dest->sub; t!=NULL; t=t->next)
-    if(t->flags & FF_DIR && !(t->flags & FF_EXL || t->flags & FF_OTHFS)) {
-      strcpy(tmp, path);
-      strcat(tmp, t->name);
-      if(calc_dir(t, tmp))
+    if(t->flags & FF_DIR && !(t->flags & FF_EXL || t->flags & FF_OTHFS))
+      if(calc_dir(t))
         return 1;
-    }
+
+  /* chdir back */
+  if(chdir("..") < 0) {
+    failed = 1;
+    strcpy(errmsg, "Couldn't chdir to previous directory");
+    return 1;
+  }
 
   return 0;
 }
@@ -295,6 +307,11 @@ void calc_process() {
     strcpy(errmsg, "Directory not found");
     goto fail;
   }
+  if(path_chdir(tmp) < 0 || chdir("..") < 0) {
+    failed = 1;
+    strcpy(errmsg, "Couldn't chdir into directory");
+    goto fail;
+  }
 
   /* initialize parent dir */
   t = (struct dir *) calloc(1, sizeof(struct dir));
@@ -306,7 +323,7 @@ void calc_process() {
   curdev = fs.st_dev;
 
   /* start calculating */
-  if(!calc_dir(root, tmp) && !failed) {
+  if(!calc_dir(root) && !failed) {
     browse_init(root->sub);
 
     /* update references and free original item */
@@ -344,10 +361,22 @@ fail:
 
 
 void calc_init(char *dir, struct dir *org) {
-  failed = anpos = lasterr[0] = 0;
+  failed = anpos = 0;
   lastupdate = 999;
   orig = org;
+  if(curpathl == 0) {
+    curpathl = strlen(dir);
+    curpath = malloc(curpathl);
+  } else if(curpathl < (int)strlen(dir)+1) {
+    curpathl = strlen(dir)+1;
+    curpath = realloc(curpath, curpathl);
+  }
   strcpy(curpath, dir);
+  if(lasterrl == 0) {
+    lasterrl = 1;
+    lasterr = malloc(lasterrl);
+  }
+  lasterr[0] = 0;
   pstate = ST_CALC;
 }
 
diff --git a/src/delete.c b/src/delete.c
index 98139fece5a19179e20793681296bae87206fa57..502e436f7bb585eb0d3e593817f4ea94b62154d7 100644
--- a/src/delete.c
+++ b/src/delete.c
@@ -27,6 +27,7 @@
 #include "ncdu.h"
 #include "util.h"
 #include "browser.h"
+#include "path.h"
 
 #include <string.h>
 #include <errno.h>
@@ -42,10 +43,10 @@
 int delete_delay = 100;
 
 long lastupdate;
-struct dir *root, *nextsel;
+struct dir *root, *nextsel, *curdir;
 char noconfirm = 0,
      ignoreerr = 0,
-     state, seloption, curfile[PATH_MAX];
+     state, seloption;
 int lasterrno;
 
 
@@ -77,7 +78,7 @@ void delete_draw_confirm() {
 void delete_draw_progress() {
   nccreate(6, 60, "Deleting...");
 
-  ncaddstr(1, 2, cropstr(curfile, 47));
+  ncaddstr(1, 2, cropstr(getpath(curdir), 47));
   ncaddstr(4, 41, "Press q to abort");
 }
 
@@ -85,7 +86,7 @@ void delete_draw_progress() {
 void delete_draw_error() {
   nccreate(6, 60, "Error!");
 
-  ncprint(1, 2, "Can't delete %s:", cropstr(curfile, 42));
+  ncprint(1, 2, "Can't delete %s:", cropstr(getpath(curdir), 42));
   ncaddstr(2, 4, strerror(lasterrno));
 
   if(seloption == 0)
@@ -187,15 +188,14 @@ int delete_key(int ch) {
 int delete_dir(struct dir *dr) {
   struct dir *nxt, *cur;
   int r;
-  char file[PATH_MAX];
+  char *path;
 
-  getpath(dr, file);
-  if(file[strlen(file)-1] != '/')
-    strcat(file, "/");
-  strcat(file, dr->name);
+  /* calling path_chdir() this often isn't exactly efficient... */
+  path = getpath(dr->sub);
+  path_chdir(path);
 
   /* check for input or screen resizes */
-  strcpy(curfile, file);
+  curdir = dr;
   if(input_handle(1))
     return 1;
 
@@ -210,9 +210,9 @@ int delete_dir(struct dir *dr) {
           return 1;
       }
     }
-    r = rmdir(file);
+    r = rmdir(dr->name);
   } else
-    r = unlink(file);
+    r = unlink(dr->name);
 
   /* error occured, ask user what to do */
   if(r == -1 && !ignoreerr) {
diff --git a/src/util.c b/src/util.c
index d6002fa3e6fe30f9804281d97bd81e10f28388da..76f43d7b123355f47856a79bd9065212c536e5fe 100644
--- a/src/util.c
+++ b/src/util.c
@@ -35,6 +35,8 @@ int subwinr, subwinc;
 char cropstrdat[4096];
 char formatsizedat[8];
 char fullsizedat[20]; /* max: 999.999.999.999.999 */
+char *getpathdat;
+int getpathdatl = 0;
 
 
 char *cropstr(const char *from, int s) {
@@ -208,20 +210,36 @@ void freedir(struct dir *dr) {
 }
 
 
-char *getpath(struct dir *cur, char *to) {
-  struct dir *d, *list[100];
-  int c = 0;
+char *getpath(struct dir *cur) {
+  struct dir *d, **list;
+  int c, i;
 
-  for(d = cur; (d = d->parent) != NULL; )
+  c = i = 1;
+  for(d=cur; d!=NULL; d=d->parent) {
+    i += strlen(d->name)+1;
+    c++;
+  }
+
+  if(getpathdatl == 0) {
+    getpathdatl = i;
+    getpathdat = malloc(i);
+  } else if(getpathdatl < i) {
+    getpathdatl = i;
+    getpathdat = realloc(getpathdat, i);
+  }
+  list = malloc(c*sizeof(struct dir *));
+
+  c = 0;
+  for(d=cur; d!=NULL; d=d->parent)
     list[c++] = d;
 
-  to[0] = '\0';
+  getpathdat[0] = '\0';
   while(c--) {
-    if(list[c]->parent && list[c]->parent->name[strlen(list[c]->parent->name)-1] != '/')
-      strcat(to, "/");
-    strcat(to, list[c]->name);
+    if(list[c]->parent)
+      strcat(getpathdat, "/");
+    strcat(getpathdat, list[c]->name);
   }
-
-  return to;
+  free(list);
+  return getpathdat;
 }
 
diff --git a/src/util.h b/src/util.h
index 72f303882ae9ae4aac39ad99612736ea35bc3dcc..265f6fbfb02b55bc82d2c7ef1d1cf2a58dc5251c 100644
--- a/src/util.h
+++ b/src/util.h
@@ -74,8 +74,9 @@ char *fullsize(const off_t);
 /* recursively free()s a directory tree */
 void freedir(struct dir *);
 
-/* generates full path from a dir item */
-char *getpath(struct dir *, char *);
+/* generates full path from a dir item,
+   returned pointer will be overwritten with a subsequent call */
+char *getpath(struct dir *);
 
 #endif