File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / rsync / delete.c
Revision 1.1.1.3 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Wed Mar 17 00:32:36 2021 UTC (3 years, 3 months ago) by misho
Branches: rsync, MAIN
CVS tags: v3_2_3, HEAD
rsync 3.2.3

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

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>