// ref: MS-FSCC

package smb2

import (
	
)

const (
	IO_REPARSE_TAG_RESERVED_ZERO   = 0x00000000
	IO_REPARSE_TAG_RESERVED_ONE    = 0x00000001
	IO_REPARSE_TAG_MOUNT_POINT     = 0xA0000003
	IO_REPARSE_TAG_HSM             = 0xC0000004
	IO_REPARSE_TAG_HSM2            = 0x80000006
	IO_REPARSE_TAG_DRIVER_EXTENDER = 0x80000005
	IO_REPARSE_TAG_SIS             = 0x80000007
	IO_REPARSE_TAG_DFS             = 0x8000000A
	IO_REPARSE_TAG_DFSR            = 0x80000012
	IO_REPARSE_TAG_FILTER_MANAGER  = 0x8000000B
	IO_REPARSE_TAG_SYMLINK         = 0xA000000C
)

const (
	FSCTL_DFS_GET_REFERRALS            = 0x00060194
	FSCTL_PIPE_PEEK                    = 0x0011400C
	FSCTL_PIPE_WAIT                    = 0x00110018
	FSCTL_PIPE_TRANSCEIVE              = 0x0011C017
	FSCTL_SRV_COPYCHUNK                = 0x001440F2
	FSCTL_SRV_ENUMERATE_SNAPSHOTS      = 0x00144064
	FSCTL_SRV_REQUEST_RESUME_KEY       = 0x00140078
	FSCTL_SRV_READ_HASH                = 0x001441bb
	FSCTL_SRV_COPYCHUNK_WRITE          = 0x001480F2
	FSCTL_LMR_REQUEST_RESILIENCY       = 0x001401D4
	FSCTL_QUERY_NETWORK_INTERFACE_INFO = 0x001401FC
	FSCTL_GET_REPARSE_POINT            = 0x000900A8
	FSCTL_SET_REPARSE_POINT            = 0x000900A4
	FSCTL_DFS_GET_REFERRALS_EX         = 0x000601B0
	FSCTL_FILE_LEVEL_TRIM              = 0x00098208
	FSCTL_VALIDATE_NEGOTIATE_INFO      = 0x00140204
)

type SymbolicLinkReparseDataBuffer struct {
	Flags          uint32
	SubstituteName string
	PrintName      string
}

func ( *SymbolicLinkReparseDataBuffer) () int {
	return 20 + utf16le.EncodedStringLen(.SubstituteName) + utf16le.EncodedStringLen(.PrintName)
}

func ( *SymbolicLinkReparseDataBuffer) ( []byte) {
	 := utf16le.EncodeString([20:], .SubstituteName)
	 := utf16le.EncodeString([20+:], .PrintName)

	le.PutUint32([:4], IO_REPARSE_TAG_SYMLINK)
	le.PutUint16([4:6], uint16(len()-8)) // ReparseDataLength
	le.PutUint16([8:10], 0)               // SubstituteNameOffset
	le.PutUint16([10:12], uint16())   // SubstituteNameLength
	le.PutUint16([14:16], uint16())   // PrintNameLength
	le.PutUint16([12:14], uint16())   // PrintNameOffset
	le.PutUint32([16:20], .Flags)
}

type SymbolicLinkReparseDataBufferDecoder []byte

func ( SymbolicLinkReparseDataBufferDecoder) () bool {
	if len() < 20 {
		return true
	}

	if .ReparseTag() != IO_REPARSE_TAG_SYMLINK {
		return true
	}

	 := int(.ReparseDataLength())
	 := int(.SubstituteNameOffset())
	 := int(.SubstituteNameLength())
	 := int(.PrintNameOffset())
	 := int(.PrintNameLength())

	if (&1 | &1) != 0 {
		return true
	}

	if len() < 8+ {
		return true
	}

	if  < 12++ ||  < 12++ {
		return true
	}

	return false
}

func ( SymbolicLinkReparseDataBufferDecoder) () uint32 {
	return le.Uint32([:4])
}

func ( SymbolicLinkReparseDataBufferDecoder) () uint16 {
	return le.Uint16([4:6])
}

func ( SymbolicLinkReparseDataBufferDecoder) () uint16 {
	return le.Uint16([8:10])
}

