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