fix workspace output and cleanup uncertainty
This commit is contained in:
@@ -131,6 +131,22 @@ func closeWindowsHandles(handles []windows.Handle) {
|
||||
}
|
||||
}
|
||||
|
||||
var windowsDeleteHandle = deleteWindowsHandle
|
||||
var windowsCloseHandle = windows.CloseHandle
|
||||
var windowsCloseStage = func(file *os.File) error { return file.Close() }
|
||||
|
||||
func cleanupWindowsStage(handle windows.Handle, closeStage func() error) error {
|
||||
disposeErr := windowsDeleteHandle(handle)
|
||||
closeErr := closeStage()
|
||||
if disposeErr == nil && closeErr == nil {
|
||||
// A successful disposition plus close proves the named stage is gone.
|
||||
return ErrUnsafeFile
|
||||
}
|
||||
// Either a failed disposition or an uncertain close leaves the named
|
||||
// candidate's reachability unresolved. Never classify this as retry-safe.
|
||||
return ErrIndeterminateFile
|
||||
}
|
||||
|
||||
func writeCanonicalExclusive(path string, contents []byte, mode fs.FileMode) error {
|
||||
if err := ValidateCanonicalPath(path); err != nil || len(contents) > 16<<20 || mode.Perm() != 0o600 {
|
||||
return ErrUnsafeFile
|
||||
@@ -160,8 +176,11 @@ func writeCanonicalExclusive(path string, contents []byte, mode fs.FileMode) err
|
||||
}
|
||||
stageFile := os.NewFile(uintptr(stageHandle), "thothctl-safeio-stage")
|
||||
if stageFile == nil {
|
||||
_ = deleteWindowsHandle(stageHandle)
|
||||
_ = windows.CloseHandle(stageHandle)
|
||||
disposeErr := windowsDeleteHandle(stageHandle)
|
||||
closeErr := windowsCloseHandle(stageHandle)
|
||||
if disposeErr != nil || closeErr != nil {
|
||||
return ErrIndeterminateFile
|
||||
}
|
||||
return ErrUnsafeFile
|
||||
}
|
||||
closed := false
|
||||
@@ -170,14 +189,14 @@ func writeCanonicalExclusive(path string, contents []byte, mode fs.FileMode) err
|
||||
return nil
|
||||
}
|
||||
closed = true
|
||||
return stageFile.Close()
|
||||
return windowsCloseStage(stageFile)
|
||||
}
|
||||
defer func() { _ = closeStage() }()
|
||||
var staged windows.ByHandleFileInformation
|
||||
if err := windows.GetFileInformationByHandle(stageHandle, &staged); err != nil || staged.NumberOfLinks != 1 || staged.FileAttributes&windows.FILE_ATTRIBUTE_REPARSE_POINT != 0 || staged.FileAttributes&windows.FILE_ATTRIBUTE_DIRECTORY != 0 {
|
||||
return failWindowsStage(stageHandle, closeStage)
|
||||
return cleanupWindowsStage(stageHandle, closeStage)
|
||||
}
|
||||
fail := func() error { _ = deleteWindowsHandle(stageHandle); _ = closeStage(); return ErrUnsafeFile }
|
||||
fail := func() error { return cleanupWindowsStage(stageHandle, closeStage) }
|
||||
if n, err := stageFile.Write(contents); err != nil || n != len(contents) {
|
||||
return fail()
|
||||
}
|
||||
@@ -199,13 +218,6 @@ func writeCanonicalExclusive(path string, contents []byte, mode fs.FileMode) err
|
||||
return nil
|
||||
}
|
||||
|
||||
// failWindowsStage disposes an exact handle when initial identity inspection fails.
|
||||
func failWindowsStage(handle windows.Handle, closeStage func() error) error {
|
||||
_ = deleteWindowsHandle(handle)
|
||||
_ = closeStage()
|
||||
return ErrUnsafeFile
|
||||
}
|
||||
|
||||
func deleteWindowsHandle(handle windows.Handle) error {
|
||||
var disposition byte = 1
|
||||
return windows.SetFileInformationByHandle(handle, windows.FileDispositionInfo, &disposition, uint32(unsafe.Sizeof(disposition)))
|
||||
|
||||
Reference in New Issue
Block a user