wdm 0.0.2-mingw32

Sign up to get free protection for your applications and to get access to all the features.
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.
@@ -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)
@@ -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
+ }
@@ -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
@@ -0,0 +1,9 @@
1
+ require 'mkmf'
2
+
3
+ if have_library("kernel32") and
4
+ have_header("windows.h") and
5
+ have_header("ruby.h") and
6
+ have_const('HAVE_RUBY_ENCODING_H')
7
+ then
8
+ create_makefile("wdm")
9
+ end
@@ -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
+ }
@@ -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
@@ -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
+ }
@@ -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
@@ -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
+ }