summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLennart Poettering <lennart@poettering.net>2003-09-07 23:11:37 +0000
committerLennart Poettering <lennart@poettering.net>2003-09-07 23:11:37 +0000
commit17fac7f2c92df794b88648a95bea6796621dbe83 (patch)
treef50baaf521f683a24e3de98141643863fab74af1
parent411862e81940e9eaea542ae1c4a04cca5e5b88a3 (diff)
Many fixes, primarily documentation
git-svn-id: file:///home/lennart/svn/public/syrep/trunk@32 07ea20a6-d2c5-0310-9e02-9ef735347d72
-rw-r--r--Makefile.am8
-rw-r--r--configure.ac18
-rw-r--r--doc/Makefile.am18
-rw-r--r--doc/README1
-rw-r--r--doc/README.html.in218
-rw-r--r--doc/style.css31
-rw-r--r--doc/todo.txt6
-rw-r--r--man/Makefile.am43
-rw-r--r--man/man.css30
-rw-r--r--man/man.xsl120
-rw-r--r--man/syrep.1.xml.in323
-rw-r--r--src/Makefile.am5
-rw-r--r--src/context.c104
-rw-r--r--src/makepatch.c8
-rw-r--r--src/merge.c8
-rw-r--r--src/package.c37
-rw-r--r--src/package.h2
-rw-r--r--src/syrep.c4
-rw-r--r--src/util.c17
19 files changed, 945 insertions, 56 deletions
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 @@
+<?xml version="1.0" encoding="iso-8895-15"?> <!-- -*-html-helper-*- -->
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+
+<head>
+<title>syrep @PACKAGE_VERSION@</title>
+<link rel="stylesheet" type="text/css" href="style.css" />
+</head>
+
+<body>
+<h1><a name="top">syrep @PACKAGE_VERSION@</a></h1>
+
+<p><i>Copyright 2003 Lennart Poettering &lt;@PACKAGE_BUGREPORT@&gt;</i></p>
+
+<ul class="toc">
+ <li><a href="#license">License</a></li>
+ <li><a href="#news">News</a></li>
+ <li><a href="#overview">Overview</a></li>
+ <li><a href="#status">Status</a></li>
+ <li><a href="#documentation">Documentation</a></li>
+ <li><a href="#requirements">Requirements</a></li>
+ <li><a href="#installation">Installation</a></li>
+ <li><a href="#acks">Acknowledgements</a></li>
+ <li><a href="#download">Download</a></li>
+</ul>
+
+<h2><a name="license">License</a></h2>
+
+<p>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.</p>
+
+<p>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.</p>
+
+<p>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.</p>
+
+<h2><a name="news">News</a></h2>
+
+<div class="news-date">Mon Sep 8 2003: </div> <p class="news-text"><a
+href="@PACKAGE_URL@syrep-0.1.tar.gz">Version
+0.1</a> released.</p>
+
+<h2><a name="overview">Overview</a></h2>
+
+<p><tt>syrep</tt> is a generic file repository synchronization tool. It may be
+used to synchronize large file hierarchies bidirectionally by
+exchanging patch files. <tt>Syrep</tt> 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.</p>
+
+<p>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). <tt>syrep</tt> doesn't distuinguish between soft and
+hard links. In fact even copies of files are treated as the
+same. Currently, <tt>syrep</tt> doesn't synchronize file attributes like
+access modes or modification times.</p>
+
+<p><tt>Syrep</tt> 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.</p>
+
+<p><tt>Syrep</tt> is able to cope with 64 bit file sizes. (LFS)</p>
+
+<p><tt>Syrep</tt> is optimized for speed. It may make use of a message digest
+cache to accelerate the calculation of digests of a whole directory
+hierarchy.</p>
+
+<h2><a name="status">Status</a></h2>
+
+<p>Version @PACKAGE_VERSION@ is more or less stable and fulfills its purpose.</p>
+
+<h2><a name="documentation">Documentation</a></h2>
+
+<p>Have a look on the man page <a href="@PACKAGE_URL@syrep.1.xml"><tt>syrep(1)</tt></a>. (A XSLT capable browser is required)</p>
+
+<h3>Method of operation</h3>
+
+<p><tt>Syrep</tt>'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.</p>
+
+<p>To keep the file operation log in a sensible state it is crucial to
+update the snapshot frequently, probably by adding a new <tt>cron</tt>
+job.</p>
+
+<h3>Example usage</h3>
+
+<p>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 <tt>syrep</tt>:</p>
+
+<pre>fred$ syrep -zp --update ~/mp3/
+...
+karl$ syrep -zp --update ~/mp3/</pre>
+
+<p>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 <tt>crontab</tt>:</p>
+
+<pre>1 3 * * * syrep -z --update ~/mp3/</pre>
+
+<p>When the snapshot creation finished, they send the newly created
+patch files <tt>~/mp3/.syrep/curent.syrep</tt> to each other. As these
+snapshots are only about 400K of size for a 80GB repository they do
+that via email:</p>
+
+<pre>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</pre>
+
+<p>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:</p>
+
+<pre>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
+</pre>
+
+<p>As next step they exchange their harddisks. Back at home they merge the newly acquired patch into their own repository:</p>
+
+<pre>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
+</pre>
+
+<p>At this moment both have the same file hierarchy. To update the
+local snapshot log with the newly merged files they both should run
+<tt>--update</tt> 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 <tt>--update</tt> runs:</p>
+
+<pre>fred$ syrep -zp --update ~/mp3/
+...
+karl$ syrep -zp --update ~/mp3/</pre>
+
+<p>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.</p>
+
+<p>And now, several iterations of the story described above
+follow.</p>
+
+<p>That's the end of the story.</p>
+
+<p>OK, not quite. Sometimes a conflict happens, e.g. at the same time both created a
+file <tt>foo.mp3</tt> 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.</p>
+
+<p>There is no need that the synchronization operations happen in such
+a "symmetric" way as described above.</p>
+
+<h2><a name="requirements">Requirements</a></h2>
+
+<p><tt>syrep</tt> requires installed development versions of <tt><a href="http://www.gzip.org/zlib/">zlib</a></tt> and <tt><a href="http://www.sleepycat.com/">Berkeley DB</a></tt>.</p>
+
+<p><tt>syrep</tt> 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.</p>
+
+<p>Some support for for big endian architectures is included, however, it is incomplete. You're welcome to send me patches.</p>
+
+<h2><a name="installation">Installation</a></h2>
+
+<p>As this package is made with the GNU autotools you should run
+<tt>./configure</tt> inside the distribution directory for configuring
+the source tree. After that you should run <tt>make</tt> for
+compilation and <tt>make install</tt> (as root) for installation of
+<tt>syrep</tt>.</p>
+
+<h2><a name="acks">Acknowledgements</a></h2>
+
+<p>This software includes an implementation of the MD5 algorithm by
+L. Peter Deutsch. Thanks to him for this.</p>
+
+<h2><a name="download">Download</a></h2>
+
+<p>The newest release is always available from <a href="@PACKAGE_URL@">@PACKAGE_URL@</a></p>
+
+<p>The current release is <a href="@PACKAGE_URL@syrep-@PACKAGE_VERSION@.tar.gz">@PACKAGE_VERSION@</a></p>
+
+<hr/>
+
+<address>Lennart Poettering &lt;@PACKAGE_BUGREPORT@&gt;, Sep 2003</address>
+
+<div><i>$Id$</i></div>
+
+</body>
+</html>
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 @@
+<?xml version="1.0" encoding="iso-8859-1"?>
+<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns="http://www.w3.org/1999/xhtml">
+
+<!--
+ This file is part of xmltoman.
+
+ xmltoman 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.
+
+ xmltoman 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 xmltoman; if not, write to the Free Software Foundation,
+ Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+-->
+
+<xsl:template match="/manpage">
+ <xsl:text disable-output-escaping="yes">
+ &lt;!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"&gt;
+ </xsl:text>
+ <html>
+
+ <head>
+ <title>
+ <xsl:value-of select="@name"/>(<xsl:value-of select="@section"/>)
+ </title>
+ <link rel="stylesheet" type="text/css" href="man.css"/>
+ </head>
+ <body>
+ <h1>Name</h1>
+ <p><xsl:value-of select="@name"/>
+ <xsl:if test="string-length(@desc) &gt; 0">
+ - <xsl:value-of select="@desc"/>
+ </xsl:if>
+ </p>
+ <xsl:apply-templates />
+ </body>
+ </html>
+</xsl:template>
+
+<xsl:template match="p">
+ <p>
+ <xsl:apply-templates/>
+ </p>
+</xsl:template>
+
+<xsl:template match="cmd">
+ <p class="cmd">
+ <xsl:apply-templates/>
+ </p>
+</xsl:template>
+
+<xsl:template match="arg">
+ <span class="arg"><xsl:apply-templates/></span>
+</xsl:template>
+
+<xsl:template match="opt">
+ <span class="opt"><xsl:apply-templates/></span>
+</xsl:template>
+
+<xsl:template match="file">
+ <span class="file"><xsl:apply-templates/></span>
+</xsl:template>
+
+<xsl:template match="optdesc">
+ <div class="optdesc">
+ <xsl:apply-templates/>
+ </div>
+</xsl:template>
+
+<xsl:template match="synopsis">
+ <h1>Synopsis</h1>
+ <xsl:apply-templates/>
+</xsl:template>
+
+<xsl:template match="seealso">
+ <h1>Synopsis</h1>
+ <xsl:apply-templates/>
+</xsl:template>
+
+<xsl:template match="description">
+ <h1>Description</h1>
+ <xsl:apply-templates/>
+</xsl:template>
+
+<xsl:template match="options">
+ <h1>Options</h1>
+ <xsl:apply-templates/>
+</xsl:template>
+
+<xsl:template match="section">
+ <h1><xsl:value-of select="@name"/></h1>
+ <xsl:apply-templates/>
+</xsl:template>
+
+<xsl:template match="option">
+ <div class="option"><xsl:apply-templates/></div>
+</xsl:template>
+
+<xsl:template match="manref">
+ <xsl:choose>
+ <xsl:when test="string-length(@href) &gt; 0">
+ <a class="manref"><xsl:attribute name="href"><xsl:value-of select="@href"/></xsl:attribute><xsl:value-of select="@name"/>(<xsl:value-of select="@section"/>)</a>
+ </xsl:when>
+ <xsl:otherwise>
+ <span class="manref"><xsl:value-of select="@name"/>(<xsl:value-of select="@section"/>)</span>
+ </xsl:otherwise>
+ </xsl:choose>
+</xsl:template>
+
+<xsl:template match="url">
+ <a class="url"><xsl:attribute name="href"><xsl:value-of select="@href"/></xsl:attribute><xsl:value-of select="@href"/></a>
+</xsl:template>
+
+</xsl:stylesheet>
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 @@
+<?xml version="1.0"?> <!-- -*-xae-*- -->
+<!DOCTYPE manpage SYSTEM "man.dtd">
+<?xml-stylesheet type="text/xsl" href="man.xsl" ?>
+
+<!-- $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.
+-->
+
+ <manpage name="syrep" section="8" desc="A file repository synchronization tool">
+
+ <synopsis>
+ <cmd>syrep [<opt>options...</opt>] <opt>--list</opt> <arg>SNAPSHOT</arg> ...</cmd>
+ <cmd>syrep [<opt>options...</opt>] <opt>--info</opt> <arg>SNAPSHOT</arg> ...</cmd>
+ <cmd>syrep [<opt>options...</opt>] <opt>--history</opt> <arg>SNAPSHOT</arg> ...</cmd>
+ <cmd>syrep [<opt>options...</opt>] <opt>--dump</opt> <arg>SNAPSHOT</arg> ...</cmd>
+ <cmd>syrep [<opt>options...</opt>] <opt>--update</opt> <arg>DIRECTORY</arg> ...</cmd>
+ <cmd>syrep [<opt>options...</opt>] <opt>--diff</opt> <arg>SNAPSHOT</arg> <arg>SNAPSHOT</arg></cmd>
+ <cmd>syrep [<opt>options...</opt>] <opt>--merge</opt> <arg>SNAPSHOT</arg> <arg>DIRECTORY</arg></cmd>
+ <cmd>syrep [<opt>options...</opt>] <opt>--makepatch</opt> <arg>DIRECTORY</arg> <arg>SNAPSHOT</arg></cmd>
+ <cmd>syrep [<opt>options...</opt>] <opt>--extract</opt> <arg>SNAPSHOT</arg> ...</cmd>
+ <cmd>syrep [<opt>options...</opt>] <opt>--cleanup</opt> <arg>SNAPSHOT</arg> ...</cmd>
+ </synopsis>
+
+ <description>
+
+ <p>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.</p>
+
+ <p>Files are tracked by their message digests, currently MD5.</p>
+
+ <p>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.</p>
+
+ <p>Syrep is able to cope with 64 bit file sizes. (LFS)</p>
+
+ <p>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.</p>
+
+ </description>
+
+ <section name="General options">
+
+ <p>Exactly one command has to be specified on the command line. On the other hand multiple options are allowed.</p>
+
+ <option>
+ <p><opt>-v</opt> | <opt>--verbose</opt> (option)</p>
+
+ <optdesc>Enable more verbose operation</optdesc>
+ </option>
+
+ <option>
+ <p><opt>-T</opt> | <opt>--local-temp</opt> (option)</p>
+ <optdesc>Use temporary directory inside repository. This is very useful when the file repository you apply patches to is on a different partition than /tmp, because files my be hard linked instead of copied. This requires a read-writable file system however.
+ </optdesc>
+ </option>
+
+ <option>
+ <p><opt>--ignore-origin</opt> (option)</p>
+ <optdesc>Normally syrep warns you if you update, merge or makepatch a repository with a matching snapshot not generated on the original host, and asks the user if he really wants to proceed. This option may be used to disable this question.
+ </optdesc>
+ </option>
+
+ <option>
+ <p><opt>-z</opt> | <opt>--compress</opt> (option)</p>
+ <optdesc>Compress output snapshots or patches. This may slow down syrep extraordinarily and is more or less useless if the data to compress is already compressed. I suggest using it for --update but not for --makepatch if the file repository contains MP3 or MPEG files only.
+ </optdesc>
+ </option>
+
+ <option>
+ <p><opt>-p</opt> | <opt>--progress</opt> (option)</p>
+ <optdesc>Show a rotating dash while executing operations</optdesc>
+ </option>
+
+ </section>
+
+ <section name="General commands">
+ <option>
+ <p><opt>-h</opt> | <opt>--help</opt> (command)</p>
+ <optdesc>Print help and exit</optdesc>
+ </option>
+
+ <option>
+ <p><opt>-V</opt> | <opt>--version</opt> (command)</p>
+ <optdesc>Print version information and exit</optdesc>
+ </option>
+
+ </section>
+
+ <section name="Listing snapshot contents">
+
+ <option>
+ <p><opt>--list</opt> (command)</p>
+ <optdesc>Command for listing the file log of a repository snapshot</optdesc>
+ </option>
+
+ <option>
+ <p><opt>--show-deleted</opt> (option)</p>
+ <optdesc>Show deleted entries</optdesc>
+ </option>
+
+ <option>
+ <p><opt>--show-by-md</opt> (option)</p>
+ <optdesc>Show files by message digests</optdesc>
+ </option>
+
+ <option>
+ <p><opt>--show-times</opt> (option)</p>
+ <optdesc>Show first and last seen times</optdesc>
+ </option>
+
+ </section>
+
+ <section name="Showing snapshot information">
+ <option>
+ <p><opt>--info</opt> (command)</p>
+ <optdesc>Show information about a repository or snapshot, such as origin, current timestamp and version, database size.</optdesc>
+ </option>
+ </section>
+
+ <section name="Showing snapshot history">
+ <option><p><opt>--history</opt> (command)</p>
+ <optdesc>Show the version and timestamp history of a snapshot's updates</optdesc>
+ </option>
+ </section>
+
+ <section name="Dumping snapshot contents">
+ <option><p><opt>--dump</opt> (command)</p>
+ <optdesc>Show a structure dump of a repository or snapshot</optdesc>
+ </option>
+ </section>
+
+ <section name="Updating a snapshot">
+ <option>
+ <p><opt>--update</opt> (command)</p>
+ <optdesc>Update or create a snapshot for a repository directory. That is: iterate through the specified hierarchy and update the snapshot log information accordingly.</optdesc>
+ </option>
+ <option>
+ <p><opt>-S</opt><arg>STRING</arg> | <opt>--snapshot=</opt><arg>STRING</arg> (option)</p>
+ <optdesc>Use the specified snapshot file instead of the one contained in the repository directory. This may be helpful if your file hierarchy is read only.</optdesc>
+ </option>
+ <option>
+ <p><opt>-C</opt><arg>STRING</arg> | <opt>--cache=</opt><arg>STRING</arg> (option)</p>
+ <optdesc>Use the specified message digest cache file instead of the one contained in the repository directory. This may be helpful if your file hierarchy is read only or when you plan to maintain a system wide message digest cache. In the latter case you should use <opt>--no-purge</opt> as well.</optdesc>
+ </option>
+ <option>
+ <p><opt>--no-cache</opt> (option)</p>
+ <optdesc>Don't use a message digest cache.</optdesc>
+ </option>
+ <option>
+ <p><opt>--no-purge</opt> (option)</p>
+ <optdesc>Don't purge obsolete entries from cache after update run. The may be useful if you plan to maintain a system wide message digest cache.</optdesc>
+ </option>
+ <option>
+ <p><opt>--ro-cache</opt> (option)</p>
+ <optdesc>Use cache in a read only fashion</optdesc>
+ </option>
+
+ </section>
+ <section name="Showing differences between two snapshots">
+ <option>
+ <p><opt>--diff</opt> (command)</p>
+ <optdesc>Show difference between two repositories or snapshots</optdesc>
+ </option>
+ </section>
+
+ <section name="Merging a snapshot into a directory">
+ <option>
+ <p><opt>--merge</opt> (command)</p>
+ <optdesc>Merge a snapshot or a patch into a repository. Afterwards, you should run <opt>--update</opt> on the repository to update the snapshot.</optdesc>
+ </option>
+ <option>
+ <p><opt>-q</opt> | <opt>--question</opt> (option)</p>
+ <optdesc>Ask a question before each action</optdesc>
+ </option>
+ <option>
+ <p><opt>--prune-empty</opt> (option)</p>
+ <optdesc>Prune empty directories</optdesc>
+ </option>
+ <option>
+ <p><opt>--keep-trash</opt> (option)</p>
+ <optdesc>Don't empty trash. Deleted files are copied into a trash folder inside the repository directory. If this option is specified this trash is not emptied when the operation is completed.</optdesc>
+ </option>
+ </section>
+
+ <section name="Making a patch for a snapshot against a directory">
+ <option>
+ <p><opt>--makepatch</opt> (command)</p>
+ <optdesc>Make a patch against the specified repository. The patch is written to STDOUT unless <opt>-o</opt> is specified.</optdesc>
+ </option>
+ <option>
+ <p><opt>-o</opt><arg>STRING</arg> | <opt>--output-file=</opt><arg>STRING</arg> (option)</p>
+ <optdesc>Write output to specified file instead of STDOUT</optdesc>
+ </option>
+ <option>
+ <p><opt>--include-all</opt> (option)</p>
+ <optdesc>Include files in patch which do exist on the other side under a different name</optdesc>
+ </option>
+ </section>
+
+ <section name="Extracting a snapshot's contents">
+ <option>
+ <p><opt>--extract</opt> (command)</p>
+ <optdesc>Extract the contents of a snapshot or patch to the local directory unless <opt>-D</opt> is specified.</optdesc>
+ </option>
+ <option>
+ <p><opt>-D</opt><arg>STRING</arg> | <opt>--output-directory=</opt><arg>STRING</arg> (option)</p>
+ <optdesc>Write output to specified directory</optdesc>
+ </option>
+ </section>
+
+ <section name="Cleaning up a repository">
+ <option>
+ <p><opt>--cleanup</opt> (command)</p>
+ <optdesc>Remove syrep info from repository</optdesc>
+ </option>
+
+ <option>
+ <p><opt>-l</opt><arg>INT</arg> | <opt>--cleanup-level=</opt><arg>INT</arg></p>
+ <optdesc>1: just remove temporary data and trash (default); 2: remove message digest cache as well; 3: remove all syrep data</optdesc>
+ </option>
+ </section>
+
+ <section name="Repositories, Snapshots and Patches">
+
+ <p>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
+ <file>$(REPOSITORY)/.syrep/current.syrep</file>. You may create
+ and update it by running <opt>--update</opt>. 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 <manref
+ name="cron" section="8"/></p>
+
+ <p>Two snapshots of two distinct repositories (possibly from
+ different hosts) may be compared with <opt>---diff</opt>. This
+ will show you which files should be copied or deleted from or to
+ the other repository. <opt>--makepatch</opt> 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 <opt>--merge</opt>.</p>
+
+ <p>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 <opt>--diff</opt> 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.</p>
+
+ <p>To extract the contents of a patch you may use
+ <opt>--extract</opt>. 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.</p>
+
+ </section>
+
+ <section name="Files">
+
+ <p><file>$(REPOSITORY)/.syrep/current.syrep</file> is the current
+ snapshot of the repository. It is created and updated by running
+ <opt>--update</opt> on the directory. Use this file to create
+ patches on other repositories against this one. This file may be compressed by specifiying <opt>--compress</opt> when running <opt>--update</opt>.</p>
+
+ <p><file>$(REPOSITORY)/.syrep/md-cache</file> is the message digest
+ cache which may be used to accelerate the repeated operation of
+ <opt>---update</opt>. 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. </p>
+
+ <p><file>$(REPOSITORY)/.syrep/trash/</file> is the trash directory
+ used by <opt>--merge</opt>. Files are moved in here on
+ deletion. After successful completion it is emptied unless
+ <opt>--keep-trash</opt> is specified.</p>
+
+ <p><file>$(REPOSITORY)/.syrep/tmp/</file> is used as temporary file
+ space for extracting snaphots when option <opt>--local-temp</opt>
+ is used.</p>
+ </section>
+
+ <section name="Return values">
+ <p><arg>0</arg> Success</p>
+ <p><arg>Nonzero</arg> Failure</p>
+ </section>
+
+ <section name="Author">
+ <p>Syrep was written by Lennart Poettering &lt;@PACKAGE_BUGREPORT@&gt;.</p>
+
+ <p>Syrep is available at <url href="@PACKAGE_URL@"/></p>
+
+ <p>You are encouraged to improve this documentation, feel free to send me patches. This is free software, after all.</p>
+ </section>
+
+ <section name="See also">
+ <p><manref name="rsync" section="1"/>, <manref name="cron" section="8"/></p>
+ </section>
+
+ <section name="Comments">
+ <p>This man page was written using <manref name="xml2man" section="1"
+ href="http://masqmail.cx/xml2man/"/> by Oliver Kurth.</p>
+ </section>
+
+ </manpage>
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] <command> [argument...]\n\n"
+ "Usage: %s [options...] <command> [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 <stdio.h>
#include <assert.h>
#include <stdlib.h>
@@ -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;
-
}