#!/usr/bin/env python3
"""
检测 SQLite 数据库锁定情况并找出锁定进程
"""

import os
import subprocess
import sys
import ctypes
from ctypes import wintypes

# 定义 Windows API 常量
FILE_SHARE_READ = 0x00000001
FILE_SHARE_WRITE = 0x00000002
FILE_SHARE_DELETE = 0x00000004
OPEN_EXISTING = 3
GENERIC_READ = 0x80000000
GENERIC_WRITE = 0x40000000
ERROR_SHARING_VIOLATION = 32
ERROR_LOCK_VIOLATION = 33

# 定义 Windows API 结构
class SECURITY_ATTRIBUTES(ctypes.Structure):
    _fields_ = [
        ("nLength", wintypes.DWORD),
        ("lpSecurityDescriptor", wintypes.LPVOID),
        ("bInheritHandle", wintypes.BOOL)
    ]

# 加载 Windows API 函数
kernel32 = ctypes.WinDLL('kernel32', use_last_error=True)
CreateFile = kernel32.CreateFileW
CreateFile.argtypes = [
    wintypes.LPCWSTR,  # lpFileName
    wintypes.DWORD,     # dwDesiredAccess
    wintypes.DWORD,     # dwShareMode
    ctypes.POINTER(SECURITY_ATTRIBUTES),  # lpSecurityAttributes
    wintypes.DWORD,     # dwCreationDisposition
    wintypes.DWORD,     # dwFlagsAndAttributes
    wintypes.HANDLE     # hTemplateFile
]
CreateFile.restype = wintypes.HANDLE

CloseHandle = kernel32.CloseHandle
CloseHandle.argtypes = [wintypes.HANDLE]
CloseHandle.restype = wintypes.BOOL


def check_db_lock(db_path):
    """
    检查数据库文件是否被锁定
    返回 True 如果被锁定，False 否则
    """
    # 构建安全属性
    sa = SECURITY_ATTRIBUTES()
    sa.nLength = ctypes.sizeof(SECURITY_ATTRIBUTES)
    sa.lpSecurityDescriptor = None
    sa.bInheritHandle = False
    
    # 尝试以独占方式打开文件
    hFile = CreateFile(
        db_path,
        GENERIC_READ | GENERIC_WRITE,
        0,  # 不共享
        ctypes.byref(sa),
        OPEN_EXISTING,
        0,
        None
    )
    
    if hFile == wintypes.HANDLE(-1):
        error_code = ctypes.get_last_error()
        if error_code == ERROR_SHARING_VIOLATION:
            print(f"数据库文件 {db_path} 被锁定（共享冲突）")
            return True
        elif error_code == ERROR_LOCK_VIOLATION:
            print(f"数据库文件 {db_path} 被锁定（锁定冲突）")
            return True
        else:
            print(f"打开文件失败，错误码: {error_code}")
            return False
    else:
        # 成功打开，文件未被锁定
        CloseHandle(hFile)
        print(f"数据库文件 {db_path} 未被锁定")
        return False


def find_locking_processes(file_path):
    """
    查找锁定指定文件的进程
    使用 PowerShell 命令来查找锁定进程
    """
    try:
        # 构建 PowerShell 命令
        ps_command = f"Get-Process | ForEach-Object {{ $process = $_; try {{ $_.Modules | ForEach-Object {{ if ($_.FileName -eq '{file_path.replace(chr(92), chr(92)*2)}') {{ $process.Name + ' (PID: ' + $process.Id + ')' }} }} }} catch {{}} }}"
        
        # 执行 PowerShell 命令
        result = subprocess.run(
            ['powershell', '-Command', ps_command],
            capture_output=True,
            text=True,
            timeout=10
        )
        
        if result.stdout.strip():
            print("锁定文件的进程:")
            print(result.stdout.strip())
        else:
            # 尝试另一种方法
            ps_command2 = f"Handle.exe '{file_path}' 2>&1 | Select-String -Pattern 'PID:'"
            try:
                result2 = subprocess.run(
                    ['powershell', '-Command', ps_command2],
                    capture_output=True,
                    text=True,
                    timeout=10
                )
                if result2.stdout.strip():
                    print("锁定文件的进程 (使用 Handle.exe):")
                    print(result2.stdout.strip())
                else:
                    print("未找到锁定进程，但文件确实被锁定")
            except Exception:
                print("未找到锁定进程，但文件确实被锁定")
                
    except Exception as e:
        print(f"查找锁定进程时出错: {e}")


def main():
    """主函数"""
    print("=== 数据库锁定检测工具 ===")
    
    # 数据库文件路径
    db_path = r"\\ll\D\xtrssvjj\db\dpd.db"
    
    print(f"检查数据库: {db_path}")
    print("-" * 80)
    
    # 检查是否被锁定
    is_locked = check_db_lock(db_path)
    
    if is_locked:
        print("-" * 80)
        print("正在查找锁定进程...")
        find_locking_processes(db_path)
    
    print("-" * 80)
    print("检测完成")


if __name__ == "__main__":
    main()