Added some small boring scripts and programs writen in few last years
[mirrors/Programs.git] / bash / bbs / utils / fm / fm-1.0 / fs.c
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 #include "fm.h"
18
19 GNode *tree_root;
20
21 void init_tree(char *name)
22 {
23 char *path;
24
25 if (name != NULL)
26 tree_root = g_node_new(create_new_file(name, NULL, TRUE));
27 else {
28 path = g_get_current_dir();
29 tree_root = g_node_new(create_new_file(path, NULL, TRUE));
30 free(path);
31 }
32 }
33
34 File *create_new_file(char *name, char *path, gboolean exit_on_error)
35 {
36 struct stat info, link_info;
37 File *file = malloc(sizeof(File));
38 char *file_path;
39
40 if (path != NULL)
41 file_path = g_strconcat(path, "/", name, NULL);
42 else
43 file_path = name;
44
45 if (stat(file_path, &info) == -1) {
46 if (exit_on_error)
47 PRINT_ERRNO_AND_EXIT();
48 else {
49 PRINT_ERRNO_INFO();
50 file->type = file_type;
51 file->no_info = TRUE;
52 }
53 } else if (S_ISDIR(info.st_mode)) {
54 file->type = directory_type;
55 file->no_info = FALSE;
56 } else {
57 file->type = file_type;
58 file->no_info = FALSE;
59 }
60
61 if (lstat(file_path, &link_info) == -1) {
62 PRINT_ERRNO_INFO();
63 file->link_path = NULL;
64 file->link = FALSE;
65 } else if (S_ISLNK(link_info.st_mode)) {
66 if (link_info.st_size == 0)
67 link_info.st_size = PATH_MAX;
68
69 file->link_path = malloc(link_info.st_size + 1);
70 file->link_path[link_info.st_size] = '\0';
71 file->link_path[0] = '\0';
72 file->link = TRUE;
73
74 if (readlink(file_path, file->link_path, link_info.st_size) == -1)
75 PRINT_ERRNO_INFO();
76 } else {
77 file->link_path = NULL;
78 file->link = FALSE;
79 }
80 if (file->link == TRUE) {
81 file->no_info = FALSE;
82 file->info = link_info;
83 } else if (file->no_info == FALSE)
84 file->info = info;
85
86 file->name = strdup(name);
87 file->read = FALSE;
88 file->open = FALSE;
89 file->show_dotfiles = FALSE;
90 file->line = NULL;
91 file->dotfiles = NULL;
92
93 if (path != NULL)
94 free(file_path);
95
96 return file;
97 }
98
99 gboolean read_directory(GNode *directory)
100 {
101 DIR *dir;
102 struct dirent *entry;
103 File *new_file;
104 char *path = get_path(directory);
105
106 if ((dir = opendir(path)) == NULL) {
107 PRINT_ERRNO_INFO();
108 return FALSE;
109 }
110 for (; (entry = readdir(dir)) != NULL; ) {
111 if (!strcmp(entry->d_name, ".") || !strcmp(entry->d_name, ".."))
112 continue;
113
114 if ((new_file = create_new_file(entry->d_name, path, FALSE)) == NULL)
115 continue;
116
117 if (new_file->name[0] == '.')
118 insert_sorted_in_dotfiles(directory, new_file);
119 else
120 insert_sorted_in_tree(directory, new_file);
121 }
122 if (errno == EBADF)
123 PRINT_ERRNO_AND_EXIT();
124 if (closedir(dir) == -1)
125 PRINT_ERRNO_AND_EXIT();
126 free(path);
127 FILE(directory)->read = TRUE;
128
129 return TRUE;
130 }
131
132 void free_element_data(gpointer element_data, gpointer data)
133 {
134 if (FILE((GNode *) element_data)->type == directory_type)
135 destroy_directory_content((GNode *) element_data);
136 free_node_data((GNode *) element_data, NULL);
137 }
138
139 void destroy_dotfiles(GList *dotfiles)
140 {
141 g_list_foreach(dotfiles, free_element_data, NULL);
142 g_list_free(dotfiles);
143 }
144
145 gboolean free_node_data(GNode *node, gpointer data)
146 {
147 free(FILE(node)->name);
148 free(FILE(node)->link_path);
149 destroy_dotfiles(FILE(node)->dotfiles);
150 free(node->data);
151
152 return FALSE;
153 }
154
155 void destroy_directory_content(GNode *directory)
156 {
157 GNode *file_ptr, *file_ptr2;
158
159 for (file_ptr = g_node_first_child(directory); file_ptr != NULL; ) {
160 file_ptr2 = file_ptr;
161 file_ptr = g_node_next_sibling(file_ptr);
162
163 g_node_unlink(file_ptr2);
164 g_node_traverse(file_ptr2, G_PRE_ORDER, G_TRAVERSE_ALL, -1, free_node_data, NULL);
165 g_node_destroy(file_ptr2);
166 }
167 destroy_dotfiles(FILE(directory)->dotfiles);
168 FILE(directory)->dotfiles = NULL;
169 FILE(directory)->read = FALSE;
170 }
171
172 void add_dotfiles(GNode *directory)
173 {
174 GList *line_ptr;
175 GNode *file_ptr;
176 int position;
177
178 for (line_ptr = g_list_next(FILE(directory)->line), position = 0;
179 FILE(directory)->dotfiles != NULL; position++) {
180 file_ptr = NODE(FILE(directory)->dotfiles);
181 FILE(directory)->dotfiles = g_list_delete_link(FILE(directory)->dotfiles,
182 FILE(directory)->dotfiles);
183 g_node_insert(directory, position, file_ptr);
184 lines = g_list_insert_before(lines, line_ptr, file_ptr);
185 FILE(file_ptr)->line = g_list_previous(line_ptr);
186 if (FILE(file_ptr)->type == directory_type && FILE(file_ptr)->open == TRUE)
187 add_directory_content(file_ptr);
188 }
189 FILE(directory)->show_dotfiles = TRUE;
190 }
191
192 void remove_dotfiles(GNode *directory)
193 {
194 GNode *file_ptr;
195 GList *line_ptr, *line_ptr_aux;
196
197 for (file_ptr = g_node_first_child(directory); file_ptr != NULL &&
198 FILE(file_ptr)->name[0] == '.'; ) {
199 lines = g_list_delete_link(lines, FILE(file_ptr)->line);
200 FILE(directory)->dotfiles = g_list_insert(FILE(directory)->dotfiles, file_ptr, -1);
201 FILE(file_ptr)->line = NULL;
202 file_ptr = g_node_next_sibling(file_ptr);
203 g_node_unlink(NODE(g_list_last(FILE(directory)->dotfiles)));
204
205 for (line_ptr = g_list_previous(FILE(file_ptr)->line);
206 line_ptr != FILE(directory)->line; ) {
207 line_ptr_aux = line_ptr;
208 line_ptr = g_list_previous(line_ptr);
209 FILE(NODE(line_ptr_aux))->line = NULL;
210 lines = g_list_delete_link(lines, line_ptr_aux);
211 }
212 }
213 FILE(directory)->show_dotfiles = FALSE;
214 }
215
216 int file_cmp(File *file1, File *file2)
217 {
218 if (file1->type == file2->type)
219 return strcmp(file1->name, file2->name);
220 else if (file1->type == directory_type)
221 return -1;
222 else
223 return 1;
224 }
225
226 int file_cmp_list(gconstpointer file1, gconstpointer file2)
227 {
228 return file_cmp(FILE((GNode *) file1), FILE((GNode *) file2));
229 }
230
231 void insert_sorted_in_dotfiles(GNode *directory, File *file)
232 {
233 FILE(directory)->dotfiles = g_list_insert_sorted(FILE(directory)->dotfiles,
234 g_node_new(file), file_cmp_list);
235 }
236
237 void insert_sorted_in_tree(GNode *directory, File *file)
238 {
239 GNode *file_ptr;
240
241 if (G_NODE_IS_LEAF(directory))
242 g_node_append_data(directory, file);
243 else if (file_cmp(file, FILE(g_node_first_child(directory))) < 0)
244 g_node_prepend_data(directory, file);
245 else {
246 for (file_ptr = g_node_last_child(directory); file_ptr != NULL;
247 file_ptr = g_node_prev_sibling(file_ptr)) {
248 if (file_cmp(file, FILE(file_ptr)) > 0) {
249 g_node_insert_after(directory, file_ptr, g_node_new(file));
250 break;
251 }
252 }
253 }
254 }
255
256 char *get_path(GNode *file)
257 {
258 GNode *file_ptr;
259 GString *path = g_string_new(FILE(file)->name);
260
261 for (file_ptr = file->parent; file_ptr != NULL; file_ptr = file_ptr->parent) {
262 g_string_prepend(path, "/");
263 g_string_prepend(path, FILE(file_ptr)->name);
264 }
265
266 return g_string_free(path, FALSE);
267 }
268
269 GNode *get_next_file__real(GNode *file, gboolean go_deeper)
270 {
271 GNode *file_ptr, *directory_ptr;
272
273 if (go_deeper && (file_ptr = g_node_first_child(file)) != NULL && FILE(file)->open == TRUE)
274 return file_ptr;
275 else if ((file_ptr = g_node_next_sibling(file)) != NULL)
276 return file_ptr;
277 else {
278 for (directory_ptr = file->parent; directory_ptr != NULL;
279 directory_ptr = directory_ptr->parent) {
280 if ((file_ptr = g_node_next_sibling(directory_ptr)) != NULL)
281 return file_ptr;
282 }
283
284 return NULL;
285 }
286 }
287
288 GNode *get_previous_file(GNode *file)
289 {
290 GNode *file_ptr;
291
292 if (G_NODE_IS_ROOT(file))
293 return NULL;
294 else if (file == g_node_first_sibling(file))
295 return file->parent;
296 else if (!G_NODE_IS_LEAF(file_ptr = g_node_prev_sibling(file)) &&
297 FILE(file_ptr)->open == TRUE) {
298 do
299 file_ptr = g_node_last_child(file_ptr);
300 while (!G_NODE_IS_LEAF(file_ptr) && FILE(file_ptr)->open == TRUE);
301 return file_ptr;
302 } else
303 return file_ptr;
304 }
305
306 GNode *get_next_file(GNode *file)
307 {
308 return get_next_file__real(file, TRUE);
309 }
310
311 GNode *get_next_file_not_deepper(GNode *file)
312 {
313 return get_next_file__real(file, FALSE);
314 }
315
316 char *get_file_info(GNode *file)
317 {
318 struct passwd *pw;
319 struct group *grp;
320 struct tm *mtime;
321 char mode[11], mtime_str[17], size_suffix;
322 double size;
323
324 switch (FILE(file)->info.st_mode & S_IFMT) {
325 case S_IFSOCK:
326 mode[0] = 's';
327 break;
328 case S_IFLNK:
329 mode[0] = 'l';
330 break;
331 case S_IFREG:
332 mode[0] = '-';
333 break;
334 case S_IFBLK:
335 mode[0] = 'b';
336 break;
337 case S_IFDIR:
338 mode[0] = 'd';
339 break;
340 case S_IFCHR:
341 mode[0] = 'c';
342 break;
343 case S_IFIFO:
344 mode[0] = 'p';
345 break;
346 }
347 mode[1] = (FILE(file)->info.st_mode & S_IRUSR) ? 'r' : '-';
348 mode[2] = (FILE(file)->info.st_mode & S_IWUSR) ? 'w' : '-';
349 mode[3] = (FILE(file)->info.st_mode & S_IXUSR) ? 'x' : '-';
350
351 mode[4] = (FILE(file)->info.st_mode & S_IRGRP) ? 'r' : '-';
352 mode[5] = (FILE(file)->info.st_mode & S_IWGRP) ? 'w' : '-';
353 mode[6] = (FILE(file)->info.st_mode & S_IXGRP) ? 'x' : '-';
354
355 mode[7] = (FILE(file)->info.st_mode & S_IROTH) ? 'r' : '-';
356 mode[8] = (FILE(file)->info.st_mode & S_IWOTH) ? 'w' : '-';
357 mode[9] = (FILE(file)->info.st_mode & S_IXOTH) ? 'x' : '-';
358 mode[10] = '\0';
359
360 if (FILE(file)->info.st_mode & S_ISUID && mode[3] == 'x')
361 mode[9] = 's';
362 else if (FILE(file)->info.st_mode & S_ISUID && mode[3] == '-')
363 mode[9] = 'S';
364 if (FILE(file)->info.st_mode & S_ISGID && mode[6] == 'x')
365 mode[9] = 's';
366 else if (FILE(file)->info.st_mode & S_ISGID && mode[6] == '-')
367 mode[9] = 'S';
368 if (FILE(file)->info.st_mode & S_ISVTX && mode[9] == 'x')
369 mode[9] = 't';
370 else if (FILE(file)->info.st_mode & S_ISVTX && mode[9] == '-')
371 mode[9] = 'T';
372
373 if ((pw = getpwuid(FILE(file)->info.st_uid)) == NULL) {
374 PRINT_ERRNO_INFO();
375 return NULL;
376 } if ((grp = getgrgid(FILE(file)->info.st_gid)) == NULL) {
377 PRINT_ERRNO_INFO();
378 return NULL;
379 }
380
381 if ((size =(double) FILE(file)->info.st_size / (1024.0 * 1024.0 * 1024.0)) > 1.0)
382 size_suffix = 'G';
383 else if ((size =(double) FILE(file)->info.st_size / (1024.0 * 1024.0)) > 1.0)
384 size_suffix = 'M';
385 else if ((size =(double) FILE(file)->info.st_size / (1024.0)) > 1.0)
386 size_suffix = 'K';
387 else {
388 size =(double) FILE(file)->info.st_size;
389 size_suffix = ' ';
390 }
391
392 if ((mtime = localtime(&(FILE(file)->info.st_mtime))) == NULL) {
393 PRINT_ERRNO_INFO();
394 return NULL;
395 }
396 if (strftime(mtime_str, sizeof(mtime_str), "%Y-%m-%d %H:%M", mtime) == 0) {
397 PRINT_ERRNO_INFO();
398 return NULL;
399 }
400
401 if (FILE(file)->link == TRUE) {
402 if (size_suffix == ' ')
403 return g_strdup_printf("%s %s %s %i %s %s -> %s", mode, pw->pw_name, grp->gr_name,
404 (int) size, mtime_str, FILE(file)->name, FILE(file)->link_path);
405 else
406 return g_strdup_printf("%s %s %s %.2f%c %s %s -> %s", mode, pw->pw_name, grp->gr_name,
407 size, size_suffix, mtime_str, FILE(file)->name, FILE(file)->link_path);
408 } else {
409 if (size_suffix == ' ')
410 return g_strdup_printf("%s %s %s %i %s %s", mode, pw->pw_name, grp->gr_name,
411 (int) size, mtime_str, FILE(file)->name);
412 else
413 return g_strdup_printf("%s %s %s %.2f%c %s %s", mode, pw->pw_name, grp->gr_name,
414 size, size_suffix, mtime_str, FILE(file)->name);
415 }
416 }
This page took 0.698109 seconds and 4 git commands to generate.