Code:
/ 4.0 / 4.0 / untmp / DEVDIV_TFS / Dev10 / Releases / RTMRel / ndp / clr / src / BCL / System / IO / PathHelper.cs / 1305376 / PathHelper.cs
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.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 class 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 private char* m_arrayPtr; // StringBuilder private StringBuilder m_sb; // whether to operate on stack alloc'd or heap alloc'd array private bool useStackAlloc; // 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_arrayPtr = charArrayPtr; this.m_capacity = length; this.m_maxPath = Path.MaxPath; useStackAlloc = true; } // Instantiates a PathHelper with a heap alloc'd array of ints. Will create a StringBuilder internal PathHelper(int capacity, int maxPath) { this.m_sb = new StringBuilder(capacity); this.m_capacity = capacity; this.m_maxPath = maxPath; } 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 } Buffer.memcpy(finalBuffer, 0, m_arrayPtr, 0, 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(); } m_sb = finalBuffer; return result; } } [System.Security.SecurityCritical] internal unsafe bool TryExpandShortFileName() { 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\ return false; } // Safe to copy as we have already done Path.MaxPath bound checking Buffer.memcpy(shortFileNameBuffer, 0, buffer, 0, 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\ 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]; Buffer.memcpy(m_arrayPtr, lastSlash + 1, savedName, 0, lenSavedName); Length = lastSlash; NullTerminate(); 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")); Buffer.memcpy(savedName, 0, m_arrayPtr, Length, lenSavedName); Length = Length + lenSavedName; } else { String savedName = m_sb.ToString(lastSlash + 1, lenSavedName); Length = lastSlash; 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.SecuritySafeCritical] public override String ToString() { if (useStackAlloc) { return new String(m_arrayPtr, 0, Length); } else { return m_sb.ToString(); } } [System.Security.SecurityCritical] private unsafe char* UnsafeGetArrayPtr() { Contract.Assert(useStackAlloc, "This should never be called for PathHelpers wrapping a StringBuilder"); return m_arrayPtr; } private StringBuilder GetStringBuilder() { Contract.Assert(!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.Assert(useStackAlloc, "This should never be called for PathHelpers wrapping a StringBuilder"); m_arrayPtr[m_length] = '\0'; } } } // File provided for Reference Use Only by Microsoft Corporation (c) 2007. // Copyright (c) Microsoft Corporation. All rights reserved.
Link Menu
This book is available now!
Buy at Amazon US or
Buy at Amazon UK
- RectAnimationBase.cs
- DataRow.cs
- _TLSstream.cs
- COM2ExtendedUITypeEditor.cs
- BeginEvent.cs
- pingexception.cs
- DoubleAnimationBase.cs
- SqlTrackingWorkflowInstance.cs
- TokenBasedSet.cs
- ModulesEntry.cs
- XmlSchemaSimpleTypeList.cs
- XamlPointCollectionSerializer.cs
- PropertyOverridesTypeEditor.cs
- ItemType.cs
- WebPartConnectVerb.cs
- BaseConfigurationRecord.cs
- SctClaimDictionary.cs
- BindingWorker.cs
- Internal.cs
- Substitution.cs
- FaultDescriptionCollection.cs
- MaterializeFromAtom.cs
- IisTraceWebEventProvider.cs
- TextContainerChangedEventArgs.cs
- TextBox.cs
- CursorConverter.cs
- StrongNamePublicKeyBlob.cs
- xmlsaver.cs
- SqlCacheDependencyDatabase.cs
- OracleConnectionFactory.cs
- ScriptReferenceEventArgs.cs
- ViewStateModeByIdAttribute.cs
- MemberRelationshipService.cs
- BaseTreeIterator.cs
- XdrBuilder.cs
- RoleServiceManager.cs
- TreeNodeBindingDepthConverter.cs
- AuthorizationContext.cs
- CompilationAssemblyInstallComponent.cs
- infer.cs
- DefaultAsyncDataDispatcher.cs
- ListViewSelectEventArgs.cs
- DescendantQuery.cs
- XmlObjectSerializerContext.cs
- LogSwitch.cs
- ButtonChrome.cs
- ListManagerBindingsCollection.cs
- LinkConverter.cs
- FaultBookmark.cs
- SqlColumnizer.cs
- PathTooLongException.cs
- ListItemCollection.cs
- FormCollection.cs
- CompiledXpathExpr.cs
- LogicalTreeHelper.cs
- SQlBooleanStorage.cs
- Block.cs
- PersistChildrenAttribute.cs
- DoubleKeyFrameCollection.cs
- StringFormat.cs
- WsdlEndpointConversionContext.cs
- SqlConnectionFactory.cs
- PerfCounterSection.cs
- TreeViewImageIndexConverter.cs
- xdrvalidator.cs
- Utils.cs
- StyleXamlTreeBuilder.cs
- ServiceThrottlingElement.cs
- Span.cs
- MetadataSource.cs
- ConsumerConnectionPointCollection.cs
- WebConfigurationHost.cs
- ObjectStateManagerMetadata.cs
- Transactions.cs
- Visitor.cs
- ExtentCqlBlock.cs
- ProcessModuleDesigner.cs
- QueryableFilterRepeater.cs
- XmlValueConverter.cs
- CounterSetInstance.cs
- ImagingCache.cs
- ZipIOModeEnforcingStream.cs
- RequestNavigateEventArgs.cs
- DataGridClipboardHelper.cs
- DataGridViewCellPaintingEventArgs.cs
- odbcmetadatacolumnnames.cs
- XmlSchemaDocumentation.cs
- ZipArchive.cs
- XmlDataLoader.cs
- IndexedEnumerable.cs
- SizeConverter.cs
- ItemContainerGenerator.cs
- TypeUsage.cs
- MultipartIdentifier.cs
- ModuleElement.cs
- SQLInt64.cs
- FormsAuthenticationCredentials.cs
- DbgUtil.cs
- DBDataPermissionAttribute.cs
- DrawingContextDrawingContextWalker.cs