xref: /freebsd/contrib/libarchive/cpio/test/test_option_c.c (revision e64fe029e9d3ce476e77a478318e0c3cd201ff08)
1caf54c4fSMartin Matuska /*-
2caf54c4fSMartin Matuska  * Copyright (c) 2003-2007 Tim Kientzle
3caf54c4fSMartin Matuska  * All rights reserved.
4caf54c4fSMartin Matuska  *
5caf54c4fSMartin Matuska  * Redistribution and use in source and binary forms, with or without
6caf54c4fSMartin Matuska  * modification, are permitted provided that the following conditions
7caf54c4fSMartin Matuska  * are met:
8caf54c4fSMartin Matuska  * 1. Redistributions of source code must retain the above copyright
9caf54c4fSMartin Matuska  *    notice, this list of conditions and the following disclaimer.
10caf54c4fSMartin Matuska  * 2. Redistributions in binary form must reproduce the above copyright
11caf54c4fSMartin Matuska  *    notice, this list of conditions and the following disclaimer in the
12caf54c4fSMartin Matuska  *    documentation and/or other materials provided with the distribution.
13caf54c4fSMartin Matuska  *
14caf54c4fSMartin Matuska  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
15caf54c4fSMartin Matuska  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
16caf54c4fSMartin Matuska  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
17caf54c4fSMartin Matuska  * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
18caf54c4fSMartin Matuska  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
19caf54c4fSMartin Matuska  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
20caf54c4fSMartin Matuska  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
21caf54c4fSMartin Matuska  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22caf54c4fSMartin Matuska  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
23caf54c4fSMartin Matuska  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24caf54c4fSMartin Matuska  */
25caf54c4fSMartin Matuska #include "test.h"
26caf54c4fSMartin Matuska __FBSDID("$FreeBSD$");
27caf54c4fSMartin Matuska 
28caf54c4fSMartin Matuska static int
29caf54c4fSMartin Matuska is_octal(const char *p, size_t l)
30caf54c4fSMartin Matuska {
31caf54c4fSMartin Matuska 	while (l > 0) {
32caf54c4fSMartin Matuska 		if (*p < '0' || *p > '7')
33caf54c4fSMartin Matuska 			return (0);
34caf54c4fSMartin Matuska 		--l;
35caf54c4fSMartin Matuska 		++p;
36caf54c4fSMartin Matuska 	}
37caf54c4fSMartin Matuska 	return (1);
38caf54c4fSMartin Matuska }
39caf54c4fSMartin Matuska 
40*e64fe029SMartin Matuska static long long int
41caf54c4fSMartin Matuska from_octal(const char *p, size_t l)
42caf54c4fSMartin Matuska {
43*e64fe029SMartin Matuska 	long long int r = 0;
44caf54c4fSMartin Matuska 
45caf54c4fSMartin Matuska 	while (l > 0) {
46caf54c4fSMartin Matuska 		r *= 8;
47caf54c4fSMartin Matuska 		r += *p - '0';
48caf54c4fSMartin Matuska 		--l;
49caf54c4fSMartin Matuska 		++p;
50caf54c4fSMartin Matuska 	}
51caf54c4fSMartin Matuska 	return (r);
52caf54c4fSMartin Matuska }
53caf54c4fSMartin Matuska 
546c95142eSMartin Matuska #if !defined(_WIN32) || defined(__CYGWIN__)
556c95142eSMartin Matuska static int
566c95142eSMartin Matuska nlinks(const char *p)
576c95142eSMartin Matuska {
586c95142eSMartin Matuska 	struct stat st;
596c95142eSMartin Matuska 	assertEqualInt(0, stat(p, &st));
606c95142eSMartin Matuska 	return st.st_nlink;
616c95142eSMartin Matuska }
626c95142eSMartin Matuska #endif
636c95142eSMartin Matuska 
64caf54c4fSMartin Matuska DEFINE_TEST(test_option_c)
65caf54c4fSMartin Matuska {
66caf54c4fSMartin Matuska 	FILE *filelist;
67caf54c4fSMartin Matuska 	int r;
68cdf63a70SMartin Matuska 	int uid = 1000;
69cdf63a70SMartin Matuska 	int dev, ino, gid = 1000;
70caf54c4fSMartin Matuska 	time_t t, now;
71caf54c4fSMartin Matuska 	char *p, *e;
72caf54c4fSMartin Matuska 	size_t s;
73caf54c4fSMartin Matuska 
74caf54c4fSMartin Matuska 	assertUmask(0);
75caf54c4fSMartin Matuska 
76caf54c4fSMartin Matuska 	/*
77caf54c4fSMartin Matuska 	 * Create an assortment of files.
78caf54c4fSMartin Matuska 	 * TODO: Extend this to cover more filetypes.
79caf54c4fSMartin Matuska 	 */
80caf54c4fSMartin Matuska 	filelist = fopen("filelist", "w");
81caf54c4fSMartin Matuska 
82caf54c4fSMartin Matuska 	/* "file" */
83caf54c4fSMartin Matuska 	assertMakeFile("file", 0644, "1234567890");
84caf54c4fSMartin Matuska 	fprintf(filelist, "file\n");
85caf54c4fSMartin Matuska 
86caf54c4fSMartin Matuska 	/* "symlink" */
87caf54c4fSMartin Matuska 	if (canSymlink()) {
8852c2bb75SMartin Matuska 		assertMakeSymlink("symlink", "file", 0);
89caf54c4fSMartin Matuska 		fprintf(filelist, "symlink\n");
90caf54c4fSMartin Matuska 	}
91caf54c4fSMartin Matuska 
92caf54c4fSMartin Matuska 	/* "dir" */
93caf54c4fSMartin Matuska 	assertMakeDir("dir", 0775);
94caf54c4fSMartin Matuska 	/* Record some facts about what we just created: */
95caf54c4fSMartin Matuska 	now = time(NULL); /* They were all created w/in last two seconds. */
96caf54c4fSMartin Matuska 	fprintf(filelist, "dir\n");
97caf54c4fSMartin Matuska 
98caf54c4fSMartin Matuska 	/* Use the cpio program to create an archive. */
99caf54c4fSMartin Matuska 	fclose(filelist);
100cdf63a70SMartin Matuska 	r = systemf("%s -R 1000:1000 -oc <filelist >basic.out 2>basic.err", testprog);
101caf54c4fSMartin Matuska 	/* Verify that nothing went to stderr. */
102caf54c4fSMartin Matuska 	assertTextFileContents("1 block\n", "basic.err");
103caf54c4fSMartin Matuska 
104caf54c4fSMartin Matuska 	/* Assert that the program finished. */
105caf54c4fSMartin Matuska 	failure("%s -oc crashed", testprog);
106caf54c4fSMartin Matuska 	if (!assertEqualInt(r, 0))
107caf54c4fSMartin Matuska 		return;
108caf54c4fSMartin Matuska 
109caf54c4fSMartin Matuska 	/* Verify that stdout is a well-formed cpio file in "odc" format. */
110caf54c4fSMartin Matuska 	p = slurpfile(&s, "basic.out");
111caf54c4fSMartin Matuska 	assertEqualInt(s, 512);
112caf54c4fSMartin Matuska 	e = p;
113caf54c4fSMartin Matuska 
114caf54c4fSMartin Matuska 	/*
115caf54c4fSMartin Matuska 	 * Some of these assertions could be stronger, but it's
116caf54c4fSMartin Matuska 	 * a little tricky because they depend on the local environment.
117caf54c4fSMartin Matuska 	 */
118caf54c4fSMartin Matuska 
119caf54c4fSMartin Matuska 	/* First entry is "file" */
120caf54c4fSMartin Matuska 	assert(is_octal(e, 76)); /* Entire header is octal digits. */
121caf54c4fSMartin Matuska 	assertEqualMem(e + 0, "070707", 6); /* Magic */
122caf54c4fSMartin Matuska 	assert(is_octal(e + 6, 6)); /* dev */
123caf54c4fSMartin Matuska 	dev = from_octal(e + 6, 6);
124caf54c4fSMartin Matuska 	assert(is_octal(e + 12, 6)); /* ino */
125caf54c4fSMartin Matuska 	ino = from_octal(e + 12, 6);
126caf54c4fSMartin Matuska #if defined(_WIN32) && !defined(__CYGWIN__)
127caf54c4fSMartin Matuska 	/* Group members bits and others bits do not work. */
128caf54c4fSMartin Matuska 	assertEqualMem(e + 18, "100666", 6); /* Mode */
129caf54c4fSMartin Matuska #else
130caf54c4fSMartin Matuska 	assertEqualMem(e + 18, "100644", 6); /* Mode */
131caf54c4fSMartin Matuska #endif
132caf54c4fSMartin Matuska 	if (uid < 0)
133caf54c4fSMartin Matuska 		uid = from_octal(e + 24, 6);
134caf54c4fSMartin Matuska 	assertEqualInt(from_octal(e + 24, 6), uid); /* uid */
135caf54c4fSMartin Matuska 	assert(is_octal(e + 30, 6)); /* gid */
136caf54c4fSMartin Matuska 	gid = from_octal(e + 30, 6);
137caf54c4fSMartin Matuska 	assertEqualMem(e + 36, "000001", 6); /* nlink */
138caf54c4fSMartin Matuska 	failure("file entries should not have rdev set (dev field was 0%o)",
139caf54c4fSMartin Matuska 	    dev);
140caf54c4fSMartin Matuska 	assertEqualMem(e + 42, "000000", 6); /* rdev */
141caf54c4fSMartin Matuska 	t = from_octal(e + 48, 11); /* mtime */
142caf54c4fSMartin Matuska 	assert(t <= now); /* File wasn't created in future. */
143caf54c4fSMartin Matuska 	assert(t >= now - 2); /* File was created w/in last 2 secs. */
144caf54c4fSMartin Matuska 	assertEqualMem(e + 59, "000005", 6); /* Name size */
145caf54c4fSMartin Matuska 	assertEqualMem(e + 65, "00000000012", 11); /* File size */
146caf54c4fSMartin Matuska 	assertEqualMem(e + 76, "file\0", 5); /* Name contents */
147caf54c4fSMartin Matuska 	assertEqualMem(e + 81, "1234567890", 10); /* File contents */
148caf54c4fSMartin Matuska 	e += 91;
149caf54c4fSMartin Matuska 
150caf54c4fSMartin Matuska 	/* "symlink" pointing to "file" */
151caf54c4fSMartin Matuska 	if (canSymlink()) {
152caf54c4fSMartin Matuska 		assert(is_octal(e, 76)); /* Entire header is octal digits. */
153caf54c4fSMartin Matuska 		assertEqualMem(e + 0, "070707", 6); /* Magic */
154caf54c4fSMartin Matuska 		assertEqualInt(dev, from_octal(e + 6, 6)); /* dev */
155caf54c4fSMartin Matuska 		assert(ino != from_octal(e + 12, 6)); /* ino */
156caf54c4fSMartin Matuska #if !defined(_WIN32) || defined(__CYGWIN__)
157caf54c4fSMartin Matuska 		/* On Windows, symbolic link and group members bits and
158caf54c4fSMartin Matuska 		 * others bits do not work. */
159caf54c4fSMartin Matuska 		assertEqualMem(e + 18, "120777", 6); /* Mode */
160caf54c4fSMartin Matuska #endif
161caf54c4fSMartin Matuska 		assertEqualInt(from_octal(e + 24, 6), uid); /* uid */
162caf54c4fSMartin Matuska 		assertEqualInt(gid, from_octal(e + 30, 6)); /* gid */
163caf54c4fSMartin Matuska 		assertEqualMem(e + 36, "000001", 6); /* nlink */
164*e64fe029SMartin Matuska 		failure("file entries should have rdev == 0 (dev was 0%llo)",
165caf54c4fSMartin Matuska 		    from_octal(e + 6, 6));
166caf54c4fSMartin Matuska 		assertEqualMem(e + 42, "000000", 6); /* rdev */
167caf54c4fSMartin Matuska 		t = from_octal(e + 48, 11); /* mtime */
168caf54c4fSMartin Matuska 		assert(t <= now); /* File wasn't created in future. */
169caf54c4fSMartin Matuska 		assert(t >= now - 2); /* File was created w/in last 2 secs. */
170caf54c4fSMartin Matuska 		assertEqualMem(e + 59, "000010", 6); /* Name size */
171caf54c4fSMartin Matuska 		assertEqualMem(e + 65, "00000000004", 11); /* File size */
172caf54c4fSMartin Matuska 		assertEqualMem(e + 76, "symlink\0", 8); /* Name contents */
173caf54c4fSMartin Matuska 		assertEqualMem(e + 84, "file", 4); /* Symlink target. */
174caf54c4fSMartin Matuska 		e += 88;
175caf54c4fSMartin Matuska 	}
176caf54c4fSMartin Matuska 
177caf54c4fSMartin Matuska 	/* "dir" */
178caf54c4fSMartin Matuska 	assert(is_octal(e, 76));
179caf54c4fSMartin Matuska 	assertEqualMem(e + 0, "070707", 6); /* Magic */
180caf54c4fSMartin Matuska 	/* Dev should be same as first entry. */
181caf54c4fSMartin Matuska 	assert(is_octal(e + 6, 6)); /* dev */
182caf54c4fSMartin Matuska 	assertEqualInt(dev, from_octal(e + 6, 6));
183caf54c4fSMartin Matuska 	/* Ino must be different from first entry. */
184caf54c4fSMartin Matuska 	assert(is_octal(e + 12, 6)); /* ino */
185caf54c4fSMartin Matuska 	assert(ino != from_octal(e + 12, 6));
186caf54c4fSMartin Matuska #if defined(_WIN32) && !defined(__CYGWIN__)
187caf54c4fSMartin Matuska 	/* Group members bits and others bits do not work. */
188caf54c4fSMartin Matuska 	assertEqualMem(e + 18, "040777", 6); /* Mode */
189caf54c4fSMartin Matuska #else
1906c95142eSMartin Matuska 	/* Accept 042775 to accommodate systems where sgid bit propagates. */
191caf54c4fSMartin Matuska 	if (memcmp(e + 18, "042775", 6) != 0)
192caf54c4fSMartin Matuska 		assertEqualMem(e + 18, "040775", 6); /* Mode */
193caf54c4fSMartin Matuska #endif
1946c95142eSMartin Matuska 	assertEqualInt(uid, from_octal(e + 24, 6)); /* uid */
195caf54c4fSMartin Matuska 	/* Gid should be same as first entry. */
196caf54c4fSMartin Matuska 	assert(is_octal(e + 30, 6)); /* gid */
197caf54c4fSMartin Matuska 	assertEqualInt(gid, from_octal(e + 30, 6));
1986c95142eSMartin Matuska 
1996c95142eSMartin Matuska #if !defined(_WIN32) || defined(__CYGWIN__)
2006c95142eSMartin Matuska 	assertEqualInt(nlinks("dir"), from_octal(e + 36, 6)); /* Nlink */
201caf54c4fSMartin Matuska #endif
2026c95142eSMartin Matuska 
203caf54c4fSMartin Matuska 	t = from_octal(e + 48, 11); /* mtime */
204caf54c4fSMartin Matuska 	assert(t <= now); /* File wasn't created in future. */
205caf54c4fSMartin Matuska 	assert(t >= now - 2); /* File was created w/in last 2 secs. */
206caf54c4fSMartin Matuska 	assertEqualMem(e + 59, "000004", 6); /* Name size */
207caf54c4fSMartin Matuska 	assertEqualMem(e + 65, "00000000000", 11); /* File size */
208caf54c4fSMartin Matuska 	assertEqualMem(e + 76, "dir\0", 4); /* name */
209caf54c4fSMartin Matuska 	e += 80;
210caf54c4fSMartin Matuska 
211caf54c4fSMartin Matuska 	/* TODO: Verify other types of entries. */
212caf54c4fSMartin Matuska 
213caf54c4fSMartin Matuska 	/* Last entry is end-of-archive marker. */
214caf54c4fSMartin Matuska 	assert(is_octal(e, 76));
215caf54c4fSMartin Matuska 	assertEqualMem(e + 0, "070707", 6); /* Magic */
216caf54c4fSMartin Matuska 	assertEqualMem(e + 6, "000000", 6); /* dev */
217caf54c4fSMartin Matuska 	assertEqualMem(e + 12, "000000", 6); /* ino */
218caf54c4fSMartin Matuska 	assertEqualMem(e + 18, "000000", 6); /* Mode */
219caf54c4fSMartin Matuska 	assertEqualMem(e + 24, "000000", 6); /* uid */
220caf54c4fSMartin Matuska 	assertEqualMem(e + 30, "000000", 6); /* gid */
221caf54c4fSMartin Matuska 	assertEqualMem(e + 36, "000001", 6); /* Nlink */
222caf54c4fSMartin Matuska 	assertEqualMem(e + 42, "000000", 6); /* rdev */
223caf54c4fSMartin Matuska 	assertEqualMem(e + 48, "00000000000", 11); /* mtime */
224caf54c4fSMartin Matuska 	assertEqualMem(e + 59, "000013", 6); /* Name size */
225caf54c4fSMartin Matuska 	assertEqualMem(e + 65, "00000000000", 11); /* File size */
226caf54c4fSMartin Matuska 	assertEqualMem(e + 76, "TRAILER!!!\0", 11); /* Name */
227caf54c4fSMartin Matuska 
228caf54c4fSMartin Matuska 	free(p);
229caf54c4fSMartin Matuska }
230