Commit | Line | Data |
---|---|---|
974e1819 WD |
1 | /* |
2 | * Deletion routines used in rsync. | |
3 | * | |
4 | * Copyright (C) 1996-2000 Andrew Tridgell | |
5 | * Copyright (C) 1996 Paul Mackerras | |
6 | * Copyright (C) 2002 Martin Pool <mbp@samba.org> | |
7 | * Copyright (C) 2003-2009 Wayne Davison | |
8 | * | |
9 | * This program is free software; you can redistribute it and/or modify | |
10 | * it under the terms of the GNU General Public License as published by | |
11 | * the Free Software Foundation; either version 3 of the License, or | |
12 | * (at your option) any later version. | |
13 | * | |
14 | * This program is distributed in the hope that it will be useful, | |
15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
17 | * GNU General Public License for more details. | |
18 | * | |
19 | * You should have received a copy of the GNU General Public License along | |
20 | * with this program; if not, visit the http://fsf.org website. | |
21 | */ | |
22 | ||
23 | #include "rsync.h" | |
24 | ||
25 | extern int am_root; | |
26 | extern int make_backups; | |
27 | extern int max_delete; | |
28 | extern char *backup_dir; | |
29 | extern char *backup_suffix; | |
30 | extern int backup_suffix_len; | |
974e1819 WD |
31 | extern struct stats stats; |
32 | ||
33 | int ignore_perishable = 0; | |
34 | int non_perishable_cnt = 0; | |
35 | int skipped_deletes = 0; | |
36 | ||
37 | static inline int is_backup_file(char *fn) | |
38 | { | |
39 | int k = strlen(fn) - backup_suffix_len; | |
40 | return k > 0 && strcmp(fn+k, backup_suffix) == 0; | |
41 | } | |
42 | ||
43 | /* The directory is about to be deleted: if DEL_RECURSE is given, delete all | |
44 | * its contents, otherwise just checks for content. Returns DR_SUCCESS or | |
45 | * DR_NOT_EMPTY. Note that fname must point to a MAXPATHLEN buffer! (The | |
46 | * buffer is used for recursion, but returned unchanged.) | |
47 | */ | |
48 | static enum delret delete_dir_contents(char *fname, uint16 flags) | |
49 | { | |
50 | struct file_list *dirlist; | |
51 | enum delret ret; | |
52 | unsigned remainder; | |
53 | void *save_filters; | |
54 | int j, dlen; | |
55 | char *p; | |
56 | ||
57 | if (DEBUG_GTE(DEL, 3)) { | |
58 | rprintf(FINFO, "delete_dir_contents(%s) flags=%d\n", | |
59 | fname, flags); | |
60 | } | |
61 | ||
62 | dlen = strlen(fname); | |
63 | save_filters = push_local_filters(fname, dlen); | |
64 | ||
65 | non_perishable_cnt = 0; | |
66 | dirlist = get_dirlist(fname, dlen, 0); | |
67 | ret = non_perishable_cnt ? DR_NOT_EMPTY : DR_SUCCESS; | |
68 | ||
69 | if (!dirlist->used) | |
70 | goto done; | |
71 | ||
72 | if (!(flags & DEL_RECURSE)) { | |
73 | ret = DR_NOT_EMPTY; | |
74 | goto done; | |
75 | } | |
76 | ||
77 | p = fname + dlen; | |
78 | if (dlen != 1 || *fname != '/') | |
79 | *p++ = '/'; | |
80 | remainder = MAXPATHLEN - (p - fname); | |
81 | ||
82 | /* We do our own recursion, so make delete_item() non-recursive. */ | |
83 | flags = (flags & ~(DEL_RECURSE|DEL_MAKE_ROOM|DEL_NO_UID_WRITE)) | |
84 | | DEL_DIR_IS_EMPTY; | |
85 | ||
86 | for (j = dirlist->used; j--; ) { | |
87 | struct file_struct *fp = dirlist->files[j]; | |
88 | ||
89 | if (fp->flags & FLAG_MOUNT_DIR && S_ISDIR(fp->mode)) { | |
90 | if (DEBUG_GTE(DEL, 1)) { | |
91 | rprintf(FINFO, | |
92 | "mount point, %s, pins parent directory\n", | |
93 | f_name(fp, NULL)); | |
94 | } | |
95 | ret = DR_NOT_EMPTY; | |
96 | continue; | |
97 | } | |
98 | ||
99 | strlcpy(p, fp->basename, remainder); | |
57edc480 | 100 | if (!(fp->mode & S_IWUSR) && !am_root && fp->flags & FLAG_OWNED_BY_US) |
974e1819 WD |
101 | do_chmod(fname, fp->mode | S_IWUSR); |
102 | /* Save stack by recursing to ourself directly. */ | |
103 | if (S_ISDIR(fp->mode)) { | |
104 | if (delete_dir_contents(fname, flags | DEL_RECURSE) != DR_SUCCESS) | |
105 | ret = DR_NOT_EMPTY; | |
106 | } | |
107 | if (delete_item(fname, fp->mode, flags) != DR_SUCCESS) | |
108 | ret = DR_NOT_EMPTY; | |
109 | } | |
110 | ||
111 | fname[dlen] = '\0'; | |
112 | ||
113 | done: | |
114 | flist_free(dirlist); | |
115 | pop_local_filters(save_filters); | |
116 | ||
117 | if (ret == DR_NOT_EMPTY) { | |
118 | rprintf(FINFO, "cannot delete non-empty directory: %s\n", | |
119 | fname); | |
120 | } | |
121 | return ret; | |
122 | } | |
123 | ||
124 | /* Delete a file or directory. If DEL_RECURSE is set in the flags, this will | |
125 | * delete recursively. | |
126 | * | |
127 | * Note that fbuf must point to a MAXPATHLEN buffer if the mode indicates it's | |
128 | * a directory! (The buffer is used for recursion, but returned unchanged.) | |
129 | */ | |
130 | enum delret delete_item(char *fbuf, uint16 mode, uint16 flags) | |
131 | { | |
132 | enum delret ret; | |
133 | char *what; | |
134 | int ok; | |
135 | ||
136 | if (DEBUG_GTE(DEL, 2)) { | |
137 | rprintf(FINFO, "delete_item(%s) mode=%o flags=%d\n", | |
138 | fbuf, (int)mode, (int)flags); | |
139 | } | |
140 | ||
141 | if (flags & DEL_NO_UID_WRITE) | |
142 | do_chmod(fbuf, mode | S_IWUSR); | |
143 | ||
144 | if (S_ISDIR(mode) && !(flags & DEL_DIR_IS_EMPTY)) { | |
974e1819 WD |
145 | /* This only happens on the first call to delete_item() since |
146 | * delete_dir_contents() always calls us w/DEL_DIR_IS_EMPTY. */ | |
974e1819 WD |
147 | ignore_perishable = 1; |
148 | /* If DEL_RECURSE is not set, this just reports emptiness. */ | |
149 | ret = delete_dir_contents(fbuf, flags); | |
150 | ignore_perishable = 0; | |
974e1819 WD |
151 | if (ret == DR_NOT_EMPTY || ret == DR_AT_LIMIT) |
152 | goto check_ret; | |
153 | /* OK: try to delete the directory. */ | |
154 | } | |
155 | ||
156 | if (!(flags & DEL_MAKE_ROOM) && max_delete >= 0 && stats.deleted_files >= max_delete) { | |
157 | skipped_deletes++; | |
158 | return DR_AT_LIMIT; | |
159 | } | |
160 | ||
161 | if (S_ISDIR(mode)) { | |
162 | what = "rmdir"; | |
163 | ok = do_rmdir(fbuf) == 0; | |
974e1819 | 164 | } else { |
7e6c8ad6 | 165 | if (make_backups > 0 && !(flags & DEL_FOR_BACKUP) && (backup_dir || !is_backup_file(fbuf))) { |
21cddef2 WD |
166 | what = "make_backup"; |
167 | ok = make_backup(fbuf, True); | |
168 | if (ok == 2) { | |
169 | what = "unlink"; | |
170 | ok = robust_unlink(fbuf) == 0; | |
171 | } | |
172 | } else { | |
173 | what = "unlink"; | |
174 | ok = robust_unlink(fbuf) == 0; | |
175 | } | |
974e1819 WD |
176 | } |
177 | ||
178 | if (ok) { | |
179 | if (!(flags & DEL_MAKE_ROOM)) { | |
180 | log_delete(fbuf, mode); | |
181 | stats.deleted_files++; | |
182 | if (S_ISREG(mode)) { | |
183 | /* Nothing more to count */ | |
184 | } else if (S_ISDIR(mode)) | |
185 | stats.deleted_dirs++; | |
186 | #ifdef SUPPORT_LINKS | |
187 | else if (S_ISLNK(mode)) | |
188 | stats.deleted_symlinks++; | |
189 | #endif | |
190 | else if (IS_DEVICE(mode)) | |
191 | stats.deleted_symlinks++; | |
192 | else | |
193 | stats.deleted_specials++; | |
194 | } | |
195 | ret = DR_SUCCESS; | |
196 | } else { | |
197 | if (S_ISDIR(mode) && errno == ENOTEMPTY) { | |
198 | rprintf(FINFO, "cannot delete non-empty directory: %s\n", | |
199 | fbuf); | |
200 | ret = DR_NOT_EMPTY; | |
201 | } else if (errno != ENOENT) { | |
202 | rsyserr(FERROR, errno, "delete_file: %s(%s) failed", | |
203 | what, fbuf); | |
204 | ret = DR_FAILURE; | |
205 | } else | |
206 | ret = DR_SUCCESS; | |
207 | } | |
208 | ||
209 | check_ret: | |
210 | if (ret != DR_SUCCESS && flags & DEL_MAKE_ROOM) { | |
211 | const char *desc; | |
212 | switch (flags & DEL_MAKE_ROOM) { | |
213 | case DEL_FOR_FILE: desc = "regular file"; break; | |
214 | case DEL_FOR_DIR: desc = "directory"; break; | |
215 | case DEL_FOR_SYMLINK: desc = "symlink"; break; | |
216 | case DEL_FOR_DEVICE: desc = "device file"; break; | |
217 | case DEL_FOR_SPECIAL: desc = "special file"; break; | |
218 | default: exit_cleanup(RERR_UNSUPPORTED); /* IMPOSSIBLE */ | |
219 | } | |
21cddef2 WD |
220 | rprintf(FERROR_XFER, "could not make way for %s %s: %s\n", |
221 | flags & DEL_FOR_BACKUP ? "backup" : "new", | |
974e1819 WD |
222 | desc, fbuf); |
223 | } | |
224 | return ret; | |
225 | } | |
21cddef2 WD |
226 | |
227 | uint16 get_del_for_flag(uint16 mode) | |
228 | { | |
229 | if (S_ISREG(mode)) | |
230 | return DEL_FOR_FILE; | |
231 | if (S_ISDIR(mode)) | |
232 | return DEL_FOR_DIR; | |
233 | if (S_ISLNK(mode)) | |
234 | return DEL_FOR_SYMLINK; | |
235 | if (IS_DEVICE(mode)) | |
236 | return DEL_FOR_DEVICE; | |
237 | if (IS_SPECIAL(mode)) | |
238 | return DEL_FOR_SPECIAL; | |
239 | exit_cleanup(RERR_UNSUPPORTED); /* IMPOSSIBLE */ | |
240 | } |