dbc9f3fdb11cb8f73440b8c95b550f733701ff84
[platform/core/uifw/pepper.git] / src / lib / inotify / pepper-inotify.c
1 /*
2 * Copyright © 2015-2017 Samsung Electronics co., Ltd. All Rights Reserved.
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 * and/or sell copies of the Software, and to permit persons to whom the
9 * Software is furnished to do so, subject to the following conditions:
10 *
11 * The above copyright notice and this permission notice (including the next
12 * paragraph) shall be included in all copies or substantial portions of the
13 * Software.
14 *
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
18 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
21 * DEALINGS IN THE SOFTWARE.
22 */
23
24 #define _GNU_SOURCE
25
26 #include <sys/types.h>
27 #include <sys/stat.h>
28 #include <fcntl.h>
29 #include <unistd.h>
30 #include <string.h>
31 #include <errno.h>
32 #include <stdint.h>
33 #include <dirent.h>
34 #include <stdlib.h>
35 #include <stdio.h>
36 #include <linux/input.h>
37 #include <sys/inotify.h>
38
39 #include <pepper-inotify-internal.h>
40
41 static void
42 _inotify_event_post(pepper_inotify_watch_t *watch, pepper_inotify_event_type_t type, const char *name, pepper_bool_t is_dir)
43 {
44         pepper_inotify_event_t ev;
45
46         PEPPER_CHECK(watch->inotify->callback.cb, return, "Current inotify has no callback");
47
48         ev.inotify = watch->inotify;
49
50         ev.name = (char *)name;
51         ev.is_dir = is_dir;
52         ev.path = watch->path;
53
54         watch->inotify->callback.cb(type, &ev, watch->inotify->callback.data);
55 }
56
57 static void
58 _inotify_event_process(struct inotify_event *ev, pepper_inotify_watch_t *watch)
59 {
60         if (!ev->len) return;
61
62         if (ev->mask & IN_CREATE) {
63                 _inotify_event_post(watch, PEPPER_INOTIFY_EVENT_TYPE_CREATE,
64                                         ev->name, (ev->mask & IN_ISDIR) ? PEPPER_TRUE : PEPPER_FALSE);
65         }
66         else if (ev->mask & IN_DELETE) {
67                 _inotify_event_post(watch, PEPPER_INOTIFY_EVENT_TYPE_REMOVE,
68                                         ev->name, (ev->mask & IN_ISDIR) ? PEPPER_TRUE : PEPPER_FALSE);
69         }
70         else if (ev->mask & IN_MODIFY) {
71                 _inotify_event_post(watch, PEPPER_INOTIFY_EVENT_TYPE_MODIFY,
72                                         ev->name, (ev->mask & IN_ISDIR) ? PEPPER_TRUE : PEPPER_FALSE);
73         }
74 }
75
76 static int
77 _inotify_fd_read(int fd, uint32_t mask, void *data)
78 {
79         uint32_t i;
80         int nread;
81         char buf[128];
82         struct inotify_event ev[32];
83         pepper_inotify_watch_t *watch_data = data;
84
85         PEPPER_CHECK(!(mask & (WL_EVENT_HANGUP | WL_EVENT_ERROR)),
86                         return 0,
87                         "[%s] With the given fd, there is an error or it's been hung-up.\n",
88                         __FUNCTION__);
89
90         if (!(mask & WL_EVENT_READABLE))
91                 return 0;
92
93         nread = read(fd, &ev, sizeof(ev));
94         PEPPER_CHECK(nread >= 0, return 0,
95                         "Failed on reading given fd. (error : %s, fd:%d)\n",
96                         strerror_r(errno, buf, 128), fd);
97
98         for (i = 0 ; i < (nread / sizeof(ev[0])); i++) {
99                 if (ev[i].wd == watch_data->wd)
100                         _inotify_event_process(&ev[i], watch_data);
101         }
102
103         return 0;
104 }
105
106 PEPPER_API char *
107 pepper_inotify_event_name_get(pepper_inotify_event_t *ev)
108 {
109         PEPPER_CHECK(ev, return NULL,
110                         "Invalid inotify event\n");
111
112         return ev->name;
113 }
114
115 PEPPER_API char *
116 pepper_inotify_event_path_get(pepper_inotify_event_t *ev)
117 {
118         PEPPER_CHECK(ev, return NULL,
119                         "Invalid inotify event\n");
120
121         return ev->path;
122 }
123
124 PEPPER_API pepper_bool_t
125 pepper_inotify_event_is_directory(pepper_inotify_event_t *ev)
126 {
127         PEPPER_CHECK(ev, return PEPPER_FALSE,
128                         "Invalid inotify event\n");
129
130         return ev->is_dir;
131 }
132
133 PEPPER_API pepper_bool_t
134 pepper_inotify_add(pepper_inotify_t *inotify, const char *path)
135 {
136         pepper_inotify_watch_t *watch_data;
137         char buf[128];
138
139         PEPPER_CHECK(inotify, return PEPPER_FALSE, "Invalid pepper_inotify_t object\n");
140         PEPPER_CHECK(path, return PEPPER_FALSE, "Invalid path\n");
141
142         watch_data = (pepper_inotify_watch_t *)calloc(1, sizeof(pepper_inotify_watch_t));
143         PEPPER_CHECK(watch_data, return PEPPER_FALSE,
144                 "Failed to allocate pepper_inotify_watch_t\n");
145
146         watch_data->inotify = inotify;
147
148         watch_data->wd = inotify_add_watch(inotify->fd, path,
149                         IN_MODIFY | IN_CREATE | IN_DELETE | IN_MOVED_FROM | IN_MOVED_TO | IN_MOVE_SELF);
150         PEPPER_CHECK(watch_data->wd >= 0, goto failed,
151                         "Failed to add watch for %s\n", path, strerror_r(errno, buf, 128));
152
153         strncpy(watch_data->path, path, MAX_PATH_LEN - 1);
154
155         watch_data->event_source = wl_event_loop_add_fd(inotify->event_loop, inotify->fd,
156                         WL_EVENT_READABLE, _inotify_fd_read, watch_data);
157         PEPPER_CHECK(watch_data->event_source, goto failed,
158                         "Failed to add fd as an event source.\n");
159
160         pepper_list_insert(&inotify->watched_list, &watch_data->link);
161
162         return PEPPER_TRUE;
163
164 failed:
165         if (watch_data->event_source)
166                 wl_event_source_remove(watch_data->event_source);
167         if (watch_data->wd)
168                 inotify_rm_watch(inotify->fd, watch_data->wd);
169         free(watch_data);
170
171         return PEPPER_FALSE;
172 }
173
174 PEPPER_API void
175 pepper_inotify_del(pepper_inotify_t *inotify, const char *path)
176 {
177         pepper_inotify_watch_t *watch_data, *watch_data_tmp;
178
179         PEPPER_CHECK(inotify, return, "Invalid pepper_inotify_t object\n");
180         PEPPER_CHECK(path, return, "Invalid path\n");
181
182         if (!pepper_list_empty(&inotify->watched_list))
183         {
184                 pepper_list_for_each_safe(watch_data, watch_data_tmp, &inotify->watched_list, link)
185                 {
186                         if (!strncmp(watch_data->path, path, MAX_PATH_LEN - 1))
187                         {
188                                 if (watch_data->wd)
189                                         inotify_rm_watch(inotify->fd, watch_data->wd);
190                                 if (watch_data->event_source)
191                                         wl_event_source_remove(watch_data->event_source);
192                                 pepper_list_remove(&watch_data->link);
193                                 free(watch_data);
194                                 break;
195                         }
196                 }
197         }
198 }
199
200 PEPPER_API pepper_inotify_t *
201 pepper_inotify_create(pepper_compositor_t *compositor, pepper_inotify_event_cb_t cb, void *data)
202 {
203         pepper_inotify_t *inotify;
204
205         PEPPER_CHECK(compositor, return NULL, "Invalid compositor object\n");
206
207         inotify = (pepper_inotify_t *)calloc(1, sizeof(pepper_inotify_t));
208         PEPPER_CHECK(inotify, return NULL, "Failed to allocate pepper_inotify_t\n");
209
210         inotify->display = pepper_compositor_get_display(compositor);
211         PEPPER_CHECK(inotify->display, goto failed, "Invaild wl_display\n");
212
213         inotify->event_loop = wl_display_get_event_loop(inotify->display);
214         PEPPER_CHECK(inotify->event_loop, goto failed, "Invaild wl_event_loop\n");
215
216         inotify->fd = inotify_init();
217         PEPPER_CHECK(inotify->fd >= 0, goto failed, "Failed to init inotify. fd: %d\n", inotify->fd);
218
219         inotify->callback.cb = cb;
220         inotify->callback.data = data;
221
222         pepper_list_init(&inotify->watched_list);
223
224         return inotify;
225
226 failed:
227         if (inotify) {
228                 if (inotify->fd)
229                         close(inotify->fd);
230                 free(inotify);
231         }
232         return NULL;
233 }
234
235 PEPPER_API void
236 pepper_inotify_destroy(pepper_inotify_t *inotify)
237 {
238         pepper_inotify_watch_t *watch_data, *watch_data_tmp;
239
240         PEPPER_CHECK(inotify, return, "Invalid pepper_inotify_t object\n");
241
242         if (!pepper_list_empty(&inotify->watched_list))
243         {
244                 pepper_list_for_each_safe(watch_data, watch_data_tmp, &inotify->watched_list, link)
245                 {
246                         if (watch_data->wd)
247                                 inotify_rm_watch(inotify->fd, watch_data->wd);
248                         if (watch_data->event_source)
249                                 wl_event_source_remove(watch_data->event_source);
250
251                         pepper_list_remove(&watch_data->link);
252                         free(watch_data);
253                 }
254
255                 pepper_list_remove(&inotify->watched_list);
256         }
257
258         if (inotify->fd)
259                 close(inotify->fd);
260
261         free(inotify);
262         inotify = NULL;
263 }
264