From c89cd40fa38beb2612a220dfca8cb47361d6f251 Mon Sep 17 00:00:00 2001
From: Brian Carrier <carrier@sleuthkit.org>
Date: Sun, 2 Nov 2008 04:55:29 +0000
Subject: [PATCH] Make virtual files for HFS fs files

---
 tsk3/fs/hfs.c     | 799 +++++++++++++++++++++++++++-------------------
 tsk3/fs/tsk_hfs.h |   4 +-
 2 files changed, 476 insertions(+), 327 deletions(-)

diff --git a/tsk3/fs/hfs.c b/tsk3/fs/hfs.c
index 7507b2a6c..2e8a7aca6 100644
--- a/tsk3/fs/hfs.c
+++ b/tsk3/fs/hfs.c
@@ -113,7 +113,7 @@ hfs2unixtime(uint32_t hfsdate)
  * @param cnid Metadata address to convert
  * @param array [out] Array to write data into.
  */
-static void 
+static void
 cnid_to_array(uint32_t cnid, uint8_t array[4])
 {
     array[3] = (cnid >> 0) & 0xff;
@@ -246,7 +246,7 @@ hfs_ext_find_node_offset(HFS_INFO * hfs, hfs_btree_header_record * hdr,
 
     while (f_offs < n_offs) {
 
-        if (n_offs <= (f_offs + (TSK_OFF_T)bytes)) {
+        if (n_offs <= (f_offs + (TSK_OFF_T) bytes)) {
 
             r_offs += n_offs - f_offs;
             f_offs = n_offs;
@@ -754,7 +754,8 @@ hfs_ext_find_extent_record(HFS_INFO * hfs, uint32_t cnid,
                 /* if we've moved on to a different file (or fork), stop */
                 if ((tsk_getu32(fs->endian, key.file_id) != cnid) ||
                     (key.fork_type[0] != 0)) {
-                    memset(((char *) out_ext) + (num_out_ext * 8 - 64), 0, 64);
+                    memset(((char *) out_ext) + (num_out_ext * 8 - 64), 0,
+                        64);
                     return out_ext;
                 }
 
@@ -848,7 +849,8 @@ hfs_ext_find_extent_record(HFS_INFO * hfs, uint32_t cnid,
  * @returns NULL on error
  */
 static TSK_FS_ATTR_RUN *
-hfs_extents_to_attr(TSK_FS_INFO * a_fs, const hfs_ext_desc * a_extents, TSK_OFF_T a_start_off)
+hfs_extents_to_attr(TSK_FS_INFO * a_fs, const hfs_ext_desc * a_extents,
+    TSK_OFF_T a_start_off)
 {
     TSK_FS_ATTR_RUN *head_run = NULL;
     TSK_FS_ATTR_RUN *prev_run = NULL;
@@ -857,11 +859,9 @@ hfs_extents_to_attr(TSK_FS_INFO * a_fs, const hfs_ext_desc * a_extents, TSK_OFF_
 
     for (i = 0; i < 8; i++) {
         TSK_FS_ATTR_RUN *cur_run;
-        
-        uint32_t addr =
-            tsk_getu32(a_fs->endian, a_extents[i].start_blk);
-        uint32_t len =
-            tsk_getu32(a_fs->endian, a_extents[i].blk_cnt);
+
+        uint32_t addr = tsk_getu32(a_fs->endian, a_extents[i].start_blk);
+        uint32_t len = tsk_getu32(a_fs->endian, a_extents[i].blk_cnt);
 
         if ((addr == 0) && (len == 0))
             break;
@@ -873,7 +873,7 @@ hfs_extents_to_attr(TSK_FS_INFO * a_fs, const hfs_ext_desc * a_extents, TSK_OFF_
         cur_run->addr = addr;
         cur_run->len = len;
         cur_run->offset = cur_off;
-        
+
         if (head_run == NULL)
             head_run = cur_run;
         if (prev_run != NULL)
@@ -881,7 +881,7 @@ hfs_extents_to_attr(TSK_FS_INFO * a_fs, const hfs_ext_desc * a_extents, TSK_OFF_
         cur_off += (cur_run->len * a_fs->block_size);
         prev_run = cur_run;
     }
-    
+
     return head_run;
 }
 
@@ -903,31 +903,34 @@ hfs_ext_find_extent_record_attr(HFS_INFO * hfs, uint32_t cnid,
     char *node = NULL;
 
     tsk_error_reset();
-    
+
     // Load the extents attribute, if it has not been done so yet.
     if (hfs->extents_file == NULL) {
         ssize_t cnt;
-        
+
         if ((hfs->extents_file =
-             tsk_fs_file_open_meta(fs, NULL, HFS_EXTENTS_FILE_ID)) == NULL) {
+                tsk_fs_file_open_meta(fs, NULL,
+                    HFS_EXTENTS_FILE_ID)) == NULL) {
             return 0;
         }
-        
+
         /* cache the data attribute */
         hfs->extents_attr =
-            tsk_fs_attrlist_get(hfs->extents_file->meta->attr, TSK_FS_ATTR_TYPE_DEFAULT);
+            tsk_fs_attrlist_get(hfs->extents_file->meta->attr,
+            TSK_FS_ATTR_TYPE_DEFAULT);
         if (!hfs->catalog_attr) {
-            strncat(tsk_errstr2, " - Default Attribute not found in Extents File",
-                    TSK_ERRSTR_L - strlen(tsk_errstr2));
+            strncat(tsk_errstr2,
+                " - Default Attribute not found in Extents File",
+                TSK_ERRSTR_L - strlen(tsk_errstr2));
             return 0;
         }
-        
+
         // cache the extents file header
         cnt = tsk_fs_attr_read(hfs->extents_attr, 14,
-                               (char *) &(hfs->extents_header),
-                               sizeof(hfs_btree_header_record), 0);
+            (char *) &(hfs->extents_header),
+            sizeof(hfs_btree_header_record), 0);
         if (cnt != sizeof(hfs_btree_header_record)) {
-            return 0;        
+            return 0;
         }
     }
 
@@ -1013,7 +1016,7 @@ hfs_ext_find_extent_record_attr(HFS_INFO * hfs, uint32_t cnid,
                         "hfs_ext_find_extent_record: record %" PRIu16
                         " ; keylen %" PRIu16 " (%" PRIu32
                         ", %" PRIu8 ", %" PRIu32 "); compare: %d\n", rec,
-                         tsk_getu16(fs->endian, key->key_len),
+                        tsk_getu16(fs->endian, key->key_len),
                         tsk_getu32(fs->endian, key->file_id),
                         key->fork_type[0], tsk_getu32(fs->endian,
                             key->start_block), cmp);
@@ -1044,7 +1047,7 @@ hfs_ext_find_extent_record_attr(HFS_INFO * hfs, uint32_t cnid,
                 uint32_t rec_cnid;
                 hfs_extents *extents;
                 TSK_OFF_T ext_off = 0;
-				int keylen;
+                int keylen;
                 TSK_FS_ATTR_RUN *attr_run;
 
                 // get the record offset in the node
@@ -1061,7 +1064,7 @@ hfs_ext_find_extent_record_attr(HFS_INFO * hfs, uint32_t cnid,
                         "hfs_ext_find_extent_record: record %" PRIu16
                         "; keylen %" PRIu16 " (%" PRIu32
                         ", %" PRIu8 ", %" PRIu32 ")\n", rec,
-                         tsk_getu16(fs->endian, key->key_len),
+                        tsk_getu16(fs->endian, key->key_len),
                         tsk_getu32(fs->endian, key->file_id),
                         key->fork_type[0], tsk_getu32(fs->endian,
                             key->start_block));
@@ -1081,15 +1084,15 @@ hfs_ext_find_extent_record_attr(HFS_INFO * hfs, uint32_t cnid,
                 // @@@ SANITY CHECK ON NODELEN AND rec_addr+2+keylen
 
                 extents = (hfs_extents *) & node[rec_off + keylen];
-                        
-                attr_run = 
+
+                attr_run =
                     hfs_extents_to_attr(fs, extents->extents, ext_off);
                 if (attr_run == NULL) {
-                        /// @@@
+                    /// @@@
                 }
 
                 if (tsk_fs_attr_add_run(fs, a_attr, attr_run)) {
-                        // @@@
+                    // @@@
                 }
             }
         }
@@ -1146,100 +1149,101 @@ hfs_cat_get_record_offset(HFS_INFO * hfs, hfs_cat_key * needle)
 {
     TSK_FS_INFO *fs = &(hfs->fs_info);
     uint32_t cur_node;          /* node id of the current node */
-    char *node;    
+    char *node;
 
     uint16_t nodesize;
     uint8_t is_done = 0;
-    
+
     tsk_error_reset();
 
-    
+
     nodesize = tsk_getu16(fs->endian, hfs->catalog_header.nodesize);
     if ((node = (char *) tsk_malloc(nodesize)) == NULL)
         return 0;
     // @@@ ADD FREE CODE
-    
+
     /* start at root node */
     cur_node = tsk_getu32(fs->endian, hfs->catalog_header.root);
-    
+
     /* if the root node is zero, then the extents btree is empty */
     /* if no files have overflow extents, the Extents B-tree still
-        exists on disk, but is an empty B-tree containing only
-        the header node */
+       exists on disk, but is an empty B-tree containing only
+       the header node */
     if (cur_node == 0) {
         if (tsk_verbose)
             tsk_fprintf(stderr, "hfs_cat_get_record_offset: "
-                        "empty extents btree\n");
+                "empty extents btree\n");
         return 0;
     }
-    
+
     if (tsk_verbose)
         tsk_fprintf(stderr, "hfs_cat_get_record_offset: starting at "
-                    "root node %" PRIu32 "; nodesize = %"
-                    PRIu16 "\n", cur_node, nodesize);
-    
+            "root node %" PRIu32 "; nodesize = %"
+            PRIu16 "\n", cur_node, nodesize);
+
     is_done = 0;
     while (is_done == 0) {
         TSK_OFF_T cur_off;      /* start address of cur_node */
         uint16_t num_rec;       /* number of records in this node */
         ssize_t cnt;
         hfs_btree_node *node_desc;
-        
+
         cur_off = cur_node * nodesize;
-        
+
         cnt = tsk_fs_attr_read(hfs->catalog_attr, cur_off,
-                               node, nodesize, 0);
+            node, nodesize, 0);
         if (cnt != nodesize) {
             // @@@
             return 0;
         }
-        
+
         node_desc = (hfs_btree_node *) node;
-        
+
         num_rec = tsk_getu16(fs->endian, node_desc->num_rec);
-        
+
         if (tsk_verbose)
             tsk_fprintf(stderr, "hfs_cat_get_record_offset: node %" PRIu32
-                        " @ %" PRIu64 " has %" PRIu16 " records\n",
-                        cur_node, cur_off, num_rec);
-        
+                " @ %" PRIu64 " has %" PRIu16 " records\n",
+                cur_node, cur_off, num_rec);
+
         if (num_rec == 0) {
             tsk_errno = TSK_ERR_FS_GENFS;
             snprintf(tsk_errstr, TSK_ERRSTR_L,
-                     "hfs_cat_get_record_offset: zero records in node %"
-                     PRIu32, cur_node);
+                "hfs_cat_get_record_offset: zero records in node %"
+                PRIu32, cur_node);
             return 0;
         }
-        
+
         if (node_desc->kind == HFS_BTREE_INDEX_NODE) {
             uint32_t next_node = 0;
             int rec;
-            
+
             /* find largest key smaller than or equal to cnid */
             for (rec = 0; rec < num_rec; rec++) {
                 size_t rec_off;
                 hfs_cat_key *key;
-                
+
                 // get the record offset in the node
                 rec_off =
                     tsk_getu16(fs->endian,
-                               &node[nodesize - (rec + 1) * 2]);
+                    &node[nodesize - (rec + 1) * 2]);
                 if (rec_off > nodesize) {
                     // @@@ ERROR
                     return TSK_ERR;
                 }
                 key = (hfs_cat_key *) & node[rec_off];
-                
+
                 if (tsk_verbose)
                     tsk_fprintf(stderr,
-                                "hfs_cat_get_record_offset: record %" PRIu16
-                                " ; keylen %" PRIu16 " (%" PRIu32")\n", rec,
-                                tsk_getu16(fs->endian, key->key_len),
-                                tsk_getu32(fs->endian, key->parent_cnid));
-                
+                        "hfs_cat_get_record_offset: record %" PRIu16
+                        " ; keylen %" PRIu16 " (%" PRIu32 ")\n", rec,
+                        tsk_getu16(fs->endian, key->key_len),
+                        tsk_getu32(fs->endian, key->parent_cnid));
+
                 /* find the largest key less than or equal to our key */
                 /* if all keys are larger than our key, select the leftmost key */
-                if ((hfs_cat_compare_keys(hfs, key, needle) <= 0) || (next_node == 0)) {
+                if ((hfs_cat_compare_keys(hfs, key, needle) <= 0)
+                    || (next_node == 0)) {
                     int keylen = tsk_getu16(fs->endian, key->key_len) + 2;
                     if (rec_off + keylen > nodesize) {
                         // @@@ ERROR
@@ -1259,37 +1263,37 @@ hfs_cat_get_record_offset(HFS_INFO * hfs, hfs_cat_key * needle)
             }
             cur_node = next_node;
         }
-        
+
         else if (node_desc->kind == HFS_BTREE_LEAF_NODE) {
             int rec;
-            
+
             for (rec = 0; rec < num_rec; rec++) {
                 size_t rec_off;
                 hfs_cat_key *key;
                 size_t rec_off2;
                 int diff;
-                
+
                 // get the record offset in the node
                 rec_off =
                     tsk_getu16(fs->endian,
-                               &node[nodesize - (rec + 1) * 2]);
+                    &node[nodesize - (rec + 1) * 2]);
                 if (rec_off > nodesize) {
                     // @@@ ERROR
                     return 0;
                 }
                 key = (hfs_cat_key *) & node[rec_off];
-                
+
                 if (tsk_verbose)
                     tsk_fprintf(stderr,
-                                "hfs_cat_get_record_offset: record %" PRIu16
-                                "; keylen %" PRIu16 " (%" PRIu32")\n", rec,
-                                tsk_getu16(fs->endian, key->key_len),
-                                tsk_getu32(fs->endian, key->parent_cnid));
-                
+                        "hfs_cat_get_record_offset: record %" PRIu16
+                        "; keylen %" PRIu16 " (%" PRIu32 ")\n", rec,
+                        tsk_getu16(fs->endian, key->key_len),
+                        tsk_getu32(fs->endian, key->parent_cnid));
+
                 //                rec_cnid = tsk_getu32(fs->endian, key->file_id);
-                
+
                 diff = hfs_cat_compare_keys(hfs, key, needle);
-                
+
                 // see if this record is for our file or if we passed the interesting entries
                 if (diff < 0) {
                     continue;
@@ -1298,22 +1302,23 @@ hfs_cat_get_record_offset(HFS_INFO * hfs, hfs_cat_key * needle)
                     is_done = 1;
                     break;
                 }
-                
-                rec_off2 = rec_off + 2 + tsk_getu16(fs->endian, key->key_len);
+
+                rec_off2 =
+                    rec_off + 2 + tsk_getu16(fs->endian, key->key_len);
                 if (rec_off2 > nodesize) {
                     // @@@ ERROR
                     return 0;
                 }
-                
+
                 return cur_off + rec_off2;
             }
         }
         else {
             tsk_errno = TSK_ERR_FS_GENFS;
             snprintf(tsk_errstr, TSK_ERRSTR_L,
-                     "hfs_cat_get_record_offset: btree node %" PRIu32
-                     " (%" PRIu64 ") is neither index nor leaf (%" PRIu8 ")",
-                     cur_node, cur_off, node_desc->kind);
+                "hfs_cat_get_record_offset: btree node %" PRIu32
+                " (%" PRIu64 ") is neither index nor leaf (%" PRIu8 ")",
+                cur_node, cur_off, node_desc->kind);
             return 0;
         }
     }
@@ -1340,7 +1345,7 @@ hfs_cat_read_thread_record(HFS_INFO * hfs, TSK_OFF_T off,
     size_t cnt;
 
     memset(thread, 0, sizeof(hfs_thread));
-    cnt = tsk_fs_attr_read(hfs->catalog_attr, off, (char *)thread, 10, 0);
+    cnt = tsk_fs_attr_read(hfs->catalog_attr, off, (char *) thread, 10, 0);
     if (cnt != 10) {
         // @@@
         return 1;
@@ -1361,13 +1366,15 @@ hfs_cat_read_thread_record(HFS_INFO * hfs, TSK_OFF_T off,
     if (uni_len > 255) {
         tsk_errno = TSK_ERR_FS_INODE_COR;
         snprintf(tsk_errstr, TSK_ERRSTR_L,
-            "hfs_cat_read_thread_record: invalid string length (%" PRIu16 ")",
-            uni_len);
+            "hfs_cat_read_thread_record: invalid string length (%" PRIu16
+            ")", uni_len);
         return 1;
     }
 
-    cnt = tsk_fs_attr_read(hfs->catalog_attr, off + 10, (char *)thread->name.unicode, uni_len*2, 0);
-    if (cnt != uni_len*2) {
+    cnt =
+        tsk_fs_attr_read(hfs->catalog_attr, off + 10,
+        (char *) thread->name.unicode, uni_len * 2, 0);
+    if (cnt != uni_len * 2) {
         // @@@
         return 1;
     }
@@ -1391,14 +1398,16 @@ hfs_cat_read_file_folder_record(HFS_INFO * hfs, TSK_OFF_T off,
     size_t cnt;
 
     memset(record, 0, sizeof(hfs_file_folder));
-    cnt = tsk_fs_attr_read(hfs->catalog_attr, off, (char *)record, 2, 0);
+    cnt = tsk_fs_attr_read(hfs->catalog_attr, off, (char *) record, 2, 0);
     if (cnt != 2) {
         // @@@
         return 1;
     }
-        
+
     if (tsk_getu16(fs->endian, record->file.rec_type) == HFS_FOLDER_RECORD) {
-        cnt = tsk_fs_attr_read(hfs->catalog_attr, off, (char *)record, sizeof(hfs_folder), 0);
+        cnt =
+            tsk_fs_attr_read(hfs->catalog_attr, off, (char *) record,
+            sizeof(hfs_folder), 0);
         if (cnt != sizeof(hfs_folder)) {
             // @@@
             return 1;
@@ -1406,7 +1415,9 @@ hfs_cat_read_file_folder_record(HFS_INFO * hfs, TSK_OFF_T off,
     }
     else if (tsk_getu16(fs->endian,
             record->file.rec_type) == HFS_FILE_RECORD) {
-        cnt = tsk_fs_attr_read(hfs->catalog_attr, off, (char *)record, sizeof(hfs_file), 0);
+        cnt =
+            tsk_fs_attr_read(hfs->catalog_attr, off, (char *) record,
+            sizeof(hfs_file), 0);
         if (cnt != sizeof(hfs_file)) {
             // @@@
             return 1;
@@ -1415,8 +1426,8 @@ hfs_cat_read_file_folder_record(HFS_INFO * hfs, TSK_OFF_T off,
     else {
         tsk_errno = TSK_ERR_FS_GENFS;
         snprintf(tsk_errstr, TSK_ERRSTR_L,
-            "hfs_cat_read_file_folder_record: unexpected record type %" PRIu16,
-            tsk_getu16(fs->endian, record->file.rec_type));
+            "hfs_cat_read_file_folder_record: unexpected record type %"
+            PRIu16, tsk_getu16(fs->endian, record->file.rec_type));
         return 1;
     }
 
@@ -1446,23 +1457,23 @@ hfs_cat_file_lookup(HFS_INFO * hfs, TSK_INUM_T inum, HFS_ENTRY * entry)
     if (tsk_verbose)
         tsk_fprintf(stderr,
             "hfs_cat_file_lookup: called for inum %" PRIuINUM "\n", inum);
-    
+
     // Test if this is a special file that is not located in the catalog
     if ((inum == HFS_EXTENTS_FILE_ID) ||
-       (inum == HFS_CATALOG_FILE_ID) || 
-       (inum == HFS_ALLOCATION_FILE_ID) ||
-       (inum == HFS_STARTUP_FILE_ID) ||
-       (inum == HFS_ATTRIBUTES_FILE_ID)) {
+        (inum == HFS_CATALOG_FILE_ID) ||
+        (inum == HFS_ALLOCATION_FILE_ID) ||
+        (inum == HFS_STARTUP_FILE_ID) ||
+        (inum == HFS_ATTRIBUTES_FILE_ID)) {
         // @@@ Add error message
         return 1;
     }
-    
+
     /* first look up the thread record for the item we're searching for */
-    
+
     /* set up the thread record key */
     memset((char *) &key, 0, sizeof(hfs_cat_key));
-    cnid_to_array((uint32_t)inum, key.parent_cnid);
-    
+    cnid_to_array((uint32_t) inum, key.parent_cnid);
+
     /* look up the thread record */
     off = hfs_cat_get_record_offset(hfs, &key);
 
@@ -1477,8 +1488,9 @@ hfs_cat_file_lookup(HFS_INFO * hfs, TSK_INUM_T inum, HFS_ENTRY * entry)
 
     /* build key */
     memset((char *) &key, 0, sizeof(hfs_cat_key));
-    memcpy((char *)key.parent_cnid, (char *)thread.parent_cnid, sizeof(key.parent_cnid));
-    memcpy((char *)&key.name, (char *)&thread.name, sizeof(key.name));
+    memcpy((char *) key.parent_cnid, (char *) thread.parent_cnid,
+        sizeof(key.parent_cnid));
+    memcpy((char *) &key.name, (char *) &thread.name, sizeof(key.name));
 
     /* look up the record */
     off = hfs_cat_get_record_offset(hfs, &key);
@@ -1503,8 +1515,8 @@ hfs_cat_file_lookup(HFS_INFO * hfs, TSK_INUM_T inum, HFS_ENTRY * entry)
             record.file.rec_type) == HFS_FILE_RECORD) {
         if (tsk_verbose)
             fprintf(stderr,
-                "hfs_cat_file_lookup: found file record cnid %" PRIu32 "\n",
-                tsk_getu32(fs->endian, record.file.cnid));
+                "hfs_cat_file_lookup: found file record cnid %" PRIu32
+                "\n", tsk_getu32(fs->endian, record.file.cnid));
         memcpy((char *) &entry->cat, (char *) &record, sizeof(hfs_file));
     }
     /* other cases already caught by hfs_cat_read_file_folder_record */
@@ -1530,19 +1542,19 @@ hfs_find_highest_inum(HFS_INFO * hfs)
 {
     // @@@ get actual number from Catalog file
     /* I haven't gotten looking at the end of the Catalog B-Tree to work
-    properly. A fast method: if HFS_BIT_VOLUME_CNIDS_REUSED is set, then
-    the maximum CNID is 2^32-1; if it's not set, then nextCatalogId is
-    supposed to be larger than all CNIDs on disk.
-    */
-    
+       properly. A fast method: if HFS_BIT_VOLUME_CNIDS_REUSED is set, then
+       the maximum CNID is 2^32-1; if it's not set, then nextCatalogId is
+       supposed to be larger than all CNIDs on disk.
+     */
+
     TSK_FS_INFO *fs = (TSK_FS_INFO *) & (hfs->fs_info);
-    
+
     if (tsk_getu32(fs->endian,
-                   hfs->fs->attr) & HFS_BIT_VOLUME_CNIDS_REUSED)
+            hfs->fs->attr) & HFS_BIT_VOLUME_CNIDS_REUSED)
         return (TSK_INUM_T) 0xffffffff;
     else
         return (TSK_INUM_T) tsk_getu32(fs->endian,
-                                       hfs->fs->next_cat_id) - 1;
+            hfs->fs->next_cat_id) - 1;
 }
 
 
@@ -1612,82 +1624,97 @@ hfsmode2tskmetatype(uint16_t a_mode)
 }
 
 
-/**
- * \internal
- * Create an FS_INODE structure for the catalog file. 
- *
- * @param hfs File system to analyze
- * @param fs_file Structure to copy file information into.
- * @return 1 on error and 0 on success
- */
 static uint8_t
-hfs_make_catalog(HFS_INFO * hfs, TSK_FS_FILE * fs_file)
+hfs_make_specialbase(TSK_FS_FILE * fs_file)
 {
-    TSK_FS_INFO *fs = (TSK_FS_INFO *) hfs;
-    TSK_FS_ATTR *fs_attr;
-    TSK_FS_ATTR_RUN *attr_run;
-    
     fs_file->meta->type = TSK_FS_META_TYPE_VIRT;
     fs_file->meta->mode = 0;
     fs_file->meta->nlink = 1;
-    fs_file->meta->addr = HFS_CATALOG_FILE_ID;
-    fs_file->meta->flags = (TSK_FS_META_FLAG_USED | TSK_FS_META_FLAG_ALLOC);
+    fs_file->meta->flags =
+        (TSK_FS_META_FLAG_USED | TSK_FS_META_FLAG_ALLOC);
     fs_file->meta->uid = fs_file->meta->gid = 0;
-    fs_file->meta->mtime = fs_file->meta->atime = fs_file->meta->ctime = fs_file->meta->crtime = 0;
-    
+    fs_file->meta->mtime = fs_file->meta->atime = fs_file->meta->ctime =
+        fs_file->meta->crtime = 0;
+
     if (fs_file->meta->name2 == NULL) {
         if ((fs_file->meta->name2 = (TSK_FS_META_NAME_LIST *)
-             tsk_malloc(sizeof(TSK_FS_META_NAME_LIST))) == NULL)
+                tsk_malloc(sizeof(TSK_FS_META_NAME_LIST))) == NULL)
             return 1;
         fs_file->meta->name2->next = NULL;
     }
-    strncpy(fs_file->meta->name2->name, HFS_CATALOGNAME,
-            TSK_FS_META_NAME_LIST_NSIZE);
-    
-    fs_file->meta->size = tsk_getu64(fs->endian, hfs->fs->cat_file.logic_sz); 
-    
-    
+
     if (fs_file->meta->attr != NULL) {
         tsk_fs_attrlist_markunused(fs_file->meta->attr);
     }
-    else  {
+    else {
         fs_file->meta->attr = tsk_fs_attrlist_alloc();
     }
-    
-    if ((attr_run = hfs_extents_to_attr(fs, hfs->fs->cat_file.extents, 0)) == NULL) {
+    return 0;
+}
+
+/**
+ * \internal
+ * Create an FS_INODE structure for the catalog file. 
+ *
+ * @param hfs File system to analyze
+ * @param fs_file Structure to copy file information into.
+ * @return 1 on error and 0 on success
+ */
+static uint8_t
+hfs_make_catalog(HFS_INFO * hfs, TSK_FS_FILE * fs_file)
+{
+    TSK_FS_INFO *fs = (TSK_FS_INFO *) hfs;
+    TSK_FS_ATTR *fs_attr;
+    TSK_FS_ATTR_RUN *attr_run;
+
+    if (hfs_make_specialbase(fs_file))
+        return 1;
+
+    fs_file->meta->addr = HFS_CATALOG_FILE_ID;
+    strncpy(fs_file->meta->name2->name, HFS_CATALOGNAME,
+        TSK_FS_META_NAME_LIST_NSIZE);
+
+    fs_file->meta->size =
+        tsk_getu64(fs->endian, hfs->fs->cat_file.logic_sz);
+
+
+    if ((attr_run =
+            hfs_extents_to_attr(fs, hfs->fs->cat_file.extents,
+                0)) == NULL) {
         strncat(tsk_errstr2, " - hfs_make_catalog",
-                TSK_ERRSTR_L - strlen(tsk_errstr2));
+            TSK_ERRSTR_L - strlen(tsk_errstr2));
         return 1;
     }
-    
-    if ((fs_attr = tsk_fs_attrlist_getnew(fs_file->meta->attr, TSK_FS_ATTR_NONRES)) == NULL) {
+
+    if ((fs_attr =
+            tsk_fs_attrlist_getnew(fs_file->meta->attr,
+                TSK_FS_ATTR_NONRES)) == NULL) {
         strncat(tsk_errstr2, " - hfs_make_catalog",
-                TSK_ERRSTR_L - strlen(tsk_errstr2));
+            TSK_ERRSTR_L - strlen(tsk_errstr2));
         tsk_fs_attr_run_free(attr_run);
         return 1;
     }
-    
+
     // initialize the data run
     if (tsk_fs_attr_set_run(fs_file, fs_attr, attr_run, NULL,
-                            TSK_FS_ATTR_TYPE_DEFAULT, TSK_FS_ATTR_ID_DEFAULT,
-                            tsk_getu64(fs->endian, hfs->fs->cat_file.logic_sz), 
-                            tsk_getu64(fs->endian, hfs->fs->cat_file.logic_sz), 0, 0)) {
+            TSK_FS_ATTR_TYPE_DEFAULT, TSK_FS_ATTR_ID_DEFAULT,
+            tsk_getu64(fs->endian, hfs->fs->cat_file.logic_sz),
+            tsk_getu64(fs->endian, hfs->fs->cat_file.logic_sz), 0, 0)) {
         strncat(tsk_errstr2, " - hfs_make_catalog",
-                TSK_ERRSTR_L - strlen(tsk_errstr2));
+            TSK_ERRSTR_L - strlen(tsk_errstr2));
         tsk_fs_attr_free(fs_attr);
         tsk_fs_attr_run_free(attr_run);
         return 1;
     }
-    
+
     // see if catalog file has additional runs
-    if (hfs_ext_find_extent_record_attr(hfs, HFS_CATALOG_FILE_ID,
-                                        fs_attr)) {
+    if (hfs_ext_find_extent_record_attr(hfs, HFS_CATALOG_FILE_ID, fs_attr)) {
         strncat(tsk_errstr2, " - hfs_make_catalog",
-                TSK_ERRSTR_L - strlen(tsk_errstr2));
+            TSK_ERRSTR_L - strlen(tsk_errstr2));
         fs_file->meta->attr_state = TSK_FS_META_ATTR_ERROR;
         return 1;
     }
-    
+
     fs_file->meta->attr_state = TSK_FS_META_ATTR_STUDIED;
     return 0;
 }
@@ -1706,68 +1733,56 @@ hfs_make_extents(HFS_INFO * hfs, TSK_FS_FILE * fs_file)
     TSK_FS_INFO *fs = (TSK_FS_INFO *) hfs;
     TSK_FS_ATTR *fs_attr;
     TSK_FS_ATTR_RUN *attr_run;
-    
-    fs_file->meta->type = TSK_FS_META_TYPE_VIRT;
-    fs_file->meta->mode = 0;
-    fs_file->meta->nlink = 1;
+
+    if (hfs_make_specialbase(fs_file))
+        return 1;
+
     fs_file->meta->addr = HFS_EXTENTS_FILE_ID;
-    fs_file->meta->flags = (TSK_FS_META_FLAG_USED | TSK_FS_META_FLAG_ALLOC);
-    fs_file->meta->uid = fs_file->meta->gid = 0;
-    fs_file->meta->mtime = fs_file->meta->atime = fs_file->meta->ctime = fs_file->meta->crtime = 0;
-    
-    if (fs_file->meta->name2 == NULL) {
-        if ((fs_file->meta->name2 = (TSK_FS_META_NAME_LIST *)
-             tsk_malloc(sizeof(TSK_FS_META_NAME_LIST))) == NULL)
-            return 1;
-        fs_file->meta->name2->next = NULL;
-    }
     strncpy(fs_file->meta->name2->name, HFS_EXTENTSNAME,
-            TSK_FS_META_NAME_LIST_NSIZE);
-    
-    fs_file->meta->size = tsk_getu64(fs->endian, hfs->fs->ext_file.logic_sz); 
-    
-    
-    if (fs_file->meta->attr != NULL) {
-        tsk_fs_attrlist_markunused(fs_file->meta->attr);
-    }
-    else  {
-        fs_file->meta->attr = tsk_fs_attrlist_alloc();
-    }
-    
-    if ((attr_run = hfs_extents_to_attr(fs, hfs->fs->ext_file.extents, 0)) == NULL) {
+        TSK_FS_META_NAME_LIST_NSIZE);
+
+    fs_file->meta->size =
+        tsk_getu64(fs->endian, hfs->fs->ext_file.logic_sz);
+
+
+    if ((attr_run =
+            hfs_extents_to_attr(fs, hfs->fs->ext_file.extents,
+                0)) == NULL) {
         strncat(tsk_errstr2, " - hfs_make_extents",
-                TSK_ERRSTR_L - strlen(tsk_errstr2));
+            TSK_ERRSTR_L - strlen(tsk_errstr2));
         return 1;
     }
