Example #1
0
 def test_listdir(self):
     """Unit test for listdir()"""
     if 'posix' == os.name:
         dir1 = '/tmp'
         dir2 = expanduser('~/.config')
     if 'nt' == os.name:
         dir1 = expandvars(r'%windir%\fonts')
         dir2 = expandvars(r'%userprofile%\desktop')
     # If these directories do not exist, the test results are not valid.
     self.assertExists(dir1)
     self.assertExists(dir2)
     # Every path found in dir1 and dir2 should be found in (dir1, dir2).
     paths1 = set(listdir(dir1))
     paths2 = set(listdir(dir2))
     paths12 = set(listdir((dir1,dir2)))
     self.assertTrue(paths1 < paths12)
     self.assertTrue(paths2 < paths12)
     # The individual calls should be equivalent to a combined call.
     self.assertSetEqual(paths1.union(paths2), paths12)
     # The directories should not be empty.
     self.assertGreater(len(paths1), 0)
     self.assertGreater(len(paths2), 0)
     # Every path found should exist.
     for pathname in paths12:
         self.assertLExists(pathname)
Example #2
0
def delete_updates():
    """Returns commands for deleting Windows Updates files"""
    windir = bleachbit.expandvars('$windir')
    dirs = glob.glob(os.path.join(windir, '$NtUninstallKB*'))
    dirs += [bleachbit.expandvars('$windir\\SoftwareDistribution\\Download')]
    dirs += [bleachbit.expandvars('$windir\\ie7updates')]
    dirs += [bleachbit.expandvars('$windir\\ie8updates')]
    if not dirs:
        # if nothing to delete, then also do not restart service
        return

    import win32serviceutil
    wu_running = win32serviceutil.QueryServiceStatus('wuauserv')[1] == 4

    args = ['net', 'stop', 'wuauserv']

    def wu_service():
        General.run_external(args)
        return 0
    if wu_running:
        yield Command.Function(None, wu_service, " ".join(args))

    for path1 in dirs:
        for path2 in FileUtilities.children_in_directory(path1, True):
            yield Command.Delete(path2)
        if os.path.exists(path1):
            yield Command.Delete(path1)

    args = ['net', 'start', 'wuauserv']
    if wu_running:
        yield Command.Function(None, wu_service, " ".join(args))
Example #3
0
def winapp_expand_vars(pathname):
    """Expand environment variables using special Winapp2.ini rules"""
    # This is the regular expansion
    expand1 = expandvars(pathname)
    # Winapp2.ini expands %ProgramFiles% to %ProgramW6432%, etc.
    subs = (('ProgramFiles', 'ProgramW6432'),
            ('CommonProgramFiles', 'CommonProgramW6432'))
    for (sub_orig, sub_repl) in subs:
        pattern = re.compile('%{}%'.format(sub_orig), flags=re.IGNORECASE)
        if pattern.match(pathname):
            expand2 = pattern.sub('%{}%'.format(sub_repl), pathname)
            return expand1, expandvars(expand2)
    return expand1,
Example #4
0
 def is_running(self):
     """Return whether the program is currently running"""
     logger = logging.getLogger(__name__)
     for running in self.running:
         test = running[0]
         pathname = running[1]
         if 'exe' == test and 'posix' == os.name:
             if Unix.is_running(pathname):
                 logger.debug("process '%s' is running", pathname)
                 return True
         elif 'exe' == test and 'nt' == os.name:
             if Windows.is_process_running(pathname):
                 logger.debug("process '%s' is running", pathname)
                 return True
         elif 'pathname' == test:
             expanded = expanduser(expandvars(pathname))
             for globbed in glob.iglob(expanded):
                 if os.path.exists(globbed):
                     logger.debug(
                         "file '%s' exists indicating '%s' is running", globbed, self.name)
                     return True
         else:
             raise RuntimeError(
                 "Unknown running-detection test '%s'" % test)
     return False
Example #5
0
def expand_glob_join(pathname1, pathname2):
    """Join pathname1 and pathname1, expand pathname, glob, and return as list"""
    ret = []
    pathname3 = expanduser(bleachbit.expandvars(os.path.join(pathname1, pathname2)))
    for pathname4 in glob.iglob(pathname3):
        ret.append(pathname4)
    return ret
Example #6
0
def guess_overwrite_paths():
    """Guess which partitions to overwrite (to hide deleted files)"""
    # In case overwriting leaves large files, placing them in
    # ~/.config makes it easy to find them and clean them.
    ret = []
    if 'posix' == os.name:
        home = expanduser('~/.cache')
        if not os.path.exists(home):
            home = expanduser("~")
        ret.append(home)
        if not same_partition(home, '/tmp/'):
            ret.append('/tmp')
    elif 'nt' == os.name:
        localtmp = bleachbit.expandvars('$TMP')
        if not os.path.exists(localtmp):
            logger.warning('%TMP% does not exist: %s', localtmp)
            localtmp = None
        from bleachbit.Windows import get_fixed_drives
        for drive in get_fixed_drives():
            if localtmp and same_partition(localtmp, drive):
                ret.append(localtmp)
            else:
                ret.append(drive)
    else:
        NotImplementedError('Unsupported OS in guess_overwrite_paths')
    return ret
Example #7
0
 def test_delete(self):
     """Unit test for class Delete"""
     paths = [u'~']
     if 'nt' == os.name:
         # Python 2.6 and later supports %foo%
         paths.append(u'%USERPROFILE%')
         # Python 2.5 and later supports $foo
         paths.append(u'${USERPROFILE}')
         paths.append(u'$USERPROFILE')
     if 'posix' == os.name:
         paths.append(u'$HOME')
     for path in paths:
         for mode in ('delete', 'truncate', 'delete_forward'):
             expanded = expanduser(expandvars(path))
             filename = self.mkstemp(dir=expanded, prefix='bleachbit-action-delete')
             command = mode
             if 'delete_forward' == mode:
                 # forward slash needs to be normalized on Windows
                 if 'nt' == os.name:
                     command = 'delete'
                     filename = filename.replace('\\', '/')
                 else:
                     # test not needed on this OS
                     os.remove(filename)
                     continue
             action_str = u'<action command="%s" search="file" path="%s" />' % \
                 (command, filename)
             self._test_action_str(action_str)
             self.assertNotExists(filename)
Example #8
0
    def test_whitelisted_speed(self):
        """Benchmark the speed of whitelisted()

        It is called frequently, so the speed is important."""
        d = '/usr/bin'
        whitelist = [('file', '/home/foo'), ('folder', '/home/folder')]
        if 'nt' == os.name:
            d = expandvars('%windir%\system32')
            whitelist = [('file', r'c:\\filename'), ('folder', r'c:\\folder')]
        reps = 20
        paths = [p for p in children_in_directory(d, True)]
        paths = paths[:1000]  # truncate
        self.assertGreater(len(paths), 10)
        old_whitelist = options.get_whitelist_paths()
        options.set_whitelist_paths(whitelist)

        t0 = time.time()
        for i in xrange(0, reps):
            for p in paths:
                _ = whitelisted(p)
        t1 = time.time()
        logger.info('whitelisted() with {} repetitions and {} paths took {:.3g} seconds '.format(
            reps, len(paths), t1 - t0))

        options.set_whitelist_paths(old_whitelist)
Example #9
0
 def __init__(self, action_element, path_vars=None):
     self.cmd = expandvars(action_element.getAttribute('cmd'))
     # by default, wait
     self.wait = True
     wait = action_element.getAttribute('wait')
     if wait and wait.lower()[0] in ('f', 'n'):
         # false or no
         self.wait = False
Example #10
0
 def _set_paths(self, raw_path, path_vars):
     """Set the list of paths to work on"""
     self.paths = []
     # expand special $$foo$$ which may give multiple values
     for path2 in expand_multi_var(raw_path, path_vars):
         path3 = expanduser(expandvars(path2))
         if os.name == 'nt' and path3:
             # convert forward slash to backslash for compatibility with getsize()
             # and for display.  Do not convert an empty path, or it will become
             # the current directory (.).
             path3 = os.path.normpath(path3)
         self.paths.append(path3)
Example #11
0
def get_autostart_path():
    """Return the path of the BleachBit shortcut in the user's startup folder"""
    try:
        startupdir = shell.SHGetSpecialFolderPath(None, shellcon.CSIDL_STARTUP)
    except:
        # example of failure
        # https://www.bleachbit.org/forum/error-windows-7-x64-bleachbit-091
        logger.exception('exception in get_autostart_path()')
        msg = 'Error finding user startup folder: %s ' % (
            str(sys.exc_info()[1]))
        from bleachbit import GuiBasic
        GuiBasic.message_dialog(None, msg)
        # as a fallback, guess
        # Windows XP: C:\Documents and Settings\(username)\Start Menu\Programs\Startup
        # Windows 7:
        # C:\Users\(username)\AppData\Roaming\Microsoft\Windows\Start
        # Menu\Programs\Startup
        startupdir = bleachbit.expandvars('$USERPROFILE\\Start Menu\\Programs\\Startup')
        if not os.path.exists(startupdir):
            startupdir = bleachbit.expandvars('$APPDATA\\Roaming\\Microsoft\\Windows\\Start Menu\\Programs\\Startup')
    return os.path.join(startupdir, 'bleachbit.lnk')
