View | Details | Raw Unified | Return to bug 214338 | Differences between
and this patch

Collapse All | Expand All

(-)devel/glib20/Makefile (-1 / +12 lines)
Lines 48-54 Link Here
48
		glib-compile-resources.1 gresource.1 gdbus-codegen.1
48
		glib-compile-resources.1 gresource.1 gdbus-codegen.1
49
gobject_MAN=	glib-genmarshal.1 glib-mkenums.1 gobject-query.1
49
gobject_MAN=	glib-genmarshal.1 glib-mkenums.1 gobject-query.1
50
50
51
OPTIONS_DEFINE=	COLLATION_FIX DEBUG NLS
51
OPTIONS_DEFINE=	COLLATION_FIX DEBUG FAM_ALTBACKEND NLS
52
OPTIONS_SUB=	yes
52
OPTIONS_SUB=	yes
53
# libc collation was fixed by https://svnweb.freebsd.org/changeset/base/290494
53
# libc collation was fixed by https://svnweb.freebsd.org/changeset/base/290494
54
COLLATION_FIX_DESC=	Use ICU for UTF-8 string collation (if libc is broken)
54
COLLATION_FIX_DESC=	Use ICU for UTF-8 string collation (if libc is broken)
Lines 65-70 Link Here
65
# http://www.freebsd.org/cgi/query-pr.cgi?pr=175930 see comment by ed@
65
# http://www.freebsd.org/cgi/query-pr.cgi?pr=175930 see comment by ed@
66
#COLLATION_FIX_CONFIGURE_ENV+=	CFLAGS="-D__STDC_ISO_10646__"
66
#COLLATION_FIX_CONFIGURE_ENV+=	CFLAGS="-D__STDC_ISO_10646__"
67
67
68
FAM_ALTBACKEND_DESC=		Alternate file monitor backend
69
FAM_ALTBACKEND_USES+=		autoreconf:build
70
FAM_ALTBACKEND_EXTRA_PATCHES=	${FILESDIR}/extra-patch-gio_kqueue_Makefile.am
71
72
68
.include <bsd.port.pre.mk>
73
.include <bsd.port.pre.mk>
69
74
70
# doesn't build yet
75
# doesn't build yet
Lines 98-103 Link Here
98
		s|-Werror|| ; \
103
		s|-Werror|| ; \
99
		s|#define HAVE_SYS_INOTIFY_H 1||' ${WRKSRC}/configure
104
		s|#define HAVE_SYS_INOTIFY_H 1||' ${WRKSRC}/configure
100
105
106
post-patch-FAM_ALTBACKEND-on:
107
	@${CP} -f ${FILESDIR}/gkqueuefilemonitor.c.in ${WRKSRC}/gio/kqueue/gkqueuefilemonitor.c
108
	@${CP} ${FILESDIR}/kqueue_fnm.c.in ${WRKSRC}/gio/kqueue/kqueue_fnm.c
109
	@${CP} ${FILESDIR}/kqueue_fnm.h.in ${WRKSRC}/gio/kqueue/kqueue_fnm.h
110
	@(cd ${WRKSRC} && ${AUTORECONF} -fvi)
111
101
post-install:
112
post-install:
102
	@${MKDIR} ${STAGEDIR}${PREFIX}/share/GConf/gsettings
113
	@${MKDIR} ${STAGEDIR}${PREFIX}/share/GConf/gsettings
103
	@${MKDIR} ${STAGEDIR}${PREFIX}/lib/gio/modules
114
	@${MKDIR} ${STAGEDIR}${PREFIX}/lib/gio/modules
(-)devel/glib20/files/extra-patch-gio_kqueue_Makefile.am (+26 lines)
Line 0 Link Here
1
--- gio/kqueue/Makefile.am.orig	2015-10-14 14:41:16.000000000 +0300
2
+++ gio/kqueue/Makefile.am	2016-11-06 05:08:37.646089000 +0300
3
@@ -4,21 +4,8 @@
4
 
5
 libkqueue_la_SOURCES = \
6
        gkqueuefilemonitor.c \
7
-       gkqueuefilemonitor.h \
8
-       kqueue-helper.c \
9
-       kqueue-helper.h \
10
-       kqueue-thread.c \
11
-       kqueue-thread.h \
12
-       kqueue-sub.c \
13
-       kqueue-sub.h \
14
-       kqueue-missing.c \
15
-       kqueue-missing.h \
16
-       kqueue-utils.c \
17
-       kqueue-utils.h \
18
-       kqueue-exclusions.c \
19
-       kqueue-exclusions.h \
20
-       dep-list.c \
21
-       dep-list.h \
22
+       kqueue_fnm.c \
23
+       kqueue_fnm.h \
24
        $(NULL)
25
 
26
 libkqueue_la_CFLAGS = \
(-)devel/glib20/files/gkqueuefilemonitor.c.in (+201 lines)
Line 0 Link Here
1
/*-
2
 * Copyright (c) 2016 - 2017 Rozhuk Ivan <rozhuk.im@gmail.com>
3
 * All rights reserved.
4
 *
5
 * Redistribution and use in source and binary forms, with or without
6
 * modification, are permitted provided that the following conditions
7
 * are met:
8
 * 1. Redistributions of source code must retain the above copyright
9
 *    notice, this list of conditions and the following disclaimer.
10
 * 2. Redistributions in binary form must reproduce the above copyright
11
 *    notice, this list of conditions and the following disclaimer in the
12
 *    documentation and/or other materials provided with the distribution.
13
 *
14
 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
15
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
18
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24
 * SUCH DAMAGE.
25
 *
26
 * Author: Rozhuk Ivan <rozhuk.im@gmail.com>
27
 *
28
 */
29
30
#include "config.h"
31
32
#include <glib-object.h>
33
#include <string.h>
34
#include <gio/gfilemonitor.h>
35
#include <gio/glocalfilemonitor.h>
36
#include <gio/giomodule.h>
37
#include "glib-private.h"
38
#include <glib-unix.h>
39
#include "kqueue_fnm.h"
40
41
/* Defaults. */
42
#ifndef KQUEUE_USE_THREAD
43
#define KQUEUE_USE_THREAD		1
44
#endif
45
46
#ifndef KQUEUE_MON_LOCAL_SUBFILES
47
#define KQUEUE_MON_LOCAL_SUBFILES	1
48
#endif
49
50
51
static GMutex			kqueue_lock;
52
static volatile kqueue_fnm_p	kqueue_fnm = NULL;
53
54
#define G_TYPE_KQUEUE_FILE_MONITOR      (g_kqueue_file_monitor_get_type())
55
#define G_KQUEUE_FILE_MONITOR(inst)     (G_TYPE_CHECK_INSTANCE_CAST((inst), \
56
					 G_TYPE_KQUEUE_FILE_MONITOR, GKqueueFileMonitor))
