Skip to content

Commit f85053f

Browse files
committed
8291911: java/io/File/GetXSpace.java fails with "53687091200 != 161051996160"
8298619: java/io/File/GetXSpace.java is failing 8305646: compile error on Alpine with gcc12 after 8298619 in libGetXSpace.c 8309216: Cast from jchar* to char* in test java/io/GetXSpace.java Reviewed-by: lucy Backport-of: 749335d34ac570760279ac81308d5d323aba4067
1 parent 5a9ceba commit f85053f

File tree

3 files changed

+286
-78
lines changed

3 files changed

+286
-78
lines changed

make/test/JtregNativeJdk.gmk

+2
Original file line numberDiff line numberDiff line change
@@ -66,9 +66,11 @@ ifeq ($(call isTargetOs, windows), true)
6666
BUILD_JDK_JTREG_EXECUTABLES_LIBS_exeCallerAccessTest := jvm.lib
6767
BUILD_JDK_JTREG_EXECUTABLES_LIBS_exerevokeall := advapi32.lib
6868
BUILD_JDK_JTREG_LIBRARIES_CFLAGS_libAsyncStackWalk := /EHsc
69+
BUILD_JDK_JTREG_LIBRARIES_LIBS_libGetXSpace := $(WIN_LIB_JAVA)
6970
else
7071
BUILD_JDK_JTREG_LIBRARIES_LIBS_libstringPlatformChars := -ljava
7172
BUILD_JDK_JTREG_LIBRARIES_LIBS_libDirectIO := -ljava
73+
BUILD_JDK_JTREG_LIBRARIES_LIBS_libGetXSpace := -ljava
7274
BUILD_JDK_JTREG_EXCLUDE += exerevokeall.c
7375
ifeq ($(call isTargetOs, linux), true)
7476
BUILD_JDK_JTREG_LIBRARIES_LIBS_libInheritedChannel := -ljava

test/jdk/java/io/File/GetXSpace.java

+120-78
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2005, 2022, Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 2005, 2023, Oracle and/or its affiliates. All rights reserved.
33
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
44
*
55
* This code is free software; you can redistribute it and/or modify it
@@ -29,7 +29,7 @@
2929
* @summary Basic functionality of File.get-X-Space methods.
3030
* @library .. /test/lib
3131
* @build jdk.test.lib.Platform
32-
* @run main/othervm -Djava.security.manager=allow GetXSpace
32+
* @run main/othervm/native -Djava.security.manager=allow GetXSpace
3333
*/
3434

3535
import java.io.BufferedReader;
@@ -52,13 +52,13 @@
5252

