ReactOS  0.4.15-dev-3163-gf17c2c0
CDirectoryWatcher Class Reference

#include <CDirectoryWatcher.h>

Collaboration diagram for CDirectoryWatcher:

Public Member Functions

 ~CDirectoryWatcher ()
 
BOOL IsDead () const
 
BOOL RestartWatching ()
 
void QuitWatching ()
 
BOOL RequestAddWatcher ()
 
BOOL RequestTermination ()
 
void ReadCompletion (DWORD dwErrorCode, DWORD dwNumberOfBytesTransfered)
 

Static Public Member Functions

static CDirectoryWatcherCreate (LPCWSTR pszDirectoryPath, BOOL fSubTree)
 
static void RequestAllWatchersTermination ()
 

Public Attributes

HANDLE m_hDirectory
 
WCHAR m_szDirectoryPath [MAX_PATH]
 

Protected Member Functions

BOOL CreateAPCThread ()
 
void ProcessNotification ()
 
 CDirectoryWatcher (LPCWSTR pszDirectoryPath, BOOL fSubTree)
 

Protected Attributes

BOOL m_fDead
 
BOOL m_fRecursive
 
CDirectoryList m_dir_list
 
OVERLAPPED m_overlapped
 

Detailed Description

Definition at line 14 of file CDirectoryWatcher.h.

Constructor & Destructor Documentation

◆ ~CDirectoryWatcher()

CDirectoryWatcher::~CDirectoryWatcher ( )

Definition at line 104 of file CDirectoryWatcher.cpp.

105 {
106  TRACE("CDirectoryWatcher::~CDirectoryWatcher: %p, '%S'\n", this, m_szDirectoryPath);
107 
110 }
WCHAR m_szDirectoryPath[MAX_PATH]
#define CloseHandle
Definition: compat.h:598
#define INVALID_HANDLE_VALUE
Definition: compat.h:590
#define TRACE(s)
Definition: solgame.cpp:4

◆ CDirectoryWatcher()

CDirectoryWatcher::CDirectoryWatcher ( LPCWSTR  pszDirectoryPath,
BOOL  fSubTree 
)
protected

Definition at line 71 of file CDirectoryWatcher.cpp.

72  : m_fDead(FALSE)
73  , m_fRecursive(fSubTree)
74  , m_dir_list(pszDirectoryPath, fSubTree)
75 {
76  TRACE("CDirectoryWatcher::CDirectoryWatcher: %p, '%S'\n", this, pszDirectoryPath);
77 
78  lstrcpynW(m_szDirectoryPath, pszDirectoryPath, MAX_PATH);
79 
80  // open the directory to watch changes (for ReadDirectoryChangesW)
81  m_hDirectory = CreateFileW(pszDirectoryPath, FILE_LIST_DIRECTORY,
85  NULL);
86 }
WCHAR m_szDirectoryPath[MAX_PATH]
#define FILE_SHARE_WRITE
Definition: nt_native.h:681
#define FILE_SHARE_READ
Definition: compat.h:136
#define lstrcpynW
Definition: compat.h:597
#define FALSE
Definition: types.h:117
#define OPEN_EXISTING
Definition: compat.h:634
#define TRACE(s)
Definition: solgame.cpp:4
#define FILE_LIST_DIRECTORY
Definition: nt_native.h:629
#define MAX_PATH
Definition: compat.h:34
#define FILE_SHARE_DELETE
Definition: nt_native.h:682
#define NULL
Definition: types.h:112
#define CreateFileW
Definition: compat.h:600
#define FILE_FLAG_BACKUP_SEMANTICS
Definition: disk.h:41
CDirectoryList m_dir_list
#define FILE_FLAG_OVERLAPPED
Definition: disk.h:46

Referenced by Create().

Member Function Documentation

◆ Create()

CDirectoryWatcher * CDirectoryWatcher::Create ( LPCWSTR  pszDirectoryPath,
BOOL  fSubTree 
)
static

Definition at line 89 of file CDirectoryWatcher.cpp.

