~ubuntu-branches/ubuntu/utopic/gettext/utopic

« back to all changes in this revision

Viewing changes to gettext-tools/gnulib-lib/clean-temp.c

  • Committer: Colin Watson
  • Date: 2010-08-01 21:36:08 UTC
  • mfrom: (2.1.10 sid)
  • Revision ID: cjwatson@canonical.com-20100801213608-yy7vkm8lpatep3ci
merge from Debian 0.18.1.1-1

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
1
/* Temporary directories and temporary files with automatic cleanup.
2
 
   Copyright (C) 2001, 2003, 2006-2007 Free Software Foundation, Inc.
 
2
   Copyright (C) 2001, 2003, 2006-2007, 2009-2010 Free Software Foundation,
 
3
   Inc.
3
4
   Written by Bruno Haible <bruno@clisp.org>, 2006.
4
5
 
5
6
   This program is free software: you can redistribute it and/or modify
40
41
#include "tmpdir.h"
41
42
#include "xalloc.h"
42
43
#include "xmalloca.h"
 
44
#include "gl_xlist.h"
43
45
#include "gl_linkedhash_list.h"
44
46
#include "gettext.h"
45
47
#if GNULIB_FWRITEERROR
199
201
 
200
202
    if (fds != NULL)
201
203
      {
202
 
        gl_list_iterator_t iter;
203
 
        const void *element;
 
204
        gl_list_iterator_t iter;
 
205
        const void *element;
204
206
 
205
 
        iter = gl_list_iterator (fds);
206
 
        while (gl_list_iterator_next (&iter, &element, NULL))
207
 
          {
208
 
            int fd = (int) (uintptr_t) element;
209
 
            close (fd);
210
 
          }
211
 
        gl_list_iterator_free (&iter);
 
207
        iter = gl_list_iterator (fds);
 
208
        while (gl_list_iterator_next (&iter, &element, NULL))
 
209
          {
 
210
            int fd = (int) (uintptr_t) element;
 
211
            close (fd);
 
212
          }
 
213
        gl_list_iterator_free (&iter);
212
214
      }
213
215
  }
214
216
 
217
219
      struct tempdir *dir = cleanup_list.tempdir_list[i];
218
220
 
219
221
      if (dir != NULL)
220
 
        {
221
 
          gl_list_iterator_t iter;
222
 
          const void *element;
223
 
 
224
 
          /* First cleanup the files in the subdirectories.  */
225
 
          iter = gl_list_iterator (dir->files);
226
 
          while (gl_list_iterator_next (&iter, &element, NULL))
227
 
            {
228
 
              const char *file = (const char *) element;
229
 
              unlink (file);
230
 
            }
231
 
          gl_list_iterator_free (&iter);
232
 
 
233
 
          /* Then cleanup the subdirectories.  */
234
 
          iter = gl_list_iterator (dir->subdirs);
235
 
          while (gl_list_iterator_next (&iter, &element, NULL))
236
 
            {
237
 
              const char *subdir = (const char *) element;
238
 
              rmdir (subdir);
239
 
            }
240
 
          gl_list_iterator_free (&iter);
241
 
 
242
 
          /* Then cleanup the temporary directory itself.  */
243
 
          rmdir (dir->dirname);
244
 
        }
 
222
        {
 
223
          gl_list_iterator_t iter;
 
224
          const void *element;
 
225
 
 
226
          /* First cleanup the files in the subdirectories.  */
 
227
          iter = gl_list_iterator (dir->files);
 
228
          while (gl_list_iterator_next (&iter, &element, NULL))
 
229
            {
 
230
              const char *file = (const char *) element;
 
231
              unlink (file);
 
232
            }
 
233
          gl_list_iterator_free (&iter);
 
234
 
 
235
          /* Then cleanup the subdirectories.  */
 
236
          iter = gl_list_iterator (dir->subdirs);
 
237
          while (gl_list_iterator_next (&iter, &element, NULL))
 
238
            {
 
239
              const char *subdir = (const char *) element;
 
240
              rmdir (subdir);
 
241
            }
 
242
          gl_list_iterator_free (&iter);
 
243
 
 
244
          /* Then cleanup the temporary directory itself.  */
 
245
          rmdir (dir->dirname);
 
246
        }