5353
@SuppressWarnings("removal")
5454
public class GetXSpace {
55+
static {
56+
System.loadLibrary("GetXSpace");
57+
}
5558

5659
private static SecurityManager [] sma = { null, new Allow(), new DenyFSA(),
5760
new DenyRead() };
5861

59-
// FileSystem Total Used Available Use% MountedOn
60-
private static final Pattern DF_PATTERN = Pattern.compile("([^\\s]+)\\s+(\\d+)\\s+\\d+\\s+(\\d+)\\s+\\d+%\\s+([^\\s].*)\n");
61-
6262
private static int fail = 0;
6363
private static int pass = 0;
6464
private static Throwable first;
@@ -100,39 +100,46 @@ private static void setFirst(String s) {
100100
}
101101

102102
private static class Space {
103-
private static final long KSIZE = 1024;
104103
private final String name;
104+
private final long size;
105105
private final long total;
106106
private final long free;
107+
private final long available;
107108

108-
Space(String total, String free, String name) {
109-
try {
110-
this.total = Long.parseLong(total) * KSIZE;
111-
this.free = Long.parseLong(free) * KSIZE;
112-
} catch (NumberFormatException x) {
113-
throw new RuntimeException("the regex should have caught this", x);
114-
}
109+
Space(String name) {
115110
this.name = name;
111+
long[] sizes = new long[4];
112+
if (getSpace0(name, sizes))
113+
System.err.println("WARNING: total space is estimated");
114+
this.size = sizes[0];
115+
this.total = sizes[1];
116+
this.free = sizes[2];
117+
this.available = sizes[3];
116118
}
117119

118120
String name() { return name; }
121+
long size() { return size; }
119122
long total() { return total; }
123+
long available() { return available; }
120124
long free() { return free; }
125+
121126
boolean woomFree(long freeSpace) {
122-
return ((freeSpace >= (free / 10)) && (freeSpace <= (free * 10)));
127+
return ((freeSpace >= (available / 10)) &&
128+
(freeSpace <= (available * 10)));
123129
}
130+
124131
public String toString() {
125-
return String.format("%s (%d/%d)", name, free, total);
132+
return String.format("%s (%d/%d/%d)", name, total, free, available);
126133
}
127134
}
128135

129-
private static ArrayList<Space> space(String f) throws IOException {
136+
private static void diskFree() throws IOException {
130137
ArrayList<Space> al = new ArrayList<>();
131138

132-
String cmd = "df -k -P" + (f == null ? "" : " " + f);
139+
String cmd = "fsutil volume diskFree C:\\";
133140
StringBuilder sb = new StringBuilder();
134141
Process p = Runtime.getRuntime().exec(cmd);
135-
try (BufferedReader in = new BufferedReader(new InputStreamReader(p.getInputStream()))) {
142+
try (BufferedReader in = p.inputReader()) {
136143
String s;
137144
int i = 0;
138145
while ((s = in.readLine()) != null) {
@@ -142,33 +149,18 @@ private static ArrayList<Space> space(String f) throws IOException {
142149
}
143150
}
144151
out.println(sb);
152+
}
145153

146-
Matcher m = DF_PATTERN.matcher(sb);
147-
int j = 0;
148-
while (j < sb.length()) {
149-
if (m.find(j)) {
150-
// swap can change while this test is running
151-
if (!m.group(1).equals("swap")) {
152-
String name = f;
153-
if (name == null) {
154-
// cygwin's df lists windows path as FileSystem (1st group)
155-
name = Platform.isWindows() ? m.group(1) : m.group(4);
156-
}
157-
al.add(new Space(m.group(2), m.group(3), name));;
158-
}
159-
j = m.end();
160-
} else {
161-
throw new RuntimeException("unrecognized df output format: "
162-
+ "charAt(" + j + ") = '"
163-
+ sb.charAt(j) + "'");
164-
}
165-
}
154+
private static ArrayList<String> paths() throws IOException {
155+
ArrayList<String> al = new ArrayList<>();
166156

167-
if (al.size() == 0) {
168-
// df did not produce output
169-
String name = (f == null ? "" : f);
170-
al.add(new Space("0", "0", name));
157+
File[] roots = File.listRoots();
158+
long[] space = new long[4];
159+
for (File root : roots) {
160+
String path = root.toString();
161+
al.add(path);
171162
}
163+
172164
return al;
173165
}
174166

@@ -208,14 +200,15 @@ private static void compare(Space s) {
208200
long fs = f.getFreeSpace();
209201
long us = f.getUsableSpace();
210202

211-
out.format("%s:%n", s.name());
212-
String fmt = " %-4s total= %12d free = %12d usable = %12d%n";
213-
out.format(fmt, "df", s.total(), 0, s.free());
214-
out.format(fmt, "getX", ts, fs, us);
203+
out.format("%s (%d):%n", s.name(), s.size());
204+
String fmt = " %-4s total = %12d free = %12d usable = %12d%n";
205+
out.format(fmt, "getSpace0", s.total(), s.free(), s.available());
206+
out.format(fmt, "getXSpace", ts, fs, us);
215207

216208
// If the file system can dynamically change size, this check will fail.
217209
// This can happen on macOS for the /dev files system.
218-
if (ts != s.total() && (!Platform.isOSX() || !s.name().equals("/dev"))) {
210+
if (ts != s.total()
211+
&& (!Platform.isOSX() || !s.name().equals("/dev"))) {
219212
long blockSize = 1;
220213
long numBlocks = 0;
221214
try {
@@ -232,34 +225,76 @@ private static void compare(Space s) {
232225
throw new RuntimeException(e);
233226
}
234227

235-
// On macOS, the number of 1024 byte blocks might be incorrectly
236-
// calculated by 'df' using integer division by 2 of the number of
237-
// 512 byte blocks, resulting in a size smaller than the actual
238-
// value when the number of blocks is odd.
239-
if (!Platform.isOSX() || blockSize != 512 || numBlocks % 2 == 0
240-
|| ts - s.total() != 512) {
241-
fail(s.name(), s.total(), "!=", ts);
228+
if (Platform.isWindows()) {
229+
if (ts > s.total()) {
230+
fail(s.name() + " total space", ts, ">", s.total());
231+
}
232+
} else if (ts != s.total()) {
233+
fail(s.name() + " total space", ts, "!=", s.total());
242234
}
243235
} else {
244236
pass();
245237
}
246238

247-
// unix df returns statvfs.f_bavail
239+
// unix usable space is from statvfs.f_bavail
248240
long tsp = (!Platform.isWindows() ? us : fs);
249241
if (!s.woomFree(tsp)) {
250-
fail(s.name(), s.free(), "??", tsp);
242+
fail(s.name(), s.available(), "??", tsp);
251243
} else {
252244
pass();
253245
}
254246

255-
if (fs > s.total()) {
256-
fail(s.name(), s.total(), ">", fs);
247+
//
248+
// Invariants are:
249+
// total space <= size
250+
// total space == size (Unix)
251+
// free space <= total space (if no quotas in effect) (Windows)
252+
// free space < size (if quotas in effect) (Windows)
253+
// usable space <= total space
254+
// usable space <= free space
255+
//
256+
257+
// total space <= size
258+
if (ts > s.size()) {
259+
fail(s.name() + " size", ts, ">", s.size());
257260
} else {
258261
pass();
259262
}
260263

264+
// On Unix the total space should always be the volume size
265+
if (Platform.isWindows()) {
266+
// ts != s.size() indicates that quotas are in effect
267+
if (ts == s.size() && fs > s.total()) {
268+
fail(s.name() + " free space", fs, ">", s.total());
269+
} else if (ts < s.size() && fs > s.size()) {
270+
fail(s.name() + " free space (quota)", fs, ">", s.size());
271+
} else {
272+
pass();
273+
}
274+
} else { // not Windows
275+
if (ts != s.size()) {
276+
fail(s.name() + " total space", ts, "!=", s.size());
277+
} else {
278+
pass();
279+
}
280+
}
281+
282+
// usable space <= total space
261283
if (us > s.total()) {
262-
fail(s.name(), s.total(), ">", us);
284+
fail(s.name() + " usable space", us, ">", s.total());
285+
} else {
286+
pass();
287+
}
288+
289+
// usable space <= free space
290+
if (us > s.free()) {
291+
// free and usable change dynamically
292+
System.err.println("Warning: us > s.free()");
293+
if (1.0 - Math.abs((double)s.free()/(double)us) > 0.01) {
294+
fail(s.name() + " usable vs. free space", us, ">", s.free());
295+
} else {
296+
pass();
297+
}
263298
} else {
264299
pass();
265300
}
@@ -316,14 +351,14 @@ private static class Deny extends SecurityManager {
316351
public void checkPermission(Permission p) {
317352
if (p.implies(new RuntimePermission("setSecurityManager"))
318353
|| p.implies(new RuntimePermission("getProtectionDomain")))
319-
return;
354+
return;
320355
super.checkPermission(p);
321356
}
322357

323358
public void checkPermission(Permission p, Object context) {
324359
if (p.implies(new RuntimePermission("setSecurityManager"))
325360
|| p.implies(new RuntimePermission("getProtectionDomain")))
326-
return;
361+
return;
327362
super.checkPermission(p, context);
328363
}
329364
}
@@ -355,31 +390,28 @@ public void checkRead(String file) {
355390
private static int testFile(Path dir) {
356391
String dirName = dir.toString();
357392
out.format("--- Testing %s%n", dirName);
358-
ArrayList<Space> l;
359-
try {
360-
l = space(dirName);
361-
} catch (IOException x) {
362-
throw new RuntimeException(dirName + " can't get file system information", x);
363-
}
364-
compare(l.get(0));
393+
compare(new Space(dir.getRoot().toString()));
365394

366395
if (fail != 0) {
367396
err.format("%d tests: %d failure(s); first: %s%n",
368-
fail + pass, fail, first);
397+
fail + pass, fail, first);
369398
} else {
370399
out.format("all %d tests passed%n", fail + pass);
371400
}
372401

373402
return fail != 0 ? 1 : 0;
374403
}
375404

376-
private static int testDF() {
377-
out.println("--- Testing df");
378-
// Find all of the partitions on the machine and verify that the size
379-
// returned by "df" is equivalent to File.getXSpace() values.
380-
ArrayList<Space> l;
405+
private static int testVolumes() {
406+
out.println("--- Testing volumes");
407+
// Find all of the partitions on the machine and verify that the sizes
408+
// returned by File::getXSpace are equivalent to those from getSpace0
409+
ArrayList<String> l;
381410
try {
382-
l = space(null);
411+
l = paths();
412+
if (Platform.isWindows()) {
413+
diskFree();
414+
}
383415
} catch (IOException x) {
384416
throw new RuntimeException("can't get file system information", x);
385417
}
@@ -395,7 +427,8 @@ private static int testDF() {
395427

396428
out.format("%nSecurityManager = %s%n" ,
397429
(sm == null ? "null" : sm.getClass().getName()));
398-
for (var s : l) {
430+
for (var p : l) {
431+
Space s = new Space(p);
399432
if (sm instanceof Deny) {
400433
tryCatch(s);
401434
} else {
@@ -410,7 +443,7 @@ private static int testDF() {
410443

411444
if (fail != 0) {
412445
err.format("%d tests: %d failure(s); first: %s%n",
413-
fail + pass, fail, first);
446+
fail + pass, fail, first);
414447
} else {
415448
out.format("all %d tests passed%n", fail + pass);
416449
}
@@ -433,7 +466,7 @@ private static void allow(Path path) throws IOException {
433466
}
434467

435468
public static void main(String[] args) throws Exception {
436-
int failedTests = testDF();
469+
int failedTests = testVolumes();
437470
reset();
438471

439472
Path tmpDir = Files.createTempDirectory(null);
@@ -452,4 +485,13 @@ public static void main(String[] args) throws Exception {
452485
throw new RuntimeException(failedTests + " test(s) failed");
453486
}
454487
}
488+
489+
//
490+
// root the root of the volume
491+
// size[0] total size: number of bytes in the volume
492+
// size[1] total space: number of bytes visible to the caller
493+
// size[2] free space: number of free bytes in the volume
494+
// size[3] usable space: number of bytes available to the caller
495+
//
496+
private static native boolean getSpace0(String root, long[] space);
455497
}

0 commit comments

Comments
 (0)