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