fileinteraction and monitoring

SVN revision: 13442
This commit is contained in:
sebastid 2005-02-20 12:17:07 +00:00 committed by sebastid
parent 7dbcc92602
commit 813c77c392
10 changed files with 1680 additions and 0 deletions

View File

@ -0,0 +1,6 @@
.deps
.libs
Makefile
Makefile.in
*.lo
libecore_file.la

View File

@ -0,0 +1,98 @@
/*
* vim:ts=8:sw=3:sts=8:noexpandtab:cino=>5n-3f0^-2{2
*/
#ifndef ECORE_FILE_H
#define ECORE_FILE_H
/*
* TODO:
* - More events, move/rename of directory file
*/
#ifdef EAPI
#undef EAPI
#endif
#ifdef WIN32
# ifdef BUILDING_DLL
# define EAPI __declspec(dllexport)
# else
# define EAPI __declspec(dllimport)
# endif
#else
# ifdef GCC_HASCLASSVISIBILITY
# define EAPI __attribute__ ((visibility("default")))
# else
# define EAPI
# endif
#endif
#include <Evas.h>
#include <time.h>
EAPI int ecore_file_init(void);
EAPI int ecore_file_shutdown(void);
EAPI time_t ecore_file_mod_time(char *file);
EAPI int ecore_file_exists(char *file);
EAPI int ecore_file_is_dir(char *file);
EAPI int ecore_file_mkdir(char *dir);
EAPI int ecore_file_mkpath(char *path);
EAPI int ecore_file_cp(char *src, char *dst);
EAPI char *ecore_file_realpath(char *file);
EAPI char *ecore_file_get_file(char *path);
EAPI char *ecore_file_get_dir(char *path);
EAPI int ecore_file_can_exec(char *file);
EAPI char *ecore_file_readlink(char *link);
EAPI Evas_List *ecore_file_ls(char *dir);
typedef struct _Ecore_File_Monitor Ecore_File_Monitor;
typedef struct _Ecore_File_Monitor_Event Ecore_File_Monitor_Event;
typedef enum {
ECORE_FILE_TYPE_NONE,
ECORE_FILE_TYPE_FILE,
ECORE_FILE_TYPE_DIRECTORY
} Ecore_File_Type;
typedef enum {
ECORE_FILE_EVENT_NONE,
ECORE_FILE_EVENT_CREATED,
ECORE_FILE_EVENT_DELETED,
ECORE_FILE_EVENT_CHANGED,
ECORE_FILE_EVENT_EXISTS
} Ecore_File_Event;
struct _Ecore_File_Monitor {
void (*func) (void *data,
Ecore_File_Monitor *ecore_file_monitor,
Ecore_File_Type type,
Ecore_File_Event event,
const char *path);
char *path;
Ecore_File_Type type;
void *data;
};
#if 0
struct _Ecore_File_Monitor_Event {
Ecore_File_Monitor *ecore_file_monitor;
Ecore_File_Type type;
Ecore_File_Event event;
char *path;
void *data;
};
#endif
#define ECORE_FILE_MONITOR(x) ((Ecore_File_Monitor *)(x))
EAPI Ecore_File_Monitor *ecore_file_monitor_add(const char *path,
void (*func) (void *data,
Ecore_File_Monitor *ecore_file_monitor,
Ecore_File_Type type,
Ecore_File_Event event,
const char *path),
void *data);
EAPI void ecore_file_monitor_del(Ecore_File_Monitor *ecore_file_monitor);
#endif

View File

@ -0,0 +1,38 @@
## Process this file with automake to produce Makefile.in
INCLUDES = \
-I$(top_srcdir)/src/lib/ecore \
-I$(top_builddir)/src/lib/ecore \
@evas_cflags@
libecore_file_la_LDFLAGS = -version-info 1:0:0 \
-L$(top_builddir)/src/lib/ecore/.libs
if BUILD_ECORE_FILE
lib_LTLIBRARIES = libecore_file.la
include_HEADERS = Ecore_File.h
libecore_file_la_SOURCES = \
ecore_file.c \
ecore_file_private.h \
ecore_file_monitor_fam.c \
ecore_file_monitor_inotify.c \
ecore_file_monitor_dnotify.c \
ecore_file_monitor_poll.c
libecore_file_la_LIBADD = \
$(top_builddir)/src/lib/ecore/libecore.la \
@fam_libs@ \
@evas_libs@
endif
EXTRA_DIST = \
ecore_file.c \
ecore_file_private.h \
ecore_file_monitor_fam.c \
ecore_file_monitor_inotify.c \
ecore_file_monitor_dnotify.c \
ecore_file_monitor_poll.c

View File

