Coverage Report

Created: 2025-10-10 06:29

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/sleuthkit/tsk/vs/mm_part.c
Line
Count
Source
1
/*
2
 * The Sleuth Kit
3
 *
4
 * Brian Carrier [carrier <at> sleuthkit [dot] org]
5
 * Copyright (c) 2003-2011 Brian Carrier.  All rights reserved
6
 *
7
 * This software is distributed under the Common Public License 1.0
8
 */
9
10
/** \file mm_part.c
11
 * Contains the functions need to create, maintain, and access the linked list of
12
 * partitions in a volume.
13
 */
14
#include "tsk_vs_i.h"
15
16
17
/**
18
 * Add a partition to a sorted list
19
 * @param a_vs Volume system that partition belongs to
20
 * @param a_start Starting sector address of volume (relative to start of volume)
21
 * @param len Length of volume in sectors
22
 * @param type Type of volume
23
 * @param desc Text description of partition.  Note that this is not copied
24
 * and must not be freed until the volume system has been closed.
25
 * @param table The table ID that the volume was located in or -1 for volumes not in a partition table.
26
 * @param slot The slot number in the partition table that the volume was located in or -1 for volumes not in a partition table.
27
 * @returns Pointer to structure that was created for the partition or NULL on error.
28
 */
29
TSK_VS_PART_INFO *
30
tsk_vs_part_add(TSK_VS_INFO * a_vs, TSK_DADDR_T a_start, TSK_DADDR_T len,
31
    TSK_VS_PART_FLAG_ENUM type, char *desc, int8_t table, int16_t slot)
32
1.44M
{
33
1.44M
    TSK_VS_PART_INFO *part;
34
1.44M
    TSK_VS_PART_INFO *cur_part;
35
36
1.44M
    if ((part =
37
1.44M
            (TSK_VS_PART_INFO *) tsk_malloc(sizeof(TSK_VS_PART_INFO))) ==
38
1.44M
        NULL) {
39
0
        return NULL;
40
0
    }
41
42
    /* set the values */
43
1.44M
    part->next = NULL;
44
1.44M
    part->prev = NULL;
45
1.44M
    part->start = a_start;
46
1.44M
    part->len = len;
47
1.44M
    part->desc = desc;
48
1.44M
    part->table_num = table;
49
1.44M
    part->slot_num = slot;
50
1.44M
    part->flags = type;
51
1.44M
    part->vs = a_vs;
52
1.44M
    part->addr = 0;
53
1.44M
    part->tag = TSK_VS_PART_INFO_TAG;
54
55
    /* is this the first entry in the list */
56
1.44M
    if (a_vs->part_list == NULL) {
57
28.2k
        a_vs->part_list = part;
58
28.2k
        a_vs->part_count = 1;
59
28.2k
        return part;
60
28.2k
    }
61
62
    /* Cycle through to find the correct place to put it into */
63
710M
    for (cur_part = a_vs->part_list; cur_part != NULL;
64
710M
        cur_part = cur_part->next) {
65
        /* The one to add starts before this partition */
66
710M
        if (cur_part->start > part->start) {
67
3.02k
            part->next = cur_part;
68
3.02k
            part->prev = cur_part->prev;
69
3.02k
            if (part->prev)
70
0
                part->prev->next = part;
71
3.02k
            cur_part->prev = part;
72
73
            /* If we are now the head update a_vs */
74
3.02k
            if (part->prev == NULL)
75
3.02k
                a_vs->part_list = part;
76
77
            /* update the count and address numbers */
78
3.02k
            a_vs->part_count++;
79
3.02k
            part->addr = cur_part->addr;
80
19.7k
            for (; cur_part != NULL; cur_part = cur_part->next)
81
16.7k
                cur_part->addr++;
82
83
3.02k
            return part;
84
3.02k
        }
85
86
        /* the one to add is bigger then current and the list is done */
87
710M
        else if (cur_part->next == NULL) {
88
144k
            cur_part->next = part;
89
144k
            part->prev = cur_part;
90
91
            /* Update partition counts and addresses */
92
144k
            a_vs->part_count++;
93
144k
            part->addr = cur_part->addr + 1;
94
144k
            return part;
95
144k
        }
96
97
        /* The one to add fits in between this and the next */
98
710M
        else if (cur_part->next->start > part->start) {
99
1.26M
            part->prev = cur_part;
100
1.26M
            part->next = cur_part->next;
101
1.26M
            cur_part->next->prev = part;
102
1.26M
            cur_part->next = part;
103
104
            /* Update partition counts and addresses */
105
1.26M
            a_vs->part_count++;
106
1.26M
            part->addr = cur_part->addr + 1;
107
680M
            for (cur_part = part->next; cur_part != NULL;
108
679M
                cur_part = cur_part->next)
109
679M
                cur_part->addr++;
110
1.26M
            return part;
111
1.26M
        }
112
710M
    }
113
0
    return NULL;
114
1.41M
}
115
116
/**
117
 * Identify regions in the partition list where there are unused sectors
118
 * and create new entries for them.
119
 *
120
 * @param a_vs Pointer to open volume system
121
 * @returns 1 on error and 0 on success
122
 */
