I was trying to combine the many options of cp to create a simple backup program when
I run into an unexpected behaviour of the program. I was using the cp from the
fileutils 1.4.2 distribution, so I downloaded coreutils-5.0 and compiled it and I
still have the same problem. Here it is the test case.
Run this script
------------------------------------------------------------------------------
#!/bin/sh
if [ ! -d bug-demo-dir ]; then
mkdir bug-demo-dir
else
rm bug-demo-dir/*
fi
cd bug-demo-dir
echo source > source
cp --backup=numbered --preserve --update source dest
cp --backup=numbered --preserve --update source dest
ls -la dest*
------------------------------------------------------------------------------
(The --backup option is there only to spot the problem more easily.)
You'll see that the source file is copied twice.
The behaviour I expected is that the second run of cp won't copy anything, because the
source file didn't change.
However cp does copy it and this seems to break the semantic of the --update option,
if I got it right.
I looked at the source code (src/copy.c) and I found that utime is used to preserve
the timestamps. It seems that utime sets the nanoseconds of the timestamp of the
destination file to zero, making it older than the source file. That's why it is
copied again over the destination after the check made by --update on the second run
of cp.
The fix I devised is to make cp check if --update is used together
--preserve=timestamps
In that case cp will use a modified timestamp comparation macro that doesn't look at
the nanoseconds. IMHO this
level of inaccuracy is good enough for the kind of applications that the combination
of those two options is useful for. The patch is below.
(copy-original.c is the file in the coreutils distribution, copy-new.c is my version)
------------------------------------------------------------------------------
--- copy-original.c 2003-03-11 19:02:23.000000000 +0100
+++ copy-new.c 2004-01-09 12:56:56.497432000 +0100
@@ -46,6 +46,12 @@
#include "same.h"
#include "xreadlink.h"
+
+/* 2 macros to handle timestamp comparison in the --preserve --update case */
+#define ST_TIME_CMP_SEC(a, b, s) \
+ ((a).s < (b).s ? -1 : (a).s > (b).s ? 1 : 0)
+#define MTIME_CMP_SEC(a, b) ST_TIME_CMP_SEC (a, b, st_mtime)
+
#define DO_CHOWN(Chown, File, New_uid, New_gid)
\
(Chown (File, New_uid, New_gid) \
/* If non-root uses -p, it's ok if we can't preserve ownership. \
@@ -800,6 +806,7 @@
int copied_as_regular = 0;
int ran_chown = 0;
int preserve_metadata;
+ int preserve_update_test;
if (x->move_mode && rename_succeeded)
*rename_succeeded = 0;
@@ -906,8 +913,20 @@
return 1;
}
- if (x->update && MTIME_CMP (src_sb, dst_sb) <= 0)
- {
+ /* If --update is used in combination with preservation of
+ * timestamps, don't use nanoseconds when comparing timestamps.
+ */
+ if (x->preserve_timestamps && x->update)
+ {
+ preserve_update_test = MTIME_CMP_SEC (src_sb, dst_sb);
+ }
+ else
+ {
+ preserve_update_test = x->update
+ && MTIME_CMP (src_sb, dst_sb);
+ }
+ if (preserve_update_test <= 0)
+ {
/* We're using --update and the source file is older
than the destination file, so there is no need to
copy or move. */
------------------------------------------------------------------------------
If you run the test script with this version of cp you'll see that it copies the
source file only once.
If I'm mistaken about the semantic of --update or if there is a way to get this result
without patching cp, I'd love to learn it.
Paolo
--
Play Go! http://www.figg.org
_______________________________________________
Bug-coreutils mailing list
[EMAIL PROTECTED]
http://mail.gnu.org/mailman/listinfo/bug-coreutils