@ -0,0 +1,223 @@
/*
* vim:ts=8:sw=3:sts=8:noexpandtab:cino=>5n-3f0^-2{2
*/
#include "Ecore_File.h"
#include "ecore_file_private.h"
/* externally accessible functions */
int
ecore_file_init()
{
if (!ecore_file_monitor_init())
return 0;
return 1;
}
int
ecore_file_shutdown()
{
if (!ecore_file_monitor_shutdown())
return 0;
return 1;
}
time_t
ecore_file_mod_time(char *file)
{
struct stat st;
if (stat(file, &st) < 0) return 0;
return st.st_mtime;
}
int
ecore_file_exists(char *file)
{
struct stat st;
if (stat(file, &st) < 0) return 0;
return 1;
}
int
ecore_file_is_dir(char *file)
{
struct stat st;
if (stat(file, &st) < 0) return 0;
if (S_ISDIR(st.st_mode)) return 1;
return 0;
}
static mode_t default_mode = S_IRUSR | S_IWUSR | S_IXUSR | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH;
int
ecore_file_mkdir(char *dir)
{
if (mkdir(dir, default_mode) < 0) return 0;
return 1;
}
int
ecore_file_mkpath(char *path)
{
char ss[PATH_MAX];
int i, ii;
ss[0] = 0;
i = 0;
ii = 0;
while (path[i])
{
if (ii == sizeof(ss) - 1) return 0;
ss[ii++] = path[i];
ss[ii] = 0;
if (path[i] == '/')
{
if (!ecore_file_is_dir(ss)) ecore_file_mkdir(ss);
else if (!ecore_file_is_dir(ss)) return 0;
}
i++;
}
if (!ecore_file_is_dir(ss)) ecore_file_mkdir(ss);
else if (!ecore_file_is_dir(ss)) return 0;
return 1;
}
int
ecore_file_cp(char *src, char *dst)
{
FILE *f1, *f2;
char buf[16384];
size_t num;
f1 = fopen(src, "rb");
if (!f1) return 0;
f2 = fopen(dst, "wb");
if (!f2)
{
fclose(f1);
return 0;
}
while ((num = fread(buf, 1, 16384, f1)) > 0) fwrite(buf, 1, num, f2);
fclose(f1);
fclose(f2);
return 1;
}
char *
ecore_file_realpath(char *file)
{
char buf[PATH_MAX];
struct stat st;
if (!realpath(file, buf) || stat(buf, &st)) return strdup("");
return strdup(buf);
}
char *
ecore_file_get_file(char *path)
{
char *result = NULL;
if (!path) return NULL;
if ((result = strrchr(path, '/'))) result++;
else result = path;
return result;
}
char *
ecore_file_get_dir(char *file)
{
char *p;
char buf[PATH_MAX];
strncpy(buf, file, PATH_MAX);
p = strrchr(buf, '/');
if (!p)
{
return strdup(file);
}
*p = 0;
return strdup(buf);
}
int
ecore_file_can_exec(char *file)
{
static int have_uid = 0;
static uid_t uid = -1;
static gid_t gid = -1;
struct stat st;
int ok;
if (!file) return 0;
if (stat(file, &st) < 0) return 0;
ok = 0;
if (!have_uid) uid = getuid();
if (!have_uid) gid = getgid();
have_uid = 1;
if (st.st_uid == uid)
{
if (st.st_mode & S_IXUSR) ok = 1;
}
else if (st.st_gid == gid)
{
if (st.st_mode & S_IXGRP) ok = 1;
}
else
{
if (st.st_mode & S_IXOTH) ok = 1;
}
return(ok);
}
char *
ecore_file_readlink(char *link)
{
char buf[PATH_MAX];
int count;
if ((count = readlink(link, buf, sizeof(buf))) < 0) return NULL;
buf[count] = 0;
return strdup(buf);
}
Evas_List *
ecore_file_ls(char *dir)
{
DIR *dirp;
struct dirent *dp;
Evas_List *list;
dirp = opendir(dir);
if (!dirp) return NULL;
list = NULL;
while ((dp = readdir(dirp)))
{
if ((strcmp(dp->d_name, ".")) && (strcmp(dp->d_name, "..")))
{
Evas_List *l;
char *f;
/* insertion sort */
for (l = list; l; l = l->next)
{
if (strcmp(l->data, dp->d_name) > 0)
{
f = strdup(dp->d_name);
list = evas_list_prepend_relative(list, f, l->data);
break;
}
}
/* nowhwre to go? just append it */
f = strdup(dp->d_name);
if (!l)
list = evas_list_append(list, f);
}
}
closedir(dirp);
return list;
}

View File

