1 /*
2  * Copyright (c) 2008, 2015, 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
devFor(UnixPath file)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 
UnixFileStore(UnixPath file)62     UnixFileStore(UnixPath file) throws IOException {
63         this.file = file;
64         this.dev = devFor(file);
65         this.entry = findMountEntry();
66     }
67 
UnixFileStore(UnixFileSystem fs, UnixMountEntry entry)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      */
findMountEntry()77     abstract UnixMountEntry findMountEntry() throws IOException;
78 
file()79     UnixPath file() {
80         return file;
81     }
82 
dev()83     long dev() {
84         return dev;
85     }
86 
entry()87     UnixMountEntry entry() {
88         return entry;
89     }
90 
91     @Override
name()92     public String name() {
93         return entry.name();
94     }
95 
96     @Override
type()97     public String type() {
98         return entry.fstype();
99     }
100 
101     @Override
isReadOnly()102     public boolean isReadOnly() {
103         return entry.isReadOnly();
104     }
105 
106     // uses statvfs to read the file system information
readAttributes()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
getTotalSpace()117     public long getTotalSpace() throws IOException {
118         UnixFileStoreAttributes attrs = readAttributes();
119         return attrs.blockSize() * attrs.totalBlocks();
120     }
121 
122     @Override
getUsableSpace()123     public long getUsableSpace() throws IOException {
124        UnixFileStoreAttributes attrs = readAttributes();
125        return attrs.blockSize() * attrs.availableBlocks();
126     }
127 
128     @Override
getUnallocatedSpace()129     public long getUnallocatedSpace() throws IOException {
130         UnixFileStoreAttributes attrs = readAttributes();
131         return attrs.blockSize() * attrs.freeBlocks();
132     }
133 
134     @Override
getFileStoreAttributeView(Class<V> view)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
getAttribute(String attribute)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
supportsFileAttributeView(Class<? extends FileAttributeView> type)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
supportsFileAttributeView(String name)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
equals(Object ob)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                this.entry.name().equals(other.entry.name());
191     }
192 
193     @Override
hashCode()194     public int hashCode() {
195         return (int)(dev ^ (dev >>> 32)) ^ Arrays.hashCode(entry.dir());
196     }
197 
198     @Override
toString()199     public String toString() {
200         StringBuilder sb = new StringBuilder(Util.toString(entry.dir()));
201         sb.append(" (");
202         sb.append(entry.name());
203         sb.append(")");
204         return sb.toString();
205     }
206 
207     // -- fstypes.properties --
208 
209     private static final Object loadLock = new Object();
210     private static volatile Properties props;
211 
212     enum FeatureStatus {
213         PRESENT,
214         NOT_PRESENT,
215         UNKNOWN;
216     }
217 
218     /**
219      * Returns status to indicate if file system supports a given feature
220      */
checkIfFeaturePresent(String feature)221     FeatureStatus checkIfFeaturePresent(String feature) {
222         if (props == null) {
223             synchronized (loadLock) {
224                 if (props == null) {
225                     props = AccessController.doPrivileged(
226                         new PrivilegedAction<Properties>() {
227                             @Override
228                             public Properties run() {
229                                 return loadProperties();
230                             }});
231                 }
232             }
233         }
234 
235         String value = props.getProperty(type());
236         if (value != null) {
237             String[] values = value.split("\\s");
238             for (String s: values) {
239                 s = s.trim().toLowerCase();
240                 if (s.equals(feature)) {
241                     return FeatureStatus.PRESENT;
242                 }
243                 if (s.startsWith("no")) {
244                     s = s.substring(2);
245                     if (s.equals(feature)) {
246                         return FeatureStatus.NOT_PRESENT;
247                     }
248                 }
249             }
250         }
251         return FeatureStatus.UNKNOWN;
252     }
253 
loadProperties()254     private static Properties loadProperties() {
255         Properties result = new Properties();
256         String fstypes = System.getProperty("java.home") + "/lib/fstypes.properties";
257         Path file = Paths.get(fstypes);
258         try {
259             try (ReadableByteChannel rbc = Files.newByteChannel(file)) {
260                 result.load(Channels.newReader(rbc, "UTF-8"));
261             }
262         } catch (IOException x) {
263         }
264         return result;
265     }
266 }
267