Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/contrib/libarchive/tar/test/test_copy.c
39507 views
1
/*-
2
* SPDX-License-Identifier: BSD-2-Clause
3
*
4
* Copyright (c) 2003-2007 Tim Kientzle
5
* All rights reserved.
6
*/
7
#include "test.h"
8
9
#if defined(__CYGWIN__)
10
# include <limits.h>
11
# include <sys/cygwin.h>
12
#endif
13
#if defined(_WIN32) && !defined(__CYGWIN__)
14
# include <direct.h>
15
#endif
16
17
/*
18
* Try to figure out how deep we can go in our tests. Assumes that
19
* the first call to this function has the longest starting cwd (which
20
* is currently "<testdir>/original"). This is mostly to work around
21
* limits in our Win32 support.
22
*
23
* Background: On Posix systems, PATH_MAX is merely a limit on the
24
* length of the string passed into a system call. By repeatedly
25
* calling chdir(), you can work with arbitrarily long paths on such
26
* systems. In contrast, Win32 APIs apply PATH_MAX limits to the full
27
* absolute path, so the permissible length of a system call argument
28
* varies with the cwd. Some APIs actually enforce limits
29
* significantly less than PATH_MAX to ensure that you can create
30
* files within the current working directory. The Win32 limits also
31
* apply to Cygwin before 1.7.
32
*
33
* Someday, I want to convert the Win32 support to use newer
34
* wide-character paths with '\\?\' prefix, which has a 32k PATH_MAX
35
* instead of the rather anemic 260 character limit of the older
36
* system calls. Then we can drop this mess (unless we want to
37
* continue to special-case Cygwin 1.5 and earlier).
38
*/
39
static int
40
compute_loop_max(void)
41
{
42
#if defined(_WIN32) && !defined(__CYGWIN__)
43
static int LOOP_MAX = 0;
44
char buf[MAX_PATH];
45
size_t cwdlen;
46
47
if (LOOP_MAX == 0) {
48
assert(_getcwd(buf, MAX_PATH) != NULL);
49
cwdlen = strlen(buf);
50
/* 12 characters = length of 8.3 filename */
51
/* 4 characters = length of "/../" used in symlink tests */
52
/* 1 character = length of extra "/" separator */
53
LOOP_MAX = MAX_PATH - (int)cwdlen - 12 - 4 - 1;
54
}
55
return LOOP_MAX;
56
#elif defined(__CYGWIN__) && !defined(HAVE_CYGWIN_CONV_PATH)
57
static int LOOP_MAX = 0;
58
if (LOOP_MAX == 0) {
59
char wbuf[PATH_MAX];
60
char pbuf[PATH_MAX];
61
size_t wcwdlen;
62
size_t pcwdlen;
63
size_t cwdlen;
64
assert(getcwd(pbuf, PATH_MAX) != NULL);
65
pcwdlen = strlen(pbuf);
66
cygwin_conv_to_full_win32_path(pbuf, wbuf);
67
wcwdlen = strlen(wbuf);
68
cwdlen = ((wcwdlen > pcwdlen) ? wcwdlen : pcwdlen);
69
/* Cygwin helper needs an extra few characters. */
70
LOOP_MAX = PATH_MAX - (int)cwdlen - 12 - 4 - 4;
71
}
72
return LOOP_MAX;
73
#else
74
/* cygwin-1.7 ends up here, along with "normal" unix */
75
return 200; /* restore pre-r278 depth */
76
#endif
77
}
78
79
/* filenames[i] is a distinctive filename of length i. */
80
/* To simplify interpreting failures, each filename ends with a
81
* decimal integer which is the length of the filename. E.g., A
82
* filename ending in "_92" is 92 characters long. To detect errors
83
* which drop or misplace characters, the filenames use a repeating
84
* "abcdefghijklmnopqrstuvwxyz..." pattern. */
85
static char *filenames[201];
86
87
static void
88
compute_filenames(void)
89
{
90
char buff[250];
91
size_t i,j;
92
93
filenames[0] = strdup("");
94
filenames[1] = strdup("1");
95
filenames[2] = strdup("a2");
96
for (i = 3; i < sizeof(filenames)/sizeof(filenames[0]); ++i) {
97
/* Fill with "abcdefghij..." */
98
for (j = 0; j < i; ++j)
99
buff[j] = 'a' + (j % 26);
100
buff[j--] = '\0';
101
/* Work from the end to fill in the number portion. */
102
buff[j--] = '0' + (i % 10);
103
if (i > 9) {
104
buff[j--] = '0' + ((i / 10) % 10);
105
if (i > 99)
106
buff[j--] = '0' + (char)(i / 100);
107
}
108
buff[j] = '_';
109
/* Guard against obvious screwups in the above code. */
110
assertEqualInt(strlen(buff), i);
111
filenames[i] = strdup(buff);
112
}
113
}
114
115
static void
116
create_tree(void)
117
{
118
char buff[260];
119
char buff2[260];
120
int i;
121
int LOOP_MAX;
122
123
compute_filenames();
124
125
/* Log that we'll be omitting some checks. */
126
if (!canSymlink()) {
127
skipping("Symlink checks");
128
}
129
130
assertMakeDir("original", 0775);
131
assertEqualInt(0, chdir("original"));
132
LOOP_MAX = compute_loop_max();
133
134
assertMakeDir("f", 0775);
135
assertMakeDir("l", 0775);
136
assertMakeDir("m", 0775);
137
assertMakeDir("s", 0775);
138
assertMakeDir("d", 0775);
139
140
for (i = 1; i < LOOP_MAX; i++) {
141
failure("Internal sanity check failed: i = %d", i);
142
assert(filenames[i] != NULL);
143
144
snprintf(buff, sizeof(buff), "f/%s", filenames[i]);
145
assertMakeFile(buff, 0777, buff);
146
147
/* Create a link named "l/abcdef..." to the above. */
148
snprintf(buff2, sizeof(buff2), "l/%s", filenames[i]);
149
assertMakeHardlink(buff2, buff);
150
151
/* Create a link named "m/abcdef..." to the above. */
152
snprintf(buff2, sizeof(buff2), "m/%s", filenames[i]);
153
assertMakeHardlink(buff2, buff);
154
155
if (canSymlink()) {
156
/* Create a symlink named "s/abcdef..." to the above. */
157
snprintf(buff, sizeof(buff), "s/%s", filenames[i]);
158
snprintf(buff2, sizeof(buff2), "../f/%s", filenames[i]);
159
failure("buff=\"%s\" buff2=\"%s\"", buff, buff2);
160
assertMakeSymlink(buff, buff2, 0);
161
}
162
/* Create a dir named "d/abcdef...". */
163
buff[0] = 'd';
164
failure("buff=\"%s\"", buff);
165
assertMakeDir(buff, 0775);
166
}
167
168
assertEqualInt(0, chdir(".."));
169
}
170
171
#define LIMIT_NONE 200
172
#define LIMIT_USTAR 100
173
174
static void
175
verify_tree(size_t limit, const char *format)
176
{
177
char name1[260];
178
char name2[260];
179
size_t i, LOOP_MAX;
180
181
LOOP_MAX = compute_loop_max();
182
183
/* Generate the names we know should be there and verify them. */
184
for (i = 1; i < LOOP_MAX; i++) {
185
/* Verify a file named "f/abcdef..." */
186
snprintf(name1, sizeof(name1), "f/%s", filenames[i]);
187
if (i <= limit) {
188
failure("Verifying %s", format);
189
assertFileExists(name1);
190
assertFileContents(name1, (int)strlen(name1), name1);
191
}
192
193
snprintf(name2, sizeof(name2), "l/%s", filenames[i]);
194
if (i + 2 <= limit) {
195
/* Verify hardlink "l/abcdef..." */
196
failure("Verifying %s", format);
197
assertIsHardlink(name1, name2);
198
/* Verify hardlink "m/abcdef..." */
199
name2[0] = 'm';
200
assertIsHardlink(name1, name2);
201
}
202
203
if (canSymlink()) {
204
/* Verify symlink "s/abcdef..." */
205
snprintf(name1, sizeof(name1), "s/%s", filenames[i]);
206
snprintf(name2, sizeof(name2), "../f/%s", filenames[i]);
207
if (strlen(name2) <= limit) {
208
failure("Verifying %s", format);
209
assertIsSymlink(name1, name2, 0);
210
}
211
}
212
213
/* Verify dir "d/abcdef...". */
214
snprintf(name1, sizeof(name1), "d/%s", filenames[i]);
215
if (i + 1 <= limit) { /* +1 for trailing slash */
216
failure("Verifying %s", format);
217
if (assertIsDir(name1, -1)) {
218
/* TODO: opendir/readdir this
219
* directory and make sure
220
* it's empty.
221
*/
222
}
223
}
224
}
225
226
#if !defined(_WIN32) || defined(__CYGWIN__)
227
{
228
const char *dp;
229
/* Now make sure nothing is there that shouldn't be. */
230
for (dp = "dflms"; *dp != '\0'; ++dp) {
231
DIR *d;
232
struct dirent *de;
233
char dir[2];
234
dir[0] = *dp; dir[1] = '\0';
235
d = opendir(dir);
236
failure("Unable to open dir '%s' for testing %s", dir, format);
237
if (!assert(d != NULL))
238
continue;
239
while ((de = readdir(d)) != NULL) {
240
char *p = de->d_name;
241
if (p[0] == '.')
242
continue;
243
switch(dp[0]) {
244
case 'l': case 'm': case 'd':
245
failure("strlen(p)=%zu", strlen(p));
246
assert(strlen(p) < limit);
247
assertEqualString(p,
248
filenames[strlen(p)]);
249
break;
250
case 'f': case 's':
251
failure("strlen(p)=%zu", strlen(p));
252
assert(strlen(p) < limit + 1);
253
assertEqualString(p,
254
filenames[strlen(p)]);
255
break;
256
default:
257
failure("File %s shouldn't be here", p);
258
assert(0);
259
}
260
}
261
closedir(d);
262
}
263
}
264
#endif
265
}
266
267
static void
268
copy_basic(const char *extra_args, const char *name)
269
{
270
int r;
271
272
/* NOTE: for proper operation on cygwin-1.5 and windows, the
273
* length of the name of the directory below must be
274
* less than or equal to the length of the name of the original
275
* directory, "original" This restriction derives from the
276
* extremely limited pathname lengths on those platforms.
277
*/
278
assertMakeDir(name, 0775);
279
assertEqualInt(0, chdir(name));
280
281
/*
282
* Use the tar program to create an archive.
283
*/
284
r = systemf("%s cf archive %s -C ../original f d l m s >pack.out 2>pack.err",
285
testprog, extra_args);
286
failure("Error invoking \"%s cf archive %s\"", testprog, extra_args);
287
assertEqualInt(r, 0);
288
289
/* Verify that nothing went to stdout or stderr. */
290
assertEmptyFile("pack.err");
291
assertEmptyFile("pack.out");
292
293
/*
294
* Use tar to unpack the archive into another directory.
295
*/
296
r = systemf("%s xf archive >unpack.out 2>unpack.err", testprog);
297
failure("Error invoking %s xf archive", testprog);
298
assertEqualInt(r, 0);
299
300
/* Verify that nothing went to stdout or stderr. */
301
assertEmptyFile("unpack.err");
302
assertEmptyFile("unpack.out");
303
304
verify_tree(LIMIT_NONE, name);
305
assertEqualInt(0, chdir(".."));
306
}
307
308
static void
309
copy_ustar(void)
310
{
311
const char *target = "ustar";
312
int r;
313
314
/* NOTE: for proper operation on cygwin-1.5 and windows, the
315
* length of the name of the directory below, "ustar", must be
316
* less than or equal to the length of the name of the original
317
* directory, "original" This restriction derives from the
318
* extremely limited pathname lengths on those platforms.
319
*/
320
assertMakeDir(target, 0775);
321
assertEqualInt(0, chdir(target));
322
323
/*
324
* Use the tar program to create an archive.
325
*/
326
r = systemf("%s cf archive --format=ustar -C ../original f d l m s >pack.out 2>pack.err",
327
testprog);
328
failure("Error invoking \"%s cf archive --format=ustar\"", testprog);
329
assertEqualInt(r, 0);
330
331
/* Verify that nothing went to stdout. */
332
assertEmptyFile("pack.out");
333
/* Stderr is non-empty, since there are a bunch of files
334
* with filenames too long to archive. */
335
336
/*
337
* Use tar to unpack the archive into another directory.
338
*/
339
r = systemf("%s xf archive >unpack.out 2>unpack.err", testprog);
340
failure("Error invoking %s xf archive", testprog);
341
assertEqualInt(r, 0);
342
343
/* Verify that nothing went to stdout or stderr. */
344
assertEmptyFile("unpack.err");
345
assertEmptyFile("unpack.out");
346
347
verify_tree(LIMIT_USTAR, "ustar");
348
assertEqualInt(0, chdir(".."));
349
}
350
351
DEFINE_TEST(test_copy)
352
{
353
assertUmask(0);
354
create_tree(); /* Create sample files in "original" dir. */
355
356
/* Test simple "tar -c | tar -x" pipeline copy. */
357
copy_basic("", "default");
358
359
/* Same, but constrain to ustar format. */
360
copy_ustar();
361
362
/* Same, but with pax format. */
363
copy_basic(" --format pax", "pax");
364
}
365
366