You've already forked linux-packaging-mono
Imported Upstream version 5.4.0.167
Former-commit-id: 5624ac747d633e885131e8349322922b6a59baaa
This commit is contained in:
parent
e49d6f06c0
commit
536cd135cc
@@ -35,10 +35,10 @@ Global
|
||||
{F0D49126-6A1C-42D5-9428-4374C868BAF8}.Debug|Any CPU.Build.0 = netcoreapp-Windows_NT-Debug|Any CPU
|
||||
{F0D49126-6A1C-42D5-9428-4374C868BAF8}.Release|Any CPU.ActiveCfg = netcoreapp-Windows_NT-Release|Any CPU
|
||||
{F0D49126-6A1C-42D5-9428-4374C868BAF8}.Release|Any CPU.Build.0 = netcoreapp-Windows_NT-Release|Any CPU
|
||||
{3C42F714-82AF-4A43-9B9C-744DE31B5C5D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{3C42F714-82AF-4A43-9B9C-744DE31B5C5D}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{3C42F714-82AF-4A43-9B9C-744DE31B5C5D}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{3C42F714-82AF-4A43-9B9C-744DE31B5C5D}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{3C42F714-82AF-4A43-9B9C-744DE31B5C5D}.Debug|Any CPU.ActiveCfg = netstandard-Debug|Any CPU
|
||||
{3C42F714-82AF-4A43-9B9C-744DE31B5C5D}.Debug|Any CPU.Build.0 = netstandard-Debug|Any CPU
|
||||
{3C42F714-82AF-4A43-9B9C-744DE31B5C5D}.Release|Any CPU.ActiveCfg = netstandard-Release|Any CPU
|
||||
{3C42F714-82AF-4A43-9B9C-744DE31B5C5D}.Release|Any CPU.Build.0 = netstandard-Release|Any CPU
|
||||
{1B528B61-14F9-4BFC-A79A-F0BDB3339150}.Debug|Any CPU.ActiveCfg = netcoreapp-Windows_NT-Debug|Any CPU
|
||||
{1B528B61-14F9-4BFC-A79A-F0BDB3339150}.Debug|Any CPU.Build.0 = netcoreapp-Windows_NT-Debug|Any CPU
|
||||
{1B528B61-14F9-4BFC-A79A-F0BDB3339150}.Release|Any CPU.ActiveCfg = netcoreapp-Windows_NT-Release|Any CPU
|
||||
|
||||
@@ -2,7 +2,8 @@
|
||||
<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<Import Project="..\dir.props" />
|
||||
<PropertyGroup>
|
||||
<AssemblyVersion>4.1.0.0</AssemblyVersion>
|
||||
<AssemblyVersion>4.1.1.0</AssemblyVersion>
|
||||
<AssemblyKey>MSFT</AssemblyKey>
|
||||
<IsNETCoreApp>true</IsNETCoreApp>
|
||||
<IsUAP>true</IsUAP>
|
||||
</PropertyGroup>
|
||||
|
||||
@@ -1,52 +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.
|
||||
|
||||
using System;
|
||||
using System.Security;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Threading;
|
||||
using Microsoft.Win32;
|
||||
|
||||
namespace Microsoft.Win32.SafeHandles
|
||||
{
|
||||
[System.Security.SecurityCritical] // auto-generated_required
|
||||
public sealed class SafeFileHandle : SafeHandleZeroOrMinusOneIsInvalid
|
||||
{
|
||||
private bool? _isAsync;
|
||||
|
||||
private SafeFileHandle() : base(true)
|
||||
{
|
||||
_isAsync = null;
|
||||
}
|
||||
|
||||
public SafeFileHandle(IntPtr preexistingHandle, bool ownsHandle) : base(ownsHandle)
|
||||
{
|
||||
SetHandle(preexistingHandle);
|
||||
|
||||
_isAsync = null;
|
||||
}
|
||||
|
||||
internal bool? IsAsync
|
||||
{
|
||||
get
|
||||
{
|
||||
return _isAsync;
|
||||
}
|
||||
|
||||
set
|
||||
{
|
||||
_isAsync = value;
|
||||
}
|
||||
}
|
||||
|
||||
internal ThreadPoolBoundHandle ThreadPoolBinding { get; set; }
|
||||
|
||||
[System.Security.SecurityCritical]
|
||||
override protected bool ReleaseHandle()
|
||||
{
|
||||
return Interop.Kernel32.CloseHandle(handle);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,61 +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.
|
||||
|
||||
using System;
|
||||
using System.Security;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Threading;
|
||||
using Microsoft.Win32;
|
||||
|
||||
namespace Microsoft.Win32.SafeHandles
|
||||
{
|
||||
[System.Security.SecurityCritical] // auto-generated_required
|
||||
public sealed class SafeFileHandle : SafeHandle
|
||||
{
|
||||
private bool? _isAsync;
|
||||
|
||||
private SafeFileHandle() : base(IntPtr.Zero, true)
|
||||
{
|
||||
_isAsync = null;
|
||||
}
|
||||
|
||||
public SafeFileHandle(IntPtr preexistingHandle, bool ownsHandle) : base(IntPtr.Zero, ownsHandle)
|
||||
{
|
||||
SetHandle(preexistingHandle);
|
||||
|
||||
_isAsync = null;
|
||||
}
|
||||
|
||||
internal bool? IsAsync
|
||||
{
|
||||
get
|
||||
{
|
||||
return _isAsync;
|
||||
}
|
||||
|
||||
set
|
||||
{
|
||||
_isAsync = value;
|
||||
}
|
||||
}
|
||||
|
||||
internal ThreadPoolBoundHandle ThreadPoolBinding { get; set; }
|
||||
|
||||
[System.Security.SecurityCritical]
|
||||
override protected bool ReleaseHandle()
|
||||
{
|
||||
return Interop.Kernel32.CloseHandle(handle);
|
||||
}
|
||||
|
||||
public override bool IsInvalid
|
||||
{
|
||||
[System.Security.SecurityCritical]
|
||||
get
|
||||
{
|
||||
return handle == IntPtr.Zero || handle == new IntPtr(-1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,6 +2,5 @@ kernel32.dll!CopyFileExW
|
||||
kernel32.dll!CreateFileW
|
||||
kernel32.dll!DeleteVolumeMountPointW
|
||||
kernel32.dll!GetLogicalDrives
|
||||
kernel32.dll!LockFile
|
||||
kernel32.dll!SetErrorMode
|
||||
kernel32.dll!UnlockFile
|
||||
kernel32.dll!SetThreadErrorMode
|
||||
|
||||
|
||||
@@ -223,4 +223,7 @@
|
||||
<data name="ObjectDisposed_StreamClosed" xml:space="preserve">
|
||||
<value>Cannot access a closed Stream.</value>
|
||||
</data>
|
||||
<data name="PlatformNotSupported_FileEncryption" xml:space="preserve">
|
||||
<value>File encryption is not supported on this platform.</value>
|
||||
</data>
|
||||
</root>
|
||||
|
||||
@@ -15,7 +15,6 @@
|
||||
<PropertyGroup Condition="'$(TargetsUnix)' == 'true'">
|
||||
<NoWarn>$(NoWarn);414</NoWarn>
|
||||
</PropertyGroup>
|
||||
<!-- Help VS understand available configurations -->
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netcoreapp-Unix-Debug|AnyCPU'" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netcoreapp-Unix-Release|AnyCPU'" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netcoreapp-Windows_NT-Debug|AnyCPU'" />
|
||||
@@ -86,6 +85,9 @@
|
||||
<Compile Include="$(CommonPath)\System\HResults.cs">
|
||||
<Link>Common\System\HResults.cs</Link>
|
||||
</Compile>
|
||||
<Compile Include="$(CommonPath)\System\IO\DriveInfoInternal.Win32.cs">
|
||||
<Link>Common\System\IO\DriveInfoInternal.Win32.cs</Link>
|
||||
</Compile>
|
||||
<Compile Include="$(CommonPath)\System\IO\PathInternal.Windows.cs">
|
||||
<Link>Common\System\IO\PathInternal.Windows.cs</Link>
|
||||
</Compile>
|
||||
@@ -200,9 +202,6 @@
|
||||
<Compile Include="$(CommonPath)\Interop\Windows\kernel32\Interop.GetLogicalDrive.cs">
|
||||
<Link>Common\Interop\Windows\Interop.GetLogicalDrive.cs</Link>
|
||||
</Compile>
|
||||
<Compile Include="$(CommonPath)\System\IO\DriveInfoInternal.Win32.cs">
|
||||
<Link>Common\System\IO\DriveInfoInternal.Win32.cs</Link>
|
||||
</Compile>
|
||||
<Compile Include="System\IO\FileSystem.Current.Win32.cs" />
|
||||
<Compile Include="System\IO\FileSystemInfo.Win32.cs" />
|
||||
<Compile Include="$(CommonPath)\Interop\Windows\kernel32\Interop.CreateFile.cs">
|
||||
@@ -214,11 +213,8 @@
|
||||
<Compile Include="$(CommonPath)\Interop\Windows\kernel32\Interop.DeleteVolumeMountPoint.cs">
|
||||
<Link>Common\Interop\Windows\Interop.DeleteVolumeMountPoint.cs</Link>
|
||||
</Compile>
|
||||
<Compile Include="$(CommonPath)\Interop\Windows\kernel32\Interop.LockFile.cs">
|
||||
<Link>Common\Interop\Windows\Interop.LockFile.cs</Link>
|
||||
</Compile>
|
||||
<Compile Include="$(CommonPath)\Interop\Windows\kernel32\Interop.SetErrorMode.cs">
|
||||
<Link>Common\Interop\Windows\Interop.SetErrorMode.cs</Link>
|
||||
<Compile Include="$(CommonPath)\Interop\Windows\kernel32\Interop.SetThreadErrorMode.cs">
|
||||
<Link>Common\Interop\Windows\Interop.SetThreadErrorMode.cs</Link>
|
||||
</Compile>
|
||||
</ItemGroup>
|
||||
<!-- Windows : UAP - Win32 + WinRT -->
|
||||
@@ -232,14 +228,8 @@
|
||||
<Compile Include="$(CommonPath)\Interop\Windows\kernel32\Interop.DeleteVolumeMountPoint.Uap.cs">
|
||||
<Link>Common\Interop\Windows\Interop.DeleteVolumeMountPoint.Uap.cs</Link>
|
||||
</Compile>
|
||||
<Compile Include="$(CommonPath)\Interop\Windows\mincore\Interop.LockFile.Uap.cs">
|
||||
<Link>Common\Interop\Windows\Interop.LockFile.Uap.cs</Link>
|
||||
</Compile>
|
||||
<Compile Include="$(CommonPath)\Interop\Windows\kernel32\Interop.SetErrorMode.Uap.cs">
|
||||
<Link>Common\Interop\Windows\Interop.SetErrorMode.Uap.cs</Link>
|
||||
</Compile>
|
||||
<Compile Include="$(CommonPath)\System\IO\DriveInfoInternal.Uap.cs">
|
||||
<Link>Common\System\IO\DriveInfoInternal.Uap.cs</Link>
|
||||
<Compile Include="$(CommonPath)\Interop\Windows\kernel32\Interop.SetThreadErrorMode.Uap.cs">
|
||||
<Link>Common\Interop\Windows\Interop.SetThreadErrorMode.Uap.cs</Link>
|
||||
</Compile>
|
||||
<Compile Include="System\IO\FileSystem.Current.MuxWin32WinRT.cs" />
|
||||
<Compile Include="System\IO\FileSystemInfo.WinRT.cs" />
|
||||
|
||||
@@ -564,6 +564,14 @@ namespace System.IO
|
||||
if (!String.Equals(sourceRoot, destinationRoot, pathComparison))
|
||||
throw new IOException(SR.IO_SourceDestMustHaveSameRoot);
|
||||
|
||||
// Windows will throw if the source file/directory doesn't exist, we preemptively check
|
||||
// to make sure our cross platform behavior matches NetFX behavior.
|
||||
if (!FileSystem.Current.DirectoryExists(fullsourceDirName) && !FileSystem.Current.FileExists(fullsourceDirName))
|
||||
throw new DirectoryNotFoundException(SR.Format(SR.IO_PathNotFound_Path, fullsourceDirName));
|
||||
|
||||
if (FileSystem.Current.DirectoryExists(fulldestDirName))
|
||||
throw new IOException(SR.Format(SR.IO_AlreadyExists_Name, fulldestDirName));
|
||||
|
||||
FileSystem.Current.MoveDirectory(fullsourceDirName, fulldestDirName);
|
||||
}
|
||||
|
||||
|
||||
@@ -36,11 +36,6 @@ namespace System.IO
|
||||
DisplayPath = GetDisplayName(OriginalPath);
|
||||
}
|
||||
|
||||
private DirectoryInfo(SerializationInfo info, StreamingContext context) : base(info, context)
|
||||
{
|
||||
DisplayPath = GetDisplayName(OriginalPath);
|
||||
}
|
||||
|
||||
public override String Name
|
||||
{
|
||||
get
|
||||
@@ -379,7 +374,7 @@ namespace System.IO
|
||||
}
|
||||
|
||||
[System.Security.SecuritySafeCritical]
|
||||
public void MoveTo(String destDirName)
|
||||
public void MoveTo(string destDirName)
|
||||
{
|
||||
if (destDirName == null)
|
||||
throw new ArgumentNullException(nameof(destDirName));
|
||||
@@ -387,11 +382,12 @@ namespace System.IO
|
||||
throw new ArgumentException(SR.Argument_EmptyFileName, nameof(destDirName));
|
||||
Contract.EndContractBlock();
|
||||
|
||||
String fullDestDirName = Path.GetFullPath(destDirName);
|
||||
if (fullDestDirName[fullDestDirName.Length - 1] != Path.DirectorySeparatorChar)
|
||||
fullDestDirName = fullDestDirName + PathHelpers.DirectorySeparatorCharAsString;
|
||||
string destination = Path.GetFullPath(destDirName);
|
||||
string destinationWithSeparator = destination;
|
||||
if (destinationWithSeparator[destinationWithSeparator.Length - 1] != Path.DirectorySeparatorChar)
|
||||
destinationWithSeparator = destinationWithSeparator + PathHelpers.DirectorySeparatorCharAsString;
|
||||
|
||||
String fullSourcePath;
|
||||
string fullSourcePath;
|
||||
if (FullPath.Length > 0 && FullPath[FullPath.Length - 1] == Path.DirectorySeparatorChar)
|
||||
fullSourcePath = FullPath;
|
||||
else
|
||||
@@ -400,22 +396,30 @@ namespace System.IO
|
||||
if (PathInternal.IsDirectoryTooLong(fullSourcePath))
|
||||
throw new PathTooLongException(SR.IO_PathTooLong);
|
||||
|
||||
if (PathInternal.IsDirectoryTooLong(fullDestDirName))
|
||||
if (PathInternal.IsDirectoryTooLong(destinationWithSeparator))
|
||||
throw new PathTooLongException(SR.IO_PathTooLong);
|
||||
|
||||
StringComparison pathComparison = PathInternal.StringComparison;
|
||||
if (String.Equals(fullSourcePath, fullDestDirName, pathComparison))
|
||||
if (string.Equals(fullSourcePath, destinationWithSeparator, pathComparison))
|
||||
throw new IOException(SR.IO_SourceDestMustBeDifferent);
|
||||
|
||||
String sourceRoot = Path.GetPathRoot(fullSourcePath);
|
||||
String destinationRoot = Path.GetPathRoot(fullDestDirName);
|
||||
string sourceRoot = Path.GetPathRoot(fullSourcePath);
|
||||
string destinationRoot = Path.GetPathRoot(destinationWithSeparator);
|
||||
|
||||
if (!String.Equals(sourceRoot, destinationRoot, pathComparison))
|
||||
if (!string.Equals(sourceRoot, destinationRoot, pathComparison))
|
||||
throw new IOException(SR.IO_SourceDestMustHaveSameRoot);
|
||||
|
||||
FileSystem.Current.MoveDirectory(FullPath, fullDestDirName);
|
||||
// Windows will throw if the source file/directory doesn't exist, we preemptively check
|
||||
// to make sure our cross platform behavior matches NetFX behavior.
|
||||
if (!Exists && !FileSystem.Current.FileExists(FullPath))
|
||||
throw new DirectoryNotFoundException(SR.Format(SR.IO_PathNotFound_Path, FullPath));
|
||||
|
||||
FullPath = fullDestDirName;
|
||||
if (FileSystem.Current.DirectoryExists(destinationWithSeparator))
|
||||
throw new IOException(SR.Format(SR.IO_AlreadyExists_Name, destinationWithSeparator));
|
||||
|
||||
FileSystem.Current.MoveDirectory(FullPath, destination);
|
||||
|
||||
FullPath = destinationWithSeparator;
|
||||
OriginalPath = destDirName;
|
||||
DisplayPath = GetDisplayName(OriginalPath);
|
||||
|
||||
|
||||
@@ -708,7 +708,7 @@ namespace System.IO
|
||||
// available, we can put this into the FileSystem abstraction and implement it
|
||||
// properly for Win32.
|
||||
|
||||
throw new PlatformNotSupportedException();
|
||||
throw new PlatformNotSupportedException(SR.PlatformNotSupported_FileEncryption);
|
||||
}
|
||||
|
||||
public static void Decrypt(String path)
|
||||
@@ -721,7 +721,7 @@ namespace System.IO
|
||||
// available, we can put this into the FileSystem abstraction and implement it
|
||||
// properly for Win32.
|
||||
|
||||
throw new PlatformNotSupportedException();
|
||||
throw new PlatformNotSupportedException(SR.PlatformNotSupported_FileEncryption);
|
||||
}
|
||||
|
||||
// UTF-8 without BOM and with error detection. Same as the default encoding for StreamWriter.
|
||||
@@ -1005,7 +1005,7 @@ namespace System.IO
|
||||
int index = 0;
|
||||
while (index < count)
|
||||
{
|
||||
int batchSize = Math.Min(DefaultBufferSize, count);
|
||||
int batchSize = Math.Min(DefaultBufferSize, count - index);
|
||||
contents.CopyTo(index, buffer, 0, batchSize);
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
await sw.WriteAsync(buffer, 0, batchSize).ConfigureAwait(false);
|
||||
|
||||
@@ -33,12 +33,6 @@ namespace System.IO
|
||||
Init(fileName);
|
||||
}
|
||||
|
||||
private FileInfo(SerializationInfo info, StreamingContext context) : base(info, context)
|
||||
{
|
||||
_name = Path.GetFileName(OriginalPath);
|
||||
DisplayPath = GetDisplayPath(OriginalPath);
|
||||
}
|
||||
|
||||
[System.Security.SecurityCritical]
|
||||
private void Init(String fileName)
|
||||
{
|
||||
|
||||
@@ -1,38 +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.
|
||||
|
||||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace System.IO
|
||||
{
|
||||
// Maps to FILE_FLAG_DELETE_ON_CLOSE and similar values from winbase.h.
|
||||
// We didn't expose a number of these values because we didn't believe
|
||||
// a number of them made sense in managed code, at least not yet.
|
||||
|
||||
/// <devdoc>
|
||||
/// Additional options to how to create a FileStream.
|
||||
/// </devdoc>
|
||||
[Serializable]
|
||||
[Flags]
|
||||
public enum FileOptions
|
||||
{
|
||||
// NOTE: any change to FileOptions enum needs to be
|
||||
// matched in the FileStream ctor for error validation
|
||||
None = 0,
|
||||
WriteThrough = unchecked((int)0x80000000),
|
||||
Asynchronous = unchecked((int)0x40000000), // FILE_FLAG_OVERLAPPED
|
||||
// NoBuffering = 0x20000000,
|
||||
RandomAccess = 0x10000000,
|
||||
DeleteOnClose = 0x04000000,
|
||||
SequentialScan = 0x08000000,
|
||||
// AllowPosix = 0x01000000, // FILE_FLAG_POSIX_SEMANTICS
|
||||
// BackupOrRestore,
|
||||
// DisallowReparsePoint = 0x00200000, // FILE_FLAG_OPEN_REPARSE_POINT
|
||||
// NoRemoteRecall = 0x00100000, // FILE_FLAG_OPEN_NO_RECALL
|
||||
// FirstPipeInstance = 0x00080000, // FILE_FLAG_FIRST_PIPE_INSTANCE
|
||||
Encrypted = 0x00004000, // FILE_ATTRIBUTE_ENCRYPTED
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,6 +11,11 @@ namespace System.IO
|
||||
/// <summary>true if <see cref="_fileStatus"/> represents a symlink and the target of that symlink is a directory.</summary>
|
||||
private bool _targetOfSymlinkIsDirectory;
|
||||
|
||||
/// <summary>
|
||||
/// Exists as a path as of last refresh.
|
||||
/// </summary>
|
||||
private bool _exists;
|
||||
|
||||
/// <summary>
|
||||
/// Whether we've successfully cached a stat structure.
|
||||
/// -1 if we need to refresh _fileStatus, 0 if we've successfully cached one,
|
||||
@@ -35,6 +40,9 @@ namespace System.IO
|
||||
{
|
||||
EnsureStatInitialized();
|
||||
|
||||
if (!_exists)
|
||||
return (FileAttributes)(-1);
|
||||
|
||||
FileAttributes attrs = default(FileAttributes);
|
||||
|
||||
if (IsDirectoryAssumesInitialized) // this is the one attribute where we follow symlinks
|
||||
@@ -49,7 +57,15 @@ namespace System.IO
|
||||
{
|
||||
attrs |= FileAttributes.ReparsePoint;
|
||||
}
|
||||
if (Path.GetFileName(FullPath).StartsWith("."))
|
||||
|
||||
// If the filename starts with a period, it's hidden. Or if this is a directory ending in a slash,
|
||||
// if the directory name starts with a period, it's hidden.
|
||||
string fileName = Path.GetFileName(FullPath);
|
||||
if (string.IsNullOrEmpty(fileName))
|
||||
{
|
||||
fileName = Path.GetFileName(Path.GetDirectoryName(FullPath));
|
||||
}
|
||||
if (!string.IsNullOrEmpty(fileName) && fileName[0] == '.')
|
||||
{
|
||||
attrs |= FileAttributes.Hidden;
|
||||
}
|
||||
@@ -77,11 +93,31 @@ namespace System.IO
|
||||
// The only thing we can reasonably change is whether the file object is readonly,
|
||||
// just changing its permissions accordingly.
|
||||
EnsureStatInitialized();
|
||||
|
||||
if (!_exists)
|
||||
{
|
||||
ThrowNotFound(FullPath);
|
||||
}
|
||||
|
||||
IsReadOnlyAssumesInitialized = (value & FileAttributes.ReadOnly) != 0;
|
||||
_fileStatusInitialized = -1;
|
||||
}
|
||||
}
|
||||
|
||||
internal static void ThrowNotFound(string path)
|
||||
{
|
||||
// Windows distinguishes between whether the directory or the file isn't found,
|
||||
// and throws a different exception in these cases. We attempt to approximate that
|
||||
// here; there is a race condition here, where something could change between
|
||||
// when the error occurs and our checks, but it's the best we can do, and the
|
||||
// worst case in such a race condition (which could occur if the file system is
|
||||
// being manipulated concurrently with these checks) is that we throw a
|
||||
// FileNotFoundException instead of DirectoryNotFoundException.
|
||||
|
||||
bool directoryError = !Directory.Exists(Path.GetDirectoryName(PathHelpers.TrimEndingDirectorySeparator(path)));
|
||||
throw Interop.GetExceptionForIoErrno(new Interop.ErrorInfo(Interop.Error.ENOENT), path, directoryError);
|
||||
}
|
||||
|
||||
/// <summary>Gets whether stat reported this system object as a directory.</summary>
|
||||
private bool IsDirectoryAssumesInitialized =>
|
||||
(_fileStatus.Mode & Interop.Sys.FileTypes.S_IFMT) == Interop.Sys.FileTypes.S_IFDIR ||
|
||||
@@ -153,7 +189,7 @@ namespace System.IO
|
||||
}
|
||||
|
||||
return
|
||||
_fileStatusInitialized == 0 && // avoid throwing if Refresh failed; instead just return false
|
||||
_exists &&
|
||||
(this is DirectoryInfo) == IsDirectoryAssumesInitialized;
|
||||
}
|
||||
}
|
||||
@@ -163,16 +199,19 @@ namespace System.IO
|
||||
get
|
||||
{
|
||||
EnsureStatInitialized();
|
||||
return (_fileStatus.Flags & Interop.Sys.FileStatusFlags.HasBirthTime) != 0 ?
|
||||
DateTimeOffset.FromUnixTimeSeconds(_fileStatus.BirthTime).ToLocalTime() :
|
||||
default(DateTimeOffset);
|
||||
if (!_exists)
|
||||
return DateTimeOffset.FromFileTime(0);
|
||||
|
||||
long rawTime = (_fileStatus.Flags & Interop.Sys.FileStatusFlags.HasBirthTime) != 0 ?
|
||||
_fileStatus.BirthTime :
|
||||
Math.Min(_fileStatus.CTime, _fileStatus.MTime); // fall back to the oldest time we have in between change and modify time
|
||||
return DateTimeOffset.FromUnixTimeSeconds(rawTime).ToLocalTime();
|
||||
}
|
||||
set
|
||||
{
|
||||
// The ctime in Unix can be interpreted differently by different formats so there isn't
|
||||
// a reliable way to set this; however, we can't just do nothing since the FileSystemWatcher
|
||||
// specifically looks for this call to make a Metatdata Change, so we should set the
|
||||
// LastAccessTime of the file to cause the metadata change we need.
|
||||
// There isn't a reliable way to set this; however, we can't just do nothing since the
|
||||
// FileSystemWatcher specifically looks for this call to make a Metatdata Change, so we
|
||||
// should set the LastAccessTime of the file to cause the metadata change we need.
|
||||
LastAccessTime = LastAccessTime;
|
||||
}
|
||||
}
|
||||
@@ -182,6 +221,8 @@ namespace System.IO
|
||||
get
|
||||
{
|
||||
EnsureStatInitialized();
|
||||
if (!_exists)
|
||||
return DateTimeOffset.FromFileTime(0);
|
||||
return DateTimeOffset.FromUnixTimeSeconds(_fileStatus.ATime).ToLocalTime();
|
||||
}
|
||||
set { SetAccessWriteTimes(value.ToUnixTimeSeconds(), null); }
|
||||
@@ -192,6 +233,8 @@ namespace System.IO
|
||||
get
|
||||
{
|
||||
EnsureStatInitialized();
|
||||
if (!_exists)
|
||||
return DateTimeOffset.FromFileTime(0);
|
||||
return DateTimeOffset.FromUnixTimeSeconds(_fileStatus.MTime).ToLocalTime();
|
||||
}
|
||||
set { SetAccessWriteTimes(null, value.ToUnixTimeSeconds()); }
|
||||
@@ -228,17 +271,32 @@ namespace System.IO
|
||||
// storing those results separately. We only report failure if the initial
|
||||
// lstat fails, as a broken symlink should still report info on exists, attributes, etc.
|
||||
_targetOfSymlinkIsDirectory = false;
|
||||
int result = Interop.Sys.LStat(FullPath, out _fileStatus);
|
||||
string path = PathHelpers.TrimEndingDirectorySeparator(FullPath);
|
||||
int result = Interop.Sys.LStat(path, out _fileStatus);
|
||||
if (result < 0)
|
||||
{
|
||||
Interop.ErrorInfo errorInfo = Interop.Sys.GetLastErrorInfo();
|
||||
_fileStatusInitialized = errorInfo.RawErrno;
|
||||
|
||||
// This should never set the error if the file can't be found.
|
||||
// (see the Windows refresh passing returnErrorOnNotFound: false).
|
||||
if (errorInfo.Error == Interop.Error.ENOENT
|
||||
|| errorInfo.Error == Interop.Error.ENOTDIR)
|
||||
{
|
||||
_fileStatusInitialized = 0;
|
||||
_exists = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
_fileStatusInitialized = errorInfo.RawErrno;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
_exists = true;
|
||||
|
||||
Interop.Sys.FileStatus targetStatus;
|
||||
if ((_fileStatus.Mode & Interop.Sys.FileTypes.S_IFMT) == Interop.Sys.FileTypes.S_IFLNK &&
|
||||
Interop.Sys.Stat(FullPath, out targetStatus) >= 0)
|
||||
Interop.Sys.Stat(path, out targetStatus) >= 0)
|
||||
{
|
||||
_targetOfSymlinkIsDirectory = (targetStatus.Mode & Interop.Sys.FileTypes.S_IFMT) == Interop.Sys.FileTypes.S_IFDIR;
|
||||
}
|
||||
@@ -257,20 +315,7 @@ namespace System.IO
|
||||
{
|
||||
int errno = _fileStatusInitialized;
|
||||
_fileStatusInitialized = -1;
|
||||
var errorInfo = new Interop.ErrorInfo(errno);
|
||||
|
||||
// Windows distinguishes between whether the directory or the file isn't found,
|
||||
// and throws a different exception in these cases. We attempt to approximate that
|
||||
// here; there is a race condition here, where something could change between
|
||||
// when the error occurs and our checks, but it's the best we can do, and the
|
||||
// worst case in such a race condition (which could occur if the file system is
|
||||
// being manipulated concurrently with these checks) is that we throw a
|
||||
// FileNotFoundException instead of DirectoryNotFoundexception.
|
||||
|
||||
// directoryError is true only if a FileNotExists error was provided and the parent
|
||||
// directory of the file represented by _fullPath is nonexistent
|
||||
bool directoryError = (errorInfo.Error == Interop.Error.ENOENT && !Directory.Exists(Path.GetDirectoryName(PathHelpers.TrimEndingDirectorySeparator(FullPath)))); // The destFile's path is invalid
|
||||
throw Interop.GetExceptionForIoErrno(errorInfo, FullPath, directoryError);
|
||||
throw Interop.GetExceptionForIoErrno(new Interop.ErrorInfo(errno), FullPath);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -106,7 +106,7 @@ namespace System.IO
|
||||
get
|
||||
{
|
||||
EnsureDataInitialized();
|
||||
return ((long)_data.fileSizeHigh) << 32 | ((long)_data.fileSizeLow & 0xFFFFFFFFL);
|
||||
return ((long)_data.fileSizeHigh) << 32 | _data.fileSizeLow & 0xFFFFFFFFL;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -126,7 +126,7 @@ namespace System.IO
|
||||
{
|
||||
// This should not throw, instead we store the result so that we can throw it
|
||||
// when someone actually accesses a property
|
||||
_dataInitialized = Win32FileSystem.FillAttributeInfo(FullPath, ref _data, false, false);
|
||||
_dataInitialized = Win32FileSystem.FillAttributeInfo(FullPath, ref _data, tryagain: false, returnErrorOnNotFound: false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -27,19 +27,12 @@ namespace System.IO
|
||||
|
||||
protected FileSystemInfo(SerializationInfo info, StreamingContext context)
|
||||
{
|
||||
if (info == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(info));
|
||||
}
|
||||
|
||||
FullPath = Path.GetFullPath(info.GetString(nameof(FullPath)));
|
||||
OriginalPath = info.GetString(nameof(OriginalPath));
|
||||
throw new PlatformNotSupportedException();
|
||||
}
|
||||
|
||||
public virtual void GetObjectData(SerializationInfo info, StreamingContext context)
|
||||
{
|
||||
info.AddValue(nameof(OriginalPath), OriginalPath, typeof(String));
|
||||
info.AddValue(nameof(FullPath), FullPath, typeof(String));
|
||||
throw new PlatformNotSupportedException();
|
||||
}
|
||||
|
||||
// Full path of the directory/file
|
||||
|
||||
@@ -27,5 +27,10 @@ namespace System.IO
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal static string TrimEndingDirectorySeparator(string path) =>
|
||||
path.Length > 1 && PathInternal.IsDirectorySeparator(path[path.Length - 1]) ? // exclude root "/"
|
||||
path.Substring(0, path.Length - 1) :
|
||||
path;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -118,5 +118,10 @@ namespace System.IO
|
||||
|
||||
return tempStr;
|
||||
}
|
||||
|
||||
internal static string TrimEndingDirectorySeparator(string path) =>
|
||||
EndsInDirectorySeparator(path) ?
|
||||
path.Substring(0, path.Length - 1) :
|
||||
path;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -38,12 +38,5 @@ namespace System.IO
|
||||
{
|
||||
return path.Length > 0 && PathInternal.IsDirectorySeparator(path[path.Length - 1]);
|
||||
}
|
||||
|
||||
internal static string TrimEndingDirectorySeparator(string path)
|
||||
{
|
||||
return EndsInDirectorySeparator(path) ?
|
||||
path.Substring(0, path.Length - 1) :
|
||||
path;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,7 +11,6 @@ namespace System.IO
|
||||
/// retrieve files/directories from the current directory alone
|
||||
/// or should include all the subdirectories also.
|
||||
/// </devdoc>
|
||||
[Serializable]
|
||||
public enum SearchOption
|
||||
{
|
||||
/// <devdoc>
|
||||
|
||||
@@ -82,8 +82,24 @@ namespace System.IO
|
||||
{
|
||||
// The desired behavior for Move(source, dest) is to not overwrite the destination file
|
||||
// if it exists. Since rename(source, dest) will replace the file at 'dest' if it exists,
|
||||
// link/unlink are used instead. Note that the Unix FileSystemWatcher will treat a Move
|
||||
// as a Creation and Deletion instead of a Rename and thus differ from Windows.
|
||||
// link/unlink are used instead. However, if the source path and the dest path refer to
|
||||
// the same file, then do a rename rather than a link and an unlink. This is important
|
||||
// for case-insensitive file systems (e.g. renaming a file in a way that just changes casing),
|
||||
// so that we support changing the casing in the naming of the file. If this fails in any
|
||||
// way (e.g. source file doesn't exist, dest file doesn't exist, rename fails, etc.), we
|
||||
// just fall back to trying the link/unlink approach and generating any exceptional messages
|
||||
// from there as necessary.
|
||||
Interop.Sys.FileStatus sourceStat, destStat;
|
||||
if (Interop.Sys.LStat(sourceFullPath, out sourceStat) == 0 && // source file exists
|
||||
Interop.Sys.LStat(destFullPath, out destStat) == 0 && // dest file exists
|
||||
sourceStat.Dev == destStat.Dev && // source and dest are on the same device
|
||||
sourceStat.Ino == destStat.Ino && // and source and dest are the same file on that device
|
||||
Interop.Sys.Rename(sourceFullPath, destFullPath) == 0) // try the rename
|
||||
{
|
||||
// Renamed successfully.
|
||||
return;
|
||||
}
|
||||
|
||||
if (Interop.Sys.Link(sourceFullPath, destFullPath) < 0)
|
||||
{
|
||||
// If link fails, we can fall back to doing a full copy, but we'll only do so for
|
||||
@@ -260,6 +276,24 @@ namespace System.IO
|
||||
|
||||
public override void MoveDirectory(string sourceFullPath, string destFullPath)
|
||||
{
|
||||
// Windows doesn't care if you try and copy a file via "MoveDirectory"...
|
||||
if (FileExists(sourceFullPath))
|
||||
{
|
||||
// ... but it doesn't like the source to have a trailing slash ...
|
||||
|
||||
// On Windows we end up with ERROR_INVALID_NAME, which is
|
||||
// "The filename, directory name, or volume label syntax is incorrect."
|
||||
//
|
||||
// This surfaces as a IOException, if we let it go beyond here it would
|
||||
// give DirectoryNotFound.
|
||||
|
||||
if (PathHelpers.EndsInDirectorySeparator(sourceFullPath))
|
||||
throw new IOException(SR.Format(SR.IO_PathNotFound_Path, sourceFullPath));
|
||||
|
||||
// ... but it doesn't care if the destination has a trailing separator.
|
||||
destFullPath = PathHelpers.TrimEndingDirectorySeparator(destFullPath);
|
||||
}
|
||||
|
||||
if (Interop.Sys.Rename(sourceFullPath, destFullPath) < 0)
|
||||
{
|
||||
Interop.ErrorInfo errorInfo = Interop.Sys.GetLastErrorInfo();
|
||||
@@ -373,7 +407,9 @@ namespace System.IO
|
||||
public override bool FileExists(string fullPath)
|
||||
{
|
||||
Interop.ErrorInfo ignored;
|
||||
return FileExists(fullPath, Interop.Sys.FileTypes.S_IFREG, out ignored);
|
||||
|
||||
// Windows doesn't care about the trailing separator
|
||||
return FileExists(PathHelpers.TrimEndingDirectorySeparator(fullPath), Interop.Sys.FileTypes.S_IFREG, out ignored);
|
||||
}
|
||||
|
||||
private static bool FileExists(string fullPath, int fileType, out Interop.ErrorInfo errorInfo)
|
||||
@@ -412,14 +448,27 @@ namespace System.IO
|
||||
{
|
||||
case SearchTarget.Files:
|
||||
return new FileSystemEnumerable<FileInfo>(fullPath, searchPattern, searchOption, searchTarget, (path, isDir) =>
|
||||
new FileInfo(path, null));
|
||||
{
|
||||
var info = new FileInfo(path, null);
|
||||
info.Refresh();
|
||||
return info;
|
||||
});
|
||||
case SearchTarget.Directories:
|
||||
return new FileSystemEnumerable<DirectoryInfo>(fullPath, searchPattern, searchOption, searchTarget, (path, isDir) =>
|
||||
new DirectoryInfo(path, null));
|
||||
{
|
||||
var info = new DirectoryInfo(path, null);
|
||||
info.Refresh();
|
||||
return info;
|
||||
});
|
||||
default:
|
||||
return new FileSystemEnumerable<FileSystemInfo>(fullPath, searchPattern, searchOption, searchTarget, (path, isDir) => isDir ?
|
||||
(FileSystemInfo)new DirectoryInfo(path, null) :
|
||||
(FileSystemInfo)new FileInfo(path, null));
|
||||
return new FileSystemEnumerable<FileSystemInfo>(fullPath, searchPattern, searchOption, searchTarget, (path, isDir) =>
|
||||
{
|
||||
var info = isDir ?
|
||||
(FileSystemInfo)new DirectoryInfo(path, null) :
|
||||
(FileSystemInfo)new FileInfo(path, null);
|
||||
info.Refresh();
|
||||
return info;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -468,6 +517,21 @@ namespace System.IO
|
||||
}
|
||||
searchPattern = searchPattern.Substring(lastSlash + 1);
|
||||
}
|
||||
|
||||
// Typically we shouldn't see either of these cases, an upfront check is much faster
|
||||
foreach (char c in searchPattern)
|
||||
{
|
||||
if (c == '\\' || c == '[')
|
||||
{
|
||||
// We need to escape any escape characters in the search pattern
|
||||
searchPattern = searchPattern.Replace(@"\", @"\\");
|
||||
|
||||
// And then escape '[' to prevent it being picked up as a wildcard
|
||||
searchPattern = searchPattern.Replace(@"[", @"\[");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
string fullPath = Path.GetFullPath(userPath);
|
||||
|
||||
// Store everything for the enumerator
|
||||
@@ -602,6 +666,7 @@ namespace System.IO
|
||||
{
|
||||
searchPattern += "*";
|
||||
}
|
||||
|
||||
return searchPattern;
|
||||
}
|
||||
|
||||
@@ -636,7 +701,12 @@ namespace System.IO
|
||||
|
||||
public override FileAttributes GetAttributes(string fullPath)
|
||||
{
|
||||
return new FileInfo(fullPath, null).Attributes;
|
||||
FileAttributes attributes = new FileInfo(fullPath, null).Attributes;
|
||||
|
||||
if (attributes == (FileAttributes)(-1))
|
||||
FileSystemInfo.ThrowNotFound(fullPath);
|
||||
|
||||
return attributes;
|
||||
}
|
||||
|
||||
public override void SetAttributes(string fullPath, FileAttributes attributes)
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user