Example #12
0
def set_environ(varname, path):
    """Define an environment variable for use in CleanerML and Winapp2.ini"""
    if not path:
        return
    if varname in os.environ:
        #logger.debug('set_environ(%s, %s): skipping because environment variable is already defined', varname, path)
        if 'nt' == os.name:
            os.environ[varname] = bleachbit.expandvars(u'%%%s%%' % varname).encode('utf-8')
        # Do not redefine the environment variable when it already exists
        # But re-encode them with utf-8 instead of mbcs
        return
    try:
        if not os.path.exists(path):
            raise RuntimeError('Variable %s points to a non-existent path %s' % (varname, path))
        os.environ[varname] = path.encode('utf8')
    except:
        logger.exception('set_environ(%s, %s): exception when setting environment variable', varname, path)
Example #13
0
    def get_commands(self, option_id):
        files = []
        # backup files
        if 'backup' == option_id:
            bookmark_bu_dir = os.path.join(self.profile_dir, 'bookmarkbackups')
            files += FileUtilities.expand_glob_join(bookmark_bu_dir, "*.json")
            files += FileUtilities.expand_glob_join(bookmark_bu_dir,
                                                    "*.jsonlz4")
        # browser cache
        cache_base = None
        if 'posix' == os.name:
            cache_base = self.profile_dir
        elif 'nt' == os.name:
            cache_base = "$localappdata\\Mozilla\\Firefox\\Profiles\\*.default*"
        if 'cache' == option_id:
            dirs = FileUtilities.expand_glob_join(cache_base, "Cache*")
            dirs += FileUtilities.expand_glob_join(cache_base, "OfflineCache")
            if 'nt' == os.name:
                dirs += FileUtilities.expand_glob_join(
                    cache_base, "jumpListCache")  # Windows 8
            if 'posix' == os.name:
                # This path is whitelisted under the System - Cache cleaner,
                # so it can be cleaned here.
                dirs += [expanduser('~/.cache/mozilla')]
            for dirname in dirs:
                for filename in children_in_directory(dirname, False):
                    yield Command.Delete(filename)
            # Necko Predictive Network Actions
            # https://wiki.mozilla.org/Privacy/Reviews/Necko
            files += FileUtilities.expand_glob_join(self.profile_dir,
                                                    "netpredictions.sqlite")
        # cookies
        if 'cookies' == option_id:
            files += FileUtilities.expand_glob_join(self.profile_dir,
                                                    "cookies.txt")
            files += FileUtilities.expand_glob_join(self.profile_dir,
                                                    "cookies.sqlite")
        # crash reports
        if 'posix' == os.name:
            crashdir = expanduser("~/.mozilla/firefox/Crash Reports")
        if 'nt' == os.name:
            crashdir = expandvars(
                "$USERPROFILE\\Application Data\\Mozilla\\Firefox\\Crash Reports"
            )
        if 'crash_reports' == option_id:
            for filename in children_in_directory(crashdir, False):
                files += [filename]
            files += FileUtilities.expand_glob_join(self.profile_dir,
                                                    "minidumps/*.dmp")
        # DOM storage
        if 'dom' == option_id:
            files += FileUtilities.expand_glob_join(self.profile_dir,
                                                    "webappsstore.sqlite")

        # download history
        if 'download_history' == option_id:
            # Firefox version 1
            files += FileUtilities.expand_glob_join(self.profile_dir,
                                                    "downloads.rdf")
            # Firefox version 3
            files += FileUtilities.expand_glob_join(self.profile_dir,
                                                    "downloads.sqlite")
        # forms
        if 'forms' == option_id:
            files += FileUtilities.expand_glob_join(self.profile_dir,
                                                    "formhistory.dat")
            files += FileUtilities.expand_glob_join(self.profile_dir,
                                                    "formhistory.sqlite")
        # passwords
        if 'passwords' == option_id:
            # http://kb.mozillazine.org/Password_Manager
            files += FileUtilities.expand_glob_join(self.profile_dir,
                                                    "signons.txt")
            files += FileUtilities.expand_glob_join(self.profile_dir,
                                                    "signons[2-3].txt")
            files += FileUtilities.expand_glob_join(self.profile_dir,
                                                    "signons.sqlite")
            files += FileUtilities.expand_glob_join(self.profile_dir,
                                                    "logins.json")
        # session restore
        if 'session_restore' == option_id:
            # Names include sessionstore.js, sessionstore.bak,
            # sessionstore.bak-20140715214327, sessionstore-1.js
            files += FileUtilities.expand_glob_join(self.profile_dir,
                                                    "sessionstore*.js")
            files += FileUtilities.expand_glob_join(self.profile_dir,
                                                    "sessionstore.bak*")
            ss_bu_dir = os.path.join(self.profile_dir, 'sessionstore-backups')
            files += FileUtilities.expand_glob_join(ss_bu_dir, 'previous.js')
            files += FileUtilities.expand_glob_join(ss_bu_dir,
                                                    'upgrade.js-20*')
            files += FileUtilities.expand_glob_join(ss_bu_dir, 'recovery.js')
            files += FileUtilities.expand_glob_join(ss_bu_dir, 'recovery.bak')
        # site-specific preferences
        if 'site_preferences' == option_id:
            files += FileUtilities.expand_glob_join(self.profile_dir,
                                                    "content-prefs.sqlite")

        # URL history
        if 'url_history' == option_id:
            # Firefox version 1
            files += FileUtilities.expand_glob_join(self.profile_dir,
                                                    "history.dat")
            # Firefox 21 on Windows
            if 'nt' == os.name:
                files += FileUtilities.expand_glob_join(
                    cache_base, "thumbnails/*.png")
            # see also function other_cleanup()
        # finish
        for filename in files:
            yield Command.Delete(filename)

        # URL history
        if 'url_history' == option_id:
            for path in FileUtilities.expand_glob_join(self.profile_dir,
                                                       "places.sqlite"):
                yield Command.Function(path,
                                       Special.delete_mozilla_url_history,
                                       _('Delete the usage history'))

        # vacuum
        if 'vacuum' == option_id:
            paths = []
            paths += FileUtilities.expand_glob_join(self.profile_dir,
                                                    "*.sqlite")
            if not cache_base == self.profile_dir:
                paths += FileUtilities.expand_glob_join(cache_base, "*.sqlite")
            for path in paths:
                yield Command.Function(path, FileUtilities.vacuum_sqlite3,
                                       _("Vacuum"))
