direct write patch
Don Mahurin
dmahurin at berkeley.innomedia.com
Tue Nov 13 05:12:54 EST 2001
I have attached a patch that supports a new "--direct-write" option.
The result of using this option is to write directly to the destination
files, instead of a temporary file first.
The reason this patch is needed is for rsyncing to a device where the
device is full or nearly full.
Say that I am writing to a device that has 1 Meg free, and a 2 meg file
on that device is out of date.
Rsync will first attempt to write a new temp file, and fail, SIGUSR1'ing
itself, and outputting "Error 20".
Specifically, I am writing a linux root fs to a 32Meg compact flash, and
libc needs to be updated, and rsync fails.
This patch simply sets fnametmp to fname.
Two issues with the patch, that hopefully developers can answer:
- In direct-write mode, I open without O_EXCL, as the file likely does
exist.
Should the destination file be deleted instead? (I do not know what
exactly the race condition is)
- There is a section after the assignment of fnametmp, and before the
open that does do_mktemp, then
receive_data. What is the purpose of this part? I skip it for
direct-write, and it works, but what do I know?
-don
-------------- next part --------------
Only in rsync-2.4.6-direct-write/lib: dummy
diff -ru rsync-2.4.6/options.c rsync-2.4.6-direct-write/options.c
--- rsync-2.4.6/options.c Tue Sep 5 19:46:43 2000
+++ rsync-2.4.6-direct-write/options.c Sun Nov 11 10:40:01 2001
@@ -22,6 +22,7 @@
int make_backups = 0;
+int direct_write = 0;
int whole_file = 0;
int copy_links = 0;
int preserve_links = 0;
@@ -147,6 +148,7 @@
rprintf(F," --ignore-errors delete even if there are IO errors\n");
rprintf(F," --max-delete=NUM don't delete more than NUM files\n");
rprintf(F," --partial keep partially transferred files\n");
+ rprintf(F," --direct-write write directly to the destination files\n");
rprintf(F," --force force deletion of directories even if not empty\n");
rprintf(F," --numeric-ids don't map uid/gid values by user/group name\n");
rprintf(F," --timeout=TIME set IO timeout in seconds\n");
@@ -188,7 +190,7 @@
OPT_LOG_FORMAT, OPT_PASSWORD_FILE, OPT_SIZE_ONLY, OPT_ADDRESS,
OPT_DELETE_AFTER, OPT_EXISTING, OPT_MAX_DELETE, OPT_BACKUP_DIR,
OPT_IGNORE_ERRORS, OPT_BWLIMIT, OPT_BLOCKING_IO,
- OPT_MODIFY_WINDOW};
+ OPT_MODIFY_WINDOW, OPT_DIRECT_WRITE};
static char *short_options = "oblLWHpguDCtcahvqrRIxnSe:B:T:zP";
@@ -227,6 +229,7 @@
{"perms", 0, 0, 'p'},
{"links", 0, 0, 'l'},
{"copy-links", 0, 0, 'L'},
+ {"direct-write", 0, 0, OPT_DIRECT_WRITE},
{"copy-unsafe-links", 0, 0, OPT_COPY_UNSAFE_LINKS},
{"safe-links", 0, 0, OPT_SAFE_LINKS},
{"whole-file", 0, 0, 'W'},
@@ -400,6 +403,10 @@
safe_symlinks=1;
break;
+ case OPT_DIRECT_WRITE:
+ direct_write = 1;
+ break;
+
case 'h':
usage(FINFO);
exit_cleanup(0);
@@ -554,6 +561,8 @@
keep_partial = 1;
break;
+
+
case OPT_IGNORE_ERRORS:
ignore_errors = 1;
break;
@@ -691,6 +700,9 @@
slprintf(mdelete,sizeof(mdelete),"--max-delete=%d",max_delete);
args[ac++] = mdelete;
}
+
+ if (direct_write)
+ args[ac++] = "--direct-write";
if (io_timeout) {
slprintf(iotime,sizeof(iotime),"--timeout=%d",io_timeout);
diff -ru rsync-2.4.6/receiver.c rsync-2.4.6-direct-write/receiver.c
--- rsync-2.4.6/receiver.c Thu Mar 30 06:23:03 2000
+++ rsync-2.4.6-direct-write/receiver.c Sun Nov 11 11:14:43 2001
@@ -34,6 +34,7 @@
extern char *tmpdir;
extern char *compare_dest;
extern int make_backups;
+extern int direct_write;
extern char *backup_suffix;
static struct delete_list {
@@ -302,7 +303,8 @@
int fd1,fd2;
STRUCT_STAT st;
char *fname;
- char fnametmp[MAXPATHLEN];
+ char *fnametmp;
+ char fnametmpbuf[MAXPATHLEN];
char *fnamecmp;
char fnamecmpbuf[MAXPATHLEN];
struct map_struct *buf;
@@ -314,6 +316,7 @@
extern int preserve_perms;
extern int delete_after;
struct stats initial_stats;
+ int write_flags;
if (verbose > 2) {
rprintf(FINFO,"recv_files(%d) starting\n",flist->count);
@@ -404,22 +407,29 @@
buf = NULL;
}
- if (!get_tmpname(fnametmp,fname)) {
- if (buf) unmap_file(buf);
- if (fd1 != -1) close(fd1);
- continue;
- }
+ if(direct_write) {
+ fnametmp = fname;
+ write_flags = O_WRONLY|O_CREAT;
+ } else {
+ fnametmp = fnametmpbuf;
+ if (!get_tmpname(fnametmp,fname)) {
+ if (buf) unmap_file(buf);
+ if (fd1 != -1) close(fd1);
+ continue;
+ }
+ write_flags = O_WRONLY|O_CREAT|O_EXCL;
/* mktemp is deliberately used here instead of mkstemp.
because O_EXCL is used on the open, the race condition
is not a problem or a security hole, and we want to
control the access permissions on the created file. */
- if (NULL == do_mktemp(fnametmp)) {
- rprintf(FERROR,"mktemp %s failed\n",fnametmp);
- receive_data(f_in,buf,-1,NULL,file->length);
- if (buf) unmap_file(buf);
- if (fd1 != -1) close(fd1);
- continue;
+ if (NULL == do_mktemp(fnametmp)) {
+ rprintf(FERROR,"mktemp %s failed\n",fnametmp);
+ receive_data(f_in,buf,-1,NULL,file->length);
+ if (buf) unmap_file(buf);
+ if (fd1 != -1) close(fd1);
+ continue;
+ }
}
/* we initially set the perms without the
@@ -428,7 +438,7 @@
the lchown. Thanks to snabb at epipe.fi for pointing
this out. We also set it initially without group
access because of a similar race condition. */
- fd2 = do_open(fnametmp,O_WRONLY|O_CREAT|O_EXCL,
+ fd2 = do_open(fnametmp,write_flags,
file->mode & INITACCESSPERMS);
/* in most cases parent directories will already exist
@@ -436,7 +446,7 @@
transferred, but that may not be the case with -R */
if (fd2 == -1 && relative_paths && errno == ENOENT &&
create_directory_path(fnametmp) == 0) {
- fd2 = do_open(fnametmp,O_WRONLY|O_CREAT|O_EXCL,
+ fd2 = do_open(fnametmp,write_flags,
file->mode & INITACCESSPERMS);
}
if (fd2 == -1) {
More information about the rsync
mailing list