mirror of
https://github.com/aaPanel/aaPanel.git
synced 2026-09-24 02:14:53 +02:00
update to 6.8.37
This commit is contained in:
@@ -0,0 +1,104 @@
|
||||
#coding: utf-8
|
||||
import public,os
|
||||
|
||||
|
||||
class filesBase:
|
||||
|
||||
|
||||
__upload_objs = ['bos','alioss','obs','upyun','txcos'] #支持下载的云存储
|
||||
__down_objs = ['bos','alioss','txcos','obs'] #支持上传的云存储
|
||||
|
||||
def __init__(self):
|
||||
pass
|
||||
|
||||
|
||||
#************************ start 对象存储 ************************
|
||||
def get_base_objects(self,objs):
|
||||
"""
|
||||
@name 获取可上传的对象存储
|
||||
"""
|
||||
import panelPlugin
|
||||
plu_obj = panelPlugin.panelPlugin()
|
||||
res = []
|
||||
for name in objs:
|
||||
is_conf = 0
|
||||
info = plu_obj.get_soft_find(name)
|
||||
if not info: continue
|
||||
if info['setup']:
|
||||
is_conf = self._check_objects_conf(info['name'])
|
||||
res.append({'name':info['name'],'title':info['title'],'setup':info['setup'],'is_conf':is_conf})
|
||||
return res
|
||||
|
||||
def get_all_objects(self,get):
|
||||
"""
|
||||
@name 获取可上传的对象存储
|
||||
"""
|
||||
result = {}
|
||||
result['upload'] = []
|
||||
result['down'] = self.get_base_objects(self.__down_objs)
|
||||
for info in result['down']:
|
||||
if info['name'] in self.__upload_objs:
|
||||
result['upload'].append(info)
|
||||
return result
|
||||
|
||||
|
||||
|
||||
def get_upload_objects(self,get):
|
||||
|
||||
"""
|
||||
@name 获取可上传的对象存储
|
||||
"""
|
||||
return self.get_base_objects(self.__upload_objs)
|
||||
|
||||
def get_down_objects(self,get):
|
||||
"""
|
||||
@name 获取可下载的对象存储
|
||||
"""
|
||||
return self.get_base_objects(self.__down_objs)
|
||||
|
||||
|
||||
def _check_objects_conf(self,plu_name):
|
||||
"""
|
||||
@name 获取插件是否配置
|
||||
"""
|
||||
plugin_obj = self.get_plugin_main_object(plu_name)
|
||||
|
||||
args = public.dict_obj()
|
||||
args.path = '/bt_upload/'
|
||||
|
||||
res = plugin_obj.get_config(args)
|
||||
if 'status' in res and not res['status']:
|
||||
return 0
|
||||
for key in res:
|
||||
if not res[key].strip(): return 0
|
||||
return 1
|
||||
|
||||
|
||||
def get_plugin_main_object(self,plugin_name):
|
||||
"""
|
||||
@name 获取插件主对象
|
||||
@param plugin_name 插件名称
|
||||
"""
|
||||
sys_path = '{}/plugin/{}'.format(public.get_panel_path(),plugin_name)
|
||||
if not os.path.exists(sys_path): return False
|
||||
public.sys_path_append(sys_path)
|
||||
|
||||
os_file = '{}/{}_main.py'.format(sys_path,plugin_name)
|
||||
|
||||
plugin_obj = __import__(plugin_name + '_main')
|
||||
plugin_obj = getattr(plugin_obj, plugin_name + '_main')()
|
||||
|
||||
return plugin_obj
|
||||
|
||||
|
||||
def get_soft_find(self,name):
|
||||
"""
|
||||
@获取插件详细
|
||||
"""
|
||||
import panelPlugin
|
||||
plu_obj = panelPlugin.panelPlugin()
|
||||
|
||||
return plu_obj.get_soft_find(name)
|
||||
|
||||
|
||||
#************************ end 对象存储 ************************
|
||||
@@ -0,0 +1,46 @@
|
||||
#coding: utf-8
|
||||
#-------------------------------------------------------------------
|
||||
# 宝塔Linux面板
|
||||
#-------------------------------------------------------------------
|
||||
# Copyright (c) 2015-2099 宝塔软件(http://bt.cn) All rights reserved.
|
||||
#-------------------------------------------------------------------
|
||||
# Author: cjxin <cjxin@bt.cn>
|
||||
#-------------------------------------------------------------------
|
||||
|
||||
# 上传文件至oss
|
||||
#------------------------------
|
||||
from filesModel.base import filesBase
|
||||
import public
|
||||
|
||||
class main(filesBase):
|
||||
|
||||
|
||||
def __init__(self):
|
||||
pass
|
||||
|
||||
|
||||
def get_oss_objects(self,get):
|
||||
"""
|
||||
@name 获取可上传的对象存储
|
||||
"""
|
||||
return self.get_all_objects(get)
|
||||
|
||||
|
||||
def download_file(self,get):
|
||||
"""
|
||||
@name 下载文件
|
||||
@param get
|
||||
file:文件路径
|
||||
"""
|
||||
|
||||
info = self.get_soft_find(get.name)
|
||||
if not info['setup']:
|
||||
return public.returnMsg(False,'未安装[{}]插件'.format(info['title']))
|
||||
|
||||
import panelTask
|
||||
task_obj = panelTask.bt_task()
|
||||
task_obj.create_task('下载文件', 1, get.url, get.path + '/' + get.filename)
|
||||
public.set_module_logs('files_down_to_file', 'download_file', 1)
|
||||
public.WriteLog('TYPE_FILE', '从 [{}] 下载文件 [{}] 到 {}'.format(info['title'],get.filename,get.path))
|
||||
return public.returnMsg(True, 'FILE_DOANLOAD')
|
||||
|
||||
@@ -0,0 +1,342 @@
|
||||
#coding: utf-8
|
||||
#-------------------------------------------------------------------
|
||||
# 宝塔Linux面板
|
||||
#-------------------------------------------------------------------
|
||||
# Copyright (c) 2015-2099 宝塔软件(http://bt.cn) All rights reserved.
|
||||
#-------------------------------------------------------------------
|
||||
# Author: cjxin <cjxin@bt.cn>
|
||||
#-------------------------------------------------------------------
|
||||
|
||||
#
|
||||
#------------------------------
|
||||
|
||||
import os,sys,re
|
||||
from filesModel.base import filesBase
|
||||
import public,json
|
||||
import tarfile,shutil,gzip
|
||||
|
||||
class main(filesBase):
|
||||
|
||||
def __init__(self):
|
||||
pass
|
||||
|
||||
|
||||
def __check_zipfile(self,sfile,is_close = False):
|
||||
'''
|
||||
@name 检查文件是否为zip文件
|
||||
@param sfile 文件路径
|
||||
@return bool
|
||||
'''
|
||||
|
||||
pass
|
||||
|
||||
def get_zip_files(self,args):
|
||||
'''
|
||||
@name 获取压缩包内文件列表
|
||||
@param args['path'] 压缩包路径
|
||||
@return list
|
||||
'''
|
||||
sfile = args.sfile
|
||||
if not os.path.exists(sfile):
|
||||
return public.returnMsg(False,'FILE_NOT_EXISTS')
|
||||
|
||||
if not tarfile.is_tarfile(sfile):
|
||||
return public.returnMsg(False,'Not a valid tar.gz archive file')
|
||||
|
||||
zip_file = tarfile.open(sfile)
|
||||
data = {}
|
||||
for item in zip_file.getmembers():
|
||||
|
||||
sub_data = data
|
||||
f_name = self.__get_zip_filename(item)
|
||||
|
||||
f_dirs = f_name.split('/')
|
||||
for d in f_dirs:
|
||||
if not d: continue
|
||||
if not d in sub_data:
|
||||
if d == f_name[-len(d):]:
|
||||
|
||||
sub_data[d] = {
|
||||
'file_size': item.size,
|
||||
'filename':d,
|
||||
'fullpath':f_name,
|
||||
'date_time': public.format_date(times=item.mtime),
|
||||
'is_dir': 0
|
||||
}
|
||||
if item.isdir():
|
||||
sub_data[d]['is_dir'] = 1
|
||||
else:
|
||||
sub_data[d] = {}
|
||||
sub_data = sub_data[d]
|
||||
|
||||
return data
|
||||
|
||||
|
||||
def get_fileinfo_by(self,args):
|
||||
'''
|
||||
@name 获取压缩包内文件信息
|
||||
@param args['path'] 压缩包路径
|
||||
@param args['filename'] 文件名
|
||||
@return dict
|
||||
'''
|
||||
|
||||
sfile = args.sfile
|
||||
filename = args.filename
|
||||
if not os.path.exists(sfile):
|
||||
return public.returnMsg(False,'FILE_NOT_EXISTS')
|
||||
|
||||
tmp_path = '{}/tmp/{}'.format(public.get_panel_path(),public.md5(sfile + filename))
|
||||
result = {}
|
||||
result['status'] = True
|
||||
result['data'] = ''
|
||||
with tarfile.open(sfile,'r') as zip_file:
|
||||
try:
|
||||
zip_file.extract(filename,tmp_path)
|
||||
result['data'] = public.readFile('{}/{}'.format(tmp_path,filename))
|
||||
except:pass
|
||||
try:
|
||||
public.rmdir(tmp_path)
|
||||
except:pass
|
||||
return result
|
||||
|
||||
def delete_zip_file(self,args):
|
||||
'''
|
||||
@name 删除压缩包内文件
|
||||
@param args['path'] 压缩包路径
|
||||
@param args['filenames'] 文件名列表,数组格式
|
||||
@return dict
|
||||
'''
|
||||
sfile = args.sfile
|
||||
filenames = args.filenames
|
||||
|
||||
if not tarfile.is_tarfile(sfile):
|
||||
return public.returnMsg(False,'Not a valid tar.gz archive file')
|
||||
|
||||
tmp_path = self.__unzip_tmp_path(sfile)
|
||||
if not tmp_path: return public.returnMsg(False,'Failed edit!')
|
||||
|
||||
#组装原有的文件
|
||||
s_list = []
|
||||
src_list = {}
|
||||
public.get_file_list(tmp_path,s_list)
|
||||
for f in s_list:
|
||||
if not os.path.isfile(f): continue
|
||||
src_file = f.replace(tmp_path,'').strip('/')
|
||||
if src_file in filenames:
|
||||
continue
|
||||
src_list[src_file] = f
|
||||
|
||||
with tarfile.open(sfile,'w') as new_zfile:
|
||||
try:
|
||||
for src_file in src_list:
|
||||
new_zfile.add(src_list[src_file],src_file)
|
||||
except:
|
||||
shutil.rmtree(tmp_path, True)
|
||||
return public.returnMsg(False,'Failed delete file,error:' + public.get_error_info())
|
||||
|
||||
shutil.rmtree(tmp_path, True)
|
||||
return public.returnMsg(True,'Compressed package file modified successfully')
|
||||
|
||||
|
||||
def write_zip_file(self,args):
|
||||
'''
|
||||
@name 写入压缩包内文件
|
||||
@param args['path'] 压缩包路径
|
||||
@param args['filename'] 文件名
|
||||
@param args['data'] 写入数据
|
||||
@return dict
|
||||
'''
|
||||
|
||||
sfile = args.sfile
|
||||
filename = args.filename
|
||||
data = args.data
|
||||
|
||||
if not os.path.exists(sfile):
|
||||
return public.returnMsg(False,'FILE_NOT_EXISTS')
|
||||
|
||||
tmp_path = self.__unzip_tmp_path(sfile)
|
||||
if not tmp_path: return public.returnMsg(False,'Failed edit!')
|
||||
public.writeFile('{}/{}'.format(tmp_path,filename),data)
|
||||
|
||||
#组装原有的文件
|
||||
s_list = []
|
||||
src_list = {}
|
||||
public.get_file_list(tmp_path,s_list)
|
||||
for f in s_list:
|
||||
if os.path.isdir(f):
|
||||
continue
|
||||
src_file = f.replace(tmp_path,'').strip('/')
|
||||
if src_file in src_list:
|
||||
continue
|
||||
src_list[src_file] = f
|
||||
|
||||
with tarfile.open(sfile,'w') as new_zfile:
|
||||
try:
|
||||
for src_file in src_list:
|
||||
new_zfile.add(src_list[src_file],src_file)
|
||||
except:
|
||||
shutil.rmtree(tmp_path, True)
|
||||
return public.returnMsg(False,'Failed modify file,error:' + public.get_error_info())
|
||||
|
||||
shutil.rmtree(tmp_path, True)
|
||||
return public.returnMsg(True,'Compressed package file modified successfully')
|
||||
|
||||
|
||||
|
||||
def extract_byfiles(self,args):
|
||||
"""
|
||||
@name 解压部分文件
|
||||
@param args['path'] 压缩包路径
|
||||
@param args['extract_path'] 解压路径
|
||||
@param args['filenames'] 文件名列表,数组格式
|
||||
"""
|
||||
sfile = args.sfile
|
||||
filenames = args.filenames
|
||||
extract_path = args.extract_path
|
||||
if not os.path.exists(sfile):
|
||||
return public.returnMsg(False,'FILE_NOT_EXISTS')
|
||||
|
||||
if not os.path.exists(extract_path):
|
||||
os.makedirs(extract_path,384)
|
||||
|
||||
tmp_path = '{}/tmp/{}'.format(public.get_panel_path(),public.md5(public.GetRandomString(32)))
|
||||
if not os.path.exists(tmp_path):
|
||||
os.makedirs(tmp_path,384)
|
||||
|
||||
with tarfile.open(sfile) as zip_file:
|
||||
try:
|
||||
m_list = {}
|
||||
|
||||
f_infos = zip_file.getmembers()
|
||||
for item in f_infos:
|
||||
filename = self.__get_zip_filename(item)
|
||||
|
||||
if filename in filenames:
|
||||
spath = os.path.join(tmp_path,filename).strip('/')
|
||||
if item.isdir():
|
||||
m_list[spath] = []
|
||||
else:
|
||||
if not 'other' in m_list:
|
||||
m_list['other'] = []
|
||||
|
||||
dir_key = os.path.dirname(spath)
|
||||
info = {'src':spath,'dst':'{}/{}'.format(extract_path, filename.strip('/'))}
|
||||
if dir_key in m_list:
|
||||
info['dst'] = '{}/{}'.format(extract_path,'/'.join(filename.split('/')[1:]))
|
||||
s_path = os.path.dirname(info['dst'])
|
||||
if not os.path.exists(s_path): os.makedirs(s_path,384)
|
||||
|
||||
m_list[dir_key].append(info)
|
||||
else:
|
||||
m_list['other'].append(info)
|
||||
|
||||
s_path = os.path.dirname(info['dst'])
|
||||
if not os.path.exists(s_path): os.makedirs(s_path, 384)
|
||||
zip_file.extract(filename.strip('/'),tmp_path)
|
||||
|
||||
for key in m_list:
|
||||
try:
|
||||
for info in m_list[key]:
|
||||
if os.getenv('BT_PANEL'):
|
||||
shutil.copyfile(info['src'],info['dst'])
|
||||
else:
|
||||
shutil.copyfile('/' + info['src'],'/' + info['dst'])
|
||||
except:
|
||||
pass
|
||||
shutil.rmtree(tmp_path, True)
|
||||
except:
|
||||
return public.returnMsg(False,'Decompression failed,error:' + public.get_error_info())
|
||||
return public.returnMsg(True,'File was decompressed successfully')
|
||||
|
||||
def __unzip_tmp_path(self,sfile):
|
||||
'''
|
||||
@name 获取临时解压路径
|
||||
@param sfile 压缩包路径
|
||||
@return str
|
||||
'''
|
||||
tmp_path = '{}/tmp/{}'.format(public.get_soft_path(),public.md5(public.GetRandomString(32)))
|
||||
with tarfile.open(sfile) as zip_file:
|
||||
try:
|
||||
zip_file.extractall(tmp_path)
|
||||
except: return False
|
||||
|
||||
return tmp_path
|
||||
|
||||
|
||||
def add_zip_file(self,args):
|
||||
'''
|
||||
@name 添加文件到压缩包
|
||||
@param args['r_path'] 跟路径
|
||||
@param args['filename'] 文件名
|
||||
@param args['f_list'] 写入数据
|
||||
@return dict
|
||||
'''
|
||||
|
||||
sfile = args.sfile
|
||||
r_path = args.r_path
|
||||
f_list = args.f_list
|
||||
if not os.path.exists(sfile):
|
||||
return public.returnMsg(False,'FILE_NOT_EXISTS')
|
||||
|
||||
tmp_path = self.__unzip_tmp_path(sfile)
|
||||
if not tmp_path: return public.returnMsg(False,'Failed edit!')
|
||||
|
||||
#组装新添加的文件
|
||||
src_list = {}
|
||||
for fname in f_list:
|
||||
if os.path.isdir(fname):
|
||||
s_list = []
|
||||
public.get_file_list(fname,s_list)
|
||||
|
||||
for f in s_list:
|
||||
if os.path.isdir(f):
|
||||
continue
|
||||
src_file = '{}/{}{}'.format(r_path,os.path.basename(fname),f.replace(fname,'')).replace('//','/')
|
||||
src_list[src_file] = f
|
||||
else:
|
||||
src_file = '{}/{}'.format(r_path, os.path.basename(fname)).replace('//','/')
|
||||
src_list[src_file] = fname
|
||||
|
||||
#组装原有的文件
|
||||
s_list = []
|
||||
public.get_file_list(tmp_path,s_list)
|
||||
for f in s_list:
|
||||
if os.path.isdir(f):
|
||||
continue
|
||||
src_file = f.replace(tmp_path,'').strip('/')
|
||||
if src_file in src_list:
|
||||
continue
|
||||
src_list[src_file] = f
|
||||
|
||||
with tarfile.open(sfile,'w') as new_zfile:
|
||||
try:
|
||||
for src_file in src_list:
|
||||
new_zfile.add(src_list[src_file],src_file)
|
||||
except:
|
||||
shutil.rmtree(tmp_path, True)
|
||||
return public.returnMsg(False,'Failed add file,error:' + public.get_error_info())
|
||||
|
||||
shutil.rmtree(tmp_path, True)
|
||||
return public.returnMsg(True,'Compressed package file modified successfully')
|
||||
|
||||
|
||||
|
||||
def __get_zip_filename(self,item):
|
||||
'''
|
||||
@name 获取压缩包文件名
|
||||
@param item 压缩包文件对象
|
||||
@return string
|
||||
'''
|
||||
filename = item.name
|
||||
try:
|
||||
filename = item.name.encode('cp437').decode('gbk')
|
||||
except:pass
|
||||
if item.isdir():
|
||||
filename += '/'
|
||||
return filename
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,289 @@
|
||||
#coding: utf-8
|
||||
#-------------------------------------------------------------------
|
||||
# 宝塔Linux面板
|
||||
#-------------------------------------------------------------------
|
||||
# Copyright (c) 2015-2099 宝塔软件(http://bt.cn) All rights reserved.
|
||||
#-------------------------------------------------------------------
|
||||
# Author: cjxin <cjxin@bt.cn>
|
||||
#-------------------------------------------------------------------
|
||||
|
||||
#
|
||||
#------------------------------
|
||||
import os,sys,re
|
||||
from filesModel.base import filesBase
|
||||
import public,files,json,time
|
||||
|
||||
from BTPanel import cache
|
||||
|
||||
class main(filesBase):
|
||||
|
||||
|
||||
__objs = ['bos']
|
||||
def __init__(self):
|
||||
pass
|
||||
|
||||
|
||||
def get_logs_info(self,get):
|
||||
"""
|
||||
@查看日志
|
||||
@param get
|
||||
limit:每页显示条数
|
||||
file:日志文件
|
||||
"""
|
||||
p = 1
|
||||
limit = 200
|
||||
search = None
|
||||
file = get.file
|
||||
if 'limit' in get: limit = int(get.limit)
|
||||
if 'p' in get: limit = int(get.p)
|
||||
if 'search' in get: search = get.search
|
||||
|
||||
if not os.path.exists(file):
|
||||
return public.returnMsg(False,'Please specify file!')
|
||||
|
||||
res = {}
|
||||
res['status'] = True
|
||||
res['data'] = self.GetNumLines(file,limit,p,search)
|
||||
|
||||
res['md5'] = public.md5(res['data'])
|
||||
res['limit'] = limit
|
||||
|
||||
if not cache.get(file+'_logs_info'):
|
||||
public.set_module_logs('files_get_logs_info','get_logs_info')
|
||||
cache.set(file+'_logs_info','1',86400)
|
||||
return res
|
||||
|
||||
|
||||
def set_log_split(self,get):
|
||||
"""
|
||||
@name 文件切割
|
||||
@param filename 文件路径
|
||||
@param stype 切割类型 day:按天切割 size:按大小切割
|
||||
@param size 切割大小(stype=size必传)
|
||||
"""
|
||||
filename = get.filename
|
||||
stype = get.stype
|
||||
limit = int(get.limit)
|
||||
if not stype in ['day','size']:
|
||||
return public.returnMsg(False,'Cut type passing error.')
|
||||
|
||||
if not os.path.exists(filename):
|
||||
return public.returnMsg(False,'FILE_NOT_EXISTS')
|
||||
|
||||
if limit < 3:
|
||||
return public.returnMsg(False,'The number of reserved copies cannot be less than 3.')
|
||||
|
||||
data = {'type':stype,'limit':limit,'addtime':int(time.time())}
|
||||
if stype == 'size':
|
||||
size = int(get.size)
|
||||
if size < 1024:
|
||||
return public.returnMsg(False,'Cut size cannot be empty.')
|
||||
data['size'] = size
|
||||
|
||||
public.set_split_logs(filename,1,data)
|
||||
|
||||
return public.returnMsg(True,'successfully set.')
|
||||
|
||||
|
||||
def get_log_split(self,get):
|
||||
"""
|
||||
@name 获取文件切割信息
|
||||
@param filename 文件路径
|
||||
"""
|
||||
data = {}
|
||||
sfile = '{}/data/cutting_log.json'.format(public.get_panel_path())
|
||||
if os.path.exists(sfile):
|
||||
try:
|
||||
data = json.loads(public.readFile(sfile))
|
||||
except:pass
|
||||
|
||||
return data
|
||||
|
||||
|
||||
def get_file_ext(self,filename):
|
||||
"""
|
||||
@name 获取文件扩展名
|
||||
@param filename
|
||||
"""
|
||||
ss_exts = ['.tar.gz','.tar.bz2','.tar.bz']
|
||||
for s in ss_exts:
|
||||
e_len = len(s)
|
||||
f_len = len(filename)
|
||||
if f_len < e_len: continue
|
||||
if filename[-e_len:] == s:
|
||||
return filename[:-e_len] ,s
|
||||
if filename.find('.') == -1: return filename,''
|
||||
return os.path.splitext(filename)
|
||||
|
||||
def copy_file_to(self, get):
|
||||
"""
|
||||
@name 创建文件副本
|
||||
@param get
|
||||
@return
|
||||
"""
|
||||
|
||||
sfile = get.sfile
|
||||
if not os.path.exists(sfile):
|
||||
return public.returnMsg(False, 'FILE_NOT_EXISTS')
|
||||
|
||||
spath,ext = sfile,''
|
||||
if os.path.isfile(get.sfile):
|
||||
spath,ext = self.get_file_ext(sfile)
|
||||
|
||||
# public.print_log(spath)
|
||||
for x in range(1,1000):
|
||||
dfile = '{} - copy ({}){}'.format(spath,x,ext)
|
||||
if not os.path.exists(dfile):
|
||||
break
|
||||
|
||||
get.dfile = dfile
|
||||
f_obj = files.files()
|
||||
if os.path.isdir(get.sfile):
|
||||
public.WriteLog("File manager","Create copy of the directory [{}]".format(sfile))
|
||||
return f_obj.CopyDir(get)
|
||||
|
||||
import shutil
|
||||
try:
|
||||
shutil.copyfile(get.sfile, get.dfile)
|
||||
public.WriteLog('TYPE_FILE', 'FILE_COPY_SUCCESS',
|
||||
(get.sfile, get.dfile))
|
||||
try:
|
||||
stat = os.stat(get.sfile)
|
||||
os.chmod(get.dfile,stat.st_mode)
|
||||
os.chown(get.dfile, stat.st_uid, stat.st_gid)
|
||||
except:pass
|
||||
public.WriteLog("File manager","Create copy of the file[{}]".format(sfile))
|
||||
return public.returnMsg(True, 'FILE_COPY_SUCCESS')
|
||||
except:
|
||||
return public.returnMsg(False, 'FILE_COPY_ERR')
|
||||
|
||||
|
||||
def set_topping_status(self,get):
|
||||
"""
|
||||
@name 设置文件或目录置顶
|
||||
@param get
|
||||
file:文件路径
|
||||
type:置顶类型
|
||||
"""
|
||||
sfile = get.sfile
|
||||
status = int(get.status)
|
||||
if not os.path.exists(sfile):
|
||||
import html
|
||||
sfile = html.unescape(sfile)
|
||||
if not os.path.exists(sfile):
|
||||
return public.returnMsg(False, 'File or directory does not exist.')
|
||||
|
||||
|
||||
data = {}
|
||||
conf_file = '{}/data/toping.json'.format(public.get_panel_path())
|
||||
try :
|
||||
if os.path.exists(conf_file):
|
||||
data = json.loads(public.readFile(conf_file))
|
||||
except:pass
|
||||
|
||||
if sfile in data: del data[sfile]
|
||||
|
||||
if status:
|
||||
data[sfile] = status
|
||||
public.writeFile(conf_file, json.dumps(data))
|
||||
public.set_module_logs('files_set_topping_status','set_topping_status')
|
||||
public.WriteLog("File manager","Modify [{}] top status".format(sfile))
|
||||
return public.returnMsg(True, 'Successful set.')
|
||||
|
||||
|
||||
def GetNumLines(self,path, num, p=1,search = None):
|
||||
"""
|
||||
@name 取文件指定尾行数
|
||||
@param path 文件路径
|
||||
@param num 取尾行数
|
||||
@param p 当前页
|
||||
@param search 搜索关键字
|
||||
@return list
|
||||
"""
|
||||
pyVersion = sys.version_info[0]
|
||||
max_len = 1024 * 128
|
||||
try:
|
||||
from html import escape
|
||||
if not os.path.exists(path): return ""
|
||||
start_line = (p - 1) * num
|
||||
count = start_line + num
|
||||
fp = open(path, 'rb')
|
||||
|
||||
buf = ""
|
||||
fp.seek(-1, 2)
|
||||
if fp.read(1) == "\n": fp.seek(-1, 2)
|
||||
data = []
|
||||
total_len = 0
|
||||
b = True
|
||||
n = 0
|
||||
|
||||
for i in range(count):
|
||||
while True:
|
||||
newline_pos = str.rfind(str(buf), "\n")
|
||||
|
||||
pos = fp.tell()
|
||||
if newline_pos != -1:
|
||||
if n >= start_line:
|
||||
line = buf[newline_pos + 1:]
|
||||
|
||||
is_res = True
|
||||
if search:
|
||||
is_res = False
|
||||
if line.find(search) >= 0 or re.search(search,line):
|
||||
is_res = True
|
||||
|
||||
if is_res:
|
||||
line_len = len(line)
|
||||
total_len += line_len
|
||||
sp_len = total_len - max_len
|
||||
if sp_len > 0:
|
||||
line = line[sp_len:]
|
||||
try:
|
||||
data.insert(0, escape(line))
|
||||
except:
|
||||
pass
|
||||
buf = buf[:newline_pos]
|
||||
n += 1
|
||||
break
|
||||
else:
|
||||
if pos == 0:
|
||||
b = False
|
||||
break
|
||||
to_read = min(4096, pos)
|
||||
fp.seek(-to_read, 1)
|
||||
t_buf = fp.read(to_read)
|
||||
if pyVersion == 3:
|
||||
try:
|
||||
if type(t_buf) == bytes: t_buf = t_buf.decode('utf-8',errors='ignore')
|
||||
except:
|
||||
try:
|
||||
if type(t_buf) == bytes: t_buf = t_buf.decode('gbk',errors='ignore')
|
||||
except:
|
||||
t_buf = str(t_buf)
|
||||
buf = t_buf + buf
|
||||
fp.seek(-to_read, 1)
|
||||
if pos - to_read == 0:
|
||||
buf = "\n" + buf
|
||||
if total_len >= max_len: break
|
||||
if not b: break
|
||||
fp.close()
|
||||
result = "\n".join(data)
|
||||
|
||||
if not result: raise Exception('null')
|
||||
except:
|
||||
result = ''
|
||||
if len(result) > max_len:
|
||||
result = result[-max_len:]
|
||||
|
||||
try:
|
||||
try:
|
||||
result = json.dumps(result)
|
||||
return json.loads(result).strip()
|
||||
except:
|
||||
if pyVersion == 2:
|
||||
result = result.decode('utf8', errors='ignore')
|
||||
else:
|
||||
result = result.encode('utf-8', errors='ignore').decode("utf-8", errors="ignore")
|
||||
return result.strip()
|
||||
except:
|
||||
return ""
|
||||
@@ -0,0 +1,243 @@
|
||||
#coding: utf-8
|
||||
#-------------------------------------------------------------------
|
||||
# 宝塔Linux面板
|
||||
#-------------------------------------------------------------------
|
||||
# Copyright (c) 2015-2099 宝塔软件(http://bt.cn) All rights reserved.
|
||||
#-------------------------------------------------------------------
|
||||
# Author: cjxin <cjxin@bt.cn>
|
||||
#-------------------------------------------------------------------
|
||||
|
||||
#
|
||||
#------------------------------
|
||||
|
||||
import os,sys,re
|
||||
from filesModel.base import filesBase
|
||||
import public,json
|
||||
import zipfile,shutil
|
||||
try:
|
||||
from unrar import rarfile
|
||||
except:
|
||||
os.system('btpip install unrar')
|
||||
from unrar import rarfile
|
||||
|
||||
|
||||
class main(filesBase):
|
||||
|
||||
def __init__(self):
|
||||
pass
|
||||
|
||||
|
||||
def __check_zipfile(self,sfile,is_close = False):
|
||||
'''
|
||||
@name 检查文件是否为zip文件
|
||||
@param sfile 文件路径
|
||||
@return bool
|
||||
'''
|
||||
|
||||
zip_file = None
|
||||
try:
|
||||
zip_file = rarfile.RarFile(sfile)
|
||||
except:pass
|
||||
|
||||
if is_close and zip_file:
|
||||
zip_file.close()
|
||||
|
||||
return zip_file
|
||||
|
||||
def get_zip_files(self,args):
|
||||
'''
|
||||
@name 获取压缩包内文件列表
|
||||
@param args['path'] 压缩包路径
|
||||
@return list
|
||||
'''
|
||||
sfile = args.sfile
|
||||
if not os.path.exists(sfile):
|
||||
return public.returnMsg(False,'FILE_NOT_EXISTS')
|
||||
|
||||
zip_file = self.__check_zipfile(sfile)
|
||||
if not zip_file:
|
||||
return public.returnMsg(False,'NOT_ZIP_FILE')
|
||||
|
||||
data = {}
|
||||
for item in zip_file.infolist():
|
||||
|
||||
sub_data = data
|
||||
f_name = self.__get_zip_filename(item)
|
||||
|
||||
f_dirs = f_name.split('/')
|
||||
for d in f_dirs:
|
||||
if not d: continue
|
||||
if not d in sub_data:
|
||||
if d == f_name[-len(d):]:
|
||||
tmps = item.date_time
|
||||
|
||||
sub_data[d] = {
|
||||
'file_size': item.file_size,
|
||||
'compress_size': item.compress_size,
|
||||
'filename':d,
|
||||
'fullpath':f_name,
|
||||
'date_time': public.to_date(times = '{}-{}-{} {}:{}:{}'.format(tmps[0],tmps[1],tmps[2],tmps[3],tmps[4],tmps[5])),
|
||||
'is_dir': 0
|
||||
}
|
||||
if item.flag_bits == 32:
|
||||
sub_data[d]['is_dir'] = 1
|
||||
else:
|
||||
sub_data[d] = {}
|
||||
sub_data = sub_data[d]
|
||||
|
||||
return data
|
||||
|
||||
|
||||
def get_fileinfo_by(self,args):
|
||||
'''
|
||||
@name 获取压缩包内文件信息
|
||||
@param args['path'] 压缩包路径
|
||||
@param args['filename'] 文件名
|
||||
@return dict
|
||||
'''
|
||||
|
||||
sfile = args.sfile
|
||||
filename = args.filename
|
||||
if not os.path.exists(sfile):
|
||||
return public.returnMsg(False,'FILE_NOT_EXISTS')
|
||||
|
||||
result = {}
|
||||
result['status'] = True
|
||||
result['data'] = ''
|
||||
with rarfile.RarFile(sfile,'r') as zip_file:
|
||||
for item in zip_file.infolist():
|
||||
z_filename = self.__get_zip_filename(item)
|
||||
if z_filename == filename:
|
||||
|
||||
buff = zip_file.read(item.filename)
|
||||
encoding,srcBody = public.decode_data(buff)
|
||||
result['encoding'] = encoding
|
||||
result['data'] = srcBody
|
||||
break
|
||||
return result
|
||||
|
||||
def delete_zip_file(self,args):
|
||||
'''
|
||||
@name 删除压缩包内文件
|
||||
@param args['path'] 压缩包路径
|
||||
@param args['filenames'] 文件名列表,数组格式
|
||||
@return dict
|
||||
'''
|
||||
sfile = args.sfile
|
||||
filenames = args.filenames
|
||||
|
||||
return public.returnMsg(False,'RAR archive files do not support file deletion')
|
||||
|
||||
def write_zip_file(self,args):
|
||||
'''
|
||||
@name 写入压缩包内文件
|
||||
@param args['path'] 压缩包路径
|
||||
@param args['filename'] 文件名
|
||||
@param args['data'] 写入数据
|
||||
@return dict
|
||||
'''
|
||||
|
||||
sfile = args.sfile
|
||||
filename = args.filename
|
||||
data = args.data
|
||||
return public.returnMsg(False,'RAR archive does not support this function!')
|
||||
|
||||
def extract_byfiles(self,args):
|
||||
"""
|
||||
@name 解压部分文件
|
||||
@param args['path'] 压缩包路径
|
||||
@param args['extract_path'] 解压路径
|
||||
@param args['filenames'] 文件名列表,数组格式
|
||||
"""
|
||||
sfile = args.sfile
|
||||
filenames = args.filenames
|
||||
extract_path = args.extract_path
|
||||
if not os.path.exists(sfile):
|
||||
return public.returnMsg(False,'FILE_NOT_EXISTS')
|
||||
|
||||
if not os.path.exists(extract_path):
|
||||
os.makedirs(extract_path,384)
|
||||
|
||||
tmp_path = '{}/tmp/{}'.format(public.get_soft_path(),public.md5(public.GetRandomString(32)))
|
||||
if not os.path.exists(tmp_path):
|
||||
os.makedirs(tmp_path,384)
|
||||
|
||||
with rarfile.RarFile(sfile) as zip_file:
|
||||
try:
|
||||
m_list = {}
|
||||
|
||||
f_infos = zip_file.infolist()
|
||||
f_infos = sorted(f_infos,key=lambda x:x.filename)
|
||||
for item in f_infos:
|
||||
filename = self.__get_zip_filename(item)
|
||||
|
||||
if filename in filenames:
|
||||
spath = os.path.join(tmp_path,filename).strip('/')
|
||||
if item.flag_bits == 32:
|
||||
m_list[spath] = []
|
||||
else:
|
||||
if not 'other' in m_list:
|
||||
m_list['other'] = []
|
||||
|
||||
dir_key = os.path.dirname(spath)
|
||||
info = {'src':spath,'dst':'{}/{}'.format(extract_path,os.path.basename(spath))}
|
||||
if dir_key in m_list:
|
||||
info['dst'] = '{}/{}'.format(extract_path,'/'.join(filename.split('/')[1:]))
|
||||
s_path = os.path.dirname(info['dst'])
|
||||
if not os.path.exists(s_path): os.makedirs(s_path,384)
|
||||
|
||||
m_list[dir_key].append(info)
|
||||
else:
|
||||
m_list['other'].append(info)
|
||||
zip_file.extract(filename.strip('/').replace('/','\\'),tmp_path)
|
||||
for key in m_list:
|
||||
try:
|
||||
# if key != 'other':
|
||||
# dir_name = '{}/{}'.format(extract_path,os.path.basename(key))
|
||||
# if not os.path.exists(dir_name): os.makedirs(dir_name,384)
|
||||
|
||||
for info in m_list[key]:
|
||||
shutil.copyfile(info['src'],info['dst'])
|
||||
except:pass
|
||||
|
||||
shutil.rmtree(tmp_path, True)
|
||||
except:
|
||||
return public.returnMsg(False,'Decompression failed,error:' + public.get_error_info())
|
||||
return public.returnMsg(True,'The file was decompressed successfully')
|
||||
|
||||
def add_zip_file(self,args):
|
||||
'''
|
||||
@name 添加文件到压缩包
|
||||
@param args['r_path'] 跟路径
|
||||
@param args['filename'] 文件名
|
||||
@param args['f_list'] 写入数据
|
||||
@return dict
|
||||
'''
|
||||
|
||||
sfile = args.sfile
|
||||
r_path = args.r_path
|
||||
f_list = args.f_list
|
||||
return public.returnMsg(False,'RAR archive does not support this function!')
|
||||
|
||||
|
||||
|
||||
def __get_zip_filename(self,item):
|
||||
'''
|
||||
@name 获取压缩包文件名
|
||||
@param item 压缩包文件对象
|
||||
@return string
|
||||
'''
|
||||
filename = item.filename
|
||||
try:
|
||||
filename = item.filename.encode('cp437').decode('gbk')
|
||||
except:pass
|
||||
if item.flag_bits == 32:
|
||||
filename += '/'
|
||||
|
||||
return filename.replace('\\','/')
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,307 @@
|
||||
#coding: utf-8
|
||||
#-------------------------------------------------------------------
|
||||
# 宝塔Linux面板
|
||||
#-------------------------------------------------------------------
|
||||
# Copyright (c) 2015-2099 宝塔软件(http://bt.cn) All rights reserved.
|
||||
#-------------------------------------------------------------------
|
||||
# Author: cjxin <cjxin@bt.cn>
|
||||
#-------------------------------------------------------------------
|
||||
|
||||
#
|
||||
#------------------------------
|
||||
|
||||
import os, re
|
||||
from filesModel.base import filesBase
|
||||
import public, json
|
||||
from html import escape
|
||||
|
||||
|
||||
class main(filesBase):
|
||||
|
||||
__s_class = []
|
||||
|
||||
def __init__(self):
|
||||
for i in range(1, 100):
|
||||
self.__s_class.append('f-s-%s' % i)
|
||||
|
||||
def get_search_status(self, get):
|
||||
"""
|
||||
@name 验证是否可用
|
||||
"""
|
||||
return public.returnMsg(True, '1')
|
||||
|
||||
def get_search_result(self, get):
|
||||
"""
|
||||
@name 搜索文件
|
||||
@param get
|
||||
path:搜索路径
|
||||
search:搜索关键字
|
||||
limit:每页显示条数
|
||||
p:页码
|
||||
"""
|
||||
result = {}
|
||||
is_dir = 0
|
||||
search = []
|
||||
|
||||
if not 'ext' in get: get.ext = '*'
|
||||
if 'search' in get: search = get.search
|
||||
if 'is_dir' in get: is_dir = get.is_dir
|
||||
|
||||
public.set_module_logs('searchModel', 'get_search_result')
|
||||
if not is_dir:
|
||||
if len(search) == 0:
|
||||
return public.returnMsg(False, 'Please enter search keywords!')
|
||||
|
||||
if not os.path.exists(get.path):
|
||||
return public.returnMsg(False, 'Search directory does not exist!')
|
||||
|
||||
slist = self.get_search_files(get)
|
||||
if is_dir: return slist
|
||||
num = 0
|
||||
total_num = len(slist)
|
||||
if slist: public.writeSpeed('files_search', num, total_num)
|
||||
for sfile in slist:
|
||||
data = self.__check_file_contents(sfile, search)
|
||||
if data:
|
||||
result[sfile] = data
|
||||
num += 1
|
||||
public.writeSpeed('files_search', num, total_num)
|
||||
progress = int(public.getSpeed()['progress'])
|
||||
if '_ws' in get:
|
||||
get._ws.send(
|
||||
public.getJson({
|
||||
"end": False if progress < 100 else True,
|
||||
"ws_callback": get.ws_callback,
|
||||
"file": sfile,
|
||||
"progress": progress,
|
||||
"total": total_num,
|
||||
"num": num,
|
||||
"type": "get_search_result"
|
||||
}))
|
||||
if not slist and '_ws' in get:
|
||||
get._ws.send(
|
||||
public.getJson({
|
||||
"end": True,
|
||||
"ws_callback": get.ws_callback,
|
||||
"file": '',
|
||||
"progress": 100,
|
||||
"total": 0,
|
||||
"num": 0,
|
||||
"type": "get_search_result"
|
||||
}))
|
||||
return result
|
||||
|
||||
def get_search_files(self, get):
|
||||
"""
|
||||
@name 搜索文件
|
||||
@param get
|
||||
path:搜索路径
|
||||
search:搜索关键字
|
||||
"""
|
||||
|
||||
data = {}
|
||||
|
||||
data['is_sub'] = 0
|
||||
if 'is_sub' in get:
|
||||
data['is_sub'] = int(get.is_sub)
|
||||
|
||||
data['ext'] = []
|
||||
for ext in get.ext.split(','):
|
||||
if ext: data['ext'].append(ext)
|
||||
|
||||
data['s_time'] = 0
|
||||
data['e_time'] = 4070880000
|
||||
if 's_time' in get:
|
||||
data['s_time'] = int(get.s_time)
|
||||
if 'e_time' in get:
|
||||
data['e_time'] = int(get.e_time)
|
||||
|
||||
data['min_size'] = 0
|
||||
data['max_size'] = 1024 * 1024 * 10
|
||||
if 'min_size' in get:
|
||||
data['min_size'] = int(get.min_size)
|
||||
|
||||
if 'max_size' in get:
|
||||
data['max_size'] = int(get.max_size)
|
||||
|
||||
data['names'] = []
|
||||
if 'names' in get:
|
||||
data['names'] = get.names
|
||||
|
||||
flist = []
|
||||
self.__get_file_list(get.path, data, flist)
|
||||
|
||||
return flist
|
||||
|
||||
def __check_file_contents(self, sfile, contents):
|
||||
"""
|
||||
@name 验证文件内容
|
||||
@param sfile:文件路径
|
||||
@param contents:文件内容
|
||||
"""
|
||||
n = 1
|
||||
result = {}
|
||||
try:
|
||||
for line in open(sfile, 'rb'):
|
||||
try:
|
||||
if type(line) == bytes: line = line.decode('utf-8')
|
||||
except:
|
||||
line = str(line)
|
||||
|
||||
rep_list = {}
|
||||
_line = escape(line)
|
||||
p = 0
|
||||
for txt in contents:
|
||||
if not txt: continue
|
||||
p += 1
|
||||
txt = escape(txt)
|
||||
if line.find(txt) >= 0:
|
||||
_line = self.__replace_contents(
|
||||
_line, txt, p, rep_list)
|
||||
else:
|
||||
tmp = re.search('(' + txt + ')', _line, flags=re.I)
|
||||
if tmp:
|
||||
_line = self.__replace_contents(
|
||||
_line,
|
||||
tmp.groups()[0], p, rep_list)
|
||||
|
||||
for key in rep_list:
|
||||
# public.print_log(json.dumps(rep_list))
|
||||
result[n] = _line.replace(key, rep_list[key])
|
||||
n += 1
|
||||
except:
|
||||
pass
|
||||
return result
|
||||
|
||||
# line = line.replace("BT_SEARCH".format(p), )
|
||||
def __replace_contents(self, line, txt, p, rep_list):
|
||||
"""
|
||||
@name 替换文件内容
|
||||
@param line:文件内容
|
||||
@param txt:替换内容
|
||||
@param p:替换位置
|
||||
"""
|
||||
n_data = 'BT_SEARCH{}'.format(p)
|
||||
line = line.replace(txt, n_data)
|
||||
rep_list[n_data] = "<span class='{}'>{}</span>".format(
|
||||
self.__s_class[p - 1], txt)
|
||||
return line
|
||||
|
||||
def __get_file_list(self, path, data, flist):
|
||||
"""
|
||||
@name 获取文件列表
|
||||
@param path:文件路径
|
||||
@param ext:文件类型
|
||||
@param s_time:开始时间
|
||||
@param e_time:结束时间
|
||||
@param min_size:最小文件大小
|
||||
@param max_size:最大文件大小
|
||||
@param flist:返回文件列表
|
||||
"""
|
||||
|
||||
exts, s_time, e_time, min_size, max_size, names = data['ext'], data[
|
||||
's_time'], data['e_time'], data['min_size'], data[
|
||||
'max_size'], data['names']
|
||||
|
||||
for name in os.listdir(path):
|
||||
sfile = os.path.join(path, name)
|
||||
|
||||
if os.path.isdir(sfile):
|
||||
if not data['is_sub']: continue
|
||||
|
||||
self.__get_file_list(sfile, data, flist)
|
||||
else:
|
||||
|
||||
#第一步:验证文件名
|
||||
if not self.__check_filename(sfile=sfile, names=names):
|
||||
continue
|
||||
|
||||
#第二步:验证后缀
|
||||
if not self.__check_ext(sfile=sfile, exts=exts):
|
||||
continue
|
||||
|
||||
#第三步:验证时间
|
||||
if not self.__check_time(
|
||||
sfile=sfile, s_time=s_time, e_time=e_time):
|
||||
continue
|
||||
|
||||
#第四步:验证大小
|
||||
if not self.__check_size(
|
||||
sfile=sfile, min_size=min_size, max_size=max_size):
|
||||
continue
|
||||
|
||||
flist.append(sfile)
|
||||
|
||||
def __check_filename(self, sfile, names):
|
||||
"""
|
||||
@name 验证文件名
|
||||
@param sfile:文件路径
|
||||
@param names:文件名
|
||||
"""
|
||||
try:
|
||||
if len(names) == 0: return True
|
||||
|
||||
filename = os.path.basename(sfile)
|
||||
for name in names:
|
||||
if filename.find(name) >= 0:
|
||||
return True
|
||||
try:
|
||||
if re.search(name, filename):
|
||||
return True
|
||||
except:
|
||||
pass
|
||||
except:
|
||||
pass
|
||||
return False
|
||||
|
||||
def __check_ext(self, sfile, exts):
|
||||
"""
|
||||
@name 验证文件后缀
|
||||
@param sfile:文件路径
|
||||
@param exts:文件类型
|
||||
"""
|
||||
try:
|
||||
if "*" in exts:
|
||||
return True
|
||||
|
||||
spath, ext = os.path.splitext(sfile)
|
||||
if ext:
|
||||
if ext[1:] in exts:
|
||||
return True
|
||||
else:
|
||||
if 'no_ext' in exts:
|
||||
return True
|
||||
except:
|
||||
pass
|
||||
return False
|
||||
|
||||
def __check_time(self, sfile, s_time, e_time):
|
||||
"""
|
||||
@name 验证文件时间
|
||||
@param sfile:文件路径
|
||||
@param s_time:开始时间
|
||||
@param e_time:结束时间
|
||||
"""
|
||||
try:
|
||||
st_time = int(os.stat(sfile).st_mtime)
|
||||
if st_time >= s_time and st_time <= e_time:
|
||||
return True
|
||||
except:
|
||||
pass
|
||||
return False
|
||||
|
||||
def __check_size(self, sfile, min_size, max_size):
|
||||
"""
|
||||
@name 验证文件大小
|
||||
@param sfile:文件路径
|
||||
@param min_size:最小文件大小
|
||||
@param max_size:最大文件大小
|
||||
"""
|
||||
try:
|
||||
f_size = os.path.getsize(sfile)
|
||||
|
||||
if f_size >= min_size and f_size <= max_size:
|
||||
return True
|
||||
except:
|
||||
pass
|
||||
return False
|
||||
@@ -0,0 +1,287 @@
|
||||
#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
|
||||
@@ -0,0 +1,170 @@
|
||||
#coding: utf-8
|
||||
#-------------------------------------------------------------------
|
||||
# 宝塔Linux面板
|
||||
#-------------------------------------------------------------------
|
||||
# Copyright (c) 2015-2099 宝塔软件(http://bt.cn) All rights reserved.
|
||||
#-------------------------------------------------------------------
|
||||
# Author: cjxin <cjxin@bt.cn>
|
||||
#-------------------------------------------------------------------
|
||||
|
||||
# 上传文件至oss
|
||||
#------------------------------
|
||||
import os
|
||||
from filesModel.base import filesBase
|
||||
import public,smtplib
|
||||
|
||||
from email.mime.text import MIMEText
|
||||
from email.mime.multipart import MIMEMultipart
|
||||
from email.utils import formataddr
|
||||
|
||||
class main(filesBase):
|
||||
|
||||
|
||||
def __init__(self):
|
||||
pass
|
||||
|
||||
|
||||
def get_oss_objects(self,get):
|
||||
"""
|
||||
@name 获取可上传的对象存储
|
||||
"""
|
||||
return self.get_all_objects(get)
|
||||
|
||||
|
||||
|
||||
def get_file_list(self,get):
|
||||
"""
|
||||
@name 获取可上传的对象存储
|
||||
"""
|
||||
return self.get_base_objects(get)
|
||||
|
||||
|
||||
|
||||
def check_email_config(self,get):
|
||||
"""
|
||||
@name 检测邮箱是否配置
|
||||
"""
|
||||
import config
|
||||
|
||||
c_obj = config.config()
|
||||
mail_config = c_obj.get_msg_configs(get)['mail']
|
||||
|
||||
return mail_config
|
||||
|
||||
def send_to_email(self,get):
|
||||
"""
|
||||
@name 发送文件到邮件
|
||||
@flist list 文件列表
|
||||
@msg string 邮件正文
|
||||
@to string 邮件接收人,多个逗号隔开
|
||||
"""
|
||||
|
||||
import config
|
||||
c_obj = config.config()
|
||||
|
||||
try:
|
||||
mail_config = c_obj.get_msg_configs(get)['mail']['data']
|
||||
if not mail_config :
|
||||
return public.returnMsg(False,'未正确配置邮箱信息。')
|
||||
|
||||
if not mail_config['send']['qq_mail']:
|
||||
return public.returnMsg(False,'未正确配置邮箱信息。')
|
||||
except:
|
||||
return public.returnMsg(False,'未正确配置邮箱信息。')
|
||||
|
||||
msg = get.msg
|
||||
receive_list = get.to_email.split(',')
|
||||
if len(receive_list) <= 0:
|
||||
return public.returnMsg(False,'发送失败,接收者不能为空.')
|
||||
|
||||
|
||||
#附件文件
|
||||
flist = []
|
||||
if 'flist' in get: flist = get.flist
|
||||
|
||||
result = {}
|
||||
result['status'] = True
|
||||
result['list'] = {}
|
||||
for email in receive_list:
|
||||
slist = {}
|
||||
try:
|
||||
data = MIMEMultipart()
|
||||
data['From'] = formataddr([mail_config['send']['qq_mail'], mail_config['send']['qq_mail']])
|
||||
data['To'] = formataddr([mail_config['send']['qq_mail'], email.strip()])
|
||||
data['Subject'] = '宝塔面板消息通知'
|
||||
if int(mail_config['send']['port']) == 465:
|
||||
server = smtplib.SMTP_SSL(str(mail_config['send']['hosts']), str(mail_config['send']['port']))
|
||||
else:
|
||||
server = smtplib.SMTP(str(mail_config['send']['hosts']), str(mail_config['send']['port']))
|
||||
|
||||
data.attach(MIMEText(msg, 'html', 'utf-8'))
|
||||
|
||||
slist['error'] = {}
|
||||
#添加附件
|
||||
for filename in flist:
|
||||
if not os.path.exists(filename):
|
||||
slist['error'][filename] = '文件不存在'
|
||||
continue
|
||||
|
||||
#超过50M无法发送
|
||||
if os.path.getsize(filename) > 50 * 1024 *1024:
|
||||
slist['error'][filename] = '文件大于50M'
|
||||
continue
|
||||
|
||||
#中文无法发送
|
||||
if public.check_chinese(filename):
|
||||
slist['error'][filename] = '文件名包含中文,发送失败.'
|
||||
continue
|
||||
|
||||
att1 = MIMEText(open(filename, 'rb').read(), 'base64', 'utf-8')
|
||||
att1["Content-Type"] = 'application/octet-stream'
|
||||
att1["Content-Disposition"] = 'attachment; filename="' + os.path.basename(filename) + '"'
|
||||
data.attach(att1)
|
||||
|
||||
server.login(mail_config['send']['qq_mail'], mail_config['send']['qq_stmp_pwd'])
|
||||
server.sendmail(mail_config['send']['qq_mail'], [email.strip(), ], data.as_string())
|
||||
server.quit()
|
||||
slist['status'] = True
|
||||
except :
|
||||
slist = '发送失败,' + public.get_error_info()
|
||||
|
||||
result['list'][email] = slist
|
||||
public.set_module_logs('files_send_to_email', 'send_to_email', 1)
|
||||
return result
|
||||
|
||||
|
||||
|
||||
def upload_file(self,args):
|
||||
"""
|
||||
@name 上传文件到指定的对象存储
|
||||
"""
|
||||
|
||||
name = args.name
|
||||
filename = args.filename
|
||||
bucket = args.object_name.rstrip('/')
|
||||
|
||||
if not os.path.exists(filename):
|
||||
return public.returnMsg(False,'FILE_NOT_EXIST')
|
||||
|
||||
info = self.get_soft_find(name)
|
||||
if not info['setup']:
|
||||
return public.returnMsg(False,'未安装[{}]插件'.format(info['title']))
|
||||
|
||||
sfile = '{path}/plugin/{name}/{name}_main.py'.format(path=public.get_panel_path(),name=name)
|
||||
if public.readFile(sfile).find('upload_to') == -1:
|
||||
return public.returnMsg(False,'暂不支持该操作,请将[{}]插件升级到最新版'.format(info['title']))
|
||||
|
||||
#创建任务
|
||||
import panelTask
|
||||
task_obj = panelTask.bt_task()
|
||||
msg = '上传文件{}到{}'.format(filename,info['title'])
|
||||
exec_shell = 'btpython -u {spath} upload_to {file} {bucket}/{filename}'.format(spath=sfile,file=filename,bucket=bucket,filename=os.path.basename(filename))
|
||||
task_obj.create_task(msg, 0, exec_shell)
|
||||
|
||||
public.set_module_logs('files_upload_to_file', 'upload_file', 1)
|
||||
public.WriteLog('TYPE_FILE', msg)
|
||||
return public.returnMsg(True, '已添加到上传队列.')
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,327 @@
|
||||
#coding: utf-8
|
||||
#-------------------------------------------------------------------
|
||||
# 宝塔Linux面板
|
||||
#-------------------------------------------------------------------
|
||||
# Copyright (c) 2015-2099 宝塔软件(http://bt.cn) All rights reserved.
|
||||
#-------------------------------------------------------------------
|
||||
# Author: cjxin <cjxin@bt.cn>
|
||||
#-------------------------------------------------------------------
|
||||
|
||||
#
|
||||
#------------------------------
|
||||
|
||||
import os,sys,re
|
||||
from filesModel.base import filesBase
|
||||
import public,json
|
||||
import zipfile,shutil
|
||||
from pathlib import Path
|
||||
class main(filesBase):
|
||||
|
||||
def __init__(self):
|
||||
pass
|
||||
|
||||
|
||||
def __check_zipfile(self,sfile,is_close = False):
|
||||
'''
|
||||
@name 检查文件是否为zip文件
|
||||
@param sfile 文件路径
|
||||
@return bool
|
||||
'''
|
||||
|
||||
zip_file = None
|
||||
try:
|
||||
zip_file = zipfile.ZipFile(sfile)
|
||||
except:pass
|
||||
|
||||
if is_close and zip_file:
|
||||
zip_file.close()
|
||||
|
||||
return zip_file
|
||||
|
||||
def get_zip_files(self,args):
|
||||
'''
|
||||
@name 获取压缩包内文件列表
|
||||
@param args['path'] 压缩包路径
|
||||
@return list
|
||||
'''
|
||||
sfile = args.sfile
|
||||
if not os.path.exists(sfile):
|
||||
return public.returnMsg(False,'FILE_NOT_EXISTS')
|
||||
|
||||
zip_file = self.__check_zipfile(sfile)
|
||||
if not zip_file:
|
||||
return public.returnMsg(False,'NOT_ZIP_FILE')
|
||||
|
||||
data = {}
|
||||
for item in zip_file.infolist():
|
||||
sub_data = data
|
||||
f_name = self.__get_zip_filename(item)
|
||||
|
||||
f_dirs = f_name.split('/')
|
||||
|
||||
d_idx = 0
|
||||
for d in f_dirs:
|
||||
if not d: continue
|
||||
if not d in sub_data:
|
||||
if d == f_name[-len(d):] and d_idx == len(f_dirs) - 1:
|
||||
tmps = item.date_time
|
||||
sub_data[d] = {
|
||||
'file_size': item.file_size,
|
||||
'compress_size': item.compress_size,
|
||||
'compress_type': item.compress_type,
|
||||
'filename':d,
|
||||
'fullpath':f_name,
|
||||
'date_time': public.to_date(times = '{}-{}-{} {}:{}:{}'.format(tmps[0],tmps[1],tmps[2],tmps[3],tmps[4],tmps[5])),
|
||||
'is_dir': 0
|
||||
}
|
||||
if item.is_dir():
|
||||
sub_data[d]['is_dir'] = 1
|
||||
else:
|
||||
sub_data[d] = {}
|
||||
d_idx += 1
|
||||
sub_data = sub_data[d]
|
||||
|
||||
zip_file.close()
|
||||
return data
|
||||
|
||||
|
||||
def get_fileinfo_by(self,args):
|
||||
'''
|
||||
@name 获取压缩包内文件信息
|
||||
@param args['path'] 压缩包路径
|
||||
@param args['filename'] 文件名
|
||||
@return dict
|
||||
'''
|
||||
|
||||
sfile = args.sfile
|
||||
filename = args.filename
|
||||
if not os.path.exists(sfile):
|
||||
return public.returnMsg(False,'FILE_NOT_EXISTS')
|
||||
|
||||
result = {}
|
||||
result['status'] = True
|
||||
result['data'] = ''
|
||||
with zipfile.ZipFile(sfile,'r') as zip_file:
|
||||
for item in zip_file.infolist():
|
||||
z_filename = self.__get_zip_filename(item)
|
||||
if z_filename == filename:
|
||||
|
||||
buff = zip_file.read(item.filename)
|
||||
encoding,srcBody = public.decode_data(buff)
|
||||
result['encoding'] = encoding
|
||||
result['data'] = srcBody
|
||||
break
|
||||
return result
|
||||
|
||||
def delete_zip_file(self,args):
|
||||
'''
|
||||
@name 删除压缩包内文件
|
||||
@param args['path'] 压缩包路径
|
||||
@param args['filenames'] 文件名列表,数组格式
|
||||
@return dict
|
||||
'''
|
||||
sfile = args.sfile
|
||||
filenames = args.filenames
|
||||
if not os.path.exists(sfile):
|
||||
return public.returnMsg(False,'FILE_NOT_EXISTS')
|
||||
|
||||
with zipfile.ZipFile(sfile,'r') as zip_file:
|
||||
with zipfile.ZipFile(sfile + '.tmp','w',zipfile.ZIP_DEFLATED) as new_zfile:
|
||||
for item in zip_file.infolist():
|
||||
filename = self.__get_zip_filename(item)
|
||||
|
||||
if filename in filenames:
|
||||
continue
|
||||
src_name = item.filename
|
||||
item.filename = filename
|
||||
new_zfile.writestr(item,zip_file.read(src_name))
|
||||
shutil.move(sfile + '.tmp',sfile)
|
||||
return public.returnMsg(True,'File deleted successfully')
|
||||
|
||||
def write_zip_file(self,args):
|
||||
'''
|
||||
@name 写入压缩包内文件
|
||||
@param args['path'] 压缩包路径
|
||||
@param args['filename'] 文件名
|
||||
@param args['data'] 写入数据
|
||||
@return dict
|
||||
'''
|
||||
|
||||
sfile = args.sfile
|
||||
filename = args.filename
|
||||
data = args.data
|
||||
if not os.path.exists(sfile):
|
||||
return public.returnMsg(False,'FILE_NOT_EXISTS')
|
||||
|
||||
with zipfile.ZipFile(sfile,'r') as zip_file:
|
||||
with zipfile.ZipFile(sfile + '.tmp','w',zipfile.ZIP_DEFLATED) as new_zfile:
|
||||
for item in zip_file.infolist():
|
||||
z_filename = self.__get_zip_filename(item)
|
||||
if z_filename == filename:
|
||||
continue
|
||||
|
||||
new_zfile.writestr(item,zip_file.read(item.filename))
|
||||
new_zfile.writestr(filename, data=data, compress_type=zipfile.ZIP_DEFLATED)
|
||||
|
||||
shutil.move(sfile + '.tmp',sfile)
|
||||
return public.returnMsg(True,'File written successfully')
|
||||
|
||||
|
||||
def extract_byfiles(self,args):
|
||||
"""
|
||||
@name 解压部分文件
|
||||
@param args['path'] 压缩包路径
|
||||
@param args['extract_path'] 解压路径
|
||||
@param args['filenames'] 文件名列表,数组格式
|
||||
"""
|
||||
|
||||
zip_path = ''
|
||||
if 'zip_path' in args: zip_path = args.zip_path
|
||||
sfile = args.sfile
|
||||
filenames = args.filenames
|
||||
extract_path = args.extract_path
|
||||
if not os.path.exists(sfile):
|
||||
return public.returnMsg(False,'FILE_NOT_EXISTS')
|
||||
|
||||
if not os.path.exists(extract_path):
|
||||
os.makedirs(extract_path,384)
|
||||
|
||||
tmp_path = '{}/tmp/{}'.format(public.get_soft_path(),public.md5(public.GetRandomString(32)))
|
||||
if not os.path.exists(tmp_path):
|
||||
os.makedirs(tmp_path,384)
|
||||
|
||||
with zipfile.ZipFile(sfile) as zip_file:
|
||||
try:
|
||||
m_list = {}
|
||||
for item in zip_file.infolist():
|
||||
filename = self.__get_zip_filename(item)
|
||||
|
||||
if filename in filenames:
|
||||
spath = os.path.join(tmp_path,filename).strip('/')
|
||||
if item.is_dir():
|
||||
m_list[spath] = []
|
||||
else:
|
||||
if not 'other' in m_list:
|
||||
m_list['other'] = []
|
||||
|
||||
dir_key = os.path.dirname(spath)
|
||||
info = {'src':spath,'dst':'{}/{}'.format(extract_path,filename.strip('/'))}
|
||||
if zip_path:
|
||||
info['dst'] = '{}/{}'.format(extract_path,filename.replace(zip_path,'').strip('/'))
|
||||
|
||||
s_path = os.path.dirname(info['dst'])
|
||||
if not os.path.exists(s_path): os.makedirs(s_path,384)
|
||||
|
||||
if dir_key in m_list:
|
||||
m_list[dir_key].append(info)
|
||||
else:
|
||||
m_list['other'].append(info)
|
||||
|
||||
item.filename = filename
|
||||
zip_file.extract(item,tmp_path)
|
||||
|
||||
for key in m_list:
|
||||
try:
|
||||
for info in m_list[key]:
|
||||
if os.getenv('BT_PANEL'):
|
||||
shutil.copyfile(info['src'],info['dst'])
|
||||
else:
|
||||
shutil.copyfile('/' + info['src'],'/' + info['dst'])
|
||||
except:
|
||||
pass
|
||||
|
||||
shutil.rmtree(tmp_path, True)
|
||||
except:
|
||||
return public.returnMsg(False,'Decompression failed,error:' + public.get_error_info())
|
||||
return public.returnMsg(True,'The file was decompressed successfully')
|
||||
|
||||
def add_zip_file(self,args):
|
||||
'''
|
||||
@name 添加文件到压缩包
|
||||
@param args['r_path'] 跟路径
|
||||
@param args['filename'] 文件名
|
||||
@param args['f_list'] 写入数据
|
||||
@return dict
|
||||
'''
|
||||
|
||||
sfile = args.sfile
|
||||
r_path = args.r_path
|
||||
f_list = args.f_list
|
||||
if not os.path.exists(sfile):
|
||||
return public.returnMsg(False,'FILE_NOT_EXISTS')
|
||||
|
||||
#追加原路径
|
||||
src_list = {}
|
||||
for fname in f_list:
|
||||
if os.path.isdir(fname):
|
||||
s_list = []
|
||||
public.get_file_list(fname,s_list)
|
||||
|
||||
for f in s_list:
|
||||
if os.path.isdir(f):
|
||||
continue
|
||||
src_file = '{}/{}{}'.format(r_path,os.path.basename(fname),f.replace(fname,''))
|
||||
src_list[src_file] = f
|
||||
else:
|
||||
src_file = r_path + '/' + os.path.basename(fname)
|
||||
src_list[src_file] = fname
|
||||
|
||||
tmp_path = sfile + '.tmp'
|
||||
if os.path.exists(tmp_path):
|
||||
os.remove(tmp_path)
|
||||
|
||||
with zipfile.ZipFile(sfile,'r') as zip_file:
|
||||
with zipfile.ZipFile(tmp_path,'w',zipfile.ZIP_DEFLATED) as new_zfile:
|
||||
try:
|
||||
#过滤旧文件
|
||||
for item in zip_file.namelist():
|
||||
if item in src_list:
|
||||
continue
|
||||
new_zfile.writestr(item,zip_file.read(item))
|
||||
|
||||
#追加新文件
|
||||
for src_file in src_list:
|
||||
new_zfile.write(src_list[src_file],src_file)
|
||||
except:
|
||||
return public.returnMsg(False,'Failed add file,error:' + public.get_error_info())
|
||||
|
||||
shutil.move(tmp_path,sfile)
|
||||
return public.returnMsg(True,'Compressed package file modified successfully')
|
||||
|
||||
|
||||
# def __get_zip_filename(self,item):
|
||||
# '''
|
||||
# @name 获取压缩包文件名
|
||||
# @param item 压缩包文件对象
|
||||
# @return string
|
||||
# '''
|
||||
# path = item.filename
|
||||
# try:
|
||||
# path_name = path.decode('utf-8')
|
||||
# except:
|
||||
# path_name = path.encode('cp437').decode('gbk')
|
||||
# path_name = path_name.encode('utf-8').decode('utf-8')
|
||||
# return path_name
|
||||
|
||||
|
||||
|
||||
|
||||
def __get_zip_filename(self,item):
|
||||
'''
|
||||
@name 获取压缩包文件名
|
||||
@param item 压缩包文件对象
|
||||
@return string
|
||||
'''
|
||||
|
||||
|
||||
filename = item.filename
|
||||
try:
|
||||
filename = item.filename.encode('cp437').decode('gbk')
|
||||
except:pass
|
||||
return filename
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user