Skip to content

Instantly share code, notes, and snippets.

@rbmm
Created November 18, 2023 09:00
Show Gist options
  • Save rbmm/d81717283e2ca33828be34d5a8edbcf0 to your computer and use it in GitHub Desktop.
Save rbmm/d81717283e2ca33828be34d5a8edbcf0 to your computer and use it in GitHub Desktop.
#define FILE_NOTIFY_VALID_MASK 0x00000fff
class RDC : OVERLAPPED
{
HANDLE _M_hFile = 0;
SRWLOCK _M_lock {};
LONG _M_dwRef = 1;
union {
FILE_NOTIFY_INFORMATION _M_fni;
UCHAR _M_buf[0x1000];
};
~RDC()
{
if (_M_hFile) CloseHandle(_M_hFile);
}
void Dump(PFILE_NOTIFY_INFORMATION pfni)
{
DWORD NextEntryOffset = 0;
do
{
(PBYTE&)pfni += NextEntryOffset;
DbgPrint("[%x]: %.*S\n", pfni->Action, pfni->FileNameLength / sizeof(WCHAR), pfni->FileName);
} while (NextEntryOffset = pfni->NextEntryOffset);
}
VOID WINAPI cb(
_In_ DWORD dwErrorCode,
_In_ DWORD dwNumberOfBytesTransfered)
{
switch (dwErrorCode)
{
case NOERROR:
if (dwNumberOfBytesTransfered)
{
Dump(&_M_fni);
}
Read();
break;
case ERROR_NOTIFY_ENUM_DIR:
DbgPrint("ERROR_NOTIFY_CLEANUP\n");
Read();
break;
case ERROR_NOTIFY_CLEANUP:
DbgPrint("ERROR_NOTIFY_CLEANUP\n");
default:
DbgPrint("!! IoResult=%u\n", dwErrorCode);
break;
}
Release();
}
static VOID WINAPI _M_cb(
_In_ DWORD status,
_In_ DWORD dwNumberOfBytesTransfered,
_Inout_ LPOVERLAPPED lpOverlapped)
{
static_cast<RDC*>(lpOverlapped)->cb(RtlNtStatusToDosError(status), dwNumberOfBytesTransfered);
}
void Read()
{
AddRef();
AcquireSRWLockShared(&_M_lock);
ULONG IoResult = _M_hFile ? (ReadDirectoryChangesW(_M_hFile, &_M_buf, sizeof(_M_buf), TRUE,
FILE_NOTIFY_VALID_MASK, 0, this, 0) ? NOERROR : GetLastError()) : ERROR_NOTIFY_CLEANUP;
ReleaseSRWLockShared(&_M_lock);
if (NOERROR != IoResult)
{
// this is not 100% correct due bug in ReadDirectoryChangesW
// STATUS_DATATYPE_MISALIGNMENT in case _M_buf wrong aligned is not recognized
cb(IoResult, 0);
}
}
public:
ULONG Init(PCWSTR psz)
{
HANDLE hFile = CreateFileW(psz, FILE_LIST_DIRECTORY, FILE_SHARE_READ|FILE_SHARE_WRITE, 0, OPEN_EXISTING,
FILE_FLAG_OVERLAPPED|FILE_FLAG_BACKUP_SEMANTICS, 0);
if (INVALID_HANDLE_VALUE != hFile)
{
_M_hFile = hFile;
if (BindIoCompletionCallback(hFile, _M_cb, 0))
{
hEvent = 0;
Read();
return NOERROR;
}
}
return GetLastError();
}
void Stop()
{
AcquireSRWLockExclusive(&_M_lock);
if (_M_hFile) CloseHandle(_M_hFile), _M_hFile = 0;
ReleaseSRWLockExclusive(&_M_lock);
}
void AddRef()
{
InterlockedIncrementNoFence(&_M_dwRef);
}
void Release()
{
if (!InterlockedDecrement(&_M_dwRef))
{
delete this;
}
}
};
void test(PCWSTR psz)
{
if (RDC* p = new RDC)
{
if (NOERROR == p->Init(psz))
{
MessageBoxW(0, 0, 0, 0);
p->Stop();
}
p->Release();
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment