FileSnap: Save Files with Snapshots

By Mitch Stuart
Copyright © 2002-2003 FullSpan Software  -  Usage subject to license
Software Version: 1.3  -  Document Version: $Revision: 1.4 $, $Date: 2003/12/31 07:30:21 $

Contents

1. Introduction

2. Using FileSnap

2.1. FileSnap Operation

2.2. Options

2.3. Environment Variable

2.4. Examples

3. Installation

3.1. Windows

3.2. *nix

4. Motivation

5. Goals

6. Programming and Testing Information

1. Introduction

FileSnap is a Perl program (script) that makes it easy to take a "snapshot in time" of a file (or set of files), so that you can later recover or compare different versions of the file. You run FileSnap and give it the names of the files you want to snapshot, and it makes a copy of each file with a snapshot sequence number embedded in the filename. FileSnap works with any kind of file - it simply automates and streamlines the process of copying the file with a new name for safekeeping.

When I am working on the computer, I often feel the need to save interim versions of a file, whether I am writing, programming, doing system administration, working on financial records, etc. A typical case is when I have gotten a program working to a certain degree, and I want to introduce a new feature or try a new algorithm. It's nice to take a snapshot of the file(s) before starting the changes — if the changes don't work out, I can easily revert to the prior version without having to manually remove my changes and reconstruct the file as it was before.

Getting FileSnap

2. Using FileSnap

To run FileSnap from the command line, use the following syntax:
  filesnap.pl [options] fileList
FileSnap copies each file and directory named on the command line to the FileSnap destination directory, giving it a new name that is based on the original name, but with a snapshot sequence number embedded. The fileList can be one or more files or directories (or a mixture), and wildcards are allowed.

For example, if you run this command:

  filesnap.pl shopping.txt taxes.xls
FileSnap will create two files in the destination directory: shopping_fs0001.txt and taxes_0001.xls. (This example assumes you have set the default destination directory as discussed below.)

You can install FileSnap in a way that makes it more convenient to invoke, by using a short alias for the script name, or (on Windows) using a "Send To" menu entry to snapshot files directly from Windows Explorer:

Example of Send To menu

These installation options are discussed in detail in the Installation section.

2.1. FileSnap Operation

FileSnap processes the files you select in the following way:

2.2. Options

The available options are shown below. You can use either single letters (like -d) or full names (like -destdir) for the option name. The only required option is the destination directory.

The following options are used mainly for debugging or testing.

2.3. Environment Variable

The FILESNAP_OPT environment variable can be used to specify options rather than having to type them on the command line. For example, you should set FILESNAP_OPT to your default destination directory (for example, "-d c:\backup" or "-d /home/someuser/backup"). Then, each time you run FileSnap, that directory will be used as the snapshot destination.

If you have some compound extensions that you use on a regular basis, you should also include those in your FILESNAP_OPT variable definition.

If you specify an option on the command line, it overrides the setting of that option (if any) in the FILESNAP_OPT variable. This allows you to, for example, set a default destination directory for most executions of FileSnap, but then use an alternate destination on occasion as needed.

2.4. Examples

Let's assume we have a directory called src, with subdirectories and files as follows:
  src/
    a.txt
    b.txt
    .bashrc
    dir1/
      c.txt
      d.txt
      dir1a/
        e.txt
    dir2/
      c.txt
    dir3/
      f.foo.bar
The following table shows a sequence of FileSnap commands, and the resulting files and directories that are created (this assumes that the destination directory has been specified with the FILESNAP_OPT variable).

FileSnap Command and Resulting Files Comments
filesnap.pl src/a.txt

Creates:

dest/
  a_fs0001.txt
