From 3564d325e6620a3027f780ad6734ddbfdef36ffb Mon Sep 17 00:00:00 2001 From: Rob McKenna Date: Tue, 8 Feb 2022 00:23:34 +0000 Subject: [PATCH] 8278356: Improve file creation Reviewed-by: bpb --- src/java.base/share/classes/java/io/File.java | 10 ++--- .../share/classes/java/io/FileSystem.java | 7 ++- .../unix/classes/java/io/UnixFileSystem.java | 7 ++- .../classes/java/io/WinNTFileSystem.java | 45 ++++++++++++++++++- 4 files changed, 61 insertions(+), 8 deletions(-) diff --git a/src/java.base/share/classes/java/io/File.java b/src/java.base/share/classes/java/io/File.java index 3f7cd86cf70..35e9da5ae0a 100644 --- a/src/java.base/share/classes/java/io/File.java +++ b/src/java.base/share/classes/java/io/File.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1994, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1994, 2022, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -175,8 +175,9 @@ public class File /** * Check if the file has an invalid path. Currently, the inspection of - * a file path is very limited, and it only covers Nul character check. - * Returning true means the path is definitely invalid/garbage. But + * a file path is very limited, and it only covers Nul character check + * unless further checking is explicitly enabled by a system property. + * Returning true means the path is definitely invalid/garbage, but * returning false does not guarantee that the path is valid. * * @return true if the file path is invalid. @@ -184,8 +185,7 @@ public class File final boolean isInvalid() { PathStatus s = status; if (s == null) { - s = (this.path.indexOf('\u0000') < 0) ? PathStatus.CHECKED - : PathStatus.INVALID; + s = fs.isInvalid(this) ? PathStatus.INVALID : PathStatus.CHECKED; status = s; } return s == PathStatus.INVALID; diff --git a/src/java.base/share/classes/java/io/FileSystem.java b/src/java.base/share/classes/java/io/FileSystem.java index a1cea852d95..b41120bf360 100644 --- a/src/java.base/share/classes/java/io/FileSystem.java +++ b/src/java.base/share/classes/java/io/FileSystem.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2022, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -87,6 +87,11 @@ abstract class FileSystem { */ public abstract boolean isAbsolute(File f); + /** + * Tell whether the given abstract pathname is invalid. + */ + public abstract boolean isInvalid(File f); + /** * Resolve the given abstract pathname into absolute form. Invoked by the * getAbsolutePath and getCanonicalPath methods in the File class. diff --git a/src/java.base/unix/classes/java/io/UnixFileSystem.java b/src/java.base/unix/classes/java/io/UnixFileSystem.java index e03825ff458..501b5d8883b 100644 --- a/src/java.base/unix/classes/java/io/UnixFileSystem.java +++ b/src/java.base/unix/classes/java/io/UnixFileSystem.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2022, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -141,6 +141,11 @@ class UnixFileSystem extends FileSystem { return (f.getPrefixLength() != 0); } + @Override + public boolean isInvalid(File f) { + return f.getPath().indexOf('\u0000') < 0 ? false : true; + } + @Override public String resolve(File f) { if (isAbsolute(f)) return f.getPath(); diff --git a/src/java.base/windows/classes/java/io/WinNTFileSystem.java b/src/java.base/windows/classes/java/io/WinNTFileSystem.java index 0fc52d6299b..2140c8e2032 100644 --- a/src/java.base/windows/classes/java/io/WinNTFileSystem.java +++ b/src/java.base/windows/classes/java/io/WinNTFileSystem.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2022, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -26,6 +26,7 @@ package java.io; import java.io.File; +import java.nio.file.InvalidPathException; import java.nio.file.Path; import java.util.BitSet; import java.util.Locale; @@ -45,6 +46,21 @@ class WinNTFileSystem extends FileSystem { private final char semicolon; private final String userDir; + // Whether to enable alternative data streams (ADS) by suppressing + // checking the path for invalid characters, in particular ":". + // ADS support will be enabled if and only if the property is set and + // is the empty string or is equal, ignoring case, to the string "true". + // By default ADS support is disabled. + private static final boolean ENABLE_ADS; + static { + String enableADS = GetPropertyAction.privilegedGetProperty("jdk.io.File.enableADS"); + if (enableADS != null) { + ENABLE_ADS = "".equals(enableADS) || Boolean.parseBoolean(enableADS); + } else { + ENABLE_ADS = false; + } + } + public WinNTFileSystem() { Properties props = GetPropertyAction.privilegedGetProperties(); slash = props.getProperty("file.separator").charAt(0); @@ -305,6 +321,33 @@ class WinNTFileSystem extends FileSystem { || (pl == 3)); } + @Override + public boolean isInvalid(File f) { + if (f.getPath().indexOf('\u0000') >= 0) + return true; + + if (ENABLE_ADS) + return false; + + // Invalid if there is a ":" at a position greater than 1, or if there + // is a ":" at position 1 and the first character is not a letter + String pathname = f.getPath(); + int lastColon = pathname.lastIndexOf(":"); + if (lastColon > 1 || + (lastColon == 1 && !isLetter(pathname.charAt(0)))) + return true; + + // Invalid if path creation fails + Path path = null; + try { + path = sun.nio.fs.DefaultFileSystemProvider.theFileSystem().getPath(pathname); + return false; + } catch (InvalidPathException ignored) { + } + + return true; + } + @Override public String resolve(File f) { String path = f.getPath();