//go:build windows package safeio import ( "errors" "io" "os" "runtime" "sort" "time" "unsafe" "golang.org/x/sys/windows" ) // windowsPrivateDirectory keeps the root's canonical component handles alive, then uses NT // RootDirectory-relative opens for every descendant. Unlike a lexical child path, an NT relative // object name is resolved by the already-open directory handle and cannot be redirected by a // rename, replacement, or reparse point at the original root path. type windowsPrivateDirectory struct { anchors *windowsParentHandles parent windows.Handle handle windows.Handle info windows.ByHandleFileInformation } type windowsPrivateRegularAt struct { handle windows.Handle info windows.ByHandleFileInformation } func openPrivateDirectory(path string, ensure bool) (PrivateDirectoryHandle, bool, error) { anchors, target, err := openCanonicalWindowsParent(path) if err != nil || anchors == nil || len(anchors.handles) == 0 { if anchors != nil { anchors.Close() } return nil, false, ErrUnsafeFile } parent := anchors.handles[len(anchors.handles)-1] handle, found, err := openWindowsPrivateDirectoryAt(parent, target, false) if err != nil { anchors.Close() return nil, false, ErrUnsafeFile } if !found { // The final root is absent. The retained canonical parent must prove that the same // ensure operation could create it; validation itself must remain side-effect free. // FILE_APPEND_DATA is the Win32 spelling of directory FILE_ADD_SUBDIRECTORY. probe, probeErr := openWindowsComponentWithAccess(anchors.directory, true, windows.FILE_APPEND_DATA) if probeErr != nil { anchors.Close() return nil, false, ErrUnsafeFile } _ = windows.CloseHandle(probe) if !ensure { anchors.Close() return nil, false, nil } // The canonical parent chain remains pinned by anchors; this extra handle supplies // FILE_ADD_SUBDIRECTORY for the one initial root creation without reopening a child // beneath the private root lexically. writableParent, writableErr := openWindowsComponentWithAccess(anchors.directory, true, windows.FILE_APPEND_DATA) if writableErr != nil { anchors.Close() return nil, false, ErrUnsafeFile } handle, found, err = openWindowsPrivateDirectoryAt(writableParent, target, true) _ = windows.CloseHandle(writableParent) if err != nil || !found { anchors.Close() return nil, false, ErrUnsafeFile } } value := &windowsPrivateDirectory{anchors: anchors, handle: handle} if value.captureAndValidate() != nil { _ = value.Close() return nil, false, ErrUnsafeFile } return value, true, nil } func openWindowsPrivateDirectoryAt(parent windows.Handle, name string, ensure bool) (windows.Handle, bool, error) { if parent == 0 || !validPrivateLeafName(name) { return 0, false, ErrUnsafeFile } for attempt := 0; attempt < 2; attempt++ { handle, err := openWindowsRelativeDirectory(parent, name) if err == nil { return handle, true, nil } if !isWindowsRelativeNotFound(err) { return 0, false, ErrUnsafeFile } if !ensure { return 0, false, nil } handle, err = createWindowsRelativePrivateDirectory(parent, name) if err == nil { return handle, true, nil } } return 0, false, ErrUnsafeFile } func openWindowsRelativeDirectory(parent windows.Handle, name string) (windows.Handle, error) { handle, err := openWindowsRelativeObject( parent, name, // The retained directory handle is also the RootDirectory for create, rename, // hard-link, and delete operations below, so it needs the owner's full private // directory capability rather than a read-only probe handle. windows.FILE_GENERIC_READ|windows.FILE_GENERIC_WRITE|windows.DELETE, windows.FILE_OPEN, windows.FILE_DIRECTORY_FILE|windows.FILE_SYNCHRONOUS_IO_NONALERT|windows.FILE_OPEN_REPARSE_POINT, nil, ) if err != nil { return 0, err } if _, err := privateWindowsDirectoryInfo(handle); err != nil { _ = windows.CloseHandle(handle) return 0, ErrUnsafeFile } return handle, nil } func createWindowsRelativePrivateDirectory(parent windows.Handle, name string) (windows.Handle, error) { security, err := newOwnerOnlySecurityDescriptor() if err != nil { return 0, ErrUnsafeFile } defer security.Close() handle, err := openWindowsRelativeObject( parent, name, windows.FILE_GENERIC_READ|windows.FILE_GENERIC_WRITE|windows.DELETE, windows.FILE_CREATE, windows.FILE_DIRECTORY_FILE|windows.FILE_SYNCHRONOUS_IO_NONALERT|windows.FILE_OPEN_REPARSE_POINT, security, ) if err != nil { return 0, err } if _, err := privateWindowsDirectoryInfo(handle); err != nil { _ = markWindowsHandleForDelete(handle) _ = windows.CloseHandle(handle) return 0, ErrUnsafeFile } return handle, nil } func openWindowsRelativeObject( parent windows.Handle, name string, access uint32, disposition uint32, options uint32, security *ownerOnlySecurityDescriptor, ) (windows.Handle, error) { if parent == 0 || !validPrivateLeafName(name) { return 0, ErrUnsafeFile } objectName, err := windows.NewNTUnicodeString(name) if err != nil { return 0, ErrUnsafeFile } attributes := &windows.OBJECT_ATTRIBUTES{ Length: uint32(unsafe.Sizeof(windows.OBJECT_ATTRIBUTES{})), RootDirectory: parent, ObjectName: objectName, Attributes: windows.OBJ_CASE_INSENSITIVE, SecurityDescriptor: nil, } if security != nil { attributes.SecurityDescriptor = security.descriptor } var ( handle windows.Handle status windows.IO_STATUS_BLOCK allocationSize int64 ) err = windows.NtCreateFile( &handle, access, attributes, &status, &allocationSize, windows.FILE_ATTRIBUTE_NORMAL, windowsRetainedHandleShareMode, disposition, options, 0, 0, ) runtime.KeepAlive(objectName) runtime.KeepAlive(security) if err != nil { return 0, err } return handle, nil } func privateWindowsDirectoryInfo(handle windows.Handle) (windows.ByHandleFileInformation, error) { var info windows.ByHandleFileInformation if handle == 0 || windows.GetFileInformationByHandle(handle, &info) != nil || info.FileAttributes&windows.FILE_ATTRIBUTE_REPARSE_POINT != 0 || info.FileAttributes&windows.FILE_ATTRIBUTE_DIRECTORY == 0 || validateOwnerOnlyDACL(handle) != nil { return windows.ByHandleFileInformation{}, ErrUnsafeFile } return info, nil } func privateWindowsRegularInfo(handle windows.Handle, allowedLinks ...uint32) (windows.ByHandleFileInformation, error) { var info windows.ByHandleFileInformation if handle == 0 || windows.GetFileInformationByHandle(handle, &info) != nil || info.FileAttributes&windows.FILE_ATTRIBUTE_REPARSE_POINT != 0 || info.FileAttributes&windows.FILE_ATTRIBUTE_DIRECTORY != 0 || validateOwnerOnlyDACL(handle) != nil { return windows.ByHandleFileInformation{}, ErrUnsafeFile } for _, links := range allowedLinks { if info.NumberOfLinks == links { return info, nil } } return windows.ByHandleFileInformation{}, ErrUnsafeFile } func isWindowsRelativeNotFound(err error) bool { return errors.Is(err, windows.ERROR_FILE_NOT_FOUND) || errors.Is(err, windows.ERROR_PATH_NOT_FOUND) || errors.Is(err, windows.STATUS_NO_SUCH_FILE) || errors.Is(err, windows.STATUS_OBJECT_NAME_NOT_FOUND) || errors.Is(err, windows.STATUS_OBJECT_PATH_NOT_FOUND) } func isWindowsRelativeCollision(err error) bool { return errors.Is(err, windows.ERROR_FILE_EXISTS) || errors.Is(err, windows.ERROR_ALREADY_EXISTS) || errors.Is(err, windows.STATUS_OBJECT_NAME_COLLISION) } func (directory *windowsPrivateDirectory) captureAndValidate() error { if directory == nil || directory.handle == 0 { return ErrUnsafeFile } info, err := privateWindowsDirectoryInfo(directory.handle) if err != nil { return ErrUnsafeFile } directory.info = info return nil } func (directory *windowsPrivateDirectory) Close() error { if directory == nil { return nil } var result error if directory.handle != 0 { if err := windows.CloseHandle(directory.handle); err != nil { result = ErrUnsafeFile } directory.handle = 0 } if directory.parent != 0 { if err := windows.CloseHandle(directory.parent); err != nil { result = ErrUnsafeFile } directory.parent = 0 } if directory.anchors != nil { directory.anchors.Close() directory.anchors = nil } return result } func sameWindowsPrivateDirectoryIdentity(left, right windows.ByHandleFileInformation) bool { return left.VolumeSerialNumber == right.VolumeSerialNumber && left.FileIndexHigh == right.FileIndexHigh && left.FileIndexLow == right.FileIndexLow && left.FileAttributes == right.FileAttributes } func sameWindowsPrivateDirectorySnapshot(left, right windows.ByHandleFileInformation) bool { return sameWindowsPrivateDirectoryIdentity(left, right) && left.LastWriteTime == right.LastWriteTime } func (directory *windowsPrivateDirectory) Validate() error { if directory == nil || directory.handle == 0 || (directory.anchors == nil && directory.parent == 0) { return ErrUnsafeFile } if directory.anchors != nil && len(directory.anchors.handles) == 0 { return ErrUnsafeFile } if directory.parent != 0 { if _, err := privateWindowsDirectoryInfo(directory.parent); err != nil { return ErrUnsafeFile } } current, err := privateWindowsDirectoryInfo(directory.handle) if err != nil || !sameWindowsPrivateDirectoryIdentity(directory.info, current) { return ErrUnsafeFile } return nil } func duplicateWindowsRetainedHandle(handle windows.Handle) (windows.Handle, error) { if handle == 0 { return 0, ErrUnsafeFile } var duplicate windows.Handle process := windows.CurrentProcess() if err := windows.DuplicateHandle(process, handle, process, &duplicate, 0, false, windows.DUPLICATE_SAME_ACCESS); err != nil { return 0, ErrUnsafeFile } return duplicate, nil } func (directory *windowsPrivateDirectory) OpenChild(name string, ensure bool) (PrivateDirectoryHandle, bool, error) { if directory.Validate() != nil || !validPrivateLeafName(name) { return nil, false, ErrUnsafeFile } parent, err := duplicateWindowsRetainedHandle(directory.handle) if err != nil { return nil, false, ErrUnsafeFile } handle, found, err := openWindowsPrivateDirectoryAt(parent, name, ensure) if err != nil || !found { _ = windows.CloseHandle(parent) if err != nil { return nil, false, ErrUnsafeFile } return nil, false, nil } child := &windowsPrivateDirectory{parent: parent, handle: handle} if child.captureAndValidate() != nil || directory.Validate() != nil { _ = child.Close() return nil, false, ErrUnsafeFile } return child, true, nil } func openWindowsPrivateRegularAt( parent windows.Handle, name string, access uint32, allowedLinks ...uint32, ) (*windowsPrivateRegularAt, error) { handle, err := openWindowsRelativeObject( parent, name, access, windows.FILE_OPEN, windows.FILE_NON_DIRECTORY_FILE|windows.FILE_SYNCHRONOUS_IO_NONALERT|windows.FILE_OPEN_REPARSE_POINT, nil, ) if err != nil { return nil, err } info, err := privateWindowsRegularInfo(handle, allowedLinks...) if err != nil { _ = windows.CloseHandle(handle) return nil, ErrUnsafeFile } return &windowsPrivateRegularAt{handle: handle, info: info}, nil } func openWindowsPrivateRegularAtAllowedLinks( parent windows.Handle, name string, access uint32, allowedLinks ...uint32, ) (*windowsPrivateRegularAt, error) { var ( lastError error unsafeFound bool ) for _, links := range allowedLinks { value, err := openWindowsPrivateRegularAt(parent, name, access, links) if err == nil { return value, nil } lastError = err if !isWindowsRelativeNotFound(err) { unsafeFound = true } } if unsafeFound { return nil, ErrUnsafeFile } return nil, lastError } func createWindowsPrivateRegularAt(parent windows.Handle, name string) (*windowsPrivateRegularAt, error) { return createWindowsPrivateRegularAtWithAccess(parent, name, windows.FILE_GENERIC_READ|windows.FILE_GENERIC_WRITE|windows.DELETE) } // createWindowsPrivateRegularAtWithAccess creates the final leaf beneath an already-retained // parent with an owner-only DACL in the same NtCreateFile operation. The caller never re-resolves // an absolute pathname after the parent is pinned. func createWindowsPrivateRegularAtWithAccess(parent windows.Handle, name string, access uint32) (*windowsPrivateRegularAt, error) { security, err := newOwnerOnlySecurityDescriptor() if err != nil { return nil, ErrUnsafeFile } defer security.Close() handle, err := openWindowsRelativeObject( parent, name, access|windows.DELETE, windows.FILE_CREATE, windows.FILE_NON_DIRECTORY_FILE|windows.FILE_SYNCHRONOUS_IO_NONALERT|windows.FILE_OPEN_REPARSE_POINT, security, ) if err != nil { return nil, err } info, err := privateWindowsRegularInfo(handle, 1) if err != nil { _ = markWindowsHandleForDelete(handle) _ = windows.CloseHandle(handle) return nil, ErrUnsafeFile } return &windowsPrivateRegularAt{handle: handle, info: info}, nil } func (value *windowsPrivateRegularAt) Close() error { if value == nil || value.handle == 0 { return nil } handle := value.handle value.handle = 0 if err := windows.CloseHandle(handle); err != nil { return ErrUnsafeFile } return nil } func writeWindowsPrivateRegular(value *windowsPrivateRegularAt, contents []byte) error { if value == nil || value.handle == 0 || len(contents) == 0 { return ErrUnsafeFile } for remaining := contents; len(remaining) > 0; { var written uint32 if err := windows.WriteFile(value.handle, remaining, &written, nil); err != nil || written == 0 || int(written) > len(remaining) { return ErrUnsafeFile } remaining = remaining[written:] } if err := windows.FlushFileBuffers(value.handle); err != nil { return ErrUnsafeFile } info, err := privateWindowsRegularInfo(value.handle, 1) if err != nil { return ErrUnsafeFile } value.info = info return nil } func readWindowsPrivateRegular(value *windowsPrivateRegularAt, maximum int64, links uint32) ([]byte, error) { if value == nil || value.handle == 0 || maximum < 0 || maximum == int64(^uint64(0)>>1) { return nil, ErrUnsafeFile } contents := make([]byte, 0, 4096) buffer := make([]byte, 4096) for { var read uint32 err := windows.ReadFile(value.handle, buffer, &read, nil) if read > 0 { if int64(len(contents))+int64(read) > maximum { return nil, ErrUnsafeFile } contents = append(contents, buffer[:read]...) } if err != nil { if errors.Is(err, windows.ERROR_HANDLE_EOF) { break } return nil, ErrUnsafeFile } if read == 0 { break } } after, err := privateWindowsRegularInfo(value.handle, links) if err != nil || !sameWindowsPrivateFile(value.info, after) { return nil, ErrUnsafeFile } value.info = after return contents, nil } func markWindowsHandleForDelete(handle windows.Handle) error { if handle == 0 { return ErrUnsafeFile } buffer := [1]byte{1} var status windows.IO_STATUS_BLOCK if err := windows.NtSetInformationFile(handle, &status, &buffer[0], uint32(len(buffer)), windows.FileDispositionInformation); err != nil { return ErrUnsafeFile } return nil } func closeAndDeleteWindowsPrivateRegular(value *windowsPrivateRegularAt) error { if value == nil || value.handle == 0 || markWindowsHandleForDelete(value.handle) != nil || value.Close() != nil { return ErrUnsafeFile } return nil } func (directory *windowsPrivateDirectory) CreateRegular(name string, contents []byte) (bool, error) { if directory.Validate() != nil || !validPrivateLeafName(name) || len(contents) == 0 { return false, ErrUnsafeFile } value, err := createWindowsPrivateRegularAt(directory.handle, name) if err != nil { existing, existingErr := openWindowsPrivateRegularAt(directory.handle, name, windows.FILE_GENERIC_READ, 1) if existingErr == nil { _ = existing.Close() return false, nil } return false, ErrUnsafeFile } published := false defer func() { if !published { _ = closeAndDeleteWindowsPrivateRegular(value) } }() if writeWindowsPrivateRegular(value, contents) != nil || directory.Validate() != nil { return false, ErrUnsafeFile } if value.Close() != nil { return false, ErrUnsafeFile } published = true return true, nil } func (directory *windowsPrivateDirectory) ReadRegular(name string, maximum int64) ([]byte, bool, error) { if directory.Validate() != nil || !validPrivateLeafName(name) || maximum < 0 || maximum == int64(^uint64(0)>>1) { return nil, false, ErrUnsafeFile } value, err := openWindowsPrivateRegularAt(directory.handle, name, windows.FILE_GENERIC_READ, 1) if isWindowsRelativeNotFound(err) { return nil, false, nil } if err != nil { return nil, false, ErrUnsafeFile } defer value.Close() contents, err := readWindowsPrivateRegular(value, maximum, 1) if err != nil || directory.Validate() != nil { return nil, false, ErrUnsafeFile } return contents, true, nil } type windowsRelativeNameInformation struct { Flags uint32 RootDirectory windows.Handle FileNameLength uint32 FileName [1]uint16 } func setWindowsRelativeNameInformation( handle windows.Handle, parent windows.Handle, name string, class uint32, flags uint32, ) error { if handle == 0 || parent == 0 || !validPrivateLeafName(name) { return ErrUnsafeFile } encoded, err := windows.UTF16FromString(name) if err != nil || len(encoded) < 2 { return ErrUnsafeFile } nameBytes := (len(encoded) - 1) * 2 var header windowsRelativeNameInformation size := int(unsafe.Offsetof(header.FileName)) + nameBytes buffer := make([]byte, size) value := (*windowsRelativeNameInformation)(unsafe.Pointer(&buffer[0])) value.Flags = flags value.RootDirectory = parent value.FileNameLength = uint32(nameBytes) copy(unsafe.Slice(&value.FileName[0], len(encoded)-1), encoded[:len(encoded)-1]) var status windows.IO_STATUS_BLOCK if err := windows.NtSetInformationFile(handle, &status, &buffer[0], uint32(len(buffer)), class); err != nil { return ErrUnsafeFile } runtime.KeepAlive(encoded) runtime.KeepAlive(buffer) return nil } func renameWindowsPrivateRegularAt(handle windows.Handle, parent windows.Handle, name string) error { return setWindowsRelativeNameInformation(handle, parent, name, windows.FileRenameInformation, windows.FILE_RENAME_REPLACE_IF_EXISTS) } func linkWindowsPrivateRegularAt(handle windows.Handle, parent windows.Handle, name string) error { return setWindowsRelativeNameInformation(handle, parent, name, windows.FileLinkInformation, 0) } func createWindowsPrivateTemporaryAt(parent windows.Handle, contents []byte) (*windowsPrivateRegularAt, error) { for attempt := 0; attempt < 16; attempt++ { name, err := randomTemporaryName() if err != nil { return nil, ErrUnsafeFile } value, err := createWindowsPrivateRegularAt(parent, name) if err != nil { if isWindowsRelativeCollision(err) { continue } return nil, ErrUnsafeFile } if writeWindowsPrivateRegular(value, contents) == nil { return value, nil } _ = closeAndDeleteWindowsPrivateRegular(value) return nil, ErrUnsafeFile } return nil, ErrUnsafeFile } func (directory *windowsPrivateDirectory) ReplaceRegular(name string, contents []byte) error { if directory.Validate() != nil || !validPrivateLeafName(name) || len(contents) == 0 { return ErrUnsafeFile } existing, err := openWindowsPrivateRegularAt(directory.handle, name, windows.FILE_GENERIC_READ, 1) if err != nil { return ErrUnsafeFile } if existing.Close() != nil { return ErrUnsafeFile } temporary, err := createWindowsPrivateTemporaryAt(directory.handle, contents) if err != nil { return ErrUnsafeFile } renamed := false defer func() { if !renamed { _ = closeAndDeleteWindowsPrivateRegular(temporary) } }() current, err := openWindowsPrivateRegularAt(directory.handle, name, windows.FILE_GENERIC_READ, 1) if err != nil || current.Close() != nil || directory.Validate() != nil { return ErrUnsafeFile } if renameWindowsPrivateRegularAt(temporary.handle, directory.handle, name) != nil || temporary.Close() != nil { return ErrUnsafeFile } renamed = true replaced, err := openWindowsPrivateRegularAt(directory.handle, name, windows.FILE_GENERIC_READ, 1) if err != nil || replaced.Close() != nil || directory.Validate() != nil { return ErrUnsafeFile } return nil } func (directory *windowsPrivateDirectory) RemoveRegular(name string) (bool, error) { if directory.Validate() != nil || !validPrivateLeafName(name) { return false, ErrUnsafeFile } value, err := openWindowsPrivateRegularAt(directory.handle, name, windows.FILE_GENERIC_READ|windows.DELETE, 1) if isWindowsRelativeNotFound(err) { return false, nil } if err != nil { return false, ErrUnsafeFile } if closeAndDeleteWindowsPrivateRegular(value) != nil || directory.Validate() != nil { return false, ErrUnsafeFile } return true, nil } func (directory *windowsPrivateDirectory) ListPage( maximumEntries int, afterName string, validName func(string) bool, validLinks func(string, uint64) bool, ) (PrivateDirectoryPage, error) { if directory.Validate() != nil || maximumEntries < 1 || maximumEntries > 4096 || validName == nil || validLinks == nil || (afterName != "" && !validName(afterName)) { return PrivateDirectoryPage{}, ErrUnsafeFile } var before windows.ByHandleFileInformation if err := windows.GetFileInformationByHandle(directory.handle, &before); err != nil || !sameWindowsPrivateDirectoryIdentity(directory.info, before) { return PrivateDirectoryPage{}, ErrUnsafeFile } duplicate, err := duplicateWindowsRetainedHandle(directory.handle) if err != nil { return PrivateDirectoryPage{}, ErrUnsafeFile } file := os.NewFile(uintptr(duplicate), "tht-safeio-private-root-list") if file == nil { _ = windows.CloseHandle(duplicate) return PrivateDirectoryPage{}, ErrUnsafeFile } defer file.Close() seen := make(map[string]struct{}, maximumEntries+1) selected := make([]PrivateDirectoryEntry, 0, maximumEntries+1) scanned := 0 for { entries, readErr := file.ReadDir(1) if readErr != nil && !errors.Is(readErr, io.EOF) { return PrivateDirectoryPage{}, ErrUnsafeFile } if len(entries) == 0 { break } if len(entries) != 1 { return PrivateDirectoryPage{}, ErrUnsafeFile } scanned++ if scanned > maximumPrivateDirectoryPageScanEntries { return PrivateDirectoryPage{}, ErrUnsafeFile } name := entries[0].Name() if !validPrivateLeafName(name) || !validName(name) { return PrivateDirectoryPage{}, ErrUnsafeFile } if _, duplicate := seen[name]; duplicate { return PrivateDirectoryPage{}, ErrUnsafeFile } seen[name] = struct{}{} value, valueErr := openWindowsPrivateRegularAtAllowedLinks(directory.handle, name, windows.FILE_GENERIC_READ, 1, 2) if valueErr != nil { return PrivateDirectoryPage{}, ErrUnsafeFile } info := value.info if value.Close() != nil { return PrivateDirectoryPage{}, ErrUnsafeFile } if !validLinks(name, uint64(info.NumberOfLinks)) { return PrivateDirectoryPage{}, ErrUnsafeFile } if name > afterName { selected = appendBoundedPrivateDirectoryEntry(selected, PrivateDirectoryEntry{ Name: name, ModifiedUnixMs: time.Unix(0, info.LastWriteTime.Nanoseconds()).UnixMilli(), }, maximumEntries+1) } if errors.Is(readErr, io.EOF) { break } } var after windows.ByHandleFileInformation if windows.GetFileInformationByHandle(directory.handle, &after) != nil || directory.Validate() != nil || !sameWindowsPrivateDirectorySnapshot(before, after) { return PrivateDirectoryPage{}, ErrUnsafeFile } sort.Slice(selected, func(left, right int) bool { return selected[left].Name < selected[right].Name }) more := len(selected) > maximumEntries if more { selected = selected[:maximumEntries] } return PrivateDirectoryPage{Entries: selected, More: more}, nil } func sameWindowsRelativeClaim(source, claim *windowsPrivateRegularAt) bool { return source != nil && claim != nil && sameWindowsPrivateFile(source.info, claim.info) } func windowsRelativeClaimPairExists(directory *windowsPrivateDirectory, source, claim string) (bool, error) { left, err := openWindowsPrivateRegularAt(directory.handle, source, windows.FILE_GENERIC_READ, 2) if isWindowsRelativeNotFound(err) { return false, nil } if err != nil { return false, ErrUnsafeFile } defer left.Close() right, err := openWindowsPrivateRegularAt(directory.handle, claim, windows.FILE_GENERIC_READ, 2) if isWindowsRelativeNotFound(err) { return false, nil } if err != nil { return false, ErrUnsafeFile } defer right.Close() return sameWindowsRelativeClaim(left, right), nil } func windowsRelativeClaimAbsentOrOrphan(directory *windowsPrivateDirectory, source, claim string) (bool, error) { current, err := openWindowsPrivateRegularAtAllowedLinks(directory.handle, source, windows.FILE_GENERIC_READ, 1, 2) if err == nil { _ = current.Close() return false, nil } if !isWindowsRelativeNotFound(err) { return false, ErrUnsafeFile } orphan, err := openWindowsPrivateRegularAt(directory.handle, claim, windows.FILE_GENERIC_READ, 1) if err == nil { _ = orphan.Close() return true, nil } if isWindowsRelativeNotFound(err) { return true, nil } return false, ErrUnsafeFile } func (directory *windowsPrivateDirectory) ClaimRegular(source, claim string) (bool, error) { if directory.Validate() != nil || !validPrivateLeafName(source) || !validPrivateLeafName(claim) { return false, ErrUnsafeFile } value, err := openWindowsPrivateRegularAt( directory.handle, source, windows.FILE_GENERIC_READ|windows.FILE_GENERIC_WRITE|windows.DELETE, 1, ) if err != nil { pair, pairErr := windowsRelativeClaimPairExists(directory, source, claim) if pairErr == nil && pair { return false, nil } orphan, orphanErr := windowsRelativeClaimAbsentOrOrphan(directory, source, claim) if orphanErr == nil && orphan { return false, nil } return false, ErrUnsafeFile } defer value.Close() if linkWindowsPrivateRegularAt(value.handle, directory.handle, claim) != nil { existing, existingErr := openWindowsPrivateRegularAtAllowedLinks(directory.handle, claim, windows.FILE_GENERIC_READ, 1, 2) if existingErr == nil { _ = existing.Close() return false, nil } return false, ErrUnsafeFile } after, err := privateWindowsRegularInfo(value.handle, 2) if err != nil { return false, ErrUnsafeFile } value.info = after claimed, err := openWindowsPrivateRegularAt(directory.handle, claim, windows.FILE_GENERIC_READ, 2) if err != nil { return false, ErrUnsafeFile } defer claimed.Close() if !sameWindowsRelativeClaim(value, claimed) || directory.Validate() != nil { return false, ErrUnsafeFile } return true, nil } func (directory *windowsPrivateDirectory) ReadClaim(source, claim string, maximum int64) ([]byte, bool, error) { if directory.Validate() != nil || !validPrivateLeafName(source) || !validPrivateLeafName(claim) || maximum < 0 || maximum == int64(^uint64(0)>>1) { return nil, false, ErrUnsafeFile } value, err := openWindowsPrivateRegularAt(directory.handle, source, windows.FILE_GENERIC_READ, 2) if err != nil { orphan, orphanErr := windowsRelativeClaimAbsentOrOrphan(directory, source, claim) if orphanErr == nil && orphan { return nil, false, nil } return nil, false, ErrUnsafeFile } defer value.Close() claimed, err := openWindowsPrivateRegularAt(directory.handle, claim, windows.FILE_GENERIC_READ, 2) if isWindowsRelativeNotFound(err) { return nil, false, nil } if err != nil { return nil, false, ErrUnsafeFile } defer claimed.Close() if !sameWindowsRelativeClaim(value, claimed) { return nil, false, ErrUnsafeFile } contents, err := readWindowsPrivateRegular(value, maximum, 2) if err != nil { return nil, false, ErrUnsafeFile } afterClaim, err := privateWindowsRegularInfo(claimed.handle, 2) if err != nil || !sameWindowsPrivateFile(value.info, afterClaim) || directory.Validate() != nil { return nil, false, ErrUnsafeFile } return contents, true, nil } func (directory *windowsPrivateDirectory) RemoveClaim(source, claim string) (bool, error) { if directory.Validate() != nil || !validPrivateLeafName(source) || !validPrivateLeafName(claim) { return false, ErrUnsafeFile } value, err := openWindowsPrivateRegularAt(directory.handle, source, windows.FILE_GENERIC_READ|windows.DELETE, 2) if err != nil { orphan, orphanErr := windowsRelativeClaimAbsentOrOrphan(directory, source, claim) if orphanErr == nil && orphan { return false, nil } return false, ErrUnsafeFile } claimed, err := openWindowsPrivateRegularAt(directory.handle, claim, windows.FILE_GENERIC_READ, 2) if isWindowsRelativeNotFound(err) { _ = value.Close() return false, nil } if err != nil || !sameWindowsRelativeClaim(value, claimed) { _ = value.Close() if claimed != nil { _ = claimed.Close() } return false, ErrUnsafeFile } if claimed.Close() != nil || closeAndDeleteWindowsPrivateRegular(value) != nil { return false, ErrUnsafeFile } remaining, err := openWindowsPrivateRegularAt(directory.handle, claim, windows.FILE_GENERIC_READ|windows.DELETE, 1) if err != nil || closeAndDeleteWindowsPrivateRegular(remaining) != nil || directory.Validate() != nil { return false, ErrUnsafeFile } return true, nil }