diff options
author | 2015-09-18 13:45:55 +0000 | |
---|---|---|
committer | 2015-09-21 08:57:26 +0000 | |
commit | e76dd5e223acbf1b9fea9a4764a6226f8b42edd1 (patch) | |
tree | a9ef8afe58e287806ee1ac59991b5658e207b105 /src/main | |
parent | 391d67ca07c15b2383e14c6bbeefd42149361626 (diff) |
Tighten up the requirements on workspace names
Fixes #462.
RELNOTES: Workspace names are now restricted to being in their base directory
(that is, the names cannot contain up-level references or /./).
--
MOS_MIGRATED_REVID=103379893
Diffstat (limited to 'src/main')
-rw-r--r-- | src/main/java/com/google/devtools/build/lib/cmdline/PackageIdentifier.java | 99 |
1 files changed, 77 insertions, 22 deletions
diff --git a/src/main/java/com/google/devtools/build/lib/cmdline/PackageIdentifier.java b/src/main/java/com/google/devtools/build/lib/cmdline/PackageIdentifier.java index 9d0ef0edcf..89167dd433 100644 --- a/src/main/java/com/google/devtools/build/lib/cmdline/PackageIdentifier.java +++ b/src/main/java/com/google/devtools/build/lib/cmdline/PackageIdentifier.java @@ -85,35 +85,90 @@ public final class PackageIdentifier implements Comparable<PackageIdentifier>, S this.name = name; } - /** - * Performs validity checking. Returns null on success, an error message otherwise. - */ - private static String validate(String name) { - if (name.isEmpty()) { - return null; - } + private static class Lexer { + private static final char EOF = '\0'; - if (!name.startsWith("@")) { - return "workspace name must start with '@'"; + private final String name; + private int pos; + + public Lexer(String name) { + this.name = name; + this.pos = 0; } - // Check for any character outside of [/0-9A-Za-z_.-]. Try to evaluate the - // conditional quickly (by looking in decreasing order of character class - // likelihood). - if (name.startsWith("@/") || name.endsWith("/")) { - return "workspace names cannot start nor end with '/'"; - } else if (name.contains("//")) { - return "workspace names cannot contain multiple '/'s in a row"; + public String lex() { + if (name.isEmpty()) { + return null; + } + + if (name.charAt(pos) != '@') { + return "workspace names must start with '@'"; + } + + // @// is valid. + if (name.length() == 1) { + return null; + } + + pos++; + // Disallow strings starting with “/”, “./”, or “../” + // Disallow strings identical to ".", or “..” + if (name.charAt(pos) == '/') { + return "workspace names are not allowed to start with '@/'"; + } else if (name.charAt(pos) == '.') { + char next = peek(1); + char nextNext = peek(2); + // Forbid '@.' and '@..' as complete labels and '@./' and '@../' as label starts. + if (next == EOF) { + return "workspace names are not allowed to be '@.'"; + } else if (next == '/') { + return "workspace names are not allowed to start with '@./'"; + } else if (next == '.' && (nextNext == '/' || nextNext == EOF)) { + return "workspace names are not allowed to start with '@..'"; + } + } + + // This lexes the first letter a second time, to make sure it fulfills the general + // workspace name criteria (as well as the more strict criteria for the beginning of a + // workspace name). + // Disallow strings containing “//”, “/./”, or “/../” + // Disallow strings ending in “/”, "/.", or “/..” + // name = @( <alphanum> | [/._-] )* + for (; pos < name.length(); pos++) { + char c = name.charAt(pos); + if (c == '/') { + char next = peek(1); + if (next == '/') { + return "workspace names are not allowed to contain '//'"; + } else if (next == EOF) { + return "workspace names are not allowed to end with '/'"; + } else if (next == '.' && (peek(2) == '/' || peek(2) == EOF)) { + return "workspace names are not allowed to contain '/./'"; + } else if (next == '.' && peek(2) == '.' && (peek(3) == '/' || peek(3) == EOF)) { + return "workspace names are not allowed to contain '/../'"; + } + } else if ((c < 'a' || c > 'z') && c != '_' && c != '-' && c != '/' && c != '.' + && (c < '0' || c > '9') && (c < 'A' || c > 'Z')) { + return "workspace names may contain only A-Z, a-z, 0-9, '-', '_', '.', and '/'"; + } + } + + return null; } - for (int i = name.length() - 1; i >= 1; --i) { - char c = name.charAt(i); - if ((c < 'a' || c > 'z') && c != '_' && c != '-' && c != '/' && c != '.' - && (c < '0' || c > '9') && (c < 'A' || c > 'Z')) { - return "workspace names may contain only A-Z, a-z, 0-9, '-', '_', '.', and '/'"; + private char peek(int num) { + if (pos + num >= name.length()) { + return EOF; } + return name.charAt(pos + num); } - return null; + } + + /** + * Performs validity checking. Returns null on success, an error message otherwise. + */ + private static String validate(String name) { + return new Lexer(name).lex(); } /** |