


	Possible ways of handling deleted files


Each deleted file/directory could be tagged in the overlay with another
file, consisting of a modified version of the original filename.
For example, appending the string '[DELETED]' would create a filename
visible in a directory listing, but very unlikely to be created
by a user because of the presence of shell meta-characters.

Now, when attempting to access the file, if the pathname doesn't exist
in the overlay, but a pathname+'[DELETED]' file exists,
overlays_match() immediately returns NULL with errno = ENOENT.

Consider the case where an underlying directory is deleted (flagged in
overlay) and then recreated.  The unions.so module, after finding
the '[DELETED]' entry, has to ignore anything in the underlying
directory.  So, finding a '[DELETED]' entry must cause the overlays
tree to be "truncated" at the overlay for the remainder of the
path lookup.

Here's an example of the kind of trouble you can get into using
this program.  I was running bash with "unions" preloaded, and
was cd'ed inside my overlay tree.  I had the binary code for a
program overlayed on top the source code, and most of the
directories were replicated in both trees.  The directory
I was interested in was called "boot", and I had a backup of
the source code in that directory in another dir called "boot.bak".
I wanted to swap the two directories.

	$ mv boot boot.changed

This flags directory "boot" as deleted, by creating a zero-length file
called "boot[DELETED]" in the overlay partition.  Creating a directory
isn't good enough, since a directory could exist just because an
underlying file was deleted (to hold it's [DELETED] file).

Next, create "boot.changed" as a symlink to "!boot".  Symlinks
starting with "!" are special - they point to a name in the underlying
tree, not the parent.  cwd.so, when lstat()ing, sees a real directory,
not a symlink, and recurses into it.  This means that unions.so needs
to lstat() each element of an overlay path (in a delete overlay) to
see if it's a symlink, and to see if a [DELETED] file exists.

Now, our overlay looks like:

		boot[DELETED]
		boot.changed -> !boot

	$ touch boot.changed/stuff

This creates "stuff" in the overlay's "boot" directory, by following
the special symlink as the name gets expanded.

		boot/stuff
		boot[DELETED]
		boot.changed -> !boot

	$ mv boot.changed/dir1 boot.changed/dir1.changed

This creates a symlink (dir1.changed -> !dir) in the overlay's
"boot" directory, as well as a zero length file called "dir1[DELETED]".

		boot/stuff
		boot/dir1[DELETED]
		boot/dir1.changed -> !dir1
		boot[DELETED]
		boot.changed -> !boot

	$ mv boot.changed boot.changed.again

This flags "boot.changed" as deleted, and makes "boot.changed.again"
a symlink to the original "boot" in the underlying partition.

		boot/stuff
		boot/dir1[DELETED]
		boot/dir1.changed -> !dir1
		boot[DELETED]
		boot.changed[DELETED]
		boot.changed.again -> !boot

	$ mv boot.bak boot

This flags directory "boot.bak" as deleted, and makes "boot/boot.bak"
a symlink to "!../boot.bak".  This is because boot exists in the
overlay as a directory, so we have to follow directory semantics.

		boot/stuff
		boot/dir1[DELETED]
		boot/dir1.changed -> !dir1
		boot/boot.bak -> !../boot.bak
		boot[DELETED]
		boot.bak[DELETED]
		boot.changed[DELETED]
		boot.changed.again -> !boot