245
247
    }
246
248
}
247
249
 
256
258
   is shown and NULL is returned.  */
257
259
struct temp_dir *
258
260
create_temp_dir (const char *prefix, const char *parentdir,
259
 
                 bool cleanup_verbose)
 
261
                 bool cleanup_verbose)
260
262
{
261
263
  struct tempdir * volatile *tmpdirp = NULL;
262
264
  struct tempdir *tmpdir;
269
271
  for (i = 0; i < cleanup_list.tempdir_count; i++)
270
272
    if (cleanup_list.tempdir_list[i] == NULL)
271
273
      {
272
 
        tmpdirp = &cleanup_list.tempdir_list[i];
273
 
        break;
 
274
        tmpdirp = &cleanup_list.tempdir_list[i];
 
275
        break;
274
276
      }
275
277
  if (tmpdirp == NULL)
276
278
    {
277
279
      /* See whether the array needs to be extended.  */
278
280
      if (cleanup_list.tempdir_count == cleanup_list.tempdir_allocated)
279
 
        {
280
 
          /* Note that we cannot use xrealloc(), because then the cleanup()
281
 
             function could access an already deallocated array.  */
282
 
          struct tempdir * volatile *old_array = cleanup_list.tempdir_list;
283
 
          size_t old_allocated = cleanup_list.tempdir_allocated;
284
 
          size_t new_allocated = 2 * cleanup_list.tempdir_allocated + 1;
285
 
          struct tempdir * volatile *new_array =
286
 
            XNMALLOC (new_allocated, struct tempdir * volatile);
287
 
 
288
 
          if (old_allocated == 0)
289
 
            /* First use of this facility.  Register the cleanup handler.  */
290
 
            at_fatal_signal (&cleanup);
291
 
          else
292
 
            {
293
 
              /* Don't use memcpy() here, because memcpy takes non-volatile
294
 
                 arguments and is therefore not guaranteed to complete all
295
 
                 memory stores before the next statement.  */
296
 
              size_t k;
297
 
 
298
 
              for (k = 0; k < old_allocated; k++)
299
 
                new_array[k] = old_array[k];
300
 
            }
301
 
 
302
 
          cleanup_list.tempdir_list = new_array;
303
 
          cleanup_list.tempdir_allocated = new_allocated;
304
 
 
305
 
          /* Now we can free the old array.  */
306
 
          if (old_array != NULL)
307
 
            free ((struct tempdir **) old_array);
308
 
        }
 
281
        {
 
282
          /* Note that we cannot use xrealloc(), because then the cleanup()
 
283
             function could access an already deallocated array.  */
 
284
          struct tempdir * volatile *old_array = cleanup_list.tempdir_list;
 
285
          size_t old_allocated = cleanup_list.tempdir_allocated;
 
286
          size_t new_allocated = 2 * cleanup_list.tempdir_allocated + 1;
 
287
          struct tempdir * volatile *new_array =
 
288
            XNMALLOC (new_allocated, struct tempdir * volatile);
 
289
 
 
290
          if (old_allocated == 0)
 
291
            /* First use of this facility.  Register the cleanup handler.  */
 
292
            at_fatal_signal (&cleanup);
 
293
          else
 
294
            {
 
295
              /* Don't use memcpy() here, because memcpy takes non-volatile
 
296
                 arguments and is therefore not guaranteed to complete all
 
297
                 memory stores before the next statement.  */
 
298
              size_t k;
 
299
 
 
300
              for (k = 0; k < old_allocated; k++)
 
301
                new_array[k] = old_array[k];
 
302
            }
 
303
 
 
304
          cleanup_list.tempdir_list = new_array;
 
305
          cleanup_list.tempdir_allocated = new_allocated;
 
306
 
 
307
          /* Now we can free the old array.  */
 
308
          if (old_array != NULL)
 
309
            free ((struct tempdir **) old_array);
 
310
        }
309
311
 
310
312
      tmpdirp = &cleanup_list.tempdir_list[cleanup_list.tempdir_count];
311
313
      /* Initialize *tmpdirp before incrementing tempdir_count, so that
312
 
         cleanup() will skip this entry before it is fully initialized.  */
 
314
         cleanup() will skip this entry before it is fully initialized.  */
313
315
      *tmpdirp = NULL;
314
316
      cleanup_list.tempdir_count++;
315
317
    }
319
321
  tmpdir->dirname = NULL;
320
322
  tmpdir->cleanup_verbose = cleanup_verbose;
321
323
  tmpdir->subdirs = gl_list_create_empty (GL_LINKEDHASH_LIST,
322
 
                                          string_equals, string_hash, NULL,
323
 
                                          false);
 
324
                                          string_equals, string_hash, NULL,
 
325
                                          false);
