1 /*
2 * Copyright (c) Christos Zoulas 2003.
3 * All Rights Reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice immediately at the beginning of the file, without modification,
10 * this list of conditions, and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
19 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25 * SUCH DAMAGE.
26 */
27 #include "file.h"
28
29 #ifndef lint
30 FILE_RCSID("@(#)$File: funcs.c,v 1.115 2020/02/20 15:50:20 christos Exp $")
31 #endif /* lint */
32
33 #include "magic.h"
34 #include <assert.h>
35 #include <stdarg.h>
36 #include <stdlib.h>
37 #include <string.h>
38 #include <ctype.h>
39 #if defined(HAVE_WCHAR_H)
40 #include <wchar.h>
41 #endif
42 #if defined(HAVE_WCTYPE_H)
43 #include <wctype.h>
44 #endif
45 #include <limits.h>
46
47 #ifndef SIZE_MAX
48 #define SIZE_MAX ((size_t)~0)
49 #endif
50
51 #include "php.h"
52 #include "main/php_network.h"
53
54 #ifndef PREG_OFFSET_CAPTURE
55 # define PREG_OFFSET_CAPTURE (1<<8)
56 #endif
57
58 protected char *
file_copystr(char * buf,size_t blen,size_t width,const char * str)59 file_copystr(char *buf, size_t blen, size_t width, const char *str)
60 {
61 if (++width > blen)
62 width = blen;
63 strlcpy(buf, str, width);
64 return buf;
65 }
66
67 private void
file_clearbuf(struct magic_set * ms)68 file_clearbuf(struct magic_set *ms)
69 {
70 efree(ms->o.buf);
71 ms->o.buf = NULL;
72 ms->o.blen = 0;
73 }
74
75 private int
file_checkfield(char * msg,size_t mlen,const char * what,const char ** pp)76 file_checkfield(char *msg, size_t mlen, const char *what, const char **pp)
77 {
78 const char *p = *pp;
79 int fw = 0;
80
81 while (*p && isdigit((unsigned char)*p))
82 fw = fw * 10 + (*p++ - '0');
83
84 *pp = p;
85
86 if (fw < 1024)
87 return 1;
88 if (msg)
89 snprintf(msg, mlen, "field %s too large: %d", what, fw);
90
91 return 0;
92 }
93
94 protected int
file_checkfmt(char * msg,size_t mlen,const char * fmt)95 file_checkfmt(char *msg, size_t mlen, const char *fmt)
96 {
97 for (const char *p = fmt; *p; p++) {
98 if (*p != '%')
99 continue;
100 if (*++p == '%')
101 continue;
102 // Skip uninteresting.
103 while (strchr("0.'+- ", *p) != NULL)
104 p++;
105 if (*p == '*') {
106 if (msg)
107 snprintf(msg, mlen, "* not allowed in format");
108 return -1;
109 }
110
111 if (!file_checkfield(msg, mlen, "width", &p))
112 return -1;
113
114 if (*p == '.') {
115 p++;
116 if (!file_checkfield(msg, mlen, "precision", &p))
117 return -1;
118 }
119
120 if (!isalpha((unsigned char)*p)) {
121 if (msg)
122 snprintf(msg, mlen, "bad format char: %c", *p);
123 return -1;
124 }
125 }
126 return 0;
127 }
128
129 protected int
file_printf(struct magic_set * ms,const char * fmt,...)130 file_printf(struct magic_set *ms, const char *fmt, ...)
131 {
132 va_list ap;
133 char *buf = NULL, *newstr;
134
135 va_start(ap, fmt);
136 vspprintf(&buf, 0, fmt, ap);
137 va_end(ap);
138
139 if (ms->o.buf != NULL) {
140 spprintf(&newstr, 0, "%s%s", ms->o.buf, (buf ? buf : ""));
141 if (buf) {
142 efree(buf);
143 }
144 efree(ms->o.buf);
145 ms->o.buf = newstr;
146 } else {
147 ms->o.buf = buf;
148 }
149 return 0;
150 }
151
152 /*
153 * error - print best error message possible
154 */
155 /*VARARGS*/
156 private void
file_error_core(struct magic_set * ms,int error,const char * f,va_list va,size_t lineno)157 file_error_core(struct magic_set *ms, int error, const char *f, va_list va,
158 size_t lineno)
159 {
160 char *buf = NULL;
161
162 /* Only the first error is ok */
163 if (ms->event_flags & EVENT_HAD_ERR)
164 return;
165 if (lineno != 0) {
166 efree(ms->o.buf);
167 ms->o.buf = NULL;
168 file_printf(ms, "line %" SIZE_T_FORMAT "u:", lineno);
169 }
170
171 vspprintf(&buf, 0, f, va);
172 va_end(va);
173
174 if (error > 0) {
175 file_printf(ms, "%s (%s)", (*buf ? buf : ""), strerror(error));
176 } else if (*buf) {
177 file_printf(ms, "%s", buf);
178 }
179
180 if (buf) {
181 efree(buf);
182 }
183
184 ms->event_flags |= EVENT_HAD_ERR;
185 ms->error = error;
186 }
187
188 /*VARARGS*/
189 protected void
file_error(struct magic_set * ms,int error,const char * f,...)190 file_error(struct magic_set *ms, int error, const char *f, ...)
191 {
192 va_list va;
193 va_start(va, f);
194 file_error_core(ms, error, f, va, 0);
195 va_end(va);
196 }
197
198 /*
199 * Print an error with magic line number.
200 */
201 /*VARARGS*/
202 protected void
file_magerror(struct magic_set * ms,const char * f,...)203 file_magerror(struct magic_set *ms, const char *f, ...)
204 {
205 va_list va;
206 va_start(va, f);
207 file_error_core(ms, 0, f, va, ms->line);
208 va_end(va);
209 }
210
211 protected void
file_oomem(struct magic_set * ms,size_t len)212 file_oomem(struct magic_set *ms, size_t len)
213 {
214 file_error(ms, errno, "cannot allocate %" SIZE_T_FORMAT "u bytes",
215 len);
216 }
217
218 protected void
file_badseek(struct magic_set * ms)219 file_badseek(struct magic_set *ms)
220 {
221 file_error(ms, errno, "error seeking");
222 }
223
224 protected void
file_badread(struct magic_set * ms)225 file_badread(struct magic_set *ms)
226 {
227 file_error(ms, errno, "error reading");
228 }
229
230 #ifndef COMPILE_ONLY
231
232 protected int
file_separator(struct magic_set * ms)233 file_separator(struct magic_set *ms)
234 {
235 return file_printf(ms, "\n- ");
236 }
237
238 static int
checkdone(struct magic_set * ms,int * rv)239 checkdone(struct magic_set *ms, int *rv)
240 {
241 if ((ms->flags & MAGIC_CONTINUE) == 0)
242 return 1;
243 if (file_separator(ms) == -1)
244 *rv = -1;
245 return 0;
246 }
247
248 protected int
file_default(struct magic_set * ms,size_t nb)249 file_default(struct magic_set *ms, size_t nb)
250 {
251 if (ms->flags & MAGIC_MIME) {
252 if ((ms->flags & MAGIC_MIME_TYPE) &&
253 file_printf(ms, "application/%s",
254 nb ? "octet-stream" : "x-empty") == -1)
255 return -1;
256 return 1;
257 }
258 if (ms->flags & MAGIC_APPLE) {
259 if (file_printf(ms, "UNKNUNKN") == -1)
260 return -1;
261 return 1;
262 }
263 if (ms->flags & MAGIC_EXTENSION) {
264 if (file_printf(ms, "???") == -1)
265 return -1;
266 return 1;
267 }
268 return 0;
269 }
270
271 /*
272 * The magic detection functions return:
273 * 1: found
274 * 0: not found
275 * -1: error
276 */
277 /*ARGSUSED*/
278 protected int
file_buffer(struct magic_set * ms,php_stream * stream,zend_stat_t * st,const char * inname,const void * buf,size_t nb)279 file_buffer(struct magic_set *ms, php_stream *stream, zend_stat_t *st,
280 const char *inname,
281 const void *buf, size_t nb)
282 {
283 int m = 0, rv = 0, looks_text = 0;
284 const char *code = NULL;
285 const char *code_mime = "binary";
286 const char *def = "data";
287 const char *ftype = NULL;
288 char *rbuf = NULL;
289 struct buffer b;
290 int fd = -1;
291
292 if (stream) {
293 #ifdef _WIN64
294 php_socket_t _fd = fd;
295 #else
296 int _fd;
297 #endif
298 int _ret = php_stream_cast(stream, PHP_STREAM_AS_FD, (void **)&_fd, 0);
299 if (SUCCESS == _ret) {
300 fd = (int)_fd;
301 }
302 }
303
304 buffer_init(&b, fd, st, buf, nb);
305 ms->mode = b.st.st_mode;
306
307 if (nb == 0) {
308 def = "empty";
309 goto simple;
310 } else if (nb == 1) {
311 def = "very short file (no magic)";
312 goto simple;
313 }
314
315 if ((ms->flags & MAGIC_NO_CHECK_ENCODING) == 0) {
316 looks_text = file_encoding(ms, &b, NULL, 0,
317 &code, &code_mime, &ftype);
318 }
319
320 #ifdef __EMX__
321 if ((ms->flags & MAGIC_NO_CHECK_APPTYPE) == 0 && inname) {
322 m = file_os2_apptype(ms, inname, &b);
323 if ((ms->flags & MAGIC_DEBUG) != 0)
324 (void)fprintf(stderr, "[try os2_apptype %d]\n", m);
325 switch (m) {
326 case -1:
327 return -1;
328 case 0:
329 break;
330 default:
331 return 1;
332 }
333 }
334 #endif
335
336 #if PHP_FILEINFO_UNCOMPRESS
337 /* try compression stuff */
338 if ((ms->flags & MAGIC_NO_CHECK_COMPRESS) == 0) {
339 m = file_zmagic(ms, &b, inname);
340 if ((ms->flags & MAGIC_DEBUG) != 0)
341 (void)fprintf(stderr, "[try zmagic %d]\n", m);
342 if (m) {
343 goto done_encoding;
344 }
345 }
346 #endif
347 /* Check if we have a tar file */
348 if ((ms->flags & MAGIC_NO_CHECK_TAR) == 0) {
349 m = file_is_tar(ms, &b);
350 if ((ms->flags & MAGIC_DEBUG) != 0)
351 (void)fprintf(stderr, "[try tar %d]\n", m);
352 if (m) {
353 if (checkdone(ms, &rv))
354 goto done;
355 }
356 }
357
358 /* Check if we have a JSON file */
359 if ((ms->flags & MAGIC_NO_CHECK_JSON) == 0) {
360 m = file_is_json(ms, &b);
361 if ((ms->flags & MAGIC_DEBUG) != 0)
362 (void)fprintf(stderr, "[try json %d]\n", m);
363 if (m) {
364 if (checkdone(ms, &rv))
365 goto done;
366 }
367 }
368
369 /* Check if we have a CSV file */
370 if ((ms->flags & MAGIC_NO_CHECK_CSV) == 0) {
371 m = file_is_csv(ms, &b, looks_text);
372 if ((ms->flags & MAGIC_DEBUG) != 0)
373 (void)fprintf(stderr, "[try csv %d]\n", m);
374 if (m) {
375 if (checkdone(ms, &rv))
376 goto done;
377 }
378 }
379
380 /* Check if we have a CDF file */
381 if ((ms->flags & MAGIC_NO_CHECK_CDF) == 0) {
382 m = file_trycdf(ms, &b);
383 if ((ms->flags & MAGIC_DEBUG) != 0)
384 (void)fprintf(stderr, "[try cdf %d]\n", m);
385 if (m) {
386 if (checkdone(ms, &rv))
387 goto done;
388 }
389 }
390 #ifdef BUILTIN_ELF
391 if ((ms->flags & MAGIC_NO_CHECK_ELF) == 0 && nb > 5 && fd != -1) {
392 file_pushbuf_t *pb;
393 /*
394 * We matched something in the file, so this
395 * *might* be an ELF file, and the file is at
396 * least 5 bytes long, so if it's an ELF file
397 * it has at least one byte past the ELF magic
398 * number - try extracting information from the
399 * ELF headers that cannot easily be extracted
400 * with rules in the magic file. We we don't
401 * print the information yet.
402 */
403 if ((pb = file_push_buffer(ms)) == NULL)
404 return -1;
405
406 rv = file_tryelf(ms, &b);
407 rbuf = file_pop_buffer(ms, pb);
408 if (rv == -1) {
409 free(rbuf);
410 rbuf = NULL;
411 }
412 if ((ms->flags & MAGIC_DEBUG) != 0)
413 (void)fprintf(stderr, "[try elf %d]\n", m);
414 }
415 #endif
416
417 /* try soft magic tests */
418 if ((ms->flags & MAGIC_NO_CHECK_SOFT) == 0) {
419 m = file_softmagic(ms, &b, NULL, NULL, BINTEST, looks_text);
420 if ((ms->flags & MAGIC_DEBUG) != 0)
421 (void)fprintf(stderr, "[try softmagic %d]\n", m);
422 if (m == 1 && rbuf) {
423 if (file_printf(ms, "%s", rbuf) == -1)
424 goto done;
425 }
426 if (m) {
427 if (checkdone(ms, &rv))
428 goto done;
429 }
430 }
431
432 /* try text properties */
433 if ((ms->flags & MAGIC_NO_CHECK_TEXT) == 0) {
434
435 m = file_ascmagic(ms, &b, looks_text);
436 if ((ms->flags & MAGIC_DEBUG) != 0)
437 (void)fprintf(stderr, "[try ascmagic %d]\n", m);
438 if (m) {
439 goto done;
440 }
441 }
442
443 simple:
444 /* give up */
445 if (m == 0) {
446 m = 1;
447 rv = file_default(ms, nb);
448 if (rv == 0)
449 if (file_printf(ms, "%s", def) == -1)
450 rv = -1;
451 }
452 done:
453 if ((ms->flags & MAGIC_MIME_ENCODING) != 0) {
454 if (ms->flags & MAGIC_MIME_TYPE)
455 if (file_printf(ms, "; charset=") == -1)
456 rv = -1;
457 if (file_printf(ms, "%s", code_mime) == -1)
458 rv = -1;
459 }
460 #if PHP_FILEINFO_UNCOMPRESS
461 done_encoding:
462 #endif
463 efree(rbuf);
464 buffer_fini(&b);
465 if (rv)
466 return rv;
467
468 return m;
469 }
470 #endif
471
472 protected int
file_reset(struct magic_set * ms,int checkloaded)473 file_reset(struct magic_set *ms, int checkloaded)
474 {
475 if (checkloaded && ms->mlist[0] == NULL) {
476 file_error(ms, 0, "no magic files loaded");
477 return -1;
478 }
479 file_clearbuf(ms);
480 if (ms->o.pbuf) {
481 efree(ms->o.pbuf);
482 ms->o.pbuf = NULL;
483 }
484 ms->event_flags &= ~EVENT_HAD_ERR;
485 ms->error = -1;
486 return 0;
487 }
488
489 #define OCTALIFY(n, o) \
490 /*LINTED*/ \
491 (void)(*(n)++ = '\\', \
492 *(n)++ = ((CAST(uint32_t, *(o)) >> 6) & 3) + '0', \
493 *(n)++ = ((CAST(uint32_t, *(o)) >> 3) & 7) + '0', \
494 *(n)++ = ((CAST(uint32_t, *(o)) >> 0) & 7) + '0', \
495 (o)++)
496
497 protected const char *
file_getbuffer(struct magic_set * ms)498 file_getbuffer(struct magic_set *ms)
499 {
500 char *pbuf, *op, *np;
501 size_t psize, len;
502
503 if (ms->event_flags & EVENT_HAD_ERR)
504 return NULL;
505
506 if (ms->flags & MAGIC_RAW)
507 return ms->o.buf;
508
509 if (ms->o.buf == NULL)
510 return NULL;
511
512 /* * 4 is for octal representation, + 1 is for NUL */
513 len = strlen(ms->o.buf);
514 if (len > (SIZE_MAX - 1) / 4) {
515 file_oomem(ms, len);
516 return NULL;
517 }
518 psize = len * 4 + 1;
519 if ((pbuf = CAST(char *, erealloc(ms->o.pbuf, psize))) == NULL) {
520 file_oomem(ms, psize);
521 return NULL;
522 }
523 ms->o.pbuf = pbuf;
524
525 #if defined(HAVE_WCHAR_H) && defined(HAVE_MBRTOWC) && defined(HAVE_WCWIDTH)
526 {
527 mbstate_t state;
528 wchar_t nextchar;
529 int mb_conv = 1;
530 size_t bytesconsumed;
531 char *eop;
532 (void)memset(&state, 0, sizeof(mbstate_t));
533
534 np = ms->o.pbuf;
535 op = ms->o.buf;
536 eop = op + len;
537
538 while (op < eop) {
539 bytesconsumed = mbrtowc(&nextchar, op,
540 CAST(size_t, eop - op), &state);
541 if (bytesconsumed == CAST(size_t, -1) ||
542 bytesconsumed == CAST(size_t, -2)) {
543 mb_conv = 0;
544 break;
545 }
546
547 if (iswprint(nextchar)) {
548 (void)memcpy(np, op, bytesconsumed);
549 op += bytesconsumed;
550 np += bytesconsumed;
551 } else {
552 while (bytesconsumed-- > 0)
553 OCTALIFY(np, op);
554 }
555 }
556 *np = '\0';
557
558 /* Parsing succeeded as a multi-byte sequence */
559 if (mb_conv != 0)
560 return ms->o.pbuf;
561 }
562 #endif
563
564 for (np = ms->o.pbuf, op = ms->o.buf; *op;) {
565 if (isprint(CAST(unsigned char, *op))) {
566 *np++ = *op++;
567 } else {
568 OCTALIFY(np, op);
569 }
570 }
571 *np = '\0';
572 return ms->o.pbuf;
573 }
574
575 protected int
file_check_mem(struct magic_set * ms,unsigned int level)576 file_check_mem(struct magic_set *ms, unsigned int level)
577 {
578 size_t len;
579
580 if (level >= ms->c.len) {
581 len = (ms->c.len = 20 + level) * sizeof(*ms->c.li);
582 ms->c.li = CAST(struct level_info *, (ms->c.li == NULL) ?
583 emalloc(len) :
584 erealloc(ms->c.li, len));
585 if (ms->c.li == NULL) {
586 file_oomem(ms, len);
587 return -1;
588 }
589 }
590 ms->c.li[level].got_match = 0;
591 #ifdef ENABLE_CONDITIONALS
592 ms->c.li[level].last_match = 0;
593 ms->c.li[level].last_cond = COND_NONE;
594 #endif /* ENABLE_CONDITIONALS */
595 return 0;
596 }
597
598 protected size_t
file_printedlen(const struct magic_set * ms)599 file_printedlen(const struct magic_set *ms)
600 {
601 return ms->o.buf == NULL ? 0 : strlen(ms->o.buf);
602 }
603
604 protected int
file_replace(struct magic_set * ms,const char * pat,const char * rep)605 file_replace(struct magic_set *ms, const char *pat, const char *rep)
606 {
607 zend_string *pattern;
608 uint32_t opts = 0;
609 pcre_cache_entry *pce;
610 zend_string *res;
611 zend_string *repl;
612 size_t rep_cnt = 0;
613
614 opts |= PCRE2_MULTILINE;
615 pattern = convert_libmagic_pattern((char*)pat, strlen(pat), opts);
616 if ((pce = pcre_get_compiled_regex_cache_ex(pattern, 0)) == NULL) {
617 zend_string_release(pattern);
618 rep_cnt = -1;
619 goto out;
620 }
621 zend_string_release(pattern);
622
623 repl = zend_string_init(rep, strlen(rep), 0);
624 res = php_pcre_replace_impl(pce, NULL, ms->o.buf, strlen(ms->o.buf), repl, -1, &rep_cnt);
625
626 zend_string_release_ex(repl, 0);
627 if (NULL == res) {
628 rep_cnt = -1;
629 goto out;
630 }
631
632 strncpy(ms->o.buf, ZSTR_VAL(res), ZSTR_LEN(res));
633 ms->o.buf[ZSTR_LEN(res)] = '\0';
634
635 zend_string_release_ex(res, 0);
636
637 out:
638 return rep_cnt;
639 }
640
641 protected file_pushbuf_t *
file_push_buffer(struct magic_set * ms)642 file_push_buffer(struct magic_set *ms)
643 {
644 file_pushbuf_t *pb;
645
646 if (ms->event_flags & EVENT_HAD_ERR)
647 return NULL;
648
649 if ((pb = (CAST(file_pushbuf_t *, emalloc(sizeof(*pb))))) == NULL)
650 return NULL;
651
652 pb->buf = ms->o.buf;
653 pb->blen = ms->o.blen;
654 pb->offset = ms->offset;
655
656 ms->o.buf = NULL;
657 ms->o.blen = 0;
658 ms->offset = 0;
659
660 return pb;
661 }
662
663 protected char *
file_pop_buffer(struct magic_set * ms,file_pushbuf_t * pb)664 file_pop_buffer(struct magic_set *ms, file_pushbuf_t *pb)
665 {
666 char *rbuf;
667
668 if (ms->event_flags & EVENT_HAD_ERR) {
669 efree(pb->buf);
670 efree(pb);
671 return NULL;
672 }
673
674 rbuf = ms->o.buf;
675
676 ms->o.buf = pb->buf;
677 ms->o.blen = pb->blen;
678 ms->offset = pb->offset;
679
680 efree(pb);
681 return rbuf;
682 }
683
684 /*
685 * convert string to ascii printable format.
686 */
687 protected char *
file_printable(char * buf,size_t bufsiz,const char * str,size_t slen)688 file_printable(char *buf, size_t bufsiz, const char *str, size_t slen)
689 {
690 char *ptr, *eptr = buf + bufsiz - 1;
691 const unsigned char *s = RCAST(const unsigned char *, str);
692 const unsigned char *es = s + slen;
693
694 for (ptr = buf; ptr < eptr && s < es && *s; s++) {
695 if (isprint(*s)) {
696 *ptr++ = *s;
697 continue;
698 }
699 if (ptr >= eptr - 3)
700 break;
701 *ptr++ = '\\';
702 *ptr++ = ((CAST(unsigned int, *s) >> 6) & 7) + '0';
703 *ptr++ = ((CAST(unsigned int, *s) >> 3) & 7) + '0';
704 *ptr++ = ((CAST(unsigned int, *s) >> 0) & 7) + '0';
705 }
706 *ptr = '\0';
707 return buf;
708 }
709
710 struct guid {
711 uint32_t data1;
712 uint16_t data2;
713 uint16_t data3;
714 uint8_t data4[8];
715 };
716
717 protected int
file_parse_guid(const char * s,uint64_t * guid)718 file_parse_guid(const char *s, uint64_t *guid)
719 {
720 struct guid *g = CAST(struct guid *, guid);
721 return sscanf(s,
722 "%8x-%4hx-%4hx-%2hhx%2hhx-%2hhx%2hhx%2hhx%2hhx%2hhx%2hhx",
723 &g->data1, &g->data2, &g->data3, &g->data4[0], &g->data4[1],
724 &g->data4[2], &g->data4[3], &g->data4[4], &g->data4[5],
725 &g->data4[6], &g->data4[7]) == 11 ? 0 : -1;
726 }
727
728 protected int
file_print_guid(char * str,size_t len,const uint64_t * guid)729 file_print_guid(char *str, size_t len, const uint64_t *guid)
730 {
731 const struct guid *g = CAST(const struct guid *, guid);
732
733 return snprintf(str, len, "%.8X-%.4hX-%.4hX-%.2hhX%.2hhX-"
734 "%.2hhX%.2hhX%.2hhX%.2hhX%.2hhX%.2hhX",
735 g->data1, g->data2, g->data3, g->data4[0], g->data4[1],
736 g->data4[2], g->data4[3], g->data4[4], g->data4[5],
737 g->data4[6], g->data4[7]);
738 }
739