unlink.c 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158
  1. /* This file is part of GNU tar.
  2. Copyright (C) 2009 Free Software Foundation, Inc.
  3. This program is free software; you can redistribute it and/or modify it
  4. under the terms of the GNU General Public License as published by the
  5. Free Software Foundation; either version 3, or (at your option) any later
  6. version.
  7. This program is distributed in the hope that it will be useful, but
  8. WITHOUT ANY WARRANTY; without even the implied warranty of
  9. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
  10. Public License for more details.
  11. You should have received a copy of the GNU General Public License along
  12. with this program; if not, write to the Free Software Foundation, Inc.,
  13. 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
  14. #include <system.h>
  15. #include "common.h"
  16. #include <quotearg.h>
  17. struct deferred_unlink
  18. {
  19. struct deferred_unlink *next; /* Next unlink in the queue */
  20. char *file_name; /* Absolute name of the file to unlink */
  21. bool is_dir; /* True if file_name is a directory */
  22. off_t records_written; /* Number of records written when this
  23. entry got added to the queue */
  24. };
  25. /* The unlink queue */
  26. static struct deferred_unlink *dunlink_head, *dunlink_tail;
  27. /* Number of entries in the queue */
  28. static size_t dunlink_count;
  29. /* List of entries available for allocation */
  30. static struct deferred_unlink *dunlink_avail;
  31. /* Delay (number of records written) between adding entry to the
  32. list and its actual removal. */
  33. size_t deferred_unlink_delay = 0;
  34. static struct deferred_unlink *
  35. dunlink_alloc ()
  36. {
  37. struct deferred_unlink *p;
  38. if (dunlink_avail)
  39. {
  40. p = dunlink_avail;
  41. dunlink_avail = p->next;
  42. p->next = NULL;
  43. }
  44. else
  45. p = xmalloc (sizeof (*p));
  46. return p;
  47. }
  48. static void
  49. dunlink_reclaim (struct deferred_unlink *p)
  50. {
  51. free (p->file_name);
  52. p->next = dunlink_avail;
  53. dunlink_avail = p;
  54. }
  55. static void
  56. flush_deferred_unlinks (bool force)
  57. {
  58. struct deferred_unlink *p, *prev = NULL;
  59. for (p = dunlink_head; p; )
  60. {
  61. struct deferred_unlink *next = p->next;
  62. if (force
  63. || records_written > p->records_written + deferred_unlink_delay)
  64. {
  65. if (p->is_dir)
  66. {
  67. if (rmdir (p->file_name) != 0)
  68. {
  69. switch (errno)
  70. {
  71. case ENOENT:
  72. /* nothing to worry about */
  73. break;
  74. case ENOTEMPTY:
  75. if (!force)
  76. {
  77. /* Keep the record in list, in the hope we'll
  78. be able to remove it later */
  79. prev = p;
  80. p = next;
  81. continue;
  82. }
  83. /* fall through */
  84. default:
  85. rmdir_error (p->file_name);
  86. }
  87. }
  88. }
  89. else
  90. {
  91. if (unlink (p->file_name) != 0 && errno != ENOENT)
  92. unlink_error (p->file_name);
  93. }
  94. dunlink_reclaim (p);
  95. dunlink_count--;
  96. p = next;
  97. if (prev)
  98. prev->next = p;
  99. else
  100. dunlink_head = p;
  101. }
  102. else
  103. {
  104. prev = p;
  105. p = next;
  106. }
  107. }
  108. if (!dunlink_head)
  109. dunlink_tail = NULL;
  110. }
  111. void
  112. finish_deferred_unlinks ()
  113. {
  114. flush_deferred_unlinks (true);
  115. while (dunlink_avail)
  116. {
  117. struct deferred_unlink *next = dunlink_avail->next;
  118. free (dunlink_avail);
  119. dunlink_avail = next;
  120. }
  121. }
  122. void
  123. queue_deferred_unlink (const char *name, bool is_dir)
  124. {
  125. struct deferred_unlink *p;
  126. if (dunlink_head
  127. && records_written > dunlink_head->records_written + deferred_unlink_delay)
  128. flush_deferred_unlinks (false);
  129. p = dunlink_alloc ();
  130. p->next = NULL;
  131. p->file_name = normalize_filename (name);
  132. p->is_dir = is_dir;
  133. p->records_written = records_written;
  134. if (dunlink_tail)
  135. dunlink_tail->next = p;
  136. else
  137. dunlink_head = p;
  138. dunlink_tail = p;
  139. dunlink_count++;
  140. }