90 {
91  WCHAR szFullPath[MAX_PATH];
92  GetFullPathNameW(pszDirectoryPath, _countof(szFullPath), szFullPath, NULL);
93 
94  CDirectoryWatcher *pDirectoryWatcher = new CDirectoryWatcher(szFullPath, fSubTree);
95  if (pDirectoryWatcher->m_hDirectory == INVALID_HANDLE_VALUE)
96  {
97  ERR("CreateFileW failed\n");
98  delete pDirectoryWatcher;
99  pDirectoryWatcher = NULL;
100  }
101  return pDirectoryWatcher;
102 }
#define INVALID_HANDLE_VALUE
Definition: compat.h:590
DWORD WINAPI GetFullPathNameW(IN LPCWSTR lpFileName, IN DWORD nBufferLength, OUT LPWSTR lpBuffer, OUT LPWSTR *lpFilePart)
Definition: path.c:1105
__wchar_t WCHAR
Definition: xmlstorage.h:180
#define _countof(array)
Definition: sndvol32.h:68
#define MAX_PATH
Definition: compat.h:34
#define ERR(fmt,...)
Definition: debug.h:110
#define NULL
Definition: types.h:112
CDirectoryWatcher(LPCWSTR pszDirectoryPath, BOOL fSubTree)

Referenced by CreateDirectoryWatcherFromRegEntry().

◆ CreateAPCThread()

BOOL CDirectoryWatcher::CreateAPCThread ( )
protected

Definition at line 336 of file CDirectoryWatcher.cpp.

337 {
338  if (s_hThreadAPC != NULL)
339  return TRUE;
340 
341  unsigned tid;
344  NULL, 0, &tid);
345  return s_hThreadAPC != NULL;
346 }
static HANDLE s_hThreadAPC
#define TRUE
Definition: types.h:120
static unsigned __stdcall DirectoryWatcherThreadFuncAPC(void *)
_CRTIMP uintptr_t __cdecl _beginthreadex(_In_opt_ void *_Security, _In_ unsigned _StackSize, _In_ unsigned(__stdcall *_StartAddress)(void *), _In_opt_ void *_ArgList, _In_ unsigned _InitFlag, _Out_opt_ unsigned *_ThrdAddr)
#define FALSE
Definition: types.h:117
PVOID HANDLE
Definition: typedefs.h:73
#define NULL
Definition: types.h:112
static BOOL s_fTerminateAllWatchers
static TfClientId tid

Referenced by RequestAddWatcher().

◆ IsDead()

BOOL CDirectoryWatcher::IsDead ( ) const

Definition at line 391 of file CDirectoryWatcher.cpp.

392 {
393  return m_fDead;
394 }

Referenced by ReadCompletion(), and RestartWatching().

◆ ProcessNotification()

void CDirectoryWatcher::ProcessNotification ( )
protected

Definition at line 135 of file CDirectoryWatcher.cpp.

