I therefore have to transfer the music files piece meal. I have therefore written a bit of perl that supports the copying of files but maintains a Tag file of what files have been transferred - ie its a simple mirror program that:
- Keeps a record of files that already been copied;
- Restricts the files transferred to those with a given suffix (currently .mp3);
- Fails carefully when out of space on target directory;
- Will recopy files that have changed since original copy.
Usage is (mount/umount will probably have be done as root):
- Mount memory card on your linux computer
Eg: if you're card is /dev/sdb and you have created a directory /tmp/ext, as root:
mount -t auto /dev/sdb /tmp/ext - Make sure memory card is empty:
rm -rf /tmp/ext/* - Run perl copy script calling out:
- The tags file you want to use
- The Source directory
- The Target directory on your memory card:
Eg:
./cpto.pl ~/carmusic.tags /home/music /tmp/ext/music - This will either complete fully or will fail with "No space left on device"
- Unmount the card on your linux computer:
umount /tmp/ext - Put memory card in your ICE and copy to Hard Disk selecting Replace files
- If step 4 failed with "No space left on device" then repeat from step 1.
/home/music/la_roux/la_roux/armour_love.mp3^1251554384^C /home/music/la_roux/la_roux/reflections_are_protection.mp3^1251554386^C /home/music/la_roux/la_roux/growing_pains.mp3^1251554686^C /home/music/Green Day/International Superhits/Basket Case.mp3^1235913966^C /home/music/Green Day/International Superhits/Brainstew.mp3^1235914182^C /home/music/Green Day/International Superhits/Geek Stink Breath.mp3^1235914132^C /home/music/Green Day/International Superhits/Good Riddance Time of Your Life.mp3^1235914370^C /home/music/Green Day/International Superhits/Hitchin A Ride.mp3^1235914324^C /home/music/Green Day/International Superhits/JAR Jason Andrew Relva.mp3^1235914098^C /home/music/Green Day/International Superhits/Jaded.mp3^1235914206^.Note that the file format is:
FromFileName^ModificationTime^Status
Where Status is "." if copy is in progress and "C" is completed copy. Source: cpto.pl
#!/opt/bin/perl
# This perl script is used to mirro files from one dir to another
# It keeps a tag file of files that have been copied and the modification time
# of the source file when copy was done so that copies
# are not repeated.
#
# It is designed to fill up a device with files to be copied until its out of space
# You can then do what you want with the files on the device (eg copy them to another device)
# clear the device nd run the copy again. The tags file ensures that only as yet uncopied
# files are placed on the device.
#
# I wrote this so that I can transfer my music files to my car's enterntainment system using
# a 2Gb memory card - the maximum card size supported by the ICE.
#
# Usage:
# cpto.pl tagFileName /home/music /mnt/extcard/music
# Author: Tony.Jewell@Cregganna.Com
# See: http://www.tonyjewell.com/2013/10/copying-music-to-in-car-entertainment.html
# Disclaimer: I take not responsibility for any damage or other nepharious effects this
# script will have on your PC - use at yoru own risk.
use strict;
use warnings;
use diagnostics;
use File::stat;
use File::Basename;
use File::Path;
if ( $#ARGV < 2 ) {
print "Usage: cpto TagFile Source Destination\n";
exit 1;
}
my @suffixes = ( ".mp3" );
my $buffSize = 8 * 2**10;
my $tagsFile = "${ARGV[0]}";
# tags is keyed by file name and value is date/time of cp from file
my %tags;
sub loadTags {
# Check that we can write to it
open (TAGS, ">>${tagsFile}") || die "Unable to open ${tagsFile} for writing: $!";
close(TAGS);
if ( -f "${tagsFile}" ) {
open( my $TAGS, "<${tagsFile}") || die "Unable to open ${tagsFile}: $!";
while (my $tagLine = <$TAGS>) {
chomp $tagLine;
my @tag = split('\^', $tagLine);
if ($#tag >= 2 && $tag[2] =~ "C") {
$tags{$tag[0]} = $tag[1];
}
}
close(TAGS);
}
}
# We write a start Copy to make sure there is room to write to the tags file
# This writes a pending line with status "."
sub tagStartCopy {
my $name = shift;
my $mtime = shift;
open (TAGS, "+<${tagsFile}") || die "Unable to open ${tagsFile} for writing: $!";
# Seek to end
sysseek(TAGS, 0, 2 ) || die "Unable to seek file $tagsFile: $!";
my $tagPos = tell(TAGS);
syswrite(TAGS, "$name^$mtime^.\n"); # Mark as pending
close(TAGS) || die "Unable to close $tagsFile after writing: $!";
return $tagPos;
}
# Rewrite the tag line with the completed copy status of "C".
sub tagEndCopy {
my $tagPos = shift;
my $name = shift;
my $mtime = shift;
open (TAGS, "+<${tagsFile}") || die "Unable to open ${tagsFile} for writing: $!";
sysseek(TAGS, $tagPos, 0 ) || die "Unable to seek file $tagsFile: $!";
syswrite(TAGS, "$name^$mtime^C\n");
close(TAGS) || die "Unable to close $tagsFile after writing: $!";
$tags{$name} = $mtime;
}
sub chkDirExists {
my $dir = dirname(shift);
if (! -d $dir) {
mkpath($dir) || die "Unable to create Directory: $dir: $!";
}
}
sub cpFile {
my $fromName = shift;
my $toName = shift;
my($filename, $directories, $suffix) = fileparse($fromName, @suffixes);
if ( ! $suffix ) {
return;
}
my $from = stat($fromName) || die "Unable to stat $fromName: $!";
my $tag = $tags{$fromName};
if ( $tag && $tag >= $from->mtime ) {
# Already done this one
return;
}
print "$fromName => $toName....";
&chkDirExists($toName);
my $tagPos = &tagStartCopy($fromName, $from->mtime);
open( IN, "< $fromName") || die "Unable to open for Reading: $fromName: $!";
open( OUT, "> $toName") || die "Unable to open for Writing: $toName: $!";
binmode(IN);
binmode(OUT);
my $buff;
while (read(IN, $buff, $buffSize)) {
print OUT $buff;
}
close( IN ) || die "Unable to close for Reading: $fromName: $!";
close( OUT ) || die "Unable to close for Writing: $toName: $!";
&tagEndCopy($tagPos, $fromName, $from->mtime);
print "\n";
}
sub cpDir {
my $fromName = shift;
my $toName = shift;
opendir(my $DIR, $fromName) || die "Unable to read directory: $fromName: $!";
while(my $file = readdir $DIR) {
if ( ! ($file =~ /^[.]+$/ ) ) {
&cp($fromName . '/' . $file, $toName . '/' . $file);
}
}
closedir $DIR;
}
sub cp {
my $fromName = shift;
my $toName = shift;
if (-d $fromName) {
&cpDir($fromName, $toName);
} elsif (-f $fromName) {
&cpFile($fromName, $toName);
}
}
&loadTags();
&cp($ARGV[1], $ARGV[2]);