123
uint8_t
124
tsk_vs_part_unused(TSK_VS_INFO * a_vs)
125
2.84k
{
126
2.84k
    TSK_VS_PART_INFO *part = a_vs->part_list;
127
2.84k
    TSK_DADDR_T prev_end = 0;
128
129
    /* prev_ent is set to where the previous entry stopped  plus 1 */
130
78.5k
    for (part = a_vs->part_list; part != NULL; part = part->next) {
131
132
        // ignore the META volume
133
75.6k
        if (part->flags & TSK_VS_PART_FLAG_META)
134
12.9k
            continue;
135
136
        // there is space before current and previous volume
137
62.7k
        if (part->start > prev_end) {
138
25.3k
            char *str;
139
25.3k
            if ((str = tsk_malloc(12)) == NULL)
140
0
                return 1;
141
142
25.3k
            snprintf(str, 12, "Unallocated");
143
25.3k
            if (NULL == tsk_vs_part_add(a_vs, prev_end,
144
25.3k
                    part->start - prev_end, TSK_VS_PART_FLAG_UNALLOC, str,
145
25.3k
                    -1, -1)) {
146
0
                free(str);
147
0
                return 1;
148
0
            }
149
25.3k
        }
150
151
62.7k
        prev_end = part->start + part->len;
152
62.7k
    }
153
154
    /* Is there unallocated space at the end? */
155
2.84k
    if (prev_end < (TSK_DADDR_T) (a_vs->img_info->size / a_vs->block_size)) {
156
217
        char *str;
157
217
        if ((str = tsk_malloc(12)) == NULL)
158
0
            return 1;
159
160
217
        snprintf(str, 12, "Unallocated");
161
217
        if (NULL == tsk_vs_part_add(a_vs, prev_end,
162
217
                a_vs->img_info->size / a_vs->block_size - prev_end,
163
217
                TSK_VS_PART_FLAG_UNALLOC, str, -1, -1)) {
164
0
            free(str);
165
0
            return 1;
166
0
        }
167
217
    }
168
169
2.84k
    return 0;
170
2.84k
}
171
172
/*
173
 * free the buffer with the description
174
 */
175
void
176
tsk_vs_part_free(TSK_VS_INFO * a_vs)
177
142k
{
178
142k
    TSK_VS_PART_INFO *part = a_vs->part_list;
179
142k
    TSK_VS_PART_INFO *part2;
180
181
1.58M
    while (part) {
182
1.44M
        free(part->desc);
183
1.44M
        part->tag = 0;
184
1.44M
        part2 = part->next;
185
1.44M
        free(part);
186
1.44M
        part = part2;
187
1.44M
    }
188
142k
    a_vs->part_list = NULL;
189
142k
}
190
191
/**
192
 * \ingroup vslib
193
 * Return handle to a volume in the volume system.
194
 *
195
 * @param a_vs Open volume system
196
 * @param a_idx Index for volume to return (0-based)
197
 * @returns Handle to volume or NULL on error
198
 */
