fix workspace output and cleanup uncertainty

This commit is contained in:
2026-08-11 04:46:48 +02:00
parent c7f7a6e1b0
commit 69cc47c13f
12 changed files with 358 additions and 91 deletions
+24 -12
View File
@@ -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)))