113 lines
3.4 KiB
Go
113 lines
3.4 KiB
Go
//go:build windows
|
|
|
|
package safeio
|
|
|
|
import (
|
|
"path/filepath"
|
|
|
|
"golang.org/x/sys/windows"
|
|
)
|
|
|
|
type windowsPrivateRegular struct {
|
|
parents *windowsParentHandles
|
|
handle windows.Handle
|
|
info windows.ByHandleFileInformation
|
|
}
|
|
|
|
func (value *windowsPrivateRegular) Close() {
|
|
if value.handle != 0 {
|
|
_ = windows.CloseHandle(value.handle)
|
|
value.handle = 0
|
|
}
|
|
if value.parents != nil {
|
|
value.parents.Close()
|
|
value.parents = nil
|
|
}
|
|
}
|
|
|
|
func openWindowsPrivateRegular(path string, links uint32) (*windowsPrivateRegular, error) {
|
|
parents, target, err := openCanonicalWindowsParent(path)
|
|
if err != nil || parents == nil || len(parents.handles) == 0 || validateOwnerOnlyDACL(parents.handles[len(parents.handles)-1]) != nil {
|
|
if parents != nil {
|
|
parents.Close()
|
|
}
|
|
return nil, ErrUnsafeFile
|
|
}
|
|
value, err := openWindowsPrivateRegularAt(parents.handles[len(parents.handles)-1], target, windows.GENERIC_READ, links)
|
|
if err != nil {
|
|
parents.Close()
|
|
return nil, err
|
|
}
|
|
handle := value.handle
|
|
value.handle = 0
|
|
return &windowsPrivateRegular{
|
|
parents: parents,
|
|
handle: handle,
|
|
info: value.info,
|
|
}, nil
|
|
}
|
|
|
|
func claimCanonicalPrivateRegular(source, claim string) (claimed bool, resultErr error) {
|
|
directory, sourceName, claimName, err := openWindowsPrivateClaimDirectory(source, claim)
|
|
if err != nil {
|
|
return false, ErrUnsafeFile
|
|
}
|
|
defer func() {
|
|
if closeErr := directory.Close(); closeErr != nil && resultErr == nil {
|
|
claimed = false
|
|
resultErr = ErrUnsafeFile
|
|
}
|
|
}()
|
|
return directory.ClaimRegular(sourceName, claimName)
|
|
}
|
|
|
|
func readCanonicalPrivateClaim(source, claim string, maximum int64) (contents []byte, found bool, resultErr error) {
|
|
directory, sourceName, claimName, err := openWindowsPrivateClaimDirectory(source, claim)
|
|
if err != nil {
|
|
return nil, false, ErrUnsafeFile
|
|
}
|
|
defer func() {
|
|
if closeErr := directory.Close(); closeErr != nil && resultErr == nil {
|
|
contents = nil
|
|
found = false
|
|
resultErr = ErrUnsafeFile
|
|
}
|
|
}()
|
|
return directory.ReadClaim(sourceName, claimName, maximum)
|
|
}
|
|
|
|
func openWindowsPrivateClaimDirectory(source, claim string) (PrivateDirectoryHandle, string, string, error) {
|
|
parentPath := filepath.Dir(source)
|
|
sourceName := filepath.Base(source)
|
|
claimName := filepath.Base(claim)
|
|
if parentPath != filepath.Dir(claim) || !validPrivateLeafName(sourceName) || !validPrivateLeafName(claimName) {
|
|
return nil, "", "", ErrUnsafeFile
|
|
}
|
|
directory, found, err := OpenPrivateDirectory(parentPath, false)
|
|
if err != nil || !found {
|
|
if directory != nil {
|
|
_ = directory.Close()
|
|
}
|
|
return nil, "", "", ErrUnsafeFile
|
|
}
|
|
return directory, sourceName, claimName, nil
|
|
}
|
|
|
|
func removeCanonicalPrivateClaim(source, claim string) (removed bool, resultErr error) {
|
|
directory, sourceName, claimName, err := openWindowsPrivateClaimDirectory(source, claim)
|
|
if err != nil {
|
|
return false, ErrUnsafeFile
|
|
}
|
|
defer func() {
|
|
if closeErr := directory.Close(); closeErr != nil && resultErr == nil {
|
|
resultErr = ErrUnsafeFile
|
|
}
|
|
}()
|
|
NotifyPrivateDirectoryTestHookForTest("after-canonical-private-claim-parent-open")
|
|
return directory.RemoveClaim(sourceName, claimName)
|
|
}
|
|
|
|
func sameWindowsPrivateFile(left, right windows.ByHandleFileInformation) bool {
|
|
return left.VolumeSerialNumber == right.VolumeSerialNumber && left.FileIndexHigh == right.FileIndexHigh && left.FileIndexLow == right.FileIndexLow && left.FileSizeHigh == right.FileSizeHigh && left.FileSizeLow == right.FileSizeLow && left.LastWriteTime == right.LastWriteTime
|
|
}
|