ReactOS  0.4.15-dev-1397-g19779b3
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 333 of file CDirectoryWatcher.cpp.

334 {
335  if (s_hThreadAPC != NULL)
336  return TRUE;
337 
338  unsigned tid;
341  NULL, 0, &tid);
342  return s_hThreadAPC != NULL;
343 }
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 388 of file CDirectoryWatcher.cpp.

389 {
390  return m_fDead;
391 }

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  }
168 
169  // convert action to event
170  fDir = PathIsDirectoryW(szPath);
171  dwEvent = ConvertActionToEvent(pInfo->Action, fDir);
172 
173  // convert SHCNE_DELETE to SHCNE_RMDIR if the path is a directory
174  if (!fDir && (dwEvent == SHCNE_DELETE) && m_dir_list.ContainsPath(szPath))
175  {
176  fDir = TRUE;
177  dwEvent = SHCNE_RMDIR;
178  }
179 
180  // update m_dir_list
181  switch (dwEvent)
182  {
183  case SHCNE_MKDIR:
185  dwEvent = 0;
186  break;
187  case SHCNE_CREATE:
189  dwEvent = 0;
190  break;
191  case SHCNE_RENAMEFOLDER:
193  dwEvent = 0;
194  break;
195  case SHCNE_RENAMEITEM:
197  dwEvent = 0;
198  break;
199  case SHCNE_RMDIR:
201  dwEvent = 0;
202  break;
203  case SHCNE_DELETE:
204  if (PathFileExistsW(szPath))
205  dwEvent = 0;
206  break;
207  }
208 
209  if (dwEvent != 0)
210  {
211  // notify
212  if (pInfo->Action == FILE_ACTION_RENAMED_NEW_NAME)
214  else
216  }
217  else if (pInfo->Action == FILE_ACTION_RENAMED_OLD_NAME)
218  {
219  // save path for next FILE_ACTION_RENAMED_NEW_NAME
221  }
222 
223  if (pInfo->NextEntryOffset == 0)
224  break; // there is no next entry
225 
226  // go next entry
227  pInfo = (PFILE_NOTIFY_INFORMATION)((LPBYTE)pInfo + pInfo->NextEntryOffset);
228  }
229 
230  TRACE("CDirectoryWatcher::ProcessNotification: leave\n");
231 }
#define SHCNE_MKDIR
Definition: shlobj.h:1732
BOOL WINAPI PathIsDirectoryW(LPCWSTR lpszPath)
Definition: path.c:1702
WCHAR m_szDirectoryPath[MAX_PATH]
#define SHCNE_RMDIR
Definition: shlobj.h:1733
#define FILE_ACTION_RENAMED_OLD_NAME
#define TRUE
Definition: types.h:120
#define SHCNE_RENAMEFOLDER
Definition: shlobj.h:1746
#define ZeroMemory
Definition: winbase.h:1648
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:121
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:1756
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:1646
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:35
#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 380 of file CDirectoryWatcher.cpp.

381 {
382  assert(this != NULL);
383 
384  m_fDead = TRUE;
386 }
#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 233 of file CDirectoryWatcher.cpp.

234 {
235  // If the FSD doesn't support directory change notifications, there's no
236  // no need to retry and requeue notification
237  if (dwErrorCode == ERROR_INVALID_FUNCTION)
238  {
239  ERR("ERROR_INVALID_FUNCTION\n");
240  return;
241  }
242 
243  // Also, if the notify operation was canceled (like, user moved to another
244  // directory), then, don't requeue notification.
245  if (dwErrorCode == ERROR_OPERATION_ABORTED)
246  {
247  TRACE("ERROR_OPERATION_ABORTED\n");
248  if (IsDead())
249  delete this;
250  return;
251  }
252 
253  // is this watch dead?
254  if (IsDead())
255  {
256  TRACE("IsDead()\n");
257  delete this;
258  return;
259  }
260 
261  // This likely means overflow, so force whole directory refresh.
262  if (dwNumberOfBytesTransfered == 0)
263  {
264  // do notify a SHCNE_UPDATEDIR
266  }
267  else
268  {
269  // do notify
271  }
272 
273  // restart a watch
274  RestartWatching();
275 }
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 345 of file CDirectoryWatcher.cpp.

346 {
347  assert(this != NULL);
348 
349  // create an APC thread for directory watching
350  if (!CreateAPCThread())
351  return FALSE;
352 
353  // request adding the watch
355  return TRUE;
356 }
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 371 of file CDirectoryWatcher.cpp.

372 {
373  if (!s_hThreadAPC)
374  return;
375 
376  // request termination of all directory watches
378 }
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 358 of file CDirectoryWatcher.cpp.

359 {
360  assert(this != NULL);
361 
362  if (s_hThreadAPC)
363  {
365  return TRUE;
366  }
367 
368  return FALSE;
369 }
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 304 of file CDirectoryWatcher.cpp.

305 {
306  assert(this != NULL);
307 
308  if (IsDead())
309  {
310  delete this;
311  return FALSE; // the watch is dead
312  }
313 
314  // initialize the buffer and the overlapped
315  ZeroMemory(s_buffer, sizeof(s_buffer));
317  m_overlapped.hEvent = (HANDLE)this;
318 
319  // start the directory watch
322  m_fRecursive, dwFilter, NULL,
324  {
325  ERR("ReadDirectoryChangesW for '%S' failed (error: %ld)\n",
327  return FALSE; // failure
328  }
329 
330  return TRUE; // success
331 }
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:1044
#define ZeroMemory
Definition: winbase.h:1648
static BYTE s_buffer[BUFFER_SIZE]
#define FALSE
Definition: types.h:117
#define SHCNE_ALLEVENTS
Definition: shlobj.h:1753
HANDLE hEvent
Definition: winbase.h:798
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: