1/*
2 * Copyright (c) 2008, 2013, 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
26package sun.nio.fs;
27
28import java.nio.file.*;
29import java.nio.file.attribute.*;
30import java.nio.channels.*;
31import java.util.*;
32import java.io.IOException;
33import java.security.AccessController;
34import java.security.PrivilegedAction;
35
36/**
37 * Base implementation of FileStore for Unix/like implementations.
38 */
39
40abstract 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(Util.toString(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}
266