Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/contrib/libarchive/cpio/test/test_format_newc.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
/* Number of bytes needed to pad 'n' to multiple of 'block', assuming
10
* that 'block' is a power of two. This trick can be more easily
11
* remembered as -n & (block - 1), but many compilers quite reasonably
12
* warn about "-n" when n is an unsigned value. (~(n) + 1) is the
13
* same thing, but written in a way that won't offend anyone. */
14
#define PAD(n, block) ((~(n) + 1) & ((block) - 1))
15
16
static int
17
is_hex(const char *p, size_t l)
18
{
19
while (l > 0) {
20
if ((*p >= '0' && *p <= '9')
21
|| (*p >= 'a' && *p <= 'f')
22
|| (*p >= 'A' && *p <= 'F'))
23
{
24
--l;
25
++p;
26
} else
27
return (0);
28
29
}
30
return (1);
31
}
32
33
/* Convert up to 8 hex characters to unsigned 32-bit decimal integer */
34
static uint32_t
35
from_hex(const char *p, size_t l)
36
{
37
uint32_t r = 0;
38
39
while (l > 0) {
40
r *= 16;
41
if (*p >= 'a' && *p <= 'f')
42
r += *p + 10 - 'a';
43
else if (*p >= 'A' && *p <= 'F')
44
r += *p + 10 - 'A';
45
else
46
r += *p - '0';
47
--l;
48
++p;
49
}
50
return (r);
51
}
52
53
#if !defined(_WIN32) || defined(__CYGWIN__)
54
static int
55
nlinks(const char *p)
56
{
57
struct stat st;
58
assertEqualInt(0, stat(p, &st));
59
return st.st_nlink;
60
}
61
#endif
62
63
DEFINE_TEST(test_format_newc)
64
{
65
FILE *list;
66
int r;
67
uint32_t devmajor, devminor, ino, gid, uid;
68
time_t t, t2, now;
69
char *p, *e;
70
size_t s;
71
uint64_t fs, ns;
72
char result[1024];
73
74
assertUmask(0);
75
76
#if !defined(_WIN32)
77
uid = getuid();
78
#endif
79
80
/*
81
* Create an assortment of files.
82
* TODO: Extend this to cover more filetypes.
83
*/
84
list = fopen("list", "w");
85
86
/* "file1" */
87
assertMakeFile("file1", 0644, "1234567890");
88
fprintf(list, "file1\n");
89
90
/* "hardlink" */
91
assertMakeHardlink("hardlink", "file1");
92
fprintf(list, "hardlink\n");
93
94
/* Another hardlink, but this one won't be archived. */
95
assertMakeHardlink("hardlink2", "file1");
96
97
/* "symlink" */
98
if (canSymlink()) {
99
assertMakeSymlink("symlink", "file1", 0);
100
fprintf(list, "symlink\n");
101
}
102
103
/* "dir" */
104
assertMakeDir("dir", 0775);
105
fprintf(list, "dir\n");
106
107
/* Setup result message. */
108
memset(result, 0, sizeof(result));
109
if (is_LargeInode("file1")) {
110
strncat(result,
111
"bsdcpio: file1: large inode number truncated: ",
112
sizeof(result) - strlen(result) -1);
113
strncat(result, strerror(ERANGE),
114
sizeof(result) - strlen(result) -1);
115
strncat(result, "\n",
116
sizeof(result) - strlen(result) -1);
117
}
118
if (canSymlink() && is_LargeInode("symlink")) {
119
strncat(result,
120
"bsdcpio: symlink: large inode number truncated: ",
121
sizeof(result) - strlen(result) -1);
122
strncat(result, strerror(ERANGE),
123
sizeof(result) - strlen(result) -1);
124
strncat(result, "\n",
125
sizeof(result) - strlen(result) -1);
126
}
127
if (is_LargeInode("dir")) {
128
strncat(result,
129
"bsdcpio: dir: large inode number truncated: ",
130
sizeof(result) - strlen(result) -1);
131
strncat(result, strerror(ERANGE),
132
sizeof(result) - strlen(result) -1);
133
strncat(result, "\n",
134
sizeof(result) - strlen(result) -1);
135
}
136
if (is_LargeInode("hardlink")) {
137
strncat(result,
138
"bsdcpio: hardlink: large inode number truncated: ",
139
sizeof(result) - strlen(result) -1);
140
strncat(result, strerror(ERANGE),
141
sizeof(result) - strlen(result) -1);
142
strncat(result, "\n",
143
sizeof(result) - strlen(result) -1);
144
}
145
146
/* Record some facts about what we just created: */
147
now = time(NULL); /* They were all created w/in last two seconds. */
148
149
/* Use the cpio program to create an archive. */
150
fclose(list);
151
r = systemf("%s -o --format=newc <list >newc.out 2>newc.err",
152
testprog);
153
if (!assertEqualInt(r, 0))
154
return;
155
156
/* Verify that nothing went to stderr. */
157
if (canSymlink()) {
158
strncat(result, "2 blocks\n", sizeof(result) - strlen(result) -1);
159
} else {
160
strncat(result, "1 block\n", sizeof(result) - strlen(result) -1);
161
}
162
assertTextFileContents(result, "newc.err");
163
164
/* Verify that stdout is a well-formed cpio file in "newc" format. */
165
p = slurpfile(&s, "newc.out");
166
assertEqualInt(s, canSymlink() ? 1024 : 512);
167
e = p;
168
169
/*
170
* Some of these assertions could be stronger, but it's
171
* a little tricky because they depend on the local environment.
172
*/
173
174
/* First entry is "file1" */
175
assert(is_hex(e, 110)); /* Entire header is octal digits. */
176
assertEqualMem(e + 0, "070701", 6); /* Magic */
177
ino = from_hex(e + 6, 8); /* ino */
178
#if defined(_WIN32) && !defined(__CYGWIN__)
179
/* Group members bits and others bits do not work. */
180
assertEqualInt(0x8180, from_hex(e + 14, 8) & 0xffc0); /* Mode */
181
#else
182
assertEqualInt(0x81a4, from_hex(e + 14, 8)); /* Mode */
183
#endif
184
#if defined(_WIN32)
185
uid = from_hex(e + 22, 8);
186
#else
187
assertEqualInt(from_hex(e + 22, 8), uid); /* uid */
188
#endif
189
gid = from_hex(e + 30, 8); /* gid */
190
assertEqualMem(e + 38, "00000003", 8); /* nlink */
191
t = from_hex(e + 46, 8); /* mtime */
192
failure("t=%#08jx now=%#08jx=%jd", (uintmax_t)t, (uintmax_t)now,
193
(intmax_t)now);
194
assert(t <= now); /* File wasn't created in future. */
195
failure("t=%#08jx now - 2=%#08jx=%jd", (uintmax_t)t, (uintmax_t)now - 2,
196
(intmax_t)now - 2);
197
assert(t >= now - 2); /* File was created w/in last 2 secs. */
198
failure("newc format stores body only with last appearance of a link\n"
199
" first appearance should be empty, so this file size\n"
200
" field should be zero");
201
assertEqualInt(0, from_hex(e + 54, 8)); /* File size */
202
fs = (uint64_t)from_hex(e + 54, 8);
203
fs += PAD(fs, 4);
204
devmajor = from_hex(e + 62, 8); /* devmajor */
205
devminor = from_hex(e + 70, 8); /* devminor */
206
assert(is_hex(e + 78, 8)); /* rdevmajor */
207
assert(is_hex(e + 86, 8)); /* rdevminor */
208
assertEqualMem(e + 94, "00000006", 8); /* Name size */
209
ns = (uint64_t)from_hex(e + 94, 8);
210
ns += PAD(ns + 2, 4);
211
assertEqualInt(0, from_hex(e + 102, 8)); /* check field */
212
assertEqualMem(e + 110, "file1\0", 6); /* Name contents */
213
/* Since there's another link, no file contents here. */
214
/* But add in file size so that an error here doesn't cascade. */
215
e += 110 + fs + ns;
216
217
if (canSymlink()) {
218
/* "symlink" pointing to "file1" */
219
assert(is_hex(e, 110));
220
assertEqualMem(e + 0, "070701", 6); /* Magic */
221
assert(is_hex(e + 6, 8)); /* ino */
222
#if defined(_WIN32) && !defined(__CYGWIN__)
223
/* Mode: Group members bits and others bits do not work. */
224
assertEqualInt(0xa180, from_hex(e + 14, 8) & 0xffc0);
225
#else
226
assertEqualInt(0xa1ff, from_hex(e + 14, 8)); /* Mode */
227
#endif
228
assertEqualInt(from_hex(e + 22, 8), uid); /* uid */
229
assertEqualInt(gid, from_hex(e + 30, 8)); /* gid */
230
assertEqualMem(e + 38, "00000001", 8); /* nlink */
231
t2 = from_hex(e + 46, 8); /* mtime */
232
failure("First entry created at t=%#08jx this entry created"
233
" at t2=%#08jx", (uintmax_t)t, (uintmax_t)t2);
234
assert(t2 == t || t2 == t + 1); /* Almost same as first entry. */
235
assertEqualMem(e + 54, "00000005", 8); /* File size */
236
fs = (uint64_t)from_hex(e + 54, 8);
237
fs += PAD(fs, 4);
238
assertEqualInt(devmajor, from_hex(e + 62, 8)); /* devmajor */
239
assertEqualInt(devminor, from_hex(e + 70, 8)); /* devminor */
240
assert(is_hex(e + 78, 8)); /* rdevmajor */
241
assert(is_hex(e + 86, 8)); /* rdevminor */
242
assertEqualMem(e + 94, "00000008", 8); /* Name size */
243
ns = (uint64_t)from_hex(e + 94, 8);
244
ns += PAD(ns + 2, 4);
245
assertEqualInt(0, from_hex(e + 102, 8)); /* check field */
246
assertEqualMem(e + 110, "symlink\0\0\0", 10); /* Name contents */
247
assertEqualMem(e + 110 + ns, "file1\0\0\0", 8); /* symlink target */
248
e += 110 + fs + ns;
249
}
250
251
/* "dir" */
252
assert(is_hex(e, 110));
253
assertEqualMem(e + 0, "070701", 6); /* Magic */
254
assert(is_hex(e + 6, 8)); /* ino */
255
#if defined(_WIN32) && !defined(__CYGWIN__)
256
/* Group members bits and others bits do not work. */
257
assertEqualInt(0x41c0, from_hex(e + 14, 8) & 0xffc0); /* Mode */
258
#else
259
/* Mode: sgid bit sometimes propagates from parent dirs, ignore it. */
260
assertEqualInt(040775, from_hex(e + 14, 8) & ~02000);
261
#endif
262
assertEqualInt(uid, from_hex(e + 22, 8)); /* uid */
263
assertEqualInt(gid, from_hex(e + 30, 8)); /* gid */
264
#if !defined(_WIN32) || defined(__CYGWIN__)
265
assertEqualInt(nlinks("dir"), from_hex(e + 38, 8)); /* nlinks */
266
#endif
267
t2 = from_hex(e + 46, 8); /* mtime */
268
failure("First entry created at t=%#08jx this entry created at"
269
"t2=%#08jx", (uintmax_t)t, (uintmax_t)t2);
270
assert(t2 == t || t2 == t + 1); /* Almost same as first entry. */
271
assertEqualMem(e + 54, "00000000", 8); /* File size */
272
fs = (uint64_t)from_hex(e + 54, 8);
273
fs += PAD(fs, 4);
274
assertEqualInt(devmajor, from_hex(e + 62, 8)); /* devmajor */
275
assertEqualInt(devminor, from_hex(e + 70, 8)); /* devminor */
276
assert(is_hex(e + 78, 8)); /* rdevmajor */
277
assert(is_hex(e + 86, 8)); /* rdevminor */
278
assertEqualMem(e + 94, "00000004", 8); /* Name size */
279
ns = (uint64_t)from_hex(e + 94, 8);
280
ns += PAD(ns + 2, 4);
281
assertEqualInt(0, from_hex(e + 102, 8)); /* check field */
282
assertEqualMem(e + 110, "dir\0\0\0", 6); /* Name contents */
283
e += 110 + fs + ns;
284
285
/* Hardlink identical to "file1" */
286
/* Since we only wrote two of the three links to this
287
* file, this link should get deferred by the hardlink logic. */
288
assert(is_hex(e, 110));
289
assertEqualMem(e + 0, "070701", 6); /* Magic */
290
failure("If these aren't the same, then the hardlink detection failed to match them.");
291
assertEqualInt(ino, from_hex(e + 6, 8)); /* ino */
292
#if defined(_WIN32) && !defined(__CYGWIN__)
293
/* Group members bits and others bits do not work. */
294
assertEqualInt(0x8180, from_hex(e + 14, 8) & 0xffc0); /* Mode */
295
#else
296
assertEqualInt(0x81a4, from_hex(e + 14, 8)); /* Mode */
297
#endif
298
assertEqualInt(from_hex(e + 22, 8), uid); /* uid */
299
assertEqualInt(gid, from_hex(e + 30, 8)); /* gid */
300
assertEqualMem(e + 38, "00000003", 8); /* nlink */
301
t2 = from_hex(e + 46, 8); /* mtime */
302
failure("First entry created at t=%#08jx this entry created at"
303
"t2=%#08jx", (uintmax_t)t, (uintmax_t)t2);
304
assert(t2 == t || t2 == t + 1); /* Almost same as first entry. */
305
assertEqualInt(10, from_hex(e + 54, 8)); /* File size */
306
fs = (uint64_t)from_hex(e + 54, 8);
307
fs += PAD(fs, 4);
308
assertEqualInt(devmajor, from_hex(e + 62, 8)); /* devmajor */
309
assertEqualInt(devminor, from_hex(e + 70, 8)); /* devminor */
310
assert(is_hex(e + 78, 8)); /* rdevmajor */
311
assert(is_hex(e + 86, 8)); /* rdevminor */
312
assertEqualMem(e + 94, "00000009", 8); /* Name size */
313
ns = (uint64_t)from_hex(e + 94, 8);
314
ns += PAD(ns + 2, 4);
315
assertEqualInt(0, from_hex(e + 102, 8)); /* check field */
316
assertEqualMem(e + 110, "hardlink\0\0", 10); /* Name contents */
317
assertEqualMem(e + 110 + ns, "1234567890\0\0", 12); /* File contents */
318
e += 110 + ns + fs;
319
320
/* Last entry is end-of-archive marker. */
321
assert(is_hex(e, 110));
322
assertEqualMem(e + 0, "070701", 6); /* Magic */
323
assertEqualMem(e + 8, "00000000", 8); /* ino */
324
assertEqualMem(e + 14, "00000000", 8); /* mode */
325
assertEqualMem(e + 22, "00000000", 8); /* uid */
326
assertEqualMem(e + 30, "00000000", 8); /* gid */
327
assertEqualMem(e + 38, "00000001", 8); /* nlink */
328
assertEqualMem(e + 46, "00000000", 8); /* mtime */
329
assertEqualMem(e + 54, "00000000", 8); /* size */
330
assertEqualMem(e + 62, "00000000", 8); /* devmajor */
331
assertEqualMem(e + 70, "00000000", 8); /* devminor */
332
assertEqualMem(e + 78, "00000000", 8); /* rdevmajor */
333
assertEqualMem(e + 86, "00000000", 8); /* rdevminor */
334
assertEqualInt(11, from_hex(e + 94, 8)); /* name size */
335
assertEqualMem(e + 102, "00000000", 8); /* check field */
336
assertEqualMem(e + 110, "TRAILER!!!\0\0", 12); /* Name */
337
338
free(p);
339
}
340
341