This source file includes following definitions.
- gl_lock_define_initialized
- create_temp_dir
- register_temp_file
- unregister_temp_file
- register_temp_subdir
- unregister_temp_subdir
- do_rmdir
- cleanup_temp_file
- cleanup_temp_subdir
- cleanup_temp_dir_contents
- cleanup_temp_dir
- supports_delete_on_close
- register_fd
- open_temp
- fopen_temp
- try_create_file
- gen_register_open_temp
- close_temp
- fclose_variant_temp
- fclose_temp
- fwriteerror_temp
- close_stream_temp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 #include <config.h>
20
21
22 #include "clean-temp.h"
23
24 #include <errno.h>
25 #include <fcntl.h>
26 #include <signal.h>
27 #include <stdbool.h>
28 #include <stdio.h>
29 #include <stdlib.h>
30 #include <string.h>
31 #include <unistd.h>
32
33 #if defined _WIN32 && ! defined __CYGWIN__
34 # define WIN32_LEAN_AND_MEAN
35 # include <windows.h>
36 #endif
37
38 #include "clean-temp-simple.h"
39 #include "clean-temp-private.h"
40 #include "error.h"
41 #include "fatal-signal.h"
42 #include "asyncsafe-spin.h"
43 #include "pathmax.h"
44 #include "tmpdir.h"
45 #include "xalloc.h"
46 #include "xmalloca.h"
47 #include "glthread/lock.h"
48 #include "thread-optim.h"
49 #include "gl_xlist.h"
50 #include "gl_linkedhash_list.h"
51 #include "gl_linked_list.h"
52 #include "gettext.h"
53 #if GNULIB_TEMPNAME
54 # include "tempname.h"
55 #endif
56 #if GNULIB_FWRITEERROR
57 # include "fwriteerror.h"
58 #endif
59 #if GNULIB_CLOSE_STREAM
60 # include "close-stream.h"
61 #endif
62 #if GNULIB_FCNTL_SAFER
63 # include "fcntl--.h"
64 #endif
65 #if GNULIB_FOPEN_SAFER
66 # include "stdio--.h"
67 #endif
68
69 #define _(str) gettext (str)
70
71
72
73 #ifndef PATH_MAX
74 # define PATH_MAX 1024
75 #endif
76
77 #if defined _WIN32 && ! defined __CYGWIN__
78
79 # undef OSVERSIONINFO
80 # define OSVERSIONINFO OSVERSIONINFOA
81 # undef GetVersionEx
82 # define GetVersionEx GetVersionExA
83 #endif
84
85
86
87
88 gl_lock_define_initialized (static, dir_cleanup_list_lock)
89
90
91
92 gl_lock_define_initialized (static, descriptors_lock)
93
94
95
96
97
98 static int
99 asyncsafe_fclose_variant (struct closeable_fd *element, FILE *fp,
100 int (*fclose_variant) (FILE *))
101 {
102 if (fileno (fp) != element->fd)
103 abort ();
104
105
106 fflush (fp);
107
108 sigset_t saved_mask;
109 int ret;
110 int saved_errno;
111
112 asyncsafe_spin_lock (&element->lock, get_fatal_signal_set (), &saved_mask);
113 if (!element->closed)
114 {
115 ret = fclose_variant (fp);
116 saved_errno = errno;
117 element->closed = true;
118 }
119 else
120 {
121 ret = 0;
122 saved_errno = 0;
123 }
124 asyncsafe_spin_unlock (&element->lock, &saved_mask);
125 element->done = true;
126
127 errno = saved_errno;
128 return ret;
129 }
130
131
132
133
134
135
136
137
138
139
140
141
142
143 struct temp_dir *
144 create_temp_dir (const char *prefix, const char *parentdir,
145 bool cleanup_verbose)
146 {
147 bool mt = gl_multithreaded ();
148
149 if (mt) gl_lock_lock (dir_cleanup_list_lock);
150
151 struct tempdir * volatile *tmpdirp = NULL;
152 struct tempdir *tmpdir;
153 size_t i;
154 char *xtemplate;
155 char *tmpdirname;
156
157
158
159 for (i = 0; i < dir_cleanup_list.tempdir_count; i++)
160 if (dir_cleanup_list.tempdir_list[i] == NULL)
161 {
162 tmpdirp = &dir_cleanup_list.tempdir_list[i];
163 break;
164 }
165 if (tmpdirp == NULL)
166 {
167
168 if (dir_cleanup_list.tempdir_count == dir_cleanup_list.tempdir_allocated)
169 {
170
171
172 struct tempdir * volatile *old_array = dir_cleanup_list.tempdir_list;
173 size_t old_allocated = dir_cleanup_list.tempdir_allocated;
174 size_t new_allocated = 2 * dir_cleanup_list.tempdir_allocated + 1;
175 struct tempdir * volatile *new_array =
176 XNMALLOC (new_allocated, struct tempdir * volatile);
177
178 if (old_allocated == 0)
179 {
180
181 if (clean_temp_init () < 0)
182 xalloc_die ();
183 }
184 else
185 {
186
187
188
189 size_t k;
190
191 for (k = 0; k < old_allocated; k++)
192 new_array[k] = old_array[k];
193 }
194
195 dir_cleanup_list.tempdir_list = new_array;
196 dir_cleanup_list.tempdir_allocated = new_allocated;
197
198
199
200
201
202
203
204 #if 0
205 if (old_array != NULL)
206 free ((struct tempdir **) old_array);
207 #endif
208 }
209
210 tmpdirp = &dir_cleanup_list.tempdir_list[dir_cleanup_list.tempdir_count];
211
212
213 *tmpdirp = NULL;
214 dir_cleanup_list.tempdir_count++;
215 }
216
217
218 tmpdir = XMALLOC (struct tempdir);
219 tmpdir->dirname = NULL;
220 tmpdir->cleanup_verbose = cleanup_verbose;
221 tmpdir->subdirs =
222 gl_list_create_empty (GL_LINKEDHASH_LIST,
223 clean_temp_string_equals, clean_temp_string_hash,
224 NULL, false);
225 tmpdir->files =
226 gl_list_create_empty (GL_LINKEDHASH_LIST,
227 clean_temp_string_equals, clean_temp_string_hash,
228 NULL, false);
229
230
231 xtemplate = (char *) xmalloca (PATH_MAX);
232 if (path_search (xtemplate, PATH_MAX, parentdir, prefix, parentdir == NULL))
233 {
234 error (0, errno,
235 _("cannot find a temporary directory, try setting $TMPDIR"));
236 goto quit;
237 }
238 block_fatal_signals ();
239 tmpdirname = mkdtemp (xtemplate);
240 int saved_errno = errno;
241 if (tmpdirname != NULL)
242 {
243 tmpdir->dirname = tmpdirname;
244 *tmpdirp = tmpdir;
245 }
246 unblock_fatal_signals ();
247 if (tmpdirname == NULL)
248 {
249 error (0, saved_errno,
250 _("cannot create a temporary directory using template \"%s\""),
251 xtemplate);
252 goto quit;
253 }
254
255
256
257
258 tmpdir->dirname = xstrdup (tmpdirname);
259 if (mt) gl_lock_unlock (dir_cleanup_list_lock);
260 freea (xtemplate);
261 return (struct temp_dir *) tmpdir;
262
263 quit:
264 if (mt) gl_lock_unlock (dir_cleanup_list_lock);
265 freea (xtemplate);
266 return NULL;
267 }
268
269
270
271
272 void
273 register_temp_file (struct temp_dir *dir,
274 const char *absolute_file_name)
275 {
276 struct tempdir *tmpdir = (struct tempdir *)dir;
277 bool mt = gl_multithreaded ();
278
279 if (mt) gl_lock_lock (dir_cleanup_list_lock);
280
281
282 if (gl_list_search (tmpdir->files, absolute_file_name) == NULL)
283 gl_list_add_first (tmpdir->files, xstrdup (absolute_file_name));
284
285 if (mt) gl_lock_unlock (dir_cleanup_list_lock);
286 }
287
288
289
290
291 void
292 unregister_temp_file (struct temp_dir *dir,
293 const char *absolute_file_name)
294 {
295 struct tempdir *tmpdir = (struct tempdir *)dir;
296 bool mt = gl_multithreaded ();
297
298 if (mt) gl_lock_lock (dir_cleanup_list_lock);
299
300 gl_list_t list = tmpdir->files;
301 gl_list_node_t node;
302
303 node = gl_list_search (list, absolute_file_name);
304 if (node != NULL)
305 {
306 char *old_string = (char *) gl_list_node_value (list, node);
307
308 gl_list_remove_node (list, node);
309 free (old_string);
310 }
311
312 if (mt) gl_lock_unlock (dir_cleanup_list_lock);
313 }
314
315
316
317
318 void
319 register_temp_subdir (struct temp_dir *dir,
320 const char *absolute_dir_name)
321 {
322 struct tempdir *tmpdir = (struct tempdir *)dir;
323 bool mt = gl_multithreaded ();
324
325 if (mt) gl_lock_lock (dir_cleanup_list_lock);
326
327
328 if (gl_list_search (tmpdir->subdirs, absolute_dir_name) == NULL)
329 gl_list_add_first (tmpdir->subdirs, xstrdup (absolute_dir_name));
330
331 if (mt) gl_lock_unlock (dir_cleanup_list_lock);
332 }
333
334
335
336
337
338 void
339 unregister_temp_subdir (struct temp_dir *dir,
340 const char *absolute_dir_name)
341 {
342 struct tempdir *tmpdir = (struct tempdir *)dir;
343 bool mt = gl_multithreaded ();
344
345 if (mt) gl_lock_lock (dir_cleanup_list_lock);
346
347 gl_list_t list = tmpdir->subdirs;
348 gl_list_node_t node;
349
350 node = gl_list_search (list, absolute_dir_name);
351 if (node != NULL)
352 {
353 char *old_string = (char *) gl_list_node_value (list, node);
354
355 gl_list_remove_node (list, node);
356 free (old_string);
357 }
358
359 if (mt) gl_lock_unlock (dir_cleanup_list_lock);
360 }
361
362
363
364 static int
365 do_rmdir (const char *absolute_dir_name, bool cleanup_verbose)
366 {
367 if (rmdir (absolute_dir_name) < 0 && cleanup_verbose
368 && errno != ENOENT)
369 {
370 error (0, errno,
371 _("cannot remove temporary directory %s"), absolute_dir_name);
372 return -1;
373 }
374 return 0;
375 }
376
377
378
379 int
380 cleanup_temp_file (struct temp_dir *dir,
381 const char *absolute_file_name)
382 {
383 int err;
384
385 err = clean_temp_unlink (absolute_file_name, dir->cleanup_verbose);
386 unregister_temp_file (dir, absolute_file_name);
387
388 return err;
389 }
390
391
392
393 int
394 cleanup_temp_subdir (struct temp_dir *dir,
395 const char *absolute_dir_name)
396 {
397 int err;
398
399 err = do_rmdir (absolute_dir_name, dir->cleanup_verbose);
400 unregister_temp_subdir (dir, absolute_dir_name);
401
402 return err;
403 }
404
405
406
407
408 int
409 cleanup_temp_dir_contents (struct temp_dir *dir)
410 {
411 struct tempdir *tmpdir = (struct tempdir *)dir;
412 int err = 0;
413 gl_list_t list;
414 gl_list_iterator_t iter;
415 const void *element;
416 gl_list_node_t node;
417
418
419 list = tmpdir->files;
420 iter = gl_list_iterator (list);
421 while (gl_list_iterator_next (&iter, &element, &node))
422 {
423 char *file = (char *) element;
424
425 err |= clean_temp_unlink (file, dir->cleanup_verbose);
426 gl_list_remove_node (list, node);
427
428 free (file);
429 }
430 gl_list_iterator_free (&iter);
431
432
433 list = tmpdir->subdirs;
434 iter = gl_list_iterator (list);
435 while (gl_list_iterator_next (&iter, &element, &node))
436 {
437 char *subdir = (char *) element;
438
439 err |= do_rmdir (subdir, dir->cleanup_verbose);
440 gl_list_remove_node (list, node);
441
442 free (subdir);
443 }
444 gl_list_iterator_free (&iter);
445
446 return err;
447 }
448
449
450
451
452 int
453 cleanup_temp_dir (struct temp_dir *dir)
454 {
455 bool mt = gl_multithreaded ();
456
457 if (mt) gl_lock_lock (dir_cleanup_list_lock);
458
459 struct tempdir *tmpdir = (struct tempdir *)dir;
460 int err = 0;
461 size_t i;
462
463 err |= cleanup_temp_dir_contents (dir);
464 err |= do_rmdir (tmpdir->dirname, dir->cleanup_verbose);
465
466 for (i = 0; i < dir_cleanup_list.tempdir_count; i++)
467 if (dir_cleanup_list.tempdir_list[i] == tmpdir)
468 {
469
470 if (i + 1 == dir_cleanup_list.tempdir_count)
471 {
472 while (i > 0 && dir_cleanup_list.tempdir_list[i - 1] == NULL)
473 i--;
474 dir_cleanup_list.tempdir_count = i;
475 }
476 else
477 dir_cleanup_list.tempdir_list[i] = NULL;
478
479
480 gl_list_free (tmpdir->files);
481 gl_list_free (tmpdir->subdirs);
482 free (tmpdir->dirname);
483 free (tmpdir);
484 if (mt) gl_lock_unlock (dir_cleanup_list_lock);
485 return err;
486 }
487
488
489 abort ();
490 }
491
492
493
494
495 #if defined _WIN32 && ! defined __CYGWIN__
496
497
498
499
500
501
502
503 static bool
504 supports_delete_on_close ()
505 {
506 static int known;
507 if (!known)
508 {
509 OSVERSIONINFO v;
510
511
512
513
514 v.dwOSVersionInfoSize = sizeof (OSVERSIONINFO);
515
516 if (GetVersionEx (&v))
517 known = (v.dwPlatformId == VER_PLATFORM_WIN32_NT ? 1 : -1);
518 else
519 known = -1;
520 }
521 return (known > 0);
522 }
523
524 #endif
525
526
527
528 static void
529 register_fd (int fd)
530 {
531 bool mt = gl_multithreaded ();
532
533 if (mt) gl_lock_lock (descriptors_lock);
534
535 if (descriptors == NULL)
536 descriptors = gl_list_create_empty (GL_LINKED_LIST, NULL, NULL, NULL,
537 false);
538
539 struct closeable_fd *element = XMALLOC (struct closeable_fd);
540 element->fd = fd;
541 element->closed = false;
542 asyncsafe_spin_init (&element->lock);
543 element->done = false;
544
545 gl_list_add_first (descriptors, element);
546
547 if (mt) gl_lock_unlock (descriptors_lock);
548 }
549
550
551
552
553
554
555 int
556 open_temp (const char *file_name, int flags, mode_t mode, bool delete_on_close)
557 {
558 int fd;
559 int saved_errno;
560
561 block_fatal_signals ();
562
563 #if defined _WIN32 && ! defined __CYGWIN__
564
565
566 if (delete_on_close && supports_delete_on_close ())
567 fd = open (file_name, flags | _O_TEMPORARY, mode);
568 else
569 #endif
570 fd = open (file_name, flags, mode);
571 saved_errno = errno;
572 if (fd >= 0)
573 register_fd (fd);
574 unblock_fatal_signals ();
575 errno = saved_errno;
576 return fd;
577 }
578
579
580
581
582
583
584 FILE *
585 fopen_temp (const char *file_name, const char *mode, bool delete_on_close)
586 {
587 FILE *fp;
588 int saved_errno;
589
590 block_fatal_signals ();
591
592 #if defined _WIN32 && ! defined __CYGWIN__
593
594
595 if (delete_on_close && supports_delete_on_close ())
596 {
597 size_t mode_len = strlen (mode);
598 char *augmented_mode = (char *) xmalloca (mode_len + 2);
599 memcpy (augmented_mode, mode, mode_len);
600 memcpy (augmented_mode + mode_len, "D", 2);
601
602 fp = fopen (file_name, augmented_mode);
603 saved_errno = errno;
604
605 freea (augmented_mode);
606 }
607 else
608 #endif
609 {
610 fp = fopen (file_name, mode);
611 saved_errno = errno;
612 }
613 if (fp != NULL)
614 {
615
616
617
618 int fd = fileno (fp);
619 if (!(fd >= 0))
620 abort ();
621 register_fd (fd);
622 }
623 unblock_fatal_signals ();
624 errno = saved_errno;
625 return fp;
626 }
627
628 #if GNULIB_TEMPNAME
629
630 struct try_create_file_params
631 {
632 int flags;
633 mode_t mode;
634 };
635
636 static int
637 try_create_file (char *file_name_tmpl, void *params_)
638 {
639 struct try_create_file_params *params = params_;
640 return open (file_name_tmpl,
641 (params->flags & ~O_ACCMODE) | O_RDWR | O_CREAT | O_EXCL,
642 params->mode);
643 }
644
645
646
647
648
649
650
651
652
653 int
654 gen_register_open_temp (char *file_name_tmpl, int suffixlen,
655 int flags, mode_t mode)
656 {
657 block_fatal_signals ();
658
659 struct try_create_file_params params;
660 params.flags = flags;
661 params.mode = mode;
662
663 int fd = try_tempname (file_name_tmpl, suffixlen, ¶ms, try_create_file);
664
665 int saved_errno = errno;
666 if (fd >= 0)
667 {
668 if (clean_temp_init () < 0)
669 xalloc_die ();
670 register_fd (fd);
671 if (register_temporary_file (file_name_tmpl) < 0)
672 xalloc_die ();
673 }
674 unblock_fatal_signals ();
675 errno = saved_errno;
676 return fd;
677 }
678
679 #endif
680
681
682
683
684 int
685 close_temp (int fd)
686 {
687 if (fd < 0)
688 return close (fd);
689
690 clean_temp_init_asyncsafe_close ();
691
692 int result = 0;
693 int saved_errno = 0;
694
695 bool mt = gl_multithreaded ();
696
697 if (mt) gl_lock_lock (descriptors_lock);
698
699 gl_list_t list = descriptors;
700 if (list == NULL)
701
702 abort ();
703
704
705 bool found = false;
706 gl_list_iterator_t iter = gl_list_iterator (list);
707 const void *elt;
708 gl_list_node_t node;
709 if (gl_list_iterator_next (&iter, &elt, &node))
710 for (;;)
711 {
712 struct closeable_fd *element = (struct closeable_fd *) elt;
713
714
715
716 if (element->fd == fd)
717 {
718 found = true;
719 result = clean_temp_asyncsafe_close (element);
720 saved_errno = errno;
721 }
722
723 bool free_this_node = element->done;
724 struct closeable_fd *element_to_free = element;
725 gl_list_node_t node_to_free = node;
726
727 bool have_next = gl_list_iterator_next (&iter, &elt, &node);
728
729 if (free_this_node)
730 {
731 free (element_to_free);
732 gl_list_remove_node (list, node_to_free);
733 }
734
735 if (!have_next)
736 break;
737 }
738 gl_list_iterator_free (&iter);
739 if (!found)
740
741 abort ();
742
743 if (mt) gl_lock_unlock (descriptors_lock);
744
745 errno = saved_errno;
746 return result;
747 }
748
749 static int
750 fclose_variant_temp (FILE *fp, int (*fclose_variant) (FILE *))
751 {
752 int fd = fileno (fp);
753
754 int result = 0;
755 int saved_errno = 0;
756
757 bool mt = gl_multithreaded ();
758
759 if (mt) gl_lock_lock (descriptors_lock);
760
761 gl_list_t list = descriptors;
762 if (list == NULL)
763
764 abort ();
765
766
767 bool found = false;
768 gl_list_iterator_t iter = gl_list_iterator (list);
769 const void *elt;
770 gl_list_node_t node;
771 if (gl_list_iterator_next (&iter, &elt, &node))
772 for (;;)
773 {
774 struct closeable_fd *element = (struct closeable_fd *) elt;
775
776
777
778 if (element->fd == fd)
779 {
780 found = true;
781 result = asyncsafe_fclose_variant (element, fp, fclose_variant);
782 saved_errno = errno;
783 }
784
785 bool free_this_node = element->done;
786 struct closeable_fd *element_to_free = element;
787 gl_list_node_t node_to_free = node;
788
789 bool have_next = gl_list_iterator_next (&iter, &elt, &node);
790
791 if (free_this_node)
792 {
793 free (element_to_free);
794 gl_list_remove_node (list, node_to_free);
795 }
796
797 if (!have_next)
798 break;
799 }
800 gl_list_iterator_free (&iter);
801 if (!found)
802
803 abort ();
804
805 if (mt) gl_lock_unlock (descriptors_lock);
806
807 errno = saved_errno;
808 return result;
809 }
810
811
812
813
814
815 int
816 fclose_temp (FILE *fp)
817 {
818 return fclose_variant_temp (fp, fclose);
819 }
820
821 #if GNULIB_FWRITEERROR
822
823
824
825
826 int
827 fwriteerror_temp (FILE *fp)
828 {
829 return fclose_variant_temp (fp, fwriteerror);
830 }
831 #endif
832
833 #if GNULIB_CLOSE_STREAM
834
835
836
837
838 int
839 close_stream_temp (FILE *fp)
840 {
841 return fclose_variant_temp (fp, close_stream);
842 }
843 #endif