1 /* 2 * Copyright (c) 2005, 2020, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. 8 * 9 * This code is distributed in the hope that it will be useful, but WITHOUT 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 12 * version 2 for more details (a copy is included in the LICENSE file that 13 * accompanied this code). 14 * 15 * You should have received a copy of the GNU General Public License version 16 * 2 along with this work; if not, write to the Free Software Foundation, 17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 18 * 19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 20 * or visit www.oracle.com if you need additional information or have any 21 * questions. 22 */ 23 24 /** 25 * @test 26 * @bug 4057701 6286712 6364377 27 * @run build GetXSpace 28 * @run shell GetXSpace.sh 29 * @summary Basic functionality of File.get-X-Space methods. 30 * @key randomness 31 */ 32 33 import java.io.BufferedReader; 34 import java.io.File; 35 import java.io.FilePermission; 36 import java.io.InputStreamReader; 37 import java.io.IOException; 38 import java.security.Permission; 39 import java.util.ArrayList; 40 import java.util.regex.Matcher; 41 import java.util.regex.Pattern; 42 43 import static java.lang.System.out; 44 45 public class GetXSpace { 46 47 private static SecurityManager [] sma = { null, new Allow(), new DenyFSA(), 48 new DenyRead() }; 49 50 private static final String osName = System.getProperty("os.name"); 51 // FileSystem Total Used Available Use% MountedOn 52 private static final Pattern dfPattern = Pattern.compile("([^\\s]+)\\s+(\\d+)\\s+\\d+\\s+(\\d+)\\s+\\d+%\\s+([^\\s].*)\n"); 53 54 private static int fail = 0; 55 private static int pass = 0; 56 private static Throwable first; 57 58 static void pass() { 59 pass++; 60 } 61 62 static void fail(String p) { 63 setFirst(p); 64 System.err.format("FAILED: %s%n", p); 65 fail++; 66 } 67 68 static void fail(String p, long exp, String cmp, long got) { 69 String s = String.format("'%s': %d %s %d", p, exp, cmp, got); 70 setFirst(s); 71 System.err.format("FAILED: %s%n", s); 72 fail++; 73 } 74 75 private static void fail(String p, Class ex) { 76 String s = String.format("'%s': expected %s - FAILED%n", p, ex.getName()); 77 setFirst(s); 78 System.err.format("FAILED: %s%n", s); 79 fail++; 80 } 81 82 private static void setFirst(String s) { 83 if (first == null) { 84 first = new RuntimeException(s); 85 } 86 } 87 88 private static class Space { 89 private static final long KSIZE = 1024; 90 private final String name; 91 private final long total; 92 private final long free; 93 94 Space(String total, String free, String name) { 95 try { 96 this.total = Long.valueOf(total) * KSIZE; 97 this.free = Long.valueOf(free) * KSIZE; 98 } catch (NumberFormatException x) { 99 throw new RuntimeException("the regex should have caught this", x); 100 } 101 this.name = name; 102 } 103 104 String name() { return name; } 105 long total() { return total; } 106 long free() { return free; } 107 boolean woomFree(long freeSpace) { 108 return ((freeSpace >= (free / 10)) && (freeSpace <= (free * 10))); 109 } 110 public String toString() { 111 return String.format("%s (%d/%d)", name, free, total); 112 } 113 } 114 115 private static ArrayList<Space> space(String f) throws IOException { 116 ArrayList<Space> al = new ArrayList<>(); 117 118 String cmd = "df -k -P" + (f == null ? "" : " " + f); 119 StringBuilder sb = new StringBuilder(); 120 Process p = Runtime.getRuntime().exec(cmd); 121 try (BufferedReader in = new BufferedReader(new InputStreamReader(p.getInputStream()))) { 122 String s; 123 int i = 0; 124 while ((s = in.readLine()) != null) { 125 // skip header 126 if (i++ == 0) continue; 127 sb.append(s).append("\n"); 128 } 129 } 130 out.println(sb); 131 132 Matcher m = dfPattern.matcher(sb); 133 int j = 0; 134 while (j < sb.length()) { 135 if (m.find(j)) { 136 // swap can change while this test is running 137 if (!m.group(1).equals("swap")) { 138 String name = f; 139 if (name == null) { 140 // cygwin's df lists windows path as FileSystem (1st group) 141 name = osName.startsWith("Windows") ? m.group(1) : m.group(4); 142 } 143 al.add(new Space(m.group(2), m.group(3), name));; 144 } 145 j = m.end() + 1; 146 } else { 147 throw new RuntimeException("unrecognized df output format: " 148 + "charAt(" + j + ") = '" 149 + sb.charAt(j) + "'"); 150 } 151 } 152 153 if (al.size() == 0) { 154 // df did not produce output 155 String name = (f == null ? "" : f); 156 al.add(new Space("0", "0", name)); 157 } 158 return al; 159 } 160 161 private static void tryCatch(Space s) { 162 out.format("%s:%n", s.name()); 163 File f = new File(s.name()); 164 SecurityManager sm = System.getSecurityManager(); 165 if (sm instanceof Deny) { 166 String fmt = " %14s: \"%s\" thrown as expected%n"; 167 try { 168 f.getTotalSpace(); 169 fail(s.name(), SecurityException.class); 170 } catch (SecurityException x) { 171 out.format(fmt, "getTotalSpace", x); 172 pass(); 173 } 174 try { 175 f.getFreeSpace(); 176 fail(s.name(), SecurityException.class); 177 } catch (SecurityException x) { 178 out.format(fmt, "getFreeSpace", x); 179 pass(); 180 } 181 try { 182 f.getUsableSpace(); 183 fail(s.name(), SecurityException.class); 184 } catch (SecurityException x) { 185 out.format(fmt, "getUsableSpace", x); 186 pass(); 187 } 188 } 189 } 190 191 private static void compare(Space s) { 192 File f = new File(s.name()); 193 long ts = f.getTotalSpace(); 194 long fs = f.getFreeSpace(); 195 long us = f.getUsableSpace(); 196 197 out.format("%s:%n", s.name()); 198 String fmt = " %-4s total= %12d free = %12d usable = %12d%n"; 199 out.format(fmt, "df", s.total(), 0, s.free()); 200 out.format(fmt, "getX", ts, fs, us); 201 202 // if the file system can dynamically change size, this check will fail 203 if (ts != s.total()) { 204 fail(s.name(), s.total(), "!=", ts); 205 } else { 206 pass(); 207 } 208 209 // unix df returns statvfs.f_bavail 210 long tsp = (!osName.startsWith("Windows") ? us : fs); 211 if (!s.woomFree(tsp)) { 212 fail(s.name(), s.free(), "??", tsp); 213 } else { 214 pass(); 215 } 216 217 if (fs > s.total()) { 218 fail(s.name(), s.total(), ">", fs); 219 } else { 220 pass(); 221 } 222 223 if (us > s.total()) { 224 fail(s.name(), s.total(), ">", us); 225 } else { 226 pass(); 227 } 228 } 229 230 private static String FILE_PREFIX = "/getSpace."; 231 private static void compareZeroNonExist() { 232 File f; 233 while (true) { 234 f = new File(FILE_PREFIX + Math.random()); 235 if (f.exists()) { 236 continue; 237 } 238 break; 239 } 240 241 long [] s = { f.getTotalSpace(), f.getFreeSpace(), f.getUsableSpace() }; 242 243 for (int i = 0; i < s.length; i++) { 244 if (s[i] != 0L) { 245 fail(f.getName(), s[i], "!=", 0L); 246 } else { 247 pass(); 248 } 249 } 250 } 251 252 private static void compareZeroExist() { 253 try { 254 File f = File.createTempFile("tmp", null, new File(".")); 255 256 long [] s = { f.getTotalSpace(), f.getFreeSpace(), f.getUsableSpace() }; 257 258 for (int i = 0; i < s.length; i++) { 259 if (s[i] == 0L) { 260 fail(f.getName(), s[i], "==", 0L); 261 } else { 262 pass(); 263 } 264 } 265 } catch (IOException x) { 266 x.printStackTrace(); 267 fail("Couldn't create temp file for test"); 268 } 269 } 270 271 private static class Allow extends SecurityManager { 272 public void checkRead(String file) {} 273 public void checkPermission(Permission p) {} 274 public void checkPermission(Permission p, Object context) {} 275 } 276 277 private static class Deny extends SecurityManager { 278 public void checkPermission(Permission p) { 279 if (p.implies(new RuntimePermission("setSecurityManager")) 280 || p.implies(new RuntimePermission("getProtectionDomain"))) 281 return; 282 super.checkPermission(p); 283 } 284 285 public void checkPermission(Permission p, Object context) { 286 if (p.implies(new RuntimePermission("setSecurityManager")) 287 || p.implies(new RuntimePermission("getProtectionDomain"))) 288 return; 289 super.checkPermission(p, context); 290 } 291 } 292 293 private static class DenyFSA extends Deny { 294 private String err = "sorry - getFileSystemAttributes"; 295 296 public void checkPermission(Permission p) { 297 if (p.implies(new RuntimePermission("getFileSystemAttributes"))) 298 throw new SecurityException(err); 299 super.checkPermission(p); 300 } 301 302 public void checkPermission(Permission p, Object context) { 303 if (p.implies(new RuntimePermission("getFileSystemAttributes"))) 304 throw new SecurityException(err); 305 super.checkPermission(p, context); 306 } 307 } 308 309 private static class DenyRead extends Deny { 310 private String err = "sorry - checkRead()"; 311 312 public void checkRead(String file) { 313 throw new SecurityException(err); 314 } 315 } 316 317 private static void testFile(String dirName) { 318 out.format("--- Testing %s%n", dirName); 319 ArrayList<Space> l; 320 try { 321 l = space(dirName); 322 } catch (IOException x) { 323 throw new RuntimeException(dirName + " can't get file system information", x); 324 } 325 compare(l.get(0)); 326 } 327 328 private static void testDF() { 329 out.println("--- Testing df"); 330 // Find all of the partitions on the machine and verify that the size 331 // returned by "df" is equivalent to File.getXSpace() values. 332 ArrayList<Space> l; 333 try { 334 l = space(null); 335 } catch (IOException x) { 336 throw new RuntimeException("can't get file system information", x); 337 } 338 if (l.size() == 0) 339 throw new RuntimeException("no partitions?"); 340 341 for (int i = 0; i < sma.length; i++) { 342 System.setSecurityManager(sma[i]); 343 SecurityManager sm = System.getSecurityManager(); 344 if (sma[i] != null && sm == null) 345 throw new RuntimeException("Test configuration error " 346 + " - can't set security manager"); 347 348 out.format("%nSecurityManager = %s%n" , 349 (sm == null ? "null" : sm.getClass().getName())); 350 for (var s : l) { 351 if (sm instanceof Deny) { 352 tryCatch(s); 353 } else { 354 compare(s); 355 compareZeroNonExist(); 356 compareZeroExist(); 357 } 358 } 359 } 360 } 361 362 public static void main(String [] args) { 363 if (args.length > 0) { 364 testFile(args[0]); 365 } else { 366 testDF(); 367 } 368 369 if (fail != 0) { 370 throw new RuntimeException((fail + pass) + " tests: " 371 + fail + " failure(s), first", first); 372 } else { 373 out.format("all %d tests passed%n", fail + pass); 374 } 375 } 376 }