-    
-    if ((fs_attr = tsk_fs_attrlist_getnew(fs_file->meta->attr, TSK_FS_ATTR_NONRES)) == NULL) {
+
+    if ((fs_attr =
+            tsk_fs_attrlist_getnew(fs_file->meta->attr,
+                TSK_FS_ATTR_NONRES)) == NULL) {
         strncat(tsk_errstr2, " - hfs_make_extents",
-                TSK_ERRSTR_L - strlen(tsk_errstr2));
+            TSK_ERRSTR_L - strlen(tsk_errstr2));
         tsk_fs_attr_run_free(attr_run);
         return 1;
     }
-    
+
     // initialize the data run
     if (tsk_fs_attr_set_run(fs_file, fs_attr, attr_run, NULL,
-                            TSK_FS_ATTR_TYPE_DEFAULT, TSK_FS_ATTR_ID_DEFAULT,
-                            tsk_getu64(fs->endian, hfs->fs->ext_file.logic_sz), 
-                            tsk_getu64(fs->endian, hfs->fs->ext_file.logic_sz), 0, 0)) {
+            TSK_FS_ATTR_TYPE_DEFAULT, TSK_FS_ATTR_ID_DEFAULT,
+            tsk_getu64(fs->endian, hfs->fs->ext_file.logic_sz),
+            tsk_getu64(fs->endian, hfs->fs->ext_file.logic_sz), 0, 0)) {
         strncat(tsk_errstr2, " - hfs_make_extents",
-                TSK_ERRSTR_L - strlen(tsk_errstr2));
+            TSK_ERRSTR_L - strlen(tsk_errstr2));
         tsk_fs_attr_free(fs_attr);
         tsk_fs_attr_run_free(attr_run);
         return 1;
     }
