Coverage Report

Created: 2025-08-29 06:55

/src/sleuthkit/tsk/fs/fs_name.cpp
Line
Count
Source (jump to first uncovered line)
1
/*
2
** fs_name
3
** The Sleuth Kit
4
**
5
** Display and manipulate directory entries
6
** This file contains generic functions that call the appropriate function
7
** depending on the file system type.
8
**
9
** Brian Carrier [carrier <at> sleuthkit [dot] org]
10
** Copyright (c) 2006-2013 Brian Carrier.  All Rights reserved
11
** Copyright (c) 2003-2005 Brian Carrier.  All rights reserved
12
**
13
** TASK
14
** Copyright (c) 2002 Brian Carrier, @stake Inc.  All rights reserved
15
**
16
** TCTUTILs
17
** Copyright (c) 2001 Brian Carrier.  All rights reserved
18
**
19
** This software is distributed under the Common Public License 1.0
20
*/
21
22
/**
23
 * \file fs_name.c
24
 * Code to allocate and free the TSK_FS_NAME structures.
25
 */
26
#include "tsk_fs_i.h"
27
28
#include <time.h>
29
30
// 2025-07-01 - commented out; do not use an internal structure
31
// #ifndef TZNAME
32
// #define TZNAME __tzname
33
// #endif
34
35
char tsk_fs_name_type_str[TSK_FS_NAME_TYPE_STR_MAX][2] =
36
    { "-", "p", "c", "d", "b", "r",
37
    "l", "s", "h", "w", "v", "V"
38
};
39
40
/**
41
 * \internal
42
 * Allocate a fs_name structure */
43
TSK_FS_NAME *
44
tsk_fs_name_alloc(size_t norm_namelen, size_t shrt_namelen)
45
9.98M
{
46
9.98M
    TSK_FS_NAME *fs_name;
47
9.98M
    fs_name = (TSK_FS_NAME *) tsk_malloc(sizeof(*fs_name));
48
9.98M
    if (fs_name == NULL)
49
0
        return NULL;
50
51
9.98M
    fs_name->name = (char *) tsk_malloc(norm_namelen + 1);
52
9.98M
    if (fs_name->name == NULL) {
53
0
        free(fs_name);
54
0
        return NULL;
55
0
    }
56
9.98M
    fs_name->name_size = norm_namelen;
57
58
9.98M
    fs_name->flags = (TSK_FS_NAME_FLAG_ENUM) 0;
59
60
9.98M
    fs_name->shrt_name_size = shrt_namelen;
61
9.98M
    if (shrt_namelen == 0) {
62
9.90M
        fs_name->shrt_name = NULL;
63
9.90M
    }
64
79.5k
    else {
65
79.5k
        fs_name->shrt_name = (char *) tsk_malloc(shrt_namelen + 1);
66
79.5k
        if (fs_name->shrt_name == NULL) {
67
0
            free(fs_name->name);
68
0
            free(fs_name);
69
0
            return NULL;
70
0
        }
71
79.5k
    }
72
73
9.98M
    fs_name->type = TSK_FS_NAME_TYPE_UNDEF;
74
9.98M
    fs_name->tag = TSK_FS_NAME_TAG;
75
9.98M
    return fs_name;
76
9.98M
}
77
78
79
/**
80
 * \internal
81
 * returns 1 on error
82
 */
83
uint8_t
84
tsk_fs_name_realloc(TSK_FS_NAME * fs_name, size_t namelen)
85
0
{
86
0
    if ((fs_name == NULL) || (fs_name->tag != TSK_FS_NAME_TAG))
87
0
        return 1;
88
89
0
    if (fs_name->name_size >= namelen)
90
0
        return 0;
91
92
0
    fs_name->name = (char *) tsk_realloc(fs_name->name, namelen + 1);
93
0
    if (fs_name->name == NULL) {
94
0
        fs_name->name_size = 0;
95
0
        return 1;
96
0
    }
97
98
0
    fs_name->type = TSK_FS_NAME_TYPE_UNDEF;
99
0
    fs_name->name_size = namelen;
100
101
0
    return 0;
102
0
}
103
104
/**
105
 * \internal
106
 * reset the values in the TSK_FS_NAME structure
107
 * @param a_fs_name Name structure to reset
108
 */
