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