The simplest FileSnap case copies a single file.
filesnap.pl src/*.txt

Creates:

dest/
  a_fs0002.txt
  b_fs0002.txt
This example shows the usage of wildcards. Note that the snapshot sequence number has increased from 0001 to 0002, and the same snapshot tag has been applied to all the files specified in this run of FileSnap. The file a.txt now has two snapshots in the destination directory: a_fs0001.txt and a_fs0002.txt.
filesnap.pl src/.bashrc

Creates:

dest/
  .bashrc_fs0003
This example shows the special-case treatment of a filename beginning with a period. As discussed above, in this case the text following the initial period is treated as the basename of the file, not as the extension.
filesnap.pl src/dir1 src/dir2

Creates:

dest/
  dir1_fs0004/
    c.txt
    d.txt
    dir1a/
      e.txt
  dir2_fs0004/
    c.txt
This example shows how snapshots of directories work. Note that the entire directory, including all of its files and directories, is copied to the destination.

Notice that only the directory name is transformed by the insertion of the snapshot tag. There is no need to transform the filenames of the contained files and directories because they are safely stored underneath the unique snapshot directory name.

filesnap.pl dir1/c.txt dir2/c.txt

Creates:

dest/
  c_fs0005.txt
  c_fs0006.txt
This examples shows how duplicate filenames are handled. When FileSnap finds a duplicate file or directory name in the list of files to be saved, it increments the snapshot sequence number. This duplicate detection and sequence number change only applies to "top level" files.

The snapshot sequence number is only incremented when it would cause a conflicting filename. This becomes clear by looking at the difference between the previous example and this one. In both cases, two instances of c.txt were copied. But in the previous case, the c.txt files were underneath directories that were copied, whereas in this case the c.txt files are copied as top-level files.

filesnap.pl -e .foo.bar dir3/*

Creates:

dest/
  f_fs0007.foo.bar
This example shows how compound extensions work. Note the placement of the snapshot tag in between the base name and the compound extension.

3. Installation

3.1. Windows

  1. Save filesnap.pl to a local directory, for example, c:\bin\filesnap.pl.

  2. Create a directory to hold your snapshots, for example, c:\backup\filesnap.

  3. Create an environment variable named FILESNAP_OPT, with a value that sets the FileSnap destination directory. For example, -d c:\backup\filesnap. (Search in Windows Help for "environment variable" if you need help with this.)

  4. Open a new command prompt window. Type echo %FILESNAP_OPT% and make sure the FILESNAP_OPT variable is set properly.

  5. Run FileSnap on a sample file, using a command like the following (adjust the paths for your environment):
      c:\perl\bin\perl c:\bin\filesnap.pl test.txt

    Check the destination directory and make sure the file was saved.

  6. Create a batch file to call FileSnap with a shorter command line. Call it fs.bat (or another name of your choice), and add the following lines (adjust the paths for your environment):
      @echo off
      c:\perl\bin\perl c:\bin\filesnap.pl %*

    Test the batch file with a command like:

      fs test.txt

    Check the destination directory and make sure the file was saved.

  7. Install FileSnap as a Send To option. This will allow you to right-click on files and directories in Windows Explorer and save snapshots of them with FileSnap. Create a new Send To item (search in Windows Help for "send to" if you need help with this). For the Target, enter a command like the following (adjust the paths for your environment):
      C:\perl\bin\wPerl.exe c:\bin\filesnap.pl

    and for the name, enter FileSnap (or another name of your choice).

    To test the Send To feature, right-click on a filename in Windows Explorer, select "Send To", and choose FileSnap from the context menu that appears. Check the destination directory to make sure the file was saved.

    Note the use of wPerl.exe instead of Perl.exe. wPerl is part of the ActiveState Perl distribution for Windows. (wPerl or a similar program may be available with other distributions also.) It is almost identical to Perl.exe, except that wPerl.exe is marked as a Windows GUI application, whereas Perl.exe is marked as a Windows Console application. If you use Perl.exe from a Send To command, or another GUI launch method, you may see the flash of a Command Prompt (Console) window opening and closing. Because wPerl.exe is marked as a GUI applcation, it does not cause a Command Prompt to open. (If you do not have wPerl.exe available, you should still be able to create a Send To item using the standard Perl.exe.)

3.2. *nix

  1. Save filesnap.pl to a local directory, either a user directory such as /home/someuser/bin or a common directory such as /usr/local/bin. Make the script executable with chmod if necessary.

  2. Create a directory to hold your snapshots, for example, /home/someuser/backup/filesnap.

  3. Create an environment variable in your startup file (.bashrc or similar) named FILESNAP_OPT, with a value that sets the FileSnap destination directory. For example:
      export FILESNAP_OPT="-d /home/someuser/backup/filesnap"

  4. Open a new shell window. Type echo $FILESNAP_OPT and make sure the FILESNAP_OPT variable is set properly.

  5. Run FileSnap on a sample file, using a command like the following (adjust the paths for your environment):
      /home/someuser/bin/filesnap.pl test.txt

    Check the destination directory and make sure the file was saved.

  6. Add an alias to your startup file (.bashrc or similar), for example:
      alias fs='/home/someuser/bin/filesnap.pl'

    Test the alias with a command like:

      fs test.txt

    Check the destination directory and make sure the file was saved.

4. Motivation

There are ways other than FileSnap to accomplish the same general thing, but those methods have their limitations:

Each of these file-saving methods has its place, and I use all of them. But I use FileSnap for the very specific task of taking quick file snapshots throughout the day.

5. Goals

These are the design and implementation goals that I had in mind for FileSnap.

6. Programming and Testing Information

FileSnap is written in Perl for portability. Along with the main filesnap.pl script, there is also a test script called filesnap_test.pl. Run filensnap_test.pl with no arguments for a usage message. Depending on your Perl version and distribution, to run the filesnap_test.pl (but not filesnap.pl itself) you may need to get the Test::Simple and Test::Harness modules from CPAN if they are not already installed in your environment. Just run filesnap_test.pl with no arguments and you will get a message if the modules are not currently installed in your environment.

FileSnap has been tested primarily on Windows 2000, Windows XP, Cygwin, and Linux. Earlier versions were tested on Solaris and FreeBSD. The testing was done with various versions of Perl, all of which were 5.6.0 or above.

There are two platform-specific issues that had to be addressed in the code. First, Windows does not support shell globbing (expansion of filename wildcard characters by the shell prior to invoking a program). Therefore, if FileSnap encounters the * or ? characters in a filename on the command line, it uses the File::DosGlob 'glob' function to expand the filename into all matching names. Second, Windows paths specified on the command line may include backslashes, which causes problems when doing manipulation of those strings. Fortunately, Perl on Win32 works just fine using forward slashes as the separator character, so FileSnap internally translates backslashes to forward slashes.