@ -0,0 +1,323 @@
/*
* vim:ts=8:sw=3:sts=8:noexpandtab:cino=>5n-3f0^-2{2
*/
#include "ecore_file_private.h"
#include "Ecore_File.h"
/*
* TODO:
* - Check the return value from fcntl.
* - Try different realtime numbers if one fail.
* - Doesn't work right!
* - Misses fileupdates
* - Misses filedeletions
*/
#ifdef HAVE_DNOTIFY
#include <fcntl.h>
typedef struct _Ecore_File_Monitor_Dnotify Ecore_File_Monitor_Dnotify;
typedef struct _Ecore_File Ecore_File;
#define ECORE_FILE_MONITOR_DNOTIFY(x) ((Ecore_File_Monitor_Dnotify *)(x))
struct _Ecore_File_Monitor_Dnotify
{
Ecore_File_Monitor monitor;
int fd;
Evas_List *files;
unsigned char deleted;
};
struct _Ecore_File
{
char *name;
int mtime;
Ecore_File_Type type;
};
static Ecore_Event_Handler *_eh;
static Evas_List *_monitors = NULL;
static int _lock = 0;
static int _ecore_file_monitor_handler(void *data, int type, void *event);
static void _ecore_file_monitor_check(Ecore_File_Monitor *em);
static int _ecore_file_monitor_checking(Ecore_File_Monitor *em, char *path);
int
ecore_file_monitor_init(void)
{
_eh = ecore_event_handler_add(ECORE_EVENT_SIGNAL_REALTIME, _ecore_file_monitor_handler, NULL);
return 1;
}
int
ecore_file_monitor_shutdown(void)
{
Evas_List *l;
if (_eh) ecore_event_handler_del(_eh);
for (l = _monitors; l;)
{
Ecore_File_Monitor *em;
em = l->data;
l = l->next;
ecore_file_monitor_del(em);
}
evas_list_free(_monitors);
return 1;
}
Ecore_File_Monitor *
ecore_file_monitor_add(const char *path,
void (*func) (void *data, Ecore_File_Monitor *em,
Ecore_File_Type type,
Ecore_File_Event event,
const char *path),
void *data)
{
Ecore_File_Monitor *em;
Ecore_File_Monitor_Dnotify *emd;
int len;
if (!path) return NULL;
if (!func) return NULL;
emd = calloc(1, sizeof(Ecore_File_Monitor_Dnotify));
em = ECORE_FILE_MONITOR(emd);
if (!em) return NULL;
em->func = func;
em->data = data;
em->path = strdup(path);
len = strlen(em->path);
if (em->path[len - 1] == '/')
em->path[len - 1] = '\0';
if (ecore_file_exists(em->path))
{
em->type = ecore_file_is_dir(em->path) ?
ECORE_FILE_TYPE_DIRECTORY :
ECORE_FILE_TYPE_FILE;
if (em->type == ECORE_FILE_TYPE_DIRECTORY)
{
/* Check for subdirs */
Evas_List *files, *l;
files = ecore_file_ls(em->path);
for (l = files; l; l = l->next)
{
Ecore_File *f;
char *file;
char buf[PATH_MAX];
file = l->data;
f = calloc(1, sizeof(Ecore_File));
if (!f)
{
free(file);
continue;
}
snprintf(buf, sizeof(buf), "%s/%s", em->path, file);
f->name = file;
f->mtime = ecore_file_mod_time(buf);
f->type = ecore_file_is_dir(buf) ?
ECORE_FILE_TYPE_DIRECTORY :
ECORE_FILE_TYPE_FILE;
em->func(em->data, em, f->type, ECORE_FILE_EVENT_EXISTS, buf);
emd->files = evas_list_append(emd->files, f);
}
evas_list_free(files);
emd->fd = open(em->path, O_RDONLY);
if (fcntl(emd->fd, F_SETSIG, SIGRTMIN + 1))
printf("ERROR: F_SETSIG\n");
if (fcntl(emd->fd, F_NOTIFY, DN_ACCESS|DN_MODIFY|DN_CREATE|DN_DELETE|DN_MULTISHOT))
printf("ERROR: F_NOTIFY\n");
}
else
{
/* TODO: We do not support monitoring files! */
free(em);
return NULL;
}
}
else
{
em->type = ECORE_FILE_TYPE_NONE;
em->func(em->data, em, em->type, ECORE_FILE_EVENT_DELETED, em->path);
}
_monitors = evas_list_append(_monitors, em);
return em;
}
void
ecore_file_monitor_del(Ecore_File_Monitor *em)
{
Ecore_File_Monitor_Dnotify *emd;
Evas_List *l;
emd = ECORE_FILE_MONITOR_DNOTIFY(em);
if (_lock)
{
emd->deleted = 1;
return;
}
close(emd->fd);
/* Remove files */
for (l = emd->files; l; l = l->next)
{
Ecore_File *f;
f = l->data;
free(f->name);
free(f);
}
evas_list_free(emd->files);
_monitors = evas_list_remove(_monitors, em);
free(em->path);
free(em);
}
static int
_ecore_file_monitor_handler(void *data, int type, void *event)
{
Ecore_Event_Signal_Realtime *ev;
Evas_List *monitor;
ev = event;
_lock = 1;
for (monitor = _monitors; monitor;)
{
Ecore_File_Monitor *em;
Ecore_File_Monitor_Dnotify *emd;
em = monitor->data;
emd = ECORE_FILE_MONITOR_DNOTIFY(em);
monitor = monitor->next;
if (emd->fd == ev->data.si_fd)
_ecore_file_monitor_check(em);
}
_lock = 0;
for (monitor = _monitors; monitor;)
{
Ecore_File_Monitor *em;
Ecore_File_Monitor_Dnotify *emd;
em = monitor->data;
emd = ECORE_FILE_MONITOR_DNOTIFY(em);
monitor = monitor->next;
if (emd->deleted)
ecore_file_monitor_del(em);
}
return 1;
}
#if 0
static Ecore_File_Monitor_Request *
_ecore_file_monitor_request_find(Ecore_File_Monitor *em, char *path)
{
Evas_List *l;
for (l = em->requests; l; l = l->next)
{
Ecore_File_Monitor_Request *er;
er = l->data;
if (!strcmp(er->path, path))
return er;
}
return NULL;
}
#endif
static void
_ecore_file_monitor_check(Ecore_File_Monitor *em)
{
Ecore_File_Monitor_Dnotify *emd;
Evas_List *files, *l;
/* Check for changed files */
emd = ECORE_FILE_MONITOR_DNOTIFY(em);
for (l = emd->files; l;)
{
Ecore_File *f;
char buf[PATH_MAX];
int mtime;
f = l->data;
l = l->next;
snprintf(buf, sizeof(buf), "%s/%s", em->path, f->name);
mtime = ecore_file_mod_time(buf);
if (mtime < f->mtime)
{
em->func(em->data, em, f->type, ECORE_FILE_EVENT_DELETED, buf);
emd->files = evas_list_remove(emd->files, f);
free(f->name);
free(f);
}
else if (mtime > f->mtime)
em->func(em->data, em, f->type, ECORE_FILE_EVENT_CHANGED, buf);
f->mtime = mtime;
}
files = ecore_file_ls(em->path);
for (l = files; l; l = l->next)
{
Ecore_File *f;
char *file;
char buf[PATH_MAX];
file = l->data;
if (_ecore_file_monitor_checking(em, file))
{
free(file);
continue;
}
f = calloc(1, sizeof(Ecore_File));
if (!f)
{
free(file);
continue;
}
snprintf(buf, sizeof(buf), "%s/%s", em->path, file);
f->name = file;
f->mtime = ecore_file_mod_time(buf);
f->type = ecore_file_is_dir(buf) ?
ECORE_FILE_TYPE_DIRECTORY :
ECORE_FILE_TYPE_FILE;
em->func(em->data, em, f->type, ECORE_FILE_EVENT_CREATED, buf);
emd->files = evas_list_append(emd->files, f);
}
}
static int
_ecore_file_monitor_checking(Ecore_File_Monitor *em, char *name)
{
Ecore_File_Monitor_Dnotify *emd;
Evas_List *l;
emd = ECORE_FILE_MONITOR_DNOTIFY(em);
for (l = emd->files; l; l = l->next)
{
Ecore_File *f;
f = l->data;
if (!strcmp(f->name, name))
return 1;
}
return 0;
}
#endif

