module: reject Windows shortnames as path components

This backports golang.org/cl/154102 to reduce the differences between
the path checking done for import paths by the go command, and
module.CheckImportPath

For golang/go#29230

Change-Id: I1b03de85e560504b5ddb32ebdaf6d7e4384f992c
Reviewed-on: https://go-review.googlesource.com/c/mod/+/250920
Run-TryBot: Michael Matloob <matloob@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Jay Conrod <jayconrod@google.com>
Reviewed-by: Bryan C. Mills <bcmills@google.com>
diff --git a/module/module.go b/module/module.go
index 77d6f8e..c1c5263 100644
--- a/module/module.go
+++ b/module/module.go
@@ -318,7 +318,9 @@
 // It must not begin or end with a dot (U+002E), nor contain two dots in a row.
 //
 // The element prefix up to the first dot must not be a reserved file name
-// on Windows, regardless of case (CON, com1, NuL, and so on).
+// on Windows, regardless of case (CON, com1, NuL, and so on). The element
+// must not have a suffix of a tilde followed by one or more ASCII digits
+// (to exclude paths elements that look like Windows short-names).
 //
 // CheckImportPath may be less restrictive in the future, but see the
 // top-level package documentation for additional information about
@@ -403,6 +405,29 @@
 			return fmt.Errorf("%q disallowed as path element component on Windows", short)
 		}
 	}
+
+	if fileName {
+		// don't check for Windows short-names in file names. They're
+		// only an issue for import paths.
+		return nil
+	}
+
+	// Reject path components that look like Windows short-names.
+	// Those usually end in a tilde followed by one or more ASCII digits.
+	if tilde := strings.LastIndexByte(short, '~'); tilde >= 0 && tilde < len(short)-1 {
+		suffix := short[tilde+1:]
+		suffixIsDigits := true
+		for _, r := range suffix {
+			if r < '0' || r > '9' {
+				suffixIsDigits = false
+				break
+			}
+		}
+		if suffixIsDigits {
+			return fmt.Errorf("trailing tilde and digits in path element")
+		}
+	}
+
 	return nil
 }
 
diff --git a/module/module_test.go b/module/module_test.go
index 8e56749..9e40367 100644
--- a/module/module_test.go
+++ b/module/module_test.go
@@ -163,6 +163,13 @@
 	{"x.y/com1", false, false, false},
 	{"x.y/com1.txt", false, false, false},
 	{"x.y/calm1", true, true, true},
+	{"x.y/z~", true, true, true},
+	{"x.y/z~0", false, false, true},
+	{"x.y/z~09", false, false, true},
+	{"x.y/z09", true, true, true},
+	{"x.y/z09~", true, true, true},
+	{"x.y/z09~09z", true, true, true},
+	{"x.y/z09~09z~09", false, false, true},
 	{"github.com/!123/logrus", false, false, true},
 
 	// TODO: CL 41822 allowed Unicode letters in old "go get"