Branch data Line data Source code
1 : : /*
2 : : * Copyright 2015 Red Hat, Inc.
3 : : *
4 : : * SPDX-License-Identifier: LGPL-2.1-or-later
5 : : *
6 : : * This library is free software; you can redistribute it and/or
7 : : * modify it under the terms of the GNU Lesser General Public
8 : : * License as published by the Free Software Foundation; either
9 : : * version 2.1 of the License, or (at your option) any later version.
10 : : *
11 : : * This library is distributed in the hope that it will be useful,
12 : : * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 : : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 : : * Lesser General Public License for more details.
15 : : *
16 : : * You should have received a copy of the GNU Lesser General Public
17 : : * License along with this library; if not, see <http://www.gnu.org/licenses/>.
18 : : *
19 : : * Author: Matthias Clasen <mclasen@redhat.com>
20 : : */
21 : :
22 : : #include "config.h"
23 : :
24 : : #include <gio/gio.h>
25 : : #include <gi18n.h>
26 : :
27 : : #include "gio-tool.h"
28 : :
29 : :
30 : : static gboolean show_hidden = FALSE;
31 : : static gboolean follow_symlinks = FALSE;
32 : :
33 : : static const GOptionEntry entries[] = {
34 : : { "hidden", 'h', 0, G_OPTION_ARG_NONE, &show_hidden, N_("Show hidden files"), NULL },
35 : : { "follow-symlinks", 'l', 0, G_OPTION_ARG_NONE, &follow_symlinks, N_("Follow symbolic links, mounts and shortcuts"), NULL },
36 : : G_OPTION_ENTRY_NULL
37 : : };
38 : :
39 : : static gint
40 : 0 : sort_info_by_name (GFileInfo *a, GFileInfo *b)
41 : : {
42 : : const char *na;
43 : : const char *nb;
44 : :
45 : 0 : na = g_file_info_get_name (a);
46 : 0 : nb = g_file_info_get_name (b);
47 : :
48 : 0 : if (na == NULL)
49 : 0 : na = "";
50 : 0 : if (nb == NULL)
51 : 0 : nb = "";
52 : :
53 : 0 : return strcmp (na, nb);
54 : : }
55 : :
56 : : static void
57 : 0 : do_tree (GFile *f, unsigned int level, guint64 pattern)
58 : : {
59 : : GFileEnumerator *enumerator;
60 : 0 : GError *error = NULL;
61 : : unsigned int n;
62 : : GFileInfo *info;
63 : :
64 : 0 : info = g_file_query_info (f,
65 : : G_FILE_ATTRIBUTE_STANDARD_TYPE ","
66 : : G_FILE_ATTRIBUTE_STANDARD_TARGET_URI,
67 : : 0,
68 : : NULL, NULL);
69 : 0 : if (info != NULL)
70 : : {
71 : 0 : if (g_file_info_get_attribute_uint32 (info, G_FILE_ATTRIBUTE_STANDARD_TYPE) == G_FILE_TYPE_MOUNTABLE)
72 : : {
73 : : /* don't process mountables; we avoid these by getting the target_uri below */
74 : 0 : g_object_unref (info);
75 : 0 : return;
76 : : }
77 : 0 : g_object_unref (info);
78 : : }
79 : :
80 : 0 : enumerator = g_file_enumerate_children (f,
81 : : G_FILE_ATTRIBUTE_STANDARD_NAME ","
82 : : G_FILE_ATTRIBUTE_STANDARD_TYPE ","
83 : : G_FILE_ATTRIBUTE_STANDARD_IS_HIDDEN ","
84 : : G_FILE_ATTRIBUTE_STANDARD_IS_SYMLINK ","
85 : : G_FILE_ATTRIBUTE_STANDARD_SYMLINK_TARGET ","
86 : : G_FILE_ATTRIBUTE_STANDARD_TARGET_URI,
87 : : 0,
88 : : NULL,
89 : : &error);
90 : 0 : if (enumerator != NULL)
91 : : {
92 : : GList *l;
93 : : GList *info_list;
94 : :
95 : 0 : info_list = NULL;
96 : 0 : while ((info = g_file_enumerator_next_file (enumerator, NULL, NULL)) != NULL)
97 : : {
98 : 0 : if (g_file_info_has_attribute (info, G_FILE_ATTRIBUTE_STANDARD_IS_HIDDEN) &&
99 : 0 : g_file_info_get_is_hidden (info) &&
100 : 0 : !show_hidden)
101 : : {
102 : 0 : g_object_unref (info);
103 : : }
104 : : else
105 : : {
106 : 0 : info_list = g_list_prepend (info_list, info);
107 : : }
108 : : }
109 : 0 : g_object_unref (enumerator);
110 : :
111 : 0 : info_list = g_list_sort (info_list, (GCompareFunc) sort_info_by_name);
112 : :
113 : 0 : for (l = info_list; l != NULL; l = l->next)
114 : : {
115 : : const char *name;
116 : : const char *target_uri;
117 : : GFileType type;
118 : : gboolean is_last_item;
119 : :
120 : 0 : info = l->data;
121 : 0 : is_last_item = (l->next == NULL);
122 : :
123 : 0 : name = g_file_info_get_name (info);
124 : 0 : type = g_file_info_get_attribute_uint32 (info, G_FILE_ATTRIBUTE_STANDARD_TYPE);
125 : 0 : if (name != NULL)
126 : : {
127 : :
128 : 0 : for (n = 0; n < level; n++)
129 : : {
130 : 0 : if (pattern & (1<<n))
131 : : {
132 : 0 : g_print ("| ");
133 : : }
134 : : else
135 : : {
136 : 0 : g_print (" ");
137 : : }
138 : : }
139 : :
140 : 0 : if (is_last_item)
141 : : {
142 : 0 : g_print ("`-- %s", name);
143 : : }
144 : : else
145 : : {
146 : 0 : g_print ("|-- %s", name);
147 : : }
148 : :
149 : 0 : target_uri = g_file_info_get_attribute_string (info, G_FILE_ATTRIBUTE_STANDARD_TARGET_URI);
150 : 0 : if (target_uri != NULL)
151 : : {
152 : 0 : g_print (" -> %s", target_uri);
153 : : }
154 : : else
155 : : {
156 : 0 : if (g_file_info_has_attribute (info, G_FILE_ATTRIBUTE_STANDARD_IS_SYMLINK) &&
157 : 0 : g_file_info_get_is_symlink (info))
158 : : {
159 : : const char *target;
160 : 0 : target = g_file_info_get_symlink_target (info);
161 : 0 : g_print (" -> %s", target);
162 : : }
163 : : }
164 : :
165 : 0 : g_print ("\n");
166 : :
167 : 0 : if ((type & G_FILE_TYPE_DIRECTORY) &&
168 : 0 : (follow_symlinks ||
169 : 0 : !(g_file_info_has_attribute (info, G_FILE_ATTRIBUTE_STANDARD_IS_SYMLINK) &&
170 : 0 : g_file_info_get_is_symlink (info))))
171 : : {
172 : : guint64 new_pattern;
173 : : GFile *child;
174 : :
175 : 0 : if (is_last_item)
176 : 0 : new_pattern = pattern;
177 : : else
178 : 0 : new_pattern = pattern | (1<<level);
179 : :
180 : 0 : child = NULL;
181 : 0 : if (target_uri != NULL)
182 : : {
183 : 0 : if (follow_symlinks)
184 : 0 : child = g_file_new_for_uri (target_uri);
185 : : }
186 : : else
187 : : {
188 : 0 : child = g_file_get_child (f, name);
189 : : }
190 : :
191 : 0 : if (child != NULL)
192 : : {
193 : 0 : do_tree (child, level + 1, new_pattern);
194 : 0 : g_object_unref (child);
195 : : }
196 : : }
197 : : }
198 : 0 : g_object_unref (info);
199 : : }
200 : 0 : g_list_free (info_list);
201 : : }
202 : : else
203 : : {
204 : 0 : for (n = 0; n < level; n++)
205 : : {
206 : 0 : if (pattern & (1<<n))
207 : : {
208 : 0 : g_print ("| ");
209 : : }
210 : : else
211 : : {
212 : 0 : g_print (" ");
213 : : }
214 : : }
215 : :
216 : 0 : g_print (" [%s]\n", error->message);
217 : :
218 : 0 : g_error_free (error);
219 : : }
220 : : }
221 : :
222 : : static void
223 : 0 : tree (GFile *f)
224 : : {
225 : : char *uri;
226 : :
227 : 0 : uri = g_file_get_uri (f);
228 : 0 : g_print ("%s\n", uri);
229 : 0 : g_free (uri);
230 : :
231 : 0 : do_tree (f, 0, 0);
232 : 0 : }
233 : :
234 : : int
235 : 0 : handle_tree (int argc, char *argv[], gboolean do_help)
236 : : {
237 : : GOptionContext *context;
238 : 0 : GError *error = NULL;
239 : : GFile *file;
240 : : gchar *param;
241 : : int i;
242 : :
243 : 0 : g_set_prgname ("gio tree");
244 : :
245 : : /* Translators: commandline placeholder */
246 : 0 : param = g_strdup_printf ("[%s…]", _("LOCATION"));
247 : 0 : context = g_option_context_new (param);
248 : 0 : g_free (param);
249 : 0 : g_option_context_set_help_enabled (context, FALSE);
250 : 0 : g_option_context_set_summary (context,
251 : 0 : _("List contents of directories in a tree-like format."));
252 : 0 : g_option_context_add_main_entries (context, entries, GETTEXT_PACKAGE);
253 : :
254 : 0 : if (do_help)
255 : : {
256 : 0 : show_help (context, NULL);
257 : 0 : g_option_context_free (context);
258 : 0 : return 0;
259 : : }
260 : :
261 : 0 : g_option_context_parse (context, &argc, &argv, &error);
262 : :
263 : 0 : if (error != NULL)
264 : : {
265 : 0 : show_help (context, error->message);
266 : 0 : g_error_free (error);
267 : 0 : g_option_context_free (context);
268 : 0 : return 1;
269 : : }
270 : :
271 : 0 : g_option_context_free (context);
272 : :
273 : 0 : if (argc > 1)
274 : : {
275 : 0 : for (i = 1; i < argc; i++)
276 : : {
277 : 0 : file = g_file_new_for_commandline_arg (argv[i]);
278 : 0 : tree (file);
279 : 0 : g_object_unref (file);
280 : : }
281 : : }
282 : : else
283 : : {
284 : : char *cwd;
285 : :
286 : 0 : cwd = g_get_current_dir ();
287 : 0 : file = g_file_new_for_path (cwd);
288 : 0 : g_free (cwd);
289 : 0 : tree (file);
290 : 0 : g_object_unref (file);
291 : : }
292 : :
293 : 0 : return 0;
294 : : }
|