github.com/SagerNet/gvisor@v0.0.0-20210707092255-7731c139d75c/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  // func VersionSupportsX(v int32) bool {
    69  //	...
    70  // )
    71  func parseVersion(str string) (uint32, bool) {
    72  	// Special case the base version which lacks the ".Google.X" suffix.  This
    73  	// version always means version 0.
    74  	if str == baseVersion {
    75  		return 0, true
    76  	}
    77  	substr := strings.Split(str, ".")
    78  	if len(substr) != 4 {
    79  		return 0, false
    80  	}
    81  	if substr[0] != "9P2000" || substr[1] != "L" || substr[2] != "Google" || len(substr[3]) == 0 {
    82  		return 0, false
    83  	}
    84  	version, err := strconv.ParseUint(substr[3], 10, 32)
    85  	if err != nil {
    86  		return 0, false
    87  	}
    88  	return uint32(version), true
    89  }
    90  
    91  // versionString formats a p9 version number into a Tversion version string.
    92  func versionString(version uint32) string {
    93  	// Special case the base version so that clients expecting this string
    94  	// instead of the 9P2000.L.Google.0 equivalent get it.  This is important
    95  	// for backwards compatibility with legacy servers that check for exactly
    96  	// the baseVersion and allow nothing else.
    97  	if version == 0 {
    98  		return baseVersion
    99  	}
   100  	return fmt.Sprintf("9P2000.L.Google.%d", version)
   101  }
   102  
   103  // VersionSupportsTflushf returns true if version v supports the Tflushf message.
   104  // This predicate must be checked by clients before attempting to make a Tflushf
   105  // request.  If this predicate returns false, then clients may safely no-op.
   106  func VersionSupportsTflushf(v uint32) bool {
   107  	return v >= 1
   108  }
   109  
   110  // versionSupportsTwalkgetattr returns true if version v supports the
   111  // Twalkgetattr message. This predicate must be checked by clients before
   112  // attempting to make a Twalkgetattr request.
   113  func versionSupportsTwalkgetattr(v uint32) bool {
   114  	return v >= 2
   115  }
   116  
   117  // versionSupportsTucreation returns true if version v supports the Tucreation
   118  // messages (Tucreate, Tusymlink, Tumkdir, Tumknod). This predicate must be
   119  // checked by clients before attempting to make a Tucreation request.
   120  // If Tucreation messages are not supported, their non-UID supporting
   121  // counterparts (Tlcreate, Tsymlink, Tmkdir, Tmknod) should be used.
   122  func versionSupportsTucreation(v uint32) bool {
   123  	return v >= 3
   124  }
   125  
   126  // VersionSupportsConnect returns true if version v supports the Tlconnect
   127  // message. This predicate must be checked by clients
   128  // before attempting to make a Tlconnect request. If Tlconnect messages are not
   129  // supported, Tlopen should be used.
   130  func VersionSupportsConnect(v uint32) bool {
   131  	return v >= 4
   132  }
   133  
   134  // VersionSupportsAnonymous returns true if version v supports Tlconnect
   135  // with the AnonymousSocket mode. This predicate must be checked by clients
   136  // before attempting to use the AnonymousSocket Tlconnect mode.
   137  func VersionSupportsAnonymous(v uint32) bool {
   138  	return v >= 5
   139  }
   140  
   141  // VersionSupportsMultiUser returns true if version v supports multi-user fake
   142  // directory permissions and ID values.
   143  func VersionSupportsMultiUser(v uint32) bool {
   144  	return v >= 6
   145  }
   146  
   147  // versionSupportsTallocate returns true if version v supports Allocate().
   148  func versionSupportsTallocate(v uint32) bool {
   149  	return v >= 7
   150  }
   151  
   152  // versionSupportsFlipcall returns true if version v supports IPC channels from
   153  // the flipcall package. Note that these must be negotiated, but this version
   154  // string indicates that such a facility exists.
   155  func versionSupportsFlipcall(v uint32) bool {
   156  	return v >= 8
   157  }
   158  
   159  // VersionSupportsOpenTruncateFlag returns true if version v supports
   160  // passing the OpenTruncate flag to Tlopen.
   161  func VersionSupportsOpenTruncateFlag(v uint32) bool {
   162  	return v >= 9
   163  }
   164  
   165  // versionSupportsGetSetXattr returns true if version v supports
   166  // the Tgetxattr and Tsetxattr messages.
   167  func versionSupportsGetSetXattr(v uint32) bool {
   168  	return v >= 10
   169  }
   170  
   171  // versionSupportsListRemoveXattr returns true if version v supports
   172  // the Tlistxattr and Tremovexattr messages.
   173  func versionSupportsListRemoveXattr(v uint32) bool {
   174  	return v >= 11
   175  }
   176  
   177  // versionSupportsTsetattrclunk returns true if version v supports
   178  // the Tsetattrclunk message.
   179  func versionSupportsTsetattrclunk(v uint32) bool {
   180  	return v >= 12
   181  }
   182  
   183  // versionSupportsTmultiGetAttr returns true if version v supports
   184  // the TmultiGetAttr message.
   185  func versionSupportsTmultiGetAttr(v uint32) bool {
   186  	return v >= 13
   187  }