Imported Upstream version 6.8.0.73

Former-commit-id: d18deab1b47cfd3ad8cba82b3f37d00eec2170af
This commit is contained in:
Xamarin Public Jenkins (auto-signing)
2019-12-10 18:00:56 +00:00
parent bceda29824
commit 73ee7591e8
1043 changed files with 16271 additions and 22080 deletions

View File

@@ -30,21 +30,21 @@ internal static partial class Interop
internal byte* Name;
internal int NameLength;
internal NodeType InodeType;
internal const int NameBufferSize = 256;
internal const int NameBufferSize = 256; // sizeof(dirent->d_name) == NAME_MAX + 1
internal ReadOnlySpan<char> GetName(Span<char> buffer)
{
Debug.Assert(buffer.Length >= Encoding.UTF8.GetMaxCharCount(NameBufferSize - 1), "should have enough space for the max file name");
// -1 for null terminator (buffer will not include one),
// and -1 because GetMaxCharCount pessimistically assumes the buffer may start with a partial surrogate
Debug.Assert(buffer.Length >= Encoding.UTF8.GetMaxCharCount(NameBufferSize - 1 - 1));
Debug.Assert(Name != null, "should not have a null name");
ReadOnlySpan<byte> nameBytes = (NameLength == -1)
// In this case the struct was allocated via struct dirent *readdir(DIR *dirp);
? new ReadOnlySpan<byte>(Name, new ReadOnlySpan<byte>(Name, NameBufferSize - 1).IndexOf<byte>(0))
? new ReadOnlySpan<byte>(Name, new ReadOnlySpan<byte>(Name, NameBufferSize).IndexOf<byte>(0))
: new ReadOnlySpan<byte>(Name, NameLength);
Debug.Assert(nameBytes.Length > 0, "we shouldn't have gotten a garbage value from the OS");
if (nameBytes.Length == 0)
return buffer.Slice(0, 0);
int charCount = Encoding.UTF8.GetChars(nameBytes, buffer);
ReadOnlySpan<char> value = buffer.Slice(0, charCount);

View File

@@ -33,6 +33,7 @@ internal static partial class Interop
internal long BirthTimeNsec;
internal long Dev;
internal long Ino;
internal uint UserFlags;
}
internal static class FileTypes

View File

@@ -0,0 +1,26 @@
// 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;
internal static partial class Interop
{
internal static partial class Sys
{
[Flags]
internal enum UserFlags : uint
{
UF_HIDDEN = 0x8000
}
[DllImport(Libraries.SystemNative, EntryPoint = "SystemNative_LChflags", SetLastError = true)]
internal static extern int LChflags(string path, uint flags);
internal static readonly bool CanSetHiddenFlag = (LChflagsCanSetHiddenFlag() != 0);
[DllImport(Libraries.SystemNative, EntryPoint = "SystemNative_LChflagsCanSetHiddenFlag")]
private static extern int LChflagsCanSetHiddenFlag();
}
}

View File

@@ -33,6 +33,7 @@ internal static partial class Interop
internal long BirthTimeNsec;
internal long Dev;
internal long Ino;
internal uint UserFlags;
}
internal static class FileTypes

View File

@@ -16,6 +16,8 @@
#cmakedefine01 HAVE_STAT_TIMESPEC
#cmakedefine01 HAVE_STAT_TIM
#cmakedefine01 HAVE_STAT_NSEC
#cmakedefine01 HAVE_STAT_FLAGS
#cmakedefine01 HAVE_LCHFLAGS
#cmakedefine01 HAVE_GNU_STRERROR_R
#cmakedefine01 HAVE_READDIR_R
#cmakedefine01 HAVE_DIRENT_NAME_LEN

View File

