Re: compare-dest support for openrsync

2021-07-02 Thread Claudio Jeker
On Wed, Jun 30, 2021 at 05:47:16PM +0200, Claudio Jeker wrote:
> Thge compare-dest option of rsync is something I would like to use in
> rpki-client. This implements just that and I think after that adding
> copy-dest and link-dest options should be somewhat easy to add as well.
> Lightly tested with my particular need.
 
There is some unveil issues with this diff that need to be worked out.
Until then it people can test by commenting the unveil calls in receiver.c

> -- 
> :wq Claudio
> 
> Index: Makefile
> ===
> RCS file: /cvs/src/usr.bin/rsync/Makefile,v
> retrieving revision 1.10
> diff -u -p -r1.10 Makefile
> --- Makefile  8 May 2019 21:30:11 -   1.10
> +++ Makefile  30 Jun 2021 15:40:19 -
> @@ -1,14 +1,18 @@
>  #$OpenBSD: Makefile,v 1.10 2019/05/08 21:30:11 benno Exp $
>  
>  PROG=openrsync
> -SRCS=blocks.c client.c downloader.c fargs.c flist.c hash.c ids.c \
> +SRCS=blocks.c client.c copy.c downloader.c fargs.c flist.c hash.c 
> ids.c \
>   io.c log.c mkpath.c mktemp.c receiver.c sender.c server.c session.c \
>   socket.c symlinks.c uploader.c main.c misc.c
>  LDADD+= -lcrypto -lm
>  DPADD+= ${LIBCRYPTO} ${LIBM}
>  MAN= openrsync.1
>  
> -CFLAGS+=-g -W -Wall -Wextra
> +CFLAGS+= -Wall -Wextra
> +CFLAGS+= -Wstrict-prototypes -Wmissing-prototypes
> +CFLAGS+= -Wmissing-declarations
> +CFLAGS+= -Wshadow
> +
>  
>  openrsync.1: rsync.1
>   ln -sf ${.CURDIR}/rsync.1 openrsync.1
> Index: copy.c
> ===
> RCS file: copy.c
> diff -N copy.c
> --- /dev/null 1 Jan 1970 00:00:00 -
> +++ copy.c30 Jun 2021 15:40:19 -
> @@ -0,0 +1,90 @@
> +/*   $OpenBSD$ */
> +/*
> + * Copyright (c) 2021 Claudio Jeker 
> + *
> + * Permission to use, copy, modify, and distribute this software for any
> + * purpose with or without fee is hereby granted, provided that the above
> + * copyright notice and this permission notice appear in all copies.
> + *
> + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
> + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
> + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
> + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
> + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
> + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
> + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
> + */
> +
> +#include/* for MAXBSIZE */
> +
> +#include 
> +#include 
> +#include 
> +
> +#include "extern.h"
> +
> +/*
> + * Return true if all bytes in buffer are zero.
> + * A buffer of zero lenght is also considered a zero buffer.
> + */
> +static int
> +iszero(const void *b, size_t len)
> +{
> + const unsigned char *c = b;
> +
> + for (; len > 0; len--) {
> + if (*c++ != '\0')
> + return 0;
> + }
> + return 1;
> +}
> +
> +static int
> +copy_internal(int fromfd, int tofd)
> +{
> + char buf[MAXBSIZE];
> + ssize_t r, w;
> +
> + while ((r = read(fromfd, buf, sizeof(buf))) > 0) {
> + if (iszero(buf, sizeof(buf))) {
> + if (lseek(tofd, r, SEEK_CUR) == -1)
> + return -1;
> + } else {
> + w = write(tofd, buf, r);
> + if (r != w || w == -1)
> + return -1;
> + }
> + }
> + if (r == -1)
> + return -1;
> + if (ftruncate(tofd, lseek(tofd, 0, SEEK_CUR)) == -1)
> + return -1;
> + return 0;
> +}
> +
> +void
> +copy_file(int rootfd, const char *basedir, const struct flist *f)
> +{
> + int fromfd, tofd, dfd;
> +
> + dfd = openat(rootfd, basedir, O_RDONLY | O_DIRECTORY, 0);
> + if (dfd == -1)
> + err(ERR_FILE_IO, "%s: openat", basedir);
> +
> + fromfd = openat(dfd, f->path, O_RDONLY | O_NOFOLLOW, 0);
> + if (fromfd == -1)
> + err(ERR_FILE_IO, "%s/%s: openat", basedir, f->path);
> + close(dfd);
> +
> + tofd = openat(rootfd, f->path,
> + O_WRONLY | O_NOFOLLOW | O_TRUNC | O_CREAT | O_EXCL,
> + 0600);
> + if (tofd == -1)
> + err(ERR_FILE_IO, "%s: openat", f->path);
> +
> + if (copy_internal(fromfd, tofd) == -1)
> + err(ERR_FILE_IO, "%s: copy file", f->path);
> +
> + close(fromfd);
> + close(tofd);
> +}
> Index: extern.h
> ===
> RCS file: /cvs/src/usr.bin/rsync/extern.h,v
> retrieving revision 1.39
> diff -u -p -r1.39 extern.h
> --- extern.h  30 Jun 2021 15:24:10 -  1.39
> +++ extern.h  30 Jun 2021 15:40:19 -
> @@ -34,6 +34,15 @@
>  #define  BLOCK_SIZE_MIN  (700)
>  
>  /*
> + * Maximum number of base directories that can be used.
> + */
> +#define MAX_BASEDIR 

