diff options
author | Stefano Facchini <stefano.facchini@gmail.com> | 2020-06-13 18:52:43 +0200 |
---|---|---|
committer | Stefano Facchini <stefano.facchini@gmail.com> | 2020-06-15 12:40:24 +0200 |
commit | 64db13ea2949a00e39313f623e96439cc2aac27a (patch) | |
tree | f97ce8fc735001f826fea4a8bcecc51e1583cf5c | |
parent | 0efc5ffd473d55ea53f20e3aaa9e63278c1ddf32 (diff) | |
download | baobab-admin-scan.tar.gz |
Add ability to scan as administratoradmin-scan
When we encounter an inaccessible subdirectory, we try the GIO URI "admin:///path/to/directory".
If the user fails to authenticate, we just go on with the regular scan.
Since the "admin://" scheme is used only for subdirectories that can't be read as
a regular user, it shouldn't be *too* much slower, hopefully.
-rw-r--r-- | data/ui/baobab-main-window.ui | 42 | ||||
-rw-r--r-- | src/baobab-application.vala | 2 | ||||
-rw-r--r-- | src/baobab-scanner.vala | 52 | ||||
-rw-r--r-- | src/baobab-window.vala | 52 |
4 files changed, 110 insertions, 38 deletions
diff --git a/data/ui/baobab-main-window.ui b/data/ui/baobab-main-window.ui index fbded4c..e48dbaa 100644 --- a/data/ui/baobab-main-window.ui +++ b/data/ui/baobab-main-window.ui @@ -27,6 +27,16 @@ </item> </section> </menu> + <menu id="rescan_menu"> + <item> + <attribute name="label" translatable="yes">Rescan</attribute> + <attribute name="action">win.rescan</attribute> + </item> + <item> + <attribute name="label" translatable="yes">Rescan as administrator…</attribute> + <attribute name="action">win.rescan_as_admin</attribute> + </item> + </menu> <object class="GtkMenu" id="treeview_popup_menu"> <property name="visible">True</property> <property name="can_focus">False</property> @@ -86,18 +96,34 @@ </packing> </child> <child> - <object class="GtkButton" id="reload_button"> - <property name="valign">center</property> - <property name="can_focus">True</property> - <property name="action_name">win.reload</property> + <object class="GtkBox" id="rescan_box"> <style> - <class name="image-button"/> + <class name="linked"/> </style> <child> - <object class="GtkImage" id="reload_button_image"> + <object class="GtkButton" id="rescan_button"> <property name="visible">True</property> - <property name="icon_size">1</property> - <property name="icon_name">view-refresh-symbolic</property> + <property name="valign">center</property> + <property name="can_focus">True</property> + <property name="action_name">win.rescan</property> + <style> + <class name="image-button"/> + </style> + <child> + <object class="GtkImage" id="reload_button_image"> + <property name="visible">True</property> + <property name="icon_size">1</property> + <property name="icon_name">view-refresh-symbolic</property> + </object> + </child> + </object> + </child> + <child> + <object class="GtkMenuButton" id="rescan_menu_button"> + <property name="visible">True</property> + <property name="valign">center</property> + <property name="menu_model">rescan_menu</property> + <property name="can_focus">True</property> </object> </child> </object> diff --git a/src/baobab-application.vala b/src/baobab-application.vala index 50492ef..c491cc7 100644 --- a/src/baobab-application.vala +++ b/src/baobab-application.vala @@ -83,7 +83,7 @@ namespace Baobab { set_accels_for_action ("win.show-home-page", { "<Alt>Left" }); set_accels_for_action ("win.show-primary-menu", { "F10" }); set_accels_for_action ("win.scan-folder", { "<Primary>o" }); - set_accels_for_action ("win.reload", { "<Primary>r" }); + set_accels_for_action ("win.rescan", { "<Primary>r" }); set_accels_for_action ("win.help", { "F1" }); set_accels_for_action ("app.quit", { "<Primary>q" }); } diff --git a/src/baobab-scanner.vala b/src/baobab-scanner.vala index b3ba68c..b800317 100644 --- a/src/baobab-scanner.vala +++ b/src/baobab-scanner.vala @@ -86,8 +86,12 @@ namespace Baobab { FileAttribute.UNIX_NLINK + "," + FileAttribute.UNIX_INODE + "," + FileAttribute.UNIX_DEVICE + "," + + FileAttribute.ACCESS_CAN_EXECUTE + "," + FileAttribute.ACCESS_CAN_READ; + bool scan_as_admin = false; + bool auth_failed = false; + [Compact] class HardLink { internal uint64 inode; @@ -265,9 +269,21 @@ namespace Baobab { var results = new Results (info, parent); + File admin_directory = directory; + bool try_admin_access = scan_as_admin && + !(info.get_attribute_boolean (FileAttribute.ACCESS_CAN_READ) && + info.get_attribute_boolean (FileAttribute.ACCESS_CAN_EXECUTE)) && + !auth_failed; + if (try_admin_access) { + admin_directory = File.new_for_uri ("admin://" + directory.get_path ()); + } + try { - add_children (directory, results, results_array); + add_children (admin_directory, results, results_array); } catch (Error e) { + if (e is IOError.PERMISSION_DENIED) { + auth_failed = true; + } results.error = e; } @@ -287,6 +303,25 @@ namespace Baobab { return results; } + void mount_enclosing_volume_sync (File file) { + var loop = new MainLoop (); + + var operation = new Gtk.MountOperation (null); + file.mount_enclosing_volume.begin (MountMountFlags.NONE, operation, cancellable, (obj, res) => { + try { + file.mount_enclosing_volume.end (res); + } catch (IOError.ALREADY_MOUNTED e) { + // We can ignore this one + } catch (Error e) { + scan_error = e; + } + + loop.quit (); + }); + + loop.run (); + } + void* scan_in_thread () { try { var array = new ResultsArray (); @@ -424,16 +459,29 @@ namespace Baobab { cancellable.reset (); scan_error = null; + auth_failed = false; } - public void scan (bool force) { + public void scan (bool force, bool scan_as_admin) { if (force) { successful = false; } + this.scan_as_admin = scan_as_admin; + if (!successful) { cancel_and_reset (); + if (scan_as_admin) { + var admin_directory = File.new_for_uri ("admin://" + directory.get_path ()); + mount_enclosing_volume_sync (admin_directory); + } + + if (scan_error != null) { + completed (); + return; + } + // the thread owns a reference on the Scanner object this.self = this; diff --git a/src/baobab-window.vala b/src/baobab-window.vala index 5674f2e..165f5a3 100644 --- a/src/baobab-window.vala +++ b/src/baobab-window.vala @@ -31,7 +31,7 @@ namespace Baobab { [GtkChild] private Gtk.Button back_button; [GtkChild] - private Gtk.Button reload_button; + private Gtk.Box rescan_box; [GtkChild] private Gtk.MenuButton menu_button; [GtkChild] @@ -81,7 +81,8 @@ namespace Baobab { { "show-primary-menu", on_show_primary_menu_activate, null, "false", null }, { "show-home-page", on_show_home_page_activate }, { "scan-folder", on_scan_folder_activate }, - { "reload", on_reload_activate }, + { "rescan", on_rescan_activate }, + { "rescan_as_admin", on_rescan_as_admin_activate }, { "clear-recent", on_clear_recent }, { "help", on_help_activate }, { "about", on_about_activate } @@ -251,13 +252,12 @@ namespace Baobab { }); } - void on_reload_activate () { - if (active_location != null) { - if (active_location.scanner != null) { - active_location.scanner.cancel (); - } - scan_active_location (true); - } + void on_rescan_activate () { + scan_active_location (true); + } + + void on_rescan_as_admin_activate () { + scan_active_location (true, true); } void on_clear_recent () { @@ -469,18 +469,15 @@ namespace Baobab { void set_ui_state (Gtk.Widget child, bool busy) { menu_button.visible = (child == home_page); - reload_button.visible = (child == result_page); + rescan_box.visible = (child == result_page); back_button.visible = (child == result_page); set_busy (busy); if (child == home_page) { - var action = lookup_action ("reload") as SimpleAction; - action.set_enabled (false); header_bar.title = _("Devices & Locations"); + active_location = null; } else { - var action = lookup_action ("reload") as SimpleAction; - action.set_enabled (true); header_bar.title = active_location.name; } @@ -509,9 +506,17 @@ namespace Baobab { treemap_chart.model = model; } - void scan_active_location (bool force) { + void scan_active_location (bool force, bool scan_as_admin=false) { + if (active_location == null) { + return; + } + var scanner = active_location.scanner; + if (scanner != null) { + scanner.cancel (); + } + scan_completed_handler = scanner.completed.connect(() => { if (scan_completed_handler > 0) { scanner.disconnect (scan_completed_handler); @@ -523,18 +528,11 @@ namespace Baobab { } catch (IOError.CANCELLED e) { // Handle cancellation silently return; + } catch (IOError.PERMISSION_DENIED e) { + // Do nothing } catch (Error e) { - Gtk.TreeIter iter; - Scanner.State state; - scanner.get_iter_first (out iter); - scanner.get (iter, Scanner.Columns.STATE, out state); - if (state == Scanner.State.ERROR) { - var primary = _("Could not scan folder “%s”").printf (scanner.directory.get_parse_name ()); - message (primary, e.message, Gtk.MessageType.ERROR); - } else { - var primary = _("Could not scan some of the folders contained in “%s”").printf (scanner.directory.get_parse_name ()); - message (primary, e.message, Gtk.MessageType.WARNING); - } + var primary = _("An error occured while scanning “%s”").printf (scanner.directory.get_parse_name ()); + message (primary, e.message, Gtk.MessageType.ERROR); } set_chart_model (active_location.scanner); @@ -555,7 +553,7 @@ namespace Baobab { clear_message (); set_ui_state (result_page, true); - scanner.scan (force); + scanner.scan (force, scan_as_admin); treeview.model = scanner; expand_first_row (); |