From 5884e1434a066ea923190f49ac0e263657550708 Mon Sep 17 00:00:00 2001 From: Shota Osepashvili Date: Wed, 28 Jul 2021 02:00:54 -0400 Subject: [PATCH 01/17] Add hostname guessing feature in simple mode --- csync2.c | 48 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 48 insertions(+) diff --git a/csync2.c b/csync2.c index 8eac868..23c727c 100644 --- a/csync2.c +++ b/csync2.c @@ -684,9 +684,57 @@ int main(int argc, char ** argv) if (!csync_database || !csync_database[0] || csync_database[0] == '/') csync_database = db_default_database(csync_database); + + + // If local hostname is not set, try to guess it by getting the addrinfo of every hostname in the + // group and try to bind on that address. If bind is successful set that host as local hostname. + { + struct csync_group *g; + struct csync_group_host *h; + struct csync_group_host *prev = 0; + struct addrinfo *rp, *result; + int sfd; + int bind_status; + + for (g=csync_group; g; g=g->next) { + if ( !g->myname ) { + h = g->host; + while(h && !g->myname) { + getaddrinfo(h->hostname, NULL, NULL, &result); + for (rp = result; rp != NULL; rp = rp->ai_next) { + sfd = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol); + if (sfd == -1) + continue; + bind_status = bind(sfd, rp->ai_addr, rp->ai_addrlen); + close(sfd); + + if (bind_status == 0) { + g->myname = h->hostname; + snprintf(myhostname, 256, "%s", h->hostname); + g->local_slave = h->slave; + + if (!prev) { + g->host = h->next; + } else { + prev->next = h->next; + } + free(h); + csync_debug(1, "My hostname guessed as: %s\n", g->myname); + break; + } + } + freeaddrinfo(result); + prev = h; + h = h->next; + } + } + } + } + csync_debug(2, "My hostname is %s.\n", myhostname); csync_debug(2, "Database-File: %s\n", csync_database); + { const struct csync_group *g; for (g=csync_group; g; g=g->next) From eb371be7a78fa0b31e7b82b98ba7d39133fe009e Mon Sep 17 00:00:00 2001 From: Shota Osepashvili Date: Wed, 28 Jul 2021 02:29:00 -0400 Subject: [PATCH 02/17] Add atomicpatch command to the protocol --- csync2.h | 2 +- daemon.c | 79 +++++++++++++++++++++++++++++++++++++------------------- rsync.c | 27 +++++++++++++++---- update.c | 50 +++++++++++++++++++++-------------- 4 files changed, 107 insertions(+), 51 deletions(-) diff --git a/csync2.h b/csync2.h index 840565e..9baee4b 100644 --- a/csync2.h +++ b/csync2.h @@ -233,7 +233,7 @@ extern int db_sync_mode; extern int csync_rs_check(const char *filename, int isreg); extern void csync_rs_sig(const char *filename); extern int csync_rs_delta(const char *filename); -extern int csync_rs_patch(const char *filename); +extern int csync_rs_patch(const char *filename, struct stat *atomic_stats); extern int mkpath(const char *path, mode_t mode); extern void split_dirname_basename(char *dirname, char* basename, const char *filepath); diff --git a/daemon.c b/daemon.c index 7fb53bb..7683a07 100644 --- a/daemon.c +++ b/daemon.c @@ -290,38 +290,39 @@ struct csync_command { }; enum { - A_SIG, A_FLUSH, A_MARK, A_TYPE, A_GETTM, A_GETSZ, A_DEL, A_PATCH, - A_MKDIR, A_MKCHR, A_MKBLK, A_MKFIFO, A_MKLINK, A_MKSOCK, + A_SIG, A_FLUSH, A_MARK, A_TYPE, A_GETTM, A_GETSZ, A_DEL, A_ATOMIC, + A_PATCH, A_MKDIR, A_MKCHR, A_MKBLK, A_MKFIFO, A_MKLINK, A_MKSOCK, A_SETOWN, A_SETMOD, A_SETIME, A_LIST, A_GROUP, A_DEBUG, A_HELLO, A_BYE }; struct csync_command cmdtab[] = { - { "sig", 1, 0, 0, 0, 1, A_SIG }, - { "mark", 1, 0, 0, 0, 1, A_MARK }, - { "type", 2, 0, 0, 0, 1, A_TYPE }, - { "gettm", 1, 0, 0, 0, 1, A_GETTM }, - { "getsz", 1, 0, 0, 0, 1, A_GETSZ }, - { "flush", 1, 1, 0, 0, 1, A_FLUSH }, - { "del", 1, 1, 0, 1, 1, A_DEL }, - { "patch", 1, 1, 2, 1, 1, A_PATCH }, - { "mkdir", 1, 1, 1, 1, 1, A_MKDIR }, - { "mkchr", 1, 1, 1, 1, 1, A_MKCHR }, - { "mkblk", 1, 1, 1, 1, 1, A_MKBLK }, - { "mkfifo", 1, 1, 1, 1, 1, A_MKFIFO }, - { "mklink", 1, 1, 1, 1, 1, A_MKLINK }, - { "mksock", 1, 1, 1, 1, 1, A_MKSOCK }, - { "setown", 1, 1, 0, 2, 1, A_SETOWN }, - { "setmod", 1, 1, 0, 2, 1, A_SETMOD }, - { "setime", 1, 0, 0, 2, 1, A_SETIME }, - { "list", 0, 0, 0, 0, 1, A_LIST }, + { "sig", 1, 0, 0, 0, 1, A_SIG }, + { "mark" 1, 0, 0, 0, 1, A_MARK }, + { "type" 2, 0, 0, 0, 1, A_TYPE }, + { "gettm" 1, 0, 0, 0, 1, A_GETTM }, + { "getsz" 1, 0, 0, 0, 1, A_GETSZ }, + { "flush" 1, 1, 0, 0, 1, A_FLUSH }, + { "del", 1, 1, 0, 1, 1, A_DEL }, + { "atomicpatch", 1, 1, 2, 1, 1, A_ATOMIC }, + { "patch", 1, 1, 2, 1, 1, A_PATCH }, + { "mkdir", 1, 1, 1, 1, 1, A_MKDIR }, + { "mkchr", 1, 1, 1, 1, 1, A_MKCHR }, + { "mkblk", 1, 1, 1, 1, 1, A_MKBLK }, + { "mkfifo", 1, 1, 1, 1, 1, A_MKFIFO }, + { "mklink", 1, 1, 1, 1, 1, A_MKLINK }, + { "mksock", 1, 1, 1, 1, 1, A_MKSOCK }, + { "setown", 1, 1, 0, 2, 1, A_SETOWN }, + { "setmod", 1, 1, 0, 2, 1, A_SETMOD }, + { "setime", 1, 0, 0, 2, 1, A_SETIME }, + { "list", 0, 0, 0, 0, 1, A_LIST }, #if 0 - { "debug", 0, 0, 0, 0, 1, A_DEBUG }, + { "debug", 0, 0, 0, 0, 1, A_DEBUG }, #endif - { "group", 0, 0, 0, 0, 0, A_GROUP }, - { "hello", 0, 0, 0, 0, 0, A_HELLO }, - { "bye", 0, 0, 0, 0, 0, A_BYE }, - { 0, 0, 0, 0, 0, 0, 0 } + { "group", 0, 0, 0, 0, 0, A_GROUP }, + { "hello", 0, 0, 0, 0, 0, A_HELLO }, + { "bye", 0, 0, 0, 0, 0, A_BYE }, + { 0, 0, 0, 0, 0, 0, 0 } }; typedef union address { @@ -481,6 +482,7 @@ void csync_daemon_session() socklen_t peerlen = sizeof(peername); char *peer=0, *tag[32]; int i; + struct stat atomic_stats; if (fstat(0, &sb)) @@ -506,9 +508,17 @@ void csync_daemon_session() if (!setup_tag(tag, line)) continue; + for (cmdnr=0; cmdtab[cmdnr].text; cmdnr++) if ( !strcasecmp(cmdtab[cmdnr].text, tag[0]) ) break; + // Print command and it's arguments fully + csync_debug(1, "START COMMAND -> %s\n", tag[0]); + for (int i = 1; i < 32; i++){ + csync_debug(1, "[Arg %d] -> %s\n", i, tag[i]); + } + csync_debug(1, "FINISH COMMAND -> %s\n", tag[0]); + if ( !cmdtab[cmdnr].text ) { cmd_error = conn_response(CR_ERR_UNKNOWN_COMMAND); goto abort_cmd; @@ -628,11 +638,28 @@ void csync_daemon_session() if (!csync_file_backup(tag[2])) csync_unlink(tag[2], 0); break; + case A_ATOMIC: + if (!csync_file_backup(tag[2])) { + conn_resp(CR_OK_SEND_DATA); + csync_rs_sig(tag[2]); + + memset(&atomic_stats, 0, sizeof(atomic_stats)); + atomic_stats.st_uid = atoll(tag[3]); + atomic_stats.st_gid = atoll(tag[4]); + atomic_stats.st_mode = atoll(tag[5]); + atomic_stats.st_mtime = atoll(tag[6]); + + + if (csync_rs_patch(tag[2], &atomic_stats)) + cmd_error = strerror(errno); + } + break; case A_PATCH: if (!csync_file_backup(tag[2])) { conn_resp(CR_OK_SEND_DATA); csync_rs_sig(tag[2]); - if (csync_rs_patch(tag[2])) + + if (csync_rs_patch(tag[2], NULL)) cmd_error = strerror(errno); } break; diff --git a/rsync.c b/rsync.c index 8317274..1659f59 100644 --- a/rsync.c +++ b/rsync.c @@ -22,6 +22,7 @@ #include #include #include +#include #include #include @@ -704,12 +705,18 @@ int csync_rs_delta(const char *filename) * mtime, ACLs and other meta data as context information before starting to * act on it on the receiving side, I don't see how. */ -static void clone_ownership_and_permissions(const char *newfname, const char *oldfname) +static void clone_ownership_and_permissions(const char *newfname, const char *oldfname, struct stat *atomic_stats) { struct stat sbuf; int uid, gid; - if (stat(oldfname, &sbuf)) - return; /* At least we tried */ + + if (atomic_stats) { + sbuf = *atomic_stats; + } else { + if (stat(oldfname, &sbuf)) + return; /* At least we tried */ + } + uid = csync_ignore_uid ? -1 : sbuf.st_uid; gid = csync_ignore_gid ? -1 : sbuf.st_gid; csync_debug(3, "Cloning ownership and permissions to tmp file: 0o%03o %d:%d %s [%s]\n", @@ -725,7 +732,7 @@ static void clone_ownership_and_permissions(const char *newfname, const char *ol * as long as csync2 is no acl aware, there is no point, though */ } -int csync_rs_patch(const char *filename) +int csync_rs_patch(const char *filename, struct stat *atomic_stats) { FILE *basis_file = 0, *delta_file = 0, *new_file = 0; int backup_errno; @@ -797,7 +804,17 @@ int csync_rs_patch(const char *filename) } #endif - clone_ownership_and_permissions(newfname, prefixsubst(filename)); + clone_ownership_and_permissions(newfname, prefixsubst(filename), atomic_stats); + + // Set modification time + if (atomic_stats) { + struct utimbuf utb; + utb.actime = atomic_stats->st_mtime; + utb.modtime = atomic_stats->st_mtime; + if ( utime(newfname, &utb) ) + csync_debug(1, "Could not change the modification date\n"); + + } if (rename(newfname, prefixsubst(filename))) { char buffer[512]; diff --git a/update.c b/update.c index 306a5de..022ddcd 100644 --- a/update.c +++ b/update.c @@ -297,6 +297,7 @@ void csync_update_file_del(const char *peername, enum connection_response csync_update_file_mod(const char *peername, const char *filename, int force, int dry_run) { + int atomic_update = 1; struct stat st; enum connection_response last_conn_status = CR_ERROR; int auto_resolve_run = 0; @@ -378,8 +379,16 @@ enum connection_response csync_update_file_mod(const char *peername, } if ( S_ISREG(st.st_mode) ) { - conn_printf("PATCH %s %s\n", - url_encode(key), url_encode(filename)); + if (atomic_update) { + conn_printf("ATOMICPATCH %s %s %d %d %d %d\n", + url_encode(key), url_encode(filename), + st.st_uid, st.st_gid, + st.st_mode, + (long long)st.st_mtime); + } else { + conn_printf("PATCH %s %s\n", + url_encode(key), url_encode(filename)); + } last_conn_status = read_conn_status(filename, peername); /* FIXME be more specific? * (last_conn_status != CR_OK_SEND_DATA) ?? @@ -452,29 +461,32 @@ enum connection_response csync_update_file_mod(const char *peername, goto got_error; } - conn_printf("SETOWN %s %s %d %d\n", - url_encode(key), url_encode(filename), - st.st_uid, st.st_gid); - last_conn_status = read_conn_status(filename, peername); - if (!is_ok_response(last_conn_status)) - goto got_error; + if (!atomic_update) { - if ( !S_ISLNK(st.st_mode) ) { - conn_printf("SETMOD %s %s %d\n", url_encode(key), - url_encode(filename), st.st_mode); + conn_printf("SETOWN %s %s %d %d\n", + url_encode(key), url_encode(filename), + st.st_uid, st.st_gid); last_conn_status = read_conn_status(filename, peername); if (!is_ok_response(last_conn_status)) goto got_error; - } + + if ( !S_ISLNK(st.st_mode) ) { + conn_printf("SETMOD %s %s %d\n", url_encode(key), + url_encode(filename), st.st_mode); + last_conn_status = read_conn_status(filename, peername); + if (!is_ok_response(last_conn_status)) + goto got_error; + } skip_action: - if ( !S_ISLNK(st.st_mode) ) { - conn_printf("SETIME %s %s %lld\n", - url_encode(key), url_encode(filename), - (long long)st.st_mtime); - last_conn_status = read_conn_status(filename, peername); - if (!is_ok_response(last_conn_status)) - goto got_error; + if ( !S_ISLNK(st.st_mode) ) { + conn_printf("SETIME %s %s %lld\n", + url_encode(key), url_encode(filename), + (long long)st.st_mtime); + last_conn_status = read_conn_status(filename, peername); + if (!is_ok_response(last_conn_status)) + goto got_error; + } } SQL("Remove dirty-file entry.", From cb2aaf11ed709f052071aaa2e9d8a74c5f7aa54f Mon Sep 17 00:00:00 2001 From: Shota Osepashvili Date: Wed, 28 Jul 2021 02:38:29 -0400 Subject: [PATCH 03/17] Fix missing commas in struct --- .gitignore | 108 +++++++++++++++++++++++++++++++++++++++++++++++++++++ daemon.c | 10 ++--- 2 files changed, 113 insertions(+), 5 deletions(-) create mode 100644 .gitignore diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..e486ca2 --- /dev/null +++ b/.gitignore @@ -0,0 +1,108 @@ +# http://www.gnu.org/software/automake + +Makefile.in +/ar-lib +/mdate-sh +/py-compile +/test-driver +/ylwrap +.deps/ +.dirstamp + +# http://www.gnu.org/software/autoconf + +autom4te.cache +/autoscan.log +/autoscan-*.log +/aclocal.m4 +/compile +/config.cache +/config.guess +/config.h.in +/config.log +/config.status +/config.sub +/configure +/configure.scan +/depcomp +/install-sh +/missing +/stamp-h1 + +# https://www.gnu.org/software/libtool/ + +/ltmain.sh + +# http://www.gnu.org/software/texinfo + +/texinfo.tex + +# http://www.gnu.org/software/m4/ + +m4/libtool.m4 +m4/ltoptions.m4 +m4/ltsugar.m4 +m4/ltversion.m4 +m4/lt~obsolete.m4 + +# Generated Makefile +# (meta build system like autotools, +# can automatically generate from config.status script +# (which is called by configure script)) +Makefile + + +# Prerequisites +*.d + +# Object files +*.o +*.ko +*.obj +*.elf + +# Linker output +*.ilk +*.map +*.exp + +# Precompiled Headers +*.gch +*.pch + +# Libraries +*.lib +*.a +*.la +*.lo + +# Shared objects (inc. Windows DLLs) +*.dll +*.so +*.so.* +*.dylib + +# Executables +*.exe +*.out +*.app +*.i*86 +*.x86_64 +*.hex + +# Debug files +*.dSYM/ +*.su +*.idb +*.pdb + +# Kernel Module Compile Results +*.mod* +*.cmd +.tmp_versions/ +modules.order +Module.symvers +Mkfile.old +dkms.conf + +*.swp diff --git a/daemon.c b/daemon.c index 7683a07..5fe2809 100644 --- a/daemon.c +++ b/daemon.c @@ -298,11 +298,11 @@ enum { struct csync_command cmdtab[] = { { "sig", 1, 0, 0, 0, 1, A_SIG }, - { "mark" 1, 0, 0, 0, 1, A_MARK }, - { "type" 2, 0, 0, 0, 1, A_TYPE }, - { "gettm" 1, 0, 0, 0, 1, A_GETTM }, - { "getsz" 1, 0, 0, 0, 1, A_GETSZ }, - { "flush" 1, 1, 0, 0, 1, A_FLUSH }, + { "mark", 1, 0, 0, 0, 1, A_MARK }, + { "type", 2, 0, 0, 0, 1, A_TYPE }, + { "gettm", 1, 0, 0, 0, 1, A_GETTM }, + { "getsz", 1, 0, 0, 0, 1, A_GETSZ }, + { "flush", 1, 1, 0, 0, 1, A_FLUSH }, { "del", 1, 1, 0, 1, 1, A_DEL }, { "atomicpatch", 1, 1, 2, 1, 1, A_ATOMIC }, { "patch", 1, 1, 2, 1, 1, A_PATCH }, From df46ed99a968ebf20a0776f00b15ae5167fe6dde Mon Sep 17 00:00:00 2001 From: Shota Osepashvili Date: Wed, 28 Jul 2021 02:48:22 -0400 Subject: [PATCH 04/17] Add -a flag to activate atomicpatch --- csync2.c | 6 +++++- csync2.h | 1 + update.c | 5 ++--- 3 files changed, 8 insertions(+), 4 deletions(-) diff --git a/csync2.c b/csync2.c index 23c727c..d267cf8 100644 --- a/csync2.c +++ b/csync2.c @@ -67,6 +67,7 @@ int csync_error_count = 0; int csync_debug_level = 0; FILE *csync_debug_out = 0; int csync_syslog = 0; +int csync_atomic_patch = 0; int csync_server_child_pid = 0; int csync_timestamps = 0; @@ -436,7 +437,7 @@ int main(int argc, char ** argv) return 1; } - while ( (opt = getopt(argc, argv, "W:s:Ftp:G:P:C:D:N:HBAIXULlSTMRvhcuoimfxrd")) != -1 ) { + while ( (opt = getopt(argc, argv, "W:s:Ftp:G:P:C:D:N:HBAIXULlSTMRavhcuoimfxrd")) != -1 ) { switch (opt) { case 'W': @@ -463,6 +464,9 @@ int main(int argc, char ** argv) case 'G': active_grouplist = optarg; break; + case 'a': + csync_atomic_patch = 1; + break; case 'P': active_peerlist = optarg; break; diff --git a/csync2.h b/csync2.h index 9baee4b..d7cf212 100644 --- a/csync2.h +++ b/csync2.h @@ -435,6 +435,7 @@ extern int csync_messages_printed; extern int csync_server_child_pid; extern int csync_timestamps; extern int csync_new_force; +extern int csync_atomic_patch; extern char myhostname[]; extern int bind_to_myhostname; diff --git a/update.c b/update.c index 022ddcd..731da01 100644 --- a/update.c +++ b/update.c @@ -297,7 +297,6 @@ void csync_update_file_del(const char *peername, enum connection_response csync_update_file_mod(const char *peername, const char *filename, int force, int dry_run) { - int atomic_update = 1; struct stat st; enum connection_response last_conn_status = CR_ERROR; int auto_resolve_run = 0; @@ -379,7 +378,7 @@ enum connection_response csync_update_file_mod(const char *peername, } if ( S_ISREG(st.st_mode) ) { - if (atomic_update) { + if (csync_atomic_patch) { conn_printf("ATOMICPATCH %s %s %d %d %d %d\n", url_encode(key), url_encode(filename), st.st_uid, st.st_gid, @@ -461,7 +460,7 @@ enum connection_response csync_update_file_mod(const char *peername, goto got_error; } - if (!atomic_update) { + if (!csync_atomic_patch) { conn_printf("SETOWN %s %s %d %d\n", url_encode(key), url_encode(filename), From 3c2aa4d6c5b89e89eeaa6961669810abdea6095c Mon Sep 17 00:00:00 2001 From: Shota Osepashvili Date: Wed, 28 Jul 2021 02:52:54 -0400 Subject: [PATCH 05/17] Fix command argument printing to only include existent arguments --- .gitignore | 7 +++++++ daemon.c | 5 ++++- 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index e486ca2..3cf96ec 100644 --- a/.gitignore +++ b/.gitignore @@ -105,4 +105,11 @@ Module.symvers Mkfile.old dkms.conf +# Project specific *.swp +*.swo +cfgfile_parser.c +cfgfile_parser.h +cfgfile_scanner.c +config.h +csync2 diff --git a/daemon.c b/daemon.c index 5fe2809..0fe8ca3 100644 --- a/daemon.c +++ b/daemon.c @@ -512,9 +512,12 @@ void csync_daemon_session() for (cmdnr=0; cmdtab[cmdnr].text; cmdnr++) if ( !strcasecmp(cmdtab[cmdnr].text, tag[0]) ) break; - // Print command and it's arguments fully + // Print command and its arguments fully csync_debug(1, "START COMMAND -> %s\n", tag[0]); for (int i = 1; i < 32; i++){ + if (!tag[i]) + break; + csync_debug(1, "[Arg %d] -> %s\n", i, tag[i]); } csync_debug(1, "FINISH COMMAND -> %s\n", tag[0]); From 31e4eed4d15bf3fd139eb7010dd4bffdfba45006 Mon Sep 17 00:00:00 2001 From: Shota Osepashvili Date: Wed, 28 Jul 2021 03:00:16 -0400 Subject: [PATCH 06/17] Fix bug in command argument printing to check for empty, not NULL, string --- daemon.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/daemon.c b/daemon.c index 0fe8ca3..105f75e 100644 --- a/daemon.c +++ b/daemon.c @@ -515,7 +515,7 @@ void csync_daemon_session() // Print command and its arguments fully csync_debug(1, "START COMMAND -> %s\n", tag[0]); for (int i = 1; i < 32; i++){ - if (!tag[i]) + if (!(*tag[i])) break; csync_debug(1, "[Arg %d] -> %s\n", i, tag[i]); From dc6a89a9c90d49ad3d426160448d287555a0633a Mon Sep 17 00:00:00 2001 From: Shota Osepashvili Date: Wed, 28 Jul 2021 05:08:41 -0400 Subject: [PATCH 07/17] Add conformance to gnu90 std --- daemon.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/daemon.c b/daemon.c index 105f75e..f5a6f77 100644 --- a/daemon.c +++ b/daemon.c @@ -514,7 +514,7 @@ void csync_daemon_session() // Print command and its arguments fully csync_debug(1, "START COMMAND -> %s\n", tag[0]); - for (int i = 1; i < 32; i++){ + for (i = 1; i < 32; i++){ if (!(*tag[i])) break; From 2d6a28ad0865a1cb8cdedc5e62fcdbc04360403e Mon Sep 17 00:00:00 2001 From: Shota Osepashvili Date: Tue, 3 Aug 2021 00:02:18 -0400 Subject: [PATCH 08/17] Add logging to file --- error.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/error.c b/error.c index 59b654f..dfd7440 100644 --- a/error.c +++ b/error.c @@ -34,6 +34,9 @@ int csync_messages_printed = 0; time_t csync_startup_time = 0; +FILE *full_debug_log = 0; +char *logname = "/tmp/csync2_full_log.log"; + void csync_printtime() { if (csync_timestamps || csync_timestamp_out) @@ -102,6 +105,17 @@ static int csync_log_level_to_sys_log_level(int lv) void csync_vdebug(int lv, const char *fmt, va_list ap) { + va_list debug_file_va; + if (full_debug_log == NULL) { + if((full_debug_log = fopen(logname, "w+")) == NULL) { + fprintf(stderr, "Could not open full log file: %s\n", logname); + exit(1); + } + } + + va_copy(debug_file_va, ap); + vfprintf(full_debug_log, fmt, debug_file_va); + if (csync_debug_level < lv) return; From 6f365589270c7de1c8676ec3af208622e5945582 Mon Sep 17 00:00:00 2001 From: Shota Osepashvili Date: Tue, 24 Aug 2021 14:33:36 -0400 Subject: [PATCH 09/17] Fix the timestamp bug --- rsync.c | 1 + 1 file changed, 1 insertion(+) diff --git a/rsync.c b/rsync.c index 1659f59..b4b948e 100644 --- a/rsync.c +++ b/rsync.c @@ -807,6 +807,7 @@ int csync_rs_patch(const char *filename, struct stat *atomic_stats) clone_ownership_and_permissions(newfname, prefixsubst(filename), atomic_stats); // Set modification time + fflush(new_file); if (atomic_stats) { struct utimbuf utb; utb.actime = atomic_stats->st_mtime; From e50b975fa4352c1db8ab0a34b305634ca0d015b5 Mon Sep 17 00:00:00 2001 From: Shota Osepashvili Date: Tue, 31 Aug 2021 11:30:42 -0400 Subject: [PATCH 10/17] Remove the debug file --- error.c | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/error.c b/error.c index dfd7440..59b654f 100644 --- a/error.c +++ b/error.c @@ -34,9 +34,6 @@ int csync_messages_printed = 0; time_t csync_startup_time = 0; -FILE *full_debug_log = 0; -char *logname = "/tmp/csync2_full_log.log"; - void csync_printtime() { if (csync_timestamps || csync_timestamp_out) @@ -105,17 +102,6 @@ static int csync_log_level_to_sys_log_level(int lv) void csync_vdebug(int lv, const char *fmt, va_list ap) { - va_list debug_file_va; - if (full_debug_log == NULL) { - if((full_debug_log = fopen(logname, "w+")) == NULL) { - fprintf(stderr, "Could not open full log file: %s\n", logname); - exit(1); - } - } - - va_copy(debug_file_va, ap); - vfprintf(full_debug_log, fmt, debug_file_va); - if (csync_debug_level < lv) return; From f9c1eaa6af0f39d8b8fc44a7a30da1a07dc1885a Mon Sep 17 00:00:00 2001 From: Shota Osepashvili Date: Tue, 31 Aug 2021 12:22:13 -0400 Subject: [PATCH 11/17] Hide debug logging behind -O flag --- csync2.c | 11 ++++++++++- csync2.h | 1 + error.c | 9 +++++++++ 3 files changed, 20 insertions(+), 1 deletion(-) diff --git a/csync2.c b/csync2.c index d267cf8..eb95cea 100644 --- a/csync2.c +++ b/csync2.c @@ -437,7 +437,7 @@ int main(int argc, char ** argv) return 1; } - while ( (opt = getopt(argc, argv, "W:s:Ftp:G:P:C:D:N:HBAIXULlSTMRavhcuoimfxrd")) != -1 ) { + while ( (opt = getopt(argc, argv, "W:s:Ftp:G:P:C:D:N:O::HBAIXULlSTMRavhcuoimfxrd")) != -1 ) { switch (opt) { case 'W': @@ -452,6 +452,15 @@ int main(int argc, char ** argv) csync_fatal("Can't open timestanp file `%s': %s\n", optarg, strerror(errno)); break; + case 'O': + { + char *logname = optarg ? optarg : "/tmp/csync2_full_log.log"; + if((debug_file = fopen(logname, "w+")) == NULL) { + fprintf(stderr, "Could not open full log file: %s\n", logname); + exit(1); + } + } + break; case 'F': csync_new_force = 1; break; diff --git a/csync2.h b/csync2.h index d7cf212..146a0cd 100644 --- a/csync2.h +++ b/csync2.h @@ -78,6 +78,7 @@ extern int csync_perm(const char *filename, const char *key, const char *hostnam /* error.c */ +extern FILE* debug_file; extern void csync_printtime(); extern void csync_printtotaltime(); extern void csync_fatal(const char *fmt, ...); diff --git a/error.c b/error.c index 59b654f..b3dc880 100644 --- a/error.c +++ b/error.c @@ -34,6 +34,8 @@ int csync_messages_printed = 0; time_t csync_startup_time = 0; +FILE *debug_file; + void csync_printtime() { if (csync_timestamps || csync_timestamp_out) @@ -102,6 +104,13 @@ static int csync_log_level_to_sys_log_level(int lv) void csync_vdebug(int lv, const char *fmt, va_list ap) { + + va_list debug_file_va; + if (debug_file) { + va_copy(debug_file_va, ap); + vfprintf(debug_file, fmt, debug_file_va); + } + if (csync_debug_level < lv) return; From 673c3d7687340f3f5c99659b381de961ae269edb Mon Sep 17 00:00:00 2001 From: Shota Osepashvili Date: Sun, 12 Sep 2021 08:51:49 -0400 Subject: [PATCH 12/17] Add nanosecond accuracy to timestamp --- checktxt.c | 7 +++++-- daemon.c | 16 +++++++++++----- rsync.c | 8 ++++---- update.c | 8 +++++--- 4 files changed, 25 insertions(+), 14 deletions(-) diff --git a/checktxt.c b/checktxt.c index 9a522d5..3baf816 100644 --- a/checktxt.c +++ b/checktxt.c @@ -19,6 +19,7 @@ */ #include "csync2.h" +#include #include #include #include @@ -48,8 +49,10 @@ const char *csync_genchecktxt(const struct stat *st, const char *filename, int i /* version 1 of this check text */ xxprintf("v1"); - if ( !S_ISLNK(st->st_mode) && !S_ISDIR(st->st_mode) ) - xxprintf(":mtime=%lld", ign_mtime ? (long long)0 : (long long)st->st_mtime); + if ( !S_ISLNK(st->st_mode) && !S_ISDIR(st->st_mode) ) { + int64_t timestamp = st->st_mtime * 1000000000 + st->st_mtim.tv_nsec; + xxprintf(":mtime=%lld", ign_mtime ? (long long)0 : (long long)timestamp); + } if ( !csync_ignore_mod ) xxprintf(":mode=%d", (int)st->st_mode); diff --git a/daemon.c b/daemon.c index f5a6f77..c1e4645 100644 --- a/daemon.c +++ b/daemon.c @@ -650,7 +650,11 @@ void csync_daemon_session() atomic_stats.st_uid = atoll(tag[3]); atomic_stats.st_gid = atoll(tag[4]); atomic_stats.st_mode = atoll(tag[5]); - atomic_stats.st_mtime = atoll(tag[6]); + long long timestamp = atoll(tag[6]); + struct timespec tsp; + tsp.tv_sec = (int) (timestamp / 1000000000); + tsp.tv_nsec = timestamp % 1000000000; + atomic_stats.st_mtim = tsp; if (csync_rs_patch(tag[2], &atomic_stats)) @@ -732,11 +736,13 @@ void csync_daemon_session() break; case A_SETIME: { - struct utimbuf utb; - utb.actime = atoll(tag[3]); - utb.modtime = atoll(tag[3]); - if ( utime(prefixsubst(tag[2]), &utb) ) + struct timespec tsp[2]; + long long timestamp = atoll(tag[3]); + tsp[0].tv_sec = tsp[1].tv_sec = (int) (timestamp / 1000000000); + tsp[0].tv_nsec = tsp[1].tv_nsec = timestamp % 1000000000; + if(utimensat(0, prefixsubst(tag[2]), tsp, 0)) cmd_error = strerror(errno); + } break; case A_LIST: diff --git a/rsync.c b/rsync.c index b4b948e..8f995e6 100644 --- a/rsync.c +++ b/rsync.c @@ -809,10 +809,10 @@ int csync_rs_patch(const char *filename, struct stat *atomic_stats) // Set modification time fflush(new_file); if (atomic_stats) { - struct utimbuf utb; - utb.actime = atomic_stats->st_mtime; - utb.modtime = atomic_stats->st_mtime; - if ( utime(newfname, &utb) ) + struct timespec tsp[2]; + tsp[0].tv_sec = tsp[1].tv_sec = atomic_stats->st_mtim.tv_sec; + tsp[0].tv_nsec = tsp[1].tv_nsec = atomic_stats->st_mtim.tv_sec; + if(utimensat(0, newfname, tsp, 0)) csync_debug(1, "Could not change the modification date\n"); } diff --git a/update.c b/update.c index 731da01..62ba046 100644 --- a/update.c +++ b/update.c @@ -316,6 +316,8 @@ enum connection_response csync_update_file_mod(const char *peername, goto got_error; } + long long nano_timestamp = st.st_mtime * 1000000000 + st.st_mtim.tv_nsec; + if ( force ) { if ( dry_run ) { printf("!M: %-15s %s\n", peername, filename); @@ -379,11 +381,11 @@ enum connection_response csync_update_file_mod(const char *peername, if ( S_ISREG(st.st_mode) ) { if (csync_atomic_patch) { - conn_printf("ATOMICPATCH %s %s %d %d %d %d\n", + conn_printf("ATOMICPATCH %s %s %d %d %d %lld\n", url_encode(key), url_encode(filename), st.st_uid, st.st_gid, st.st_mode, - (long long)st.st_mtime); + nano_timestamp); } else { conn_printf("PATCH %s %s\n", url_encode(key), url_encode(filename)); @@ -481,7 +483,7 @@ enum connection_response csync_update_file_mod(const char *peername, if ( !S_ISLNK(st.st_mode) ) { conn_printf("SETIME %s %s %lld\n", url_encode(key), url_encode(filename), - (long long)st.st_mtime); + nano_timestamp); last_conn_status = read_conn_status(filename, peername); if (!is_ok_response(last_conn_status)) goto got_error; From e733bca582d868613e1e94d93bb56458f8ea7ce0 Mon Sep 17 00:00:00 2001 From: Shota Osepashvili Date: Sun, 12 Sep 2021 09:24:07 -0400 Subject: [PATCH 13/17] Add skipping dirty marking on non active hosts with -P flag --- check.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/check.c b/check.c index 1477314..f9dc856 100644 --- a/check.c +++ b/check.c @@ -98,7 +98,13 @@ void csync_mark(const char *file, const char *thispeer, const char *peerfilter) } csync_debug(1, "Marking file as dirty: %s\n", file); - for (pl_idx=0; pl[pl_idx].peername; pl_idx++) + for (pl_idx=0; pl[pl_idx].peername; pl_idx++) { + // In case of -P flag, don't mark files as dirty + if (active_peerlist && !strstr(active_peerlist, pl[pl_idx].peername)) { + csync_debug(1, "Not marking host %s as dirty because -P flag was specified\n", pl[pl_idx].peername); + continue; + } + if (!peerfilter || !strcmp(peerfilter, pl[pl_idx].peername)) { SQL("Deleting old dirty file entries", "DELETE FROM dirty WHERE filename = '%s' AND peername = '%s'", @@ -113,6 +119,7 @@ void csync_mark(const char *file, const char *thispeer, const char *peerfilter) url_encode(pl[pl_idx].myname), url_encode(pl[pl_idx].peername)); } + } free(pl); } From e4ac6d2035ccfea6ee025160e079bc08722588c9 Mon Sep 17 00:00:00 2001 From: Shota Osepashvili Date: Wed, 15 Sep 2021 02:15:35 -0400 Subject: [PATCH 14/17] Fix the nanosecond timestamp related bug --- rsync.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rsync.c b/rsync.c index 8f995e6..e985254 100644 --- a/rsync.c +++ b/rsync.c @@ -811,7 +811,7 @@ int csync_rs_patch(const char *filename, struct stat *atomic_stats) if (atomic_stats) { struct timespec tsp[2]; tsp[0].tv_sec = tsp[1].tv_sec = atomic_stats->st_mtim.tv_sec; - tsp[0].tv_nsec = tsp[1].tv_nsec = atomic_stats->st_mtim.tv_sec; + tsp[0].tv_nsec = tsp[1].tv_nsec = atomic_stats->st_mtim.tv_nsec; if(utimensat(0, newfname, tsp, 0)) csync_debug(1, "Could not change the modification date\n"); From 4893e275a85618f04917044857c016f4246d4ce1 Mon Sep 17 00:00:00 2001 From: Shota Osepashvili Date: Mon, 4 Oct 2021 02:14:37 -0400 Subject: [PATCH 15/17] Fix Directory timestamp sync --- update.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/update.c b/update.c index 62ba046..faa2858 100644 --- a/update.c +++ b/update.c @@ -462,7 +462,7 @@ enum connection_response csync_update_file_mod(const char *peername, goto got_error; } - if (!csync_atomic_patch) { + if (!csync_atomic_patch || !S_ISREG(st.st_mode)) { conn_printf("SETOWN %s %s %d %d\n", url_encode(key), url_encode(filename), From 5a28781a1f50723dc70ec968ff3e0df4ade4c7f3 Mon Sep 17 00:00:00 2001 From: Shota Osepashvili Date: Mon, 4 Oct 2021 02:15:41 -0400 Subject: [PATCH 16/17] Make atomicpatch default command --- csync2.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/csync2.c b/csync2.c index eb95cea..678bdb9 100644 --- a/csync2.c +++ b/csync2.c @@ -67,7 +67,7 @@ int csync_error_count = 0; int csync_debug_level = 0; FILE *csync_debug_out = 0; int csync_syslog = 0; -int csync_atomic_patch = 0; +int csync_atomic_patch = 1; //TODO - make an inverse flag. int csync_server_child_pid = 0; int csync_timestamps = 0; From eead8c581dfc74449cc5d17369c3efb5d148dee2 Mon Sep 17 00:00:00 2001 From: Shota Osepashvili Date: Wed, 6 Oct 2021 04:56:54 -0400 Subject: [PATCH 17/17] Atomic dir update --- daemon.c | 38 +++++++++++++++++++++++++++++++++----- update.c | 14 +++++++++++--- 2 files changed, 44 insertions(+), 8 deletions(-) diff --git a/daemon.c b/daemon.c index c1e4645..05149f5 100644 --- a/daemon.c +++ b/daemon.c @@ -468,12 +468,39 @@ static int setup_tag(char *tag[32], char *line) return 1; } +void csync_dir_update(char* tag[]) { + const char *directory = prefixsubst(tag[2]); + uid_t uid = atoll(tag[3]); + gid_t gid = atoll(tag[4]); + + if (mkdir(directory, atoll(tag[5]) )) return; + + if (!csync_atomic_patch) return; + + + if (chown(directory, uid, gid)) + csync_debug(3, "Error '%s' for chown(%s,%d,%d)\n", + strerror(errno), directory, uid, gid); + + struct timespec tsp[2]; + long long timestamp = atoll(tag[6]); + tsp[0].tv_sec = tsp[1].tv_sec = (int) (timestamp / 1000000000); + tsp[0].tv_nsec = tsp[1].tv_nsec = timestamp % 1000000000; + + if(utimensat(0, directory, tsp, 0)) + csync_debug(3, "Error '%s' for utimensat\n", + strerror(errno), directory); + + +} + static void destroy_tag(char *tag[32]) { int i = 0; for (i = 0; i < 32; i++) free(tag[i]); } + void csync_daemon_session() { static char line[4 * 4096]; @@ -694,11 +721,11 @@ void csync_daemon_session() } } #else - if ( mkdir(prefixsubst(tag[2]), 0700) ) { - struct stat st; - if ( lstat_strict((prefixsubst(tag[2])), &st) != 0 || !S_ISDIR(st.st_mode)) - cmd_error = strerror(errno); - } + csync_dir_update(tag); + + struct stat st; + if ( lstat_strict((prefixsubst(tag[2])), &st) != 0 || !S_ISDIR(st.st_mode)) + cmd_error = strerror(errno); #endif break; case A_MKCHR: @@ -841,3 +868,4 @@ found_asactive: ; destroy_tag(tag); } } + diff --git a/update.c b/update.c index faa2858..52584ff 100644 --- a/update.c +++ b/update.c @@ -407,8 +407,16 @@ enum connection_response csync_update_file_mod(const char *peername, goto got_error; } else if ( S_ISDIR(st.st_mode) ) { - conn_printf("MKDIR %s %s\n", - url_encode(key), url_encode(filename)); + if (csync_atomic_patch) { + conn_printf("MKDIR %s %s %d %d %d %lld\n", + url_encode(key), url_encode(filename), + st.st_uid, st.st_gid, + st.st_mode, + nano_timestamp); + } else { + conn_printf("MKDIR %s %s\n", + url_encode(key), url_encode(filename)); + } last_conn_status = read_conn_status(filename, peername); if (!is_ok_response(last_conn_status)) goto maybe_auto_resolve; @@ -462,7 +470,7 @@ enum connection_response csync_update_file_mod(const char *peername, goto got_error; } - if (!csync_atomic_patch || !S_ISREG(st.st_mode)) { + if (!csync_atomic_patch || (!S_ISREG(st.st_mode) && S_ISDIR(st.st_mode))) { conn_printf("SETOWN %s %s %d %d\n", url_encode(key), url_encode(filename),