109
void
110
tsk_fs_name_reset(TSK_FS_NAME * a_fs_name)
111
878k
{
112
878k
    if (a_fs_name->name)
113
878k
        a_fs_name->name[0] = '\0';
114
115
878k
    if (a_fs_name->shrt_name)
116
878k
        a_fs_name->shrt_name[0] = '\0';
117
118
878k
    a_fs_name->meta_addr = 0;
119
878k
    a_fs_name->meta_seq = 0;
120
878k
    a_fs_name->par_addr = 0;
121
878k
    a_fs_name->par_seq = 0;
122
878k
    a_fs_name->type = TSK_FS_NAME_TYPE_UNDEF;
123
878k
    a_fs_name->flags = (TSK_FS_NAME_FLAG_ENUM) 0;
124
878k
}
125
126
/**
127
 * \internal
128
 */
129
void
130
tsk_fs_name_free(TSK_FS_NAME * fs_name)
131
9.98M
{
132
9.98M
    if ((!fs_name) || (fs_name->tag != TSK_FS_NAME_TAG))
133
0
        return;
134
135
9.98M
    free(fs_name->name);
136
9.98M
    fs_name->name = NULL;
137
138
9.98M
    free(fs_name->shrt_name);
139
9.98M
    fs_name->shrt_name = NULL;
140
141
9.98M
    free(fs_name);
142
9.98M
}
143
144
/** \internal
145
 * Copy the contents of a TSK_FS_NAME structure to another
146
 * structure.
147
 * @param a_fs_name_to Destination structure to copy to
148
 * @param a_fs_name_from Source structure to copy from
149
 * @returns 1 on error
150
 */
151
uint8_t
152
tsk_fs_name_copy(TSK_FS_NAME * a_fs_name_to,
153
    const TSK_FS_NAME * a_fs_name_from)
154
6.54M
{
155
6.54M
    if ((a_fs_name_to == NULL) || (a_fs_name_from == NULL))
156
0
        return 1;
157
158
    /* If the source has a full name,  copy it */
159
6.54M
    if (a_fs_name_from->name) {
160
6.54M
        size_t name_len = strlen(a_fs_name_from->name);
161
162
        // make sure there is enough space
163
6.54M
        if (name_len >= a_fs_name_to->name_size) {
164
6.53M
            char * to_name =
165
6.53M
                (char *) tsk_realloc(a_fs_name_to->name,
166
6.53M
                name_len + 16);
167
6.53M
            if (to_name == NULL)
168
0
                return 1;
169
170
6.53M
            a_fs_name_to->name = to_name;
171
6.53M
            a_fs_name_to->name_size = name_len + 16;
172
6.53M
        }
173
6.54M
        strncpy(a_fs_name_to->name, a_fs_name_from->name,
174
6.54M
            name_len);
175
6.54M
        a_fs_name_to->name[name_len] = 0;
176
6.54M
    }
177
0
    else {
178
0
        if (a_fs_name_to->name_size > 0)
179
0
            a_fs_name_to->name[0] = '\0';
180
0
        else
181
0
            a_fs_name_to->name = NULL;
182
0
    }
183
184
    // copy the short name, if one exists
185
6.54M
    if (a_fs_name_from->shrt_name) {
186
1.12M
        if (strlen(a_fs_name_from->shrt_name) >=
187
1.12M
            a_fs_name_to->shrt_name_size) {
188
1.12M
            a_fs_name_to->shrt_name_size =
189
1.12M
                strlen(a_fs_name_from->shrt_name) + 16;
190
1.12M
            a_fs_name_to->shrt_name =
191
1.12M
                (char *) tsk_realloc(a_fs_name_to->shrt_name,
192
1.12M
                a_fs_name_to->shrt_name_size);
193
1.12M
            if (a_fs_name_to->shrt_name == NULL)
194
0
                return 1;
195
1.12M
        }
196
1.12M
        strncpy(a_fs_name_to->shrt_name, a_fs_name_from->shrt_name,
197
1.12M
            a_fs_name_to->shrt_name_size);
198
1.12M
    }
199
5.41M
    else {
200
5.41M
        if (a_fs_name_to->shrt_name_size > 0)
201
0
            a_fs_name_to->shrt_name[0] = '\0';
202
5.41M
        else
203
5.41M
            a_fs_name_to->shrt_name = NULL;
204
5.41M
    }
205
206
6.54M
    a_fs_name_to->meta_addr = a_fs_name_from->meta_addr;
207
6.54M
    a_fs_name_to->meta_seq = a_fs_name_from->meta_seq;
208
6.54M
    a_fs_name_to->par_addr = a_fs_name_from->par_addr;
209
6.54M
    a_fs_name_to->par_seq = a_fs_name_from->par_seq;
210
6.54M
    a_fs_name_to->type = a_fs_name_from->type;
211
6.54M
    a_fs_name_to->flags = a_fs_name_from->flags;
212
6.54M
    a_fs_name_to->date_added = a_fs_name_from->date_added;
213
214
6.54M
    return 0;
215
6.54M
}
216
217
218
219
220
221
/***********************************************************************
222
 * Printing functions
223
 ***********************************************************************/
