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
28static void
29verify_files(const char *msg)
30{
31	/*
32	 * Verify unpacked files.
33	 */
34
35	/* Regular file with 2 links. */
36	failure("%s", msg);
37	assertIsReg("file", 0644);
38	failure("%s", msg);
39	assertFileSize("file", 10);
40	failure("%s", msg);
41	assertFileNLinks("file", 2);
42
43	/* Another name for the same file. */
44	failure("%s", msg);
45	assertIsHardlink("linkfile", "file");
46
47	/* Symlink */
48	if (canSymlink())
49		assertIsSymlink("symlink", "file", 0);
50
51	/* Another file with 1 link and different permissions. */
52	failure("%s", msg);
53	assertIsReg("file2", 0777);
54	failure("%s", msg);
55	assertFileSize("file2", 10);
56	failure("%s", msg);
57	assertFileNLinks("file2", 1);
58
59	/* dir */
60	assertIsDir("dir", 0775);
61}
62
63static void
64basic_cpio(const char *target,
65    const char *pack_options,
66    const char *unpack_options,
67    const char *se, const char *se2)
68{
69	int r;
70
71	if (!assertMakeDir(target, 0775))
72	    return;
73
74	/* Use the cpio program to create an archive. */
75	r = systemf("%s -R 1000:1000 -o %s < filelist >%s/archive 2>%s/pack.err",
76	    testprog, pack_options, target, target);
77	failure("Error invoking %s -o %s", testprog, pack_options);
78	assertEqualInt(r, 0);
79
80	assertChdir(target);
81
82	/* Verify stderr. */
83	failure("Expected: %s, options=%s", se, pack_options);
84	assertTextFileContents(se, "pack.err");
85
86	/*
87	 * Use cpio to unpack the archive into another directory.
88	 */
89	r = systemf("%s -i %s< archive >unpack.out 2>unpack.err",
90	    testprog, unpack_options);
91	failure("Error invoking %s -i %s", testprog, unpack_options);
92	assertEqualInt(r, 0);
93
94	/* Verify stderr. */
95	failure("Error invoking %s -i %s in dir %s", testprog, unpack_options, target);
96	assertTextFileContents(se2, "unpack.err");
97
98	verify_files(pack_options);
99
100	assertChdir("..");
101}
102
103static void
104passthrough(const char *target)
105{
106	int r;
107
108	if (!assertMakeDir(target, 0775))
109		return;
110
111	/*
112	 * Use cpio passthrough mode to copy files to another directory.
113	 */
114	r = systemf("%s -p %s <filelist >%s/stdout 2>%s/stderr",
115	    testprog, target, target, target);
116	failure("Error invoking %s -p", testprog);
117	assertEqualInt(r, 0);
118
119	assertChdir(target);
120
121	/* Verify stderr. */
122	failure("Error invoking %s -p in dir %s",
123	    testprog, target);
124	assertTextFileContents("1 block\n", "stderr");
125
126	verify_files("passthrough");
127	assertChdir("..");
128}
129
130DEFINE_TEST(test_basic)
131{
132	FILE *filelist;
133	const char *msg;
134	char result[1024];
135
136	assertUmask(0);
137
138	/*
139	 * Create an assortment of files on disk.
140	 */
141	filelist = fopen("filelist", "w");
142	memset(result, 0, sizeof(result));
143
144	/* File with 10 bytes content. */
145	assertMakeFile("file", 0644, "1234567890");
146	fprintf(filelist, "file\n");
147	if (is_LargeInode("file")) {
148		strncat(result,
149		    "bsdcpio: file: large inode number truncated: ",
150		    sizeof(result) - strlen(result) -1);
151		strncat(result,
152		    strerror(ERANGE),
153		    sizeof(result) - strlen(result) -1);
154		strncat(result,
155		    "\n",
156		    sizeof(result) - strlen(result) -1);
157	}
158
159	/* hardlink to above file. */
160	assertMakeHardlink("linkfile", "file");
161	fprintf(filelist, "linkfile\n");
162	if (is_LargeInode("linkfile")) {
163		strncat(result,
164		    "bsdcpio: linkfile: large inode number truncated: ",
165		    sizeof(result) - strlen(result) -1);
166		strncat(result,
167		    strerror(ERANGE),
168		    sizeof(result) - strlen(result) -1);
169		strncat(result,
170		    "\n",
171		    sizeof(result) - strlen(result) -1);
172	}
173
174	/* Symlink to above file. */
175	if (canSymlink()) {
176		assertMakeSymlink("symlink", "file", 0);
177		fprintf(filelist, "symlink\n");
178		if (is_LargeInode("symlink")) {
179			strncat(result,
180			    "bsdcpio: symlink: large inode number truncated: ",
181			    sizeof(result) - strlen(result) -1);
182			strncat(result,
183			    strerror(ERANGE),
184			    sizeof(result) - strlen(result) -1);
185			strncat(result,
186			    "\n",
187			    sizeof(result) - strlen(result) -1);
188		}
189	}
190
191	/* Another file with different permissions. */
192	assertMakeFile("file2", 0777, "1234567890");
193	fprintf(filelist, "file2\n");
194	if (is_LargeInode("file2")) {
195		strncat(result,
196		    "bsdcpio: file2: large inode number truncated: ",
197		    sizeof(result) - strlen(result) -1);
198		strncat(result,
199		    strerror(ERANGE),
200		    sizeof(result) - strlen(result) -1);
201		strncat(result,
202		    "\n",
203		    sizeof(result) - strlen(result) -1);
204	}
205
206	/* Directory. */
207	assertMakeDir("dir", 0775);
208	fprintf(filelist, "dir\n");
209	if (is_LargeInode("dir")) {
210		strncat(result,
211		    "bsdcpio: dir: large inode number truncated: ",
212		    sizeof(result) - strlen(result) -1);
213		strncat(result,
214		    strerror(ERANGE),
215		    sizeof(result) - strlen(result) -1);
216		strncat(result,
217		    "\n",
218		    sizeof(result) - strlen(result) -1);
219	}
220	strncat(result, "2 blocks\n", sizeof(result) - strlen(result) -1);
221
222	/* All done. */
223	fclose(filelist);
224
225	assertUmask(022);
226
227	/* Archive/dearchive with a variety of options. */
228	msg = canSymlink() ? "2 blocks\n" : "1 block\n";
229	basic_cpio("copy", "", "", msg, msg);
230	basic_cpio("copy_odc", "--format=odc", "", msg, msg);
231	basic_cpio("copy_newc", "-H newc", "", result, "2 blocks\n");
232	basic_cpio("copy_cpio", "-H odc", "", msg, msg);
233	msg = canSymlink() ? "9 blocks\n" : "8 blocks\n";
234	basic_cpio("copy_ustar", "-H ustar", "", msg, msg);
235
236	/* Copy in one step using -p */
237	passthrough("passthrough");
238}
239