Coverage Report

Created: 2025-07-18 07:08

/src/sleuthkit/tsk/fs/hfs_dent.cpp
Line
Count
Source (jump to first uncovered line)
1
/*
2
** The Sleuth Kit
3
**
4
** This software is subject to the IBM Public License ver. 1.0,
5
** which was displayed prior to download and is included in the readme.txt
6
** file accompanying the Sleuth Kit files.  It may also be requested from:
7
** Crucial Security Inc.
8
** 14900 Conference Center Drive
9
** Chantilly, VA 20151
10
**
11
** Copyright (c) 2009-2011 Brian Carrier.  All rights reserved.
12
**
13
** Judson Powers [jpowers@atc-nycorp.com]
14
** Matt Stillerman [matt@atc-nycorp.com]
15
** Copyright (c) 2008, 2012 ATC-NY.  All rights reserved.
16
** This file contains data developed with support from the National
17
** Institute of Justice, Office of Justice Programs, U.S. Department of Justice.
18
**
19
** Wyatt Banks [wbanks@crucialsecurity.com]
20
** Copyright (c) 2005 Crucial Security Inc.  All rights reserved.
21
**
22
** Brian Carrier [carrier@sleuthkit.org]
23
** Copyright (c) 2003-2005 Brian Carrier.  All rights reserved
24
**
25
** Copyright (c) 1997,1998,1999, International Business Machines
26
** Corporation and others. All Rights Reserved.
27
*/
28
29
/* TCT
30
 * LICENSE
31
 *      This software is distributed under the IBM Public License.
32
 * AUTHOR(S)
33
 *      Wietse Venema
34
 *      IBM T.J. Watson Research
35
 *      P.O. Box 704
36
 *      Yorktown Heights, NY 10598, USA
37
 --*/
38
39
/*
40
** You may distribute the Sleuth Kit, or other software that incorporates
41
** part of all of the Sleuth Kit, in object code form under a license agreement,
42
** provided that:
43
** a) you comply with the terms and conditions of the IBM Public License
44
**    ver 1.0; and
45
** b) the license agreement
46
**     i) effectively disclaims on behalf of all Contributors all warranties
47
**        and conditions, express and implied, including warranties or
48
**        conditions of title and non-infringement, and implied warranties
49
**        or conditions of merchantability and fitness for a particular
50
**        purpose.
51
**    ii) effectively excludes on behalf of all Contributors liability for
52
**        damages, including direct, indirect, special, incidental and
53
**        consequential damages such as lost profits.
54
**   iii) states that any provisions which differ from IBM Public License
55
**        ver. 1.0 are offered by that Contributor alone and not by any
56
**        other party; and
57
**    iv) states that the source code for the program is available from you,
58
**        and informs licensees how to obtain it in a reasonable manner on or
59
**        through a medium customarily used for software exchange.
60
**
61
** When the Sleuth Kit or other software that incorporates part or all of
62
** the Sleuth Kit is made available in source code form:
63
**     a) it must be made available under IBM Public License ver. 1.0; and
64
**     b) a copy of the IBM Public License ver. 1.0 must be included with
65
**        each copy of the program.
66
*/
67
68
/** \file hfs_dent.c
69
 * Contains the file name layer code for HFS+ file systems -- not included in
70
 * code by default.
71
 */
72
73
#include "tsk_fs_i.h"
74
#include "tsk_hfs.h"
75
76
/* convert HFS+'s UTF16 to UTF8
77
 * replaces null characters with another character (0xfffd)
78
 * replaces slashes (permitted by HFS+ but causes problems with TSK)
79
 *   with colons (generally not allowed by Mac OS X)
80
 * note that at least one directory on HFS+ volumes begins with
81
 *   four nulls, so we do need to handle nulls; also, Apple chooses
82
 *   to encode nulls as UTF8 \xC0\x80, which is not a valid UTF8 sequence
83
 *
84
 *   @param fs  the file system
85
 *   @param uni  the UTF16 string as a sequence of bytes
86
 *   @param ulen  then length of the UTF16 string in characters
87
 *   @param asc   a buffer to hold the UTF8 result
88
 *   @param alen  the length of that buffer
89
 *   @param flags  control some aspects of the conversion
90
 *   @return 0 on success, 1 on failure; sets up to error string 1
91
 *
92
 *   HFS_U16U8_FLAG_REPLACE_SLASH  if this flag is set, then slashes will be replaced
93
 *   by colons.  Otherwise, they will not be replaced.
94
 *
95
 *   HFS_U16U8_FLAG_REPLACE_CONTROL if this flag is set, then all control characters
96
 *   will be replaced by the UTF16_NULL_REPLACE character. N.B., always replaces
97
 *   null characters regardless of this flag.
98
 */