-    
+
     // Extents doesn't have an entry in itself
-    
+
     fs_file->meta->attr_state = TSK_FS_META_ATTR_STUDIED;
     return 0;
 }
 
 
 /**
-* \internal
+ * \internal
  * Create an FS_INODE structure for the blockmap / allocation file. 
  *
  * @param hfs File system to analyze
@@ -1780,68 +1795,189 @@ hfs_make_blockmap(HFS_INFO * hfs, TSK_FS_FILE * fs_file)
     TSK_FS_INFO *fs = (TSK_FS_INFO *) hfs;
     TSK_FS_ATTR *fs_attr;
     TSK_FS_ATTR_RUN *attr_run;
-    
-    fs_file->meta->type = TSK_FS_META_TYPE_VIRT;
-    fs_file->meta->mode = 0;
-    fs_file->meta->nlink = 1;
+
+    if (hfs_make_specialbase(fs_file))
+        return 1;
+
     fs_file->meta->addr = HFS_ALLOCATION_FILE_ID;
-    fs_file->meta->flags = (TSK_FS_META_FLAG_USED | TSK_FS_META_FLAG_ALLOC);
-    fs_file->meta->uid = fs_file->meta->gid = 0;
-    fs_file->meta->mtime = fs_file->meta->atime = fs_file->meta->ctime = fs_file->meta->crtime = 0;
-    
-    if (fs_file->meta->name2 == NULL) {
-        if ((fs_file->meta->name2 = (TSK_FS_META_NAME_LIST *)
-             tsk_malloc(sizeof(TSK_FS_META_NAME_LIST))) == NULL)
-            return 1;
-        fs_file->meta->name2->next = NULL;
-    }
     strncpy(fs_file->meta->name2->name, HFS_ALLOCATIONNAME,
-            TSK_FS_META_NAME_LIST_NSIZE);
-    
-    fs_file->meta->size = tsk_getu64(fs->endian, hfs->fs->alloc_file.logic_sz); 
-    
-    
-    if (fs_file->meta->attr != NULL) {
-        tsk_fs_attrlist_markunused(fs_file->meta->attr);
+        TSK_FS_META_NAME_LIST_NSIZE);
+
+    fs_file->meta->size =
+        tsk_getu64(fs->endian, hfs->fs->alloc_file.logic_sz);
+
+    if ((attr_run =
+            hfs_extents_to_attr(fs, hfs->fs->alloc_file.extents,
+                0)) == NULL) {
+        strncat(tsk_errstr2, " - hfs_make_blockmap",
+            TSK_ERRSTR_L - strlen(tsk_errstr2));
+        return 1;
     }
-    else  {
-        fs_file->meta->attr = tsk_fs_attrlist_alloc();
+
+    if ((fs_attr =
+            tsk_fs_attrlist_getnew(fs_file->meta->attr,
+                TSK_FS_ATTR_NONRES)) == NULL) {
+        strncat(tsk_errstr2, " - hfs_make_blockmap",
+            TSK_ERRSTR_L - strlen(tsk_errstr2));
+        tsk_fs_attr_run_free(attr_run);
+        return 1;
     }
-    
-    if ((attr_run = hfs_extents_to_attr(fs, hfs->fs->alloc_file.extents, 0)) == NULL) {
-        strncat(tsk_errstr2, " - hfs_make_catalog",
-                TSK_ERRSTR_L - strlen(tsk_errstr2));
+
+    // initialize the data run
+    if (tsk_fs_attr_set_run(fs_file, fs_attr, attr_run, NULL,
+            TSK_FS_ATTR_TYPE_DEFAULT, TSK_FS_ATTR_ID_DEFAULT,
+            tsk_getu64(fs->endian, hfs->fs->alloc_file.logic_sz),
+            tsk_getu64(fs->endian, hfs->fs->alloc_file.logic_sz), 0, 0)) {
+        strncat(tsk_errstr2, " - hfs_make_blockmap",
+            TSK_ERRSTR_L - strlen(tsk_errstr2));
+        tsk_fs_attr_free(fs_attr);
+        tsk_fs_attr_run_free(attr_run);
         return 1;
     }
-    
-    if ((fs_attr = tsk_fs_attrlist_getnew(fs_file->meta->attr, TSK_FS_ATTR_NONRES)) == NULL) {
-        strncat(tsk_errstr2, " - hfs_make_catalog",
-                TSK_ERRSTR_L - strlen(tsk_errstr2));
+
+    // see if catalog file has additional runs
+    if (hfs_ext_find_extent_record_attr(hfs, HFS_ALLOCATION_FILE_ID,
+            fs_attr)) {
+        strncat(tsk_errstr2, " - hfs_make_blockmap",
+            TSK_ERRSTR_L - strlen(tsk_errstr2));
+        fs_file->meta->attr_state = TSK_FS_META_ATTR_ERROR;
+        return 1;
+    }
+
+    fs_file->meta->attr_state = TSK_FS_META_ATTR_STUDIED;
+    return 0;
+}
+
+/**
+* \internal
+ * Create an FS_INODE structure for the startup / boot file. 
+ *
+ * @param hfs File system to analyze
+ * @param fs_file Structure to copy file information into.
+ * @return 1 on error and 0 on success
+ */
+static uint8_t
+hfs_make_startfile(HFS_INFO * hfs, TSK_FS_FILE * fs_file)
+{
+    TSK_FS_INFO *fs = (TSK_FS_INFO *) hfs;
+    TSK_FS_ATTR *fs_attr;
+    TSK_FS_ATTR_RUN *attr_run;
+
+    if (hfs_make_specialbase(fs_file))
+        return 1;
+
+    fs_file->meta->addr = HFS_STARTUP_FILE_ID;
+    strncpy(fs_file->meta->name2->name, HFS_STARTUPNAME,
+        TSK_FS_META_NAME_LIST_NSIZE);
+
+    fs_file->meta->size =
+        tsk_getu64(fs->endian, hfs->fs->start_file.logic_sz);
+
+    if ((attr_run =
+            hfs_extents_to_attr(fs, hfs->fs->start_file.extents,
+                0)) == NULL) {
+        strncat(tsk_errstr2, " - hfs_make_startfile",
+            TSK_ERRSTR_L - strlen(tsk_errstr2));
+        return 1;
+    }
+
+    if ((fs_attr =
+            tsk_fs_attrlist_getnew(fs_file->meta->attr,
+                TSK_FS_ATTR_NONRES)) == NULL) {
+        strncat(tsk_errstr2, " - hfs_make_startfile",
+            TSK_ERRSTR_L - strlen(tsk_errstr2));
         tsk_fs_attr_run_free(attr_run);
         return 1;
     }
-    
+
     // initialize the data run
     if (tsk_fs_attr_set_run(fs_file, fs_attr, attr_run, NULL,
-                            TSK_FS_ATTR_TYPE_DEFAULT, TSK_FS_ATTR_ID_DEFAULT,
-                            tsk_getu64(fs->endian, hfs->fs->alloc_file.logic_sz), 
-                            tsk_getu64(fs->endian, hfs->fs->alloc_file.logic_sz), 0, 0)) {
-        strncat(tsk_errstr2, " - hfs_make_catalog",
-                TSK_ERRSTR_L - strlen(tsk_errstr2));
+            TSK_FS_ATTR_TYPE_DEFAULT, TSK_FS_ATTR_ID_DEFAULT,
+            tsk_getu64(fs->endian, hfs->fs->start_file.logic_sz),
+            tsk_getu64(fs->endian, hfs->fs->start_file.logic_sz), 0, 0)) {
+        strncat(tsk_errstr2, " - hfs_make_startfile",
+            TSK_ERRSTR_L - strlen(tsk_errstr2));
         tsk_fs_attr_free(fs_attr);
         tsk_fs_attr_run_free(attr_run);
         return 1;
     }
