diff options
Diffstat (limited to 'pkg/p9/version.go')
-rw-r--r-- | pkg/p9/version.go | 150 |
1 files changed, 150 insertions, 0 deletions
diff --git a/pkg/p9/version.go b/pkg/p9/version.go new file mode 100644 index 000000000..c2a2885ae --- /dev/null +++ b/pkg/p9/version.go @@ -0,0 +1,150 @@ +// Copyright 2018 The gVisor Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package p9 + +import ( + "fmt" + "strconv" + "strings" +) + +const ( + // highestSupportedVersion is the highest supported version X in a + // version string of the format 9P2000.L.Google.X. + // + // Clients are expected to start requesting this version number and + // to continuously decrement it until a Tversion request succeeds. + highestSupportedVersion uint32 = 7 + + // lowestSupportedVersion is the lowest supported version X in a + // version string of the format 9P2000.L.Google.X. + // + // Clients are free to send a Tversion request at a version below this + // value but are expected to encounter an Rlerror in response. + lowestSupportedVersion uint32 = 0 + + // baseVersion is the base version of 9P that this package must always + // support. It is equivalent to 9P2000.L.Google.0. + baseVersion = "9P2000.L" +) + +// HighestVersionString returns the highest possible version string that a client +// may request or a server may support. +func HighestVersionString() string { + return versionString(highestSupportedVersion) +} + +// parseVersion parses a Tversion version string into a numeric version number +// if the version string is supported by p9. Otherwise returns (0, false). +// +// From Tversion(9P): "Version strings are defined such that, if the client string +// contains one or more period characters, the initial substring up to but not +// including any single period in the version string defines a version of the protocol." +// +// p9 intentionally diverges from this and always requires that the version string +// start with 9P2000.L to express that it is always compatible with 9P2000.L. The +// only supported versions extensions are of the format 9p2000.L.Google.X where X +// is an ever increasing version counter. +// +// Version 9P2000.L.Google.0 implies 9P2000.L. +// +// New versions must always be a strict superset of 9P2000.L. A version increase must +// define a predicate representing the feature extension introduced by that version. The +// predicate must be commented and should take the format: +// +// // VersionSupportsX returns true if version v supports X and must be checked when ... +// func VersionSupportsX(v int32) bool { +// ... +// ) +func parseVersion(str string) (uint32, bool) { + // Special case the base version which lacks the ".Google.X" suffix. This + // version always means version 0. + if str == baseVersion { + return 0, true + } + substr := strings.Split(str, ".") + if len(substr) != 4 { + return 0, false + } + if substr[0] != "9P2000" || substr[1] != "L" || substr[2] != "Google" || len(substr[3]) == 0 { + return 0, false + } + version, err := strconv.ParseUint(substr[3], 10, 32) + if err != nil { + return 0, false + } + return uint32(version), true +} + +// versionString formats a p9 version number into a Tversion version string. +func versionString(version uint32) string { + // Special case the base version so that clients expecting this string + // instead of the 9P2000.L.Google.0 equivalent get it. This is important + // for backwards compatibility with legacy servers that check for exactly + // the baseVersion and allow nothing else. + if version == 0 { + return baseVersion + } + return fmt.Sprintf("9P2000.L.Google.%d", version) +} + +// VersionSupportsTflushf returns true if version v supports the Tflushf message. +// This predicate must be checked by clients before attempting to make a Tflushf +// request. If this predicate returns false, then clients may safely no-op. +func VersionSupportsTflushf(v uint32) bool { + return v >= 1 +} + +// versionSupportsTwalkgetattr returns true if version v supports the +// Twalkgetattr message. This predicate must be checked by clients before +// attempting to make a Twalkgetattr request. +func versionSupportsTwalkgetattr(v uint32) bool { + return v >= 2 +} + +// versionSupportsTucreation returns true if version v supports the Tucreation +// messages (Tucreate, Tusymlink, Tumkdir, Tumknod). This predicate must be +// checked by clients before attempting to make a Tucreation request. +// If Tucreation messages are not supported, their non-UID supporting +// counterparts (Tlcreate, Tsymlink, Tmkdir, Tmknod) should be used. +func versionSupportsTucreation(v uint32) bool { + return v >= 3 +} + +// VersionSupportsConnect returns true if version v supports the Tlconnect +// message. This predicate must be checked by clients +// before attempting to make a Tlconnect request. If Tlconnect messages are not +// supported, Tlopen should be used. +func VersionSupportsConnect(v uint32) bool { + return v >= 4 +} + +// VersionSupportsAnonymous returns true if version v supports Tlconnect +// with the AnonymousSocket mode. This predicate must be checked by clients +// before attempting to use the AnonymousSocket Tlconnect mode. +func VersionSupportsAnonymous(v uint32) bool { + return v >= 5 +} + +// VersionSupportsMultiUser returns true if version v supports multi-user fake +// directory permissions and ID values. +func VersionSupportsMultiUser(v uint32) bool { + return v >= 6 +} + +// versionSupportsTallocate returns true if version v supports Allocate(). +func versionSupportsTallocate(v uint32) bool { + return v >= 7 +} |