# coding:utf-8

# ---------------------------------------------------------------------------------
# MW-Linux面板
# ---------------------------------------------------------------------------------
# copyright (c) 2018-∞(https://github.com/midoks/mdserver-web) All rights reserved.
# ---------------------------------------------------------------------------------
# Author: midoks <midoks@163.com>
# ---------------------------------------------------------------------------------

import os
import pwd
import time
import shutil
import json
import base64

import core.mw as mw
import thisdb

def uploadSegment(path,name,size,start,dir_mode,file_mode,b64_data,upload_files):
    if not mw.fileNameCheck(name):
        return mw.returnData(False, '文件名中不能包含特殊字符!')

    if path == '/':
        return mw.returnData(False, '不能直接上传文件到系统根目录!')

    if name.find('./') != -1 or path.find('./') != -1:
        return mw.returnData(False, '错误的参数')

    if not os.path.exists(path):
        os.makedirs(path, 493)
        if not dir_mode != '' or not file_mode != '':
            mw.setMode(path)

    save_path = os.path.join(path, name + '.' + str(int(size)) + '.upload.tmp')
    d_size = 0
    if os.path.exists(save_path):
        d_size = os.path.getsize(save_path)

    if d_size != int(start):
        return mw.returnData(True, 'size', d_size)

    f = open(save_path, 'ab')
    if b64_data == '1':
        b64_data = base64.b64decode(b64_data)
        f.write(b64_data)
    else:
        for tmp_f in upload_files:
            f.write(tmp_f.read())

    f.close()
    f_size = os.path.getsize(save_path)
    if f_size != int(size):
        return mw.returnData(True, 'size', f_size)

    new_name = os.path.join(path, name)
    if os.path.exists(new_name):
        if new_name.find('.user.ini') != -1:
            mw.execShell("chattr -i " + new_name)
        try:
            os.remove(new_name)
        except:
            mw.execShell("rm -f %s" % new_name)

    os.renames(save_path, new_name)

    if dir_mode != '' and dir_mode != '':
        mode_tmp1 = dir_mode.split(',')
        mw.setMode(path, mode_tmp1[0])
        mw.setOwn(path, mode_tmp1[1])
        mode_tmp2 = file_mode.split(',')
        mw.setMode(new_name, mode_tmp2[0])
        mw.setOwn(new_name, mode_tmp2[1])
    else:
        setMode(new_name)

    msg = mw.getInfo('上传文件[{1}] 到 [{2}]成功!', (new_name, path))
    mw.writeLog('文件管理', msg)
    return mw.returnData(True, '上传成功!', f_size)


def mvFile(sfile, dfile):
    if not checkFileName(dfile):
        return mw.returnData(False, '文件名中不能包含特殊字符!')
    if not os.path.exists(sfile):
        return mw.returnData(False, '指定文件不存在!')

    if not checkDir(sfile):
        return mw.returnData(False, 'FILE_DANGER')


    try:
        pass
    except Exception as e:
        raise e

    try:
        shutil.move(sfile, dfile)
        msg = mw.getInfo('移动或重名命文件[{1}]到[{2}]成功!', (sfile, dfile,))
        mw.writeLog('文件管理', msg)
        return mw.returnData(True, '移动或重名命文件成功!')
    except Exception as e:
        return mw.returnData(False, '移动或重名命文件失败!'+str(e))

def unzip(sfile, dfile, stype, path):
    if dfile == '' or dfile == '/':
        return mw.returnData(False, '不能在根目录解压!')

    if not os.path.exists(sfile):
        return mw.returnData(False, '指定文件不存在!')

    try:
        tmps = mw.getPanelDir() + '/logs/panel_exec.log'
        if stype == 'zip':
            mw.execShell("cd " + path + " && unzip -o -d '" + dfile +"' '" + sfile + "' > " + tmps + " 2>&1 &")
        else:
            sfiles = ''
            for sfile in sfile.split(','):
                if not sfile:
                    continue
                sfiles += " '" + sfile + "'"
            mw.execShell("cd " + path + " && tar -zxvf " + sfiles +" -C " + dfile + " > " + tmps + " 2>&1 &")

        if os.path.exists(dfile):
            if dfile.startswith("/www/wwwroot"):
                setFileAccept(dfile)
        mw.writeLog("文件管理", '文件[{1}]解压[{2}]成功!', (sfile, dfile))
        return mw.returnData(True, '文件解压成功!')
    except:
        return mw.returnData(False, '文件解压失败!')

