Monday 24 October 2011

Just do it!

So I ran into a "cp: cannot overwrite non-directory" problem. It means I've tried to overwrite a symbolic link with a directory with the same name.
Imagine you have a folder structure:
/folder2/
          /test1.txt
/folder1/
          / folder2->../folder2/ /
                                  /test1.txt


And
/folder3/
          /folder2/
                    /test1.txt
       
To try this out:
:/tmp$ mkdir folder2
:/tmp$ touch folder2/test1.txt
:/tmp$ mkdir folder1
:/tmp$ cd folder1
:/tmp/folder1$ ln -s ../folder2 .
:/tmp/folder1$ cd ../
:/tmp$ mkdir folder3
:/tmp$ cd folder3
:/tmp/folder3$ mkdir folder2
:/tmp/folder3$ touch folder2/test1.txt
:/tmp$ cp -rf folder3/folder2 folder1/
cp: cannot overwrite non-directory `folder1/folder2' with directory `folder3/folder2'

I tried googling but my searching skills were bad today and 'man' page wasn't helpful too. It seems basic cp cannot do the trick.
Now, I do know python/ruby/perl/shell/many other fancy words however I need to copy really large number of files, millions. Estimations show that just plain cp would take a few days to complete, what can we expect from all those less then perfect scripts?

But as one guy (don't really remember his name) said: "Those that can, do. Those that can't, complain" so the real solution is in the very soul of open source:
cd /tmp
mkdir coreutils
sudo apt-get build-dep coreutils
apt-get source coreutils
emacs coreutils-8.5/src/copy.c

Now the diff is:
--- coreutils-8.5/src/copy.c 2010-04-20 22:52:04.000000000 +0300
+++ /tmp/new/copy.c 2011-10-24 17:50:49.633017303 +0300
@@ -1412,10 +1412,21 @@
                     }
                   else
                     {
-                      error (0, 0,
-                       _("cannot overwrite non-directory %s with directory %s"),
-                             quote_n (0, dst_name), quote_n (1, src_name));
-                      return false;
+                      if (unlink (dst_name) != 0)
+                        {
+                          error (0, errno, _("cannot remove %s"), quote (dst_name));
+                        }
+                      if (x->verbose)
+                        printf (_("removed %s\n"), quote (dst_name));
+
+                      /* Tell caller that the destination file was unlinked.  */
+                      new_dst = true;
+                    
+
+                      /* error (0, 0, */
+                      /*  _("cannot overwrite non-directory %s with directory %s"), */
+                      /*        quote_n (0, dst_name), quote_n (1, src_name)); */
+                      /* return false; */
                     }
                 }
 

And build it:
./configure --prefix=/home/sam/new-coreutils
make
make install
cd /tmp
~/new-coreutils/bin/cp -rf folder3/folder2 folder1/
 
Now it works as I need here.

No comments:

Post a Comment