-    
+
     // see if catalog file has additional runs
-    if (hfs_ext_find_extent_record_attr(hfs, HFS_ALLOCATION_FILE_ID,
-                                        fs_attr)) {
-        strncat(tsk_errstr2, " - hfs_make_catalog",
-                TSK_ERRSTR_L - strlen(tsk_errstr2));
+    if (hfs_ext_find_extent_record_attr(hfs, HFS_STARTUP_FILE_ID, fs_attr)) {
+        strncat(tsk_errstr2, " - hfs_make_startfile",
+            TSK_ERRSTR_L - strlen(tsk_errstr2));
+        fs_file->meta->attr_state = TSK_FS_META_ATTR_ERROR;
+        return 1;
+    }
+
+    fs_file->meta->attr_state = TSK_FS_META_ATTR_STUDIED;
+    return 0;
+}
+
+
+/**
+* \internal
+ * Create an FS_INODE structure for the attributes file. 
+ *
+ * @param hfs File system to analyze
+ * @param fs_file Structure to copy file information into.
+ * @return 1 on error and 0 on success
+ */
+static uint8_t
+hfs_make_attrfile(HFS_INFO * hfs, TSK_FS_FILE * fs_file)
+{
+    TSK_FS_INFO *fs = (TSK_FS_INFO *) hfs;
+    TSK_FS_ATTR *fs_attr;
+    TSK_FS_ATTR_RUN *attr_run;
+
+    if (hfs_make_specialbase(fs_file))
+        return 1;
+
+    fs_file->meta->addr = HFS_ATTRIBUTES_FILE_ID;
+    strncpy(fs_file->meta->name2->name, HFS_ATTRIBUTESNAME,
+        TSK_FS_META_NAME_LIST_NSIZE);
+
+    fs_file->meta->size =
+        tsk_getu64(fs->endian, hfs->fs->attr_file.logic_sz);
+
+    if ((attr_run =
+            hfs_extents_to_attr(fs, hfs->fs->attr_file.extents,
+                0)) == NULL) {
+        strncat(tsk_errstr2, " - hfs_make_attrfile",
+            TSK_ERRSTR_L - strlen(tsk_errstr2));
+        return 1;
+    }
+
+    if ((fs_attr =
+            tsk_fs_attrlist_getnew(fs_file->meta->attr,
+                TSK_FS_ATTR_NONRES)) == NULL) {
+        strncat(tsk_errstr2, " - hfs_make_attrfile",
+            TSK_ERRSTR_L - strlen(tsk_errstr2));
+        tsk_fs_attr_run_free(attr_run);
+        return 1;
+    }
+
+    // initialize the data run
+    if (tsk_fs_attr_set_run(fs_file, fs_attr, attr_run, NULL,
+            TSK_FS_ATTR_TYPE_DEFAULT, TSK_FS_ATTR_ID_DEFAULT,
+            tsk_getu64(fs->endian, hfs->fs->attr_file.logic_sz),
+            tsk_getu64(fs->endian, hfs->fs->attr_file.logic_sz), 0, 0)) {
+        strncat(tsk_errstr2, " - hfs_make_attrfile",
+            TSK_ERRSTR_L - strlen(tsk_errstr2));
+        tsk_fs_attr_free(fs_attr);
+        tsk_fs_attr_run_free(attr_run);
+        return 1;
+    }
+
+    // see if catalog file has additional runs
+    if (hfs_ext_find_extent_record_attr(hfs, HFS_ATTRIBUTES_FILE_ID,
+            fs_attr)) {
+        strncat(tsk_errstr2, " - hfs_make_attrfile",
+            TSK_ERRSTR_L - strlen(tsk_errstr2));
         fs_file->meta->attr_state = TSK_FS_META_ATTR_ERROR;
         return 1;
     }
-    
+
     fs_file->meta->attr_state = TSK_FS_META_ATTR_STUDIED;
     return 0;
 }