def uncompress(sfile, dfile, path):
    if dfile == '' or dfile == '/':
        return mw.returnData(False, '不能在根目录解压!')

    if not os.path.exists(sfile):
        return mw.returnData(False, '指定文件不存在!')

    filename = os.path.basename(sfile)
    extension = os.path.splitext(filename)[-1]
    extension = extension.strip('.')

    tar_gz = 'tar.gz'
    tar_gz_len = len(tar_gz)
    suffix_gz = sfile[-tar_gz_len:]
    if suffix_gz == tar_gz:
        extension = suffix_gz

    if not extension in ['tar.gz', 'gz', 'zip', 'rar', '7z', 'xz','bz2']:
        return mw.returnData(False, '现在仅支持gz,zip,rar,7z,xz,bz2格式解压!')

    if extension == 'rar' and not mw.checkBinExist('rar'):
        return mw.returnData(False, 'rar解压命令不存在，请安装!')
    if extension == '7z' and not mw.checkBinExist('7z'):
        return mw.returnData(False, '7z解压命令不存在，请安装!')


    cmd = "cd " + path + " "
    try:
        tmps = mw.getPanelDir() + '/logs/panel_exec.log'
        if extension == 'zip':
            cmd += "&& unzip -o -d '" + dfile + "' '" + sfile + "' > " + tmps + " 2>&1 &"
            mw.execShell(cmd)
        elif extension == 'tar.gz':
            cmd += "&& tar -zxvf " + sfile + " -C " + dfile + " > " + tmps + " 2>&1 &"
            mw.execShell(cmd)
        elif extension == 'gz':
            cmd += "&& gunzip -k " + sfile + " > " + tmps + " 2>&1 &"
            mw.execShell(cmd)
        elif extension == 'rar':
            cmd += "&& unrar x " + sfile + " " + dfile + " > " + tmps + " 2>&1 &"
            mw.execShell(cmd)
        elif extension == '7z':
            cmd += "&& 7z x " + sfile + " -r -o" + dfile + " > " + tmps + " 2>&1 &"
            mw.execShell(cmd)
        elif extension == 'xz':
            cmd += "&& tar -Jxvf " + sfile + " -C " + dfile + " > " + tmps + " 2>&1 &"
            mw.execShell(cmd)
        elif extension == 'bz2':
            cmd += "&& tar -xjvf " + sfile + " -C " + dfile + " > " + tmps + " 2>&1 &"
            mw.execShell(cmd)

        if os.path.exists(dfile):
            if dfile.startswith("/www/wwwroot"):
                setFileAccept(dfile)
        mw.writeLog("文件管理", '文件[{1}]解压[{2}]成功!', (sfile, dfile,))
        return mw.returnData(True, '文件解压成功!')
    except Exception as e:
        return mw.returnData(False, '文件解压失败!:' + str(e))

def setBatchData(path, stype, access, user, data):
    from admin import session
    if stype == '1' or stype == '2':
        session['selected'] = {
            'path': path,
            'type': stype,
            'access': access,
            'user': user,
            'data': data
        }
        return mw.returnData(True, '标记成功,请在目标目录点击粘贴所有按钮!')
    elif stype == '3':
        for key in json.loads(data):
            try:
                filename = path + '/' + key
                if not checkDir(filename):
                    return mw.returnData(False, 'FILE_DANGER')
                os.system('chmod -R ' + access + " '" + filename + "'")
                os.system('chown -R ' + user + ':' + user + " '" + filename + "'")
            except:
                continue
        mw.writeLog('文件管理', '批量设置权限成功!')
        return mw.returnData(True, '批量设置权限成功!')
    else:
        recycle_bin = thisdb.getOption('recycle_bin')
        is_recycle = False
        if recycle_bin == 'open':
            is_recycle = True
        data = json.loads(data)
        l = len(data)
        i = 0
        for key in data:
            try:
                filename = path + '/' + key
                topath = filename
                if not os.path.exists(filename):
                    continue

                i += 1
                mw.writeSpeed(key, i, l)
                if os.path.isdir(filename):
                    if not checkDir(filename):
                        return mw.returnData(False, '请不要花样作死!')
                    if is_recycle:
                        mvRecycleBin(topath)
                    else:
                        shutil.rmtree(filename)
                else:
                    if key == '.user.ini':
                        os.system('which chattr && chattr -i ' + filename)
                    if is_recycle:
                        mvRecycleBin(topath)
                    else:
                        os.remove(filename)
            except:
                continue
            mw.writeSpeed(None, 0, 0)
        mw.writeLog('文件管理', '批量删除成功!')
        return mw.returnData(True, '批量删除成功！')