Example #14
0
    def get_commands(self, option_id):
        # cache
        if 'posix' == os.name and 'cache' == option_id:
            dirname = expanduser("~/.cache/")
            for filename in children_in_directory(dirname, True):
                if not self.whitelisted(filename):
                    yield Command.Delete(filename)

        # custom
        if 'custom' == option_id:
            for (c_type, c_path) in options.get_custom_paths():
                if 'file' == c_type:
                    yield Command.Delete(c_path)
                elif 'folder' == c_type:
                    yield Command.Delete(c_path)
                    for path in children_in_directory(c_path, True):
                        yield Command.Delete(path)
                else:
                    raise RuntimeError(
                        'custom folder has invalid type %s' % c_type)

        # menu
        menu_dirs = ['~/.local/share/applications',
                     '~/.config/autostart',
                     '~/.gnome/apps/',
                     '~/.gnome2/panel2.d/default/launchers',
                     '~/.gnome2/vfolders/applications/',
                     '~/.kde/share/apps/RecentDocuments/',
                     '~/.kde/share/mimelnk',
                     '~/.kde/share/mimelnk/application/ram.desktop',
                     '~/.kde2/share/mimelnk/application/',
                     '~/.kde2/share/applnk']

        if 'posix' == os.name and 'desktop_entry' == option_id:
            for dirname in menu_dirs:
                for filename in [fn for fn in children_in_directory(dirname, False)
                                 if fn.endswith('.desktop')]:
                    if Unix.is_broken_xdg_desktop(filename):
                        yield Command.Delete(filename)

        # unwanted locales
        if 'posix' == os.name and 'localizations' == option_id:
            for path in Unix.locales.localization_paths(locales_to_keep=options.get_languages()):
                if os.path.isdir(path):
                    for f in FileUtilities.children_in_directory(path, True):
                        yield Command.Delete(f)
                yield Command.Delete(path)

        # Windows logs
        if 'nt' == os.name and 'logs' == option_id:
            paths = (
                '$ALLUSERSPROFILE\\Application Data\\Microsoft\\Dr Watson\\*.log',
                '$ALLUSERSPROFILE\\Application Data\\Microsoft\\Dr Watson\\user.dmp',
                '$LocalAppData\\Microsoft\\Windows\\WER\\ReportArchive\\*\\*',
                '$LocalAppData\\Microsoft\\Windows\WER\\ReportQueue\\*\\*',
                '$programdata\\Microsoft\\Windows\\WER\\ReportArchive\\*\\*',
                '$programdata\\Microsoft\\Windows\\WER\\ReportQueue\\*\\*',
                '$localappdata\\Microsoft\\Internet Explorer\\brndlog.bak',
                '$localappdata\\Microsoft\\Internet Explorer\\brndlog.txt',
                '$windir\\*.log',
                '$windir\\imsins.BAK',
                '$windir\\OEWABLog.txt',
                '$windir\\SchedLgU.txt',
                '$windir\\ntbtlog.txt',
                '$windir\\setuplog.txt',
                '$windir\\REGLOCS.OLD',
                '$windir\\Debug\\*.log',
                '$windir\\Debug\\Setup\\UpdSh.log',
                '$windir\\Debug\\UserMode\\*.log',
                '$windir\\Debug\\UserMode\\ChkAcc.bak',
                '$windir\\Debug\\UserMode\\userenv.bak',
                '$windir\\Microsoft.NET\Framework\*\*.log',
                '$windir\\pchealth\\helpctr\\Logs\\hcupdate.log',
                '$windir\\security\\logs\\*.log',
                '$windir\\security\\logs\\*.old',
                '$windir\\SoftwareDistribution\\*.log',
                '$windir\\SoftwareDistribution\\DataStore\\Logs\\*',
                '$windir\\system32\\TZLog.log',
                '$windir\\system32\\config\\systemprofile\\Application Data\\Microsoft\\Internet Explorer\\brndlog.bak',
                '$windir\\system32\\config\\systemprofile\\Application Data\\Microsoft\\Internet Explorer\\brndlog.txt',
                '$windir\\system32\\LogFiles\\AIT\\AitEventLog.etl.???',
                '$windir\\system32\\LogFiles\\Firewall\\pfirewall.log*',
                '$windir\\system32\\LogFiles\\Scm\\SCM.EVM*',
                '$windir\\system32\\LogFiles\\WMI\\Terminal*.etl',
                '$windir\\system32\\LogFiles\\WMI\\RTBackup\EtwRT.*etl',
                '$windir\\system32\\wbem\\Logs\\*.lo_',
                '$windir\\system32\\wbem\\Logs\\*.log', )

            for path in paths:
                expanded = expandvars(path)
                for globbed in glob.iglob(expanded):
                    yield Command.Delete(globbed)

        # memory
        if sys.platform.startswith('linux') and 'memory' == option_id:
            yield Command.Function(None, Memory.wipe_memory, _('Memory'))

        # memory dump
        # how to manually create this file
        # http://www.pctools.com/guides/registry/detail/856/
        if 'nt' == os.name and 'memory_dump' == option_id:
            fname = expandvars('$windir\\memory.dmp')
            if os.path.exists(fname):
                yield Command.Delete(fname)
            for fname in glob.iglob(expandvars('$windir\\Minidump\\*.dmp')):
                yield Command.Delete(fname)

        # most recently used documents list
        if 'posix' == os.name and 'recent_documents' == option_id:
            ru_fn = expanduser("~/.recently-used")
            if os.path.lexists(ru_fn):
                yield Command.Delete(ru_fn)
            # GNOME 2.26 (as seen on Ubuntu 9.04) will retain the list
            # in memory if it is simply deleted, so it must be shredded
            # (or at least truncated).
            #
            # GNOME 2.28.1 (Ubuntu 9.10) and 2.30 (10.04) do not re-read
            # the file after truncation, but do re-read it after
            # shredding.
            #
            # https://bugzilla.gnome.org/show_bug.cgi?id=591404

            def gtk_purge_items():
                """Purge GTK items"""
                gtk.RecentManager().purge_items()
                yield 0

            for pathname in ["~/.recently-used.xbel", "~/.local/share/recently-used.xbel"]:
                pathname = expanduser(pathname)
                if os.path.lexists(pathname):
                    yield Command.Shred(pathname)
            if HAVE_GTK:
                # Use the Function to skip when in preview mode
                yield Command.Function(None, gtk_purge_items, _('Recent documents list'))

        if 'posix' == os.name and 'rotated_logs' == option_id:
            for path in Unix.rotated_logs():
                yield Command.Delete(path)

        # temporary files
        if 'posix' == os.name and 'tmp' == option_id:
            dirnames = ['/tmp', '/var/tmp']
            for dirname in dirnames:
                for path in children_in_directory(dirname, True):
                    is_open = FileUtilities.openfiles.is_open(path)
                    ok = not is_open and os.path.isfile(path) and \
                        not os.path.islink(path) and \
                        FileUtilities.ego_owner(path) and \
                        not self.whitelisted(path)
                    if ok:
                        yield Command.Delete(path)

        # temporary files
        if 'nt' == os.name and 'tmp' == option_id:
            dirname1 = expandvars(
                "$USERPROFILE\\Local Settings\\Temp\\")
            dirname2 = expandvars(r'%temp%')
            dirname3 = expandvars("%windir%\\temp\\")
            dirnames = []
            if Windows.get_windows_version() >= 6.0:
                # Windows Vista or later
                dirnames.append(dirname2)
            else:
                # Windows XP
                dirnames.append(dirname1)
            dirnames.append(dirname3)
            # whitelist the folder %TEMP%\Low but not its contents
            # https://bugs.launchpad.net/bleachbit/+bug/1421726
            for dirname in dirnames:
                low = os.path.join(dirname, 'low').lower()
                for filename in children_in_directory(dirname, True):
                    if not low == filename.lower():
                        yield Command.Delete(filename)

        # trash
        if 'posix' == os.name and 'trash' == option_id:
            dirname = expanduser("~/.Trash")
            for filename in children_in_directory(dirname, False):
                yield Command.Delete(filename)
            # fixme http://www.ramendik.ru/docs/trashspec.html
            # http://standards.freedesktop.org/basedir-spec/basedir-spec-0.6.html
            # ~/.local/share/Trash
            # * GNOME 2.22, Fedora 9
            # * KDE 4.1.3, Ubuntu 8.10
            dirname = expanduser("~/.local/share/Trash/files")
            for filename in children_in_directory(dirname, True):
                yield Command.Delete(filename)
            dirname = expanduser("~/.local/share/Trash/info")
            for filename in children_in_directory(dirname, True):
                yield Command.Delete(filename)
            dirname = expanduser("~/.local/share/Trash/expunged")
            # [email protected] tells me that the trash
            # backend puts files in here temporary, but in some situations
            # the files are stuck.
            for filename in children_in_directory(dirname, True):
                yield Command.Delete(filename)

        # clipboard
        if HAVE_GTK and 'clipboard' == option_id:
            def clear_clipboard():
                gtk.gdk.threads_enter()
                clipboard = gtk.clipboard_get()
                clipboard.set_text("")
                gtk.gdk.threads_leave()
                return 0
            yield Command.Function(None, clear_clipboard, _('Clipboard'))

        # overwrite free space
        shred_drives = options.get_list('shred_drives')
        if 'free_disk_space' == option_id and shred_drives:
            for pathname in shred_drives:
                # TRANSLATORS: 'Free' means 'unallocated.'
                # %s expands to a path such as C:\ or /tmp/
                display = _("Overwrite free disk space %s") % pathname

                def wipe_path_func():
                    for ret in FileUtilities.wipe_path(pathname, idle=True):
                        # Yield control to GTK idle because this process
                        # is very slow.  Also display progress.
                        yield ret
                    yield 0
                yield Command.Function(None, wipe_path_func, display)

        # MUICache
        if 'nt' == os.name and 'muicache' == option_id:
            keys = (
                'HKCU\\Software\\Microsoft\\Windows\\ShellNoRoam\\MUICache',
                'HKCU\\Software\\Classes\\Local Settings\\Software\\Microsoft\\Windows\\Shell\\MuiCache')
            for key in keys:
                yield Command.Winreg(key, None)

        # prefetch
        if 'nt' == os.name and 'prefetch' == option_id:
            for path in glob.iglob(expandvars('$windir\\Prefetch\\*.pf')):
                yield Command.Delete(path)

        # recycle bin
        if 'nt' == os.name and 'recycle_bin' == option_id:
            # This method allows shredding
            recycled_any = False
            for path in Windows.get_recycle_bin():
                recycled_any = True
                yield Command.Delete(path)
            # If there were any files deleted, Windows XP will show the
            # wrong icon for the recycle bin indicating it is not empty.
            # The icon will be incorrect until logging in to Windows again
            # or until it is emptied using the Windows API call for emptying
            # the recycle bin.

            # Windows 10 refreshes the recycle bin icon when the user
            # opens the recycle bin folder.

            # This is a hack to refresh the icon.
            def empty_recycle_bin_func():
                import tempfile
                tmpdir = tempfile.mkdtemp()
                Windows.move_to_recycle_bin(tmpdir)
                try:
                    Windows.empty_recycle_bin(None, True)
                except:
                    logging.getLogger(__name__).info('error in empty_recycle_bin()', exc_info=True)
                yield 0
            # Using the Function Command prevents emptying the recycle bin
            # when in preview mode.
            if recycled_any:
                yield Command.Function(None, empty_recycle_bin_func, _('Empty the recycle bin'))

        # Windows Updates
        if 'nt' == os.name and 'updates' == option_id:
            for wu in Windows.delete_updates():
                yield wu
Example #15
0
 def test_expandvars(self):
     """Unit test for expandvars()."""
     expanded = expandvars('$HOME')
     self.assertIsUnicodeString(expanded)
Example #16
0
 def test_expandvars(self):
     """Unit test for expandvars."""
     var = bleachbit.expandvars('$HOME')
     self.assertIsUnicodeString(var)
Example #17
0
def expandvars(path):
    return bleachbit.expandvars(path)
Example #18
0
 def test_expandvars(self):
     """Unit test for expandvars()."""
     expanded = expandvars('$HOME')
     self.assertIsUnicodeString(expanded)
