Coverage Report

Created: 2025-07-12 06:14

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