199
const TSK_VS_PART_INFO *
200
tsk_vs_part_get(const TSK_VS_INFO * a_vs, TSK_PNUM_T a_idx)
201
0
{
202
0
    TSK_VS_PART_INFO *part;
203
204
0
    if ((a_vs == NULL) || (a_vs->tag != TSK_VS_INFO_TAG)) {
205
0
        tsk_error_reset();
206
0
        tsk_error_set_errno(TSK_ERR_VS_ARG);
207
0
        tsk_error_set_errstr
208
0
            ("tsk_vs_part_get: pointer is NULL or has unallocated structures");
209
0
        return NULL;
210
0
    }
211
212
0
    if (a_idx >= a_vs->part_count) {
213
0
        tsk_error_reset();
214
0
        tsk_error_set_errno(TSK_ERR_VS_ARG);
215
0
        tsk_error_set_errstr("tsk_vs_part_get: Volume address is too big");
216
0
        return NULL;
217
0
    }
218
219
0
    for (part = a_vs->part_list; part != NULL; part = part->next) {
220
0
        if (part->addr == a_idx)
221
0
            return part;
222
0
    }
223
224
0
    return NULL;
225
0
}
226
227
228
/**
229
 * \ingroup vslib
230
 * Walk a range of partitions and pass the data to a callback function.
231
 *
232
 * @param a_vs Pointer to open volume system
233
 * @param a_start Address of first partition to walk from.
234
 * @param a_last Address of last partition to walk to.
235
 * @param a_flags Flags that are used to identify which of the partitions in the range should be returned (if 0, all partitions will be returned).
236
 * @param a_action Callback action to call for each partition.
237
 * @param a_ptr Pointer to data that will be passed to callback.
238
 * @returns 1 on error and 0 on success
239
 */
240
uint8_t
241
tsk_vs_part_walk(TSK_VS_INFO * a_vs, TSK_PNUM_T a_start, TSK_PNUM_T a_last,
242
    TSK_VS_PART_FLAG_ENUM a_flags, TSK_VS_PART_WALK_CB a_action,
243
    void *a_ptr)
244
2.84k
{
245
2.84k
    TSK_VS_PART_INFO *part;
246
247
2.84k
    if (a_start >= a_vs->part_count) {
248
0
        tsk_error_reset();
249
0
        tsk_error_set_errno(TSK_ERR_VS_WALK_RNG);
250
0
        tsk_error_set_errstr
251
0
            ("tsk_vs_part_walk: Start partition too large: %" PRIuPNUM "",
252
0
            a_start);
253
0
        return 1;
254
0
    }
255
256
2.84k
    if (a_last >= a_vs->part_count) {
257
0
        tsk_error_reset();
258
0
        tsk_error_set_errno(TSK_ERR_VS_WALK_RNG);
259
0
        tsk_error_set_errstr("tsk_vs_part_walk: End partition too large: %"
260
0
            PRIuPNUM "", a_last);
261
0
        return 1;
262
0
    }
263
264
2.84k
    if (a_flags == 0) {
265
0
        a_flags |=
266
0
            (TSK_VS_PART_FLAG_ALLOC | TSK_VS_PART_FLAG_UNALLOC |
267
0
            TSK_VS_PART_FLAG_META);
268
0
    }
269
270
101k
    for (part = a_vs->part_list; part != NULL; part = part->next) {
271
101k
        if ((part->addr >= a_start) && ((part->flags & a_flags) != 0)) {
272
101k
            switch (a_action(a_vs, part, a_ptr)) {
273
101k
            case TSK_WALK_CONT:   break;
274
0
            case TSK_WALK_STOP:   return 0;
275
0
            case TSK_WALK_ERROR:  return 1;
276
101k
            }
277
101k
        }
278
279
101k
        if (part->addr >= a_last)
280
2.84k
            break;
281
101k
    }
282
2.84k
    return 0;
283
2.84k
}