2 * Copyright 2012 Samsung Electronics Co., Ltd
4 * Licensed under the Flora License, Version 1.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://floralicense.org/license/
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
24 #include <sys/inotify.h>
25 #include <sys/types.h>
33 #include "mf-ug-dlog.h"
34 #include "mf-ug-inotify-handle.h"
36 #define MF_WATCH_FLAGS \
37 IN_CREATE | IN_DELETE | IN_DELETE_SELF | IN_MOVE_SELF | IN_MOVED_FROM | IN_MOVED_TO | IN_CLOSE_WRITE
39 #define MF_EVENT_SIZE (sizeof(struct inotify_event))
40 /** reasonable guess as to size of 1024 events */
41 #define MF_EVENT_BUF_LEN (1024 * (MF_EVENT_SIZE + 16))
42 #define MF_U32_MAX 0xFFFFFFFF
43 typedef struct _mf_inotify_t {
47 unsigned int prev_event;
49 mf_ug_inotify_cb callback;
53 static pthread_mutex_t mf_noti_lock;
54 static mf_inotify_t *g_handle;
56 static void __mf_ug_inotify_handle_free_handle(void)
58 pthread_mutex_destroy(&mf_noti_lock);
61 if (g_handle->fd >= 0) {
66 g_free(g_handle->path);
67 g_handle->path = NULL;
76 static mf_inotify_t *__mf_ug_inotify_handle_init_handle(void)
78 __mf_ug_inotify_handle_free_handle();
79 g_handle = g_new0(mf_inotify_t, 1);
83 pthread_mutex_init(&mf_noti_lock, NULL);
84 pthread_mutex_lock(&mf_noti_lock);
86 pthread_mutex_unlock(&mf_noti_lock);
92 static void __mf_ug_inotify_handle_clean_up_thread(void *data)
94 pthread_mutex_t *lock = (pthread_mutex_t *) data;
95 ug_mf_debug("Thread cancel Clean_up function");
97 pthread_mutex_unlock(lock);
103 static gpointer __mf_ug_inotify_handle_watch_thread(gpointer user_data)
105 mf_inotify_t *handle = (mf_inotify_t *) user_data;
108 ug_mf_retvm_if(handle == NULL, NULL, "handle is NULL");
109 ug_mf_debug("Create __mf_ug_inotify_handle_watch_thread!!! ");
111 pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, &oldtype);
116 char event_buff[MF_EVENT_BUF_LEN] = { 0, };
118 if (handle->fd < 0) {
119 ug_mf_error("fd is not a vaild one");
123 len = read(handle->fd, event_buff, sizeof(event_buff) - 1);
124 if (len <= 0 || len > sizeof(event_buff) - 1) {
125 ug_mf_error("Fail to read() -fd : %d, len : %d", handle->fd, len);
130 struct inotify_event *pevent = (struct inotify_event *)&event_buff[i];
131 mf_ug_inotify_event s_event = UG_MF_INOTI_NONE;
132 ug_mf_error("mask=%x dir=%s len=%d name=%s",
133 pevent->mask, (pevent->mask & IN_ISDIR) ? "yes" : "no", pevent->len, (pevent->len) ? pevent->name : NULL);
135 if (pevent->len && strncmp(pevent->name, ".", 1) == 0) {
136 s_event = UG_MF_INOTI_NONE;
137 } else if (pevent->mask & IN_ISDIR) {
138 if (pevent->mask & IN_DELETE_SELF)
139 s_event = UG_MF_INOTI_DELETE_SELF;
141 if (pevent->mask & IN_MOVE_SELF)
142 s_event = UG_MF_INOTI_MOVE_SELF;
144 if (pevent->mask & IN_CREATE)
145 s_event = UG_MF_INOTI_CREATE;
147 if (pevent->mask & IN_DELETE)
148 s_event = UG_MF_INOTI_DELETE;
150 if (pevent->mask & IN_MOVED_FROM)
151 s_event = UG_MF_INOTI_MOVE_OUT;
153 if (pevent->mask & IN_MOVED_TO)
154 s_event = UG_MF_INOTI_MOVE_IN;
156 if (pevent->mask & IN_CREATE) {
157 s_event = UG_MF_INOTI_NONE;
158 handle->prev_event = IN_CREATE;
161 if (pevent->mask & IN_CLOSE_WRITE) {
162 if (handle->prev_event == IN_CREATE) {
163 s_event = UG_MF_INOTI_CREATE;
165 s_event = UG_MF_INOTI_MODIFY;
167 handle->prev_event = 0;
170 if (pevent->mask & IN_DELETE)
171 s_event = UG_MF_INOTI_DELETE;
173 if (pevent->mask & IN_MOVED_FROM)
174 s_event = UG_MF_INOTI_MOVE_OUT;
176 if (pevent->mask & IN_MOVED_TO)
177 s_event = UG_MF_INOTI_MOVE_IN;
180 ug_mf_debug("s_event : %d, prev_event: %x, callback : %p", s_event, handle->prev_event, handle->callback);
181 if (s_event != UG_MF_INOTI_NONE) {
182 pthread_cleanup_push(__mf_ug_inotify_handle_clean_up_thread, (void *)&mf_noti_lock);
183 pthread_mutex_lock(&mf_noti_lock);
184 if (handle->callback) {
185 handle->callback(s_event, (pevent->len) ? pevent->name : NULL, handle->u_data);
187 pthread_mutex_unlock(&mf_noti_lock);
188 pthread_cleanup_pop(0);
191 if ((MF_U32_MAX - pevent->len) >= MF_EVENT_SIZE) {
192 i += sizeof(struct inotify_event) + pevent->len;
199 ug_mf_debug("end __mf_ug_inotify_handle_watch_thread!!! ");
204 int mf_ug_inotify_handle_init_inotify(void)
206 mf_inotify_t *handle = NULL;
207 handle = __mf_ug_inotify_handle_init_handle();
208 ug_mf_retvm_if(handle == NULL, -1, "fail to __mf_ug_inotify_handle_init_handle()");
210 handle->fd = inotify_init();
212 if (handle->fd < 0) {
215 ug_mf_error("The user limit on the total number of inotify instances has been reached.\n");
218 ug_mf_error("The system limit on the total number of file descriptors has been reached.\n");
221 ug_mf_error("Insufficient kernel memory is available.\n");
224 ug_mf_error("Fail to inotify_init(), Unknown error.\n");
229 pthread_create(&handle->monitor, NULL, __mf_ug_inotify_handle_watch_thread, handle);
233 int mf_ug_inotify_handle_add_inotify_watch(const char *path, mf_ug_inotify_cb callback, void *user_data)
235 mf_inotify_t *handle = NULL;
237 ug_mf_retvm_if(handle == NULL, -1, "handle is NULL");
239 if (handle->wd >= 0) {
240 ug_mf_warnig("The mf_notify module supports single instance, the watch descript [%d] is removed automatically\n", handle->wd);
241 mf_ug_inotify_handle_rm_inotify_watch();
244 pthread_mutex_lock(&mf_noti_lock);
245 handle->wd = inotify_add_watch(handle->fd, path, MF_WATCH_FLAGS);
247 if (handle->wd < 0) {
250 ug_mf_error("Read access to the given file is not permitted.\n");
253 ug_mf_error("The given file descriptor is not valid.\n");
257 ug_mf_error("pathname points outside of the process's accessible address space.\n");
260 ug_mf_error("The given event mask contains no legal events; or fd is not an inotify file descriptor.\n");
263 ug_mf_error("Insufficient kernel memory is available.\n");
266 ug_mf_error("User limit on the total num of inotify watch was reached or the kernel failed to alloc a needed resource.\n");
269 ug_mf_error("Fail to ug_ug_mf_inotify_add_watch(), Unknown error.\n");
272 pthread_mutex_unlock(&mf_noti_lock);
276 ug_mf_debug("start watching [%s] directory", path);
278 g_free(handle->path);
281 handle->path = g_strdup(path);
282 handle->callback = callback;
283 handle->u_data = user_data;
284 pthread_mutex_unlock(&mf_noti_lock);
291 int mf_ug_inotify_handle_rm_inotify_watch(void)
294 mf_inotify_t *handle = NULL;
297 ug_mf_retvm_if(handle == NULL, -1, "handle is NULL");
299 if (handle->fd < 0 || handle->wd < 0) {
300 ug_mf_warnig("inotify is not initialized or has no watching dir - fd [%d] wd [%d]", handle->fd, handle->wd);
304 pthread_mutex_lock(&mf_noti_lock);
306 ret = inotify_rm_watch(handle->fd, handle->wd);
310 ug_mf_error("fd is not a valid file descriptor\n");
314 ug_mf_error("The watch descriptor wd is not valid; or fd is not an inotify file descriptor.\n");
318 ug_mf_error("Fail to mf_ug_inotify_handle_add_inotify_watch(), Unknown error.\n");
321 pthread_mutex_unlock(&mf_noti_lock);
324 ug_mf_debug("stop watching [%s] directory", handle->path);
326 g_free(handle->path);
329 handle->callback = NULL;
330 handle->u_data = NULL;
332 pthread_mutex_unlock(&mf_noti_lock);
337 void mf_ug_inotify_handle_finalize_inotify(void)
339 mf_inotify_t *handle = NULL;
342 ug_mf_retm_if(handle == NULL, "handle is NULL");
344 if (handle->fd >= 0 && handle->wd >= 0) {
345 mf_ug_inotify_handle_rm_inotify_watch();
348 pthread_cancel(handle->monitor);
349 pthread_join(handle->monitor, NULL);
351 __mf_ug_inotify_handle_free_handle();