@@ -1852,7 +1988,7 @@ hfs_make_blockmap(HFS_INFO * hfs, TSK_FS_FILE * fs_file)
  * Returns 1 on error.
  */
 static uint8_t
-hfs_dinode_copy(HFS_INFO * hfs, hfs_file *entry, TSK_FS_META * fs_meta)
+hfs_dinode_copy(HFS_INFO * hfs, hfs_file * entry, TSK_FS_META * fs_meta)
 {
     TSK_FS_INFO *fs = (TSK_FS_INFO *) & hfs->fs_info;
 
@@ -1870,8 +2006,7 @@ hfs_dinode_copy(HFS_INFO * hfs, hfs_file *entry, TSK_FS_META * fs_meta)
     if (tsk_getu16(fs->endian, entry->rec_type) == HFS_FOLDER_RECORD) {
         fs_meta->size = 0;
         fs_meta->type =
-            hfsmode2tskmetatype(tsk_getu16(fs->endian,
-                entry->perm.mode));
+            hfsmode2tskmetatype(tsk_getu16(fs->endian, entry->perm.mode));
         if (fs_meta->type != TSK_FS_META_TYPE_DIR) {
             tsk_fprintf(stderr,
                 "hfs_dinode_copy error: folder has non-directory type %"
@@ -1879,12 +2014,10 @@ hfs_dinode_copy(HFS_INFO * hfs, hfs_file *entry, TSK_FS_META * fs_meta)
             return 1;
         }
     }
-    else if (tsk_getu16(fs->endian,
-            entry->rec_type) == HFS_FILE_RECORD) {
+    else if (tsk_getu16(fs->endian, entry->rec_type) == HFS_FILE_RECORD) {
         fs_meta->size = tsk_getu64(fs->endian, entry->data.logic_sz);
         fs_meta->type =
-            hfsmode2tskmetatype(tsk_getu16(fs->endian,
-                entry->perm.mode));
+            hfsmode2tskmetatype(tsk_getu16(fs->endian, entry->perm.mode));
         if (fs_meta->type == TSK_FS_META_TYPE_DIR) {
             tsk_fprintf(stderr,
                 "hfs_dinode_copy error: file has directory type\n");
@@ -1899,19 +2032,16 @@ hfs_dinode_copy(HFS_INFO * hfs, hfs_file *entry, TSK_FS_META * fs_meta)
 
     fs_meta->uid = tsk_getu32(fs->endian, entry->perm.owner);
     fs_meta->gid = tsk_getu32(fs->endian, entry->perm.group);
-    fs_meta->mtime =
-        hfs2unixtime(tsk_getu32(fs->endian, entry->cmtime));
-    fs_meta->atime =
-        hfs2unixtime(tsk_getu32(fs->endian, entry->atime));
-    fs_meta->crtime =
-        hfs2unixtime(tsk_getu32(fs->endian, entry->ctime));
+    fs_meta->mtime = hfs2unixtime(tsk_getu32(fs->endian, entry->cmtime));
+    fs_meta->atime = hfs2unixtime(tsk_getu32(fs->endian, entry->atime));
+    fs_meta->crtime = hfs2unixtime(tsk_getu32(fs->endian, entry->ctime));
     fs_meta->ctime =
         hfs2unixtime(tsk_getu32(fs->endian, entry->attr_mtime));
     fs_meta->time2.hfs.bkup_time =
         hfs2unixtime(tsk_getu32(fs->endian, entry->bkup_date));
-    fs_meta->addr = 0; // @@@@ entry->inum;
+    fs_meta->addr = tsk_getu32(fs->endian, entry->cnid);
 
-    fs_meta->flags = 0; // @@@ entry->flags;
+    fs_meta->flags = 0;         // @@@ entry->flags;
 
     /* TODO could fill in name2 with this entry's name and parent inode
        from Catalog entry */
@@ -1956,16 +2086,16 @@ hfs_inode_lookup(TSK_FS_INFO * fs, TSK_FS_FILE * a_fs_file,
     if (tsk_verbose)
         tsk_fprintf(stderr, "hfs_inode_lookup: looking up %" PRIuINUM "\n",
             inum);
-    
+
     // @@@ Will need to add orphan stuff here too
-    
+
     /* First see if this is a special entry
-        * the special ones have their metadata stored in the volume header */
+     * the special ones have their metadata stored in the volume header */
     if (inum == HFS_EXTENTS_FILE_ID) {
         if (hfs_make_extents(hfs, a_fs_file))
             return 1;
         else
-            return 0; 
+            return 0;
     }
     else if (inum == HFS_CATALOG_FILE_ID) {
         if (hfs_make_catalog(hfs, a_fs_file))
@@ -1980,12 +2110,18 @@ hfs_inode_lookup(TSK_FS_INFO * fs, TSK_FS_FILE * a_fs_file,
             return 0;
     }
     else if (inum == HFS_STARTUP_FILE_ID) {
-        // @@@
+        if (hfs_make_startfile(hfs, a_fs_file))
+            return 1;
+        else
+            return 0;
     }
     else if (inum == HFS_ATTRIBUTES_FILE_ID) {
-        // @@@
+        if (hfs_make_attrfile(hfs, a_fs_file))
+            return 1;
+        else
+            return 0;
     }
-    
+
     /* Lookup inode and store it in the HFS structure */
     if (hfs_cat_file_lookup(hfs, inum, &entry))
         return 1;
@@ -2071,7 +2207,7 @@ hfs_make_data_run(TSK_FS_FILE * fs_file)
     }
 
     extents =
-        hfs_ext_find_extent_record(hfs, (uint32_t)entry.inum,
+        hfs_ext_find_extent_record(hfs, (uint32_t) entry.inum,
         entry.cat.data.extents);
 
     if (extents == NULL)
@@ -2124,43 +2260,48 @@ hfs_block_is_alloc(HFS_INFO * hfs, TSK_DADDR_T a_addr)
     TSK_FS_INFO *fs = &(hfs->fs_info);
     int b;
     int b2;
-    
+
     // lazy loading
     if (hfs->blockmap_file == NULL) {
         if ((hfs->blockmap_file =
-             tsk_fs_file_open_meta(fs, NULL, HFS_ALLOCATION_FILE_ID)) == NULL) {
+                tsk_fs_file_open_meta(fs, NULL,
+                    HFS_ALLOCATION_FILE_ID)) == NULL) {
             strncat(tsk_errstr2, " - Loading blockmap file",
-                    TSK_ERRSTR_L - strlen(tsk_errstr2));
+                TSK_ERRSTR_L - strlen(tsk_errstr2));
             return -1;
         }
-        
+
         /* cache the data attribute */
         hfs->blockmap_attr =
-            tsk_fs_attrlist_get(hfs->blockmap_file->meta->attr, TSK_FS_ATTR_TYPE_DEFAULT);
+            tsk_fs_attrlist_get(hfs->blockmap_file->meta->attr,
+            TSK_FS_ATTR_TYPE_DEFAULT);
         if (!hfs->blockmap_attr) {
-            strncat(tsk_errstr2, " - Data Attribute not found in Blockmap File",
-                    TSK_ERRSTR_L - strlen(tsk_errstr2));
+            strncat(tsk_errstr2,
+                " - Data Attribute not found in Blockmap File",
+                TSK_ERRSTR_L - strlen(tsk_errstr2));
             return -1;
         }
         hfs->blockmap_cache_start = -1;
     }
-    
+
     // get the byte offset
-    b = (int)a_addr / 8;
+    b = (int) a_addr / 8;
     if (b > hfs->blockmap_file->meta->size) {
         tsk_errno = TSK_ERR_FS_CORRUPT;
         snprintf(tsk_errstr, TSK_ERRSTR_L,
-                    "hfs_block_is_alloc: block %" PRIuDADDR
-                    " is too large for bitmap (%"PRIuOFF")", a_addr, hfs->blockmap_file->meta->size);
+            "hfs_block_is_alloc: block %" PRIuDADDR
+            " is too large for bitmap (%" PRIuOFF ")", a_addr,
+            hfs->blockmap_file->meta->size);
         return -1;
     }
-    
+
     // see if it is in the cache
-    if ((hfs->blockmap_cache_start == -1) || (hfs->blockmap_cache_start > b) 
+    if ((hfs->blockmap_cache_start == -1)
+        || (hfs->blockmap_cache_start > b)
         || (hfs->blockmap_cache_start + sizeof(hfs->blockmap_cache) <= b)) {
         size_t cnt = tsk_fs_attr_read(hfs->blockmap_attr, b,
-                               hfs->blockmap_cache,
-                               sizeof(hfs->blockmap_cache), 0);
+            hfs->blockmap_cache,
+            sizeof(hfs->blockmap_cache), 0);
         if (cnt != sizeof(hfs->blockmap_cache)) {
             // @@@
             return -1;
@@ -2666,7 +2807,7 @@ hfs_istat(TSK_FS_INFO * fs, FILE * hFile, TSK_INUM_T inum,
 
     tsk_fprintf(hFile, "Type:\t");
 
-    
+
     if (fs_file->meta->type == TSK_FS_META_TYPE_REG)
         tsk_fprintf(hFile, "File\n");
     else if (fs_file->meta->type == TSK_FS_META_TYPE_DIR)
@@ -2674,79 +2815,83 @@ hfs_istat(TSK_FS_INFO * fs, FILE * hFile, TSK_INUM_T inum,
 
     tsk_fs_make_ls(fs_file->meta, hfs_mode);
     tsk_fprintf(hFile, "Mode:\t%s\n", hfs_mode);
-    
+
     tsk_fprintf(hFile, "Created:\t%s", ctime(&fs_file->meta->crtime));
     tsk_fprintf(hFile, "Content Modified:\t%s",
-                ctime(&fs_file->meta->mtime));
+        ctime(&fs_file->meta->mtime));
     tsk_fprintf(hFile, "Attributes Modified:\t%s",
-                ctime(&fs_file->meta->ctime));
+        ctime(&fs_file->meta->ctime));
     tsk_fprintf(hFile, "Accessed:\t%s", ctime(&fs_file->meta->atime));
     tsk_fprintf(hFile, "Backed Up:\t%s",
-                ctime(&fs_file->meta->time2.hfs.bkup_time));
-    
-    
+        ctime(&fs_file->meta->time2.hfs.bkup_time));
+
+
     if (hfs_cat_file_lookup(hfs, inum, &entry) == 0) {
-        tsk_fprintf(hFile, "Owner-ID:\t%" PRIu32 "\n", tsk_getu32(fs->endian,
-                entry.cat.perm.owner));
-        tsk_fprintf(hFile, "Group-ID:\t%" PRIu32 "\n", tsk_getu32(fs->endian,
-                entry.cat.perm.group));
+        tsk_fprintf(hFile, "Owner-ID:\t%" PRIu32 "\n",
+            tsk_getu32(fs->endian, entry.cat.perm.owner));
+        tsk_fprintf(hFile, "Group-ID:\t%" PRIu32 "\n",
+            tsk_getu32(fs->endian, entry.cat.perm.group));
         if (((tsk_getu16(fs->endian,
-                         entry.cat.perm.mode) & HFS_IN_IFMT) == HFS_IN_IFCHR)
+                        entry.cat.perm.mode) & HFS_IN_IFMT) ==
+                HFS_IN_IFCHR)
             || ((tsk_getu16(fs->endian,
-                            entry.cat.perm.mode) & HFS_IN_IFMT) == HFS_IN_IFBLK)) {
+                        entry.cat.perm.mode) & HFS_IN_IFMT) ==
+                HFS_IN_IFBLK)) {
             tsk_fprintf(hFile, "Device ID:\t%" PRIu32 "\n",
-                        tsk_getu32(fs->endian, entry.cat.perm.special.raw));
+                tsk_getu32(fs->endian, entry.cat.perm.special.raw));
         }
         else if ((tsk_getu32(fs->endian,
-                             entry.cat.u_info.file_type) == HFS_HARDLINK_FILE_TYPE)
-                 && (tsk_getu32(fs->endian,
-                                entry.cat.u_info.file_cr) == HFS_HARDLINK_FILE_CREATOR)) {
+                    entry.cat.u_info.file_type) == HFS_HARDLINK_FILE_TYPE)
+            && (tsk_getu32(fs->endian,
+                    entry.cat.u_info.file_cr) ==
+                HFS_HARDLINK_FILE_CREATOR)) {
             // technically, the creation date of this item should be the same as either the
             // creation date of the "HFS+ Private Data" folder or the creation date of the root folder
             tsk_fprintf(hFile, "Hard link inode number\t %" PRIu32 "\n",
-                        tsk_getu32(fs->endian, entry.cat.perm.special.inum));
+                tsk_getu32(fs->endian, entry.cat.perm.special.inum));
         }
         else {
             // only files within the "HFS+ Private Data" folder are actually hard link files
             // (and even then, only the ones labelled "iNode*"
             tsk_fprintf(hFile, "Link count:\t%" PRIu32 "\n",
-                        tsk_getu32(fs->endian, entry.cat.perm.special.nlink));
-    }
-        
+                tsk_getu32(fs->endian, entry.cat.perm.special.nlink));
+        }
+
         if (tsk_getu16(fs->endian, entry.cat.flags) & HFS_FILE_FLAG_LOCKED)
             tsk_fprintf(hFile, "Locked\n");
         if (tsk_getu16(fs->endian, entry.cat.flags) & HFS_FILE_FLAG_ATTR)
             tsk_fprintf(hFile, "Has extended attributes\n");
         if (tsk_getu16(fs->endian, entry.cat.flags) & HFS_FILE_FLAG_ACL)
             tsk_fprintf(hFile, "Has security data (ACLs)\n");
