From d57dbed7d57a54ad2b7634d95cc18cc6c90b9045 Mon Sep 17 00:00:00 2001
From: Brian Carrier <carrier@sleuthkit.org>
Date: Mon, 2 Feb 2009 02:29:42 +0000
Subject: [PATCH] Changed fix for BUG 2534449

---
 CHANGES.txt         |   3 +
 tsk3/fs/fs_dir.c    |   3 +-
 tsk3/fs/ifind_lib.c | 201 ++++++++++++++++++++++++--------------------
 3 files changed, 115 insertions(+), 92 deletions(-)

diff --git a/CHANGES.txt b/CHANGES.txt
index 2d78efca3..e23ba15b9 100644
--- a/CHANGES.txt
+++ b/CHANGES.txt
@@ -32,6 +32,9 @@ to meta type).  (Bug: 2389901). Reported by Barry Grundy.
 shown if the MFT address was changed to 0 because fs_dir_add was
 checking the address and name.  Reported by Andy Bontoft.
 
+1/29/09: Update: Fixed fix for bug 2534449.  The fix is in ifind 
+instead of fs_dir_add().  
+
 
 ---------------- VERSION 3.0.0 -------------- 
 0/00/00: Update: Many, many, many API changes.
diff --git a/tsk3/fs/fs_dir.c b/tsk3/fs/fs_dir.c
index ce2cd4c21..6e1e741d1 100644
--- a/tsk3/fs/fs_dir.c
+++ b/tsk3/fs/fs_dir.c
@@ -102,7 +102,8 @@ tsk_fs_dir_add(TSK_FS_DIR * a_fs_dir, const TSK_FS_NAME * a_fs_name)
 
     // see if we already have it in the buffer / queue
     for (i = 0; i < a_fs_dir->names_used; i++) {
-        if (strcmp(a_fs_name->name, a_fs_dir->names[i].name) == 0) {
+        if ((a_fs_name->meta_addr == a_fs_dir->names[i].meta_addr) &&
+            (strcmp(a_fs_name->name, a_fs_dir->names[i].name) == 0)) {
 
             /* We do not check type because then we cannot detect NTFS orphan file
              * duplicates that are added as "-/r" while a similar entry exists as "r/r"  
diff --git a/tsk3/fs/ifind_lib.c b/tsk3/fs/ifind_lib.c
index e20307e42..54311d99e 100644
--- a/tsk3/fs/ifind_lib.c
+++ b/tsk3/fs/ifind_lib.c
@@ -153,7 +153,10 @@ tsk_fs_ifind_par(TSK_FS_INFO * fs, TSK_FS_IFIND_FLAG_ENUM lclflags,
 /**
  * \ingroup fslib
  * 
- * Find the meta data address for a given file name (UTF-8)
+ * Find the meta data address for a given file name (UTF-8).
+ * The basic idea of the function is to break the given name into its
+ * subdirectories and start looking for each (starting in the root
+ * directory). 
  *
  * @param a_fs FS to analyze
  * @param a_path UTF-8 path of file to search for
@@ -171,17 +174,17 @@ tsk_fs_path2inum(TSK_FS_INFO * a_fs, const char *a_path,
     char *cur_attr;             // The "current" attribute of the dir we are looking for
     char *strtok_last;
     TSK_INUM_T next_meta;
-
+    uint8_t is_done;
     *a_result = 0;
 
-    // copy to a buffer that we can modify
+    // copy path to a buffer that we can modify
     clen = strlen(a_path) + 1;
     if ((cpath = (char *) tsk_malloc(clen)) == NULL) {
         return -1;
     }
     strncpy(cpath, a_path, clen);
 
-
+    // Get the first part of the directory path. 
     cur_dir = (char *) strtok_r(cpath, "/", &strtok_last);
     cur_attr = NULL;
 
@@ -218,25 +221,28 @@ tsk_fs_path2inum(TSK_FS_INFO * a_fs, const char *a_path,
 
     // we loop until we know the outcome and then exit. 
     // everything should return from inside the loop.
-    while (1) {
+    is_done = 0;
+    while (is_done == 0) {
         size_t i;
-        uint8_t found_name;
+        TSK_FS_FILE *fs_file_alloc = NULL;      // set to the allocated file that is our target
+        TSK_FS_FILE *fs_file_del = NULL;        // set to an unallocated file that matches our criteria
+
         TSK_FS_DIR *fs_dir = NULL;
 
+        // open the next directory in the recursion
         if ((fs_dir = tsk_fs_dir_open_meta(a_fs, next_meta)) == NULL) {
             free(cpath);
             return -1;
         }
 
-        // will be set to 1 if an entry in this dir matches the target
-        found_name = 0;
-
         // cycle through each entry
         for (i = 0; i < tsk_fs_dir_getsize(fs_dir); i++) {
 
             TSK_FS_FILE *fs_file;
+            uint8_t found_name = 0;
 
             if ((fs_file = tsk_fs_dir_get(fs_dir, i)) == NULL) {
+                tsk_fs_dir_close(fs_dir);
                 free(cpath);
                 return -1;
             }
@@ -249,7 +255,8 @@ tsk_fs_path2inum(TSK_FS_INFO * a_fs, const char *a_path,
              */
             if (TSK_FS_TYPE_ISFFS(a_fs->ftype)
                 || TSK_FS_TYPE_ISEXT(a_fs->ftype)) {
-                if ((fs_file->name->name) && (strcmp(fs_file->name->name, cur_dir) == 0)) {
+                if ((fs_file->name->name)
+                    && (strcmp(fs_file->name->name, cur_dir) == 0)) {
                     found_name = 1;
                 }
             }
@@ -257,18 +264,21 @@ tsk_fs_path2inum(TSK_FS_INFO * a_fs, const char *a_path,
              * the short name 
              */
             else if (TSK_FS_TYPE_ISFAT(a_fs->ftype)) {
-                if ((fs_file->name->name) && (strcasecmp(fs_file->name->name, cur_dir) == 0)) {
+                if ((fs_file->name->name)
+                    && (strcasecmp(fs_file->name->name, cur_dir) == 0)) {
                     found_name = 1;
                 }
-                else if ((fs_file->name->shrt_name) && (strcasecmp(fs_file->name->shrt_name,
-                        cur_dir) == 0)) {
+                else if ((fs_file->name->shrt_name)
+                    && (strcasecmp(fs_file->name->shrt_name,
+                            cur_dir) == 0)) {
                     found_name = 1;
                 }
             }
 
             /* NTFS gets a case insensitive comparison */
             else if (TSK_FS_TYPE_ISNTFS(a_fs->ftype)) {
-                if ((fs_file->name->name) && (strcasecmp(fs_file->name->name, cur_dir) == 0)) {
+                if ((fs_file->name->name)
+                    && (strcasecmp(fs_file->name->name, cur_dir) == 0)) {
                     /*  ensure we have the right attribute name */
                     if (cur_attr == NULL) {
                         found_name = 1;
@@ -285,35 +295,30 @@ tsk_fs_path2inum(TSK_FS_INFO * a_fs, const char *a_path,
                                 if (!fs_attr)
                                     continue;
 
-                                if ((fs_attr->name) && (strcasecmp(fs_attr->name,
-                                        cur_attr) == 0)) {
+                                if ((fs_attr->name)
+                                    && (strcasecmp(fs_attr->name,
+                                            cur_attr) == 0)) {
                                     found_name = 1;
                                 }
                             }
                         }
-                        if (found_name != 1) {
-                            free(cpath);
-
-                            if (tsk_verbose)
-                                tsk_fprintf(stderr,
-                                    "Attribute name (%s) not found in %s: %"
-                                    PRIuINUM "\n", cur_attr, cur_dir,
-                                    fs_file->name->meta_addr);
-                            return 1;
-                        }
                     }
                 }
             }
 
             /* HFS+ can be case-sensitive or case-insensitive */
             else if (TSK_FS_TYPE_ISHFS(a_fs->ftype)) {
-                HFS_INFO *hfs = (HFS_INFO *)a_fs;
-                if ( hfs->is_case_sensitive ) {
-                    if (strcmp(fs_file->name->name, cur_dir) == 0) {
+                HFS_INFO *hfs = (HFS_INFO *) a_fs;
+                if (hfs->is_case_sensitive) {
+                    if ((fs_file->name->name)
+                        && (strcmp(fs_file->name->name, cur_dir) == 0)) {
                         found_name = 1;
                     }
-                } else {
-                    if (strcasecmp(fs_file->name->name, cur_dir) == 0) {
+                }
+                else {
+                    if ((fs_file->name->name)
+                        && (strcasecmp(fs_file->name->name,
+                                cur_dir) == 0)) {
                         found_name = 1;
                     }
                 }
@@ -321,88 +326,102 @@ tsk_fs_path2inum(TSK_FS_INFO * a_fs, const char *a_path,
 
             /* Unknown how to compare names in this filesystem */
             else {
+                tsk_fs_dir_close(fs_dir);
+                free(cpath);
                 tsk_errno = TSK_ERR_FS_GENFS;
                 snprintf(tsk_errstr, TSK_ERRSTR_L,
-                         "tsk_fs_path2inum: File System type not supported for file name comparison (%X)",
-                         a_fs->ftype);
-                return TSK_WALK_ERROR;
+                    "tsk_fs_path2inum: File System type not supported for file name comparison (%X)",
+                    a_fs->ftype);
+                return -1;
             }
-			
-            /* if found_name is 1, this entry was our target.  Update
-             * data and move on to the next step, if needed. */
-            if (found_name) {
-                const char *pname;
 
-                pname = cur_dir;        // save a copy of the current name pointer
+            if (found_name) {
+                /* If we found our file and it is allocated, then stop. If
+                 * it is unallocated, keep on going to see if we can get
+                 * an allocated hit */
+                if (fs_file->name->flags & TSK_FS_NAME_FLAG_ALLOC) {
+                    fs_file_alloc = fs_file;
+                    break;
+                }
+                else {
+                    // if we already have an unalloc and its addr is 0, then use the new one
+                    if ((fs_file_del)
+                        && (fs_file_del->name->meta_addr == 0)) {
+                        tsk_fs_file_close(fs_file_del);
+                    }
+                    fs_file_del = fs_file;
+                }
+            }
+            // close the file if we did not save it for future analysis.
+            else {
+                tsk_fs_file_close(fs_file);
+                fs_file = NULL;
+            }
+        }
 
-                // advance to the next name
-                cur_dir = (char *) strtok_r(NULL, "/", &(strtok_last));
-                cur_attr = NULL;
+        // we found a directory, go into it 
+        if ((fs_file_alloc) || (fs_file_del)) {
 
-                if (tsk_verbose)
-                    tsk_fprintf(stderr,
-                        "Found it (%s), now looking for %s\n", pname,
-                        cur_dir);
+            const char *pname;
+            TSK_FS_FILE *fs_file_tmp;
 
+            // choose the alloc one first (if they both exist)
+            if (fs_file_alloc)
+                fs_file_tmp = fs_file_alloc;
+            else
+                fs_file_tmp = fs_file_del;
 
-                /* That was the last name in the path -- we found the file! */
-                if (cur_dir == NULL) {
-                    *a_result = fs_file->name->meta_addr;
+            pname = cur_dir;    // save a copy of the current name pointer
 
-                    // make a copy if one was requested
-                    if (a_fs_name) {
-                        tsk_fs_name_copy(a_fs_name, fs_file->name);
-                    }
+            // advance to the next name
+            cur_dir = (char *) strtok_r(NULL, "/", &(strtok_last));
+            cur_attr = NULL;
 
-                    free(cpath);
-                    return 0;
-                }
+            if (tsk_verbose)
+                tsk_fprintf(stderr,
+                    "Found it (%s), now looking for %s\n", pname, cur_dir);
 
-                // update the attribute field, if needed
-                if (TSK_FS_TYPE_ISNTFS(a_fs->ftype)
-                    && ((cur_attr = strchr(cur_dir, ':')) != NULL)) {
-                    *(cur_attr) = '\0';
-                    cur_attr++;
-                }
+            /* That was the last name in the path -- we found the file! */
+            if (cur_dir == NULL) {
+                *a_result = fs_file_tmp->name->meta_addr;
 
-                /* Before we recurse into this directory, check it */
-                if (fs_file->meta == NULL) {
-                    free(cpath);
-                    if (tsk_verbose)
-                        tsk_fprintf(stderr,
-                            "Name does not point to an inode (%s)\n",
-                            fs_file->name->name);
-                    return 1;
+                // make a copy if one was requested
+                if (a_fs_name) {
+                    tsk_fs_name_copy(a_fs_name, fs_file_tmp->name);
                 }
 
-                /* Make sure this name is for a directory */
-                else if (fs_file->meta->type != TSK_FS_META_TYPE_DIR) {
-                    free(cpath);
-                    if (tsk_verbose)
-                        tsk_fprintf(stderr,
-                            "Name is not for a directory (%s) (type: %x)\n",
-                            fs_file->name->name, fs_file->meta->type);
-                    return 1;
-                }
+                tsk_fs_dir_close(fs_dir);
+                free(cpath);
+                return 0;
+            }
 
-                next_meta = fs_file->name->meta_addr;
+            // update the attribute field, if needed
+            if (TSK_FS_TYPE_ISNTFS(a_fs->ftype)
+                && ((cur_attr = strchr(cur_dir, ':')) != NULL)) {
+                *(cur_attr) = '\0';
+                cur_attr++;
             }
 
-            tsk_fs_file_close(fs_file);
-            fs_file = NULL;
+            // update the value for the next directory to open
+            next_meta = fs_file_tmp->name->meta_addr;
 
-            if (found_name)
-                break;
+            if (fs_file_alloc) {
+                tsk_fs_file_close(fs_file_alloc);
+                fs_file_alloc = NULL;
+            }
+            if (fs_file_del) {
+                tsk_fs_file_close(fs_file_del);
+                fs_file_del = NULL;
+            }
+        }
+
+        // no hit in directory
+        else {
+            is_done = 1;
         }
 
         tsk_fs_dir_close(fs_dir);
         fs_dir = NULL;
-
-        // didn't find the name in this directory...
-        if (found_name == 0) {
-            free(cpath);
-            return 1;
-        }
     }
 
     free(cpath);
-- 
GitLab