99
uint8_t
100
hfs_UTF16toUTF8(TSK_FS_INFO * fs, uint8_t * uni, int ulen, char *asc,
101
    int alen, uint32_t flags)
102
28.0k
{
103
28.0k
    UTF8 *ptr8;
104
28.0k
    uint8_t *uniclean;
105
28.0k
    UTF16 *ptr16;
106
28.0k
    int i;
107
28.0k
    TSKConversionResult r;
108
109
    // remove nulls from the Unicode string
110
    // convert / to :
111
28.0k
    uniclean = (uint8_t *) tsk_malloc(ulen * 2);
112
28.0k
    if (!uniclean)
113
0
        return 1;
114
115
28.0k
    memcpy(uniclean, uni, ulen * 2);
116
117
646k
    for (i = 0; i < ulen; ++i) {
118
618k
        uint16_t uc = tsk_getu16(fs->endian, uniclean + i * 2);
119
120
121
618k
        int changed = 0;
122
618k
        if (uc == UTF16_NULL) {
123
114k
            uc = UTF16_NULL_REPLACE;
124
114k
            changed = 1;
125
114k
        }
126
503k
        else if ((flags & HFS_U16U8_FLAG_REPLACE_SLASH)
127
503k
            && uc == UTF16_SLASH) {
128
690
            uc = UTF16_COLON;
129
690
            changed = 1;
130
690
        }
131
132
502k
        else if ((flags & HFS_U16U8_FLAG_REPLACE_CONTROL)
133
502k
            && uc < UTF16_LEAST_PRINTABLE) {
134
0
            uc = (uint16_t) UTF16_NULL_REPLACE;
135
0
            changed = 1;
136
0
        }
137
138
618k
        if (changed)
139
115k
            *((uint16_t *) (uniclean + i * 2)) =
140
115k
                tsk_getu16(fs->endian, (uint8_t *) & uc);
141
618k
    }
142
143
    // convert to UTF-8
144
28.0k
    memset(asc, 0, alen);
145
146
28.0k
    ptr8 = (UTF8 *) asc;
147
28.0k
    ptr16 = (UTF16 *) uniclean;
148
28.0k
    r = tsk_UTF16toUTF8(fs->endian, (const UTF16 **) &ptr16,
149
28.0k
        (const UTF16 *) (&uniclean[ulen * 2]), &ptr8,
150
28.0k
        (UTF8 *) & asc[alen], TSKstrictConversion);
151
152
28.0k
    free(uniclean);
153
28.0k
    if (r != TSKconversionOK) {
154
218
        tsk_error_set_errno(TSK_ERR_FS_UNICODE);
155
218
        tsk_error_set_errstr
156
218
            ("hfs_UTF16toUTF8: unicode conversion failed (%d)", (int) r);
157
218
        return 1;
158
218
    }
159
160
27.7k
    return 0;
161
28.0k
}
162
163
static TSK_FS_NAME_TYPE_ENUM
164
hfsmode2tsknametype(uint16_t a_mode)
165
9.26k
{
166
9.26k
    switch (a_mode & HFS_IN_IFMT) {
167
19
    case HFS_IN_IFIFO:
168
19
        return TSK_FS_NAME_TYPE_FIFO;
169
54
    case HFS_IN_IFCHR:
170
54
        return TSK_FS_NAME_TYPE_CHR;
171
157
    case HFS_IN_IFDIR:
172
157
        return TSK_FS_NAME_TYPE_DIR;
173
41
    case HFS_IN_IFBLK:
174
41
        return TSK_FS_NAME_TYPE_BLK;
175
1.87k
    case HFS_IN_IFREG:
176
1.87k
        return TSK_FS_NAME_TYPE_REG;
177
1.38k
    case HFS_IN_IFLNK:
178
1.38k
        return TSK_FS_NAME_TYPE_LNK;
179
42
    case HFS_IN_IFSOCK:
180
42
        return TSK_FS_NAME_TYPE_SOCK;
181
81
    case HFS_IFWHT:
182
81
        return TSK_FS_NAME_TYPE_WHT;
183
0
    case HFS_IFXATTR:
184
0
        return TSK_FS_NAME_TYPE_UNDEF;
185
5.60k
    default:
186
        /* error */
187
5.60k
        return TSK_FS_NAME_TYPE_UNDEF;
188
9.26k
    }
189
9.26k
}
190
191
192
// used to pass data to the callback
193
typedef struct {
194
    TSK_FS_DIR *fs_dir;
195
    TSK_FS_NAME *fs_name;
196
    uint32_t cnid;
197
} HFS_DIR_OPEN_META_INFO;
198
199
static uint8_t
200
hfs_dir_open_meta_cb(
201
  HFS_INFO * hfs,
202
  int8_t level_type,
203
  const hfs_btree_key_cat * cur_key,
204
  int cur_keylen,
205
  size_t nodesize,
206
  [[maybe_unused]] TSK_OFF_T key_off,
207
  void *ptr)
