simple snapshotting via copying (plus ramdisks support)

A Snapshotter can provide a path to a 'snapshot' of one or more directories.

An example use case might be snapshotting a source tree to avoid seeing inconsistent sources due to change during a build.

get() on a Snapshotter returns the path to a new snapshot
destroy(path) expects to be handed a value previously returned by calling get() on the same

A snapshotter delegates to a SnapshotManager dir_manager for creating and destroying directories.
Beyond the simple mkdir/rmtree, an example dir_manager might mount and unmount ramdisks (see OsxRamDiskManager)

To avoid blocking builds on copying when get() is called, a more advanced Snapshotter might choose to keep a snapshot ready by listening for file system changes until get() is called. Such and implementation will be in a followup commit.