Code:
/ 4.0 / 4.0 / DEVDIV_TFS / Dev10 / Releases / RTMRel / ndp / fx / src / Configuration / System / Configuration / Internal / WriteFileContext.cs / 1305376 / WriteFileContext.cs
//------------------------------------------------------------------------------ //// Copyright (c) Microsoft Corporation. All rights reserved. // //----------------------------------------------------------------------------- namespace System.Configuration.Internal { using System.Configuration; using System.IO; using System.Security.Permissions; using System.Reflection; using System.Threading; using System.Security; using System.CodeDom.Compiler; using Microsoft.Win32; #if !FEATURE_PAL using System.Security.AccessControl; #endif internal class WriteFileContext { private const int SAVING_TIMEOUT = 10000; // 10 seconds private const int SAVING_RETRY_INTERVAL = 100; // 100 milliseconds private static bool _osPlatformDetermined; private static PlatformID _osPlatform; private TempFileCollection _tempFiles; private string _tempNewFilename; private string _templateFilename; internal WriteFileContext(string filename, string templateFilename) { string directoryname = UrlPath.GetDirectoryOrRootName(filename); _templateFilename = templateFilename; _tempFiles = new TempFileCollection(directoryname); try { _tempNewFilename = _tempFiles.AddExtension("newcfg"); } catch { ((IDisposable)_tempFiles).Dispose(); _tempFiles = null; throw; } } static WriteFileContext() { _osPlatformDetermined = false; } internal string TempNewFilename { get {return _tempNewFilename;} } // Complete // // Cleanup the WriteFileContext object based on either success // or failure // // Note: The current algorithm guarantess // 1) The file we are saving to will always be present // on the file system (ie. there will be no window // during saving in which there won't be a file there) // 2) It will always be available for reading from a // client and it will be complete and accurate. // // ... This means that writing is a bit more complicated, and may // have to be retried (because of reading lock), but I don't see // anyway to get around this given 1 and 2. // internal void Complete(string filename, bool success) { try { if (success) { if ( File.Exists( filename ) ) { // Test that we can write to the file ValidateWriteAccess( filename ); // Copy Attributes from original DuplicateFileAttributes( filename, _tempNewFilename ); } else { if ( _templateFilename != null ) { // Copy Acl from template file DuplicateTemplateAttributes( _templateFilename, _tempNewFilename ); } } ReplaceFile(_tempNewFilename, filename); // Don't delete, since we just moved it. _tempFiles.KeepFiles = true; } } finally { ((IDisposable)_tempFiles).Dispose(); _tempFiles = null; } } // DuplicateFileAttributes // // Copy all the files attributes that we care about from the source // file to the destination file // private void DuplicateFileAttributes( string source, string destination ) { #if !FEATURE_PAL FileAttributes attributes; DateTime creationTime; // Copy File Attributes, ie. Hidden, Readonly, etc. attributes = File.GetAttributes( source ); File.SetAttributes( destination, attributes ); // Copy Creation Time creationTime = File.GetCreationTimeUtc( source ); File.SetCreationTimeUtc( destination, creationTime ); // Copy ACL's DuplicateTemplateAttributes( source, destination ); #endif // FEATURE_PAL } // DuplicateTemplateAttributes // // Copy over all the attributes you would want copied from a template file. // As of right now this is just acl's // private void DuplicateTemplateAttributes( string source, string destination ) { #if !FEATURE_PAL if (IsWinNT) { FileSecurity fileSecurity; // Copy Security information fileSecurity = File.GetAccessControl( source, AccessControlSections.Access ); // Mark dirty, so effective for write fileSecurity.SetAccessRuleProtection( fileSecurity.AreAccessRulesProtected, true ); File.SetAccessControl( destination, fileSecurity ); } else { FileAttributes fileAttributes; fileAttributes = File.GetAttributes( source ); File.SetAttributes( destination, fileAttributes ); } #endif // FEATURE_PAL } // ValidateWriteAccess // // Validate that we can write to the file. This will enforce the ACL's // on the file. Since we do our moving of files to replace, this is // nice to ensure we are not by-passing some security permission // that someone set (although that could bypass this via move themselves) // // Note: 1) This is really just a nice to have, since with directory permissions // they could do the same thing we are doing // // 2) We are depending on the current behavior that if the file is locked // and we can not open it, that we will get an UnauthorizedAccessException // and not the IOException. // private void ValidateWriteAccess( string filename ) { FileStream fs = null; try { // Try to open file for write access fs = new FileStream( filename, FileMode.Open, FileAccess.Write, FileShare.ReadWrite ); } catch ( UnauthorizedAccessException ) { // Access was denied, make sure we throw this throw; } catch ( IOException ) { // Someone else was using the file. Since we did not get // the unauthorizedAccessException we have access to the file } catch ( Exception ) { // Unexpected, so just throw for safety sake throw; } finally { if ( fs != null ) { fs.Close(); } } } // ReplaceFile // // Replace one file with another using MoveFileEx. This will // retry the operation if the file is locked because someone // is reading it // private void ReplaceFile( string Source, string Target ) { bool WriteSucceeded = false; int Duration = 0; WriteSucceeded = AttemptMove( Source, Target ); // The file may be open for read, if it is then // lets try again because maybe they will finish // soon, and we will be able to replace while ( !WriteSucceeded && ( Duration < SAVING_TIMEOUT ) && File.Exists( Target ) && !FileIsWriteLocked( Target ) ) { Thread.Sleep( SAVING_RETRY_INTERVAL ); Duration += SAVING_RETRY_INTERVAL; WriteSucceeded = AttemptMove( Source, Target ); } if ( !WriteSucceeded ) { throw new ConfigurationErrorsException( SR.GetString(SR.Config_write_failed, Target) ); } } // AttemptMove // // Attempt to move a file from one location to another // // Return Values: // TRUE - Move Successful // FALSE - Move Failed private bool AttemptMove( string Source, string Target ) { bool MoveSuccessful = false; if ( IsWinNT ) { // We can only call this when we have kernel32.dll MoveSuccessful = UnsafeNativeMethods.MoveFileEx( Source, Target, UnsafeNativeMethods.MOVEFILE_REPLACE_EXISTING ); } else { try { // VSWhidbey 548017: // File.Move isn't supported on Win9x. We'll use File.Copy // instead. Please note that Source is a temporary file which // will be deleted when _tempFiles is disposed. File.Copy(Source, Target, true); MoveSuccessful = true; } catch { MoveSuccessful = false; } } return MoveSuccessful; } // FileIsWriteLocked // // Is the file write locked or not? // private bool FileIsWriteLocked( string FileName ) { Stream FileStream = null; bool WriteLocked = true; if (!FileUtil.FileExists(FileName, true)) { // It can't be locked if it doesn't exist return false; } try { FileShare fileShare = FileShare.Read; if (IsWinNT) { fileShare |= FileShare.Delete; } // Try to open for shared reading FileStream = new FileStream( FileName, FileMode.Open, FileAccess.Read, fileShare); // If we can open it for shared reading, it is not // write locked WriteLocked = false; } finally { if ( FileStream != null ) { FileStream.Close(); FileStream = null; } } return WriteLocked; } // IsWinNT // // Are we running in WinNT or not? // private bool IsWinNT { get { if ( !_osPlatformDetermined ) { _osPlatform = Environment.OSVersion.Platform; _osPlatformDetermined = true; } return ( _osPlatform == System.PlatformID.Win32NT ); } } } } // File provided for Reference Use Only by Microsoft Corporation (c) 2007. //------------------------------------------------------------------------------ //// Copyright (c) Microsoft Corporation. All rights reserved. // //----------------------------------------------------------------------------- namespace System.Configuration.Internal { using System.Configuration; using System.IO; using System.Security.Permissions; using System.Reflection; using System.Threading; using System.Security; using System.CodeDom.Compiler; using Microsoft.Win32; #if !FEATURE_PAL using System.Security.AccessControl; #endif internal class WriteFileContext { private const int SAVING_TIMEOUT = 10000; // 10 seconds private const int SAVING_RETRY_INTERVAL = 100; // 100 milliseconds private static bool _osPlatformDetermined; private static PlatformID _osPlatform; private TempFileCollection _tempFiles; private string _tempNewFilename; private string _templateFilename; internal WriteFileContext(string filename, string templateFilename) { string directoryname = UrlPath.GetDirectoryOrRootName(filename); _templateFilename = templateFilename; _tempFiles = new TempFileCollection(directoryname); try { _tempNewFilename = _tempFiles.AddExtension("newcfg"); } catch { ((IDisposable)_tempFiles).Dispose(); _tempFiles = null; throw; } } static WriteFileContext() { _osPlatformDetermined = false; } internal string TempNewFilename { get {return _tempNewFilename;} } // Complete // // Cleanup the WriteFileContext object based on either success // or failure // // Note: The current algorithm guarantess // 1) The file we are saving to will always be present // on the file system (ie. there will be no window // during saving in which there won't be a file there) // 2) It will always be available for reading from a // client and it will be complete and accurate. // // ... This means that writing is a bit more complicated, and may // have to be retried (because of reading lock), but I don't see // anyway to get around this given 1 and 2. // internal void Complete(string filename, bool success) { try { if (success) { if ( File.Exists( filename ) ) { // Test that we can write to the file ValidateWriteAccess( filename ); // Copy Attributes from original DuplicateFileAttributes( filename, _tempNewFilename ); } else { if ( _templateFilename != null ) { // Copy Acl from template file DuplicateTemplateAttributes( _templateFilename, _tempNewFilename ); } } ReplaceFile(_tempNewFilename, filename); // Don't delete, since we just moved it. _tempFiles.KeepFiles = true; } } finally { ((IDisposable)_tempFiles).Dispose(); _tempFiles = null; } } // DuplicateFileAttributes // // Copy all the files attributes that we care about from the source // file to the destination file // private void DuplicateFileAttributes( string source, string destination ) { #if !FEATURE_PAL FileAttributes attributes; DateTime creationTime; // Copy File Attributes, ie. Hidden, Readonly, etc. attributes = File.GetAttributes( source ); File.SetAttributes( destination, attributes ); // Copy Creation Time creationTime = File.GetCreationTimeUtc( source ); File.SetCreationTimeUtc( destination, creationTime ); // Copy ACL's DuplicateTemplateAttributes( source, destination ); #endif // FEATURE_PAL } // DuplicateTemplateAttributes // // Copy over all the attributes you would want copied from a template file. // As of right now this is just acl's // private void DuplicateTemplateAttributes( string source, string destination ) { #if !FEATURE_PAL if (IsWinNT) { FileSecurity fileSecurity; // Copy Security information fileSecurity = File.GetAccessControl( source, AccessControlSections.Access ); // Mark dirty, so effective for write fileSecurity.SetAccessRuleProtection( fileSecurity.AreAccessRulesProtected, true ); File.SetAccessControl( destination, fileSecurity ); } else { FileAttributes fileAttributes; fileAttributes = File.GetAttributes( source ); File.SetAttributes( destination, fileAttributes ); } #endif // FEATURE_PAL } // ValidateWriteAccess // // Validate that we can write to the file. This will enforce the ACL's // on the file. Since we do our moving of files to replace, this is // nice to ensure we are not by-passing some security permission // that someone set (although that could bypass this via move themselves) // // Note: 1) This is really just a nice to have, since with directory permissions // they could do the same thing we are doing // // 2) We are depending on the current behavior that if the file is locked // and we can not open it, that we will get an UnauthorizedAccessException // and not the IOException. // private void ValidateWriteAccess( string filename ) { FileStream fs = null; try { // Try to open file for write access fs = new FileStream( filename, FileMode.Open, FileAccess.Write, FileShare.ReadWrite ); } catch ( UnauthorizedAccessException ) { // Access was denied, make sure we throw this throw; } catch ( IOException ) { // Someone else was using the file. Since we did not get // the unauthorizedAccessException we have access to the file } catch ( Exception ) { // Unexpected, so just throw for safety sake throw; } finally { if ( fs != null ) { fs.Close(); } } } // ReplaceFile // // Replace one file with another using MoveFileEx. This will // retry the operation if the file is locked because someone // is reading it // private void ReplaceFile( string Source, string Target ) { bool WriteSucceeded = false; int Duration = 0; WriteSucceeded = AttemptMove( Source, Target ); // The file may be open for read, if it is then // lets try again because maybe they will finish // soon, and we will be able to replace while ( !WriteSucceeded && ( Duration < SAVING_TIMEOUT ) && File.Exists( Target ) && !FileIsWriteLocked( Target ) ) { Thread.Sleep( SAVING_RETRY_INTERVAL ); Duration += SAVING_RETRY_INTERVAL; WriteSucceeded = AttemptMove( Source, Target ); } if ( !WriteSucceeded ) { throw new ConfigurationErrorsException( SR.GetString(SR.Config_write_failed, Target) ); } } // AttemptMove // // Attempt to move a file from one location to another // // Return Values: // TRUE - Move Successful // FALSE - Move Failed private bool AttemptMove( string Source, string Target ) { bool MoveSuccessful = false; if ( IsWinNT ) { // We can only call this when we have kernel32.dll MoveSuccessful = UnsafeNativeMethods.MoveFileEx( Source, Target, UnsafeNativeMethods.MOVEFILE_REPLACE_EXISTING ); } else { try { // VSWhidbey 548017: // File.Move isn't supported on Win9x. We'll use File.Copy // instead. Please note that Source is a temporary file which // will be deleted when _tempFiles is disposed. File.Copy(Source, Target, true); MoveSuccessful = true; } catch { MoveSuccessful = false; } } return MoveSuccessful; } // FileIsWriteLocked // // Is the file write locked or not? // private bool FileIsWriteLocked( string FileName ) { Stream FileStream = null; bool WriteLocked = true; if (!FileUtil.FileExists(FileName, true)) { // It can't be locked if it doesn't exist return false; } try { FileShare fileShare = FileShare.Read; if (IsWinNT) { fileShare |= FileShare.Delete; } // Try to open for shared reading FileStream = new FileStream( FileName, FileMode.Open, FileAccess.Read, fileShare); // If we can open it for shared reading, it is not // write locked WriteLocked = false; } finally { if ( FileStream != null ) { FileStream.Close(); FileStream = null; } } return WriteLocked; } // IsWinNT // // Are we running in WinNT or not? // private bool IsWinNT { get { if ( !_osPlatformDetermined ) { _osPlatform = Environment.OSVersion.Platform; _osPlatformDetermined = true; } return ( _osPlatform == System.PlatformID.Win32NT ); } } } } // File provided for Reference Use Only by Microsoft Corporation (c) 2007.
Link Menu
This book is available now!
Buy at Amazon US or
Buy at Amazon UK
- DSACryptoServiceProvider.cs
- DataGridViewHitTestInfo.cs
- PointLightBase.cs
- XmlReader.cs
- BrowserCapabilitiesFactory.cs
- DataGridViewCellStyle.cs
- CalendarDay.cs
- DATA_BLOB.cs
- NavigatorOutput.cs
- TypeSystemHelpers.cs
- Int32Storage.cs
- CodeDomComponentSerializationService.cs
- ConfigurationSectionHelper.cs
- SafeProcessHandle.cs
- __ConsoleStream.cs
- XmlBoundElement.cs
- XmlSchemaAnnotation.cs
- AlgoModule.cs
- SqlWebEventProvider.cs
- BaseTemplateCodeDomTreeGenerator.cs
- FontFamily.cs
- ExtensionDataReader.cs
- RemoteHelper.cs
- SspiHelper.cs
- DataGridViewTextBoxEditingControl.cs
- SafeWaitHandle.cs
- DeferredReference.cs
- ConfigXmlElement.cs
- WindowPatternIdentifiers.cs
- HandlerBase.cs
- SynchronizedInputProviderWrapper.cs
- SemaphoreSecurity.cs
- TextParagraphProperties.cs
- FocusManager.cs
- PropertiesTab.cs
- FontStretchConverter.cs
- FixedSOMImage.cs
- PersonalizableTypeEntry.cs
- RichTextBoxConstants.cs
- OdbcDataAdapter.cs
- DetailsViewRow.cs
- SqlFileStream.cs
- XmlSchemaComplexContentExtension.cs
- BaseAddressElement.cs
- ValidationErrorCollection.cs
- ItemType.cs
- DescendentsWalkerBase.cs
- WsdlParser.cs
- BulletedListDesigner.cs
- Soap.cs
- CheckBoxBaseAdapter.cs
- CompilerState.cs
- querybuilder.cs
- BamlBinaryWriter.cs
- InertiaTranslationBehavior.cs
- TextRangeProviderWrapper.cs
- SafePointer.cs
- UnsafeNativeMethods.cs
- EdgeProfileValidation.cs
- metadatamappinghashervisitor.cs
- TextWriterTraceListener.cs
- PackagePart.cs
- TemplateControlCodeDomTreeGenerator.cs
- CodeVariableDeclarationStatement.cs
- CodeAttributeArgument.cs
- Comparer.cs
- XmlBinaryReader.cs
- TypedServiceOperationListItem.cs
- OleDbRowUpdatingEvent.cs
- MetafileHeader.cs
- MenuCommandService.cs
- EntityContainerEmitter.cs
- ImageClickEventArgs.cs
- BitmapEffect.cs
- RouteCollection.cs
- LiteralTextContainerControlBuilder.cs
- TextTrailingWordEllipsis.cs
- ReliableOutputConnection.cs
- ControlPropertyNameConverter.cs
- RangeExpression.cs
- HttpDictionary.cs
- PriorityItem.cs
- FileReader.cs
- PenThreadWorker.cs
- TextReader.cs
- ObjectFullSpanRewriter.cs
- SqlTriggerAttribute.cs
- OutputScopeManager.cs
- TextEditor.cs
- ScriptComponentDescriptor.cs
- cookieexception.cs
- DataBindingHandlerAttribute.cs
- XmlKeywords.cs
- Binding.cs
- ObjectContext.cs
- AuthStoreRoleProvider.cs
- StorageAssociationTypeMapping.cs
- ResourceContainer.cs
- QilInvokeLateBound.cs
- ImageButton.cs