208
99.8k
{
209
99.8k
    HFS_DIR_OPEN_META_INFO *info = (HFS_DIR_OPEN_META_INFO *) ptr;
210
99.8k
    TSK_FS_INFO *fs = &hfs->fs_info;
211
212
99.8k
    if (tsk_verbose)
213
0
        fprintf(stderr,
214
0
            "hfs_dir_open_meta_cb: want %" PRIu32 " vs got %" PRIu32
215
0
            " (%s node)\n", info->cnid, tsk_getu32(hfs->fs_info.endian,
216
0
                cur_key->parent_cnid),
217
0
            (level_type == HFS_BT_NODE_TYPE_IDX) ? "Index" : "Leaf");
218
219
99.8k
    if (level_type == HFS_BT_NODE_TYPE_IDX) {
220
9.84k
        if (tsk_getu32(hfs->fs_info.endian,
221
9.84k
                cur_key->parent_cnid) < info->cnid) {
222
8.06k
            return HFS_BTREE_CB_IDX_LT;
223
8.06k
        }
224
1.78k
        else {
225
1.78k
            return HFS_BTREE_CB_IDX_EQGT;
226
1.78k
        }
227
9.84k
    }
228
89.9k
    else {
229
89.9k
        uint8_t *rec_buf = (uint8_t *) cur_key;
230
89.9k
        uint16_t rec_type;
231
89.9k
        size_t rec_off2;
232
233
89.9k
        if (tsk_getu32(hfs->fs_info.endian,
234
89.9k
                cur_key->parent_cnid) < info->cnid) {
235
54.2k
            return HFS_BTREE_CB_LEAF_GO;
236
54.2k
        }
237
35.6k
        else if (tsk_getu32(hfs->fs_info.endian,
238
35.6k
                cur_key->parent_cnid) > info->cnid) {
239
5.63k
            return HFS_BTREE_CB_LEAF_STOP;
240
5.63k
        }
241
  // Need at least 2 bytes for key_len
242
30.0k
        if (cur_keylen < 2) {
243
0
            tsk_error_set_errno(TSK_ERR_FS_GENFS);
244
0
            tsk_error_set_errstr("hfs_dir_open_meta: cur_keylen value out of bounds");
245
0
            return HFS_BTREE_CB_ERR;
246
0
        }
247
30.0k
        rec_off2 = 2 + tsk_getu16(hfs->fs_info.endian, cur_key->key_len);
248
249
30.0k
        if ((nodesize < 2) || (rec_off2 >= nodesize - 2)) {
250
12
            tsk_error_set_errno(TSK_ERR_FS_GENFS);
251
12
            tsk_error_set_errstr("hfs_dir_open_meta: nodesize value out of bounds");
252
12
            return HFS_BTREE_CB_ERR;
253
12
        }
254
30.0k
        rec_type = tsk_getu16(hfs->fs_info.endian, &rec_buf[rec_off2]);
255
256
        // Catalog entry is for a file
257
30.0k
        if (rec_type == HFS_FILE_THREAD) {
258
912
            tsk_error_set_errno(TSK_ERR_FS_GENFS);
259
912
            tsk_error_set_errstr("hfs_dir_open_meta: Entry"
260
912
                " is a file, not a folder");
261
912
            return HFS_BTREE_CB_ERR;
262
912
        }
263
264
        /* This will link the folder to its parent, which is the ".." entry */
265
29.1k
        else if (rec_type == HFS_FOLDER_THREAD) {
266
7.24k
            hfs_thread *thread = (hfs_thread *) & rec_buf[rec_off2];
267
268
            // hfs_thread is of variable size on disk. The minimum size is
269
            // 10 bytes (8 for the non-name fields, 2 for the length of an
270
            // empty name).
271
7.24k
            const size_t min_hfs_thread_size = sizeof(hfs_thread) - sizeof(hfs_uni_str) + 2;
272
273
            // First, check that we can read as far as the name length; then
274
            // get the name length and check that the whole record fits into
275
            // the buffer.
276
7.24k
            if (rec_off2 > nodesize - min_hfs_thread_size ||
277
7.24k
                rec_off2 > nodesize - (min_hfs_thread_size + tsk_getu16(hfs->fs_info.endian, thread->name.length))) {
278
12
                tsk_error_set_errno(TSK_ERR_FS_GENFS);
279
12
                tsk_error_set_errstr("hfs_dir_open_meta: nodesize value out of bounds");
280
12
                return HFS_BTREE_CB_ERR;
281
12
            }
282
283
7.23k
            strcpy(info->fs_name->name, "..");
284
7.23k
            info->fs_name->meta_addr =
285
7.23k
                tsk_getu32(hfs->fs_info.endian, thread->parent_cnid);
286
7.23k
            info->fs_name->type = TSK_FS_NAME_TYPE_DIR;
287
7.23k
            info->fs_name->flags = TSK_FS_NAME_FLAG_ALLOC;
288
7.23k
        }
289
290
        /* This is a folder in the folder */
291
21.8k
        else if (rec_type == HFS_FOLDER_RECORD) {
292
12.4k
            if ((nodesize < sizeof(hfs_folder)) || (rec_off2 > nodesize - sizeof(hfs_folder))) {
293
21
                tsk_error_set_errno(TSK_ERR_FS_GENFS);
294
21
                tsk_error_set_errstr("hfs_dir_open_meta: nodesize value out of bounds");
295
21
                return HFS_BTREE_CB_ERR;
296
21
            }
297
12.3k
            hfs_folder *folder = (hfs_folder *) & rec_buf[rec_off2];
298
299
12.3k
            info->fs_name->meta_addr =
300
12.3k
                tsk_getu32(hfs->fs_info.endian, folder->std.cnid);
301
12.3k
            info->fs_name->type = TSK_FS_NAME_TYPE_DIR;
302
12.3k
            info->fs_name->flags = TSK_FS_NAME_FLAG_ALLOC;
303
304
            // Make sure there is enough space in cur_key for the name
305
            // (name is unicode so each characters is two bytes; 6 bytes
306
            // of non-name characters)
307
12.3k
            const int32_t nameLength =
308
12.3k
                tsk_getu16(hfs->fs_info.endian, cur_key->name.length);
309
310
12.3k
            if (2*nameLength > tsk_getu16(hfs->fs_info.endian, cur_key->key_len) - 6) {
311
119
                error_returned
312
119
                ("hfs_dir_open_meta_cb: name length is too long");
313
119
                return HFS_BTREE_CB_ERR;
314
119
            }
315
12.2k
            if (hfs_UTF16toUTF8(fs, (uint8_t *) cur_key->name.unicode,
316
12.2k
                    nameLength, info->fs_name->name, HFS_MAXNAMLEN + 1,
317
12.2k
                    HFS_U16U8_FLAG_REPLACE_SLASH)) {
318
59
                return HFS_BTREE_CB_ERR;
319
59
            }
320
12.2k
        }
321
322
        /* This is a normal file in the folder */
323
9.49k
        else if (rec_type == HFS_FILE_RECORD) {
324
9.28k
            if ((nodesize < sizeof(hfs_file)) || (rec_off2 > nodesize - sizeof(hfs_file))) {
325
21
                tsk_error_set_errno(TSK_ERR_FS_GENFS);
326
21
                tsk_error_set_errstr("hfs_dir_open_meta: nodesize value out of bounds");
327
21
                return HFS_BTREE_CB_ERR;
328
21
            }
329
9.26k
            hfs_file *file = (hfs_file *) & rec_buf[rec_off2];
330
            // This could be a hard link.  We need to test this CNID, and follow it if necessary.
331
9.26k
            unsigned char is_err;
332
9.26k
            TSK_INUM_T file_cnid =
333
9.26k
                tsk_getu32(hfs->fs_info.endian, file->std.cnid);
334
9.26k
            TSK_INUM_T target_cnid =
335
9.26k
                hfs_follow_hard_link(hfs, file, &is_err);
336
9.26k
            if (is_err > 1) {
337
0
                error_returned
338
0
                    ("hfs_dir_open_meta_cb: trying to follow a possible hard link in the directory");
339
0
                return HFS_BTREE_CB_ERR;
340
0
            }
341
9.26k
            if (target_cnid != file_cnid) {
342
0
                HFS_ENTRY entry;
343
0
                uint8_t lkup;   // lookup result
344
345
                // This is a hard link.  We need to fill in the name->type and name->meta_addr from the target
346
0
                info->fs_name->meta_addr = target_cnid;
347
                // get the Catalog entry for the target CNID
348
349
0
                lkup = hfs_cat_file_lookup(hfs, target_cnid, &entry,
350
0
                    FALSE);
351
0
                if (lkup != 0) {
352
0
                    error_returned
353
0
                        ("hfs_dir_open_meta_cb: retrieving the catalog entry for the target of a hard link");
354
0
                    return HFS_BTREE_CB_ERR;
355
0
                }
356
0
                info->fs_name->type =
357
0
                    hfsmode2tsknametype(tsk_getu16(hfs->fs_info.endian,
358
0
                        entry.cat.std.perm.mode));
359
0
            }
360
9.26k
            else {
361
                // This is NOT a hard link.
362
9.26k
                info->fs_name->meta_addr =
363
9.26k
                    tsk_getu32(hfs->fs_info.endian, file->std.cnid);
364
9.26k
                info->fs_name->type =
365
9.26k
                    hfsmode2tsknametype(tsk_getu16(hfs->fs_info.endian,
366
9.26k
                        file->std.perm.mode));
367
9.26k
            }
368
9.26k
            info->fs_name->flags = TSK_FS_NAME_FLAG_ALLOC;
369
370
            // Make sure there is enough space in cur_key for the name
371
            // (name is unicode so each characters is two bytes; 6 bytes
372
            // of non-name characters)
373
9.26k
            const int32_t nameLength =
374
9.26k
                tsk_getu16(hfs->fs_info.endian, cur_key->name.length);
375
9.26k
            if (2*nameLength > tsk_getu16(hfs->fs_info.endian, cur_key->key_len) - 6) {
376
90
                error_returned
377
90
                ("hfs_dir_open_meta_cb: name length is too long");
378
90
                return HFS_BTREE_CB_ERR;
379
90
            }
380
9.17k
            if (hfs_UTF16toUTF8(fs, (uint8_t *) cur_key->name.unicode,
381
9.17k
                    nameLength, info->fs_name->name, HFS_MAXNAMLEN + 1,
382
9.17k
                    HFS_U16U8_FLAG_REPLACE_SLASH)) {
383
65
                return HFS_BTREE_CB_ERR;
384
65
            }
385
9.17k
        }
386
210
        else {
387
210
            tsk_error_set_errno(TSK_ERR_FS_GENFS);
388
            // @@@ MAY NEED TO IMPROVE BELOW MESSAGE
389
210
            tsk_error_set_errstr
390
210
                ("hfs_dir_open_meta: Unknown record type %d in leaf node",
391
210
                rec_type);
392
210
            return HFS_BTREE_CB_ERR;
393
210
        }
394
395
28.5k
        if (tsk_fs_dir_add(info->fs_dir, info->fs_name)) {
396
0
            return HFS_BTREE_CB_ERR;
397
0
        }
398
28.5k
        return HFS_BTREE_CB_LEAF_GO;
399
28.5k
    }
400
99.8k
}
401
402
/** \internal
403
* Process a directory and load up FS_DIR with the entries. If a pointer to
404
* an already allocated FS_DIR structure is given, it will be cleared.  If no existing
405
* FS_DIR structure is passed (i.e. NULL), then a new one will be created. If the return
406
* value is error or corruption, then the FS_DIR structure could
407
* have entries (depending on when the error occurred).
408
*
409
* @param a_fs File system to analyze
410
* @param a_fs_dir Pointer to FS_DIR pointer. Can contain an already allocated
411
* structure or a new structure.
412
* @param a_addr Address of directory to process.
413
* @param recursion_depth Recursion depth to limit the number of self-calls
414
* @returns error, corruption, ok etc.
415
*/
416
TSK_RETVAL_ENUM
417
hfs_dir_open_meta(
418
  TSK_FS_INFO * fs,
419
  TSK_FS_DIR ** a_fs_dir,
420
  TSK_INUM_T a_addr,
421
  [[maybe_unused]] int recursion_depth)
