1 /*
   2  * Copyright (c) 2008, 2011, 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     // uses statvfs to read the file system information
 107     private UnixFileStoreAttributes readAttributes() throws IOException {
 108         try {
 109             return UnixFileStoreAttributes.get(file);
 110         } catch (UnixException x) {
 111             x.rethrowAsIOException(file);
 112             return null;    // keep compile happy
 113         }
 114     }
 115 
 116     @Override
 117     public long getTotalSpace() throws IOException {
 118         UnixFileStoreAttributes attrs = readAttributes();
 119         return attrs.blockSize() * attrs.totalBlocks();
 120     }
 121 
 122     @Override
 123     public long getUsableSpace() throws IOException {
 124        UnixFileStoreAttributes attrs = readAttributes();
 125        return attrs.blockSize() * attrs.availableBlocks();
 126     }
 127 
 128     @Override
 129     public long getUnallocatedSpace() throws IOException {
 130         UnixFileStoreAttributes attrs = readAttributes();
 131         return attrs.blockSize() * attrs.freeBlocks();
 132     }
 133 
 134     @Override
 135     public <V extends FileStoreAttributeView> V getFileStoreAttributeView(Class<V> view)
 136     {
 137         if (view == null)
 138             throw new NullPointerException();
 139         return (V) null;
 140     }
 141 
 142     @Override
 143     public Object getAttribute(String attribute) throws IOException {
 144         if (attribute.equals("totalSpace"))
 145             return getTotalSpace();
 146         if (attribute.equals("usableSpace"))
 147             return getUsableSpace();
 148         if (attribute.equals("unallocatedSpace"))
 149             return getUnallocatedSpace();
 150         throw new UnsupportedOperationException("'" + attribute + "' not recognized");
 151     }
 152 
 153     @Override
 154     public boolean supportsFileAttributeView(Class<? extends FileAttributeView> type) {
 155         if (type == null)
 156             throw new NullPointerException();
 157         if (type == BasicFileAttributeView.class)
 158             return true;
 159         if (type == PosixFileAttributeView.class ||
 160             type == FileOwnerAttributeView.class)
 161         {
 162             // lookup fstypes.properties
 163             FeatureStatus status = checkIfFeaturePresent("posix");
 164             // assume supported if UNKNOWN
 165             return (status != FeatureStatus.NOT_PRESENT);
 166         }
 167         return false;
 168     }
 169 
 170     @Override
 171     public boolean supportsFileAttributeView(String name) {
 172         if (name.equals("basic") || name.equals("unix"))
 173             return true;
 174         if (name.equals("posix"))
 175             return supportsFileAttributeView(PosixFileAttributeView.class);
 176         if (name.equals("owner"))
 177             return supportsFileAttributeView(FileOwnerAttributeView.class);
 178         return false;
 179     }
 180 
 181     @Override
 182     public boolean equals(Object ob) {
 183         if (ob == this)
 184             return true;
 185         if (!(ob instanceof UnixFileStore))
 186             return false;
 187         UnixFileStore other = (UnixFileStore)ob;
 188         return (this.dev == other.dev) &&
 189                Arrays.equals(this.entry.dir(), other.entry.dir());
 190     }
 191 
 192     @Override
 193     public int hashCode() {
 194         return (int)(dev ^ (dev >>> 32)) ^ Arrays.hashCode(entry.dir());
 195     }
 196 
 197     @Override
 198     public String toString() {
 199         StringBuilder sb = new StringBuilder(new String(entry.dir()));
 200         sb.append(" (");
 201         sb.append(entry.name());
 202         sb.append(")");
 203         return sb.toString();
 204     }
 205 
 206     // -- fstypes.properties --
 207 
 208     private static final Object loadLock = new Object();
 209     private static volatile Properties props;
 210 
 211     enum FeatureStatus {
 212         PRESENT,
 213         NOT_PRESENT,
 214         UNKNOWN;
 215     }
 216 
 217     /**
 218      * Returns status to indicate if file system supports a given feature
 219      */
 220     FeatureStatus checkIfFeaturePresent(String feature) {
 221         if (props == null) {
 222             synchronized (loadLock) {
 223                 if (props == null) {
 224                     props = AccessController.doPrivileged(
 225                         new PrivilegedAction<Properties>() {
 226                             @Override
 227                             public Properties run() {
 228                                 return loadProperties();
 229                             }});
 230                 }
 231             }
 232         }
 233 
 234         String value = props.getProperty(type());
 235         if (value != null) {
 236             String[] values = value.split("\\s");
 237             for (String s: values) {
 238                 s = s.trim().toLowerCase();
 239                 if (s.equals(feature)) {
 240                     return FeatureStatus.PRESENT;
 241                 }
 242                 if (s.startsWith("no")) {
 243                     s = s.substring(2);
 244                     if (s.equals(feature)) {
 245                         return FeatureStatus.NOT_PRESENT;
 246                     }
 247                 }
 248             }
 249         }
 250         return FeatureStatus.UNKNOWN;
 251     }
 252 
 253     private static Properties loadProperties() {
 254         Properties result = new Properties();
 255         String fstypes = System.getProperty("java.home") + "/lib/fstypes.properties";
 256         Path file = Paths.get(fstypes);
 257         try {
 258             try (ReadableByteChannel rbc = Files.newByteChannel(file)) {
 259                 result.load(Channels.newReader(rbc, "UTF-8"));
 260             }
 261         } catch (IOException x) {
 262         }
 263         return result;
 264     }
 265 }