324
326
  tmpdir->files = gl_list_create_empty (GL_LINKEDHASH_LIST,
325
 
                                        string_equals, string_hash, NULL,
326
 
                                        false);
 
327
                                        string_equals, string_hash, NULL,
 
328
                                        false);
327
329
 
328
330
  /* Create the temporary directory.  */
329
331
  xtemplate = (char *) xmalloca (PATH_MAX);
330
332
  if (path_search (xtemplate, PATH_MAX, parentdir, prefix, parentdir == NULL))
331
333
    {
332
334
      error (0, errno,
333
 
             _("cannot find a temporary directory, try setting $TMPDIR"));
 
335
             _("cannot find a temporary directory, try setting $TMPDIR"));
334
336
      goto quit;
335
337
    }
336
338
  block_fatal_signals ();
344
346
  if (tmpdirname == NULL)
345
347
    {
346
348
      error (0, errno,
347
 
             _("cannot create a temporary directory using template \"%s\""),
348
 
             xtemplate);
 
349
             _("cannot create a temporary directory using template \"%s\""),
 
350
             xtemplate);
349
351
      goto quit;
350
352
    }
351
353
  /* Replace tmpdir->dirname with a copy that has indefinite extent.
366
368
   Should be called before the file ABSOLUTE_FILE_NAME is created.  */
367
369
void
368
370
register_temp_file (struct temp_dir *dir,
369
 
                    const char *absolute_file_name)
 
371
                    const char *absolute_file_name)
370
372
{
371
373
  struct tempdir *tmpdir = (struct tempdir *)dir;
372
374
 
380
382
   Should be called when the file ABSOLUTE_FILE_NAME could not be created.  */
381
383
void
382
384
unregister_temp_file (struct temp_dir *dir,
383
 
                      const char *absolute_file_name)
 
385
                      const char *absolute_file_name)
384
386
{
385
387
  struct tempdir *tmpdir = (struct tempdir *)dir;
386
388
  gl_list_t list = tmpdir->files;
401
403
   Should be called before the subdirectory ABSOLUTE_DIR_NAME is created.  */
402
404
void
403
405
register_temp_subdir (struct temp_dir *dir,
404
 
                      const char *absolute_dir_name)
 
406
                      const char *absolute_dir_name)
405
407
{
406
408
  struct tempdir *tmpdir = (struct tempdir *)dir;
407
409
 
416
418
   created.  */
417
419
void
418
420
unregister_temp_subdir (struct temp_dir *dir,
419
 
                        const char *absolute_dir_name)
 
421
                        const char *absolute_dir_name)
420
422
{
421
423
  struct tempdir *tmpdir = (struct tempdir *)dir;
422
424
  gl_list_t list = tmpdir->subdirs;
455
457
      && errno != ENOENT)
456
458
    {
457
459
      error (0, errno,
458
 
             _("cannot remove temporary directory %s"), absolute_dir_name);
 
460
             _("cannot remove temporary directory %s"), absolute_dir_name);
459
461
      return -1;
460
462
    }
461
463
  return 0;
465
467
   Return 0 upon success, or -1 if there was some problem.  */
