unlink.c 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179
  1. /* Unlink files.
  2. Copyright 2009, 2013 Free Software Foundation, Inc.
  3. This file is part of GNU tar.
  4. GNU tar is free software; you can redistribute it and/or modify
  5. it under the terms of the GNU General Public License as published by
  6. the Free Software Foundation; either version 3 of the License, or
  7. (at your option) any later version.
  8. GNU tar is distributed in the hope that it will be useful,
  9. but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  11. GNU General Public License for more details.
  12. You should have received a copy of the GNU General Public License
  13. along with this program. If not, see <http://www.gnu.org/licenses/>. */
  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. int dir_idx; /* Directory index in wd */
  21. char *file_name; /* Name of the file to unlink, relative
  22. to dir_idx */
  23. bool is_dir; /* True if file_name is a directory */
  24. off_t records_written; /* Number of records written when this
  25. entry got added to the queue */
  26. };
  27. /* The unlink queue */
  28. static struct deferred_unlink *dunlink_head, *dunlink_tail;
  29. /* Number of entries in the queue */
  30. static size_t dunlink_count;
  31. /* List of entries available for allocation */
  32. static struct deferred_unlink *dunlink_avail;
  33. /* Delay (number of records written) between adding entry to the
  34. list and its actual removal. */
  35. static size_t deferred_unlink_delay = 0;
  36. static struct deferred_unlink *
  37. dunlink_alloc (void)
  38. {
  39. struct deferred_unlink *p;
  40. if (dunlink_avail)
  41. {
  42. p = dunlink_avail;
  43. dunlink_avail = p->next;
  44. p->next = NULL;
  45. }
  46. else
  47. p = xmalloc (sizeof (*p));
  48. return p;
  49. }
  50. static void
  51. dunlink_reclaim (struct deferred_unlink *p)
  52. {
  53. free (p->file_name);
  54. p->next = dunlink_avail;
  55. dunlink_avail = p;
  56. }
  57. static void
  58. flush_deferred_unlinks (bool force)
  59. {
  60. struct deferred_unlink *p, *prev = NULL;
  61. int saved_chdir = chdir_current;
  62. for (p = dunlink_head; p; )
  63. {
  64. struct deferred_unlink *next = p->next;
  65. if (force
  66. || records_written > p->records_written + deferred_unlink_delay)
  67. {
  68. chdir_do (p->dir_idx);
  69. if (p->is_dir)
  70. {
  71. const char *fname;
  72. if (p->file_name[0] == 0 ||
  73. strcmp (p->file_name, ".") == 0)
  74. {
  75. fname = tar_dirname ();
  76. chdir_do (p->dir_idx - 1);
  77. }
  78. else
  79. fname = p->file_name;
  80. if (unlinkat (chdir_fd, fname, AT_REMOVEDIR) != 0)
  81. {
  82. switch (errno)
  83. {
  84. case ENOENT:
  85. /* nothing to worry about */
  86. break;
  87. case ENOTEMPTY:
  88. if (!force)
  89. {
  90. /* Keep the record in list, in the hope we'll
  91. be able to remove it later */
  92. prev = p;
  93. p = next;
  94. continue;
  95. }
  96. /* fall through */
  97. default:
  98. rmdir_error (fname);
  99. }
  100. }
  101. }
  102. else
  103. {
  104. if (unlinkat (chdir_fd, p->file_name, 0) != 0 && errno != ENOENT)
  105. unlink_error (p->file_name);
  106. }
  107. dunlink_reclaim (p);
  108. dunlink_count--;
  109. p = next;
  110. if (prev)
  111. prev->next = p;
  112. else
  113. dunlink_head = p;
  114. }
  115. else
  116. {
  117. prev = p;
  118. p = next;
  119. }
  120. }
  121. if (!dunlink_head)
  122. dunlink_tail = NULL;
  123. chdir_do (saved_chdir);
  124. }
  125. void
  126. finish_deferred_unlinks (void)
  127. {
  128. flush_deferred_unlinks (true);
  129. while (dunlink_avail)
  130. {
  131. struct deferred_unlink *next = dunlink_avail->next;
  132. free (dunlink_avail);
  133. dunlink_avail = next;
  134. }
  135. }
  136. void
  137. queue_deferred_unlink (const char *name, bool is_dir)
  138. {
  139. struct deferred_unlink *p;
  140. if (dunlink_head
  141. && records_written > dunlink_head->records_written + deferred_unlink_delay)
  142. flush_deferred_unlinks (false);
  143. p = dunlink_alloc ();
  144. p->next = NULL;
  145. p->dir_idx = chdir_current;
  146. p->file_name = xstrdup (name);
  147. normalize_filename_x (p->file_name);
  148. p->is_dir = is_dir;
  149. p->records_written = records_written;
  150. if (dunlink_tail)
  151. dunlink_tail->next = p;
  152. else
  153. dunlink_head = p;
  154. dunlink_tail = p;
  155. dunlink_count++;
  156. }