1 /* Temporary file handling for tests.
2 Copyright (C) 1998-2024 Free Software Foundation, Inc.
3 Copyright The GNU Tools Authors.
4 This file is part of the GNU C Library.
6 The GNU C Library is free software; you can redistribute it and/or
7 modify it under the terms of the GNU Lesser General Public
8 License as published by the Free Software Foundation; either
9 version 2.1 of the License, or (at your option) any later version.
11 The GNU C Library is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 Lesser General Public License for more details.
16 You should have received a copy of the GNU Lesser General Public
17 License along with the GNU C Library; if not, see
18 <https://www.gnu.org/licenses/>. */
20 /* This is required to get an mkstemp which can create large files on
21 some 32-bit platforms. */
22 #define _FILE_OFFSET_BITS 64
24 #include <support/check.h>
25 #include <support/temp_file.h>
26 #include <support/temp_file-internal.h>
27 #include <support/support.h>
37 /* List of temporary files. */
38 static struct temp_name_list
40 struct temp_name_list
*next
;
46 /* Location of the temporary files. Set by the test skeleton via
47 support_set_test_dir. The string is not be freed. */
48 static const char *test_dir
= _PATH_TMP
;
50 /* Name of subdirectories in a too long temporary directory tree. */
51 static char toolong_subdir
[NAME_MAX
+ 1];
52 static bool toolong_initialized
;
53 static size_t toolong_path_max
;
56 add_temp_file_internal (const char *name
, bool toolong
)
58 struct temp_name_list
*newp
59 = (struct temp_name_list
*) xcalloc (sizeof (*newp
), 1);
60 char *newname
= strdup (name
);
64 newp
->next
= temp_name_list
;
65 newp
->owner
= getpid ();
66 newp
->toolong
= toolong
;
67 temp_name_list
= newp
;
74 add_temp_file (const char *name
)
76 add_temp_file_internal (name
, false);
80 create_temp_file_in_dir (const char *base
, const char *dir
, char **filename
)
85 fname
= xasprintf ("%s/%sXXXXXX", dir
, base
);
90 printf ("cannot open temporary file '%s': %m\n", fname
);
95 add_temp_file (fname
);
105 create_temp_file (const char *base
, char **filename
)
107 return create_temp_file_in_dir (base
, test_dir
, filename
);
111 create_temp_directory_internal (const char *base
, bool toolong
)
113 char *path
= xasprintf ("%s/%sXXXXXX", test_dir
, base
);
114 if (mkdtemp (path
) == NULL
)
116 printf ("error: mkdtemp (\"%s\"): %m", path
);
119 add_temp_file_internal (path
, toolong
);
124 support_create_temp_directory (const char *base
)
126 return create_temp_directory_internal (base
, false);
130 ensure_toolong_initialized (void)
132 if (!toolong_initialized
)
133 FAIL_EXIT1 ("uninitialized toolong directory tree\n");
137 initialize_toolong (const char *base
)
139 long name_max
= pathconf (base
, _PC_NAME_MAX
);
140 name_max
= (name_max
< 0 ? 64
141 : (name_max
< sizeof (toolong_subdir
) ? name_max
142 : sizeof (toolong_subdir
) - 1));
144 long path_max
= pathconf (base
, _PC_PATH_MAX
);
145 path_max
= (path_max
< 0 ? 1024
146 : path_max
<= PTRDIFF_MAX
? path_max
: PTRDIFF_MAX
);
148 /* Sanity check to ensure that the test does not create temporary directories
149 in different filesystems because this API doesn't support it. */
150 if (toolong_initialized
)
152 if (name_max
!= strlen (toolong_subdir
))
153 FAIL_UNSUPPORTED ("name_max: Temporary directories in different"
154 " filesystems not supported yet\n");
155 if (path_max
!= toolong_path_max
)
156 FAIL_UNSUPPORTED ("path_max: Temporary directories in different"
157 " filesystems not supported yet\n");
161 toolong_path_max
= path_max
;
163 size_t len
= name_max
;
164 memset (toolong_subdir
, 'X', len
);
165 toolong_initialized
= true;
169 support_create_and_chdir_toolong_temp_directory (const char *basename
)
171 char *base
= create_temp_directory_internal (basename
, true);
174 initialize_toolong (base
);
176 size_t sz
= strlen (toolong_subdir
);
178 /* Create directories and descend into them so that the final path is larger
180 for (size_t i
= 0; i
<= toolong_path_max
/ sz
; i
++)
182 int ret
= mkdir (toolong_subdir
, S_IRWXU
);
183 if (ret
!= 0 && errno
== ENAMETOOLONG
)
184 FAIL_UNSUPPORTED ("Filesystem does not support creating too long "
185 "directory trees\n");
187 FAIL_EXIT1 ("Failed to create directory tree: %m\n");
188 xchdir (toolong_subdir
);
194 support_chdir_toolong_temp_directory (const char *base
)
196 ensure_toolong_initialized ();
200 size_t sz
= strlen (toolong_subdir
);
201 for (size_t i
= 0; i
<= toolong_path_max
/ sz
; i
++)
202 xchdir (toolong_subdir
);
205 /* Helper functions called by the test skeleton follow. */
208 remove_toolong_subdirs (const char *base
)
210 ensure_toolong_initialized ();
212 if (chdir (base
) != 0)
214 printf ("warning: toolong cleanup base failed: chdir (\"%s\"): %m\n",
221 size_t sz
= strlen (toolong_subdir
);
222 for (levels
= 0; levels
<= toolong_path_max
/ sz
; levels
++)
223 if (chdir (toolong_subdir
) != 0)
225 printf ("warning: toolong cleanup failed: chdir (\"%s\"): %m\n",
230 /* Ascend and remove. */
231 while (--levels
>= 0)
233 if (chdir ("..") != 0)
235 printf ("warning: toolong cleanup failed: chdir (\"..\"): %m\n");
238 if (remove (toolong_subdir
) != 0)
240 printf ("warning: could not remove subdirectory: %s: %m\n",
248 support_delete_temp_files (void)
250 pid_t pid
= getpid ();
251 while (temp_name_list
!= NULL
)
253 /* Only perform the removal if the path was registered in the same
254 process, as identified by the PID. (This assumes that the
255 parent process which registered the temporary file sticks
256 around, to prevent PID reuse.) */
257 if (temp_name_list
->owner
== pid
)
259 if (temp_name_list
->toolong
)
260 remove_toolong_subdirs (temp_name_list
->name
);
262 if (remove (temp_name_list
->name
) != 0)
263 printf ("warning: could not remove temporary file: %s: %m\n",
264 temp_name_list
->name
);
266 free (temp_name_list
->name
);
268 struct temp_name_list
*next
= temp_name_list
->next
;
269 free (temp_name_list
);
270 temp_name_list
= next
;
275 support_print_temp_files (FILE *f
)
277 if (temp_name_list
!= NULL
)
279 struct temp_name_list
*n
;
280 fprintf (f
, "temp_files=(\n");
281 for (n
= temp_name_list
; n
!= NULL
; n
= n
->next
)
282 fprintf (f
, " '%s'\n", n
->name
);
288 support_set_test_dir (const char *path
)