From 8eb6547bb13b605b98a8f60cbfeec22e0fe08b56 Mon Sep 17 00:00:00 2001
From: Ann Priestman <apriestman@basistech.com>
Date: Tue, 25 Oct 2016 09:36:51 -0400
Subject: [PATCH] Adding fs_file entries for slack

---
 tsk/auto/auto_db.cpp       | 99 +++++++++++++++++++++++++++++++++++++-
 tsk/auto/db_postgresql.cpp | 49 ++++++++++++++++++-
 tsk/auto/db_sqlite.cpp     | 57 +++++++++++++++++++++-
 tsk/auto/tsk_case_db.h     |  4 ++
 tsk/auto/tsk_db.h          |  1 +
 5 files changed, 207 insertions(+), 3 deletions(-)

diff --git a/tsk/auto/auto_db.cpp b/tsk/auto/auto_db.cpp
index 949be1345..e8cc374f1 100644
--- a/tsk/auto/auto_db.cpp
+++ b/tsk/auto/auto_db.cpp
@@ -348,6 +348,103 @@ TSK_RETVAL_ENUM
         return TSK_ERR;
     }
 
+    //return insertSlackFileData(fs_file, fs_attr, path, md5, known);
+    return TSK_OK;
+}
+
+TSK_RETVAL_ENUM
+    TskAutoDb::insertSlackFileData(TSK_FS_FILE * fs_file,
+    const TSK_FS_ATTR * fs_attr, const char *path,
+    const unsigned char *const md5,
+    const TSK_DB_FILES_KNOWN_ENUM known)
+{
+    // Should do check that file name does not already end in "-slack". Or maybe can just test for type somehow later
+    int name_length;
+    TSK_FS_NAME* slack_name;
+    TSK_FS_NAME* orig_name;
+
+    if((fs_file->name == NULL) || (fs_file->name->name == NULL) ||
+        (fs_file->meta == NULL)){
+            printf("Null name, name->name, or meta\n");
+    } 
+    else {
+        printf("fs_file: %s\n  size: %d\n  content len:  %d\n", fs_file->name->name, fs_file->meta->size,
+            fs_file->meta->content_len);
+    }
+
+    if(fs_file->meta == NULL){
+        printf("  fs_file->meta is null, giving up\n");
+        return TSK_OK;
+    }
+    printf("  type: %x\n", fs_file->meta->type);
+    if(fs_file->meta->type != TSK_FS_META_TYPE_REG){
+        printf("  Not a file\n");
+        return TSK_OK;
+    }
+    if(fs_file->name == NULL){
+        printf("  fs_file->name is null! giving up\n");
+        return TSK_OK;
+    }
+
+    if(fs_file->name->name == NULL){
+        printf("  fs_file->name->name is null! giving up\n");
+        return TSK_OK;
+    }
+
+    if(fs_file->meta->attr_state == TSK_FS_META_ATTR_STUDIED){
+        printf("  attr_state is studied\n");
+        TSK_FS_ATTR *fs_attr_cur;
+        for (fs_attr_cur = fs_file->meta->attr->head; fs_attr_cur;fs_attr_cur = fs_attr_cur->next) {
+            printf("  attr name: %s\n", fs_attr_cur->name);
+            printf("    flags: %x (non-resident: %x)", fs_attr_cur->flags, fs_attr_cur->flags & TSK_FS_ATTR_NONRES);
+            printf("    attr type: %x\n", fs_attr_cur->type);
+            printf("    alloc: 0x%llx\n", fs_attr_cur->nrd.allocsize);
+            printf("    size:  0x%llx\n", fs_attr_cur->size);
+
+        }
+
+    }
+    else {
+        printf("  attr_state is not studied\n");
+    }
+
+    // Ok we're good to go.
+    //TSK_FS_FILE * slack_file = tsk_fs_file_alloc(fs_file->fs_info);
+
+    // Allocate the new name structure
+    name_length = strlen(fs_file->name->name) + 6;
+    if ((slack_name = tsk_fs_name_alloc(name_length, 32)) == NULL) {
+        return TSK_ERR;
+    }
+
+    if(tsk_fs_name_copy(slack_name, fs_file->name)){
+        tsk_fs_name_free(slack_name);
+        return TSK_ERR;
+    }
+
+    // The name copy could end up resizing the array. It currently allocates an extra 16 bytes but we shouldn't count on that.
+    if(slack_name->name_size < name_length){
+        tsk_fs_name_realloc(slack_name, name_length);
+    }
+
+    // Add the "-slack"
+    strncat(slack_name->name, "-slack", 6);
+
+    printf("  Trying to add fs_file %s with metadata addr %x\n", slack_name->name, fs_file->meta->addr);
+
+    // Swap in the new name block and re-add the file
+    orig_name = fs_file->name;
+    fs_file->name = slack_name;
+    if (m_db->addFsFile(fs_file, fs_attr, path, md5, known, m_curFsId, m_curFileId,
+            m_curImgId)) {
+        fs_file->name = orig_name;
+        tsk_fs_name_free(slack_name);
+        registerError();
+        return TSK_ERR;
+    }
+    fs_file->name = orig_name;
+    tsk_fs_name_free(slack_name);
+    
     return TSK_OK;
 }
 
