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
27 /*
28 * Exercise various lengths of filenames in ustar archives.
29 */
30
31 static void
test_filename(const char * prefix,int dlen,int flen)32 test_filename(const char *prefix, int dlen, int flen)
33 {
34 char buff[8192];
35 char filename[400];
36 char dirname[400];
37 struct archive_entry *ae;
38 struct archive *a;
39 size_t used;
40 int separator = 0;
41 int i = 0;
42
43 if (prefix != NULL) {
44 strcpy(filename, prefix);
45 i = (int)strlen(prefix);
46 }
47 if (dlen > 0) {
48 for (; i < dlen; i++)
49 filename[i] = 'a';
50 filename[i++] = '/';
51 separator = 1;
52 }
53 for (; i < dlen + flen + separator; i++)
54 filename[i] = 'b';
55 filename[i] = '\0';
56
57 strcpy(dirname, filename);
58
59 /* Create a new archive in memory. */
60 assert((a = archive_write_new()) != NULL);
61 assertA(0 == archive_write_set_format_ustar(a));
62 assertA(0 == archive_write_add_filter_none(a));
63 assertA(0 == archive_write_set_bytes_per_block(a,0));
64 assertA(0 == archive_write_open_memory(a, buff, sizeof(buff), &used));
65
66 /*
67 * Write a file to it.
68 */
69 assert((ae = archive_entry_new()) != NULL);
70 archive_entry_copy_pathname(ae, filename);
71 archive_entry_set_mode(ae, S_IFREG | 0755);
72 failure("dlen=%d, flen=%d", dlen, flen);
73 if (flen > 100) {
74 assertEqualIntA(a, ARCHIVE_FAILED, archive_write_header(a, ae));
75 } else {
76 assertEqualIntA(a, 0, archive_write_header(a, ae));
77 }
78 archive_entry_free(ae);
79
80 /*
81 * Write a dir to it (without trailing '/').
82 */
83 assert((ae = archive_entry_new()) != NULL);
84 archive_entry_copy_pathname(ae, dirname);
85 archive_entry_set_mode(ae, S_IFDIR | 0755);
86 failure("dlen=%d, flen=%d", dlen, flen);
87 if (flen >= 100) {
88 assertEqualIntA(a, ARCHIVE_FAILED, archive_write_header(a, ae));
89 } else {
90 assertEqualIntA(a, 0, archive_write_header(a, ae));
91 }
92 archive_entry_free(ae);
93
94 /* Tar adds a '/' to directory names. */
95 strcat(dirname, "/");
96
97 /*
98 * Write a dir to it (with trailing '/').
99 */
100 assert((ae = archive_entry_new()) != NULL);
101 archive_entry_copy_pathname(ae, dirname);
102 archive_entry_set_mode(ae, S_IFDIR | 0755);
103 failure("dlen=%d, flen=%d", dlen, flen);
104 if (flen >= 100) {
105 assertEqualIntA(a, ARCHIVE_FAILED, archive_write_header(a, ae));
106 } else {
107 assertEqualIntA(a, 0, archive_write_header(a, ae));
108 }
109 archive_entry_free(ae);
110
111 /* Close out the archive. */
112 assertEqualIntA(a, ARCHIVE_OK, archive_write_close(a));
113 assertEqualInt(ARCHIVE_OK, archive_write_free(a));
114
115 /*
116 * Now, read the data back.
117 */
118 assert((a = archive_read_new()) != NULL);
119 assertA(0 == archive_read_support_format_all(a));
120 assertA(0 == archive_read_support_filter_all(a));
121 assertA(0 == archive_read_open_memory(a, buff, used));
122
123 if (flen <= 100) {
124 /* Read the file and check the filename. */
125 assertA(0 == archive_read_next_header(a, &ae));
126 failure("dlen=%d, flen=%d", dlen, flen);
127 assertEqualString(filename, archive_entry_pathname(ae));
128 assertEqualInt((S_IFREG | 0755), archive_entry_mode(ae));
129 }
130
131 /*
132 * Read the two dirs and check the names.
133 *
134 * Both dirs should read back with the same name, since
135 * tar should add a trailing '/' to any dir that doesn't
136 * already have one.
137 */
138 if (flen <= 99) {
139 assertA(0 == archive_read_next_header(a, &ae));
140 assert((S_IFDIR | 0755) == archive_entry_mode(ae));
141 failure("dlen=%d, flen=%d", dlen, flen);
142 assertEqualString(dirname, archive_entry_pathname(ae));
143 }
144
145 if (flen <= 99) {
146 assertA(0 == archive_read_next_header(a, &ae));
147 assert((S_IFDIR | 0755) == archive_entry_mode(ae));
148 assertEqualString(dirname, archive_entry_pathname(ae));
149 }
150
151 /* Verify the end of the archive. */
152 failure("This fails if entries were written that should not have been written. dlen=%d, flen=%d", dlen, flen);
153 assertEqualInt(1, archive_read_next_header(a, &ae));
154 assertEqualIntA(a, ARCHIVE_OK, archive_read_close(a));
155 assertEqualInt(ARCHIVE_OK, archive_read_free(a));
156 }
157
DEFINE_TEST(test_ustar_filenames)158 DEFINE_TEST(test_ustar_filenames)
159 {
160 int dlen, flen;
161
162 /* Try a bunch of different file/dir lengths that add up
163 * to just a little less or a little more than 100 bytes.
164 * This exercises the code that splits paths between ustar
165 * filename and prefix fields.
166 */
167 for (dlen = 5; dlen < 70; dlen += 5) {
168 for (flen = 100 - dlen - 5; flen < 100 - dlen + 5; flen++) {
169 test_filename(NULL, dlen, flen);
170 test_filename("/", dlen, flen);
171 }
172 }
173
174 /* Probe the 100-char limit for paths with no '/'. */
175 for (flen = 90; flen < 110; flen++) {
176 test_filename(NULL, 0, flen);
177 test_filename("/", dlen, flen);
178 }
179
180 /* XXXX TODO Probe the 100-char limit with a dir prefix. */
181 /* XXXX TODO Probe the 255-char total limit. */
182 }
183