func ( SymbolicLinkReparseDataBufferDecoder) () uint16 {
	return le.Uint16([10:12])
}

func ( SymbolicLinkReparseDataBufferDecoder) () uint16 {
	return le.Uint16([12:14])
}

func ( SymbolicLinkReparseDataBufferDecoder) () uint16 {
	return le.Uint16([14:16])
}

func ( SymbolicLinkReparseDataBufferDecoder) () uint32 {
	return le.Uint32([16:20])
}

func ( SymbolicLinkReparseDataBufferDecoder) () []byte {
	return [20:]
}

func ( SymbolicLinkReparseDataBufferDecoder) () string {
	 := .SubstituteNameOffset()
	 := .SubstituteNameLength()
	return utf16le.DecodeToString(.PathBuffer()[ : +])
}

func ( SymbolicLinkReparseDataBufferDecoder) () string {
	 := .PrintNameOffset()
	 := .PrintNameLength()
	return utf16le.DecodeToString(.PathBuffer()[ : +])
}

type SrvRequestResumeKeyResponseDecoder []byte

func ( SrvRequestResumeKeyResponseDecoder) () bool {
	if len() < int(28+.ContextLength()) {
		return true
	}
	return false
}

func ( SrvRequestResumeKeyResponseDecoder) () []byte {
	return [:24]
}

func ( SrvRequestResumeKeyResponseDecoder) () uint32 {
	return le.Uint32([24:28])
}

func ( SrvRequestResumeKeyResponseDecoder) () []byte {
	return [28 : 28+.ContextLength()]
}

type SrvCopychunkCopy struct {
	SourceKey [24]byte
	Chunks    []*SrvCopychunk
}

func ( *SrvCopychunkCopy) () int {
	return 32 + len(.Chunks)*24
}

func ( *SrvCopychunkCopy) ( []byte) {
	copy([:24], .SourceKey[:])
	le.PutUint32([24:28], uint32(len(.Chunks)))
	 := 32
	for ,  := range .Chunks {
		.Encode([+*24 : +*24+24])
	}
}

type SrvCopychunk struct {
	SourceOffset int64
	TargetOffset int64
	Length       uint32
}

func ( *SrvCopychunk) () int {
	return 24
}

func ( *SrvCopychunk) ( []byte) {
	le.PutUint64([:8], uint64(.SourceOffset))
	le.PutUint64([8:16], uint64(.TargetOffset))
	le.PutUint32([16:20], .Length)
}

type SrvCopychunkResponseDecoder []byte

func ( SrvCopychunkResponseDecoder) () bool {
	return len() < 12
}

func ( SrvCopychunkResponseDecoder) () uint32 {
	return le.Uint32([:4])
}

func ( SrvCopychunkResponseDecoder) () uint32 {
	return le.Uint32([4:8])
}

func ( SrvCopychunkResponseDecoder) () uint32 {
	return le.Uint32([8:12])
}

const (
	FILE_ATTRIBUTE_ARCHIVE             = 0x20
	FILE_ATTRIBUTE_COMPRESSED          = 0x800
	FILE_ATTRIBUTE_DIRECTORY           = 0x10
	FILE_ATTRIBUTE_ENCRYPTED           = 0x4000
	FILE_ATTRIBUTE_HIDDEN              = 0x2
	FILE_ATTRIBUTE_NORMAL              = 0x80
	FILE_ATTRIBUTE_NOT_CONTENT_INDEXED = 0x2000
	FILE_ATTRIBUTE_OFFLINE             = 0x1000
	FILE_ATTRIBUTE_READONLY            = 0x1
	FILE_ATTRIBUTE_REPARSE_POINT       = 0x400
	FILE_ATTRIBUTE_SPARSE_FILE         = 0x200
	FILE_ATTRIBUTE_SYSTEM              = 0x4
	FILE_ATTRIBUTE_TEMPORARY           = 0x100
	FILE_ATTRIBUTE_INTEGRITY_STREAM    = 0x8000
	FILE_ATTRIBUTE_NO_SCRUB_DATA       = 0x20000
)