422
12.3k
{
423
12.3k
    HFS_INFO *hfs = (HFS_INFO *) fs;
424
12.3k
    uint32_t cnid;              /* catalog node ID of the entry (= inum) */
425
12.3k
    TSK_FS_DIR *fs_dir;
426
12.3k
    TSK_FS_NAME *fs_name;
427
12.3k
    HFS_DIR_OPEN_META_INFO info;
428
429
430
12.3k
    tsk_error_reset();
431
432
12.3k
    cnid = (uint32_t) a_addr;
433
434
12.3k
    if (tsk_verbose)
435
0
        fprintf(stderr,
436
0
            "hfs_dir_open_meta: called for directory %" PRIu32 "\n", cnid);
437
438
12.3k
    if (a_addr < fs->first_inum || a_addr > fs->last_inum) {
439
951
        tsk_error_reset();
440
951
        tsk_error_set_errno(TSK_ERR_FS_WALK_RNG);
441
951
        tsk_error_set_errstr("hfs_dir_open_meta: Invalid inode value: %"
442
951
            PRIuINUM, a_addr);
443
951
        return TSK_ERR;
444
951
    }
445
11.4k
    else if (a_fs_dir == NULL) {
446
0
        tsk_error_reset();
447
0
        tsk_error_set_errno(TSK_ERR_FS_ARG);
448
0
        tsk_error_set_errstr
449
0
            ("hfs_dir_open_meta: NULL fs_dir argument given");
450
0
        return TSK_ERR;
451
0
    }
452
453
11.4k
    if (tsk_verbose)
454
0
        tsk_fprintf(stderr,
455
0
            "hfs_dir_open_meta: Processing directory %" PRIuINUM "\n",
456
0
            a_addr);
457
458
11.4k
    fs_dir = *a_fs_dir;
459
11.4k
    if (fs_dir) {
460
0
        tsk_fs_dir_reset(fs_dir);
461
0
        fs_dir->addr = a_addr;
462
0
    }
463
11.4k
    else if ((*a_fs_dir = fs_dir =
464
11.4k
            tsk_fs_dir_alloc(fs, a_addr, 128)) == NULL) {
465
0
        return TSK_ERR;
466
0
    }
467
468
11.4k
    if ((fs_name = tsk_fs_name_alloc(HFS_MAXNAMLEN + 1, 0)) == NULL) {
469
0
        return TSK_ERR;
470
0
    }
471
11.4k
    info.fs_dir = fs_dir;
472
11.4k
    info.fs_name = fs_name;
473
474
11.4k
    if ((fs_dir->fs_file =
475
11.4k
            tsk_fs_file_open_meta(fs, NULL, a_addr)) == NULL) {
476
3.21k
        tsk_error_errstr2_concat(" - hfs_dir_open_meta");
477
3.21k
        tsk_fs_name_free(fs_name);
478
3.21k
        return TSK_ERR;
479
3.21k
    }
480
481
    // if we are listing the root directory, add the Orphan directory and special HFS file entries
482
8.20k
    if (a_addr == fs->root_inum) {
483
5.03k
        int i;
484
35.2k
        for (i = 0; i < 6; i++) {
485
30.2k
            switch (i) {
486
5.03k
            case 0:
487
5.03k
                if (!hfs->has_extents_file)
488
1.08k
                    continue;
489
3.95k
                strncpy(fs_name->name, HFS_EXTENTS_FILE_NAME,
490
3.95k
                    fs_name->name_size);
491
3.95k
                fs_name->meta_addr = HFS_EXTENTS_FILE_ID;
492
3.95k
                break;
493
5.03k
            case 1:
494
5.03k
                strncpy(fs_name->name, HFS_CATALOG_FILE_NAME,
495
5.03k
                    fs_name->name_size);
496
5.03k
                fs_name->meta_addr = HFS_CATALOG_FILE_ID;
497
5.03k
                break;
498
5.03k
            case 2:
499
                // Note: the Extents file and the BadBlocks file are really the same.
500
5.03k
                if (!hfs->has_extents_file)
501
1.08k
                    continue;
502
3.95k
                strncpy(fs_name->name, HFS_BAD_BLOCK_FILE_NAME,
503
3.95k
                    fs_name->name_size);
504
3.95k
                fs_name->meta_addr = HFS_BAD_BLOCK_FILE_ID;
505
3.95k
                break;
506
5.03k
            case 3:
507
5.03k
                strncpy(fs_name->name, HFS_ALLOCATION_FILE_NAME,
508
5.03k
                    fs_name->name_size);
509
5.03k
                fs_name->meta_addr = HFS_ALLOCATION_FILE_ID;
510
5.03k
                break;
511
5.03k
            case 4:
512
5.03k
                if (!hfs->has_startup_file)
513
1.43k
                    continue;
514
3.60k
                strncpy(fs_name->name, HFS_STARTUP_FILE_NAME,
515
3.60k
                    fs_name->name_size);
516
3.60k
                fs_name->meta_addr = HFS_STARTUP_FILE_ID;
517
3.60k
                break;
518
5.03k
            case 5:
519
5.03k
                if (!hfs->has_attributes_file)
520
881
                    continue;
521
4.15k
                strncpy(fs_name->name, HFS_ATTRIBUTES_FILE_NAME,
522
4.15k
                    fs_name->name_size);
523
4.15k
                fs_name->meta_addr = HFS_ATTRIBUTES_FILE_ID;
524
4.15k
                break;
525
                /*
526
                   case 6:
527
                   strncpy(fs_name->name, HFS_REPAIR_CATALOG_FILE_NAME, fs_name->name_size);
528
                   fs_name->meta_addr = HFS_REPAIR_CATALOG_FILE_ID;
529
                   break;
530
                   case 7:
531
                   strncpy(fs_name->name, HFS_BOGUS_EXTENT_FILE_NAME, fs_name->name_size);
532
                   fs_name->meta_addr = HFS_BOGUS_EXTENT_FILE_ID;
533
                   break;
534
                 */
535
30.2k
            }
536
25.7k
            fs_name->type = TSK_FS_NAME_TYPE_REG;
537
25.7k
            fs_name->flags = TSK_FS_NAME_FLAG_ALLOC;
538
25.7k
            if (tsk_fs_dir_add(fs_dir, fs_name)) {
539
0
                tsk_fs_name_free(fs_name);
540
0
                return TSK_ERR;
541
0
            }
542
25.7k
        }
543
5.03k
    }
544
545
8.20k
    info.cnid = cnid;
546
8.20k
    if (hfs_cat_traverse(hfs, hfs_dir_open_meta_cb, &info)) {
547
2.12k
        tsk_fs_name_free(fs_name);
548
2.12k
        return TSK_ERR;
549
2.12k
    }
550
551
6.08k
    tsk_fs_name_free(fs_name);
552
6.08k
    return TSK_OK;
553
8.20k
}
554
555
int
556
hfs_name_cmp(TSK_FS_INFO * a_fs_info, const char *s1, const char *s2)
557
11.8k
{
558
11.8k
    HFS_INFO *hfs = (HFS_INFO *) a_fs_info;
559
11.8k
    if (hfs->is_case_sensitive)
560
152
        return strcmp(s1, s2);
561
11.6k
    else
562
11.6k
        return strcasecmp(s1, s2);
563
11.8k
}