224
225
/**
226
 * \ingroup fslib
227
 * Makes the "ls -l" permissions string for a file.
228
 *
229
 * @param a_fs_meta File to be processed
230
 * @param a_buf [out] Buffer to write results to (must be 12 bytes or longer)
231
 * @param a_len Length of buffer
232
 */
233
uint8_t
234
tsk_fs_meta_make_ls(const TSK_FS_META * a_fs_meta, char *a_buf,
235
    size_t a_len)
236
0
{
237
0
    if (a_len < 12) {
238
0
        return 1;
239
0
    }
240
241
    /* put the default values in */
242
0
    strcpy(a_buf, "----------");
243
244
0
    if (a_fs_meta->type < TSK_FS_META_TYPE_STR_MAX)
245
0
        a_buf[0] = tsk_fs_meta_type_str[a_fs_meta->type][0];
246
247
    /* user perms */
248
0
    if (a_fs_meta->mode & TSK_FS_META_MODE_IRUSR)
249
0
        a_buf[1] = 'r';
250
0
    if (a_fs_meta->mode & TSK_FS_META_MODE_IWUSR)
251
0
        a_buf[2] = 'w';
252
    /* set uid */
253
0
    if (a_fs_meta->mode & TSK_FS_META_MODE_ISUID) {
254
0
        if (a_fs_meta->mode & TSK_FS_META_MODE_IXUSR)
255
0
            a_buf[3] = 's';
256
0
        else
257
0
            a_buf[3] = 'S';
258
0
    }
259
0
    else if (a_fs_meta->mode & TSK_FS_META_MODE_IXUSR)
260
0
        a_buf[3] = 'x';
261
262
    /* group perms */
263
0
    if (a_fs_meta->mode & TSK_FS_META_MODE_IRGRP)
264
0
        a_buf[4] = 'r';
265
0
    if (a_fs_meta->mode & TSK_FS_META_MODE_IWGRP)
266
0
        a_buf[5] = 'w';
267
    /* set gid */
268
0
    if (a_fs_meta->mode & TSK_FS_META_MODE_ISGID) {
269
0
        if (a_fs_meta->mode & TSK_FS_META_MODE_IXGRP)
270
0
            a_buf[6] = 's';
271
0
        else
272
0
            a_buf[6] = 'S';
273
0
    }
274
0
    else if (a_fs_meta->mode & TSK_FS_META_MODE_IXGRP)
275
0
        a_buf[6] = 'x';
276
277
    /* other perms */
278
0
    if (a_fs_meta->mode & TSK_FS_META_MODE_IROTH)
279
0
        a_buf[7] = 'r';
280
0
    if (a_fs_meta->mode & TSK_FS_META_MODE_IWOTH)
281
0
        a_buf[8] = 'w';
282
283
    /* sticky bit */
284
0
    if (a_fs_meta->mode & TSK_FS_META_MODE_ISVTX) {
285
0
        if (a_fs_meta->mode & TSK_FS_META_MODE_IXOTH)
286
0
            a_buf[9] = 't';
287
0
        else
288
0
            a_buf[9] = 'T';
289
0
    }
290
0
    else if (a_fs_meta->mode & TSK_FS_META_MODE_IXOTH)
291
0
        a_buf[9] = 'x';
292
0
    return 0;
293
0
}
294
295
296
/** \ingroup fslib
297
 * Converts a time value to a string representation. Prints
298
 * all zero values instead of 1970 if time is 0.
299
 * @param time Time to be displayed.
300
 * @param buf Buffer to print into (must be 128 byes or larger)
301
 * @returns Pointer to buffer that was passed in.
302
 */
