1 /*
2  * SPDX-License-Identifier: BSD-3-Clause
3  *
4  * Copyright © 2022 Keith Packard
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  *
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  *
13  * 2. Redistributions in binary form must reproduce the above
14  *    copyright notice, this list of conditions and the following
15  *    disclaimer in the documentation and/or other materials provided
16  *    with the distribution.
17  *
18  * 3. Neither the name of the copyright holder nor the names of its
19  *    contributors may be used to endorse or promote products derived
20  *    from this software without specific prior written permission.
21  *
22  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
23  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
24  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
25  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
26  * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
27  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
28  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
29  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
31  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
32  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
33  * OF THE POSSIBILITY OF SUCH DAMAGE.
34  */
35 #define _DEFAULT_SOURCE
36 #include <stdio.h>
37 #include <stdlib.h>
38 #include <string.h>
39 
40 #define check(condition, message) do {                  \
41         if (!(condition)) {                             \
42             printf("%s: %s\n", message, #condition);    \
43             if (f)                                      \
44                 fclose(f);                              \
45             (void) remove(template);                    \
46             exit(1);                                    \
47         }                                               \
48     } while(0)
49 
50 static const char NAME_TEMPLATE[] = "foo-XXXXXX";
51 
52 static const char NAME_TEMPLATE_EXT[] = "foo-XXXXXX.txt";
53 
54 #define EXT_LEN                 4
55 
56 #define MESSAGE "hello, world\n"
57 
58 void
check_contents(char * template,int repeats)59 check_contents(char *template,int repeats)
60 {
61     FILE *f;
62     char *s;
63     int r;
64     int c;
65 
66     f = fopen(template, "r");
67     check(f != NULL, "fopen r");
68     for (r = 0; r < repeats; r++) {
69         for (s = MESSAGE; *s; s++) {
70             c = getc(f);
71             check((char) c == *s, "contents");
72         }
73     }
74     c = getc(f);
75     check(c == EOF, "EOF");
76     r = fclose(f);
77     f = NULL;
78     check(r == 0, "fclose r");
79 }
80 
81 /* Allow testing mktemp which is deprecated (for good reason) */
82 #pragma GCC diagnostic ignored "-Wpragmas"
83 #pragma GCC diagnostic ignored "-Wunknown-warning-option"
84 #pragma GCC diagnostic ignored "-Wdeprecated-declarations"
85 
86 int
main(void)87 main(void)
88 {
89     char        template[sizeof(NAME_TEMPLATE_EXT)];
90     char        *s_ret;
91     FILE        *f = NULL;
92     int         i_ret;
93 
94     /* Create temp file */
95     strcpy(template, NAME_TEMPLATE);
96     s_ret = mktemp(template);
97     check(s_ret == template, "mktemp");
98 
99     /* Make sure we can create a file, write contents and read them back */
100     f = fopen(template, "w");
101     check(f != NULL, "fopen w");
102     fputs(MESSAGE, f);
103     fclose(f);
104     f = NULL;
105     check_contents(template, 1);
106     (void) remove(template);
107 
108     /* Create temp file */
109     strcpy(template, NAME_TEMPLATE);
110     i_ret = mkstemp(template);
111     check(i_ret >= 0, "mkstemp");
112 
113     /* Make sure we can create a file, write contents and read them back */
114     f = fdopen(i_ret, "w");
115     check(f != NULL, "fopen w");
116     fputs(MESSAGE, f);
117     fclose(f);
118     f = NULL;
119     check_contents(template, 1);
120     (void) remove(template);
121 
122     /* Create temp file with extension */
123     strcpy(template, NAME_TEMPLATE_EXT);
124     i_ret = mkstemps(template, EXT_LEN);
125     check(i_ret >= 0, "mkstemps");
126 
127     /* Make sure the name still ends with the extension */
128     check(strcmp(template + sizeof(NAME_TEMPLATE_EXT) - EXT_LEN,
129                  NAME_TEMPLATE_EXT + sizeof(NAME_TEMPLATE_EXT) - EXT_LEN) == 0, "extension");
130     f = fdopen(i_ret, "w");
131     check(f != NULL, "fopen w");
132     fputs(MESSAGE, f);
133     fclose(f);
134     check_contents(template, 1);
135     (void) remove(template);
136 
137     exit(0);
138 }
139