extern int delete_after;
extern int module_id;
extern int ignore_errors;
+extern int flist_extra_ndx;
extern int remove_source_files;
extern int delay_updates;
extern int update_only;
extern int max_delete;
extern int force_delete;
extern int one_file_system;
+extern int file_struct_len;
extern struct stats stats;
extern dev_t filesystem_dev;
extern char *backup_dir;
int non_perishable_cnt = 0;
static int deletion_count = 0; /* used to implement --max-delete */
+static FILE *delete_delay_fp = NULL;
/* For calling delete_item() and delete_dir_contents(). */
#define DEL_RECURSE (1<<1) /* recurse */
/* Delete a file or directory. If DEL_RECURSE is set in the flags, this will
* delete recursively.
*
- * Note that fname 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.)
*/
-static enum delret delete_item(char *fname, int mode, char *replace, int flags)
+static enum delret delete_item(char *fbuf, int mode, char *replace, int flags)
{
enum delret ret;
char *what;
if (verbose > 2) {
rprintf(FINFO, "delete_item(%s) mode=%o flags=%d\n",
- fname, mode, flags);
+ fbuf, mode, flags);
}
if (S_ISDIR(mode) && !(flags & DEL_DIR_IS_EMPTY)) {
ignore_perishable = 1;
/* If DEL_RECURSE is not set, this just reports emptiness. */
- ret = delete_dir_contents(fname, flags);
+ ret = delete_dir_contents(fbuf, flags);
ignore_perishable = 0;
if (ret == DR_NOT_EMPTY || ret == DR_AT_LIMIT)
goto check_ret;
if (S_ISDIR(mode)) {
what = "rmdir";
- ok = do_rmdir(fname) == 0;
- } else if (make_backups && (backup_dir || !is_backup_file(fname))) {
+ ok = do_rmdir(fbuf) == 0;
+ } else if (make_backups && (backup_dir || !is_backup_file(fbuf))) {
what = "make_backup";
- ok = make_backup(fname);
+ ok = make_backup(fbuf);
} else {
what = "unlink";
- ok = robust_unlink(fname) == 0;
+ ok = robust_unlink(fbuf) == 0;
}
if (ok) {
if (!replace)
- log_delete(fname, mode);
+ log_delete(fbuf, mode);
ret = DR_SUCCESS;
} else {
if (S_ISDIR(mode) && errno == ENOTEMPTY) {
rprintf(FINFO, "cannot delete non-empty directory: %s\n",
- fname);
+ fbuf);
ret = DR_NOT_EMPTY;
} else if (errno != ENOENT) {
rsyserr(FERROR, errno, "delete_file: %s(%s) failed",
- what, full_fname(fname));
+ what, fbuf);
ret = DR_FAILURE;
} else {
deletion_count--;
check_ret:
if (replace && ret != DR_SUCCESS) {
rprintf(FERROR, "could not make way for new %s: %s\n",
- replace, fname);
+ replace, fbuf);
}
return ret;
}
for (j = dirlist->count; j--; ) {
struct file_struct *fp = dirlist->files[j];
- if (fp->flags & FLAG_MOUNT_POINT) {
+ if (fp->flags & FLAG_MOUNT_DIR) {
if (verbose > 1) {
rprintf(FINFO,
"mount point, %s, pins parent directory\n",
return ret;
}
+static void start_delete_temp(void)
+{
+ char fnametmp[MAXPATHLEN];
+ int fd, save_dry_run = dry_run;
+
+ dry_run = 0;
+ if (!get_tmpname(fnametmp, "deldelay")
+ || (fd = do_mkstemp(fnametmp, 0600)) < 0
+ || !(delete_delay_fp = fdopen(fd, "w+"))) {
+ rprintf(FERROR, "Unable to create delete-delay temp file.\n");
+ exit_cleanup(RERR_FILEIO);
+ }
+ dry_run = save_dry_run;
+ unlink(fnametmp);
+}
+
+static int read_delay_line(FILE *fp, char *buf, int bsize)
+{
+ int ch, mode = 0;
+
+ if ((ch = fgetc(fp)) == EOF)
+ return -1;
+
+ while (1) {
+ if (ch == ' ')
+ break;
+ if (ch > '7' || ch < '0') {
+ rprintf(FERROR, "invalid data in delete-delay file.\n");
+ exit_cleanup(RERR_FILEIO);
+ }
+ mode = mode*8 + ch - '0';
+ if ((ch = fgetc(fp)) == EOF) {
+ unexpected_eof:
+ rprintf(FERROR, "unexpected EOF in delete-delay file.\n");
+ exit_cleanup(RERR_FILEIO);
+ }
+ }
+
+ while (1) {
+ if ((ch = fgetc(fp)) == EOF)
+ goto unexpected_eof;
+ if (bsize-- <= 0) {
+ rprintf(FERROR, "filename too long in delete-delay file.\n");
+ exit_cleanup(RERR_FILEIO);
+ }
+ *buf++ = (char)ch;
+ if (ch == '\0')
+ break;
+ }
+
+ return mode;
+}
+
+static void delayed_deletions(char *delbuf)
+{
+ int mode;
+
+ fseek(delete_delay_fp, 0, 0);
+ while ((mode = read_delay_line(delete_delay_fp, delbuf, MAXPATHLEN)) >= 0)
+ delete_item(delbuf, mode, NULL, DEL_RECURSE);
+ fclose(delete_delay_fp);
+}
/* This function is used to implement per-directory deletion, and is used by
* all the --delete-WHEN options. Note that the fbuf pointer must point to a
struct file_struct *fp = dirlist->files[i];
if (!fp->basename)
continue;
- if (fp->flags & FLAG_MOUNT_POINT) {
+ if (fp->flags & FLAG_MOUNT_DIR) {
if (verbose > 1)
rprintf(FINFO, "cannot delete mount point: %s\n",
f_name(fp, NULL));
}
if (flist_find(flist, fp) < 0) {
f_name(fp, delbuf);
- delete_item(delbuf, fp->mode, NULL, DEL_RECURSE);
+ if (delete_delay_fp)
+ fprintf(delete_delay_fp, "%o %s%c", (short)fp->mode, delbuf, '\0');
+ else
+ delete_item(delbuf, fp->mode, NULL, DEL_RECURSE);
}
}
for (j = 0; j < flist->count; j++) {
struct file_struct *file = flist->files[j];
- if (!(file->flags & FLAG_DEL_HERE))
+ if (!(file->flags & FLAG_XFER_DIR))
continue;
f_name(file, fbuf);
&& (st->st_mode & CHMOD_BITS) != (file->mode & CHMOD_BITS))
return 0;
- if (am_root && preserve_uid && st->st_uid != file->uid)
+ if (am_root && preserve_uid && st->st_uid != F_UID(file))
return 0;
- if (preserve_gid && file->gid != GID_NONE && st->st_gid != file->gid)
+ if (preserve_gid && F_GID(file) != GID_NONE && st->st_gid != F_GID(file))
return 0;
return 1;
iflags |= ITEM_REPORT_TIME;
if ((file->mode & CHMOD_BITS) != (st->st_mode & CHMOD_BITS))
iflags |= ITEM_REPORT_PERMS;
- if (preserve_uid && am_root && file->uid != st->st_uid)
+ if (preserve_uid && am_root && F_UID(file) != st->st_uid)
iflags |= ITEM_REPORT_OWNER;
- if (preserve_gid && file->gid != GID_NONE
- && st->st_gid != file->gid)
+ if (preserve_gid && F_GID(file) != GID_NONE
+ && st->st_gid != F_GID(file))
iflags |= ITEM_REPORT_GROUP;
} else
iflags |= ITEM_IS_NEW;
if (always_checksum && S_ISREG(st->st_mode)) {
char sum[MD4_SUM_LENGTH];
file_checksum(fn, sum, st->st_size);
- return memcmp(sum, file->u.sum, checksum_len) == 0;
+ return memcmp(sum, F_SUM(file), checksum_len) == 0;
}
if (size_only)
sum->flength = len;
sum->blength = blength;
sum->s2length = s2length;
- sum->remainder = len % blength;
- sum->count = len / blength + (sum->remainder != 0);
+ sum->remainder = (int32)(len % blength);
+ sum->count = (int32)(len / blength) + (sum->remainder != 0);
if (sum->count && verbose > 2) {
rprintf(FINFO,
int len, suf_len;
uint32 dist;
- if (!S_ISREG(fp->mode) || !fp->length
- || fp->flags & FLAG_NO_FUZZY)
+ if (!S_ISREG(fp->mode) || !fp->length || fp->flags & FLAG_SENT)
continue;
name = fp->basename;
continue;
file = the_file_list->files[ndx];
- if (!file->link_u.links)
+ if (!IS_HLINKED(file))
continue;
- hard_link_cluster(file, ndx, itemizing, code);
+ hard_link_cluster(file, ndx, itemizing, code, -1);
}
}
if (hard_link_one(file, ndx, fname, 0, stp,
cmpbuf, 1, i, code) < 0)
goto try_a_copy;
- if (preserve_hard_links && file->link_u.links) {
- if (dry_run)
- file->link_u.links->link_dest_used = j + 1;
- hard_link_cluster(file, ndx, itemizing, code);
- }
+ if (preserve_hard_links && IS_HLINKED(file))
+ hard_link_cluster(file, ndx, itemizing, code, j);
} else
#endif
if (itemizing)
rprintf(code, "%s%s\n", fname,
match_level == 3 ? " is uptodate" : "");
}
- if (preserve_hard_links && file->link_u.links)
- hard_link_cluster(file, ndx, itemizing, code);
+ if (preserve_hard_links && IS_HLINKED(file))
+ hard_link_cluster(file, ndx, itemizing, code, j);
return -2;
}
break;
case TYPE_SPECIAL:
case TYPE_DEVICE:
- if (stp->st_rdev != file->u.rdev)
+ if (stp->st_rdev != MAKEDEV(F_DMAJOR(file), F_DMINOR(file)))
continue;
break;
#ifdef SUPPORT_LINKS
if ((len = readlink(cmpbuf, lnk, MAXPATHLEN-1)) <= 0)
continue;
lnk[len] = '\0';
- if (strcmp(lnk, file->u.link) != 0)
+ if (strcmp(lnk, F_SYMLINK(file)) != 0)
continue;
break;
#endif
cmpbuf, fname);
return j;
}
- if (preserve_hard_links && file->link_u.links)
- hard_link_cluster(file, ndx, itemizing, code);
+ if (preserve_hard_links && IS_HLINKED(file))
+ hard_link_cluster(file, ndx, itemizing, code, -1);
} else
#endif
match_level = 2;
rsyserr(FERROR, errno,
"recv_generator: mkdir %s failed",
full_fname(fname));
- file->flags |= FLAG_MISSING;
+ file->flags |= FLAG_MISSING_DIR;
if (ndx+1 < the_file_list->count
&& the_file_list->files[ndx+1]->dir.depth > file->dir.depth) {
rprintf(FERROR,
if (real_ret != 0 && one_file_system)
real_st.st_dev = filesystem_dev;
if (delete_during && f_out != -1 && !phase && dry_run < 2
- && (file->flags & FLAG_DEL_HERE))
+ && (file->flags & FLAG_XFER_DIR))
delete_in_dir(the_file_list, fname, file, &real_st);
return;
}
- if (preserve_hard_links && file->link_u.links
+ if (preserve_hard_links && IS_HLINKED(file)
&& hard_link_check(file, ndx, fname, statret, &st,
itemizing, code, HL_CHECK_MASTER))
return;
if (preserve_links && S_ISLNK(file->mode)) {
#ifdef SUPPORT_LINKS
- if (safe_symlinks && unsafe_symlink(file->u.link, fname)) {
+ const char *sl = F_SYMLINK(file);
+ if (safe_symlinks && unsafe_symlink(sl, fname)) {
if (verbose) {
if (the_file_list->count == 1)
fname = f_name(file, NULL);
rprintf(FINFO,
"ignoring unsafe symlink %s -> \"%s\"\n",
- full_fname(fname), file->u.link);
+ full_fname(fname), sl);
}
return;
}
if (!S_ISLNK(st.st_mode))
statret = -1;
else if ((len = readlink(fname, lnk, MAXPATHLEN-1)) > 0
- && strncmp(lnk, file->u.link, len) == 0
- && file->u.link[len] == '\0') {
+ && strncmp(lnk, sl, len) == 0 && sl[len] == '\0') {
/* The link is pointing to the right place. */
if (itemizing)
itemize(file, ndx, 0, &st, 0, 0, NULL);
set_file_attrs(fname, file, &st, maybe_ATTRS_REPORT);
- if (preserve_hard_links && file->link_u.links)
- hard_link_cluster(file, ndx, itemizing, code);
+ if (preserve_hard_links && IS_HLINKED(file))
+ hard_link_cluster(file, ndx, itemizing, code, -1);
if (remove_source_files == 1)
goto return_with_success;
return;
} else if (j >= 0)
statret = 1;
}
- if (preserve_hard_links && file->link_u.links
+ if (preserve_hard_links && IS_HLINKED(file)
&& hard_link_check(file, ndx, fname, -1, &st,
itemizing, code, HL_SKIP))
return;
- if (do_symlink(file->u.link, fname) != 0) {
+ if (do_symlink(sl, fname) != 0) {
rsyserr(FERROR, errno, "symlink %s -> \"%s\" failed",
- full_fname(fname), file->u.link);
+ full_fname(fname), sl);
} else {
set_file_attrs(fname, file, NULL, 0);
if (itemizing) {
ITEM_LOCAL_CHANGE, 0, NULL);
}
if (code != FNONE && verbose)
- rprintf(code, "%s -> %s\n", fname, file->u.link);
- if (preserve_hard_links && file->link_u.links)
- hard_link_cluster(file, ndx, itemizing, code);
+ rprintf(code, "%s -> %s\n", fname, sl);
+ if (preserve_hard_links && IS_HLINKED(file))
+ hard_link_cluster(file, ndx, itemizing, code, -1);
/* This does not check remove_source_files == 1
* because this is one of the items that the old
* --remove-sent-files option would remove. */
if ((am_root && preserve_devices && IS_DEVICE(file->mode))
|| (preserve_specials && IS_SPECIAL(file->mode))) {
+ dev_t rdev = MAKEDEV(F_DMAJOR(file), F_DMINOR(file));
if (statret == 0) {
char *t;
if (IS_DEVICE(file->mode)) {
}
if (statret == 0
&& (st.st_mode & ~CHMOD_BITS) == (file->mode & ~CHMOD_BITS)
- && st.st_rdev == file->u.rdev) {
+ && st.st_rdev == rdev) {
/* The device or special file is identical. */
if (itemizing)
itemize(file, ndx, 0, &st, 0, 0, NULL);
set_file_attrs(fname, file, &st, maybe_ATTRS_REPORT);
- if (preserve_hard_links && file->link_u.links)
- hard_link_cluster(file, ndx, itemizing, code);
+ if (preserve_hard_links && IS_HLINKED(file))
+ hard_link_cluster(file, ndx, itemizing, code, -1);
if (remove_source_files == 1)
goto return_with_success;
return;
} else if (j >= 0)
statret = 1;
}
- if (preserve_hard_links && file->link_u.links
+ if (preserve_hard_links && IS_HLINKED(file)
&& hard_link_check(file, ndx, fname, -1, &st,
itemizing, code, HL_SKIP))
return;
if (verbose > 2) {
rprintf(FINFO,"mknod(%s,0%o,0x%x)\n",
- fname, (int)file->mode, (int)file->u.rdev);
+ fname, (int)file->mode, (int)rdev);
}
- if (do_mknod(fname, file->mode, file->u.rdev) < 0) {
+ if (do_mknod(fname, file->mode, rdev) < 0) {
rsyserr(FERROR, errno, "mknod %s failed",
full_fname(fname));
} else {
}
if (code != FNONE && verbose)
rprintf(code, "%s\n", fname);
- if (preserve_hard_links && file->link_u.links)
- hard_link_cluster(file, ndx, itemizing, code);
+ if (preserve_hard_links && IS_HLINKED(file))
+ hard_link_cluster(file, ndx, itemizing, code, -1);
if (remove_source_files == 1)
goto return_with_success;
}
}
if (statret != 0) {
- if (preserve_hard_links && file->link_u.links
+ if (preserve_hard_links && IS_HLINKED(file)
&& hard_link_check(file, ndx, fname, statret, &st,
itemizing, code, HL_SKIP))
return;
0, 0, NULL);
}
set_file_attrs(fname, file, &st, maybe_ATTRS_REPORT);
- if (preserve_hard_links && file->link_u.links)
- hard_link_cluster(file, ndx, itemizing, code);
+ if (preserve_hard_links && IS_HLINKED(file))
+ hard_link_cluster(file, ndx, itemizing, code, -1);
if (remove_source_files != 1)
return;
return_with_success:
if (fuzzy_dirlist) {
int j = flist_find(fuzzy_dirlist, file);
if (j >= 0) /* don't use changing file as future fuzzy basis */
- fuzzy_dirlist->files[j]->flags |= FLAG_NO_FUZZY;
+ fuzzy_dirlist->files[j]->flags |= FLAG_SENT;
}
/* open the file */
full_fname(fnamecmp));
pretend_missing:
/* pretend the file didn't exist */
- if (preserve_hard_links && file->link_u.links
+ if (preserve_hard_links && IS_HLINKED(file)
&& hard_link_check(file, ndx, fname, statret, &st,
itemizing, code, HL_SKIP))
return;
if (robust_unlink(backupptr) && errno != ENOENT) {
rsyserr(FERROR, errno, "unlink %s",
full_fname(backupptr));
- free(back_file);
+ unmake_file(back_file);
close(fd);
return;
}
O_WRONLY | O_CREAT | O_TRUNC | O_EXCL, 0600)) < 0) {
rsyserr(FERROR, errno, "open %s",
full_fname(backupptr));
- free(back_file);
+ unmake_file(back_file);
close(fd);
return;
}
}
if (!do_xfers) {
- if (preserve_hard_links && file->link_u.links)
- hard_link_cluster(file, ndx, itemizing, code);
+ if (preserve_hard_links && IS_HLINKED(file))
+ hard_link_cluster(file, ndx, itemizing, code, -1);
return;
}
if (read_batch)
rprintf(FINFO, "backed up %s to %s\n",
fname, backupptr);
}
- free(back_file);
+ unmake_file(back_file);
}
close(fd);
if (delete_before && !local_name && flist->count > 0)
do_delete_pass(flist);
+ if (delete_during == 2)
+ start_delete_temp();
do_progress = 0;
if (append_mode || whole_file < 0)
if (verbose > 2)
rprintf(FINFO,"generate_files phase=%d\n",phase);
- write_int(f_out, -1);
+ write_int(f_out, NDX_DONE);
/* files can cycle through the system more than once
* to catch initial checksum errors */
if (verbose > 2)
rprintf(FINFO,"generate_files phase=%d\n",phase);
- write_int(f_out, -1);
+ write_int(f_out, NDX_DONE);
/* Reduce round-trip lag-time for a useless delay-updates phase. */
if (protocol_version >= 29 && !delay_updates)
- write_int(f_out, -1);
+ write_int(f_out, NDX_DONE);
/* Read MSG_DONE for the redo phase (and any prior messages). */
get_redo_num(itemizing, code);
if (verbose > 2)
rprintf(FINFO, "generate_files phase=%d\n", phase);
if (delay_updates)
- write_int(f_out, -1);
+ write_int(f_out, NDX_DONE);
/* Read MSG_DONE for delay-updates phase & prior messages. */
get_redo_num(itemizing, code);
}
do_progress = save_do_progress;
+ if (delete_delay_fp)
+ delayed_deletions(fbuf);
if (delete_after && !local_name && flist->count > 0)
do_delete_pass(flist);
continue;
if (!need_retouch_dir_times && file->mode & S_IWUSR)
continue;
- if (file->flags & FLAG_MISSING) {
+ if (file->flags & FLAG_MISSING_DIR) {
int missing = file->dir.depth;
while (++i < flist->count) {
file = flist->files[i];