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