From 17fac7f2c92df794b88648a95bea6796621dbe83 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sun, 7 Sep 2003 23:11:37 +0000 Subject: Many fixes, primarily documentation git-svn-id: file:///home/lennart/svn/public/syrep/trunk@32 07ea20a6-d2c5-0310-9e02-9ef735347d72 --- Makefile.am | 8 +- configure.ac | 18 ++- doc/Makefile.am | 18 ++- doc/README | 1 - doc/README.html.in | 218 ++++++++++++++++++++++++++++++++++++ doc/style.css | 31 +++++ doc/todo.txt | 6 +- man/Makefile.am | 43 +++++++ man/man.css | 30 +++++ man/man.xsl | 120 ++++++++++++++++++++ man/syrep.1.xml.in | 323 +++++++++++++++++++++++++++++++++++++++++++++++++++++ src/Makefile.am | 5 +- src/context.c | 104 ++++++++++++++--- src/makepatch.c | 8 +- src/merge.c | 8 +- src/package.c | 37 ++++-- src/package.h | 2 +- src/syrep.c | 4 +- src/util.c | 17 ++- 19 files changed, 945 insertions(+), 56 deletions(-) delete mode 100644 doc/README create mode 100644 doc/README.html.in create mode 100644 doc/style.css create mode 100644 man/Makefile.am create mode 100644 man/man.css create mode 100644 man/man.xsl create mode 100644 man/syrep.1.xml.in diff --git a/Makefile.am b/Makefile.am index e3b08e4..2740d76 100644 --- a/Makefile.am +++ b/Makefile.am @@ -17,7 +17,7 @@ # Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. EXTRA_DIST=bootstrap.sh README LICENSE -SUBDIRS=src doc # man +SUBDIRS=src doc man MAINTAINERCLEANFILES = README noinst_DATA = README @@ -28,11 +28,13 @@ README: ln -s doc/README README homepage: + $(MAKE) -C doc all + $(MAKE) -C man all test -d $$HOME/homepage/lennart mkdir -p $$HOME/homepage/lennart/projects/syrep cp *.tar.gz $$HOME/homepage/lennart/projects/syrep - cp doc/README.html doc/style.css $$HOME/homepage/lennart/projects/syrep - cp $$HOME/homepage/lennart/projects/syrep/README.html $$HOME/homepage/lennart/projects/syrep/index.html + cp doc/README.html doc/style.css man/syrep.1.xhtml man/man.css man/man.xsl $$HOME/homepage/lennart/projects/syrep + ln -sf $$HOME/homepage/lennart/projects/syrep/README.html $$HOME/homepage/lennart/projects/syrep/index.html distcleancheck: @: diff --git a/configure.ac b/configure.ac index 88f058f..b535a44 100644 --- a/configure.ac +++ b/configure.ac @@ -36,13 +36,24 @@ if test -d /usr/local/stow ; then AC_PREFIX_DEFAULT([/usr/local/stow/${PACKAGE_NAME}-${PACKAGE_VERSION}]) fi +# Check for zlib AC_CHECK_LIB([z], [inflate],, [AC_MSG_ERROR([*** Sorry, you have to install zlib ***])]) AC_CHECK_HEADER([zlib.h],, [AC_MSG_ERROR([*** Sorry, you have to install the zlib headers ***])]) +# Check for Berkeley DB (needs to be improved) AC_CHECK_HEADER([db.h],, [AC_MSG_ERROR([*** Sorry, you have to install the Berkeley Database Library (libdb) 4.1 or newer ***])]) - LIBS="$LIBS -ldb" +# Check for Linux sendfile() +AC_CHECK_HEADER([sys/sendfile.h], sendfile=yes, sendfile=no) + +if test "x$sendfile" = xyes ; then + AC_CHECK_LIB([c], [sendfile], sendfile=yes, sendfile=no) + CPPFLAGS="$CPPFLAGS -DUSE_SENDFILE" +fi + +AM_CONDITIONAL([USE_SENDFILE], [test "x$sendfile" = xyes]) + # If using GCC specify some additional parameters if test "x$GCC" = "xyes" ; then CFLAGS="$CFLAGS -pipe -Wall" @@ -51,7 +62,7 @@ fi AC_C_BIGENDIAN if test "x$ac_cv_c_bigendian" = "xyes"; then - CFLAGS="$CPPFLAGS -DARCH_IS_BIG_ENDIAN=1" + CFLAGS="$CPPFLAGS -DARCH_IS_BIG_ENDIAN=1" else CPPFLAGS="$CPPFLAGS -DARCH_IS_BIG_ENDIAN=0" fi @@ -157,6 +168,5 @@ fi AM_CONDITIONAL([USE_SUBVERSION], [test "x$subversion" = xyes]) - -AC_CONFIG_FILES([src/Makefile Makefile doc/Makefile]) # man/Makefile doc/Makefile doc/README.html +AC_CONFIG_FILES([src/Makefile Makefile doc/Makefile man/Makefile doc/README.html]) AC_OUTPUT diff --git a/doc/Makefile.am b/doc/Makefile.am index 023a636..59432f6 100644 --- a/doc/Makefile.am +++ b/doc/Makefile.am @@ -16,4 +16,20 @@ # along with syrep; if not, write to the Free Software Foundation, # Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. -EXTRA_DIST = todo.txt package.txt usage-intro.txt +noinst_DATA = README.html README +EXTRA_DIST = $(noinst_DATA) style.css README.html.in todo.txt package.txt usage-intro.txt + +MAINTAINERCLEANFILES = README README.html +CLEANFILES = + +if USE_LYNX +README: README.html + lynx --dump $^ | sed 's,file://localhost/.*/doc/README.html,README,' > $@ + +CLEANFILES += README +endif + +tidy: README.html + tidy -e < README.html + +.PHONY: tidy diff --git a/doc/README b/doc/README deleted file mode 100644 index 1f7ff7e..0000000 --- a/doc/README +++ /dev/null @@ -1 +0,0 @@ -No README yet diff --git a/doc/README.html.in b/doc/README.html.in new file mode 100644 index 0000000..f0a038c --- /dev/null +++ b/doc/README.html.in @@ -0,0 +1,218 @@ + + + + + +syrep @PACKAGE_VERSION@ + + + + +

