1 /* 2 * Copyright (c) 2008, 2018, 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. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 package sun.nio.fs; 27 28 import sun.nio.cs.UTF_8; 29 30 import jdk.internal.util.StaticProperty; 31 32 import java.nio.file.*; 33 import java.nio.file.attribute.*; 34 import java.nio.channels.*; 35 import java.util.*; 36 import java.io.IOException; 37 import java.security.AccessController; 38 import java.security.PrivilegedAction; 39 40 /** 41 * Base implementation of FileStore for Unix/like implementations. 42 */ 43 44 abstract class UnixFileStore 45 extends FileStore 46 { 47 // original path of file that identified file system 48 private final UnixPath file; 49 50 // device ID 51 private final long dev; 52 53 // entry in the mount tab 54 private final UnixMountEntry entry; 55 56 // return the device ID where the given file resides devFor(UnixPath file)57 private static long devFor(UnixPath file) throws IOException { 58 try { 59 return UnixFileAttributes.get(file, true).dev(); 60 } catch (UnixException x) { 61 x.rethrowAsIOException(file); 62 return 0L; // keep compiler happy 63 } 64 } 65 UnixFileStore(UnixPath file)66 UnixFileStore(UnixPath file) throws IOException { 67 this.file = file; 68 this.dev = devFor(file); 69 this.entry = findMountEntry(); 70 } 71 UnixFileStore(UnixFileSystem fs, UnixMountEntry entry)72 UnixFileStore(UnixFileSystem fs, UnixMountEntry entry) throws IOException { 73 this.file = new UnixPath(fs, entry.dir()); 74 this.dev = (entry.dev() == 0L) ? devFor(this.file) : entry.dev(); 75 this.entry = entry; 76 } 77 78 /** 79 * Find the mount entry for the file store 80 */ findMountEntry()81 abstract UnixMountEntry findMountEntry() throws IOException; 82 file()83 UnixPath file() { 84 return file; 85 } 86 dev()87 long dev() { 88 return dev; 89 } 90 entry()91 UnixMountEntry entry() { 92 return entry; 93 } 94 95 @Override name()96 public String name() { 97 return entry.name(); 98 } 99 100 @Override type()101 public String type() { 102 return entry.fstype(); 103 } 104 105 @Override isReadOnly()106 public boolean isReadOnly() { 107 return entry.isReadOnly(); 108 } 109 110 // uses statvfs to read the file system information readAttributes()111 private UnixFileStoreAttributes readAttributes() throws IOException { 112 try { 113 return UnixFileStoreAttributes.get(file); 114 } catch (UnixException x) { 115 x.rethrowAsIOException(file); 116 return null; // keep compile happy 117 } 118 } 119 120 @Override getTotalSpace()121 public long getTotalSpace() throws IOException { 122 UnixFileStoreAttributes attrs = readAttributes(); 123 return attrs.blockSize() * attrs.totalBlocks(); 124 } 125 126 @Override getUsableSpace()127 public long getUsableSpace() throws IOException { 128 UnixFileStoreAttributes attrs = readAttributes(); 129 return attrs.blockSize() * attrs.availableBlocks(); 130 } 131 132 @Override getBlockSize()133 public long getBlockSize() throws IOException { 134 UnixFileStoreAttributes attrs = readAttributes(); 135 return attrs.blockSize(); 136 } 137 138 @Override getUnallocatedSpace()139 public long getUnallocatedSpace() throws IOException { 140 UnixFileStoreAttributes attrs = readAttributes(); 141 return attrs.blockSize() * attrs.freeBlocks(); 142 } 143 144 @Override getFileStoreAttributeView(Class<V> view)145 public <V extends FileStoreAttributeView> V getFileStoreAttributeView(Class<V> view) 146 { 147 if (view == null) 148 throw new NullPointerException(); 149 return (V) null; 150 } 151 152 @Override getAttribute(String attribute)153 public Object getAttribute(String attribute) throws IOException { 154 if (attribute.equals("totalSpace")) 155 return getTotalSpace(); 156 if (attribute.equals("usableSpace")) 157 return getUsableSpace(); 158 if (attribute.equals("unallocatedSpace")) 159 return getUnallocatedSpace(); 160 throw new UnsupportedOperationException("'" + attribute + "' not recognized"); 161 } 162 163 @Override supportsFileAttributeView(Class<? extends FileAttributeView> type)164 public boolean supportsFileAttributeView(Class<? extends FileAttributeView> type) { 165 if (type == null) 166 throw new NullPointerException(); 167 if (type == BasicFileAttributeView.class) 168 return true; 169 if (type == PosixFileAttributeView.class || 170 type == FileOwnerAttributeView.class) 171 { 172 // lookup fstypes.properties 173 FeatureStatus status = checkIfFeaturePresent("posix"); 174 // assume supported if UNKNOWN 175 return (status != FeatureStatus.NOT_PRESENT); 176 } 177 return false; 178 } 179 180 @Override supportsFileAttributeView(String name)181 public boolean supportsFileAttributeView(String name) { 182 if (name.equals("basic") || name.equals("unix")) 183 return true; 184 if (name.equals("posix")) 185 return supportsFileAttributeView(PosixFileAttributeView.class); 186 if (name.equals("owner")) 187 return supportsFileAttributeView(FileOwnerAttributeView.class); 188 return false; 189 } 190 191 @Override equals(Object ob)192 public boolean equals(Object ob) { 193 if (ob == this) 194 return true; 195 if (!(ob instanceof UnixFileStore)) 196 return false; 197 UnixFileStore other = (UnixFileStore)ob; 198 return (this.dev == other.dev) && 199 Arrays.equals(this.entry.dir(), other.entry.dir()) && 200 this.entry.name().equals(other.entry.name()); 201 } 202 203 @Override hashCode()204 public int hashCode() { 205 return (int)(dev ^ (dev >>> 32)) ^ Arrays.hashCode(entry.dir()); 206 } 207 208 @Override toString()209 public String toString() { 210 StringBuilder sb = new StringBuilder(Util.toString(entry.dir())); 211 sb.append(" ("); 212 sb.append(entry.name()); 213 sb.append(")"); 214 return sb.toString(); 215 } 216 217 // -- fstypes.properties -- 218 219 private static final Object loadLock = new Object(); 220 private static volatile Properties props; 221 222 enum FeatureStatus { 223 PRESENT, 224 NOT_PRESENT, 225 UNKNOWN; 226 } 227 228 /** 229 * Returns status to indicate if file system supports a given feature 230 */ checkIfFeaturePresent(String feature)231 FeatureStatus checkIfFeaturePresent(String feature) { 232 if (props == null) { 233 synchronized (loadLock) { 234 if (props == null) { 235 props = AccessController.doPrivileged( 236 new PrivilegedAction<>() { 237 @Override 238 public Properties run() { 239 return loadProperties(); 240 }}); 241 } 242 } 243 } 244 245 String value = props.getProperty(type()); 246 if (value != null) { 247 String[] values = value.split("\\s"); 248 for (String s: values) { 249 s = s.trim().toLowerCase(); 250 if (s.equals(feature)) { 251 return FeatureStatus.PRESENT; 252 } 253 if (s.startsWith("no")) { 254 s = s.substring(2); 255 if (s.equals(feature)) { 256 return FeatureStatus.NOT_PRESENT; 257 } 258 } 259 } 260 } 261 return FeatureStatus.UNKNOWN; 262 } 263 loadProperties()264 private static Properties loadProperties() { 265 Properties result = new Properties(); 266 String fstypes = StaticProperty.javaHome() + "/lib/fstypes.properties"; 267 Path file = Path.of(fstypes); 268 try { 269 try (ReadableByteChannel rbc = Files.newByteChannel(file)) { 270 result.load(Channels.newReader(rbc, UTF_8.INSTANCE)); 271 } 272 } catch (IOException x) { 273 } 274 return result; 275 } 276 } 277