/**************************************************************************** * ReadDirectoryChangesW (KERNEL32.@) * * NOTES * * The filter is remember from the first run and ignored on successive runs. * * If there's no output buffer on the first run, it's ignored successive runs * and STATUS_NOTIFY_ENUM_DIRECTORY is returned with an empty buffer. * * If a NULL overlapped->hEvent is passed, the directory handle is used * for signalling. */ BOOL WINAPI ReadDirectoryChangesW( HANDLE handle, LPVOID buffer, DWORD len, BOOL subtree, DWORD filter, LPDWORD returned, LPOVERLAPPED overlapped, LPOVERLAPPED_COMPLETION_ROUTINE completion ) { OVERLAPPED ov, *pov; IO_STATUS_BLOCK *ios; NTSTATUS status; BOOL ret = TRUE; LPVOID cvalue = NULL; TRACE("%p %p %08x %d %08x %p %p %p\n", handle, buffer, len, subtree, filter, returned, overlapped, completion ); if (!overlapped) { memset( &ov, 0, sizeof ov ); ov.hEvent = CreateEventW( NULL, 0, 0, NULL ); pov = &ov; } else { pov = overlapped; if(completion) cvalue = completion; else if (((ULONG_PTR)overlapped->hEvent & 1) == 0) cvalue = overlapped; } ios = (PIO_STATUS_BLOCK) pov; ios->u.Status = STATUS_PENDING; status = NtNotifyChangeDirectoryFile( handle, completion && overlapped ? NULL : pov->hEvent, completion && overlapped ? invoke_completion : NULL, cvalue, ios, buffer, len, filter, subtree ); if (status == STATUS_PENDING) { if (overlapped) return TRUE; WaitForSingleObjectEx( ov.hEvent, INFINITE, TRUE ); CloseHandle( ov.hEvent ); if (returned) *returned = ios->Information; status = ios->u.Status; } if (status != STATUS_SUCCESS) { SetLastError( RtlNtStatusToDosError(status) ); ret = FALSE; } return ret; }
/**************************************************************************** * FindNextChangeNotification (KERNEL32.@) */ BOOL WINAPI FindNextChangeNotification( HANDLE handle ) { NTSTATUS status; TRACE("%p\n",handle); status = NtNotifyChangeDirectoryFile( handle, NULL, NULL, NULL, &FindFirstChange_iosb, NULL, 0, FILE_NOTIFY_CHANGE_SIZE, 0 ); if (status != STATUS_PENDING) { SetLastError( RtlNtStatusToDosError(status) ); return FALSE; } return TRUE; }
/**************************************************************************** * FindFirstChangeNotificationW (KERNEL32.@) */ HANDLE WINAPI FindFirstChangeNotificationW( LPCWSTR lpPathName, BOOL bWatchSubtree, DWORD dwNotifyFilter) { UNICODE_STRING nt_name; OBJECT_ATTRIBUTES attr; NTSTATUS status; HANDLE handle = INVALID_HANDLE_VALUE; TRACE( "%s %d %x\n", debugstr_w(lpPathName), bWatchSubtree, dwNotifyFilter ); if (!RtlDosPathNameToNtPathName_U( lpPathName, &nt_name, NULL, NULL )) { SetLastError( ERROR_PATH_NOT_FOUND ); return handle; } attr.Length = sizeof(attr); attr.RootDirectory = 0; attr.Attributes = OBJ_CASE_INSENSITIVE; attr.ObjectName = &nt_name; attr.SecurityDescriptor = NULL; attr.SecurityQualityOfService = NULL; status = NtOpenFile( &handle, FILE_LIST_DIRECTORY | SYNCHRONIZE, &attr, &FindFirstChange_iosb, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, FILE_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT ); RtlFreeUnicodeString( &nt_name ); if (status != STATUS_SUCCESS) { SetLastError( RtlNtStatusToDosError(status) ); return INVALID_HANDLE_VALUE; } status = NtNotifyChangeDirectoryFile( handle, NULL, NULL, NULL, &FindFirstChange_iosb, NULL, 0, dwNotifyFilter, bWatchSubtree ); if (status != STATUS_PENDING) { NtClose( handle ); SetLastError( RtlNtStatusToDosError(status) ); return INVALID_HANDLE_VALUE; } return handle; }
BOOLEAN NotifyChangeDirectoryTest( VOID ) { HANDLE rootDirHandle; UCHAR buffer[512]; IO_STATUS_BLOCK ioStatusBlock; OBJECT_ATTRIBUTES objectAttributes; UNICODE_STRING nameString; NTSTATUS status; RtlInitUnicodeString( &nameString, L"\\Device\\Mailslot\\" ); InitializeObjectAttributes( &objectAttributes, &nameString, OBJ_CASE_INSENSITIVE, NULL, NULL ); printf( "Attempting to open mailslot directory \"%wZ\"\n", &nameString ); status = NtOpenFile ( &rootDirHandle, GENERIC_READ, &objectAttributes, &ioStatusBlock, 0, 0L ); printf( "MSFS root dir open status = %lx\n", status ); if (!NT_SUCCESS(status)) { return FALSE; } status = NtNotifyChangeDirectoryFile( rootDirHandle, (HANDLE) NULL, (PIO_APC_ROUTINE) NULL, (PVOID) NULL, &ioStatusBlock, buffer, sizeof( buffer ), FILE_NOTIFY_CHANGE_NAME | FILE_NOTIFY_CHANGE_ATTRIBUTES | FILE_NOTIFY_CHANGE_SIZE | FILE_NOTIFY_CHANGE_LAST_WRITE | FILE_NOTIFY_CHANGE_LAST_ACCESS | FILE_NOTIFY_CHANGE_CREATION | FILE_NOTIFY_CHANGE_EA | FILE_NOTIFY_CHANGE_SECURITY, FALSE ); printf("Notify change directory status = %lx\n", status ); if ( !NT_SUCCESS( status )) { return FALSE; } status = NtWaitForSingleObject( rootDirHandle, TRUE, NULL ); printf( "NtWaitForSingleObject returns %lx\n", status ); status = ioStatusBlock.Status; printf( "Find notify final status = %d\n", status ); return( (BOOLEAN)NT_SUCCESS( status )); }