Tuesday, April 13, 2004

How to copy files

A deceptively simple question was asked on freebsd-questions:


How do I copy all the files, including subdirectories, from a cdrom to an arbitrary direcory?


My first inclination is to merely use cp:


$ cp -Rp /cdrom .


This will copy all the files from a (mounted) CDROM to a folder in your currently directory called 'cdrom'. The -R says to do it recursively, thus picking up all the subfolders (creating them in the destination folder as well), while the -p says to preserve the various attributes, like mod time and user id.



Actually, to be truly honest, I normally would have suggested cp -r /cdrom . as a command. But the -r (note lowercase) is an archaic, obsolete and "strongly discouraged" option, as it has even more trouble with non-standard files like links and other special files.



There are, however, a couple of problems with this. One is that I can never remember at what depth is the destination folder created - ie., does it create the cdrom folder, or will it copy all the files in cdrom in the current directory? There is a subtle but important difference between cp -R /cdrom . and cp -R /cdrom/* .. The latter starts in the /cdrom directory for the files, while the former will create the cdrom directory in the current directly and then start copying.



Another, perhaps more important problem has to do with links. Symbolic links are copied like files, which may mean they no longer make sense. Ie, if you had a symbolic link that pointed to ../../test/test.cpp, and didn't copy the test folder, then it wouldn't point to anything useful. And hard links are not copied as links at all, but rather are copied as separate files, which may or may not be what you want.



To get away from those problems, the man pages suggests tar(1), cpio(1) or pax(1). Here's how it was suggested by Matthew Seaman on how to do it via tar:


% cd /cdrom

% mkdir /home/jerry/cdimage

% tar -cvf - . | ( cd /home/jerry/cdimage ; tar -xvpf - )



This tells tar to dump the current directory to stdout, and then cd to the destination directory and read the input from stdin. A cool example of using Unix building blocks, bringing them together via the wonders of stdin and stdout and pipes.






No comments:

Post a Comment