Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 16 additions & 0 deletions src/fs.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,12 @@
// Virtual file system the Java side sees. Paths are absolute and use "/".

export interface Space {
bsize: bigint;
blocks: bigint;
bfree: bigint;
bavail: bigint;
}

export interface Stat {
dir: boolean;
size: number;
Expand Down Expand Up @@ -33,6 +40,8 @@ export interface Backend {
mkdir?(path: string): boolean;
remove?(path: string): boolean;
rename?(from: string, to: string): boolean;
// the file system holding path: block size and block counts, as statvfs gives them
space?(path: string): Space | null;
// sets the modification time, in milliseconds since the epoch
setMtime?(path: string, ms: number): boolean;
// whether the host refuses to write the file, or to create it when it is missing
Expand Down Expand Up @@ -202,6 +211,13 @@ export class VFS {
return !!r && r[0].writable;
}

// A file system without its own figures reports 4 KB blocks and no space,
// as Linux does for virtual file systems such as /proc.
space(path: string): Space {
const r = this.resolve(path);
return (r && r[0].space?.(r[1])) ?? { bsize: 4096n, blocks: 0n, bfree: 0n, bavail: 0n };
}

// ns, when given, is the exact time asked for. Hosts keep times as floating
// point seconds or milliseconds, which lose nanoseconds, so stat reports ns
// for as long as the file keeps the time this set.
Expand Down
8 changes: 7 additions & 1 deletion src/natives/io.ts
Original file line number Diff line number Diff line change
Expand Up @@ -549,6 +549,12 @@ export const natives: Natives = {
renamePath(t, resolvePath(t, pathOf(t, a)), resolvePath(t, pathOf(t, b))),
[`${UFS}.setLastModifiedTime0(Ljava/io/File;J)Z`]: (t, [, f, ms]) => setMtime(t, resolvePath(t, pathOf(t, f)), Number(ms), BigInt(ms) * 1_000_000n),
[`${UFS}.setReadOnly0(Ljava/io/File;)Z`]: (t, [, f]) => chmod(t, f, (m) => m & ~0o222),
[`${UFS}.getSpace0(Ljava/io/File;I)J`]: () => 0n,
// SPACE_TOTAL, SPACE_FREE or SPACE_USABLE of the file system holding f; 0 if f is missing
[`${UFS}.getSpace0(Ljava/io/File;I)J`]: (t, [, f, kind]) => {
const abs = resolvePath(t, pathOf(t, f));
if (!t.vm.fs.stat(abs)) return 0n;
const s = t.vm.fs.space(abs);
return s.bsize * (kind === 0 ? s.blocks : kind === 1 ? s.bfree : s.bavail);
},
[`${UFS}.getNameMax0(Ljava/lang/String;)J`]: () => 255n,
};
18 changes: 16 additions & 2 deletions src/natives/nio.ts
Original file line number Diff line number Diff line change
Expand Up @@ -247,7 +247,15 @@ export const natives: Natives = {
[`${N}getpwnam0(J)I`]: () => 1000,
[`${N}getgrnam0(J)I`]: () => 1000,
[`${N}fchmodatNoFollowSupported0()Z`]: () => 0,
[`${N}statvfs0(JLsun/nio/fs/UnixFileStoreAttributes;)V`]: () => undefined,
[`${N}statvfs0(JLsun/nio/fs/UnixFileStoreAttributes;)V`]: (t, [p, attrs]) => {
const abs = path(t, p);
if (!t.vm.fs.stat(abs)) unixError(ENOENT);
const s = t.vm.fs.space(abs), A = "sun/nio/fs/UnixFileStoreAttributes";
t.vm.setField(attrs, A, "f_frsize", s.bsize);
t.vm.setField(attrs, A, "f_blocks", s.blocks);
t.vm.setField(attrs, A, "f_bfree", s.bfree);
t.vm.setField(attrs, A, "f_bavail", s.bavail);
},
[`${N}flistxattr(IJI)I`]: () => 0,
[`${N}getlinelen(J)I`]: () => -1,
[`${N}rewind(J)V`]: () => undefined,
Expand Down Expand Up @@ -441,7 +449,13 @@ Object.assign(natives, {
"java/nio/MappedMemoryUtils.isLoaded0(JJJ)Z": () => 1,
"java/nio/MappedMemoryUtils.load0(JJ)V": () => undefined,
"java/nio/MappedMemoryUtils.unload0(JJ)V": () => undefined,
[`${UFD}setDirect0(Ljava/io/FileDescriptor;)I`]: () => -1,
// Bytes go through the same buffers either way; this only reports the block
// size direct I/O aligns to, as fstatvfs gives it.
[`${UFD}setDirect0(Ljava/io/FileDescriptor;)I`]: (t, [fd]) => {
const f = chanFile(t, fd);
// an unlinked file has no path; the one it had names its file system
return Number(t.vm.fs.space(f.path || f.detached?.path || "/").bsize);
},
"sun/nio/ch/FileDispatcherImpl.init0()V": () => undefined,
"sun/nio/ch/FileDispatcherImpl.transferTo0(Ljava/io/FileDescriptor;JJLjava/io/FileDescriptor;Z)J": () => BigInt(UNSUPPORTED_CASE),
"sun/nio/ch/FileDispatcherImpl.transferFrom0(Ljava/io/FileDescriptor;Ljava/io/FileDescriptor;JJZ)J": () => BigInt(UNSUPPORTED_CASE),
Expand Down
8 changes: 8 additions & 0 deletions src/node.ts
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,14 @@ export class NodeBackend implements Backend {
return false;
}
}
space(p: string) {
try {
const s = fs.statfsSync(this.host(p), { bigint: true });
return { bsize: s.bsize, blocks: s.blocks, bfree: s.bfree, bavail: s.bavail };
} catch {
return null;
}
}
setMtime(p: string, ms: number) {
try {
fs.utimesSync(this.host(p), fs.statSync(this.host(p)).atime, ms / 1000);
Expand Down
20 changes: 20 additions & 0 deletions test/java/FileStores.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import java.io.File;
import java.nio.ByteBuffer;
import java.nio.file.*;

// A file store reports its host file system's block size and totals, as
// statvfs gives them; direct I/O sizes its buffers from the block size.
public class FileStores {
public static void main(String[] args) throws Exception {
Path tmp = Path.of(System.getProperty("java.io.tmpdir"));
FileStore store = Files.getFileStore(tmp);
long block = store.getBlockSize();
System.out.println("block size " + block);
System.out.println("total positive " + (store.getTotalSpace() > 0));
System.out.println("File total matches " + (tmp.toFile().getTotalSpace() == store.getTotalSpace()));
System.out.println("usable within total " + (store.getUsableSpace() <= store.getTotalSpace()));
System.out.println("missing file " + new File(tmp.toFile(), "no-such-file").getTotalSpace());
ByteBuffer buf = ByteBuffer.allocateDirect((int) block * 2).alignedSlice((int) block);
System.out.println("aligned capacity " + buf.capacity());
}
}
5 changes: 4 additions & 1 deletion test/jtreg/passing.txt
Original file line number Diff line number Diff line change
Expand Up @@ -1979,6 +1979,10 @@ java/nio/channels/FileChannel/Truncate.java
java/nio/channels/FileChannel/TruncateRAF.java
java/nio/channels/FileChannel/TryLock.java
java/nio/channels/FileChannel/Write.java
java/nio/channels/FileChannel/directio/PreadDirect.java
java/nio/channels/FileChannel/directio/PwriteDirect.java
java/nio/channels/FileChannel/directio/ReadDirect.java
java/nio/channels/FileChannel/directio/WriteDirect.java
java/nio/channels/FileLock/FileLockConstructor.java
java/nio/channels/FileLock/FileLockGC.java
java/nio/channels/FileLock/Overlaps.java
Expand Down Expand Up @@ -2109,7 +2113,6 @@ java/nio/file/Files/CopyToNonDefaultFS.java
java/nio/file/Files/CreateDirectories.java
java/nio/file/Files/CustomOptions.java
java/nio/file/Files/FileAttributes.java
java/nio/file/Files/InterruptCopy.java
java/nio/file/Files/Links.java
java/nio/file/Files/Misc.java
java/nio/file/Files/Mismatch.java
Expand Down
1 change: 0 additions & 1 deletion test/jtreg/times.tsv
Original file line number Diff line number Diff line change
Expand Up @@ -3393,7 +3393,6 @@
1201 java/nio/channels/DatagramChannel/NoSender.java
1187 java/nio/channels/Pipe/NonBlocking.java
1178 java/nio/channels/DatagramChannel/IsConnected.java
1157 java/nio/file/Files/InterruptCopy.java
1150 java/net/ResponseCache/B6181108.java
1143 java/net/URL/TestRFC2732.java
1143 java/lang/annotation/typeAnnotations/TestObjectMethods.java
Expand Down
Loading