def batchPaste(path, stype):
    from admin import session
    if not checkDir(path):
        return mw.returnData(False, '请不要花样作死!')
    i = 0
    myfiles = json.loads(session['selected']['data'])
    l = len(myfiles)
    if stype == '1':
        for key in myfiles:
            i += 1
            mw.writeSpeed(key, i, l)
            try:

                sfile = session['selected'][
                    'path'] + '/' + key
                dfile = path + '/' + key

                if os.path.isdir(sfile):
                    shutil.copytree(sfile, dfile)
                else:
                    shutil.copyfile(sfile, dfile)
                stat = os.stat(sfile)
                os.chown(dfile, stat.st_uid, stat.st_gid)
            except:
                continue
        msg = mw.getInfo('从[{1}]批量复制到[{2}]成功',(session['selected']['path'], path,))
        mw.writeLog('文件管理', msg)
    else:
        for key in myfiles:
            try:
                i += 1
                mw.writeSpeed(key, i, l)

                sfile = session['selected'][
                    'path'] + '/' + key
                dfile = path + '/' + key

                shutil.move(sfile, dfile)
            except:
                continue
        msg = mw.getInfo('从[{1}]批量移动到[{2}]成功',(session['selected']['path'], path,))
        mw.writeLog('文件管理', msg)
    mw.writeSpeed(None, 0, 0)
    errorCount = len(myfiles) - i
    del(session['selected'])
    msg = mw.getInfo('批量操作成功[{1}],失败[{2}]', (str(i), str(errorCount)))
    return mw.returnData(True, msg)


