Coverage Report

Created: 2025-10-10 06:29

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