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
26package sun.nio.fs;
27
28import java.nio.file.*;
29import java.nio.file.attribute.*;
30import java.io.IOException;
31
32import static sun.nio.fs.WindowsConstants.*;
33import static sun.nio.fs.WindowsNativeDispatcher.*;
34
35/**
36 * Windows implementation of FileStore.
37 */
38
39class WindowsFileStore
40    extends FileStore
41{
42    private final String root;
43    private final VolumeInformation volInfo;
44    private final int volType;
45    private final String displayName;   // returned by toString
46
47    private WindowsFileStore(String root) throws WindowsException {
48        assert root.charAt(root.length()-1) == '\\';
49        this.root = root;
50        this.volInfo = GetVolumeInformation(root);
51        this.volType = GetDriveType(root);
52
53        // file store "display name" is the volume name if available
54        String vol = volInfo.volumeName();
55        if (vol.length() > 0) {
56            this.displayName = vol;
57        } else {
58            // TBD - should we map all types? Does this need to be localized?
59            this.displayName = (volType == DRIVE_REMOVABLE) ? "Removable Disk" : "";
60        }
61    }
62
63    static WindowsFileStore create(String root, boolean ignoreNotReady)
64        throws IOException
65    {
66        try {
67            return new WindowsFileStore(root);
68        } catch (WindowsException x) {
69            if (ignoreNotReady && x.lastError() == ERROR_NOT_READY)
70                return null;
71            x.rethrowAsIOException(root);
72            return null; // keep compiler happy
73        }
74    }
75
76    static WindowsFileStore create(WindowsPath file) throws IOException {
77        try {
78            // if the file is a link then GetVolumePathName returns the
79            // volume that the link is on so we need to call it with the
80            // final target
81            String target = WindowsLinkSupport.getFinalPath(file, true);
82            try {
83                return createFromPath(target);
84            } catch (WindowsException e) {
85                if (e.lastError() != ERROR_DIR_NOT_ROOT)
86                    throw e;
87                target = WindowsLinkSupport.getFinalPath(file);
88                if (target == null)
89                    throw new FileSystemException(file.getPathForExceptionMessage(),
90                            null, "Couldn't resolve path");
91                return createFromPath(target);
92            }
93        } catch (WindowsException x) {
94            x.rethrowAsIOException(file);
95            return null; // keep compiler happy
96        }
97    }
98
99    private static WindowsFileStore createFromPath(String target) throws WindowsException {
100        String root = GetVolumePathName(target);
101        return new WindowsFileStore(root);
102    }
103
104    VolumeInformation volumeInformation() {
105        return volInfo;
106    }
107
108    int volumeType() {
109        return volType;
110    }
111
112    @Override
113    public String name() {
114        return volInfo.volumeName();   // "SYSTEM", "DVD-RW", ...
115    }
116
117    @Override
118    public String type() {
119        return volInfo.fileSystemName();  // "FAT", "NTFS", ...
120    }
121
122    @Override
123    public boolean isReadOnly() {
124        return ((volInfo.flags() & FILE_READ_ONLY_VOLUME) != 0);
125    }
126
127    // read the free space info
128    private DiskFreeSpace readDiskFreeSpace() throws IOException {
129        try {
130            return GetDiskFreeSpaceEx(root);
131        } catch (WindowsException x) {
132            x.rethrowAsIOException(root);
133            return null;
134        }
135    }
136
137    @Override
138    public long getTotalSpace() throws IOException {
139        return readDiskFreeSpace().totalNumberOfBytes();
140    }
141
142    @Override
143    public long getUsableSpace() throws IOException {
144        return readDiskFreeSpace().freeBytesAvailable();
145    }
146
147    @Override
148    public long getUnallocatedSpace() throws IOException {
149        return readDiskFreeSpace().freeBytesAvailable();
150    }
151
152    @Override
153    public <V extends FileStoreAttributeView> V getFileStoreAttributeView(Class<V> type) {
154        if (type == null)
155            throw new NullPointerException();
156        return (V) null;
157    }
158
159    @Override
160    public Object getAttribute(String attribute) throws IOException {
161        // standard
162        if (attribute.equals("totalSpace"))
163            return getTotalSpace();
164        if (attribute.equals("usableSpace"))
165            return getUsableSpace();
166        if (attribute.equals("unallocatedSpace"))
167            return getUnallocatedSpace();
168        // windows specific for testing purposes
169        if (attribute.equals("volume:vsn"))
170            return volInfo.volumeSerialNumber();
171        if (attribute.equals("volume:isRemovable"))
172            return volType == DRIVE_REMOVABLE;
173        if (attribute.equals("volume:isCdrom"))
174            return volType == DRIVE_CDROM;
175        throw new UnsupportedOperationException("'" + attribute + "' not recognized");
176    }
177
178    @Override
179    public boolean supportsFileAttributeView(Class<? extends FileAttributeView> type) {
180        if (type == null)
181            throw new NullPointerException();
182        if (type == BasicFileAttributeView.class || type == DosFileAttributeView.class)
183            return true;
184        if (type == AclFileAttributeView.class || type == FileOwnerAttributeView.class)
185            return ((volInfo.flags() & FILE_PERSISTENT_ACLS) != 0);
186        if (type == UserDefinedFileAttributeView.class)
187            return ((volInfo.flags() & FILE_NAMED_STREAMS) != 0);
188        return false;
189    }
190
191    @Override
192    public boolean supportsFileAttributeView(String name) {
193        if (name.equals("basic") || name.equals("dos"))
194            return true;
195        if (name.equals("acl"))
196            return supportsFileAttributeView(AclFileAttributeView.class);
197        if (name.equals("owner"))
198            return supportsFileAttributeView(FileOwnerAttributeView.class);
199        if (name.equals("user"))
200            return supportsFileAttributeView(UserDefinedFileAttributeView.class);
201        return false;
202    }
203
204    @Override
205    public boolean equals(Object ob) {
206        if (ob == this)
207            return true;
208        if (!(ob instanceof WindowsFileStore))
209            return false;
210        WindowsFileStore other = (WindowsFileStore)ob;
211        return root.equals(other.root);
212    }
213
214    @Override
215    public int hashCode() {
216        return root.hashCode();
217    }
218
219    @Override
220    public String toString() {
221        StringBuilder sb = new StringBuilder(displayName);
222        if (sb.length() > 0)
223            sb.append(" ");
224        sb.append("(");
225        // drop trailing slash
226        sb.append(root.subSequence(0, root.length()-1));
227        sb.append(")");
228        return sb.toString();
229    }
230 }
231