gvisor.dev/gvisor@v0.0.0-20240520182842-f9d4d51c7e0f/pkg/p9/version.go (about) 1 // Copyright 2018 The gVisor Authors. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package p9 16 17 import ( 18 "fmt" 19 "strconv" 20 "strings" 21 ) 22 23 const ( 24 // highestSupportedVersion is the highest supported version X in a 25 // version string of the format 9P2000.L.Google.X. 26 // 27 // Clients are expected to start requesting this version number and 28 // to continuously decrement it until a Tversion request succeeds. 29 highestSupportedVersion uint32 = 13 30 31 // lowestSupportedVersion is the lowest supported version X in a 32 // version string of the format 9P2000.L.Google.X. 33 // 34 // Clients are free to send a Tversion request at a version below this 35 // value but are expected to encounter an Rlerror in response. 36 lowestSupportedVersion uint32 = 0 37 38 // baseVersion is the base version of 9P that this package must always 39 // support. It is equivalent to 9P2000.L.Google.0. 40 baseVersion = "9P2000.L" 41 ) 42 43 // HighestVersionString returns the highest possible version string that a client 44 // may request or a server may support. 45 func HighestVersionString() string { 46 return versionString(highestSupportedVersion) 47 } 48 49 // parseVersion parses a Tversion version string into a numeric version number 50 // if the version string is supported by p9. Otherwise returns (0, false). 51 // 52 // From Tversion(9P): "Version strings are defined such that, if the client string 53 // contains one or more period characters, the initial substring up to but not 54 // including any single period in the version string defines a version of the protocol." 55 // 56 // p9 intentionally diverges from this and always requires that the version string 57 // start with 9P2000.L to express that it is always compatible with 9P2000.L. The 58 // only supported versions extensions are of the format 9p2000.L.Google.X where X 59 // is an ever increasing version counter. 60 // 61 // Version 9P2000.L.Google.0 implies 9P2000.L. 62 // 63 // New versions must always be a strict superset of 9P2000.L. A version increase must 64 // define a predicate representing the feature extension introduced by that version. The 65 // predicate must be commented and should take the format: 66 // 67 // // VersionSupportsX returns true if version v supports X and must be checked when ... 68 // 69 // func VersionSupportsX(v int32) bool { 70 // ... 71 // } 72 func parseVersion(str string) (uint32, bool) { 73 // Special case the base version which lacks the ".Google.X" suffix. This 74 // version always means version 0. 75 if str == baseVersion { 76 return 0, true 77 } 78 substr := strings.Split(str, ".") 79 if len(substr) != 4 { 80 return 0, false 81 } 82 if substr[0] != "9P2000" || substr[1] != "L" || substr[2] != "Google" || len(substr[3]) == 0 { 83 return 0, false 84 } 85 version, err := strconv.ParseUint(substr[3], 10, 32) 86 if err != nil { 87 return 0, false 88 } 89 return uint32(version), true 90 } 91 92 // versionString formats a p9 version number into a Tversion version string. 93 func versionString(version uint32) string { 94 // Special case the base version so that clients expecting this string 95 // instead of the 9P2000.L.Google.0 equivalent get it. This is important 96 // for backwards compatibility with legacy servers that check for exactly 97 // the baseVersion and allow nothing else. 98 if version == 0 { 99 return baseVersion 100 } 101 return fmt.Sprintf("9P2000.L.Google.%d", version) 102 } 103 104 // VersionSupportsTflushf returns true if version v supports the Tflushf message. 105 // This predicate must be checked by clients before attempting to make a Tflushf 106 // request. If this predicate returns false, then clients may safely no-op. 107 func VersionSupportsTflushf(v uint32) bool { 108 return v >= 1 109 } 110 111 // versionSupportsTwalkgetattr returns true if version v supports the 112 // Twalkgetattr message. This predicate must be checked by clients before 113 // attempting to make a Twalkgetattr request. 114 func versionSupportsTwalkgetattr(v uint32) bool { 115 return v >= 2 116 } 117 118 // versionSupportsTucreation returns true if version v supports the Tucreation 119 // messages (Tucreate, Tusymlink, Tumkdir, Tumknod). This predicate must be 120 // checked by clients before attempting to make a Tucreation request. 121 // If Tucreation messages are not supported, their non-UID supporting 122 // counterparts (Tlcreate, Tsymlink, Tmkdir, Tmknod) should be used. 123 func versionSupportsTucreation(v uint32) bool { 124 return v >= 3 125 } 126 127 // VersionSupportsConnect returns true if version v supports the Tlconnect 128 // message. This predicate must be checked by clients 129 // before attempting to make a Tlconnect request. If Tlconnect messages are not 130 // supported, Tlopen should be used. 131 func VersionSupportsConnect(v uint32) bool { 132 return v >= 4 133 } 134 135 // VersionSupportsAnonymous returns true if version v supports Tlconnect 136 // with the AnonymousSocket mode. This predicate must be checked by clients 137 // before attempting to use the AnonymousSocket Tlconnect mode. 138 func VersionSupportsAnonymous(v uint32) bool { 139 return v >= 5 140 } 141 142 // VersionSupportsMultiUser returns true if version v supports multi-user fake 143 // directory permissions and ID values. 144 func VersionSupportsMultiUser(v uint32) bool { 145 return v >= 6 146 } 147 148 // versionSupportsTallocate returns true if version v supports Allocate(). 149 func versionSupportsTallocate(v uint32) bool { 150 return v >= 7 151 } 152 153 // versionSupportsFlipcall returns true if version v supports IPC channels from 154 // the flipcall package. Note that these must be negotiated, but this version 155 // string indicates that such a facility exists. 156 func versionSupportsFlipcall(v uint32) bool { 157 return v >= 8 158 } 159 160 // VersionSupportsOpenTruncateFlag returns true if version v supports 161 // passing the OpenTruncate flag to Tlopen. 162 func VersionSupportsOpenTruncateFlag(v uint32) bool { 163 return v >= 9 164 } 165 166 // versionSupportsGetSetXattr returns true if version v supports 167 // the Tgetxattr and Tsetxattr messages. 168 func versionSupportsGetSetXattr(v uint32) bool { 169 return v >= 10 170 } 171 172 // versionSupportsListRemoveXattr returns true if version v supports 173 // the Tlistxattr and Tremovexattr messages. 174 func versionSupportsListRemoveXattr(v uint32) bool { 175 return v >= 11 176 } 177 178 // versionSupportsTsetattrclunk returns true if version v supports 179 // the Tsetattrclunk message. 180 func versionSupportsTsetattrclunk(v uint32) bool { 181 return v >= 12 182 } 183 184 // versionSupportsTmultiGetAttr returns true if version v supports 185 // the TmultiGetAttr message. 186 func versionSupportsTmultiGetAttr(v uint32) bool { 187 return v >= 13 188 } 189 190 // versionSupportsBind returns true if version v supports the Tbind message. 191 func versionSupportsBind(v uint32) bool { 192 // TODO(b/194709873): Bump version and gate with that. 193 return false 194 }