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