1 /*
2 * Copyright (c) 2007 Vreixo Formoso
3 * Copyright (c) 2007 Mario Danic
4 * Copyright (c) 2009 - 2019 Thomas Schmitt
5 *
6 * This file is part of the libisofs project; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License version 2
8 * or later as published by the Free Software Foundation.
9 * See COPYING file for details.
10 */
11
12 #ifdef HAVE_CONFIG_H
13 #include "../config.h"
14 #endif
15
16 #include "util.h"
17 #include "libisofs.h"
18 #include "messages.h"
19 #include "joliet.h"
20 #include "node.h"
21
22 #include <stdlib.h>
23 #include <wchar.h>
24 #include <string.h>
25 #include <errno.h>
26 #include <ctype.h>
27 #include <stdio.h>
28 #include <limits.h>
29 #include <iconv.h>
30 #include <locale.h>
31 #include <langinfo.h>
32
33 #include <unistd.h>
34
35 /* if we don't have eaccess, we check file access by opening it */
36 #ifndef HAVE_EACCESS
37 #include <sys/types.h>
38 #include <sys/stat.h>
39 #include <fcntl.h>
40 #endif
41
42
43 /* Produce possibly inflationary error messages directly to stderr */
44 static int iso_iconv_debug = 0;
45
46
47 struct iso_iconv_handle {
48 int status; /* bit0= open , bit1= identical mapping */
49 iconv_t descr;
50 };
51
52
53 /*
54 @param flag bit0= shortcut by identical mapping is not allowed
55 */
56 static
iso_iconv_open(struct iso_iconv_handle * handle,char * tocode,char * fromcode,int flag)57 int iso_iconv_open(struct iso_iconv_handle *handle,
58 char *tocode, char *fromcode, int flag)
59 {
60 handle->status = 0;
61 handle->descr = (iconv_t) -1;
62
63 if (strcmp(tocode, fromcode) == 0 && !(flag & 1)) {
64 handle->status = 1 | 2;
65 return 1;
66 }
67 handle->descr = iconv_open(tocode, fromcode);
68 if (handle->descr == (iconv_t) -1) {
69 if (strlen(tocode) + strlen(fromcode) <= 160 && iso_iconv_debug)
70 fprintf(stderr,
71 "libisofs_DEBUG: iconv_open(\"%s\", \"%s\") failed: errno= %d %s\n",
72 tocode, fromcode, errno, strerror(errno));
73 return 0;
74 }
75 handle->status = 1;
76 return 1;
77 }
78
79
80 static
iso_iconv(struct iso_iconv_handle * handle,char ** inbuf,size_t * inbytesleft,char ** outbuf,size_t * outbytesleft,int flag)81 size_t iso_iconv(struct iso_iconv_handle *handle,
82 char **inbuf, size_t *inbytesleft,
83 char **outbuf, size_t *outbytesleft, int flag)
84 {
85 size_t ret;
86 /* The build system might indicate iconv(,const char **inbuf,) by
87 defining ICONV_CONST const
88 */
89 #ifndef ICONV_CONST
90 #define ICONV_CONST
91 #endif
92 ICONV_CONST char **local_inbuf;
93
94 local_inbuf = (ICONV_CONST char **) inbuf;
95
96 if (!(handle->status & 1)) {
97 if (iso_iconv_debug)
98 fprintf(stderr,
99 "libisofs_DEBUG: iso_iconv(): iso_iconv_handle not in open state\n");
100 return (size_t) -1;
101 }
102 if (handle->status & 2) {
103 if (inbuf == NULL || outbuf == NULL) {
104 null_buf:;
105 if (iso_iconv_debug)
106 fprintf(stderr,
107 "libisofs_DEBUG: iso_iconv(): NULL buffers not allowed in shortcut mapping\n");
108 return (size_t) -1;
109 }
110 if (*inbuf == NULL || *outbuf == NULL)
111 goto null_buf;
112 while (*inbytesleft > 0 && *outbytesleft > 0) {
113 *((*outbuf)++) = *((*inbuf)++);
114 (*inbytesleft)--;
115 (*outbytesleft)--;
116 }
117 if (*inbytesleft > 0 && *outbytesleft <= 0)
118 return (size_t) -1;
119 return (size_t) 0;
120 }
121 ret = iconv(handle->descr, local_inbuf, inbytesleft, outbuf, outbytesleft);
122 if (ret == (size_t) -1) {
123 if (iso_iconv_debug)
124 fprintf(stderr, "libisofs_DEBUG: iconv() failed: errno= %d %s\n",
125 errno, strerror(errno));
126 return (size_t) -1;
127 }
128 return ret;
129 }
130
131
132 static
iso_iconv_close(struct iso_iconv_handle * handle,int flag)133 int iso_iconv_close(struct iso_iconv_handle *handle, int flag)
134 {
135 int ret;
136
137 if (!(handle->status & 1)) {
138 if (iso_iconv_debug)
139 fprintf(stderr,
140 "libisofs_DEBUG: iso_iconv_close(): iso_iconv_handle not in open state\n");
141 return -1;
142 }
143 handle->status &= ~1;
144 if (handle->status & 2)
145 return 0;
146
147 ret = iconv_close(handle->descr);
148 if (ret == -1) {
149 if (iso_iconv_debug)
150 fprintf(stderr,
151 "libisofs_DEBUG: iconv_close() failed: errno= %d %s\n",
152 errno, strerror(errno));
153 return -1;
154 }
155 return ret;
156 }
157
158
int_pow(int base,int power)159 int int_pow(int base, int power)
160 {
161 int result = 1;
162 while (--power >= 0) {
163 result *= base;
164 }
165 return result;
166 }
167
168 /* This static variable can override the locale's charset by its getter
169 function which should be used whenever the local character set name
170 is to be inquired. I.e. instead of calling nl_langinfo(CODESET) directly.
171 If the variable is empty then it forwards nl_langinfo(CODESET).
172 */
173 static char libisofs_local_charset[4096]= {""};
174
175 /* API function */
iso_set_local_charset(char * name,int flag)176 int iso_set_local_charset(char *name, int flag)
177 {
178 if(strlen(name) >= sizeof(libisofs_local_charset))
179 return(0);
180 strcpy(libisofs_local_charset, name);
181 return 1;
182 }
183
184 /* API function */
iso_get_local_charset(int flag)185 char *iso_get_local_charset(int flag)
186 {
187 if(libisofs_local_charset[0])
188 return libisofs_local_charset;
189 return nl_langinfo(CODESET);
190 }
191
strconv(const char * str,const char * icharset,const char * ocharset,char ** output)192 int strconv(const char *str, const char *icharset, const char *ocharset,
193 char **output)
194 {
195 size_t inbytes;
196 size_t outbytes;
197 size_t n;
198 struct iso_iconv_handle conv;
199 int conv_ret;
200
201 char *out = NULL;
202 char *src;
203 char *ret;
204 int retval;
205
206 inbytes = strlen(str);
207 outbytes = (inbytes + 1) * MB_LEN_MAX;
208 out = calloc(outbytes, 1);
209 if (out == NULL) {
210 retval = ISO_OUT_OF_MEM;
211 goto ex;
212 }
213
214 conv_ret = iso_iconv_open(&conv, (char *) ocharset, (char *) icharset, 0);
215 if (conv_ret <= 0) {
216 retval = ISO_CHARSET_CONV_ERROR;
217 goto ex;
218 }
219 src = (char *)str;
220 ret = (char *)out;
221 n = iso_iconv(&conv, &src, &inbytes, &ret, &outbytes, 0);
222 if (n == (size_t) -1) {
223 /* error */
224 iso_iconv_close(&conv, 0);
225 retval = ISO_CHARSET_CONV_ERROR;
226 goto ex;
227 }
228 *ret = '\0';
229 iso_iconv_close(&conv, 0);
230
231 *output = malloc(ret - out + 1);
232 if (*output == NULL) {
233 retval = ISO_OUT_OF_MEM;
234 goto ex;
235 }
236 memcpy(*output, out, ret - out + 1);
237 retval = ISO_SUCCESS;
238 ex:;
239 if (out != NULL)
240 free(out);
241 return retval;
242 }
243
strnconvl(const char * str,const char * icharset,const char * ocharset,size_t len,char ** output,size_t * out_len)244 int strnconvl(const char *str, const char *icharset, const char *ocharset,
245 size_t len, char **output, size_t *out_len)
246 {
247 size_t inbytes;
248 size_t outbytes;
249 size_t n;
250 struct iso_iconv_handle conv;
251 int conv_ret;
252 char *out = NULL;
253 char *src;
254 char *ret;
255 int retval;
256
257 inbytes = len;
258 outbytes = (inbytes + 1) * MB_LEN_MAX;
259 out = calloc(outbytes, 1);
260 if (out == NULL) {
261 retval = ISO_OUT_OF_MEM;
262 goto ex;
263 }
264 conv_ret = iso_iconv_open(&conv, (char *) ocharset, (char *) icharset, 0);
265 if (conv_ret <= 0) {
266 retval = ISO_CHARSET_CONV_ERROR;
267 goto ex;
268 }
269 src = (char *)str;
270 ret = (char *)out;
271 n = iso_iconv(&conv, &src, &inbytes, &ret, &outbytes, 0);
272 if (n == (size_t) -1) {
273 /* error */
274 iso_iconv_close(&conv, 0);
275 retval = ISO_CHARSET_CONV_ERROR;
276 goto ex;
277 }
278 *ret = '\0';
279 iso_iconv_close(&conv, 0);
280
281 *out_len = ret - out;
282 *output = malloc(*out_len + 1);
283 if (*output == NULL) {
284 retval = ISO_OUT_OF_MEM;
285 goto ex;
286 }
287 memcpy(*output, out, ret - out + 1);
288 retval = ISO_SUCCESS;
289 ex:;
290 if (out != NULL)
291 free(out);
292 return retval;
293 }
294
strnconv(const char * str,const char * icharset,const char * ocharset,size_t len,char ** output)295 int strnconv(const char *str, const char *icharset, const char *ocharset,
296 size_t len, char **output)
297 {
298 size_t l;
299
300 return strnconvl(str, icharset, ocharset, len, output, &l);
301 }
302
303
304 /**
305 * Convert a str in a specified codeset to WCHAR_T.
306 * The result must be free() when no more needed
307 *
308 * @return
309 * 1 success, < 0 error
310 */
311 static
str2wchar(const char * icharset,const char * input,wchar_t ** output)312 int str2wchar(const char *icharset, const char *input, wchar_t **output)
313 {
314 struct iso_iconv_handle conv;
315 int conv_ret;
316
317 /* That while loop smells like a potential show stopper */
318 size_t loop_counter = 0, loop_limit = 3;
319
320 size_t inbytes;
321 size_t outbytes;
322 char *ret;
323 char *src;
324 wchar_t *wstr;
325 size_t n;
326
327 if (icharset == NULL || input == NULL || output == NULL) {
328 return ISO_NULL_POINTER;
329 }
330
331 conv_ret = iso_iconv_open(&conv, "WCHAR_T", (char *) icharset, 0);
332 if (conv_ret <= 0) {
333 return ISO_CHARSET_CONV_ERROR;
334 }
335
336 inbytes = strlen(input);
337 loop_limit = inbytes + 3;
338 outbytes = (inbytes + 1) * sizeof(wchar_t);
339
340 /* we are sure that numchars <= inbytes */
341 wstr = malloc(outbytes);
342 if (wstr == NULL) {
343 return ISO_OUT_OF_MEM;
344 }
345 ret = (char *)wstr;
346 src = (char *)input;
347
348 n = iso_iconv(&conv, &src, &inbytes, &ret, &outbytes, 0);
349 while (n == (size_t) -1) {
350
351 if (errno == E2BIG) {
352 /* error, should never occur */
353 goto conv_error;
354 } else {
355 wchar_t *wret;
356
357 /*
358 * Invalid input string charset.
359 * This can happen if input is in fact encoded in a charset
360 * different than icharset.
361 * We can't do anything better than replace by "_" and continue.
362 */
363 inbytes--;
364 src++;
365
366 wret = (wchar_t*) ret;
367 *wret++ = (wchar_t) '_';
368 ret = (char *) wret;
369 outbytes -= sizeof(wchar_t);
370
371 if (!inbytes)
372 break;
373
374 /* Just to appease my remorse about unclear loop ends */
375 loop_counter++;
376 if (loop_counter > loop_limit)
377 goto conv_error;
378 n = iso_iconv(&conv, &src, &inbytes, &ret, &outbytes, 0);
379 }
380 }
381 iso_iconv_close(&conv, 0);
382 *( (wchar_t *)ret )='\0';
383 *output = wstr;
384 return ISO_SUCCESS;
385
386 conv_error:;
387 iso_iconv_close(&conv, 0);
388 free(wstr);
389 return ISO_CHARSET_CONV_ERROR;
390 }
391
str2ascii(const char * icharset,const char * input,char ** output)392 int str2ascii(const char *icharset, const char *input, char **output)
393 {
394 int result;
395 wchar_t *wsrc_ = NULL;
396 char *ret = NULL;
397 char *ret_ = NULL;
398 char *src;
399 struct iso_iconv_handle conv;
400 int conv_ret;
401 int direct_conv = 0;
402
403 /* That while loop smells like a potential show stopper */
404 size_t loop_counter = 0, loop_limit = 3;
405
406 /* Fallback in case that iconv() is too demanding for system */
407 unsigned char *cpt;
408
409 size_t numchars;
410 size_t outbytes;
411 size_t inbytes;
412 size_t n;
413
414
415 if (icharset == NULL || input == NULL || output == NULL) {
416 return ISO_NULL_POINTER;
417 }
418
419 /* First try the traditional way via intermediate character set WCHAR_T.
420 * Up to August 2011 this was the only way. But it will not work if
421 * there is no character set "WCHAR_T". E.g. on Solaris.
422 */
423 /* convert the string to a wide character string. Note: outbytes
424 * is in fact the number of characters in the string and doesn't
425 * include the last NULL character.
426 */
427 conv_ret = 0;
428 result = str2wchar(icharset, input, &wsrc_);
429 if (result == (int) ISO_SUCCESS) {
430 src = (char *)wsrc_;
431 numchars = wcslen(wsrc_);
432
433 inbytes = numchars * sizeof(wchar_t);
434 loop_limit = inbytes + 3;
435
436 ret_ = malloc(numchars + 1);
437 if (ret_ == NULL) {
438 free(wsrc_);
439 return ISO_OUT_OF_MEM;
440 }
441 outbytes = numchars;
442 ret = ret_;
443
444 /* initialize iconv */
445 conv_ret = iso_iconv_open(&conv, "ASCII", "WCHAR_T", 0);
446 if (conv_ret <= 0) {
447 free(wsrc_);
448 wsrc_ = NULL;
449 free(ret_);
450 ret = ret_ = NULL;
451 }
452 } else if (result != (int) ISO_CHARSET_CONV_ERROR)
453 return result;
454
455 /* If this did not succeed : Try the untraditional direct conversion.
456 */
457 if (conv_ret <= 0) {
458 conv_ret = iso_iconv_open(&conv, "ASCII", (char *) icharset, 0);
459 if (conv_ret <= 0)
460 goto fallback;
461 direct_conv = 1;
462 src = (char *) input;
463 inbytes = strlen(input);
464 loop_limit = inbytes + 3;
465 outbytes = (inbytes + 1) * sizeof(uint16_t);
466 ret_ = malloc(outbytes);
467 if (ret_ == NULL)
468 return ISO_OUT_OF_MEM;
469 ret = ret_;
470 }
471
472 n = iso_iconv(&conv, &src, &inbytes, &ret, &outbytes, 0);
473 while (n == (size_t) -1) {
474 /* The destination buffer is too small. Stops here. */
475 if (errno == E2BIG)
476 break;
477
478 /* An incomplete multi bytes sequence was found. We
479 * can't do anything here. That's quite unlikely. */
480 if (errno == EINVAL)
481 break;
482
483 /* The last possible error is an invalid multi bytes
484 * sequence. Just replace the character with a "_".
485 * Probably the character doesn't exist in ascii like
486 * "é, è, à, ç, ..." in French. */
487 *ret++ = '_';
488 outbytes--;
489
490 if (!outbytes)
491 break;
492
493 /* There was an error with one character but some other remain
494 * to be converted. That's probably a multibyte character.
495 * See above comment. */
496 if (direct_conv) {
497 src++;
498 inbytes--;
499 } else {
500 src += sizeof(wchar_t);
501 inbytes -= sizeof(wchar_t);
502 }
503
504 if (!inbytes)
505 break;
506
507 /* Just to appease my remorse about unclear loop ends */
508 loop_counter++;
509 if (loop_counter > loop_limit)
510 break;
511 n = iso_iconv(&conv, &src, &inbytes, &ret, &outbytes, 0);
512 }
513 iso_iconv_close(&conv, 0);
514 *ret = 0;
515 if (wsrc_ != NULL)
516 free(wsrc_);
517
518 *output = ret_;
519 return ISO_SUCCESS;
520
521 fallback:;
522 /* Assume to have a single byte charset with ASCII as core.
523 Anything suspicious will be mapped to '_'.
524 */
525 *output = strdup(input);
526 for (cpt = (unsigned char *) *output; *cpt; cpt++) {
527 if (*cpt < 32 || *cpt > 126)
528 *cpt = '_';
529 }
530 return ISO_SUCCESS;
531 }
532
533 static
set_ucsbe(uint16_t * ucs,char c)534 void set_ucsbe(uint16_t *ucs, char c)
535 {
536 char *v = (char*)ucs;
537 v[0] = (char)0;
538 v[1] = c;
539 }
540
541 /**
542 * @return
543 * -1, 0, 1 if *ucs <, == or > than c
544 */
545 static
cmp_ucsbe(const uint16_t * ucs,char c)546 int cmp_ucsbe(const uint16_t *ucs, char c)
547 {
548 char *v = (char*)ucs;
549 if (v[0] != 0) {
550 return 1;
551 } else if (v[1] == c) {
552 return 0;
553 } else {
554 return (uint8_t)c > (uint8_t)v[1] ? -1 : 1;
555 }
556 }
557
str2ucs(const char * icharset,const char * input,uint16_t ** output)558 int str2ucs(const char *icharset, const char *input, uint16_t **output)
559 {
560 int result;
561 wchar_t *wsrc_ = NULL;
562 char *src;
563 char *ret = NULL;
564 char *ret_ = NULL;
565 struct iso_iconv_handle conv;
566 int conv_ret = 0;
567 int direct_conv = 0;
568
569 /* That while loop smells like a potential show stopper */
570 size_t loop_counter = 0, loop_limit = 3;
571
572 size_t numchars;
573 size_t outbytes;
574 size_t inbytes;
575 size_t n;
576
577 if (icharset == NULL || input == NULL || output == NULL) {
578 return ISO_NULL_POINTER;
579 }
580
581 /* convert the string to a wide character string. Note: outbytes
582 * is in fact the number of characters in the string and doesn't
583 * include the last NULL character.
584 */
585 /* First try the traditional way via intermediate character set WCHAR_T.
586 * Up to August 2011 this was the only way. But it will not work if
587 * there is no character set "WCHAR_T". E.g. on Solaris.
588 */
589 conv_ret = 0;
590 result = str2wchar(icharset, input, &wsrc_);
591 if (result == (int) ISO_SUCCESS) {
592 src = (char *)wsrc_;
593 numchars = wcslen(wsrc_);
594
595 inbytes = numchars * sizeof(wchar_t);
596 loop_limit = inbytes + 3;
597
598 ret_ = malloc((numchars+1) * sizeof(uint16_t));
599 if (ret_ == NULL) {
600 free(wsrc_);
601 return ISO_OUT_OF_MEM;
602 }
603 outbytes = numchars * sizeof(uint16_t);
604 ret = ret_;
605
606 /* initialize iconv */
607 conv_ret = iso_iconv_open(&conv, "UCS-2BE", "WCHAR_T", 0);
608 if (conv_ret <= 0) {
609 free(wsrc_);
610 wsrc_ = NULL;
611 free(ret_);
612 ret = ret_ = NULL;
613 }
614 } else if (result != (int) ISO_CHARSET_CONV_ERROR)
615 return result;
616
617 /* If this did not succeed : Try the untraditional direct conversion.
618 */
619 if (conv_ret <= 0) {
620 conv_ret = iso_iconv_open(&conv, "UCS-2BE", (char *) icharset, 0);
621 if (conv_ret <= 0) {
622 return ISO_CHARSET_CONV_ERROR;
623 }
624 direct_conv = 1;
625 src = (char *) input;
626 inbytes = strlen(input);
627 loop_limit = inbytes + 3;
628 outbytes = (inbytes + 1) * sizeof(uint16_t);
629 ret_ = malloc(outbytes);
630 if (ret_ == NULL)
631 return ISO_OUT_OF_MEM;
632 ret = ret_;
633 }
634
635 n = iso_iconv(&conv, &src, &inbytes, &ret, &outbytes, 0);
636 while (n == (size_t) -1) {
637 /* The destination buffer is too small. Stops here. */
638 if (errno == E2BIG)
639 break;
640
641 /* An incomplete multi bytes sequence was found. We
642 * can't do anything here. That's quite unlikely. */
643 if (errno == EINVAL)
644 break;
645
646 /* The last possible error is an invalid multi bytes
647 * sequence. Just replace the character with a "_".
648 * Probably the character doesn't exist in UCS */
649 set_ucsbe((uint16_t*) ret, '_');
650 ret += sizeof(uint16_t);
651 outbytes -= sizeof(uint16_t);
652
653 if (!outbytes)
654 break;
655
656 /* There was an error with one character but some other remain
657 * to be converted. That's probably a multibyte character.
658 * See above comment. */
659 if (direct_conv) {
660 src++;
661 inbytes--;
662 } else {
663 src += sizeof(wchar_t);
664 inbytes -= sizeof(wchar_t);
665 }
666
667 if (!inbytes)
668 break;
669
670 /* Just to appease my remorse about unclear loop ends */
671 loop_counter++;
672 if (loop_counter > loop_limit)
673 break;
674 n = iso_iconv(&conv, &src, &inbytes, &ret, &outbytes, 0);
675 }
676 iso_iconv_close(&conv, 0);
677
678 /* close the ucs string */
679 set_ucsbe((uint16_t*) ret, '\0');
680 if (wsrc_ != NULL)
681 free(wsrc_);
682
683 *output = (uint16_t*)ret_;
684 return ISO_SUCCESS;
685 }
686
str2utf16be(const char * icharset,const char * input,uint16_t ** output)687 int str2utf16be(const char *icharset, const char *input, uint16_t **output)
688 {
689 int result;
690 wchar_t *wsrc_ = NULL;
691 char *src;
692 char *ret = NULL;
693 char *ret_ = NULL;
694 struct iso_iconv_handle conv;
695 int conv_ret = 0;
696 int direct_conv = 0;
697 size_t loop_counter = 0, loop_limit = 3;
698 size_t numchars;
699 size_t outbytes;
700 size_t inbytes;
701 size_t n;
702
703 if (icharset == NULL || input == NULL || output == NULL) {
704 return ISO_NULL_POINTER;
705 }
706
707 /*
708 Try the direct conversion.
709 */
710 conv_ret = iso_iconv_open(&conv, "UTF-16BE", (char *) icharset, 0);
711 if (conv_ret > 0) {
712 direct_conv = 1;
713 src = (char *) input;
714 inbytes = strlen(input);
715 loop_limit = inbytes + 3;
716 outbytes = (2 * inbytes + 1) * sizeof(uint16_t);
717 ret_ = malloc(outbytes);
718 if (ret_ == NULL)
719 return ISO_OUT_OF_MEM;
720 ret = ret_;
721 } else {
722 /* Try via intermediate character set WCHAR_T.
723 */
724 result = str2wchar(icharset, input, &wsrc_);
725 if (result == (int) ISO_SUCCESS) {
726 src = (char *)wsrc_;
727 numchars = wcslen(wsrc_);
728
729 inbytes = numchars * sizeof(wchar_t);
730 loop_limit = inbytes + 3;
731
732 ret_ = malloc((2 * numchars+1) * sizeof(uint16_t));
733 if (ret_ == NULL) {
734 free(wsrc_);
735 return ISO_OUT_OF_MEM;
736 }
737 outbytes = 2 * numchars * sizeof(uint16_t);
738 ret = ret_;
739
740 /* initialize iconv */
741 conv_ret = iso_iconv_open(&conv, "UTF-16BE", "WCHAR_T", 0);
742 if (conv_ret <= 0) {
743 free(wsrc_);
744 free(ret_);
745 }
746 } else if (result != (int) ISO_CHARSET_CONV_ERROR)
747 return result;
748 }
749
750 if (conv_ret <= 0) {
751 return ISO_CHARSET_CONV_ERROR;
752 }
753
754 n = iso_iconv(&conv, &src, &inbytes, &ret, &outbytes, 0);
755 while (n == (size_t) -1) {
756 /* The destination buffer is too small. Stops here. */
757 if (errno == E2BIG)
758 break;
759
760 /* An incomplete multi bytes sequence was found. We
761 * can't do anything here. That's quite unlikely. */
762 if (errno == EINVAL)
763 break;
764
765 /* The last possible error is an invalid multi bytes
766 * sequence. Just replace the character with a "_".
767 * Probably the character doesn't exist in UCS */
768 set_ucsbe((uint16_t*) ret, '_');
769 ret += sizeof(uint16_t);
770 outbytes -= sizeof(uint16_t);
771
772 if (!outbytes)
773 break;
774
775 /* There was an error with one character but some other remain
776 * to be converted. That's probably a multibyte character.
777 * See above comment. */
778 if (direct_conv) {
779 src++;
780 inbytes--;
781 } else {
782 src += sizeof(wchar_t);
783 inbytes -= sizeof(wchar_t);
784 }
785
786 if (!inbytes)
787 break;
788
789 /* Just to appease my remorse about unclear loop ends */
790 loop_counter++;
791 if (loop_counter > loop_limit)
792 break;
793 n = iso_iconv(&conv, &src, &inbytes, &ret, &outbytes, 0);
794 }
795 iso_iconv_close(&conv, 0);
796
797 /* close the UTF-16 string */
798 set_ucsbe((uint16_t*) ret, '\0');
799 if (wsrc_ != NULL)
800 free(wsrc_);
801
802 *output = (uint16_t*)ret_;
803 return ISO_SUCCESS;
804 }
805
valid_d_char(char c)806 static int valid_d_char(char c)
807 {
808 return (c >= '0' && c <= '9') || (c >= 'A' && c <= 'Z') || (c == '_');
809 }
810
valid_a_char(char c)811 static int valid_a_char(char c)
812 {
813 return (c >= ' ' && c <= '"') || (c >= '%' && c <= '?') ||
814 (c >= 'A' && c <= 'Z') || (c == '_');
815 }
816
valid_j_char(uint16_t c)817 static int valid_j_char(uint16_t c)
818 {
819 return cmp_ucsbe(&c, ' ') != -1 && cmp_ucsbe(&c, '*') && cmp_ucsbe(&c, '/')
820 && cmp_ucsbe(&c, ':') && cmp_ucsbe(&c, ';') && cmp_ucsbe(&c, '?')
821 && cmp_ucsbe(&c, '\\');
822 }
823
824 /* @param relaxed bit0+1 0= strict ECMA-119
825 1= additionally allow lowercase (else map to upper)
826 2= allow all 8-bit characters
827 bit2 allow all 7-bit characters (but map to upper if
828 not bit0+1 == 2)
829 */
map_fileid_char(char c,int relaxed)830 static char map_fileid_char(char c, int relaxed)
831 {
832 char upper;
833
834 if (c == '/') /* Allowing slashes would cause lots of confusion */
835 return '_';
836 if ((relaxed & 3) == 2)
837 return c;
838 if (valid_d_char(c))
839 return c;
840 if ((relaxed & 4) && (c & 0x7f) == c && (c < 'a' || c > 'z'))
841 return c;
842 upper= toupper(c);
843 if (valid_d_char(upper)) {
844 if (relaxed & 3) {
845 /* lower chars are allowed */
846 return c;
847 }
848 return upper;
849 }
850 return '_';
851 }
852
853 static
iso_dirid(const char * src,int size,int relaxed)854 char *iso_dirid(const char *src, int size, int relaxed)
855 {
856 size_t len, i;
857 char name[32];
858
859 len = strlen(src);
860 if ((int) len > size) {
861 len = size;
862 }
863 for (i = 0; i < len; i++) {
864
865 #ifdef Libisofs_old_ecma119_nameS
866
867 char c= toupper(src[i]);
868 name[i] = valid_d_char(c) ? c : '_';
869
870 #else /* Libisofs_old_ecma119_nameS */
871
872 name[i] = map_fileid_char(src[i], relaxed);
873
874 #endif /* ! Libisofs_old_ecma119_nameS */
875
876 }
877
878 name[len] = '\0';
879 return strdup(name);
880 }
881
iso_1_dirid(const char * src,int relaxed)882 char *iso_1_dirid(const char *src, int relaxed)
883 {
884 return iso_dirid(src, 8, relaxed);
885 }
886
iso_2_dirid(const char * src)887 char *iso_2_dirid(const char *src)
888 {
889 return iso_dirid(src, 31, 0);
890 }
891
iso_1_fileid(const char * src,int relaxed,int force_dots)892 char *iso_1_fileid(const char *src, int relaxed, int force_dots)
893 {
894 char *dot; /* Position of the last dot in the filename, will be used
895 * to calculate lname and lext. */
896 int lname, lext, pos, i;
897 char dest[13]; /* 13 = 8 (name) + 1 (.) + 3 (ext) + 1 (\0) */
898
899 if (src == NULL) {
900 return NULL;
901 }
902 dot = strrchr(src, '.');
903 if (dot == src && strlen(src) > 4)
904 dot = NULL; /* Use the long extension instead of the empty name */
905 lext = dot ? strlen(dot + 1) : 0;
906 lname = strlen(src) - lext - (dot ? 1 : 0);
907
908 /* If we can't build a filename, return NULL. */
909 if (lname == 0 && lext == 0) {
910 return NULL;
911 }
912
913 pos = 0;
914
915 /* Convert up to 8 characters of the filename. */
916 for (i = 0; i < lname && i < 8; i++) {
917
918 #ifdef Libisofs_old_ecma119_nameS
919
920 char c= toupper(src[i]);
921
922 dest[pos++] = valid_d_char(c) ? c : '_';
923
924 #else /* Libisofs_old_ecma119_nameS */
925
926 if (dot == NULL && src[i] == '.')
927 dest[pos++] = '_'; /* make sure that ignored dots do not appear */
928 else
929 dest[pos++] = map_fileid_char(src[i], relaxed);
930
931 #endif /* ! Libisofs_old_ecma119_nameS */
932
933 }
934
935 /* This dot is mandatory, even if there is no extension. */
936 if (force_dots || lext > 0)
937 dest[pos++] = '.';
938
939 /* Convert up to 3 characters of the extension, if any. */
940 for (i = 0; i < lext && i < 3; i++) {
941
942 #ifdef Libisofs_old_ecma119_nameS
943
944 char c= toupper(src[lname + 1 + i]);
945
946 dest[pos++] = valid_d_char(c) ? c : '_';
947
948 #else /* Libisofs_old_ecma119_nameS */
949
950 dest[pos++] = map_fileid_char(src[lname + 1 + i], relaxed);
951
952 #endif /* ! Libisofs_old_ecma119_nameS */
953
954 }
955
956 dest[pos] = '\0';
957 return strdup(dest);
958 }
959
iso_2_fileid(const char * src)960 char *iso_2_fileid(const char *src)
961 {
962 char *dot;
963 int lname, lext, lnname, lnext, pos, i;
964 char dest[32]; /* 32 = 30 (name + ext) + 1 (.) + 1 (\0) */
965
966 if (src == NULL) {
967 return NULL;
968 }
969
970 dot = strrchr(src, '.');
971
972 /*
973 * Since the maximum length can be divided freely over the name and
974 * extension, we need to calculate their new lengths (lnname and
975 * lnext). If the original filename is too long, we start by trimming
976 * the extension, but keep a minimum extension length of 3.
977 */
978 if (dot == NULL || *(dot + 1) == '\0') {
979 lname = strlen(src);
980 lnname = (lname > 30) ? 30 : lname;
981 lext = lnext = 0;
982 } else {
983 lext = strlen(dot + 1);
984 lname = strlen(src) - lext - 1;
985 lnext = (strlen(src) > 31 && lext > 3) ? (lname < 27 ? 30 - lname : 3)
986 : lext;
987 lnname = (strlen(src) > 31) ? 30 - lnext : lname;
988 }
989
990 if (lnname == 0 && lnext == 0) {
991 return NULL;
992 }
993
994 pos = 0;
995
996 /* Convert up to lnname characters of the filename. */
997 for (i = 0; i < lnname; i++) {
998 char c= toupper(src[i]);
999
1000 dest[pos++] = valid_d_char(c) ? c : '_';
1001 }
1002 dest[pos++] = '.';
1003
1004 /* Convert up to lnext characters of the extension, if any. */
1005 for (i = 0; i < lnext; i++) {
1006 char c= toupper(src[lname + 1 + i]);
1007
1008 dest[pos++] = valid_d_char(c) ? c : '_';
1009 }
1010 dest[pos] = '\0';
1011 return strdup(dest);
1012 }
1013
1014 /**
1015 * Create a dir name suitable for an ISO image with relaxed constraints.
1016 *
1017 * @param size
1018 * Max len for the name
1019 * @param relaxed
1020 * bit0+1: 0 only allow d-characters,
1021 * 1 allow also lowe case chars,
1022 * 2 allow all 8-bit characters,
1023 * bit2: allow 7-bit characters (but map lowercase to uppercase if
1024 * not bit0+1 == 2)
1025 */
iso_r_dirid(const char * src,int size,int relaxed)1026 char *iso_r_dirid(const char *src, int size, int relaxed)
1027 {
1028 size_t len, i;
1029 char *dest;
1030
1031 len = strlen(src);
1032 if ((int) len > size) {
1033 len = size;
1034 }
1035 dest = malloc(len + 1);
1036 if (dest == NULL)
1037 return NULL;
1038 for (i = 0; i < len; i++) {
1039
1040 #ifdef Libisofs_old_ecma119_nameS
1041
1042 char c= src[i];
1043 if (relaxed == 2) {
1044 /* all chars are allowed */
1045 dest[i] = c;
1046 } else if (valid_d_char(c)) {
1047 /* it is a valid char */
1048 dest[i] = c;
1049 } else {
1050 c= toupper(src[i]);
1051 if (valid_d_char(c)) {
1052 if (relaxed) {
1053 /* lower chars are allowed */
1054 dest[i] = src[i];
1055 } else {
1056 dest[i] = c;
1057 }
1058 } else {
1059 dest[i] = '_';
1060 }
1061 }
1062
1063 #else /* Libisofs_old_ecma119_nameS */
1064
1065 dest[i] = map_fileid_char(src[i], relaxed);
1066
1067 #endif /* ! Libisofs_old_ecma119_nameS */
1068
1069 }
1070
1071 dest[len] = '\0';
1072 return dest;
1073 }
1074
1075 /**
1076 * Create a file name suitable for an ISO image with level > 1 and
1077 * with relaxed constraints.
1078 *
1079 * @param len
1080 * Max len for the name, without taken the "." into account.
1081 * @param relaxed
1082 * bit0+1: 0 only allow d-characters,
1083 * 1 allow also lowe case chars,
1084 * 2 allow all 8-bit characters,
1085 * bit2: allow 7-bit characters (but map lowercase to uppercase if
1086 * not bit0+1 == 2)
1087 * @param forcedot
1088 * Whether to ensure that "." is added
1089 */
iso_r_fileid(const char * src,size_t len,int relaxed,int forcedot)1090 char *iso_r_fileid(const char *src, size_t len, int relaxed, int forcedot)
1091 {
1092 char *dot, *retval = NULL;
1093 int lname, lext, lnname, lnext, pos, i;
1094 char *dest = NULL;
1095
1096 dest = calloc(len + 1 + 1, 1);
1097 if (dest == NULL)
1098 goto ex;
1099
1100 if (src == NULL) {
1101 goto ex;
1102 }
1103
1104 dot = strrchr(src, '.');
1105
1106 /*
1107 * Since the maximum length can be divided freely over the name and
1108 * extension, we need to calculate their new lengths (lnname and
1109 * lnext). If the original filename is too long, we start by trimming
1110 * the extension, but keep a minimum extension length of 3.
1111 */
1112 if (dot == NULL || *(dot + 1) == '\0') {
1113 lname = strlen(src);
1114 lnname = (lname > (int) len) ? (int) len : lname;
1115 lext = lnext = 0;
1116 } else {
1117 lext = strlen(dot + 1);
1118 lname = strlen(src) - lext - 1;
1119 lnext = (strlen(src) > len + 1 && lext > 3) ?
1120 (lname < (int) len - 3 ? (int) len - lname : 3)
1121 : lext;
1122 lnname = (strlen(src) > len + 1) ? (int) len - lnext : lname;
1123 }
1124
1125 if (lnname == 0 && lnext == 0) {
1126 goto ex;
1127 }
1128
1129 pos = 0;
1130
1131 /* Convert up to lnname characters of the filename. */
1132 for (i = 0; i < lnname; i++) {
1133
1134 #ifdef Libisofs_old_ecma119_nameS
1135
1136 char c= src[i];
1137 if (relaxed == 2) {
1138 /* all chars are allowed */
1139 dest[pos++] = c;
1140 } else if (valid_d_char(c)) {
1141 /* it is a valid char */
1142 dest[pos++] = c;
1143 } else {
1144 c= toupper(src[i]);
1145 if (valid_d_char(c)) {
1146 if (relaxed) {
1147 /* lower chars are allowed */
1148 dest[pos++] = src[i];
1149 } else {
1150 dest[pos++] = c;
1151 }
1152 } else {
1153 dest[pos++] = '_';
1154 }
1155 }
1156
1157 #else /* Libisofs_old_ecma119_nameS */
1158
1159 dest[pos++] = map_fileid_char(src[i], relaxed);
1160
1161 #endif /* ! Libisofs_old_ecma119_nameS */
1162
1163 }
1164 if (lnext > 0 || forcedot) {
1165 dest[pos++] = '.';
1166 }
1167
1168 /* Convert up to lnext characters of the extension, if any. */
1169 for (i = lname + 1; i < lname + 1 + lnext; i++) {
1170
1171 #ifdef Libisofs_old_ecma119_nameS
1172
1173 char c= src[i];
1174 if (relaxed == 2) {
1175 /* all chars are allowed */
1176 dest[pos++] = c;
1177 } else if (valid_d_char(c)) {
1178 /* it is a valid char */
1179 dest[pos++] = c;
1180 } else {
1181 c= toupper(src[i]);
1182 if (valid_d_char(c)) {
1183 if (relaxed) {
1184 /* lower chars are allowed */
1185 dest[pos++] = src[i];
1186 } else {
1187 dest[pos++] = c;
1188 }
1189 } else {
1190 dest[pos++] = '_';
1191 }
1192 }
1193
1194 #else /* Libisofs_old_ecma119_nameS */
1195
1196 dest[pos++] = map_fileid_char(src[i], relaxed);
1197
1198 #endif /* ! Libisofs_old_ecma119_nameS */
1199
1200 }
1201 dest[pos] = '\0';
1202
1203 retval = strdup(dest);
1204
1205 ex:;
1206 if (dest != NULL)
1207 free(dest);
1208 return retval;
1209 }
1210
1211 /*
1212 bit0= no_force_dots
1213 bit1= allow 103 characters rather than 64
1214 */
iso_j_file_id(const uint16_t * src,int flag)1215 uint16_t *iso_j_file_id(const uint16_t *src, int flag)
1216 {
1217 uint16_t *dot, *retval = NULL;
1218 size_t lname, lext, lnname, lnext, pos, i, maxchar = 64;
1219 uint16_t *dest = NULL, c;
1220
1221 LIBISO_ALLOC_MEM_VOID(dest, uint16_t, LIBISO_JOLIET_NAME_MAX);
1222 /* was: 66 = 64 (name + ext) + 1 (.) + 1 (\0) */
1223
1224 if (src == NULL) {
1225 goto ex;
1226 }
1227 if (flag & 2)
1228 maxchar = 103;
1229
1230 dot = ucsrchr(src, '.');
1231
1232 /*
1233 * Since the maximum length can be divided freely over the name and
1234 * extension, we need to calculate their new lengths (lnname and
1235 * lnext). If the original filename is too long, we start by trimming
1236 * the extension, but keep a minimum extension length of 3.
1237 */
1238 if (dot == NULL || cmp_ucsbe(dot + 1, '\0') == 0) {
1239 lname = ucslen(src);
1240 lnname = (lname > maxchar) ? maxchar : lname;
1241 lext = lnext = 0;
1242 } else {
1243 lext = ucslen(dot + 1);
1244 lname = ucslen(src) - lext - 1;
1245 lnext = (ucslen(src) > maxchar + 1 && lext > 3)
1246 ? (lname < maxchar - 3 ? maxchar - lname : 3)
1247 : lext;
1248 lnname = (ucslen(src) > maxchar + 1) ? maxchar - lnext : lname;
1249 }
1250
1251 if (lnname == 0 && lnext == 0) {
1252 goto ex;
1253 }
1254
1255 pos = 0;
1256
1257 /* Convert up to lnname characters of the filename. */
1258 for (i = 0; i < lnname; i++) {
1259 c = src[i];
1260 if (valid_j_char(c)) {
1261 dest[pos++] = c;
1262 } else {
1263 set_ucsbe(dest + pos, '_');
1264 pos++;
1265 }
1266 }
1267 if (pos > 0)
1268 iso_handle_split_utf16(dest + (pos - 1));
1269
1270 if ((flag & 1) && lnext <= 0)
1271 goto is_done;
1272
1273 set_ucsbe(dest + pos, '.');
1274 pos++;
1275
1276 /* Convert up to lnext characters of the extension, if any. */
1277 for (i = 0; i < lnext; i++) {
1278 uint16_t c = src[lname + 1 + i];
1279 if (valid_j_char(c)) {
1280 dest[pos++] = c;
1281 } else {
1282 set_ucsbe(dest + pos, '_');
1283 pos++;
1284 }
1285 }
1286 iso_handle_split_utf16(dest + (pos - 1));
1287
1288 is_done:;
1289 set_ucsbe(dest + pos, '\0');
1290 retval = ucsdup(dest);
1291 ex:;
1292 LIBISO_FREE_MEM(dest);
1293 return retval;
1294 }
1295
1296 /* @param flag bit1= allow 103 characters rather than 64
1297 */
iso_j_dir_id(const uint16_t * src,int flag)1298 uint16_t *iso_j_dir_id(const uint16_t *src, int flag)
1299 {
1300 size_t len, i, maxchar = 64;
1301 uint16_t *dest = NULL, *retval = NULL;
1302 /* was: 65 = 64 + 1 (\0) */
1303 LIBISO_ALLOC_MEM_VOID(dest, uint16_t, LIBISO_JOLIET_NAME_MAX);
1304
1305 if (src == NULL) {
1306 goto ex;
1307 }
1308 if (flag & 2)
1309 maxchar = 103;
1310
1311 len = ucslen(src);
1312 if (len > maxchar) {
1313 len = maxchar;
1314 }
1315 for (i = 0; i < len; i++) {
1316 uint16_t c = src[i];
1317 if (valid_j_char(c)) {
1318 dest[i] = c;
1319 } else {
1320 set_ucsbe(dest + i, '_');
1321 }
1322 }
1323 iso_handle_split_utf16(dest + (len - 1));
1324 set_ucsbe(dest + len, '\0');
1325 retval = ucsdup(dest);
1326 ex:
1327 LIBISO_FREE_MEM(dest);
1328 return retval;
1329 }
1330
ucslen(const uint16_t * str)1331 size_t ucslen(const uint16_t *str)
1332 {
1333 size_t i;
1334
1335 for (i = 0; str[i]; i++)
1336 ;
1337 return i;
1338 }
1339
ucsrchr(const uint16_t * str,char c)1340 uint16_t *ucsrchr(const uint16_t *str, char c)
1341 {
1342 size_t len = ucslen(str);
1343
1344 while (len-- > 0) {
1345 if (cmp_ucsbe(str + len, c) == 0) {
1346 return (uint16_t*)(str + len);
1347 }
1348 }
1349 return NULL;
1350 }
1351
ucsdup(const uint16_t * str)1352 uint16_t *ucsdup(const uint16_t *str)
1353 {
1354 uint16_t *ret;
1355 size_t len = ucslen(str);
1356
1357 ret = malloc(2 * (len + 1));
1358 if (ret == NULL)
1359 return NULL;
1360 if (ret != NULL) {
1361 memcpy(ret, str, 2 * (len + 1));
1362 }
1363 return ret;
1364 }
1365
1366 /**
1367 * Although each character is 2 bytes, we actually compare byte-by-byte
1368 * because the words are big-endian. Comparing possibly swapped words
1369 * would make the sorting order depend on the machine byte order.
1370 */
ucscmp(const uint16_t * s1,const uint16_t * s2)1371 int ucscmp(const uint16_t *s1, const uint16_t *s2)
1372 {
1373 const uint8_t *s = (const uint8_t*)s1;
1374 const uint8_t *t = (const uint8_t*)s2;
1375 size_t len1 = ucslen(s1);
1376 size_t len2 = ucslen(s2);
1377 size_t i, len = MIN(len1, len2) * 2;
1378
1379 for (i = 0; i < len; i++) {
1380 if (s[i] < t[i]) {
1381 return -1;
1382 } else if (s[i] > t[i]) {
1383 return 1;
1384 }
1385 }
1386
1387 if (len1 < len2)
1388 return -1;
1389 else if (len1 > len2)
1390 return 1;
1391 return 0;
1392 }
1393
ucscpy(uint16_t * dest,const uint16_t * src)1394 uint16_t *ucscpy(uint16_t *dest, const uint16_t *src)
1395 {
1396 size_t n = ucslen(src) + 1;
1397 memcpy(dest, src, n*2);
1398 return dest;
1399 }
1400
ucsncpy(uint16_t * dest,const uint16_t * src,size_t n)1401 uint16_t *ucsncpy(uint16_t *dest, const uint16_t *src, size_t n)
1402 {
1403 n = MIN(n, ucslen(src) + 1);
1404 memcpy(dest, src, n*2);
1405 if (n >= 2)
1406 iso_handle_split_utf16(dest + (n - 2));
1407 return dest;
1408 }
1409
str2d_char(const char * icharset,const char * input,char ** output)1410 int str2d_char(const char *icharset, const char *input, char **output)
1411 {
1412 int ret;
1413 char *ascii;
1414 size_t len, i;
1415
1416 if (output == NULL) {
1417 return ISO_OUT_OF_MEM;
1418 }
1419
1420 /** allow NULL input */
1421 if (input == NULL) {
1422 *output = NULL;
1423 return 0;
1424 }
1425
1426 /* this checks for NULL parameters */
1427 ret = str2ascii(icharset, input, &ascii);
1428 if (ret < 0) {
1429 *output = NULL;
1430 return ret;
1431 }
1432
1433 len = strlen(ascii);
1434
1435 for (i = 0; i < len; ++i) {
1436 char c= toupper(ascii[i]);
1437 ascii[i] = valid_d_char(c) ? c : '_';
1438 }
1439
1440 *output = ascii;
1441 return ISO_SUCCESS;
1442 }
1443
str2a_char(const char * icharset,const char * input,char ** output)1444 int str2a_char(const char *icharset, const char *input, char **output)
1445 {
1446 int ret;
1447 char *ascii;
1448 size_t len, i;
1449
1450 if (output == NULL) {
1451 return ISO_OUT_OF_MEM;
1452 }
1453
1454 /** allow NULL input */
1455 if (input == NULL) {
1456 *output = NULL;
1457 return 0;
1458 }
1459
1460 /* this checks for NULL parameters */
1461 ret = str2ascii(icharset, input, &ascii);
1462 if (ret < 0) {
1463 *output = NULL;
1464 return ret;
1465 }
1466
1467 len = strlen(ascii);
1468
1469 for (i = 0; i < len; ++i) {
1470 char c= toupper(ascii[i]);
1471 ascii[i] = valid_a_char(c) ? c : '_';
1472 }
1473
1474 *output = ascii;
1475 return ISO_SUCCESS;
1476 }
1477
iso_lsb(uint8_t * buf,uint32_t num,int bytes)1478 void iso_lsb(uint8_t *buf, uint32_t num, int bytes)
1479 {
1480 int i;
1481
1482 for (i = 0; i < bytes; ++i)
1483 buf[i] = (num >> (8 * i)) & 0xff;
1484 }
1485
iso_lsb64(uint8_t * buf,uint64_t num)1486 void iso_lsb64(uint8_t *buf, uint64_t num)
1487 {
1488 int i;
1489
1490 for (i = 0; i < 8; ++i)
1491 buf[i] = (num >> (8 * i)) & 0xff;
1492 }
1493
iso_msb(uint8_t * buf,uint32_t num,int bytes)1494 void iso_msb(uint8_t *buf, uint32_t num, int bytes)
1495 {
1496 int i;
1497
1498 for (i = 0; i < bytes; ++i)
1499 buf[bytes - 1 - i] = (num >> (8 * i)) & 0xff;
1500 }
1501
iso_bb(uint8_t * buf,uint32_t num,int bytes)1502 void iso_bb(uint8_t *buf, uint32_t num, int bytes)
1503 {
1504 iso_lsb(buf, num, bytes);
1505 iso_msb(buf+bytes, num, bytes);
1506 }
1507
1508 /* An alternative to iso_lsb() which advances the write pointer
1509 */
iso_lsb_to_buf(char ** wpt,uint32_t value,int bytes,int flag)1510 int iso_lsb_to_buf(char **wpt, uint32_t value, int bytes, int flag)
1511 {
1512 int b, bits;
1513
1514 bits = bytes * 8;
1515 for (b = 0; b < bits; b += 8)
1516 *((unsigned char *) ((*wpt)++)) = (value >> b) & 0xff;
1517 return (1);
1518 }
1519
iso_read_lsb(const uint8_t * buf,int bytes)1520 uint32_t iso_read_lsb(const uint8_t *buf, int bytes)
1521 {
1522 int i;
1523 uint32_t ret = 0;
1524
1525 for (i=0; i<bytes; i++) {
1526 ret += ((uint32_t) buf[i]) << (i*8);
1527 }
1528 return ret;
1529 }
1530
iso_read_msb(const uint8_t * buf,int bytes)1531 uint32_t iso_read_msb(const uint8_t *buf, int bytes)
1532 {
1533 int i;
1534 uint32_t ret = 0;
1535
1536 for (i=0; i<bytes; i++) {
1537 ret += ((uint32_t) buf[bytes-i-1]) << (i*8);
1538 }
1539 return ret;
1540 }
1541
iso_read_bb(const uint8_t * buf,int bytes,int * error)1542 uint32_t iso_read_bb(const uint8_t *buf, int bytes, int *error)
1543 {
1544 uint32_t v1 = iso_read_lsb(buf, bytes);
1545
1546 if (error) {
1547 uint32_t v2 = iso_read_msb(buf + bytes, bytes);
1548 if (v1 != v2)
1549 *error = 1;
1550 }
1551 return v1;
1552 }
1553
iso_read_lsb64(const uint8_t * buf)1554 uint64_t iso_read_lsb64(const uint8_t *buf)
1555 {
1556 int i;
1557 uint64_t ret = 0;
1558
1559 for (i=0; i < 8; i++)
1560 ret += ((uint64_t) buf[i]) << (i * 8);
1561 return ret;
1562 }
1563
iso_read_msb64(const uint8_t * buf)1564 uint64_t iso_read_msb64(const uint8_t *buf)
1565 {
1566 int i;
1567 uint64_t ret = 0;
1568
1569 for (i=0; i < 8; i++)
1570 ret += ((uint64_t) buf[7 - i]) << (i * 8);
1571 return ret;
1572 }
1573
iso_datetime_7(unsigned char * buf,time_t t,int always_gmt)1574 void iso_datetime_7(unsigned char *buf, time_t t, int always_gmt)
1575 {
1576 static int tzsetup = 0;
1577 int tzoffset;
1578 struct tm tm;
1579
1580 if (!tzsetup) {
1581 tzset();
1582 tzsetup = 1;
1583 }
1584
1585 memset(&tm, 0, sizeof(tm));
1586 tm.tm_isdst = -1; /* some OSes change tm_isdst only if it is -1 */
1587 localtime_r(&t, &tm);
1588
1589 #ifdef HAVE_TM_GMTOFF
1590 tzoffset = tm.tm_gmtoff / 60 / 15;
1591 #else
1592 if (tm.tm_isdst < 0)
1593 tm.tm_isdst = 0;
1594 #ifndef Libburnia_timezonE
1595 #define Libburnia_timezonE timezone
1596 #endif
1597 #if Libburnia_timezonE == 0
1598 always_gmt = 1;
1599 #endif
1600 tzoffset = ( - Libburnia_timezonE / 60 / 15 ) + 4 * tm.tm_isdst;
1601 #endif /* ! HAVE_TM_GMTOFF */
1602
1603 if (tzoffset > 52 || tzoffset < -48 || always_gmt) {
1604 /* absurd timezone offset, represent time in GMT */
1605 gmtime_r(&t, &tm);
1606 tzoffset = 0;
1607 }
1608
1609 if (tm.tm_year < 0) {
1610 tm.tm_year = 0;
1611 tm.tm_mon = 0;
1612 tm.tm_mday = 1;
1613 tm.tm_hour = 0;
1614 tm.tm_min = 0;
1615 tm.tm_sec = 0;
1616 } else if (tm.tm_year > 255) {
1617 tm.tm_year = 255;
1618 tm.tm_mon = 11;
1619 tm.tm_mday = 31;
1620 tm.tm_hour = 23;
1621 tm.tm_min = 59;
1622 tm.tm_sec = 59;
1623 }
1624 buf[0] = tm.tm_year;
1625 buf[1] = tm.tm_mon + 1;
1626 buf[2] = tm.tm_mday;
1627 buf[3] = tm.tm_hour;
1628 buf[4] = tm.tm_min;
1629 buf[5] = tm.tm_sec;
1630 buf[6] = tzoffset;
1631 }
1632
iso_datetime_17(unsigned char * buf,time_t t,int always_gmt)1633 void iso_datetime_17(unsigned char *buf, time_t t, int always_gmt)
1634 {
1635 static int tzsetup = 0;
1636 static int tzoffset;
1637 struct tm tm;
1638
1639 if (t == (time_t) - 1) {
1640 /* unspecified time */
1641 memset(buf, '0', 16);
1642 buf[16] = 0;
1643 return;
1644 }
1645
1646 if (!tzsetup) {
1647 tzset();
1648 tzsetup = 1;
1649 }
1650
1651 memset(&tm, 0, sizeof(tm));
1652 tm.tm_isdst = -1; /* some OSes change tm_isdst only if it is -1 */
1653 localtime_r(&t, &tm);
1654
1655 localtime_r(&t, &tm);
1656
1657 #ifdef HAVE_TM_GMTOFF
1658 tzoffset = tm.tm_gmtoff / 60 / 15;
1659 #else
1660 if (tm.tm_isdst < 0)
1661 tm.tm_isdst = 0;
1662 #ifndef Libburnia_timezonE
1663 #define Libburnia_timezonE timezone
1664 #endif
1665 #if Libburnia_timezonE == 0
1666 always_gmt = 1;
1667 #endif
1668 tzoffset = ( - Libburnia_timezonE / 60 / 15 ) + 4 * tm.tm_isdst;
1669 #endif /* ! HAVE_TM_GMTOFF */
1670
1671 if (tzoffset > 52 || tzoffset < -48 || always_gmt) {
1672 /* absurd timezone offset, represent time in GMT */
1673 gmtime_r(&t, &tm);
1674 tzoffset = 0;
1675 }
1676
1677 if (tm.tm_year <= -1900) {
1678 strcpy((char *) buf, "00010101000000");
1679 } else if (tm.tm_year >= 8100) {
1680 strcpy((char *) buf, "99991231235959");
1681 } else {
1682 sprintf((char*)&buf[0], "%04d", tm.tm_year + 1900);
1683 sprintf((char*)&buf[4], "%02d", tm.tm_mon + 1);
1684 sprintf((char*)&buf[6], "%02d", tm.tm_mday);
1685 sprintf((char*)&buf[8], "%02d", tm.tm_hour);
1686 sprintf((char*)&buf[10], "%02d", tm.tm_min);
1687 sprintf((char*)&buf[12], "%02d", MIN(59, tm.tm_sec));
1688 }
1689 memcpy(&buf[14], "00", 2);
1690 buf[16] = tzoffset;
1691
1692 }
1693
1694 #ifndef HAVE_TIMEGM
1695
1696 /* putenv is SVr4, POSIX.1-2001, 4.3BSD , setenv is 4.3BSD, POSIX.1-2001.
1697 So putenv is more widely available.
1698 Also, setenv spoils eventual putenv expectation of applications because
1699 putenv installs the original string which then may be altered from
1700 its owner. setenv installs a copy that may not be altered.
1701 Both are slow.
1702 Thus first try with a naive implementation that assumes no leap seconds.
1703 If it fails a test with gmtime() then use the slow function with mktime().
1704 */
1705 #define Libisofs_use_putenV yes
1706
1707 static
env_timegm(struct tm * tm)1708 time_t env_timegm(struct tm *tm)
1709 {
1710 time_t ret;
1711 char *tz;
1712
1713 #ifdef Libisofs_use_putenV
1714
1715 static char unset_name[] = {"TZ"};
1716
1717 tz = getenv("TZ");
1718 putenv("TZ=");
1719 tzset();
1720 ret = mktime(tm);
1721 if (tz != NULL) {
1722 /* tz is a pointer to the value part in a string of form "TZ="value */
1723 putenv(tz - 3);
1724 } else
1725 putenv(unset_name); /* not daring to submit constant */
1726 tzset();
1727
1728 #else /* Libisofs_use_putenV */
1729
1730 tz = getenv("TZ");
1731 setenv("TZ", "", 1);
1732 tzset();
1733 ret = mktime(tm);
1734 if (tz)
1735 setenv("TZ", tz, 1);
1736 else
1737 unsetenv("TZ");
1738 tzset();
1739
1740 #endif /* ! Libisofs_use_putenV */
1741
1742 return ret;
1743 }
1744
1745 static
ts_is_leapyear(int tm_year)1746 int ts_is_leapyear(int tm_year) /* years since 1900 */
1747 {
1748 return ((tm_year % 4) == 0 && ((tm_year % 100) != 0 ||
1749 (tm_year % 400) == 100));
1750 }
1751
1752 /* Fast implementation without leap seconds.
1753 Inspired by but not copied from code by Kungliga Tekniska Hgskolan
1754 (Royal Institute of Technology, Stockholm, Sweden),
1755 which was modified by Andrew Tridgell for Samba4.
1756 I claim own copyright 2011 Thomas Schmitt <scdbackup@gmx.net>.
1757 */
1758 static
ts_timegm(struct tm * tm)1759 time_t ts_timegm(struct tm *tm)
1760 {
1761 time_t ret;
1762 static int month_length_normal[12] =
1763 {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
1764 static int month_length_leap[12] =
1765 {31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
1766 int *month_length_pt;
1767 int years, i;
1768
1769 ret = 0;
1770
1771 years = tm->tm_year - 70; /* Years since 1970 */
1772 if (years < 0)
1773 return ret;
1774 for (i = 0; i < years; i++) {
1775 ret += 365 * 86400;
1776 if (ts_is_leapyear(70 + i))
1777 ret += 86400;
1778 }
1779 if (ts_is_leapyear(tm->tm_year))
1780 month_length_pt = month_length_leap;
1781 else
1782 month_length_pt = month_length_normal;
1783 for (i = 0; i < tm->tm_mon; i++)
1784 ret += month_length_pt[i] * 86400;
1785 ret += (tm->tm_mday - 1) * 86400;
1786 ret += tm->tm_hour * 3600;
1787 ret += tm->tm_min * 60;
1788 ret += tm->tm_sec;
1789 return ret;
1790 }
1791
1792 static
timegm(struct tm * tm)1793 time_t timegm(struct tm *tm)
1794 {
1795 time_t raw_t, ret;
1796 struct tm *test_tm, input_tm_copy;
1797
1798 /* Beware of ill effects if tm is result of gmtime() or alike */
1799 memcpy(&input_tm_copy, tm, sizeof(struct tm));
1800
1801 /* Try without leapseconds (which are rarely implemented, as it seems) */
1802 raw_t = ts_timegm(tm);
1803 if (raw_t == 0)
1804 return raw_t;
1805
1806 /* Check whether this translates back to the input values */
1807 test_tm = gmtime(&raw_t);
1808 if (input_tm_copy.tm_sec == test_tm->tm_sec &&
1809 input_tm_copy.tm_min == test_tm->tm_min &&
1810 input_tm_copy.tm_hour == test_tm->tm_hour &&
1811 input_tm_copy.tm_mday == test_tm->tm_mday &&
1812 input_tm_copy.tm_mon == test_tm->tm_mon &&
1813 input_tm_copy.tm_year == test_tm->tm_year) {
1814 ret = raw_t;
1815 } else {
1816 /* Mismatch. Use slow method around mktime() */
1817 ret = env_timegm(&input_tm_copy);
1818 }
1819 return ret;
1820 }
1821
1822
1823 #endif /* ! HAVE_TIMEGM */
1824
1825
iso_datetime_read_7(const uint8_t * buf)1826 time_t iso_datetime_read_7(const uint8_t *buf)
1827 {
1828 struct tm tm;
1829
1830 tm.tm_year = buf[0];
1831 tm.tm_mon = buf[1] - 1;
1832 tm.tm_mday = buf[2];
1833 tm.tm_hour = buf[3];
1834 tm.tm_min = buf[4];
1835 tm.tm_sec = buf[5];
1836 tm.tm_isdst = 0;
1837
1838 return timegm(&tm) - ((int8_t)buf[6]) * 60 * 15;
1839 }
1840
iso_datetime_read_17(const uint8_t * buf)1841 time_t iso_datetime_read_17(const uint8_t *buf)
1842 {
1843 struct tm tm;
1844
1845 sscanf((char*)&buf[0], "%4d", &tm.tm_year);
1846 sscanf((char*)&buf[4], "%2d", &tm.tm_mon);
1847 sscanf((char*)&buf[6], "%2d", &tm.tm_mday);
1848 sscanf((char*)&buf[8], "%2d", &tm.tm_hour);
1849 sscanf((char*)&buf[10], "%2d", &tm.tm_min);
1850 sscanf((char*)&buf[12], "%2d", &tm.tm_sec);
1851 tm.tm_year -= 1900;
1852 tm.tm_mon -= 1;
1853 tm.tm_isdst = 0;
1854
1855 return timegm(&tm) - ((int8_t)buf[16]) * 60 * 15;
1856 }
1857
1858 /**
1859 * Check whether the caller process has read access to the given local file.
1860 *
1861 * @return
1862 * 1 on success (i.e, the process has read access), < 0 on error
1863 * (including ISO_FILE_ACCESS_DENIED on access denied to the specified file
1864 * or any directory on the path).
1865 */
iso_eaccess(const char * path)1866 int iso_eaccess(const char *path)
1867 {
1868 int access;
1869
1870 /* use non standard eaccess when available, open() otherwise */
1871 #ifdef HAVE_EACCESS
1872 access = !eaccess(path, R_OK);
1873 #else
1874 int fd = open(path, O_RDONLY);
1875 if (fd != -1) {
1876 close(fd);
1877 access = 1;
1878 } else {
1879 access = 0;
1880 }
1881 #endif
1882
1883 if (!access) {
1884 int err;
1885
1886 /* error, choose an appropriate return code */
1887 switch (errno) {
1888 case EACCES:
1889 err = ISO_FILE_ACCESS_DENIED;
1890 break;
1891 case ENOTDIR:
1892 case ENAMETOOLONG:
1893 case ELOOP:
1894 err = ISO_FILE_BAD_PATH;
1895 break;
1896 case ENOENT:
1897 err = ISO_FILE_DOESNT_EXIST;
1898 break;
1899 case EFAULT:
1900 case ENOMEM:
1901 err = ISO_OUT_OF_MEM;
1902 break;
1903 default:
1904 err = ISO_FILE_ERROR;
1905 break;
1906 }
1907 return err;
1908 }
1909 return ISO_SUCCESS;
1910 }
1911
iso_util_strcopy(const char * buf,size_t len)1912 char *iso_util_strcopy(const char *buf, size_t len)
1913 {
1914 char *str;
1915
1916 str = calloc(len + 1, 1);
1917 if (str == NULL) {
1918 return NULL;
1919 }
1920 strncpy(str, buf, len);
1921 str[len] = '\0';
1922 return str;
1923 }
1924
iso_util_strcopy_untail(const char * buf,size_t len_in)1925 char *iso_util_strcopy_untail(const char *buf, size_t len_in)
1926 {
1927 char *str;
1928 int len;
1929
1930 str = iso_util_strcopy(buf, len_in);
1931 if (str == NULL) {
1932 return NULL;
1933 }
1934 /* remove trailing spaces */
1935 for (len = len_in - 1; len >= 0; --len) {
1936 if (str[len] != ' ')
1937 break;
1938 str[len] = 0;
1939 }
1940 return str;
1941 }
1942
1943 /**
1944 * Copy up to \p max characters from \p src to \p dest. If \p src has less than
1945 * \p max characters, we pad dest with " " characters.
1946 */
strncpy_pad(char * dest,const char * src,size_t max)1947 void strncpy_pad(char *dest, const char *src, size_t max)
1948 {
1949 size_t len, i;
1950
1951 if (src != NULL) {
1952 len = MIN(strlen(src), max);
1953 for (i = 0; i < len; ++i)
1954 dest[i] = src[i];
1955 } else {
1956 len = 0;
1957 }
1958
1959 for (i = len; i < max; ++i)
1960 dest[i] = ' ';
1961 }
1962
ucs2str(const char * buf,size_t len)1963 char *ucs2str(const char *buf, size_t len)
1964 {
1965 size_t outbytes, inbytes;
1966 char *str, *src, *out = NULL, *retval = NULL;
1967 struct iso_iconv_handle conv;
1968 int conv_ret;
1969 size_t n;
1970
1971 inbytes = len;
1972
1973 outbytes = (inbytes+1) * MB_LEN_MAX;
1974
1975 /* ensure enough space */
1976 out = calloc(outbytes, 1);
1977 if (out == NULL)
1978 return NULL;
1979
1980 /* convert to local charset */
1981 conv_ret = iso_iconv_open(&conv, iso_get_local_charset(0), "UCS-2BE", 0);
1982 if (conv_ret <= 0) {
1983 goto ex;
1984 }
1985 src = (char *)buf;
1986 str = (char *)out;
1987
1988 n = iso_iconv(&conv, &src, &inbytes, &str, &outbytes, 0);
1989 iso_iconv_close(&conv, 0);
1990 if (n == (size_t) -1) {
1991 /* error */
1992 goto ex;
1993 }
1994 *str = '\0';
1995
1996 /* remove trailing spaces */
1997 for (len = strlen(out) - 1; out[len] == ' ' && len > 0; --len)
1998 out[len] = '\0';
1999
2000 retval = strdup(out);
2001
2002 ex:;
2003 if (out != NULL)
2004 free(out);
2005 return retval;
2006 }
2007
iso_lib_version(int * major,int * minor,int * micro)2008 void iso_lib_version(int *major, int *minor, int *micro)
2009 {
2010
2011 *major = iso_lib_header_version_major;
2012 *minor = iso_lib_header_version_minor;
2013 *micro = iso_lib_header_version_micro;
2014
2015 /* No more: values from version.h generated from version.h.in and
2016 macro values defined in configure.ac
2017
2018 *major = LIBISOFS_MAJOR_VERSION;
2019 *minor = LIBISOFS_MINOR_VERSION;
2020 *micro = LIBISOFS_MICRO_VERSION;
2021 */
2022 }
2023
iso_lib_is_compatible(int major,int minor,int micro)2024 int iso_lib_is_compatible(int major, int minor, int micro)
2025 {
2026 int cmajor, cminor, cmicro;
2027
2028 /* for now, the rule is that library is compatible if requested
2029 * version is lower */
2030 iso_lib_version(&cmajor, &cminor, &cmicro);
2031
2032 return cmajor > major
2033 || (cmajor == major
2034 && (cminor > minor
2035 || (cminor == minor && cmicro >= micro)));
2036 }
2037
iso_init_locale(int flag)2038 int iso_init_locale(int flag)
2039 {
2040 setlocale(LC_CTYPE, "");
2041 return 1;
2042 }
2043
2044
iso_util_encode_len_bytes(uint32_t data,char * buffer,int data_len,int * result_len,int flag)2045 int iso_util_encode_len_bytes(uint32_t data, char *buffer, int data_len,
2046 int *result_len, int flag)
2047 {
2048 uint32_t x;
2049 int i, l;
2050 char *wpt = buffer;
2051
2052 if (data_len <= 0) {
2053 x = data;
2054 for (i = 0; i < 4 && x != 0; i++)
2055 x = x >> 8;
2056 l = i;
2057 if (l == 0)
2058 l = 1;
2059 } else
2060 l = data_len;
2061 *((unsigned char *) (wpt++)) = l;
2062 for (i = 0; i < l; i++)
2063 *((unsigned char *) (wpt++)) = data >> (8 * (l - i - 1));
2064 *result_len = l + 1;
2065 return ISO_SUCCESS;
2066 }
2067
2068
iso_util_decode_len_bytes(uint32_t * data,char * buffer,int * data_len,int buffer_len,int flag)2069 int iso_util_decode_len_bytes(uint32_t *data, char *buffer, int *data_len,
2070 int buffer_len, int flag)
2071 {
2072 int i;
2073
2074 *data = 0;
2075 *data_len = ((unsigned char *) buffer)[0];
2076 if (*data_len > buffer_len - 1)
2077 *data_len = buffer_len - 1;
2078 for (i = 1; i <= *data_len; i++)
2079 *data = (*data << 8) | ((unsigned char *) buffer)[i];
2080 return ISO_SUCCESS;
2081 }
2082
2083
iso_util_dec_to_uint32(char * dec,uint32_t * value,int flag)2084 int iso_util_dec_to_uint32(char *dec, uint32_t *value, int flag)
2085 {
2086 double num;
2087
2088 sscanf(dec, "%lf", &num);
2089 if (num < 0 || num > 4294967295.0)
2090 return 0;
2091 *value = num;
2092 return 1;
2093 }
2094
2095
iso_util_bin_to_hex(char * target,uint8_t * bytes,int num_bytes,int flag)2096 int iso_util_bin_to_hex(char *target, uint8_t *bytes, int num_bytes, int flag)
2097 {
2098 int i;
2099
2100 for (i = 0; i < num_bytes; i++)
2101 sprintf(target + 2 * i, "%-2.2x", bytes[i]);
2102 target[2 * num_bytes] = 0;
2103 return 1;
2104 }
2105
2106
iso_util_hex_to_bin(char * hex,char * bin,int bin_size,int * bin_count,int flag)2107 int iso_util_hex_to_bin(char *hex, char *bin, int bin_size, int *bin_count,
2108 int flag)
2109 {
2110 static char *allowed = {"0123456789ABCDEFabcdef"};
2111 char b[3];
2112 int i;
2113 unsigned int u;
2114
2115 b[2] = 0;
2116 *bin_count = 0;
2117 for (i = 0; i < bin_size; i++) {
2118 b[0] = hex[2 * i];
2119 b[1] = hex[2 * i + 1];
2120 if (strchr(allowed, b[0]) == NULL || strchr(allowed, b[1]) == NULL)
2121 break;
2122 sscanf(b, "%x", &u);
2123 ((unsigned char *) bin)[i] = u;
2124 (*bin_count)++;
2125 }
2126 return (*bin_count > 0);
2127 }
2128
2129
iso_util_tag_magic(int tag_type,char ** tag_magic,int * len,int flag)2130 int iso_util_tag_magic(int tag_type, char **tag_magic, int *len, int flag)
2131 {
2132 static char *magic[] = {"",
2133 "libisofs_checksum_tag_v1",
2134 "libisofs_sb_checksum_tag_v1",
2135 "libisofs_tree_checksum_tag_v1",
2136 "libisofs_rlsb32_checksum_tag_v1"};
2137 static int magic_len[]= {0, 24, 27, 29, 31};
2138 static int magic_max = 4;
2139
2140 *tag_magic = NULL;
2141 *len = 0;
2142 if (tag_type < 0 || tag_type > magic_max)
2143 return ISO_WRONG_ARG_VALUE;
2144 *tag_magic = magic[tag_type];
2145 *len = magic_len[tag_type];
2146 return magic_max;
2147 }
2148
2149
iso_util_decode_md5_tag(char data[2048],int * tag_type,uint32_t * pos,uint32_t * range_start,uint32_t * range_size,uint32_t * next_tag,char md5[16],int flag)2150 int iso_util_decode_md5_tag(char data[2048], int *tag_type, uint32_t *pos,
2151 uint32_t *range_start, uint32_t *range_size,
2152 uint32_t *next_tag, char md5[16], int flag)
2153 {
2154 int ret, bin_count, i, mode, magic_first = 1, magic_last = 4;
2155 int magic_len = 0;
2156 char *cpt, self_md5[16], tag_md5[16], *tag_magic;
2157 void *ctx = NULL;
2158
2159 *next_tag = 0;
2160 mode = flag & 255;
2161 if (mode > magic_last)
2162 return ISO_WRONG_ARG_VALUE;
2163 if (mode > 0)
2164 magic_first = magic_last = mode;
2165 for (i = magic_first; i <= magic_last; i++) {
2166 iso_util_tag_magic(i, &tag_magic, &magic_len, 0);
2167 if (strncmp(data, tag_magic, magic_len) == 0)
2168 break;
2169 }
2170 if (i > magic_last )
2171 return 0;
2172 *tag_type = i;
2173 cpt = data + magic_len + 1;
2174 if (strncmp(cpt, "pos=", 4) != 0)
2175 return 0;
2176 cpt+= 4;
2177 ret = iso_util_dec_to_uint32(cpt, pos, 0);
2178 if (ret <= 0)
2179 return 0;
2180 cpt = strstr(cpt, "range_start=");
2181 if (cpt == NULL)
2182 return(0);
2183 ret = iso_util_dec_to_uint32(cpt + 12, range_start, 0);
2184 if (ret <= 0)
2185 return 0;
2186 cpt = strstr(cpt, "range_size=");
2187 if (cpt == NULL)
2188 return(0);
2189 ret = iso_util_dec_to_uint32(cpt + 11, range_size, 0);
2190 if (ret <= 0)
2191 return 0;
2192 if (*tag_type == 2 || *tag_type == 3) {
2193 cpt = strstr(cpt, "next=");
2194 if (cpt == NULL)
2195 return(0);
2196 ret = iso_util_dec_to_uint32(cpt + 5, next_tag, 0);
2197 if (ret <= 0)
2198 return 0;
2199 } else if (*tag_type == 4) {
2200 cpt = strstr(cpt, "session_start=");
2201 if (cpt == NULL)
2202 return(0);
2203 ret = iso_util_dec_to_uint32(cpt + 14, next_tag, 0);
2204 if (ret <= 0)
2205 return 0;
2206 }
2207 cpt = strstr(cpt, "md5=");
2208 if (cpt == NULL)
2209 return(0);
2210 ret = iso_util_hex_to_bin(cpt + 4, md5, 16, &bin_count, 0);
2211 if (ret <= 0 || bin_count != 16)
2212 return 0;
2213
2214 cpt += 4 + 32;
2215 ret = iso_md5_start(&ctx);
2216 if (ret < 0)
2217 return ret;
2218 iso_md5_compute(ctx, data , cpt - data);
2219 iso_md5_end(&ctx, tag_md5);
2220 cpt = strstr(cpt, "self=");
2221 if (cpt == NULL)
2222 return(0);
2223 ret = iso_util_hex_to_bin(cpt + 5, self_md5, 16, &bin_count, 0);
2224 if (ret <= 0 || bin_count != 16)
2225 return 0;
2226 for(i= 0; i < 16; i++)
2227 if(self_md5[i] != tag_md5[i])
2228 return ISO_MD5_AREA_CORRUPTED;
2229 if (*(cpt + 5 + 32) != '\n')
2230 return 0;
2231 return(1);
2232 }
2233
2234
iso_util_eval_md5_tag(char * block,int desired,uint32_t lba,void * ctx,uint32_t ctx_start_lba,int * tag_type,uint32_t * next_tag,int flag)2235 int iso_util_eval_md5_tag(char *block, int desired, uint32_t lba,
2236 void *ctx, uint32_t ctx_start_lba,
2237 int *tag_type, uint32_t *next_tag, int flag)
2238 {
2239 int decode_ret, ret;
2240 char md5[16], cloned_md5[16];
2241 uint32_t pos, range_start, range_size;
2242 void *cloned_ctx = NULL;
2243
2244 *tag_type = 0;
2245 decode_ret = iso_util_decode_md5_tag(block, tag_type, &pos,
2246 &range_start, &range_size, next_tag, md5, 0);
2247 if (decode_ret != 1 && decode_ret != (int) ISO_MD5_AREA_CORRUPTED)
2248 return 0;
2249 if (*tag_type > 30)
2250 goto unexpected_type;
2251
2252 if (decode_ret == (int) ISO_MD5_AREA_CORRUPTED) {
2253 ret = decode_ret;
2254 goto ex;
2255 } else if (!((1 << *tag_type) & desired)) {
2256 unexpected_type:;
2257 iso_msg_submit(-1, ISO_MD5_TAG_UNEXPECTED, 0, NULL);
2258 ret = 0;
2259 goto ex;
2260 } else if (pos != lba) {
2261 if (*tag_type == 2) { /* Superblock tag */
2262 if (lba < 32) {
2263 /* Check whether this is a copied superblock */
2264 range_start -= (off_t) pos - (off_t) lba;
2265 if (range_start != ctx_start_lba) {
2266
2267 /* >>> check for matching MD5 ? */;
2268
2269 ret = ISO_MD5_TAG_MISPLACED;
2270 } else
2271 ret = ISO_MD5_TAG_COPIED;
2272 goto ex;
2273 }
2274 }
2275 ret = ISO_MD5_TAG_MISPLACED;
2276 goto ex;
2277 } else if (range_start != ctx_start_lba) {
2278 ret = ISO_MD5_TAG_MISPLACED;
2279 goto ex;
2280 }
2281 ret = iso_md5_clone(ctx, &cloned_ctx);
2282 if (ret < 0)
2283 goto ex;
2284 iso_md5_end(&cloned_ctx, cloned_md5);
2285 if (! iso_md5_match(cloned_md5, md5)) {
2286 ret = ISO_MD5_TAG_MISMATCH;
2287 goto ex;
2288 }
2289 ret = 1;
2290 ex:;
2291 if (ret < 0)
2292 iso_msg_submit(-1, ret, 0, NULL);
2293 return ret;
2294 }
2295
2296
iso_alloc_mem(size_t size,size_t count,int flag)2297 void *iso_alloc_mem(size_t size, size_t count, int flag)
2298 {
2299 void *pt;
2300
2301 pt = calloc(size, count);
2302 if(pt == NULL)
2303 iso_msg_submit(-1, ISO_OUT_OF_MEM, 0, "Out of virtual memory");
2304 return pt;
2305 }
2306
2307
iso_ntohs(uint16_t v)2308 uint16_t iso_ntohs(uint16_t v)
2309 {
2310 return iso_read_msb((uint8_t *) &v, 2);
2311 }
2312
iso_htons(uint16_t v)2313 uint16_t iso_htons(uint16_t v)
2314 {
2315 uint16_t ret;
2316
2317 iso_msb((uint8_t *) &ret, (uint32_t) v, 2);
2318
2319 return ret;
2320 }
2321
2322
2323 /* If an UTF-16 surrogate pair was split : Change to UTF-16 '_'.
2324 (UCS-2 is promised to reserve 0xd800 to 0xdbff for UTF-16).
2325 */
iso_handle_split_utf16(uint16_t * utf_word)2326 void iso_handle_split_utf16(uint16_t *utf_word)
2327 {
2328 unsigned char *hb;
2329
2330 hb = (unsigned char *) utf_word;
2331 if ((hb[0] & 0xfc) == 0xd8)
2332 set_ucsbe(utf_word, '_');
2333 }
2334
2335
iso_clone_mem(char * in,char ** out,size_t size)2336 int iso_clone_mem(char *in, char **out, size_t size)
2337 {
2338 if (in == NULL) {
2339 *out = NULL;
2340 return 1;
2341 }
2342 if (size == 0)
2343 size = strlen(in) + 1;
2344 *out = calloc(1, size);
2345 if (*out == NULL)
2346 return ISO_OUT_OF_MEM;
2347 memcpy(*out, in, size);
2348 return ISO_SUCCESS;
2349 }
2350
2351
iso_clone_mgtd_mem(char * in,char ** out,size_t size)2352 int iso_clone_mgtd_mem(char *in, char **out, size_t size)
2353 {
2354 if (*out != NULL)
2355 free(*out);
2356 return iso_clone_mem(in, out, size);
2357 }
2358
2359
2360 /** Convert a text into a number of type double and multiply it by unit code
2361 [kmgt] (2^10 to 2^40) or [s] (2048) or [d] (512).
2362 (Also accepts capital letters.)
2363 @param text Input like "42", "223062s", "3m" or "-1g"
2364 @param flag Bitfield for control purposes:
2365 bit0= return -1 rather than 0 on failure
2366 bit1= if scaled then compute the last byte of the last unit
2367 @return The derived value
2368 */
iso_scanf_io_size(char * text,int flag)2369 off_t iso_scanf_io_size(char *text, int flag)
2370 {
2371 int c;
2372 off_t ret = 0, fac = 1;
2373 char *rpt;
2374
2375 for (rpt = text; *rpt >= '0' && *rpt <= '9'; rpt++)
2376 ret = ret * 10 + (*rpt - '0');
2377 if (rpt == text)
2378 return (off_t) (flag & 1 ? -1 : 0);
2379 c = *rpt;
2380 if (c=='k' || c=='K')
2381 fac = 1024;
2382 else if (c=='m' || c=='M')
2383 fac = 1024 * 1024;
2384 else if (c=='g' || c=='G')
2385 fac = 1024 * 1024 * 1024;
2386 else if (c=='t' || c=='T')
2387 fac = ((off_t) 1024) * 1024 * 1024 * 1024;
2388 else if (c=='s' || c=='S')
2389 fac = 2048;
2390 else if (c=='d' || c=='D')
2391 fac = 512;
2392 ret *= fac;
2393 if (flag & 2)
2394 ret += fac - 1;
2395 return ret;
2396 }
2397
2398
2399 /* Find backward from idx the start byte of a possible UTF-8 character.
2400 https://en.wikipedia.org/wiki/UTF-8#Description
2401 */
2402 static
find_utf8_start(char * name,int idx,int flag)2403 int find_utf8_start(char *name, int idx, int flag)
2404 {
2405 unsigned char *uname, uch;
2406 int i;
2407
2408 uname= (unsigned char *) name;
2409 if ((uname[idx] & 0xc0) != 0x80)
2410 return idx; /* not an UTF-8 tail byte */
2411 for (i = 0; i < 5 && idx - 1 - i >= 0; i++) { /* up to deprecated 6-byte codes */
2412 uch = uname[idx - 1 - i];
2413 if ((uch & 0xe0) == 0xc0 || (uch & 0xf0) == 0xe0 ||
2414 (uch & 0xf8) == 0xf0 || (uch & 0xfc) == 0xf8 ||
2415 (uch & 0xfe) == 0xfc)
2416 return (idx - 1 - i); /* UTF-8 start byte found */
2417 if ((uch & 0xc0) != 0x80)
2418 return idx; /* not an UTF-8 tail byte, so no UTF-8 */
2419 }
2420 return idx; /* no UTF-8 start found */
2421 }
2422
2423 /* @param flag bit0= do not issue warning message
2424 */
iso_truncate_rr_name(int truncate_mode,int truncate_length,char * name,int flag)2425 int iso_truncate_rr_name(int truncate_mode, int truncate_length,
2426 char *name, int flag)
2427 {
2428 int neck, goal, ret, l, i;
2429 static int hash_size = 32;
2430 void *ctx = NULL;
2431 char hashval[16];
2432
2433 l = strlen(name);
2434 if (l <= truncate_length)
2435 return ISO_SUCCESS;
2436 if (truncate_mode == 0)
2437 return ISO_RR_NAME_TOO_LONG;
2438
2439 /* Compute hash */
2440 ret = iso_md5_start(&ctx);
2441 if (ret < 0)
2442 goto ex;
2443 ret = iso_md5_compute(ctx, name, l > 4095 ? 4095 : l);
2444 if (ret < 0)
2445 goto ex;
2446 ret = iso_md5_end(&ctx, hashval);
2447 if (ret < 0)
2448 goto ex;
2449
2450 if (!(flag & 1))
2451 iso_msg_submit(-1, ISO_RR_NAME_TRUNCATED, 0,
2452 "File name had to be truncated and MD5 marked: %s", name);
2453
2454 /* Avoid to produce incomplete UTF-8 characters */
2455 goal = truncate_length - hash_size - 1;
2456 neck = find_utf8_start(name, goal, 0);
2457 for (; neck < goal; neck++)
2458 name[neck] = '_';
2459
2460 /* Write colon and hash text over end of truncated name */
2461 name[goal] = ':';
2462 goal++;
2463 for (i = 0; goal < truncate_length - 1 && i < hash_size / 2; goal += 2) {
2464 sprintf(name + goal, "%2.2x", *((unsigned char *) (hashval + i)));
2465 i++;
2466 }
2467 name[truncate_length] = 0;
2468
2469 ret = ISO_SUCCESS;
2470 ex:;
2471 if (ctx != NULL)
2472 iso_md5_end(&ctx, hashval);
2473 return ret;
2474 }
2475
2476 /* API */
iso_truncate_leaf_name(int mode,int length,char * name,int flag)2477 int iso_truncate_leaf_name(int mode, int length, char *name, int flag)
2478 {
2479 int ret;
2480
2481 if (mode < 0 || mode > 1)
2482 return ISO_WRONG_ARG_VALUE;
2483 if (length < 64 || length > LIBISOFS_NODE_NAME_MAX)
2484 return ISO_WRONG_ARG_VALUE;
2485 ret = iso_truncate_rr_name(mode, length, name, 1);
2486 return ret;
2487 }
2488
2489 /* API */
2490 /* @param flag bit0= *now contains the time to be set as nowtime override
2491 bit1= disable the nowtime override
2492 @return 1= *now is not overridden , 2= *now is overridden
2493 */
iso_nowtime(time_t * now,int flag)2494 int iso_nowtime(time_t *now, int flag)
2495 {
2496 static int now_time_overridden = 0;
2497 static time_t now_time_override = 0;
2498
2499 if (flag & 1) {
2500 now_time_overridden = 1;
2501 now_time_override = *now;
2502 }
2503 if (flag & 2) {
2504 now_time_overridden = 0;
2505 }
2506 *now = time(NULL);
2507 if (!now_time_overridden)
2508 return 1;
2509 *now = now_time_override;
2510 return 2;
2511 }
2512
2513