diff --git a/src/calc.c b/src/calc.c
index 7a738787c0c1ef7c450464a3acaea6121edd4ad8..4a0bc7df15417d3f65d45ea5bd1e41f337388f5b 100644
--- a/src/calc.c
+++ b/src/calc.c
@@ -168,13 +168,12 @@ int calc_item(struct dir *par, char *name) {
     return 0;
 
   /* allocate dir and fix references */
-  d = calloc(sizeof(struct dir), 1);
+  d = calloc(SDIRSIZE+strlen(name), 1);
   d->parent = par;
   d->next = par->sub;
   par->sub = d;
   if(d->next)
     d->next->prev = d;
-  d->name = malloc(strlen(name)+1);
   strcpy(d->name, name);
 
 #ifdef __CYGWIN__
@@ -434,16 +433,15 @@ int calc_process() {
   }
 
   /* initialize parent dir */
-  t = (struct dir *) calloc(1, sizeof(struct dir));
+  n = orig ? strlen(orig->name) : strlen(path)+strlen(name)+1;
+  t = (struct dir *) calloc(1, SDIRSIZE+n);
   t->size = fs.st_blocks * S_BLKSIZE;
   t->asize = fs.st_size;
   t->flags |= FF_DIR;
   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;
     if(strcmp(path, "/"))
       strcpy(t->name, path);
diff --git a/src/dirlist.c b/src/dirlist.c
index 2239914a9734d2adc4c847893fa2db526c61a867..db0bd0dbe2870d7c1656a2c9304dd988645efbe4 100644
--- a/src/dirlist.c
+++ b/src/dirlist.c
@@ -197,7 +197,7 @@ void dirlist_open(struct dir *d) {
   dirlist_parent_alloc.flags &= ~FF_BSEL;
   if(head->parent->parent) {
     dirlist_parent = &dirlist_parent_alloc;
-    dirlist_parent->name = "..";
+    strcpy(dirlist_parent->name, "..");
     dirlist_parent->next = head;
     dirlist_parent->parent = head->parent;
     dirlist_parent->sub = head->parent;
diff --git a/src/global.h b/src/global.h
index e48a58bbdc75eb5ede2634625fb91f9b63bcce92..ceb1a2b59ba8eced5568a2ac6794dbdf9b06a42c 100644
--- a/src/global.h
+++ b/src/global.h
@@ -53,13 +53,21 @@
  *      fixed-size integers instead, which are much more predictable */
 struct dir {
   struct dir *parent, *next, *prev, *sub, *hlnk;
-  char *name;
   off_t size, asize;
+  ino_t ino;
   unsigned long items;
-  unsigned char flags;
   dev_t dev;
-  ino_t ino;
+  unsigned char flags;
+  char name[3]; /* must be large enough to hold ".." */
 }; 
+/* sizeof(total dir) = SDIRSIZE + strlen(name) = sizeof(struct dir) - 3 + strlen(name) + 1 */
+#define SDIRSIZE (sizeof(struct dir)-2)
+
+/* Ideally, the name array should be as large as the padding added to the end of
+ * the struct, but I can't figure out a portable way to calculate this. We can
+ * be sure that it's at least 3 bytes, though, as the struct is aligned to at
+ * least 4 bytes and the flags field is a single byte. */
+
 
 /* program state */
 extern int pstate;
diff --git a/src/util.c b/src/util.c
index a0dc92dd056397efcd71715e1f642395a91f727e..bea2483c4fbf0f195a38149d55b35ba8f7cc6b3b 100644
--- a/src/util.c
+++ b/src/util.c
@@ -211,7 +211,6 @@ void freedir_rec(struct dir *dr) {
     freedir_hlnk(tmp);
     /* remove item */
     if(tmp->sub) freedir_rec(tmp->sub);
-    free(tmp->name);
     tmp2 = tmp->next;
     free(tmp);
   }
@@ -245,7 +244,6 @@ void freedir(struct dir *dr) {
     tmp->items -= dr->items+1;
   }
 
-  free(dr->name);
   free(dr);
 }