+ check_ret:
+ if (ret != DR_SUCCESS && flags & DEL_MAKE_ROOM) {
+ const char *desc;
+ switch (flags & DEL_MAKE_ROOM) {
+ case DEL_FOR_FILE: desc = "regular file"; break;
+ case DEL_FOR_DIR: desc = "directory"; break;
+ case DEL_FOR_SYMLINK: desc = "symlink"; break;
+ case DEL_FOR_DEVICE: desc = "device file"; break;
+ case DEL_FOR_SPECIAL: desc = "special file"; break;
+ default: exit_cleanup(RERR_UNSUPPORTED); /* IMPOSSIBLE */
+ }
+ rprintf(FERROR_XFER, "could not make way for new %s: %s\n",
+ desc, fbuf);
+ }
+ return ret;
+}
+
+/* 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
+ * DR_NOT_EMPTY. Note that fname must point to a MAXPATHLEN buffer! (The
+ * buffer is used for recursion, but returned unchanged.)
+ */
+static enum delret delete_dir_contents(char *fname, uint16 flags)
+{
+ struct file_list *dirlist;
+ enum delret ret;
+ unsigned remainder;
+ void *save_filters;
+ int j, dlen;
+ char *p;
+
+ if (verbose > 3) {
+ rprintf(FINFO, "delete_dir_contents(%s) flags=%d\n",
+ fname, flags);
+ }
+
+ dlen = strlen(fname);
+ save_filters = push_local_filters(fname, dlen);
+
+ non_perishable_cnt = 0;
+ dirlist = get_dirlist(fname, dlen, 0);
+ ret = non_perishable_cnt ? DR_NOT_EMPTY : DR_SUCCESS;
+
+ if (!dirlist->used)
+ goto done;
+
+ if (!(flags & DEL_RECURSE)) {
+ ret = DR_NOT_EMPTY;
+ goto done;
+ }
+
+ p = fname + dlen;
+ if (dlen != 1 || *fname != '/')
+ *p++ = '/';
+ remainder = MAXPATHLEN - (p - fname);
+
+ /* We do our own recursion, so make delete_item() non-recursive. */
+ flags = (flags & ~(DEL_RECURSE|DEL_MAKE_ROOM|DEL_NO_UID_WRITE))
+ | DEL_DIR_IS_EMPTY;
+
+ for (j = dirlist->used; j--; ) {
+ struct file_struct *fp = dirlist->files[j];
+
+ if (fp->flags & FLAG_MOUNT_DIR && S_ISDIR(fp->mode)) {
+ if (verbose > 1) {
+ rprintf(FINFO,
+ "mount point, %s, pins parent directory\n",
+ f_name(fp, NULL));
+ }
+ ret = DR_NOT_EMPTY;
+ continue;
+ }
+
+ strlcpy(p, fp->basename, remainder);
+ if (!(fp->mode & S_IWUSR) && !am_root && (uid_t)F_OWNER(fp) == our_uid)
+ do_chmod(fname, fp->mode | S_IWUSR);
+ /* Save stack by recursing to ourself directly. */
+ if (S_ISDIR(fp->mode)) {
+ if (delete_dir_contents(fname, flags | DEL_RECURSE) != DR_SUCCESS)
+ ret = DR_NOT_EMPTY;
+ }
+ if (delete_item(fname, fp->mode, flags) != DR_SUCCESS)
+ ret = DR_NOT_EMPTY;
+ }
+
+ fname[dlen] = '\0';
+
+ done:
+ flist_free(dirlist);
+ pop_local_filters(save_filters);
+
+ if (ret == DR_NOT_EMPTY) {
+ rprintf(FINFO, "cannot delete non-empty directory: %s\n",
+ fname);
+ }
+ return ret;
+}
+
+static int start_delete_delay_temp(void)
+{
+ char fnametmp[MAXPATHLEN];
+ int save_dry_run = dry_run;
+
+ dry_run = 0;
+ if (!get_tmpname(fnametmp, "deldelay")
+ || (deldelay_fd = do_mkstemp(fnametmp, 0600)) < 0) {
+ rprintf(FINFO, "NOTE: Unable to create delete-delay temp file%s.\n",
+ inc_recurse ? "" : " -- switching to --delete-after");
+ delete_during = 0;
+ delete_after = !inc_recurse;
+ dry_run = save_dry_run;
+ return 0;
+ }
+ unlink(fnametmp);
+ dry_run = save_dry_run;
+ return 1;
+}
+
+static int flush_delete_delay(void)
+{
+ if (deldelay_fd < 0 && !start_delete_delay_temp())
+ return 0;
+ if (write(deldelay_fd, deldelay_buf, deldelay_cnt) != deldelay_cnt) {
+ rsyserr(FERROR, errno, "flush of delete-delay buffer");
+ delete_during = 0;
+ delete_after = !inc_recurse;
+ close(deldelay_fd);
+ return 0;