def zip(sfile, dfile, stype, path):
    tmps = mw.getPanelDir() + '/logs/panel_exec.log'
    if sfile.find(',') == -1:
        if stype == 'zip':
            mw.execShell("cd '" + path + "' && zip '" + dfile + "' -r '" + sfile + "' > " + tmps + " 2>&1")
        elif stype == '7z':
            if not mw.checkBinExist('7z'):
                return mw.returnData(False, '7z压缩命令不存在，请安装!')
            mw.execShell("cd '" + path + "' && 7z a '" + dfile + "' -r '" + sfile + "' > " + tmps + " 2>&1")
        elif stype == 'tar_gz':
            mw.execShell("cd '" + path + "' && tar -zcvf '" + dfile + "' " + sfile + " > " + tmps + " 2>&1")
        elif stype == 'xz':
            # if not mw.checkBinExist('xz'):
            #     return mw.returnData(False, 'xz压缩命令不存在，请安装!')
            # dfile = dfile.strip(".xz")
            # cmd = "cd '" + path + "' && tar -cvf '" + dfile + ".tar' " + sfile + " && xz -z '" + dfile + ".tar' > " + tmps + " 2>&1 &"
            cmd = "cd '" + path + "' && tar -cJf '" + dfile + "' " + sfile + " > " + tmps + " 2>&1"
            # print(cmd)
            mw.execShell(cmd)
        elif stype == 'rar':
            if not mw.checkBinExist('rar'):
                return mw.returnData(False, 'rar压缩命令不存在，请安装!')
            mw.execShell("cd '" + path + "' && rar a '" + dfile + "' '" + sfile + "' > " + tmps + " 2>&1")
        elif stype == 'bz2':
            mw.execShell("cd '" + path + "' && tar -cjvf '" + dfile + "' " + sfile + " > " + tmps + " 2>&1")
        else:
            return mw.returnData(False, '未知压缩格式')
        mw.writeLog("文件管理", '文件[{1}]压缩[{2}]成功!', (sfile, dfile))
    else:
        sfiles = ''
        for sfile in sfile.split(','):
            if not sfile:
                continue
            if not os.path.exists(sfile):
                return mw.returnData(False, '指定文件不存在!')
            
            sfiles += " '" + sfile.replace(path+'/','') + "'"

        if stype == 'zip':
            mw.execShell("cd '" + path + "' && zip '" + dfile + "' -r " + sfiles + " > " + tmps + " 2>&1")
        elif stype == '7z':
            if not mw.checkBinExist('7z'):
                return mw.returnData(False, '7z压缩命令不存在，请安装!')
            mw.execShell("cd '" + path + "' && 7z a '" + dfile + "' -r " + sfiles + " > " + tmps + " 2>&1")
        elif stype == 'tar_gz':
            mw.execShell("cd '" + path + "' && tar -zcvf '" + dfile + "' " + sfiles + " > " + tmps + " 2>&1")
        elif stype == 'rar':
            if not mw.checkBinExist('rar'):
                return mw.returnData(False, 'rar压缩命令不存在，请安装!')
            mw.execShell("cd '" + path + "' && rar a '" + dfile + "' " + sfiles + " > " + tmps + " 2>&1")
        elif stype == 'bz2':
            mw.execShell("cd '" + path + "' && tar -cjvf '" + dfile + "' " + sfiles + " > " + tmps + " 2>&1")
        else:
            return mw.returnData(False, '未知压缩格式')

        mw.writeLog("文件管理", '文件[{1}]压缩[{2}]成功!', (sfiles, dfile))
    setFileAccept(dfile)
    return mw.returnData(True, '文件压缩成功!')

def getAccess(filename):
    data = {}
    try:
        stat = os.stat(filename)
        data['chmod'] = str(oct(stat.st_mode)[-3:])
        data['chown'] = pwd.getpwuid(stat.st_uid).pw_name
    except:
        data['chmod'] = 755
        data['chown'] = 'www'
    return data

def copyDir(src_file, dst_file):
    if not os.path.exists(src_file):
        return mw.returnData(False, '指定目录不存在!')

    if os.path.exists(dst_file):
        return mw.returnData(False, '指定目录已存在!')

    try:
        shutil.copytree(src_file, dst_file)
        stat = os.stat(src_file)
        os.chown(dst_file, stat.st_uid, stat.st_gid)
        msg = mw.getInfo('复制目录[{1}]到[{2}]成功!', (src_file, dst_file))
        mw.writeLog('文件管理', msg)
        return mw.returnData(True, '目录复制成功!')
    except:
        return mw.returnData(False, '目录复制失败!')

def copyFile(src_file, dst_file):
    if src_file == dst_file:
        return mw.returnJson(False, '源与目的一致!')

    if not os.path.exists(src_file):
        return mw.returnJson(False, '指定文件不存在!')

    if os.path.isdir(src_file):
        return copyDir(src_file, dst_file)

    try:
        shutil.copyfile(src_file, dst_file)
        msg = mw.getInfo('复制文件[{1}]到[{2}]成功!', (src_file, dst_file,))
        mw.writeLog('文件管理', msg)
        stat = os.stat(src_file)
        os.chown(dst_file, stat.st_uid, stat.st_gid)
        return mw.returnData(True, '文件复制成功!')
    except:
        return mw.returnData(False, '文件复制失败!')

def setFileAccept(filename):
    auth = 'www:www'
    if mw.getOs() == 'darwin':
        user = mw.execShell("who | sed -n '2, 1p' |awk '{print $1}'")[0].strip()
        auth = user + ':staff'
    os.system('chown -R ' + auth + ' ' + filename)
    os.system('chmod -R 755 ' + filename)