View File

@ -0,0 +1,249 @@
/*
* vim:ts=8:sw=3:sts=8:noexpandtab:cino=>5n-3f0^-2{2
*/
#include "ecore_file_private.h"
#include "Ecore_File.h"
/*
* TODO:
* - When several subdirectories are created really fast, the code
* doesn't keep up! Putting in a random printf() makes it work..
* - Same for deletion of files in deleted directories!
*/
#ifdef HAVE_FAM
#include <fam.h>
typedef struct _Ecore_File_Monitor_Fam Ecore_File_Monitor_Fam;
typedef struct _Ecore_File Ecore_File;
struct _Ecore_File_Monitor_Fam
{
Ecore_File_Monitor monitor;
FAMRequest *request;
Evas_List *files;
};
struct _Ecore_File
{
char *name;
Ecore_File_Type type;
};
#define ECORE_FILE_MONITOR_FAM(x) ((Ecore_File_Monitor_Fam *)(x))
static Ecore_Fd_Handler *_fdh = NULL;
static FAMConnection *_fc = NULL;
static Evas_List *_monitors = NULL;
static int _ecore_file_monitor_handler(void *data, Ecore_Fd_Handler *fdh);
static Ecore_File * _ecore_file_monitor_file_find(Ecore_File_Monitor *em, char *name);
static Ecore_File_Event _ecore_file_monitor_event_get(FAMCodes change);
int
ecore_file_monitor_init(void)
{
_fc = calloc(1, sizeof(FAMConnection));
if (!_fc) return 0;
FAMOpen(_fc);
_fdh = ecore_main_fd_handler_add(FAMCONNECTION_GETFD(_fc), ECORE_FD_READ, _ecore_file_monitor_handler,
NULL, NULL, NULL);
return 1;
}
int
ecore_file_monitor_shutdown(void)
{
Evas_List *l;
for (l = _monitors; l; l = l->next)
ecore_file_monitor_del(ECORE_FILE_MONITOR(l->data));
evas_list_free(_monitors);
if (_fdh) ecore_main_fd_handler_del(_fdh);
if (_fc)
{
FAMClose(_fc);
free(_fc);
}
return 1;
}
Ecore_File_Monitor *
ecore_file_monitor_add(const char *path,
void (*func) (void *data,
Ecore_File_Monitor *em,
Ecore_File_Type type,
Ecore_File_Event event,
const char *path),
void *data)
{
Ecore_File_Monitor *em;
Ecore_File_Monitor_Fam *emf;
int len;
emf = calloc(1, sizeof(Ecore_File_Monitor_Fam));
em = ECORE_FILE_MONITOR(emf);
if (!em) return NULL;
em->func = func;
em->data = data;
_monitors = evas_list_append(_monitors, em);
em->path = strdup(path);
len = strlen(em->path);
if (em->path[len - 1] == '/')
em->path[len - 1] = '\0';
if (ecore_file_exists(em->path))
{
em->type = ecore_file_is_dir(em->path) ?
ECORE_FILE_TYPE_DIRECTORY :
ECORE_FILE_TYPE_FILE;
/* TODO: Check if calloc succeded! */
emf->request = calloc(1, sizeof(FAMRequest));
if (em->type == ECORE_FILE_TYPE_DIRECTORY)
{
FAMMonitorDirectory(_fc, em->path, emf->request, em);
}
else
{
FAMMonitorFile(_fc, em->path, emf->request, em);
em->func(em->data, em, em->type, ECORE_FILE_EVENT_EXISTS, em->path);
}
}
else
{
em->type = ECORE_FILE_TYPE_NONE;
em->func(em->data, em, em->type, ECORE_FILE_EVENT_DELETED, em->path);
}
return em;
}
void
ecore_file_monitor_del(Ecore_File_Monitor *em)
{
Ecore_File_Monitor_Fam *emf;
Evas_List *l;
emf = ECORE_FILE_MONITOR_FAM(em);
for (l = emf->files; l; l = l->next)
{
Ecore_File *f;
f = l->data;
free(f->name);
free(f);
}
evas_list_free(emf->files);
_monitors = evas_list_remove(_monitors, em);
FAMCancelMonitor(_fc, emf->request);
free(emf->request);
free(em->path);
free(em);
}
static int
_ecore_file_monitor_handler(void *data, Ecore_Fd_Handler *fdh)
{
int pending, i;
while ((pending = FAMPending(_fc)))
{
for (i = 0; i < pending; i++)
{
Ecore_File_Monitor *em;
Ecore_File_Monitor_Fam *emf;
FAMEvent fe;
Ecore_File_Event event;
char buf[PATH_MAX];
FAMNextEvent(_fc, &fe);
event = _ecore_file_monitor_event_get(fe.code);
em = fe.userdata;
emf = ECORE_FILE_MONITOR_FAM(em);
if (!em) continue;
if (event == ECORE_FILE_EVENT_NONE) continue;
if ((em->type == ECORE_FILE_TYPE_DIRECTORY)
&& !strcmp(em->path, fe.filename))
continue;
/* Create path */
snprintf(buf, sizeof(buf), "%s/%s", em->path, fe.filename);
if (event == ECORE_FILE_EVENT_DELETED)
{
Ecore_File *f;
f = _ecore_file_monitor_file_find(em, fe.filename);
if (f)
{
emf->files = evas_list_remove(emf->files, f);
em->func(em->data, em, f->type, event, buf);
free(f->name);
free(f);
}
}
else
{
Ecore_File *f;
f = calloc(1, sizeof(Ecore_File));
if (!f) continue;
f->type = ecore_file_is_dir(buf) ?
ECORE_FILE_TYPE_DIRECTORY :
ECORE_FILE_TYPE_FILE;
f->name = strdup(fe.filename);
emf->files = evas_list_append(emf->files, f);
em->func(em->data, em, f->type, event, buf);
}
}
}
return 1;
}
static Ecore_File *
_ecore_file_monitor_file_find(Ecore_File_Monitor *em, char *name)
{
Ecore_File_Monitor_Fam *emf;
Evas_List *l;
emf = ECORE_FILE_MONITOR_FAM(em);
for (l = emf->files; l; l = l->next)
{
Ecore_File *f;
f = l->data;
if (!strcmp(f->name, name))
return f;
}
return NULL;
}
static Ecore_File_Event
_ecore_file_monitor_event_get(FAMCodes code)
{
switch (code)
{
case FAMCreated:
return ECORE_FILE_EVENT_CREATED;
case FAMDeleted:
return ECORE_FILE_EVENT_DELETED;
case FAMChanged:
return ECORE_FILE_EVENT_CHANGED;
case FAMExists:
return ECORE_FILE_EVENT_EXISTS;
case FAMStartExecuting:
case FAMStopExecuting:
case FAMMoved:
case FAMAcknowledge:
case FAMEndExist:
return ECORE_FILE_EVENT_NONE;
}
return ECORE_FILE_EVENT_NONE;
}
#endif

