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

Reply via email to