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 <alex.brainman@gmail.com>
Trust: Emmanuel Odeke <emmanuel@orijtech.com>
Run-TryBot: Alex Brainman <alex.brainman@gmail.com>
TryBot-Result: Go Bot <gobot@golang.org>
Reviewed-by: Alex Brainman <alex.brainman@gmail.com>
diff --git a/windows/syscall_windows.go b/windows/syscall_windows.go
index 42b4945..53ee74e 100644
--- a/windows/syscall_windows.go
+++ b/windows/syscall_windows.go
@@ -423,6 +423,7 @@
 //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 6b1389a..45836c9 100644
--- a/windows/syscall_windows_test.go
+++ b/windows/syscall_windows_test.go
@@ -858,3 +858,77 @@
 			(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 53e2152..286dd1e 100644
--- a/windows/types_windows.go
+++ b/windows/types_windows.go
@@ -2562,6 +2562,60 @@
 	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 42e10dd..ef3cfcf 100644
--- a/windows/zsyscall_windows.go
+++ b/windows/zsyscall_windows.go
@@ -366,6 +366,7 @@
 	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 @@
 	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 {