]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - tests/sys/fs/tarfs/mktar.c
Merge llvm-project release/15.x llvmorg-15.0.2-10-gf3c5289e7846
[FreeBSD/FreeBSD.git] / tests / sys / fs / tarfs / mktar.c
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 SPARSEFILENAME  "sparse_file"
45 #define HARDLINKNAME    "hard_link"
46 #define SHORTLINKNAME   "short_link"
47 #define LONGLINKNAME    "long_link"
48
49 static bool opt_v;
50
51 static void verbose(const char *fmt, ...)
52 {
53         va_list ap;
54
55         if (!opt_v)
56                 return;
57         fprintf(stderr, "%s: ", PROGNAME);
58         va_start(ap, fmt);
59         vfprintf(stderr, fmt, ap);
60         va_end(ap);
61         fprintf(stderr, "\n");
62 }
63
64 static void
65 mksparsefile(const char *filename, mode_t mode)
66 {
67         char buf[511];
68         ssize_t res;
69         int fd;
70
71         if ((fd = open(filename, O_RDWR|O_CREAT|O_TRUNC, mode)) < 0)
72                 err(1, "%s", filename);
73         for (unsigned int i = 33; i <= 126; i++) {
74                 memset(buf, i, sizeof(buf));
75                 if (lseek(fd, 1048576LU * (i - 32), SEEK_SET) < 0)
76                         err(1, "%s", filename);
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         }
83         close(fd);
84 }
85
86 static char *
87 mklonglinktarget(const char *dirname, const char *filename)
88 {
89         char *piece, *target;
90
91         if (asprintf(&piece, "%1$s/../%1$s/../%1$s/../%1$s/../", dirname) < 0)
92                 err(1, "asprintf()");
93         if (asprintf(&target, "%1$s%1$s%1$s%1$s%1$s%1$s%1$s%1$s%2$s", piece, filename) < 0)
94                 err(1, "asprintf()");
95         free(piece);
96         return target;
97 }
98
99 static void
100 mktar(void)
101 {
102         char *linktarget;
103
104         /* create a subdirectory */
105         verbose("mkdir %s", SUBDIRNAME);
106         if (mkdir(SUBDIRNAME, 0755) != 0)
107                 err(1, "%s", SUBDIRNAME);
108
109         /* create a sparse file */
110         verbose("creating %s", SPARSEFILENAME);
111         mksparsefile(SPARSEFILENAME, 0644);
112         chflags(SPARSEFILENAME, UF_NODUMP);
113
114         /* create a hard link */
115         verbose("link %s %s", SPARSEFILENAME, HARDLINKNAME);
116         if (link(SPARSEFILENAME, HARDLINKNAME) != 0)
117                 err(1, "%s", HARDLINKNAME);
118
119         /* create a symbolic link with a short target */
120         verbose("symlink %s %s", SPARSEFILENAME, SHORTLINKNAME);
121         if (symlink(SPARSEFILENAME, SHORTLINKNAME) != 0)
122                 err(1, "%s", SHORTLINKNAME);
123
124         /* create a symbolic link with a long target */
125         linktarget = mklonglinktarget(SUBDIRNAME, SPARSEFILENAME);
126         verbose("symlink %s %s", linktarget, LONGLINKNAME);
127         if (symlink(linktarget, LONGLINKNAME) != 0)
128                 err(1, "%s", LONGLINKNAME);
129         free(linktarget);
130 }
131
132 static void
133 usage(void)
134 {
135
136         fprintf(stderr, "usage: %s [-v] tarfile\n", PROGNAME);
137         exit(EXIT_FAILURE);
138 }
139
140 int
141 main(int argc, char *argv[])
142 {
143         const char *tarfilename;
144         char *dirname;
145         int opt, wstatus;
146         pid_t pid;
147
148         while ((opt = getopt(argc, argv, "v")) != -1)
149                 switch (opt) {
150                 case 'v':
151                         opt_v = true;
152                         break;
153                 default:
154                         usage();
155                 }
156
157         argc -= optind;
158         argv += optind;
159
160         if (argc != 1)
161                 usage();
162         tarfilename = *argv;
163
164         if (asprintf(&dirname, "%s%s.XXXXXXXX", _PATH_TMP, PROGNAME) < 0)
165                 err(1, "asprintf()");
166         if (mkdtemp(dirname) == NULL)
167                 err(1, "%s", dirname);
168         verbose("mkdir %s", dirname);
169
170         /* fork a child to create the files */
171         if ((pid = fork()) < 0)
172                 err(1, "fork()");
173         if (pid == 0) {
174                 verbose("cd %s", dirname);
175                 if (chdir(dirname) != 0)
176                         err(1, "%s", dirname);
177                 verbose("umask 022");
178                 umask(022);
179                 mktar();
180                 verbose("cd -");
181                 exit(0);
182         }
183         if (waitpid(pid, &wstatus, 0) < 0)
184                 err(1, "waitpid()");
185         if (!WIFEXITED(wstatus) || WEXITSTATUS(wstatus) != 0)
186                 errx(1, "child failed");
187
188         /* fork a child to create the tarball */
189         if ((pid = fork()) < 0)
190                 err(1, "fork()");
191         if (pid == 0) {
192                 verbose("creating tarball");
193                 execlp("tar", "tar",
194                     "-c",
195                     "-f", tarfilename,
196                     "-C", dirname,
197                     "--zstd",
198 #if 0
199                     "--options", "zstd:frame-per-file",
200 #endif
201                     ".",
202                     NULL);
203                 err(1, "execlp()");
204         }
205         if (waitpid(pid, &wstatus, 0) < 0)
206                 err(1, "waitpid()");
207         if (!WIFEXITED(wstatus) || WEXITSTATUS(wstatus) != 0)
208                 errx(1, "child failed");
209
210         /* fork a child to delete everything */
211         if ((pid = fork()) < 0)
212                 err(1, "fork()");
213         if (pid == 0) {
214                 verbose("cd %s", dirname);
215                 if (chdir(dirname) != 0)
216                         err(1, "%s", dirname);
217                 verbose("rm %s", LONGLINKNAME);
218                 (void)unlink(LONGLINKNAME);
219                 verbose("rm %s", SHORTLINKNAME);
220                 (void)unlink(SHORTLINKNAME);
221                 verbose("rm %s", HARDLINKNAME);
222                 (void)unlink(HARDLINKNAME);
223                 verbose("rm %s", SPARSEFILENAME);
224                 (void)unlink(SPARSEFILENAME);
225                 verbose("rm %s", SUBDIRNAME);
226                 (void)rmdir(SUBDIRNAME);
227                 verbose("cd -");
228                 exit(0);
229         }
230         if (waitpid(pid, &wstatus, 0) < 0)
231                 err(1, "waitpid()");
232         if (!WIFEXITED(wstatus) || WEXITSTATUS(wstatus) != 0)
233                 errx(1, "child failed");
234         verbose("rmdir %s", dirname);
235         (void)rmdir(dirname);
236
237         exit(0);
238 }