57
58
typedef GLocalFileMonitorClass	GKqueueFileMonitorClass;
59
60
typedef struct {
61
	GLocalFileMonitor	parent_instance;
62
	kqueue_file_mon_data_p	fmd;
63
} GKqueueFileMonitor;
64
65
GType g_kqueue_file_monitor_get_type(void);
66
G_DEFINE_TYPE_WITH_CODE (GKqueueFileMonitor, g_kqueue_file_monitor, G_TYPE_LOCAL_FILE_MONITOR,
67
       g_io_extension_point_implement(G_LOCAL_FILE_MONITOR_EXTENSION_POINT_NAME,
68
               g_define_type_id,
69
               "kqueue",
70
               10))
71
72
73
static void
74
kqueue_event_handler(kqueue_fnm_p kfnm,
75
    kqueue_file_mon_data_p fmd, void *udata, uint32_t event,
76
    const char *base, const char *filename, const char *new_filename) {
77
	static const uint32_t kfnm_to_glib_map[] = {
78
		0,				/* KF_EVENT_NOT_CHANGED */
79
		G_FILE_MONITOR_EVENT_CREATED,	/* KF_EVENT_CREATED */
80
		G_FILE_MONITOR_EVENT_DELETED,	/* KF_EVENT_DELETED */
81
		G_FILE_MONITOR_EVENT_RENAMED,	/* KF_EVENT_RENAMED */
82
		G_FILE_MONITOR_EVENT_CHANGED	/* KF_EVENT_CHANGED */
83
	};
84
85
	if (NULL == kfnm || NULL == filename ||
86
	    KF_EVENT_CREATED > event ||
87
	    KF_EVENT_CHANGED < event)
88
		return;
89
	g_file_monitor_source_handle_event(udata,
90
	    kfnm_to_glib_map[event],
91
	    filename, new_filename, NULL,
92
	    g_get_monotonic_time());
93
}
94
95
static gboolean
96
g_kqueue_file_monitor_is_supported(void) {
97
	kqueue_file_mon_settings_t kfms;
98
99
	if (NULL != kqueue_fnm)
100
		return (TRUE);
101
	/* Init only once. */
102
	g_mutex_lock(&kqueue_lock);
103
	if (NULL != kqueue_fnm) {
104
		g_mutex_unlock(&kqueue_lock);
105
		return (TRUE); /* Initialized while wait lock. */
106
	}
107
108
	kfms.use_thread = KQUEUE_USE_THREAD;
109
	kfms.mon_local_subfiles = KQUEUE_MON_LOCAL_SUBFILES;
110
	kqueue_fnm = kqueue_fnm_create(&kfms, kqueue_event_handler);
111
	if (NULL == kqueue_fnm) {
112
		g_mutex_unlock(&kqueue_lock);
113
		return (FALSE); /* Init fail. */
114
	}
115
	g_mutex_unlock(&kqueue_lock);
116
117
	return (TRUE);
118
}
119
120
static gboolean
121
g_kqueue_file_monitor_cancel(GFileMonitor *monitor) {
122
	GKqueueFileMonitor *gffm = G_KQUEUE_FILE_MONITOR(monitor);
123
124
	kqueue_fnm_del(kqueue_fnm, gffm->fmd);
125
	gffm->fmd = NULL;
126
127
	return (TRUE);
128
}
129
130
static void
131
g_kqueue_file_monitor_finalize(GObject *object) {
132
	GKqueueFileMonitor *gffm = G_KQUEUE_FILE_MONITOR(object);
133
134
	kqueue_fnm_del(kqueue_fnm, gffm->fmd);
135
	gffm->fmd = NULL;
136
}
137
138
static void
139
g_kqueue_file_monitor_start(GLocalFileMonitor *local_monitor,
140
    const gchar *dirname, const gchar *basename,
141
    const gchar *filename, GFileMonitorSource *source) {
142
	GKqueueFileMonitor *gffm = G_KQUEUE_FILE_MONITOR(local_monitor);
143
144
	g_assert(NULL != kqueue_fnm);
145
	g_source_ref((GSource*)source);
146
147
	if (NULL == filename) {
148
		filename = dirname;
149
	}
150
	gffm->fmd = kqueue_fnm_add(kqueue_fnm, filename, source);
151
}
152
153
static void
154
g_kqueue_file_monitor_init(GKqueueFileMonitor *monitor) {
155
	
156
}
157
158
static void
159
g_kqueue_file_monitor_class_init(GKqueueFileMonitorClass *class) {
160
	GObjectClass *gobject_class = G_OBJECT_CLASS(class);
161
	GFileMonitorClass *file_monitor_class = G_FILE_MONITOR_CLASS(class);
162
163
	class->is_supported = g_kqueue_file_monitor_is_supported;
164
	class->start = g_kqueue_file_monitor_start;
165
	class->mount_notify = TRUE; /* TODO: ??? */
166
	file_monitor_class->cancel = g_kqueue_file_monitor_cancel;
167
	gobject_class->finalize = g_kqueue_file_monitor_finalize;
168
}
169
170
static void
171
g_kqueue_file_monitor_class_finalize(GKqueueFileMonitorClass *class) {
172
	
173
}
174
175
void
176
g_io_module_load(GIOModule *module) {
177
178
	g_type_module_use(G_TYPE_MODULE(module));
179
180
	g_io_extension_point_implement(G_LOCAL_FILE_MONITOR_EXTENSION_POINT_NAME,
181
	    G_TYPE_KQUEUE_FILE_MONITOR, "kqueue", 10);
182
	g_io_extension_point_implement(G_NFS_FILE_MONITOR_EXTENSION_POINT_NAME,
183
	    G_TYPE_KQUEUE_FILE_MONITOR, "kqueue", 10);
184
}
185
186
void
187
g_io_module_unload(GIOModule *module) {
188
	
189
	g_assert_not_reached();
190
}
191
192
char **
193
g_io_module_query(void) {
194
	char *eps[] = {
195
		G_LOCAL_FILE_MONITOR_EXTENSION_POINT_NAME,
196
		G_NFS_FILE_MONITOR_EXTENSION_POINT_NAME,
197
		NULL
198
	};
199
200
	return (g_strdupv(eps));
201
}
(-)devel/glib20/files/kqueue_fnm.c.in (+866 lines)
Line 0 Link Here
1
/*-
2
 * Copyright (c) 2016 - 2017 Rozhuk Ivan <rozhuk.im@gmail.com>
3
 * All rights reserved.
4
 *
5
 * Redistribution and use in source and binary forms, with or without
6
 * modification, are permitted provided that the following conditions
7
 * are met:
8
 * 1. Redistributions of source code must retain the above copyright
9
 *    notice, this list of conditions and the following disclaimer.
10
 * 2. Redistributions in binary form must reproduce the above copyright
11
 *    notice, this list of conditions and the following disclaimer in the
12
 *    documentation and/or other materials provided with the distribution.
13
 *
14
 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
15
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
18
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24
 * SUCH DAMAGE.
25
 *
26
 * Author: Rozhuk Ivan <rozhuk.im@gmail.com>
27
 *
28
 */
