1
+ // ******************************************************************************
2
+ // ** FileSystemWatcherNative Class
3
+ // ******************************************************************************
4
+ /* *
5
+ * JNI code used to monitor changes made to a directory.
6
+ *
7
+ ******************************************************************************/
8
+
9
+ // This file needs to be compiled with _UNICODE flag, since java string uses unicode.
10
+
11
+ #include " stdafx.h"
12
+ #include " FileSystemWatcherNative.h"
13
+ #include < sstream>
14
+ #include < ctime>
15
+ using namespace std ;
16
+
17
+
18
+ BOOL bWatchSubtree; // flag used to set whether to watch subdirectories
19
+ DWORD dwNotifyFilter; // notification filter
20
+ HANDLE hDirectory; // handle to the directory being monitored
21
+ wstring sDirectory ; // a string representing the path to the directory
22
+
23
+ size_t nBufSize = 32 *1024 ;
24
+ FILE_NOTIFY_INFORMATION* pBuffer = (FILE_NOTIFY_INFORMATION*)calloc(1 , nBufSize);
25
+ FILE_NOTIFY_INFORMATION* pBufferCurrent;
26
+
27
+
28
+ // **************************************************************************
29
+ // ** FindFirstChangeNotification
30
+ // **************************************************************************
31
+ /* *
32
+ * Class: FileSystemWatcherNative
33
+ * Method: FindFirstChangeNotification
34
+ * Signature: (Ljava/lang/String;ZI)J
35
+ */
36
+ JNIEXPORT jlong JNICALL Java_javaxt_io_FileSystemWatcherNative_FindFirstChangeNotification
37
+ (JNIEnv* env, jclass, jstring filename, jboolean javaWatchSubtree, jint javaNotifyFilter)
38
+ {
39
+
40
+ // Convert jstring to wstring
41
+ const jchar *_filename = env->GetStringChars (filename, 0 );
42
+ jsize len = env->GetStringLength (filename);
43
+ sDirectory .assign (_filename, _filename + len);
44
+ env->ReleaseStringChars (filename, _filename);
45
+
46
+
47
+
48
+ // Update Inputs
49
+ bWatchSubtree = (BOOL)javaWatchSubtree;
50
+ dwNotifyFilter = // (DWORD)javaNotifyFilter;
51
+ FILE_NOTIFY_CHANGE_LAST_WRITE| // Triggered when a file or directory has been modified
52
+ FILE_NOTIFY_CHANGE_DIR_NAME| // Triggered when a directory has been created or deleted
53
+ FILE_NOTIFY_CHANGE_FILE_NAME; // Triggered when a file has been created or deleted
54
+
55
+
56
+ // Call FindFirstChangeNotification
57
+ HANDLE handle = FindFirstChangeNotificationW (sDirectory .c_str (), bWatchSubtree, dwNotifyFilter);
58
+ if (handle == INVALID_HANDLE_VALUE || handle == (HANDLE)ERROR_INVALID_FUNCTION){
59
+ DWORD errorCode = GetLastError ();
60
+ stringstream ss;
61
+ ss << " FindFirstChangeNotification failed. Error Code: " << errorCode;
62
+ const char * msg = (const char *)( ss.str ().c_str ());
63
+ jclass exceptionClass = env->FindClass (" java/lang/Exception" );
64
+ env->ThrowNew (exceptionClass, msg );
65
+ }
66
+
67
+
68
+ // Create File Handle
69
+ hDirectory = CreateFileW (
70
+ sDirectory .c_str (), // pointer to the directory
71
+ GENERIC_READ, // access (read/write) mode
72
+ FILE_SHARE_READ|
73
+ FILE_SHARE_WRITE|
74
+ FILE_SHARE_DELETE, // share mode
75
+ NULL , // security descriptor
76
+ OPEN_EXISTING, // how to create
77
+ FILE_FLAG_BACKUP_SEMANTICS, // file attributes
78
+ NULL // file with attributes to copy
79
+ );
80
+
81
+
82
+ // Return FindFirstChangeNotification Handle
83
+ return (jlong)handle;
84
+ }
85
+
86
+
87
+ // **************************************************************************
88
+ // ** FindNextChangeNotification
89
+ // **************************************************************************
90
+ /* *
91
+ * Class: FileSystemWatcherNative
92
+ * Method: FindNextChangeNotification
93
+ * Signature: (J)V
94
+ */
95
+ JNIEXPORT void JNICALL Java_javaxt_io_FileSystemWatcherNative_FindNextChangeNotification
96
+ (JNIEnv *javaEnv, jclass, jlong handle)
97
+ {
98
+ if (!FindNextChangeNotification ((HANDLE) handle)){
99
+ DWORD errorCode = GetLastError ();
100
+ stringstream ss;
101
+ ss << " FindNextChangeNotification failed. Error Code: " << errorCode;
102
+ const char * msg = (const char *)( ss.str ().c_str ());
103
+ jclass exceptionClass = javaEnv->FindClass (" java/lang/Exception" );
104
+ javaEnv->ThrowNew (exceptionClass, msg);
105
+ }
106
+ }
107
+
108
+
109
+ // **************************************************************************
110
+ // ** FindCloseChangeNotification
111
+ // **************************************************************************
112
+ /* *
113
+ * Class: FileSystemWatcherNative
114
+ * Method: FindCloseChangeNotification
115
+ * Signature: (J)V
116
+ */
117
+ JNIEXPORT void JNICALL Java_javaxt_io_FileSystemWatcherNative_FindCloseChangeNotification
118
+ (JNIEnv *javaEnv, jclass, jlong handle)
119
+ {
120
+
121
+ if (!FindCloseChangeNotification ((HANDLE) handle)){
122
+ DWORD errorCode = GetLastError ();
123
+ stringstream ss;
124
+ ss << " FindCloseChangeNotification failed. Error Code: " << errorCode;
125
+ const char * msg = (const char *)( ss.str ().c_str ());
126
+ jclass exceptionClass = javaEnv->FindClass (" java/lang/Exception" );
127
+ javaEnv->ThrowNew (exceptionClass, msg);
128
+ }
129
+
130
+
131
+ // Close File Handle
132
+ if (hDirectory!=NULL ){
133
+ CloseHandle (hDirectory);
134
+ }
135
+ }
136
+
137
+
138
+ // **************************************************************************
139
+ // ** WaitForSingleObject
140
+ // **************************************************************************
141
+ /* *
142
+ * Class: FileSystemWatcherNative
143
+ * Method: WaitForSingleObject
144
+ * Signature: (JI)I
145
+ */
146
+ JNIEXPORT jint JNICALL Java_javaxt_io_FileSystemWatcherNative_WaitForSingleObject
147
+ (JNIEnv *javaEnv , jclass, jlong hWaitHandle, jint waitTimeoutMillis)
148
+ {
149
+ return WaitForSingleObject ((HANDLE) hWaitHandle, (DWORD) waitTimeoutMillis);
150
+ }
151
+
152
+
153
+ std::wstring s2ws (const std::string& s){
154
+ int len;
155
+ int slength = (int )s.length () + 1 ;
156
+ len = MultiByteToWideChar (CP_ACP, 0 , s.c_str (), slength, 0 , 0 );
157
+ wchar_t * buf = new wchar_t [len];
158
+ MultiByteToWideChar (CP_ACP, 0 , s.c_str (), slength, buf, len);
159
+ std::wstring r (buf);
160
+ delete[] buf;
161
+ return r;
162
+ }
163
+
164
+
165
+ // **************************************************************************
166
+ // ** ReadDirectoryChangesW
167
+ // **************************************************************************
168
+ /* *
169
+ * Class: FileSystemWatcherNative
170
+ * Method: ReadDirectoryChangesW
171
+ * Signature: (Ljava/lang/String;ZI)J
172
+ */
173
+ JNIEXPORT jstring JNICALL Java_javaxt_io_FileSystemWatcherNative_ReadDirectoryChangesW
174
+ (JNIEnv *env, jclass)
175
+ {
176
+
177
+ wstringstream ss;
178
+ DWORD BytesReturned;
179
+
180
+ if (ReadDirectoryChangesW (
181
+ hDirectory, // handle to directory
182
+ pBuffer, // read results buffer
183
+ nBufSize, // length of buffer
184
+ bWatchSubtree, // WatchSubtree
185
+ dwNotifyFilter, // notification filter
186
+ &BytesReturned, // bytes returned
187
+ NULL , // overlapped buffer
188
+ NULL // completion routine
189
+ )){
190
+
191
+ // Iterate through the file changes
192
+ pBufferCurrent = pBuffer;
193
+ while (pBufferCurrent){
194
+
195
+ // Get current timestamp
196
+ time_t d = time (NULL );
197
+ string date ( ctime (&d) );
198
+ date.erase (date.find_last_not_of (" \t\n " )+1 ); // right trim
199
+
200
+
201
+ // Get action
202
+ wstring action = L" " ;
203
+ switch (pBufferCurrent->Action ){
204
+ case FILE_ACTION_ADDED: action = L" Create" ; break ;
205
+ case FILE_ACTION_REMOVED: action = L" Delete" ; break ;
206
+ case FILE_ACTION_MODIFIED: action = L" Modify" ; break ;
207
+ case FILE_ACTION_RENAMED_OLD_NAME: action = L" Rename" ; break ;
208
+ case FILE_ACTION_RENAMED_NEW_NAME: action = L" Renam2" ; break ;
209
+ }
210
+
211
+
212
+ // Get filename
213
+ WCHAR* _filename = pBufferCurrent->FileName ;
214
+ int len = (int )pBufferCurrent->FileNameLength /2 ;
215
+ wstring filename;
216
+ filename.assign (_filename, _filename + len);
217
+
218
+
219
+ // Join date, action, and filename into 1 event string
220
+ ss << L" [" << s2ws (date) << L" ] " << action << L" " << sDirectory << filename << L" \n " ;
221
+
222
+
223
+ // Update pBufferCurrent
224
+ if (pBufferCurrent->NextEntryOffset )
225
+ pBufferCurrent = (FILE_NOTIFY_INFORMATION*)(((BYTE*)pBufferCurrent) + pBufferCurrent->NextEntryOffset );
226
+ else
227
+ pBufferCurrent = NULL ;
228
+
229
+
230
+ } // end while pBufferCurrent
231
+ }
232
+
233
+ wstring event = ss.str ();
234
+ int len = event.size ();
235
+ jchar* raw = new jchar[len];
236
+ memcpy (raw, event.c_str (), len*sizeof (wchar_t ));
237
+ jstring result = env->NewString (raw, len);
238
+ delete[] raw;
239
+ return result;
240
+ }
0 commit comments