136 {
139  DWORD dwEvent, cbName;
140  BOOL fDir;
141  TRACE("CDirectoryWatcher::ProcessNotification: enter\n");
142 
143  // for each entry in s_buffer
144  szPath[0] = szTempPath[0] = 0;
145  for (;;)
146  {
147  // get name (relative from m_szDirectoryPath)
148  cbName = pInfo->FileNameLength;
149  if (sizeof(szName) - sizeof(UNICODE_NULL) < cbName)
150  {
151  ERR("pInfo->FileName is longer than szName\n");
152  break;
153  }
154  // NOTE: FILE_NOTIFY_INFORMATION.FileName is not null-terminated.
155  ZeroMemory(szName, sizeof(szName));
156  CopyMemory(szName, pInfo->FileName, cbName);
157 
158  // get full path
161 
162  // convert to long pathname if it contains '~'
163  if (StrChrW(szPath, L'~') != NULL)
164  {
167  {
169  }
170  }
171 
172  // convert action to event
173  fDir = PathIsDirectoryW(szPath);
174  dwEvent = ConvertActionToEvent(pInfo->Action, fDir);
175 
176  // convert SHCNE_DELETE to SHCNE_RMDIR if the path is a directory
177  if (!fDir && (dwEvent == SHCNE_DELETE) && m_dir_list.ContainsPath(szPath))
178  {
179  fDir = TRUE;
180  dwEvent = SHCNE_RMDIR;
181  }
182 
183  // update m_dir_list
184  switch (dwEvent)
185  {
186  case SHCNE_MKDIR:
188  dwEvent = 0;
189  break;
190  case SHCNE_CREATE:
192  dwEvent = 0;
193  break;
194  case SHCNE_RENAMEFOLDER:
196  dwEvent = 0;
197  break;
198  case SHCNE_RENAMEITEM:
200  dwEvent = 0;
201  break;
202  case SHCNE_RMDIR:
204  dwEvent = 0;
205  break;
206  case SHCNE_DELETE:
207  if (PathFileExistsW(szPath))
208  dwEvent = 0;
209  break;
210  }
211 
212  if (dwEvent != 0)
213  {
214  // notify
215  if (pInfo->Action == FILE_ACTION_RENAMED_NEW_NAME)
217  else
219  }
220  else if (pInfo->Action == FILE_ACTION_RENAMED_OLD_NAME)
221  {
222  // save path for next FILE_ACTION_RENAMED_NEW_NAME
224  }
225 
226  if (pInfo->NextEntryOffset == 0)
227  break; // there is no next entry
228 
229  // go next entry
230  pInfo = (PFILE_NOTIFY_INFORMATION)((LPBYTE)pInfo + pInfo->NextEntryOffset);
231  }
232 
233  TRACE("CDirectoryWatcher::ProcessNotification: leave\n");
234 }
#define SHCNE_MKDIR
Definition: shlobj.h:1732
BOOL WINAPI PathIsDirectoryW(LPCWSTR lpszPath)
Definition: path.c:1722
WCHAR m_szDirectoryPath[MAX_PATH]
#define SHCNE_RMDIR
Definition: shlobj.h:1733
BOOL WINAPI PathIsRelativeW(LPCWSTR lpszPath)
Definition: path.c:1578
#define FILE_ACTION_RENAMED_OLD_NAME
#define TRUE
Definition: types.h:120
#define SHCNE_RENAMEFOLDER
Definition: shlobj.h:1746
#define ZeroMemory
Definition: winbase.h:1664
static BYTE s_buffer[BUFFER_SIZE]
#define SHCNE_RENAMEITEM
Definition: shlobj.h:1729
BOOL RenamePath(LPCWSTR pszPath1, LPCWSTR pszPath2)
#define lstrcpynW
Definition: compat.h:597
BOOL WINAPI PathAppendW(LPWSTR lpszPath, LPCWSTR lpszAppend)
Definition: path.c:126
unsigned char * LPBYTE
Definition: typedefs.h:53
#define UNICODE_NULL
BOOL AddPath(LPCWSTR pszPath)
unsigned int BOOL
Definition: ntddk_ex.h:94
BOOL WINAPI PathFileExistsW(LPCWSTR lpszPath)
Definition: path.c:1776
BOOL ContainsPath(LPCWSTR pszPath) const
static TCHAR szTempPath[MAX_PATH]
Definition: CImage.cpp:25
DWORD WINAPI GetLongPathNameW(IN LPCWSTR lpszShortPath, OUT LPWSTR lpszLongPath, IN DWORD cchBuffer)
Definition: path.c:1455
#define TRACE(s)
Definition: solgame.cpp:4
__wchar_t WCHAR
Definition: xmlstorage.h:180
#define _countof(array)
Definition: sndvol32.h:68
#define MAX_PATH
Definition: compat.h:34
#define CopyMemory
Definition: winbase.h:1662
unsigned long DWORD
Definition: ntddk_ex.h:95
static const WCHAR L[]
Definition: oid.c:1250
#define FILE_ACTION_RENAMED_NEW_NAME
#define ERR(fmt,...)
Definition: debug.h:110
LPCWSTR szPath
Definition: env.c:37
#define SHCNE_DELETE
Definition: shlobj.h:1731
LPWSTR WINAPI StrChrW(LPCWSTR lpszStr, WCHAR ch)
Definition: string.c:468
BOOL DeletePath(LPCWSTR pszPath)
#define NULL
Definition: types.h:112
static void NotifyFileSystemChange(LONG wEventId, LPCWSTR path1, LPCWSTR path2)
static const WCHAR szName[]
Definition: msipriv.h:1194
struct _FILE_NOTIFY_INFORMATION * PFILE_NOTIFY_INFORMATION
#define SHCNE_CREATE
Definition: shlobj.h:1730
CDirectoryList m_dir_list
static DWORD ConvertActionToEvent(DWORD Action, BOOL fDir)