Example #19
0
    def get_commands(self, option_id):
        # cache
        if 'posix' == os.name and 'cache' == option_id:  # 운영체제이름이 posix이고 option_id가 캐시인 경우 
            dirname = expanduser("~/.cache/") # ~/.cache/에서 "~"을 사용자 디렉토리의 절대경로로 대체한 것을 dirname에 저장
                                              # dirname = C:\\Documents and Settings\\Administrator\\.cache\ 가 된다.
                
            for filename in children_in_directory(dirname, True): 
                # C:\\Documents and Settings\\Administrator\\.cache\ 의 파일 및 선택적으로 하위 디렉토리를 반복
                if not self.whitelisted(filename): # filename이 whitelist인지 확인해서 true일 경우
                    yield Command.Delete(filename) # filename을 삭제하는 메서드를 return

        # custom
        if 'custom' == option_id:             # option_id가 custom인지 확인 custom = 사용자 정의 
            for (c_type, c_path) in options.get_custom_paths(): # 사용자 정의 경로의 파일 및 폴더를 반복 
                if 'file' == c_type: 
                    yield Command.Delete(c_path) # file타입일 경우 삭제
                elif 'folder' == c_type:
                    yield Command.Delete(c_path) # folder타입일 경우 삭제
                    for path in children_in_directory(c_path, True):  # c_path(사용자 정의 경로)의 파일 및 선택적으로 하위 디렉토리 반복
                        yield Command.Delete(path) # 반복되는 파일 및 하위 디렉토리 삭제
                else:
                    raise RuntimeError(    # 파일도 폴더도 아닐경우 런타임에러 발생
                        'custom folder has invalid type %s' % c_type)

        # menu
        menu_dirs = ['~/.local/share/applications',
                     '~/.config/autostart',
                     '~/.gnome/apps/',
                     '~/.gnome2/panel2.d/default/launchers',
                     '~/.gnome2/vfolders/applications/',
                     '~/.kde/share/apps/RecentDocuments/',
                     '~/.kde/share/mimelnk',
                     '~/.kde/share/mimelnk/application/ram.desktop',
                     '~/.kde2/share/mimelnk/application/',
                     '~/.kde2/share/applnk']
        # 메뉴 디렉토리에 다음 경로들을 설정

        if 'posix' == os.name and 'desktop_entry' == option_id:          #  운영체제가 posix이고 option_id가 desktop_entry인 경우
            for dirname in menu_dirs: # 메뉴 디렉토리에 있는 경로를 반복 
                for filename in [fn for fn in children_in_directory(dirname, False)  
                                 if fn.endswith('.desktop')]: 
                    if Unix.is_broken_xdg_desktop(filename): # filename의 XDG 데스크톱 항목 파일의 손상 여부 확인 
                        yield Command.Delete(filename) # filename 삭제 

        # unwanted locales
        if 'posix' == os.name and 'localizations' == option_id: # 운영체제가 posix고 option_id가 localizations일때 
            for path in Unix.locales.localization_paths(locales_to_keep=options.get_languages()):
                # 이전에 추가한 xml 구성과 일치하는 모든 위치 지정 항목을 반복
                if os.path.isdir(path): # path가 존재하는지 확인 
                    for f in FileUtilities.children_in_directory(path, True): # path의 파일 및 하위 디렉토리 반복
                        yield Command.Delete(f) # path의 파일 및 하위 디렉토리 삭제
                yield Command.Delete(path) # path삭제

        # Windows logs
        if 'nt' == os.name and 'logs' == option_id:   # os가 윈도우고 option_id가 로그일때 
            paths = (
                '$ALLUSERSPROFILE\\Application Data\\Microsoft\\Dr Watson\\*.log',
                '$ALLUSERSPROFILE\\Application Data\\Microsoft\\Dr Watson\\user.dmp',
                '$LocalAppData\\Microsoft\\Windows\\WER\\ReportArchive\\*\\*',
                '$LocalAppData\\Microsoft\\Windows\WER\\ReportQueue\\*\\*',
                '$programdata\\Microsoft\\Windows\\WER\\ReportArchive\\*\\*',
                '$programdata\\Microsoft\\Windows\\WER\\ReportQueue\\*\\*',
                '$localappdata\\Microsoft\\Internet Explorer\\brndlog.bak',
                '$localappdata\\Microsoft\\Internet Explorer\\brndlog.txt',
                '$windir\\*.log',
                '$windir\\imsins.BAK',
                '$windir\\OEWABLog.txt',
                '$windir\\SchedLgU.txt',
                '$windir\\ntbtlog.txt',
                '$windir\\setuplog.txt',
                '$windir\\REGLOCS.OLD',
                '$windir\\Debug\\*.log',
                '$windir\\Debug\\Setup\\UpdSh.log',
                '$windir\\Debug\\UserMode\\*.log',
                '$windir\\Debug\\UserMode\\ChkAcc.bak',
                '$windir\\Debug\\UserMode\\userenv.bak',
                '$windir\\Microsoft.NET\Framework\*\*.log',
                '$windir\\pchealth\\helpctr\\Logs\\hcupdate.log',
                '$windir\\security\\logs\\*.log',
                '$windir\\security\\logs\\*.old',
                '$windir\\SoftwareDistribution\\*.log',
                '$windir\\SoftwareDistribution\\DataStore\\Logs\\*',
                '$windir\\system32\\TZLog.log',
                '$windir\\system32\\config\\systemprofile\\Application Data\\Microsoft\\Internet Explorer\\brndlog.bak',
                '$windir\\system32\\config\\systemprofile\\Application Data\\Microsoft\\Internet Explorer\\brndlog.txt',
                '$windir\\system32\\LogFiles\\AIT\\AitEventLog.etl.???',
                '$windir\\system32\\LogFiles\\Firewall\\pfirewall.log*',
                '$windir\\system32\\LogFiles\\Scm\\SCM.EVM*',
                '$windir\\system32\\LogFiles\\WMI\\Terminal*.etl',
                '$windir\\system32\\LogFiles\\WMI\\RTBackup\EtwRT.*etl',
                '$windir\\system32\\wbem\\Logs\\*.lo_',
                '$windir\\system32\\wbem\\Logs\\*.log', )
               
            for path in paths: # paths에 있는 경로 반복
                expanded = expandvars(path) # 경로에 환경변수가 포함되어있으면 확장
                for globbed in glob.iglob(expanded): # 확장한 경로의 파일및 디렉토리를 반복
                    yield Command.Delete(globbed) # 삭제

        # memory
        if sys.platform.startswith('linux') and 'memory' == option_id: # 시스템의 플랫폼이 lunux로 시작하고 option_id가 메모리이면
            yield Command.Function(None, Memory.wipe_memory, _('Memory')) # 메모리를 지우는 간단한 파이썬 함수를 만듬

        # memory dump
        # how to manually create this file
        # http://www.pctools.com/guides/registry/detail/856/
        if 'nt' == os.name and 'memory_dump' == option_id: # os가 윈도우고 option_id가 memory_dump 일때
            fname = expandvars('$windir\\memory.dmp') # $windir\\memory.dmp에 환경변수가 있으면 확장
            if os.path.exists(fname): # 확장한 경로가 존재하는지 확인
                yield Command.Delete(fname) # 존재하면 삭제
            for fname in glob.iglob(expandvars('$windir\\Minidump\\*.dmp')): # $windir\\Minidump\\*.dmp 를 확장하고 파일 및 디렉토리 반복
                yield Command.Delete(fname) # $windir\\Minidump\\*.dmp'의 파일 및 디렉토리들을 삭제

        # most recently used documents list
        if 'posix' == os.name and 'recent_documents' == option_id: # os가 posix고 option_id가 최근 문서일 경우
            ru_fn = expanduser("~/.recently-used") # ~/.recently-used 에서 "~"을 사용자 디렉토리의 경로로 대체
            if os.path.lexists(ru_fn): # 사용자 디렉토리/.recently-used 가 존재하는지 확인
                yield Command.Delete(ru_fn) # 존재하면 삭제
            # GNOME 2.26 (as seen on Ubuntu 9.04) will retain the list
            # in memory if it is simply deleted, so it must be shredded
            # (or at least truncated).
            #
            # GNOME 2.28.1 (Ubuntu 9.10) and 2.30 (10.04) do not re-read
            # the file after truncation, but do re-read it after
            # shredding.
            #
            # https://bugzilla.gnome.org/show_bug.cgi?id=591404

            def gtk_purge_items(): 
                """Purge GTK items"""                      # GTK 항목 제거
                gtk.RecentManager().purge_items()
                yield 0

            for pathname in ["~/.recently-used.xbel", "~/.local/share/recently-used.xbel"]:
                pathname = expanduser(pathname) # 경로에서 "~"을 사용자 디렉토리로 대체
                if os.path.lexists(pathname): # 경로의 파일이 존재하는지 확인
                    yield Command.Shred(pathname) # 있으면 pathname 잘라내기
            if HAVE_GTK:
                # Use the Function to skip when in preview mode
                yield Command.Function(None, gtk_purge_items, _('Recent documents list'))
                      # GTK 모듈을 불러오는데 성공했으면 최근 문서 목록을 나타내는 간단한 함수 생성

        if 'posix' == os.name and 'rotated_logs' == option_id: # 운영체제가 posix고 option_id 가 순환로그일때 
            for path in Unix.rotated_logs():  #  /var/log/에서 순환 로그(예: 이전 로그) 목록을 반복 
                yield Command.Delete(path) # 삭제

        # temporary files
        if 'posix' == os.name and 'tmp' == option_id: # 운영체제가 posix이고 option_id가 tmp ( 임시파일) 일때
            dirnames = ['/tmp', '/var/tmp'] # 경로 저장
            for dirname in dirnames: # 임시파일의 경로 반복
                for path in children_in_directory(dirname, True): # 경로의 파일 및 하위 디렉토리 반복
                    is_open = FileUtilities.openfiles.is_open(path)  # path의 파일이 열려있는지 여부 
                    ok = not is_open and os.path.isfile(path) and # path의 파일이 열려있지 않고 path가 존재하며
                        not os.path.islink(path) and \ # path가 link파일 혹은 폴더가 아니고
                        FileUtilities.ego_owner(path) and \ # 현재 사용자가 파일을 소유하고 있고
                        not self.whitelisted(path) # path가 화이트리스트인지 확인 
                    if ok:
                        yield Command.Delete(path) # path 삭제