def createFile(file_path):
    try:
        if not checkFileName(file_path):
            return mw.returnData(False, '文件名中不能包含特殊字符!')
        if os.path.exists(file_path):
            return mw.returnData(False, '指定文件已存在!')
        _path = os.path.dirname(file_path)
        if not os.path.exists(_path):
            os.makedirs(_path)
        open(file_path, 'w+').close()
        setFileAccept(file)
        msg = mw.getInfo('创建文件[{1}]成功!', (file_path,))
        mw.writeLog('文件管理', msg)
        return mw.returnData(True, '文件创建成功!')
    except Exception as e:
        return mw.returnData(True, '文件创建失败:'+str(e))

def createDir(path):
    try:
        if not checkFileName(path):
            return mw.returnData(False, '目录名中不能包含特殊字符!')
        if os.path.exists(path):
            return mw.returnData(False, '指定目录已存在!')
        os.makedirs(path)
        setFileAccept(path)
        msg = mw.getInfo('创建目录[{1}]成功!', (path,))
        mw.writeLog('文件管理', msg)
        return mw.returnData(True, '目录创建成功!')
    except Exception as e:
        print(e)
        return mw.returnData(False, '目录创建失败!')

# 检查敏感目录
def checkDir(path):
    path = path.replace('//', '/')
    if path[-1:] == '/':
        path = path[:-1]

    sense_dir = ('',
        '/',
        '/*',
        '/www',
        '/root',
        '/boot',
        '/bin',
        '/etc',
        '/home',
        '/dev',
        '/sbin',
        '/var',
        '/usr',
        '/tmp',
        '/sys',
        '/proc',
        '/media',
        '/mnt',
        '/opt',
        '/lib',
        '/srv',
        '/selinux',
        '/www/server',
        mw.getRootDir())
    return not path in sense_dir

def getFileBody(path):
    if not os.path.exists(path):
        return mw.returnData(False, '文件不存在', (path,))

    if os.path.getsize(path) > 2097152:
        return mw.returnData(False, '不能在线编辑大于2MB的文件!')

    if os.path.isdir(path):
        return mw.returnData(False, '这不是一个文件!')

    fp = open(path, 'rb')
    data = {}
    data['status'] = True
    if fp:
        srcBody = fp.read()
        fp.close()

        encoding_list = ['utf-8', 'GBK', 'BIG5']
        for el in encoding_list:
            try:
                data['encoding'] = el
                data['data'] = srcBody.decode(data['encoding'])
                break
            except Exception as ex:
                if el == 'BIG5':
                    return mw.returnData(False, '文件编码不被兼容，无法正确读取文件!' + str(ex))
    else:
        return mw.returnData(False, '文件未正常打开!')
    return mw.returnData(True, 'OK', data)

def saveBody(path, data, encoding):
    if not os.path.exists(path):
        return mw.returnData(False, '文件不存在')
    try:
        if encoding == 'ascii':
            encoding = 'utf-8'

        data = data.encode(encoding, errors='ignore').decode(encoding)
        fp = open(path, 'w+', encoding=encoding)
        fp.write(data)
        fp.close()

        if path.find("web_conf") > 0:
            mw.restartWeb()
        mw.writeLog('文件管理', '文件[{1}]保存成功', (path,))
        return mw.returnData(True, '文件保存成功')
    except Exception as ex:
        return mw.returnData(False, '文件保存错误:' + str(ex))


def sortFileList(path, ftype = 'mtime', sort = 'desc'):
    flist = os.listdir(path)
    if ftype == 'mtime':
        try:
            if sort == 'desc':
                flist = sorted(flist, key=lambda f: os.path.getmtime(os.path.join(path,f)), reverse=True)
            if sort == 'asc':
                flist = sorted(flist, key=lambda f: os.path.getmtime(os.path.join(path,f)), reverse=False)
        except Exception as e:
            if sort == 'desc':
                flist = sorted(flist, key=lambda f: os.path.getctime(os.path.join(path,f)), reverse=True)
            if sort == 'asc':
                flist = sorted(flist, key=lambda f: os.path.getctime(os.path.join(path,f)), reverse=False)
        

    if ftype == 'size':
        if sort == 'desc':
            flist = sorted(flist, key=lambda f: os.path.getsize(os.path.join(path,f)), reverse=True)
        if sort == 'asc':
            flist = sorted(flist, key=lambda f: os.path.getsize(os.path.join(path,f)), reverse=False)

    if ftype == 'fname':
        if sort == 'desc':
            flist = sorted(flist, key=lambda f: os.path.join(path,f), reverse=True)
        if sort == 'asc':
            flist = sorted(flist, key=lambda f: os.path.join(path,f), reverse=False)
    return flist

