1 /* 2 * Copyright (c) 2008, 2010, 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 java.nio.file.*; 29 import java.nio.file.attribute.*; 30 import java.nio.channels.*; 31 import java.util.*; 32 import java.io.IOException; 33 import java.security.AccessController; 34 import java.security.PrivilegedAction; 35 36 /** 37 * Base implementation of FileStore for Unix/like implementations. 38 */ 39 40 abstract class UnixFileStore 41 extends FileStore 42 { 43 // original path of file that identified file system 44 private final UnixPath file; 45 46 // device ID 47 private final long dev; 48 49 // entry in the mount tab 50 private final UnixMountEntry entry; 51 52 // return the device ID where the given file resides 53 private static long devFor(UnixPath file) throws IOException { 54 try { 55 return UnixFileAttributes.get(file, true).dev(); 56 } catch (UnixException x) { 57 x.rethrowAsIOException(file); 58 return 0L; // keep compiler happy 59 } 60 } 61 62 UnixFileStore(UnixPath file) throws IOException { 63 this.file = file; 64 this.dev = devFor(file); 65 this.entry = findMountEntry(); 66 } 67 68 UnixFileStore(UnixFileSystem fs, UnixMountEntry entry) throws IOException { 69 this.file = new UnixPath(fs, entry.dir()); 70 this.dev = (entry.dev() == 0L) ? devFor(this.file) : entry.dev(); 71 this.entry = entry; 72 } 73 74 /** 75 * Find the mount entry for the file store 76 */ 77 abstract UnixMountEntry findMountEntry() throws IOException; 78 79 UnixPath file() { 80 return file; 81 } 82 83 long dev() { 84 return dev; 85 } 86 87 UnixMountEntry entry() { 88 return entry; 89 } 90 91 @Override 92 public String name() { 93 return entry.name(); 94 } 95 96 @Override 97 public String type() { 98 return entry.fstype(); 99 } 100 101 @Override 102 public boolean isReadOnly() { 103 return entry.isReadOnly(); 104 } 105 106 @Override 107 @SuppressWarnings("unchecked") 108 public <V extends FileStoreAttributeView> V getFileStoreAttributeView(Class<V> view) 109 { 110 if (view == null) 111 throw new NullPointerException(); 112 if (view == FileStoreSpaceAttributeView.class) 113 return (V) new UnixFileStoreSpaceAttributeView(this); 114 return (V) null; 115 } 116 117 @Override 118 public Object getAttribute(String attribute) throws IOException { 119 if (attribute.equals("space:totalSpace")) 120 return new UnixFileStoreSpaceAttributeView(this) 121 .readAttributes().totalSpace(); 122 if (attribute.equals("space:usableSpace")) 123 return new UnixFileStoreSpaceAttributeView(this) 124 .readAttributes().usableSpace(); 125 if (attribute.equals("space:unallocatedSpace")) 126 return new UnixFileStoreSpaceAttributeView(this) 127 .readAttributes().unallocatedSpace(); 128 throw new UnsupportedOperationException("'" + attribute + "' not recognized"); 129 } 130 131 @Override 132 public boolean supportsFileAttributeView(Class<? extends FileAttributeView> type) { 133 if (type == null) 134 throw new NullPointerException(); 135 if (type == BasicFileAttributeView.class) 136 return true; 137 if (type == PosixFileAttributeView.class || 138 type == FileOwnerAttributeView.class) 139 { 140 // lookup fstypes.properties 141 FeatureStatus status = checkIfFeaturePresent("posix"); 142 // assume supported if UNKNOWN 143 return (status != FeatureStatus.NOT_PRESENT); 144 } 145 return false; 146 } 147 148 @Override 149 public boolean supportsFileAttributeView(String name) { 150 if (name.equals("basic") || name.equals("unix")) 151 return true; 152 if (name.equals("posix")) 153 return supportsFileAttributeView(PosixFileAttributeView.class); 154 if (name.equals("owner")) 155 return supportsFileAttributeView(FileOwnerAttributeView.class); 156 return false; 157 } 158 159 @Override 160 public boolean equals(Object ob) { 161 if (ob == this) 162 return true; 163 if (!(ob instanceof UnixFileStore)) 164 return false; 165 UnixFileStore other = (UnixFileStore)ob; 166 return (this.dev == other.dev) && 167 Arrays.equals(this.entry.dir(), other.entry.dir()); 168 } 169 170 @Override 171 public int hashCode() { 172 return (int)(dev ^ (dev >>> 32)) ^ Arrays.hashCode(entry.dir()); 173 } 174 175 @Override 176 public String toString() { 177 StringBuilder sb = new StringBuilder(new String(entry.dir())); 178 sb.append(" ("); 179 sb.append(entry.name()); 180 sb.append(")"); 181 return sb.toString(); 182 } 183 184 private static class UnixFileStoreSpaceAttributeView 185 implements FileStoreSpaceAttributeView 186 { 187 private final UnixFileStore fs; 188 189 UnixFileStoreSpaceAttributeView(UnixFileStore fs) { 190 this.fs = fs; 191 } 192 193 @Override 194 public String name() { 195 return "space"; 196 } 197 198 @Override 199 public FileStoreSpaceAttributes readAttributes() 200 throws IOException 201 { 202 UnixPath file = fs.file(); 203 final UnixFileStoreAttributes attrs; 204 try { 205 attrs = UnixFileStoreAttributes.get(file); 206 } catch (UnixException x) { 207 x.rethrowAsIOException(file); 208 return null; // keep compile happy 209 } 210 211 return new FileStoreSpaceAttributes() { 212 @Override 213 public long totalSpace() { 214 return attrs.blockSize() * attrs.totalBlocks(); 215 } 216 @Override 217 public long usableSpace() { 218 return attrs.blockSize() * attrs.availableBlocks(); 219 } 220 @Override 221 public long unallocatedSpace() { 222 return attrs.blockSize() * attrs.freeBlocks(); 223 } 224 }; 225 } 226 } 227 228 // -- fstypes.properties -- 229 230 private static final Object loadLock = new Object(); 231 private static volatile Properties props; 232 233 enum FeatureStatus { 234 PRESENT, 235 NOT_PRESENT, 236 UNKNOWN; 237 } 238 239 /** 240 * Returns status to indicate if file system supports a given feature 241 */ 242 FeatureStatus checkIfFeaturePresent(String feature) { 243 if (props == null) { 244 synchronized (loadLock) { 245 if (props == null) { 246 props = AccessController.doPrivileged( 247 new PrivilegedAction<Properties>() { 248 @Override 249 public Properties run() { 250 return loadProperties(); 251 }}); 252 } 253 } 254 } 255 256 String value = props.getProperty(type()); 257 if (value != null) { 258 String[] values = value.split("\\s"); 259 for (String s: values) { 260 s = s.trim().toLowerCase(); 261 if (s.equals(feature)) { 262 return FeatureStatus.PRESENT; 263 } 264 if (s.startsWith("no")) { 265 s = s.substring(2); 266 if (s.equals(feature)) { 267 return FeatureStatus.NOT_PRESENT; 268 } 269 } 270 } 271 } 272 return FeatureStatus.UNKNOWN; 273 } 274 275 private static Properties loadProperties() { 276 Properties result = new Properties(); 277 String fstypes = System.getProperty("java.home") + "/lib/fstypes.properties"; 278 Path file = Paths.get(fstypes); 279 try { 280 ReadableByteChannel rbc = file.newByteChannel(); 281 try { 282 result.load(Channels.newReader(rbc, "UTF-8")); 283 } finally { 284 rbc.close(); 285 } 286 } catch (IOException x) { 287 } 288 return result; 289 } 290 }