View File

@ -0,0 +1,317 @@
/*
* vim:ts=8:sw=3:sts=8:noexpandtab:cino=>5n-3f0^-2{2
*/
#include "ecore_file_private.h"
#include "Ecore_File.h"
/*
* TODO:
* - Everything!
*/
#ifdef HAVE_INOTIFY
typedef struct _Ecore_File_Monitor_Inotify Ecore_File_Monitor_Inotify;
typedef struct _Ecore_File Ecore_File;
#define ECORE_FILE_MONITOR_INOTIFY(x) ((Ecore_File_Monitor_Inotify *)(x))
struct _Ecore_File_Monitor_Inotify
{
Ecore_File_Monitor monitor;
int fd;
Evas_List *files;
unsigned char deleted;
};
struct _Ecore_File
{
char *name;
int mtime;
Ecore_File_Type type;
};
static Ecore_Event_Handler *_eh;
static Evas_List *_monitors = NULL;
static int _lock = 0;
static int _ecore_file_monitor_handler(void *data, int type, void *event);
static void _ecore_file_monitor_check(Ecore_File_Monitor *em);
static int _ecore_file_monitor_checking(Ecore_File_Monitor *em, char *path);
int
ecore_file_monitor_init(void)
{
_eh = ecore_event_handler_add(ECORE_EVENT_SIGNAL_REALTIME, _ecore_file_monitor_handler, NULL);
return 1;
}
int
ecore_file_monitor_shutdown(void)
{
Evas_List *l;
if (_eh) ecore_event_handler_del(_eh);
for (l = _monitors; l;)
{
Ecore_File_Monitor *em;
em = l->data;
l = l->next;
ecore_file_monitor_del(em);
}
evas_list_free(_monitors);
return 1;
}
Ecore_File_Monitor *
ecore_file_monitor_add(const char *path,
void (*func) (void *data, Ecore_File_Monitor *em,
Ecore_File_Type type,
Ecore_File_Event event,
const char *path),
void *data)
{
Ecore_File_Monitor *em;
Ecore_File_Monitor_Inotify *emd;
int len;
if (!path) return NULL;
if (!func) return NULL;
emd = calloc(1, sizeof(Ecore_File_Monitor_Inotify));
em = ECORE_FILE_MONITOR(emd);
if (!em) return NULL;
em->func = func;
em->data = data;
em->path = strdup(path);
len = strlen(em->path);
if (em->path[len - 1] == '/')
em->path[len - 1] = '\0';
if (ecore_file_exists(em->path))
{
em->type = ecore_file_is_dir(em->path) ?
ECORE_FILE_TYPE_DIRECTORY :
ECORE_FILE_TYPE_FILE;
if (em->type == ECORE_FILE_TYPE_DIRECTORY)
{
/* Check for subdirs */
Evas_List *files, *l;
files = ecore_file_ls(em->path);
for (l = files; l; l = l->next)
{
Ecore_File *f;
char *file;
char buf[PATH_MAX];
file = l->data;
f = calloc(1, sizeof(Ecore_File));
if (!f)
{
free(file);
continue;
}
snprintf(buf, sizeof(buf), "%s/%s", em->path, file);
f->name = file;
f->mtime = ecore_file_mod_time(buf);
f->type = ecore_file_is_dir(buf) ?
ECORE_FILE_TYPE_DIRECTORY :
ECORE_FILE_TYPE_FILE;
em->func(em->data, em, f->type, ECORE_FILE_EVENT_EXISTS, buf);
emd->files = evas_list_append(emd->files, f);
}
evas_list_free(files);
emd->fd = open(em->path, O_RDONLY);
if (fcntl(emd->fd, F_SETSIG, SIGRTMIN + 1))
printf("ERROR: F_SETSIG\n");
if (fcntl(emd->fd, F_NOTIFY, DN_ACCESS|DN_MODIFY|DN_CREATE|DN_DELETE|DN_MULTISHOT))
printf("ERROR: F_NOTIFY\n");
}
else
{
/* TODO: We do not support monitoring files! */
free(em);
return NULL;
}
}
else
{
em->type = ECORE_FILE_TYPE_NONE;
em->func(em->data, em, em->type, ECORE_FILE_EVENT_DELETED, em->path);
}
_monitors = evas_list_append(_monitors, em);
return em;
}
void
ecore_file_monitor_del(Ecore_File_Monitor *em)
{
Ecore_File_Monitor_Inotify *emd;
Evas_List *l;
emd = ECORE_FILE_MONITOR_INOTIFY(em);
if (_lock)
{
emd->deleted = 1;
return;
}
close(emd->fd);
/* Remove files */
for (l = emd->files; l; l = l->next)
{
Ecore_File *f;
f = l->data;
free(f->name);
free(f);
}
evas_list_free(emd->files);
_monitors = evas_list_remove(_monitors, em);
free(em->path);
free(em);
}
static int
_ecore_file_monitor_handler(void *data, int type, void *event)
{
Ecore_Event_Signal_Realtime *ev;
Evas_List *monitor;
ev = event;
_lock = 1;
for (monitor = _monitors; monitor;)
{
Ecore_File_Monitor *em;
Ecore_File_Monitor_Inotify *emd;
em = monitor->data;
emd = ECORE_FILE_MONITOR_INOTIFY(em);
monitor = monitor->next;
if (emd->fd == ev->data.si_fd)
_ecore_file_monitor_check(em);
}
_lock = 0;
for (monitor = _monitors; monitor;)
{
Ecore_File_Monitor *em;
Ecore_File_Monitor_Inotify *emd;
em = monitor->data;
emd = ECORE_FILE_MONITOR_INOTIFY(em);
monitor = monitor->next;
if (emd->deleted)
ecore_file_monitor_del(em);
}
return 1;
}
#if 0
static Ecore_File_Monitor_Request *
_ecore_file_monitor_request_find(Ecore_File_Monitor *em, char *path)
{
Evas_List *l;
for (l = em->requests; l; l = l->next)
{
Ecore_File_Monitor_Request *er;
er = l->data;
if (!strcmp(er->path, path))
return er;
}
return NULL;
}
#endif
static void
_ecore_file_monitor_check(Ecore_File_Monitor *em)
{
Ecore_File_Monitor_Inotify *emd;
Evas_List *files, *l;
/* Check for changed files */
emd = ECORE_FILE_MONITOR_INOTIFY(em);
for (l = emd->files; l;)
{
Ecore_File *f;
char buf[PATH_MAX];
int mtime;
f = l->data;
l = l->next;
snprintf(buf, sizeof(buf), "%s/%s", em->path, f->name);
mtime = ecore_file_mod_time(buf);
if (mtime < f->mtime)
{
em->func(em->data, em, f->type, ECORE_FILE_EVENT_DELETED, buf);
emd->files = evas_list_remove(emd->files, f);
free(f->name);
free(f);
}
else if (mtime > f->mtime)
em->func(em->data, em, f->type, ECORE_FILE_EVENT_CHANGED, buf);
f->mtime = mtime;
}
files = ecore_file_ls(em->path);
for (l = files; l; l = l->next)
{
Ecore_File *f;
char *file;
char buf[PATH_MAX];
file = l->data;
if (_ecore_file_monitor_checking(em, file))
{
free(file);
continue;
}
f = calloc(1, sizeof(Ecore_File));
if (!f)
{
free(file);
continue;
}
snprintf(buf, sizeof(buf), "%s/%s", em->path, file);
f->name = file;
f->mtime = ecore_file_mod_time(buf);
f->type = ecore_file_is_dir(buf) ?
ECORE_FILE_TYPE_DIRECTORY :
ECORE_FILE_TYPE_FILE;
em->func(em->data, em, f->type, ECORE_FILE_EVENT_CREATED, buf);
emd->files = evas_list_append(emd->files, f);
}
}
static int
_ecore_file_monitor_checking(Ecore_File_Monitor *em, char *name)
{
Ecore_File_Monitor_Inotify *emd;
Evas_List *l;
emd = ECORE_FILE_MONITOR_INOTIFY(em);
for (l = emd->files; l; l = l->next)
{
Ecore_File *f;
f = l->data;
if (!strcmp(f->name, name))
return 1;
}
return 0;
}
#endif

