wdm 0.0.1 → 0.0.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/ext/wdm/queue.c +57 -4
- data/ext/wdm/queue.h +26 -2
- data/ext/wdm/rb_change.c +12 -2
- data/ext/wdm/rb_monitor.c +49 -27
- data/ext/wdm/rb_monitor.h +1 -0
- data/ext/wdm/utils.c +13 -1
- data/ext/wdm/utils.h +1 -0
- data/ext/wdm/wdm.c +1 -0
- metadata +22 -4
data/ext/wdm/queue.c
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
#include <stdarg.h>
|
2
|
+
|
1
3
|
#include "wdm.h"
|
2
4
|
|
3
5
|
#include "memory.h"
|
@@ -7,22 +9,73 @@
|
|
7
9
|
// Queue item functions
|
8
10
|
// ---------------------------------------------------------
|
9
11
|
|
12
|
+
WDM_PQueueItemError wdm_queue_item_error_new(VALUE exception, LPCSTR format, ...) {
|
13
|
+
WDM_PQueueItemError error;
|
14
|
+
va_list ap;
|
15
|
+
int length;
|
16
|
+
|
17
|
+
error = WDM_ALLOC(WDM_QueueItemError);
|
18
|
+
|
19
|
+
va_start(ap, format);
|
20
|
+
length = _vscprintf(format, ap);
|
21
|
+
error->message = WDM_ALLOC_N(CHAR, length + 1);
|
22
|
+
vsprintf(error->message, format, ap);
|
23
|
+
va_end(ap);
|
24
|
+
|
25
|
+
error->exception_klass = exception;
|
26
|
+
|
27
|
+
return error;
|
28
|
+
}
|
29
|
+
|
30
|
+
void wdm_queue_item_error_free(WDM_PQueueItemError error) {
|
31
|
+
if ( error->message != NULL ) free(error->message);
|
32
|
+
free(error);
|
33
|
+
}
|
34
|
+
|
35
|
+
WDM_PQueueItemData wdm_queue_item_data_new() {
|
36
|
+
WDM_PQueueItemData data;
|
37
|
+
|
38
|
+
data = ALLOC(WDM_QueueItemData);
|
39
|
+
data->user_data = NULL;
|
40
|
+
|
41
|
+
ZeroMemory(&data->buffer, WDM_BUFFER_SIZE);
|
42
|
+
|
43
|
+
return data;
|
44
|
+
}
|
45
|
+
|
46
|
+
void wdm_queue_item_data_free(WDM_PQueueItemData data) {
|
47
|
+
free(data);
|
48
|
+
}
|
49
|
+
|
10
50
|
WDM_PQueueItem
|
11
|
-
wdm_queue_item_new() {
|
51
|
+
wdm_queue_item_new(WDM_QueueItemType type) {
|
12
52
|
WDM_PQueueItem item;
|
13
53
|
|
14
54
|
item = WDM_ALLOC(WDM_QueueItem);
|
15
|
-
item->
|
55
|
+
item->type = type;
|
56
|
+
|
57
|
+
if ( type == WDM_QUEUE_ITEM_TYPE_ERROR ) {
|
58
|
+
item->error = NULL;
|
59
|
+
}
|
60
|
+
else {
|
61
|
+
item->data = NULL;
|
62
|
+
}
|
63
|
+
|
16
64
|
item->previous = NULL;
|
17
65
|
item->next = NULL;
|
18
66
|
|
19
|
-
ZeroMemory(&item->buffer, WDM_BUFFER_SIZE);
|
20
|
-
|
21
67
|
return item;
|
22
68
|
}
|
23
69
|
|
24
70
|
void
|
25
71
|
wdm_queue_item_free(WDM_PQueueItem item) {
|
72
|
+
if ( item->type == WDM_QUEUE_ITEM_TYPE_ERROR ) {
|
73
|
+
if ( item->error != NULL ) wdm_queue_item_error_free(item->error);
|
74
|
+
}
|
75
|
+
else {
|
76
|
+
if ( item->data != NULL ) wdm_queue_item_data_free(item->data);
|
77
|
+
}
|
78
|
+
|
26
79
|
// We can't really do anything to the prev pointer nor the next pointer,
|
27
80
|
// because we might break any linking the user has established.
|
28
81
|
free(item);
|
data/ext/wdm/queue.h
CHANGED
@@ -13,9 +13,27 @@ extern "C" {
|
|
13
13
|
// Types
|
14
14
|
// ---------------------------------------------------------
|
15
15
|
|
16
|
-
typedef
|
16
|
+
typedef enum {
|
17
|
+
WDM_QUEUE_ITEM_TYPE_ERROR,
|
18
|
+
WDM_QUEUE_ITEM_TYPE_DATA
|
19
|
+
} WDM_QueueItemType;
|
20
|
+
|
21
|
+
typedef struct {
|
17
22
|
WDM_PEntryUserData user_data;
|
18
23
|
BYTE buffer[WDM_BUFFER_SIZE];
|
24
|
+
} WDM_QueueItemData, *WDM_PQueueItemData;
|
25
|
+
|
26
|
+
typedef struct {
|
27
|
+
VALUE exception_klass;
|
28
|
+
LPSTR message;
|
29
|
+
} WDM_QueueItemError, *WDM_PQueueItemError;
|
30
|
+
|
31
|
+
typedef struct WDM_QueueItem {
|
32
|
+
WDM_QueueItemType type;
|
33
|
+
union {
|
34
|
+
WDM_PQueueItemData data;
|
35
|
+
WDM_PQueueItemError error;
|
36
|
+
};
|
19
37
|
struct WDM_QueueItem* previous;
|
20
38
|
struct WDM_QueueItem* next;
|
21
39
|
} WDM_QueueItem, *WDM_PQueueItem;
|
@@ -30,7 +48,13 @@ typedef struct WDM_Queue {
|
|
30
48
|
// Prototypes
|
31
49
|
// ---------------------------------------------------------
|
32
50
|
|
33
|
-
|
51
|
+
WDM_PQueueItemError wdm_queue_item_error_new(VALUE, LPCSTR, ...);
|
52
|
+
void wdm_queue_item_error_free(WDM_PQueueItemError);
|
53
|
+
|
54
|
+
WDM_PQueueItemData wdm_queue_item_data_new();
|
55
|
+
void wdm_queue_item_data_free(WDM_PQueueItemData);
|
56
|
+
|
57
|
+
WDM_PQueueItem wdm_queue_item_new(WDM_QueueItemType);
|
34
58
|
void wdm_queue_item_free(WDM_PQueueItem);
|
35
59
|
|
36
60
|
WDM_PQueue wdm_queue_new();
|
data/ext/wdm/rb_change.c
CHANGED
@@ -86,12 +86,22 @@ extract_absolute_path_from_notification(const LPWSTR base_dir, const PFILE_NOTIF
|
|
86
86
|
{
|
87
87
|
LPWSTR unicode_absolute_filepath;
|
88
88
|
WCHAR absolute_long_filepath[WDM_MAX_WCHAR_LONG_PATH];
|
89
|
+
BOOL is_unc_path;
|
89
90
|
|
90
|
-
|
91
|
+
is_unc_path = wdm_utils_is_unc_path(absolute_filepath);
|
92
|
+
|
93
|
+
unicode_absolute_filepath = ALLOCA_N(WCHAR, absolute_filepath_len + (is_unc_path ? 8 : 4) + 1); // 8 for "\\?\UNC\" or 4 for "\\?\", and 1 for \0
|
91
94
|
|
92
95
|
unicode_absolute_filepath[0] = L'\0';
|
93
96
|
wcscat(unicode_absolute_filepath, L"\\\\?\\");
|
94
|
-
|
97
|
+
|
98
|
+
if ( is_unc_path ) {
|
99
|
+
wcscat(unicode_absolute_filepath, L"UNC\\");
|
100
|
+
wcscat(unicode_absolute_filepath, absolute_filepath + 2); // +2 to skip the begin of a UNC path
|
101
|
+
}
|
102
|
+
else {
|
103
|
+
wcscat(unicode_absolute_filepath, absolute_filepath);
|
104
|
+
}
|
95
105
|
|
96
106
|
// Convert to the long filename form. Unfortunately, this
|
97
107
|
// does not work for deletions, so it's an imperfect fix.
|
data/ext/wdm/rb_monitor.c
CHANGED
@@ -47,7 +47,7 @@ static VALUE rb_monitor_watch(int, VALUE*, VALUE);
|
|
47
47
|
static VALUE rb_monitor_watch_recursively(int, VALUE*, VALUE);
|
48
48
|
|
49
49
|
static void CALLBACK handle_entry_change(DWORD, DWORD, LPOVERLAPPED);
|
50
|
-
static
|
50
|
+
static BOOL register_monitoring_entry(WDM_PEntry);
|
51
51
|
static DWORD WINAPI start_monitoring(LPVOID);
|
52
52
|
|
53
53
|
static VALUE wait_for_changes(LPVOID);
|
@@ -169,9 +169,6 @@ combined_watch(BOOL recursively, int argc, VALUE *argv, VALUE self) {
|
|
169
169
|
entry->user_data->callback = rb_block_proc();
|
170
170
|
entry->user_data->flags = RARRAY_LEN(flags) == 0 ? WDM_MONITOR_FLAGS_DEFAULT : extract_flags_from_rb_array(flags);
|
171
171
|
|
172
|
-
// Prevent the GC from collecting the block until we are done.
|
173
|
-
rb_global_variable(&entry->user_data->callback);
|
174
|
-
|
175
172
|
// WTF Ruby source: The original code (file.c) uses the following macro to make sure that the encoding
|
176
173
|
// of the string is ASCII-compatible, but UTF-16LE (Windows default encoding) is not!!!
|
177
174
|
//
|
@@ -273,14 +270,15 @@ handle_entry_change(
|
|
273
270
|
}
|
274
271
|
|
275
272
|
param = (WDM_PMonitorCallbackParam)event_container->hEvent;
|
276
|
-
data_to_process = wdm_queue_item_new();
|
273
|
+
data_to_process = wdm_queue_item_new(WDM_QUEUE_ITEM_TYPE_DATA);
|
274
|
+
data_to_process->data = wdm_queue_item_data_new();
|
277
275
|
|
278
276
|
WDM_WDEBUG("Change detected in '%s'", param->entry->user_data->dir);
|
279
277
|
|
280
|
-
data_to_process->user_data = param->entry->user_data;
|
278
|
+
data_to_process->data->user_data = param->entry->user_data;
|
281
279
|
|
282
280
|
// Copy change data to the backup buffer
|
283
|
-
memcpy(data_to_process->buffer, param->entry->buffer, bytes_transfered);
|
281
|
+
memcpy(data_to_process->data->buffer, param->entry->buffer, bytes_transfered);
|
284
282
|
|
285
283
|
// Add the backup buffer to the change queue
|
286
284
|
wdm_queue_enqueue(param->monitor->changes, data_to_process);
|
@@ -289,12 +287,12 @@ handle_entry_change(
|
|
289
287
|
register_monitoring_entry(param->entry);
|
290
288
|
|
291
289
|
// Tell the processing thread to process the changes
|
292
|
-
if ( WaitForSingleObject(
|
290
|
+
if ( WaitForSingleObject(param->monitor->process_event, 0) != WAIT_OBJECT_0 ) { // Check if already signaled
|
293
291
|
SetEvent(param->monitor->process_event);
|
294
292
|
}
|
295
293
|
}
|
296
294
|
|
297
|
-
static
|
295
|
+
static BOOL
|
298
296
|
register_monitoring_entry(WDM_PEntry entry) {
|
299
297
|
BOOL success;
|
300
298
|
DWORD bytes;
|
@@ -312,11 +310,11 @@ register_monitoring_entry(WDM_PEntry entry) {
|
|
312
310
|
);
|
313
311
|
|
314
312
|
if ( ! success ) {
|
315
|
-
|
316
|
-
|
317
|
-
// --------------------------
|
318
|
-
WDM_DEBUG("Failed registering directory: '%s'!", entry->user_data->dir);
|
313
|
+
WDM_DEBUG("ReadDirectoryChangesW failed with error (%d): %s", GetLastError(), rb_w32_strerror(GetLastError()));
|
314
|
+
return FALSE;
|
319
315
|
}
|
316
|
+
|
317
|
+
return TRUE;
|
320
318
|
}
|
321
319
|
|
322
320
|
static DWORD WINAPI
|
@@ -330,7 +328,24 @@ start_monitoring(LPVOID param) {
|
|
330
328
|
WDM_DEBUG("Starting the monitoring thread!");
|
331
329
|
|
332
330
|
while(curr_entry != NULL) {
|
333
|
-
register_monitoring_entry(curr_entry)
|
331
|
+
if ( ! register_monitoring_entry(curr_entry) ) {
|
332
|
+
WDM_PQueueItem error_item;
|
333
|
+
int directory_bytes;
|
334
|
+
LPSTR multibyte_directory;
|
335
|
+
|
336
|
+
directory_bytes = WideCharToMultiByte(CP_UTF8, 0, curr_entry->user_data->dir, -1, NULL, 0, NULL, NULL);
|
337
|
+
multibyte_directory = ALLOCA_N(CHAR, directory_bytes);
|
338
|
+
WideCharToMultiByte(CP_UTF8, 0, curr_entry->user_data->dir, -1, multibyte_directory, directory_bytes, NULL, NULL);
|
339
|
+
|
340
|
+
error_item = wdm_queue_item_new(WDM_QUEUE_ITEM_TYPE_ERROR);
|
341
|
+
error_item->error = wdm_queue_item_error_new(
|
342
|
+
eWDM_UnwatchableDirectoryError, "Can't watch directory: '%s'!", multibyte_directory
|
343
|
+
);
|
344
|
+
|
345
|
+
wdm_queue_enqueue(monitor->changes, error_item);
|
346
|
+
SetEvent(monitor->process_event);
|
347
|
+
}
|
348
|
+
|
334
349
|
curr_entry = curr_entry->next;
|
335
350
|
}
|
336
351
|
|
@@ -367,23 +382,29 @@ process_changes(WDM_PQueue changes) {
|
|
367
382
|
|
368
383
|
while( ! wdm_queue_is_empty(changes) ) {
|
369
384
|
item = wdm_queue_dequeue(changes);
|
370
|
-
current_info_entry_offset = (LPBYTE)item->buffer;
|
371
385
|
|
372
|
-
|
373
|
-
|
374
|
-
|
386
|
+
if ( item->type == WDM_QUEUE_ITEM_TYPE_ERROR ) {
|
387
|
+
rb_raise(item->error->exception_klass, item->error->message);
|
388
|
+
}
|
389
|
+
else {
|
390
|
+
current_info_entry_offset = (LPBYTE)item->data->buffer;
|
375
391
|
|
376
|
-
|
377
|
-
|
378
|
-
|
392
|
+
for(;;) {
|
393
|
+
info = (PFILE_NOTIFY_INFORMATION)current_info_entry_offset;
|
394
|
+
event = wdm_rb_change_new_from_notification(item->data->user_data->dir, info);
|
379
395
|
|
380
|
-
|
396
|
+
WDM_DEBUG("---------------------------");
|
397
|
+
WDM_DEBUG("Running user callback");
|
398
|
+
WDM_DEBUG("--------------------------");
|
381
399
|
|
382
|
-
|
400
|
+
rb_funcall(item->data->user_data->callback, wdm_rb_sym_call, 1, event);
|
383
401
|
|
384
|
-
|
402
|
+
WDM_DEBUG("---------------------------");
|
385
403
|
|
386
|
-
|
404
|
+
if ( ! info->NextEntryOffset ) break;
|
405
|
+
|
406
|
+
current_info_entry_offset += info->NextEntryOffset;
|
407
|
+
}
|
387
408
|
}
|
388
409
|
|
389
410
|
wdm_queue_item_free(item);
|
@@ -450,7 +471,7 @@ rb_monitor_run_bang(VALUE self) {
|
|
450
471
|
|
451
472
|
if (already_running) {
|
452
473
|
WDM_DEBUG("Not doing anything because the monitor is already running!");
|
453
|
-
return;
|
474
|
+
return Qnil;
|
454
475
|
}
|
455
476
|
|
456
477
|
// Reset events
|
@@ -479,7 +500,7 @@ rb_monitor_run_bang(VALUE self) {
|
|
479
500
|
|
480
501
|
if ( ! monitor->running ) {
|
481
502
|
wdm_queue_empty(monitor->changes);
|
482
|
-
return;
|
503
|
+
return Qnil;
|
483
504
|
}
|
484
505
|
|
485
506
|
process_changes(monitor->changes);
|
@@ -523,6 +544,7 @@ wdm_rb_monitor_init() {
|
|
523
544
|
eWDM_MonitorRunningError = rb_define_class_under(mWDM, "MonitorRunningError", eWDM_Error);
|
524
545
|
eWDM_InvalidDirectoryError = rb_define_class_under(mWDM, "InvalidDirectoryError", eWDM_Error);
|
525
546
|
eWDM_UnknownFlagError = rb_define_class_under(mWDM, "UnknownFlagError", eWDM_Error);
|
547
|
+
eWDM_UnwatchableDirectoryError = rb_define_class_under(mWDM, "UnwatchableDirectoryError", eWDM_Error);
|
526
548
|
|
527
549
|
cWDM_Monitor = rb_define_class_under(mWDM, "Monitor", rb_cObject);
|
528
550
|
|
data/ext/wdm/rb_monitor.h
CHANGED
@@ -23,6 +23,7 @@ extern VALUE cWDM_Monitor;
|
|
23
23
|
extern VALUE eWDM_UnknownFlagError;
|
24
24
|
extern VALUE eWDM_MonitorRunningError;
|
25
25
|
extern VALUE eWDM_InvalidDirectoryError;
|
26
|
+
extern VALUE eWDM_UnwatchableDirectoryError;
|
26
27
|
|
27
28
|
// ---------------------------------------------------------
|
28
29
|
// Prototypes
|
data/ext/wdm/utils.c
CHANGED
@@ -46,7 +46,14 @@ wdm_utils_unicode_is_directory(const LPWSTR path) {
|
|
46
46
|
WCHAR unicode_path[WDM_MAX_WCHAR_LONG_PATH];
|
47
47
|
|
48
48
|
wcscpy(unicode_path, L"\\\\?\\");
|
49
|
-
|
49
|
+
|
50
|
+
if ( wdm_utils_is_unc_path(path) ) {
|
51
|
+
wcscat(unicode_path, L"UNC\\");
|
52
|
+
wcscat(unicode_path, path + 2); // +2 to skip the begin of a UNC path
|
53
|
+
}
|
54
|
+
else {
|
55
|
+
wcscat(unicode_path, path);
|
56
|
+
}
|
50
57
|
|
51
58
|
return wdm_utils_is_directory(unicode_path);
|
52
59
|
}
|
@@ -57,4 +64,9 @@ wdm_utils_is_directory(const LPWSTR path) {
|
|
57
64
|
|
58
65
|
return (dwAttrib != INVALID_FILE_ATTRIBUTES &&
|
59
66
|
(dwAttrib & FILE_ATTRIBUTE_DIRECTORY));
|
67
|
+
}
|
68
|
+
|
69
|
+
BOOL
|
70
|
+
wdm_utils_is_unc_path(const LPWSTR path) {
|
71
|
+
return path[0] == path[1] && path[0] == L'\\';
|
60
72
|
}
|
data/ext/wdm/utils.h
CHANGED
@@ -13,6 +13,7 @@ extern "C" {
|
|
13
13
|
|
14
14
|
LPWSTR wdm_utils_convert_back_to_forward_slashes(LPWSTR, DWORD);
|
15
15
|
LPWSTR wdm_utils_full_pathname(const LPWSTR path);
|
16
|
+
BOOL wdm_utils_is_unc_path(const LPWSTR);
|
16
17
|
BOOL wdm_utils_is_directory(const LPWSTR);
|
17
18
|
BOOL wdm_utils_unicode_is_directory(const LPWSTR);
|
18
19
|
|
data/ext/wdm/wdm.c
CHANGED
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: wdm
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.3
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2012-
|
12
|
+
date: 2012-08-15 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: rake-compiler
|
@@ -107,6 +107,22 @@ dependencies:
|
|
107
107
|
- - ! '>='
|
108
108
|
- !ruby/object:Gem::Version
|
109
109
|
version: '0'
|
110
|
+
- !ruby/object:Gem::Dependency
|
111
|
+
name: pimpmychangelog
|
112
|
+
requirement: !ruby/object:Gem::Requirement
|
113
|
+
none: false
|
114
|
+
requirements:
|
115
|
+
- - ! '>='
|
116
|
+
- !ruby/object:Gem::Version
|
117
|
+
version: '0'
|
118
|
+
type: :development
|
119
|
+
prerelease: false
|
120
|
+
version_requirements: !ruby/object:Gem::Requirement
|
121
|
+
none: false
|
122
|
+
requirements:
|
123
|
+
- - ! '>='
|
124
|
+
- !ruby/object:Gem::Version
|
125
|
+
version: '0'
|
110
126
|
description: Windows Directory Monitor (WDM) is a library which can be used to monitor
|
111
127
|
directories for changes. It's mostly implemented in C and uses the Win32 API for
|
112
128
|
a better performance.
|
@@ -157,11 +173,13 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
157
173
|
- - ! '>='
|
158
174
|
- !ruby/object:Gem::Version
|
159
175
|
version: '0'
|
176
|
+
segments:
|
177
|
+
- 0
|
178
|
+
hash: 341068911
|
160
179
|
requirements: []
|
161
180
|
rubyforge_project:
|
162
|
-
rubygems_version: 1.8.
|
181
|
+
rubygems_version: 1.8.24
|
163
182
|
signing_key:
|
164
183
|
specification_version: 3
|
165
184
|
summary: Windows Directory Monitor (WDM) is a threaded directories monitor for Windows.
|
166
185
|
test_files: []
|
167
|
-
has_rdoc:
|