mirror of
https://github.com/aaPanel/aaPanel.git
synced 2026-08-17 21:25:47 +02:00
287 lines
11 KiB
Python
287 lines
11 KiB
Python
#coding: utf-8
|
||
#-------------------------------------------------------------------
|
||
# 宝塔Linux面板
|
||
#-------------------------------------------------------------------
|
||
# Copyright (c) 2015-2099 宝塔软件(http://bt.cn) All rights reserved.
|
||
#-------------------------------------------------------------------
|
||
# Author: cjxin <cjxin@bt.cn>
|
||
#-------------------------------------------------------------------
|
||
import copy
|
||
import random
|
||
# 获取目录大小
|
||
#------------------------------
|
||
import sys, os
|
||
import json, os, time, re
|
||
|
||
import public
|
||
from filesModel.base import filesBase
|
||
|
||
panelPath = '/www/server/panel'
|
||
os.chdir(panelPath)
|
||
|
||
|
||
class main(filesBase):
|
||
_exe_cmd = 'ncdu'
|
||
# 扫描历史
|
||
log_path = '{}/data/scan/'.format(public.get_panel_path())
|
||
# 缓存
|
||
cache_file = '{}/config/scan_disk_cache.json'.format(public.get_panel_path())
|
||
|
||
def __init__(self):
|
||
self.is_use = False
|
||
if os.path.isdir("{}/plugin/disk_analysis".format(public.get_panel_path())):
|
||
self.is_use = True
|
||
if not os.path.exists(self.log_path):
|
||
os.makedirs(self.log_path)
|
||
if not os.path.exists(self.cache_file):
|
||
public.writeFile(self.cache_file,"{}")
|
||
if os.getenv('BT_PANEL'):
|
||
self._exe_cmd = '{}/plugin/disk_analysis/ncdu'.format(panelPath)
|
||
|
||
def get_path_size(self, get):
|
||
"""
|
||
@name 根据排除目录获取路径的总大小
|
||
@param path 目标路径
|
||
"""
|
||
if self.is_use is False:
|
||
return {"code": 404, "status": False, "msg": 'Please install [Disk analysis] first !'}
|
||
path = get.path
|
||
is_refresh = get.is_refresh == "true"
|
||
|
||
real_path_dict = {} # 软连接处理
|
||
temp_path_list = []
|
||
for path in str(path).split(","):
|
||
r_path = os.path.realpath(path)
|
||
if r_path != path:
|
||
real_path_dict[r_path] = path
|
||
path = r_path
|
||
if path != "/": path = str(path).rstrip("/")
|
||
temp_path_list.append(path)
|
||
|
||
try:
|
||
cache_data = json.loads(public.readFile(self.cache_file))
|
||
except:
|
||
cache_data = {}
|
||
|
||
result = {}
|
||
|
||
path_list = []
|
||
if is_refresh is True:
|
||
path_list = temp_path_list
|
||
else:
|
||
for path in temp_path_list:
|
||
if cache_data.get(path) is not None:
|
||
result[path] = cache_data.get(path)
|
||
else:
|
||
path_list.append(path)
|
||
|
||
if path_list:
|
||
scan_path = path_list[0]
|
||
if os.path.isfile(scan_path):
|
||
scan_path = os.path.split(scan_path)[0]
|
||
for path in path_list[1:]:
|
||
while True:
|
||
if path.startswith(scan_path):
|
||
break
|
||
scan_path = os.path.split(scan_path)[0]
|
||
import string
|
||
code = "".join(random.sample(string.ascii_letters + string.digits, 8))
|
||
result_file = '{}{}'.format(self.log_path, f"temp_scan_size_{code}")
|
||
scan_time = int(time.time())
|
||
exec_shell = "{} '{}' -o '{}' ".format(self._exe_cmd, scan_path, result_file).replace('\\', '/').replace('//','/')
|
||
public.ExecShell(exec_shell)
|
||
scan_result = self.__get_log_size(result_file, path_list, scan_time, cache_data)
|
||
os.remove(result_file)
|
||
result.update(scan_result)
|
||
public.writeFile(self.cache_file, json.dumps(cache_data))
|
||
for r_path, path in real_path_dict.items():
|
||
result[path] = result[r_path]
|
||
del result[r_path]
|
||
return result
|
||
|
||
@classmethod
|
||
def __get_log_size(cls, log_file, path_list, scan_time, cache_data):
|
||
"""
|
||
@name 获取文件或目录大小
|
||
@param log_file 日志文件
|
||
"""
|
||
result = {}
|
||
for path in path_list:
|
||
result[path] = None
|
||
data = public.readFile(log_file)
|
||
data = json.loads(data)
|
||
data = data[-1]
|
||
root_path = data[0]["name"]
|
||
if root_path in path_list:
|
||
result[root_path] = data
|
||
else:
|
||
cls.__get_sub_size(data[1:], root_path, path_list, result)
|
||
for path,info in result.items():
|
||
if info is None:
|
||
continue
|
||
if isinstance(info, dict):
|
||
info["type"] = 0
|
||
info["asize"] = info.get("asize", 0)
|
||
info["dsize"] = info.get("dsize", 0)
|
||
info["dir_num"] = 0
|
||
info["file_num"] = 0
|
||
info["total_asize"] = info.get("asize", 0)
|
||
info["total_dsize"] = info.get("dsize", 0)
|
||
info["stime"] = scan_time
|
||
cls.__get_stat(path, info)
|
||
cache_data[path] = info
|
||
else:
|
||
cls.__get_dirs_size(info)
|
||
cls.__get_stat(path, info[0])
|
||
result[path] = info[0]
|
||
result[path]["stime"] = scan_time
|
||
cache_data[path] = result[path]
|
||
return result
|
||
|
||
@classmethod
|
||
def __get_sub_size(cls, data, root_path, path_list, result):
|
||
"""
|
||
@name 获取子目录数据
|
||
@param id int 记录id
|
||
@param path string 目录
|
||
"""
|
||
if len(path_list) == 0: return
|
||
for val in data:
|
||
if isinstance(val, list):
|
||
sfile = f"{root_path}/{val[0]['name']}".replace('\\', '/').replace('//', '/')
|
||
if sfile in path_list:
|
||
result[sfile] = val
|
||
path_list.remove(sfile)
|
||
if len(val) > 1:
|
||
cls.__get_sub_size(val[1:], sfile, path_list, result)
|
||
elif isinstance(val, dict):
|
||
sfile = f"{root_path}/{val['name']}".replace('\\', '/').replace('//', '/')
|
||
if sfile in path_list:
|
||
result[sfile] = val
|
||
path_list.remove(sfile)
|
||
|
||
@classmethod
|
||
def __get_dirs_size(cls, dirs_list):
|
||
"""
|
||
@param info 目录信息
|
||
@param result 结果
|
||
"""
|
||
dir_info = dirs_list[0]
|
||
dir_info["type"] = 1
|
||
dir_info["asize"] = dir_info.get("asize", 0)
|
||
dir_info["dsize"] = dir_info.get("dsize", 0)
|
||
dir_info["dirs"] = 0
|
||
dir_info["files"] = 0
|
||
dir_info["dir_num"] = 0
|
||
dir_info["file_num"] = 0
|
||
dir_info["total_asize"] = dir_info.get("asize", 0)
|
||
dir_info["total_dsize"] = dir_info.get("dsize", 0)
|
||
for info in dirs_list[1:]:
|
||
if isinstance(info, list): # 目录
|
||
dir_info["dirs"] += 1
|
||
dir_info["dir_num"] += 1
|
||
cls.__get_dirs_size(info)
|
||
temp_info = info[0]
|
||
dir_info["dir_num"] += temp_info["dir_num"]
|
||
dir_info["file_num"] += temp_info["file_num"]
|
||
dir_info["total_asize"] += temp_info["total_asize"]
|
||
dir_info["total_dsize"] += temp_info["total_dsize"]
|
||
else:
|
||
if info.get("excluded") == "pattern":
|
||
continue
|
||
dir_info["files"] += 1
|
||
dir_info["file_num"] += 1
|
||
if info.get("asize") is None: info["asize"] = 0
|
||
if info.get("dsize") is None: info["dsize"] = 0
|
||
info["type"] = 0
|
||
dir_info["total_asize"] += info["asize"]
|
||
dir_info["total_dsize"] += info["dsize"]
|
||
|
||
@classmethod
|
||
def __get_stat(cls, path, info):
|
||
if not os.path.exists(path):
|
||
info["accept"] = None
|
||
info["user"] = None
|
||
info["mtime"] = "--"
|
||
info["ps"] = None
|
||
return
|
||
stat_file = os.stat(path)
|
||
|
||
info["accept"] = oct(stat_file.st_mode)[-3:]
|
||
import pwd
|
||
try:
|
||
info["user"] = pwd.getpwuid(stat_file.st_uid).pw_name
|
||
except:
|
||
info["user"] = str(stat_file.st_uid)
|
||
info["atime"] = int(stat_file.st_atime)
|
||
info["ctime"] = int(stat_file.st_ctime)
|
||
info["mtime"] = int(stat_file.st_mtime)
|
||
info["ps"] = cls.get_file_ps(path)
|
||
|
||
@classmethod
|
||
def get_file_ps(cls,filename):
|
||
'''
|
||
@name 获取文件或目录备注
|
||
@author hwliang<2020-10-22>
|
||
@param filename<string> 文件或目录全路径
|
||
@return string
|
||
'''
|
||
|
||
ps_path = public.get_panel_path() + '/data/files_ps'
|
||
f_key1 = '/'.join((ps_path,public.md5(filename)))
|
||
if os.path.exists(f_key1):
|
||
return public.readFile(f_key1)
|
||
|
||
f_key2 = '/'.join((ps_path,public.md5(os.path.basename(filename))))
|
||
if os.path.exists(f_key2):
|
||
return public.readFile(f_key2)
|
||
|
||
pss = {
|
||
'/www/server/data': 'This is the default data directory of the MySQL database, please do not delete it!',
|
||
'/www/server/mysql': 'MySQL program directory',
|
||
'/www/server/redis': 'Redis program directory',
|
||
'/www/server/mongodb': 'MongoDB program directory',
|
||
'/www/server/nvm': 'PM2/NVM/NPM program directory',
|
||
'/www/server/pass': 'Website BasicAuth authentication password storage directory',
|
||
'/www/server/speed': 'Website acceleration data directory',
|
||
'/www/server/docker': 'Docker plugin and data directory',
|
||
'/www/server/total': 'Website monitoring report data directory',
|
||
'/www/server/btwaf': 'WAF firewall data directory',
|
||
'/www/server/pure-ftpd': 'ftp program directory',
|
||
'/www/server/phpmyadmin': 'phpMyAdmin program directory',
|
||
'/www/server/rar': 'rar expansion library directory, will lose support for RAR compressed files after deletion',
|
||
'/www/server/stop': 'The website deactivates the page directory, please do not delete it!',
|
||
'/www/server/nginx': 'Nginx program directory',
|
||
'/www/server/apache': 'Apache program directory',
|
||
'/www/server/cron': 'Scheduled task script and log directory',
|
||
'/www/server/php': 'PHP directory, all PHP version interpreters are in this directory',
|
||
'/www/server/tomcat': 'Tomcat program directory',
|
||
'/www/php_session': 'PHP-SESSION isolation directory',
|
||
'/www/server/panel': 'aaPanel program directory',
|
||
'/proc': 'system process directory',
|
||
'/dev': 'system device directory',
|
||
'/sys': 'system call directory',
|
||
'/tmp': 'system temporary file directory',
|
||
'/var/log': 'System log directory',
|
||
'/var/run': 'System running log directory',
|
||
'/var/spool': 'system queue directory',
|
||
'/var/lock': 'system lock directory',
|
||
'/var/mail': 'system mail directory',
|
||
'/mnt': 'System mount directory',
|
||
'/media': 'System multimedia directory',
|
||
'/dev/shm': 'system shared memory directory',
|
||
'/lib': 'system dynamic library directory',
|
||
'/lib64': 'system dynamic library directory',
|
||
'/lib32': 'system dynamic library directory',
|
||
'/usr/lib': 'system dynamic library directory',
|
||
'/usr/lib64': 'system dynamic library directory',
|
||
'/usr/local/lib': 'system dynamic library directory',
|
||
'/usr/local/lib64': 'system dynamic library directory',
|
||
'/usr/local/libexec': 'system dynamic library directory',
|
||
'/usr/local/sbin': 'System script directory',
|
||
'/usr/local/bin': 'System script directory'
|
||
|
||
|
||
}
|
||
if filename in pss: return "PS:" + pss[filename]
|
||
return None |