Vì vậy, tôi đang cố gắng chuyển một phần mở rộng C-python mà tôi đã viết để xử lý các liên kết/liên kết tượng trưng/vv trên Windows sang Python thuần túy bằng mô-đun ctypes. Thật không may, kể từ khi sử dụng trước đây của tôi của ctypes là khá hạn chế, tôi nghĩ rằng tôi có thể làm cho một sai lầm một nơi nào đó gây ra mã của tôi hoạt động không chính xác. Dưới đây là những gì tôi có cho đến thời điểm này:Sử dụng cấu trúc làm đối số hàm với mô-đun ctypes python
from os import path
from ctypes import *
from ctypes.wintypes import *
# Python implementation of:
#
# typedef struct {
# DWORD ReparseTag;
# DWORD ReparseDataLength;
# WORD Reserved;
# WORD ReparseTargetLength;
# WORD ReparseTargetMaximumLength;
# WORD Reserved1;
# WCHAR ReparseTarget[1];
# } REPARSE_MOUNTPOINT_DATA_BUFFER, *PREPARSE_MOUNTPOINT_DATA_BUFFER;
class ReparsePoint(Structure):
_fields_ = [
("ReparseTag", DWORD),
("ReparseDataLength", DWORD),
("Reserved", WORD),
("ReparseTargetLength", WORD),
("ReparseTargetMaximumLength", WORD),
("Reserved1", WORD),
("ReparseTarget", c_wchar_p),
]
GENERIC_READ = 0x80000000
GENERIC_WRITE = 0x40000000
FILE_SHARE_DELETE = 0x00000004
FILE_SHARE_READ = 0x00000001
FILE_SHARE_WRITE = 0x00000002
FILE_SHARE_READ_WRITE = (FILE_SHARE_READ | FILE_SHARE_WRITE)
OPEN_EXISTING = 3
IO_REPARSE_TAG_MOUNT_POINT = 0xA0000003
REPARSE_MOUNTPOINT_HEADER_SIZE = 8
FSCTL_SET_REPARSE_POINT = 589988
FILE_FLAG_OPEN_REPARSE_POINT = 2097152
FILE_FLAG_BACKUP_SEMANTICS = 33554432
FILE_FLAG_REPARSE_BACKUP = 35651584 # FILE_FLAG_OPEN_REPARSE_POINT | FILE_FLAG_BACKUP_SEMANTICS
INVALID_HANDLE_VALUE = -1
LPOVERLAPPED = c_void_p
LPSECURITY_ATTRIBUTES = c_void_p
NULL = 0
FALSE = BOOL(0)
TRUE = BOOL(1)
def CreateFile(filename, access, sharemode, creation, flags):
return HANDLE(windll.kernel32.CreateFileW(
LPWSTR(filename),
DWORD(access),
DWORD(sharemode),
LPSECURITY_ATTRIBUTES(NULL),
DWORD(creation),
DWORD(flags),
HANDLE(NULL)
))
def CreateDirectory(fpath):
return windll.kernel32.CreateDirectoryW(LPWSTR(fpath), LPSECURITY_ATTRIBUTES(NULL)) != FALSE
def RemoveDirectory(fpath):
return windll.kernel32.RemoveDirectoryW(LPWSTR(fpath)) != FALSE
def translate_path(fpath):
fpath = path.abspath(fpath)
if fpath[len(fpath)-1] == '\\' and fpath[len(fpath)-2] == ':':
fpath = fpath[:len(fpath)-1]
return '\\??\\%s' % fpath
def junction(source, link_name):
""" Create a junction at link_name pointing to source directory. """
if not path.isdir(source):
raise Exception('Junction source does not exist or is not a directory.')
link_name = path.abspath(link_name)
if path.exists(link_name):
raise Exception('Filepath for new junction already exists.')
if not CreateDirectory(link_name):
raise Exception('Failed to create new directory for target junction.')
source = translate_path(source)
hFile = CreateFile(link_name, GENERIC_WRITE, 0, OPEN_EXISTING, FILE_FLAG_REPARSE_BACKUP)
if hFile == HANDLE(INVALID_HANDLE_VALUE):
raise Exception('Failed to open directory for junction creation.')
datalen = len(source) * sizeof(c_wchar)
reparseInfo = ReparsePoint(
IO_REPARSE_TAG_MOUNT_POINT,
datalen + 12,
0,
datalen,
datalen + sizeof(c_wchar),
0,
source
)
pReparseInfo = pointer(reparseInfo)
print reparseInfo.ReparseTarget
returnedLength = DWORD(0)
result = BOOL(
windll.kernel32.DeviceIoControl(
hFile,
DWORD(FSCTL_SET_REPARSE_POINT),
pReparseInfo,
DWORD(reparseInfo.ReparseDataLength + REPARSE_MOUNTPOINT_HEADER_SIZE),
LPVOID(NULL),
DWORD(0),
byref(returnedLength),
LPOVERLAPPED(NULL)
)
) == TRUE
#if not result:
#RemoveDirectory(link_name)
windll.kernel32.CloseHandle(hFile)
return result
print junction('G:\\cpp.workspace\\tools', 'test')
"""
Just putting this here for the moment so I know how to call the function.
BOOL WINAPI DeviceIoControl(
__in HANDLE hDevice,
__in DWORD dwIoControlCode,
__in_opt LPVOID lpInBuffer,
__in DWORD nInBufferSize,
__out_opt LPVOID lpOutBuffer,
__in DWORD nOutBufferSize,
__out_opt LPDWORD lpBytesReturned,
__inout_opt LPOVERLAPPED lpOverlapped
);
"""
Hiện tại khi chạy, mã tạo thư mục cho giao lộ mục tiêu. (Trong trường hợp này, kiểm tra) Nó thậm chí dường như đang áp dụng thẻ reparse để báo hiệu cho hệ thống rằng thư mục là một đường giao nhau. Tuy nhiên, thay vì trỏ đến "G: \ cpp.workspace \ tools" (hoặc đúng hơn, tới \ ?? \ G: \ cpp.workspace \ tools), đường giao nhau dường như trỏ tới: 㢨 \ 獬
Bây giờ, rõ ràng đây là một vấn đề với reparseInfo.ReparseTarget, nhưng tôi đã không thể tìm ra những gì tôi đã làm sai.
Cảm ơn. Đã làm việc bằng cách thay đổi ReparseTarget thành c_wchar * MAX_PATH (MAX_PATH là 260), sau đó thêm reparseInfo._fields_ [6] = ('ReparseTarget', datalen) trước khi gọi DeviceIoControl. –