mirror of
https://github.com/RsyncProject/rsync.git
synced 2026-10-24 06:38:15 -04:00
My version of Mark Curtis's --inplace option.
This commit is contained in:
1 parent
2c713fcdfa
commit
a3221d2ac1
7 files changed
+163
-54
No files matched your search
@@ -23,6 +23,7 @@ extern int verbose;
|
||||
extern int am_server;
|
||||
extern int do_progress;
|
||||
extern int checksum_seed;
|
||||
extern int inplace;
|
||||
|
||||
typedef unsigned short tag;
|
||||
|
||||
@@ -200,6 +201,12 @@ static void hash_search(int f,struct sum_struct *s,
|
||||
if (l != s->sums[i].len)
|
||||
continue;
|
||||
|
||||
/* inplace: ensure chunk's offset is either >= our
|
||||
* offset or that the data didn't move. */
|
||||
if (inplace && s->sums[i].offset < offset
|
||||
&& !(s->sums[i].flags & SUMFLG_SAME_OFFSET))
|
||||
continue;
|
||||
|
||||
if (verbose > 3)
|
||||
rprintf(FINFO,"potential match at %.0f target=%.0f %.0f sum=%08x\n",
|
||||
(double)offset,(double)j,(double)i,sum);
|
||||
@@ -215,15 +222,41 @@ static void hash_search(int f,struct sum_struct *s,
|
||||
continue;
|
||||
}
|
||||
|
||||
/* If inplace is enabled, the best possible match is
|
||||
* one with an identical offset, so we prefer that over
|
||||
* the following want_i optimization. */
|
||||
if (inplace) {
|
||||
do {
|
||||
size_t i2 = targets[j].i;
|
||||
if (s->sums[i2].offset != offset)
|
||||
continue;
|
||||
if (i2 != i) {
|
||||
if (sum != s->sums[i2].sum1)
|
||||
break;
|
||||
if (memcmp(sum2, s->sums[i2].sum2,
|
||||
s->s2length) != 0)
|
||||
break;
|
||||
i = i2;
|
||||
}
|
||||
/* This chunk was at the same offset on
|
||||
* both the sender and the receiver. */
|
||||
s->sums[i].flags |= SUMFLG_SAME_OFFSET;
|
||||
goto set_want_i;
|
||||
} while (++j < s->count && targets[j].t == t);
|
||||
}
|
||||
|
||||
/* we've found a match, but now check to see
|
||||
* if want_i can hint at a better match. */
|
||||
if (i != want_i && want_i < s->count
|
||||
&& (!inplace || s->sums[want_i].offset >= offset
|
||||
|| s->sums[want_i].flags & SUMFLG_SAME_OFFSET)
|
||||
&& sum == s->sums[want_i].sum1
|
||||
&& memcmp(sum2, s->sums[want_i].sum2, s->s2length) == 0) {
|
||||
/* we've found an adjacent match - the RLL coder
|
||||
* will be happy */
|
||||
i = want_i;
|
||||
}
|
||||
set_want_i:
|
||||
want_i = i + 1;
|
||||
|
||||
matched(f,s,buf,offset,i);
|
||||
|
||||
@@ -94,6 +94,7 @@ int ignore_errors = 0;
|
||||
int modify_window = 0;
|
||||
int blocking_io = -1;
|
||||
int checksum_seed = 0;
|
||||
int inplace = 0;
|
||||
unsigned int block_size = 0;
|
||||
|
||||
|
||||
@@ -148,6 +149,7 @@ char *bind_address;
|
||||
static void print_rsync_version(enum logcode f)
|
||||
{
|
||||
char const *got_socketpair = "no ";
|
||||
char const *have_inplace = "no ";
|
||||
char const *hardlinks = "no ";
|
||||
char const *links = "no ";
|
||||
char const *ipv6 = "no ";
|
||||
@@ -157,6 +159,10 @@ static void print_rsync_version(enum logcode f)
|
||||
got_socketpair = "";
|
||||
#endif
|
||||
|
||||
#if HAVE_FTRUNCATE
|
||||
have_inplace = "";
|
||||
#endif
|
||||
|
||||
#if SUPPORT_HARD_LINKS
|
||||
hardlinks = "";
|
||||
#endif
|
||||
@@ -182,8 +188,8 @@ static void print_rsync_version(enum logcode f)
|
||||
/* Note that this field may not have type ino_t. It depends
|
||||
* on the complicated interaction between largefile feature
|
||||
* macros. */
|
||||
rprintf(f, " %sIPv6, %d-bit system inums, %d-bit internal inums\n",
|
||||
ipv6,
|
||||
rprintf(f, " %sinplace, %sIPv6, %d-bit system inums, %d-bit internal inums\n",
|
||||
have_inplace, ipv6,
|
||||
(int) (sizeof dumstat->st_ino * 8),
|
||||
(int) (sizeof (uint64) * 8));
|
||||
#ifdef MAINTAINER_MODE
|
||||
@@ -233,6 +239,7 @@ void usage(enum logcode F)
|
||||
rprintf(F," --backup-dir make backups into this directory\n");
|
||||
rprintf(F," --suffix=SUFFIX backup suffix (default %s w/o --backup-dir)\n",BACKUP_SUFFIX);
|
||||
rprintf(F," -u, --update update only (don't overwrite newer files)\n");
|
||||
rprintf(F," --inplace update the destination file inplace (see man page)\n");
|
||||
rprintf(F," -K, --keep-dirlinks treat symlinked dir on receiver as dir\n");
|
||||
rprintf(F," -l, --links copy symlinks as symlinks\n");
|
||||
rprintf(F," -L, --copy-links copy the referent of all symlinks\n");
|
||||
@@ -340,6 +347,7 @@ static struct poptOption long_options[] = {
|
||||
{"sparse", 'S', POPT_ARG_NONE, &sparse_files, 0, 0, 0 },
|
||||
{"cvs-exclude", 'C', POPT_ARG_NONE, &cvs_exclude, 0, 0, 0 },
|
||||
{"update", 'u', POPT_ARG_NONE, &update_only, 0, 0, 0 },
|
||||
{"inplace", 0, POPT_ARG_NONE, &inplace, 0, 0, 0 },
|
||||
{"keep-dirlinks", 'K', POPT_ARG_NONE, &keep_dirlinks, 0, 0, 0 },
|
||||
{"links", 'l', POPT_ARG_NONE, &preserve_links, 0, 0, 0 },
|
||||
{"copy-links", 'L', POPT_ARG_NONE, ©_links, 0, 0, 0 },
|
||||
@@ -754,6 +762,17 @@ int parse_arguments(int *argc, const char ***argv, int frommain)
|
||||
bwlimit_writemax = 512;
|
||||
}
|
||||
|
||||
if (inplace) {
|
||||
#if HAVE_FTRUNCATE
|
||||
keep_partial = 0;
|
||||
#else
|
||||
snprintf(err_buf, sizeof err_buf,
|
||||
"inplace is not supported on this %s\n",
|
||||
am_server ? "server" : "client");
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
if (files_from) {
|
||||
char *colon;
|
||||
if (*argc != 2 && !(am_server && am_sender && *argc == 1)) {
|
||||
@@ -971,6 +990,9 @@ void server_options(char **args,int *argc)
|
||||
if (opt_ignore_existing && am_sender)
|
||||
args[ac++] = "--ignore-existing";
|
||||
|
||||
if (inplace)
|
||||
args[ac++] = "--inplace";
|
||||
|
||||
if (tmpdir) {
|
||||
args[ac++] = "--temp-dir";
|
||||
args[ac++] = tmpdir;
|
||||
|
||||
+68
-38
@@ -48,6 +48,7 @@ extern int ignore_errors;
|
||||
extern int orig_umask;
|
||||
extern int keep_partial;
|
||||
extern int checksum_seed;
|
||||
extern int inplace;
|
||||
|
||||
static void delete_one(char *fn, int is_dir)
|
||||
{
|
||||
@@ -255,16 +256,30 @@ static int receive_data(int f_in,struct map_struct *mapbuf,int fd,char *fname,
|
||||
sum_update(map,len);
|
||||
}
|
||||
|
||||
if (fd != -1 && write_file(fd, map, len) != (int)len) {
|
||||
rsyserr(FERROR, errno, "write failed on %s",
|
||||
full_fname(fname));
|
||||
exit_cleanup(RERR_FILEIO);
|
||||
if (!inplace || offset != offset2) {
|
||||
if (fd != -1 && write_file(fd, map, len) != (int)len) {
|
||||
rsyserr(FERROR, errno, "write failed on %s",
|
||||
full_fname(fname));
|
||||
exit_cleanup(RERR_FILEIO);
|
||||
}
|
||||
} else {
|
||||
flush_write_file(fd);
|
||||
if (do_lseek(fd,(OFF_T)len,SEEK_CUR) != offset+len) {
|
||||
rprintf(FERROR, "lseek failed on %s: %s, %lli, %lli, %i\n",
|
||||
full_fname(fname), strerror(errno), do_lseek(fd,0,SEEK_CUR), (offset+len), i);
|
||||
exit_cleanup(RERR_FILEIO);
|
||||
}
|
||||
}
|
||||
offset += len;
|
||||
}
|
||||
|
||||
flush_write_file(fd);
|
||||
|
||||
#ifdef HAVE_FTRUNCATE
|
||||
if (inplace)
|
||||
ftruncate(fd, offset);
|
||||
#endif
|
||||
|
||||
if (do_progress)
|
||||
end_progress(total_size);
|
||||
|
||||
@@ -414,44 +429,59 @@ int recv_files(int f_in, struct file_list *flist, char *local_name)
|
||||
} else
|
||||
mapbuf = NULL;
|
||||
|
||||
if (!get_tmpname(fnametmp,fname)) {
|
||||
if (mapbuf)
|
||||
unmap_file(mapbuf);
|
||||
if (fd1 != -1)
|
||||
close(fd1);
|
||||
continue;
|
||||
}
|
||||
/* We now check to see if we are writing file "inplace" */
|
||||
if (inplace) {
|
||||
fd2 = do_open(fnamecmp, O_WRONLY|O_CREAT, 0);
|
||||
if (fd2 == -1) {
|
||||
rsyserr(FERROR, errno, "open %s failed",
|
||||
full_fname(fnamecmp));
|
||||
receive_data(f_in,mapbuf,-1,NULL,file->length);
|
||||
if (mapbuf)
|
||||
unmap_file(mapbuf);
|
||||
if (fd1 != -1)
|
||||
close(fd1);
|
||||
continue;
|
||||
}
|
||||
} else {
|
||||
if (!get_tmpname(fnametmp,fname)) {
|
||||
if (mapbuf)
|
||||
unmap_file(mapbuf);
|
||||
if (fd1 != -1)
|
||||
close(fd1);
|
||||
continue;
|
||||
}
|
||||
|
||||
strlcpy(template, fnametmp, sizeof template);
|
||||
strlcpy(template, fnametmp, sizeof template);
|
||||
|
||||
/* we initially set the perms without the
|
||||
* setuid/setgid bits to ensure that there is no race
|
||||
* condition. They are then correctly updated after
|
||||
* the lchown. Thanks to snabb@epipe.fi for pointing
|
||||
* this out. We also set it initially without group
|
||||
* access because of a similar race condition. */
|
||||
fd2 = do_mkstemp(fnametmp, file->mode & INITACCESSPERMS);
|
||||
|
||||
/* in most cases parent directories will already exist
|
||||
* because their information should have been previously
|
||||
* transferred, but that may not be the case with -R */
|
||||
if (fd2 == -1 && relative_paths && errno == ENOENT &&
|
||||
create_directory_path(fnametmp, orig_umask) == 0) {
|
||||
strlcpy(fnametmp, template, sizeof fnametmp);
|
||||
/* we initially set the perms without the
|
||||
* setuid/setgid bits to ensure that there is no race
|
||||
* condition. They are then correctly updated after
|
||||
* the lchown. Thanks to snabb@epipe.fi for pointing
|
||||
* this out. We also set it initially without group
|
||||
* access because of a similar race condition. */
|
||||
fd2 = do_mkstemp(fnametmp, file->mode & INITACCESSPERMS);
|
||||
}
|
||||
if (fd2 == -1) {
|
||||
rsyserr(FERROR, errno, "mkstemp %s failed",
|
||||
full_fname(fnametmp));
|
||||
receive_data(f_in,mapbuf,-1,NULL,file->length);
|
||||
if (mapbuf)
|
||||
unmap_file(mapbuf);
|
||||
if (fd1 != -1)
|
||||
close(fd1);
|
||||
continue;
|
||||
}
|
||||
|
||||
cleanup_set(fnametmp, fname, file, mapbuf, fd1, fd2);
|
||||
/* in most cases parent directories will already exist
|
||||
* because their information should have been previously
|
||||
* transferred, but that may not be the case with -R */
|
||||
if (fd2 == -1 && relative_paths && errno == ENOENT
|
||||
&& create_directory_path(fnametmp, orig_umask) == 0) {
|
||||
strlcpy(fnametmp, template, sizeof fnametmp);
|
||||
fd2 = do_mkstemp(fnametmp, file->mode & INITACCESSPERMS);
|
||||
}
|
||||
if (fd2 == -1) {
|
||||
rsyserr(FERROR, errno, "mkstemp %s failed",
|
||||
full_fname(fnametmp));
|
||||
receive_data(f_in,mapbuf,-1,NULL,file->length);
|
||||
if (mapbuf)
|
||||
unmap_file(mapbuf);
|
||||
if (fd1 != -1)
|
||||
close(fd1);
|
||||
continue;
|
||||
}
|
||||
|
||||
cleanup_set(fnametmp, fname, file, mapbuf, fd1, fd2);
|
||||
}
|
||||
|
||||
if (!am_server && verbose)
|
||||
rprintf(FINFO, "%s\n", fname);
|
||||
|
||||
@@ -34,6 +34,7 @@ extern int force_delete;
|
||||
extern int recurse;
|
||||
extern int make_backups;
|
||||
extern char *backup_dir;
|
||||
extern int inplace;
|
||||
|
||||
|
||||
/*
|
||||
@@ -239,6 +240,13 @@ void finish_transfer(char *fname, char *fnametmp, struct file_struct *file,
|
||||
if (make_backups && !make_backup(fname))
|
||||
return;
|
||||
|
||||
if (inplace) {
|
||||
if (verbose > 2)
|
||||
rprintf(FINFO, "finishing %s\n", fname);
|
||||
set_perms(fname, file, NULL, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
/* move tmp file over real file */
|
||||
if (verbose > 2)
|
||||
rprintf(FINFO, "renaming %s to %s\n", fnametmp, fname);
|
||||
|
||||
@@ -458,11 +458,13 @@ struct file_list {
|
||||
struct file_struct **files;
|
||||
};
|
||||
|
||||
#define SUMFLG_SAME_OFFSET (1<<0)
|
||||
|
||||
struct sum_buf {
|
||||
OFF_T offset; /**< offset in file of this chunk */
|
||||
unsigned int len; /**< length of chunk of file */
|
||||
int i; /**< index of this chunk */
|
||||
uint32 sum1; /**< simple checksum */
|
||||
short flags; /**< flag bits */
|
||||
char sum2[SUM_LENGTH]; /**< checksum */
|
||||
};
|
||||
|
||||
|
||||
@@ -289,6 +289,7 @@ verb(
|
||||
--backup-dir make backups into this directory
|
||||
--suffix=SUFFIX backup suffix (default ~ w/o --backup-dir)
|
||||
-u, --update update only (don't overwrite newer files)
|
||||
--inplace update the destination file inplace
|
||||
-K, --keep-dirlinks treat symlinked dir on receiver as dir
|
||||
-l, --links copy symlinks as symlinks
|
||||
-L, --copy-links copy the referent of all symlinks
|
||||
@@ -484,6 +485,17 @@ dit(bf(-K, --keep-dirlinks)) On the receiving side, if a symlink is
|
||||
pointing to a directory, it will be treated as matching a directory
|
||||
from the sender.
|
||||
|
||||
dit(bf(--inplace)) This causes rsync not to create a new copy of the file
|
||||
and then move it into place. Instead rsync will overwrite the existing
|
||||
file, meaning that the rsync algorithm can't extract the full ammount of
|
||||
network reduction it might otherwise.
|
||||
|
||||
This option is useful for transfer of large files with block based changes
|
||||
and also on systems that are disk bound not network bound.
|
||||
|
||||
WARNING: If the transfer is interrupted, you will have an inconsistent file
|
||||
and the transfer should be run again.
|
||||
|
||||
dit(bf(-l, --links)) When symlinks are encountered, recreate the
|
||||
symlink on the destination.
|
||||
|
||||
|
||||
@@ -27,6 +27,7 @@ extern int dry_run;
|
||||
extern int am_server;
|
||||
extern int am_daemon;
|
||||
extern int protocol_version;
|
||||
extern struct stats stats;
|
||||
|
||||
|
||||
/**
|
||||
@@ -62,8 +63,8 @@ static struct sum_struct *receive_sums(int f)
|
||||
int i;
|
||||
OFF_T offset = 0;
|
||||
|
||||
s = new(struct sum_struct);
|
||||
if (!s) out_of_memory("receive_sums");
|
||||
if (!(s = new(struct sum_struct)))
|
||||
out_of_memory("receive_sums");
|
||||
|
||||
read_sum_head(f, s);
|
||||
|
||||
@@ -77,26 +78,28 @@ static struct sum_struct *receive_sums(int f)
|
||||
if (s->count == 0)
|
||||
return(s);
|
||||
|
||||
s->sums = new_array(struct sum_buf, s->count);
|
||||
if (!s->sums) out_of_memory("receive_sums");
|
||||
if (!(s->sums = new_array(struct sum_buf, s->count)))
|
||||
out_of_memory("receive_sums");
|
||||
|
||||
for (i = 0; i < (int) s->count; i++) {
|
||||
for (i = 0; i < (int)s->count; i++) {
|
||||
s->sums[i].sum1 = read_int(f);
|
||||
read_buf(f, s->sums[i].sum2, s->s2length);
|
||||
|
||||
s->sums[i].offset = offset;
|
||||
s->sums[i].i = i;
|
||||
s->sums[i].flags = 0;
|
||||
|
||||
if (i == (int) s->count-1 && s->remainder != 0) {
|
||||
if (i == (int)s->count-1 && s->remainder != 0)
|
||||
s->sums[i].len = s->remainder;
|
||||
} else {
|
||||
else
|
||||
s->sums[i].len = s->blength;
|
||||
}
|
||||
offset += s->sums[i].len;
|
||||
|
||||
if (verbose > 3)
|
||||
rprintf(FINFO, "chunk[%d] len=%d offset=%.0f sum1=%08x\n",
|
||||
i, s->sums[i].len, (double)s->sums[i].offset, s->sums[i].sum1);
|
||||
if (verbose > 3) {
|
||||
rprintf(FINFO,
|
||||
"chunk[%d] len=%d offset=%.0f sum1=%08x\n",
|
||||
i, s->sums[i].len, (double)s->sums[i].offset,
|
||||
s->sums[i].sum1);
|
||||
}
|
||||
}
|
||||
|
||||
s->flength = offset;
|
||||
@@ -116,7 +119,6 @@ void send_files(struct file_list *flist, int f_out, int f_in)
|
||||
int i;
|
||||
struct file_struct *file;
|
||||
int phase = 0;
|
||||
extern struct stats stats;
|
||||
struct stats initial_stats;
|
||||
int j;
|
||||
|
||||
|
||||
Reference in new issue
Block a user