Referenced by ReadCompletion().

◆ QuitWatching()

void CDirectoryWatcher::QuitWatching ( )

Definition at line 383 of file CDirectoryWatcher.cpp.

384 {
385  assert(this != NULL);
386 
387  m_fDead = TRUE;
389 }
#define TRUE
Definition: types.h:120
#define assert(x)
Definition: debug.h:53
BOOL WINAPI CancelIo(IN HANDLE hFile)
Definition: deviceio.c:290
#define NULL
Definition: types.h:112

Referenced by _RequestTerminationAPC().

◆ ReadCompletion()

void CDirectoryWatcher::ReadCompletion ( DWORD  dwErrorCode,
DWORD  dwNumberOfBytesTransfered 
)

Definition at line 236 of file CDirectoryWatcher.cpp.

237 {
238  // If the FSD doesn't support directory change notifications, there's no
239  // no need to retry and requeue notification
240  if (dwErrorCode == ERROR_INVALID_FUNCTION)
241  {
242  ERR("ERROR_INVALID_FUNCTION\n");
243  return;
244  }
245 
246  // Also, if the notify operation was canceled (like, user moved to another
247  // directory), then, don't requeue notification.
248  if (dwErrorCode == ERROR_OPERATION_ABORTED)
249  {
250  TRACE("ERROR_OPERATION_ABORTED\n");
251  if (IsDead())
252  delete this;
253  return;
254  }
255 
256  // is this watch dead?
257  if (IsDead())
258  {
259  TRACE("IsDead()\n");
260  delete this;
261  return;
262  }
263 
264  // This likely means overflow, so force whole directory refresh.
265  if (dwNumberOfBytesTransfered == 0)
266  {
267  // do notify a SHCNE_UPDATEDIR
269  }
270  else
271  {
272  // do notify
274  }
275 
276  // restart a watch
277  RestartWatching();
278 }
WCHAR m_szDirectoryPath[MAX_PATH]
#define ERROR_INVALID_FUNCTION
Definition: dderror.h:6
#define ERROR_OPERATION_ABORTED
Definition: winerror.h:575
#define TRACE(s)
Definition: solgame.cpp:4
#define ERR(fmt,...)
Definition: debug.h:110
#define SHCNE_UPDATEDIR
Definition: shlobj.h:1741
#define NULL
Definition: types.h:112
static void NotifyFileSystemChange(LONG wEventId, LPCWSTR path1, LPCWSTR path2)

Referenced by _NotificationCompletion().

◆ RequestAddWatcher()

BOOL CDirectoryWatcher::RequestAddWatcher ( )

Definition at line 348 of file CDirectoryWatcher.cpp.

349 {
350  assert(this != NULL);
351 
352  // create an APC thread for directory watching
353  if (!CreateAPCThread())
354  return FALSE;
355 
356  // request adding the watch
358  return TRUE;
359 }
static HANDLE s_hThreadAPC
#define TRUE
Definition: types.h:120
#define assert(x)
Definition: debug.h:53
uint32_t ULONG_PTR
Definition: typedefs.h:65
DWORD WINAPI QueueUserAPC(IN PAPCFUNC pfnAPC, IN HANDLE hThread, IN ULONG_PTR dwData)
Definition: thread.c:947
#define FALSE
Definition: types.h:117
static void NTAPI _AddDirectoryProcAPC(ULONG_PTR Parameter)
#define NULL
Definition: types.h:112

Referenced by CChangeNotifyServer::OnRegister().

◆ RequestAllWatchersTermination()

void CDirectoryWatcher::RequestAllWatchersTermination ( )
static

Definition at line 374 of file CDirectoryWatcher.cpp.

375 {
376  if (!s_hThreadAPC)
377  return;
378 
379  // request termination of all directory watches
381 }
static HANDLE s_hThreadAPC
static void NTAPI _RequestAllTerminationAPC(ULONG_PTR Parameter)
uint32_t ULONG_PTR
Definition: typedefs.h:65
DWORD WINAPI QueueUserAPC(IN PAPCFUNC pfnAPC, IN HANDLE hThread, IN ULONG_PTR dwData)
Definition: thread.c:947
#define NULL
Definition: types.h:112

