Line | Count | Source |
1 | | /* |
2 | | * Copyright (c) Ian F. Darwin 1986-1995. |
3 | | * Software written by Ian F. Darwin and others; |
4 | | * maintained 1995-present by Christos Zoulas and others. |
5 | | * |
6 | | * Redistribution and use in source and binary forms, with or without |
7 | | * modification, are permitted provided that the following conditions |
8 | | * are met: |
9 | | * 1. Redistributions of source code must retain the above copyright |
10 | | * notice immediately at the beginning of the file, without modification, |
11 | | * this list of conditions, and the following disclaimer. |
12 | | * 2. Redistributions in binary form must reproduce the above copyright |
13 | | * notice, this list of conditions and the following disclaimer in the |
14 | | * documentation and/or other materials provided with the distribution. |
15 | | * |
16 | | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND |
17 | | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
18 | | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
19 | | * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR |
20 | | * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
21 | | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS |
22 | | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
23 | | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
24 | | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY |
25 | | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
26 | | * SUCH DAMAGE. |
27 | | */ |
28 | | /* |
29 | | * print.c - debugging printout routines |
30 | | */ |
31 | | |
32 | | #include "file.h" |
33 | | |
34 | | #ifndef lint |
35 | | FILE_RCSID("@(#)$File: print.c,v 1.110 2025/03/20 17:46:50 christos Exp $") |
36 | | #endif /* lint */ |
37 | | |
38 | | #include <string.h> |
39 | | #include <stdarg.h> |
40 | | #include <stdlib.h> |
41 | | #ifdef HAVE_UNISTD_H |
42 | | #include <unistd.h> |
43 | | #endif |
44 | | #include <time.h> |
45 | | |
46 | | #include "cdf.h" |
47 | | |
48 | | #ifndef COMPILE_ONLY |
49 | | file_protected void |
50 | | file_mdump(struct magic *m) |
51 | 0 | { |
52 | 0 | static const char optyp[] = { FILE_OPS }; |
53 | 0 | char tbuf[256]; |
54 | |
|
55 | 0 | (void) fprintf(stderr, "%s, %u: %.*s %d", |
56 | 0 | m->desc[0] == '\0' ? m->desc + 1 : "*unknown*", m->lineno, |
57 | 0 | (m->cont_level & 7) + 1, ">>>>>>>>", m->offset); |
58 | |
|
59 | 0 | if (m->flag & INDIR) { |
60 | 0 | (void) fprintf(stderr, "(%s,", |
61 | | /* Note: type is unsigned */ |
62 | 0 | (m->in_type < file_nnames) ? file_names[m->in_type] : |
63 | 0 | "*bad in_type*"); |
64 | 0 | if (m->in_op & FILE_OPINVERSE) |
65 | 0 | (void) fputc('~', stderr); |
66 | 0 | (void) fprintf(stderr, "%c%d),", |
67 | 0 | (CAST(size_t, m->in_op & FILE_OPS_MASK) < |
68 | 0 | __arraycount(optyp)) ? |
69 | 0 | optyp[m->in_op & FILE_OPS_MASK] : '?', m->in_offset); |
70 | 0 | } |
71 | 0 | (void) fprintf(stderr, " %s%s", (m->flag & UNSIGNED) ? "u" : "", |
72 | | /* Note: type is unsigned */ |
73 | 0 | (m->type < file_nnames) ? file_names[m->type] : "*bad type"); |
74 | 0 | if (m->mask_op & FILE_OPINVERSE) |
75 | 0 | (void) fputc('~', stderr); |
76 | |
|
77 | 0 | if (IS_STRING(m->type)) { |
78 | 0 | if (m->str_flags) { |
79 | 0 | (void) fputc('/', stderr); |
80 | 0 | if (m->str_flags & STRING_COMPACT_WHITESPACE) |
81 | 0 | (void) fputc(CHAR_COMPACT_WHITESPACE, stderr); |
82 | 0 | if (m->str_flags & STRING_COMPACT_OPTIONAL_WHITESPACE) |
83 | 0 | (void) fputc(CHAR_COMPACT_OPTIONAL_WHITESPACE, |
84 | 0 | stderr); |
85 | 0 | if (m->str_flags & STRING_IGNORE_LOWERCASE) |
86 | 0 | (void) fputc(CHAR_IGNORE_LOWERCASE, stderr); |
87 | 0 | if (m->str_flags & STRING_IGNORE_UPPERCASE) |
88 | 0 | (void) fputc(CHAR_IGNORE_UPPERCASE, stderr); |
89 | 0 | if (m->str_flags & REGEX_OFFSET_START) |
90 | 0 | (void) fputc(CHAR_REGEX_OFFSET_START, stderr); |
91 | 0 | if (m->str_flags & STRING_TEXTTEST) |
92 | 0 | (void) fputc(CHAR_TEXTTEST, stderr); |
93 | 0 | if (m->str_flags & STRING_BINTEST) |
94 | 0 | (void) fputc(CHAR_BINTEST, stderr); |
95 | 0 | if (m->str_flags & PSTRING_1_BE) |
96 | 0 | (void) fputc(CHAR_PSTRING_1_BE, stderr); |
97 | 0 | if (m->str_flags & PSTRING_2_BE) |
98 | 0 | (void) fputc(CHAR_PSTRING_2_BE, stderr); |
99 | 0 | if (m->str_flags & PSTRING_2_LE) |
100 | 0 | (void) fputc(CHAR_PSTRING_2_LE, stderr); |
101 | 0 | if (m->str_flags & PSTRING_4_BE) |
102 | 0 | (void) fputc(CHAR_PSTRING_4_BE, stderr); |
103 | 0 | if (m->str_flags & PSTRING_4_LE) |
104 | 0 | (void) fputc(CHAR_PSTRING_4_LE, stderr); |
105 | 0 | if (m->str_flags & PSTRING_LENGTH_INCLUDES_ITSELF) |
106 | 0 | (void) fputc( |
107 | 0 | CHAR_PSTRING_LENGTH_INCLUDES_ITSELF, |
108 | 0 | stderr); |
109 | 0 | } |
110 | 0 | if (m->str_range) |
111 | 0 | (void) fprintf(stderr, "/%u", m->str_range); |
112 | 0 | } |
113 | 0 | else { |
114 | 0 | if (CAST(size_t, m->mask_op & FILE_OPS_MASK) < |
115 | 0 | __arraycount(optyp)) |
116 | 0 | (void) fputc(optyp[m->mask_op & FILE_OPS_MASK], stderr); |
117 | 0 | else |
118 | 0 | (void) fputc('?', stderr); |
119 | |
|
120 | 0 | if (m->num_mask) { |
121 | 0 | (void) fprintf(stderr, "%.8llx", |
122 | 0 | CAST(unsigned long long, m->num_mask)); |
123 | 0 | } |
124 | 0 | } |
125 | 0 | (void) fprintf(stderr, ",%c", m->reln); |
126 | |
|
127 | 0 | if (m->reln != 'x') { |
128 | 0 | switch (m->type) { |
129 | 0 | case FILE_BYTE: |
130 | 0 | case FILE_SHORT: |
131 | 0 | case FILE_LONG: |
132 | 0 | case FILE_LESHORT: |
133 | 0 | case FILE_LELONG: |
134 | 0 | case FILE_MELONG: |
135 | 0 | case FILE_BESHORT: |
136 | 0 | case FILE_BELONG: |
137 | 0 | case FILE_INDIRECT: |
138 | 0 | (void) fprintf(stderr, "%d", CAST(int32_t, m->value.l)); |
139 | 0 | break; |
140 | 0 | case FILE_BEQUAD: |
141 | 0 | case FILE_LEQUAD: |
142 | 0 | case FILE_QUAD: |
143 | 0 | case FILE_OFFSET: |
144 | 0 | (void) fprintf(stderr, "%" INT64_T_FORMAT "d", |
145 | 0 | CAST(long long, m->value.q)); |
146 | 0 | break; |
147 | 0 | case FILE_PSTRING: |
148 | 0 | case FILE_STRING: |
149 | 0 | case FILE_REGEX: |
150 | 0 | case FILE_BESTRING16: |
151 | 0 | case FILE_LESTRING16: |
152 | 0 | case FILE_SEARCH: |
153 | 0 | file_showstr(stderr, m->value.s, |
154 | 0 | CAST(size_t, m->vallen)); |
155 | 0 | break; |
156 | 0 | case FILE_DATE: |
157 | 0 | case FILE_LEDATE: |
158 | 0 | case FILE_BEDATE: |
159 | 0 | case FILE_MEDATE: |
160 | 0 | (void)fprintf(stderr, "%s,", |
161 | 0 | file_fmtdatetime(tbuf, sizeof(tbuf), m->value.l, 0)); |
162 | 0 | break; |
163 | 0 | case FILE_LDATE: |
164 | 0 | case FILE_LELDATE: |
165 | 0 | case FILE_BELDATE: |
166 | 0 | case FILE_MELDATE: |
167 | 0 | (void)fprintf(stderr, "%s,", |
168 | 0 | file_fmtdatetime(tbuf, sizeof(tbuf), m->value.l, |
169 | 0 | FILE_T_LOCAL)); |
170 | 0 | break; |
171 | 0 | case FILE_QDATE: |
172 | 0 | case FILE_LEQDATE: |
173 | 0 | case FILE_BEQDATE: |
174 | 0 | (void)fprintf(stderr, "%s,", |
175 | 0 | file_fmtdatetime(tbuf, sizeof(tbuf), m->value.q, 0)); |
176 | 0 | break; |
177 | 0 | case FILE_QLDATE: |
178 | 0 | case FILE_LEQLDATE: |
179 | 0 | case FILE_BEQLDATE: |
180 | 0 | (void)fprintf(stderr, "%s,", |
181 | 0 | file_fmtdatetime(tbuf, sizeof(tbuf), m->value.q, |
182 | 0 | FILE_T_LOCAL)); |
183 | 0 | break; |
184 | 0 | case FILE_QWDATE: |
185 | 0 | case FILE_LEQWDATE: |
186 | 0 | case FILE_BEQWDATE: |
187 | 0 | (void)fprintf(stderr, "%s,", |
188 | 0 | file_fmtdatetime(tbuf, sizeof(tbuf), m->value.q, |
189 | 0 | FILE_T_WINDOWS)); |
190 | 0 | break; |
191 | 0 | case FILE_FLOAT: |
192 | 0 | case FILE_BEFLOAT: |
193 | 0 | case FILE_LEFLOAT: |
194 | 0 | (void) fprintf(stderr, "%G", m->value.f); |
195 | 0 | break; |
196 | 0 | case FILE_DOUBLE: |
197 | 0 | case FILE_BEDOUBLE: |
198 | 0 | case FILE_LEDOUBLE: |
199 | 0 | (void) fprintf(stderr, "%G", m->value.d); |
200 | 0 | break; |
201 | 0 | case FILE_LEVARINT: |
202 | 0 | case FILE_BEVARINT: |
203 | 0 | (void)fprintf(stderr, "%s", file_fmtvarint( |
204 | 0 | tbuf, sizeof(tbuf), m->value.us, m->type)); |
205 | 0 | break; |
206 | 0 | case FILE_MSDOSDATE: |
207 | 0 | case FILE_BEMSDOSDATE: |
208 | 0 | case FILE_LEMSDOSDATE: |
209 | 0 | (void)fprintf(stderr, "%s,", |
210 | 0 | file_fmtdate(tbuf, sizeof(tbuf), m->value.h)); |
211 | 0 | break; |
212 | 0 | case FILE_MSDOSTIME: |
213 | 0 | case FILE_BEMSDOSTIME: |
214 | 0 | case FILE_LEMSDOSTIME: |
215 | 0 | (void)fprintf(stderr, "%s,", |
216 | 0 | file_fmttime(tbuf, sizeof(tbuf), m->value.h)); |
217 | 0 | break; |
218 | 0 | case FILE_OCTAL: |
219 | 0 | (void)fprintf(stderr, "%s", |
220 | 0 | file_fmtnum(tbuf, sizeof(tbuf), m->value.s, 8)); |
221 | 0 | break; |
222 | 0 | case FILE_DEFAULT: |
223 | | /* XXX - do anything here? */ |
224 | 0 | break; |
225 | 0 | case FILE_USE: |
226 | 0 | case FILE_NAME: |
227 | 0 | case FILE_DER: |
228 | 0 | (void) fprintf(stderr, "'%s'", m->value.s); |
229 | 0 | break; |
230 | 0 | case FILE_GUID: |
231 | 0 | (void) file_print_guid(tbuf, sizeof(tbuf), |
232 | 0 | m->value.guid); |
233 | 0 | (void) fprintf(stderr, "%s", tbuf); |
234 | 0 | break; |
235 | | |
236 | 0 | default: |
237 | 0 | (void) fprintf(stderr, "*bad type %d*", m->type); |
238 | 0 | break; |
239 | 0 | } |
240 | 0 | } |
241 | 0 | (void) fprintf(stderr, ",\"%s\"]\n", m->desc); |
242 | 0 | } |
243 | | #endif |
244 | | |
245 | | static void __attribute__((__format__(__printf__, 1, 0))) |
246 | | file_vmagwarn(const char *f, va_list va) |
247 | 0 | { |
248 | | /* cuz we use stdout for most, stderr here */ |
249 | 0 | (void) fflush(stdout); |
250 | |
|
251 | 0 | (void) fprintf(stderr, "Warning: "); |
252 | 0 | (void) vfprintf(stderr, f, va); |
253 | 0 | (void) fputc('\n', stderr); |
254 | 0 | } |
255 | | |
256 | | /*VARARGS*/ |
257 | | file_protected void |
258 | | file_magwarn1(const char *f, ...) |
259 | 0 | { |
260 | 0 | va_list va; |
261 | |
|
262 | 0 | va_start(va, f); |
263 | 0 | file_vmagwarn(f, va); |
264 | 0 | va_end(va); |
265 | 0 | } |
266 | | |
267 | | |
268 | | /*VARARGS*/ |
269 | | file_protected void |
270 | | file_magwarn(struct magic_set *ms, const char *f, ...) |
271 | 0 | { |
272 | 0 | va_list va; |
273 | |
|
274 | 0 | if (++ms->magwarn == ms->magwarn_max) { |
275 | 0 | (void) fprintf(stderr, |
276 | 0 | "%s, %lu: Maximum number of warnings (%u) exceeded.\n", |
277 | 0 | ms->file, CAST(unsigned long, ms->line), |
278 | 0 | ms->magwarn_max); |
279 | 0 | (void) fprintf(stderr, |
280 | 0 | "%s, %lu: Additional warnings are suppressed.\n", |
281 | 0 | ms->file, CAST(unsigned long, ms->line)); |
282 | 0 | } |
283 | 0 | if (ms->magwarn >= ms->magwarn_max) { |
284 | 0 | return; |
285 | 0 | } |
286 | | |
287 | 0 | if (ms->file) |
288 | 0 | (void) fprintf(stderr, "%s, %lu: ", ms->file, |
289 | 0 | CAST(unsigned long, ms->line)); |
290 | |
|
291 | 0 | va_start(va, f); |
292 | 0 | file_vmagwarn(f, va); |
293 | 0 | va_end(va); |
294 | 0 | } |
295 | | |
296 | | file_protected const char * |
297 | | file_fmtvarint(char *buf, size_t blen, const unsigned char *us, int t) |
298 | 0 | { |
299 | 0 | snprintf(buf, blen, "%jd", CAST(intmax_t, |
300 | 0 | file_varint2uintmax_t(us, t, NULL))); |
301 | 0 | return buf; |
302 | 0 | } |
303 | | |
304 | | file_protected const char * |
305 | | file_fmtdatetime(char *buf, size_t bsize, uint64_t v, int flags) |
306 | 2.19k | { |
307 | 2.19k | char *pp; |
308 | 2.19k | time_t t; |
309 | 2.19k | struct tm *tm, tmz; |
310 | | |
311 | 2.19k | if (flags & FILE_T_WINDOWS) { |
312 | 1.08k | struct timespec ts; |
313 | 1.08k | cdf_timestamp_to_timespec(&ts, CAST(cdf_timestamp_t, v)); |
314 | 1.08k | t = ts.tv_sec; |
315 | 1.11k | } else { |
316 | | // XXX: perhaps detect and print something if overflow |
317 | | // on 32 bit time_t? |
318 | 1.11k | t = CAST(time_t, v); |
319 | 1.11k | } |
320 | | |
321 | 2.19k | if (t > MAX_CTIME) |
322 | 108 | goto out; |
323 | | |
324 | 2.09k | if (flags & FILE_T_LOCAL) { |
325 | 377 | tzset(); |
326 | 377 | tm = localtime_r(&t, &tmz); |
327 | 1.71k | } else { |
328 | 1.71k | tm = gmtime_r(&t, &tmz); |
329 | 1.71k | } |
330 | 2.09k | if (tm == NULL) |
331 | 130 | goto out; |
332 | 1.96k | pp = asctime_r(tm, buf); |
333 | | |
334 | 1.96k | if (pp == NULL) |
335 | 151 | goto out; |
336 | 1.81k | pp[strcspn(pp, "\n")] = '\0'; |
337 | 1.81k | return pp; |
338 | 389 | out: |
339 | 389 | strlcpy(buf, "*Invalid datetime*", bsize); |
340 | 389 | return buf; |
341 | 1.96k | } |
342 | | |
343 | | /* |
344 | | * https://docs.microsoft.com/en-us/windows/win32/api/winbase/\ |
345 | | * nf-winbase-dosdatetimetofiletime?redirectedfrom=MSDN |
346 | | */ |
347 | | file_protected const char * |
348 | | file_fmtdate(char *buf, size_t bsize, uint16_t v) |
349 | 267 | { |
350 | 267 | struct tm tm; |
351 | | |
352 | 267 | memset(&tm, 0, sizeof(tm)); |
353 | 267 | tm.tm_mday = v & 0x1f; |
354 | 267 | tm.tm_mon = ((v >> 5) & 0xf) - 1; |
355 | | // Sanity check because some OS's coredump with invalid values. |
356 | | // Yes, Cygwin I am looking at you! |
357 | 267 | if (tm.tm_mon < 0 || tm.tm_mon > 11) |
358 | 156 | tm.tm_mon = 0; |
359 | 267 | tm.tm_year = (v >> 9) + 80; |
360 | | |
361 | 267 | if (strftime(buf, bsize, "%b %d %Y", &tm) == 0) |
362 | 0 | goto out; |
363 | | |
364 | 267 | return buf; |
365 | 0 | out: |
366 | 0 | strlcpy(buf, "*Invalid date*", bsize); |
367 | 0 | return buf; |
368 | 267 | } |
369 | | |
370 | | file_protected const char * |
371 | | file_fmttime(char *buf, size_t bsize, uint16_t v) |
372 | 267 | { |
373 | 267 | struct tm tm; |
374 | | |
375 | 267 | memset(&tm, 0, sizeof(tm)); |
376 | 267 | tm.tm_sec = (v & 0x1f) * 2; |
377 | 267 | tm.tm_min = ((v >> 5) & 0x3f); |
378 | 267 | tm.tm_hour = (v >> 11); |
379 | | |
380 | 267 | if (strftime(buf, bsize, "%T", &tm) == 0) |
381 | 0 | goto out; |
382 | | |
383 | 267 | return buf; |
384 | 0 | out: |
385 | 0 | strlcpy(buf, "*Invalid time*", bsize); |
386 | 0 | return buf; |
387 | | |
388 | 267 | } |
389 | | |
390 | | file_protected const char * |
391 | | file_fmtnum(char *buf, size_t blen, const char *us, int base) |
392 | 0 | { |
393 | 0 | char *endptr; |
394 | 0 | unsigned long long val; |
395 | |
|
396 | 0 | errno = 0; |
397 | 0 | val = strtoull(us, &endptr, base); |
398 | 0 | if (*endptr || errno) { |
399 | 0 | bad: strlcpy(buf, "*Invalid number*", blen); |
400 | 0 | return buf; |
401 | 0 | } |
402 | | |
403 | 0 | if (snprintf(buf, blen, "%llu", val) < 0) |
404 | 0 | goto bad; |
405 | 0 | return buf; |
406 | 0 | } |