29
30
#include <sys/param.h>
31
#include <sys/types.h>
32
#include <sys/event.h>
33
#include <sys/stat.h>
34
#include <sys/mount.h>
35
#include <sys/fcntl.h> /* open, fcntl */
36
37
#include <inttypes.h>
38
#include <stdlib.h> /* malloc, exit */
39
#include <unistd.h> /* close, write, sysconf */
40
#include <string.h> /* bcopy, bzero, memcpy, memmove, memset, strerror... */
41
#include <dirent.h> /* opendir, readdir */
42
#include <errno.h>
43
#include <pthread.h>
44
45
#include "kqueue_fnm.h"
46
47
48
/* Preallocate items count. */
49
#ifndef FILES_ALLOC_BLK_SIZE
50
#	define FILES_ALLOC_BLK_SIZE	32
51
#endif
52
53
#define EVENT_UDATA_TYPE_FILE_INFO	0
54
#define EVENT_UDATA_TYPE_FILE_MON_DATA	1
55
56
57
typedef struct file_info_s { /* Directory file. */
58
	uint32_t	utype;		/* Allways EVENT_UDATA_TYPE_FILE_INFO */
59
	int		fd;		/* For notify kqueue(). */
60
	struct dirent 	de;		/* d_reclen used for action. */
61
	struct stat	sb;
62
	kqueue_file_mon_data_p fmd;
63
} file_info_t, *file_info_p;
64
65
66
typedef struct readdir_data_s {
67
	int		fd;
68
	uint8_t		*buf;
69
	size_t		buf_size;
70
	size_t		buf_used;
71
	size_t		buf_pos;
72
} readdir_data_t, *readdir_data_p;
73
74
75
typedef struct kqueue_file_mon_data_s {
76
	uint32_t	utype;		/* Allways EVENT_UDATA_TYPE_FILE_MON_DATA */
77
	int		fd;		/* For notify kqueue(). */
78
	int		is_dir;
79
	int		is_local;	/* Is file system local. */
80
	char		path[(PATH_MAX + 2)];
81
	size_t		path_size;
82
	size_t		name_offset;	/* Parent path size. */
83
	size_t		st_blksize;
84
	void		*udata;
85
	kqueue_fnm_p	kfnm;
86
	/* For dir. */
87
	file_info_p	files;
88
	volatile size_t	files_count;
89
	size_t		files_allocated;
90
} kqueue_file_mon_data_t;
91
92
93
typedef struct kqueue_file_nonify_monitor_s {
94
	int		fd;		/* kqueue() fd. */
95
	int		pfd[2];		/* pipe queue specific. */
96
	uint8_t		*tmpbuf;
97
	size_t		tmpbuf_size;
98
	kfnm_event_handler_cb cb_func;	/* Callback on dir/file change. */
99
	kqueue_file_mon_settings_t s;
100
	pthread_t	tid;
101
} kqueue_fnm_t;
102
103
104
typedef void (*kq_msg_cb)(kqueue_file_mon_data_p fmd);
105
106
typedef struct kqueue_file_mon_msg_pkt_s {
107
	size_t		magic;
108
	kq_msg_cb	msg_cb;
109
	kqueue_file_mon_data_p fmd;
110
	size_t		chk_sum;
111
} kqueue_fnm_msg_pkt_t, *kqueue_fnm_msg_pkt_p;
112
113
#define KF_MSG_PKT_MAGIC	0xffddaa00
114
115
116
#ifndef O_NOATIME
117
#	define O_NOATIME	0
118
#endif
119
#ifndef O_EVTONLY
120
#	define O_EVTONLY	O_RDONLY
121
#endif
122
#define OPEN_FILE_FLAGS		(O_EVTONLY | O_NONBLOCK | O_NOFOLLOW | O_NOATIME | O_CLOEXEC)
123
124
#define EVFILT_VNODE_FLAGS_ALL	(NOTE_DELETE |				\
125
				NOTE_WRITE |				\
126
				NOTE_EXTEND |				\
127
				NOTE_ATTRIB |				\
128
				NOTE_LINK |				\
129
				NOTE_RENAME |				\
130
				NOTE_REVOKE |				\
131
				NOTE_CLOSE_WRITE)
132
#define EVFILT_VNODE_SUB_FLAGS	(NOTE_WRITE |				\
133
				NOTE_EXTEND |				\
134
				NOTE_ATTRIB |				\
135
				NOTE_LINK |				\
136
				NOTE_CLOSE_WRITE)
137
138
#ifndef _GENERIC_DIRSIZ
139
#	define _GENERIC_DIRSIZ(__de)	MIN((__de)->d_reclen, sizeof(struct dirent))
140
#endif
141
142
#define IS_NAME_DOTS(__name)	('.' == (__name)[0] &&			\
143
				 ('\0' == (__name)[1] || 		\
144
				  ('.' == (__name)[1] && '\0' == (__name)[2])))
145
#define IS_DE_NAME_EQ(__de1, __de2)  (0 == mem_cmpn((__de1)->d_name,	\
146
						    (__de1)->d_namlen,	\
147
						    (__de2)->d_name,	\
148
						    (__de2)->d_namlen))
