Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/microsoft/vs-editor-api.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'src/Text/Def/TextData/Document/FileUtilities.cs')
-rw-r--r--src/Text/Def/TextData/Document/FileUtilities.cs253
1 files changed, 0 insertions, 253 deletions
diff --git a/src/Text/Def/TextData/Document/FileUtilities.cs b/src/Text/Def/TextData/Document/FileUtilities.cs
deleted file mode 100644
index c176a73..0000000
--- a/src/Text/Def/TextData/Document/FileUtilities.cs
+++ /dev/null
@@ -1,253 +0,0 @@
-//
-// Copyright (c) Microsoft Corporation. All rights reserved.
-// Licensed under the MIT License. See License.txt in the project root for license information.
-//
-using System.Diagnostics;
-using System.IO;
-using System.Runtime.InteropServices;
-using System.Text;
-
-namespace Microsoft.VisualStudio.Text
-{
- internal class FileUtilities
- {
- public static void SaveSnapshot(ITextSnapshot snapshot,
- FileMode fileMode,
- Encoding encoding,
- string filePath)
- {
- Debug.Assert((fileMode == FileMode.Create) || (fileMode == FileMode.CreateNew));
-
- //Save the contents of the text buffer to disk.
-
- string temporaryFilePath = null;
- try
- {
- FileStream originalFileStream = null;
- FileStream temporaryFileStream = FileUtilities.CreateFileStream(filePath, fileMode, out temporaryFilePath, out originalFileStream);
- if (originalFileStream == null)
- {
- //The "normal" scenario: save the snapshot directly to disk. Either:
- // there are no hard links to the target file so we can write the snapshot to the temporary and use File.Replace.
- // we're creating a new file (in which case, temporaryFileStream is a misnomer: it is the stream for the file we are creating).
- try
- {
- using (StreamWriter streamWriter = new StreamWriter(temporaryFileStream, encoding))
- {
- snapshot.Write(streamWriter);
- }
- }
- finally
- {
- //This is somewhat redundant: disposing of streamWriter had the side-effect of disposing of temporaryFileStream
- temporaryFileStream.Dispose();
- temporaryFileStream = null;
- }
-
- if (temporaryFilePath != null)
- {
- //We were saving to the original file and already have a copy of the file on disk.
- int remainingAttempts = 3;
- do
- {
- try
- {
- //Replace the contents of filePath with the contents of the temporary using File.Replace to
- //preserve the various attributes of the original file.
- File.Replace(temporaryFilePath, filePath, null, true);
- temporaryFilePath = null;
-
- return;
- }
- catch (FileNotFoundException)
- {
- // The target file doesn't exist (someone deleted it after we detected it earlier).
- // This is an acceptable condition so don't throw.
- File.Move(temporaryFilePath, filePath);
- temporaryFilePath = null;
-
- return;
- }
- catch (IOException)
- {
- //There was some other exception when trying to replace the contents of the file
- //(probably because some other process had the file locked).
- //Wait a few ms and try again.
- System.Threading.Thread.Sleep(5);
- }
- }
- while (--remainingAttempts > 0);
-
- //We're giving up on replacing the file. Try overwriting it directly (this is essentially the old Dev11 behavior).
- //Do not try approach we are using for hard links (copying the original & restoring it if there is a failure) since
- //getting here implies something strange is going on with the file system (Git or the like locking files) so we
- //want the simplest possible fallback.
-
- //Failing here causes the exception to be passed to the calling code.
- using (FileStream stream = new FileStream(filePath, FileMode.Create, FileAccess.Write, FileShare.Read))
- {
- using (StreamWriter streamWriter = new StreamWriter(stream, encoding))
- {
- snapshot.Write(streamWriter);
- }
- }
- }
- }
- else
- {
- //filePath has hard links so we need to use a different approach to save the file:
- // copy the original file to the temporary
- // write directly to the original
- // restore the original in the event of errors (which could be encoding errors and not disk issues) if there's a problem.
- try
- {
- // Copy the contents of the original file to the temporary.
- originalFileStream.CopyTo(temporaryFileStream);
-
- //We've got a clean copy, try writing the snapshot directly to the original file
- try
- {
- originalFileStream.Seek(0, SeekOrigin.Begin);
- originalFileStream.SetLength(0);
-
- //Make sure the StreamWriter is flagged leaveOpen == true. Otherwise disposing of the StreamWriter will dispose of originalFileStream and we need to
- //leave originalFileStream open so we can use it to restore the original from the temporary copy we made.
- using (var streamWriter = new StreamWriter(originalFileStream, encoding, bufferSize: 1024, leaveOpen: true)) //1024 == the default buffer size for a StreamWriter.
- {
- snapshot.Write(streamWriter);
- }
- }
- catch
- {
- //Restore the original from the temporary copy we made (but rethrow the original exception since we didn't save the file).
- temporaryFileStream.Seek(0, SeekOrigin.Begin);
-
- originalFileStream.Seek(0, SeekOrigin.Begin);
- originalFileStream.SetLength(0);
-
- temporaryFileStream.CopyTo(originalFileStream);
-
- throw;
- }
- }
- finally
- {
- originalFileStream.Dispose();
- originalFileStream = null;
-
- temporaryFileStream.Dispose();
- temporaryFileStream = null;
- }
- }
- }
- finally
- {
- if (temporaryFilePath != null)
- {
- try
- {
- //We do not need the temporary any longer.
- if (File.Exists(temporaryFilePath))
- {
- File.Delete(temporaryFilePath);
- }
- }
- catch
- {
- //Failing to clean up the temporary is an ignorable exception.
- }
- }
- }
- }
-
- private static FileStream CreateFileStream(string filePath, FileMode fileMode, out string temporaryPath, out FileStream originalFileStream)
- {
- originalFileStream = null;
-
- if (File.Exists(filePath))
- {
- // We're writing to a file that already exists. This is an error if we're trying to do a CreateNew.
- if (fileMode == FileMode.CreateNew)
- {
- throw new IOException(filePath + " exists");
- }
-
- try
- {
- originalFileStream = new FileStream(filePath, FileMode.Open, FileAccess.ReadWrite, FileShare.None);
-
- //Even thoug SafeFileHandle is an IDisposable, we don't dispose of it since that closes the strem.
- var safeHandle = originalFileStream.SafeFileHandle;
- if (!(safeHandle.IsClosed || safeHandle.IsInvalid))
- {
- BY_HANDLE_FILE_INFORMATION fi;
- if (GetFileInformationByHandle(safeHandle, out fi))
- {
- if (fi.NumberOfLinks <= 1)
- {
- // The file we're trying to write to doesn't have any hard links ... clear out the originalFileStream
- // as a clue.
- originalFileStream.Dispose();
- originalFileStream = null;
- }
- }
- }
- }
- catch
- {
- if (originalFileStream != null)
- {
- originalFileStream.Dispose();
- originalFileStream = null;
- }
-
- //We were not able to determine whether or not the file had hard links so throw here (aborting the save)
- //since we don't know how to do it safely.
- throw;
- }
-
- string root = Path.GetDirectoryName(filePath);
-
- int count = 0;
- while (++count < 20)
- {
- try
- {
- temporaryPath = Path.Combine(root, Path.GetRandomFileName() + "~"); //The ~ suffix hides the temporary file from GIT.
- return new FileStream(temporaryPath, FileMode.CreateNew, (originalFileStream != null) ? FileAccess.ReadWrite : FileAccess.Write, FileShare.None);
- }
- catch (IOException)
- {
- //Ignore IOExceptions ... GetRandomFileName() came up with a duplicate so we need to try again.
- }
- }
-
- Debug.Fail("Unable to create a temporary file");
- }
-
- temporaryPath = null;
- return new FileStream(filePath, fileMode, FileAccess.Write, FileShare.Read);
- }
-
- [StructLayout(LayoutKind.Sequential)]
- struct BY_HANDLE_FILE_INFORMATION
- {
- public uint FileAttributes;
- public System.Runtime.InteropServices.ComTypes.FILETIME CreationTime;
- public System.Runtime.InteropServices.ComTypes.FILETIME LastAccessTime;
- public System.Runtime.InteropServices.ComTypes.FILETIME LastWriteTime;
- public uint VolumeSerialNumber;
- public uint FileSizeHigh;
- public uint FileSizeLow;
- public uint NumberOfLinks;
- public uint FileIndexHigh;
- public uint FileIndexLow;
- }
-
- [DllImport("kernel32.dll", SetLastError = true)]
- static extern bool GetFileInformationByHandle(
- Microsoft.Win32.SafeHandles.SafeFileHandle hFile,
- out BY_HANDLE_FILE_INFORMATION lpFileInformation
- );
- }
-} \ No newline at end of file