feat: full NFSv4.2 server and client in pure Go
Test / test (push) Successful in 2m4s
Release / gates (push) Successful in 2m5s
Release / build (amd64, freebsd) (push) Successful in 1m27s
Release / build (amd64, linux) (push) Successful in 1m22s
Release / build (amd64, netbsd) (push) Successful in 1m19s
Release / build (amd64, openbsd) (push) Successful in 1m20s
Release / build (arm64, darwin) (push) Successful in 1m21s
Release / build (arm64, freebsd) (push) Successful in 1m26s
Release / build (arm64, linux) (push) Successful in 1m25s
Release / build (arm64, netbsd) (push) Successful in 1m31s
Release / build (arm64, openbsd) (push) Successful in 1m27s
Release / build (loong64, linux) (push) Successful in 1m37s
Release / build (riscv64, linux) (push) Successful in 1m21s
Release / release (push) Successful in 40s

Assisted-by: GLM 5.3 Flash
This commit is contained in:
2026-09-21 18:51:17 +02:00
commit a9b8039ef7
153 changed files with 34403 additions and 0 deletions
+39
View File
@@ -0,0 +1,39 @@
// Copyright (c) 2026 Petr Balvín <opensource@petrbalvin.org> (https://petrbalvin.org)
// SPDX-License-Identifier: MIT
package rpc
import (
"testing"
)
// The RPCSEC_GSS_INIT result round trips: handle, statuses, window and
// the reply token.
func TestGSSInitResRoundTrip(t *testing.T) {
res := AppendGSSInitRes(nil, []byte("handle-2"), 0, 1, 32, []byte("ap-rep"))
handle, major, minor, window, token, err := DecodeGSSInitRes(res)
if err != nil || string(handle) != "handle-2" || major != 0 || minor != 1 ||
window != 32 || string(token) != "ap-rep" {
t.Fatalf("res %q %d %d %d %q %v", handle, major, minor, window, token, err)
}
// The empty refusal answers an empty handle and no token.
res = AppendGSSInitRes(nil, nil, 16<<16, 1, 0, nil)
if handle, major, _, _, token, err := DecodeGSSInitRes(res); err != nil ||
len(handle) != 0 || major != 16<<16 || len(token) != 0 {
t.Fatalf("refusal %q %d %q %v", handle, major, token, err)
}
// The error text of the credential sentinel is stable.
if ErrGSSCred.Error() == "" {
t.Fatal("empty error text")
}
// A truncated init result is refused word by word.
for n := 0; n < len(res); n++ {
if _, _, _, _, _, err := DecodeGSSInitRes(res[:n]); err == nil {
t.Fatalf("a %d byte prefix decoded cleanly", n)
}
}
// The NULL procedure constant the control exchange rides on.
if ProcedureNull != 0 {
t.Fatalf("null procedure %d", ProcedureNull)
}
}