def __init__(self, uac=True, shred_paths=None, auto_exit=False): if os.name == 'nt': if Windows.elevate_privileges(uac): # privileges escalated in other process sys.exit(0) if portable_mode: Windows.copy_fonts_in_portable_app(auto_exit) Gtk.Application.__init__( self, application_id='org.gnome.Bleachbit', flags=Gio.ApplicationFlags.FLAGS_NONE) GObject.threads_init() if auto_exit: # This is used for automated testing of whether the GUI can start. # It is called from assert_execute_console() in windows/setup_py2exe.py self._auto_exit = True if shred_paths: self._shred_paths = shred_paths if os.name == 'nt': # clean up nonce files https://github.com/bleachbit/bleachbit/issues/858 import atexit atexit.register(Windows.cleanup_nonce) # BitDefender false positive. BitDefender didn't mark BleachBit as infected or show # anything in its log, but sqlite would fail to import unless BitDefender was in "game mode." # https://www.bleachbit.org/forum/074-fails-errors try: import sqlite3 except ImportError: logger.exception( _("Error loading the SQLite module: the antivirus software may be blocking it."))
def detectos(required_ver, mock=False): """Returns boolean whether the detectos is compatible with the current operating system, or the mock version, if given.""" # Do not compare as string because Windows 10 (build 10.0) comes after # Windows 8.1 (build 6.3) assert isinstance(required_ver, (str, unicode)) #현재의 os를 초기화 한다. current_os = (mock if mock else Windows.parse_windows_build()) #required_ver에 required_ver을 붙인다. required_ver = required_ver.strip() #만약 '|'가 required_ver라면 if '|' in required_ver: # Format of min|max # req_min에 required_ver[0]에 '|'붙인 것을 초기화한다. req_min = required_ver.split('|')[0] # req_max에 required_ver[1]에 '|'붙인 것을 초기화한다. req_max = required_ver.split('|')[1] #비교를 통해 false와 true을 리턴한다. if req_min and current_os < Windows.parse_windows_build(req_min): return False if req_max and current_os > Windows.parse_windows_build(req_max): return False return True else: #버전이 호환된다면 현재의 os를 반환한다. # Exact version return Windows.parse_windows_build(required_ver) == current_os
def is_running(self): """Return whether the program is currently running""" resp_cli="" 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): #print "debug: process '%s' is running" % pathname logger.debug("Debug: process '%s' is running", pathname) if options.get("close_run"): if not subprocess.mswindows: #print "debug: Closing process '%s'" % pathname if "--preset" in sys.argv: resp_cli = raw_input("Do you Want BleachBit to Close " + pathname + " y/n : ") else: resp = GuiBasic.message_dialog(None,"Do you Want BleachBit to Close " + pathname,gtk.MESSAGE_WARNING, gtk.BUTTONS_YES_NO) if gtk.RESPONSE_YES == resp or resp_cli.lower() == "y": # user cancelled, so don't toggle option logger.debug("Debug: Closing process '%s'",pathname) subprocess.check_output(["killall", "-9", pathname]) if not Unix.is_running(pathname): logger.debug("Debug: Closing process '%s' successful",pathname) return False return True elif 'exe' == test and 'nt' == os.name: if Windows.is_process_running(pathname): #print "debug: process '%s' is running" % pathname logger.debug("Debug: process '%s' is running", pathname) if options.get("close_run"): if subprocess.mswindows: #print "debug: Closing process '%s'" % pathname if "--preset" in sys.argv: resp_cli = raw_input("Do you Want BleachBit to Close " + pathname + " y/n : ") else: resp = GuiBasic.message_dialog(None,"Do you Want BleachBit to Close " + pathname,gtk.MESSAGE_WARNING, gtk.BUTTONS_YES_NO) if gtk.RESPONSE_YES == resp or resp_cli.lower() == "y": logger.debug("debug: Closing process '%s'",pathname) subprocess.check_output(["taskkill", "/IM", pathname]) if not Windows.is_process_running(pathname): logger.debug("debug: Closing process '%s' successful",pathname) return False 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", self.name) return True else: raise RuntimeError( "Unknown running-detection test '%s'" % test) return False
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
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
def _show_splash_screen(self): if os.name != 'nt': return font_conf_file = Windows.get_font_conf_file() if not os.path.exists(font_conf_file): logger.error('No fonts.conf file') return has_cache = Windows.has_fontconfig_cache(font_conf_file) if not has_cache: Windows.splash_thread.start()
def browse_folder(parent, title, multiple, stock_button): """Ask the user to select a folder. Return the full path or None.""" if 'nt' == os.name and None == os.getenv('BB_NATIVE'): ret = Windows.browse_folder( parent.window.handle if parent else None, title) return [ret] if multiple and not ret is None else ret # fall back to GTK+ chooser = gtk.FileChooserDialog(parent=parent, title=title, buttons=( gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL, stock_button, gtk.RESPONSE_OK), action=gtk.FILE_CHOOSER_ACTION_SELECT_FOLDER) chooser.set_select_multiple(multiple) chooser.set_current_folder(expanduser('~')) resp = chooser.run() if multiple: ret = chooser.get_filenames() else: ret = chooser.get_filename() chooser.hide() chooser.destroy() if gtk.RESPONSE_OK != resp: # user cancelled return None return ret
def browse_folder(parent, title, multiple, stock_button): """Ask the user to select a folder. Return the full path or None.""" if 'nt' == os.name and None == os.getenv('BB_NATIVE'): ret = Windows.browse_folder( parent.window.handle if parent else None, title) return [ret] if multiple and not ret is None else ret # fall back to GTK+ chooser = Gtk.FileChooserDialog(transient_for=parent, title=title, action = Gtk.FileChooserAction.SELECT_FOLDER) chooser.add_buttons(_("_Cancel"), Gtk.ResponseType.CANCEL, stock_button, Gtk.ResponseType.OK) chooser.set_default_response(Gtk.ResponseType.OK) chooser.set_select_multiple(multiple) chooser.set_current_folder(expanduser('~')) resp = chooser.run() if multiple: ret = chooser.get_filenames() else: ret = chooser.get_filename() chooser.hide() chooser.destroy() if Gtk.ResponseType.OK != resp: # user cancelled return None return ret
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
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
def __init__(self, uac=True, shred_paths=None, auto_exit=False): if uac and os.name == 'nt' and Windows.elevate_privileges(): # privileges escalated in other process sys.exit(0) Gtk.Application.__init__(self, application_id='org.gnome.Bleachbit', flags=Gio.ApplicationFlags.FLAGS_NONE) GObject.threads_init() if shred_paths: self._shred_paths = shred_paths return if os.name == 'nt': # BitDefender false positive. BitDefender didn't mark BleachBit as infected or show # anything in its log, but sqlite would fail to import unless BitDefender was in "game mode." # https://www.bleachbit.org/forum/074-fails-errors try: import sqlite3 except ImportError: logger.exception( _("Error loading the SQLite module: the antivirus software may be blocking it." )) if auto_exit: # This is used for automated testing of whether the GUI can start. self._auto_exit = True
def is_running(self): """Return whether the program is currently running""" # 프로그램이 현재 실행 중인지 여부를 반환하는 함수 logger = logging.getLogger(__name__) # __name__에서 로거 추출 for running in self.running: # running 리스트의 값들 반복 test = running[0] # running[0] = detection_type ( add_running 함수 참고) pathname = running[1] if 'exe' == test and 'posix' == os.name: # os이름이 posix이고 exe 타입인지 확인 if Unix.is_running(pathname): # Unix에서 is_running함수썼을때 True이면 logger.debug("process '%s' is running", pathname) # 프로세스가 실행중이라는 debug 메세지를 로그하고 True반환 return True elif 'exe' == test and 'nt' == os.name: # os이름이 nt 이고 exe타입인지 확인 if Windows.is_process_running(pathname): # 만약 Windows에서 is_process_running 함수를 사용했을때 true이면 logger.debug("process '%s' is running", pathname) # 프로세스가 실행중이라는 debug 메세지를 로그하고 true반환 return True elif 'pathname' == test: # test expanded = expanduser(expandvars(pathname)) # pathname 안에 환경변수가 있으면 확장하고 현재 사용자 디렉토리의 절대경로로 대체 # ex) C:\\Documents and Settings\\Administrator\\pathname for globbed in glob.iglob(expanded): # iglob() : expanded의 모든 값을 실제로 동시에 저장하지 않고 # glob()값과 동일한 값을 산출하는 반복기를 반환함 if os.path.exists(globbed): # globbed로 저장한 경로에 특정파일이 존재하는지 확인 logger.debug( "file '%s' exists indicating '%s' is running", globbed, self.name) # 존재하면 파일이 존재하며 실행중임을 나타내는 메세지출력 return True else: raise RuntimeError( "Unknown running-detection test '%s'" % test) # test가 exe , pathname도 아니면 알수없는 실행타입메세지와 함께 런타임에러발생 return False
def browse_folder(parent, title, multiple, stock_button): """Ask the user to select a folder. Return the full path or None.""" if os.name == 'nt' and not os.getenv('BB_NATIVE'): ret = Windows.browse_folder(parent, title) return [ret] if multiple and not ret is None else ret # fall back to GTK+ chooser = Gtk.FileChooserDialog(transient_for=parent, title=title, action=Gtk.FileChooserAction.SELECT_FOLDER) chooser.add_buttons(_("_Cancel"), Gtk.ResponseType.CANCEL, stock_button, Gtk.ResponseType.OK) chooser.set_default_response(Gtk.ResponseType.OK) chooser.set_select_multiple(multiple) chooser.set_current_folder(expanduser('~')) resp = chooser.run() if multiple: ret = chooser.get_filenames() else: ret = chooser.get_filename() chooser.hide() chooser.destroy() if Gtk.ResponseType.OK != resp: # user cancelled return None return ret
def detect(self, section): """Check whether to show the section The logic: If the DetectOS does not match, the section is inactive. If any Detect or DetectFile matches, the section is active. If neither Detect or DetectFile was given, the section is active. Otherwise, the section is inactive. """ if self.parser.has_option(section, 'detectos'): required_ver = self.parser.get(section, 'detectos') if not detectos(required_ver): return False any_detect_option = False if self.parser.has_option(section, 'specialdetect'): any_detect_option = True sd_code = self.parser.get(section, 'specialdetect') if special_detect(sd_code): return True for option in self.parser.options(section): if re.match(self.re_detect, option): # Detect= checks for a registry key any_detect_option = True key = self.parser.get(section, option) if Windows.detect_registry_key(key): return True elif re.match(self.re_detectfile, option): # DetectFile= checks for a file any_detect_option = True key = self.parser.get(section, option) if detect_file(key): return True return not any_detect_option
def browse_folder(parent, title, multiple, stock_button): """Ask the user to select a folder. Return the full path or None.""" if 'nt' == os.name and None == os.getenv('BB_NATIVE'): ret = Windows.browse_folder(parent.window.handle if parent else None, title) return [ret] if multiple and not ret is None else ret # fall back to GTK+ chooser = gtk.FileChooserDialog( parent=parent, title=title, buttons=(gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL, stock_button, gtk.RESPONSE_OK), action=gtk.FILE_CHOOSER_ACTION_SELECT_FOLDER) chooser.set_select_multiple(multiple) chooser.set_current_folder(expanduser('~')) resp = chooser.run() if multiple: ret = chooser.get_filenames() else: ret = chooser.get_filename() chooser.hide() chooser.destroy() if gtk.RESPONSE_OK != resp: # user cancelled return None return ret
def __init__(self, uac=True, shred_paths=None, exit=False): if uac and 'nt' == os.name and Windows.elevate_privileges(): # privileges escalated in other process sys.exit(0) Gtk.Application.__init__(self, application_id='org.gnome.Bleachbit', flags=Gio.ApplicationFlags.FLAGS_NONE) if not exit: from bleachbit import RecognizeCleanerML RecognizeCleanerML.RecognizeCleanerML() register_cleaners() GObject.threads_init() if shred_paths: self.shred_paths(shred_paths) return if 'nt' == os.name: # BitDefender false positive. BitDefender didn't mark BleachBit as infected or show # anything in its log, but sqlite would fail to import unless BitDefender was in "game mode." # https://www.bleachbit.org/forum/074-fails-errors try: import sqlite3 except ImportError: logger.exception(_("Error loading the SQLite module: the antivirus software may be blocking it.")) if 'posix' == os.name and bleachbit.expanduser('~') == '/root': self.append_text( _('You are running BleachBit with administrative privileges for cleaning shared parts of the system, and references to the user profile folder will clean only the root account.')) if 'nt' == os.name and options.get('shred'): from win32com.shell.shell import IsUserAnAdmin if not IsUserAnAdmin(): self.append_text( _('Run BleachBit with administrator privileges to improve the accuracy of overwriting the contents of files.')) self.append_text('\n') if exit: # This is used for automated testing of whether the GUI can start. print('Success') GObject.idle_add(lambda: self.quit(), priority=GObject.PRIORITY_LOW)
def _init_windows_misc(self, auto_exit, shred_paths, uac): application_id_suffix = '' if os.name == 'nt': if Windows.elevate_privileges(uac): # privileges escalated in other process sys.exit(0) if portable_mode: Windows.copy_fonts_in_portable_app(auto_exit) if auto_exit and shred_paths: # When we have a running application and executing the Windows # context menu command we start a new process with new application_id. # That is because the command line arguments of the context menu command # are not passed to the already running instance. application_id_suffix = 'ContextMenuShred' return application_id_suffix
def detect(self, section): """Check whether to show the section The logic: If the DetectOS does not match, the section is inactive. If any Detect or DetectFile matches, the section is active. If neither Detect or DetectFile was given, the section is active. Otherwise, the section is inactive. """ if self.parser.has_option(section, 'detectos'): required_ver = self.parser.get(section, 'detectos').decode(FSE) if not detectos(required_ver): return False any_detect_option = False if self.parser.has_option(section, 'specialdetect'): any_detect_option = True sd_code = self.parser.get(section, 'specialdetect') if special_detect(sd_code): return True for option in self.parser.options(section): if re.match(self.re_detect, option): # Detect= checks for a registry key any_detect_option = True key = self.parser.get(section, option).decode(FSE) if Windows.detect_registry_key(key): return True elif re.match(self.re_detectfile, option): # DetectFile= checks for a file any_detect_option = True key = self.parser.get(section, option).decode(FSE) if detect_file(key): return True return not any_detect_option
def __init__(self, uac=True, shred_paths=None, exit=False): if uac and 'nt' == os.name and Windows.elevate_privileges(): # privileges escalated in other process sys.exit(0) if not exit: from bleachbit import RecognizeCleanerML RecognizeCleanerML.RecognizeCleanerML() register_cleaners() self.create_window() gobject.threads_init() # Redirect logging to the GUI. bb_logger = logging.getLogger('bleachbit') gtklog = GtkLoggerHandler(self.append_text) bb_logger.addHandler(gtklog) if 'nt' == os.name and 'windows_exe' == getattr(sys, 'frozen', None): # On Microsoft Windows this avoids py2exe redirecting stderr to # bleachbit.exe.log. # sys.frozen = console_exe means the console is shown from bleachbit import logger_sh bb_logger.removeHandler(logger_sh) if shred_paths: self.shred_paths(shred_paths) return if options.get("first_start") and 'posix' == os.name: pref = PreferencesDialog(self.window, self.cb_refresh_operations) pref.run() options.set('first_start', False) if bleachbit.online_update_notification_enabled and options.get( "check_online_updates"): self.check_online_updates() if 'nt' == os.name: # BitDefender false positive. BitDefender didn't mark BleachBit as infected or show # anything in its log, but sqlite would fail to import unless BitDefender was in "game mode." # https://www.bleachbit.org/forum/074-fails-errors try: import sqlite3 except ImportError: logger.exception( _("Error loading the SQLite module: the antivirus software may be blocking it." )) if 'posix' == os.name and bleachbit.expanduser('~') == '/root': self.append_text( _('You are running BleachBit with administrative privileges for cleaning shared parts of the system, and references to the user profile folder will clean only the root account.' )) if 'nt' == os.name and options.get('shred'): from win32com.shell.shell import IsUserAnAdmin if not IsUserAnAdmin(): self.append_text( _('Run BleachBit with administrator privileges to improve the accuracy of overwriting the contents of files.' )) self.append_text('\n') if exit: # This is used for automated testing of whether the GUI can start. gobject.idle_add(lambda: gtk.main_quit(), priority=gobject.PRIORITY_LOW)
def detectos(required_ver, mock=False): """Returns boolean whether the detectos is compatible with the current operating system, or the mock version, if given.""" # Do not compare as string because Windows 10 (build 10.0) comes after # Windows 8.1 (build 6.3). assert (isinstance(required_ver, (str, unicode))) current_os = (mock if mock else Windows.parse_windows_build()) required_ver = required_ver.strip() if required_ver.startswith('|'): # This is the maximum version # For example, |5.1 means Windows XP (5.1) but not Vista (6.0) return current_os <= Windows.parse_windows_build(required_ver[1:]) elif required_ver.endswith('|'): # This is the minimum version # For example, 6.1| means Windows 7 or later return current_os >= Windows.parse_windows_build(required_ver[:-1]) else: # Exact version return Windows.parse_windows_build(required_ver) == current_os
def detectos(required_ver, mock=False): """Returns boolean whether the detectos is compatible with the current operating system, or the mock version, if given.""" # Do not compare as string because Windows 10 (build 10.0) comes after # Windows 8.1 (build 6.3). assert(isinstance(required_ver, (str, unicode))) current_os = (mock if mock else Windows.parse_windows_build()) required_ver = required_ver.strip() if required_ver.startswith('|'): # This is the maximum version # For example, |5.1 means Windows XP (5.1) but not Vista (6.0) return current_os <= Windows.parse_windows_build(required_ver[1:]) elif required_ver.endswith('|'): # This is the minimum version # For example, 6.1| means Windows 7 or later return current_os >= Windows.parse_windows_build(required_ver[:-1]) else: # Exact version return Windows.parse_windows_build(required_ver) == current_os
def detectos(required_ver, mock=False): """Returns boolean whether the detectos is compatible with the current operating system, or the mock version, if given.""" # Do not compare as string because Windows 10 (build 10.0) comes after # Windows 8.1 (build 6.3). assert isinstance(required_ver, str) current_os = mock or Windows.parse_windows_build() required_ver = required_ver.strip() if '|' not in required_ver: # Exact version return Windows.parse_windows_build(required_ver) == current_os # Format of min|max req_min = required_ver.split('|')[0] req_max = required_ver.split('|')[1] if req_min and current_os < Windows.parse_windows_build(req_min): return False if req_max and current_os > Windows.parse_windows_build(req_max): return False return True
def detectos(required_ver, mock=False): """Returns boolean whether the detectos is compatible with the current operating system, or the mock version, if given.""" # Do not compare as string because Windows 10 (build 10.0) comes after # Windows 8.1 (build 6.3). assert isinstance(required_ver, (str, unicode)) current_os = (mock if mock else Windows.parse_windows_build()) required_ver = required_ver.strip() if '|' in required_ver: # Format of min|max req_min = required_ver.split('|')[0] req_max = required_ver.split('|')[1] if req_min and current_os < Windows.parse_windows_build(req_min): return False if req_max and current_os > Windows.parse_windows_build(req_max): return False return True else: # Exact version return Windows.parse_windows_build(required_ver) == current_os
def __init__(self, uac=True, shred_paths=None, exit=False): if uac and 'nt' == os.name and Windows.elevate_privileges(): # privileges escalated in other process sys.exit(0) if not exit: from bleachbit import RecognizeCleanerML RecognizeCleanerML.RecognizeCleanerML() register_cleaners() self.create_window() gobject.threads_init() # Redirect logging to the GUI. bb_logger = logging.getLogger('bleachbit') gtklog = GtkLoggerHandler(self.append_text) bb_logger.addHandler(gtklog) if 'nt' == os.name and 'windows_exe' == getattr(sys, 'frozen', None): # On Microsoft Windows this avoids py2exe redirecting stderr to # bleachbit.exe.log. # sys.frozen = console_exe means the console is shown from bleachbit import logger_sh bb_logger.removeHandler(logger_sh) if shred_paths: self.shred_paths(shred_paths) return if options.get("first_start") and 'posix' == os.name: pref = PreferencesDialog(self.window, self.cb_refresh_operations) pref.run() options.set('first_start', False) if bleachbit.online_update_notification_enabled and options.get("check_online_updates"): self.check_online_updates() if 'nt' == os.name: # BitDefender false positive. BitDefender didn't mark BleachBit as infected or show # anything in its log, but sqlite would fail to import unless BitDefender was in "game mode." # https://www.bleachbit.org/forum/074-fails-errors try: import sqlite3 except ImportError: logger.exception(_("Error loading the SQLite module: the antivirus software may be blocking it.")) if 'posix' == os.name and bleachbit.expanduser('~') == '/root': self.append_text( _('You are running BleachBit with administrative privileges for cleaning shared parts of the system, and references to the user profile folder will clean only the root account.')) if 'nt' == os.name and options.get('shred'): from win32com.shell.shell import IsUserAnAdmin if not IsUserAnAdmin(): self.append_text( _('Run BleachBit with administrator privileges to improve the accuracy of overwriting the contents of files.')) self.append_text('\n') if exit: # This is used for automated testing of whether the GUI can start. gobject.idle_add( lambda: gtk.main_quit(), priority=gobject.PRIORITY_LOW)
def special_detect(code): """Check whether the SpecialDetect== software exists""" # The last two are used only for testing sd_keys = {'DET_CHROME': r'HKCU\Software\Google\Chrome', 'DET_MOZILLA': r'HKCU\Software\Mozilla\Firefox', 'DET_OPERA': r'HKCU\Software\Opera Software', 'DET_THUNDERBIRD': r'HKLM\SOFTWARE\Clients\Mail\Mozilla Thunderbird', 'DET_WINDOWS': r'HKCU\Software\Microsoft', 'DET_SPACE_QUEST': r'HKCU\Software\Sierra Games\Space Quest'} if code in sd_keys: return Windows.detect_registry_key(sd_keys[code]) else: logger.error('Unknown SpecialDetect=%s', code) return False
def special_detect(code): """Check whether the SpecialDetect== software exists""" # The last two are used only for testing sd_keys = {'DET_CHROME': r'HKCU\Software\Google\Chrome', 'DET_MOZILLA': r'HKCU\Software\Mozilla\Firefox', 'DET_OPERA': r'HKCU\Software\Opera Software', 'DET_THUNDERBIRD': r'HKLM\SOFTWARE\Clients\Mail\Mozilla Thunderbird', 'DET_WINDOWS': r'HKCU\Software\Microsoft', 'DET_SPACE_QUEST': r'HKCU\Software\Sierra Games\Space Quest'} if sd_keys.has_key(code): return Windows.detect_registry_key(sd_keys[code]) else: logger.error('Unknown SpecialDetect=%s', code) return False
def free_space(pathname): """Return free space in bytes""" if 'nt' == os.name: from bleachbit import Windows if Windows.parse_windows_build() >= 6: # This works better with UTF-8 paths. import psutil return psutil.disk_usage(pathname).free else: # This works better with Windows XP but not UTF-8. # Deprecated. _, _, free_bytes = win32file.GetDiskFreeSpaceEx(pathname) return free_bytes mystat = os.statvfs(pathname) return mystat.f_bfree * mystat.f_bsize
def free_space(pathname): """Return free space in bytes""" if 'nt' == os.name: from bleachbit import Windows if Windows.parse_windows_build() >= 6: # This works better with UTF-8 paths. import psutil return psutil.disk_usage(pathname).free else: # This works better with Windows XP but not UTF-8. # Deprecated. _fb, _tb, total_free_bytes = win32file.GetDiskFreeSpaceEx(pathname) return total_free_bytes mystat = os.statvfs(pathname) return mystat.f_bfree * mystat.f_bsize
def cb_clipboard_uri_received(self, clipboard, targets, data): """Callback for when URIs are received from clipboard""" shred_paths = None if 'text/uri-list' in targets: # Linux shred_uris = clipboard.wait_for_contents( 'text/uri-list').get_uris() shred_paths = FileUtilities.uris_to_paths(shred_uris) elif 'FileNameW' in targets: # Windows # Use non-GTK+ functions because because GTK+ 2 does not work. shred_paths = Windows.get_clipboard_paths() if shred_paths: self.shred_paths(shred_paths) else: logger.warning(_('No paths found in clipboard.'))
def cb_clipboard_uri_received(self, clipboard, targets, data): """Callback for when URIs are received from clipboard""" shred_paths = None if Gdk.atom_intern_static_string('text/uri-list') in targets: # Linux shred_uris = clipboard.wait_for_contents( Gdk.atom_intern_static_string('text/uri-list')).get_uris() shred_paths = FileUtilities.uris_to_paths(shred_uris) elif Gdk.atom_intern_static_string('FileNameW') in targets: # Windows # Use non-GTK+ functions because because GTK+ 2 does not work. shred_paths = Windows.get_clipboard_paths() if shred_paths: GUI.shred_paths(self._window, shred_paths) else: logger.warning(_('No paths found in clipboard.'))
def browse_file(parent, title): """Prompt user to select a single file""" if 'nt' == os.name and None == os.getenv('BB_NATIVE'): return Windows.browse_file(parent.window.handle, title) chooser = gtk.FileChooserDialog(title=title, parent=parent, action=gtk.FILE_CHOOSER_ACTION_OPEN, buttons=(gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL, gtk.STOCK_OPEN, gtk.RESPONSE_OK)) chooser.set_current_folder(expanduser('~')) resp = chooser.run() path = chooser.get_filename() chooser.destroy() if gtk.RESPONSE_OK != resp: # user cancelled return None return path
def browse_file(parent, title): """Prompt user to select a single file""" if 'nt' == os.name and None == os.getenv('BB_NATIVE'): return Windows.browse_file(parent.window.handle, title) chooser = Gtk.FileChooserDialog(title=title, transient_for=parent, action=Gtk.FileChooserAction.OPEN) chooser.add_buttons(_("_Cancel"), Gtk.ResponseType.CANCEL, _("_Open"), Gtk.ResponseType.OK) chooser.set_default_response(Gtk.ResponseType.OK) chooser.set_current_folder(expanduser('~')) resp = chooser.run() path = chooser.get_filename() chooser.destroy() if Gtk.ResponseType.OK != resp: # user cancelled return None return path
def browse_file(parent, title): """Prompt user to select a single file""" if os.name == 'nt' and not os.getenv('BB_NATIVE'): return Windows.browse_file(parent, title) chooser = Gtk.FileChooserDialog(title=title, transient_for=parent, action=Gtk.FileChooserAction.OPEN) chooser.add_buttons(_("_Cancel"), Gtk.ResponseType.CANCEL, _("_Open"), Gtk.ResponseType.OK) chooser.set_default_response(Gtk.ResponseType.OK) chooser.set_current_folder(expanduser('~')) resp = chooser.run() path = chooser.get_filename() chooser.destroy() if Gtk.ResponseType.OK != resp: # user cancelled return None return path
def browse_files(parent, title): """Prompt user to select multiple files to delete""" if 'nt' == os.name and None == os.getenv('BB_NATIVE'): return Windows.browse_files(parent.window.handle, title) chooser = Gtk.FileChooserDialog(title=title, transient_for=parent, action=Gtk.FileChooserAction.OPEN) chooser.add_buttons(_("_Cancel"), Gtk.ResponseType.CANCEL, _("_Delete"), Gtk.ResponseType.OK) chooser.set_default_response(Gtk.ResponseType.OK) chooser.set_select_multiple(True) chooser.set_current_folder(expanduser('~')) resp = chooser.run() paths = chooser.get_filenames() chooser.destroy() if Gtk.ResponseType.OK != resp: # user cancelled return None return paths
def handle_section(self, section): """Parse a section""" # if simple detection fails then discard the section if self.parser.has_option(section, 'detect'): key = self.parser.get(section, 'detect').decode(FSE) if not Windows.detect_registry_key(key): return if self.parser.has_option(section, 'detectfile'): if not detect_file(self.parser.get(section, 'detectfile').decode(FSE)): return if self.parser.has_option(section, 'detectos'): required_ver = self.parser.get(section, 'detectos').decode(FSE) if not detectos(required_ver): return # in case of multiple detection, discard if none match if self.parser.has_option(section, 'detectfile1'): matches = 0 for n in range(1, MAX_DETECT): option_id = 'detectfile%d' % n if self.parser.has_option(section, option_id): if detect_file(self.parser.get(section, option_id).decode(FSE)): matches += 1 if 0 == matches: return if self.parser.has_option(section, 'detect1'): matches = 0 for n in range(1, MAX_DETECT): option_id = 'detect%d' % n if self.parser.has_option(section, option_id): if Windows.detect_registry_key(self.parser.get(section, option_id).decode(FSE)): matches += 1 if 0 == matches: return # excludekeys ignores a file, path, or registry key excludekeys = [] if self.parser.has_option(section, 'excludekey1'): for n in range(1, MAX_DETECT): option_id = 'excludekey%d' % n if self.parser.has_option(section, option_id): excludekeys.append( self.excludekey_to_nwholeregex(self.parser.get(section, option_id).decode(FSE))) # there are two ways to specify sections: langsecref= and section= if self.parser.has_option(section, 'langsecref'): # verify the langsecref number is known # langsecref_num is 3021, games, etc. langsecref_num = self.parser.get(section, 'langsecref').decode(FSE) elif self.parser.has_option(section, 'section'): langsecref_num = self.parser.get(section, 'section').decode(FSE) else: logger.error('neither option LangSecRef nor Section found in section %s', section) return # find the BleachBit internal cleaner ID lid = self.section_to_cleanerid(langsecref_num) self.cleaners[lid].add_option( section2option(section), section.replace('*', ''), '') for option in self.parser.options(section): if option.startswith('filekey'): self.handle_filekey(lid, section, option, excludekeys) elif option.startswith('regkey'): self.handle_regkey(lid, section, option) elif option == 'warning': self.cleaners[lid].set_warning( section2option(section), self.parser.get(section, 'warning').decode(FSE)) elif option in ('default', 'detectfile', 'detect', 'langsecref', 'section') \ or ['detect%d' % x for x in range(1, MAX_DETECT)] \ or ['detectfile%d' % x for x in range(1, MAX_DETECT)]: pass else: logger.warning('unknown option %s in section %s', option, section) return
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
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
def handle_section(self, section): """Parse a section""" # if simple detection fails then discard the section if self.parser.has_option(section, 'detect'): key = self.parser.get(section, 'detect').decode(FSE) if not Windows.detect_registry_key(key): return if self.parser.has_option(section, 'detectfile'): if not detect_file( self.parser.get(section, 'detectfile').decode(FSE)): return if self.parser.has_option(section, 'detectos'): required_ver = self.parser.get(section, 'detectos').decode(FSE) if not detectos(required_ver): return # in case of multiple detection, discard if none match if self.parser.has_option(section, 'detectfile1'): matches = 0 for n in range(1, MAX_DETECT): option_id = 'detectfile%d' % n if self.parser.has_option(section, option_id): if detect_file( self.parser.get(section, option_id).decode(FSE)): matches += 1 if 0 == matches: return if self.parser.has_option(section, 'detect1'): matches = 0 for n in range(1, MAX_DETECT): option_id = 'detect%d' % n if self.parser.has_option(section, option_id): if Windows.detect_registry_key( self.parser.get(section, option_id).decode(FSE)): matches += 1 if 0 == matches: return # excludekeys ignores a file, path, or registry key excludekeys = [] if self.parser.has_option(section, 'excludekey1'): for n in range(1, MAX_DETECT): option_id = 'excludekey%d' % n if self.parser.has_option(section, option_id): excludekeys.append( self.excludekey_to_nwholeregex( self.parser.get(section, option_id).decode(FSE))) # there are two ways to specify sections: langsecref= and section= if self.parser.has_option(section, 'langsecref'): # verify the langsecref number is known # langsecref_num is 3021, games, etc. langsecref_num = self.parser.get(section, 'langsecref').decode(FSE) elif self.parser.has_option(section, 'section'): langsecref_num = self.parser.get(section, 'section').decode(FSE) else: logger.error( 'neither option LangSecRef nor Section found in section %s', section) return # find the BleachBit internal cleaner ID lid = self.section_to_cleanerid(langsecref_num) self.cleaners[lid].add_option(section2option(section), section.replace('*', ''), '') for option in self.parser.options(section): if option.startswith('filekey'): self.handle_filekey(lid, section, option, excludekeys) elif option.startswith('regkey'): self.handle_regkey(lid, section, option) elif option == 'warning': self.cleaners[lid].set_warning( section2option(section), self.parser.get(section, 'warning').decode(FSE)) elif option in ('default', 'detectfile', 'detect', 'langsecref', 'section') \ or ['detect%d' % x for x in range(1, MAX_DETECT)] \ or ['detectfile%d' % x for x in range(1, MAX_DETECT)]: pass else: logger.warning('unknown option %s in section %s', option, section) return
# Map our pgettext() custom function to _p() _p = pgettext # # URLs # base_url = "https://update.bleachbit.org" help_contents_url = "%s/help/%s" \ % (base_url, APP_VERSION) release_notes_url = "%s/release-notes/%s" \ % (base_url, APP_VERSION) update_check_url = "%s/update/%s" % (base_url, APP_VERSION) # set up environment variables if 'nt' == os.name: from bleachbit import Windows Windows.setup_environment() if 'posix' == os.name: # XDG base directory specification envs = { 'XDG_DATA_HOME': os.path.expanduser('~/.local/share'), 'XDG_CONFIG_HOME': os.path.expanduser('~/.config'), 'XDG_CACHE_HOME': os.path.expanduser('~/.cache') } for varname, value in envs.iteritems(): if not os.getenv(varname): os.environ[varname] = value
# # URLs # base_url = "https://update.bleachbit.org" help_contents_url = "%s/help/%s" \ % (base_url, APP_VERSION) release_notes_url = "%s/release-notes/%s" \ % (base_url, APP_VERSION) update_check_url = "%s/update/%s" % (base_url, APP_VERSION) # set up environment variables if 'nt' == os.name: from bleachbit import Windows Windows.setup_environment() if 'posix' == os.name: # XDG base directory specification envs = { 'XDG_DATA_HOME': os.path.expanduser('~/.local/share'), 'XDG_CONFIG_HOME': os.path.expanduser('~/.config'), 'XDG_CACHE_HOME': os.path.expanduser('~/.cache') } for varname, value in envs.items(): if not os.getenv(varname): os.environ[varname] = value if 'posix' == os.name: fs_scan_re_flags = 0 # should be re.IGNORECASE on macOS else:
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