面向Linux普通用户,解决不用命令调整文件或文件夹权限的问题。让AI顺手写的,界面未优化,反正可以用。
两个功能:
一是修改指定的文件夹(或文件)的所有者为特定用户。解决文件带锁标志的问题。当修改为当前用户时,就没锁了。修改所有者为root时,普通用户看起来就是有锁的。
二是授予特定文件可执行权限,就是运行某个文件能当成程序运行。
因为部分操作需要使用sudo命令提权才能执行,当遇到此类情况时,会弹出对话框提示输出当前用户的登录密码。软件单次运行期间,正确输入密码后,后续操作不需要重复输入密码。软件退出时自动销毁密码等信息,不保持数据。
python源码如下(缺少TK库的,自己去百度安装方法):
#!/usr/bin/env python3
import os
import stat
import tkinter as tk
from tkinter import filedialog, scrolledtext, messagebox, simpledialog
import platform
import subprocess
import logging
from shlex import quote
# 配置日志
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')
class FilePermissionManager:
def __init__(self, root):
self.root = root
self.root.title("文件/文件夹权限管理")
if platform.system() == "Linux":
self.root.geometry("510x470")
else:
self.root.geometry("500x400")
try:
self.current_user = os.getlogin()
except OSError:
self.current_user = os.environ.get('USER', 'unknown')
logging.warning("无法获取登录用户,使用环境变量 USER")
# 缓存密码
self.sudo_password = None
self.main_frame = tk.Frame(root)
self.main_frame.pack(fill="both", expand=True, padx=10, pady=10)
self.left_frame = tk.Frame(self.main_frame)
self.left_frame.pack(side="left", fill="y")
self.result_frame = tk.Frame(self.main_frame)
self.result_frame.pack(side="right", fill="both", expand=True)
tk.Label(self.left_frame, text=f"当前用户: {self.current_user}").pack(pady=5)
tk.Label(self.left_frame, text="修改所有者权限").pack(pady=(0, 5))
self.owner_path_entry = tk.Entry(self.left_frame, width=30)
self.owner_path_entry.pack(pady=5)
self.button_frame = tk.Frame(self.left_frame)
self.button_frame.pack(pady=5)
tk.Button(self.button_frame, text="选择文件夹", command=self.select_owner_path).pack(side="left", padx=5)
tk.Button(self.button_frame, text="选择文件", command=self.select_owner_files).pack(side="left", padx=5)
tk.Button(self.left_frame, text="改为 root", command=self.change_owner_to_root).pack(pady=5)
tk.Button(self.left_frame, text="改为当前用户", command=self.change_owner_to_current).pack(pady=5)
tk.Label(self.left_frame, text="文件执行权限").pack(pady=(20, 5))
self.exec_path_entry = tk.Entry(self.left_frame, width=30)
self.exec_path_entry.pack(pady=5)
tk.Button(self.left_frame, text="选择文件", command=self.select_exec_file).pack(pady=5)
tk.Button(self.left_frame, text="授予权限", command=self.make_executable).pack(pady=5)
tk.Button(self.left_frame, text="撤销权限", command=self.revoke_executable).pack(pady=5)
tk.Label(self.result_frame, text="操作结果").pack()
self.result_text = scrolledtext.ScrolledText(self.result_frame, width=40, height=20)
self.result_text.pack(fill="both", expand=True)
def select_owner_path(self):
path = filedialog.askdirectory()
if path:
self.owner_path_entry.delete(0, tk.END)
self.owner_path_entry.insert(0, path)
def select_owner_files(self):
files = filedialog.askopenfilenames()
if files:
self.owner_path_entry.delete(0, tk.END)
self.owner_path_entry.insert(0, ", ".join(files))
def select_exec_file(self):
file = filedialog.askopenfilename()
if file:
self.exec_path_entry.delete(0, tk.END)
self.exec_path_entry.insert(0, file)
def ask_password(self):
if self.sudo_password is not None:
return self.sudo_password
password = simpledialog.askstring("需要权限", "请输入当前用户密码以使用 sudo:", show='*')
return password
def run_sudo_command(self, command, path, password):
try:
full_command = f"echo {quote(password)} | sudo -S {command} {quote(path)}"
result = subprocess.run(full_command, shell=True, capture_output=True, text=True)
if result.returncode == 0:
# 如果密码正确且操作成功,缓存密码
if self.sudo_password is None:
self.sudo_password = password
return True, result.stdout
else:
# 如果密码错误,清空缓存并提示
if self.sudo_password == password:
self.sudo_password = None
return False, result.stderr
except subprocess.SubprocessError as e:
logging.error(f"sudo 命令执行失败: {str(e)}")
return False, str(e)
except Exception as e:
logging.error(f"未知错误执行 sudo 命令: {str(e)}")
return False, str(e)
def change_owner(self, path_input, uid, target_user):
if not path_input:
messagebox.showerror("错误", "请指定路径或文件")
return
paths = [p.strip() for p in path_input.split(",")]
invalid_paths = [p for p in paths if not os.path.exists(p)]
if invalid_paths:
messagebox.showerror("错误", f"以下路径不存在: {', '.join(invalid_paths)}")
return
try:
for path in paths:
if os.path.isdir(path):
for root_dir, dirs, files in os.walk(path):
os.chown(root_dir, uid, -1)
for file in files:
os.chown(os.path.join(root_dir, file), uid, -1)
else:
os.chown(path, uid, -1)
self.result_text.insert(tk.END, f"已将 {path_input} 及其子内容的所有者改为 {target_user}\n")
except PermissionError:
password = self.ask_password()
if password:
target_user_name = "root" if uid == 0 else self.current_user
all_success = True
for path in paths:
success, output = self.run_sudo_command(f"chown -R {target_user_name}", path, password)
if success:
self.result_text.insert(tk.END, f"使用 sudo 已将 {path} 及其子内容的所有者改为 {target_user}\n")
else:
all_success = False
messagebox.showerror("错误", f"sudo 操作失败: {output}")
self.result_text.insert(tk.END, f"修改 {path} 失败:{output}\n")
if not all_success and self.sudo_password == password:
self.sudo_password = None # 如果密码失效,清空缓存
else:
self.result_text.insert(tk.END, f"修改 {path_input} 失败:未提供密码\n")
except OSError as e:
messagebox.showerror("错误", f"系统错误: {str(e)}")
self.result_text.insert(tk.END, f"修改 {path_input} 失败:{str(e)}\n")
logging.error(f"OSError: {str(e)}")
def change_owner_to_root(self):
self.change_owner(self.owner_path_entry.get(), 0, "root")
def change_owner_to_current(self):
try:
uid = os.getuid()
self.change_owner(self.owner_path_entry.get(), uid, self.current_user)
except OSError as e:
messagebox.showerror("错误", f"无法获取当前用户 UID: {str(e)}")
self.result_text.insert(tk.END, f"获取 UID 失败:{str(e)}\n")
logging.error(f"获取 UID 失败: {str(e)}")
def modify_executable(self, file, grant=True):
if not file:
messagebox.showerror("错误", "请指定文件")
return
if not os.path.exists(file):
messagebox.showerror("错误", "文件不存在")
return
if not os.path.isfile(file):
messagebox.showerror("错误", "请选择一个文件")
return
try:
current_perms = os.stat(file).st_mode
if grant:
new_perms = current_perms | stat.S_IXUSR | stat.S_IXGRP | stat.S_IXOTH
action = "授予"
else:
new_perms = current_perms & ~(stat.S_IXUSR | stat.S_IXGRP | stat.S_IXOTH)
action = "撤销"
os.chmod(file, new_perms)
self.result_text.insert(tk.END, f"已{action} {file} 的可执行权限\n")
except PermissionError:
password = self.ask_password()
if password:
chmod_val = "+x" if grant else "-x"
success, output = self.run_sudo_command(f"chmod {chmod_val}", file, password)
if success:
self.result_text.insert(tk.END, f"使用 sudo 已{action} {file} 的可执行权限\n")
else:
messagebox.showerror("错误", f"sudo 操作失败: {output}")
self.result_text.insert(tk.END, f"{action} {file} 失败:{output}\n")
if self.sudo_password == password:
self.sudo_password = None # 如果密码失效,清空缓存
else:
self.result_text.insert(tk.END, f"{action} {file} 失败:未提供密码\n")
except OSError as e:
messagebox.showerror("错误", f"系统错误: {str(e)}")
self.result_text.insert(tk.END, f"{action} {file} 失败:{str(e)}\n")
logging.error(f"OSError: {str(e)}")
def make_executable(self):
self.modify_executable(self.exec_path_entry.get(), grant=True)
def revoke_executable(self):
self.modify_executable(self.exec_path_entry.get(), grant=False)
if __name__ == "__main__":
try:
root = tk.Tk()
app = FilePermissionManager(root)
root.mainloop()
except Exception as e:
logging.critical(f"程序启动失败: {str(e)}")
messagebox.showerror("致命错误", f"程序启动失败: {str(e)}")