def sortAllFileList(path, ftype = 'mtime', sort = 'desc', search = '',limit = 3000):
    count = 0
    flist = []
    for d_list in os.walk(path):
        if count >= limit:
            break

        for d in d_list[1]:
            if count >= limit:
                break
            if d.lower().find(search) != -1:
                filename = d_list[0] + '/' + d
                if not os.path.exists(filename):
                    continue
                count += 1
                flist.append(filename)

        for f in d_list[2]:
            if count >= limit:
                break

            if f.lower().find(search) != -1:
                filename = d_list[0] + '/' + f
                if not os.path.exists(filename):
                    continue
                count += 1
                flist.append(filename)

    if ftype == 'mtime':
        if sort == 'desc':
            flist = sorted(flist, key=lambda f: os.path.getmtime(f), reverse=True)
        if sort == 'asc':
            flist = sorted(flist, key=lambda f: os.path.getmtime(f), reverse=False)

    if ftype == 'size':
        if sort == 'desc':
            flist = sorted(flist, key=lambda f: os.path.getsize(f), reverse=True)
        if sort == 'asc':
            flist = sorted(flist, key=lambda f: os.path.getsize(f), reverse=False)
    return flist

def getAllDirList(path, page=1, size=10, order = '', search=None):
    if page < 1:
        page == 1

    data = {}
    dirnames = []
    filenames = []
    
    max_limit = 3000
    order_split = order.split(' ')
    if len(order_split) < 2:
        flist = sortAllFileList(path, order_split[0],'',search, max_limit)
    else:
        flist = sortAllFileList(path, order_split[0], order_split[1], search, max_limit)

    count = len(flist)
    start = (page - 1) * size
    end = start + size
    if end > count:
        end = count

    plist = flist[start:end]
    for dst_file in plist:
        if not os.path.exists(dst_file):
            continue
        stat = mw.getFileStatsDesc(dst_file, path)
        if os.path.isdir(dst_file):
            dirnames.append(stat)
        else:
            filenames.append(stat)

    data['count'] = count
    data['dir'] = dirnames
    data['files'] = filenames
    data['path'] = path.replace('//', '/')
    return data

def getDirList(path, page=1, size=10, order = '', search=None):
    if page < 1:
        page == 1

    data = {}
    dirnames = []
    filenames = []

    count = getCount(path, search)
    order_split = order.strip().split(' ')
    if len(order_split) < 2:
        flist = sortFileList(path, order_split[0], '')
    else:
        flist = sortFileList(path, order_split[0], order_split[1])

    start = (page - 1) * size
    end = start + size
    if end > count:
        end = count

    
    if search or search != '':
        nlist = []
        for f in flist:
            if f.lower().find(search) == -1:
                continue
            nlist.append(f)
        plist = nlist[start:end]
    else:
        plist = flist[start:end]
    
    for filename in plist:
        abs_file = path + '/' + filename
        if not os.path.exists(abs_file):
            continue

        stats = mw.getFileStatsDesc(abs_file, path)
        if os.path.isdir(abs_file):
            dirnames.append(stats)
        else:
            filenames.append(stats)

    data['count'] = count
    data['dir'] = dirnames
    data['files'] = filenames
    data['path'] = path.replace('//', '/')
    return data

# 检测文件名
def checkFileName(filename):
    nots = ['\\', '&', '*', '|', ';']
    if filename.find('/') != -1:
        filename = filename.split('/')[-1]
    for n in nots:
        if n in filename:
            return False
    return True


# 获取目录大小
def getDirSize(filePath, size=0):
    for root, dirs, files in os.walk(filePath):
        for f in files:
            try:
                size += os.path.getsize(os.path.join(root, f))
            except Exception as e:
                pass
            # print(f)
    return size