const (
	FileDirectoryInformation           = 1 + iota // 1
	FileFullDirectoryInformation                  // 2
	FileBothDirectoryInformation                  // 3
	FileBasicInformation                          // 4
	FileStandardInformation                       // 5
	FileInternalInformation                       // 6
	FileEaInformation                             // 7
	FileAccessInformation                         // 8
	FileNameInformation                           // 9
	FileRenameInformation                         // 10
	FileLinkInformation                           // 11
	FileNamesInformation                          // 12
	FileDispositionInformation                    // 13
	FilePositionInformation                       // 14
	FileFullEaInformation                         // 15
	FileModeInformation                           // 16
	FileAlignmentInformation                      // 17
	FileAllInformation                            // 18
	FileAllocationInformation                     // 19
	FileEndOfFileInformation                      // 20
	FileAlternateNameInformation                  // 21
	FileStreamInformation                         // 22
	FilePipeInformation                           // 23
	FilePipeLocalInformation                      // 24
	FilePipeRemoteInformation                     // 25
	FileMailslotQueryInformation                  // 26
	FileMailslotSetInformation                    // 27
	FileCompressionInformation                    // 28
	FileObjectIdInformation                       // 29
	_                                             // 30
	FileMoveClusterInformation                    // 31
	FileQuotaInformation                          // 32
	FileReparsePointInformation                   // 33
	FileNetworkOpenInformation                    // 34
	FileAttributeTagInformation                   // 35
	FileTrackingInformation                       // 36
	FileIdBothDirectoryInformation                // 37
	FileIdFullDirectoryInformation                // 38
	FileValidDataLengthInformation                // 39
	FileShortNameInformation                      // 40
	_                                             // 41
	_                                             // 42
	_                                             // 43
	FileSfioReserveInformation                    // 44
	FileSfioVolumeInformation                     // 45
	FileHardLinkInformation                       // 46
	_                                             // 47
	FileNormalizedNameInformation                 // 48
	_                                             // 49
	FildIdGlobalTxDirectoryInformation            // 50
	_                                             // 51
	_                                             // 52
	_                                             // 53
	FileStardardLinkInformation                   // 54
)

const (
	FileFsVolumeInformation = 1 + iota
	FileFsLabelInformation
	FileFsSizeInformation
	FileFsDeviceInformation
	FileFsAttributeInformation
	FileFsControlInformation
	FileFsFullSizeInformation
	FileFsObjectIdInformation
	FileFsDriverPathInformation
	FileFsVolumeFlagsInformation
	FileFsSectorSizeInformation
)

type FileDirectoryInformationDecoder []byte

func ( FileDirectoryInformationDecoder) () bool {
	return len() < int(64+.FileNameLength())
}

func ( FileDirectoryInformationDecoder) () uint32 {
	return le.Uint32([:4])
}

func ( FileDirectoryInformationDecoder) () uint32 {
	return le.Uint32([4:8])
}

func ( FileDirectoryInformationDecoder) () FiletimeDecoder {
	return FiletimeDecoder([8:16])
}

func ( FileDirectoryInformationDecoder) () FiletimeDecoder {
	return FiletimeDecoder([16:24])
}

func ( FileDirectoryInformationDecoder) () FiletimeDecoder {
	return FiletimeDecoder([24:32])
}

func ( FileDirectoryInformationDecoder) () FiletimeDecoder {
	return FiletimeDecoder([32:40])
}

func ( FileDirectoryInformationDecoder) () int64 {
	return int64(le.Uint64([40:48]))
}

func ( FileDirectoryInformationDecoder) () int64 {
	return int64(le.Uint64([48:56]))
}

func ( FileDirectoryInformationDecoder) () uint32 {
	return le.Uint32([56:60])
}

func ( FileDirectoryInformationDecoder) () uint32 {
	return le.Uint32([60:64])
}

func ( FileDirectoryInformationDecoder) () string {
	return utf16le.DecodeToString([64 : 64+.FileNameLength()])
}

type FileRenameInformationType2Encoder struct {
	ReplaceIfExists uint8
	RootDirectory   uint64
	FileName        string
}

func ( *FileRenameInformationType2Encoder) () int {
	return 20 + utf16le.EncodedStringLen(.FileName)
}

func ( *FileRenameInformationType2Encoder) ( []byte) {
	 := utf16le.EncodeString([20:], .FileName)

	[0] = .ReplaceIfExists
	le.PutUint64([8:16], .RootDirectory)
	le.PutUint32([16:20], uint32())
}