303
char *
304
tsk_fs_time_to_str(time_t time, char buf[128])
305
0
{
306
0
    struct tm *tmTime;
307
308
0
    buf[0] = '\0';
309
0
    if (time <= 0 || (tmTime = localtime(&time)) == NULL) {
310
0
        strncpy(buf, "0000-00-00 00:00:00 (UTC)", 128);
311
0
    }
312
0
    else {
313
0
        snprintf(buf, 128, "%.4d-%.2d-%.2d %.2d:%.2d:%.2d (%s)",
314
0
            (int) tmTime->tm_year + 1900,
315
0
            (int) tmTime->tm_mon + 1, (int) tmTime->tm_mday,
316
0
            tmTime->tm_hour,
317
0
            (int) tmTime->tm_min, (int) tmTime->tm_sec,
318
0
            TZNAME[(tmTime->tm_isdst == 0) ? 0 : 1]);
319
0
    }
320
0
    return buf;
321
0
}
322
323
/** \ingroup fslib
324
 * Converts a time value to a string representation. Prints
325
 * all zero values instead of 1970 if time is 0.
326
 * @param time Time to be displayed.
327
 * @param buf Buffer to print into (must b 64 bytes or larger)
328
 * @param subsecs Subseconds to be printed
329
 * @returns Pointer to buffer that was passed in.
330
 */
331
char *
332
tsk_fs_time_to_str_subsecs(time_t time, unsigned int subsecs,
333
    char buf[128])
334
0
{
335
0
    struct tm *tmTime;
336
337
0
    buf[0] = '\0';
338
0
    if (time <= 0 || (tmTime = localtime(&time)) == NULL) {
339
0
        strncpy(buf, "0000-00-00 00:00:00 (UTC)", 32);
340
0
    }
341
0
    else {
342
0
        snprintf(buf, 64, "%.4d-%.2d-%.2d %.2d:%.2d:%.2d.%.9d (%s)",
343
0
            (int) tmTime->tm_year + 1900,
344
0
            (int) tmTime->tm_mon + 1, (int) tmTime->tm_mday,
345
0
            tmTime->tm_hour,
346
0
            (int) tmTime->tm_min, (int) tmTime->tm_sec,
347
0
            subsecs, TZNAME[(tmTime->tm_isdst == 0) ? 0 : 1]);
348
0
    }
349
0
    return buf;
350
0
}
351
352
353
static void
354
tsk_fs_print_time(FILE * hFile, time_t time)
355
0
{
356
0
    char foo[128];
357
0
    tsk_fs_time_to_str(time, foo);
358
0
    tsk_fprintf(hFile, "%s", foo);
359
0
}
360
361
362
// @@@ We could merge this with the tsk_fs_time_to_str in
363
// the future when the feature to include time resolution
364
// is added to TSK_FS_META (and then that value would be
365
// passed in and tsk_fs_time_to_str would decide what to
366
// round up/down to
367
368
/**
369
 * The only difference with this one is that the time is always
370
 * 00:00:00, which is applicable for the A-Time in FAT, which does
371
 * not have a time and if we do it normally it gets messed up because
372
 * of the timezone conversion
373
 */
374
static void
375
tsk_fs_print_day(FILE * hFile, time_t time)
376
0
{
377
0
    struct tm *tmTime;
378
379
0
    if (time <= 0 || (tmTime = localtime(&time)) == NULL) {
380
0
        tsk_fprintf(hFile, "0000-00-00 00:00:00 (UTC)");
381
0
    }
382
0
    else {
383
0
        tsk_fprintf(hFile, "%.4d-%.2d-%.2d 00:00:00 (%s)",
384
0
            (int) tmTime->tm_year + 1900,
385
0
            (int) tmTime->tm_mon + 1, (int) tmTime->tm_mday,
386
0
            TZNAME[(tmTime->tm_isdst == 0) ? 0 : 1]);
387
0
    }
388
0
}
389
390
391
/**
392
 * \internal
393
 * Simple print of dentry type / inode type, deleted, inode, and
394
 * name
395
 *
396
 * fs_attr is used for alternate data streams in NTFS, set to NULL
397
 * for all other file systems
398
 *
399
 * Newline is not printed at the end
400
 *
401
 * If path is NULL, then skip else use. it has the full directory name
402
 *  It needs to end with "/"
403
 */