-        
+
         tsk_fprintf(hFile,
-                    "File type:\t%04" PRIx32 "\nFile creator:\t%04" PRIx32 "\n",
-                    tsk_getu32(fs->endian, entry.cat.u_info.file_type),
-                    tsk_getu32(fs->endian, entry.cat.u_info.file_type));
-        
+            "File type:\t%04" PRIx32 "\nFile creator:\t%04" PRIx32 "\n",
+            tsk_getu32(fs->endian, entry.cat.u_info.file_type),
+            tsk_getu32(fs->endian, entry.cat.u_info.file_type));
+
         if (tsk_getu16(fs->endian,
-                       entry.cat.u_info.flags) & HFS_FINDER_FLAG_NAME_LOCKED)
+                entry.cat.u_info.flags) & HFS_FINDER_FLAG_NAME_LOCKED)
             tsk_fprintf(hFile, "Name locked\n");
         if (tsk_getu16(fs->endian,
-                       entry.cat.u_info.flags) & HFS_FINDER_FLAG_HAS_BUNDLE)
+                entry.cat.u_info.flags) & HFS_FINDER_FLAG_HAS_BUNDLE)
             tsk_fprintf(hFile, "Has bundle\n");
         if (tsk_getu16(fs->endian,
-                       entry.cat.u_info.flags) & HFS_FINDER_FLAG_IS_INVISIBLE)
+                entry.cat.u_info.flags) & HFS_FINDER_FLAG_IS_INVISIBLE)
             tsk_fprintf(hFile, "Is invisible\n");
         if (tsk_getu16(fs->endian,
-                       entry.cat.u_info.flags) & HFS_FINDER_FLAG_IS_ALIAS)
+                entry.cat.u_info.flags) & HFS_FINDER_FLAG_IS_ALIAS)
             tsk_fprintf(hFile, "Is alias\n");
