Imported Upstream version 5.4.0.167

Former-commit-id: 5624ac747d633e885131e8349322922b6a59baaa
This commit is contained in:
Xamarin Public Jenkins (auto-signing)
2017-08-21 15:34:15 +00:00
parent e49d6f06c0
commit 536cd135cc
12856 changed files with 563812 additions and 223249 deletions

View File

@@ -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

View File

@@ -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>

View File

@@ -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);
}
}
}

View File

@@ -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);
}
}
}
}

View File

@@ -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

View File

@@ -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>

View File

@@ -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" />

View File

@@ -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);
}

View File

@@ -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);

View File

@@ -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);

View File

@@ -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)
{

View File

@@ -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
}
}

View File

@@ -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);
}
}
}

View File

@@ -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);
}
}
}

View File

@@ -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

View 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;
}
}

View File

@@ -118,5 +118,10 @@ namespace System.IO
return tempStr;
}
internal static string TrimEndingDirectorySeparator(string path) =>
EndsInDirectorySeparator(path) ?
path.Substring(0, path.Length - 1) :
path;
}
}

View File

@@ -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;
}
}
}

View File

@@ -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>

View File

@@ -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