# 获取目录大小(bash)
def getDirSizeByBash(path):
    tmp = mw.execShell('du -sh ' + path)
    return tmp[0].split()[0].lower()

# 计算文件数量
def getCount(path, search = None):
    i = 0
    for name in os.listdir(path):
        if name == '.' or name == '..':
            continue
        if search:
            if name.lower().find(search) == -1:
                continue
        i += 1
    return i

# 获取文件权限
def getAccess(fname):
    data = {}
    try:
        stat = os.stat(fname)
        data['chmod'] = str(oct(stat.st_mode)[-3:])
        data['chown'] = pwd.getpwuid(stat.st_uid).pw_name
    except Exception as e:
        # print(e)
        data['chmod'] = 755
        data['chown'] = 'www'
    return data

def setFileAccess(filename,user,access):
    sall = '-R'
    try:
        if not checkDir(filename):
            return mw.returnData(False, '请不要花样作死')

        if not os.path.exists(filename):
            return mw.returnData(False, '指定文件不存在!')

        os.system('chmod ' + sall + ' ' + access + " '" + filename + "'")
        os.system('chown ' + sall + ' ' + user + ':' + user + " '" + filename + "'")
        msg = mw.getInfo('设置[{1}]权限为[{2}]所有者为[{3}]', (filename, access, user,))
        mw.writeLog('文件管理', msg)
        return mw.returnData(True, '设置成功!')
    except Exception as e:
        return mw.returnData(False, '设置失败!'+str(e))

def getSysUserList():
    pwd_file = '/etc/passwd'
    if os.path.exists(pwd_file):
        content = mw.readFile(pwd_file)
        clist = content.split('\n')
        sys_users = []
        for line in clist:
            if line.find(":")<0:
                continue
            lines = line.split(":",1)
            sys_users.append(lines[0])
        return sys_users
    return ['root','mysql','www']

def fileDelete(path):
    if not os.path.exists(path):
        return mw.returnData(False, '指定文件不存在!')

    # 检查是否为.user.ini
    if path.find('.user.ini') >= 0:
        cmd = "which chattr && chattr -i {0}".format(path)
        mw.execShell(cmd)

    try:
        recycle_bin = thisdb.getOption('recycle_bin')
        if recycle_bin == 'open':
            if mvRecycleBin(path):
                return mw.returnData(True, '已将文件移动到回收站!')
            return mw.returnData(False, '移动到回收站失败!') 
        os.remove(path)
        mw.writeLog('文件管理', mw.getInfo('删除文件[{1}]成功!', (path,)))
        return mw.returnData(True, '删除文件成功!')
    except Exception as e:
        return mw.returnData(False, '删除文件失败!')

def dirDelete(path):
    if not os.path.exists(path):
        return mw.returnData(False, '指定文件不存在!')

    # 检查是否为.user.ini
    if path.find('.user.ini'):
        os.system("which chattr && chattr -i '" + path + "'")
    try:
        recycle_bin = thisdb.getOption('recycle_bin')
        if recycle_bin == 'open':
            if mvRecycleBin(path):
                return mw.returnData(True, '已将文件移动到回收站!')
        mw.execShell('rm -rf ' + path)
        mw.writeLog('文件管理', '删除{1}成功！', (path,))
        return mw.returnData(True, '删除文件成功!')
    except:
        return mw.returnData(False, '删除文件失败!')

# 关闭
def toggleRecycleBin():
    recycle_bin = thisdb.getOption('recycle_bin')
    if recycle_bin == 'open':
        thisdb.setOption('recycle_bin','close')
        mw.writeLog('文件管理', '已关闭回收站功能!')
        return mw.returnData(True, '已关闭回收站功能!')
    else:
        thisdb.setOption('recycle_bin','open')
        mw.writeLog('文件管理', '已开启回收站功能!')
        return mw.returnData(True, '已开启回收站功能!')

