diff options
Diffstat (limited to 'src/mscorlib/src/System/IO/PathHelper.cs')
-rw-r--r-- | src/mscorlib/src/System/IO/PathHelper.cs | 448 |
1 files changed, 0 insertions, 448 deletions
diff --git a/src/mscorlib/src/System/IO/PathHelper.cs b/src/mscorlib/src/System/IO/PathHelper.cs deleted file mode 100644 index 8e39b3c537..0000000000 --- a/src/mscorlib/src/System/IO/PathHelper.cs +++ /dev/null @@ -1,448 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. - -#if FEATURE_PATHCOMPAT -using System; -using System.Collections; -using System.Text; -using Microsoft.Win32; -using System.Runtime.InteropServices; -using System.Runtime.CompilerServices; -using System.Globalization; -using System.Runtime.Versioning; -using System.Security; -using System.Security.Permissions; -using System.Diagnostics.Contracts; - -namespace System.IO { - - // ABOUT: - // Helps with path normalization; support allocating on the stack or heap - // - // PathHelper can't stackalloc the array for obvious reasons; you must pass - // in an array of chars allocated on the stack. - // - // USAGE: - // Suppose you need to represent a char array of length len. Then this is the - // suggested way to instantiate PathHelper: - // *************************************************************************** - // PathHelper pathHelper; - // if (charArrayLength less than stack alloc threshold == Path.MaxPath) - // char* arrayPtr = stackalloc char[Path.MaxPath]; - // pathHelper = new PathHelper(arrayPtr); - // else - // pathHelper = new PathHelper(capacity, maxPath); - // *************************************************************************** - // - // note in the StringBuilder ctor: - // - maxPath may be greater than Path.MaxPath (for isolated storage) - // - capacity may be greater than maxPath. This is even used for non-isolated - // storage scenarios where we want to temporarily allow strings greater - // than Path.MaxPath if they can be normalized down to Path.MaxPath. This - // can happen if the path contains escape characters "..". - // - unsafe internal struct PathHelper { // should not be serialized - - // maximum size, max be greater than max path if contains escape sequence - private int m_capacity; - // current length (next character position) - private int m_length; - // max path, may be less than capacity - private int m_maxPath; - - // ptr to stack alloc'd array of chars - [SecurityCritical] - private char* m_arrayPtr; - - // StringBuilder - private StringBuilder m_sb; - - // whether to operate on stack alloc'd or heap alloc'd array - private bool useStackAlloc; - - // Whether to skip calls to Win32Native.GetLongPathName becasue we tried before and failed: - private bool doNotTryExpandShortFileName; - - // Instantiates a PathHelper with a stack alloc'd array of chars - [System.Security.SecurityCritical] - internal PathHelper(char* charArrayPtr, int length) { - Contract.Requires(charArrayPtr != null); - // force callers to be aware of this - Contract.Requires(length == Path.MaxPath); - this.m_length = 0; - this.m_sb = null; - - this.m_arrayPtr = charArrayPtr; - this.m_capacity = length; - this.m_maxPath = Path.MaxPath; - useStackAlloc = true; - doNotTryExpandShortFileName = false; - } - - // Instantiates a PathHelper with a heap alloc'd array of ints. Will create a StringBuilder - [System.Security.SecurityCritical] - internal PathHelper(int capacity, int maxPath) - { - this.m_length = 0; - this.m_arrayPtr = null; - this.useStackAlloc = false; - - this.m_sb = new StringBuilder(capacity); - this.m_capacity = capacity; - this.m_maxPath = maxPath; - doNotTryExpandShortFileName = false; - } - - internal int Length { - get { - if (useStackAlloc) { - return m_length; - } - else { - return m_sb.Length; - } - } - set { - if (useStackAlloc) { - m_length = value; - } - else { - m_sb.Length = value; - } - } - } - - internal int Capacity { - get { - return m_capacity; - } - } - - internal char this[int index] { - [System.Security.SecurityCritical] - get { - Contract.Requires(index >= 0 && index < Length); - if (useStackAlloc) { - return m_arrayPtr[index]; - } - else { - return m_sb[index]; - } - } - [System.Security.SecurityCritical] - set { - Contract.Requires(index >= 0 && index < Length); - if (useStackAlloc) { - m_arrayPtr[index] = value; - } - else { - m_sb[index] = value; - } - } - } - - [System.Security.SecurityCritical] - internal unsafe void Append(char value) { - if (Length + 1 >= m_capacity) - throw new PathTooLongException(Environment.GetResourceString("IO.PathTooLong")); - - if (useStackAlloc) { - m_arrayPtr[Length] = value; - m_length++; - } - else { - m_sb.Append(value); - } - } - - [System.Security.SecurityCritical] - internal unsafe int GetFullPathName() { - if (useStackAlloc) { - char* finalBuffer = stackalloc char[Path.MaxPath + 1]; - int result = Win32Native.GetFullPathName(m_arrayPtr, Path.MaxPath + 1, finalBuffer, IntPtr.Zero); - - // If success, the return buffer length does not account for the terminating null character. - // If in-sufficient buffer, the return buffer length does account for the path + the terminating null character. - // If failure, the return buffer length is zero - if (result > Path.MaxPath) { - char* tempBuffer = stackalloc char[result]; - finalBuffer = tempBuffer; - result = Win32Native.GetFullPathName(m_arrayPtr, result, finalBuffer, IntPtr.Zero); - } - - // Full path is genuinely long - if (result >= Path.MaxPath) - throw new PathTooLongException(Environment.GetResourceString("IO.PathTooLong")); - - Contract.Assert(result < Path.MaxPath, "did we accidently remove a PathTooLongException check?"); - if (result == 0 && m_arrayPtr[0] != '\0') { - __Error.WinIOError(); - } - - else if (result < Path.MaxPath) { - // Null terminate explicitly (may be only needed for some cases such as empty strings) - // GetFullPathName return length doesn't account for null terminating char... - finalBuffer[result] = '\0'; // Safe to write directly as result is < Path.MaxPath - } - - // We have expanded the paths and GetLongPathName may or may not behave differently from before. - // We need to call it again to see: - doNotTryExpandShortFileName = false; - - String.wstrcpy(m_arrayPtr, finalBuffer, result); - // Doesn't account for null terminating char. Think of this as the last - // valid index into the buffer but not the length of the buffer - Length = result; - return result; - } - else { - StringBuilder finalBuffer = new StringBuilder(m_capacity + 1); - int result = Win32Native.GetFullPathName(m_sb.ToString(), m_capacity + 1, finalBuffer, IntPtr.Zero); - - // If success, the return buffer length does not account for the terminating null character. - // If in-sufficient buffer, the return buffer length does account for the path + the terminating null character. - // If failure, the return buffer length is zero - if (result > m_maxPath) { - finalBuffer.Length = result; - result = Win32Native.GetFullPathName(m_sb.ToString(), result, finalBuffer, IntPtr.Zero); - } - - // Fullpath is genuinely long - if (result >= m_maxPath) - throw new PathTooLongException(Environment.GetResourceString("IO.PathTooLong")); - - Contract.Assert(result < m_maxPath, "did we accidentally remove a PathTooLongException check?"); - if (result == 0 && m_sb[0] != '\0') { - if (Length >= m_maxPath) { - throw new PathTooLongException(Environment.GetResourceString("IO.PathTooLong")); - } - __Error.WinIOError(); - } - - // We have expanded the paths and GetLongPathName may or may not behave differently from before. - // We need to call it again to see: - doNotTryExpandShortFileName = false; - - m_sb = finalBuffer; - return result; - } - } - - [System.Security.SecurityCritical] - internal unsafe bool TryExpandShortFileName() { - - if (doNotTryExpandShortFileName) - return false; - - if (useStackAlloc) { - NullTerminate(); - char* buffer = UnsafeGetArrayPtr(); - char* shortFileNameBuffer = stackalloc char[Path.MaxPath + 1]; - - int r = Win32Native.GetLongPathName(buffer, shortFileNameBuffer, Path.MaxPath); - - // If success, the return buffer length does not account for the terminating null character. - // If in-sufficient buffer, the return buffer length does account for the path + the terminating null character. - // If failure, the return buffer length is zero - if (r >= Path.MaxPath) - throw new PathTooLongException(Environment.GetResourceString("IO.PathTooLong")); - - if (r == 0) { - // Note: GetLongPathName will return ERROR_INVALID_FUNCTION on a - // path like \\.\PHYSICALDEVICE0 - some device driver doesn't - // support GetLongPathName on that string. This behavior is - // by design, according to the Core File Services team. - // We also get ERROR_NOT_ENOUGH_QUOTA in SQL_CLR_STRESS runs - // intermittently on paths like D:\DOCUME~1\user\LOCALS~1\Temp\ - - // We do not need to call GetLongPathName if we know it will fail becasue the path does not exist: - int lastErr = Marshal.GetLastWin32Error(); - if (lastErr == Win32Native.ERROR_FILE_NOT_FOUND || lastErr == Win32Native.ERROR_PATH_NOT_FOUND) - doNotTryExpandShortFileName = true; - - return false; - } - - // Safe to copy as we have already done Path.MaxPath bound checking - String.wstrcpy(buffer, shortFileNameBuffer, r); - Length = r; - // We should explicitly null terminate as in some cases the long version of the path - // might actually be shorter than what we started with because of Win32's normalization - // Safe to write directly as bufferLength is guaranteed to be < Path.MaxPath - NullTerminate(); - return true; - } - else { - StringBuilder sb = GetStringBuilder(); - - String origName = sb.ToString(); - String tempName = origName; - bool addedPrefix = false; - if (tempName.Length > Path.MaxPath) { - tempName = Path.AddLongPathPrefix(tempName); - addedPrefix = true; - } - sb.Capacity = m_capacity; - sb.Length = 0; - int r = Win32Native.GetLongPathName(tempName, sb, m_capacity); - - if (r == 0) { - // Note: GetLongPathName will return ERROR_INVALID_FUNCTION on a - // path like \\.\PHYSICALDEVICE0 - some device driver doesn't - // support GetLongPathName on that string. This behavior is - // by design, according to the Core File Services team. - // We also get ERROR_NOT_ENOUGH_QUOTA in SQL_CLR_STRESS runs - // intermittently on paths like D:\DOCUME~1\user\LOCALS~1\Temp\ - - // We do not need to call GetLongPathName if we know it will fail becasue the path does not exist: - int lastErr = Marshal.GetLastWin32Error(); - if (Win32Native.ERROR_FILE_NOT_FOUND == lastErr || Win32Native.ERROR_PATH_NOT_FOUND == lastErr) - doNotTryExpandShortFileName = true; - - sb.Length = 0; - sb.Append(origName); - return false; - } - - if (addedPrefix) - r -= 4; - - // If success, the return buffer length does not account for the terminating null character. - // If in-sufficient buffer, the return buffer length does account for the path + the terminating null character. - // If failure, the return buffer length is zero - if (r >= m_maxPath) - throw new PathTooLongException(Environment.GetResourceString("IO.PathTooLong")); - - - sb = Path.RemoveLongPathPrefix(sb); - Length = sb.Length; - return true; - - } - } - - [System.Security.SecurityCritical] - internal unsafe void Fixup(int lenSavedName, int lastSlash) { - if (useStackAlloc) { - char* savedName = stackalloc char[lenSavedName]; - String.wstrcpy(savedName, m_arrayPtr + lastSlash + 1, lenSavedName); - Length = lastSlash; - NullTerminate(); - doNotTryExpandShortFileName = false; - bool r = TryExpandShortFileName(); - // Clean up changes made to the newBuffer. - Append(Path.DirectorySeparatorChar); - if (Length + lenSavedName >= Path.MaxPath) - throw new PathTooLongException(Environment.GetResourceString("IO.PathTooLong")); - String.wstrcpy(m_arrayPtr + Length, savedName, lenSavedName); - Length = Length + lenSavedName; - - } - else { - String savedName = m_sb.ToString(lastSlash + 1, lenSavedName); - Length = lastSlash; - doNotTryExpandShortFileName = false; - bool r = TryExpandShortFileName(); - // Clean up changes made to the newBuffer. - Append(Path.DirectorySeparatorChar); - if (Length + lenSavedName >= m_maxPath) - throw new PathTooLongException(Environment.GetResourceString("IO.PathTooLong")); - m_sb.Append(savedName); - } - } - - [System.Security.SecurityCritical] - internal unsafe bool OrdinalStartsWith(String compareTo, bool ignoreCase) { - if (Length < compareTo.Length) - return false; - - if (useStackAlloc) { - NullTerminate(); - if (ignoreCase) { - String s = new String(m_arrayPtr, 0, compareTo.Length); - return compareTo.Equals(s, StringComparison.OrdinalIgnoreCase); - } - else { - for (int i = 0; i < compareTo.Length; i++) { - if (m_arrayPtr[i] != compareTo[i]) { - return false; - } - } - return true; - } - } - else { - if (ignoreCase) { - return m_sb.ToString().StartsWith(compareTo, StringComparison.OrdinalIgnoreCase); - } - else { - return m_sb.ToString().StartsWith(compareTo, StringComparison.Ordinal); - } - } - } - - [System.Security.SecurityCritical] - private unsafe bool OrdinalEqualsStackAlloc(String compareTo) - { - Contract.Requires(useStackAlloc, "Currently no efficient implementation for StringBuilder.OrdinalEquals(String)"); - - if (Length != compareTo.Length) { - return false; - } - - for (int i = 0; i < compareTo.Length; i++) { - if (m_arrayPtr[i] != compareTo[i]) { - return false; - } - } - - return true; - } - - [System.Security.SecuritySafeCritical] - public override String ToString() { - if (useStackAlloc) { - return new String(m_arrayPtr, 0, Length); - } - else { - return m_sb.ToString(); - } - } - - [System.Security.SecuritySafeCritical] - internal String ToStringOrExisting(String existingString) - { - if (useStackAlloc) { - return OrdinalEqualsStackAlloc(existingString) ? - existingString : - new String(m_arrayPtr, 0, Length); - } - else { - string newString = m_sb.ToString(); // currently no good StringBuilder.OrdinalEquals(string) - return String.Equals(newString, existingString, StringComparison.Ordinal) ? - existingString : - newString; - } - } - - [System.Security.SecurityCritical] - private unsafe char* UnsafeGetArrayPtr() { - Contract.Requires(useStackAlloc, "This should never be called for PathHelpers wrapping a StringBuilder"); - return m_arrayPtr; - } - - private StringBuilder GetStringBuilder() { - Contract.Requires(!useStackAlloc, "This should never be called for PathHelpers that wrap a stackalloc'd buffer"); - return m_sb; - } - - [System.Security.SecurityCritical] - private unsafe void NullTerminate() { - Contract.Requires(useStackAlloc, "This should never be called for PathHelpers wrapping a StringBuilder"); - m_arrayPtr[m_length] = '\0'; - } - - } -} -#endif // FEATURE_PATHCOMPAT
\ No newline at end of file |