404
void
405
tsk_fs_name_print(
406
  FILE * hFile,
407
  const TSK_FS_FILE * fs_file,
408
  const char *a_path,
409
  [[maybe_unused]] TSK_FS_INFO * fs,
410
  const TSK_FS_ATTR * fs_attr,
411
  uint8_t print_path)
412
0
{
413
    /* type of file - based on dentry type */
414
0
    if (fs_file->name->type < TSK_FS_NAME_TYPE_STR_MAX)
415
0
        tsk_fprintf(hFile, "%s/",
416
0
            tsk_fs_name_type_str[fs_file->name->type]);
417
0
    else
418
0
        tsk_fprintf(hFile, "-/");
419
420
    /* type of file - based on inode type: we want letters though for
421
     * regular files so we use the dent_str though */
422
0
    if (fs_file->meta) {
423
        /*
424
         * An NTFS directory can have a Data stream, in which
425
         * case it would be printed with modes of a
426
         * directory, although it is really a file
427
         * So, to avoid confusion we will set the modes
428
         * to a file so it is printed that way.  The
429
         * entry for the directory itself will still be
430
         * printed as a directory
431
         */
432
0
        if ((fs_attr) && (fs_attr->type == TSK_FS_ATTR_TYPE_NTFS_DATA) &&
433
0
            (TSK_FS_IS_DIR_META(fs_file->meta->type))){
434
0
            tsk_fprintf(hFile, "r ");
435
0
        }
436
0
        else {
437
0
            if (fs_file->meta->type < TSK_FS_META_TYPE_STR_MAX)
438
0
                tsk_fprintf(hFile, "%s ",
439
0
                    tsk_fs_meta_type_str[fs_file->meta->type]);
440
0
            else
441
0
                tsk_fprintf(hFile, "- ");
442
0
        }
443
0
    }
444
0
    else {
445
0
        tsk_fprintf(hFile, "- ");
446
0
    }
447
448
449
    /* print a * if it is deleted */
450
0
    if (fs_file->name->flags & TSK_FS_NAME_FLAG_UNALLOC)
451
0
        tsk_fprintf(hFile, "* ");
452
453
0
    tsk_fprintf(hFile, "%" PRIuINUM "", fs_file->name->meta_addr);
454
455
    /* print the id and type if we have fs_attr (NTFS) */
456
0
    if (fs_attr)
457
0
        tsk_fprintf(hFile, "-%" PRIu32 "-%" PRIu16 "", fs_attr->type,
458
0
            fs_attr->id);
459
460
0
    tsk_fprintf(hFile, "%s:\t",
461
0
        ((fs_file->meta) && (fs_file->meta->flags & TSK_FS_META_FLAG_ALLOC)
462
0
            && (fs_file->name->
463
0
                flags & TSK_FS_NAME_FLAG_UNALLOC)) ? "(realloc)" : "");
464
465
0
    if ((print_path) && (a_path != NULL))
466
0
        tsk_print_sanitized(hFile, a_path);
467
468
0
    tsk_print_sanitized(hFile, fs_file->name->name);
469
470
    /*  This will add the short name in parentheses
471
        if (fs_file->name->shrt_name != NULL && fs_file->name->shrt_name[0] != '\0')
472
        tsk_fprintf(hFile, " (%s)", fs_file->name->shrt_name);
473
        */
474
475
    /* print the data stream name if we the non-data NTFS stream */
476
0
    if ((fs_attr) && (fs_attr->name)) {
477
0
        if ((fs_attr->type != TSK_FS_ATTR_TYPE_NTFS_IDXROOT) ||
478
0
            (strcmp(fs_attr->name, "$I30") != 0)) {
479
0
            tsk_fprintf(hFile, ":");
480
0
            tsk_print_sanitized(hFile, fs_attr->name);
481
0
        }
482
0
    }
483
0
}
484
485
/**
486
 * \internal
487
 * Print contents of  fs_name entry format like ls -l
488
 *
489
 * All elements are tab delimited.
490
 * Newline is not printed at the end
491
 *
492
 * If path is NULL, then skip else use. it has the full directory name
493
 *  It needs to end with "/"
494
 */
495
void
496
tsk_fs_name_print_long(FILE * hFile, const TSK_FS_FILE * fs_file,
497
    const char *a_path, TSK_FS_INFO * fs, const TSK_FS_ATTR * fs_attr,
498
    uint8_t print_path, int32_t sec_skew)