@@ -166,6 +166,12 @@ static void ConvertFileStatus(const struct stat_* src, struct FileStatus* dst)
dst->BirthTime = 0;
dst->BirthTimeNsec = 0;
#endif
#if defined(HAVE_STAT_FLAGS) && defined(UF_HIDDEN)
dst->UserFlags = ((src->st_flags & UF_HIDDEN) == UF_HIDDEN) ? PAL_UF_HIDDEN : 0;
#else
dst->UserFlags = 0;
#endif
}
// CoreCLR expects the "2" suffixes on these: they should be cleaned up in our
@@ -1460,6 +1466,28 @@ int32_t SystemNative_LockFileRegion(intptr_t fd, int64_t offset, int64_t length,
return ret;
}
int32_t SystemNative_LChflags(const char* path, uint32_t flags)
{
#if HAVE_LCHFLAGS
int32_t result;
while ((result = lchflags(path, flags)) < 0 && errno == EINTR);
return result;
#else
(void)path, (void)flags;
errno = ENOTSUP;
return -1;
#endif
}
int32_t SystemNative_LChflagsCanSetHiddenFlag(void)
{
#if defined(UF_HIDDEN) && defined(HAVE_STAT_FLAGS) && defined(HAVE_LCHFLAGS)
return true;
#else
return false;
#endif
}
int32_t SystemNative_Symlink(const char* target, const char* linkPath)
{
return symlink(target, linkPath);

View File

@@ -35,6 +35,7 @@ struct FileStatus
int64_t BirthTimeNsec; // nanosecond part
int64_t Dev; // ID of the device containing the file
int64_t Ino; // inode number of the file
uint32_t UserFlags; // user defined flags
};
/* Provide consistent access to nanosecond fields, if they exist. */
@@ -153,6 +154,14 @@ enum
FILESTATUS_FLAGS_HAS_BIRTHTIME = 1,
};
/**
* Constants for interpreting FileStatus.UserFlags.
*/
enum
{
PAL_UF_HIDDEN = 0x8000
};
/**
* Constants from dirent.h for the inode type returned from readdir variants
*/
@@ -750,6 +759,20 @@ DLLEXPORT int32_t SystemNative_GetPeerID(intptr_t socket, uid_t* euid);
*/
DLLEXPORT int32_t SystemNative_LockFileRegion(intptr_t fd, int64_t offset, int64_t length, int16_t lockType);
/**
* Changes the file flags of the file whose location is specified in path
*
* Returns 0 for success, -1 for failure. Sets errno for failure.
*/
DLLEXPORT int32_t SystemNative_LChflags(const char* path, uint32_t flags);
/**
* Determines if the current platform supports setting UF_HIDDEN (0x8000) flag
*
* Returns true (non-zero) if supported, false (zero) if not.
*/
DLLEXPORT int32_t SystemNative_LChflagsCanSetHiddenFlag(void);
/**
* Creates a symbolic link at "linkPath", pointing at "target".
* "target" may or may not exist (dangling symbolic links are valid filesystem objects)

View File

@@ -284,6 +284,9 @@
<Compile Include="$(CommonPath)\Interop\Unix\System.Native\Interop.Read.cs">
<Link>Common\Interop\Unix\Interop.Read.cs</Link>
</Compile>
<Compile Include="$(CommonPath)\Interop\Unix\System.Native\Interop.LChflags.cs">
<Link>Common\Interop\Unix\Interop.LChflags.cs</Link>
</Compile>
<Compile Include="$(CommonPath)\Interop\Unix\System.Native\Interop.Rename.cs">
<Link>Common\Interop\Unix\Interop.Rename.cs</Link>
</Compile>

View File

@@ -10,14 +10,13 @@ namespace System.IO.Enumeration
/// Lower level view of FileSystemInfo used for processing and filtering find results.
/// </summary>
public unsafe ref partial struct FileSystemEntry
{
private const int FileNameBufferSize = 256;
{
internal Interop.Sys.DirectoryEntry _directoryEntry;
private FileStatus _status;
private Span<char> _pathBuffer;
private ReadOnlySpan<char> _fullPath;
private ReadOnlySpan<char> _fileName;
private fixed char _fileNameBuffer[FileNameBufferSize];
private fixed char _fileNameBuffer[Interop.Sys.DirectoryEntry.NameBufferSize];
private FileAttributes _initialAttributes;
internal static FileAttributes Initialize(
@@ -112,7 +111,7 @@ namespace System.IO.Enumeration
{
fixed (char* c = _fileNameBuffer)
{
Span<char> buffer = new Span<char>(c, FileNameBufferSize);
Span<char> buffer = new Span<char>(c, Interop.Sys.DirectoryEntry.NameBufferSize);
_fileName = _directoryEntry.GetName(buffer);
}
}

View File

@@ -84,8 +84,8 @@ namespace System.IO
if (_isDirectory)
attributes |= FileAttributes.Directory;
// If the filename starts with a period, it's hidden.
if (fileName.Length > 0 && fileName[0] == '.')
// If the filename starts with a period or has UF_HIDDEN flag set, it's hidden.
if (fileName.Length > 0 && (fileName[0] == '.' || (_fileStatus.UserFlags & (uint)Interop.Sys.UserFlags.UF_HIDDEN) == (uint)Interop.Sys.UserFlags.UF_HIDDEN))
attributes |= FileAttributes.Hidden;
return attributes != default ? attributes : FileAttributes.Normal;
@@ -98,10 +98,10 @@ namespace System.IO
const FileAttributes allValidFlags =
FileAttributes.Archive | FileAttributes.Compressed | FileAttributes.Device |
FileAttributes.Directory | FileAttributes.Encrypted | FileAttributes.Hidden |
FileAttributes.Hidden | FileAttributes.IntegrityStream | FileAttributes.Normal |
FileAttributes.NoScrubData | FileAttributes.NotContentIndexed | FileAttributes.Offline |
FileAttributes.ReadOnly | FileAttributes.ReparsePoint | FileAttributes.SparseFile |
FileAttributes.System | FileAttributes.Temporary;
FileAttributes.IntegrityStream | FileAttributes.Normal | FileAttributes.NoScrubData |
FileAttributes.NotContentIndexed | FileAttributes.Offline | FileAttributes.ReadOnly |
FileAttributes.ReparsePoint | FileAttributes.SparseFile | FileAttributes.System |
FileAttributes.Temporary;
if ((attributes & ~allValidFlags) != 0)
{
// Using constant string for argument to match historical throw
@@ -113,6 +113,26 @@ namespace System.IO
if (!_exists)
FileSystemInfo.ThrowNotFound(path);
if (Interop.Sys.CanSetHiddenFlag)
{
if ((attributes & FileAttributes.Hidden) != 0)
{
if ((_fileStatus.UserFlags & (uint)Interop.Sys.UserFlags.UF_HIDDEN) == 0)
{
// If Hidden flag is set and cached file status does not have the flag set then set it
Interop.CheckIo(Interop.Sys.LChflags(path, (_fileStatus.UserFlags | (uint)Interop.Sys.UserFlags.UF_HIDDEN)), path, InitiallyDirectory);
}
}
else
{
if ((_fileStatus.UserFlags & (uint)Interop.Sys.UserFlags.UF_HIDDEN) == (uint)Interop.Sys.UserFlags.UF_HIDDEN)
{
// If Hidden flag is not set and cached file status does have the flag set then remove it
Interop.CheckIo(Interop.Sys.LChflags(path, (_fileStatus.UserFlags & ~(uint)Interop.Sys.UserFlags.UF_HIDDEN)), path, InitiallyDirectory);
}
}
}
// The only thing we can reasonably change is whether the file object is readonly by changing permissions.
int newMode = _fileStatus.Mode;

View File

@@ -16,9 +16,16 @@ namespace System.IO.Tests
public void SettingAttributes_Unix(FileAttributes attributes)
{
string path = CreateItem();
SetAttributes(path, attributes);
Assert.Equal(attributes, GetAttributes(path));
SetAttributes(path, 0);
AssertSettingAttributes(path, attributes);
}
[Theory]
[InlineData(FileAttributes.Hidden)]
[PlatformSpecific(TestPlatforms.OSX | TestPlatforms.FreeBSD)]
public void SettingAttributes_OSXAndFreeBSD(FileAttributes attributes)
{
string path = CreateItem();
AssertSettingAttributes(path, attributes);
}
[Theory]
@@ -33,6 +40,11 @@ namespace System.IO.Tests
public void SettingAttributes_Windows(FileAttributes attributes)
{
string path = CreateItem();
AssertSettingAttributes(path, attributes);
}
private void AssertSettingAttributes(string path, FileAttributes attributes)
{
SetAttributes(path, attributes);
Assert.Equal(attributes, GetAttributes(path));
SetAttributes(path, 0);
@@ -48,8 +60,16 @@ namespace System.IO.Tests
public void SettingInvalidAttributes_Unix(FileAttributes attributes)
{
string path = CreateItem();
SetAttributes(path, attributes);
Assert.Equal(FileAttributes.Normal, GetAttributes(path));
AssertSettingInvalidAttributes(path, attributes);
}
[Theory]
[InlineData(FileAttributes.Hidden)]
[PlatformSpecific(TestPlatforms.AnyUnix & ~(TestPlatforms.OSX | TestPlatforms.FreeBSD))]
public void SettingInvalidAttributes_UnixExceptOSXAndFreeBSD(FileAttributes attributes)
{
string path = CreateItem();
AssertSettingInvalidAttributes(path, attributes);
}
[Theory]
@@ -62,6 +82,11 @@ namespace System.IO.Tests
public void SettingInvalidAttributes_Windows(FileAttributes attributes)
{
string path = CreateItem();
AssertSettingInvalidAttributes(path, attributes);
}
private void AssertSettingInvalidAttributes(string path, FileAttributes attributes)
{
SetAttributes(path, attributes);
Assert.Equal(FileAttributes.Normal, GetAttributes(path));
}

View File

@@ -2,6 +2,9 @@
// 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.Collections.Generic;
using System.Linq;
using System.IO.Enumeration;
using Xunit;
@@ -96,5 +99,39 @@ namespace System.IO.Tests
Assert.Equal(info.FullName, ie.DirectoryFinished);
}
}
[Fact]
public void VariableLengthFileNames_AllCreatableFilesAreEnumerable()
{
DirectoryInfo testDirectory = Directory.CreateDirectory(GetTestFilePath());
var names = new List<string>();
for (int length = 1; length < 10_000; length++) // arbitrarily large limit for the test
{
string name = new string('a', length);
try { File.Create(Path.Join(testDirectory.FullName, name)).Dispose(); }
catch { break; }
names.Add(name);
}
Assert.InRange(names.Count, 1, int.MaxValue);
Assert.Equal(names.OrderBy(n => n), Directory.GetFiles(testDirectory.FullName).Select(n => Path.GetFileName(n)).OrderBy(n => n));
}
[Fact]
public void VariableLengthDirectoryNames_AllCreatableDirectoriesAreEnumerable()
{
DirectoryInfo testDirectory = Directory.CreateDirectory(GetTestFilePath());
var names = new List<string>();
for (int length = 1; length < 10_000; length++) // arbitrarily large limit for the test
{
string name = new string('a', length);
try { Directory.CreateDirectory(Path.Join(testDirectory.FullName, name)); }
catch { break; }
names.Add(name);
}
Assert.InRange(names.Count, 1, int.MaxValue);
Assert.Equal(names.OrderBy(n => n), Directory.GetDirectories(testDirectory.FullName).Select(n => Path.GetFileName(n)).OrderBy(n => n));
}
}
}

View File

@@ -168,6 +168,33 @@ namespace System.IO.Tests
#region PlatformSpecific
[Fact]
[PlatformSpecific(TestPlatforms.AnyUnix)]
public void LongDirectoryName()
{
// 255 = NAME_MAX on Linux and macOS
DirectoryInfo path = Directory.CreateDirectory(Path.Combine(GetTestFilePath(), new string('a', 255)));
Assert.True(Directory.Exists(path.FullName));
Directory.Delete(path.FullName);
Assert.False(Directory.Exists(path.FullName));
}
[Fact]
[PlatformSpecific(TestPlatforms.AnyUnix)]
public void LongFileName()
{
// 255 = NAME_MAX on Linux and macOS
var dir = GetTestFilePath();
Directory.CreateDirectory(dir);
var path = Path.Combine(dir, new string('b', 255));
File.Create(path).Dispose();
Assert.True(File.Exists(path));
File.Delete(path);
Assert.False(File.Exists(path));
}
[Fact]
[PlatformSpecific(CaseSensitivePlatforms)]
public void CaseSensitive()

View File

@@ -28,5 +28,18 @@ namespace System.IO.Tests
test.Refresh();
Assert.Equal(false, test.IsReadOnly);
}
[Theory]
[InlineData(".", true)]
[InlineData("", false)]
[PlatformSpecific(TestPlatforms.OSX)]
public void HiddenAttributeSetCorrectly_OSX(string filePrefix, bool hidden)
{
string testFilePath = Path.Combine(TestDirectory, $"{filePrefix}{GetTestFileName()}");
FileInfo fileInfo = new FileInfo(testFilePath);
fileInfo.Create().Dispose();
Assert.Equal(hidden, (fileInfo.Attributes & FileAttributes.Hidden) == FileAttributes.Hidden);
}
}
}

View File

@@ -153,7 +153,7 @@ namespace System.IO.Tests
}
}
[Theory]
[ConditionalTheory(typeof(PlatformDetection), nameof(PlatformDetection.IsNotWindowsSubsystemForLinux))] // https://github.com/dotnet/corefx/issues/34397
[InlineData(10, 0, 10, 1, 2)]
[InlineData(10, 3, 5, 3, 5)]
[InlineData(10, 3, 5, 3, 4)]

View File

@@ -31,9 +31,15 @@ namespace System.Linq.Parallel
// Whether to preserve order by default, when neither AsOrdered nor AsUnordered is used.
internal const bool DefaultPreserveOrder = false;
#if MONO
// By default limit to degree of 16 to avoid too much contention. It's
// still possible to override that to a maximum of MAX_SUPPORTED_DOP.
internal static int DefaultDegreeOfParallelism = Math.Min(Environment.ProcessorCount, 16);
#else
// The default degree of parallelism, or -1 if unspecified. Dev unit tests set this value
// to change the default DOP.
internal static int DefaultDegreeOfParallelism = Math.Min(Environment.ProcessorCount, MAX_SUPPORTED_DOP);
#endif
// The size to use for bounded buffers.
internal const int DEFAULT_BOUNDED_BUFFER_CAPACITY = 512;

View File

@@ -13,8 +13,17 @@ namespace System.Net.Http.Headers
{
private UriKind _uriKind;
#if MONO
// FIXME: Workaround for https://github.com/mono/mono/issues/17897.
// This is the same as setting the MONO_URI_DOTNETRELATIVEORABSOLUTE=true
// environment variable.
// See https://github.com/mono/mono/blob/1454b010ae1165a0f2cf261b9420e32d1b52fdaf/mcs/class/referencesource/System/net/System/URI.cs#L991.
internal static readonly UriHeaderParser RelativeOrAbsoluteUriParser =
new UriHeaderParser((UriKind)300);
#else
internal static readonly UriHeaderParser RelativeOrAbsoluteUriParser =
new UriHeaderParser(UriKind.RelativeOrAbsolute);
#endif
private UriHeaderParser(UriKind uriKind)
: base(false)