syrep @PACKAGE_VERSION@

+ +

Copyright 2003 Lennart Poettering <@PACKAGE_BUGREPORT@>

+ + + +

License

+ +

This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License as +published by the Free Software Foundation; either version 2 of the +License, or (at your option) any later version.

+ +

This program is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details.

+ +

You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.

+ +

News

+ +
Mon Sep 8 2003:

Version +0.1 released.

+ +

Overview

+ +

syrep is a generic file repository synchronization tool. It may be +used to synchronize large file hierarchies bidirectionally by +exchanging patch files. Syrep is truely peer-to-peer, no central +servers are involved. Synchronizations between more than two +repositories are supported. The patch files may be transferred via +offline media, e.g. removable hard disks or compact discs.

+ +

Files are tracked by their message digests, currently MD5. The +following file operations are tracked in the snapshot files: creation, +deletion, modification, creation of new hard or symbolic links, +renaming. (The latter is nothing more than a new hard link and removal +of the old file). syrep doesn't distuinguish between soft and +hard links. In fact even copies of files are treated as the +same. Currently, syrep doesn't synchronize file attributes like +access modes or modification times.

+ +

Syrep was written to facilitate the synchronization of two +large digital music repositories without direct network +connection. Patch files of several gigabytes are common in +this situation.

+ +

Syrep is able to cope with 64 bit file sizes. (LFS)

+ +

Syrep is optimized for speed. It may make use of a message digest +cache to accelerate the calculation of digests of a whole directory +hierarchy.

+ +

Status

+ +

Version @PACKAGE_VERSION@ is more or less stable and fulfills its purpose.

+ +

Documentation

+ +

Have a look on the man page syrep(1). (A XSLT capable browser is required)

+ +

Method of operation

+ +

Syrep's operation relies on "snapshots" of a file +repository. A snapshot contains information about all files existent +in the hierarchy combined with a limited history log of file +operations. Snapshots may be compared, files missing or deleted on one +of both sides may be detected this way. Based on this knowledge patch +files containing all missing files may be created and merged.

+ +

To keep the file operation log in a sensible state it is crucial to +update the snapshot frequently, probably by adding a new cron +job.

+ +

Example usage

+ +

Fred and Karl want to synchronize their digital music libraries by +exchanging an USB hard disk with patch files. As first step, both +initialize their repositories for usage with syrep:

+ +
fred$ syrep -zp --update ~/mp3/
+...
+karl$ syrep -zp --update ~/mp3/
+ +

Depending on the size of the repositories this takes a lot of time, +since a message digest is calculated for every file. Since exact +tracking of all file operations on the repository is crucial for +effetive synchronization, they both use the time passing to add a new +entry to their crontab:

