/src/sleuthkit/tsk/util/file_system_utils.cpp
Line | Count | Source |
1 | | |
2 | | /* |
3 | | ** The Sleuth Kit |
4 | | ** |
5 | | ** Copyright (c) 2022 Basis Technology Corp. All rights reserved |
6 | | ** Contact: Brian Carrier [carrier <at> sleuthkit [dot] org] |
7 | | ** |
8 | | ** This software is distributed under the Common Public License 1.0 |
9 | | ** |
10 | | */ |
11 | | |
12 | | /* |
13 | | * Common code used by the raw and logical images. |
14 | | */ |
15 | | |
16 | | #include "tsk/base/tsk_base_i.h" |
17 | | #include "tsk/img/tsk_img_i.h" |
18 | | #include "file_system_utils.h" |
19 | | |
20 | | #ifdef __APPLE__ |
21 | | #include <sys/disk.h> |
22 | | #endif |
23 | | |
24 | | #ifdef TSK_WIN32 |
25 | | #include <winioctl.h> |
26 | | #else |
27 | | #include <sys/types.h> |
28 | | #include <sys/stat.h> |
29 | | #include <unistd.h> |
30 | | #include <fcntl.h> |
31 | | #endif |
32 | | |
33 | | #ifndef S_IFMT |
34 | | #define S_IFMT __S_IFMT |
35 | | #endif |
36 | | |
37 | | #ifndef S_IFDIR |
38 | | #define S_IFDIR __S_IFDIR |
39 | | #endif |
40 | | |
41 | | /** |
42 | | * Test if the image is a Windows device |
43 | | * @param The path to test |
44 | | * |
45 | | * Return 1 if the path represents a Windows device, 0 otherwise |
46 | | */ |
47 | | #ifdef TSK_WIN32 |
48 | | int is_windows_device_path(const TSK_TCHAR * image_name) { |
49 | | return (TSTRNCMP(image_name, _TSK_T("\\\\.\\"), 4) == 0); |
50 | | } |
51 | | #endif |
52 | | |
53 | | /** |
54 | | * Get the size in bytes of the given file. |
55 | | * |
56 | | * @param a_file The file to test |
57 | | * @param is_winobj 1 if the file is a windows object and not a real file |
58 | | * |
59 | | * @return the size in bytes, or -1 on error/unknown, |
60 | | * -2 if unreadable, -3 if it's a directory. |
61 | | */ |
62 | | TSK_OFF_T |
63 | | get_size_of_file_on_disk(const TSK_TCHAR * a_file, uint8_t a_is_winobj) |
64 | 0 | { |
65 | 0 | TSK_OFF_T size = -1; |
66 | 0 | struct STAT_STR sb; |
67 | |
|
68 | 0 | if (TSTAT(a_file, &sb) < 0) { |
69 | 0 | if (a_is_winobj) { |
70 | | /* stat can fail for Windows objects; ignore that */ |
71 | 0 | if (tsk_verbose) { |
72 | 0 | tsk_fprintf(stderr, |
73 | 0 | "raw_open: ignoring stat result on Windows device %" |
74 | 0 | PRIttocTSK "\n", a_file); |
75 | 0 | } |
76 | 0 | } |
77 | 0 | else { |
78 | 0 | tsk_error_reset(); |
79 | 0 | tsk_error_set_errno(TSK_ERR_IMG_STAT); |
80 | 0 | tsk_error_set_errstr("raw_open: image \"%" PRIttocTSK |
81 | 0 | "\" - %s", a_file, strerror(errno)); |
82 | 0 | return -2; |
83 | 0 | } |
84 | 0 | } |
85 | 0 | else if ((sb.st_mode & S_IFMT) == S_IFDIR) { |
86 | 0 | tsk_error_reset(); |
87 | 0 | tsk_error_set_errno(TSK_ERR_IMG_MAGIC); |
88 | 0 | tsk_error_set_errstr("raw_open: image \"%" PRIttocTSK |
89 | 0 | "\" - is a directory", a_file); |
90 | 0 | return -3; |
91 | 0 | } |
92 | | |
93 | | #ifdef TSK_WIN32 |
94 | | { |
95 | | HANDLE fd; |
96 | | DWORD dwHi, dwLo; |
97 | | |
98 | | if ((fd = CreateFile(a_file, FILE_READ_DATA, |
99 | | FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, |
100 | | OPEN_EXISTING, 0, NULL)) == |
101 | | INVALID_HANDLE_VALUE) { |
102 | | int lastError = (int)GetLastError(); |
103 | | tsk_error_reset(); |
104 | | tsk_error_set_errno(TSK_ERR_IMG_OPEN); |
105 | | // print string of commonly found errors |
106 | | if (lastError == ERROR_ACCESS_DENIED) { |
107 | | tsk_error_set_errstr("raw_open: file \"%" PRIttocTSK |
108 | | "\" - access denied", a_file); |
109 | | } |
110 | | else if (lastError == ERROR_SHARING_VIOLATION) { |
111 | | tsk_error_set_errstr("raw_open: file \"%" PRIttocTSK |
112 | | "\" - sharing violation", a_file); |
113 | | } |
114 | | else if (lastError == ERROR_FILE_NOT_FOUND) { |
115 | | tsk_error_set_errstr("raw_open: file \"%" PRIttocTSK |
116 | | "\" - file not found", a_file); |
117 | | } |
118 | | else { |
119 | | tsk_error_set_errstr("raw_open: file \"%" PRIttocTSK |
120 | | "\" - (error %d)", a_file, lastError); |
121 | | } |
122 | | return -2; |
123 | | } |
124 | | |
125 | | /* We need different techniques to determine the size of Windows physical |
126 | | * devices versus normal files */ |
127 | | if (a_is_winobj == 0) { |
128 | | dwLo = GetFileSize(fd, &dwHi); |
129 | | if (dwLo == 0xffffffff) { |
130 | | int lastError = (int)GetLastError(); |
131 | | tsk_error_reset(); |
132 | | tsk_error_set_errno(TSK_ERR_IMG_OPEN); |
133 | | tsk_error_set_errstr("raw_open: file \"%" PRIttocTSK |
134 | | "\" - GetFileSize: %d", a_file, lastError); |
135 | | size = -1; |
136 | | } |
137 | | else { |
138 | | size = dwLo | ((TSK_OFF_T)dwHi << 32); |
139 | | } |
140 | | } |
141 | | else { |
142 | | |
143 | | //use GET_PARTITION_INFO_EX prior to IOCTL_DISK_GET_DRIVE_GEOMETRY |
144 | | // to determine the physical disk size because |
145 | | //calculating it with the help of GET_DRIVE_GEOMETRY gives only |
146 | | // approximate number |
147 | | DWORD junk; |
148 | | |
149 | | PARTITION_INFORMATION_EX partition; |
150 | | if (FALSE == DeviceIoControl(fd, |
151 | | IOCTL_DISK_GET_PARTITION_INFO_EX, |
152 | | NULL, 0, &partition, sizeof(partition), &junk, |
153 | | (LPOVERLAPPED)NULL)) { |
154 | | DISK_GEOMETRY pdg; |
155 | | |
156 | | if (FALSE == DeviceIoControl(fd, IOCTL_DISK_GET_DRIVE_GEOMETRY, |
157 | | NULL, 0, &pdg, sizeof(pdg), &junk, (LPOVERLAPPED)NULL)) { |
158 | | int lastError = (int)GetLastError(); |
159 | | tsk_error_reset(); |
160 | | tsk_error_set_errno(TSK_ERR_IMG_OPEN); |
161 | | tsk_error_set_errstr("raw_open: file \"%" PRIttocTSK |
162 | | "\" - DeviceIoControl: %d", a_file, |
163 | | lastError); |
164 | | size = -1; |
165 | | } |
166 | | else { |
167 | | size = pdg.Cylinders.QuadPart * |
168 | | (TSK_OFF_T)pdg.TracksPerCylinder * |
169 | | (TSK_OFF_T)pdg.SectorsPerTrack * |
170 | | (TSK_OFF_T)pdg.BytesPerSector; |
171 | | } |
172 | | } |
173 | | else { |
174 | | size = partition.PartitionLength.QuadPart; |
175 | | } |
176 | | } |
177 | | |
178 | | CloseHandle(fd); |
179 | | } |
180 | | #else |
181 | | |
182 | 0 | int fd; |
183 | |
|
184 | 0 | if ((fd = open(a_file, O_RDONLY | O_BINARY)) < 0) { |
185 | 0 | tsk_error_reset(); |
186 | 0 | tsk_error_set_errno(TSK_ERR_IMG_OPEN); |
187 | 0 | tsk_error_set_errstr("raw_open: file \"%" PRIttocTSK "\" - %s", |
188 | 0 | a_file, strerror(errno)); |
189 | 0 | return -2; |
190 | 0 | } |
191 | | |
192 | | #ifdef __APPLE__ |
193 | | /* OS X doesn't support SEEK_END on char devices */ |
194 | | if ((sb.st_mode & S_IFMT) != S_IFCHR) { |
195 | | size = lseek(fd, 0, SEEK_END); |
196 | | } |
197 | | |
198 | | if (size <= 0) { |
199 | | int blkSize; |
200 | | long long blkCnt; |
201 | | |
202 | | if (ioctl(fd, DKIOCGETBLOCKSIZE, &blkSize) >= 0) { |
203 | | if (ioctl(fd, DKIOCGETBLOCKCOUNT, &blkCnt) >= 0) { |
204 | | size = blkCnt * (long long)blkSize; |
205 | | } |
206 | | } |
207 | | } |
208 | | #else |
209 | | /* We don't use the stat output because it doesn't work on raw |
210 | | * devices and such */ |
211 | 0 | size = lseek(fd, 0, SEEK_END); |
212 | 0 | #endif |
213 | |
|
214 | 0 | close(fd); |
215 | |
|
216 | 0 | #endif |
217 | |
|
218 | 0 | return size; |
219 | 0 | } |