Coverage Report

Created: 2025-11-11 07:01

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/sleuthkit/tsk/fs/hfs_dent.cpp
Line
Count
Source
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
30.6k
{
103
30.6k
    UTF8 *ptr8;
104
30.6k
    uint8_t *uniclean;
105
30.6k
    UTF16 *ptr16;
106
30.6k
    int i;
107
30.6k
    TSKConversionResult r;
108
109
    // remove nulls from the Unicode string
110
    // convert / to :
111
30.6k
    uniclean = (uint8_t *) tsk_malloc(ulen * 2);
112
30.6k
    if (!uniclean)
113
0
        return 1;
114
115
30.6k
    memcpy(uniclean, uni, ulen * 2);
116
117
597k
    for (i = 0; i < ulen; ++i) {
118
566k
        uint16_t uc = tsk_getu16(fs->endian, uniclean + i * 2);
119
120
121
566k
        int changed = 0;
122
566k
        if (uc == UTF16_NULL) {
123
68.6k
            uc = UTF16_NULL_REPLACE;
124
68.6k
            changed = 1;
125
68.6k
        }
126
498k
        else if ((flags & HFS_U16U8_FLAG_REPLACE_SLASH)
127
274k
            && uc == UTF16_SLASH) {
128
647
            uc = UTF16_COLON;
129
647
            changed = 1;
130
647
        }
131
132
497k
        else if ((flags & HFS_U16U8_FLAG_REPLACE_CONTROL)
133
0
            && uc < UTF16_LEAST_PRINTABLE) {
134
0
            uc = (uint16_t) UTF16_NULL_REPLACE;
135
0
            changed = 1;
136
0
        }
137
138
566k
        if (changed)
139
69.3k
            *((uint16_t *) (uniclean + i * 2)) =
140
69.3k
                tsk_getu16(fs->endian, (uint8_t *) & uc);
141
566k
    }
142
143
    // convert to UTF-8
144
30.6k
    memset(asc, 0, alen);
145
146
30.6k
    ptr8 = (UTF8 *) asc;
147
30.6k
    ptr16 = (UTF16 *) uniclean;
148
30.6k
    r = tsk_UTF16toUTF8(fs->endian, (const UTF16 **) &ptr16,
149
30.6k
        (const UTF16 *) (&uniclean[ulen * 2]), &ptr8,
150
30.6k
        (UTF8 *) & asc[alen], TSKstrictConversion);
151
152
30.6k
    free(uniclean);
153
30.6k
    if (r != TSKconversionOK) {
154
193
        tsk_error_set_errno(TSK_ERR_FS_UNICODE);
155
193
        tsk_error_set_errstr
156
193
            ("hfs_UTF16toUTF8: unicode conversion failed (%d)", (int) r);
157
193
        return 1;
158
193
    }
159
160
30.4k
    return 0;
161
30.6k
}
162
163
static TSK_FS_NAME_TYPE_ENUM
164
hfsmode2tsknametype(uint16_t a_mode)
165
11.5k
{
166
11.5k
    switch (a_mode & HFS_IN_IFMT) {
167
66
    case HFS_IN_IFIFO:
168
66
        return TSK_FS_NAME_TYPE_FIFO;
169
94
    case HFS_IN_IFCHR:
170
94
        return TSK_FS_NAME_TYPE_CHR;
171
103
    case HFS_IN_IFDIR:
172
103
        return TSK_FS_NAME_TYPE_DIR;
173
40
    case HFS_IN_IFBLK:
174
40
        return TSK_FS_NAME_TYPE_BLK;
175
1.86k
    case HFS_IN_IFREG:
176
1.86k
        return TSK_FS_NAME_TYPE_REG;
177
1.43k
    case HFS_IN_IFLNK:
178
1.43k
        return TSK_FS_NAME_TYPE_LNK;
179
124
    case HFS_IN_IFSOCK:
180
124
        return TSK_FS_NAME_TYPE_SOCK;
181
87
    case HFS_IFWHT:
182
87
        return TSK_FS_NAME_TYPE_WHT;
183
0
    case HFS_IFXATTR:
184
0
        return TSK_FS_NAME_TYPE_UNDEF;
185
7.70k
    default:
186
        /* error */
187
7.70k
        return TSK_FS_NAME_TYPE_UNDEF;
188
11.5k
    }
189
11.5k
}
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
114k
{
209
114k
    HFS_DIR_OPEN_META_INFO *info = (HFS_DIR_OPEN_META_INFO *) ptr;
210
114k
    TSK_FS_INFO *fs = &hfs->fs_info;
211
212
114k
    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
114k
    if (level_type == HFS_BT_NODE_TYPE_IDX) {
220
8.52k
        if (tsk_getu32(hfs->fs_info.endian,
221
8.52k
                cur_key->parent_cnid) < info->cnid) {
222
6.95k
            return HFS_BTREE_CB_IDX_LT;
223
6.95k
        }
224
1.56k
        else {
225
1.56k
            return HFS_BTREE_CB_IDX_EQGT;
226
1.56k
        }
227
8.52k
    }
228
106k
    else {
229
106k
        uint8_t *rec_buf = (uint8_t *) cur_key;
230
106k
        uint16_t rec_type;
231
106k
        size_t rec_off2;
232
233
106k
        if (tsk_getu32(hfs->fs_info.endian,
234
106k
                cur_key->parent_cnid) < info->cnid) {
235
64.0k
            return HFS_BTREE_CB_LEAF_GO;
236
64.0k
        }
237
42.0k
        else if (tsk_getu32(hfs->fs_info.endian,
238
42.0k
                cur_key->parent_cnid) > info->cnid) {
239
6.65k
            return HFS_BTREE_CB_LEAF_STOP;
240
6.65k
        }
241
  // Need at least 2 bytes for key_len
242
35.3k
        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
35.3k
        rec_off2 = 2 + tsk_getu16(hfs->fs_info.endian, cur_key->key_len);
248
249
35.3k
        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
35.3k
        rec_type = tsk_getu16(hfs->fs_info.endian, &rec_buf[rec_off2]);
255
256
        // Catalog entry is for a file
257
35.3k
        if (rec_type == HFS_FILE_THREAD) {
258
761
            tsk_error_set_errno(TSK_ERR_FS_GENFS);
259
761
            tsk_error_set_errstr("hfs_dir_open_meta: Entry"
260
761
                " is a file, not a folder");
261
761
            return HFS_BTREE_CB_ERR;
262
761
        }
263
264
        /* This will link the folder to its parent, which is the ".." entry */
265
34.5k
        else if (rec_type == HFS_FOLDER_THREAD) {
266
8.40k
            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
8.40k
            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
8.40k
            if (rec_off2 > nodesize - min_hfs_thread_size ||
277
8.40k
                rec_off2 > nodesize - (min_hfs_thread_size + tsk_getu16(hfs->fs_info.endian, thread->name.length))) {
278
9
                tsk_error_set_errno(TSK_ERR_FS_GENFS);
279
9
                tsk_error_set_errstr("hfs_dir_open_meta: nodesize value out of bounds");
280
9
                return HFS_BTREE_CB_ERR;
281
9
            }
282
283
8.39k
            strcpy(info->fs_name->name, "..");
284
8.39k
            info->fs_name->meta_addr =
285
8.39k
                tsk_getu32(hfs->fs_info.endian, thread->parent_cnid);
286
8.39k
            info->fs_name->type = TSK_FS_NAME_TYPE_DIR;
287
8.39k
            info->fs_name->flags = TSK_FS_NAME_FLAG_ALLOC;
288
8.39k
        }
289
290
        /* This is a folder in the folder */
291
26.1k
        else if (rec_type == HFS_FOLDER_RECORD) {
292
14.4k
            if ((nodesize < sizeof(hfs_folder)) || (rec_off2 > nodesize - sizeof(hfs_folder))) {
293
24
                tsk_error_set_errno(TSK_ERR_FS_GENFS);
294
24
                tsk_error_set_errstr("hfs_dir_open_meta: nodesize value out of bounds");
295
24
                return HFS_BTREE_CB_ERR;
296
24
            }
297
14.4k
            hfs_folder *folder = (hfs_folder *) & rec_buf[rec_off2];
298
299
14.4k
            info->fs_name->meta_addr =
300
14.4k
                tsk_getu32(hfs->fs_info.endian, folder->std.cnid);
301
14.4k
            info->fs_name->type = TSK_FS_NAME_TYPE_DIR;
302
14.4k
            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
14.4k
            const int32_t nameLength =
308
14.4k
                tsk_getu16(hfs->fs_info.endian, cur_key->name.length);
309
310
14.4k
            if (2*nameLength > tsk_getu16(hfs->fs_info.endian, cur_key->key_len) - 6) {
311
91
                error_returned
312
91
                ("hfs_dir_open_meta_cb: name length is too long");
313
91
                return HFS_BTREE_CB_ERR;
314
91
            }
315
14.3k
            if (hfs_UTF16toUTF8(fs, (uint8_t *) cur_key->name.unicode,
316
14.3k
                    nameLength, info->fs_name->name, HFS_MAXNAMLEN + 1,
317
14.3k
                    HFS_U16U8_FLAG_REPLACE_SLASH)) {
318
58
                return HFS_BTREE_CB_ERR;
319
58
            }
320
14.3k
        }
321
322
        /* This is a normal file in the folder */
323
11.6k
        else if (rec_type == HFS_FILE_RECORD) {
324
11.5k
            if ((nodesize < sizeof(hfs_file)) || (rec_off2 > nodesize - sizeof(hfs_file))) {
325
15
                tsk_error_set_errno(TSK_ERR_FS_GENFS);
326
15
                tsk_error_set_errstr("hfs_dir_open_meta: nodesize value out of bounds");
327
15
                return HFS_BTREE_CB_ERR;
328
15
            }
329
11.5k
            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
11.5k
            unsigned char is_err;
332
11.5k
            TSK_INUM_T file_cnid =
333
11.5k
                tsk_getu32(hfs->fs_info.endian, file->std.cnid);
334
11.5k
            TSK_INUM_T target_cnid =
335
11.5k
                hfs_follow_hard_link(hfs, file, &is_err);
336
11.5k
            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
11.5k
            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
11.5k
            else {
361
                // This is NOT a hard link.
362
11.5k
                info->fs_name->meta_addr =
363
11.5k
                    tsk_getu32(hfs->fs_info.endian, file->std.cnid);
364
11.5k
                info->fs_name->type =
365
11.5k
                    hfsmode2tsknametype(tsk_getu16(hfs->fs_info.endian,
366
11.5k
                        file->std.perm.mode));
367
11.5k
            }
368
11.5k
            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
11.5k
            const int32_t nameLength =
374
11.5k
                tsk_getu16(hfs->fs_info.endian, cur_key->name.length);
375
11.5k
            if (2*nameLength > tsk_getu16(hfs->fs_info.endian, cur_key->key_len) - 6) {
376
94
                error_returned
377
94
                ("hfs_dir_open_meta_cb: name length is too long");
378
94
                return HFS_BTREE_CB_ERR;
379
94
            }
380
11.4k
            if (hfs_UTF16toUTF8(fs, (uint8_t *) cur_key->name.unicode,
381
11.4k
                    nameLength, info->fs_name->name, HFS_MAXNAMLEN + 1,
382
11.4k
                    HFS_U16U8_FLAG_REPLACE_SLASH)) {
383
65
                return HFS_BTREE_CB_ERR;
384
65
            }
385
11.4k
        }
386
149
        else {
387
149
            tsk_error_set_errno(TSK_ERR_FS_GENFS);
388
            // @@@ MAY NEED TO IMPROVE BELOW MESSAGE
389
149
            tsk_error_set_errstr
390
149
                ("hfs_dir_open_meta: Unknown record type %d in leaf node",
391
149
                rec_type);
392
149
            return HFS_BTREE_CB_ERR;
393
149
        }
394
395
34.0k
        if (tsk_fs_dir_add(info->fs_dir, info->fs_name)) {
396
0
            return HFS_BTREE_CB_ERR;
397
0
        }
398
34.0k
        return HFS_BTREE_CB_LEAF_GO;
399
34.0k
    }
400
114k
}
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
13.1k
{
423
13.1k
    HFS_INFO *hfs = (HFS_INFO *) fs;
424
13.1k
    uint32_t cnid;              /* catalog node ID of the entry (= inum) */
425
13.1k
    TSK_FS_DIR *fs_dir;
426
13.1k
    TSK_FS_NAME *fs_name;
427
13.1k
    HFS_DIR_OPEN_META_INFO info;
428
429
430
13.1k
    tsk_error_reset();
431
432
13.1k
    cnid = (uint32_t) a_addr;
433
434
13.1k
    if (tsk_verbose)
435
0
        fprintf(stderr,
436
0
            "hfs_dir_open_meta: called for directory %" PRIu32 "\n", cnid);
437
438
13.1k
    if (a_addr < fs->first_inum || a_addr > fs->last_inum) {
439
1.04k
        tsk_error_reset();
440
1.04k
        tsk_error_set_errno(TSK_ERR_FS_WALK_RNG);
441
1.04k
        tsk_error_set_errstr("hfs_dir_open_meta: Invalid inode value: %"
442
1.04k
            PRIuINUM, a_addr);
443
1.04k
        return TSK_ERR;
444
1.04k
    }
445
12.0k
    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
12.0k
    if (tsk_verbose)
454
0
        tsk_fprintf(stderr,
455
0
            "hfs_dir_open_meta: Processing directory %" PRIuINUM "\n",
456
0
            a_addr);
457
458
12.0k
    fs_dir = *a_fs_dir;
459
12.0k
    if (fs_dir) {
460
0
        tsk_fs_dir_reset(fs_dir);
461
0
        fs_dir->addr = a_addr;
462
0
    }
463
12.0k
    else if ((*a_fs_dir = fs_dir =
464
12.0k
            tsk_fs_dir_alloc(fs, a_addr, 128)) == NULL) {
465
0
        return TSK_ERR;
466
0
    }
467
468
12.0k
    if ((fs_name = tsk_fs_name_alloc(HFS_MAXNAMLEN + 1, 0)) == NULL) {
469
0
        return TSK_ERR;
470
0
    }
471
12.0k
    info.fs_dir = fs_dir;
472
12.0k
    info.fs_name = fs_name;
473
474
12.0k
    if ((fs_dir->fs_file =
475
12.0k
            tsk_fs_file_open_meta(fs, NULL, a_addr)) == NULL) {
476
3.04k
        tsk_error_errstr2_concat(" - hfs_dir_open_meta");
477
3.04k
        tsk_fs_name_free(fs_name);
478
3.04k
        return TSK_ERR;
479
3.04k
    }
480
481
    // if we are listing the root directory, add the Orphan directory and special HFS file entries
482
9.02k
    if (a_addr == fs->root_inum) {
483
5.16k
        int i;
484
36.1k
        for (i = 0; i < 6; i++) {
485
30.9k
            switch (i) {
486
5.16k
            case 0:
487
5.16k
                if (!hfs->has_extents_file)
488
1.18k
                    continue;
489
3.97k
                strncpy(fs_name->name, HFS_EXTENTS_FILE_NAME,
490
3.97k
                    fs_name->name_size);
491
3.97k
                fs_name->meta_addr = HFS_EXTENTS_FILE_ID;
492
3.97k
                break;
493
5.16k
            case 1:
494
5.16k
                strncpy(fs_name->name, HFS_CATALOG_FILE_NAME,
495
5.16k
                    fs_name->name_size);
496
5.16k
                fs_name->meta_addr = HFS_CATALOG_FILE_ID;
497
5.16k
                break;
498
5.16k
            case 2:
499
                // Note: the Extents file and the BadBlocks file are really the same.
500
5.16k
                if (!hfs->has_extents_file)
501
1.18k
                    continue;
502
3.97k
                strncpy(fs_name->name, HFS_BAD_BLOCK_FILE_NAME,
503
3.97k
                    fs_name->name_size);
504
3.97k
                fs_name->meta_addr = HFS_BAD_BLOCK_FILE_ID;
505
3.97k
                break;
506
5.16k
            case 3:
507
5.16k
                strncpy(fs_name->name, HFS_ALLOCATION_FILE_NAME,
508
5.16k
                    fs_name->name_size);
509
5.16k
                fs_name->meta_addr = HFS_ALLOCATION_FILE_ID;
510
5.16k
                break;
511
5.16k
            case 4:
512
5.16k
                if (!hfs->has_startup_file)
513
1.47k
                    continue;
514
3.68k
                strncpy(fs_name->name, HFS_STARTUP_FILE_NAME,
515
3.68k
                    fs_name->name_size);
516
3.68k
                fs_name->meta_addr = HFS_STARTUP_FILE_ID;
517
3.68k
                break;
518
5.16k
            case 5:
519
5.16k
                if (!hfs->has_attributes_file)
520
1.06k
                    continue;
521
4.09k
                strncpy(fs_name->name, HFS_ATTRIBUTES_FILE_NAME,
522
4.09k
                    fs_name->name_size);
523
4.09k
                fs_name->meta_addr = HFS_ATTRIBUTES_FILE_ID;
524
4.09k
                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.9k
            }
536
26.0k
            fs_name->type = TSK_FS_NAME_TYPE_REG;
537
26.0k
            fs_name->flags = TSK_FS_NAME_FLAG_ALLOC;
538
26.0k
            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
26.0k
        }
543
5.16k
    }
544
545
9.02k
    info.cnid = cnid;
546
9.02k
    if (hfs_cat_traverse(hfs, hfs_dir_open_meta_cb, &info)) {
547
1.91k
        tsk_fs_name_free(fs_name);
548
1.91k
        return TSK_ERR;
549
1.91k
    }
550
551
7.10k
    tsk_fs_name_free(fs_name);
552
7.10k
    return TSK_OK;
553
9.02k
}
554
555
int
556
hfs_name_cmp(TSK_FS_INFO * a_fs_info, const char *s1, const char *s2)
557
11.4k
{
558
11.4k
    HFS_INFO *hfs = (HFS_INFO *) a_fs_info;
559
11.4k
    if (hfs->is_case_sensitive)
560
82
        return strcmp(s1, s2);
561
11.3k
    else
562
11.3k
        return strcasecmp(s1, s2);
563
11.4k
}