311 lines
8.6 KiB
C
311 lines
8.6 KiB
C
/*
|
|
* vim:ts=8:sw=3:sts=8:noexpandtab:cino=>5n-3f0^-2{2
|
|
*/
|
|
|
|
#ifdef HAVE_CONFIG_H
|
|
# include <config.h>
|
|
#endif
|
|
|
|
#ifdef HAVE_NOTIFY_WIN32
|
|
|
|
# define WIN32_LEAN_AND_MEAN
|
|
# include <windows.h>
|
|
# undef WIN32_LEAN_AND_MEAN
|
|
# include <process.h>
|
|
|
|
# include "ecore_file_private.h"
|
|
|
|
|
|
typedef struct _Ecore_File_Monitor_Win32 Ecore_File_Monitor_Win32;
|
|
typedef struct _Ecore_File_Monitor_Win32_Data Ecore_File_Monitor_Win32_Data;
|
|
|
|
/* 4096 = 256 * sizeof(FILE_NOTIFY_INFORMATION) */
|
|
# define ECORE_FILE_MONITOR_WIN32_BUFFER_SIZE 4096
|
|
# define ECORE_FILE_MONITOR_WIN32(x) ((Ecore_File_Monitor_Win32 *)(x))
|
|
|
|
struct _Ecore_File_Monitor_Win32_Data
|
|
{
|
|
char buffer[ECORE_FILE_MONITOR_WIN32_BUFFER_SIZE];
|
|
OVERLAPPED overlapped;
|
|
HANDLE handle;
|
|
HANDLE event;
|
|
Ecore_File_Monitor *monitor;
|
|
Ecore_Win32_Handler *h;
|
|
DWORD buf_length;
|
|
int is_dir;
|
|
};
|
|
|
|
struct _Ecore_File_Monitor_Win32
|
|
{
|
|
Ecore_File_Monitor monitor;
|
|
Ecore_File_Monitor_Win32_Data *file;
|
|
Ecore_File_Monitor_Win32_Data *dir;
|
|
};
|
|
|
|
static Ecore_File_Monitor *_monitors = NULL;
|
|
|
|
static Eina_Bool _ecore_file_monitor_win32_cb(void *data, Ecore_Win32_Handler *wh);
|
|
|
|
|
|
static Ecore_File_Monitor_Win32_Data *
|
|
_ecore_file_monitor_win32_data_new(Ecore_File_Monitor *monitor, int type)
|
|
{
|
|
Ecore_File_Monitor_Win32_Data *md;
|
|
DWORD filter;
|
|
|
|
md = (Ecore_File_Monitor_Win32_Data *)calloc(1, sizeof(Ecore_File_Monitor_Win32_Data));
|
|
if (!md) return NULL;
|
|
|
|
md->handle = CreateFile(monitor->path,
|
|
FILE_LIST_DIRECTORY,
|
|
FILE_SHARE_READ |
|
|
FILE_SHARE_WRITE,
|
|
NULL,
|
|
OPEN_EXISTING,
|
|
FILE_FLAG_BACKUP_SEMANTICS |
|
|
FILE_FLAG_OVERLAPPED,
|
|
NULL);
|
|
if (md->handle == INVALID_HANDLE_VALUE)
|
|
goto free_md;
|
|
|
|
md->event = CreateEvent(NULL, FALSE, FALSE, NULL);
|
|
if (!md->event)
|
|
goto close_handle;
|
|
|
|
ZeroMemory (&md->overlapped, sizeof(md->overlapped));
|
|
md->overlapped.hEvent = md->event;
|
|
|
|
filter = (type == 0) ? FILE_NOTIFY_CHANGE_FILE_NAME : FILE_NOTIFY_CHANGE_DIR_NAME;
|
|
filter |=
|
|
FILE_NOTIFY_CHANGE_ATTRIBUTES |
|
|
FILE_NOTIFY_CHANGE_SIZE |
|
|
FILE_NOTIFY_CHANGE_LAST_WRITE |
|
|
FILE_NOTIFY_CHANGE_LAST_ACCESS |
|
|
FILE_NOTIFY_CHANGE_CREATION |
|
|
FILE_NOTIFY_CHANGE_SECURITY;
|
|
|
|
if (!ReadDirectoryChangesW(md->handle,
|
|
md->buffer,
|
|
ECORE_FILE_MONITOR_WIN32_BUFFER_SIZE,
|
|
FALSE,
|
|
filter,
|
|
&md->buf_length,
|
|
&md->overlapped,
|
|
NULL))
|
|
goto close_event;
|
|
|
|
md->h = ecore_main_win32_handler_add(md->event,
|
|
_ecore_file_monitor_win32_cb,
|
|
md);
|
|
if (!md->h)
|
|
goto close_event;
|
|
|
|
md->monitor = monitor;
|
|
md->is_dir = type;
|
|
|
|
return md;
|
|
|
|
close_event:
|
|
CloseHandle(md->event);
|
|
close_handle:
|
|
CloseHandle(md->handle);
|
|
free_md:
|
|
free(md);
|
|
|
|
return NULL;
|
|
}
|
|
|
|
static void
|
|
_ecore_file_monitor_win32_data_free(Ecore_File_Monitor_Win32_Data *md)
|
|
{
|
|
if (!md) return;
|
|
|
|
CloseHandle(md->event);
|
|
CloseHandle (md->handle);
|
|
free (md);
|
|
}
|
|
|
|
static Eina_Bool
|
|
_ecore_file_monitor_win32_cb(void *data, Ecore_Win32_Handler *wh)
|
|
{
|
|
char filename[PATH_MAX];
|
|
PFILE_NOTIFY_INFORMATION fni;
|
|
Ecore_File_Monitor_Win32_Data *md;
|
|
wchar_t *wname;
|
|
char *name;
|
|
DWORD filter;
|
|
DWORD offset;
|
|
DWORD buf_length;
|
|
Ecore_File_Event event = ECORE_FILE_EVENT_NONE;
|
|
|
|
md = (Ecore_File_Monitor_Win32_Data *)data;
|
|
|
|
if (!GetOverlappedResult (md->handle, &md->overlapped, &buf_length, TRUE))
|
|
return 1;
|
|
|
|
fni = (PFILE_NOTIFY_INFORMATION)md->buffer;
|
|
do {
|
|
if (!fni)
|
|
break;
|
|
offset = fni->NextEntryOffset;
|
|
|
|
wname = (wchar_t *)malloc(sizeof(wchar_t) * (fni->FileNameLength + 1));
|
|
if (!wname)
|
|
return 0;
|
|
|
|
memcpy(wname, fni->FileName, fni->FileNameLength);
|
|
wname[fni->FileNameLength]='\0';
|
|
name = evil_wchar_to_char(wname);
|
|
free(wname);
|
|
if (!name)
|
|
return 0;
|
|
|
|
_snprintf(filename, PATH_MAX, "%s\\%s", md->monitor->path, name);
|
|
free(name);
|
|
|
|
switch (fni->Action)
|
|
{
|
|
case FILE_ACTION_ADDED:
|
|
if (md->is_dir)
|
|
event = ECORE_FILE_EVENT_CREATED_DIRECTORY;
|
|
else
|
|
event = ECORE_FILE_EVENT_CREATED_FILE;
|
|
break;
|
|
case FILE_ACTION_REMOVED:
|
|
if (md->is_dir)
|
|
event = ECORE_FILE_EVENT_DELETED_DIRECTORY;
|
|
else
|
|
event = ECORE_FILE_EVENT_DELETED_FILE;
|
|
break;
|
|
case FILE_ACTION_MODIFIED:
|
|
if (!md->is_dir)
|
|
event = ECORE_FILE_EVENT_MODIFIED;
|
|
break;
|
|
case FILE_ACTION_RENAMED_OLD_NAME:
|
|
if (md->is_dir)
|
|
event = ECORE_FILE_EVENT_DELETED_DIRECTORY;
|
|
else
|
|
event = ECORE_FILE_EVENT_DELETED_FILE;
|
|
break;
|
|
case FILE_ACTION_RENAMED_NEW_NAME:
|
|
if (md->is_dir)
|
|
event = ECORE_FILE_EVENT_CREATED_DIRECTORY;
|
|
else
|
|
event = ECORE_FILE_EVENT_CREATED_FILE;
|
|
break;
|
|
default:
|
|
fprintf(stderr, "unknown event\n");
|
|
event = ECORE_FILE_EVENT_NONE;
|
|
break;
|
|
}
|
|
if (event != ECORE_FILE_EVENT_NONE)
|
|
md->monitor->func(md->monitor->data, md->monitor, event, filename);
|
|
|
|
fni = (PFILE_NOTIFY_INFORMATION)((LPBYTE)fni + offset);
|
|
} while (offset);
|
|
|
|
filter = (md->is_dir == 0) ? FILE_NOTIFY_CHANGE_FILE_NAME : FILE_NOTIFY_CHANGE_DIR_NAME;
|
|
filter |=
|
|
FILE_NOTIFY_CHANGE_ATTRIBUTES |
|
|
FILE_NOTIFY_CHANGE_SIZE |
|
|
FILE_NOTIFY_CHANGE_LAST_WRITE |
|
|
FILE_NOTIFY_CHANGE_LAST_ACCESS |
|
|
FILE_NOTIFY_CHANGE_CREATION |
|
|
FILE_NOTIFY_CHANGE_SECURITY;
|
|
|
|
ReadDirectoryChangesW(md->handle,
|
|
md->buffer,
|
|
ECORE_FILE_MONITOR_WIN32_BUFFER_SIZE,
|
|
FALSE,
|
|
filter,
|
|
&md->buf_length,
|
|
&md->overlapped,
|
|
NULL);
|
|
return 1;
|
|
}
|
|
|
|
int
|
|
ecore_file_monitor_win32_init(void)
|
|
{
|
|
return 1;
|
|
}
|
|
|
|
int
|
|
ecore_file_monitor_win32_shutdown(void)
|
|
{
|
|
return 1;
|
|
}
|
|
|
|
Ecore_File_Monitor *
|
|
ecore_file_monitor_win32_add(const char *path,
|
|
void (*func) (void *data, Ecore_File_Monitor *em,
|
|
Ecore_File_Event event,
|
|
const char *path),
|
|
void *data)
|
|
{
|
|
Ecore_File_Monitor_Win32 *m;
|
|
Ecore_File_Monitor *em;
|
|
size_t len;
|
|
|
|
if (!path || (*path == '\0')) return NULL;
|
|
if (!ecore_file_exists(path) || !ecore_file_is_dir(path))
|
|
return NULL;
|
|
if (!func) return NULL;
|
|
|
|
em = (Ecore_File_Monitor *)calloc(1, sizeof(Ecore_File_Monitor_Win32));
|
|
if (!em) return NULL;
|
|
|
|
em->func = func;
|
|
em->data = data;
|
|
|
|
em->path = strdup(path);
|
|
if (!em->path)
|
|
{
|
|
free(em);
|
|
return NULL;
|
|
}
|
|
len = strlen(em->path);
|
|
if (em->path[len - 1] == '/' || em->path[len - 1] == '\\')
|
|
em->path[len - 1] = '\0';
|
|
|
|
m = ECORE_FILE_MONITOR_WIN32(em);
|
|
|
|
m->file = _ecore_file_monitor_win32_data_new(em, 0);
|
|
if (!m->file)
|
|
{
|
|
free(em->path);
|
|
free(em);
|
|
return NULL;
|
|
}
|
|
|
|
m->dir = _ecore_file_monitor_win32_data_new(em, 1);
|
|
if (!m->dir)
|
|
{
|
|
_ecore_file_monitor_win32_data_free(m->file);
|
|
free(em->path);
|
|
free(em);
|
|
return NULL;
|
|
}
|
|
|
|
_monitors = ECORE_FILE_MONITOR(eina_inlist_append(EINA_INLIST_GET(_monitors), EINA_INLIST_GET(em)));
|
|
|
|
return em;
|
|
}
|
|
|
|
void
|
|
ecore_file_monitor_win32_del(Ecore_File_Monitor *em)
|
|
{
|
|
Ecore_File_Monitor_Win32 *m;
|
|
|
|
if (!em)
|
|
return;
|
|
|
|
m = ECORE_FILE_MONITOR_WIN32(em);
|
|
_ecore_file_monitor_win32_data_free(m->dir);
|
|
_ecore_file_monitor_win32_data_free(m->file);
|
|
free(em->path);
|
|
free(em);
|
|
}
|
|
|
|
#endif
|