2 * Copyright 2013 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.
22 #include <sys/inotify.h>
23 #include <sys/types.h>
32 #include "mf-inotify-handle.h"
34 #define MF_WATCH_FLAGS \
35 IN_CREATE | IN_DELETE | IN_DELETE_SELF | IN_MOVE_SELF | IN_MOVED_FROM | IN_MOVED_TO | IN_CLOSE_WRITE
37 #define MF_EVENT_SIZE (sizeof(struct inotify_event))
38 /** reasonable guess as to size of 1024 events */
39 #define MF_EVENT_BUF_LEN (1024 * (MF_EVENT_SIZE + 16))
40 #define MF_U32_MAX 0xFFFFFFFF
42 int flagInotifyMsg = 1;
43 pthread_cond_t g_cond_inotify_msg;
45 typedef struct _mf_inotify_t {
49 unsigned int prev_event;
51 mf_inotify_cb callback;
55 static pthread_mutex_t mf_noti_lock;
56 static mf_inotify_t *g_handle = NULL;
58 static void __mf_inotify_handle_free(void)
60 pthread_mutex_destroy(&mf_noti_lock);
63 if (g_handle->fd >= 0) {
68 g_free(g_handle->path);
69 g_handle->path = NULL;
78 static mf_inotify_t *__mf_inotify_handle_init(void)
80 __mf_inotify_handle_free();
81 g_handle = g_new0(mf_inotify_t, 1);
86 pthread_mutex_init(&mf_noti_lock, NULL);
92 static void __mf_inotify_handle_thread_clean_up(void *data)
94 pthread_mutex_t *lock = (pthread_mutex_t *) data;
95 mf_debug("Thread cancel Clean_up function");
97 pthread_mutex_unlock(lock);
103 static gpointer __mf_inotify_handle_watch_thread(gpointer user_data)
105 mf_inotify_t *handle = (mf_inotify_t *) user_data;
108 mf_retvm_if(handle == NULL, NULL, "handle is NULL");
109 mf_debug("Create __mf_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 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 mf_error("Fail to read() -fd : %d, len : %d", handle->fd, len);
132 struct inotify_event *pevent = (struct inotify_event *)&event_buff[i];
133 mf_inotify_event s_event = MF_INOTI_NONE;
134 mf_debug("mask=%x dir=%s len=%d name=%s",
135 pevent->mask, (pevent->mask & IN_ISDIR) ? "yes" : "no", pevent->len, (pevent->len) ? pevent->name : NULL);
137 if (pevent->len && strncmp(pevent->name, ".", 1) == 0) {
138 s_event = MF_INOTI_NONE;
139 } else if (pevent->mask & IN_ISDIR) {
140 if (pevent->mask & IN_DELETE_SELF)
141 s_event = MF_INOTI_DELETE_SELF;
143 if (pevent->mask & IN_MOVE_SELF)
144 s_event = MF_INOTI_MOVE_SELF;
146 if (pevent->mask & IN_CREATE)
147 s_event = MF_INOTI_CREATE;
149 if (pevent->mask & IN_DELETE)
150 s_event = MF_INOTI_DELETE;
152 if (pevent->mask & IN_MOVED_FROM)
153 s_event = MF_INOTI_MOVE_OUT;
155 if (pevent->mask & IN_MOVED_TO)
156 s_event = MF_INOTI_MOVE_IN;
158 if (pevent->mask & IN_CREATE) {
159 s_event = MF_INOTI_NONE;
160 handle->prev_event = IN_CREATE;
163 if (pevent->mask & IN_CLOSE_WRITE) {
164 if (handle->prev_event == IN_CREATE) {
165 s_event = MF_INOTI_CREATE;
167 s_event = MF_INOTI_MODIFY;
169 handle->prev_event = 0;
172 if (pevent->mask & IN_DELETE)
173 s_event = MF_INOTI_DELETE;
175 if (pevent->mask & IN_MOVED_FROM)
176 s_event = MF_INOTI_MOVE_OUT;
178 if (pevent->mask & IN_MOVED_TO)
179 s_event = MF_INOTI_MOVE_IN;
182 mf_debug("s_event : %d, prev_event: %x, callback : %p", s_event, handle->prev_event, handle->callback);
183 if (s_event != MF_INOTI_NONE) {
184 pthread_cleanup_push(__mf_inotify_handle_thread_clean_up, (void *)&mf_noti_lock);
185 pthread_mutex_lock(&mf_noti_lock);
187 while (flagInotifyMsg == 0) {
188 mf_debug("!!!!!!!!!!!! wait");
189 pthread_cond_wait(&g_cond_inotify_msg, &mf_noti_lock);
193 if (handle->callback) {
194 handle->callback(s_event, (pevent->len) ? pevent->name : NULL, handle->u_data);
196 pthread_mutex_unlock(&mf_noti_lock);
197 pthread_cleanup_pop(0);
200 if ((MF_U32_MAX - pevent->len) >= MF_EVENT_SIZE) {
201 i += sizeof(struct inotify_event) + pevent->len;
208 mf_debug("end __mf_inotify_handle_watch_thread!!! ");
213 void mf_inotify_handle_request_handled_send()
215 pthread_mutex_lock(&mf_noti_lock);
216 if (flagInotifyMsg == 0) {
218 pthread_cond_signal(&g_cond_inotify_msg);
220 pthread_mutex_unlock(&mf_noti_lock);
223 int mf_inotify_handle_init_inotify(void)
225 mf_inotify_t *handle = NULL;
226 handle = __mf_inotify_handle_init();
227 mf_retvm_if(handle == NULL, -1, "fail to __mf_inotify_handle_init()");
229 handle->fd = inotify_init();
231 if (handle->fd < 0) {
234 mf_error("The user limit on the total number of inotify instances has been reached.\n");
237 mf_error("The system limit on the total number of file descriptors has been reached.\n");
240 mf_error("Insufficient kernel memory is available.\n");
243 mf_error("Fail to inotify_init(), Unknown error.\n");
248 pthread_create(&handle->monitor, NULL, __mf_inotify_handle_watch_thread, handle);
252 int mf_inotify_handle_add_watch(const char *path, mf_inotify_cb callback, void *user_data)
254 mf_inotify_t *handle = NULL;
256 mf_retvm_if(handle == NULL, -1, "handle is NULL");
258 if (handle->wd >= 0) {
259 mf_warnig("The mf_notify module supports single instance, the watch descript [%d] is removed automatically\n", handle->wd);
260 mf_inotify_handle_rm_watch();
263 pthread_mutex_lock(&mf_noti_lock);
264 handle->wd = inotify_add_watch(handle->fd, path, MF_WATCH_FLAGS);
266 if (handle->wd < 0) {
269 mf_error("Read access to the given file is not permitted.\n");
272 mf_error("The given file descriptor is not valid.\n");
276 mf_error("pathname points outside of the process's accessible address space.\n");
279 mf_error("The given event mask contains no legal events; or fd is not an inotify file descriptor.\n");
282 mf_error("Insufficient kernel memory is available.\n");
285 mf_error("User limit on the total number of inotify watches was reached or the kernel failed to alloc a needed resource.\n");
288 mf_error("Fail to mf_inotify_handle_add_watch(), Unknown error.\n");
291 pthread_mutex_unlock(&mf_noti_lock);
295 mf_debug("start watching [%s] directory", path);
297 g_free(handle->path);
300 handle->path = g_strdup(path);
301 handle->callback = callback;
302 handle->u_data = user_data;
303 pthread_mutex_unlock(&mf_noti_lock);
310 int mf_inotify_handle_rm_watch(void)
313 mf_inotify_t *handle = NULL;
316 mf_retvm_if(handle == NULL, -1, "handle is NULL");
318 if (handle->fd < 0 || handle->wd < 0) {
319 mf_warnig("inotify is not initialized or has no watching dir - fd [%d] wd [%d]", handle->fd, handle->wd);
323 pthread_mutex_lock(&mf_noti_lock);
325 ret = inotify_rm_watch(handle->fd, handle->wd);
329 mf_error("fd is not a valid file descriptor\n");
333 mf_error("The watch descriptor wd is not valid; or fd is not an inotify file descriptor.\n");
337 mf_error("Fail to mf_inotify_handle_add_watch(), Unknown error.\n");
340 pthread_mutex_unlock(&mf_noti_lock);
343 mf_debug("stop watching [%s] directory", handle->path);
345 g_free(handle->path);
348 handle->callback = NULL;
349 handle->u_data = NULL;
351 pthread_mutex_unlock(&mf_noti_lock);
356 void mf_inotify_handle_finalize_inotify(void)
358 mf_inotify_t *handle = NULL;
361 mf_retm_if(handle == NULL, "handle is NULL");
363 if (handle->fd >= 0 && handle->wd >= 0) {
364 mf_inotify_handle_rm_watch();
367 pthread_cancel(handle->monitor);
368 pthread_join(handle->monitor, NULL);
370 __mf_inotify_handle_free();