diff --git a/CHANGES.txt b/CHANGES.txt
index b9d611ebc4568a06a7a9b64a4ac4566af97a6476..68732c58320957234fb937b38f0b87938efdff40 100644
--- a/CHANGES.txt
+++ b/CHANGES.txt
@@ -49,6 +49,8 @@ attributes.  Reported and patch by Jamie Butler (Mandiant).
 
 4/8/09: Fixed typo bugs in sorter as reported by Drew Hunt. 
 
+4/11/09: Feature. Addressed issue 2734458 regarding slow NTFS listing time by adding a orphan cache map.  
+
 
 ---------------- VERSION 3.0.0 -------------- 
 0/00/00: Update: Many, many, many API changes.
diff --git a/tsk3/fs/ntfs.c b/tsk3/fs/ntfs.c
index 586dd640bb9c878f25a36e92bcae36d973eb77ab..24713092f4757d62afec82ef708a431115a4c24d 100644
--- a/tsk3/fs/ntfs.c
+++ b/tsk3/fs/ntfs.c
@@ -1619,7 +1619,7 @@ ntfs_proc_attrseq(NTFS_INFO * ntfs,
 
             /* Make sure it is NULL Terminated */
             else if ((uintptr_t) name8 >= (uintptr_t) name + sizeof(name))
-                name[sizeof(name)-1] = '\0';
+                name[sizeof(name) - 1] = '\0';
             else
                 *name8 = '\0';
 
@@ -1994,7 +1994,7 @@ ntfs_proc_attrseq(NTFS_INFO * ntfs,
             /* Make sure it is NULL Terminated */
             else if ((uintptr_t) name8 >=
                 (uintptr_t) fs_name->name + sizeof(fs_name->name))
-                fs_name->name[sizeof(fs_name->name)-1] = '\0';
+                fs_name->name[sizeof(fs_name->name) - 1] = '\0';
             else
                 *name8 = '\0';
 
@@ -3637,7 +3637,7 @@ ntfs_fsstat(TSK_FS_INFO * fs, FILE * hFile)
 
         /* Make sure it is NULL Terminated */
         else if ((uintptr_t) name8 >= (uintptr_t) asc + sizeof(asc))
-            asc[sizeof(asc)-1] = '\0';
+            asc[sizeof(asc) - 1] = '\0';
         else
             *name8 = '\0';
         tsk_fprintf(hFile, "Volume Name: %s\n", asc);
@@ -3720,7 +3720,7 @@ ntfs_fsstat(TSK_FS_INFO * fs, FILE * hFile)
 
         /* Make sure it is NULL Terminated */
         else if ((uintptr_t) name8 >= (uintptr_t) asc + sizeof(asc))
-            asc[sizeof(asc)-1] = '\0';
+            asc[sizeof(asc) - 1] = '\0';
         else
             *name8 = '\0';
         tsk_fprintf(hFile, "%s (%" PRIu32 ")   ",
@@ -4273,6 +4273,8 @@ ntfs_close(TSK_FS_INFO * fs)
         tsk_list_free(fs->list_inum_named);
         fs->list_inum_named = NULL;
     }
+    if (ntfs->orphan_map)
+        ntfs_orphan_map_free(ntfs);
 
     free(fs);
 }
@@ -4590,6 +4592,7 @@ ntfs_open(TSK_IMG_INFO * img_info, TSK_OFF_T offset,
     // initialize the caches
     ntfs->attrdef = NULL;
     fs->list_inum_named = NULL;
+    ntfs->orphan_map = NULL;
 
 
     if (tsk_verbose) {
diff --git a/tsk3/fs/ntfs_dent.c b/tsk3/fs/ntfs_dent.c
index 03261adfd6ec5a03da3348bf87d9b412a4a20c4c..9a517305cae3af50e61c2e639cd1306a2f259a8b 100644
--- a/tsk3/fs/ntfs_dent.c
+++ b/tsk3/fs/ntfs_dent.c
@@ -5,7 +5,7 @@
 ** name layer support for the NTFS file system
 **
 ** Brian Carrier [carrier <at> sleuthkit [dot] org]
-** Copyright (c) 2006-2008 Brian Carrier, Basis Technology.  All Rights reserved
+** Copyright (c) 2006-2009 Brian Carrier, Basis Technology.  All Rights reserved
 ** Copyright (c) 2003-2005 Brian Carrier.  All rights reserved
 **
 ** TASK
@@ -29,46 +29,178 @@
 
 
 
+/* When we list deleted files in a directory, we need to look at all MFT entries
+ * to find unallocated ones that point to the given directory as teh parent directory.
+ * We cache these results in an "orphan map". */
 
+/** \internal
+ * Extend the number of addresses in the map buffer.
+ * @param map map entry to extend
+ * @returns 1 on error and 0 otherwise
+ */
+static uint8_t
+ntfs_orphan_map_extend(NTFS_PAR_MAP * map)
+{
+    map->alloc_cnt += 8;
+    if ((map->addrs =
+            (TSK_INUM_T *) tsk_realloc(map->addrs,
+                sizeof(TSK_INUM_T) * map->alloc_cnt)) == NULL)
+        return 1;
+    return 0;
+}
 
+/** \internal
+ * Allocate a new map entry with a default address buffer.
+ * @returns NULL on error
+ */
+static NTFS_PAR_MAP *
+ntfs_orphan_map_alloc()
+{
+    NTFS_PAR_MAP *map;
 
-/*******************************************************************************
-* Find an unallocated NTFS MFT entry based on its parent directory
-*/
+    if ((map =
+            (NTFS_PAR_MAP *) tsk_malloc((size_t) sizeof(NTFS_PAR_MAP))) ==
+        NULL) {
+        return NULL;
+    }
 
-typedef struct {
-    TSK_FS_NAME *fs_name;
-    TSK_INUM_T parinode;
-    TSK_FS_DIR *fs_dir;
-} NTFS_PAR_DATA;
+    map->alloc_cnt = 8;
+    if ((map->addrs =
+            (TSK_INUM_T *) tsk_malloc(sizeof(TSK_INUM_T) *
+                map->alloc_cnt)) == NULL) {
+        free(map);
+        return NULL;
+    }
+    return map;
+}
 
+/** \internal
+ * Add a parent and child pair to the map stored in NTFS_INFO
+ * @param ntfs structure to add the pair to
+ * @param par Parent address
+ * @param child Child address
+ * @returns 1 on error 
+ */
+static uint8_t
+ntfs_orphan_map_add(NTFS_INFO * ntfs, TSK_INUM_T par, TSK_INUM_T child)
+{
+    NTFS_PAR_MAP *map = NULL;
+    NTFS_PAR_MAP *tmp = NULL;
+
+    // look for the parent in an existing list
+    for (tmp = ntfs->orphan_map; tmp; tmp = tmp->next) {
+        if (tmp->par_addr == par) {
+            map = tmp;
+            break;
+        }
+        else if (tmp->par_addr > par) {
+            break;
+        }
+    }
 
-/* dent call back for tsk_fs_ifind_par to find unallocated files 
-* based on parent directory
-*/
+    // add a new entry for it
+    if (map == NULL) {
+        if ((map = ntfs_orphan_map_alloc()) == NULL) {
+            return 1;
+        }
+
+        map->par_addr = par;
+        if (ntfs->orphan_map == NULL) {
+            ntfs->orphan_map = map;
+        }
+        else {
+            // head of the list
+            if (ntfs->orphan_map->par_addr > par) {
+                map->next = ntfs->orphan_map;
+                ntfs->orphan_map = map;
+            }
+            else {
+                NTFS_PAR_MAP *prev = NULL;
+                // somewhere in the middle of the list
+                for (tmp = ntfs->orphan_map; tmp; tmp = tmp->next) {
+                    if (tmp->par_addr > par) {
+                        map->next = tmp;
+                        prev->next = map;
+                        break;
+                    }
+                    prev = tmp;
+                }
+
+                // at the end of the list
+                if (map->next == NULL)
+                    prev->next = map;
+            }
+        }
+    }
+
+    // add this address to it
+    if (map->used_cnt == map->alloc_cnt)
+        if (ntfs_orphan_map_extend(map))
+            return 1;
+
+    map->addrs[map->used_cnt] = child;
+    map->used_cnt++;
+
+    return 0;
+}
+
+/** \internal
+ * Look up a map entry by the parent address. 
+ * @param ntfs File system that has already been analyzed
+ * @param par Parent inode to find child files for
+ * @returns NULL on error 
+ */
+static NTFS_PAR_MAP *
+ntfs_orphan_map_get(NTFS_INFO * ntfs, TSK_INUM_T par)
+{
+    NTFS_PAR_MAP *tmp = NULL;
+
+    // look for the parent in an existing list
+    for (tmp = ntfs->orphan_map; tmp; tmp = tmp->next) {
+        if (tmp->par_addr == par) {
+            return tmp;
+        }
+        else if (tmp->par_addr > par) {
+            return NULL;
+        }
+    }
+    return NULL;
+}
+
+void
+ntfs_orphan_map_free(NTFS_INFO * a_ntfs)
+{
+    NTFS_PAR_MAP *tmp = NULL;
+
+    if (a_ntfs->orphan_map == NULL)
+        return;
+
+    tmp = a_ntfs->orphan_map;
+    while (tmp) {
+        NTFS_PAR_MAP *tmp2;
+        free(tmp->addrs);
+        tmp2 = tmp->next;
+        free(tmp);
+        tmp = tmp2;
+    }
+    a_ntfs->orphan_map = NULL;
+}
+
+
+/* inode_walk callback that is used to populate the orphan_map
+ * structure in NTFS_INFO */
 static TSK_WALK_RET_ENUM
-ntfs_par_act(TSK_FS_FILE * fs_file, void *ptr)
+ntfs_orphan_act(TSK_FS_FILE * fs_file, void *ptr)
 {
-    NTFS_PAR_DATA *par_data = (NTFS_PAR_DATA *) ptr;
+    NTFS_INFO *ntfs = (NTFS_INFO *) fs_file->fs_info;
     TSK_FS_META_NAME_LIST *fs_name_list;
 
     /* go through each file name structure */
     fs_name_list = fs_file->meta->name2;
     while (fs_name_list) {
-
-        // we got our target
-        if (fs_name_list->par_inode == par_data->parinode) {
-
-            /* Fill in the basics of the fs_name entry 
-             * so we can print in the fls formats */
-            par_data->fs_name->meta_addr = fs_file->meta->addr;
-            par_data->fs_name->flags = TSK_FS_NAME_FLAG_UNALLOC;
-            strncpy(par_data->fs_name->name, fs_name_list->name,
-                par_data->fs_name->name_size);
-            par_data->fs_name->type = TSK_FS_NAME_TYPE_UNDEF;
-
-            tsk_fs_dir_add(par_data->fs_dir, par_data->fs_name);
-        }
+        if (ntfs_orphan_map_add(ntfs, fs_name_list->par_inode,
+                fs_file->meta->addr))
+            return TSK_WALK_ERROR;
         fs_name_list = fs_name_list->next;
     }
     return TSK_WALK_CONT;
@@ -76,6 +208,8 @@ ntfs_par_act(TSK_FS_FILE * fs_file, void *ptr)
 
 
 
+/****************/
+
 static uint8_t
 ntfs_dent_copy(NTFS_INFO * ntfs, ntfs_idxentry * idxe,
     TSK_FS_NAME * fs_name)
@@ -493,7 +627,7 @@ ntfs_dir_open_meta(TSK_FS_INFO * a_fs, TSK_FS_DIR ** a_fs_dir,
     int off;
     TSK_OFF_T idxalloc_len;
     TSK_FS_LOAD_FILE load_file;
-    NTFS_PAR_DATA data;
+    NTFS_PAR_MAP *map;
 
     /* In this function, we will return immediately if we get an error.
      * If we get corruption though, we will record that in 'retval_final'
@@ -940,35 +1074,72 @@ ntfs_dir_open_meta(TSK_FS_INFO * a_fs, TSK_FS_DIR ** a_fs_dir,
         free(idxalloc);
     }
 
-    // add the orphan files that still point to this directory
 
-    data.parinode = a_addr;
-    data.fs_dir = fs_dir;
-    data.fs_name = tsk_fs_name_alloc(256, 0);
-    if (data.fs_name == NULL)
-        return TSK_ERR;
+    // get the orphan files
+    // load and cache the map if it has not already been done
+    if (ntfs->orphan_map == NULL) {
+        if (a_fs->inode_walk(a_fs, a_fs->first_inum, a_fs->last_inum,
+                TSK_FS_META_FLAG_UNALLOC, ntfs_orphan_act, NULL)) {
+            return TSK_ERR;
+        }
+    }
 
-    /* Walk unallocated MFT entries */
-    if (a_fs->inode_walk(a_fs, a_fs->first_inum, a_fs->last_inum,
-            TSK_FS_META_FLAG_UNALLOC, ntfs_par_act, &data)) {
-        tsk_fs_name_free(data.fs_name);
-        return TSK_ERR;
+    // see if there are any entries for this dir
+    map = ntfs_orphan_map_get(ntfs, a_addr);
+    if (map != NULL) {
+        int a;
+        TSK_FS_NAME *fs_name;
+        TSK_FS_FILE *fs_file_orp = NULL;
+
+        if ((fs_name = tsk_fs_name_alloc(256, 0)) == NULL)
+            return TSK_ERR;
+
+        fs_name->flags = TSK_FS_NAME_FLAG_UNALLOC;
+        fs_name->type = TSK_FS_NAME_TYPE_UNDEF;
+
+        for (a = 0; a < map->used_cnt; a++) {
+            /* Fill in the basics of the fs_name entry 
+             * so we can print in the fls formats */
+            fs_name->meta_addr = map->addrs[a];
+
+            // lookup the file to get its name (we did not cache that)
+            fs_file_orp =
+                tsk_fs_file_open_meta(a_fs, fs_file_orp, map->addrs[a]);
+            if ((fs_file_orp) && (fs_file_orp->meta)
+                && (fs_file_orp->meta->name2)) {
+                TSK_FS_META_NAME_LIST *n2 = fs_file_orp->meta->name2;
+                while (n2) {
+                    if (n2->par_inode == a_addr) {
+                        strncpy(fs_name->name, n2->name,
+                            fs_name->name_size);
+                        tsk_fs_dir_add(fs_dir, fs_name);
+                    }
+                    n2 = n2->next;
+                }
+            }
+        }
+        tsk_fs_name_free(fs_name);
     }
 
     // if we are listing the root directory, add the Orphan directory entry
     if (a_addr == a_fs->root_inum) {
-        if (tsk_fs_dir_make_orphan_dir_name(a_fs, data.fs_name)) {
-            tsk_fs_name_free(data.fs_name);
+        TSK_FS_NAME *fs_name;
+
+        if ((fs_name = tsk_fs_name_alloc(256, 0)) == NULL)
+            return TSK_ERR;
+
+        if (tsk_fs_dir_make_orphan_dir_name(a_fs, fs_name)) {
+            tsk_fs_name_free(fs_name);
             return TSK_ERR;
         }
 
-        if (tsk_fs_dir_add(fs_dir, data.fs_name)) {
-            tsk_fs_name_free(data.fs_name);
+        if (tsk_fs_dir_add(fs_dir, fs_name)) {
+            tsk_fs_name_free(fs_name);
             return TSK_ERR;
         }
+        tsk_fs_name_free(fs_name);
     }
 
-    tsk_fs_name_free(data.fs_name);
 
     return retval_final;
 }
diff --git a/tsk3/fs/tsk_ntfs.h b/tsk3/fs/tsk_ntfs.h
index b7cdac372d8ed7136b1b308b1c0a0906b5d2753c..b67b39b2ce58906d7d0628ae558515cc4451d643 100644
--- a/tsk3/fs/tsk_ntfs.h
+++ b/tsk3/fs/tsk_ntfs.h
@@ -651,6 +651,16 @@ extern "C" {
     };
 #endif
 
+    typedef struct NTFS_PAR_MAP NTFS_PAR_MAP;
+    struct NTFS_PAR_MAP {
+        TSK_INUM_T par_addr;    // parent dir address this structure is for
+        NTFS_PAR_MAP *next;     // pointer to next structure in list
+        int alloc_cnt;          // number of allocated INUM_T structures in addr
+        int used_cnt;           // number of used entries in addr
+        TSK_INUM_T *addrs;      // array for address of unallocated files in this dir
+    };
+
+
 /************************************************************************
 */
     typedef struct {
@@ -674,6 +684,7 @@ extern "C" {
         TSK_DADDR_T bmap_buf_off;       /* offset cluster in cached bitmap */
         ntfs_attrdef *attrdef;  // buffer of attrdef file contents
         size_t attrdef_len;     // length of addrdef buffer
+        NTFS_PAR_MAP *orphan_map;       // map that lists par directory to its orphans.
 
 #if TSK_USE_SID
         NTFS_SDS_ENTRY *sds;    /* Data run of ntfs_attr_sds */
@@ -693,6 +704,7 @@ extern "C" {
         ntfs_dir_open_meta(TSK_FS_INFO * a_fs, TSK_FS_DIR ** a_fs_dir,
         TSK_INUM_T a_addr);
 
+    extern void ntfs_oprhan_map_free(NTFS_INFO * a_ntfs);
 #ifdef __cplusplus
 }
 #endif