2011-04-25 10:04:46 -07:00
|
|
|
/* EIO - EFL data type library
|
|
|
|
* Copyright (C) 2011 Enlightenment Developers:
|
|
|
|
* Cedric Bail <cedric.bail@free.fr>
|
|
|
|
*
|
|
|
|
* This library is free software; you can redistribute it and/or
|
|
|
|
* modify it under the terms of the GNU Lesser General Public
|
|
|
|
* License as published by the Free Software Foundation; either
|
|
|
|
* version 2.1 of the License, or (at your option) any later version.
|
|
|
|
*
|
|
|
|
* This library is distributed in the hope that it will be useful,
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
|
|
* Lesser General Public License for more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU Lesser General Public
|
|
|
|
* License along with this library;
|
|
|
|
* if not, see <http://www.gnu.org/licenses/>.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include "eio_private.h"
|
|
|
|
#include "Eio.h"
|
|
|
|
|
2012-12-06 05:02:59 -08:00
|
|
|
#ifdef HAVE_SYS_INOTIFY_H
|
2011-04-25 10:04:46 -07:00
|
|
|
# include <sys/inotify.h>
|
|
|
|
#endif
|
|
|
|
|
2012-03-31 00:01:24 -07:00
|
|
|
/*============================================================================*
|
|
|
|
* Local *
|
|
|
|
*============================================================================*/
|
2011-04-25 10:04:46 -07:00
|
|
|
|
2012-03-31 00:01:24 -07:00
|
|
|
/**
|
|
|
|
* @cond LOCAL
|
|
|
|
*/
|
2011-04-25 10:04:46 -07:00
|
|
|
|
2011-04-27 03:27:07 -07:00
|
|
|
typedef struct _Eio_Inotify_Table Eio_Inotify_Table;
|
2012-03-31 00:01:24 -07:00
|
|
|
|
2011-04-27 03:27:07 -07:00
|
|
|
struct _Eio_Inotify_Table
|
|
|
|
{
|
|
|
|
int mask;
|
|
|
|
int *ev_file_code;
|
|
|
|
int *ev_dir_code;
|
|
|
|
};
|
|
|
|
|
2012-03-31 00:01:24 -07:00
|
|
|
struct _Eio_Monitor_Backend
|
|
|
|
{
|
|
|
|
Eio_Monitor *parent;
|
|
|
|
|
|
|
|
int hwnd;
|
|
|
|
};
|
|
|
|
|
|
|
|
static Ecore_Fd_Handler *_inotify_fdh = NULL;
|
|
|
|
static Eina_Hash *_inotify_monitors = NULL;
|
|
|
|
|
2011-04-27 03:27:07 -07:00
|
|
|
#define EIO_INOTIFY_LINE(Ino, Ef, Ed) \
|
|
|
|
{ Ino, &EIO_MONITOR_##Ef, &EIO_MONITOR_##Ed }
|
|
|
|
|
|
|
|
static const Eio_Inotify_Table match[] = {
|
|
|
|
EIO_INOTIFY_LINE(IN_ATTRIB, FILE_MODIFIED, DIRECTORY_MODIFIED),
|
|
|
|
EIO_INOTIFY_LINE(IN_CLOSE_WRITE, FILE_CLOSED, DIRECTORY_CLOSED),
|
|
|
|
EIO_INOTIFY_LINE(IN_MODIFY, FILE_MODIFIED, DIRECTORY_MODIFIED),
|
|
|
|
EIO_INOTIFY_LINE(IN_MOVED_FROM, FILE_DELETED, DIRECTORY_DELETED),
|
|
|
|
EIO_INOTIFY_LINE(IN_MOVED_TO, FILE_CREATED, DIRECTORY_CREATED),
|
|
|
|
EIO_INOTIFY_LINE(IN_DELETE, FILE_DELETED, DIRECTORY_DELETED),
|
|
|
|
EIO_INOTIFY_LINE(IN_CREATE, FILE_CREATED, DIRECTORY_CREATED),
|
|
|
|
EIO_INOTIFY_LINE(IN_DELETE_SELF, SELF_DELETED, SELF_DELETED),
|
|
|
|
EIO_INOTIFY_LINE(IN_MOVE_SELF, SELF_DELETED, SELF_DELETED),
|
|
|
|
EIO_INOTIFY_LINE(IN_UNMOUNT, SELF_DELETED, SELF_DELETED)
|
|
|
|
};
|
|
|
|
|
2012-03-31 00:01:24 -07:00
|
|
|
static void
|
|
|
|
_eio_inotify_del(void *data)
|
|
|
|
{
|
|
|
|
Eio_Monitor_Backend *emb = data;
|
|
|
|
int fd;
|
|
|
|
|
|
|
|
if (emb->hwnd)
|
|
|
|
{
|
|
|
|
fd = ecore_main_fd_handler_fd_get(_inotify_fdh);
|
|
|
|
inotify_rm_watch(fd, emb->hwnd);
|
|
|
|
emb->hwnd = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
free(emb);
|
|
|
|
}
|
|
|
|
|
2011-04-27 03:27:07 -07:00
|
|
|
static void
|
|
|
|
_eio_inotify_events(Eio_Monitor_Backend *backend, const char *file, int mask)
|
|
|
|
{
|
|
|
|
char *tmp;
|
|
|
|
unsigned int length;
|
|
|
|
unsigned int tmp_length;
|
|
|
|
unsigned int i;
|
|
|
|
Eina_Bool is_dir;
|
|
|
|
|
2014-01-13 20:33:16 -08:00
|
|
|
if (backend->parent->delete_me)
|
|
|
|
return;
|
|
|
|
|
2011-04-27 03:27:07 -07:00
|
|
|
length = file ? strlen(file) : 0;
|
|
|
|
tmp_length = eina_stringshare_strlen(backend->parent->path) + length + 2;
|
|
|
|
tmp = alloca(sizeof (char) * tmp_length);
|
|
|
|
|
2013-01-20 16:22:35 -08:00
|
|
|
if (length > 0)
|
|
|
|
snprintf(tmp, tmp_length, "%s/%s", backend->parent->path, file);
|
|
|
|
else
|
|
|
|
snprintf(tmp, tmp_length, "%s", backend->parent->path);
|
|
|
|
|
2011-04-27 03:27:07 -07:00
|
|
|
|
|
|
|
is_dir = !!(mask & IN_ISDIR);
|
|
|
|
|
|
|
|
for (i = 0; i < sizeof (match) / sizeof (Eio_Inotify_Table); ++i)
|
|
|
|
if (match[i].mask & mask)
|
|
|
|
{
|
|
|
|
_eio_monitor_send(backend->parent, tmp, is_dir ? *match[i].ev_dir_code : *match[i].ev_file_code);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* special case for IN_IGNORED */
|
|
|
|
if (mask & IN_IGNORED)
|
|
|
|
{
|
|
|
|
_eio_monitor_rename(backend->parent, tmp);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-04-25 10:04:46 -07:00
|
|
|
static Eina_Bool
|
2012-12-04 09:40:58 -08:00
|
|
|
_eio_inotify_handler(void *data EINA_UNUSED, Ecore_Fd_Handler *fdh)
|
2011-04-25 10:04:46 -07:00
|
|
|
{
|
2011-04-27 03:27:07 -07:00
|
|
|
Eio_Monitor_Backend *backend;
|
|
|
|
unsigned char buffer[16384];
|
|
|
|
struct inotify_event *event;
|
2013-08-05 03:24:11 -07:00
|
|
|
int i = 0, fd;
|
2011-04-27 03:27:07 -07:00
|
|
|
int event_size;
|
|
|
|
ssize_t size;
|
|
|
|
|
2013-08-05 03:24:11 -07:00
|
|
|
fd = ecore_main_fd_handler_fd_get(fdh);
|
|
|
|
if (fd < 0) return ECORE_CALLBACK_RENEW;
|
|
|
|
|
|
|
|
size = read(fd, buffer, sizeof(buffer));
|
2014-10-27 06:57:53 -07:00
|
|
|
while ((i + (int) sizeof(struct inotify_event)) <= (int) size)
|
2011-04-27 03:27:07 -07:00
|
|
|
{
|
|
|
|
event = (struct inotify_event *)&buffer[i];
|
|
|
|
event_size = sizeof(struct inotify_event) + event->len;
|
2014-10-27 06:57:53 -07:00
|
|
|
if ((event_size + i) > size) break ;
|
2011-04-27 03:27:07 -07:00
|
|
|
i += event_size;
|
|
|
|
|
2016-07-15 17:02:03 -07:00
|
|
|
// No need to waste time looking up for just destroyed handler
|
|
|
|
if ((event->mask & IN_IGNORED)) continue ;
|
|
|
|
|
2011-04-27 03:27:07 -07:00
|
|
|
backend = eina_hash_find(_inotify_monitors, &event->wd);
|
|
|
|
if (!backend) continue ;
|
|
|
|
if (!backend->parent) continue ;
|
|
|
|
|
|
|
|
_eio_inotify_events(backend, (event->len ? event->name : NULL), event->mask);
|
|
|
|
}
|
|
|
|
|
|
|
|
return ECORE_CALLBACK_RENEW;
|
2011-04-25 10:04:46 -07:00
|
|
|
}
|
|
|
|
|
2012-03-31 00:01:24 -07:00
|
|
|
/**
|
|
|
|
* @endcond
|
|
|
|
*/
|
2018-02-02 13:59:56 -08:00
|
|
|
static Eina_Bool reseting;
|
|
|
|
static void
|
|
|
|
_eio_monitor_reset()
|
|
|
|
{
|
|
|
|
Eina_Hash *h = _inotify_monitors;
|
|
|
|
Eina_Iterator *it;
|
|
|
|
Eio_Monitor_Backend *backend;
|
2012-03-31 00:01:24 -07:00
|
|
|
|
2018-02-02 13:59:56 -08:00
|
|
|
_inotify_monitors = NULL;
|
|
|
|
reseting = 1;
|
|
|
|
eio_monitor_backend_shutdown();
|
|
|
|
eio_monitor_backend_init();
|
|
|
|
it = eina_hash_iterator_data_new(h);
|
|
|
|
EINA_ITERATOR_FOREACH(it, backend)
|
|
|
|
eio_monitor_backend_add(backend->parent);
|
|
|
|
reseting = 0;
|
|
|
|
eina_iterator_free(it);
|
|
|
|
eina_hash_free(h);
|
|
|
|
}
|
2012-03-31 00:01:24 -07:00
|
|
|
/*============================================================================*
|
|
|
|
* Global *
|
|
|
|
*============================================================================*/
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @cond LOCAL
|
|
|
|
*/
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @endcond
|
|
|
|
*/
|
|
|
|
|
2011-04-25 10:04:46 -07:00
|
|
|
void eio_monitor_backend_init(void)
|
|
|
|
{
|
|
|
|
int fd;
|
|
|
|
|
|
|
|
fd = inotify_init();
|
|
|
|
if (fd < 0)
|
2013-06-20 04:28:18 -07:00
|
|
|
return;
|
2011-04-25 10:04:46 -07:00
|
|
|
|
2017-04-18 16:56:40 -07:00
|
|
|
eina_file_close_on_exec(fd, EINA_TRUE);
|
2012-12-07 03:01:41 -08:00
|
|
|
|
2011-04-25 10:04:46 -07:00
|
|
|
_inotify_fdh = ecore_main_fd_handler_add(fd, ECORE_FD_READ, _eio_inotify_handler, NULL, NULL, NULL);
|
|
|
|
if (!_inotify_fdh)
|
|
|
|
{
|
|
|
|
close(fd);
|
2013-06-20 04:28:18 -07:00
|
|
|
return;
|
2011-04-25 10:04:46 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
_inotify_monitors = eina_hash_int32_new(_eio_inotify_del);
|
2018-02-02 13:59:56 -08:00
|
|
|
if (!reseting)
|
|
|
|
ecore_fork_reset_callback_add(_eio_monitor_reset, NULL);
|
2011-04-25 10:04:46 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
void eio_monitor_backend_shutdown(void)
|
|
|
|
{
|
|
|
|
int fd;
|
|
|
|
|
2013-06-20 04:28:18 -07:00
|
|
|
if (!_inotify_fdh) return;
|
2011-04-25 10:04:46 -07:00
|
|
|
|
|
|
|
eina_hash_free(_inotify_monitors);
|
|
|
|
|
|
|
|
fd = ecore_main_fd_handler_fd_get(_inotify_fdh);
|
|
|
|
ecore_main_fd_handler_del(_inotify_fdh);
|
|
|
|
_inotify_fdh = NULL;
|
|
|
|
|
2013-08-05 02:56:37 -07:00
|
|
|
if (fd < 0)
|
|
|
|
return;
|
|
|
|
|
2011-04-25 10:04:46 -07:00
|
|
|
close(fd);
|
2018-02-02 13:59:56 -08:00
|
|
|
if (!reseting)
|
|
|
|
ecore_fork_reset_callback_del(_eio_monitor_reset, NULL);
|
2011-04-25 10:04:46 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
void eio_monitor_backend_add(Eio_Monitor *monitor)
|
|
|
|
{
|
|
|
|
Eio_Monitor_Backend *backend;
|
|
|
|
int mask =
|
|
|
|
IN_ATTRIB |
|
|
|
|
IN_CLOSE_WRITE |
|
|
|
|
IN_MOVED_FROM |
|
|
|
|
IN_MOVED_TO |
|
|
|
|
IN_DELETE |
|
|
|
|
IN_CREATE |
|
|
|
|
IN_MODIFY |
|
|
|
|
IN_DELETE_SELF |
|
|
|
|
IN_MOVE_SELF |
|
|
|
|
IN_UNMOUNT;
|
|
|
|
|
|
|
|
if (!_inotify_fdh)
|
2012-04-02 09:31:50 -07:00
|
|
|
{
|
|
|
|
eio_monitor_fallback_add(monitor);
|
|
|
|
return;
|
|
|
|
}
|
2011-04-25 10:04:46 -07:00
|
|
|
|
|
|
|
backend = calloc(1, sizeof (Eio_Monitor_Backend));
|
2012-04-02 09:31:50 -07:00
|
|
|
if (!backend)
|
|
|
|
{
|
|
|
|
eio_monitor_fallback_add(monitor);
|
|
|
|
return;
|
|
|
|
}
|
2011-04-25 10:04:46 -07:00
|
|
|
|
|
|
|
backend->parent = monitor;
|
|
|
|
backend->hwnd = inotify_add_watch(ecore_main_fd_handler_fd_get(_inotify_fdh), monitor->path, mask);
|
2016-07-15 17:04:21 -07:00
|
|
|
if (backend->hwnd < 0)
|
2012-04-02 09:31:50 -07:00
|
|
|
{
|
2016-07-15 17:04:21 -07:00
|
|
|
if (errno != EACCES)
|
|
|
|
eio_monitor_fallback_add(monitor);
|
|
|
|
|
2012-04-02 09:31:50 -07:00
|
|
|
free(backend);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2012-02-27 05:20:05 -08:00
|
|
|
monitor->backend = backend;
|
2012-01-24 08:00:57 -08:00
|
|
|
|
|
|
|
eina_hash_direct_add(_inotify_monitors, &backend->hwnd, backend);
|
2011-04-25 10:04:46 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
void eio_monitor_backend_del(Eio_Monitor *monitor)
|
|
|
|
{
|
2014-01-13 20:33:16 -08:00
|
|
|
Eio_Monitor_Backend *backend;
|
|
|
|
|
2011-04-25 10:04:46 -07:00
|
|
|
if (!_inotify_fdh)
|
|
|
|
eio_monitor_fallback_del(monitor);
|
|
|
|
|
2014-01-13 20:33:16 -08:00
|
|
|
backend = monitor->backend;
|
2011-04-25 10:04:46 -07:00
|
|
|
monitor->backend = NULL;
|
2014-01-13 20:33:16 -08:00
|
|
|
if (!backend) return;
|
|
|
|
|
2016-07-15 17:02:03 -07:00
|
|
|
backend->parent = NULL;
|
|
|
|
|
2014-01-13 20:33:16 -08:00
|
|
|
eina_hash_del(_inotify_monitors, &backend->hwnd, backend);
|
2011-04-25 10:04:46 -07:00
|
|
|
}
|
2012-01-19 02:26:41 -08:00
|
|
|
|
efl_io_model: next try to fix this race condition
what is happening is that a file gets announced through eio_model
listing code, at this point of time, the monitor does not yet know about
the file. If the file now gets deleted between the annoncing and the
learning of the file from the monitor, then the file got an ADD event,
but no DEL event. Which is a bug.
With this commit there is a new API which asks the monitor if the file
already has the knowledge about the files existance, or not. A few
monitors like win32 inotify or cocoa do not have context about the file
directly, if the OS is now having the same bug, then we are again in
trouble, however, we canot do anything about that. In the case of kevent
or poll, this asks the context of the monitor if the file is already
there.
Reviewed-by: Cedric BAIL <cedric.bail@free.fr>
Differential Revision: https://phab.enlightenment.org/D10006
2019-09-18 02:32:08 -07:00
|
|
|
Eina_Bool eio_monitor_context_check(const Eio_Monitor *monitor EINA_UNUSED, const char *path EINA_UNUSED)
|
|
|
|
{
|
|
|
|
return EINA_TRUE;
|
|
|
|
}
|
|
|
|
|
2012-01-19 02:26:41 -08:00
|
|
|
|
2012-03-31 00:01:24 -07:00
|
|
|
/*============================================================================*
|
|
|
|
* API *
|
|
|
|
*============================================================================*/
|