Example #20
0
def expandvars(path):
    return bleachbit.expandvars(path)
Example #21
0
 def test_expandvars(self):
     """Unit test for expandvars."""
     var = bleachbit.expandvars('$HOME')
     self.assertIsUnicodeString(var)
Example #22
0
 def assertExists(self, path, msg='', func=os.path.exists):
     """File, directory, or any path exists"""
     from bleachbit import expandvars
     path = expandvars(path)
     if not func(getTestPath(path)):
         raise AssertionError('The file %s should exist, but it does not. %s' % (path, msg))
Example #23
0
    def get_commands(self, option_id):
        # This variable will collect fully expanded file names, and
        # at the end of this function, they will be checked they exist
        # and processed through Command.Delete().
        files = []

        # cache
        if 'posix' == os.name and 'cache' == option_id:
            dirname = expanduser("~/.cache/")
            for filename in children_in_directory(dirname, True):
                if self.whitelisted(filename):
                    continue
                files += [filename]

        # custom
        if 'custom' == option_id:
            for (c_type, c_path) in options.get_custom_paths():
                if 'file' == c_type:
                    files += [c_path]
                elif 'folder' == c_type:
                    files += [c_path]
                    for path in children_in_directory(c_path, True):
                        files += [path]
                else:
                    raise RuntimeError('custom folder has invalid type %s' %
                                       c_type)

        # menu
        menu_dirs = [
            '~/.local/share/applications', '~/.config/autostart',
            '~/.gnome/apps/', '~/.gnome2/panel2.d/default/launchers',
            '~/.gnome2/vfolders/applications/',
            '~/.kde/share/apps/RecentDocuments/', '~/.kde/share/mimelnk',
            '~/.kde/share/mimelnk/application/ram.desktop',
            '~/.kde2/share/mimelnk/application/', '~/.kde2/share/applnk'
        ]

        if 'posix' == os.name and 'desktop_entry' == option_id:
            for dirname in menu_dirs:
                for filename in [
                        fn for fn in children_in_directory(dirname, False)
                        if fn.endswith('.desktop')
                ]:
                    if Unix.is_broken_xdg_desktop(filename):
                        yield Command.Delete(filename)

        # unwanted locales
        if 'posix' == os.name and 'localizations' == option_id:
            for path in Unix.locales.localization_paths(
                    locales_to_keep=options.get_languages()):
                if os.path.isdir(path):
                    for f in FileUtilities.children_in_directory(path, True):
                        yield Command.Delete(f)
                yield Command.Delete(path)

        # Windows logs
        if 'nt' == os.name and 'logs' == option_id:
            paths = (
                '$ALLUSERSPROFILE\\Application Data\\Microsoft\\Dr Watson\\*.log',
                '$ALLUSERSPROFILE\\Application Data\\Microsoft\\Dr Watson\\user.dmp',
                '$LocalAppData\\Microsoft\\Windows\\WER\\ReportArchive\\*\\*',
                '$LocalAppData\\Microsoft\\Windows\WER\\ReportQueue\\*\\*',
                '$programdata\\Microsoft\\Windows\\WER\\ReportArchive\\*\\*',
                '$programdata\\Microsoft\\Windows\\WER\\ReportQueue\\*\\*',
                '$localappdata\\Microsoft\\Internet Explorer\\brndlog.bak',
                '$localappdata\\Microsoft\\Internet Explorer\\brndlog.txt',
                '$windir\\*.log',
                '$windir\\imsins.BAK',
                '$windir\\OEWABLog.txt',
                '$windir\\SchedLgU.txt',
                '$windir\\ntbtlog.txt',
                '$windir\\setuplog.txt',
                '$windir\\REGLOCS.OLD',
                '$windir\\Debug\\*.log',
                '$windir\\Debug\\Setup\\UpdSh.log',
                '$windir\\Debug\\UserMode\\*.log',
                '$windir\\Debug\\UserMode\\ChkAcc.bak',
                '$windir\\Debug\\UserMode\\userenv.bak',
                '$windir\\Microsoft.NET\Framework\*\*.log',
                '$windir\\pchealth\\helpctr\\Logs\\hcupdate.log',
                '$windir\\security\\logs\\*.log',
                '$windir\\security\\logs\\*.old',
                '$windir\\SoftwareDistribution\\*.log',
                '$windir\\SoftwareDistribution\\DataStore\\Logs\\*',
                '$windir\\system32\\TZLog.log',
                '$windir\\system32\\config\\systemprofile\\Application Data\\Microsoft\\Internet Explorer\\brndlog.bak',
                '$windir\\system32\\config\\systemprofile\\Application Data\\Microsoft\\Internet Explorer\\brndlog.txt',
                '$windir\\system32\\LogFiles\\AIT\\AitEventLog.etl.???',
                '$windir\\system32\\LogFiles\\Firewall\\pfirewall.log*',
                '$windir\\system32\\LogFiles\\Scm\\SCM.EVM*',
                '$windir\\system32\\LogFiles\\WMI\\Terminal*.etl',
                '$windir\\system32\\LogFiles\\WMI\\RTBackup\EtwRT.*etl',
                '$windir\\system32\\wbem\\Logs\\*.lo_',
                '$windir\\system32\\wbem\\Logs\\*.log',
            )

            for path in paths:
                expanded = expandvars(path)
                for globbed in glob.iglob(expanded):
                    files += [globbed]

        # memory
        if sys.platform.startswith('linux') and 'memory' == option_id:
            yield Command.Function(None, Memory.wipe_memory, _('Memory'))

        # memory dump
        # how to manually create this file
        # http://www.pctools.com/guides/registry/detail/856/
        if 'nt' == os.name and 'memory_dump' == option_id:
            fname = expandvars('$windir\\memory.dmp')
            if os.path.exists(fname):
                files += [fname]
            for fname in glob.iglob(expandvars('$windir\\Minidump\\*.dmp')):
                files += [fname]

        # most recently used documents list
        if 'posix' == os.name and 'recent_documents' == option_id:
            files += [expanduser("~/.recently-used")]

            # GNOME 2.26 (as seen on Ubuntu 9.04) will retain the list
            # in memory if it is simply deleted, so it must be shredded
            # (or at least truncated).
            #
            # GNOME 2.28.1 (Ubuntu 9.10) and 2.30 (10.04) do not re-read
            # the file after truncation, but do re-read it after
            # shredding.
            #
            # https://bugzilla.gnome.org/show_bug.cgi?id=591404

            def gtk_purge_items():
                """Purge GTK items"""
                gtk.RecentManager().purge_items()
                yield 0

            for pathname in [
                    "~/.recently-used.xbel",
                    "~/.local/share/recently-used.xbel"
            ]:
                pathname = expanduser(pathname)
                if os.path.lexists(pathname):
                    yield Command.Shred(pathname)
            if HAVE_GTK:
                # Use the Function to skip when in preview mode
                yield Command.Function(None, gtk_purge_items,
                                       _('Recent documents list'))

        if 'posix' == os.name and 'rotated_logs' == option_id:
            for path in Unix.rotated_logs():
                yield Command.Delete(path)

        # temporary files
        if 'posix' == os.name and 'tmp' == option_id:
            dirnames = ['/tmp', '/var/tmp']
            for dirname in dirnames:
                for path in children_in_directory(dirname, True):
                    is_open = FileUtilities.openfiles.is_open(path)
                    ok = not is_open and os.path.isfile(path) and \
                        not os.path.islink(path) and \
                        FileUtilities.ego_owner(path) and \
                        not self.whitelisted(path)
                    if ok:
                        yield Command.Delete(path)

        # temporary files
        if 'nt' == os.name and 'tmp' == option_id:
            dirname1 = expandvars("$USERPROFILE\\Local Settings\\Temp\\")
            dirname2 = expandvars(r'%temp%')
            dirname3 = expandvars("%windir%\\temp\\")
            dirnames = []
            if Windows.get_windows_version() >= 6.0:
                # Windows Vista or later
                dirnames.append(dirname2)
            else:
                # Windows XP
                dirnames.append(dirname1)
            dirnames.append(dirname3)
            # whitelist the folder %TEMP%\Low but not its contents
            # https://bugs.launchpad.net/bleachbit/+bug/1421726
            for dirname in dirnames:
                low = os.path.join(dirname, 'low').lower()
                for filename in children_in_directory(dirname, True):
                    if not low == filename.lower():
                        yield Command.Delete(filename)

        # trash
        if 'posix' == os.name and 'trash' == option_id:
            dirname = expanduser("~/.Trash")
            for filename in children_in_directory(dirname, False):
                yield Command.Delete(filename)
            # fixme http://www.ramendik.ru/docs/trashspec.html
            # http://standards.freedesktop.org/basedir-spec/basedir-spec-0.6.html
            # ~/.local/share/Trash
            # * GNOME 2.22, Fedora 9
            # * KDE 4.1.3, Ubuntu 8.10
            dirname = expanduser("~/.local/share/Trash/files")
            for filename in children_in_directory(dirname, True):
                yield Command.Delete(filename)
            dirname = expanduser("~/.local/share/Trash/info")
            for filename in children_in_directory(dirname, True):
                yield Command.Delete(filename)
            dirname = expanduser("~/.local/share/Trash/expunged")
            # [email protected] tells me that the trash
            # backend puts files in here temporary, but in some situations
            # the files are stuck.
            for filename in children_in_directory(dirname, True):
                yield Command.Delete(filename)

        # clipboard
        if HAVE_GTK and 'clipboard' == option_id:

            def clear_clipboard():
                gtk.gdk.threads_enter()
                clipboard = gtk.clipboard_get()
                clipboard.set_text("")
                gtk.gdk.threads_leave()
                return 0

            yield Command.Function(None, clear_clipboard, _('Clipboard'))

        # overwrite free space
        shred_drives = options.get_list('shred_drives')
        if 'free_disk_space' == option_id and shred_drives:
            for pathname in shred_drives:
                # TRANSLATORS: 'Free' means 'unallocated.'
                # %s expands to a path such as C:\ or /tmp/
                display = _("Overwrite free disk space %s") % pathname

                def wipe_path_func():
                    for ret in FileUtilities.wipe_path(pathname, idle=True):
                        # Yield control to GTK idle because this process
                        # is very slow.  Also display progress.
                        yield ret
                    yield 0

                yield Command.Function(None, wipe_path_func, display)

        # MUICache
        if 'nt' == os.name and 'muicache' == option_id:
            keys = (
                'HKCU\\Software\\Microsoft\\Windows\\ShellNoRoam\\MUICache',
                'HKCU\\Software\\Classes\\Local Settings\\Software\\Microsoft\\Windows\\Shell\\MuiCache'
            )
            for key in keys:
                yield Command.Winreg(key, None)

        # prefetch
        if 'nt' == os.name and 'prefetch' == option_id:
            for path in glob.iglob(expandvars('$windir\\Prefetch\\*.pf')):
                yield Command.Delete(path)

        # recycle bin
        if 'nt' == os.name and 'recycle_bin' == option_id:
            # This method allows shredding
            recycled_any = False
            for path in Windows.get_recycle_bin():
                recycled_any = True
                yield Command.Delete(path)
            # If there were any files deleted, Windows XP will show the
            # wrong icon for the recycle bin indicating it is not empty.
            # The icon will be incorrect until logging in to Windows again
            # or until it is emptied using the Windows API call for emptying
            # the recycle bin.

            # Windows 10 refreshes the recycle bin icon when the user
            # opens the recycle bin folder.

            # This is a hack to refresh the icon.
            def empty_recycle_bin_func():
                import tempfile
                tmpdir = tempfile.mkdtemp()
                Windows.move_to_recycle_bin(tmpdir)
                try:
                    Windows.empty_recycle_bin(None, True)
                except:
                    logging.getLogger(__name__).info(
                        'error in empty_recycle_bin()', exc_info=True)
                yield 0

            # Using the Function Command prevents emptying the recycle bin
            # when in preview mode.
            if recycled_any:
                yield Command.Function(None, empty_recycle_bin_func,
                                       _('Empty the recycle bin'))

        # Windows Updates
        if 'nt' == os.name and 'updates' == option_id:
            for wu in Windows.delete_updates():
                yield wu

        # return queued files
        for filename in files:
            if os.path.lexists(filename):
                yield Command.Delete(filename)
