static NTSTATUS DOKAN_CALLBACK
MirrorCreateFile(LPCWSTR FileName, PDOKAN_IO_SECURITY_CONTEXT SecurityContext,
ACCESS_MASK DesiredAccess, ULONG FileAttributes,
ULONG ShareAccess, ULONG CreateDisposition,
ULONG CreateOptions, PDOKAN_FILE_INFO DokanFileInfo) {
WCHAR filePath[DOKAN_MAX_PATH] = {0};
WCHAR lowerFilePath[DOKAN_MAX_PATH] = {0};
WCHAR writeFilePath[DOKAN_MAX_PATH] = {0};
HANDLE handle;
DWORD fileAttr;
NTSTATUS status = STATUS_SUCCESS;
DWORD creationDisposition;
DWORD fileAttributesAndFlags;
DWORD error = 0;
SECURITY_ATTRIBUTES securityAttrib;
ACCESS_MASK genericDesiredAccess;
// userTokenHandle is for Impersonate Caller User Option
HANDLE userTokenHandle = INVALID_HANDLE_VALUE;
// 设置 SECURITY_ATTRIBUTES
securityAttrib.nLength = sizeof(securityAttrib);
securityAttrib.lpSecurityDescriptor =
SecurityContext->AccessState.SecurityDescriptor;
securityAttrib.bInheritHandle = FALSE;
// 映射内核创建文件标志到用户空间
DokanMapKernelToUserCreateFileFlags(
DesiredAccess, FileAttributes, CreateOptions, CreateDisposition,
&genericDesiredAccess, &fileAttributesAndFlags, &creationDisposition);
GetLowerFilePath(lowerFilePath, DOKAN_MAX_PATH, FileName);
GetFilePath(filePath, DOKAN_MAX_PATH, FileName);
GetWriteFilePath(writeFilePath, DOKAN_MAX_PATH, FileName);
BOOL isWrite = IsWriteOperation(DesiredAccess, CreateDisposition,
FileOrPathExists(lowerFilePath));
DWORD srcAttrs = GetFileAttributes(lowerFilePath);
BOOL isLowerFileExist = (srcAttrs != INVALID_FILE_ATTRIBUTES) &&
!(srcAttrs & FILE_ATTRIBUTE_DIRECTORY);
if (!isWrite) {
// 读操作:优先检查 tmpwrite 是否存在
if (PathFileExists(writeFilePath)) {
wcscpy_s(filePath, DOKAN_MAX_PATH, writeFilePath);
}
} else {
EnsureParentDirExists(writeFilePath);
if (isLowerFileExist && !FileOrPathExists(writeFilePath)) {
CopyFileFromSource(filePath, writeFilePath);
}
// 写操作:强制使用 tmpwrite 路径
wcscpy_s(filePath, DOKAN_MAX_PATH, writeFilePath);
}
// 当 filePath 指向的是目录时,调整标志以便正确打开
fileAttr = GetFileAttributes(filePath);
if (fileAttr != INVALID_FILE_ATTRIBUTES &&
fileAttr & FILE_ATTRIBUTE_DIRECTORY) {
if (CreateOptions & FILE_NON_DIRECTORY_FILE) {
DbgPrint(L"\tCannot open a dir as a file\n");
return STATUS_FILE_IS_A_DIRECTORY;
}
DokanFileInfo->IsDirectory = TRUE;
// 需要通过 FindFirstFile 来列出目录中的文件
ShareAccess |= FILE_SHARE_READ;
}
DbgPrint(L"\tFlagsAndAttributes = 0x%x\n", fileAttributesAndFlags);
// 保留原有标志处理逻辑
if (g_CaseSensitive)
fileAttributesAndFlags |= FILE_FLAG_POSIX_SEMANTICS;
// 处理用户身份验证(如果启用)
if (g_ImpersonateCallerUser) {
userTokenHandle = DokanOpenRequestorToken(DokanFileInfo);
if (userTokenHandle == INVALID_HANDLE_VALUE) {
DbgPrint(L" DokanOpenRequestorToken failed\n");
// 可以选择返回错误状态
}
}
if (DokanFileInfo->IsDirectory) {
if (wcsstr(filePath, L"www") != NULL) {
wprintf(L"it is www\n");
}
// 处理创建目录请求
if (creationDisposition == CREATE_NEW ||
creationDisposition == OPEN_ALWAYS) {
if (g_ImpersonateCallerUser && userTokenHandle != INVALID_HANDLE_VALUE) {
// 如果启用了用户模拟,进行身份模拟
if (!ImpersonateLoggedOnUser(userTokenHandle)) {
// 处理身份模拟失败
DbgPrint(L"\tImpersonateLoggedOnUser failed.\n");
}
}
wprintf(L"create creationDisposition CREATE_NEW %s to %s\n", filePath,
writeFilePath);
// We create folder
if (!CreateDirectory(filePath, &securityAttrib)) {
error = GetLastError();
// Fail to create folder for OPEN_ALWAYS is not an error
if (error != ERROR_ALREADY_EXISTS ||
creationDisposition == CREATE_NEW) {
DbgPrint(L"\terror code = %d\n\n", error);
status = DokanNtStatusFromWin32(error);
}
}
if (g_ImpersonateCallerUser && userTokenHandle != INVALID_HANDLE_VALUE) {
// Clean Up operation for impersonate
DWORD lastError = GetLastError();
if (status != STATUS_SUCCESS) //Keep the handle open for CreateFile
CloseHandle(userTokenHandle);
RevertToSelf();
SetLastError(lastError);
}
}
if (status == STATUS_SUCCESS) {
// 检查是否尝试将文件作为目录打开
if (fileAttr != INVALID_FILE_ATTRIBUTES &&
!(fileAttr & FILE_ATTRIBUTE_DIRECTORY) &&
(CreateOptions & FILE_DIRECTORY_FILE)) {
return STATUS_NOT_A_DIRECTORY;
}
if (g_ImpersonateCallerUser && userTokenHandle != INVALID_HANDLE_VALUE) {
// 取消模拟用户身份
if (!ImpersonateLoggedOnUser(userTokenHandle)) {
DbgPrint(L"\tImpersonateLoggedOnUser failed.\n");
}
}
// FILE_FLAG_BACKUP_SEMANTICS 对于打开目录句柄是必需的
handle =
CreateFile(filePath, genericDesiredAccess, ShareAccess,
&securityAttrib, OPEN_EXISTING,
fileAttributesAndFlags | FILE_FLAG_BACKUP_SEMANTICS, NULL);
// 取消模拟用户身份
if (g_ImpersonateCallerUser && userTokenHandle != INVALID_HANDLE_VALUE) {
DWORD lastError = GetLastError();
CloseHandle(userTokenHandle);
RevertToSelf();
SetLastError(lastError);
}
if (handle == INVALID_HANDLE_VALUE) {
error = GetLastError();
DbgPrint(L"\terror code = %d\n\n", error);
status = DokanNtStatusFromWin32(error);
} else {
DokanFileInfo->Context = (ULONG64)handle; // 保存文件句柄到 Context
// 如果是 OPEN_ALWAYS 且文件已存在,返回 STATUS_OBJECT_NAME_COLLISION
if (creationDisposition == OPEN_ALWAYS &&
fileAttr != INVALID_FILE_ATTRIBUTES)
return STATUS_OBJECT_NAME_COLLISION;
}
}
} else {
// 处理创建文件请求
// 防止未设置隐藏或系统属性的文件被覆盖
if (fileAttr != INVALID_FILE_ATTRIBUTES &&
((!(fileAttributesAndFlags & FILE_ATTRIBUTE_HIDDEN) &&
(fileAttr & FILE_ATTRIBUTE_HIDDEN)) ||
(!(fileAttributesAndFlags & FILE_ATTRIBUTE_SYSTEM) &&
(fileAttr & FILE_ATTRIBUTE_SYSTEM))) &&
(creationDisposition == TRUNCATE_EXISTING ||
creationDisposition == CREATE_ALWAYS))
return STATUS_ACCESS_DENIED;
// 防止删除只读文件
if ((fileAttr != INVALID_FILE_ATTRIBUTES &&
(fileAttr & FILE_ATTRIBUTE_READONLY) ||
(fileAttributesAndFlags & FILE_ATTRIBUTE_READONLY)) &&
(fileAttributesAndFlags & FILE_FLAG_DELETE_ON_CLOSE))
return STATUS_CANNOT_DELETE;
// 截断操作必须具有写访问权限
if (creationDisposition == TRUNCATE_EXISTING)
genericDesiredAccess |= GENERIC_WRITE;
if (g_ImpersonateCallerUser && userTokenHandle != INVALID_HANDLE_VALUE) {
// 如果启用了用户模拟,进行身份模拟
if (!ImpersonateLoggedOnUser(userTokenHandle)) {
// 处理身份模拟失败
DbgPrint(L"\tImpersonateLoggedOnUser failed.\n");
}
}
// 打开文件句柄
handle =
CreateFile(filePath, genericDesiredAccess, ShareAccess, &securityAttrib,
creationDisposition, fileAttributesAndFlags, NULL);
if (g_ImpersonateCallerUser && userTokenHandle != INVALID_HANDLE_VALUE) {
// 取消模拟用户身份
DWORD lastError = GetLastError();
CloseHandle(userTokenHandle);
RevertToSelf();
SetLastError(lastError);
}
if (handle == INVALID_HANDLE_VALUE) {
error = GetLastError();
DbgPrint(L"\terror code = %d\n\n", error);
wprintf(L"got a errrrrrr file:%s code = %d\n", filePath, error);
status = DokanNtStatusFromWin32(error);
} else {
// 如果是 TRUNCATE_EXISTING,更新文件属性
if (fileAttr != INVALID_FILE_ATTRIBUTES &&
creationDisposition == TRUNCATE_EXISTING) {
SetFileAttributes(filePath, fileAttributesAndFlags | fileAttr);
}
DokanFileInfo->Context = (ULONG64)handle; // 保存文件句柄到 Context
// 如果是 OPEN_ALWAYS 或 CREATE_ALWAYS 且文件已存在,返回 STATUS_OBJECT_NAME_COLLISION
if (creationDisposition == OPEN_ALWAYS ||
creationDisposition == CREATE_ALWAYS) {
error = GetLastError();
if (error == ERROR_ALREADY_EXISTS) {
DbgPrint(L"\tOpen an already existing file\n");
status = STATUS_OBJECT_NAME_COLLISION;
}
}
}
}
DbgPrint(L"\n");
return status;
}