Files
TransPyC/includes/os/_win32.py
2026-07-18 19:25:40 +08:00

235 lines
7.4 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import t, c
from stdint import *
import w32.win32base
import w32.win32file
import memhub
import stdlib
# Windows 路径最大长度
MAX_PATH_LEN: t.CDefine = 260
# INVALID_FILE_ATTRIBUTES
INVALID_FILE_ATTRIBUTES: t.CDefine = 0xFFFFFFFF
# 模块级全局 MBuddy 指针(由用户在 main 中赋值初始化)
_mbuddy: memhub.MemBuddy | t.CPtr
# =============================================================================
# 文件/目录属性查询
# =============================================================================
def _get_attrs(path: str) -> ULONG:
"""获取文件属性。失败返回 INVALID_FILE_ATTRIBUTES。"""
return w32.win32file.GetFileAttributesA(path)
def exists(path: str) -> bool:
"""检查文件/目录是否存在"""
attrs: ULONG = _get_attrs(path)
if attrs == INVALID_FILE_ATTRIBUTES:
return False
return True
def isdir(path: str) -> bool:
"""检查路径是否为目录"""
attrs: ULONG = _get_attrs(path)
if attrs == INVALID_FILE_ATTRIBUTES:
return False
if (attrs & w32.win32file.FILE_ATTRIBUTE_DIRECTORY) != 0:
return True
return False
def isfile(path: str) -> bool:
"""检查路径是否为普通文件"""
attrs: ULONG = _get_attrs(path)
if attrs == INVALID_FILE_ATTRIBUTES:
return False
if (attrs & w32.win32file.FILE_ATTRIBUTE_DIRECTORY) != 0:
return False
return True
def getsize(path: str) -> t.CInt64T:
"""返回文件大小(字节)。失败返回 -1。"""
handle: w32.win32base.HANDLE = w32.win32file.CreateFileA(
path, w32.win32file.GENERIC_READ, w32.win32file.FILE_SHARE_READ,
t.CPtr(0), w32.win32file.OPEN_EXISTING, w32.win32file.FILE_ATTRIBUTE_NORMAL, t.CPtr(0)
)
if handle == w32.win32base.INVALID_HANDLE_VALUE:
return -1
li: w32.win32base.LARGE_INTEGER = w32.win32base.LARGE_INTEGER()
result: BOOL = w32.win32file.GetFileSizeEx(handle, t.CPtr(c.Addr(li)))
w32.win32base.CloseHandle(handle)
if result == 0:
return -1
return li.QuadPart
# =============================================================================
# 工作目录
# =============================================================================
def getcwd() -> str:
"""返回当前工作目录(通过 _mbuddy 分配内存)"""
buf: bytes = _mbuddy.alloc(MAX_PATH_LEN + 1)
if buf == None: return None
length: ULONG = w32.win32file.GetCurrentDirectoryA(MAX_PATH_LEN + 1, buf)
if length == 0:
return None
if length > MAX_PATH_LEN:
# 缓冲区不够,重新分配
buf2: bytes = _mbuddy.alloc(length + 1)
if buf2 == None: return None
w32.win32file.GetCurrentDirectoryA(length + 1, buf2)
buf2[length] = 0
return str(buf2)
buf[length] = 0
return str(buf)
def chdir(path: str) -> int:
"""切换当前工作目录。成功返回 0失败返回 -1。"""
result: BOOL = w32.win32file.SetCurrentDirectoryA(path)
if result == 0:
return -1
return 0
# =============================================================================
# 文件/目录操作
# =============================================================================
def mkdir(path: str) -> int:
"""创建目录。成功返回 0失败返回 -1。"""
result: BOOL = w32.win32file.CreateDirectoryA(path, t.CPtr(0))
if result == 0:
return -1
return 0
def remove(path: str) -> int:
"""删除文件。成功返回 0失败返回 -1。"""
result: BOOL = w32.win32file.DeleteFileA(path)
if result == 0:
return -1
return 0
def rmdir(path: str) -> int:
"""删除空目录。成功返回 0失败返回 -1。"""
result: BOOL = w32.win32file.RemoveDirectoryA(path)
if result == 0:
return -1
return 0
def rename(old_path: str, new_path: str) -> int:
"""重命名/移动文件或目录。成功返回 0失败返回 -1。"""
result: BOOL = w32.win32file.MoveFileExA(
old_path, new_path,
w32.win32file.MOVEFILE_REPLACE_EXISTING | w32.win32file.MOVEFILE_COPY_ALLOWED
)
if result == 0:
return -1
return 0
def chmod(path: str, mode: int) -> int:
"""修改文件属性Windows 简化版:只处理只读位)。
mode 的 S_IWUSR 位0o200为 0 时设为只读,为 1 时设为可写。
成功返回 0失败返回 -1。"""
if (mode & 0o200) != 0:
# 可写:清除只读属性
result: BOOL = w32.win32file.SetFileAttributesA(
path, w32.win32file.FILE_ATTRIBUTE_NORMAL
)
else:
# 只读:设置只读属性
result: BOOL = w32.win32file.SetFileAttributesA(
path, w32.win32file.FILE_ATTRIBUTE_READONLY
)
if result == 0:
return -1
return 0
# =============================================================================
# 目录列举FindFirstFile / FindNextFile
# =============================================================================
def listdir(path: str, out_names: str, max_count: ULONG) -> ULONG:
"""列举目录下的文件/子目录名。
out_names 为调用者提供的字符串指针数组char**),每个元素指向一个文件名。
文件名通过 _mbuddy 分配内存。
max_count 为 out_names 数组最大容量。
返回实际列举的条目数。失败返回 0。"""
# 构造搜索模式path\*
path_len: t.CSizeT = len(path)
pattern: bytes = _mbuddy.alloc(path_len + 3)
if pattern == None: return 0
i: t.CSizeT = 0
for ch in path:
pattern[i] = ch
i += 1
# 添加 \* 后缀
if path[path_len - 1] != '\\' and path[path_len - 1] != '/':
pattern[i] = '\\'
i += 1
pattern[i] = '*'
i += 1
pattern[i] = 0
find_data: w32.win32file.WIN32_FIND_DATAA = w32.win32file.WIN32_FIND_DATAA()
handle: w32.win32base.HANDLE = w32.win32file.FindFirstFileA(pattern, t.CPtr(c.Addr(find_data)))
if handle == w32.win32base.INVALID_HANDLE_VALUE:
return 0
count: ULONG = 0
while count < max_count:
# 跳过 . 和 ..
name: str = find_data.cFileName
if name[0] == '.':
if name[1] == 0:
# "."
if w32.win32file.FindNextFileA(handle, t.CPtr(c.Addr(find_data))) == 0:
break
continue
if name[1] == '.' and name[2] == 0:
# ".."
if w32.win32file.FindNextFileA(handle, t.CPtr(c.Addr(find_data))) == 0:
break
continue
# 复制文件名到新分配的内存
name_len: t.CSizeT = len(name)
name_buf: bytes = _mbuddy.alloc(name_len + 1)
if name_buf == None: break
j: t.CSizeT = 0
for ch in name:
name_buf[j] = ch
j += 1
name_buf[name_len] = 0
out_names[count] = str(name_buf)
count += 1
if w32.win32file.FindNextFileA(handle, t.CPtr(c.Addr(find_data))) == 0:
break
w32.win32file.FindClose(handle)
return count
# =============================================================================
# 命令执行
# =============================================================================
def system(cmd: str) -> int:
"""执行命令行命令(通过 C 运行时 system())。
命令输出直接到子进程的终端(继承父进程 stdout/stderr
返回命令的退出码0 表示成功)。"""
return stdlib.system(cmd)