12

I am using CentOS 5.5 and would like to move a large amount of folders within one volume, retaining their mtime.

The best solution I could find is like this:

cp -p -r source/data target/
rm -rf source/data

With over 1TB of data on a NFS share, the copying takes forever. I do not want to copy. I want instantaneous move.

When I move a folder using mv source/data target/, the mtime of the folder (not the files) gets set to current time. This is because the contents of folder I am moving get modified by this operation (the .. entry is pointing to a different inode).

I came up with a following shell script I called mv_preserve_mtime.sh:

#!/bin/bash
# Moves source folder to target folder. 
# You are responsible for making sure the target does not exist, otherwise this blows up
export timestamp=`stat -c %y $1`
mv "$1" "$2"
touch --date="${timestamp}" $2

Well, that did not work either. The folder's mtime is restored, but all folders within the folder I move (only the ones 1 level deep) get their mtime reset for reasons I do not understand.

Does anyone have a proper, efficient and correct solution?

Roman Zenka
  • 305
  • 1
  • 2
  • 9
  • I wonder why your attempt with `touch` didn't work. Is it the `mv` step or the `touch` step that changes the mtime of the subdirectories? What OS is on the NFS server, and (if you know) what filesystem type? – Gilles 'SO- stop being evil' Dec 10 '10 at 20:22
  • @Gilles: I do not know why is it happening. It is the `mv` step that causes trouble. The NFS server is actually a NetApp storage, I know virtually nothing about its internals. – Roman Zenka Dec 10 '10 at 22:15
  • 1
    Thanks. I suspect it's a NetApp oddity. Otherwise `touch` should have worked. By the way a more portable way would be `touch -r "$1" reference.tmp; mv -- "$1" "$2"; touch -r reference.tmp -- "$2"; rm reference.tmp`. – Gilles 'SO- stop being evil' Dec 10 '10 at 22:29
  • @Gilles: Very interesting, did not realize `stat` was not portable. – Roman Zenka Dec 11 '10 at 17:09

2 Answers2

16

POSIX mv doesn't provide any option to ask for atime/mtime preservation, but as the operation is local to a same volume, you can ask cp to use hard-links instead of copying data of the regular files using the -l option:

cp -p -r -l source/date target/
rm -rf source/data

Since only directories and file references will be actually copied, it should go much faster:

For more informations on hard-links, you can consult the corresponding Wikipedia page

As for why subdirectories mtime is being reset with your current solution, it's because you only get and restore the parent directory mtime : touch is not a recursive command.

Eureka
  • 561
  • 4
  • 6
  • The mtime is more complicated than that. Only the parent directory and the directories directly under it have mtime changed. All other directories remain the same. One would expect either every single directory to be changed, or only the parent. – Roman Zenka Dec 09 '10 at 21:26
  • 1
    Actually, it makes sense: 1) The parent directory has the good mtime because it was explicitly set by touch, 2) The directory entries where recreated with the parent directory, but their mtime was not manually restored (Unix directory structure and inode format) 3) The rest of the tree structure wasn't actually changed, as we remained on the same volume : That's why `mv` has no "recursive" option, descending into subdirectories is only done if actual copy (different volumes, for example) is needed. – Eureka Dec 09 '10 at 21:51
  • @Eureka: Good explanation, but why is it done this way? If I was to implement `mv` on a directory `data`, I would simply change the `..` in the `data`'s contents and modify the `source` and `target` directories to list the moved item properly. No other directories would need to be touched. – Roman Zenka Dec 10 '10 at 05:51
  • 1
    @Roman Zenka After some search, this behaviour seems to be rather loosely specified between Unices and filesystems and to depend a lot of the underlying `rename` syscall implementation by the kernel and the used filesystem(s), NFS adding its share to the problem. There are some pointer referencing this kind of inconsistencies: http://patchwork.ozlabs.org/patch/25833/ http://bugs.opensolaris.org/bugdatabase/view_bug.do;jsessionid=cb4ea429e94190f02710a8255560?bug_id=6877802 – Eureka Dec 10 '10 at 09:56
  • @Eureka: I find it extremely hard to believe that something I would consider so basic can be such a mess. It is almost 2011. Thanks for those resources! – Roman Zenka Dec 10 '10 at 16:35
  • @Roman Zenka So do I... If you ever find a definitive explanation, I'll be interested: I couldn't find it yet. – Eureka Dec 10 '10 at 17:21
  • @Eureka Trying to do it on Android (because of this: https://stackoverflow.com/q/50540334/878126 ) I get this error : `cp: /data/local/tmp/test.apk: Cross-device link` . Any idea why? Is there perhaps a way to store and later restore the timestamp of the file? – android developer May 26 '18 at 07:51
4

Another solution may be:

rsync -a --remove-source-files source/data target/

Genjo
  • 141
  • 5