View File

@ -0,0 +1,397 @@
/*
* vim:ts=8:sw=3:sts=8:noexpandtab:cino=>5n-3f0^-2{2
*/
#include "ecore_file_private.h"
#include "Ecore_File.h"
#ifdef HAVE_POLL
/*
* TODO:
* - Implement recursive as an option!
* - Keep whole path or just name of file? (Memory or CPU...)
* - Remove requests without files?
*/
typedef struct _Ecore_File_Monitor_Poll Ecore_File_Monitor_Poll;
typedef struct _Ecore_File Ecore_File;
#define ECORE_FILE_MONITOR_POLL(x) ((Ecore_File_Monitor_Poll *)(x))
struct _Ecore_File_Monitor_Poll
{
Ecore_File_Monitor monitor;
int mtime;
Evas_List *files;
unsigned char deleted;
};
struct _Ecore_File
{
char *name;
int mtime;
Ecore_File_Type type;
};
static Ecore_Timer *_timer = NULL;
static Evas_List *_monitors = NULL;
static int _lock = 0;
static int _ecore_file_monitor_handler(void *data);
static void _ecore_file_monitor_check(Ecore_File_Monitor *em);
static int _ecore_file_monitor_checking(Ecore_File_Monitor *em, char *name);
int
ecore_file_monitor_init(void)
{
return 1;
}
int
ecore_file_monitor_shutdown(void)
{
Evas_List *l;
for (l = _monitors; l;)
{
Ecore_File_Monitor *em;
em = l->data;
l = l->next;
ecore_file_monitor_del(em);
}
evas_list_free(_monitors);
if (_timer)
{
ecore_timer_del(_timer);
_timer = NULL;
}
return 1;
}
Ecore_File_Monitor *
ecore_file_monitor_add(const char *path,
void (*func) (void *data, Ecore_File_Monitor *em,
Ecore_File_Type type,
Ecore_File_Event event,
const char *path),
void *data)
{
Ecore_File_Monitor *em;
Ecore_File_Monitor_Poll *emf;
int len;
if (!path) return NULL;
if (!func) return NULL;
emf = calloc(1, sizeof(Ecore_File_Monitor_Poll));
em = ECORE_FILE_MONITOR(emf);
if (!em) return NULL;
if (!_timer)
_timer = ecore_timer_add(1.0, _ecore_file_monitor_handler, NULL);
em->path = strdup(path);
len = strlen(em->path);
if (em->path[len - 1] == '/')
em->path[len - 1] = '\0';
em->func = func;
em->data = data;
emf->mtime = ecore_file_mod_time(em->path);
if (ecore_file_exists(em->path))
{
em->type = ecore_file_is_dir(em->path) ?
ECORE_FILE_TYPE_DIRECTORY :
ECORE_FILE_TYPE_FILE;
#if 0
em->func(em->data, em, em->type, ECORE_FILE_EVENT_EXISTS, em->path);
#endif
if (em->type == ECORE_FILE_TYPE_DIRECTORY)
{
/* Check for subdirs */
Evas_List *files, *l;
files = ecore_file_ls(em->path);
for (l = files; l; l = l->next)
{
Ecore_File *f;
char *file;
char buf[PATH_MAX];
file = l->data;
f = calloc(1, sizeof(Ecore_File));
if (!f)
{
free(file);
continue;
}
snprintf(buf, sizeof(buf), "%s/%s", em->path, file);
f->name = file;
f->mtime = ecore_file_mod_time(buf);
f->type = ecore_file_is_dir(buf) ?
ECORE_FILE_TYPE_DIRECTORY :
ECORE_FILE_TYPE_FILE;
em->func(em->data, em, f->type, ECORE_FILE_EVENT_EXISTS, buf);
emf->files = evas_list_append(emf->files, f);
}
evas_list_free(files);
}
else
em->func(em->data, em, em->type, ECORE_FILE_EVENT_EXISTS, em->path);
}
else
{
em->type = ECORE_FILE_TYPE_NONE;
em->func(em->data, em, em->type, ECORE_FILE_EVENT_DELETED, em->path);
}
_monitors = evas_list_append(_monitors, em);
return em;
}
void
ecore_file_monitor_del(Ecore_File_Monitor *em)
{
Ecore_File_Monitor_Poll *emf;
Evas_List *l;
emf = ECORE_FILE_MONITOR_POLL(em);
if (_lock)
{
emf->deleted = 1;
return;
}
/* Remove files */
for (l = emf->files; l; l = l->next)
{
Ecore_File *f;
f = l->data;
free(f->name);
free(f);
}
evas_list_free(emf->files);
_monitors = evas_list_remove(_monitors, em);
free(em->path);
free(em);
if ((!_monitors) && (_timer))
{
ecore_timer_del(_timer);
_timer = NULL;
}
}
static int
_ecore_file_monitor_handler(void *data)
{
Evas_List *monitor;
_lock = 1;
for (monitor = _monitors; monitor;)
{
Ecore_File_Monitor *em;
em = monitor->data;
monitor = monitor->next;
_ecore_file_monitor_check(em);
}
_lock = 0;
for (monitor = _monitors; monitor;)
{
Ecore_File_Monitor *em;
Ecore_File_Monitor_Poll *emf;
em = monitor->data;
emf = ECORE_FILE_MONITOR_POLL(em);
monitor = monitor->next;
if (emf->deleted)
ecore_file_monitor_del(em);
}
return 1;
}
static void
_ecore_file_monitor_check(Ecore_File_Monitor *em)
{
Ecore_File_Monitor_Poll *emf;
int mtime;
emf = ECORE_FILE_MONITOR_POLL(em);
mtime = ecore_file_mod_time(em->path);
switch (em->type)
{
case ECORE_FILE_TYPE_FILE:
if (mtime < emf->mtime)
{
em->func(em->data, em, em->type, ECORE_FILE_EVENT_DELETED, em->path);
em->type = ECORE_FILE_TYPE_NONE;
}
else if (mtime > emf->mtime)
em->func(em->data, em, em->type, ECORE_FILE_EVENT_CHANGED, em->path);
break;
case ECORE_FILE_TYPE_DIRECTORY:
if (mtime < emf->mtime)
{
/* Deleted */
Evas_List *l;
/* Notify all files deleted */
for (l = emf->files; l;)
{
Ecore_File *f;
char buf[PATH_MAX];
f = l->data;
l = l->next;
snprintf(buf, sizeof(buf), "%s/%s", em->path, f->name);
em->func(em->data, em, f->type, ECORE_FILE_EVENT_DELETED, buf);
free(f->name);
free(f);
}
emf->files = evas_list_free(emf->files);
#if 0
em->func(em->data, em, em->type, ECORE_FILE_EVENT_DELETED, em->path);
#endif
em->type = ECORE_FILE_TYPE_NONE;
}
else
{
Evas_List *l;
/* Check for changed files */
for (l = emf->files; l;)
{
Ecore_File *f;
char buf[PATH_MAX];
int mtime;
f = l->data;
l = l->next;
snprintf(buf, sizeof(buf), "%s/%s", em->path, f->name);
mtime = ecore_file_mod_time(buf);
if (mtime < f->mtime)
{
em->func(em->data, em, f->type, ECORE_FILE_EVENT_DELETED, buf);
emf->files = evas_list_remove(emf->files, f);
free(f->name);
free(f);
}
else if (mtime > f->mtime)
em->func(em->data, em, f->type, ECORE_FILE_EVENT_CHANGED, buf);
f->mtime = mtime;
}
/* Check for new files */
if (emf->mtime < mtime)
{
Evas_List *files;
/* Files have been added or removed */
#if 0
em->func(em->data, em, em->type, ECORE_FILE_EVENT_CHANGED, em->path);
#endif
files = ecore_file_ls(em->path);
for (l = files; l; l = l->next)
{
Ecore_File *f;
char *file;
char buf[PATH_MAX];
file = l->data;
if (_ecore_file_monitor_checking(em, file))
{
free(file);
continue;
}
snprintf(buf, sizeof(buf), "%s/%s", em->path, file);
f = calloc(1, sizeof(Ecore_File));
if (!f)
{
free(file);
continue;
}
f->name = file;
f->mtime = ecore_file_mod_time(buf);
f->type = ecore_file_is_dir(buf) ?
ECORE_FILE_TYPE_DIRECTORY :
ECORE_FILE_TYPE_FILE;
em->func(em->data, em, f->type, ECORE_FILE_EVENT_CREATED, buf);
emf->files = evas_list_append(emf->files, f);
}
}
}
break;
case ECORE_FILE_TYPE_NONE:
if (mtime > emf->mtime)
{
/* Something has been created! */
em->type = ecore_file_is_dir(em->path) ?
ECORE_FILE_TYPE_DIRECTORY :
ECORE_FILE_TYPE_FILE;
em->func(em->data, em, em->type, ECORE_FILE_EVENT_CREATED, em->path);
if (em->type == ECORE_FILE_TYPE_DIRECTORY)
{
/* Check for subdirs */
Evas_List *files, *l;
em->func(em->data, em, em->type, ECORE_FILE_EVENT_CREATED, em->path);
files = ecore_file_ls(em->path);
for (l = files; l; l = l->next)
{
Ecore_File *f;
char *file;
char buf[PATH_MAX];
file = l->data;
snprintf(buf, sizeof(buf), "%s/%s", em->path, file);
f = calloc(1, sizeof(Ecore_File));
if (!f)
{
free(file);
continue;
}
f->name = file;
f->mtime = ecore_file_mod_time(buf);
f->type = ecore_file_is_dir(buf) ?
ECORE_FILE_TYPE_DIRECTORY :
ECORE_FILE_TYPE_FILE;
em->func(em->data, em, f->type, ECORE_FILE_EVENT_CREATED, buf);
emf->files = evas_list_append(emf->files, f);
}
evas_list_free(files);
}
}
break;
}
emf->mtime = mtime;
}
static int
_ecore_file_monitor_checking(Ecore_File_Monitor *em, char *name)
{
Evas_List *l;
Ecore_File_Monitor_Poll *emf;
emf = ECORE_FILE_MONITOR_POLL(em);
for (l = emf->files; l; l = l->next)
{
Ecore_File *f;
f = l->data;
if (!strcmp(f->name, name))
return 1;
}
return 0;
}
#endif

View File

@ -0,0 +1,25 @@
#define _GNU_SOURCE
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <dirent.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <limits.h>
#include "config.h"
#include "Ecore.h"
int ecore_file_monitor_init(void);
int ecore_file_monitor_shutdown(void);
/*
#define HAVE_POLL
#define HAVE_FAM
#define HAVE_DNOTIFY
#define HAVE_INOTIFY
*/

View File

@ -0,0 +1,4 @@
void
_ecore_file_add_slash(char *path)
{
}