499
0
{
500
0
    tsk_fs_name_print(hFile, fs_file, a_path, fs, fs_attr, print_path);
501
502
0
    if ((fs == NULL) || (fs_file->meta == NULL)) {
503
504
0
        tsk_fprintf(hFile, "\t");
505
0
        tsk_fs_print_time(hFile, 0);    // mtime
506
0
        tsk_fprintf(hFile, "\t");
507
0
        tsk_fs_print_time(hFile, 0);    // atime
508
0
        tsk_fprintf(hFile, "\t");
509
0
        tsk_fs_print_time(hFile, 0);    // ctime
510
0
        tsk_fprintf(hFile, "\t");
511
0
        tsk_fs_print_time(hFile, 0);    // crtime
512
513
        // size, uid, gid
514
0
        tsk_fprintf(hFile, "\t0\t0\t0");
515
0
    }
516
0
    else {
517
518
        /* MAC times */
519
0
        tsk_fprintf(hFile, "\t");
520
0
        if (fs_file->meta->mtime)
521
0
            tsk_fs_print_time(hFile, fs_file->meta->mtime - sec_skew);
522
0
        else
523
0
            tsk_fs_print_time(hFile, fs_file->meta->mtime);
524
525
0
        tsk_fprintf(hFile, "\t");
526
        /* FAT only gives the day of last access */
527
0
        if ((TSK_FS_TYPE_ISFAT(fs->ftype)) || (fs_file->meta->atime == 0))
528
0
            tsk_fs_print_day(hFile, fs_file->meta->atime);
529
0
        else
530
0
            tsk_fs_print_time(hFile, fs_file->meta->atime - sec_skew);
531
532
0
        tsk_fprintf(hFile, "\t");
533
0
        if (fs_file->meta->ctime)
534
0
            tsk_fs_print_time(hFile, fs_file->meta->ctime - sec_skew);
535
0
        else
536
0
            tsk_fs_print_time(hFile, fs_file->meta->ctime);
537
538
0
        tsk_fprintf(hFile, "\t");
539
0
        if (fs_file->meta->crtime)
540
0
            tsk_fs_print_time(hFile, fs_file->meta->crtime - sec_skew);
541
0
        else
542
0
            tsk_fs_print_time(hFile, fs_file->meta->crtime);
543
544
        /* use the stream size if one was given */
545
0
        if (fs_attr)
546
0
            tsk_fprintf(hFile, "\t%" PRIdOFF, fs_attr->size);
547
0
        else
548
0
            tsk_fprintf(hFile, "\t%" PRIdOFF, fs_file->meta->size);
549
550
0
        tsk_fprintf(hFile, "\t%" PRIuGID "\t%" PRIuUID,
551
0
            fs_file->meta->gid, fs_file->meta->uid);
552
0
    }
553
0
}
554
555
/**
556
 * \internal
557
 *
558
 * Print output in the format that mactime reads.
559
 *
560
 * If the flags in the fs_file->meta structure are set to FS_FLAG_ALLOC
561
 * then it is assumed that the inode has been reallocated and the
562
 * contents are not displayed
563
 * Newline is not printed at the end
564
 *
565
 * fs is not required (only used for block size).
566
 * @param hFile handle to print results to
567
 * @param fs_file File to print details about
568
 * @param a_path Parent directory of file (needs to end with "/")
569
 * @param fs_attr Attribute in file that is being called for (NULL for non-NTFS)
570
 * @param prefix Path of mounting point for image
571
 * @param time_skew number of seconds skew to adjust time
572
 */
573
void
574
tsk_fs_name_print_mac(FILE * hFile, const TSK_FS_FILE * fs_file,
575
    const char *a_path, const TSK_FS_ATTR * fs_attr,
576
    const char *prefix, int32_t time_skew)
