1
1
/*
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.
3
3
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4
4
*
5
5
* This code is free software; you can redistribute it and/or modify it
29
29
* @summary Basic functionality of File.get-X-Space methods.
30
30
* @library .. /test/lib
31
31
* @build jdk.test.lib.Platform
32
- * @run main/othervm -Djava.security.manager=allow GetXSpace
32
+ * @run main/othervm/native -Djava.security.manager=allow GetXSpace
33
33
*/
34
34
35
35
import java .io .BufferedReader ;
52
52
53
53
@ SuppressWarnings ("removal" )
54
54
public class GetXSpace {
55
+ static {
56
+ System .loadLibrary ("GetXSpace" );
57
+ }
55
58
56
59
private static SecurityManager [] sma = { null , new Allow (), new DenyFSA (),
57
60
new DenyRead () };
58
61
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
-
62
62
private static int fail = 0 ;
63
63
private static int pass = 0 ;
64
64
private static Throwable first ;
@@ -100,39 +100,46 @@ private static void setFirst(String s) {
100
100
}
101
101
102
102
private static class Space {
103
- private static final long KSIZE = 1024 ;
104
103
private final String name ;
104
+ private final long size ;
105
105
private final long total ;
106
106
private final long free ;
107
+ private final long available ;
107
108
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 ) {
115
110
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 ];
116
118
}
117
119
118
120
String name () { return name ; }
121
+ long size () { return size ; }
119
122
long total () { return total ; }
123
+ long available () { return available ; }
120
124
long free () { return free ; }
125
+
121
126
boolean woomFree (long freeSpace ) {
122
- return ((freeSpace >= (free / 10 )) && (freeSpace <= (free * 10 )));
127
+ return ((freeSpace >= (available / 10 )) &&
128
+ (freeSpace <= (available * 10 )));
123
129
}
130
+
124
131
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 );
126
133
}
127
134
}
128
135
129
- private static ArrayList < Space > space ( String f ) throws IOException {
136
+ private static void diskFree ( ) throws IOException {
130
137
ArrayList <Space > al = new ArrayList <>();
131
138
132
- String cmd = "df -k -P" + ( f == null ? "" : " " + f ) ;
139
+ String cmd = "fsutil volume diskFree C: \\ " ;
133
140
StringBuilder sb = new StringBuilder ();
134
141
Process p = Runtime .getRuntime ().exec (cmd );
135
- try (BufferedReader in = new BufferedReader ( new InputStreamReader ( p . getInputStream ()) )) {
142
+ try (BufferedReader in = p . inputReader ( )) {
136
143
String s ;
137
144
int i = 0 ;
138
145
while ((s = in .readLine ()) != null ) {
@@ -142,33 +149,18 @@ private static ArrayList<Space> space(String f) throws IOException {
142
149
}
143
150
}
144
151
out .println (sb );
152
+ }
145
153
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 <>();
166
156
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 );
171
162
}
163
+
172
164
return al ;
173
165
}
174
166
@@ -208,14 +200,15 @@ private static void compare(Space s) {
208
200
long fs = f .getFreeSpace ();
209
201
long us = f .getUsableSpace ();
210
202
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 );
215
207
216
208
// If the file system can dynamically change size, this check will fail.
217
209
// 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" ))) {
219
212
long blockSize = 1 ;
220
213
long numBlocks = 0 ;
221
214
try {
@@ -232,34 +225,76 @@ private static void compare(Space s) {
232
225
throw new RuntimeException (e );
233
226
}
234
227
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 ());
242
234
}
243
235
} else {
244
236
pass ();
245
237
}
246
238
247
- // unix df returns statvfs.f_bavail
239
+ // unix usable space is from statvfs.f_bavail
248
240
long tsp = (!Platform .isWindows () ? us : fs );
249
241
if (!s .woomFree (tsp )) {
250
- fail (s .name (), s .free (), "??" , tsp );
242
+ fail (s .name (), s .available (), "??" , tsp );
251
243
} else {
252
244
pass ();
253
245
}
254
246
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 ());
257
260
} else {
258
261
pass ();
259
262
}
260
263
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
261
283
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
+ }
263
298
} else {
264
299
pass ();
265
300
}
@@ -316,14 +351,14 @@ private static class Deny extends SecurityManager {
316
351
public void checkPermission (Permission p ) {
317
352
if (p .implies (new RuntimePermission ("setSecurityManager" ))
318
353
|| p .implies (new RuntimePermission ("getProtectionDomain" )))
319
- return ;
354
+ return ;
320
355
super .checkPermission (p );
321
356
}
322
357
323
358
public void checkPermission (Permission p , Object context ) {
324
359
if (p .implies (new RuntimePermission ("setSecurityManager" ))
325
360
|| p .implies (new RuntimePermission ("getProtectionDomain" )))
326
- return ;
361
+ return ;
327
362
super .checkPermission (p , context );
328
363
}
329
364
}
@@ -355,31 +390,28 @@ public void checkRead(String file) {
355
390
private static int testFile (Path dir ) {
356
391
String dirName = dir .toString ();
357
392
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 ()));
365
394
366
395
if (fail != 0 ) {
367
396
err .format ("%d tests: %d failure(s); first: %s%n" ,
368
- fail + pass , fail , first );
397
+ fail + pass , fail , first );
369
398
} else {
370
399
out .format ("all %d tests passed%n" , fail + pass );
371
400
}
372
401
373
402
return fail != 0 ? 1 : 0 ;
374
403
}
375
404
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 ;
381
410
try {
382
- l = space (null );
411
+ l = paths ();
412
+ if (Platform .isWindows ()) {
413
+ diskFree ();
414
+ }
383
415
} catch (IOException x ) {
384
416
throw new RuntimeException ("can't get file system information" , x );
385
417
}
@@ -395,7 +427,8 @@ private static int testDF() {
395
427
396
428
out .format ("%nSecurityManager = %s%n" ,
397
429
(sm == null ? "null" : sm .getClass ().getName ()));
398
- for (var s : l ) {
430
+ for (var p : l ) {
431
+ Space s = new Space (p );
399
432
if (sm instanceof Deny ) {
400
433
tryCatch (s );
401
434
} else {
@@ -410,7 +443,7 @@ private static int testDF() {
410
443
411
444
if (fail != 0 ) {
412
445
err .format ("%d tests: %d failure(s); first: %s%n" ,
413
- fail + pass , fail , first );
446
+ fail + pass , fail , first );
414
447
} else {
415
448
out .format ("all %d tests passed%n" , fail + pass );
416
449
}
@@ -433,7 +466,7 @@ private static void allow(Path path) throws IOException {
433
466
}
434
467
435
468
public static void main (String [] args ) throws Exception {
436
- int failedTests = testDF ();
469
+ int failedTests = testVolumes ();
437
470
reset ();
438
471
439
472
Path tmpDir = Files .createTempDirectory (null );
@@ -452,4 +485,13 @@ public static void main(String[] args) throws Exception {
452
485
throw new RuntimeException (failedTests + " test(s) failed" );
453
486
}
454
487
}
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 );
455
497
}
0 commit comments