149
#define zalloc(__size)		calloc(1, (__size))
150
151
void 	*kqueue_fnm_proccess_events_proc(void *data);
152
153
static inline int
154
mem_cmpn(const void *buf1, const size_t buf1_size,
155
    const void *buf2, const size_t buf2_size) {
156
157
	if (buf1_size != buf2_size)
158
		return (((buf1_size > buf2_size) ? 127 : -127));
159
	if (0 == buf1_size || buf1 == buf2)
160
		return (0);
161
	if (NULL == buf1)
162
		return (-127);
163
	if (NULL == buf2)
164
		return (127);
165
	return (memcmp(buf1, buf2, buf1_size));
166
}
167
168
static inline int
169
realloc_items(void **items, const size_t item_size,
170
    size_t *allocated, const size_t alloc_blk_cnt, const size_t count) {
171
	size_t allocated_prev, allocated_new;
172
	uint8_t *items_new;
173
174
	if (NULL == items || 0 == item_size || NULL == allocated ||
175
	    0 == alloc_blk_cnt)
176
		return (EINVAL);
177
	allocated_prev = (*allocated);
178
	if (NULL != (*items) &&
179
	    allocated_prev > count &&
180
	    allocated_prev <= (count + alloc_blk_cnt))
181
		return (0);
182
	allocated_new = (((count / alloc_blk_cnt) + 1) * alloc_blk_cnt);
183
#if (defined(__FreeBSD_version) && __FreeBSD_version >= 1100000) || defined(HAVE_REALLOCARRAY)
184
	items_new = (uint8_t*)reallocarray((*items), item_size, allocated_new);
185
#else /* For old BSD systems. */
186
	items_new = (uint8_t*)realloc((*items), (item_size * allocated_new));
187
#endif
188
	if (NULL == items_new) /* Realloc fail! */
189
		return (ENOMEM);
190
191
	if (allocated_new > allocated_prev) { /* Init new mem. */
192
		memset((items_new + (allocated_prev * item_size)), 0x00,
193
		    ((allocated_new - allocated_prev) * item_size));
194
	}
195
	(*items) = items_new;
196
	(*allocated) = allocated_new;
197
198
	return (0);
199
}
200
201
202
static int
203
readdir_data_start(int fd, uint8_t *buf, size_t buf_size, readdir_data_p rdd) {
204
205
	if (-1 == fd || NULL == buf || 0 == buf_size || NULL == rdd)
206
		return (EINVAL);
207
	if (-1 == lseek(fd, 0, SEEK_SET))
208
		return (errno);
209
	memset(rdd, 0x00, sizeof(readdir_data_t));
210
	rdd->fd = fd;
211
	rdd->buf = buf;
212
	rdd->buf_size = buf_size;
213
214
	return (0);
215
}
216
217
static int
218
readdir_data_next(readdir_data_p rdd, struct dirent *de) {
219
	int ios;
220
	uint8_t *ptr;
221
222
	if (NULL == rdd || NULL == de)
223
		return (EINVAL);
224
225
retry:
226
	if (rdd->buf_used <= rdd->buf_pos) {
227
		ios = getdents(rdd->fd, (char*)rdd->buf, (int)rdd->buf_size);
228
		if (-1 == ios)
229
			return (errno);
230
		rdd->buf_used = (size_t)ios;
231
		rdd->buf_pos = 0;
232
		if (0 == ios)
233
			return (ESPIPE); /* EOF. */
234
	}
235
	/* Keep data aligned. */
236
	ptr = (rdd->buf + rdd->buf_pos);
237
	memcpy(de, ptr, (sizeof(struct dirent) - sizeof(de->d_name)));
238
	if (0 == de->d_reclen)
239
		return (ESPIPE); /* EOF. */
240
	rdd->buf_pos += de->d_reclen;
241
#ifdef DT_WHT
242
	if (DT_WHT == de->d_type)
243
		goto retry;
244
#endif
245
	memcpy(de, ptr, _GENERIC_DIRSIZ(de));
246
	if (IS_NAME_DOTS(de->d_name))
247
		goto retry;
248
	return (0);
249
}
250
251
252
static int
253
file_info_find_de_fileno(file_info_p files, size_t files_count,
254
    struct dirent *de, size_t *idx) {
255
	size_t i;
256
257
	if (NULL == files || NULL == de || NULL == idx)
258
		return (0);
259
	for (i = 0; i < files_count; i ++) {
260
		if (de->d_type != files[i].de.d_type ||
261
		    de->d_fileno != files[i].de.d_fileno)
262
			continue;
263
		(*idx) = i;
264
		return (1);
265
	}
266
	(*idx) = files_count;
267
	return (0);
268
}
269
270
static int
271
file_info_find_de_name(file_info_p files, size_t files_count,
272
    const size_t skip_idx, struct dirent *de, size_t *idx) {
273
	size_t i;
274
275
	if (NULL == files || NULL == de || NULL == idx)
276
		return (0);
277
	for (i = 0; i < files_count; i ++) {
278
		if (i == skip_idx ||
279
		    de->d_type != files[i].de.d_type ||
280
		    0 == IS_DE_NAME_EQ(de, &files[i].de))
281
			continue;
282
		(*idx) = i;
283
		return (1);
284
	}
285
	(*idx) = files_count;
286
	return (0);
287
}
288
289
290
static int
291
is_fs_local(struct statfs *stfs) {
292
293
	if (NULL == stfs)
294
		return (0);
295
	if (0 == (MNT_LOCAL & stfs->f_flags))
296
		return (0);
297
	/* fusefs exceptions check. */
298
	if (0 != memcmp(stfs->f_fstypename, "fusefs.", 7))
299
		return (1); /* Not fusefs. */
300
	if (0 == memcmp(&stfs->f_fstypename[7], "sshfs", 5))
301
		return (0);
302
	return (1);
303
}
304
305
306
static void
307
kqueue_file_mon_data_clean(kqueue_file_mon_data_p fmd) {
308
	size_t i;
309
310
	if (NULL == fmd)
311
		return;
312
	if (-1 != fmd->fd) {
313
		close(fmd->fd);
314
		fmd->fd = -1;
315
	}
316
	if (0 != fmd->is_local) { /* Stop monitoring files/dirs. */
317
		for (i = 0; i < fmd->files_count; i ++) {
318
			if (-1 == fmd->files[i].fd)
319
				continue;
320
			close(fmd->files[i].fd);
321
		}
322
	}
323
	fmd->files_count = 0;
324
	fmd->files_allocated = 0;
325
	free(fmd->files);
326
	fmd->files = NULL;
327
}
328
329
static void
330
kqueue_file_mon_data_free(kqueue_file_mon_data_p fmd) {
331
	size_t i;
332
333
	if (NULL == fmd)
334
		return;
335
	if (-1 != fmd->fd) {
336
		close(fmd->fd);
337
	}
338
	if (0 != fmd->is_local) { /* Stop monitoring files/dirs. */
339
		for (i = 0; i < fmd->files_count; i ++) {
340
			if (-1 == fmd->files[i].fd)
341
				continue;
342
			close(fmd->files[i].fd);
343
		}
344
	}
345
	free(fmd->files);
346
	free(fmd);
347
}
348
349
static kqueue_file_mon_data_p
350
kqueue_file_mon_data_alloc(kqueue_fnm_p kfnm, const char *path, void *udata) {
351
	kqueue_file_mon_data_p fmd;
352
353
	if (NULL == kfnm || NULL == path)
354
		return (NULL);
355
	fmd = zalloc(sizeof(kqueue_file_mon_data_t));
356
	if (NULL == fmd)
357
		return (NULL);
358
	fmd->utype = EVENT_UDATA_TYPE_FILE_MON_DATA;
359
	/* Remember args. */
360
	fmd->path_size = strlcpy(fmd->path, path, PATH_MAX);
361
	fmd->name_offset = fmd->path_size;
362
	fmd->udata = udata;
363
	fmd->kfnm = kfnm;
364
365
	return (fmd);
366
}
367
368
static int
369
kqueue_file_mon_data_readdir(kqueue_file_mon_data_p fmd) {
370
	int error;
371
	struct dirent *de;
372
	uint8_t *tmpbuf;
373
	readdir_data_t rdd;
374
375
	if (NULL == fmd || 0 == fmd->is_dir)
376
		return (EINVAL);
377
378
	/* Get temp buf. */
379
	if (fmd->st_blksize > fmd->kfnm->tmpbuf_size) {
380
		tmpbuf = realloc(fmd->kfnm->tmpbuf, fmd->st_blksize);
381
		if (NULL == tmpbuf)
382
			return (ENOMEM);
383
		fmd->kfnm->tmpbuf = tmpbuf;
384
		fmd->kfnm->tmpbuf_size = fmd->st_blksize;
385
	}
386
387
	fmd->files_count = 0;
388
	fmd->files_allocated = 0;
389
	free(fmd->files);
390
	fmd->files = NULL;
391
392
	error = readdir_data_start(fmd->fd, fmd->kfnm->tmpbuf, fmd->st_blksize, &rdd);
393
	if (0 != error)
394
		return (error);
395
	for (;;) {
396
		if (0 != realloc_items((void**)&fmd->files,
397
		    sizeof(file_info_t), &fmd->files_allocated,
398
		    FILES_ALLOC_BLK_SIZE, fmd->files_count)) {
399
			fmd->files_count = 0;
400
			fmd->files_allocated = 0;
401
			free(fmd->files);
402
			fmd->files = NULL;
403
			return (ENOMEM);
404
		}
405
		de = &fmd->files[fmd->files_count].de; /* Use short name. */
406
		/* Get file name from folder. */
407
		if (0 != readdir_data_next(&rdd, de))
408
			break;
409
		/* Get file attrs. */
410
		if (0 != fstatat(fmd->fd, de->d_name,
411
		    &fmd->files[fmd->files_count].sb,
412
		    AT_SYMLINK_NOFOLLOW)) {
413
			memset(&fmd->files[fmd->files_count].sb, 0x00,
414
			    sizeof(struct stat));
415
		}
416
		fmd->files[fmd->files_count].utype = EVENT_UDATA_TYPE_FILE_INFO;
417
		fmd->files[fmd->files_count].fd = -1;
418
		fmd->files[fmd->files_count].fmd = fmd;
419
		fmd->files_count ++;
420
	}
421
422
	return (0); /* OK. */
423
}
424
425
426
static void
427
kqueue_file_mon_data_init(kqueue_file_mon_data_p fmd) {
428
	size_t i;
429
	struct stat sb;
430
	struct statfs stfs;
431
	struct kevent kev;
432
433
	if (NULL == fmd)
434
		return;
435
	fmd->fd = open(fmd->path, OPEN_FILE_FLAGS);
436
	if (-1 == fmd->fd)
437
		return;
438
	if (0 != fstat(fmd->fd, &sb))
439
		goto err_out;
440
	fmd->st_blksize = (size_t)sb.st_blksize;
441
	
442
	/* Get parent folder name. */
443
	if (S_ISDIR(sb.st_mode)) {
444
		fmd->is_dir = 1;
445
		/* Be sure that folder contain trailing '/'. */
446
		if ('/' != fmd->path[(fmd->path_size - 1)]) {
447
			fmd->path[fmd->path_size] = '/';
448
			fmd->path_size ++;
449
			fmd->path[fmd->path_size] = 0;
450
		}
451
		/* Skip last '/' for parent dir search. */
452
		fmd->name_offset = (fmd->path_size - 1);
453
	}
454
455
	/* Is file system local? */
456
	if (0 != fmd->is_dir &&
457
	    0 != fmd->kfnm->s.mon_local_subfiles &&
458
	    0 == fstatfs(fmd->fd, &stfs)) {
459
		fmd->is_local = is_fs_local(&stfs);
460
	}
461
462
	/* Find parent dir path size. */
463
	while (0 < fmd->name_offset && '/' != fmd->path[(fmd->name_offset - 1)]) {
464
		fmd->name_offset --;
465
	}
466
467
	/* Dir special processing. */
468
	if (0 != fmd->is_dir) {
469
		/* Read and remember dir content. */
470
		if (0 != kqueue_file_mon_data_readdir(fmd))
471
			goto err_out;
472
	}
473
	/* Add to kqueue. */
474
	EV_SET(&kev, fmd->fd, EVFILT_VNODE, (EV_ADD | EV_CLEAR),
475
	    EVFILT_VNODE_FLAGS_ALL, 0, fmd);
476
	if (-1 == kevent(fmd->kfnm->fd, &kev, 1, NULL, 0, NULL))
477
		goto err_out;
478
	if (0 != fmd->is_local) { /* Add monitor sub files/dirs, ignory errors. */
479
		for (i = 0; i < fmd->files_count; i ++) {
480
			fmd->files[i].fd = openat(fmd->fd,
481
			    fmd->files[i].de.d_name, OPEN_FILE_FLAGS);
482
			if (-1 == fmd->files[i].fd)
483
				continue;
484
			fmd->files[i].fmd = fmd;
485
			EV_SET(&kev, fmd->files[i].fd, EVFILT_VNODE,
486
			    (EV_ADD | EV_CLEAR),
487
			    EVFILT_VNODE_SUB_FLAGS, 0, &fmd->files[i]);
488
			kevent(fmd->kfnm->fd, &kev, 1, NULL, 0, NULL);
489
		}
490
	}
491
	return; /* OK. */
492
493
err_out:
494
	kqueue_file_mon_data_clean(fmd);
495
}
496
497
498
static void
499
kqueue_handle_changes(kqueue_fnm_p kfnm, kqueue_file_mon_data_p fmd) {
500
	struct stat sb;
501
	struct kevent kev;
502
	size_t i, k, files_count;
503
	file_info_p files;
504
505
	if (NULL == kfnm || NULL == fmd)
506
		return;
507
	if (0 != fstat(fmd->fd, &sb) ||
508
	    0 == sb.st_nlink) {
509
		kqueue_file_mon_data_clean(fmd);
510
		kfnm->cb_func(kfnm, fmd, fmd->udata, KF_EVENT_DELETED,
511
		    fmd->path, "", NULL);
512
		return;
513
	}
514
	if (0 == fmd->is_dir) {
515
		fmd->path[fmd->name_offset] = 0;
516
		kfnm->cb_func(kfnm, fmd, fmd->udata, KF_EVENT_CHANGED, fmd->path,
517
		    (fmd->path + fmd->name_offset), NULL);
518
		fmd->path[fmd->name_offset] = '/';
519
		return;
520
	}
521
522
	/* Dir processing. */
523
524
	/* Save prev. */
525
	files = fmd->files;
526
	files_count = fmd->files_count;
527
	fmd->files = NULL;
528
	fmd->files_count = 0;
529
	/* Update dir. */
530
	if (0 != kqueue_file_mon_data_readdir(fmd)) {
531
		/* Restore prev state on fail. */
532
		fmd->files = files;
533
		fmd->files_count = files_count;
534
		return;
535
	}
536
	/* Notify removed first. */
537
	for (i = 0; i < files_count; i ++) {
538
		if (0 != file_info_find_de_fileno(fmd->files, fmd->files_count, &files[i].de, &k) ||
539
		    0 != file_info_find_de_name(fmd->files, fmd->files_count, (~(size_t)0), &files[i].de, &k)) /* Deleted. */
540
			continue;
541
		if (-1 != files[i].fd) {
542
			close(files[i].fd);
543
		}
544
		kfnm->cb_func(kfnm, fmd, fmd->udata, KF_EVENT_DELETED,
545
			    fmd->path, files[i].de.d_name, NULL);
546
	}
547
	/* Notify. */
548
	for (i = 0; i < fmd->files_count; i ++) {
549
		/* Is new file/folder? */
550
		if (0 == file_info_find_de_fileno(files, files_count, &fmd->files[i].de, &k) &&
551
		    0 == file_info_find_de_name(files, files_count, (~(size_t)0), &fmd->files[i].de, &k)) { /* Add new. */
552
			if (0 != fmd->is_local) { /* Add monitor sub files/dirs, ignory errors. */
553
				fmd->files[i].fd = openat(fmd->fd,
554
				    fmd->files[i].de.d_name, OPEN_FILE_FLAGS);
555
				if (-1 != fmd->files[i].fd) {
556
					fmd->files[i].fmd = fmd;
557
					EV_SET(&kev, fmd->files[i].fd, EVFILT_VNODE,
558
					    (EV_ADD | EV_CLEAR),
559
					    EVFILT_VNODE_SUB_FLAGS, 0,
560
					    &fmd->files[i]);
561
					kevent(kfnm->fd, &kev, 1, NULL, 0, NULL);
562
				}
563
			}
564
			kfnm->cb_func(kfnm, fmd, fmd->udata, KF_EVENT_CREATED,
565
			    fmd->path, fmd->files[i].de.d_name, NULL);
566
			continue;
567
		}
568
		/* Is renamed? */
569
		if (0 == IS_DE_NAME_EQ(&files[k].de, &fmd->files[i].de)) {
570
			fmd->files[i].fd = files[k].fd; /* Keep file fd. */
571
			kfnm->cb_func(kfnm, fmd, fmd->udata, KF_EVENT_RENAMED,
572
			    fmd->path, files[k].de.d_name, fmd->files[i].de.d_name);
573
			continue;
574
		}
575
		/* Is modified? */
576
		if (0 != memcmp(&fmd->files[i].sb, &files[k].sb, sizeof(struct stat))) {
577
			fmd->files[i].fd = files[k].fd; /* Keep file fd. */
578
			kfnm->cb_func(kfnm, fmd, fmd->udata, KF_EVENT_CHANGED,
579
			    fmd->path, fmd->files[i].de.d_name, NULL);
580
			continue;
581
		}
582
		/* Not changed. */
583
	}
584
585
	free(files);
586
}
587
588
static void
589
kqueue_handle_rename(kqueue_fnm_p kfnm, kqueue_file_mon_data_p fmd) {
590
	int up_dir_fd, found = 0;
591
	readdir_data_t rdd;
592
	struct dirent de;
593
	struct stat sb;
594
	char old_filename[(MAXNAMLEN + 2)];
595
	size_t old_filename_size;
596
597
	if (NULL == kfnm || NULL == fmd)
598
		return;
599
	if (0 != fstat(fmd->fd, &sb) ||
600
	    0 == sb.st_nlink) {
601
notify_removed:
602
		kqueue_file_mon_data_clean(fmd);
603
		kfnm->cb_func(kfnm, fmd, fmd->udata, KF_EVENT_DELETED,
604
		    fmd->path, "", NULL);
605
		return;
606
	}
607
	/* Save old file name. */
608
	old_filename_size = (fmd->path_size - fmd->name_offset - (size_t)fmd->is_dir);
609
	memcpy(old_filename,
610
	    (fmd->path + fmd->name_offset),
611
	    old_filename_size);
612
	old_filename[old_filename_size] = 0;
613
614
	/* Get parent folder name. */
615
	fmd->path[fmd->name_offset] = 0;
616
	/* Try to open. */
617
	up_dir_fd = open(fmd->path, (OPEN_FILE_FLAGS | O_DIRECTORY));
618
	/* Restore '/' after parent folder. */
619
	fmd->path[fmd->name_offset] = '/';
620
	if (-1 == up_dir_fd ||
621
	    0 != fstat(up_dir_fd, &sb) ||
622
	    0 != readdir_data_start(up_dir_fd, fmd->kfnm->tmpbuf, (size_t)sb.st_blksize, &rdd)) {
623
		close(up_dir_fd);
624
		return;
625
	}
626
	/* Find new name by inode. */
627
	while (0 == readdir_data_next(&rdd, &de)) {
628
		if (de.d_fileno == sb.st_ino) {
629
			found ++;
630
			break;
631
		}
632
	}
633
	close(up_dir_fd);
634
	if (0 == found)
635
		goto notify_removed; /* Not found. */
636
	/* Update name. */
637
	if (PATH_MAX <= (fmd->name_offset + de.d_namlen))
638
		return; /* Too long. */
639
	memcpy((fmd->path + fmd->name_offset), de.d_name, de.d_namlen);
640
	fmd->path_size = (fmd->name_offset + de.d_namlen);
641
	/* Add last '/' for dir. */
642
	fmd->path[fmd->path_size] = '/';
643
	fmd->path_size += (size_t)fmd->is_dir;
644
	fmd->path[fmd->path_size] = 0;
645
	/* Notify. */
646
	kfnm->cb_func(kfnm, fmd, fmd->udata, KF_EVENT_RENAMED,
647
	    fmd->path, old_filename, de.d_name);
648
}
649
650
651
static void
652
kqueue_fnm_delay_call_process(kqueue_fnm_p kfnm, kq_msg_cb forced_msg_cb) {
653
	ssize_t ios;
654
	kqueue_fnm_msg_pkt_t msg;
655
656
	for (;;) {
657
		ios = read(kfnm->pfd[0], &msg, sizeof(msg));
658
		if (0 >= ios)
659
			return;
660
		if (sizeof(msg) != ios ||
661
		    KF_MSG_PKT_MAGIC != msg.magic ||
662
		    (((size_t)msg.msg_cb) ^ ((size_t)msg.fmd)) != msg.chk_sum)
663
			continue;
664
		if (NULL != forced_msg_cb) {
665
			forced_msg_cb(msg.fmd);
666
			continue;
667
		}
668
		if (NULL == msg.msg_cb)
669
			continue;
670
		msg.msg_cb(msg.fmd);
671
	}
672
}
673
674
static int
675
kqueue_fnm_delay_call(kqueue_fnm_p kfnm, kq_msg_cb msg_cb,
676
    kqueue_file_mon_data_p fmd) {
677
	kqueue_fnm_msg_pkt_t msg;
678
679
	if (NULL == kfnm || NULL == fmd)
680
		return (EINVAL);
681
	msg.magic = KF_MSG_PKT_MAGIC;
682
	msg.msg_cb = msg_cb;
683
	msg.fmd = fmd;
684
	msg.chk_sum = (((size_t)msg.msg_cb) ^ ((size_t)msg.fmd));
685
	if (sizeof(msg) == write(kfnm->pfd[1], &msg, sizeof(msg)))
686
		return (0);
687
	return (errno);
688
}
689
690
691
void
692
kqueue_fnm_free(kqueue_fnm_p kfnm) {
693
694
	if (NULL == kfnm)
695
		return;
696
	close(kfnm->fd);
697
	pthread_join(kfnm->tid, NULL);
698
	/* Free all in delay calls queue. */
699
	kqueue_fnm_delay_call_process(kfnm, kqueue_file_mon_data_free);
700
	close(kfnm->pfd[0]);
701
	close(kfnm->pfd[1]);
702
	free(kfnm->tmpbuf);
703
	free(kfnm);
704
}
705
706
kqueue_fnm_p
707
kqueue_fnm_create(kqueue_file_mon_settings_p s, kfnm_event_handler_cb cb_func) {
708
	kqueue_fnm_p kfnm;
709
	struct kevent kev;
710
711
	if (NULL == s || NULL == cb_func)
712
		return (NULL);
713
	kfnm = zalloc(sizeof(kqueue_fnm_t));
714
	if (NULL == kfnm)
715
		return (NULL);
716
	kfnm->fd = kqueue();
717
	if (-1 == kfnm->fd)
718
		goto err_out;
719
	if (-1 == pipe2(kfnm->pfd, O_NONBLOCK))
720
		goto err_out;
721
	kfnm->cb_func = cb_func;
722
	memcpy(&kfnm->s, s, sizeof(kqueue_file_mon_settings_t));
723
724
	EV_SET(&kev, kfnm->pfd[0], EVFILT_READ, EV_ADD, 0, 0, NULL);
725
	if (-1 == kevent(kfnm->fd, &kev, 1, NULL, 0, NULL))
726
		goto err_out;
727
	if (0 != kfnm->s.use_thread) {
728
		if (0 != pthread_create(&kfnm->tid, NULL,
729
		    kqueue_fnm_proccess_events_proc, kfnm))
730
			goto err_out;
731
	}
732
	return (kfnm);
733
734
err_out:
735
	kqueue_fnm_free(kfnm);
736
	return (NULL);
737
}
738
739
kqueue_file_mon_data_p
740
kqueue_fnm_add(kqueue_fnm_p kfnm, const char *path, void *udata) {
741
	int error;
742
	kqueue_file_mon_data_p fmd;
743
	
744
	if (NULL == kfnm || NULL == path)
745
		return (NULL);
746
	fmd = kqueue_file_mon_data_alloc(kfnm, path, udata);
747
	if (NULL == fmd)
748
		return (NULL);
749
	/* Shedule delay call to init. */
750
	error = kqueue_fnm_delay_call(kfnm, kqueue_file_mon_data_init, fmd);
751
	if (0 != error) { /* Error, do no directly init to avoid freezes. */
752
		kqueue_file_mon_data_free(fmd);
753
		return (NULL);
754
	}
755
	return (fmd);
756
}
757
758
void
759
kqueue_fnm_del(kqueue_fnm_p kfnm, kqueue_file_mon_data_p fmd) {
760
	int error;
761
762
	if (NULL == kfnm || NULL == fmd)
763
		return;
764
	/* Cancel notifications. */
765
	close(fmd->fd);
766
	fmd->fd = -1;
767
	/* Shedule delay call to free. */
768
	error = kqueue_fnm_delay_call(kfnm, kqueue_file_mon_data_free, fmd);
769
	if (0 == error)
770
		return;
771
	/* Error, free directly. */
772
	kqueue_file_mon_data_free(fmd);
773
}
774
775
776
static void
777
kqueue_fnm_proccess_event(kqueue_fnm_p kfnm, struct kevent *kev) {
778
	kqueue_file_mon_data_p fmd;
779
	file_info_p fi;
780
781
	if (NULL == kfnm || NULL == kev)
782
		return;
783
784
	/* Handle delay calls. */
785
	if (kev->ident == (uintptr_t)kfnm->pfd[0] &&
786
	    kev->filter == EVFILT_READ) {
787
		kqueue_fnm_delay_call_process(kfnm, NULL);
788
		return;
789
	}
790
791
	if (0 == kev->udata)
792
		return; /* No associated data, skip. */
793
	fmd = (kqueue_file_mon_data_p)kev->udata;
794
795
	/* FS notifications. */
796
	if (EVFILT_VNODE != kev->filter)
797
		return; /* Unknown event, skip. */
798
	/* Subdir/file */
799
	if (EVENT_UDATA_TYPE_FILE_INFO == fmd->utype) {
800
		fi = (file_info_p)kev->udata;
801
		fmd = fi->fmd;
802
		/* Update file attrs. */
803
		if (0 != fstat(fi->fd, &fi->sb)) {
804
			memset(&fi->sb, 0x00, sizeof(struct stat));
805
		}
806
		kfnm->cb_func(kfnm, fmd, fmd->udata, KF_EVENT_CHANGED,
807
		    fmd->path, fi->de.d_name, NULL);
808
		return;
809
	}
810
	/* Monitored object. */
811
	if (EVENT_UDATA_TYPE_FILE_MON_DATA != fmd->utype)
812
		return;
813
	/* All flags from EVFILT_VNODE_FLAGS_ALL must be handled here. */
814
	if (EV_ERROR & kev->flags) {
815
		kev->fflags |= NOTE_REVOKE; /* Treat error as unmount. */
816
	}
817
	if (NOTE_RENAME & kev->fflags) {
818
		kqueue_handle_rename(kfnm, fmd);
819
	}
820
	if ((NOTE_WRITE | NOTE_EXTEND | NOTE_ATTRIB | NOTE_LINK | NOTE_CLOSE_WRITE) & kev->fflags) {
821
		kqueue_handle_changes(kfnm, fmd);
822
	}
823
	if ((NOTE_DELETE | NOTE_REVOKE) & kev->fflags) {
824
		kqueue_file_mon_data_clean(fmd);
825
		kfnm->cb_func(kfnm, fmd, fmd->udata, KF_EVENT_DELETED,
826
		    fmd->path, "", NULL);
827
	}
828
}
829
830
void *
831
kqueue_fnm_proccess_events_proc(void *data) {
832
	struct kevent kev;
833
	kqueue_fnm_p kfnm = data;
834
835
	if (NULL == kfnm)
836
		return (NULL);
837
	/* Get and proccess events, no wait. */
838
	while (0 < kevent(kfnm->fd, NULL, 0, &kev, 1, NULL)) {
839
		kqueue_fnm_proccess_event(kfnm, &kev);
840
	}
841
842
	return (NULL);
843
}
844
845
846
int
847
kqueue_fnm_get_ev_recv_fd(kqueue_fnm_p kfnm) {
848
849
	if (NULL == kfnm || NULL != kfnm->tid)
850
		return (-1);
851
	return (kfnm->fd);
852
}
853
854
void
855
kqueue_fnm_proccess_events(kqueue_fnm_p kfnm) {
856
	struct kevent kev;
857
	struct timespec ke_timeout;
858
859
	if (NULL == kfnm || NULL != kfnm->tid)
860
		return;
861
	/* Get and proccess events, no wait. */
862
	memset(&ke_timeout, 0x00, sizeof(ke_timeout));
863
	while (0 < kevent(kfnm->fd, NULL, 0, &kev, 1, &ke_timeout)) {
864
		kqueue_fnm_proccess_event(kfnm, &kev);
865
	}
866
}
(-)devel/glib20/files/kqueue_fnm.h.in (+73 lines)
Line 0 Link Here
1
/*-
2
 * Copyright (c) 2016 - 2017 Rozhuk Ivan <rozhuk.im@gmail.com>
3
 * All rights reserved.
4
 *
5
 * Redistribution and use in source and binary forms, with or without
6
 * modification, are permitted provided that the following conditions
7
 * are met:
8
 * 1. Redistributions of source code must retain the above copyright
9
 *    notice, this list of conditions and the following disclaimer.
10
 * 2. Redistributions in binary form must reproduce the above copyright
11
 *    notice, this list of conditions and the following disclaimer in the
12
 *    documentation and/or other materials provided with the distribution.
13
 *
14
 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
15
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
18
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24
 * SUCH DAMAGE.
25
 *
26
 * Author: Rozhuk Ivan <rozhuk.im@gmail.com>
27
 *
28
 */