577
0
{
578
0
    tsk_fs_name_print_mac_md5(hFile, fs_file, a_path, fs_attr, prefix,
579
0
        time_skew, NULL);
580
0
}
581
582
/**
583
 * \internal
584
 *
585
 * Print output in the format that mactime reads.
586
 *
587
 * If the flags in the fs_file->meta structure are set to FS_FLAG_ALLOC
588
 * then it is assumed that the inode has been reallocated and the
589
 * contents are not displayed
590
 * Newline is not printed at the end
591
 *
592
 * fs is not required (only used for block size).
593
 * @param hFile handle to print results to
594
 * @param fs_file File to print details about
595
 * @param a_path Parent directory of file (needs to end with "/")
596
 * @param fs_attr Attribute in file that is being called for (NULL for non-NTFS)
597
 * @param prefix Path of mounting point for image
598
 * @param time_skew number of seconds skew to adjust time
599
 * @param hash_results Holds the calculated md5 hash
600
 */
601
void
602
tsk_fs_name_print_mac_md5(FILE * hFile, const TSK_FS_FILE * fs_file,
603
    const char *a_path, const TSK_FS_ATTR * fs_attr,
604
    const char *prefix, int32_t time_skew,
605
    const unsigned char *hash_results)
606
0
{
607
0
    char ls[12];
608
0
    size_t i;
609
0
    uint8_t isADS = 0;
610
611
0
    if ((!hFile) || (!fs_file))
612
0
        return;
613
614
    /* see if we are going to be printing the name of the attribute
615
     * We don't do it for FNAME attributes, which we handle specially below.
616
     */
617
0
    if ((fs_attr) && (fs_attr->name)
618
0
        && (fs_attr->type != TSK_FS_ATTR_TYPE_NTFS_FNAME)
619
0
        && ((fs_attr->type != TSK_FS_ATTR_TYPE_NTFS_IDXROOT)
620
0
            || (strcmp(fs_attr->name, "$I30") != 0))) {
621
0
        isADS = 1;
622
0
    }
623
624
    /* hash
625
     * Print out the hash buffer (if not null)
626
     */
627
0
    if (hash_results == NULL) {
628
0
        tsk_fprintf(hFile, "0|");
629
0
    }
630
0
    else {
631
0
        for (i = 0; i < 16; i++) {
632
0
            tsk_fprintf(hFile, "%02x", hash_results[i]);
633
0
        }
634
0
        tsk_fprintf(hFile, "|");
635
0
    }
636
637
    /* file name */
638
0
    tsk_fprintf(hFile, "%s", prefix);
639
640
    // remove any control chars as we print the names
641
0
    if (a_path != NULL)
642
0
      tsk_print_sanitized(hFile, a_path);
643
644
0
    tsk_print_sanitized(hFile, fs_file->name->name);
645
646
    /* print the data stream name if it exists and is not the default NTFS */
647
0
    if (isADS) {
648
0
        tsk_fprintf(hFile, ":");
649
0
        tsk_print_sanitized(hFile, fs_attr->name);
650
0
    }
651
652
    // special label if FNAME
653
0
    if ((fs_attr) && (fs_attr->type == TSK_FS_ATTR_TYPE_NTFS_FNAME)) {
654
0
        tsk_fprintf(hFile, " ($FILE_NAME)");
655
0
    }
656
657
0
    if ((fs_file->meta)
658
0
        && (fs_file->meta->type == TSK_FS_META_TYPE_LNK)
659
0
        && (fs_file->meta->link)) {
660
0
        tsk_fprintf(hFile, " -> %s", fs_file->meta->link);
661
0
    }
662
663
    /* if filename is deleted add a comment and if the inode is now
664
     * allocated, then add realloc comment */
665
0
    if (fs_file->name->flags & TSK_FS_NAME_FLAG_UNALLOC)
666
0
        tsk_fprintf(hFile, " (deleted%s)", ((fs_file->meta)
667
0
                && (fs_file->meta->
668
0
                    flags & TSK_FS_META_FLAG_ALLOC)) ? "-realloc" : "");
669
670
    /* inode */
671
0
    tsk_fprintf(hFile, "|%" PRIuINUM, fs_file->name->meta_addr);
672
0
    if (fs_attr)
673
0
        tsk_fprintf(hFile, "-%" PRIu32 "-%" PRIu16 "", fs_attr->type,
674
0
            fs_attr->id);
675
676
0
    tsk_fprintf(hFile, "|");
677
678
    /* TYPE as specified in the directory entry
679
     */
680
0
    if (fs_file->name->type < TSK_FS_NAME_TYPE_STR_MAX)
681
0
        tsk_fprintf(hFile, "%s/",
682
0
            tsk_fs_name_type_str[fs_file->name->type]);
683
0
    else
684
0
        tsk_fprintf(hFile, "-/");
685
686
0
    if (!fs_file->meta) {
687
0
        tsk_fprintf(hFile, "----------|0|0|0|");
688
0
    }
689
0
    else {
690
        /* mode as string */
691
0
        tsk_fs_meta_make_ls(fs_file->meta, ls, sizeof(ls));
692
0
        tsk_fprintf(hFile, "%s|", ls);
693
694
        /* uid, gid */
695
0
        tsk_fprintf(hFile, "%" PRIuUID "|%" PRIuGID "|",
696
0
            fs_file->meta->uid, fs_file->meta->gid);
697
698
        /* size - use data stream if we have it */
699
0
        if (fs_attr)
700
0
            tsk_fprintf(hFile, "%" PRIdOFF "|", fs_attr->size);
701
0
        else
702
0
            tsk_fprintf(hFile, "%" PRIdOFF "|", fs_file->meta->size);
703
0
    }
704
705
0
    if (!fs_file->meta) {
706
0
        tsk_fprintf(hFile, "0|0|0|0");
707
0
    }
708
0
    else {
709
        // special case for NTFS FILE_NAME attribute
710
0
        if ((fs_attr) && (fs_attr->type == TSK_FS_ATTR_TYPE_NTFS_FNAME)) {
711
            /* atime, mtime, ctime, crtime */
712
0
            if (fs_file->meta->time2.ntfs.fn_atime)
713
0
                tsk_fprintf(hFile, "%" PRIu32 "|",
714
0
                    fs_file->meta->time2.ntfs.fn_atime - time_skew);
715
0
            else
716
0
                tsk_fprintf(hFile, "%" PRIu32 "|",
717
0
                    fs_file->meta->time2.ntfs.fn_atime);
718
719
0
            if (fs_file->meta->time2.ntfs.fn_mtime)
720
0
                tsk_fprintf(hFile, "%" PRIu32 "|",
721
0
                    fs_file->meta->time2.ntfs.fn_mtime - time_skew);
722
0
            else
723
0
                tsk_fprintf(hFile, "%" PRIu32 "|",
724
0
                    fs_file->meta->time2.ntfs.fn_mtime);
725
726
0
            if (fs_file->meta->time2.ntfs.fn_ctime)
727
0
                tsk_fprintf(hFile, "%" PRIu32 "|",
728
0
                    fs_file->meta->time2.ntfs.fn_ctime - time_skew);
729
0
            else
730
0
                tsk_fprintf(hFile, "%" PRIu32 "|",
731
0
                    fs_file->meta->time2.ntfs.fn_ctime);
732
733
0
            if (fs_file->meta->time2.ntfs.fn_crtime)
734
0
                tsk_fprintf(hFile, "%" PRIu32,
735
0
                    fs_file->meta->time2.ntfs.fn_crtime - time_skew);
736
0
            else
737
0
                tsk_fprintf(hFile, "%" PRIu32,
738
0
                    fs_file->meta->time2.ntfs.fn_crtime);
739
0
        }
740
0
        else {
741
            /* atime, mtime, ctime, crtime */
742
0
            if (fs_file->meta->atime)
743
0
                tsk_fprintf(hFile, "%" PRIu32 "|",
744
0
                    fs_file->meta->atime - time_skew);
745
0
            else
746
0
                tsk_fprintf(hFile, "%" PRIu32 "|", fs_file->meta->atime);
747
748
0
            if (fs_file->meta->mtime)
749
0
                tsk_fprintf(hFile, "%" PRIu32 "|",
750
0
                    fs_file->meta->mtime - time_skew);
751
0
            else
752
0
                tsk_fprintf(hFile, "%" PRIu32 "|", fs_file->meta->mtime);
753
754
0
            if (fs_file->meta->ctime)
755
0
                tsk_fprintf(hFile, "%" PRIu32 "|",
756
0
                    fs_file->meta->ctime - time_skew);
757
0
            else
758
0
                tsk_fprintf(hFile, "%" PRIu32 "|", fs_file->meta->ctime);
759
760
0
            if (fs_file->meta->crtime)
761
0
                tsk_fprintf(hFile, "%" PRIu32,
762
0
                    fs_file->meta->crtime - time_skew);
763
0
            else
764
0
                tsk_fprintf(hFile, "%" PRIu32, fs_file->meta->crtime);
765
0
        }
766
0
    }
767
0
}