Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/tests/sys/fs/tarfs/mktar.c
39537 views
1
/*-
2
* SPDX-License-Identifier: BSD-2-Clause
3
*
4
* Copyright (c) 2023 Klara, Inc.
5
*
6
* Redistribution and use in source and binary forms, with or without
7
* modification, are permitted provided that the following conditions
8
* are met:
9
* 1. Redistributions of source code must retain the above copyright
10
* notice, this list of conditions and the following disclaimer.
11
* 2. Redistributions in binary form must reproduce the above copyright
12
* notice, this list of conditions and the following disclaimer in the
13
* documentation and/or other materials provided with the distribution.
14
*
15
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25
* SUCH DAMAGE.
26
*/
27
28
#include <sys/stat.h>
29
#include <sys/wait.h>
30
31
#include <err.h>
32
#include <fcntl.h>
33
#include <paths.h>
34
#include <stdarg.h>
35
#include <stdbool.h>
36
#include <stdlib.h>
37
#include <stdio.h>
38
#include <string.h>
39
#include <unistd.h>
40
41
#define PROGNAME "mktar"
42
43
#define SUBDIRNAME "directory"
44
#define NORMALFILENAME "file"
45
#define SPARSEFILENAME "sparse_file"
46
#define HARDLINKNAME "hard_link"
47
#define SHORTLINKNAME "short_link"
48
#define LONGLINKNAME "long_link"
49
50
static bool opt_g;
51
static bool opt_v;
52
53
static void verbose(const char *fmt, ...)
54
{
55
va_list ap;
56
57
if (!opt_v)
58
return;
59
fprintf(stderr, "%s: ", PROGNAME);
60
va_start(ap, fmt);
61
vfprintf(stderr, fmt, ap);
62
va_end(ap);
63
fprintf(stderr, "\n");
64
}
65
66
static void
67
mknormalfile(const char *filename, mode_t mode)
68
{
69
char buf[512];
70
ssize_t res;
71
int fd;
72
73
if ((fd = open(filename, O_RDWR|O_CREAT|O_EXCL, mode)) < 0)
74
err(1, "%s", filename);
75
for (unsigned int i = 0; i < sizeof(buf); i++)
76
buf[i] = 32 + i % 64;
77
res = write(fd, buf, sizeof(buf));
78
if (res < 0)
79
err(1, "%s", filename);
80
if (res != sizeof(buf))
81
errx(1, "%s: short write", filename);
82
close(fd);
83
}
84
85
static void
86
mksparsefile(const char *filename, mode_t mode)
87
{
88
char buf[511];
89
ssize_t res;
90
int fd;
91
92
if ((fd = open(filename, O_RDWR|O_CREAT|O_EXCL, mode)) < 0)
93
err(1, "%s", filename);
94
for (unsigned int i = 33; i <= 126; i++) {
95
memset(buf, i, sizeof(buf));
96
if (lseek(fd, 1048576LU * (i - 32), SEEK_SET) < 0)
97
err(1, "%s", filename);
98
res = write(fd, buf, sizeof(buf));
99
if (res < 0)
100
err(1, "%s", filename);
101
if (res != sizeof(buf))
102
errx(1, "%s: short write", filename);
103
}
104
close(fd);
105
}
106
107
static char *
108
mklonglinktarget(const char *dirname, const char *filename)
109
{
110
char *piece, *target;
111
112
if (asprintf(&piece, "%1$s/../%1$s/../%1$s/../%1$s/../", dirname) < 0)
113
err(1, "asprintf()");
114
if (asprintf(&target, "%1$s%1$s%1$s%1$s%1$s%1$s%1$s%1$s%2$s", piece, filename) < 0)
115
err(1, "asprintf()");
116
free(piece);
117
return target;
118
}
119
120
static void
121
mktar(void)
122
{
123
char *linktarget;
124
125
/* create a subdirectory */
126
verbose("mkdir %s", SUBDIRNAME);
127
if (mkdir(SUBDIRNAME, 0755) != 0)
128
err(1, "%s", SUBDIRNAME);
129
130
/* create a normal file */
131
verbose("creating %s", NORMALFILENAME);
132
mknormalfile(NORMALFILENAME, 0644);
133
134
/* create a sparse file */
135
verbose("creating %s", SPARSEFILENAME);
136
mksparsefile(SPARSEFILENAME, 0644);
137
chflags(SPARSEFILENAME, UF_NODUMP);
138
139
/* create a hard link */
140
verbose("link %s %s", SPARSEFILENAME, HARDLINKNAME);
141
if (link(SPARSEFILENAME, HARDLINKNAME) != 0)
142
err(1, "%s", HARDLINKNAME);
143
144
/* create a symbolic link with a short target */
145
verbose("symlink %s %s", SPARSEFILENAME, SHORTLINKNAME);
146
if (symlink(SPARSEFILENAME, SHORTLINKNAME) != 0)
147
err(1, "%s", SHORTLINKNAME);
148
149
/* create a symbolic link with a long target */
150
linktarget = mklonglinktarget(SUBDIRNAME, SPARSEFILENAME);
151
verbose("symlink %s %s", linktarget, LONGLINKNAME);
152
if (symlink(linktarget, LONGLINKNAME) != 0)
153
err(1, "%s", LONGLINKNAME);
154
free(linktarget);
155
}
156
157
static void
158
usage(void)
159
{
160
161
fprintf(stderr, "usage: %s [-gv] tarfile\n", PROGNAME);
162
exit(EXIT_FAILURE);
163
}
164
165
int
166
main(int argc, char *argv[])
167
{
168
const char *tarfilename;
169
char *dirname;
170
int opt, wstatus;
171
pid_t pid;
172
173
while ((opt = getopt(argc, argv, "gv")) != -1)
174
switch (opt) {
175
case 'g':
176
opt_g = true;
177
break;
178
case 'v':
179
opt_v = true;
180
break;
181
default:
182
usage();
183
}
184
185
argc -= optind;
186
argv += optind;
187
188
if (argc != 1)
189
usage();
190
tarfilename = *argv;
191
192
if (asprintf(&dirname, "%s%s.XXXXXXXX", _PATH_TMP, PROGNAME) < 0)
193
err(1, "asprintf()");
194
if (mkdtemp(dirname) == NULL)
195
err(1, "%s", dirname);
196
verbose("mkdir %s", dirname);
197
198
/* fork a child to create the files */
199
if ((pid = fork()) < 0)
200
err(1, "fork()");
201
if (pid == 0) {
202
verbose("cd %s", dirname);
203
if (chdir(dirname) != 0)
204
err(1, "%s", dirname);
205
verbose("umask 022");
206
umask(022);
207
mktar();
208
verbose("cd -");
209
exit(0);
210
}
211
if (waitpid(pid, &wstatus, 0) < 0)
212
err(1, "waitpid()");
213
if (!WIFEXITED(wstatus) || WEXITSTATUS(wstatus) != 0)
214
errx(1, "child failed");
215
216
/* fork a child to create the tarball */
217
if ((pid = fork()) < 0)
218
err(1, "fork()");
219
if (pid == 0) {
220
verbose("creating tarball");
221
execlp(opt_g ? "gtar" : "tar",
222
"tar",
223
"-c",
224
"-f", tarfilename,
225
"-C", dirname,
226
"--posix",
227
"--zstd",
228
#if 0
229
"--options", "zstd:frame-per-file",
230
#endif
231
"./" SUBDIRNAME "/../" NORMALFILENAME,
232
"./" SPARSEFILENAME,
233
"./" HARDLINKNAME,
234
"./" SHORTLINKNAME,
235
"./" SUBDIRNAME,
236
"./" LONGLINKNAME,
237
NULL);
238
err(1, "execlp()");
239
}
240
if (waitpid(pid, &wstatus, 0) < 0)
241
err(1, "waitpid()");
242
if (!WIFEXITED(wstatus) || WEXITSTATUS(wstatus) != 0)
243
errx(1, "child failed");
244
245
/* fork a child to delete everything */
246
if ((pid = fork()) < 0)
247
err(1, "fork()");
248
if (pid == 0) {
249
verbose("cd %s", dirname);
250
if (chdir(dirname) != 0)
251
err(1, "%s", dirname);
252
verbose("rm %s", LONGLINKNAME);
253
(void)unlink(LONGLINKNAME);
254
verbose("rm %s", SHORTLINKNAME);
255
(void)unlink(SHORTLINKNAME);
256
verbose("rm %s", HARDLINKNAME);
257
(void)unlink(HARDLINKNAME);
258
verbose("rm %s", SPARSEFILENAME);
259
(void)unlink(SPARSEFILENAME);
260
verbose("rmdir %s", SUBDIRNAME);
261
(void)rmdir(SUBDIRNAME);
262
verbose("cd -");
263
exit(0);
264
}
265
if (waitpid(pid, &wstatus, 0) < 0)
266
err(1, "waitpid()");
267
if (!WIFEXITED(wstatus) || WEXITSTATUS(wstatus) != 0)
268
errx(1, "child failed");
269
verbose("rmdir %s", dirname);
270
(void)rmdir(dirname);
271
272
exit(0);
273
}
274
275