type FileLinkInformationType2Encoder struct {
	ReplaceIfExists uint8
	RootDirectory   uint64
	FileName        string
}

func ( *FileLinkInformationType2Encoder) () int {
	return 20 + utf16le.EncodedStringLen(.FileName)
}

func ( *FileLinkInformationType2Encoder) ( []byte) {
	 := utf16le.EncodeString([20:], .FileName)

	[0] = .ReplaceIfExists
	le.PutUint64([8:16], .RootDirectory)
	le.PutUint32([16:20], uint32())
}

type FileDispositionInformationEncoder struct {
	DeletePending uint8
}

func ( *FileDispositionInformationEncoder) () int {
	return 4
}

func ( *FileDispositionInformationEncoder) ( []byte) {
	[0] = .DeletePending
}

type FilePositionInformationEncoder struct {
	CurrentByteOffset int64
}

func ( *FilePositionInformationEncoder) () int {
	return 8
}

func ( *FilePositionInformationEncoder) ( []byte) {
	le.PutUint64([:8], uint64(.CurrentByteOffset))
}

type FileFsFullSizeInformationDecoder []byte

func ( FileFsFullSizeInformationDecoder) () bool {
	return len() < 32
}

func ( FileFsFullSizeInformationDecoder) () int64 {
	return int64(le.Uint64([:8]))
}

func ( FileFsFullSizeInformationDecoder) () int64 {
	return int64(le.Uint64([8:16]))
}

func ( FileFsFullSizeInformationDecoder) () int64 {
	return int64(le.Uint64([16:24]))
}

func ( FileFsFullSizeInformationDecoder) () uint32 {
	return le.Uint32([24:28])
}

func ( FileFsFullSizeInformationDecoder) () uint32 {
	return le.Uint32([28:32])
}

type FileQuotaInformationDecoder []byte

func ( FileQuotaInformationDecoder) () bool {
	return len() < int(40+.SidLength())
}

func ( FileQuotaInformationDecoder) () uint32 {
	return le.Uint32([:4])
}

func ( FileQuotaInformationDecoder) () uint32 {
	return le.Uint32([4:8])
}

func ( FileQuotaInformationDecoder) () FiletimeDecoder {
	return FiletimeDecoder([8:16])
}

func ( FileQuotaInformationDecoder) () int64 {
	return int64(le.Uint64([16:24]))
}

func ( FileQuotaInformationDecoder) () int64 {
	return int64(le.Uint64([24:32]))
}

func ( FileQuotaInformationDecoder) () int64 {
	return int64(le.Uint64([32:40]))
}

func ( FileQuotaInformationDecoder) () SidDecoder {
	return SidDecoder([40 : 40+.SidLength()])
}

type FileEndOfFileInformationEncoder struct {
	EndOfFile int64
}

func ( *FileEndOfFileInformationEncoder) () int {
	return 8
}

func ( *FileEndOfFileInformationEncoder) ( []byte) {
	le.PutUint64([:8], uint64(.EndOfFile))
}

type FileEndOfFileInformationDecoder []byte

func ( FileEndOfFileInformationDecoder) () bool {
	return len() < 8
}

func ( FileEndOfFileInformationDecoder) () int64 {
	return int64(le.Uint64([:8]))
}

type FileAllInformationDecoder []byte

func ( FileAllInformationDecoder) () bool {
	return len() < 96
}

func ( FileAllInformationDecoder) () FileBasicInformationDecoder {
	return FileBasicInformationDecoder([:40])
}

func ( FileAllInformationDecoder) () FileStandardInformationDecoder {
	return FileStandardInformationDecoder([40:64])
}

func ( FileAllInformationDecoder) () FileInternalInformationDecoder {
	return FileInternalInformationDecoder([64:72])
}

func ( FileAllInformationDecoder) () FileEaInformationDecoder {
	return FileEaInformationDecoder([72:76])
}

func ( FileAllInformationDecoder) () FileAccessInformationDecoder {
	return FileAccessInformationDecoder([76:80])
}

func ( FileAllInformationDecoder) () FilePositionInformationDecoder {
	return FilePositionInformationDecoder([80:88])
}

