Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
76 changes: 76 additions & 0 deletions src/libraries/Common/src/Interop/SunOS/portfs/Interop.portfs.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

// This implementation uses SunOS portfs (event ports) to watch directories.
// portfs can detect when a directory's modification time changes via port_associate,
// but cannot tell us WHAT changed in the directory. This makes it different from
// Linux inotify or Windows ReadDirectoryChangesW.
//
// The FileSystemWatcher implementation must:
// 1. Use port_associate to watch for FILE_MODIFIED events on directories
// 2. When an event occurs, re-read the directory contents
// 3. Compare with cached state to determine what actually changed
//

using System;
using System.Runtime.InteropServices;
using Microsoft.Win32.SafeHandles;

internal static partial class Interop
{
internal static partial class PortFs
{
[LibraryImport(Libraries.SystemNative, EntryPoint = "SystemNative_PortCreate",
SetLastError = true)]
internal static partial SafeFileHandle PortCreate();

// pFileObj must point to pinned memory with size >= sizeof(file_obj)
// because the address is used as an identifier in the kernel.
// dirPath string is used while making the association but is
// never referenced again after PortAssociate returns.
// mtime is the directory modification time before reading the directory
// cookie is returned by PortGet to identify which directory changed
[LibraryImport(Libraries.SystemNative, EntryPoint = "SystemNative_PortAssociate",
SetLastError = true, StringMarshalling = StringMarshalling.Utf8)]
internal static unsafe partial int PortAssociate(SafeFileHandle fd, IntPtr pFileObj, string dirPath, Interop.Sys.TimeSpec* mtime, int evmask, nuint cookie);

// Returns the cookie value from PortAssociate in the cookie parameter
[LibraryImport(Libraries.SystemNative, EntryPoint = "SystemNative_PortGet",
SetLastError = true)]
internal static unsafe partial int PortGet(SafeFileHandle fd, int* events, nuint* cookie, Interop.Sys.TimeSpec* tmo);

[LibraryImport(Libraries.SystemNative, EntryPoint = "SystemNative_PortDissociate",
SetLastError = true)]
internal static partial int PortDissociate(SafeFileHandle fd, IntPtr pFileObj);

// Send a synthetic event to wake up a blocked PortGet call
// evflags can be any PortEvent value (e.g., FILE_NOFOLLOW for cancellation)
// cookie is returned to PortGet to identify the event
[LibraryImport(Libraries.SystemNative, EntryPoint = "SystemNative_PortSend",
SetLastError = true)]
internal static partial int PortSend(SafeFileHandle fd, int evflags, nuint cookie);

[Flags]
internal enum PortEvent
{
FILE_ACCESS = 0x00000001,
FILE_MODIFIED = 0x00000002,
FILE_ATTRIB = 0x00000004,
FILE_TRUNC = 0x00100000,
FILE_NOFOLLOW = 0x10000000,
FILE_EXCEPTION = 0x20000000,

// Exception events
FILE_DELETE = 0x00000010,
FILE_RENAME_TO = 0x00000020,
FILE_RENAME_FROM = 0x00000040,
// These are unused, and the duplicate value causes warnings.
// UNMOUNTED = 0x20000000,
// MOUNTEDOVER = 0x40000000,
}

// sizeof(file_obj) = 3*sizeof(timespec) + 3*sizeof(uintptr_t) + sizeof(char*)
// On 64-bit: 3*16 + 3*8 + 8 = 80 bytes
internal const int FileObjSize = 80;
}
}
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFrameworks>$(NetCoreAppCurrent)-windows;$(NetCoreAppCurrent)-linux;$(NetCoreAppCurrent)-osx;$(NetCoreAppCurrent)-maccatalyst;$(NetCoreAppCurrent)-freebsd;$(NetCoreAppCurrent)</TargetFrameworks>
<TargetFrameworks>$(NetCoreAppCurrent)-windows;$(NetCoreAppCurrent)-linux;$(NetCoreAppCurrent)-osx;$(NetCoreAppCurrent)-maccatalyst;$(NetCoreAppCurrent)-freebsd;$(NetCoreAppCurrent)-illumos;$(NetCoreAppCurrent)-solaris;$(NetCoreAppCurrent)</TargetFrameworks>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<UseCompilerGeneratedDocXmlFile>false</UseCompilerGeneratedDocXmlFile>
</PropertyGroup>
Expand Down Expand Up @@ -89,6 +89,22 @@
Link="Common\Interop\Unix\Interop.Stat.cs" />
</ItemGroup>

<ItemGroup Condition="'$(TargetPlatformIdentifier)' == 'illumos' or '$(TargetPlatformIdentifier)' == 'solaris'">
<Compile Include="System\IO\FileSystemWatcher.SunOS.cs" />
<Compile Include="$(CommonPath)Interop\SunOS\portfs\Interop.portfs.cs"
Link="Common\Interop\SunOS\portfs\Interop.portfs.cs" />
<Compile Include="$(CommonPath)Interop\Unix\System.Native\Interop.RealPath.cs"
Link="Common\Interop\Unix\Interop.RealPath.cs" />
<Compile Include="$(CommonPath)Interop\Unix\System.Native\Interop.UTimensat.cs"
Link="Common\Interop\Unix\System.Native\Interop.UTimensat.cs" />
<Compile Include="$(CommonPath)Interop\Unix\System.Native\Interop.Poll.cs"
Link="Common\Interop\Unix\Interop.Poll.cs" />
<Compile Include="$(CommonPath)Interop\Unix\Interop.Poll.Structs.cs"
Link="Common\Interop\Unix\Interop.Poll.Structs.cs" />
<Compile Include="$(CommonPath)Interop\Unix\System.Native\Interop.Stat.cs"
Link="Common\Interop\Unix\Interop.Stat.cs" />
</ItemGroup>

<ItemGroup Condition="'$(TargetPlatformIdentifier)' == 'osx' or '$(TargetPlatformIdentifier)' == 'maccatalyst'">
<Compile Include="System\IO\FileSystemWatcher.OSX.cs" />
<Compile Include="$(CoreLibSharedDir)System\IO\FileSystem.Exists.Unix.cs"
Expand Down
Loading
Loading