+ +
1 3 * * * syrep -z --update ~/mp3/
+ +

When the snapshot creation finished, they send the newly created +patch files ~/mp3/.syrep/curent.syrep to each other. As these +snapshots are only about 400K of size for a 80GB repository they do +that via email:

+ +
fred$ mutt -a ~/mp3/.syrep/current.syrep -s "The current snapshot of fred" karl
+...
+karl$ mutt -a ~/mp3/.syrep/current.syrep -s "The current snapshot of karl" fred
+ +

When the mails arrive they both detach the snapshot and create a +patch on their USB harddisk containing all local files not existing on +the other siede:

+ +
fred$ mount /mnt/usb
+fred$ syrep -p -o /mnt/usb/patch-for-karl --makepatch ~/mp3/ ~/karls-current.syrep
+fred$ umount /mnt/usb
+...
+karl$ mount /mnt/usb
+karl$ syrep -p -o /mnt/usb/patch-for-fred --makepatch ~/mp3/ ~/freds-current.syrep
+karl$ umount /mnt/usb
+
+ +

As next step they exchange their harddisks. Back at home they merge the newly acquired patch into their own repository:

+ +
fred$ mount /mnt/usb
+fred$ syrep -pT --merge /mnt/usb/patch-for-fred ~/mp3/
+fred$ umount /mnt/usb
+...
+karl$ mount /mnt/usb
+karl$ syrep -pT --merge /mnt/usb/patch-for-karl ~/mp3/
+karl$ umount /mnt/usb
+
+ +

At this moment both have the same file hierarchy. To update the +local snapshot log with the newly merged files they both should run +--update now. This update run should be much quicker since +the message digests of all unchanged files are read from a message +cache created and update each time --update runs:

+ +
fred$ syrep -zp --update ~/mp3/
+...
+karl$ syrep -zp --update ~/mp3/
+ +

Some time later Fred got plenty of new music files, while Karl +didn't change anything on his repository. Thus, Fred is able to use +the old snapshot he recieved from Karl to generate a new patch for +him. He does it exactly the same way he did the last time, see +above.

+ +

And now, several iterations of the story described above +follow.

+ +

That's the end of the story.

+ +

OK, not quite. Sometimes a conflict happens, e.g. at the same time both created a +file foo.mp3 with different contents. When +this happens the local copy is always copied into the patch and the +user may decide during merge which file version he wants to have +locally. Because of that merging is an interactive task and cannot be +automated completely.

+ +

There is no need that the synchronization operations happen in such +a "symmetric" way as described above.

+ +

Requirements

+ +

syrep requires installed development versions of zlib and Berkeley DB.

+ +

syrep was developed and tested on Debian GNU/Linux +"testing" from September 2003, it should work on most other Linux +distributions and may be POSIX implementations since it uses GNU +autoconf for source code configuration.

+ +

Some support for for big endian architectures is included, however, it is incomplete. You're welcome to send me patches.

+ +

Installation

+ +

As this package is made with the GNU autotools you should run +./configure inside the distribution directory for configuring +the source tree. After that you should run make for +compilation and make install (as root) for installation of +syrep.

+ +

Acknowledgements

+ +

This software includes an implementation of the MD5 algorithm by +L. Peter Deutsch. Thanks to him for this.

+ +

Download

+ +

The newest release is always available from @PACKAGE_URL@

+ +

The current release is @PACKAGE_VERSION@