29
30
31
32
#ifndef __KQUEUE_FILE_NOTIFY_MONITOR_H__
33
#define __KQUEUE_FILE_NOTIFY_MONITOR_H__
34
35
#include <sys/param.h>
36
#include <sys/types.h>
37
#include <inttypes.h>
38
39
40
typedef struct kqueue_file_nonify_monitor_s	*kqueue_fnm_p;
41
typedef struct kqueue_file_mon_data_s		*kqueue_file_mon_data_p;
42
43
typedef void (*kfnm_event_handler_cb)(kqueue_fnm_p kfnm,
44
			       kqueue_file_mon_data_p fmd, void *udata,
45
			       uint32_t event,
46
			       const char *base,
47
			       const char *filename,
48
			       const char *new_filename);
49
#define KF_EVENT_NOT_CHANGED	0 /* Internal use. */
50
#define KF_EVENT_CREATED	1
51
#define KF_EVENT_DELETED	2
52
#define KF_EVENT_RENAMED	3
53
#define KF_EVENT_CHANGED	4
54
55
56
typedef struct kqueue_file_mon_settings_s {
57
	int			use_thread;
58
	int			mon_local_subfiles;	/* Enable monitoring files/subdirs changes on local file systems. */
59
} kqueue_file_mon_settings_t, *kqueue_file_mon_settings_p;
60
61
kqueue_fnm_p	kqueue_fnm_create(kqueue_file_mon_settings_p s,
62
		    kfnm_event_handler_cb cb_func);
63
void		kqueue_fnm_free(kqueue_fnm_p kfnm);
64
65
kqueue_file_mon_data_p	kqueue_fnm_add(kqueue_fnm_p kfnm,
66
			    const char *path, void *udata);
67
void		kqueue_fnm_del(kqueue_fnm_p kfnm, kqueue_file_mon_data_p fmd);
68
69
int		kqueue_fnm_get_ev_recv_fd(kqueue_fnm_p kfnm);
70
void		kqueue_fnm_proccess_events(kqueue_fnm_p kfnm);
71
72
73
#endif /* __KQUEUE_FILE_NOTIFY_MONITOR_H__ */

Return to bug 214338