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; | |
31 | extern uid_t our_uid; | |
32 | extern struct stats stats; | |
33 | ||
34 | int ignore_perishable = 0; | |
35 | int non_perishable_cnt = 0; | |
36 | int skipped_deletes = 0; | |
37 | ||
38 | static inline int is_backup_file(char *fn) | |
39 | { | |
40 | int k = strlen(fn) - backup_suffix_len; | |
41 | return k > 0 && strcmp(fn+k, backup_suffix) == 0; | |
42 | } | |
43 | ||
44 | /* The directory is about to be deleted: if DEL_RECURSE is given, delete all | |
45 | * its contents, otherwise just checks for content. Returns DR_SUCCESS or | |
46 | * DR_NOT_EMPTY. Note that fname must point to a MAXPATHLEN buffer! (The | |
47 | * buffer is used for recursion, but returned unchanged.) | |
48 | */ | |
49 | static enum delret delete_dir_contents(char *fname, uint16 flags) | |
50 | { | |
51 | struct file_list *dirlist; | |
52 | enum delret ret; | |
53 | unsigned remainder; | |
54 | void *save_filters; | |
55 | int j, dlen; | |
56 | char *p; | |
57 | ||
58 | if (DEBUG_GTE(DEL, 3)) { | |
59 | rprintf(FINFO, "delete_dir_contents(%s) flags=%d\n", | |
60 | fname, flags); | |
61 | } | |
62 | ||
63 | dlen = strlen(fname); | |
64 | save_filters = push_local_filters(fname, dlen); | |
65 | ||
66 | non_perishable_cnt = 0; | |
67 | dirlist = get_dirlist(fname, dlen, 0); | |
68 | ret = non_perishable_cnt ? DR_NOT_EMPTY : DR_SUCCESS; | |
69 | ||
70 | if (!dirlist->used) | |
71 | goto done; | |
72 | ||
73 | if (!(flags & DEL_RECURSE)) { | |
74 | ret = DR_NOT_EMPTY; | |
75 | goto done; | |
76 | } | |
77 | ||
78 | p = fname + dlen; | |
79 | if (dlen != 1 || *fname != '/') | |
80 | *p++ = '/'; | |
81 | remainder = MAXPATHLEN - (p - fname); | |
82 | ||
83 | /* We do our own recursion, so make delete_item() non-recursive. */ | |
84 | flags = (flags & ~(DEL_RECURSE|DEL_MAKE_ROOM|DEL_NO_UID_WRITE)) | |
85 | | DEL_DIR_IS_EMPTY; | |
86 | ||
87 | for (j = dirlist->used; j--; ) { | |
88 | struct file_struct *fp = dirlist->files[j]; | |
89 | ||
90 | if (fp->flags & FLAG_MOUNT_DIR && S_ISDIR(fp->mode)) { | |
91 | if (DEBUG_GTE(DEL, 1)) { | |
92 | rprintf(FINFO, | |
93 | "mount point, %s, pins parent directory\n", | |
94 | f_name(fp, NULL)); | |
95 | } | |
96 | ret = DR_NOT_EMPTY; | |
97 | continue; | |
98 | } | |
99 | ||
100 | strlcpy(p, fp->basename, remainder); | |
101 | if (!(fp->mode & S_IWUSR) && !am_root && (uid_t)F_OWNER(fp) == our_uid) | |
102 | do_chmod(fname, fp->mode | S_IWUSR); | |
103 | /* Save stack by recursing to ourself directly. */ | |
104 | if (S_ISDIR(fp->mode)) { | |
105 | if (delete_dir_contents(fname, flags | DEL_RECURSE) != DR_SUCCESS) | |
106 | ret = DR_NOT_EMPTY; | |
107 | } | |
108 | if (delete_item(fname, fp->mode, flags) != DR_SUCCESS) | |
109 | ret = DR_NOT_EMPTY; | |
110 | } | |
111 | ||
112 | fname[dlen] = '\0'; | |
113 | ||
114 | done: | |
115 | flist_free(dirlist); | |
116 | pop_local_filters(save_filters); | |
117 | ||
118 | if (ret == DR_NOT_EMPTY) { | |
119 | rprintf(FINFO, "cannot delete non-empty directory: %s\n", | |
120 | fname); | |
121 | } | |
122 | return ret; | |
123 | } | |
124 | ||
125 | /* Delete a file or directory. If DEL_RECURSE is set in the flags, this will | |
126 | * delete recursively. | |
127 | * | |
128 | * Note that fbuf must point to a MAXPATHLEN buffer if the mode indicates it's | |
129 | * a directory! (The buffer is used for recursion, but returned unchanged.) | |
130 | */ | |
131 | enum delret delete_item(char *fbuf, uint16 mode, uint16 flags) | |
132 | { | |
133 | enum delret ret; | |
134 | char *what; | |
135 | int ok; | |
136 | ||
137 | if (DEBUG_GTE(DEL, 2)) { | |
138 | rprintf(FINFO, "delete_item(%s) mode=%o flags=%d\n", | |
139 | fbuf, (int)mode, (int)flags); | |
140 | } | |
141 | ||
142 | if (flags & DEL_NO_UID_WRITE) | |
143 | do_chmod(fbuf, mode | S_IWUSR); | |
144 | ||
145 | if (S_ISDIR(mode) && !(flags & DEL_DIR_IS_EMPTY)) { | |
146 | int save_uid_ndx = uid_ndx; | |
147 | /* This only happens on the first call to delete_item() since | |
148 | * delete_dir_contents() always calls us w/DEL_DIR_IS_EMPTY. */ | |
149 | if (!uid_ndx) | |
150 | uid_ndx = ++file_extra_cnt; | |
151 | ignore_perishable = 1; | |
152 | /* If DEL_RECURSE is not set, this just reports emptiness. */ | |
153 | ret = delete_dir_contents(fbuf, flags); | |
154 | ignore_perishable = 0; | |
155 | if (!save_uid_ndx) { | |
156 | --file_extra_cnt; | |
157 | uid_ndx = 0; | |
158 | } | |
159 | if (ret == DR_NOT_EMPTY || ret == DR_AT_LIMIT) | |
160 | goto check_ret; | |
161 | /* OK: try to delete the directory. */ | |
162 | } | |
163 | ||
164 | if (!(flags & DEL_MAKE_ROOM) && max_delete >= 0 && stats.deleted_files >= max_delete) { | |
165 | skipped_deletes++; | |
166 | return DR_AT_LIMIT; | |
167 | } | |
168 | ||
169 | if (S_ISDIR(mode)) { | |
170 | what = "rmdir"; | |
171 | ok = do_rmdir(fbuf) == 0; | |
974e1819 | 172 | } else { |
21cddef2 WD |
173 | if (make_backups > 0 && (backup_dir || !is_backup_file(fbuf))) { |
174 | what = "make_backup"; | |
175 | ok = make_backup(fbuf, True); | |
176 | if (ok == 2) { | |
177 | what = "unlink"; | |
178 | ok = robust_unlink(fbuf) == 0; | |
179 | } | |
180 | } else { | |
181 | what = "unlink"; | |
182 | ok = robust_unlink(fbuf) == 0; | |
183 | } | |
974e1819 WD |
184 | } |
185 | ||
186 | if (ok) { | |
187 | if (!(flags & DEL_MAKE_ROOM)) { | |
188 | log_delete(fbuf, mode); | |
189 | stats.deleted_files++; | |
190 | if (S_ISREG(mode)) { | |
191 | /* Nothing more to count */ | |
192 | } else if (S_ISDIR(mode)) | |
193 | stats.deleted_dirs++; | |
194 | #ifdef SUPPORT_LINKS | |
195 | else if (S_ISLNK(mode)) | |
196 | stats.deleted_symlinks++; | |
197 | #endif | |
198 | else if (IS_DEVICE(mode)) | |
199 | stats.deleted_symlinks++; | |
200 | else | |
201 | stats.deleted_specials++; | |
202 | } | |
203 | ret = DR_SUCCESS; | |
204 | } else { | |
205 | if (S_ISDIR(mode) && errno == ENOTEMPTY) { | |
206 | rprintf(FINFO, "cannot delete non-empty directory: %s\n", | |
207 | fbuf); | |
208 | ret = DR_NOT_EMPTY; | |
209 | } else if (errno != ENOENT) { | |
210 | rsyserr(FERROR, errno, "delete_file: %s(%s) failed", | |
211 | what, fbuf); | |
212 | ret = DR_FAILURE; | |
213 | } else | |
214 | ret = DR_SUCCESS; | |
215 | } | |
216 | ||
217 | check_ret: | |
218 | if (ret != DR_SUCCESS && flags & DEL_MAKE_ROOM) { | |
219 | const char *desc; | |
220 | switch (flags & DEL_MAKE_ROOM) { | |
221 | case DEL_FOR_FILE: desc = "regular file"; break; | |
222 | case DEL_FOR_DIR: desc = "directory"; break; | |
223 | case DEL_FOR_SYMLINK: desc = "symlink"; break; | |
224 | case DEL_FOR_DEVICE: desc = "device file"; break; | |
225 | case DEL_FOR_SPECIAL: desc = "special file"; break; | |
226 | default: exit_cleanup(RERR_UNSUPPORTED); /* IMPOSSIBLE */ | |
227 | } | |
21cddef2 WD |
228 | rprintf(FERROR_XFER, "could not make way for %s %s: %s\n", |
229 | flags & DEL_FOR_BACKUP ? "backup" : "new", | |
974e1819 WD |
230 | desc, fbuf); |
231 | } | |
232 | return ret; | |
233 | } | |
21cddef2 WD |
234 | |
235 | uint16 get_del_for_flag(uint16 mode) | |
236 | { | |
237 | if (S_ISREG(mode)) | |
238 | return DEL_FOR_FILE; | |
239 | if (S_ISDIR(mode)) | |
240 | return DEL_FOR_DIR; | |
241 | if (S_ISLNK(mode)) | |
242 | return DEL_FOR_SYMLINK; | |
243 | if (IS_DEVICE(mode)) | |
244 | return DEL_FOR_DEVICE; | |
245 | if (IS_SPECIAL(mode)) | |
246 | return DEL_FOR_SPECIAL; | |
247 | exit_cleanup(RERR_UNSUPPORTED); /* IMPOSSIBLE */ | |
248 | } |