summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorErriez <[email protected]>2025-09-02 22:30:33 +0200
committerGitHub <[email protected]>2025-09-02 20:30:33 +0000
commite0fd9c8646d8f4d0f08df39f3f7f3bd4e958624b (patch)
tree13a7f97dc7c7fcc36ce197ce3ea8ea6659d662ce
parent3bf3603bae502e52a0acd0a85a10466c3f1dbee1 (diff)
downloadpython-caja-e0fd9c8646d8f4d0f08df39f3f7f3bd4e958624b.tar.bz2
python-caja-e0fd9c8646d8f4d0f08df39f3f7f3bd4e958624b.tar.xz
Add shred example
-rw-r--r--examples/shred.py190
1 files changed, 190 insertions, 0 deletions
diff --git a/examples/shred.py b/examples/shred.py
new file mode 100644
index 0000000..d445cee
--- /dev/null
+++ b/examples/shred.py
@@ -0,0 +1,190 @@
+# Examples: https://github.com/mate-desktop/python-caja/tree/master/examples
+#
+# This script adds a new menu's to Caja file browser:
+# - Shred: when right-mouse clicking on one or more selected files
+# or directories.
+# - Wipe freespace: when right-mouse clicking on a white area without
+# selected files or directories.
+# The executed command is shown in the statusbar.
+#
+# WARNING: THIS IS AN EXAMPLE SCRIPT AND THE USER IS RESPONSIBLE
+# FOR SHREDDING THE FULL SSD OR HARD DRIVE WHEN ABSOLUTE SECURITY IS
+# REQUIRED!
+#
+# The Linux tool `shred` is used to shred files by filling files with
+# zero's or random data and removes filenames. Overwriting files
+# multiple times has no effect on SSD's and decreases lifetime. It
+# should be used for mechanical hard drives only.
+#
+# Copy this script to a path defined in $XDG_DATA_DIRS, for example:
+# ~/.local/share/caja-python/extensions
+
+import os
+import subprocess
+
+import gi
+from gi.repository import Caja, GObject, Gio, Gtk
+
+
+class ShredMenuProvider(GObject.GObject, Caja.MenuProvider):
+ SHRED_ICON = '/usr/share/pixmaps/caja/erase.png'
+ WIPE_CMD = 'dd if=/dev/{} of={} bs=1M'
+ WIPE_FILENAME = 'tmp'
+
+ def __init__(self):
+ pass
+
+ def shred_menu_activate_cb(self, menu, data):
+ dialog = Gtk.MessageDialog(
+ parent=None,
+ flags=0,
+ message_type=Gtk.MessageType.QUESTION,
+ buttons=Gtk.ButtonsType.YES_NO,
+ title="Caja shred",
+ text="Are you sure you want to shred selected files?",
+ )
+ dialog.format_secondary_text("WARNING: This cannot be undone!")
+ response = dialog.run()
+ dialog.destroy()
+ if response == Gtk.ResponseType.YES:
+ files_skipped = False
+ shred_files = ''
+ for shred_file in data['files']:
+ file_path = shred_file.get_location().get_path()
+ if os.access(file_path, os.W_OK):
+ shred_files += ' "{}"'.format(file_path)
+ else:
+ print('Skip shred file: {}'.format(file_path))
+ files_skipped = True
+
+ # Start Shred command
+ if shred_files:
+ cmd = data['cmd'] + shred_files
+ print('Running: {}'.format(cmd))
+ subprocess.check_call(cmd, shell=True)
+
+ dialog = Gtk.MessageDialog(
+ parent=None,
+ flags=0,
+ message_type=Gtk.MessageType.INFO,
+ buttons=Gtk.ButtonsType.OK,
+ title="Caja shred",
+ text='Shred completed.',
+ )
+ if files_skipped:
+ dialog.format_secondary_text('WARNING: Some files could not be shredded.\nPlease check manually.')
+
+ response = dialog.run()
+ dialog.destroy()
+
+ def wipe_freepsace_menu_activate_cb(self, menu, data):
+ wipe_path = data['file'].get_location().get_path()
+ wipe_cmd = data['cmd'].replace('of=', 'of={}/'.format(wipe_path))
+ clean_cmd = 'rm {}/{}'.format(wipe_path, self.WIPE_FILENAME)
+
+ # Check if wipe path is writable
+ if not os.access(wipe_path, os.W_OK):
+ dialog = Gtk.MessageDialog(
+ parent=None,
+ flags=0,
+ message_type=Gtk.MessageType.ERROR,
+ buttons=Gtk.ButtonsType.OK,
+ title="Caja wipe freespace",
+ text="Error: Directory is not writable",
+ )
+ response = dialog.run()
+ dialog.destroy()
+ return
+
+ # Start wipe freespace command
+ print('Running: {}'.format(wipe_cmd))
+ try:
+ subprocess.check_call(wipe_cmd, shell=True)
+ except:
+ # Ignore disk full error
+ pass
+
+ print('Running: sync')
+ subprocess.check_call('sync', shell=True)
+
+ print('Running: {}'.format(clean_cmd))
+ subprocess.check_call(clean_cmd, shell=True)
+
+ dialog = Gtk.MessageDialog(
+ parent=None,
+ flags=0,
+ message_type=Gtk.MessageType.INFO,
+ buttons=Gtk.ButtonsType.OK,
+ title="Caja wipe freespace",
+ text="Wipe freespace completed!",
+ )
+ response = dialog.run()
+ dialog.destroy()
+
+ def get_file_items(self, window, files):
+ top_menuitem = Caja.MenuItem(name='ShredMenuProvider::Shred',
+ label='Shred',
+ tip='Delete files with the Linux "shred" tool',
+ icon=self.SHRED_ICON)
+
+ shred_submenu = Caja.Menu()
+ top_menuitem.set_submenu(shred_submenu)
+
+ # Shred fill zero's
+ shred_cmd = 'shred -uz -n 0'
+ shred_1x_zero_menuitem = Caja.MenuItem(name='ShredMenuProvider::Shred1xZero',
+ label='Fill zero\'s',
+ tip=shred_cmd + ' FILE... (NOT SECURE!)',
+ icon=self.SHRED_ICON)
+ shred_1x_zero_menuitem.connect('activate', self.shred_menu_activate_cb, {'cmd': shred_cmd, 'files': files})
+ shred_submenu.append_item(shred_1x_zero_menuitem)
+
+ # Shred fill random
+ shred_cmd = 'shred -u -n 1'
+ shred_1x_random_menuitem = Caja.MenuItem(name='ShredMenuProvider::Shred1xRandom',
+ label='Fill random',
+ tip=shred_cmd + ' FILE... (NOT SECURE!)',
+ icon=self.SHRED_ICON)
+ shred_1x_random_menuitem.connect('activate', self.shred_menu_activate_cb, {'cmd': shred_cmd, 'files': files})
+ shred_submenu.append_item(shred_1x_random_menuitem)
+
+ # Shred 3x overwrite, last zero's
+ shred_cmd = 'shred -uz'
+ shred_3x_zero_menuitem = Caja.MenuItem(name='ShredMenuProvider::Shred3xLastZero',
+ label='3x overwrite, last zero\'s',
+ tip=shred_cmd + ' FILE... (HDD\'s only!)',
+ icon=self.SHRED_ICON)
+ shred_3x_zero_menuitem.connect('activate', self.shred_menu_activate_cb, {'cmd': shred_cmd, 'files': files})
+ shred_submenu.append_item(shred_3x_zero_menuitem)
+
+ # Shred 3x overwrite (default)
+ shred_cmd = 'shred -u'
+ shred_3x_random_menuitem = Caja.MenuItem(name='ShredMenuProvider::Shred3x',
+ label='3x overwrite (Default)',
+ tip=shred_cmd + ' FILE... (HDD\'s only!)',
+ icon=self.SHRED_ICON)
+ shred_3x_random_menuitem.connect('activate', self.shred_menu_activate_cb, {'cmd': shred_cmd, 'files': files})
+ shred_submenu.append_item(shred_3x_random_menuitem)
+
+ return top_menuitem,
+
+ def get_background_items(self, window, file):
+ wipe_zero_cmd = self.WIPE_CMD.format('zero', self.WIPE_FILENAME)
+ wipe_freespace_zero_menuitem = Caja.MenuItem(name='ShredMenuProvider::WipeFreespaceZero',
+ label='Wipe freespace zero\'s',
+ tip='Wipe freespace with command: "{}"'.format(wipe_zero_cmd),
+ icon=self.SHRED_ICON)
+ wipe_freespace_zero_menuitem.connect('activate',
+ self.wipe_freepsace_menu_activate_cb,
+ {'cmd': wipe_zero_cmd, 'file': file})
+
+ wipe_random_cmd = self.WIPE_CMD.format('random', self.WIPE_FILENAME)
+ wipe_freespace_random_menuitem = Caja.MenuItem(name='ShredMenuProvider::WipeFreespaceRandom',
+ label='Wipe freespace random',
+ tip='Wipe freespace with command: "{}"'.format(wipe_random_cmd),
+ icon=self.SHRED_ICON)
+ wipe_freespace_random_menuitem.connect('activate',
+ self.wipe_freepsace_menu_activate_cb,
+ {'cmd': wipe_random_cmd, 'file': file})
+
+ return wipe_freespace_zero_menuitem, wipe_freespace_random_menuitem,