From d6a326fbbf70813f3ee5d3282c44664092a39fb1 Mon Sep 17 00:00:00 2001 From: Hao Mou Date: Wed, 13 Oct 2021 13:13:01 +0800 Subject: [PATCH] windows: add NtSetInformationFile Added NtSetInformationFile and some const values related to it. The doc for the function and the values of the file information class can be found here: https://docs.microsoft.com/en-us/windows-hardware/drivers/ddi/ntifs/nf-ntifs-ntsetinformationfile The values of the flags in the individual FILE_INFORMATION_CLASS can be found here: FILE_RENAME_INFORMATION - https://docs.microsoft.com/en-us/windows-hardware/drivers/ddi/ntifs/ns-ntifs-_file_rename_information FILE_DISPOSITION_INFORMATION_EX - https://docs.microsoft.com/en-us/windows-hardware/drivers/ddi/ntddk/ns-ntddk-_file_disposition_information_ex FILE_CASE_SENSITIVE_INFORMATION - https://docs.microsoft.com/en-us/windows-hardware/drivers/ddi/ntifs/ns-ntifs-_file_case_sensitive_information FILE_LINK_INFORMATION - https://docs.microsoft.com/en-us/windows-hardware/drivers/ddi/ntifs/ns-ntifs-_file_link_information The other file information classes do not have flag values. Fixes golang/go#48933 Change-Id: I917ff4c8df132f8584fd6d924cf5a9626a065092 Reviewed-on: https://go-review.googlesource.com/c/sys/+/355495 Trust: Alex Brainman Trust: Emmanuel Odeke Run-TryBot: Alex Brainman TryBot-Result: Go Bot Reviewed-by: Alex Brainman --- windows/syscall_windows.go | 1 + windows/syscall_windows_test.go | 74 +++++++++++++++++++++++++++++++++ windows/types_windows.go | 54 ++++++++++++++++++++++++ windows/zsyscall_windows.go | 9 ++++ 4 files changed, 138 insertions(+) diff --git a/windows/syscall_windows.go b/windows/syscall_windows.go index 42b49455..53ee74e0 100644 --- a/windows/syscall_windows.go +++ b/windows/syscall_windows.go @@ -423,6 +423,7 @@ func NewCallbackCDecl(fn interface{}) uintptr { //sys RtlInitString(destinationString *NTString, sourceString *byte) = ntdll.RtlInitString //sys NtCreateFile(handle *Handle, access uint32, oa *OBJECT_ATTRIBUTES, iosb *IO_STATUS_BLOCK, allocationSize *int64, attributes uint32, share uint32, disposition uint32, options uint32, eabuffer uintptr, ealength uint32) (ntstatus error) = ntdll.NtCreateFile //sys NtCreateNamedPipeFile(pipe *Handle, access uint32, oa *OBJECT_ATTRIBUTES, iosb *IO_STATUS_BLOCK, share uint32, disposition uint32, options uint32, typ uint32, readMode uint32, completionMode uint32, maxInstances uint32, inboundQuota uint32, outputQuota uint32, timeout *int64) (ntstatus error) = ntdll.NtCreateNamedPipeFile +//sys NtSetInformationFile(handle Handle, iosb *IO_STATUS_BLOCK, inBuffer *byte, inBufferLen uint32, class uint32) (ntstatus error) = ntdll.NtSetInformationFile //sys RtlDosPathNameToNtPathName(dosName *uint16, ntName *NTUnicodeString, ntFileNamePart *uint16, relativeName *RTL_RELATIVE_NAME) (ntstatus error) = ntdll.RtlDosPathNameToNtPathName_U_WithStatus //sys RtlDosPathNameToRelativeNtPathName(dosName *uint16, ntName *NTUnicodeString, ntFileNamePart *uint16, relativeName *RTL_RELATIVE_NAME) (ntstatus error) = ntdll.RtlDosPathNameToRelativeNtPathName_U_WithStatus //sys RtlDefaultNpAcl(acl **ACL) (ntstatus error) = ntdll.RtlDefaultNpAcl diff --git a/windows/syscall_windows_test.go b/windows/syscall_windows_test.go index 6b1389a6..45836c96 100644 --- a/windows/syscall_windows_test.go +++ b/windows/syscall_windows_test.go @@ -858,3 +858,77 @@ func TestSystemModuleVersions(t *testing.T) { (fixedInfo.FileVersionLS>>0)&0xff) } } + +type fileRenameInformation struct { + ReplaceIfExists uint32 + RootDirectory windows.Handle + FileNameLength uint32 + FileName [1]uint16 +} + +func TestNtCreateFileAndNtSetInformationFile(t *testing.T) { + var iosb windows.IO_STATUS_BLOCK + var allocSize int64 = 0 + // Open test directory with NtCreateFile. + testDirPath := t.TempDir() + objectName, err := windows.NewNTUnicodeString("\\??\\" + testDirPath) + if err != nil { + t.Fatal(err) + } + oa := &windows.OBJECT_ATTRIBUTES{ + ObjectName: objectName, + } + oa.Length = uint32(unsafe.Sizeof(*oa)) + var testDirHandle windows.Handle + err = windows.NtCreateFile(&testDirHandle, windows.FILE_GENERIC_READ|windows.FILE_GENERIC_WRITE, oa, &iosb, + &allocSize, 0, windows.FILE_SHARE_READ|windows.FILE_SHARE_WRITE|windows.FILE_SHARE_DELETE, windows.FILE_OPEN, + windows.FILE_DIRECTORY_FILE, 0, 0) + if err != nil { + t.Fatalf("NtCreateFile(%v) failed: %v", testDirPath, err) + } + defer windows.CloseHandle(testDirHandle) + // Create a file in test directory with NtCreateFile. + fileName := "filename" + filePath := filepath.Join(testDirPath, fileName) + objectName, err = windows.NewNTUnicodeString(fileName) + if err != nil { + t.Fatal(err) + } + oa.RootDirectory = testDirHandle + oa.ObjectName = objectName + var fileHandle windows.Handle + err = windows.NtCreateFile(&fileHandle, windows.FILE_GENERIC_READ|windows.FILE_GENERIC_WRITE|windows.DELETE, oa, &iosb, + &allocSize, 0, windows.FILE_SHARE_READ|windows.FILE_SHARE_WRITE|windows.FILE_SHARE_DELETE, windows.FILE_CREATE, + 0, 0, 0) + if err != nil { + t.Fatalf("NtCreateFile(%v) failed: %v", filePath, err) + } + defer windows.CloseHandle(fileHandle) + _, err = os.Stat(filePath) + if err != nil { + t.Fatalf("cannot stat file created with NtCreatefile: %v", err) + } + // Rename file with NtSetInformationFile. + newName := "newname" + newPath := filepath.Join(testDirPath, newName) + newNameUTF16, err := windows.UTF16FromString(newName) + if err != nil { + t.Fatal(err) + } + fileNameLen := len(newNameUTF16)*2 - 2 + var dummyFileRenameInfo fileRenameInformation + bufferSize := int(unsafe.Offsetof(dummyFileRenameInfo.FileName)) + fileNameLen + buffer := make([]byte, bufferSize) + typedBufferPtr := (*fileRenameInformation)(unsafe.Pointer(&buffer[0])) + typedBufferPtr.ReplaceIfExists = windows.FILE_RENAME_REPLACE_IF_EXISTS | windows.FILE_RENAME_POSIX_SEMANTICS + typedBufferPtr.FileNameLength = uint32(fileNameLen) + copy((*[1 << 29]uint16)(unsafe.Pointer(&typedBufferPtr.FileName[0]))[:], newNameUTF16) + err = windows.NtSetInformationFile(fileHandle, &iosb, &buffer[0], uint32(bufferSize), windows.FileRenameInformation) + if err != nil { + t.Fatalf("NtSetInformationFile(%v) failed: %v", newPath, err) + } + _, err = os.Stat(newPath) + if err != nil { + t.Fatalf("cannot stat rename target %v: %v", newPath, err) + } +} diff --git a/windows/types_windows.go b/windows/types_windows.go index 53e21522..286dd1ea 100644 --- a/windows/types_windows.go +++ b/windows/types_windows.go @@ -2562,6 +2562,60 @@ const ( FILE_PIPE_SERVER_END = 0x00000001 ) +const ( + // FileInformationClass for NtSetInformationFile + FileBasicInformation = 4 + FileRenameInformation = 10 + FileDispositionInformation = 13 + FilePositionInformation = 14 + FileEndOfFileInformation = 20 + FileValidDataLengthInformation = 39 + FileShortNameInformation = 40 + FileIoPriorityHintInformation = 43 + FileReplaceCompletionInformation = 61 + FileDispositionInformationEx = 64 + FileCaseSensitiveInformation = 71 + FileLinkInformation = 72 + FileCaseSensitiveInformationForceAccessCheck = 75 + FileKnownFolderInformation = 76 + + // Flags for FILE_RENAME_INFORMATION + FILE_RENAME_REPLACE_IF_EXISTS = 0x00000001 + FILE_RENAME_POSIX_SEMANTICS = 0x00000002 + FILE_RENAME_SUPPRESS_PIN_STATE_INHERITANCE = 0x00000004 + FILE_RENAME_SUPPRESS_STORAGE_RESERVE_INHERITANCE = 0x00000008 + FILE_RENAME_NO_INCREASE_AVAILABLE_SPACE = 0x00000010 + FILE_RENAME_NO_DECREASE_AVAILABLE_SPACE = 0x00000020 + FILE_RENAME_PRESERVE_AVAILABLE_SPACE = 0x00000030 + FILE_RENAME_IGNORE_READONLY_ATTRIBUTE = 0x00000040 + FILE_RENAME_FORCE_RESIZE_TARGET_SR = 0x00000080 + FILE_RENAME_FORCE_RESIZE_SOURCE_SR = 0x00000100 + FILE_RENAME_FORCE_RESIZE_SR = 0x00000180 + + // Flags for FILE_DISPOSITION_INFORMATION_EX + FILE_DISPOSITION_DO_NOT_DELETE = 0x00000000 + FILE_DISPOSITION_DELETE = 0x00000001 + FILE_DISPOSITION_POSIX_SEMANTICS = 0x00000002 + FILE_DISPOSITION_FORCE_IMAGE_SECTION_CHECK = 0x00000004 + FILE_DISPOSITION_ON_CLOSE = 0x00000008 + FILE_DISPOSITION_IGNORE_READONLY_ATTRIBUTE = 0x00000010 + + // Flags for FILE_CASE_SENSITIVE_INFORMATION + FILE_CS_FLAG_CASE_SENSITIVE_DIR = 0x00000001 + + // Flags for FILE_LINK_INFORMATION + FILE_LINK_REPLACE_IF_EXISTS = 0x00000001 + FILE_LINK_POSIX_SEMANTICS = 0x00000002 + FILE_LINK_SUPPRESS_STORAGE_RESERVE_INHERITANCE = 0x00000008 + FILE_LINK_NO_INCREASE_AVAILABLE_SPACE = 0x00000010 + FILE_LINK_NO_DECREASE_AVAILABLE_SPACE = 0x00000020 + FILE_LINK_PRESERVE_AVAILABLE_SPACE = 0x00000030 + FILE_LINK_IGNORE_READONLY_ATTRIBUTE = 0x00000040 + FILE_LINK_FORCE_RESIZE_TARGET_SR = 0x00000080 + FILE_LINK_FORCE_RESIZE_SOURCE_SR = 0x00000100 + FILE_LINK_FORCE_RESIZE_SR = 0x00000180 +) + // ProcessInformationClasses for NtQueryInformationProcess and NtSetInformationProcess. const ( ProcessBasicInformation = iota diff --git a/windows/zsyscall_windows.go b/windows/zsyscall_windows.go index 42e10dd3..ef3cfcfb 100644 --- a/windows/zsyscall_windows.go +++ b/windows/zsyscall_windows.go @@ -366,6 +366,7 @@ var ( procNetUserGetInfo = modnetapi32.NewProc("NetUserGetInfo") procNtCreateFile = modntdll.NewProc("NtCreateFile") procNtCreateNamedPipeFile = modntdll.NewProc("NtCreateNamedPipeFile") + procNtSetInformationFile = modntdll.NewProc("NtSetInformationFile") procNtQueryInformationProcess = modntdll.NewProc("NtQueryInformationProcess") procNtQuerySystemInformation = modntdll.NewProc("NtQuerySystemInformation") procNtSetInformationProcess = modntdll.NewProc("NtSetInformationProcess") @@ -3170,6 +3171,14 @@ func NtCreateNamedPipeFile(pipe *Handle, access uint32, oa *OBJECT_ATTRIBUTES, i return } +func NtSetInformationFile(handle Handle, iosb *IO_STATUS_BLOCK, inBuffer *byte, inBufferLen uint32, class uint32) (ntstatus error) { + r0, _, _ := syscall.Syscall6(procNtSetInformationFile.Addr(), 5, uintptr(handle), uintptr(unsafe.Pointer(iosb)), uintptr(unsafe.Pointer(inBuffer)), uintptr(inBufferLen), uintptr(class), 0) + if r0 != 0 { + ntstatus = NTStatus(r0) + } + return +} + func NtQueryInformationProcess(proc Handle, procInfoClass int32, procInfo unsafe.Pointer, procInfoLen uint32, retLen *uint32) (ntstatus error) { r0, _, _ := syscall.Syscall6(procNtQueryInformationProcess.Addr(), 5, uintptr(proc), uintptr(procInfoClass), uintptr(procInfo), uintptr(procInfoLen), uintptr(unsafe.Pointer(retLen)), 0) if r0 != 0 {