Example #24
0
class System(Cleaner):

    """Clean the system in general
       일반적인 시스템 청소"""

    def __init__(self):
        Cleaner.__init__(self)

        #
        # options for Linux and BSD
        #
        if 'posix' == os.name:                                                          #운영체제가 posix면
            # TRANSLATORS: desktop entries are .desktop files in Linux that
            # make up the application menu (the menu that shows BleachBit,
            # Firefox, and others.  The .desktop files also associate file
            # types, so clicking on an .html file in Nautilus brings up
            # Firefox.
            # More information:
            # http://standards.freedesktop.org/menu-spec/latest/index.html#introduction
            self.add_option('desktop_entry', _('Broken desktop files'), _(
                 # option_id=desktop entry , name =  손상된 데스크탑 파일들
                'Delete broken application menu entries and file associations')) 
                 # description = 손상된 응용 프로그램 메뉴 항목 및 파일 연결 삭제 으로 option 추가
            self.add_option('cache', _('Cache'), _('Delete the cache'))
            # 캐시 삭제를 위한 옵션 추가
            # TRANSLATORS: Localizations are files supporting specific
            # languages, so applications appear in Spanish, etc.
            self.add_option('localizations', _('Localizations'), _(
                'Delete files for unwanted languages'))
            # 원치 않는 언어를 삭제하는 옵션 추가
            self.set_warning(
                'localizations', _("Configure this option in the preferences."))\
            # localizations에 대해 기본 설정에서 이 옵션 구성하라는 경고메세지 설정\
            
            # TRANSLATORS: 'Rotated logs' refers to old system log files.
            # Linux systems often have a scheduled job to rotate the logs
            # which means compress all except the newest log and then delete
            # the oldest log.  You could translate this 'old logs.'
            self.add_option(
                'rotated_logs', _('Rotated logs'), _('Delete old system logs'))
            # 시스템 로그를 삭제기 위한 옵션 추가
            self.add_option('recent_documents', _('Recent documents list'), _(
                'Delete the list of recently used documents'))
            # 최근 사용된 문서들의 목록을 삭제하기위한 옵션 추가
            self.add_option('trash', _('Trash'), _('Empty the trash'))
            # 쓰레기통을 비우기 위한 옵션 추가

        #
        # options just for Linux
        #
        if sys.platform.startswith('linux'):          # 운영체제이름이 linux로 시작할 경우
            self.add_option('memory', _('Memory'),    # 
                            # TRANSLATORS: 'free' means 'unallocated'
                            _('Wipe the swap and free memory')) # 스왑 및 할당되지 않은 메모리를 지우는 옵션 추가
            self.set_warning(
                'memory', _('This option is experimental and may cause system problems.'))
                 # meomory에 관해 이 옵션은 실험적이며 시스템 문제를 일으킬 수 있다는 경고 메시지 설정

        #
        # options just for Microsoft Windows
        #
        if 'nt' == os.name:                                               # os가 윈도우일 경우 
            self.add_option('logs', _('Logs'), _('Delete the logs'))   # 로그를 삭제하는 옵션 추가
            self.add_option(
                'memory_dump', _('Memory dump'), _('Delete the file memory.dmp')) # 파일 메모리를 삭제하는 옵션 추가
            self.add_option('muicache', 'MUICache', _('Delete the cache')) # muicache를 삭제하는 옵션 추가
            # TRANSLATORS: Prefetch is Microsoft Windows jargon.
            self.add_option('prefetch', _('Prefetch'), _('Delete the cache'))  # prefetch 캐시를 삭제하는 옵션 추가
                                                                               # prefetch = 사용했던 프로그램 정보를 담아두는 곳
            self.add_option(
                'recycle_bin', _('Recycle bin'), _('Empty the recycle bin'))  # 휴지통을 비우는 옵션 추가
            # TRANSLATORS: 'Update' is a noun, and 'Update uninstallers' is an option to delete
            # the uninstallers for software updates.
            self.add_option('updates', _('Update uninstallers'), _(
                'Delete uninstallers for Microsoft updates including hotfixes, service packs, and Internet Explorer updates'))
                # 핫픽스, 서비스 팩 및 Internet Explorer 업데이트를 비롯한 Microsoft 업데이트용 제거 장치를 삭제하는 옵션 추가
        #
        # options for GTK+      GTK = 김프 툴킷
        #

        if HAVE_GTK:        # HAVE_GTK 는 GTK모듈을 불러올때 True로 설정했음 즉 모듈을 불러올때 오류가 나지 않았다면 다음 함수들 실행
            self.add_option('clipboard', _('Clipboard'), _(
                'The desktop environment\'s clipboard used for copy and paste operations'))
                # 데스크탑 환경에서 복사 및 붙여넣기에 사용되는 클립보드를 옵션에 추가

        #
        # options common to all platforms
        #
        # TRANSLATORS: "Custom" is an option allowing the user to specify which
        # files and folders will be erased.
        self.add_option('custom', _('Custom'), _(
            'Delete user-specified files and folders')) # 사용자 지정 파일 및 폴더를 삭제하는 옵션 추가 
        # TRANSLATORS: 'free' means 'unallocated'
        self.add_option('free_disk_space', _('Free disk space'),   #
                        # TRANSLATORS: 'free' means 'unallocated'
                        _('Overwrite free disk space to hide deleted files'))
                         # 삭제된 파일을 숨기기 위해 할당되지 않은 디스크 공간 덮어쓰기 옵션 추가
        self.set_warning('free_disk_space', _('This option is very slow.'))
                         # free_disk_space 옵션에 대해 이 옵션은 매우 느리다는 경고 메시지 설정
        self.add_option(
            'tmp', _('Temporary files'), _('Delete the temporary files'))
             # 임시파일을 삭제하는 옵션 추가

        self.description = _("The system in general") # 시스템 클래스의 설명 설정
        self.id = 'system'   # 시스템 클래스의 id 설정
        self.name = _("System")  # 시스템 클래스의 이름 설정

    def get_commands(self, option_id):
        # cache
        if 'posix' == os.name and 'cache' == option_id:  # 운영체제이름이 posix이고 option_id가 캐시인 경우 
            dirname = expanduser("~/.cache/") # ~/.cache/에서 "~"을 사용자 디렉토리의 절대경로로 대체한 것을 dirname에 저장
                                              # dirname = C:\\Documents and Settings\\Administrator\\.cache\ 가 된다.
                
            for filename in children_in_directory(dirname, True): 
                # C:\\Documents and Settings\\Administrator\\.cache\ 의 파일 및 선택적으로 하위 디렉토리를 반복
                if not self.whitelisted(filename): # filename이 whitelist인지 확인해서 true일 경우
                    yield Command.Delete(filename) # filename을 삭제하는 메서드를 return

        # custom
        if 'custom' == option_id:             # option_id가 custom인지 확인 custom = 사용자 정의 
            for (c_type, c_path) in options.get_custom_paths(): # 사용자 정의 경로의 파일 및 폴더를 반복 
                if 'file' == c_type: 
                    yield Command.Delete(c_path) # file타입일 경우 삭제
                elif 'folder' == c_type:
                    yield Command.Delete(c_path) # folder타입일 경우 삭제
                    for path in children_in_directory(c_path, True):  # c_path(사용자 정의 경로)의 파일 및 선택적으로 하위 디렉토리 반복
                        yield Command.Delete(path) # 반복되는 파일 및 하위 디렉토리 삭제
                else:
                    raise RuntimeError(    # 파일도 폴더도 아닐경우 런타임에러 발생
                        'custom folder has invalid type %s' % c_type)

        # menu
        menu_dirs = ['~/.local/share/applications',
                     '~/.config/autostart',
                     '~/.gnome/apps/',
                     '~/.gnome2/panel2.d/default/launchers',
                     '~/.gnome2/vfolders/applications/',
                     '~/.kde/share/apps/RecentDocuments/',
                     '~/.kde/share/mimelnk',
                     '~/.kde/share/mimelnk/application/ram.desktop',
                     '~/.kde2/share/mimelnk/application/',
                     '~/.kde2/share/applnk']
        # 메뉴 디렉토리에 다음 경로들을 설정

        if 'posix' == os.name and 'desktop_entry' == option_id:          #  운영체제가 posix이고 option_id가 desktop_entry인 경우
            for dirname in menu_dirs: # 메뉴 디렉토리에 있는 경로를 반복 
                for filename in [fn for fn in children_in_directory(dirname, False)  
                                 if fn.endswith('.desktop')]: 
                    if Unix.is_broken_xdg_desktop(filename): # filename의 XDG 데스크톱 항목 파일의 손상 여부 확인 
                        yield Command.Delete(filename) # filename 삭제 

        # unwanted locales
        if 'posix' == os.name and 'localizations' == option_id: # 운영체제가 posix고 option_id가 localizations일때 
            for path in Unix.locales.localization_paths(locales_to_keep=options.get_languages()):
                # 이전에 추가한 xml 구성과 일치하는 모든 위치 지정 항목을 반복
                if os.path.isdir(path): # path가 존재하는지 확인 
                    for f in FileUtilities.children_in_directory(path, True): # path의 파일 및 하위 디렉토리 반복
                        yield Command.Delete(f) # path의 파일 및 하위 디렉토리 삭제
                yield Command.Delete(path) # path삭제

        # Windows logs
        if 'nt' == os.name and 'logs' == option_id:   # os가 윈도우고 option_id가 로그일때 
            paths = (
                '$ALLUSERSPROFILE\\Application Data\\Microsoft\\Dr Watson\\*.log',
                '$ALLUSERSPROFILE\\Application Data\\Microsoft\\Dr Watson\\user.dmp',
                '$LocalAppData\\Microsoft\\Windows\\WER\\ReportArchive\\*\\*',
                '$LocalAppData\\Microsoft\\Windows\WER\\ReportQueue\\*\\*',
                '$programdata\\Microsoft\\Windows\\WER\\ReportArchive\\*\\*',
                '$programdata\\Microsoft\\Windows\\WER\\ReportQueue\\*\\*',
                '$localappdata\\Microsoft\\Internet Explorer\\brndlog.bak',
                '$localappdata\\Microsoft\\Internet Explorer\\brndlog.txt',
                '$windir\\*.log',
                '$windir\\imsins.BAK',
                '$windir\\OEWABLog.txt',
                '$windir\\SchedLgU.txt',
                '$windir\\ntbtlog.txt',
                '$windir\\setuplog.txt',
                '$windir\\REGLOCS.OLD',
                '$windir\\Debug\\*.log',
                '$windir\\Debug\\Setup\\UpdSh.log',
                '$windir\\Debug\\UserMode\\*.log',
                '$windir\\Debug\\UserMode\\ChkAcc.bak',
                '$windir\\Debug\\UserMode\\userenv.bak',
                '$windir\\Microsoft.NET\Framework\*\*.log',
                '$windir\\pchealth\\helpctr\\Logs\\hcupdate.log',
                '$windir\\security\\logs\\*.log',
                '$windir\\security\\logs\\*.old',
                '$windir\\SoftwareDistribution\\*.log',
                '$windir\\SoftwareDistribution\\DataStore\\Logs\\*',
                '$windir\\system32\\TZLog.log',
                '$windir\\system32\\config\\systemprofile\\Application Data\\Microsoft\\Internet Explorer\\brndlog.bak',
                '$windir\\system32\\config\\systemprofile\\Application Data\\Microsoft\\Internet Explorer\\brndlog.txt',
                '$windir\\system32\\LogFiles\\AIT\\AitEventLog.etl.???',
                '$windir\\system32\\LogFiles\\Firewall\\pfirewall.log*',
                '$windir\\system32\\LogFiles\\Scm\\SCM.EVM*',
                '$windir\\system32\\LogFiles\\WMI\\Terminal*.etl',
                '$windir\\system32\\LogFiles\\WMI\\RTBackup\EtwRT.*etl',
                '$windir\\system32\\wbem\\Logs\\*.lo_',
                '$windir\\system32\\wbem\\Logs\\*.log', )
               
            for path in paths: # paths에 있는 경로 반복
                expanded = expandvars(path) # 경로에 환경변수가 포함되어있으면 확장
                for globbed in glob.iglob(expanded): # 확장한 경로의 파일및 디렉토리를 반복
                    yield Command.Delete(globbed) # 삭제

        # memory
        if sys.platform.startswith('linux') and 'memory' == option_id: # 시스템의 플랫폼이 lunux로 시작하고 option_id가 메모리이면
            yield Command.Function(None, Memory.wipe_memory, _('Memory')) # 메모리를 지우는 간단한 파이썬 함수를 만듬

        # memory dump
        # how to manually create this file
        # http://www.pctools.com/guides/registry/detail/856/
        if 'nt' == os.name and 'memory_dump' == option_id: # os가 윈도우고 option_id가 memory_dump 일때
            fname = expandvars('$windir\\memory.dmp') # $windir\\memory.dmp에 환경변수가 있으면 확장
            if os.path.exists(fname): # 확장한 경로가 존재하는지 확인
                yield Command.Delete(fname) # 존재하면 삭제
            for fname in glob.iglob(expandvars('$windir\\Minidump\\*.dmp')): # $windir\\Minidump\\*.dmp 를 확장하고 파일 및 디렉토리 반복
                yield Command.Delete(fname) # $windir\\Minidump\\*.dmp'의 파일 및 디렉토리들을 삭제

        # most recently used documents list
        if 'posix' == os.name and 'recent_documents' == option_id: # os가 posix고 option_id가 최근 문서일 경우
            ru_fn = expanduser("~/.recently-used") # ~/.recently-used 에서 "~"을 사용자 디렉토리의 경로로 대체
            if os.path.lexists(ru_fn): # 사용자 디렉토리/.recently-used 가 존재하는지 확인
                yield Command.Delete(ru_fn) # 존재하면 삭제
            # GNOME 2.26 (as seen on Ubuntu 9.04) will retain the list
            # in memory if it is simply deleted, so it must be shredded
            # (or at least truncated).
            #
            # GNOME 2.28.1 (Ubuntu 9.10) and 2.30 (10.04) do not re-read
            # the file after truncation, but do re-read it after
            # shredding.
            #
            # https://bugzilla.gnome.org/show_bug.cgi?id=591404

            def gtk_purge_items(): 
                """Purge GTK items"""                      # GTK 항목 제거
                gtk.RecentManager().purge_items()
                yield 0

            for pathname in ["~/.recently-used.xbel", "~/.local/share/recently-used.xbel"]:
                pathname = expanduser(pathname) # 경로에서 "~"을 사용자 디렉토리로 대체
                if os.path.lexists(pathname): # 경로의 파일이 존재하는지 확인
                    yield Command.Shred(pathname) # 있으면 pathname 잘라내기
            if HAVE_GTK:
                # Use the Function to skip when in preview mode
                yield Command.Function(None, gtk_purge_items, _('Recent documents list'))
                      # GTK 모듈을 불러오는데 성공했으면 최근 문서 목록을 나타내는 간단한 함수 생성

        if 'posix' == os.name and 'rotated_logs' == option_id: # 운영체제가 posix고 option_id 가 순환로그일때 
            for path in Unix.rotated_logs():  #  /var/log/에서 순환 로그(예: 이전 로그) 목록을 반복 
                yield Command.Delete(path) # 삭제

        # temporary files
        if 'posix' == os.name and 'tmp' == option_id: # 운영체제가 posix이고 option_id가 tmp ( 임시파일) 일때
            dirnames = ['/tmp', '/var/tmp'] # 경로 저장
            for dirname in dirnames: # 임시파일의 경로 반복
                for path in children_in_directory(dirname, True): # 경로의 파일 및 하위 디렉토리 반복
                    is_open = FileUtilities.openfiles.is_open(path)  # path의 파일이 열려있는지 여부 
                    ok = not is_open and os.path.isfile(path) and # path의 파일이 열려있지 않고 path가 존재하며
                        not os.path.islink(path) and \ # path가 link파일 혹은 폴더가 아니고
                        FileUtilities.ego_owner(path) and \ # 현재 사용자가 파일을 소유하고 있고
                        not self.whitelisted(path) # path가 화이트리스트인지 확인 
                    if ok:
                        yield Command.Delete(path) # path 삭제

        # temporary files
        if 'nt' == os.name and 'tmp' == option_id:         # os가 윈도우일때 임시파일 삭제
            dirname1 = expandvars(
                "$USERPROFILE\\Local Settings\\Temp\\")    # $USERPROFILE\\Local Settings\\Temp\\ 경로 확장
            dirname2 = expandvars(r'%temp%')               # '%temp% 경로 확장
            dirname3 = expandvars("%windir%\\temp\\")      # %windir%\\temp\\ 경로 확장
            dirnames = []
            if Windows.get_windows_version() >= 6.0:       # 윈도우의 버전이 6.0 이상이면 비스타나 그 이후버전
                # Windows Vista or later                      
                dirnames.append(dirname2)                  # dirnames리스트에 확장한 %temp% 경로 추가
            else:
                # Windows XP
                dirnames.append(dirname1)        # 윈도우 xp의 경우 drinames에 확장한 $USERPROFILE\\Local Settings\\Temp\\ 경로 추가
            dirnames.append(dirname3)            # dirnames에 확장한 %windir%\\temp\\ 경로 추가
            # whitelist the folder %TEMP%\Low but not its contents
            # https://bugs.launchpad.net/bleachbit/+bug/1421726
            for dirname in dirnames:  # 확장한 경로 반복 
                low = os.path.join(dirname, 'low').lower() # 경로와 'low' 를 os에 맞게 연결하고 소문자로 바꿔서 저장
                for filename in children_in_directory(dirname, True): # dirname의 파일과 하위 디렉토리 반복 
                    if not low == filename.lower(): # dirname의 파일과 하위 디렉토리를 소문자로 한것이 low와 같으면 
                        yield Command.Delete(filename) # 삭제

        # trash
        if 'posix' == os.name and 'trash' == option_id:     # posix에서 option_id가 trash일때 
            dirname = expanduser("~/.Trash") # ~/.Trash에서 "~"을 사용자 디렉토리로 대체 
            for filename in children_in_directory(dirname, False): # 사용자 디렉토리/.Trash 의 파일및 하위디렉토리 삭제
                yield Command.Delete(filename)
            # fixme http://www.ramendik.ru/docs/trashspec.html
            # http://standards.freedesktop.org/basedir-spec/basedir-spec-0.6.html
            # ~/.local/share/Trash
            # * GNOME 2.22, Fedora 9
            # * KDE 4.1.3, Ubuntu 8.10
            dirname = expanduser("~/.local/share/Trash/files") # 경로 확장
            for filename in children_in_directory(dirname, True): # 경로의 파일 및 하위 디렉토리 삭제
                yield Command.Delete(filename)
            dirname = expanduser("~/.local/share/Trash/info") # 경로 확장
            for filename in children_in_directory(dirname, True): # 경로의 파일 및 하위 디렉토리 삭제
                yield Command.Delete(filename)
            dirname = expanduser("~/.local/share/Trash/expunged")
            # [email protected] tells me that the trash
            # backend puts files in here temporary, but in some situations
            # the files are stuck.
            for filename in children_in_directory(dirname, True):
                yield Command.Delete(filename)

        # clipboard
        if HAVE_GTK and 'clipboard' == option_id:   # GTK모듈을 불러오고 option_id가 클립보드이면 
            def clear_clipboard():   # 클립보드를 지우는 함수 생성 
                gtk.gdk.threads_enter()
                clipboard = gtk.clipboard_get()
                clipboard.set_text("")
                gtk.gdk.threads_leave()
                return 0
            yield Command.Function(None, clear_clipboard, _('Clipboard')) # 클립보드를 지우는 간단한 파이썬 함수 생성 명령 리턴

        # overwrite free space 사용가능한 공간 덮어쓰기 
        shred_drives = options.get_list('shred_drives') # shred_drives 리스트 추출
        if 'free_disk_space' == option_id and shred_drives:  # option_id가 free_disk_space이고 shred_drives가 존재하면
            for pathname in shred_drives:  # shred_drives의 요소를 반복
                # TRANSLATORS: 'Free' means 'unallocated.'
                # %s expands to a path such as C:\ or /tmp/
                display = _("Overwrite free disk space %s") % pathname # 사용가능한 공간을 덮어쓴다고 출력

                def wipe_path_func(): # 경로의 여유공간 를 지우는 함수 
                    for ret in FileUtilities.wipe_path(pathname, idle=True): 
                        # Yield control to GTK idle because this process  
                        # is very slow.  Also display progress.
                        # FileUtilities.wipe_path = 경로의 여유 공간 지우는 함수
                        # 이 기능은 반복기를 사용하여 GUI를 업데이트합니다.
                        yield ret  #  pathname 의 여유 공간을 지우고 return 
                    yield 0
                yield Command.Function(None, wipe_path_func, display) # 간단한 파이썬 함수 생성

        # MUICache
        if 'nt' == os.name and 'muicache' == option_id:
            keys = (
                'HKCU\\Software\\Microsoft\\Windows\\ShellNoRoam\\MUICache',
                'HKCU\\Software\\Classes\\Local Settings\\Software\\Microsoft\\Windows\\Shell\\MuiCache')
            for key in keys: 
                yield Command.Winreg(key, None)
                # keys에 있는 경로들의 윈도우 레지스트리를 지운다.

        # prefetch
        if 'nt' == os.name and 'prefetch' == option_id:
            for path in glob.iglob(expandvars('$windir\\Prefetch\\*.pf')):
                yield Command.Delete(path)
                # '$windir\\Prefetch\\*.pf' 를 환경변수가 있으면 확장하고 경로에 있는 모든 파일 및 디렉토리를 삭제

        # recycle bin
        if 'nt' == os.name and 'recycle_bin' == option_id:
            # This method allows shredding
            recycled_any = False
            for path in Windows.get_recycle_bin(): # get_recycle_bin() : 휴지통에 있는 파일 목록들 가져오는 함수
                recycled_any = True # 휴지통이 비어있는지에 대한 여부
                yield Command.Delete(path) # 휴지통에 있는 파일 목록들을 가져와서 삭제
            # If there were any files deleted, Windows XP will show the
            # wrong icon for the recycle bin indicating it is not empty.
            # The icon will be incorrect until logging in to Windows again
            # or until it is emptied using the Windows API call for emptying
            # the recycle bin.

            # Windows 10 refreshes the recycle bin icon when the user
            # opens the recycle bin folder.

            # This is a hack to refresh the icon.
            def empty_recycle_bin_func(): # 휴지통 비우기 함수 정의
                import tempfile
                tmpdir = tempfile.mkdtemp() # 중복되지않게 무작위로 임시파일 생성 
                Windows.move_to_recycle_bin(tmpdir) # 생성한 임시파일을 휴지통으로 보냄 
                try: # 예외처리부분 
                    Windows.empty_recycle_bin(None, True) # 휴지통 비우기 함수 호출 
                except:
                    logging.getLogger(__name__).info('error in empty_recycle_bin()', exc_info=True)
                    # 에러발생시 휴지통 비우기 에러 라는 로그메시지 저장
                yield 0
            # Using the Function Command prevents emptying the recycle bin
            # when in preview mode.
            if recycled_any: # 휴지통안에 파일이 있으면 
                yield Command.Function(None, empty_recycle_bin_func, _('Empty the recycle bin'))
                # 휴지통을 비우는 간단한 파이썬 함수 생성
                # name = empty_recycle_bin_func , description = 'Empty the recycle bin' 

        # Windows Updates
        if 'nt' == os.name and 'updates' == option_id: 
            for wu in Windows.delete_updates():    # 윈도우 업데이트 삭제
                yield wu