private static string SanitizeTarName(string path, Dictionary<string, string> usedNames)
{
string sanitizedPath = "";
Stack<string> bitsToEscape = new Stack<string>();
// Trim any trailing slashes (usually indicates path is a directory)
path = path.TrimEnd(new char[] { '/' });
// Take members off the end of the path until we have a name that already is
// a key in our dictionary, or until we have the empty string.
while (!usedNames.ContainsKey(path) && path.Length > 0)
{
string[] bits = path.Split(new char[] { '/' });
string lastBit = bits[bits.Length - 1];
int lengthOfLastBit = lastBit.Length;
bitsToEscape.Push(lastBit);
path = path.Substring(0, path.Length - lengthOfLastBit);
path = path.TrimEnd(new char[] { '/' });
}
if (usedNames.ContainsKey(path))
{
sanitizedPath = usedNames[path];
}
// Now for each member in the path, look up the escaping of that member if it exists; otherwise
// generate a new, unique escaping. Then append the escaped member to the end of the sanitized
// path and continue.
foreach (string member in bitsToEscape)
{
System.Diagnostics.Trace.Assert(member.Length > 0);
string sanitizedMember = SanitizeTarPathMember(member);
sanitizedPath = Path.Combine(sanitizedPath, sanitizedMember);
path = path + Path.DirectorySeparatorChar + member;
// Note: even if sanitizedMember == member, we must add it to the dictionary, since
// tar permits names that differ only in case, while Windows does not. We must e.g.:
// abc -> abc
// aBC -> aBC (1)
if (usedNames.ContainsKey(path))
{
// We have already generated an escaping for this path prefix: use it
sanitizedPath = usedNames[path];
continue;
}
// Generate the unique mapping
string pre = sanitizedPath;
int i = 1;
while (DictionaryContainsIgnoringCase(usedNames, sanitizedPath))
{
sanitizedPath = string.Format("{0} ({1})", pre, i);
i++;
}
usedNames.Add(path, sanitizedPath);
}
return sanitizedPath;
}