1 /*-
2  * Copyright (c) 2003-2007 Tim Kientzle
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, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
15  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
16  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
17  * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
18  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
19  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
20  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
21  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
23  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24  */
25 #include "test.h"
26 __FBSDID("$FreeBSD$");
27 
28 #include <locale.h>
29 
30 /*
31  * Pax interchange is supposed to encode filenames into
32  * UTF-8.  Of course, that's not always possible.  This
33  * test is intended to verify that filenames always get
34  * stored and restored correctly, regardless of the encodings.
35  */
36 
37 /*
38  * Read a manually-created archive that has filenames that are
39  * stored in binary instead of UTF-8 and verify that we get
40  * the right filename returned and that we get a warning only
41  * if the header isn't marked as binary.
42  */
43 static void
44 test_pax_filename_encoding_1(void)
45 {
46 	static const char testname[] = "test_pax_filename_encoding.tar";
47 	/*
48 	 * \314\214 is a valid 2-byte UTF-8 sequence.
49 	 * \374 is invalid in UTF-8.
50 	 */
51 	char filename[] = "abc\314\214mno\374xyz";
52 	struct archive *a;
53 	struct archive_entry *entry;
54 
55 	/*
56 	 * Read an archive that has non-UTF8 pax filenames in it.
57 	 */
58 	extract_reference_file(testname);
59 	a = archive_read_new();
60 	assertEqualInt(ARCHIVE_OK, archive_read_support_format_tar(a));
61 	assertEqualInt(ARCHIVE_OK, archive_read_support_filter_all(a));
62 	assertEqualInt(ARCHIVE_OK,
63 	    archive_read_open_filename(a, testname, 10240));
64 	/*
65 	 * First entry in this test archive has an invalid UTF-8 sequence
66 	 * in it, but the header is not marked as hdrcharset=BINARY, so that
67 	 * requires a warning.
68 	 */
69 	failure("Invalid UTF8 in a pax archive pathname should cause a warning");
70 	assertEqualInt(ARCHIVE_WARN, archive_read_next_header(a, &entry));
71 	assertEqualString(filename, archive_entry_pathname(entry));
72 	/*
73 	 * Second entry is identical except that it does have
74 	 * hdrcharset=BINARY, so no warning should be generated.
75 	 */
76 	failure("A pathname with hdrcharset=BINARY can have invalid UTF8\n"
77 	    " characters in it without generating a warning");
78 	assertEqualInt(ARCHIVE_OK, archive_read_next_header(a, &entry));
79 	assertEqualString(filename, archive_entry_pathname(entry));
80 	archive_read_free(a);
81 }
82 
83 /*
84  * Set the locale and write a pathname containing invalid characters.
85  * This should work; the underlying implementation should automatically
86  * fall back to storing the pathname in binary.
87  */
88 static void
89 test_pax_filename_encoding_2(void)
90 {
91 	char filename[] = "abc\314\214mno\374xyz";
92 	struct archive *a;
93 	struct archive_entry *entry;
94 	char buff[65536];
95 	char longname[] = "abc\314\214mno\374xyz"
96 	    "/abc\314\214mno\374xyz/abcdefghijklmnopqrstuvwxyz"
97 	    "/abc\314\214mno\374xyz/abcdefghijklmnopqrstuvwxyz"
98 	    "/abc\314\214mno\374xyz/abcdefghijklmnopqrstuvwxyz"
99 	    "/abc\314\214mno\374xyz/abcdefghijklmnopqrstuvwxyz"
100 	    "/abc\314\214mno\374xyz/abcdefghijklmnopqrstuvwxyz"
101 	    "/abc\314\214mno\374xyz/abcdefghijklmnopqrstuvwxyz"
102 	    ;
103 	size_t used;
104 
105 	/*
106 	 * We need a starting locale which has invalid sequences.
107 	 * en_US.UTF-8 seems to be commonly supported.
108 	 */
109 	/* If it doesn't exist, just warn and return. */
110 	if (NULL == setlocale(LC_ALL, "en_US.UTF-8")) {
111 		skipping("invalid encoding tests require a suitable locale;"
112 		    " en_US.UTF-8 not available on this system");
113 		return;
114 	}
115 
116 	assert((a = archive_write_new()) != NULL);
117 	assertEqualIntA(a, 0, archive_write_set_format_pax(a));
118 	assertEqualIntA(a, 0, archive_write_add_filter_none(a));
119 	assertEqualIntA(a, 0, archive_write_set_bytes_per_block(a, 0));
120 	assertEqualInt(0,
121 	    archive_write_open_memory(a, buff, sizeof(buff), &used));
122 
123 	assert((entry = archive_entry_new()) != NULL);
124 	/* Set pathname, gname, uname, hardlink to nonconvertible values. */
125 	archive_entry_copy_pathname(entry, filename);
126 	archive_entry_copy_gname(entry, filename);
127 	archive_entry_copy_uname(entry, filename);
128 	archive_entry_copy_hardlink(entry, filename);
129 	archive_entry_set_filetype(entry, AE_IFREG);
130 	failure("This should generate a warning for nonconvertible names.");
131 	assertEqualInt(ARCHIVE_WARN, archive_write_header(a, entry));
132 	archive_entry_free(entry);
133 
134 	assert((entry = archive_entry_new()) != NULL);
135 	/* Set path, gname, uname, and symlink to nonconvertible values. */
136 	archive_entry_copy_pathname(entry, filename);
137 	archive_entry_copy_gname(entry, filename);
138 	archive_entry_copy_uname(entry, filename);
139 	archive_entry_copy_symlink(entry, filename);
140 	archive_entry_set_filetype(entry, AE_IFLNK);
141 	failure("This should generate a warning for nonconvertible names.");
142 	assertEqualInt(ARCHIVE_WARN, archive_write_header(a, entry));
143 	archive_entry_free(entry);
144 
145 	assert((entry = archive_entry_new()) != NULL);
146 	/* Set pathname to a very long nonconvertible value. */
147 	archive_entry_copy_pathname(entry, longname);
148 	archive_entry_set_filetype(entry, AE_IFREG);
149 	failure("This should generate a warning for nonconvertible names.");
150 	assertEqualInt(ARCHIVE_WARN, archive_write_header(a, entry));
151 	archive_entry_free(entry);
152 
153 	assertEqualIntA(a, ARCHIVE_OK, archive_write_close(a));
154 	assertEqualInt(ARCHIVE_OK, archive_write_free(a));
155 
156 	/*
157 	 * Now read the entries back.
158 	 */
159 
160 	assert((a = archive_read_new()) != NULL);
161 	assertEqualInt(0, archive_read_support_format_tar(a));
162 	assertEqualInt(0, archive_read_open_memory(a, buff, used));
163 
164 	assertEqualInt(0, archive_read_next_header(a, &entry));
165 	assertEqualString(filename, archive_entry_pathname(entry));
166 	assertEqualString(filename, archive_entry_gname(entry));
167 	assertEqualString(filename, archive_entry_uname(entry));
168 	assertEqualString(filename, archive_entry_hardlink(entry));
169 
170 	assertEqualInt(0, archive_read_next_header(a, &entry));
171 	assertEqualString(filename, archive_entry_pathname(entry));
172 	assertEqualString(filename, archive_entry_gname(entry));
173 	assertEqualString(filename, archive_entry_uname(entry));
174 	assertEqualString(filename, archive_entry_symlink(entry));
175 
176 	assertEqualInt(0, archive_read_next_header(a, &entry));
177 	assertEqualString(longname, archive_entry_pathname(entry));
178 
179 	assertEqualIntA(a, ARCHIVE_OK, archive_read_close(a));
180 	assertEqualInt(ARCHIVE_OK, archive_read_free(a));
181 }
182 
183 #if 0 /* Disable this until Tim check out it. */
184 
185 /*
186  * Create an entry starting from a wide-character Unicode pathname,
187  * read it back into "C" locale, which doesn't support the name.
188  * TODO: Figure out the "right" behavior here.
189  */
190 static void
191 test_pax_filename_encoding_3(void)
192 {
193 	wchar_t badname[] = L"xxxAyyyBzzz";
194 	const char badname_utf8[] = "xxx\xE1\x88\xB4yyy\xE5\x99\xB8zzz";
195 	struct archive *a;
196 	struct archive_entry *entry;
197 	char buff[65536];
198 	size_t used;
199 
200 	badname[3] = 0x1234;
201 	badname[7] = 0x5678;
202 
203 	/* If it doesn't exist, just warn and return. */
204 	if (NULL == setlocale(LC_ALL, "C")) {
205 		skipping("Can't set \"C\" locale, so can't exercise "
206 		    "certain character-conversion failures");
207 		return;
208 	}
209 
210 	/* If wctomb is broken, warn and return. */
211 	if (wctomb(buff, 0x1234) > 0) {
212 		skipping("Cannot test conversion failures because \"C\" "
213 		    "locale on this system has no invalid characters.");
214 		return;
215 	}
216 
217 	/* If wctomb is broken, warn and return. */
218 	if (wctomb(buff, 0x1234) > 0) {
219 		skipping("Cannot test conversion failures because \"C\" "
220 		    "locale on this system has no invalid characters.");
221 		return;
222 	}
223 
224 	/* Skip test if archive_entry_update_pathname_utf8() is broken. */
225 	/* In particular, this is currently broken on Win32 because
226 	 * setlocale() does not set the default encoding for CP_ACP. */
227 	entry = archive_entry_new();
228 	if (archive_entry_update_pathname_utf8(entry, badname_utf8)) {
229 		archive_entry_free(entry);
230 		skipping("Cannot test conversion failures.");
231 		return;
232 	}
233 	archive_entry_free(entry);
234 
235 	assert((a = archive_write_new()) != NULL);
236 	assertEqualIntA(a, 0, archive_write_set_format_pax(a));
237 	assertEqualIntA(a, 0, archive_write_add_filter_none(a));
238 	assertEqualIntA(a, 0, archive_write_set_bytes_per_block(a, 0));
239 	assertEqualInt(0,
240 	    archive_write_open_memory(a, buff, sizeof(buff), &used));
241 
242 	assert((entry = archive_entry_new()) != NULL);
243 	/* Set pathname to non-convertible wide value. */
244 	archive_entry_copy_pathname_w(entry, badname);
245 	archive_entry_set_filetype(entry, AE_IFREG);
246 	assertEqualInt(ARCHIVE_OK, archive_write_header(a, entry));
247 	archive_entry_free(entry);
248 
249 	assert((entry = archive_entry_new()) != NULL);
250 	archive_entry_copy_pathname_w(entry, L"abc");
251 	/* Set gname to non-convertible wide value. */
252 	archive_entry_copy_gname_w(entry, badname);
253 	archive_entry_set_filetype(entry, AE_IFREG);
254 	assertEqualInt(ARCHIVE_OK, archive_write_header(a, entry));
255 	archive_entry_free(entry);
256 
257 	assert((entry = archive_entry_new()) != NULL);
258 	archive_entry_copy_pathname_w(entry, L"abc");
259 	/* Set uname to non-convertible wide value. */
260 	archive_entry_copy_uname_w(entry, badname);
261 	archive_entry_set_filetype(entry, AE_IFREG);
262 	assertEqualInt(ARCHIVE_OK, archive_write_header(a, entry));
263 	archive_entry_free(entry);
264 
265 	assert((entry = archive_entry_new()) != NULL);
266 	archive_entry_copy_pathname_w(entry, L"abc");
267 	/* Set hardlink to non-convertible wide value. */
268 	archive_entry_copy_hardlink_w(entry, badname);
269 	archive_entry_set_filetype(entry, AE_IFREG);
270 	assertEqualInt(ARCHIVE_OK, archive_write_header(a, entry));
271 	archive_entry_free(entry);
272 
273 	assert((entry = archive_entry_new()) != NULL);
274 	archive_entry_copy_pathname_w(entry, L"abc");
275 	/* Set symlink to non-convertible wide value. */
276 	archive_entry_copy_symlink_w(entry, badname);
277 	archive_entry_set_filetype(entry, AE_IFLNK);
278 	assertEqualInt(ARCHIVE_OK, archive_write_header(a, entry));
279 	archive_entry_free(entry);
280 
281 	assertEqualIntA(a, ARCHIVE_OK, archive_write_close(a));
282 	assertEqualInt(ARCHIVE_OK, archive_write_free(a));
283 
284 	/*
285 	 * Now read the entries back.
286 	 */
287 
288 	assert((a = archive_read_new()) != NULL);
289 	assertEqualInt(0, archive_read_support_format_tar(a));
290 	assertEqualInt(0, archive_read_open_memory(a, buff, used));
291 
292 	failure("A non-convertible pathname should cause a warning.");
293 	assertEqualInt(ARCHIVE_WARN, archive_read_next_header(a, &entry));
294 	assertEqualWString(badname, archive_entry_pathname_w(entry));
295 	failure("If native locale can't convert, we should get UTF-8 back.");
296 	assertEqualString(badname_utf8, archive_entry_pathname(entry));
297 
298 	failure("A non-convertible gname should cause a warning.");
299 	assertEqualInt(ARCHIVE_WARN, archive_read_next_header(a, &entry));
300 	assertEqualWString(badname, archive_entry_gname_w(entry));
301 	failure("If native locale can't convert, we should get UTF-8 back.");
302 	assertEqualString(badname_utf8, archive_entry_gname(entry));
303 
304 	failure("A non-convertible uname should cause a warning.");
305 	assertEqualInt(ARCHIVE_WARN, archive_read_next_header(a, &entry));
306 	assertEqualWString(badname, archive_entry_uname_w(entry));
307 	failure("If native locale can't convert, we should get UTF-8 back.");
308 	assertEqualString(badname_utf8, archive_entry_uname(entry));
309 
310 	failure("A non-convertible hardlink should cause a warning.");
311 	assertEqualInt(ARCHIVE_WARN, archive_read_next_header(a, &entry));
312 	assertEqualWString(badname, archive_entry_hardlink_w(entry));
313 	failure("If native locale can't convert, we should get UTF-8 back.");
314 	assertEqualString(badname_utf8, archive_entry_hardlink(entry));
315 
316 	failure("A non-convertible symlink should cause a warning.");
317 	assertEqualInt(ARCHIVE_WARN, archive_read_next_header(a, &entry));
318 	assertEqualWString(badname, archive_entry_symlink_w(entry));
319 	assertEqualWString(NULL, archive_entry_hardlink_w(entry));
320 	failure("If native locale can't convert, we should get UTF-8 back.");
321 	assertEqualString(badname_utf8, archive_entry_symlink(entry));
322 
323 	assertEqualInt(ARCHIVE_EOF, archive_read_next_header(a, &entry));
324 
325 	assertEqualIntA(a, ARCHIVE_OK, archive_read_close(a));
326 	assertEqualInt(ARCHIVE_OK, archive_read_free(a));
327 }
328 #else
329 static void
330 test_pax_filename_encoding_3(void)
331 {
332 }
333 #endif
334 
335 /*
336  * Verify that KOI8-R filenames are correctly translated to Unicode and UTF-8.
337  */
338 DEFINE_TEST(test_pax_filename_encoding_KOI8R)
339 {
340   	struct archive *a;
341   	struct archive_entry *entry;
342 	char buff[4096];
343 	size_t used;
344 
345 	if (NULL == setlocale(LC_ALL, "ru_RU.KOI8-R")) {
346 		skipping("KOI8-R locale not available on this system.");
347 		return;
348 	}
349 
350 	/* Check if the platform completely supports the string conversion. */
351 	a = archive_write_new();
352 	assertEqualInt(ARCHIVE_OK, archive_write_set_format_pax(a));
353 	if (archive_write_set_options(a, "hdrcharset=UTF-8") != ARCHIVE_OK) {
354 		skipping("This system cannot convert character-set"
355 		    " from KOI8-R to UTF-8.");
356 		archive_write_free(a);
357 		return;
358 	}
359 	archive_write_free(a);
360 
361 	/* Re-create a write archive object since filenames should be written
362 	 * in UTF-8 by default. */
363 	a = archive_write_new();
364 	assertEqualInt(ARCHIVE_OK, archive_write_set_format_pax(a));
365 	assertEqualInt(ARCHIVE_OK,
366 	    archive_write_open_memory(a, buff, sizeof(buff), &used));
367 
368 	entry = archive_entry_new2(a);
369 	archive_entry_set_pathname(entry, "\xD0\xD2\xC9");
370 	archive_entry_set_filetype(entry, AE_IFREG);
371 	archive_entry_set_size(entry, 0);
372 	assertEqualInt(ARCHIVE_OK, archive_write_header(a, entry));
373 	archive_entry_free(entry);
374 	assertEqualInt(ARCHIVE_OK, archive_write_free(a));
375 
376 	/* Above three characters in KOI8-R should translate to the following
377 	 * three characters (two bytes each) in UTF-8. */
378 	assertEqualMem(buff + 512, "15 path=\xD0\xBF\xD1\x80\xD0\xB8\x0A", 15);
379 }
380 
381 /*
382  * Verify that CP1251 filenames are correctly translated to Unicode and UTF-8.
383  */
384 DEFINE_TEST(test_pax_filename_encoding_CP1251)
385 {
386   	struct archive *a;
387   	struct archive_entry *entry;
388 	char buff[4096];
389 	size_t used;
390 
391 	if (NULL == setlocale(LC_ALL, "Russian_Russia") &&
392 	    NULL == setlocale(LC_ALL, "ru_RU.CP1251")) {
393 		skipping("KOI8-R locale not available on this system.");
394 		return;
395 	}
396 
397 	/* Check if the platform completely supports the string conversion. */
398 	a = archive_write_new();
399 	assertEqualInt(ARCHIVE_OK, archive_write_set_format_pax(a));
400 	if (archive_write_set_options(a, "hdrcharset=UTF-8") != ARCHIVE_OK) {
401 		skipping("This system cannot convert character-set"
402 		    " from KOI8-R to UTF-8.");
403 		archive_write_free(a);
404 		return;
405 	}
406 	archive_write_free(a);
407 
408 	/* Re-create a write archive object since filenames should be written
409 	 * in UTF-8 by default. */
410 	a = archive_write_new();
411 	assertEqualInt(ARCHIVE_OK, archive_write_set_format_pax(a));
412 	assertEqualInt(ARCHIVE_OK,
413 	    archive_write_open_memory(a, buff, sizeof(buff), &used));
414 
415 	entry = archive_entry_new2(a);
416 	archive_entry_set_pathname(entry, "\xef\xf0\xe8");
417 	archive_entry_set_filetype(entry, AE_IFREG);
418 	archive_entry_set_size(entry, 0);
419 	assertEqualInt(ARCHIVE_OK, archive_write_header(a, entry));
420 	archive_entry_free(entry);
421 	assertEqualInt(ARCHIVE_OK, archive_write_free(a));
422 
423 	/* Above three characters in KOI8-R should translate to the following
424 	 * three characters (two bytes each) in UTF-8. */
425 	assertEqualMem(buff + 512, "15 path=\xD0\xBF\xD1\x80\xD0\xB8\x0A", 15);
426 }
427 
428 /*
429  * Verify that EUC-JP filenames are correctly translated to Unicode and UTF-8.
430  */
431 DEFINE_TEST(test_pax_filename_encoding_EUCJP)
432 {
433   	struct archive *a;
434   	struct archive_entry *entry;
435 	char buff[4096];
436 	size_t used;
437 
438 	if (NULL == setlocale(LC_ALL, "ja_JP.eucJP")) {
439 		skipping("eucJP locale not available on this system.");
440 		return;
441 	}
442 
443 	/* Check if the platform completely supports the string conversion. */
444 	a = archive_write_new();
445 	assertEqualInt(ARCHIVE_OK, archive_write_set_format_pax(a));
446 	if (archive_write_set_options(a, "hdrcharset=UTF-8") != ARCHIVE_OK) {
447 		skipping("This system cannot convert character-set"
448 		    " from eucJP to UTF-8.");
449 		archive_write_free(a);
450 		return;
451 	}
452 	archive_write_free(a);
453 
454 	/* Re-create a write archive object since filenames should be written
455 	 * in UTF-8 by default. */
456 	a = archive_write_new();
457 	assertEqualInt(ARCHIVE_OK, archive_write_set_format_pax(a));
458 	assertEqualInt(ARCHIVE_OK,
459 	    archive_write_open_memory(a, buff, sizeof(buff), &used));
460 
461 	entry = archive_entry_new2(a);
462 	archive_entry_set_pathname(entry, "\xC9\xBD.txt");
463 	/* Check the Unicode version. */
464 	archive_entry_set_filetype(entry, AE_IFREG);
465 	archive_entry_set_size(entry, 0);
466 	assertEqualInt(ARCHIVE_OK, archive_write_header(a, entry));
467 	archive_entry_free(entry);
468 	assertEqualInt(ARCHIVE_OK, archive_write_free(a));
469 
470 	/* Check UTF-8 version. */
471 	assertEqualMem(buff + 512, "16 path=\xE8\xA1\xA8.txt\x0A", 16);
472 
473 }
474 
475 /*
476  * Verify that CP932/SJIS filenames are correctly translated to Unicode and UTF-8.
477  */
478 DEFINE_TEST(test_pax_filename_encoding_CP932)
479 {
480   	struct archive *a;
481   	struct archive_entry *entry;
482 	char buff[4096];
483 	size_t used;
484 
485 	if (NULL == setlocale(LC_ALL, "Japanese_Japan") &&
486 	    NULL == setlocale(LC_ALL, "ja_JP.SJIS")) {
487 		skipping("eucJP locale not available on this system.");
488 		return;
489 	}
490 
491 	/* Check if the platform completely supports the string conversion. */
492 	a = archive_write_new();
493 	assertEqualInt(ARCHIVE_OK, archive_write_set_format_pax(a));
494 	if (archive_write_set_options(a, "hdrcharset=UTF-8") != ARCHIVE_OK) {
495 		skipping("This system cannot convert character-set"
496 		    " from CP932/SJIS to UTF-8.");
497 		archive_write_free(a);
498 		return;
499 	}
500 	archive_write_free(a);
501 
502 	/* Re-create a write archive object since filenames should be written
503 	 * in UTF-8 by default. */
504 	a = archive_write_new();
505 	assertEqualInt(ARCHIVE_OK, archive_write_set_format_pax(a));
506 	assertEqualInt(ARCHIVE_OK,
507 	    archive_write_open_memory(a, buff, sizeof(buff), &used));
508 
509 	entry = archive_entry_new2(a);
510 	archive_entry_set_pathname(entry, "\x95\x5C.txt");
511 	/* Check the Unicode version. */
512 	archive_entry_set_filetype(entry, AE_IFREG);
513 	archive_entry_set_size(entry, 0);
514 	assertEqualInt(ARCHIVE_OK, archive_write_header(a, entry));
515 	archive_entry_free(entry);
516 	assertEqualInt(ARCHIVE_OK, archive_write_free(a));
517 
518 	/* Check UTF-8 version. */
519 	assertEqualMem(buff + 512, "16 path=\xE8\xA1\xA8.txt\x0A", 16);
520 
521 }
522 
523 /*
524  * Verify that KOI8-R filenames are not translated to Unicode and UTF-8
525  * when using hdrcharset=BINARY option.
526  */
527 DEFINE_TEST(test_pax_filename_encoding_KOI8R_BINARY)
528 {
529   	struct archive *a;
530   	struct archive_entry *entry;
531 	char buff[4096];
532 	size_t used;
533 
534 	if (NULL == setlocale(LC_ALL, "ru_RU.KOI8-R")) {
535 		skipping("KOI8-R locale not available on this system.");
536 		return;
537 	}
538 
539 	a = archive_write_new();
540 	assertEqualInt(ARCHIVE_OK, archive_write_set_format_pax(a));
541 	/* BINARY mode should be accepted. */
542 	assertEqualInt(ARCHIVE_OK,
543 	    archive_write_set_options(a, "hdrcharset=BINARY"));
544 	assertEqualInt(ARCHIVE_OK,
545 	    archive_write_open_memory(a, buff, sizeof(buff), &used));
546 
547 	entry = archive_entry_new2(a);
548 	archive_entry_set_pathname(entry, "\xD0\xD2\xC9");
549 	archive_entry_set_filetype(entry, AE_IFREG);
550 	archive_entry_set_size(entry, 0);
551 	assertEqualInt(ARCHIVE_OK, archive_write_header(a, entry));
552 	archive_entry_free(entry);
553 	assertEqualInt(ARCHIVE_OK, archive_write_free(a));
554 
555 	/* "hdrcharset=BINARY" pax attribute should be written. */
556 	assertEqualMem(buff + 512, "21 hdrcharset=BINARY\x0A", 21);
557 	/* Above three characters in KOI8-R should not translate to any
558 	 * character-set. */
559 	assertEqualMem(buff + 512+21, "12 path=\xD0\xD2\xC9\x0A", 12);
560 }
561 
562 /*
563  * Pax format writer only accepts both BINARY and UTF-8.
564  * If other character-set name is specified, you will get ARCHIVE_FAILED.
565  */
566 DEFINE_TEST(test_pax_filename_encoding_KOI8R_CP1251)
567 {
568   	struct archive *a;
569 
570 	if (NULL == setlocale(LC_ALL, "ru_RU.KOI8-R")) {
571 		skipping("KOI8-R locale not available on this system.");
572 		return;
573 	}
574 
575 	a = archive_write_new();
576 	assertEqualInt(ARCHIVE_OK, archive_write_set_format_pax(a));
577 	/* pax format writer only accepts both BINARY and UTF-8. */
578 	assertEqualInt(ARCHIVE_FAILED,
579 	    archive_write_set_options(a, "hdrcharset=CP1251"));
580 	assertEqualInt(ARCHIVE_OK, archive_write_free(a));
581 }
582 
583 
584 DEFINE_TEST(test_pax_filename_encoding)
585 {
586 	test_pax_filename_encoding_1();
587 	test_pax_filename_encoding_2();
588 	test_pax_filename_encoding_3();
589 }
590