|
|
| version 1.1, 2013/10/14 07:51:14 | version 1.1.1.3, 2021/03/17 00:32:36 |
|---|---|
| Line 4 | Line 4 |
| * Copyright (C) 1996-2000 Andrew Tridgell | * Copyright (C) 1996-2000 Andrew Tridgell |
| * Copyright (C) 1996 Paul Mackerras | * Copyright (C) 1996 Paul Mackerras |
| * Copyright (C) 2002 Martin Pool <mbp@samba.org> | * Copyright (C) 2002 Martin Pool <mbp@samba.org> |
| * Copyright (C) 2003-2013 Wayne Davison | * Copyright (C) 2003-2020 Wayne Davison |
| * | * |
| * This program is free software; you can redistribute it and/or modify | * This program is free software; you can redistribute it and/or modify |
| * it under the terms of the GNU General Public License as published by | * it under the terms of the GNU General Public License as published by |
| Line 25 | Line 25 |
| extern int am_root; | extern int am_root; |
| extern int make_backups; | extern int make_backups; |
| extern int max_delete; | extern int max_delete; |
| extern int detect_renamed; | |
| extern char *backup_dir; | extern char *backup_dir; |
| extern char *backup_suffix; | extern char *backup_suffix; |
| extern int backup_suffix_len; | extern int backup_suffix_len; |
| extern char *backup_dir_dels; | |
| extern char *backup_suffix_dels; | |
| extern int backup_suffix_dels_len; | |
| extern struct stats stats; | extern struct stats stats; |
| int ignore_perishable = 0; | int ignore_perishable = 0; |
| int non_perishable_cnt = 0; | int non_perishable_cnt = 0; |
| int skipped_deletes = 0; | int skipped_deletes = 0; |
| /* Function now compares both backup_suffix and backup_suffix_dels. */ | |
| static inline int is_backup_file(char *fn) | static inline int is_backup_file(char *fn) |
| { | { |
| int k = strlen(fn) - backup_suffix_len; | int k = strlen(fn) - backup_suffix_len; |
| return k > 0 && strcmp(fn+k, backup_suffix) == 0; | if (k > 0 && strcmp(fn+k, backup_suffix) == 0) |
| return 1; | |
| k += backup_suffix_len - backup_suffix_dels_len; | |
| return k > 0 && strcmp(fn+k, backup_suffix_dels) == 0; | |
| } | } |
| /* The directory is about to be deleted: if DEL_RECURSE is given, delete all | /* The directory is about to be deleted: if DEL_RECURSE is given, delete all |
| * its contents, otherwise just checks for content. Returns DR_SUCCESS or | * its contents, otherwise just checks for content. Returns DR_SUCCESS or |
| * DR_NOT_EMPTY. Note that fname must point to a MAXPATHLEN buffer! (The | * DR_NOT_EMPTY. Note that fname must point to a MAXPATHLEN buffer! (The |
| * buffer is used for recursion, but returned unchanged.) | * buffer is used for recursion, but returned unchanged.) |
| * | |
| * Note: --detect-rename may use this routine with DEL_NO_DELETIONS set! | |
| */ | */ |
| static enum delret delete_dir_contents(char *fname, uint16 flags) | static enum delret delete_dir_contents(char *fname, uint16 flags) |
| { | { |
| Line 63 static enum delret delete_dir_contents(char *fname, ui | Line 73 static enum delret delete_dir_contents(char *fname, ui |
| save_filters = push_local_filters(fname, dlen); | save_filters = push_local_filters(fname, dlen); |
| non_perishable_cnt = 0; | non_perishable_cnt = 0; |
| file_extra_cnt += SUM_EXTRA_CNT; | |
| dirlist = get_dirlist(fname, dlen, 0); | dirlist = get_dirlist(fname, dlen, 0); |
| file_extra_cnt -= SUM_EXTRA_CNT; | |
| ret = non_perishable_cnt ? DR_NOT_EMPTY : DR_SUCCESS; | ret = non_perishable_cnt ? DR_NOT_EMPTY : DR_SUCCESS; |
| if (!dirlist->used) | if (!dirlist->used) |
| Line 89 static enum delret delete_dir_contents(char *fname, ui | Line 101 static enum delret delete_dir_contents(char *fname, ui |
| if (fp->flags & FLAG_MOUNT_DIR && S_ISDIR(fp->mode)) { | if (fp->flags & FLAG_MOUNT_DIR && S_ISDIR(fp->mode)) { |
| if (DEBUG_GTE(DEL, 1)) { | if (DEBUG_GTE(DEL, 1)) { |
| rprintf(FINFO, | rprintf(FINFO, |
| "mount point, %s, pins parent directory\n", | "mount point, %s, pins parent directory\n", |
| f_name(fp, NULL)); | f_name(fp, NULL)); |
| } | } |
| ret = DR_NOT_EMPTY; | ret = DR_NOT_EMPTY; |
| continue; | continue; |
| } | } |
| strlcpy(p, fp->basename, remainder); | strlcpy(p, fp->basename, remainder); |
| #ifdef SUPPORT_FORCE_CHANGE | |
| if (force_change) | |
| make_mutable(fname, fp->mode, F_FFLAGS(fp), force_change); | |
| #endif | |
| if (!(fp->mode & S_IWUSR) && !am_root && fp->flags & FLAG_OWNED_BY_US) | if (!(fp->mode & S_IWUSR) && !am_root && fp->flags & FLAG_OWNED_BY_US) |
| do_chmod(fname, fp->mode | S_IWUSR); | do_chmod(fname, fp->mode | S_IWUSR, NO_FFLAGS); |
| /* Save stack by recursing to ourself directly. */ | /* Save stack by recursing to ourself directly. */ |
| if (S_ISDIR(fp->mode)) { | if (S_ISDIR(fp->mode)) { |
| if (delete_dir_contents(fname, flags | DEL_RECURSE) != DR_SUCCESS) | if (delete_dir_contents(fname, flags | DEL_RECURSE) != DR_SUCCESS) |
| ret = DR_NOT_EMPTY; | ret = DR_NOT_EMPTY; |
| } | } else if (detect_renamed && S_ISREG(fp->mode)) |
| look_for_rename(fp, fname); | |
| if (delete_item(fname, fp->mode, flags) != DR_SUCCESS) | if (delete_item(fname, fp->mode, flags) != DR_SUCCESS) |
| ret = DR_NOT_EMPTY; | ret = DR_NOT_EMPTY; |
| } | } |
| Line 126 static enum delret delete_dir_contents(char *fname, ui | Line 143 static enum delret delete_dir_contents(char *fname, ui |
| * | * |
| * Note that fbuf must point to a MAXPATHLEN buffer if the mode indicates it's | * Note that fbuf must point to a MAXPATHLEN buffer if the mode indicates it's |
| * a directory! (The buffer is used for recursion, but returned unchanged.) | * a directory! (The buffer is used for recursion, but returned unchanged.) |
| * | |
| * Also note: --detect-rename may use this routine with DEL_NO_DELETIONS set! | |
| */ | */ |
| enum delret delete_item(char *fbuf, uint16 mode, uint16 flags) | enum delret delete_item(char *fbuf, uint16 mode, uint16 flags) |
| { | { |
| Line 139 enum delret delete_item(char *fbuf, uint16 mode, uint1 | Line 158 enum delret delete_item(char *fbuf, uint16 mode, uint1 |
| } | } |
| if (flags & DEL_NO_UID_WRITE) | if (flags & DEL_NO_UID_WRITE) |
| do_chmod(fbuf, mode | S_IWUSR); | do_chmod(fbuf, mode | S_IWUSR, NO_FFLAGS); |
| if (S_ISDIR(mode) && !(flags & DEL_DIR_IS_EMPTY)) { | if (S_ISDIR(mode) && !(flags & DEL_DIR_IS_EMPTY)) { |
| /* This only happens on the first call to delete_item() since | /* This only happens on the first call to delete_item() since |
| * delete_dir_contents() always calls us w/DEL_DIR_IS_EMPTY. */ | * delete_dir_contents() always calls us w/DEL_DIR_IS_EMPTY. */ |
| #ifdef SUPPORT_FORCE_CHANGE | |
| if (force_change) { | |
| STRUCT_STAT st; | |
| if (x_lstat(fbuf, &st, NULL) == 0) | |
| make_mutable(fbuf, st.st_mode, st.st_flags, force_change); | |
| } | |
| #endif | |
| ignore_perishable = 1; | ignore_perishable = 1; |
| /* If DEL_RECURSE is not set, this just reports emptiness. */ | /* If DEL_RECURSE is not set, this just reports emptiness. */ |
| ret = delete_dir_contents(fbuf, flags); | ret = delete_dir_contents(fbuf, flags); |
| Line 153 enum delret delete_item(char *fbuf, uint16 mode, uint1 | Line 179 enum delret delete_item(char *fbuf, uint16 mode, uint1 |
| /* OK: try to delete the directory. */ | /* OK: try to delete the directory. */ |
| } | } |
| if (flags & DEL_NO_DELETIONS) | |
| return DR_SUCCESS; | |
| if (!(flags & DEL_MAKE_ROOM) && max_delete >= 0 && stats.deleted_files >= max_delete) { | if (!(flags & DEL_MAKE_ROOM) && max_delete >= 0 && stats.deleted_files >= max_delete) { |
| skipped_deletes++; | skipped_deletes++; |
| return DR_AT_LIMIT; | return DR_AT_LIMIT; |
| Line 162 enum delret delete_item(char *fbuf, uint16 mode, uint1 | Line 191 enum delret delete_item(char *fbuf, uint16 mode, uint1 |
| what = "rmdir"; | what = "rmdir"; |
| ok = do_rmdir(fbuf) == 0; | ok = do_rmdir(fbuf) == 0; |
| } else { | } else { |
| if (make_backups > 0 && !(flags & DEL_FOR_BACKUP) && (backup_dir || !is_backup_file(fbuf))) { | if (make_backups > 0 && !(flags & DEL_FOR_BACKUP) && (backup_dir_dels || !is_backup_file(fbuf))) { |
| what = "make_backup"; | what = "make_backup"; |
| ok = make_backup(fbuf, True); | ok = safe_delete(fbuf); |
| if (ok == 2) { | if (ok == 2) { |
| what = "unlink"; | what = "unlink"; |
| ok = robust_unlink(fbuf) == 0; | ok = robust_unlink(fbuf) == 0; |
| Line 199 enum delret delete_item(char *fbuf, uint16 mode, uint1 | Line 228 enum delret delete_item(char *fbuf, uint16 mode, uint1 |
| fbuf); | fbuf); |
| ret = DR_NOT_EMPTY; | ret = DR_NOT_EMPTY; |
| } else if (errno != ENOENT) { | } else if (errno != ENOENT) { |
| rsyserr(FERROR, errno, "delete_file: %s(%s) failed", | rsyserr(FERROR_XFER, errno, "delete_file: %s(%s) failed", |
| what, fbuf); | what, fbuf); |
| ret = DR_FAILURE; | ret = DR_FAILURE; |
| } else | } else |