ext/wdm/rb_change.c in wdm-0.1.0 vs ext/wdm/rb_change.c in wdm-0.1.1
- old
+ new
@@ -1,199 +1,199 @@
-#include <stdlib.h>
-#include <wchar.h>
-
-#include "wdm.h"
-
-#include "utils.h"
-
-#include "rb_change.h"
-
-// ---------------------------------------------------------
-// Internal constants
-// ---------------------------------------------------------
-
-// The _wsplitpat constants account for two NULL chars, so subtract 1 because we only need one!
-#define WDM_MAX_FILENAME (_MAX_FNAME + _MAX_EXT - 1)
-
-// ----------------------------------------------------------
-// Global variables
-// ----------------------------------------------------------
-
-VALUE cWDM_Change;
-
-static ID wdm_rb_sym_at_path;
-static ID wdm_rb_sym_at_type;
-static ID wdm_rb_sym_added;
-static ID wdm_rb_sym_modified;
-static ID wdm_rb_sym_removed;
-static ID wdm_rb_sym_renamed_old_file;
-static ID wdm_rb_sym_renamed_new_file;
-
-// ----------------------------------------------------------
-// Prototypes of static functions
-// ----------------------------------------------------------
-
-static VALUE extract_absolute_path_from_notification(const LPWSTR, const PFILE_NOTIFY_INFORMATION);
-static VALUE extract_change_type_from_notification(const PFILE_NOTIFY_INFORMATION);
-
-// ----------------------------------------------------------
-
-// TODO:
-// 1. this function uses a lot of 'alloca' calls, which AFAIK is not recommended! Can this be avoided?
-// 2. all wcscat calls can be done faster with memcpy, but is it worth sacrificing the readability?
-static VALUE
-extract_absolute_path_from_notification(const LPWSTR base_dir, const PFILE_NOTIFY_INFORMATION info)
-{
- LPWSTR buffer, absolute_filepath;
- WCHAR file[_MAX_FNAME], ext[_MAX_EXT], filename[WDM_MAX_FILENAME];
- DWORD filename_len, absolute_filepath_len;
- LPSTR multibyte_filepath;
- int multibyte_filepath_buffer_size;
- VALUE path;
-
- filename_len = info->FileNameLength/sizeof(WCHAR);
-
- // The file in the 'info' struct is NOT null-terminated, so add 1 extra char to the allocation
- buffer = ALLOCA_N(WCHAR, filename_len + 1);
-
- memcpy(buffer, info->FileName, info->FileNameLength);
-
- // Null-terminate the string
- buffer[filename_len] = L'\0';
-
- WDM_WDEBUG("change in: '%s'", buffer);
-
- absolute_filepath_len = wcslen(base_dir) + filename_len;
- absolute_filepath = ALLOCA_N(WCHAR, absolute_filepath_len + 1); // 1 for NULL
- absolute_filepath[0] = L'\0';
-
- wcscat(absolute_filepath, base_dir);
- wcscat(absolute_filepath, buffer);
-
- WDM_WDEBUG("absolute path is: '%s'", absolute_filepath);
-
- _wsplitpath(buffer, NULL, NULL, file, ext);
-
- // TODO: Extracting the file name from 'buffer' is only needed when watching sub-dirs
- filename[0] = L'\0';
- if ( file[0] != L'\0' ) wcscat(filename, file);
- if ( ext[0] != L'\0' ) wcscat(filename, ext);
-
- WDM_WDEBUG("filename: '%s'", filename);
-
- filename_len = wcslen(filename);
-
- // The maximum length of an 8.3 filename is twelve, including the dot.
- if (filename_len <= 12 && wcschr(filename, L'~'))
- {
- LPWSTR unicode_absolute_filepath;
- WCHAR absolute_long_filepath[WDM_MAX_WCHAR_LONG_PATH];
- BOOL is_unc_path;
-
- is_unc_path = wdm_utils_is_unc_path(absolute_filepath);
-
- 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
-
- unicode_absolute_filepath[0] = L'\0';
- wcscat(unicode_absolute_filepath, L"\\\\?\\");
-
- if ( is_unc_path ) {
- wcscat(unicode_absolute_filepath, L"UNC\\");
- wcscat(unicode_absolute_filepath, absolute_filepath + 2); // +2 to skip the begin of a UNC path
- }
- else {
- wcscat(unicode_absolute_filepath, absolute_filepath);
- }
-
- // Convert to the long filename form. Unfortunately, this
- // does not work for deletions, so it's an imperfect fix.
- if (GetLongPathNameW(unicode_absolute_filepath, absolute_long_filepath, WDM_MAX_WCHAR_LONG_PATH) != 0) {
- absolute_filepath = absolute_long_filepath + 4; // Skip first 4 pointers of "\\?\"
- absolute_filepath_len = wcslen(absolute_filepath);
- WDM_WDEBUG("Short path converted to long: '%s'", absolute_filepath);
- }
- else {
- WDM_DEBUG("Can't convert short path to long: '%s'", rb_w32_strerror(GetLastError()));
- }
- }
-
- // The convention in Ruby is to use forward-slashes to separate dirs on all platforms.
- wdm_utils_convert_back_to_forward_slashes(absolute_filepath, absolute_filepath_len + 1);
-
- // Convert the path from WCHAR to multibyte CHAR to use it in a ruby string
- multibyte_filepath_buffer_size =
- WideCharToMultiByte(CP_UTF8, 0, absolute_filepath, absolute_filepath_len + 1, NULL, 0, NULL, NULL);
-
- multibyte_filepath = ALLOCA_N(CHAR, multibyte_filepath_buffer_size);
-
- if ( 0 == WideCharToMultiByte(CP_UTF8, 0, absolute_filepath, absolute_filepath_len + 1,
- multibyte_filepath, multibyte_filepath_buffer_size, NULL, NULL) ) {
- rb_raise(eWDM_Error, "Failed to add the change file path to the event!");
- }
-
- WDM_DEBUG("will report change in: '%s'", multibyte_filepath);
-
- path = rb_enc_str_new(multibyte_filepath,
- multibyte_filepath_buffer_size - 1, // -1 because this func takes the chars count, not bytes count
- wdm_rb_enc_utf8);
-
- OBJ_TAINT(path);
-
- return path;
-}
-
-static VALUE
-extract_change_type_from_notification(const PFILE_NOTIFY_INFORMATION info)
-{
- ID type;
-
- switch(info->Action) {
- case FILE_ACTION_ADDED: type = wdm_rb_sym_added; break;
- case FILE_ACTION_REMOVED: type = wdm_rb_sym_removed; break;
- case FILE_ACTION_MODIFIED: type = wdm_rb_sym_modified; break;
- case FILE_ACTION_RENAMED_OLD_NAME: type = wdm_rb_sym_renamed_old_file; break;
- case FILE_ACTION_RENAMED_NEW_NAME: type = wdm_rb_sym_renamed_new_file; break;
- default:
- rb_raise(eWDM_Error, "Unknown change happened to a file in a watched directory!");
- }
-
-#if WDM_DEBUG_ENABLED // Used to avoid the func call when in release mode
- WDM_DEBUG("change type: '%s'", rb_id2name(type));
-#endif
-
- return ID2SYM(type);
-}
-
-VALUE
-wdm_rb_change_new_from_notification(const LPWSTR base_dir, const PFILE_NOTIFY_INFORMATION info)
-{
- VALUE change;
-
- change = rb_class_new_instance(0, NULL, cWDM_Change);
-
- // Set '@type' to the change type
- rb_ivar_set(change, wdm_rb_sym_at_type, extract_change_type_from_notification(info));
-
- // Set '@path' to the absolute path of the changed file/directory
- rb_ivar_set(change, wdm_rb_sym_at_path, extract_absolute_path_from_notification(base_dir, info));
-
- return change;
-}
-
-void
-wdm_rb_change_init()
-{
- WDM_DEBUG("Registering WDM::Event with Ruby!");
-
- wdm_rb_sym_at_path = rb_intern("@path");
- wdm_rb_sym_at_type = rb_intern("@type");
- wdm_rb_sym_added = rb_intern("added");
- wdm_rb_sym_modified = rb_intern("modified");
- wdm_rb_sym_removed = rb_intern("removed");
- wdm_rb_sym_renamed_old_file = rb_intern("renamed_old_file");
- wdm_rb_sym_renamed_new_file = rb_intern("renamed_new_file");
-
- cWDM_Change = rb_define_class_under(mWDM, "Change", rb_cObject);
-
- rb_define_attr(cWDM_Change, "path", 1, 0);
- rb_define_attr(cWDM_Change, "type", 1, 0);
+#include <stdlib.h>
+#include <wchar.h>
+
+#include "wdm.h"
+
+#include "utils.h"
+
+#include "rb_change.h"
+
+// ---------------------------------------------------------
+// Internal constants
+// ---------------------------------------------------------
+
+// The _wsplitpat constants account for two NULL chars, so subtract 1 because we only need one!
+#define WDM_MAX_FILENAME (_MAX_FNAME + _MAX_EXT - 1)
+
+// ----------------------------------------------------------
+// Global variables
+// ----------------------------------------------------------
+
+VALUE cWDM_Change;
+
+static ID wdm_rb_sym_at_path;
+static ID wdm_rb_sym_at_type;
+static ID wdm_rb_sym_added;
+static ID wdm_rb_sym_modified;
+static ID wdm_rb_sym_removed;
+static ID wdm_rb_sym_renamed_old_file;
+static ID wdm_rb_sym_renamed_new_file;
+
+// ----------------------------------------------------------
+// Prototypes of static functions
+// ----------------------------------------------------------
+
+static VALUE extract_absolute_path_from_notification(const LPWSTR, const PFILE_NOTIFY_INFORMATION);
+static VALUE extract_change_type_from_notification(const PFILE_NOTIFY_INFORMATION);
+
+// ----------------------------------------------------------
+
+// TODO:
+// 1. this function uses a lot of 'alloca' calls, which AFAIK is not recommended! Can this be avoided?
+// 2. all wcscat calls can be done faster with memcpy, but is it worth sacrificing the readability?
+static VALUE
+extract_absolute_path_from_notification(const LPWSTR base_dir, const PFILE_NOTIFY_INFORMATION info)
+{
+ LPWSTR buffer, absolute_filepath;
+ WCHAR file[_MAX_FNAME], ext[_MAX_EXT], filename[WDM_MAX_FILENAME];
+ DWORD filename_len, absolute_filepath_len;
+ LPSTR multibyte_filepath;
+ int multibyte_filepath_buffer_size;
+ VALUE path;
+
+ filename_len = info->FileNameLength/sizeof(WCHAR);
+
+ // The file in the 'info' struct is NOT null-terminated, so add 1 extra char to the allocation
+ buffer = ALLOCA_N(WCHAR, filename_len + 1);
+
+ memcpy(buffer, info->FileName, info->FileNameLength);
+
+ // Null-terminate the string
+ buffer[filename_len] = L'\0';
+
+ WDM_WDEBUG("change in: '%s'", buffer);
+
+ absolute_filepath_len = wcslen(base_dir) + filename_len;
+ absolute_filepath = ALLOCA_N(WCHAR, absolute_filepath_len + 1); // 1 for NULL
+ absolute_filepath[0] = L'\0';
+
+ wcscat(absolute_filepath, base_dir);
+ wcscat(absolute_filepath, buffer);
+
+ WDM_WDEBUG("absolute path is: '%s'", absolute_filepath);
+
+ _wsplitpath(buffer, NULL, NULL, file, ext);
+
+ // TODO: Extracting the file name from 'buffer' is only needed when watching sub-dirs
+ filename[0] = L'\0';
+ if ( file[0] != L'\0' ) wcscat(filename, file);
+ if ( ext[0] != L'\0' ) wcscat(filename, ext);
+
+ WDM_WDEBUG("filename: '%s'", filename);
+
+ filename_len = wcslen(filename);
+
+ // The maximum length of an 8.3 filename is twelve, including the dot.
+ if (filename_len <= 12 && wcschr(filename, L'~'))
+ {
+ LPWSTR unicode_absolute_filepath;
+ WCHAR absolute_long_filepath[WDM_MAX_WCHAR_LONG_PATH];
+ BOOL is_unc_path;
+
+ is_unc_path = wdm_utils_is_unc_path(absolute_filepath);
+
+ 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
+
+ unicode_absolute_filepath[0] = L'\0';
+ wcscat(unicode_absolute_filepath, L"\\\\?\\");
+
+ if ( is_unc_path ) {
+ wcscat(unicode_absolute_filepath, L"UNC\\");
+ wcscat(unicode_absolute_filepath, absolute_filepath + 2); // +2 to skip the begin of a UNC path
+ }
+ else {
+ wcscat(unicode_absolute_filepath, absolute_filepath);
+ }
+
+ // Convert to the long filename form. Unfortunately, this
+ // does not work for deletions, so it's an imperfect fix.
+ if (GetLongPathNameW(unicode_absolute_filepath, absolute_long_filepath, WDM_MAX_WCHAR_LONG_PATH) != 0) {
+ absolute_filepath = absolute_long_filepath + 4; // Skip first 4 pointers of "\\?\"
+ absolute_filepath_len = wcslen(absolute_filepath);
+ WDM_WDEBUG("Short path converted to long: '%s'", absolute_filepath);
+ }
+ else {
+ WDM_DEBUG("Can't convert short path to long: '%s'", rb_w32_strerror(GetLastError()));
+ }
+ }
+
+ // The convention in Ruby is to use forward-slashes to separate dirs on all platforms.
+ wdm_utils_convert_back_to_forward_slashes(absolute_filepath, absolute_filepath_len + 1);
+
+ // Convert the path from WCHAR to multibyte CHAR to use it in a ruby string
+ multibyte_filepath_buffer_size =
+ WideCharToMultiByte(CP_UTF8, 0, absolute_filepath, absolute_filepath_len + 1, NULL, 0, NULL, NULL);
+
+ multibyte_filepath = ALLOCA_N(CHAR, multibyte_filepath_buffer_size);
+
+ if ( 0 == WideCharToMultiByte(CP_UTF8, 0, absolute_filepath, absolute_filepath_len + 1,
+ multibyte_filepath, multibyte_filepath_buffer_size, NULL, NULL) ) {
+ rb_raise(eWDM_Error, "Failed to add the change file path to the event!");
+ }
+
+ WDM_DEBUG("will report change in: '%s'", multibyte_filepath);
+
+ path = rb_enc_str_new(multibyte_filepath,
+ multibyte_filepath_buffer_size - 1, // -1 because this func takes the chars count, not bytes count
+ wdm_rb_enc_utf8);
+
+ OBJ_TAINT(path);
+
+ return path;
+}
+
+static VALUE
+extract_change_type_from_notification(const PFILE_NOTIFY_INFORMATION info)
+{
+ ID type;
+
+ switch(info->Action) {
+ case FILE_ACTION_ADDED: type = wdm_rb_sym_added; break;
+ case FILE_ACTION_REMOVED: type = wdm_rb_sym_removed; break;
+ case FILE_ACTION_MODIFIED: type = wdm_rb_sym_modified; break;
+ case FILE_ACTION_RENAMED_OLD_NAME: type = wdm_rb_sym_renamed_old_file; break;
+ case FILE_ACTION_RENAMED_NEW_NAME: type = wdm_rb_sym_renamed_new_file; break;
+ default:
+ rb_raise(eWDM_Error, "Unknown change happened to a file in a watched directory!");
+ }
+
+#if WDM_DEBUG_ENABLED // Used to avoid the func call when in release mode
+ WDM_DEBUG("change type: '%s'", rb_id2name(type));
+#endif
+
+ return ID2SYM(type);
+}
+
+VALUE
+wdm_rb_change_new_from_notification(const LPWSTR base_dir, const PFILE_NOTIFY_INFORMATION info)
+{
+ VALUE change;
+
+ change = rb_class_new_instance(0, NULL, cWDM_Change);
+
+ // Set '@type' to the change type
+ rb_ivar_set(change, wdm_rb_sym_at_type, extract_change_type_from_notification(info));
+
+ // Set '@path' to the absolute path of the changed file/directory
+ rb_ivar_set(change, wdm_rb_sym_at_path, extract_absolute_path_from_notification(base_dir, info));
+
+ return change;
+}
+
+void
+wdm_rb_change_init()
+{
+ WDM_DEBUG("Registering WDM::Event with Ruby!");
+
+ wdm_rb_sym_at_path = rb_intern("@path");
+ wdm_rb_sym_at_type = rb_intern("@type");
+ wdm_rb_sym_added = rb_intern("added");
+ wdm_rb_sym_modified = rb_intern("modified");
+ wdm_rb_sym_removed = rb_intern("removed");
+ wdm_rb_sym_renamed_old_file = rb_intern("renamed_old_file");
+ wdm_rb_sym_renamed_new_file = rb_intern("renamed_new_file");
+
+ cWDM_Change = rb_define_class_under(mWDM, "Change", rb_cObject);
+
+ rb_define_attr(cWDM_Change, "path", 1, 0);
+ rb_define_attr(cWDM_Change, "type", 1, 0);
}
\ No newline at end of file