466
468
int
467
469
cleanup_temp_file (struct temp_dir *dir,
468
 
                   const char *absolute_file_name)
 
470
                   const char *absolute_file_name)
469
471
{
470
472
  int err;
471
473
 
479
481
   Return 0 upon success, or -1 if there was some problem.  */
480
482
int
481
483
cleanup_temp_subdir (struct temp_dir *dir,
482
 
                     const char *absolute_dir_name)
 
484
                     const char *absolute_dir_name)
483
485
{
484
486
  int err;
485
487
 
548
550
  for (i = 0; i < cleanup_list.tempdir_count; i++)
549
551
    if (cleanup_list.tempdir_list[i] == tmpdir)
550
552
      {
551
 
        /* Remove cleanup_list.tempdir_list[i].  */
552
 
        if (i + 1 == cleanup_list.tempdir_count)
553
 
          {
554
 
            while (i > 0 && cleanup_list.tempdir_list[i - 1] == NULL)
555
 
              i--;
556
 
            cleanup_list.tempdir_count = i;
557
 
          }
558
 
        else
559
 
          cleanup_list.tempdir_list[i] = NULL;
560
 
        /* Now only we can free the tmpdir->dirname and tmpdir itself.  */
561
 
        free (tmpdir->dirname);
562
 
        free (tmpdir);
563
 
        return err;
 
553
        /* Remove cleanup_list.tempdir_list[i].  */
 
554
        if (i + 1 == cleanup_list.tempdir_count)
 
555
          {
 
556
            while (i > 0 && cleanup_list.tempdir_list[i - 1] == NULL)
 
557
              i--;
 
558
            cleanup_list.tempdir_count = i;
 
559
          }
 
560
        else
 
561
          cleanup_list.tempdir_list[i] = NULL;
 
562
        /* Now only we can free the tmpdir->dirname and tmpdir itself.  */
 
563
        free (tmpdir->dirname);
 
564
        free (tmpdir);
 
565
        return err;
564
566
      }
565
567
 
566
568
  /* The user passed an invalid DIR argument.  */
585
587
      OSVERSIONINFO v;
586
588
 
587
589
      if (GetVersionEx (&v))
588
 
        known = (v.dwPlatformId == VER_PLATFORM_WIN32_NT ? 1 : -1);
 
590
        known = (v.dwPlatformId == VER_PLATFORM_WIN32_NT ? 1 : -1);
589
591
      else
590
 
        known = -1;
 
592
        known = -1;
591
593
    }
592
594
  return (known > 0);
593
595
}
601
603
{
602
604
  if (descriptors == NULL)
603
605
    descriptors = gl_list_create_empty (GL_LINKEDHASH_LIST, NULL, NULL, NULL,
604
 
                                        false);
 
606
                                        false);
605
607
  gl_list_add_first (descriptors, (void *) (uintptr_t) fd);
606
608
}
607
609
 
682
684
  if (fp != NULL)
683
685
    {
684
686
      /* It is sufficient to register fileno (fp) instead of the entire fp,
685
 
         because at cleanup time there is no need to do an fflush (fp); a
686
 
         close (fileno (fp)) will be enough.  */
 
687
         because at cleanup time there is no need to do an fflush (fp); a
 
688
         close (fileno (fp)) will be enough.  */
687
689
      int fd = fileno (fp);
688
690
      if (!(fd >= 0))
689
 
        abort ();
 
691
        abort ();
690
692
      register_fd (fd);
691
693
    }
692
694
  unblock_fatal_signals ();
702
704
  if (fd >= 0)
703
705
    {
704
706
      /* No blocking of signals is needed here, since a double close of a
705
 
         file descriptor is harmless.  */
 
707
         file descriptor is harmless.  */
706
708
      int result = close (fd);
707
709
      int saved_errno = errno;
708
710
 
709
711
      /* No race condition here: we assume a single-threaded program, hence
710
 
         fd cannot be re-opened here.  */
 
712
         fd cannot be re-opened here.  */
711
713
 
712
714
      unregister_fd (fd);
713
715