@@ -622,7 +719,7 @@ TskAutoDb::processFile(TSK_FS_FILE * fs_file, const char *path)
         return TSK_STOP;
     }
 
-     /* If no longe processing the same directroy as the last file, 
+     /* If no longer processing the same directory as the last file, 
       * then update the class-level setting. */
     int64_t cur = fs_file->name->par_addr;
     if (m_curDirId != cur) {
diff --git a/tsk/auto/db_postgresql.cpp b/tsk/auto/db_postgresql.cpp
index a399ac41c..680bc17cc 100755
--- a/tsk/auto/db_postgresql.cpp
+++ b/tsk/auto/db_postgresql.cpp
@@ -964,7 +964,7 @@ int TskDbPostgreSQL::addFile(TSK_FS_FILE * fs_file, const TSK_FS_ATTR * fs_attr,
     // combine name and attribute name
     size_t len = strlen(fs_file->name->name);
     char *name;
-    size_t nlen = len + attr_nlen + 5;
+    size_t nlen = len + attr_nlen + 11; // Extra space for possible colon and '-slack'
     if ((name = (char *) tsk_malloc(nlen)) == NULL) {
         return 1;
     }
@@ -1057,6 +1057,53 @@ int TskDbPostgreSQL::addFile(TSK_FS_FILE * fs_file, const TSK_FS_ATTR * fs_attr,
         return 1;
     }
 
+    // Add entry for the slack space if applicable
+    if((fs_attr != NULL)
+           && (fs_attr->flags & TSK_FS_ATTR_NONRES) 
+           && (fs_attr->nrd.allocsize !=  fs_attr->size)){
+        strncat(name, "-slack", 6);
+        name_sql = PQescapeLiteral(conn, name, strlen(name));
+        TSK_OFF_T slackSize = fs_attr->nrd.allocsize - fs_attr->size;
+
+        if (addObject(TSK_DB_OBJECT_TYPE_FILE, parObjId, objId)) {
+            free(name);
+            free(escaped_path);
+            return 1;
+        }
+
+        snprintf(zSQL, 2048, "INSERT INTO tsk_files (fs_obj_id, obj_id, data_source_obj_id, type, attr_type, attr_id, name, meta_addr, meta_seq, dir_type, meta_type, dir_flags, meta_flags, size, crtime, ctime, atime, mtime, mode, gid, uid, md5, known, parent_path) "
+            "VALUES ("
+            "%" PRId64 ",%" PRId64 ","
+            "%" PRId64 ","
+            "%d,"
+            "%d,%d,%s,"
+            "%" PRIuINUM ",%d,"
+            "%d,%d,%d,%d,"
+            "%" PRIuOFF ","
+            "%llu,%llu,%llu,%llu,"
+            "%d,%d,%d,%s,%d,"
+            "%s)",
+            fsObjId, objId, 
+            dataSourceObjId,
+            TSK_DB_FILES_TYPE_SLACK,
+            type, idx, name_sql,
+            fs_file->name->meta_addr, fs_file->name->meta_seq, 
+            fs_file->name->type, meta_type, fs_file->name->flags, meta_flags,
+            size, 
+            (unsigned long long)crtime, (unsigned long long)ctime,(unsigned long long) atime,(unsigned long long) mtime, 
+            meta_mode, gid, uid, NULL, known,
+            escaped_path_sql);
+
+        if (attempt_exec(zSQL, "TskDbPostgreSQL::addFile: Error adding data to tsk_files table: %s\n")) {
+            free(name);
+            free(escaped_path);
+            PQfreemem(name_sql);
+            PQfreemem(escaped_path_sql);
+            return 1;
+        }
+
+    }
+
     //if dir, update parent id cache
     if (meta_type == TSK_FS_META_TYPE_DIR) {
         std::string fullPath = std::string(path) + fs_file->name->name;
diff --git a/tsk/auto/db_sqlite.cpp b/tsk/auto/db_sqlite.cpp
index d19a6e591..61de45965 100755
--- a/tsk/auto/db_sqlite.cpp
+++ b/tsk/auto/db_sqlite.cpp
@@ -816,6 +816,7 @@ int64_t TskDbSqlite::findParObjId(const TSK_FS_FILE * fs_file, const char *paren
 
     // Find the parent file id in the database using the parent metadata address
     // @@@ This should use sequence number when the new database supports it
+    printf("Trying to look up parent %s %s with metadata addr %x\n", parent_path, parent_name, fs_file->name->par_addr);
     if (attempt(sqlite3_bind_int64(m_selectFilePreparedStmt, 1, fs_file->name->par_addr),
         "TskDbSqlite::findParObjId: Error binding meta_addr to statment: %s (result code %d)\n")
         || attempt(sqlite3_bind_int64(m_selectFilePreparedStmt, 2, fsObjId),
@@ -914,7 +915,7 @@ int
     size_t len = strlen(fs_file->name->name);
     char *
         name;
-    size_t nlen = len + attr_nlen + 5;
+    size_t nlen = len + attr_nlen + 11; // Extra space for possible colon and '-slack'
     if ((name = (char *) tsk_malloc(nlen)) == NULL) {
         return 1;
     }
@@ -983,12 +984,66 @@ int
         meta_mode, gid, uid, md5TextPtr, known,
         escaped_path);
 
+    printf("Adding file %s with objid %x\n", name, objId);
     if (attempt_exec(zSQL, "TskDbSqlite::addFile: Error adding data to tsk_files table: %s\n")) {
         free(name);
         free(escaped_path);
         sqlite3_free(zSQL);
         return 1;
     }
+
+    // Add entry for the slack space if applicable
+    if((fs_attr != NULL)
+           && (fs_attr->flags & TSK_FS_ATTR_NONRES) 
+           && (fs_attr->nrd.allocsize !=  fs_attr->size)){
+        printf("Adding slack for %s\n", name);
+        printf("  Non-resident\n");
+        printf("  Alloc: 0x%x\n", fs_attr->nrd.allocsize);
+        printf("  Size:  0x%x\n", fs_attr->size);
+        strncat(name, "-slack", 6);
+        printf("  Slack file: %s\n", name);
+        TSK_OFF_T slackSize = fs_attr->nrd.allocsize - fs_attr->size;
+        printf("  Slack file size: 0x%x\n", slackSize);
+
+        if (addObject(TSK_DB_OBJECT_TYPE_FILE, parObjId, objId)) {
+            free(name);
+            free(escaped_path);
+            return 1;
+        }
+
+        // Run the same insert with the new name, size, and type
+        zSQL = sqlite3_mprintf(
+        "INSERT INTO tsk_files (fs_obj_id, obj_id, data_source_obj_id, type, attr_type, attr_id, name, meta_addr, meta_seq, dir_type, meta_type, dir_flags, meta_flags, size, crtime, ctime, atime, mtime, mode, gid, uid, md5, known, parent_path) "
+        "VALUES ("
+        "%" PRId64 ",%" PRId64 ","
+        "%" PRId64 "," 
+        "%d,"
+        "%d,%d,'%q',"
+        "%" PRIuINUM ",%d,"
+        "%d,%d,%d,%d,"
+        "%" PRIuOFF ","
+        "%llu,%llu,%llu,%llu,"
+        "%d,%d,%d,%Q,%d,"
+        "'%q')",
+        fsObjId, objId,
+        dataSourceObjId,
+        TSK_DB_FILES_TYPE_SLACK,
+        type, idx, name,
+        fs_file->name->meta_addr, fs_file->name->meta_seq, 
+        fs_file->name->type, meta_type, fs_file->name->flags, meta_flags,
+        slackSize, 
+        (unsigned long long)crtime, (unsigned long long)ctime,(unsigned long long) atime,(unsigned long long) mtime, 
+        meta_mode, gid, uid, md5TextPtr, known,
+        escaped_path);
+
+        if (attempt_exec(zSQL, "TskDbSqlite::addFile: Error adding data to tsk_files table: %s\n")) {
+            free(name);
+            free(escaped_path);
+            sqlite3_free(zSQL);
+            return 1;
+        }
+    }
+
     sqlite3_free(zSQL);
 
     //if dir, update parent id cache
diff --git a/tsk/auto/tsk_case_db.h b/tsk/auto/tsk_case_db.h
index 5dcd5e39f..2132bbb0f 100644
--- a/tsk/auto/tsk_case_db.h
+++ b/tsk/auto/tsk_case_db.h
@@ -160,6 +160,10 @@ class TskAutoDb:public TskAuto {
         const TSK_FS_ATTR *, const char *path,
         const unsigned char *const md5,
         const TSK_DB_FILES_KNOWN_ENUM known);
+    TSK_RETVAL_ENUM insertSlackFileData(TSK_FS_FILE * fs_file,
+        const TSK_FS_ATTR *, const char *path,
+        const unsigned char *const md5,
+        const TSK_DB_FILES_KNOWN_ENUM known);
     virtual TSK_RETVAL_ENUM processAttribute(TSK_FS_FILE *,
         const TSK_FS_ATTR * fs_attr, const char *path);
     static TSK_WALK_RET_ENUM md5HashCallback(TSK_FS_FILE * file,
diff --git a/tsk/auto/tsk_db.h b/tsk/auto/tsk_db.h
index 9fbc6cf2c..54dec2399 100755
--- a/tsk/auto/tsk_db.h
+++ b/tsk/auto/tsk_db.h
@@ -52,6 +52,7 @@ typedef enum {
     TSK_DB_FILES_TYPE_UNALLOC_BLOCKS,   ///< Set of blocks not allocated by file system.  Parent should be image, volume, or file system.  Many columns in tsk_files will be NULL. Set layout in tsk_file_layout. 
     TSK_DB_FILES_TYPE_UNUSED_BLOCKS, ///< Set of blocks that are unallocated AND not used by a carved or other file type.  Parent should be UNALLOC_BLOCKS, many columns in tsk_files will be NULL, set layout in tsk_file_layout. 
     TSK_DB_FILES_TYPE_VIRTUAL_DIR, ///< Virtual directory (not on fs) with no meta-data entry that can be used to group files of types other than TSK_DB_FILES_TYPE_FS. Its parent is either another TSK_DB_FILES_TYPE_FS or a root directory or type TSK_DB_FILES_TYPE_FS.
+    TSK_DB_FILES_TYPE_SLACK   ///< Slack space for a single file
 } TSK_DB_FILES_TYPE_ENUM;
 
 
-- 
GitLab