/* Returns whether the path refers to a link-like object, e.g. a junction * point, symbolic link, or mounted folder. */ static int is_name_surrogate(const efile_path_t *path) { HANDLE handle; int result; handle = CreateFileW((const WCHAR*)path->data, GENERIC_READ, FILE_SHARE_FLAGS, NULL, OPEN_EXISTING, FILE_FLAG_OPEN_REPARSE_POINT | FILE_FLAG_BACKUP_SEMANTICS, NULL); result = 0; if(handle != INVALID_HANDLE_VALUE) { REPARSE_GUID_DATA_BUFFER reparse_buffer; DWORD unused_length; BOOL success; success = DeviceIoControl(handle, FSCTL_GET_REPARSE_POINT, NULL, 0, &reparse_buffer, sizeof(reparse_buffer), &unused_length, NULL); /* ERROR_MORE_DATA is tolerated since we're guaranteed to have filled * the field we want. */ if(success || GetLastError() == ERROR_MORE_DATA) { result = IsReparseTagNameSurrogate(reparse_buffer.ReparseTag); } CloseHandle(handle); } return result; }
UINT64 GetDirectorySizeInternal(OBJECT_ATTRIBUTES ObjectAttributes) { HANDLE hFile; //OBJECT_ATTRIBUTES ObjectAttributes = { sizeof(OBJECT_ATTRIBUTES), hRootDir, (UNICODE_STRING*)&FileName, OBJ_CASE_INSENSITIVE }; IO_STATUS_BLOCK IoStatusBlock; auto Status = NtOpenFile(&hFile, SYNCHRONIZE | FILE_LIST_DIRECTORY, &ObjectAttributes, &IoStatusBlock, FILE_SHARE_VALID_FLAGS, FILE_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT | FILE_OPEN_FOR_BACKUP_INTENT); if (Status) return 0; UINT64 Space = 0; byte Buffer[sizeof(FILE_FULL_DIR_INFORMATION) + 512]; FILE_FULL_DIR_INFORMATION & FileInfo = *(FILE_FULL_DIR_INFORMATION *)Buffer; UNICODE_STRING TempFileName = { 0,0,FileInfo.FileName }; ObjectAttributes.RootDirectory = hFile; ObjectAttributes.ObjectName = &TempFileName; while (ZwQueryDirectoryFile(hFile, NULL, NULL, NULL, &IoStatusBlock, Buffer, sizeof(Buffer), FileFullDirectoryInformation, -1, NULL, 0) == ERROR_SUCCESS) { if (FileInfo.FileAttributes&FILE_ATTRIBUTE_DIRECTORY) { if (FileInfo.FileAttributes&FILE_ATTRIBUTE_REPARSE_POINT) { if (IsReparseTagNameSurrogate(FileInfo.EaSize)) continue; } else { if (IsDots(FileInfo.FileName, FileInfo.FileNameLength)) continue; } TempFileName.Length = TempFileName.MaximumLength = FileInfo.FileNameLength; Space += GetDirectorySizeInternal(ObjectAttributes); } else { Space += FileInfo.AllocationSize.QuadPart; } } NtClose(hFile); return Space; }
UINT64 GetDirectoryAllocationSizeInternal(OBJECT_ATTRIBUTES ObjectAttributes, std::map<UINT64, DWORD>& FileMap) { HANDLE hFile; //OBJECT_ATTRIBUTES ObjectAttributes = { sizeof(OBJECT_ATTRIBUTES), hRootDir, (UNICODE_STRING*)&FileName, OBJ_CASE_INSENSITIVE }; IO_STATUS_BLOCK IoStatusBlock; auto Status = NtOpenFile(&hFile, SYNCHRONIZE | FILE_LIST_DIRECTORY, &ObjectAttributes, &IoStatusBlock, FILE_SHARE_VALID_FLAGS, FILE_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT | FILE_OPEN_FOR_BACKUP_INTENT); if (Status) return 0; UINT64 Space = 0; byte Buffer[sizeof(FILE_FULL_DIR_INFORMATION) + 512]; FILE_FULL_DIR_INFORMATION & FileInfo = *(FILE_FULL_DIR_INFORMATION *)Buffer; UNICODE_STRING TempFileName = { 0,0,FileInfo.FileName }; Status = -1; ObjectAttributes.RootDirectory = hFile; ObjectAttributes.ObjectName = &TempFileName; FILE_STANDARD_INFORMATION FileStandardInfo; FILE_INTERNAL_INFORMATION FileInternalInfo; while (ZwQueryDirectoryFile(hFile, NULL, NULL, NULL, &IoStatusBlock, Buffer, sizeof(Buffer), FileFullDirectoryInformation, -1, NULL, 0) == ERROR_SUCCESS) { TempFileName.Length = TempFileName.MaximumLength = FileInfo.FileNameLength; if (FileInfo.FileAttributes&FILE_ATTRIBUTE_DIRECTORY) { if (FileInfo.FileAttributes&FILE_ATTRIBUTE_REPARSE_POINT) { if (IsReparseTagNameSurrogate(FileInfo.EaSize)) continue; } else { if (IsDots(FileInfo.FileName, FileInfo.FileNameLength)) continue; } Space += GetDirectoryAllocationSizeInternal(ObjectAttributes, FileMap); } else { if (NtGetFileId(&ObjectAttributes, &FileStandardInfo, &FileInternalInfo)) continue; if (FileStandardInfo.NumberOfLinks != 1) { auto T = FileMap.insert(std::pair<UINT64, DWORD>(FileInternalInfo.IndexNumber.QuadPart, FileStandardInfo.NumberOfLinks)).first; if (--(T->second)) continue; } Space += FileInfo.AllocationSize.QuadPart; } } NtClose(hFile); return Space; }
NTSTATUS DeleteDirectoryInternal(OBJECT_ATTRIBUTES ObjectAttributes) { HANDLE hFile; //OBJECT_ATTRIBUTES ObjectAttributes = { sizeof(OBJECT_ATTRIBUTES), hRootDir, (UNICODE_STRING*)&FileName, OBJ_CASE_INSENSITIVE }; IO_STATUS_BLOCK IoStatusBlock; auto Status = NtOpenFile(&hFile, SYNCHRONIZE | FILE_LIST_DIRECTORY, &ObjectAttributes, &IoStatusBlock, FILE_SHARE_VALID_FLAGS, FILE_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT | FILE_OPEN_FOR_BACKUP_INTENT); if (Status) return Status; byte Buffer[sizeof(FILE_FULL_DIR_INFORMATION) + 512]; FILE_FULL_DIR_INFORMATION & FileInfo = *(FILE_FULL_DIR_INFORMATION *)Buffer; UNICODE_STRING TempFileName = { 0,0,FileInfo.FileName }; ObjectAttributes.RootDirectory = hFile; ObjectAttributes.ObjectName = &TempFileName; NTSTATUS Error = 0; while (ZwQueryDirectoryFile(hFile, NULL, NULL, NULL, &IoStatusBlock, Buffer, sizeof(Buffer), FileFullDirectoryInformation, -1, NULL, 0) == ERROR_SUCCESS) { TempFileName.Length = TempFileName.MaximumLength = FileInfo.FileNameLength; if (FileInfo.FileAttributes&FILE_ATTRIBUTE_DIRECTORY) { if ((FileInfo.FileAttributes&FILE_ATTRIBUTE_REPARSE_POINT)) { if (IsReparseTagNameSurrogate(FileInfo.EaSize)) goto StartDelete; } else { if (IsDots(FileInfo.FileName, FileInfo.FileNameLength)) continue; } if (Error = DeleteDirectoryInternal(ObjectAttributes)) { goto OnError; } } StartDelete: if (FileInfo.FileAttributes&FILE_ATTRIBUTE_READONLY) { //取消只读属性 if (Error = NtSetFileAttributes(&ObjectAttributes, FileInfo.FileAttributes^FILE_ATTRIBUTE_READONLY)) { goto OnError; } } if (Error = NtDeleteFile2(&ObjectAttributes)) { if (FileInfo.FileAttributes&FILE_ATTRIBUTE_READONLY) { //删除失败恢复只读属性 NtSetFileAttributes(&ObjectAttributes, FileInfo.FileAttributes); } OnError: Status = Error; } } //End: NtClose(hFile); return Status; }
NTSTATUS DeleteFile2(LPCWSTR FilePath) { UNICODE_STRING usFileName; if (!RtlDosPathNameToNtPathName_U(FilePath, &usFileName, NULL, NULL)) { return RtlGetLastNtStatus(); } OBJECT_ATTRIBUTES ObjectAttributes = { sizeof(OBJECT_ATTRIBUTES), NULL, &usFileName, OBJ_CASE_INSENSITIVE }; HANDLE hFile; IO_STATUS_BLOCK IoStatusBlock; auto Status = NtOpenFile(&hFile, FILE_READ_ATTRIBUTES | SYNCHRONIZE, &ObjectAttributes, &IoStatusBlock, FILE_SHARE_DELETE | FILE_SHARE_READ, FILE_OPEN_REPARSE_POINT | FILE_SYNCHRONOUS_IO_NONALERT | FILE_OPEN_FOR_BACKUP_INTENT); if (Status) { goto Error2; } FILE_ATTRIBUTE_TAG_INFORMATION FileAttributeTagInfo; Status = NtQueryInformationFile(hFile, &IoStatusBlock, &FileAttributeTagInfo, sizeof(FileAttributeTagInfo), FileAttributeTagInformation); NtClose(hFile); if (Status) { goto Error2; } if (FileAttributeTagInfo.FileAttributes&FILE_ATTRIBUTE_READONLY) { if (Status = NtSetFileAttributes(&ObjectAttributes, FileAttributeTagInfo.FileAttributes^FILE_ATTRIBUTE_READONLY)) goto Error2; } if (FileAttributeTagInfo.FileAttributes&FILE_ATTRIBUTE_REPARSE_POINT) { if (IsReparseTagNameSurrogate(FileAttributeTagInfo.ReparseTag)) goto Delete; } if (FileAttributeTagInfo.FileAttributes&FILE_ATTRIBUTE_DIRECTORY) { if (Status = DeleteDirectoryInternal(ObjectAttributes)) goto Error; } Delete: Status = NtDeleteFile2(&ObjectAttributes); Error: if (FileAttributeTagInfo.FileAttributes&FILE_ATTRIBUTE_REPARSE_POINT) { NtSetFileAttributes(&ObjectAttributes, FileAttributeTagInfo.FileAttributes); } Error2: RtlFreeUnicodeString(&usFileName); return Status; }