xref: /freebsd/contrib/libarchive/cpio/test/test_option_c.c (revision bd66c1b43e33540205dbc1187c2f2a15c58b57ba)
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  static int
is_octal(const char * p,size_t l)10  is_octal(const char *p, size_t l)
11  {
12  	while (l > 0) {
13  		if (*p < '0' || *p > '7')
14  			return (0);
15  		--l;
16  		++p;
17  	}
18  	return (1);
19  }
20  
21  static long long int
from_octal(const char * p,size_t l)22  from_octal(const char *p, size_t l)
23  {
24  	long long int r = 0;
25  
26  	while (l > 0) {
27  		r *= 8;
28  		r += *p - '0';
29  		--l;
30  		++p;
31  	}
32  	return (r);
33  }
34  
35  #if !defined(_WIN32) || defined(__CYGWIN__)
36  static int
nlinks(const char * p)37  nlinks(const char *p)
38  {
39  	struct stat st;
40  	assertEqualInt(0, stat(p, &st));
41  	return st.st_nlink;
42  }
43  #endif
44  
DEFINE_TEST(test_option_c)45  DEFINE_TEST(test_option_c)
46  {
47  	FILE *filelist;
48  	int r;
49  	int uid = 1000;
50  	int dev, ino, gid = 1000;
51  	time_t t, now;
52  	char *p, *e;
53  	size_t s;
54  
55  	assertUmask(0);
56  
57  	/*
58  	 * Create an assortment of files.
59  	 * TODO: Extend this to cover more filetypes.
60  	 */
61  	filelist = fopen("filelist", "w");
62  
63  	/* "file" */
64  	assertMakeFile("file", 0644, "1234567890");
65  	fprintf(filelist, "file\n");
66  
67  	/* "symlink" */
68  	if (canSymlink()) {
69  		assertMakeSymlink("symlink", "file", 0);
70  		fprintf(filelist, "symlink\n");
71  	}
72  
73  	/* "dir" */
74  	assertMakeDir("dir", 0775);
75  	/* Record some facts about what we just created: */
76  	now = time(NULL); /* They were all created w/in last two seconds. */
77  	fprintf(filelist, "dir\n");
78  
79  	/* Use the cpio program to create an archive. */
80  	fclose(filelist);
81  	r = systemf("%s -R 1000:1000 -oc <filelist >basic.out 2>basic.err", testprog);
82  	/* Verify that nothing went to stderr. */
83  	assertTextFileContents("1 block\n", "basic.err");
84  
85  	/* Assert that the program finished. */
86  	failure("%s -oc crashed", testprog);
87  	if (!assertEqualInt(r, 0))
88  		return;
89  
90  	/* Verify that stdout is a well-formed cpio file in "odc" format. */
91  	p = slurpfile(&s, "basic.out");
92  	assertEqualInt(s, 512);
93  	e = p;
94  
95  	/*
96  	 * Some of these assertions could be stronger, but it's
97  	 * a little tricky because they depend on the local environment.
98  	 */
99  
100  	/* First entry is "file" */
101  	assert(is_octal(e, 76)); /* Entire header is octal digits. */
102  	assertEqualMem(e + 0, "070707", 6); /* Magic */
103  	assert(is_octal(e + 6, 6)); /* dev */
104  	dev = (int)from_octal(e + 6, 6);
105  	assert(is_octal(e + 12, 6)); /* ino */
106  	ino = (int)from_octal(e + 12, 6);
107  #if defined(_WIN32) && !defined(__CYGWIN__)
108  	/* Group members bits and others bits do not work. */
109  	assertEqualMem(e + 18, "100666", 6); /* Mode */
110  #else
111  	assertEqualMem(e + 18, "100644", 6); /* Mode */
112  #endif
113  	if (uid < 0)
114  		uid = (int)from_octal(e + 24, 6);
115  	assertEqualInt(from_octal(e + 24, 6), uid); /* uid */
116  	assert(is_octal(e + 30, 6)); /* gid */
117  	gid = (int)from_octal(e + 30, 6);
118  	assertEqualMem(e + 36, "000001", 6); /* nlink */
119  	failure("file entries should not have rdev set (dev field was 0%o)",
120  	    dev);
121  	assertEqualMem(e + 42, "000000", 6); /* rdev */
122  	t = from_octal(e + 48, 11); /* mtime */
123  	assert(t <= now); /* File wasn't created in future. */
124  	assert(t >= now - 2); /* File was created w/in last 2 secs. */
125  	assertEqualMem(e + 59, "000005", 6); /* Name size */
126  	assertEqualMem(e + 65, "00000000012", 11); /* File size */
127  	assertEqualMem(e + 76, "file\0", 5); /* Name contents */
128  	assertEqualMem(e + 81, "1234567890", 10); /* File contents */
129  	e += 91;
130  
131  	/* "symlink" pointing to "file" */
132  	if (canSymlink()) {
133  		assert(is_octal(e, 76)); /* Entire header is octal digits. */
134  		assertEqualMem(e + 0, "070707", 6); /* Magic */
135  		assertEqualInt(dev, from_octal(e + 6, 6)); /* dev */
136  		assert(ino != from_octal(e + 12, 6)); /* ino */
137  #if !defined(_WIN32) || defined(__CYGWIN__)
138  		/* On Windows, symbolic link and group members bits and
139  		 * others bits do not work. */
140  		assertEqualMem(e + 18, "120777", 6); /* Mode */
141  #endif
142  		assertEqualInt(from_octal(e + 24, 6), uid); /* uid */
143  		assertEqualInt(gid, from_octal(e + 30, 6)); /* gid */
144  		assertEqualMem(e + 36, "000001", 6); /* nlink */
145  		failure("file entries should have rdev == 0 (dev was 0%llo)",
146  		    from_octal(e + 6, 6));
147  		assertEqualMem(e + 42, "000000", 6); /* rdev */
148  		t = from_octal(e + 48, 11); /* mtime */
149  		assert(t <= now); /* File wasn't created in future. */
150  		assert(t >= now - 2); /* File was created w/in last 2 secs. */
151  		assertEqualMem(e + 59, "000010", 6); /* Name size */
152  		assertEqualMem(e + 65, "00000000004", 11); /* File size */
153  		assertEqualMem(e + 76, "symlink\0", 8); /* Name contents */
154  		assertEqualMem(e + 84, "file", 4); /* Symlink target. */
155  		e += 88;
156  	}
157  
158  	/* "dir" */
159  	assert(is_octal(e, 76));
160  	assertEqualMem(e + 0, "070707", 6); /* Magic */
161  	/* Dev should be same as first entry. */
162  	assert(is_octal(e + 6, 6)); /* dev */
163  	assertEqualInt(dev, from_octal(e + 6, 6));
164  	/* Ino must be different from first entry. */
165  	assert(is_octal(e + 12, 6)); /* ino */
166  	assert(ino != from_octal(e + 12, 6));
167  #if defined(_WIN32) && !defined(__CYGWIN__)
168  	/* Group members bits and others bits do not work. */
169  	assertEqualMem(e + 18, "040777", 6); /* Mode */
170  #else
171  	/* Accept 042775 to accommodate systems where sgid bit propagates. */
172  	if (memcmp(e + 18, "042775", 6) != 0)
173  		assertEqualMem(e + 18, "040775", 6); /* Mode */
174  #endif
175  	assertEqualInt(uid, from_octal(e + 24, 6)); /* uid */
176  	/* Gid should be same as first entry. */
177  	assert(is_octal(e + 30, 6)); /* gid */
178  	assertEqualInt(gid, from_octal(e + 30, 6));
179  
180  #if !defined(_WIN32) || defined(__CYGWIN__)
181  	assertEqualInt(nlinks("dir"), from_octal(e + 36, 6)); /* Nlink */
182  #endif
183  
184  	t = from_octal(e + 48, 11); /* mtime */
185  	assert(t <= now); /* File wasn't created in future. */
186  	assert(t >= now - 2); /* File was created w/in last 2 secs. */
187  	assertEqualMem(e + 59, "000004", 6); /* Name size */
188  	assertEqualMem(e + 65, "00000000000", 11); /* File size */
189  	assertEqualMem(e + 76, "dir\0", 4); /* name */
190  	e += 80;
191  
192  	/* TODO: Verify other types of entries. */
193  
194  	/* Last entry is end-of-archive marker. */
195  	assert(is_octal(e, 76));
196  	assertEqualMem(e + 0, "070707", 6); /* Magic */
197  	assertEqualMem(e + 6, "000000", 6); /* dev */
198  	assertEqualMem(e + 12, "000000", 6); /* ino */
199  	assertEqualMem(e + 18, "000000", 6); /* Mode */
200  	assertEqualMem(e + 24, "000000", 6); /* uid */
201  	assertEqualMem(e + 30, "000000", 6); /* gid */
202  	assertEqualMem(e + 36, "000001", 6); /* Nlink */
203  	assertEqualMem(e + 42, "000000", 6); /* rdev */
204  	assertEqualMem(e + 48, "00000000000", 11); /* mtime */
205  	assertEqualMem(e + 59, "000013", 6); /* Name size */
206  	assertEqualMem(e + 65, "00000000000", 11); /* File size */
207  	assertEqualMem(e + 76, "TRAILER!!!\0", 11); /* Name */
208  
209  	free(p);
210  }
211