compare-dest support for openrsync

2021-06-30 Thread Claudio Jeker
Thge compare-dest option of rsync is something I would like to use in
rpki-client. This implements just that and I think after that adding
copy-dest and link-dest options should be somewhat easy to add as well.
Lightly tested with my particular need.

-- 
:wq Claudio

Index: Makefile
===
RCS file: /cvs/src/usr.bin/rsync/Makefile,v
retrieving revision 1.10
diff -u -p -r1.10 Makefile
--- Makefile8 May 2019 21:30:11 -   1.10
+++ Makefile30 Jun 2021 15:40:19 -
@@ -1,14 +1,18 @@
 #  $OpenBSD: Makefile,v 1.10 2019/05/08 21:30:11 benno Exp $
 
 PROG=  openrsync
-SRCS=  blocks.c client.c downloader.c fargs.c flist.c hash.c ids.c \
+SRCS=  blocks.c client.c copy.c downloader.c fargs.c flist.c hash.c ids.c \
io.c log.c mkpath.c mktemp.c receiver.c sender.c server.c session.c \
socket.c symlinks.c uploader.c main.c misc.c
 LDADD+= -lcrypto -lm
 DPADD+= ${LIBCRYPTO} ${LIBM}
 MAN=   openrsync.1
 
-CFLAGS+=-g -W -Wall -Wextra
+CFLAGS+= -Wall -Wextra
+CFLAGS+= -Wstrict-prototypes -Wmissing-prototypes
+CFLAGS+= -Wmissing-declarations
+CFLAGS+= -Wshadow
+
 
 openrsync.1: rsync.1
ln -sf ${.CURDIR}/rsync.1 openrsync.1
Index: copy.c
===
RCS file: copy.c
diff -N copy.c
--- /dev/null   1 Jan 1970 00:00:00 -
+++ copy.c  30 Jun 2021 15:40:19 -
@@ -0,0 +1,90 @@
+/* $OpenBSD$ */
+/*
+ * Copyright (c) 2021 Claudio Jeker 
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include  /* for MAXBSIZE */
+
+#include 
+#include 
+#include 
+
+#include "extern.h"
+
+/*
+ * Return true if all bytes in buffer are zero.
+ * A buffer of zero lenght is also considered a zero buffer.
+ */
+static int
+iszero(const void *b, size_t len)
+{
+   const unsigned char *c = b;
+
+   for (; len > 0; len--) {
+   if (*c++ != '\0')
+   return 0;
+   }
+   return 1;
+}
+
+static int
+copy_internal(int fromfd, int tofd)
+{
+   char buf[MAXBSIZE];
+   ssize_t r, w;
+
+   while ((r = read(fromfd, buf, sizeof(buf))) > 0) {
+   if (iszero(buf, sizeof(buf))) {
+   if (lseek(tofd, r, SEEK_CUR) == -1)
+   return -1;
+   } else {
+   w = write(tofd, buf, r);
+   if (r != w || w == -1)
+   return -1;
+   }
+   }
+   if (r == -1)
+   return -1;
+   if (ftruncate(tofd, lseek(tofd, 0, SEEK_CUR)) == -1)
+   return -1;
+   return 0;
+}
+
+void
+copy_file(int rootfd, const char *basedir, const struct flist *f)
+{
+   int fromfd, tofd, dfd;
+
+   dfd = openat(rootfd, basedir, O_RDONLY | O_DIRECTORY, 0);
+   if (dfd == -1)
+   err(ERR_FILE_IO, "%s: openat", basedir);
+
+   fromfd = openat(dfd, f->path, O_RDONLY | O_NOFOLLOW, 0);
+   if (fromfd == -1)
+   err(ERR_FILE_IO, "%s/%s: openat", basedir, f->path);
+   close(dfd);
+
+   tofd = openat(rootfd, f->path,
+   O_WRONLY | O_NOFOLLOW | O_TRUNC | O_CREAT | O_EXCL,
+   0600);
+   if (tofd == -1)
+   err(ERR_FILE_IO, "%s: openat", f->path);
+
+   if (copy_internal(fromfd, tofd) == -1)
+   err(ERR_FILE_IO, "%s: copy file", f->path);
+
+   close(fromfd);
+   close(tofd);
+}
Index: extern.h
===
RCS file: /cvs/src/usr.bin/rsync/extern.h,v
retrieving revision 1.39
diff -u -p -r1.39 extern.h
--- extern.h30 Jun 2021 15:24:10 -  1.39
+++ extern.h30 Jun 2021 15:40:19 -
@@ -34,6 +34,15 @@
 #defineBLOCK_SIZE_MIN  (700)
 
 /*
+ * Maximum number of base directories that can be used.
+ */
+#define MAX_BASEDIR20
+
+#define BASE_MODE_COMPARE  1
+#define BASE_MODE_COPY 2
+#define BASE_MODE_LINK 3
+
+/*
  * The sender and receiver use a two-phase synchronisation process.
  * The first uses two-byte hashes; the second, 16-byte.
  * (The second must hold a full MD4 digest.)
@@ -131,10 +140,12 @@ structopts {
int  no_motd;   /* --no-motd */
int