+ +
+ +
Lennart Poettering <@PACKAGE_BUGREPORT@>, Sep 2003
+ +
$Id$
+ + + diff --git a/doc/style.css b/doc/style.css new file mode 100644 index 0000000..110f73c --- /dev/null +++ b/doc/style.css @@ -0,0 +1,31 @@ +/* $Id$ */ + +/*** + This file is part of syrep. + + syrep is free software; you can redistribute it and/or modify it under + the terms of the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at your + option) any later version. + + syrep is distributed in the hope that it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + for more details. + + You should have received a copy of the GNU General Public License + along with syrep; if not, write to the Free Software Foundation, + Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. +***/ + +body { color: black; background-color: white; margin: 0.5cm; } +a:link, a:visited { color: #900000; } +p { margin-left: 0.5cm; margin-right: 0.5cm; } +div.news-date { margin-left: 0.5cm; font-size: 80%; color: #4f0000; } +p.news-text { margin-left: 1cm; } +ul { margin-left: .5cm; } +ol { margin-left: .5cm; } +h1 { color: #00009F; } +h2 { color: #00009F; } +h3 { color: #00004F; margin-left: 0.5cm; } +pre { margin-left: .5cm; background-color: #f0f0f0; padding: 0.4cm;} diff --git a/doc/todo.txt b/doc/todo.txt index 1faad6c..9870198 100644 --- a/doc/todo.txt +++ b/doc/todo.txt @@ -19,9 +19,9 @@ pre-0.1: - fix makepatch to not include already existing files DONE - better usage info on --help DONE - autoconf DONE - -- documentation/man pages -- testing +- syrep doesn't fail on on broken snapshot DONE +- documentation/man pages DONE +- testing DONE post-0.1: - continue merge on copy failure diff --git a/man/Makefile.am b/man/Makefile.am new file mode 100644 index 0000000..ed081db --- /dev/null +++ b/man/Makefile.am @@ -0,0 +1,43 @@ +# $Id$ + +# This file is part of syrep. +# +# syrep is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# syrep is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with syrep; if not, write to the Free Software Foundation, +# Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + +man_MANS = syrep.1 + +noinst_DATA = syrep.1.xml + +EXTRA_DIST = $(man_MANS) syrep.1.xml.in man.css man.xsl + +CLEANFILES = syrep.1.xml + +syrep.1.xml: syrep.1.xml.in Makefile + sed -e 's,@sysconfdir\@,$(sysconfdir),g' -e 's,@sbindir\@,$(sbindir),g' -e 's,@PACKAGE_URL\@,$(PACKAGE_URL),g' -e 's,@PACKAGE_BUGREPORT\@,$(PACKAGE_BUGREPORT),g' $< > $@ + +xmllint: syrep.1.xml + xmllint $< > /dev/null + +.PHONY: xmllint + +if USE_XMLTOMAN + +XMLTOMAN = ~/xmltoman.d/xmltoman +CLEANFILES += $(man_MANS) + +syrep.1: syrep.1.xml Makefile + $(XMLTOMAN) $< > $@ + +endif diff --git a/man/man.css b/man/man.css new file mode 100644 index 0000000..37dd55f --- /dev/null +++ b/man/man.css @@ -0,0 +1,30 @@ +/* $Id$ */ + +/*** + This file is part of syrep. + + syrep is free software; you can redistribute it and/or modify it under + the terms of the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at your + option) any later version. + + syrep is distributed in the hope that it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + for more details. + + You should have received a copy of the GNU General Public License + along with syrep; if not, write to the Free Software Foundation, + Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. +***/ + +body { color: black; background-color: white; margin: 0.5cm; } +a:link, a:visited { color: #900000; } +h1 { text-transform:uppercase; font-size: 18pt; color: #00009F; } +p { margin-left:1cm; margin-right:1cm; } +.cmd { font-family:monospace; } +.file { font-family:monospace; } +.arg { text-transform:uppercase; font-family:monospace; font-style: italic; } +.opt { font-family:monospace; font-weight: bold; } +.manref { font-family:monospace; } +.option .optdesc { margin-left:2cm; } diff --git a/man/man.xsl b/man/man.xsl new file mode 100644 index 0000000..7946a76 --- /dev/null +++ b/man/man.xsl @@ -0,0 +1,120 @@ + + + + + + + + <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> + + + + + + <xsl:value-of select="@name"/>(<xsl:value-of select="@section"/>) + + + + +

Name

+

+ + - + +

+ + + +
+ + +

+ +

+
+ + +

+ +

+
+ + + + + + + + + + + + + + +
+ +
+
+ + +

Synopsis

+ +
+ + +

Synopsis

+ +
+ + +

Description

+ +
+ + +

Options

+ +
+ + +

+ +
+ + +
+
+ + + + + () + + + () + + + + + + + + +
diff --git a/man/syrep.1.xml.in b/man/syrep.1.xml.in new file mode 100644 index 0000000..2b6e502 --- /dev/null +++ b/man/syrep.1.xml.in @@ -0,0 +1,323 @@ + + + + + + + + + + + + syrep [options...] --list SNAPSHOT ... + syrep [options...] --info SNAPSHOT ... + syrep [options...] --history SNAPSHOT ... + syrep [options...] --dump SNAPSHOT ... + syrep [options...] --update DIRECTORY ... + syrep [options...] --diff SNAPSHOT SNAPSHOT + syrep [options...] --merge SNAPSHOT DIRECTORY + syrep [options...] --makepatch DIRECTORY SNAPSHOT + syrep [options...] --extract SNAPSHOT ... + syrep [options...] --cleanup SNAPSHOT ... + + + + +

Syrep is a generic file repository synchronization tool. It may + be used to synchronize large file hierarchies bidirectionally by + exchanging patch files. Syrep is truely peer-to-peer, no central + servers are involved. Synchronizations between more than two + repositories are supported. The patch files may be transferred via + offline media, e.g. removable hard disks or compact discs.

+ +

Files are tracked by their message digests, currently MD5.

+ +

Syrep was written to facilitate the synchronization of two + large digital music repositories without direct network + connection. Patch files of several gigabytes are common in + this situation.

+ +

Syrep is able to cope with 64 bit file sizes. (LFS)

+ +

Syrep is optimized for speed. It may make use of a message digest cache to accelerate the calculation of digests of a whole directory hierarchy.

+ +
+ +
+ +

Exactly one command has to be specified on the command line. On the other hand multiple options are allowed.

+ + + + + + + + + + + +
+ +
+ + + + +
+ +
+ + + + + + + + + +
+ +
+ +
+ +
+ +
+ +
+ +
+ +
+ + + + + + + +
+
+ +
+ +
+ + + + +
+ +
+ + + +
+ +
+ + +
+ +
+ + + +
+ +
+ +

A syrep file repository is a POSIX file hierarchy with some + additional log data, which is used to track changes. Normally this + log data is saved as "snapshot" in the file + $(REPOSITORY)/.syrep/current.syrep. You may create + and update it by running --update. The more often this + log is updated the better modifications may be tracked. Therefore + this operation should be called at least once a day via

+ +

Two snapshots of two distinct repositories (possibly from + different hosts) may be compared with ---diff. This + will show you which files should be copied or deleted from or to + the other repository. --makepatch will attach the data + of the local missing in the remote repository to a snapshot and + write it to a patch file. This file should be transferred to the + other repository and applied there with --merge.

+ +

Keep in mind that patches contain the snapshot data of the + originating host. Because of that you may use it as a snapshot, + e.g. by running --diff on it. On the other hand you are + also able to merge snapshots without attached patch data to a + repository. This will do all required deletions and renames, but + naturally won't add any new data to the file tree.

+ +

To extract the contents of a patch you may use + --extract. This will write all files contained in the + patch or snapshot to the local directory, including snapshot log + data. Files are named by their message digests.

+ +
+ +
+ +

$(REPOSITORY)/.syrep/current.syrep is the current + snapshot of the repository. It is created and updated by running + --update on the directory. Use this file to create + patches on other repositories against this one. This file may be compressed by specifiying --compress when running --update.

+ +

$(REPOSITORY)/.syrep/md-cache is the message digest + cache which may be used to accelerate the repeated operation of + ---update. It associates device numbers, inode numbers, + file sizes and modification times with the message digest + calculated for that file. The file is only valid on the host it was + created on since it contains device numbers.

+ +

$(REPOSITORY)/.syrep/trash/ is the trash directory + used by --merge. Files are moved in here on + deletion. After successful completion it is emptied unless + --keep-trash is specified.

+ +

$(REPOSITORY)/.syrep/tmp/ is used as temporary file + space for extracting snaphots when option --local-temp + is used.

+
+ +
+

0 Success

+

Nonzero Failure

+
+ +
+

Syrep was written by Lennart Poettering <@PACKAGE_BUGREPORT@>.

+ +

Syrep is available at

+ +

You are encouraged to improve this documentation, feel free to send me patches. This is free software, after all.

+
+ +
+

,

+
+ +
+

This man page was written using by Oliver Kurth.

+
+ +
diff --git a/src/Makefile.am b/src/Makefile.am index 3386f58..078fe48 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -16,7 +16,6 @@ # along with syrep; if not, write to the Free Software Foundation, # Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. - bin_PROGRAMS = syrep syrep_SOURCES = cache.c cache.h \ @@ -44,9 +43,10 @@ syrep_SOURCES = cache.c cache.h \ EXTRA_DIST = syrep.ggo MAINTAINERCLEANFILES = BUILT_SOURCES = +CLEANFILES = if USE_GENGETOPT -MAINTAINERCLEANFILES += cmdline.c cmdline.h +CLEANFILES += cmdline.c cmdline.h BUILT_SOURCES += cmdline.c cmdline.h endif @@ -66,6 +66,7 @@ cmdline.c cmdline.h: syrep.ggo Makefile endif if USE_SUBVERSION + svn-revision.h: Makefile if test -d "$(top_srcdir)/.svn" ; then \ if REV=`svn info "$(top_srcdir)" | grep ^Revision | cut -f2 -d" "` 2> /dev/null ; then \ diff --git a/src/context.c b/src/context.c index b0cfc78..677704d 100644 --- a/src/context.c +++ b/src/context.c @@ -98,6 +98,7 @@ struct syrep_db_context* db_context_open(const char *filename, int force) { struct syrep_db_context *c = NULL; const char* path; FILE *f; + int k; if (!(c = malloc(sizeof(struct syrep_db_context)))) goto fail; @@ -107,7 +108,11 @@ struct syrep_db_context* db_context_open(const char *filename, int force) { if (!(c->package = package_open(filename, force))) goto fail; - path = package_get_item(c->package, "timestamp", 1); + if ((k = package_get_item(c->package, "timestamp", 1, &path)) < 0) + goto fail; + + assert(k); + if ((f = fopen(path, "r"))) { if (fscanf(f, "%i", &c->timestamp) != 1) c->timestamp = 0; @@ -117,14 +122,22 @@ struct syrep_db_context* db_context_open(const char *filename, int force) { if (!c->timestamp) c->timestamp = time(NULL); - path = package_get_item(c->package, "version", 1); + if ((k = package_get_item(c->package, "version", 1, &path)) < 0) + goto fail; + + assert(k); + if ((f = fopen(path, "r"))) { if (fscanf(f, "%u", &c->version) != 1) c->version = 0; fclose(f); } - path = package_get_item(c->package, "origin", 1); + if ((k = package_get_item(c->package, "origin", 1, &path)) < 0) + goto fail; + + assert(k); + if ((f = fopen(path, "r"))) { char hn[256]; if (fgets(hn, sizeof(hn), f)) { @@ -150,35 +163,75 @@ struct syrep_db_context* db_context_open(const char *filename, int force) { } /* Creating database id_meta */ - if (!(c->db_id_meta = open_db(package_get_item(c->package, "id_meta", 1), 0, 0))) + if ((k = package_get_item(c->package, "id_meta", 1, &path)) < 0) + goto fail; + + assert(k); + + if (!(c->db_id_meta = open_db(path, 0, 0))) goto fail; /* Creating database md_nrecno */ - if (!(c->db_md_nrecno = open_db(package_get_item(c->package, "md_nrecno", 1), 1, 0))) + if ((k = package_get_item(c->package, "md_nrecno", 1, &path)) < 0) + goto fail; + + assert(k); + + if (!(c->db_md_nrecno = open_db(path, 1, 0))) goto fail; /* Creating database nrecno_md */ - if (!(c->db_nrecno_md = open_db(package_get_item(c->package, "nrecno_md", 1), 1, 0))) + if ((k = package_get_item(c->package, "nrecno_md", 1, &path)) < 0) + goto fail; + + assert(k); + + if (!(c->db_nrecno_md = open_db(path, 1, 0))) goto fail; /* Creating database nrecno_lastmd */ - if (!(c->db_nrecno_lastmd = open_db(package_get_item(c->package, "nrecno_lastmd", 1), 0, 0))) + if ((k = package_get_item(c->package, "nrecno_lastmd", 1, &path)) < 0) + goto fail; + + assert(k); + + if (!(c->db_nrecno_lastmd = open_db(path, 0, 0))) goto fail; /* Creating database md_lastnrecno */ - if (!(c->db_md_lastnrecno = open_db(package_get_item(c->package, "md_lastnrecno", 1), 0, 0))) + if ((k = package_get_item(c->package, "md_lastnrecno", 1, &path)) < 0) + goto fail; + + assert(k); + + if (!(c->db_md_lastnrecno = open_db(path, 0, 0))) goto fail; /* Creating database version_timestamp */ - if (!(c->db_version_timestamp = open_db(package_get_item(c->package, "version_timestamp", 1), 0, 0))) + if ((k = package_get_item(c->package, "version_timestamp", 1, &path)) < 0) + goto fail; + + assert(k); + + if (!(c->db_version_timestamp = open_db(path, 0, 0))) goto fail; /* Creating database nhash_nrecno */ - if (!(c->db_nhash_nrecno = open_db(package_get_item(c->package, "nhash_nrecno", 1), 1, 0))) + if ((k = package_get_item(c->package, "nhash_nrecno", 1, &path)) < 0) + goto fail; + + assert(k); + + if (!(c->db_nhash_nrecno = open_db(path, 1, 0))) goto fail; /* Creating database nrecno_name */ - if (!(c->db_nrecno_name = open_db(package_get_item(c->package, "nrecno_name", 1), 0, 1))) + if ((k = package_get_item(c->package, "nrecno_name", 1, &path)) < 0) + goto fail; + + assert(k); + + if (!(c->db_nrecno_name = open_db(path, 0, 1))) goto fail; return c; @@ -192,6 +245,8 @@ fail: int db_context_save(struct syrep_db_context *c, const char *filename) { FILE *f; + int k; + const char *path; assert(c && c->package); if (c->db_id_meta) @@ -217,20 +272,41 @@ int db_context_save(struct syrep_db_context *c, const char *filename) { if (c->db_nrecno_name) c->db_nrecno_name->sync(c->db_nrecno_name, 0); + + /* Saving timestamp info */ - if (!(f = fopen(package_get_item(c->package, "timestamp", 1), "w+"))) + if ((k = package_get_item(c->package, "timestamp", 1, &path)) < 0) + return -1; + + assert(k); + + if (!(f = fopen(path, "w+"))) return -1; fprintf(f, "%i\n", c->timestamp); fclose(f); - if (!(f = fopen(package_get_item(c->package, "version", 1), "w+"))) + /* Save version info */ + + if ((k = package_get_item(c->package, "version", 1, &path)) < 0) + return -1; + + assert(k); + + if (!(f = fopen(path, "w+"))) return -1; fprintf(f, "%u\n", c->version); fclose(f); - if (!(f = fopen(package_get_item(c->package, "origin", 1), "w+"))) + /* Save origin info */ + + if ((k = package_get_item(c->package, "origin", 1, &path)) < 0) + return -1; + + assert(k); + + if (!(f = fopen(path, "w+"))) return -1; fprintf(f, "%s\n", c->origin); diff --git a/src/makepatch.c b/src/makepatch.c index 278cd38..3de8860 100644 --- a/src/makepatch.c +++ b/src/makepatch.c @@ -40,7 +40,7 @@ static int cb(DB *ddb, struct syrep_name *name, struct diff_entry *de, void *p) struct syrep_nrecno nrecno; char path[PATH_MAX+1]; char d[SYREP_DIGESTLENGTH*2+1]; - int f; + int f, k; assert(ddb && name && de && p); @@ -77,14 +77,16 @@ static int cb(DB *ddb, struct syrep_name *name, struct diff_entry *de, void *p) snprintf(path, sizeof(path), "%s/%s", cb_info->root, name->path); - if (!package_get_item(cb_info->c1->package, d, 0)) { + if ((k = package_get_item(cb_info->c1->package, d, 0, NULL)) < 0) + return -1; + + if (!k) { if (args.verbose_flag) fprintf(stderr, "Adding %s (%s) to patch.\n", name->path, d); if (package_add_file(cb_info->c1->package, d, path) < 0) return -1; - } return 0; diff --git a/src/merge.c b/src/merge.c index 206e2d9..01e1981 100644 --- a/src/merge.c +++ b/src/merge.c @@ -61,7 +61,7 @@ static int conflict_phase(DB *ddb, struct syrep_name *name, struct diff_entry *d if ((f1 = get_current_md_by_nrecno(cb_info->c1, &nrecno1, &md1)) < 0) return -1; - if ((f2 = get_nrecno_by_name(cb_info->c2, name, &nrecno1, 0)) < 0) + if ((f2 = get_nrecno_by_name(cb_info->c2, name, &nrecno2, 0)) < 0) return -1; if (f2) @@ -236,8 +236,12 @@ static int copy_phase(DB *ddb, struct syrep_name *name, struct diff_entry *de, v } else { const char* a; + int k; - if ((a = package_get_item(cb_info->c1->package, d, 0))) { + if ((k = package_get_item(cb_info->c1->package, d, 0, &a)) < 0) + return -1; + + if (k) { fprintf(stderr, "COPY: Copying file <%s> from patch.\n", name->path); if (makeprefixpath(path, 0777) < 0) diff --git a/src/package.c b/src/package.c index 3d23306..9496742 100644 --- a/src/package.c +++ b/src/package.c @@ -717,42 +717,57 @@ finish: return r; } -const char *package_get_item(struct package* p, const char *name, int c) { +int package_get_item(struct package* p, const char *name, int c, const char ** fn) { struct package_item *i; char path[PATH_MAX]; assert(p && name); for (i = p->items; i; i = i->next) - if (!strncmp(name, i->name, PACKAGE_ITEMNAMELEN)) - return i->path; + if (!strncmp(name, i->name, PACKAGE_ITEMNAMELEN)) { + if (fn) + *fn = i->path; + + return 1; + } for (;;) { int r; if ((r = read_item(p)) < 0) - return NULL; + return -1; - if (r == 0) + if (!r) break; assert(p->last); - if (!strncmp(name, p->last->name, PACKAGE_ITEMNAMELEN)) - return p->last->path; + if (!strncmp(name, p->last->name, PACKAGE_ITEMNAMELEN)) { + if (fn) + *fn = p->last->path; + + return 1; + } } if (!c) - return NULL; + return 0; snprintf(path, sizeof(path), "%s/%i", p->base, p->count++); if (!(i = item_new(name, path, 1))) { unlink(path); - return NULL; + return -1; } - + append_item(p, i); + + assert(i); + + assert(fn); - return i->path; + if (fn) + *fn = i->path; + + return 1; } int package_add_file(struct package *p, const char *name, const char *fn) { diff --git a/src/package.h b/src/package.h index 9279659..42486ad 100644 --- a/src/package.h +++ b/src/package.h @@ -33,7 +33,7 @@ struct package; struct package* package_open(const char *fn, int force); void package_remove(struct package *p); int package_save(struct package *p, const char *fn); -const char *package_get_item(struct package* p, const char *name, int c); +int package_get_item(struct package* p, const char *name, int c, char const ** fn); int package_add_file(struct package *p, const char *name, const char *fn); int package_foreach(struct package *p, int (*cb) (struct package *p, const char *name, const char *path, void *u), void *u); diff --git a/src/syrep.c b/src/syrep.c index 724f08a..e65dc1c 100644 --- a/src/syrep.c +++ b/src/syrep.c @@ -473,9 +473,9 @@ static void free_args(void) { static int help(const char *argv0) { fprintf(stderr, - "%s -- Synchronize Repositories\n\n" + "%s -- Synchronize File Repositories\n\n" - "Usage: %s [options] [argument...]\n\n" + "Usage: %s [options...] [arguments...]\n\n" "General options:\n" " -v --verbose Enable verbose operation\n" diff --git a/src/util.c b/src/util.c index 18f8fa4..ffc5dc3 100644 --- a/src/util.c +++ b/src/util.c @@ -18,8 +18,6 @@ Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ***/ -#define USE_SENDFILE - #include #include #include @@ -230,15 +228,20 @@ int copy_fd(int sfd, int dfd, off_t l) { static size_t psize = 0; #ifdef USE_SENDFILE - if (!copy_fd_sendfile(sfd, dfd, l)) + if (copy_fd_sendfile(sfd, dfd, l) == 0) return 0; + + if (errno == ENOSPC) + return -1; #endif //fprintf(stderr, "copy_fd(%u)\n", l); if (psize == 0) - psize = sysconf(_SC_PAGESIZE); + psize = (off_t) sysconf(_SC_PAGESIZE); + assert(psize > 0); + sp = dp = MAP_FAILED; if (l > BUFSIZE) { @@ -346,10 +349,8 @@ int copy_fd(int sfd, int dfd, off_t l) { fprintf(stderr, "mmap(): %s\n", strerror(errno)); return -1; } - } - } else if (dp == MAP_FAILED) { /* copy mmap to fd */ for (;;) { @@ -386,7 +387,6 @@ int copy_fd(int sfd, int dfd, off_t l) { } } - } else { /* copy mmap to mmap */ for (;;) { @@ -421,6 +421,7 @@ int copy_fd(int sfd, int dfd, off_t l) { mdfo = (dfo/psize)*psize; dm = m+(dfo-mdfo); if ((dp = mmap(NULL, dm, PROT_READ|PROT_WRITE, MAP_SHARED, dfd, mdfo)) == MAP_FAILED) { + munmap(sp, sm); fprintf(stderr, "mmap(): %s\n", strerror(errno)); return -1; } @@ -640,7 +641,6 @@ int question(const char *text, const char *replies) { } } - finish: fputc('\r', stderr); @@ -649,7 +649,6 @@ finish: fclose(f); return r; - } -- cgit