func ( FileAllInformationDecoder) () FileModeInformationDecoder {
	return FileModeInformationDecoder([88:92])
}

func ( FileAllInformationDecoder) () FileAlignmentInformationDecoder {
	return FileAlignmentInformationDecoder([92:96])
}

func ( FileAllInformationDecoder) () FileNameInformationDecoder {
	return FileNameInformationDecoder([96:])
}

type FileBasicInformationEncoder struct {
	CreationTime   *Filetime
	LastAccessTime *Filetime
	LastWriteTime  *Filetime
	ChangeTime     *Filetime
	FileAttributes uint32
}

func ( *FileBasicInformationEncoder) () int {
	return 40
}

func ( *FileBasicInformationEncoder) ( []byte) {
	if .CreationTime != nil {
		.CreationTime.Encode([:8])
	}
	if .LastAccessTime != nil {
		.LastAccessTime.Encode([8:16])
	}
	if .LastWriteTime != nil {
		.LastWriteTime.Encode([16:24])
	}
	if .ChangeTime != nil {
		.ChangeTime.Encode([24:32])
	}
	le.PutUint32([32:36], .FileAttributes)
}

type FileBasicInformationDecoder []byte

func ( FileBasicInformationDecoder) () bool {
	return len() < 40
}

func ( FileBasicInformationDecoder) () FiletimeDecoder {
	return FiletimeDecoder([:8])
}

func ( FileBasicInformationDecoder) () FiletimeDecoder {
	return FiletimeDecoder([8:16])
}

func ( FileBasicInformationDecoder) () FiletimeDecoder {
	return FiletimeDecoder([16:24])
}

func ( FileBasicInformationDecoder) () FiletimeDecoder {
	return FiletimeDecoder([24:32])
}

func ( FileBasicInformationDecoder) () uint32 {
	return le.Uint32([32:36])
}

type FileStandardInformationDecoder []byte

func ( FileStandardInformationDecoder) () bool {
	return len() < 24
}

func ( FileStandardInformationDecoder) () int64 {
	return int64(le.Uint64([:8]))
}

func ( FileStandardInformationDecoder) () int64 {
	return int64(le.Uint64([8:16]))
}

func ( FileStandardInformationDecoder) () uint32 {
	return le.Uint32([16:20])
}

func ( FileStandardInformationDecoder) () uint8 {
	return [20]
}

func ( FileStandardInformationDecoder) () uint8 {
	return [21]
}

type FileInternalInformationDecoder []byte

func ( FileInternalInformationDecoder) () bool {
	return len() < 8
}

func ( FileInternalInformationDecoder) () int64 {
	return int64(le.Uint64([:8]))
}

type FileEaInformationDecoder []byte

func ( FileEaInformationDecoder) () bool {
	return len() < 4
}

func ( FileEaInformationDecoder) () uint32 {
	return le.Uint32([:4])
}

type FileAccessInformationDecoder []byte

func ( FileAccessInformationDecoder) () bool {
	return len() < 4
}

func ( FileAccessInformationDecoder) () uint32 {
	return le.Uint32([:4])
}

type FilePositionInformationDecoder []byte

func ( FilePositionInformationDecoder) () bool {
	return len() < 8
}

func ( FilePositionInformationDecoder) () int64 {
	return int64(le.Uint64([:8]))
}

type FileModeInformationDecoder []byte

func ( FileModeInformationDecoder) () bool {
	return len() < 4
}

func ( FileModeInformationDecoder) () uint32 {
	return le.Uint32([:4])
}

type FileAlignmentInformationDecoder []byte

func ( FileAlignmentInformationDecoder) () bool {
	return len() < 4
}

func ( FileAlignmentInformationDecoder) () uint32 {
	return le.Uint32([:4])
}

type FileNameInformationDecoder []byte

func ( FileNameInformationDecoder) () bool {
	if len() < 4 {
		return true
	}

	if len() < int(4+.FileNameLength()) {
		return true
	}

	return false
}

func ( FileNameInformationDecoder) () uint32 {
	return le.Uint32([:4])
}

func ( FileNameInformationDecoder) () string {
	return utf16le.DecodeToString([4 : 4+.FileNameLength()])
}