@@ -370,7 +370,29 @@ private static IEnumerable<DirectoryChangeNotification> ReadNotifications(SafeHG
370370 {
371371 var info = buffer . GetStructAtOffset < FileNotifyInformation > ( offset ) ;
372372 var result = info . Result ;
373- ns . Add ( new DirectoryChangeNotification ( result . Action , info . Data . ReadUnicodeString ( result . FileNameLength / 2 ) ) ) ;
373+ ns . Add ( new DirectoryChangeNotification ( info ) ) ;
374+ if ( result . NextEntryOffset == 0 )
375+ {
376+ break ;
377+ }
378+ offset += result . NextEntryOffset ;
379+ }
380+ return ns . AsReadOnly ( ) ;
381+ }
382+
383+ private static IEnumerable < DirectoryChangeNotificationExtended > ReadExtendedNotifications ( SafeHGlobalBuffer buffer , IoStatus status )
384+ {
385+ List < DirectoryChangeNotificationExtended > ns = new List < DirectoryChangeNotificationExtended > ( ) ;
386+
387+ // Change buffer size to reflect what's in the buffer.
388+ buffer . Initialize ( ( uint ) status . Information32 ) ;
389+
390+ int offset = 0 ;
391+ while ( offset < buffer . Length )
392+ {
393+ var info = buffer . GetStructAtOffset < FileNotifyExtendedInformation > ( offset ) ;
394+ var result = info . Result ;
395+ ns . Add ( new DirectoryChangeNotificationExtended ( info ) ) ;
374396 if ( result . NextEntryOffset == 0 )
375397 {
376398 break ;
@@ -2788,8 +2810,9 @@ public void CancelIo()
27882810 /// <summary>
27892811 /// Get the extended attributes of a file.
27902812 /// </summary>
2813+ /// <param name="throw_on_error">True to throw on error.</param>
27912814 /// <returns>The extended attributes, empty if no extended attributes.</returns>
2792- public EaBuffer GetEa ( )
2815+ public NtResult < EaBuffer > GetEa ( bool throw_on_error )
27932816 {
27942817 int ea_size = 1024 ;
27952818 while ( true )
@@ -2804,30 +2827,51 @@ public EaBuffer GetEa()
28042827 }
28052828 else if ( status . IsSuccess ( ) )
28062829 {
2807- return new EaBuffer ( buffer ) ;
2830+ return new EaBuffer ( buffer ) . CreateResult ( ) ;
28082831 }
28092832 else if ( status == NtStatus . STATUS_NO_EAS_ON_FILE )
28102833 {
2811- return new EaBuffer ( ) ;
2834+ return new EaBuffer ( ) . CreateResult ( ) ;
28122835 }
28132836 else
28142837 {
2815- throw new NtException ( status ) ;
2838+ return status . CreateResultFromError < EaBuffer > ( throw_on_error ) ;
28162839 }
28172840 }
28182841 }
28192842
2843+ /// <summary>
2844+ /// Get the extended attributes of a file.
2845+ /// </summary>
2846+ /// <returns>The extended attributes, empty if no extended attributes.</returns>
2847+ public EaBuffer GetEa ( )
2848+ {
2849+ return GetEa ( true ) . Result ;
2850+ }
2851+
28202852 /// <summary>
28212853 /// Set the extended attributes for a file.
28222854 /// </summary>
28232855 /// <param name="ea">The EA buffer to set.</param>
2856+ /// <param name="throw_on_error">True to throw on error.</param>
28242857 /// <remarks>This will add entries if they no longer exist,
28252858 /// remove entries if the data is empty or update existing entires.</remarks>
2826- public void SetEa ( EaBuffer ea )
2859+ public NtStatus SetEa ( EaBuffer ea , bool throw_on_error )
28272860 {
28282861 byte [ ] ea_buffer = ea . ToByteArray ( ) ;
28292862 IoStatus io_status = new IoStatus ( ) ;
2830- NtSystemCalls . NtSetEaFile ( Handle , io_status , ea_buffer , ea_buffer . Length ) . ToNtException ( ) ;
2863+ return NtSystemCalls . NtSetEaFile ( Handle , io_status , ea_buffer , ea_buffer . Length ) . ToNtException ( throw_on_error ) ;
2864+ }
2865+
2866+ /// <summary>
2867+ /// Set the extended attributes for a file.
2868+ /// </summary>
2869+ /// <param name="ea">The EA buffer to set.</param>
2870+ /// <remarks>This will add entries if they no longer exist,
2871+ /// remove entries if the data is empty or update existing entires.</remarks>
2872+ public void SetEa ( EaBuffer ea )
2873+ {
2874+ SetEa ( ea , true ) ;
28312875 }
28322876
28332877 /// <summary>
@@ -2900,13 +2944,22 @@ public bool IsAccessGranted(FileDirectoryAccessRights access)
29002944 return IsAccessMaskGranted ( access ) ;
29012945 }
29022946
2947+ /// <summary>
2948+ /// Get the cached signing level for a file.
2949+ /// </summary>
2950+ /// <returns>The cached signing level.</returns>
2951+ public NtResult < CachedSigningLevel > GetCachedSigningLevel ( bool throw_on_error )
2952+ {
2953+ return NtSecurity . GetCachedSigningLevel ( Handle , throw_on_error ) ;
2954+ }
2955+
29032956 /// <summary>
29042957 /// Get the cached signing level for a file.
29052958 /// </summary>
29062959 /// <returns>The cached signing level.</returns>
29072960 public CachedSigningLevel GetCachedSigningLevel ( )
29082961 {
2909- return NtSecurity . GetCachedSigningLevel ( Handle ) ;
2962+ return GetCachedSigningLevel ( true ) . Result ;
29102963 }
29112964
29122965 /// <summary>
@@ -3356,14 +3409,114 @@ public async Task<IEnumerable<DirectoryChangeNotification>> GetChangeNotificatio
33563409 /// </summary>
33573410 /// <param name="completion_filter">The filter of events to watch for.</param>
33583411 /// <param name="watch_subtree">True to watch all sub directories.</param>
3359- /// <param name="token">Cancellation token.</param>
33603412 /// <returns>The list of changes.</returns>
33613413 public Task < IEnumerable < DirectoryChangeNotification > > GetChangeNotificationAsync (
33623414 DirectoryChangeNotifyFilter completion_filter , bool watch_subtree )
33633415 {
33643416 return GetChangeNotificationAsync ( completion_filter , watch_subtree , CancellationToken . None ) ;
33653417 }
33663418
3419+
3420+ /// <summary>
3421+ /// Get extended change notifications.
3422+ /// </summary>
3423+ /// <param name="completion_filter">The filter of events to watch for.</param>
3424+ /// <param name="watch_subtree">True to watch all sub directories.</param>
3425+ /// <param name="throw_on_error">True to throw on error.</param>
3426+ /// <returns>The list of changes.</returns>
3427+ [ SupportedVersion ( SupportedVersion . Windows10_RS3 ) ]
3428+ public NtResult < IEnumerable < DirectoryChangeNotificationExtended > > GetChangeNotificationEx (
3429+ DirectoryChangeNotifyFilter completion_filter , bool watch_subtree , bool throw_on_error )
3430+ {
3431+ using ( NtAsyncResult result = new NtAsyncResult ( this ) )
3432+ {
3433+ using ( var buffer = new SafeHGlobalBuffer ( 8192 ) )
3434+ {
3435+ return result . CompleteCall ( NtSystemCalls . NtNotifyChangeDirectoryFileEx (
3436+ Handle , result . EventHandle , IntPtr . Zero , IntPtr . Zero , result . IoStatusBuffer ,
3437+ buffer , buffer . Length , completion_filter , watch_subtree ,
3438+ DirectoryNotifyInformationClass . DirectoryNotifyExtendedInformation ) )
3439+ . CreateResult ( throw_on_error , ( ) => ReadExtendedNotifications ( buffer , result . IoStatusBuffer . Result ) ) ;
3440+ }
3441+ }
3442+ }
3443+
3444+ /// <summary>
3445+ /// Get change notifications.
3446+ /// </summary>
3447+ /// <param name="completion_filter">The filter of events to watch for.</param>
3448+ /// <param name="watch_subtree">True to watch all sub directories.</param>
3449+ /// <returns>The list of changes.</returns>
3450+ [ SupportedVersion ( SupportedVersion . Windows10_RS3 ) ]
3451+ public IEnumerable < DirectoryChangeNotificationExtended > GetChangeNotificationEx ( DirectoryChangeNotifyFilter completion_filter , bool watch_subtree )
3452+ {
3453+ return GetChangeNotificationEx ( completion_filter , watch_subtree , true ) . Result ;
3454+ }
3455+
3456+ /// <summary>
3457+ /// Get change notifications.
3458+ /// </summary>
3459+ /// <param name="completion_filter">The filter of events to watch for.</param>
3460+ /// <param name="watch_subtree">True to watch all sub directories.</param>
3461+ /// <param name="throw_on_error">True to throw on error.</param>
3462+ /// <param name="token">Cancellation token.</param>
3463+ /// <returns>The list of changes.</returns>
3464+ [ SupportedVersion ( SupportedVersion . Windows10_RS3 ) ]
3465+ public async Task < NtResult < IEnumerable < DirectoryChangeNotificationExtended > > > GetChangeNotificationExAsync (
3466+ DirectoryChangeNotifyFilter completion_filter , bool watch_subtree , CancellationToken token , bool throw_on_error )
3467+ {
3468+ using ( var buffer = new SafeHGlobalBuffer ( 8192 ) )
3469+ {
3470+ var status = await RunFileCallAsync ( result => NtSystemCalls . NtNotifyChangeDirectoryFileEx (
3471+ Handle , result . EventHandle , IntPtr . Zero , IntPtr . Zero , result . IoStatusBuffer ,
3472+ buffer , buffer . Length , completion_filter , watch_subtree ,
3473+ DirectoryNotifyInformationClass . DirectoryNotifyExtendedInformation ) , token , throw_on_error ) ;
3474+ return status . Map ( r => ReadExtendedNotifications ( buffer , r ) ) ;
3475+ }
3476+ }
3477+
3478+ /// <summary>
3479+ /// Get change notifications.
3480+ /// </summary>
3481+ /// <param name="completion_filter">The filter of events to watch for.</param>
3482+ /// <param name="watch_subtree">True to watch all sub directories.</param>
3483+ /// <param name="throw_on_error">True to throw on error.</param>
3484+ /// <returns>The list of changes.</returns>
3485+ [ SupportedVersion ( SupportedVersion . Windows10_RS3 ) ]
3486+ public Task < NtResult < IEnumerable < DirectoryChangeNotificationExtended > > > GetChangeNotificationExAsync (
3487+ DirectoryChangeNotifyFilter completion_filter , bool watch_subtree , bool throw_on_error )
3488+ {
3489+ return GetChangeNotificationExAsync ( completion_filter , watch_subtree , CancellationToken . None , throw_on_error ) ;
3490+ }
3491+
3492+ /// <summary>
3493+ /// Get change notifications.
3494+ /// </summary>
3495+ /// <param name="completion_filter">The filter of events to watch for.</param>
3496+ /// <param name="watch_subtree">True to watch all sub directories.</param>
3497+ /// <param name="token">Cancellation token.</param>
3498+ /// <returns>The list of changes.</returns>
3499+ [ SupportedVersion ( SupportedVersion . Windows10_RS3 ) ]
3500+ public async Task < IEnumerable < DirectoryChangeNotificationExtended > > GetChangeNotificationExAsync (
3501+ DirectoryChangeNotifyFilter completion_filter , bool watch_subtree , CancellationToken token )
3502+ {
3503+ var result = await GetChangeNotificationExAsync ( completion_filter , watch_subtree , token , true ) ;
3504+ return result . Result ;
3505+ }
3506+
3507+ /// <summary>
3508+ /// Get change notifications.
3509+ /// </summary>
3510+ /// <param name="completion_filter">The filter of events to watch for.</param>
3511+ /// <param name="watch_subtree">True to watch all sub directories.</param>
3512+ /// <returns>The list of changes.</returns>
3513+ [ SupportedVersion ( SupportedVersion . Windows10_RS3 ) ]
3514+ public Task < IEnumerable < DirectoryChangeNotificationExtended > > GetChangeNotificationAsyncEx (
3515+ DirectoryChangeNotifyFilter completion_filter , bool watch_subtree )
3516+ {
3517+ return GetChangeNotificationExAsync ( completion_filter , watch_subtree , CancellationToken . None ) ;
3518+ }
3519+
33673520 /// <summary>
33683521 /// Method to query information for this object type.
33693522 /// </summary>
0 commit comments