summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorStefano Facchini <stefano.facchini@gmail.com>2020-06-13 18:52:43 +0200
committerStefano Facchini <stefano.facchini@gmail.com>2020-06-15 12:40:24 +0200
commit64db13ea2949a00e39313f623e96439cc2aac27a (patch)
treef97ce8fc735001f826fea4a8bcecc51e1583cf5c
parent0efc5ffd473d55ea53f20e3aaa9e63278c1ddf32 (diff)
downloadbaobab-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.ui42
-rw-r--r--src/baobab-application.vala2
-rw-r--r--src/baobab-scanner.vala52
-rw-r--r--src/baobab-window.vala52
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 ();