def getRecycleBin():
    rb_dir = mw.getRecycleBinDir()
    recycle_bin = thisdb.getOption('recycle_bin')

    data = {}
    data['dirs'] = []
    data['files'] = []
    data['status'] = False
    if recycle_bin == 'open': 
        data['status'] = True
    
    for file in os.listdir(rb_dir):
        try:
            tmp = {}
            fname = rb_dir+'/'+ file
            tmp1 = file.split('_mw_')
            tmp2 = tmp1[len(tmp1) - 1].split('_t_')
            tmp['rname'] = file
            tmp['dname'] = file.replace('_mw_', '/').split('_t_')[0]
            tmp['name'] = tmp2[0]
            tmp['time'] = int(float(tmp2[1]))
            if os.path.islink(fname):
                filePath = os.readlink(fname)
                link = ' -> ' + filePath
                if os.path.exists(filePath):
                    tmp['size'] = os.path.getsize(filePath)
                else:
                    tmp['size'] = 0
            else:
                tmp['size'] = os.path.getsize(fname)
            if os.path.isdir(fname):
                data['dirs'].append(tmp)
            else:
                data['files'].append(tmp)
        except Exception as e:
            continue

    return mw.returnJson(True, 'OK', data)

def delRecycleBin(path):
    rb_dir = mw.getRecycleBinDir()
    rb_file = rb_dir + '/' + path
    if os.path.isdir(rb_file):
        import shutil
        shutil.rmtree(rb_file)
    else:
        os.remove(rb_file)

    tfile = path.replace('_mw_', '/').split('_t_')[0]
    msg = mw.getInfo('已彻底从回收站删除[{1}]!', (tfile,))
    mw.writeLog('文件管理', msg)
    return mw.returnJson(True, msg)

# 移动到回收站
def mvRecycleBin(path):
    rb_dir = mw.getRecycleBinDir()
    rb_file = rb_dir + '/' + path.replace('/', '_mw_') + '_t_' + str(time.time())
    try:
        import shutil
        shutil.move(path, rb_file)
        mw.writeLog('文件管理', mw.getInfo('移动[{1}]到回收站成功!', (path,)))
        return True
    except Exception as e:
        mw.writeLog('文件管理', mw.getInfo('移动[{1}]到回收站失败!', (path,)))
        return False

# 回收站文件恢复
def reRecycleBin(path):
    rb_dir = mw.getRecycleBinDir()
    dst_file = path.replace('_mw_', '/').split('_t_')[0]
    try:
        import shutil
        shutil.move(rb_dir + '/' + path, dst_file)
        msg = mw.getInfo('移动文件[{1}]到回收站成功!', (dst_file,))
        mw.writeLog('文件管理', msg)
        return mw.returnData(True, '恢复成功!')
    except Exception as e:
        msg = mw.getInfo('从回收站恢复[{1}]失败!', (dst_file,))
        mw.writeLog('文件管理', msg)
        return mw.returnData(False, '恢复失败!')


def closeRecycleBin():
    rb_dir = mw.getRecycleBinDir()
    mw.execShell('which chattr && chattr -R -i ' + rb_dir)
    rlist = os.listdir(rb_dir)
    i = 0
    l = len(rlist)
    for name in rlist:
        i += 1
        path = rb_dir + '/' + name
        mw.writeSpeed(name, i, l)
        if os.path.isdir(path):
            shutil.rmtree(path)
        else:
            os.remove(path)
    mw.writeSpeed(None, 0, 0)
    mw.writeLog('文件管理', '已清空回收站!')
    return mw.returnJson(True, '已清空回收站!')


# 设置文件和目录权限
def setMode(path):
    s_path = os.path.dirname(path)
    p_stat = os.stat(s_path)
    os.chown(path, p_stat.st_uid, p_stat.st_gid)
    os.chmod(path, p_stat.st_mode)


def closeLogs():
    log_file = mw.getLogsDir()
    os.system('rm -rf ' + log_file + '/*')
    mw.opWeb('reload')
    # os.system('kill -USR1 `cat ' + mw.getServerDir() +'/openresty/nginx/logs/nginx.pid`')
    mw.writeLog('文件管理', '网站日志已被清空!')
    tmp = getDirSizeByBash(log_file)
    return mw.returnData(True, tmp)
