Monday, September 21, 2009

Backing Up Via FTP

Backing Up Via FTP

I've been thinking of backing up to a remote server, since I have 100 GB of storage included in my domain. The obvious way to do this is via ftp--but it only makes sense to backup new files, or files modified since the last backup.

Back when I wrote PC-DOS programs, I had occasion to build some cool little utilities that made this pretty easy: one was a program that took two file names, compared the file modification dates, then copied the first file to the second file.

NEWER *.* f:*.*

It would thus compare files in the current hard disk directory to those in the current hard disk directory on drive F:, and copy all files to F: that were either not present on F:, or that had a more recent modification date than the version on F:.

I was going to write a similar program that used FTP, but it occurred to me that there may already be such a program out there that one of my reader is using. Any suggestions?

UPDATE: Oh my, was I impressed how many of you responded! While I was waiting for answers, I started writing my own FTP backup as a C# console application, and I had it working well enough that it was successfully doing backups when I started receiving your replies. Here's the core of the code--I could probably have spent a few more hours verifying that I had all the exceptions properly handled, but there were so many existing programs available to do this, it wasn't worth the effort:
class Update
{
static void Main(string[] args)
{
if (args.Length != 3)
{
Console.WriteLine("USAGE: [directory to backup] [files to backup] [destination for backup]");
return;
}
DirectoryInfo dir = new DirectoryInfo(args[0]);
FileInfo[] files = dir.GetFiles(args[1]);
foreach (FileInfo file in files)
{
DateTime lastWriteTime = file.LastWriteTime;
string name = file.Name;
Uri uri = new Uri(args[2] + "/" + name);
FtpWebRequest request = (FtpWebRequest)WebRequest.Create(uri);
FtpWebResponse response = null;
//request.EnableSsl = true;
request.Method = WebRequestMethods.Ftp.GetDateTimestamp;
try
{
response = (FtpWebResponse)request.GetResponse();
}
catch (WebException ex)
{
Console.WriteLine("file " + name + " does not exist on backup server");
BackupFile(dir, file, args[2]);
}
catch (AuthenticationException ex)
{
Console.Write(ex.ToString());
}
if (response != null && lastWriteTime > response.LastModified)
{
Console.WriteLine(name + " local time=" + lastWriteTime + "; server write time=" + response.LastModified);
BackupFile(dir, file, args[2]);
}
}
Console.WriteLine("done");
}

private static void BackupFile(DirectoryInfo dir, FileInfo file, string destBackup)
{
try
{
Uri uri = new Uri(destBackup + "/" + dir.Name + "/" + file.Name);
FtpWebRequest request = (FtpWebRequest)WebRequest.Create(uri);
request.Method = WebRequestMethods.Ftp.UploadFile;
// Copy the contents of the file to the request stream.
StreamReader sourceStream = new StreamReader(file.Name);
byte[] fileContents = Encoding.UTF8.GetBytes(sourceStream.ReadToEnd());
sourceStream.Close();
request.ContentLength = file.Length;
Stream requestStream = request.GetRequestStream();
requestStream.Write(fileContents, 0, (int)file.Length);
requestStream.Close();
FtpWebResponse response = (FtpWebResponse)request.GetResponse();
response.Close();
}
catch (Exception ex)
{
Console.WriteLine(ex.ToString());
}
}
}
Most of my readers suggested using one of the Windows ports of rsync, which talks to most *nix systems. Here's one. There were several suggestions that I use FileZilla, an open source program for this purpose. Unison was also suggested, but it required more than zero thought to install, so I didn't pursue that. I ended up installing SyncBack, a freeware program that has a nice GUI, and seems to be working just fine.

Thanks to all for your suggestions!

No comments:

Post a Comment