diff --git a/src/java.base/share/classes/java/io/File.java b/src/java.base/share/classes/java/io/File.java index 7e31379002f..15e687ebf06 100644 --- a/src/java.base/share/classes/java/io/File.java +++ b/src/java.base/share/classes/java/io/File.java @@ -56,7 +56,8 @@ import jdk.internal.util.StaticProperty; * case of Microsoft Windows UNC pathnames, a hostname. Each subsequent name * in an abstract pathname denotes a directory; the last name may denote * either a directory or a file. The empty abstract pathname has no - * prefix and an empty name sequence. + * prefix and an empty name sequence. Accessing a file with the empty abstract + * pathname is equivalent to accessing the current user directory. * *
The conversion of a pathname string to or from an abstract pathname is
* inherently system-dependent. When an abstract pathname is converted into a
diff --git a/src/java.base/share/classes/java/io/FileSystem.java b/src/java.base/share/classes/java/io/FileSystem.java
index db480d931de..3596e0e842a 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, 2023, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1998, 2025, 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
@@ -33,6 +33,22 @@ import java.lang.annotation.Native;
abstract class FileSystem {
+ /* -- Current Working Directory --*/
+
+ /* lazy initialization of CWD object */
+ private static class CurrentWorkingDirectoryHolder {
+ static final File CURRENT_WORKING_DIRECTORY = currentWorkingDirectory();
+
+ private static final File currentWorkingDirectory() {
+ return new File(".");
+ }
+ }
+
+ /* CWD object accessor */
+ static File getCWD() {
+ return CurrentWorkingDirectoryHolder.CURRENT_WORKING_DIRECTORY;
+ }
+
/* -- Normalization and construction -- */
/**
diff --git a/src/java.base/unix/classes/java/io/UnixFileSystem.java b/src/java.base/unix/classes/java/io/UnixFileSystem.java
index ea2ca28fe86..5f9edcd4356 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, 2024, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1998, 2025, 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
@@ -29,11 +29,18 @@ import java.util.Properties;
import jdk.internal.util.StaticProperty;
final class UnixFileSystem extends FileSystem {
-
private final char slash;
private final char colon;
private final String userDir;
+ private String getPathForSysCalls(String path) {
+ return path.isEmpty() ? getCWD().getPath() : path;
+ }
+
+ private File getFileForSysCalls(File file) {
+ return file.getPath().isEmpty() ? getCWD() : file;
+ }
+
UnixFileSystem() {
Properties props = System.getProperties();
slash = props.getProperty("file.separator").charAt(0);
@@ -154,7 +161,7 @@ final class UnixFileSystem extends FileSystem {
@Override
public String canonicalize(String path) throws IOException {
- return canonicalize0(path);
+ return canonicalize0(getPathForSysCalls(path));
}
private native String canonicalize0(String path) throws IOException;
@@ -164,13 +171,13 @@ final class UnixFileSystem extends FileSystem {
@Override
public int getBooleanAttributes(File f) {
- int rv = getBooleanAttributes0(f);
+ int rv = getBooleanAttributes0(getFileForSysCalls(f));
return rv | isHidden(f);
}
@Override
public boolean hasBooleanAttributes(File f, int attributes) {
- int rv = getBooleanAttributes0(f);
+ int rv = getBooleanAttributes0(getFileForSysCalls(f));
if ((attributes & BA_HIDDEN) != 0) {
rv |= isHidden(f);
}
@@ -183,25 +190,25 @@ final class UnixFileSystem extends FileSystem {
@Override
public boolean checkAccess(File f, int access) {
- return checkAccess0(f, access);
+ return checkAccess0(getFileForSysCalls(f), access);
}
private native boolean checkAccess0(File f, int access);
@Override
public long getLastModifiedTime(File f) {
- return getLastModifiedTime0(f);
+ return getLastModifiedTime0(getFileForSysCalls(f));
}
private native long getLastModifiedTime0(File f);
@Override
public long getLength(File f) {
- return getLength0(f);
+ return getLength0(getFileForSysCalls(f));
}
private native long getLength0(File f);
@Override
public boolean setPermission(File f, int access, boolean enable, boolean owneronly) {
- return setPermission0(f, access, enable, owneronly);
+ return setPermission0(getFileForSysCalls(f), access, enable, owneronly);
}
private native boolean setPermission0(File f, int access, boolean enable, boolean owneronly);
@@ -215,37 +222,37 @@ final class UnixFileSystem extends FileSystem {
@Override
public boolean delete(File f) {
- return delete0(f);
+ return delete0(getFileForSysCalls(f));
}
private native boolean delete0(File f);
@Override
public String[] list(File f) {
- return list0(f);
+ return list0(getFileForSysCalls(f));
}
private native String[] list0(File f);
@Override
public boolean createDirectory(File f) {
- return createDirectory0(f);
+ return createDirectory0(getFileForSysCalls(f));
}
private native boolean createDirectory0(File f);
@Override
public boolean rename(File f1, File f2) {
- return rename0(f1, f2);
+ return rename0(getFileForSysCalls(f1), getFileForSysCalls(f2));
}
private native boolean rename0(File f1, File f2);
@Override
public boolean setLastModifiedTime(File f, long time) {
- return setLastModifiedTime0(f, time);
+ return setLastModifiedTime0(getFileForSysCalls(f), time);
}
private native boolean setLastModifiedTime0(File f, long time);
@Override
public boolean setReadOnly(File f) {
- return setReadOnly0(f);
+ return setReadOnly0(getFileForSysCalls(f));
}
private native boolean setReadOnly0(File f);
@@ -260,7 +267,7 @@ final class UnixFileSystem extends FileSystem {
@Override
public long getSpace(File f, int t) {
- return getSpace0(f, t);
+ return getSpace0(getFileForSysCalls(f), t);
}
private native long getSpace0(File f, int t);
@@ -270,7 +277,7 @@ final class UnixFileSystem extends FileSystem {
@Override
public int getNameMax(String path) {
- long nameMax = getNameMax0(path);
+ long nameMax = getNameMax0(getPathForSysCalls(path));
if (nameMax > Integer.MAX_VALUE) {
nameMax = Integer.MAX_VALUE;
}
diff --git a/src/java.base/windows/classes/java/io/WinNTFileSystem.java b/src/java.base/windows/classes/java/io/WinNTFileSystem.java
index dd567be1827..3f383187517 100644
--- a/src/java.base/windows/classes/java/io/WinNTFileSystem.java
+++ b/src/java.base/windows/classes/java/io/WinNTFileSystem.java
@@ -79,6 +79,14 @@ final class WinNTFileSystem extends FileSystem {
return path;
}
+ private String getPathForWin32Calls(String path) {
+ return (path != null && path.isEmpty()) ? getCWD().getPath() : path;
+ }
+
+ private File getFileForWin32Calls(File file) {
+ return file.getPath().isEmpty() ? getCWD() : file;
+ }
+
WinNTFileSystem() {
Properties props = System.getProperties();
slash = props.getProperty("file.separator").charAt(0);
@@ -495,31 +503,31 @@ final class WinNTFileSystem extends FileSystem {
@Override
public int getBooleanAttributes(File f) {
- return getBooleanAttributes0(f);
+ return getBooleanAttributes0(getFileForWin32Calls(f));
}
private native int getBooleanAttributes0(File f);
@Override
public boolean checkAccess(File f, int access) {
- return checkAccess0(f, access);
+ return checkAccess0(getFileForWin32Calls(f), access);
}
private native boolean checkAccess0(File f, int access);
@Override
public long getLastModifiedTime(File f) {
- return getLastModifiedTime0(f);
+ return getLastModifiedTime0(getFileForWin32Calls(f));
}
private native long getLastModifiedTime0(File f);
@Override
public long getLength(File f) {
- return getLength0(f);
+ return getLength0(getFileForWin32Calls(f));
}
private native long getLength0(File f);
@Override
public boolean setPermission(File f, int access, boolean enable, boolean owneronly) {
- return setPermission0(f, access, enable, owneronly);
+ return setPermission0(getFileForWin32Calls(f), access, enable, owneronly);
}
private native boolean setPermission0(File f, int access, boolean enable, boolean owneronly);
@@ -533,7 +541,7 @@ final class WinNTFileSystem extends FileSystem {
@Override
public String[] list(File f) {
- return list0(f);
+ return list0(getFileForWin32Calls(f));
}
private native String[] list0(File f);
@@ -545,7 +553,7 @@ final class WinNTFileSystem extends FileSystem {
@Override
public boolean setLastModifiedTime(File f, long time) {
- return setLastModifiedTime0(f, time);
+ return setLastModifiedTime0(getFileForWin32Calls(f), time);
}
private native boolean setLastModifiedTime0(File f, long time);
@@ -591,7 +599,7 @@ final class WinNTFileSystem extends FileSystem {
// that free space <= total space
if (t == SPACE_FREE)
t = SPACE_USABLE;
- return getSpace0(f, t);
+ return getSpace0(getFileForWin32Calls(f), t);
}
return 0;
}
@@ -618,7 +626,7 @@ final class WinNTFileSystem extends FileSystem {
}
}
}
- return getNameMax0(s);
+ return getNameMax0(getPathForWin32Calls(s));
}
@Override
diff --git a/test/jdk/java/io/File/EmptyPath.java b/test/jdk/java/io/File/EmptyPath.java
index 57da428d760..d3211f917dd 100644
--- a/test/jdk/java/io/File/EmptyPath.java
+++ b/test/jdk/java/io/File/EmptyPath.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2003, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2003, 2025, 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
@@ -22,28 +22,257 @@
*/
/* @test
- @bug 4842706
- @summary Test some file operations with empty path
+ * @bug 4842706 8024695
+ * @summary Test some file operations with empty path
+ * @run junit EmptyPath
*/
-import java.io.*;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.FileStore;
+import java.nio.file.Path;
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.Set;
+
+import org.junit.jupiter.api.BeforeAll;
+import org.junit.jupiter.api.Test;
+
+import org.junit.jupiter.api.condition.DisabledOnOs;
+import org.junit.jupiter.api.condition.EnabledOnOs;
+import org.junit.jupiter.api.condition.OS;
+
+import static org.junit.jupiter.api.Assertions.*;
public class EmptyPath {
- public static void main(String [] args) throws Exception {
- File f = new File("");
- f.mkdir();
- try {
- f.createNewFile();
- throw new RuntimeException("Expected exception not thrown");
- } catch (IOException ioe) {
- // Correct result
- }
- try {
- FileInputStream fis = new FileInputStream(f);
- fis.close();
- throw new RuntimeException("Expected exception not thrown");
- } catch (FileNotFoundException fnfe) {
- // Correct result
+ private static final String EMPTY_STRING = "";
+
+ static File f;
+ static Path p;
+
+ @BeforeAll
+ public static void init() {
+ f = new File(EMPTY_STRING);
+ p = Path.of(EMPTY_STRING);
+ }
+
+ @Test
+ public void canExecute() {
+ assertTrue(f.canExecute());
+ }
+
+ @Test
+ public void canRead() {
+ assertTrue(f.canRead());
+ }
+
+ @Test
+ public void canWrite() {
+ assertTrue(f.canWrite());
+ }
+
+ @Test
+ public void compareTo() {
+ assertEquals(0, f.compareTo(p.toFile()));
+ }
+
+ @Test
+ public void createNewFile() {
+ assertThrows(IOException.class, () -> f.createNewFile());
+ }
+
+ @Test
+ public void open() throws FileNotFoundException {
+ assertThrows(FileNotFoundException.class,
+ () -> new FileInputStream(f));
+ }
+
+ @Test
+ public void delete() {
+ assertFalse(f.delete());
+ }
+
+ @Test
+ public void equals() {
+ assertTrue(f.equals(p.toFile()));
+ }
+
+ @Test
+ public void exists() {
+ assertTrue(f.exists());
+ }
+
+ @Test
+ public void getAbsolutePath() {
+ System.out.println(p.toAbsolutePath().toString() + "\n" +
+ f.getAbsolutePath());
+ assertEquals(p.toAbsolutePath().toString(), f.getAbsolutePath());
+ }
+
+ private void checkSpace(long expected, long actual) {
+ if (expected == 0) {
+ assertEquals(0L, actual);
+ } else {
+ assertTrue(actual > 0);
}
}
+
+ @Test
+ public void getFreeSpace() throws IOException {
+ FileStore fs = Files.getFileStore(f.toPath());
+ checkSpace(fs.getUnallocatedSpace(), f.getFreeSpace());
+ }
+
+ @Test
+ public void getName() {
+ assertEquals(p.getFileName().toString(), f.getName());
+ }
+
+ @Test
+ public void getParent() {
+ assertNull(f.getParent());
+ }
+
+ @Test
+ public void getPath() {
+ assertEquals(p.toString(), f.getPath());
+ }
+
+ @Test
+ public void getTotalSpace() throws IOException {
+ FileStore fs = Files.getFileStore(f.toPath());
+ checkSpace(fs.getTotalSpace(), f.getTotalSpace());
+ }
+
+ @Test
+ public void getUsableSpace() throws IOException {
+ FileStore fs = Files.getFileStore(f.toPath());
+ checkSpace(fs.getUsableSpace(), f.getUsableSpace());
+ }
+
+ @Test
+ public void isNotAbsolute() {
+ assertFalse(f.isAbsolute());
+ }
+
+ @Test
+ public void isAbsolute() {
+ assertTrue(f.getAbsoluteFile().isAbsolute());
+ }
+
+ @Test
+ public void isDirectory() {
+ assertTrue(f.isDirectory());
+ }
+
+ @Test
+ public void isFile() {
+ assertFalse(f.isFile());
+ }
+
+ @Test
+ public void isHidden() {
+ assertFalse(f.isHidden());
+ }
+
+ @Test
+ public void lastModified() {
+ assertTrue(f.lastModified() > 0);
+ }
+
+ @Test
+ public void length() throws IOException {
+ assertEquals(Files.size(f.toPath()), f.length());
+ }
+
+ @Test
+ public void list() throws IOException {
+ String[] files = f.list();
+ assertNotNull(files);
+ Set