diff --git a/tools/tht/internal/safeio/private_windows_test.go b/tools/tht/internal/safeio/private_windows_test.go index c17595b0..3cbf63c5 100644 --- a/tools/tht/internal/safeio/private_windows_test.go +++ b/tools/tht/internal/safeio/private_windows_test.go @@ -4,6 +4,7 @@ package safeio import ( "errors" + "fmt" "os" "path/filepath" "runtime" @@ -76,7 +77,7 @@ func TestOwnerOnlyDACLNativeShape(t *testing.T) { } parents, target, err := openCanonicalWindowsParent(directory) if err != nil { - t.Fatalf("openCanonicalWindowsParent() error = %T %v", err, err) + t.Fatalf("openCanonicalWindowsParent() error = %T %v; relative-open matrix: %s", err, err, windowsRelativeOpenMatrix(directory)) } defer parents.Close() handle, err := openWindowsRelativeComponent( @@ -135,6 +136,58 @@ func TestOwnerOnlyDACLNativeShape(t *testing.T) { } } +func windowsRelativeOpenMatrix(path string) string { + volume := filepath.VolumeName(path) + root := volume + `\` + components := strings.Split(strings.TrimPrefix(path, root), `\`) + if volume == "" || len(components) == 0 || components[0] == "" { + return "invalid diagnostic path" + } + rootHandle, err := openWindowsComponentWithAccess(root, true, windows.GENERIC_READ) + if err != nil { + return fmt.Sprintf("root=%T %v", err, err) + } + defer windows.CloseHandle(rootHandle) + type attempt struct { + name string + access uint32 + options uint32 + shareMode uint32 + } + attempts := []attempt{ + {name: "generic-read-directory", access: windows.GENERIC_READ, options: windows.FILE_DIRECTORY_FILE}, + {name: "generic-read-sync-directory", access: windows.GENERIC_READ, options: windows.FILE_DIRECTORY_FILE | windows.FILE_SYNCHRONOUS_IO_NONALERT}, + {name: "generic-read-reparse-directory", access: windows.GENERIC_READ, options: windows.FILE_DIRECTORY_FILE | windows.FILE_OPEN_REPARSE_POINT}, + {name: "generic-read-all-options", access: windows.GENERIC_READ, options: windows.FILE_DIRECTORY_FILE | windows.FILE_SYNCHRONOUS_IO_NONALERT | windows.FILE_OPEN_REPARSE_POINT}, + {name: "file-read-all-options", access: windows.FILE_GENERIC_READ, options: windows.FILE_DIRECTORY_FILE | windows.FILE_SYNCHRONOUS_IO_NONALERT | windows.FILE_OPEN_REPARSE_POINT}, + {name: "traverse-read-all-options", access: windows.GENERIC_READ | windows.FILE_TRAVERSE, options: windows.FILE_DIRECTORY_FILE | windows.FILE_SYNCHRONOUS_IO_NONALERT | windows.FILE_OPEN_REPARSE_POINT}, + {name: "generic-read-all-share", access: windows.GENERIC_READ, options: windows.FILE_DIRECTORY_FILE | windows.FILE_SYNCHRONOUS_IO_NONALERT | windows.FILE_OPEN_REPARSE_POINT, shareMode: windows.FILE_SHARE_READ | windows.FILE_SHARE_WRITE | windows.FILE_SHARE_DELETE}, + } + results := make([]string, 0, len(attempts)) + for _, test := range attempts { + shareMode := test.shareMode + if shareMode == 0 { + shareMode = windowsRetainedHandleShareMode + } + handle, openErr := openWindowsRelativeObjectWithShareMode( + rootHandle, + components[0], + test.access, + windows.FILE_OPEN, + test.options, + nil, + shareMode, + ) + if openErr == nil { + windows.CloseHandle(handle) + results = append(results, test.name+"=ok") + continue + } + results = append(results, fmt.Sprintf("%s=%T %v", test.name, openErr, openErr)) + } + return strings.Join(results, "; ") +} + func TestWindowsPrivateRegularCleanupClosesAfterDeleteDispositionFailure(t *testing.T) { var calls []string err := finishWindowsPrivateRegularCleanup(