1 /*
2 * csync2 - cluster synchronization tool, 2nd generation
3 * Copyright (C) 2004 - 2013 LINBIT Information Technologies GmbH
4 * http://www.linbit.com; see also AUTHORS
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19 */
20
21 #include "csync2.h"
22 #include <librsync.h>
23 #include <unistd.h>
24 #include <string.h>
25 #include <errno.h>
26 #include <stdio.h>
27
28 /* for tmpfile replacement: */
29 #include <sys/types.h>
30 #include <sys/stat.h>
31 #include <fcntl.h>
32
33 /* for MAXPATHLEN */
34 #include <sys/param.h>
35
36
37 #ifdef __CYGWIN__
38 #include <w32api/windows.h>
39 #endif
40
41
42 /* This has been taken from rsync:lib/compat.c */
43
44 #if 0
45 /**
46 * Like strncpy but does not 0 fill the buffer and always null
47 * terminates.
48 *
49 * @param bufsize is the size of the destination buffer.
50 *
51 * @return index of the terminating byte.
52 **/
53 static size_t strlcpy(char *d, const char *s, size_t bufsize)
54 {
55 size_t len = strlen(s);
56 size_t ret = len;
57 if (bufsize > 0) {
58 if (len >= bufsize)
59 len = bufsize-1;
60 memcpy(d, s, len);
61 d[len] = 0;
62 }
63 return ret;
64 }
65 #endif
66
67 /* splits filepath at the last '/', if any, like so:
68 * dirname basename filepath
69 * "/" "" "/"
70 * "/" "foo" "/foo"
71 * no trailing slash in dirname, unless it is "/".
72 * "/some/path" "" "/some/path/"
73 * "/some/path" "foo" "/some/path/foo"
74 * "" "foo" "foo"
75 *
76 * caller needs to supply enough room in dirname and basename
77 * to hold the result, or NULL, if not interested.
78 */
split_dirname_basename(char * dirname,char * basename,const char * filepath)79 void split_dirname_basename(char *dirname, char* basename, const char *filepath)
80 {
81 const char *base = strrchr(filepath, '/');
82 size_t pathlen, dirlen, baselen;
83
84 /* skip over last slash, if any. */
85 base = base ? base + 1 : filepath;
86
87 pathlen = strlen(filepath);
88 baselen = strlen(base);
89 dirlen = pathlen - baselen;
90
91 /* backtrack trailing slash(es) */
92 while (dirlen > 1 && filepath[dirlen-1] == '/')
93 --dirlen;
94
95 if (dirname)
96 strlcpy(dirname, filepath, dirlen + 1);
97 if (basename)
98 strlcpy(basename, base, baselen + 1);
99 }
100
101 /*
102 * Recursively creates the given path, with the given mode
103 * Note that path argument is not directory name here but rather
104 * a path to a file that you are going to create after calling mkpath().
105 * Works with relative paths as well.
106 * Shamelessly copied from
107 * Stackoverlow.com#http://stackoverflow.com/questions/2336242/recursive-mkdir-system-call-on-unix
108 * Returns: 0 on success and -1 on error
109 */
mkpath(const char * path,mode_t mode)110 int mkpath(const char *path, mode_t mode) {
111 char temp[MAXPATHLEN];
112 char *remaining;
113
114 if(!mode) {
115 mode=S_IRWXU;
116 }
117 if(!path){
118 csync_debug(2,"invalid path");
119 return -1;
120 }
121
122 if(strlcpy(temp,path,sizeof(temp))>=sizeof(temp)) {
123 csync_debug(1,"path too long: %s",path);
124 return -1;
125 }
126 csync_debug(1,"mkpath full path: %s",temp);
127 for( remaining=strchr(temp+1, '/'); remaining!=NULL; remaining=strchr(remaining+1, '/') ){
128 *remaining='\0';
129 if(mkdir(temp, mode)==-1) { //strchr keeps the parent in temp and child[ren] in remaining
130 if(errno != EEXIST) {
131 *remaining='/';
132 csync_debug(1,"error occured while creating path %s; cause : %s",temp,strerror(errno));
133 return -1;
134 }
135 }
136 csync_debug(1,"mkdir parent dir: %s",temp);
137 *remaining='/';
138 }
139 return 0;
140 }
141
142 /* This has been taken from rsync sources: syscall.c */
143
144 #ifndef O_BINARY
145 #define O_BINARY 0
146 #endif
147
148 /* like mkstemp but forces permissions */
do_mkstemp(char * template,mode_t perms)149 int do_mkstemp(char *template, mode_t perms)
150 {
151 perms |= S_IWUSR;
152
153 #if defined HAVE_SECURE_MKSTEMP && defined HAVE_FCHMOD && (!defined HAVE_OPEN64 || defined HAVE_MKSTEMP64)
154 {
155 int fd = mkstemp(template);
156 if (fd == -1)
157 return -1;
158 if (fchmod(fd, perms) != 0) {
159 int errno_save = errno;
160 close(fd);
161 unlink(template);
162 errno = errno_save;
163 return -1;
164 }
165 #if defined HAVE_SETMODE && O_BINARY
166 setmode(fd, O_BINARY);
167 #endif
168 return fd;
169 }
170 #else
171 if (!mktemp(template))
172 return -1;
173 return open(template, O_RDWR|O_EXCL|O_CREAT | O_BINARY, perms);
174 #endif
175 }
176
177
178 /* define the order in which directories are tried when creating temp files */
next_tempdir(char ** dir,unsigned int stage)179 static int next_tempdir(char **dir, unsigned int stage)
180 {
181 static char *dirs_to_try[] = {
182 NULL /* csync_tempdir */,
183 NULL /* stays NULL, same dir as input name */,
184 NULL /* getenv("TMPDIR") */,
185 P_tmpdir,
186 "/tmp",
187 };
188 static int n_dirs;
189 int i;
190
191 if (!n_dirs) {
192 n_dirs = sizeof(dirs_to_try)/sizeof(dirs_to_try[0]);
193 dirs_to_try[0] = csync_tempdir;
194 dirs_to_try[2] = getenv("TMPDIR");
195 for (i = 0; i < n_dirs; i++) {
196 struct stat sbuf;
197 int ret;
198 if (!dirs_to_try[i])
199 continue;
200 if (!dirs_to_try[i][0]) {
201 /* drop "" */
202 dirs_to_try[i] = NULL;
203 continue;
204 }
205 ret = stat(dirs_to_try[i], &sbuf);
206 if (ret || !S_ISDIR(sbuf.st_mode)) {
207 csync_debug(1, "dropping tempdir candidate '%s': not a directory\n",
208 dirs_to_try[i]);
209 dirs_to_try[i] = NULL;
210 }
211 }
212 }
213
214 /* skip this stage, if previous stages have been equal. */
215 for (; stage < n_dirs; stage++) {
216 if (dirs_to_try[stage] && !dirs_to_try[stage][0])
217 continue;
218
219 for (i = 0; i < stage; i++) {
220 if (dirs_to_try[i] == dirs_to_try[stage])
221 break;
222 if (!dirs_to_try[i] || !dirs_to_try[stage])
223 continue;
224 if (!strcmp(dirs_to_try[i], dirs_to_try[stage]))
225 break;
226 }
227 if (i == stage) {
228 *dir = dirs_to_try[stage];
229 return stage+1;
230 }
231 }
232 return -1;
233 }
234
235 /* This has been taken from rsync sources: receiver.c,
236 * and adapted: dropped the "make_unique" parameter,
237 * as in our use case it is always false.
238 *
239 * Added tempdir parameter,
240 * so we can try several dirs before giving up.
241 */
242
243 #define TMPNAME_SUFFIX ".XXXXXX"
244 #define TMPNAME_SUFFIX_LEN ((int)sizeof TMPNAME_SUFFIX - 1)
245
246 /* get_tmpname() - create a tmp filename for a given filename
247 *
248 * If a tmpdir is defined, use that as the directory to put it in. Otherwise,
249 * the tmp filename is in the same directory as the given name. Note that
250 * there may be no directory at all in the given name!
251 *
252 * The tmp filename is basically the given filename with a dot prepended, and
253 * .XXXXXX appended (for mkstemp() to put its unique gunk in). We take care
254 * to not exceed either the MAXPATHLEN or NAME_MAX, especially the last, as
255 * the basename basically becomes 8 characters longer. In such a case, the
256 * original name is shortened sufficiently to make it all fit.
257 *
258 * Of course, the only reason the file is based on the original name is to
259 * make it easier to figure out what purpose a temp file is serving when a
260 * transfer is in progress. */
get_tmpname(char * fnametmp,const char * tempdir,const char * fname)261 static int get_tmpname(char *fnametmp, const char *tempdir, const char *fname)
262 {
263 int maxname, length = 0;
264 const char *f;
265 char *suf;
266
267 if (tempdir) {
268 /* Note: this can't overflow, so the return value is safe */
269 length = strlcpy(fnametmp, tempdir, MAXPATHLEN - 2);
270 fnametmp[length++] = '/';
271 }
272
273 if ((f = strrchr(fname, '/')) != NULL) {
274 ++f;
275 if (!tempdir) {
276 length = f - fname;
277 /* copy up to and including the slash */
278 strlcpy(fnametmp, fname, length + 1);
279 }
280 } else
281 f = fname;
282 if (*f == '.') /* avoid an extra leading dot for OS X's sake */
283 f++;
284 fnametmp[length++] = '.';
285
286 /* The maxname value is bufsize, and includes space for the '\0'.
287 * NAME_MAX needs an extra -1 for the name's leading dot. */
288 maxname = MIN(MAXPATHLEN - length - TMPNAME_SUFFIX_LEN,
289 NAME_MAX - 1 - TMPNAME_SUFFIX_LEN);
290
291 if (maxname < 0) {
292 csync_debug(1, "temporary filename too long: %s\n", fname);
293 fnametmp[0] = '\0';
294 return 0;
295 }
296
297 if (maxname) {
298 int added = strlcpy(fnametmp + length, f, maxname);
299 if (added >= maxname)
300 added = maxname - 1;
301 suf = fnametmp + length + added;
302
303 /* Trim any dangling high-bit chars if the first-trimmed char (if any) is
304 * also a high-bit char, just in case we cut into a multi-byte sequence.
305 * We are guaranteed to stop because of the leading '.' we added. */
306 if ((int)f[added] & 0x80) {
307 while ((int)suf[-1] & 0x80)
308 suf--;
309 }
310 /* trim one trailing dot before our suffix's dot */
311 if (suf[-1] == '.')
312 suf--;
313 } else
314 suf = fnametmp + length - 1; /* overwrite the leading dot with suffix's dot */
315
316 memcpy(suf, TMPNAME_SUFFIX, TMPNAME_SUFFIX_LEN+1);
317
318 return 1;
319 }
320
321 /* Returns open file handle for a temp file that resides in the
322 * csync_tempdir (if specified), or
323 * the same directory as fname.
324 * If tempfile creation was not possible, before giving up,
325 * TMPDIR, P_tmpdir, or /tmp are also tried, in that order.
326 * The file must be removed after usage, or renamed into place.
327 */
328
open_temp_file(char * fnametmp,const char * fname)329 static FILE* open_temp_file(char *fnametmp, const char *fname)
330 {
331 FILE *f = NULL;
332 char *dir = NULL;
333 int fd;
334 int i = 0;
335
336 do {
337 if (i > 0)
338 csync_debug(3, "mkstemp %s failed: %s\n", fnametmp, strerror(errno));
339
340 i = next_tempdir(&dir, i);
341 if (i < 0)
342 return NULL;
343
344 if (!get_tmpname(fnametmp, dir, fname))
345 return NULL;
346
347 fd = do_mkstemp(fnametmp, S_IRUSR|S_IWUSR);
348 } while (fd < 0 && errno == ENOENT);
349
350 if (fd >= 0) {
351 f = fdopen(fd, "wb+");
352 /* not unlinking since rename wouldn't work then */
353 }
354
355 if (fd < 0 || !f) {
356 csync_debug(1, "mkstemp %s failed: %s\n", fnametmp, strerror(errno));
357 return NULL;
358 }
359
360 return f;
361 }
362
363 /* FIXME ftell? long? seriously?
364 *
365 * Then again, it is only a sigfile, so the base file size would need to be
366 * positively huge to have the size of the signature overflow a 32 bit LONG_MAX.
367 * In which case csync2 would be the wrong tool anyways.
368 */
369
csync_send_file(FILE * in)370 void csync_send_file(FILE *in)
371 {
372 char buffer[512];
373 int rc, chunk;
374 long size;
375
376 fflush(in);
377 size = ftell(in);
378 rewind(in);
379
380 conn_printf("octet-stream %ld\n", size);
381
382 while ( size > 0 ) {
383 chunk = size > 512 ? 512 : size;
384 rc = fread(buffer, 1, chunk, in);
385
386 if ( rc <= 0 )
387 csync_fatal("Read-error while sending data.\n");
388 chunk = rc;
389
390 rc = conn_write(buffer, chunk);
391 if ( rc != chunk )
392 csync_fatal("Write-error while sending data.\n");
393
394 size -= chunk;
395 }
396 }
397
csync_recv_file(FILE * out)398 int csync_recv_file(FILE *out)
399 {
400 char buffer[512];
401 int rc, chunk;
402 long size;
403
404 if ( !conn_gets(buffer, 100) || sscanf(buffer, "octet-stream %ld\n", &size) != 1 ) {
405 if (!strcmp(buffer, "ERROR\n")) { errno=EIO; return -1; }
406 csync_fatal("Format-error while receiving data.\n");
407 }
408 if (size < 0) { errno=EIO; return -1; }
409
410 csync_debug(3, "Receiving %ld bytes ..\n", size);
411
412 while ( size > 0 ) {
413 chunk = size > 512 ? 512 : size;
414 rc = conn_read(buffer, chunk);
415
416 if ( rc <= 0 )
417 csync_fatal("Read-error while receiving data.\n");
418 chunk = rc;
419
420 rc = fwrite(buffer, chunk, 1, out);
421 if ( rc != 1 )
422 csync_fatal("Write-error while receiving data.\n");
423
424 size -= chunk;
425 csync_debug(3, "Got %d bytes, %ld bytes left ..\n",
426 chunk, size);
427 }
428
429 fflush(out);
430 rewind(out);
431 return 0;
432 }
433
434 /*
435 * Return:
436 * 0, *sig_file == NULL: base file does not exist, empty sig.
437 * 0, *sig_file != NULL: sig_file contains the sig
438 * -1, *sig_file == NULL: "IO Error"
439 * -1, *sig_file != NULL: librsync error
440 */
csync_rs_sigfile(const char * filename,FILE ** sig_file_out)441 int csync_rs_sigfile(const char *filename, FILE **sig_file_out)
442 {
443 char tmpfname[MAXPATHLEN];
444 struct stat st;
445 FILE *basis_file;
446 FILE *sig_file = NULL;
447 int r = -1;
448 rs_result result;
449 rs_stats_t stats;
450
451 csync_debug(3, "Opening basis_file and sig_file for %s\n", filename);
452 *sig_file_out = NULL;
453
454 basis_file = fopen(prefixsubst(filename), "rb");
455 if (!basis_file && errno == ENOENT) {
456 csync_debug(3, "Basis file does not exist.\n");
457 return 0;
458 }
459 if (!basis_file || fstat(fileno(basis_file), &st) || !S_ISREG(st.st_mode))
460 goto out;
461
462 sig_file = open_temp_file(tmpfname, prefixsubst(filename));
463 if (!sig_file)
464 goto out;
465 if (unlink(tmpfname) < 0)
466 goto out;
467
468 csync_debug(3, "Running rs_sig_file() from librsync....\n");
469 /* see upstream
470 * https://github.com/librsync/librsync/commit/152323729ac831727032daf50a10c1448b48f252
471 * as reaction to SECURITY: CVE-2014-8242
472 */
473 #ifdef RS_DEFAULT_STRONG_LEN
474 result = rs_sig_file(basis_file, sig_file, RS_DEFAULT_BLOCK_LEN, RS_DEFAULT_STRONG_LEN, &stats);
475 #else
476 /* For backward compatibility, for now hardcode RS_MD4_SIG_MAGIC.
477 * TODO: allow changing to RS_BLAKE2_SIG_MAGIC. */
478 result = rs_sig_file(basis_file, sig_file, RS_DEFAULT_BLOCK_LEN, 0, RS_MD4_SIG_MAGIC, &stats);
479 #endif
480 *sig_file_out = sig_file;
481 sig_file = NULL;
482 if (result != RS_DONE)
483 csync_debug(0, "Internal error from rsync library!\n");
484 else
485 r = 0;
486 out:
487 if (basis_file)
488 fclose(basis_file);
489 if (sig_file)
490 fclose(sig_file);
491 return r;
492 }
493
csync_rs_check(const char * filename,int isreg)494 int csync_rs_check(const char *filename, int isreg)
495 {
496 FILE *sig_file = 0;
497 char buffer1[512], buffer2[512];
498 int rc, chunk, found_diff = 0;
499 int backup_errno;
500 long size;
501 long my_size = 0;
502
503 csync_debug(3, "Csync2 / Librsync: csync_rs_check('%s', %d [%s])\n",
504 filename, isreg, isreg ? "regular file" : "non-regular file");
505
506 csync_debug(3, "Reading signature size from peer....\n");
507 if (!conn_gets(buffer1, 100) || sscanf(buffer1, "octet-stream %ld\n", &size) != 1)
508 csync_fatal("Format-error while receiving data.\n");
509
510 if (size < 0) {
511 errno = EIO;
512 goto io_error;
513 }
514
515 csync_debug(3, "Receiving %ld bytes ..\n", size);
516
517 if (isreg) {
518 if (csync_rs_sigfile(filename, &sig_file)) {
519 if (!sig_file)
520 goto io_error;
521 goto error;
522 }
523 if (sig_file) {
524 fflush(sig_file);
525 my_size = ftell(sig_file);
526 rewind(sig_file);
527 }
528 }
529
530 if (size != my_size) {
531 csync_debug(2, "Signature size differs: local=%d, peer=%d\n", my_size, size);
532 found_diff = 1;
533 }
534
535 while (size > 0) {
536 chunk = size > 512 ? 512 : size;
537 rc = conn_read(buffer1, chunk);
538
539 if (rc <= 0)
540 csync_fatal("Read-error while receiving data.\n");
541 chunk = rc;
542
543 if (sig_file) {
544 if (fread(buffer2, chunk, 1, sig_file) != 1) {
545 csync_debug(2, "Found EOF in local sig file.\n");
546 found_diff = 1;
547 }
548 if (memcmp(buffer1, buffer2, chunk)) {
549 csync_debug(2, "Found diff in sig at -%d:-%d\n", size, size - chunk);
550 found_diff = 1;
551 }
552 } /* else just drain */
553
554 size -= chunk;
555 csync_debug(3, "Got %d bytes, %ld bytes left ..\n", chunk, size);
556 }
557
558 csync_debug(3, "File has been checked successfully (%s).\n", found_diff ? "difference found" : "files are equal");
559 if (sig_file)
560 fclose(sig_file);
561 return found_diff;
562
563 io_error:
564 csync_debug(0, "I/O Error '%s' in rsync-check: %s\n", strerror(errno), prefixsubst(filename));
565 error:
566 backup_errno = errno;
567
568 /* drain response */
569 while (size > 0) {
570 chunk = size > 512 ? 512 : size;
571 rc = conn_read(buffer1, chunk);
572 if (rc <= 0)
573 csync_fatal("Read-error while receiving data.\n");
574 size -= rc;
575 }
576
577 if (sig_file)
578 fclose(sig_file);
579 errno = backup_errno;
580 return -1;
581 }
582
csync_rs_sig(const char * filename)583 void csync_rs_sig(const char *filename)
584 {
585 FILE *sig_file;
586
587 csync_debug(3, "Csync2 / Librsync: csync_rs_sig('%s')\n", filename);
588
589 if (csync_rs_sigfile(filename, &sig_file)) {
590 /* error */
591 if (sig_file)
592 csync_fatal("Got an error from librsync, too bad!\n");
593 csync_debug(0, "I/O Error '%s' in rsync-sig: %s\n",
594 strerror(errno), prefixsubst(filename));
595
596 /* FIXME.
597 * Peer expected some sort of sig,
598 * we need to communicate an error instead. */
599 conn_printf("octet-stream -1\n");
600 return;
601 }
602
603 /* no error */
604 csync_debug(3, "Sending sig_file to peer..\n");
605 if (sig_file) {
606 csync_send_file(sig_file);
607 fclose(sig_file);
608 } else {
609 /* This is the signature for an "empty" file
610 * as returned by rs_sig_file(/dev/null).
611 * No point in re-calculating it over and over again. */
612 conn_printf("octet-stream 12\n");
613 conn_write("rs\0016\000\000\010\000\000\000\000\010", 12);
614 }
615 csync_debug(3, "Signature has been successfully sent.\n");
616 }
617
618
619
csync_rs_delta(const char * filename)620 int csync_rs_delta(const char *filename)
621 {
622 FILE *sig_file = 0, *new_file = 0, *delta_file = 0;
623 rs_result result;
624 rs_signature_t *sumset;
625 rs_stats_t stats;
626 char tmpfname[MAXPATHLEN];
627
628 csync_debug(3, "Csync2 / Librsync: csync_rs_delta('%s')\n", filename);
629
630 csync_debug(3, "Receiving sig_file from peer..\n");
631 sig_file = open_temp_file(tmpfname, prefixsubst(filename));
632 if ( !sig_file ) goto io_error;
633 if (unlink(tmpfname) < 0) goto io_error;
634
635 if ( csync_recv_file(sig_file) ) {
636 fclose(sig_file);
637 return -1;
638 }
639 result = rs_loadsig_file(sig_file, &sumset, &stats);
640 if (result != RS_DONE)
641 csync_fatal("Got an error from librsync, too bad!\n");
642 fclose(sig_file);
643
644 csync_debug(3, "Opening new_file and delta_file..\n");
645 new_file = fopen(prefixsubst(filename), "rb");
646 if ( !new_file ) {
647 int backup_errno = errno;
648 const char *errstr = strerror(errno);
649 csync_debug(0, "I/O Error '%s' while %s in rsync-delta: %s\n",
650 errstr, "opening data file for reading", filename);
651 conn_printf("%s\n", errstr);
652 fclose(new_file);
653 errno = backup_errno;
654 return -1;
655 }
656
657 delta_file = open_temp_file(tmpfname, prefixsubst(filename));
658 if ( !delta_file ) goto io_error;
659 if (unlink(tmpfname) < 0) goto io_error;
660
661 csync_debug(3, "Running rs_build_hash_table() from librsync..\n");
662 result = rs_build_hash_table(sumset);
663 if (result != RS_DONE)
664 csync_fatal("Got an error from librsync, too bad!\n");
665
666 csync_debug(3, "Running rs_delta_file() from librsync..\n");
667 result = rs_delta_file(sumset, new_file, delta_file, &stats);
668 if (result != RS_DONE)
669 csync_fatal("Got an error from librsync, too bad!\n");
670
671 csync_debug(3, "Sending delta_file to peer..\n");
672 csync_send_file(delta_file);
673
674 csync_debug(3, "Delta has been created successfully.\n");
675 rs_free_sumset(sumset);
676 fclose(delta_file);
677 fclose(new_file);
678
679 return 0;
680
681 io_error:
682 csync_debug(0, "I/O Error '%s' in rsync-delta: %s\n",
683 strerror(errno), prefixsubst(filename));
684
685 if (new_file) fclose(new_file);
686 if (delta_file) fclose(delta_file);
687 if (sig_file) fclose(sig_file);
688
689 return -1;
690 }
691
csync_rs_patch(const char * filename)692 int csync_rs_patch(const char *filename)
693 {
694 FILE *basis_file = 0, *delta_file = 0, *new_file = 0;
695 int backup_errno;
696 rs_stats_t stats;
697 rs_result result;
698 char *errstr = "?";
699 char tmpfname[MAXPATHLEN], newfname[MAXPATHLEN];
700
701 csync_debug(3, "Csync2 / Librsync: csync_rs_patch('%s')\n", filename);
702
703 csync_debug(3, "Receiving delta_file from peer..\n");
704 delta_file = open_temp_file(tmpfname, prefixsubst(filename));
705 if ( !delta_file ) { errstr="creating delta temp file"; goto io_error; }
706 if (unlink(tmpfname) < 0) { errstr="removing delta temp file"; goto io_error; }
707 if ( csync_recv_file(delta_file) ) goto error;
708
709 csync_debug(3, "Opening to be patched file on local host..\n");
710 basis_file = fopen(prefixsubst(filename), "rb");
711 if ( !basis_file ) {
712 basis_file = open_temp_file(tmpfname, prefixsubst(filename));
713 if ( !basis_file ) { errstr="opening data file for reading"; goto io_error; }
714 if (unlink(tmpfname) < 0) { errstr="removing data temp file"; goto io_error; }
715 }
716
717 csync_debug(3, "Opening temp file for new data on local host..\n");
718 new_file = open_temp_file(newfname, prefixsubst(filename));
719 if ( !new_file ) { errstr="creating new data temp file"; goto io_error; }
720
721 csync_debug(3, "Running rs_patch_file() from librsync..\n");
722 result = rs_patch_file(basis_file, delta_file, new_file, &stats);
723 if (result != RS_DONE) {
724 csync_debug(0, "Internal error from rsync library!\n");
725 goto error;
726 }
727
728 csync_debug(3, "Renaming tmp file to data file..\n");
729 fclose(basis_file);
730 basis_file = NULL;
731
732 #ifdef __CYGWIN__
733
734 /* TODO: needed? */
735 // This creates the file using the native windows API, bypassing
736 // the cygwin wrappers and so making sure that we do not mess up the
737 // permissions..
738 {
739 char winfilename[MAX_PATH];
740 HANDLE winfh;
741
742 cygwin_conv_to_win32_path(prefixsubst(filename), winfilename);
743
744 winfh = CreateFile(TEXT(winfilename),
745 GENERIC_WRITE, // open for writing
746 0, // do not share
747 NULL, // default security
748 CREATE_ALWAYS, // overwrite existing
749 FILE_ATTRIBUTE_NORMAL | // normal file
750 FILE_FLAG_OVERLAPPED, // asynchronous I/O
751 NULL); // no attr. template
752
753 if (winfh == INVALID_HANDLE_VALUE) {
754 csync_debug(0, "Win32 I/O Error %d in rsync-patch: %s\n",
755 (int)GetLastError(), winfilename);
756 errno = EACCES;
757 goto error;
758 }
759 CloseHandle(winfh);
760 goto copy;
761 }
762 #endif
763
764 if (rename(newfname, prefixsubst(filename))) {
765 char buffer[512];
766 int rc;
767
768 if (errno != EXDEV) {
769 errstr="renaming tmp file to to be patched file";
770 goto io_error;
771 }
772 #ifdef __CYGWIN__
773 copy:
774 #endif
775 csync_debug(1, "rename not possible! Will truncate and copy instead.\n");
776 basis_file = fopen(prefixsubst(filename), "wb");
777 if ( !basis_file ) {
778 errstr="opening data file for writing";
779 goto io_error;
780 }
781
782 /* FIXME
783 * Can easily lead to partially transfered files on the receiving side!
784 * Think truncate, then connection loss.
785 * Or any other failure scenario.
786 * Need better error checks!
787 */
788 rewind(new_file);
789 while ( (rc = fread(buffer, 1, 512, new_file)) > 0
790 && fwrite(buffer, rc, 1, basis_file) == rc )
791 ;
792 /* at least retain the temp file, if something went wrong. */
793 if (ferror(new_file) || ferror(basis_file)) {
794 csync_debug(0, "ERROR while copying temp file '%s' to basis file '%s'; "
795 "basis file may be corrupted; temp file has been retained.\n",
796 newfname, prefixsubst(filename));
797 goto error;
798 }
799 unlink(newfname);
800 fclose(basis_file);
801 basis_file = NULL;
802 }
803
804 csync_debug(3, "File has been patched successfully.\n");
805 fclose(delta_file);
806 fclose(new_file);
807
808 return 0;
809
810 io_error:
811 backup_errno = errno;
812 csync_debug(0, "I/O Error '%s' while %s in rsync-patch: %s\n",
813 strerror(errno), errstr, prefixsubst(filename));
814 errno = backup_errno;
815 error:;
816 backup_errno = errno;
817 if ( delta_file ) fclose(delta_file);
818 if ( basis_file ) fclose(basis_file);
819 if ( new_file ) fclose(new_file);
820 errno = backup_errno;
821 return -1;
822 }
823
824