Referenced by CChangeNotifyServer::OnDestroy().

◆ RequestTermination()

BOOL CDirectoryWatcher::RequestTermination ( )

Definition at line 361 of file CDirectoryWatcher.cpp.

362 {
363  assert(this != NULL);
364 
365  if (s_hThreadAPC)
366  {
368  return TRUE;
369  }
370 
371  return FALSE;
372 }
static HANDLE s_hThreadAPC
#define TRUE
Definition: types.h:120
static void NTAPI _RequestTerminationAPC(ULONG_PTR Parameter)
#define assert(x)
Definition: debug.h:53
uint32_t ULONG_PTR
Definition: typedefs.h:65
DWORD WINAPI QueueUserAPC(IN PAPCFUNC pfnAPC, IN HANDLE hThread, IN ULONG_PTR dwData)
Definition: thread.c:947
#define FALSE
Definition: types.h:117
#define NULL
Definition: types.h:112

Referenced by CChangeNotifyServer::DestroyItem().

◆ RestartWatching()

BOOL CDirectoryWatcher::RestartWatching ( )

Definition at line 307 of file CDirectoryWatcher.cpp.

308 {
309  assert(this != NULL);
310 
311  if (IsDead())
312  {
313  delete this;
314  return FALSE; // the watch is dead
315  }
316 
317  // initialize the buffer and the overlapped
318  ZeroMemory(s_buffer, sizeof(s_buffer));
320  m_overlapped.hEvent = (HANDLE)this;
321 
322  // start the directory watch
325  m_fRecursive, dwFilter, NULL,
327  {
328  ERR("ReadDirectoryChangesW for '%S' failed (error: %ld)\n",
330  return FALSE; // failure
331  }
332 
333  return TRUE; // success
334 }
WCHAR m_szDirectoryPath[MAX_PATH]
#define TRUE
Definition: types.h:120
#define assert(x)
Definition: debug.h:53
DWORD WINAPI GetLastError(VOID)
Definition: except.c:1040
#define ZeroMemory
Definition: winbase.h:1664
static BYTE s_buffer[BUFFER_SIZE]
#define FALSE
Definition: types.h:117
#define SHCNE_ALLEVENTS
Definition: shlobj.h:1753
HANDLE hEvent
Definition: winbase.h:814
static void CALLBACK _NotificationCompletion(DWORD dwErrorCode, DWORD dwNumberOfBytesTransfered, LPOVERLAPPED lpOverlapped)
static DWORD GetFilterFromEvents(DWORD fEvents)
unsigned long DWORD
Definition: ntddk_ex.h:95
PVOID HANDLE
Definition: typedefs.h:73
#define ERR(fmt,...)
Definition: debug.h:110
#define NULL
Definition: types.h:112
BOOL WINAPI ReadDirectoryChangesW(IN HANDLE hDirectory, IN LPVOID lpBuffer OPTIONAL, IN DWORD nBufferLength, IN BOOL bWatchSubtree, IN DWORD dwNotifyFilter, OUT LPDWORD lpBytesReturned, IN LPOVERLAPPED lpOverlapped OPTIONAL, IN LPOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine)
Definition: cnotify.c:253

Referenced by _AddDirectoryProcAPC(), and ReadCompletion().

Member Data Documentation

◆ m_dir_list

CDirectoryList CDirectoryWatcher::m_dir_list
protected

Definition at line 34 of file CDirectoryWatcher.h.

Referenced by ProcessNotification().

◆ m_fDead

BOOL CDirectoryWatcher::m_fDead
protected

Definition at line 32 of file CDirectoryWatcher.h.

Referenced by IsDead(), and QuitWatching().

◆ m_fRecursive

BOOL CDirectoryWatcher::m_fRecursive
protected

Definition at line 33 of file CDirectoryWatcher.h.

Referenced by RestartWatching().

◆ m_hDirectory

HANDLE CDirectoryWatcher::m_hDirectory

◆ m_overlapped

OVERLAPPED CDirectoryWatcher::m_overlapped
protected

Definition at line 35 of file CDirectoryWatcher.h.

Referenced by RestartWatching().

◆ m_szDirectoryPath

WCHAR CDirectoryWatcher::m_szDirectoryPath[MAX_PATH]

The documentation for this class was generated from the following files: