wdm 0.0.2-mingw32
Sign up to get free protection for your applications and to get access to all the features.
- data/LICENSE +22 -0
- data/README.md +58 -0
- data/ext/wdm/entry.c +67 -0
- data/ext/wdm/entry.h +47 -0
- data/ext/wdm/extconf.rb +9 -0
- data/ext/wdm/memory.c +27 -0
- data/ext/wdm/memory.h +32 -0
- data/ext/wdm/monitor.c +70 -0
- data/ext/wdm/monitor.h +50 -0
- data/ext/wdm/queue.c +108 -0
- data/ext/wdm/queue.h +50 -0
- data/ext/wdm/rb_change.c +185 -0
- data/ext/wdm/rb_change.h +28 -0
- data/ext/wdm/rb_monitor.c +531 -0
- data/ext/wdm/rb_monitor.h +39 -0
- data/ext/wdm/utils.c +60 -0
- data/ext/wdm/utils.h +25 -0
- data/ext/wdm/wdm.c +45 -0
- data/ext/wdm/wdm.h +66 -0
- data/ext/wdm/wdm.sln +20 -0
- data/ext/wdm/wdm.vcxproj +104 -0
- data/ext/wdm/wdm.vcxproj.filters +74 -0
- metadata +167 -0
data/LICENSE
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2012 Maher Sallam
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,58 @@
|
|
1
|
+
# Windows Directory Monitor (WDM)
|
2
|
+
|
3
|
+
Windows Directory Monitor (WDM) is a library which can be used to monitor directories for changes.
|
4
|
+
It's mostly implemented in C and uses the Win32 API for a better performance.
|
5
|
+
|
6
|
+
**Note:** This is still a work in progress, so it's not advisable to use
|
7
|
+
it yet in anything (unless you are testing it, which is very much appreciated :)).
|
8
|
+
|
9
|
+
TODO:
|
10
|
+
|
11
|
+
- Fix all the TODO's in the source.
|
12
|
+
- ~~Enable watching subdirectories.~~
|
13
|
+
- ~~Add options to the `watch` method.~~
|
14
|
+
- ~~Provide info about the change in the callback.~~
|
15
|
+
- ~~Convert \ to / in paths.~~
|
16
|
+
- ~~Don't allow directories to be watched while the monitor is running.~~
|
17
|
+
- ~~Check if the passed direcoty exists.~~
|
18
|
+
- ~~Convert passed directories to absolute paths.~~
|
19
|
+
|
20
|
+
## Installation
|
21
|
+
|
22
|
+
Add this line to your application's Gemfile:
|
23
|
+
|
24
|
+
gem 'wdm'
|
25
|
+
|
26
|
+
And then execute:
|
27
|
+
|
28
|
+
$ bundle
|
29
|
+
|
30
|
+
Or install it yourself as:
|
31
|
+
|
32
|
+
$ gem install wdm
|
33
|
+
|
34
|
+
## Compiling the extension for developers
|
35
|
+
|
36
|
+
Download the source, then run the following:
|
37
|
+
|
38
|
+
$ rake compile
|
39
|
+
|
40
|
+
To get debug messages, you need to enable them in the `global.h` file:
|
41
|
+
|
42
|
+
#define WDM_DEBUG_ENABLED TRUE // This is disabled by default
|
43
|
+
|
44
|
+
## Usage
|
45
|
+
|
46
|
+
TODO: Write usage instructions here
|
47
|
+
|
48
|
+
## Contributing
|
49
|
+
|
50
|
+
1. Fork it
|
51
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
52
|
+
3. Commit your changes (`git commit -am 'Added some feature'`)
|
53
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
54
|
+
5. Create new Pull Request
|
55
|
+
|
56
|
+
## Author
|
57
|
+
|
58
|
+
[Maher Sallam](https://github.com/Maher4Ever)
|
data/ext/wdm/entry.c
ADDED
@@ -0,0 +1,67 @@
|
|
1
|
+
#include "wdm.h"
|
2
|
+
|
3
|
+
#include "memory.h"
|
4
|
+
#include "entry.h"
|
5
|
+
|
6
|
+
// ---------------------------------------------------------
|
7
|
+
// Entry user data functions
|
8
|
+
// ---------------------------------------------------------
|
9
|
+
|
10
|
+
WDM_PEntryUserData
|
11
|
+
wdm_entry_user_data_new() {
|
12
|
+
WDM_PEntryUserData user_data;
|
13
|
+
|
14
|
+
user_data = WDM_ALLOC(WDM_EntryUserData);
|
15
|
+
|
16
|
+
user_data->dir = NULL;
|
17
|
+
user_data->watch_childeren = FALSE;
|
18
|
+
|
19
|
+
return user_data;
|
20
|
+
}
|
21
|
+
|
22
|
+
void
|
23
|
+
wdm_entry_user_data_free(WDM_PEntryUserData user_data) {
|
24
|
+
if ( user_data->dir != NULL ) free(user_data->dir);
|
25
|
+
free(user_data);
|
26
|
+
}
|
27
|
+
|
28
|
+
// ---------------------------------------------------------
|
29
|
+
// Entry functions
|
30
|
+
// ---------------------------------------------------------
|
31
|
+
|
32
|
+
WDM_PEntry
|
33
|
+
wdm_entry_new() {
|
34
|
+
WDM_PEntry entry;
|
35
|
+
|
36
|
+
entry = WDM_ALLOC(WDM_Entry);
|
37
|
+
|
38
|
+
entry->user_data = wdm_entry_user_data_new();
|
39
|
+
entry->dir_handle = INVALID_HANDLE_VALUE;
|
40
|
+
entry->next = NULL;
|
41
|
+
|
42
|
+
ZeroMemory(&entry->buffer, WDM_BUFFER_SIZE);
|
43
|
+
ZeroMemory(&entry->event_container, sizeof(OVERLAPPED));
|
44
|
+
|
45
|
+
return entry;
|
46
|
+
}
|
47
|
+
|
48
|
+
void
|
49
|
+
wdm_entry_free(WDM_PEntry entry) {
|
50
|
+
if ( entry->dir_handle != INVALID_HANDLE_VALUE ) {
|
51
|
+
CancelIo(entry->dir_handle); // Stop monitoring changes
|
52
|
+
CloseHandle(entry->dir_handle);
|
53
|
+
}
|
54
|
+
wdm_entry_user_data_free(entry->user_data);
|
55
|
+
free(entry);
|
56
|
+
}
|
57
|
+
|
58
|
+
void
|
59
|
+
wdm_entry_list_free(WDM_PEntry entry) {
|
60
|
+
WDM_PEntry tmp;
|
61
|
+
|
62
|
+
while(entry != NULL) {
|
63
|
+
tmp = entry;
|
64
|
+
entry = entry->next;
|
65
|
+
wdm_entry_free(tmp);
|
66
|
+
}
|
67
|
+
}
|
data/ext/wdm/entry.h
ADDED
@@ -0,0 +1,47 @@
|
|
1
|
+
#include <Windows.h>
|
2
|
+
#include <ruby.h>
|
3
|
+
|
4
|
+
#ifndef WDM_ENTRY_H
|
5
|
+
#define WDM_ENTRY_H
|
6
|
+
|
7
|
+
#ifdef __cplusplus
|
8
|
+
extern "C" {
|
9
|
+
#endif // __cplusplus
|
10
|
+
|
11
|
+
// ---------------------------------------------------------
|
12
|
+
// Types
|
13
|
+
// ---------------------------------------------------------
|
14
|
+
|
15
|
+
typedef struct {
|
16
|
+
LPWSTR dir; // Name of directory to watch
|
17
|
+
VALUE callback; // Proc object to call when there are changes
|
18
|
+
BOOL watch_childeren; // Watch sub-directories
|
19
|
+
DWORD flags; // Flags for the type of changes to report
|
20
|
+
} WDM_EntryUserData, *WDM_PEntryUserData;
|
21
|
+
|
22
|
+
typedef struct WDM_Entry {
|
23
|
+
WDM_PEntryUserData user_data; // User-supplied data
|
24
|
+
HANDLE dir_handle; // IO handle of the directory
|
25
|
+
BYTE buffer[WDM_BUFFER_SIZE]; // Buffer for the results
|
26
|
+
OVERLAPPED event_container; // Async IO event container
|
27
|
+
struct WDM_Entry* next; // Well, this is a linked list, so this is self-explanatory :)
|
28
|
+
} WDM_Entry, *WDM_PEntry;
|
29
|
+
|
30
|
+
// ---------------------------------------------------------
|
31
|
+
// Prototypes
|
32
|
+
// ---------------------------------------------------------
|
33
|
+
|
34
|
+
WDM_PEntryUserData wdm_entry_user_data_new();
|
35
|
+
void wdm_entry_user_data_free(WDM_PEntryUserData);
|
36
|
+
|
37
|
+
WDM_PEntry wdm_entry_new();
|
38
|
+
void wdm_entry_free(WDM_PEntry);
|
39
|
+
void wdm_entry_list_free(WDM_PEntry);
|
40
|
+
|
41
|
+
// ---------------------------------------------------------
|
42
|
+
|
43
|
+
#ifdef __cplusplus
|
44
|
+
}
|
45
|
+
#endif // __cplusplus
|
46
|
+
|
47
|
+
#endif // WDM_ENTRY_H
|
data/ext/wdm/extconf.rb
ADDED
data/ext/wdm/memory.c
ADDED
@@ -0,0 +1,27 @@
|
|
1
|
+
#include "wdm.h"
|
2
|
+
|
3
|
+
#include "memory.h"
|
4
|
+
|
5
|
+
void *
|
6
|
+
wdm_memory_malloc (size_t size)
|
7
|
+
{
|
8
|
+
void *memory = malloc(size);
|
9
|
+
|
10
|
+
if ( memory == NULL ) {
|
11
|
+
rb_fatal("failed to allocate memory");
|
12
|
+
}
|
13
|
+
|
14
|
+
return memory;
|
15
|
+
}
|
16
|
+
|
17
|
+
void *
|
18
|
+
wdm_memory_realloc (void *ptr, size_t size)
|
19
|
+
{
|
20
|
+
void *memory = realloc(ptr, size);
|
21
|
+
|
22
|
+
if ( memory == NULL ) {
|
23
|
+
rb_fatal("failed to re-allocate memory");
|
24
|
+
}
|
25
|
+
|
26
|
+
return memory;
|
27
|
+
}
|
data/ext/wdm/memory.h
ADDED
@@ -0,0 +1,32 @@
|
|
1
|
+
#ifndef WDM_MEMORY_H
|
2
|
+
#define WDM_MEMORY_H
|
3
|
+
|
4
|
+
#ifdef __cplusplus
|
5
|
+
extern "C" {
|
6
|
+
#endif // __cplusplus
|
7
|
+
|
8
|
+
// ---------------------------------------------------------
|
9
|
+
// Prototypes
|
10
|
+
// ---------------------------------------------------------
|
11
|
+
|
12
|
+
void *
|
13
|
+
wdm_memory_malloc (size_t);
|
14
|
+
|
15
|
+
void *
|
16
|
+
wdm_memory_realloc (void *, size_t);
|
17
|
+
|
18
|
+
// ---------------------------------------------------------
|
19
|
+
// Macros
|
20
|
+
// ---------------------------------------------------------
|
21
|
+
|
22
|
+
#define WDM_ALLOC_N(type,n) ((type*)wdm_memory_malloc((n) * sizeof(type)))
|
23
|
+
#define WDM_ALLOC(type) ((type*)wdm_memory_malloc(sizeof(type)))
|
24
|
+
#define WDM_REALLOC_N(var,type,n) ((var)=(type*)wdm_memory_realloc((void*)(var), (n) * sizeof(type)))
|
25
|
+
|
26
|
+
// ---------------------------------------------------------
|
27
|
+
|
28
|
+
#ifdef __cplusplus
|
29
|
+
}
|
30
|
+
#endif // __cplusplus
|
31
|
+
|
32
|
+
#endif // WDM_MEMORY_H
|
data/ext/wdm/monitor.c
ADDED
@@ -0,0 +1,70 @@
|
|
1
|
+
#include "wdm.h"
|
2
|
+
|
3
|
+
#include "memory.h"
|
4
|
+
#include "entry.h"
|
5
|
+
#include "queue.h"
|
6
|
+
|
7
|
+
#include "monitor.h"
|
8
|
+
|
9
|
+
WDM_PMonitor
|
10
|
+
wdm_monitor_new() {
|
11
|
+
WDM_PMonitor monitor;
|
12
|
+
|
13
|
+
monitor = WDM_ALLOC(WDM_Monitor);
|
14
|
+
|
15
|
+
monitor->running = FALSE;
|
16
|
+
|
17
|
+
monitor->head = NULL;
|
18
|
+
monitor->monitoring_thread = INVALID_HANDLE_VALUE;
|
19
|
+
|
20
|
+
monitor->changes = wdm_queue_new();
|
21
|
+
|
22
|
+
monitor->process_event = CreateEvent(NULL, TRUE, FALSE, NULL);
|
23
|
+
monitor->stop_event = CreateEvent(NULL, TRUE, FALSE, NULL);
|
24
|
+
|
25
|
+
if ( ! InitializeCriticalSectionAndSpinCount(&monitor->lock,
|
26
|
+
0x00000400) ) // TODO: look into the best value for spinning.
|
27
|
+
{
|
28
|
+
rb_raise(eWDM_Error, "Can't create a lock for the monitor");
|
29
|
+
}
|
30
|
+
|
31
|
+
return monitor;
|
32
|
+
}
|
33
|
+
|
34
|
+
void
|
35
|
+
wdm_monitor_free(WDM_PMonitor monitor) {
|
36
|
+
if ( monitor->monitoring_thread != INVALID_HANDLE_VALUE ) CloseHandle(monitor->monitoring_thread);
|
37
|
+
|
38
|
+
wdm_entry_list_free(monitor->head);
|
39
|
+
wdm_queue_free(monitor->changes);
|
40
|
+
DeleteCriticalSection(&monitor->lock);
|
41
|
+
CloseHandle(monitor->process_event); // TODO: Look into why this crashes the app when exiting!
|
42
|
+
CloseHandle(monitor->stop_event);
|
43
|
+
|
44
|
+
free(monitor);
|
45
|
+
}
|
46
|
+
|
47
|
+
void
|
48
|
+
wdm_monitor_update_head(WDM_PMonitor monitor, WDM_PEntry new_head) {
|
49
|
+
EnterCriticalSection(&monitor->lock);
|
50
|
+
new_head->next = monitor->head;
|
51
|
+
monitor->head = new_head;
|
52
|
+
LeaveCriticalSection(&monitor->lock);
|
53
|
+
}
|
54
|
+
|
55
|
+
WDM_PMonitorCallbackParam
|
56
|
+
wdm_monitor_callback_param_new(WDM_PMonitor monitor, WDM_PEntry entry) {
|
57
|
+
WDM_PMonitorCallbackParam param;
|
58
|
+
|
59
|
+
param = WDM_ALLOC(WDM_MonitorCallbackParam);
|
60
|
+
|
61
|
+
param->monitor = monitor;
|
62
|
+
param->entry = entry;
|
63
|
+
|
64
|
+
return param;
|
65
|
+
}
|
66
|
+
|
67
|
+
void
|
68
|
+
wdm_monitor_callback_param_free(WDM_PMonitorCallbackParam param) {
|
69
|
+
free(param);
|
70
|
+
}
|
data/ext/wdm/monitor.h
ADDED
@@ -0,0 +1,50 @@
|
|
1
|
+
#include <Windows.h>
|
2
|
+
|
3
|
+
#include "entry.h"
|
4
|
+
#include "queue.h"
|
5
|
+
|
6
|
+
#ifndef WDM_MONITOR_H
|
7
|
+
#define WDM_MONITOR_H
|
8
|
+
|
9
|
+
#ifdef __cplusplus
|
10
|
+
extern "C" {
|
11
|
+
#endif // __cplusplus
|
12
|
+
|
13
|
+
// ---------------------------------------------------------
|
14
|
+
// Types
|
15
|
+
// ---------------------------------------------------------
|
16
|
+
|
17
|
+
typedef struct {
|
18
|
+
BOOL running;
|
19
|
+
WDM_PEntry head;
|
20
|
+
WDM_PQueue changes;
|
21
|
+
CRITICAL_SECTION lock;
|
22
|
+
HANDLE monitoring_thread;
|
23
|
+
HANDLE process_event;
|
24
|
+
HANDLE stop_event;
|
25
|
+
} WDM_Monitor, *WDM_PMonitor;
|
26
|
+
|
27
|
+
typedef struct {
|
28
|
+
WDM_PEntry entry;
|
29
|
+
WDM_PMonitor monitor;
|
30
|
+
} WDM_MonitorCallbackParam, *WDM_PMonitorCallbackParam;
|
31
|
+
|
32
|
+
// ---------------------------------------------------------
|
33
|
+
// Prototypes
|
34
|
+
// ---------------------------------------------------------
|
35
|
+
|
36
|
+
WDM_PMonitor wdm_monitor_new();
|
37
|
+
void wdm_monitor_free(WDM_PMonitor);
|
38
|
+
|
39
|
+
void wdm_monitor_update_head(WDM_PMonitor, WDM_PEntry);
|
40
|
+
|
41
|
+
WDM_PMonitorCallbackParam wdm_monitor_callback_param_new(WDM_PMonitor, WDM_PEntry);
|
42
|
+
void wdm_monitor_callback_param_free(WDM_PMonitorCallbackParam);
|
43
|
+
|
44
|
+
// ---------------------------------------------------------
|
45
|
+
|
46
|
+
#ifdef __cplusplus
|
47
|
+
}
|
48
|
+
#endif // __cplusplus
|
49
|
+
|
50
|
+
#endif // WDM_MONITOR_H
|
data/ext/wdm/queue.c
ADDED
@@ -0,0 +1,108 @@
|
|
1
|
+
#include "wdm.h"
|
2
|
+
|
3
|
+
#include "memory.h"
|
4
|
+
#include "queue.h"
|
5
|
+
|
6
|
+
// ---------------------------------------------------------
|
7
|
+
// Queue item functions
|
8
|
+
// ---------------------------------------------------------
|
9
|
+
|
10
|
+
WDM_PQueueItem
|
11
|
+
wdm_queue_item_new() {
|
12
|
+
WDM_PQueueItem item;
|
13
|
+
|
14
|
+
item = WDM_ALLOC(WDM_QueueItem);
|
15
|
+
item->user_data = NULL;
|
16
|
+
item->previous = NULL;
|
17
|
+
item->next = NULL;
|
18
|
+
|
19
|
+
ZeroMemory(&item->buffer, WDM_BUFFER_SIZE);
|
20
|
+
|
21
|
+
return item;
|
22
|
+
}
|
23
|
+
|
24
|
+
void
|
25
|
+
wdm_queue_item_free(WDM_PQueueItem item) {
|
26
|
+
// We can't really do anything to the prev pointer nor the next pointer,
|
27
|
+
// because we might break any linking the user has established.
|
28
|
+
free(item);
|
29
|
+
}
|
30
|
+
|
31
|
+
// ---------------------------------------------------------
|
32
|
+
// Queue functions
|
33
|
+
// ---------------------------------------------------------
|
34
|
+
|
35
|
+
WDM_PQueue
|
36
|
+
wdm_queue_new() {
|
37
|
+
WDM_PQueue queue;
|
38
|
+
|
39
|
+
queue = WDM_ALLOC(WDM_Queue);
|
40
|
+
queue->front = NULL;
|
41
|
+
queue->rear = NULL;
|
42
|
+
|
43
|
+
if ( ! InitializeCriticalSectionAndSpinCount(&queue->lock,
|
44
|
+
0x00000400) ) // TODO: look into the best value for spinning.
|
45
|
+
{
|
46
|
+
rb_raise(eWDM_Error, "Can't create a lock for the queue");
|
47
|
+
}
|
48
|
+
|
49
|
+
return queue;
|
50
|
+
}
|
51
|
+
|
52
|
+
void
|
53
|
+
wdm_queue_free(WDM_PQueue queue) {
|
54
|
+
wdm_queue_empty(queue);
|
55
|
+
free(queue);
|
56
|
+
}
|
57
|
+
|
58
|
+
void
|
59
|
+
wdm_queue_enqueue(WDM_PQueue queue, WDM_PQueueItem item) {
|
60
|
+
EnterCriticalSection(&queue->lock);
|
61
|
+
|
62
|
+
if ( queue->rear == NULL && queue->front == NULL ) {
|
63
|
+
queue->front = queue->rear = item;
|
64
|
+
}
|
65
|
+
else {
|
66
|
+
queue->rear->next = item;
|
67
|
+
item->previous = queue->rear;
|
68
|
+
queue->rear = item;
|
69
|
+
}
|
70
|
+
|
71
|
+
LeaveCriticalSection(&queue->lock);
|
72
|
+
}
|
73
|
+
|
74
|
+
WDM_PQueueItem
|
75
|
+
wdm_queue_dequeue(WDM_PQueue queue) {
|
76
|
+
WDM_PQueueItem item;
|
77
|
+
|
78
|
+
EnterCriticalSection(&queue->lock);
|
79
|
+
|
80
|
+
if ( queue->rear == NULL && queue->front == NULL ) {
|
81
|
+
item = NULL;
|
82
|
+
}
|
83
|
+
else {
|
84
|
+
item = queue->front;
|
85
|
+
queue->front = queue->front->next;
|
86
|
+
|
87
|
+
// Reset the rear when the queue is empty
|
88
|
+
if ( queue->front == NULL ) queue->rear = NULL;
|
89
|
+
|
90
|
+
// Don't allow the user to mess with the queue
|
91
|
+
item->previous = item->next = NULL;
|
92
|
+
}
|
93
|
+
|
94
|
+
LeaveCriticalSection(&queue->lock);
|
95
|
+
|
96
|
+
return item;
|
97
|
+
}
|
98
|
+
|
99
|
+
void wdm_queue_empty(WDM_PQueue queue) {
|
100
|
+
while( ! wdm_queue_is_empty(queue) ) {
|
101
|
+
wdm_queue_item_free(wdm_queue_dequeue(queue));
|
102
|
+
}
|
103
|
+
}
|
104
|
+
|
105
|
+
BOOL
|
106
|
+
wdm_queue_is_empty(WDM_PQueue queue) {
|
107
|
+
return queue->front == NULL && queue->rear == NULL;
|
108
|
+
}
|