Groups | Blog | Home
all groups > dotnet sdk > june 2006 >

dotnet sdk : get canonical filename?



David Thielen
6/15/2006 9:11:17 AM
Hi;

How can I get the canonical version of a filename. For example, if I pass in
c:/windows/fonts I get back C:\\WINDOWS\\Fonts (how it is on my system).

--
thanks - dave
david_at_windward_dot_net
http://www.windwardreports.com
Peter Ritchie
6/15/2006 2:39:01 PM
Path.GetFullPath(text) works for me.

--
http://www.peterRitchie.com/


[quoted text, click to view]
David Thielen
6/15/2006 2:51:02 PM
I tried that and got back fonts instead of Fonts.

--
thanks - dave
david_at_windward_dot_net
http://www.windwardreports.com



[quoted text, click to view]
Peter Ritchie
6/15/2006 6:22:01 PM
I wouldn't consider that canonical... Short of recursively calling Platform
SDK FindFirstFile on each directory part, I don't think a single function or
method exists to get the "actual" file/path matching case.

--
http://www.peterRitchie.com/


[quoted text, click to view]
David Thielen
6/15/2006 6:54:02 PM
That's what I was afraid of. Java has this but probably because in the unix
world Fonts and fonts are different directories.

--
thanks - dave
david_at_windward_dot_net
http://www.windwardreports.com



[quoted text, click to view]
Peter Ritchie
6/15/2006 8:01:02 PM
Yep, "Fonts" and "fonts" are the same in Windows... But, it wouldn't be to
hard to code a method to do this. Yanking the FindFirstFile prototypes and
structures from some of Stephen Toub's articles [1][2] and throwing together
a loop:
/// <summary>
/// Get the actual path case-correct for <paramref name="path"/>
/// </summary>
/// <author>Peter Ritchie</author>
/// <param name="path"></param>
/// <returns>Actual Path</returns>
/// <exception cref="T:System.Security.SecurityException">The caller does
not have the required permissions. </exception>
/// <exception cref="T:System.ArgumentNullException">path is null.
</exception>
/// <exception cref="T:System.ArgumentException">path is a zero-length
string, contains only white space, or contains one or more invalid characters
as defined by <see cref="F:Path.InvalidPathChars"></see>, or contains a
wildcard character.-or- The system could not retrieve the absolute path.
</exception>
/// <exception cref="T:System.NotSupportedException">path contains a colon
(":"). </exception>
/// <exception cref="T:PathTooLongException">The specified path, file name,
or both exceed the system-defined maximum length. For example, on
Windows-based platforms, paths must be less than 248 characters, and file
names must be less than 260 characters. </exception>
/// <exception cref="T:System.ArgumentException">The path parameter contains
invalid characters, is empty, or contains only white spaces, or contains a
wildcard character. </exception>
/// <using>
/// using System.IO;
/// using Microsoft.Win32.SafeHandles;
/// using System.Security.Permissions;
/// using System.Runtime.ConstrainedExecution;
/// </using>
static String GetPathActual ( String path )
{
String result = "";
path = Path.GetFullPath(path);
Win32Native.WIN32_FIND_DATA findData = new Win32Native.WIN32_FIND_DATA();
if (File.Exists(path))
{
Win32Native.FindFirstFile(path, findData);
result = findData.fileName;
path = Path.GetDirectoryName(path);
}
DirectoryInfo directoryInfo = new DirectoryInfo(path);
while(Directory.Exists(path) && directoryInfo.Root.Name != path)
{
Win32Native.FindFirstFile(path, findData);
result = findData.fileName + Path.DirectorySeparatorChar + result;
System.Diagnostics.Debug.WriteLine(path);
path = Path.GetDirectoryName(path);
directoryInfo = new DirectoryInfo(path);
}
return path + result;
}

internal sealed class SafeFindHandle : SafeHandleZeroOrMinusOneIsInvalid
{
[SecurityPermission(SecurityAction.LinkDemand, UnmanagedCode = true)]
private SafeFindHandle ( ) : base(true)
{
}

protected override bool ReleaseHandle ( )
{
return FindClose(this.handle);
}

[DllImport("kernel32.dll")]
[ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
private static extern bool FindClose ( IntPtr handle );
}

[System.Security.SuppressUnmanagedCodeSecurity]
internal static class Win32Native
{
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
public class WIN32_FIND_DATA
{
public int fileAttributes = 0;
// creationTime was an embedded FILETIME structure.
public int creationTime_lowDateTime = 0;
public int creationTime_highDateTime = 0;
// lastAccessTime was an embedded FILETIME structure.
public int lastAccessTime_lowDateTime = 0;
public int lastAccessTime_highDateTime = 0;
// lastWriteTime was an embedded FILETIME structure.
public int lastWriteTime_lowDateTime = 0;
public int lastWriteTime_highDateTime = 0;
public int nFileSizeHigh = 0;
public int nFileSizeLow = 0;
public int dwReserved0 = 0;
public int dwReserved1 = 0;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 256)]
public String fileName = null;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 14)]
public String alternateFileName = null;
}
[DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
internal static extern SafeFindHandle FindFirstFile ( string lpFileName,
[In, Out, MarshalAs(UnmanagedType.LPStruct)]
WIN32_FIND_DATA lpFindFileData );
}


[1] http://msdn.microsoft.com/msdnmag/issues/05/12/NETMatters
[2] http://msdn.microsoft.com/msdnmag/issues/05/10/Reliability

--
http://www.peterRitchie.com/


[quoted text, click to view]
Peter Ritchie
6/15/2006 8:03:02 PM
Sorry, that previous example is missing "SafeFindHandle handle = " before
each call to FindFileFirst.

--
http://www.peterRitchie.com/


[quoted text, click to view]
Chris Mullins
7/11/2006 6:00:17 PM
[Canonical file name]

[quoted text, click to view]

Generally speaking, canonical names are lower case.

In the work I've done with StringPrep and IDNA "Fonts" would be case folded
down to "fonts". This is what you want in a canonical case on a file system
that doesn't distinguish between case. Otherwise you would have a big mess -
fonts could be:
"FOnts"
"fOnts"
"foNts"
"fonTs"
"fontS"

(and all the other combinations).

The only two cases that makes sense are "FONTS" or "fonts", and forever
whatever reason lower case is used in all the cases I've ever seen.

As a result of this getting back "fonts" and not "Fonts" is a good thing
that makes me believe this is a canonical file name.

--
Chris Mullins
Coversant, Inc.

David Thielen
7/11/2006 6:31:01 PM
But what if it's a drive that is mapped to a linux share?

--
thanks - dave
david_at_windward_dot_net
http://www.windwardreports.com



[quoted text, click to view]
Chris Mullins
7/11/2006 8:27:06 PM
[canonical file names]

After looking this up on Google, there is a difference between a canonical
path and a real path. Things like file system compares cannot be done using
canonical paths, for this reason.

In general, I would punt on it and say it's the responsability of the driver
(Samba in the case of a Linux share) to take care of mapping a canonical
Win32 path to a valid Linux Filesystem path.

--
Chris Mullins


[quoted text, click to view]

AddThis Social Bookmark Button