some playing with bbs - new fm
[mirrors/Programs.git] / bash / bbs / utils / fm / fm / ino.c
CommitLineData
db4042d6
H
1/* Copyright (C) 2008 Ricardo Catalinas Jiménez <jimenezrick@gmail.com>
2 *
3 * This program is free software: you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License as published by
5 * the Free Software Foundation, either version 3 of the License, or
6 * (at your option) any later version.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 */
16
17#ifdef INOTIFY
18
19#include "fm.h"
20
21gboolean inotify_enabled = FALSE, debug_inotify = FALSE;
22GHashTable *watches_table;
23int inotify_descriptor;
24char events_buffer[BUFFER_LENGTH];
25
26void init_inotify(GNode *tree_root)
27{
28 if ((inotify_descriptor = inotify_init()) == -1) {
29 PRINT_ERRNO_INFO();
30 return;
31 }
32 watches_table = g_hash_table_new(g_int_hash, g_int_equal);
33 inotify_enabled = TRUE;
34}
35
36void stop_inotify(void)
37{
38 CHECK_INOTIFY_ENABLED();
39 g_hash_table_destroy(watches_table);
40 close(inotify_descriptor);
41 inotify_enabled = FALSE;
42}
43
44void add_watch_directory(GNode *directory)
45{
46 char *path;
47 int watch;
48
49 CHECK_INOTIFY_ENABLED();
50 path = get_path(directory);
51 if ((watch = inotify_add_watch(inotify_descriptor, path, IN_CREATE | IN_MOVED_FROM |
52 IN_MOVED_TO | IN_DELETE)) == -1)
53 PRINT_ERRNO_INFO();
54 else {
55 FILE(directory)->watch = watch;
56 g_hash_table_insert(watches_table, &(FILE(directory)->watch), directory);
57 }
58 free(path);
59}
60
61void remove_watch_directory(GNode *directory, gboolean remove_watch)
62{
63 CHECK_INOTIFY_ENABLED();
64 if (FILE(directory)->watch == -1)
65 PRINT_ERROR_INFO("Directory doesn't have a watch associated");
66 else if (remove_watch && inotify_rm_watch(inotify_descriptor, FILE(directory)->watch) == -1)
67 PRINT_ERRNO_INFO();
68 else if (g_hash_table_remove(watches_table, &(FILE(directory)->watch)) == FALSE)
69 PRINT_ERROR_INFO("Element removal failed in watches_table");
70}
71
72void watch_events(void)
73{
74 GNode *modified_directory, *removed_file;
75 File *new_file;
76 gboolean refresh_request = FALSE;
77 struct timeval time;
78 struct inotify_event *event;
79 int n, i;
80 fd_set fds;
81
82 CHECK_INOTIFY_ENABLED();
83again: time.tv_sec = 0;
84 time.tv_usec = 0;
85 FD_ZERO(&fds);
86 FD_SET(inotify_descriptor, &fds);
87 while ((n = select(inotify_descriptor + 1, &fds, NULL, NULL, &time)) == 1) {
88again2: if ((n = read(inotify_descriptor, events_buffer, BUFFER_LENGTH)) > 0) {
89 for (i = 0; i < n; i += sizeof(struct inotify_event) + event->len) {
90 event = (struct inotify_event *) (events_buffer + i);
91 if (debug_inotify == TRUE)
92 dump_event(event);
93 modified_directory = (GNode *) g_hash_table_lookup(
94 watches_table, &(event->wd));
95
96 if (event->mask & IN_CREATE || event->mask & IN_MOVED_TO) {
97 if ((new_file = create_new_file(event->name,
98 get_path(modified_directory), FALSE)) != NULL)
99 refresh_request |= insert_in_tree(modified_directory, new_file);
100 } else if (event->mask & IN_DELETE || event->mask & IN_MOVED_FROM) {
101 if ((removed_file = search_node_by_name(modified_directory,
102 event->name)) != NULL)
103 refresh_request |= remove_from_tree(removed_file, FALSE);
104 } else if (event->mask & IN_UNMOUNT) {
105 refresh_request |= remove_from_tree(modified_directory, TRUE);
106 }
107 }
108 } else if (n == -1) {
109 if (errno == EINTR)
110 goto again2;
111 else
112 PRINT_ERRNO_AND_EXIT();
113 }
114 }
115 if (n == -1) {
116 if (errno == EINTR)
117 goto again;
118 else
119 PRINT_ERRNO_AND_EXIT();
120 }
121 if (refresh_request == TRUE)
122 refresh_screen();
123}
124
125gboolean insert_in_tree(GNode *directory, File *file)
126{
127 GNode *new_file, *file_ptr;
128 int position;
129
130 if (file->name[0] == '.' && FILE(directory)->show_dotfiles == FALSE) {
131 insert_sorted_in_dotfiles(directory, file);
132
133 return FALSE;
134 }
135 new_file = insert_sorted_in_tree(directory, file);
136 file_ptr = get_previous_file(new_file);
137 position = g_list_position(lines, FILE(file_ptr)->line);
138 lines = g_list_insert(lines, new_file, position + 1);
139 file->line = g_list_nth(lines, position + 1);
140
141 if (g_list_length(first_line) - g_list_length(last_line) + 1) {
142 if (g_list_previous(first_line) == file->line)
143 first_line = file->line;
144 else if (g_list_next(last_line) == file->line)
145 last_line = file->line;
146 }
147 if (g_list_position(lines, first_line) <= position + 1 &&
148 position + 1 <= g_list_position(lines, last_line)) {
149 if (position + 1 < g_list_position(lines, selected_line)) {
150 if (g_list_length(first_line) <= getmaxy(tree_window))
151 print_lines(first_line, last_line, FALSE);
152 else {
153 first_line = g_list_next(first_line);
154 print_lines(first_line, file->line, FALSE);
155 }
156 } else {
157 if (g_list_length(first_line) > getmaxy(tree_window))
158 last_line = g_list_previous(last_line);
159
160 if (g_node_last_sibling(new_file) == new_file)
161 print_lines(g_list_previous(file->line), last_line, FALSE);
162 else
163 print_lines(file->line, last_line, FALSE);
164 }
165
166 return TRUE;
167 }
168
169 return FALSE;
170}
171
172gboolean remove_from_tree(GNode *file, gboolean unmount)
173{
174 int position = g_list_position(lines, FILE(file)->line);
175 gboolean refresh_needed = FALSE;
176 GList *line_ptr, *line_ptr2;
177
178 if (G_NODE_IS_ROOT(file)) {
179 endwin();
180 clean_up();
181 printf("The tree root was removed\n");
182 exit(EXIT_SUCCESS);
183 }
184 if (g_node_is_ancestor(file, NODE(selected_line)))
185 select_file(file);
186 if (FILE(file)->type == directory_type) {
187 close_directory(file);
188 destroy_directory_content_real(file, FALSE);
189 if (unmount)
190 return TRUE;
191 }
192 g_node_unlink(file);
193
194 if (g_list_position(lines, first_line) <= position &&
195 position <= g_list_position(lines, last_line)) {
196 if (first_line == FILE(file)->line && selected_line == FILE(file)->line) {
197 selected_line = first_line = g_list_previous(first_line);
198 lines = g_list_delete_link(lines, FILE(file)->line);
199 print_lines(first_line, first_line, FALSE);
200 } else if (position < g_list_position(lines, selected_line)) {
201 if (first_line == FILE(file)->line)
202 first_line = g_list_next(first_line);
203 line_ptr = g_list_previous(FILE(file)->line);
204 lines = g_list_delete_link(lines, FILE(file)->line);
205 if ((line_ptr2 = g_list_previous(first_line)) != NULL) {
206 first_line = line_ptr2;
207 print_lines(first_line, line_ptr, FALSE);
208 } else if ((line_ptr2 = g_list_next(last_line)) != NULL) {
209 last_line = line_ptr2;
210 print_lines(line_ptr, last_line, FALSE);
211 } else
212 print_lines(line_ptr, last_line, TRUE);
213 } else {
214 if (FILE(file)->line == selected_line)
215 selected_line = g_list_previous(selected_line);
216 if (last_line == FILE(file)->line)
217 last_line = g_list_previous(last_line);
218 line_ptr = g_list_previous(FILE(file)->line);
219 lines = g_list_delete_link(lines, FILE(file)->line);
220 if ((line_ptr2 = g_list_next(last_line)) != NULL) {
221 last_line = line_ptr2;
222 print_lines(line_ptr, last_line, FALSE);
223 } else
224 print_lines(line_ptr, last_line, TRUE);
225 }
226 refresh_needed = TRUE;
227 } else {
228 if (last_line == g_list_previous(FILE(file)->line)) {
229 lines = g_list_delete_link(lines, FILE(file)->line);
230 print_lines(last_line, last_line, FALSE);
231 refresh_needed = TRUE;
232 } else
233 lines = g_list_delete_link(lines, FILE(file)->line);
234 }
235 free_node_data(file, NULL);
236 g_node_destroy(file);
237
238 return refresh_needed;
239}
240
241GNode *search_node_by_name(GNode *directory, char *name)
242{
243 GNode *file_ptr;
244
245 for (file_ptr = g_node_first_child(directory); file_ptr != NULL;
246 file_ptr = g_node_next_sibling(file_ptr)) {
247 if (!strcmp(FILE(file_ptr)->name, name))
248 return file_ptr;
249 }
250
251 return NULL;
252}
253
254void dump_event(struct inotify_event *event)
255{
256 static int first = 0;
257
258 if (first != 0)
259 fprintf(stderr, "================================\n");
260 if (event->len > 0) {
261 fprintf(stderr, "wd = %i\ncookie = %i\nlen = %i\nname = %s\nmask = ",
262 event->wd, event->cookie, event->len, event->name);
263 } else {
264 fprintf(stderr, "wd = %i\ncookie = %i\nlen = %i\nname =\nmask = ",
265 event->wd, event->cookie, event->len);
266 }
267 dump_mask(event->mask);
268 first = 1;
269}
270
271void dump_mask(int mask)
272{
273 if (mask & IN_ACCESS)
274 fprintf(stderr, " IN_ACCESS ");
275 if (mask & IN_ATTRIB)
276 fprintf(stderr, " IN_ATTRIB ");
277 if (mask & IN_CLOSE_WRITE)
278 fprintf(stderr, " IN_CLOSE_WRITE ");
279 if (mask & IN_CLOSE_NOWRITE)
280 fprintf(stderr, " IN_CLOSE_NOWRITE ");
281 if (mask & IN_CREATE)
282 fprintf(stderr, " IN_CREATE ");
283 if (mask & IN_DELETE)
284 fprintf(stderr, " IN_DELETE ");
285 if (mask & IN_DELETE_SELF)
286 fprintf(stderr, " IN_DELETE_SELF ");
287 if (mask & IN_MODIFY)
288 fprintf(stderr, " IN_MODIFY ");
289 if (mask & IN_MOVE_SELF)
290 fprintf(stderr, " IN_MOVE_SELF ");
291 if (mask & IN_MOVED_FROM)
292 fprintf(stderr, " IN_MOVED_FROM ");
293 if (mask & IN_MOVED_TO)
294 fprintf(stderr, " IN_MOVED_TO ");
295 if (mask & IN_OPEN)
296 fprintf(stderr, " IN_OPEN ");
297 if (mask & IN_IGNORED)
298 fprintf(stderr, " IN_IGNORED ");
299 if (mask & IN_ISDIR)
300 fprintf(stderr, " IN_ISDIR ");
301 if (mask & IN_Q_OVERFLOW)
302 fprintf(stderr, " IN_Q_OVERFLOW ");
303 if (mask & IN_UNMOUNT)
304 fprintf(stderr, " IN_UNMOUNT ");
305 fprintf(stderr, "\n");
306}
307
308#endif
This page took 0.554701 seconds and 4 git commands to generate.