-        
+
         tsk_fprintf(hFile, "Text encoding:\t%" PRIx32 "\n",
-                    tsk_getu32(fs->endian, entry.cat.text_enc));
-        
+            tsk_getu32(fs->endian, entry.cat.text_enc));
+
         if (tsk_getu16(fs->endian, entry.cat.rec_type) == HFS_FILE_RECORD) {
             tsk_fprintf(hFile,
-                        "Data fork size:\t%" PRIu64 "\nResource fork size:\t%" PRIu64
-                        "\n", tsk_getu64(fs->endian, entry.cat.data.logic_sz),
-                        tsk_getu64(fs->endian, entry.cat.resource.logic_sz));
-        }        
+                "Data fork size:\t%" PRIu64 "\nResource fork size:\t%"
+                PRIu64 "\n", tsk_getu64(fs->endian,
+                    entry.cat.data.logic_sz), tsk_getu64(fs->endian,
+                    entry.cat.resource.logic_sz));
+        }
     }
 
     print.idx = 0;
@@ -2782,7 +2927,7 @@ hfs_close(TSK_FS_INFO * fs)
         tsk_fs_file_close(hfs->blockmap_file);
         hfs->blockmap_attr = NULL;
     }
-    
+
     free(hfs);
 }
 
@@ -2899,9 +3044,9 @@ hfs_open(TSK_IMG_INFO * img_info, TSK_OFF_T offset,
 
     fs->first_inum = HFS_ROOT_INUM;
     fs->root_inum = HFS_ROOT_INUM;
-    fs->last_inum = HFS_FIRST_USER_CNID - 1;        // we will later increase this
+    fs->last_inum = HFS_FIRST_USER_CNID - 1;    // we will later increase this
     fs->inum_count = fs->last_inum - fs->first_inum + 1;
-    
+
     /* Load the Catalog file extents (data runs) starting with 
      * the data in the volume header */
     // @@@@ How will this know to load only one entry from the volume header?
@@ -2916,43 +3061,45 @@ hfs_open(TSK_IMG_INFO * img_info, TSK_OFF_T offset,
     }
 
     hfs->extents_file = NULL;   // we will load this when needed
-    hfs->extents_attr = NULL;   
-    
-    
-    
+    hfs->extents_attr = NULL;
+
+
+
     if ((hfs->catalog_file =
-         tsk_fs_file_open_meta(fs, NULL, HFS_CATALOG_FILE_ID)) == NULL) {
+            tsk_fs_file_open_meta(fs, NULL,
+                HFS_CATALOG_FILE_ID)) == NULL) {
         fs->tag = 0;
         free(hfs->fs);
         free(hfs);
         return NULL;
     }
