| 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; |
| 172 | } else { |
| 173 | if (make_backups > 0 && !(flags & DEL_FOR_BACKUP) && (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 | } |
| 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 | } |
| 228 | rprintf(FERROR_XFER, "could not make way for %s %s: %s\n", |
| 229 | flags & DEL_FOR_BACKUP ? "backup" : "new", |
| 230 | desc, fbuf); |
| 231 | } |
| 232 | return ret; |
| 233 | } |
| 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 | } |