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  }