-    
+
     /* cache the data attribute */
     hfs->catalog_attr =
-        tsk_fs_attrlist_get(hfs->catalog_file->meta->attr, TSK_FS_ATTR_TYPE_DEFAULT);
+        tsk_fs_attrlist_get(hfs->catalog_file->meta->attr,
+        TSK_FS_ATTR_TYPE_DEFAULT);
     if (!hfs->catalog_attr) {
         fs->tag = 0;
         tsk_fs_file_close(hfs->catalog_file);
         free(hfs->fs);
         free(hfs);
         strncat(tsk_errstr2, " - Data Attribute not found in Catalog File",
-                TSK_ERRSTR_L - strlen(tsk_errstr2));
+            TSK_ERRSTR_L - strlen(tsk_errstr2));
         return NULL;
     }
 
     // cache the catalog file header
     cnt = tsk_fs_attr_read(hfs->catalog_attr, 14,
-                           (char *) &(hfs->catalog_header),
-                           sizeof(hfs_btree_header_record), 0);
+        (char *) &(hfs->catalog_header),
+        sizeof(hfs_btree_header_record), 0);
     if (cnt != sizeof(hfs_btree_header_record)) {
         // @@@
         fs->tag = 0;
         free(hfs->fs);
         free(hfs);
-        return NULL;        
+        return NULL;
     }
-    
+
     if (tsk_getu16(fs->endian, hfs->fs->version) == 4)
         hfs->is_case_sensitive = 0;
     else if (tsk_getu16(fs->endian, hfs->fs->version) == 5) {
diff --git a/tsk3/fs/tsk_hfs.h b/tsk3/fs/tsk_hfs.h
index f67c5e972..cee47f134 100644
--- a/tsk3/fs/tsk_hfs.h
+++ b/tsk3/fs/tsk_hfs.h
@@ -149,7 +149,9 @@
 
 #define HFS_CATALOGNAME "$CatalogFile"
 #define HFS_EXTENTSNAME "$ExtentsFile"
-#define HFS_ALLOCATIONNAME "$BitMap"
+#define HFS_ALLOCATIONNAME "$BitMapFile"
+#define HFS_STARTUPNAME "$BootFile"
+#define HFS_ATTRIBUTESNAME "$AttributesFile"
 
 /*
  * HFS structures
-- 
GitLab