1
2
3
4
5 package oshi.software.os.windows;
6
7 import java.util.ArrayList;
8 import java.util.HashMap;
9 import java.util.List;
10 import java.util.Locale;
11 import java.util.Map;
12 import java.util.stream.Collectors;
13
14 import com.sun.jna.Native;
15 import com.sun.jna.platform.win32.Kernel32;
16 import com.sun.jna.platform.win32.WinBase;
17 import com.sun.jna.platform.win32.WinNT;
18 import com.sun.jna.platform.win32.COM.WbemcliUtil.WmiResult;
19
20 import oshi.annotation.concurrent.ThreadSafe;
21 import oshi.driver.windows.perfmon.ProcessInformation;
22 import oshi.driver.windows.perfmon.ProcessInformation.HandleCountProperty;
23 import oshi.driver.windows.wmi.Win32LogicalDisk;
24 import oshi.driver.windows.wmi.Win32LogicalDisk.LogicalDiskProperty;
25 import oshi.jna.ByRef.CloseableIntByReference;
26 import oshi.software.common.AbstractFileSystem;
27 import oshi.software.os.OSFileStore;
28 import oshi.util.ParseUtil;
29 import oshi.util.platform.windows.WmiUtil;
30
31
32
33
34
35
36 @ThreadSafe
37 public class WindowsFileSystem extends AbstractFileSystem {
38
39 private static final int BUFSIZE = 255;
40
41 private static final int SEM_FAILCRITICALERRORS = 0x0001;
42
43 private static final int FILE_CASE_SENSITIVE_SEARCH = 0x00000001;
44 private static final int FILE_CASE_PRESERVED_NAMES = 0x00000002;
45 private static final int FILE_FILE_COMPRESSION = 0x00000010;
46 private static final int FILE_DAX_VOLUME = 0x20000000;
47 private static final int FILE_NAMED_STREAMS = 0x00040000;
48 private static final int FILE_PERSISTENT_ACLS = 0x00000008;
49 private static final int FILE_READ_ONLY_VOLUME = 0x00080000;
50 private static final int FILE_SEQUENTIAL_WRITE_ONCE = 0x00100000;
51 private static final int FILE_SUPPORTS_ENCRYPTION = 0x00020000;
52 private static final int FILE_SUPPORTS_OBJECT_IDS = 0x00010000;
53 private static final int FILE_SUPPORTS_REPARSE_POINTS = 0x00000080;
54 private static final int FILE_SUPPORTS_SPARSE_FILES = 0x00000040;
55 private static final int FILE_SUPPORTS_TRANSACTIONS = 0x00200000;
56 private static final int FILE_SUPPORTS_USN_JOURNAL = 0x02000000;
57 private static final int FILE_UNICODE_ON_DISK = 0x00000004;
58 private static final int FILE_VOLUME_IS_COMPRESSED = 0x00008000;
59 private static final int FILE_VOLUME_QUOTAS = 0x00000020;
60
61 private static final Map<Integer, String> OPTIONS_MAP = new HashMap<>();
62 static {
63 OPTIONS_MAP.put(FILE_CASE_PRESERVED_NAMES, "casepn");
64 OPTIONS_MAP.put(FILE_CASE_SENSITIVE_SEARCH, "casess");
65 OPTIONS_MAP.put(FILE_FILE_COMPRESSION, "fcomp");
66 OPTIONS_MAP.put(FILE_DAX_VOLUME, "dax");
67 OPTIONS_MAP.put(FILE_NAMED_STREAMS, "streams");
68 OPTIONS_MAP.put(FILE_PERSISTENT_ACLS, "acls");
69 OPTIONS_MAP.put(FILE_SEQUENTIAL_WRITE_ONCE, "wronce");
70 OPTIONS_MAP.put(FILE_SUPPORTS_ENCRYPTION, "efs");
71 OPTIONS_MAP.put(FILE_SUPPORTS_OBJECT_IDS, "oids");
72 OPTIONS_MAP.put(FILE_SUPPORTS_REPARSE_POINTS, "reparse");
73 OPTIONS_MAP.put(FILE_SUPPORTS_SPARSE_FILES, "sparse");
74 OPTIONS_MAP.put(FILE_SUPPORTS_TRANSACTIONS, "trans");
75 OPTIONS_MAP.put(FILE_SUPPORTS_USN_JOURNAL, "journaled");
76 OPTIONS_MAP.put(FILE_UNICODE_ON_DISK, "unicode");
77 OPTIONS_MAP.put(FILE_VOLUME_IS_COMPRESSED, "vcomp");
78 OPTIONS_MAP.put(FILE_VOLUME_QUOTAS, "quota");
79 }
80
81 static final long MAX_WINDOWS_HANDLES;
82 static {
83
84
85
86 if (System.getenv("ProgramFiles(x86)") == null) {
87 MAX_WINDOWS_HANDLES = 16_777_216L - 32_768L;
88 } else {
89 MAX_WINDOWS_HANDLES = 16_777_216L - 65_536L;
90 }
91 }
92
93
94
95
96
97
98 public WindowsFileSystem() {
99
100 Kernel32.INSTANCE.SetErrorMode(SEM_FAILCRITICALERRORS);
101 }
102
103 @Override
104 public List<OSFileStore> getFileStores(boolean localOnly) {
105
106 ArrayList<OSFileStore> result;
107
108
109 result = getLocalVolumes(null);
110
111
112 Map<String, OSFileStore> volumeMap = new HashMap<>();
113 for (OSFileStore volume : result) {
114 volumeMap.put(volume.getMount(), volume);
115 }
116
117
118
119 for (OSFileStore wmiVolume : getWmiVolumes(null, localOnly)) {
120 if (volumeMap.containsKey(wmiVolume.getMount())) {
121
122
123 OSFileStore volume = volumeMap.get(wmiVolume.getMount());
124 result.remove(volume);
125 result.add(new WindowsOSFileStore(wmiVolume.getName(), volume.getVolume(),
126 volume.getLabel().isEmpty() ? wmiVolume.getLabel() : volume.getLabel(), volume.getMount(),
127 volume.getOptions(), volume.getUUID(), "", volume.getDescription(), volume.getType(),
128 volume.getFreeSpace(), volume.getUsableSpace(), volume.getTotalSpace(), 0, 0));
129 } else if (!localOnly) {
130
131 result.add(wmiVolume);
132 }
133 }
134 return result;
135 }
136
137
138
139
140
141
142
143 static ArrayList<OSFileStore> getLocalVolumes(String volumeToMatch) {
144 ArrayList<OSFileStore> fs;
145 String volume;
146 String strFsType;
147 String strName;
148 String strMount;
149 WinNT.HANDLE hVol;
150 WinNT.LARGE_INTEGER userFreeBytes;
151 WinNT.LARGE_INTEGER totalBytes;
152 WinNT.LARGE_INTEGER systemFreeBytes;
153 char[] aVolume;
154 char[] fstype;
155 char[] name;
156 char[] mount;
157
158 fs = new ArrayList<>();
159 aVolume = new char[BUFSIZE];
160
161 hVol = Kernel32.INSTANCE.FindFirstVolume(aVolume, BUFSIZE);
162 if (WinBase.INVALID_HANDLE_VALUE.equals(hVol)) {
163 return fs;
164 }
165 try (CloseableIntByReference pFlags = new CloseableIntByReference()) {
166 do {
167 fstype = new char[16];
168 name = new char[BUFSIZE];
169 mount = new char[BUFSIZE];
170
171 userFreeBytes = new WinNT.LARGE_INTEGER(0L);
172 totalBytes = new WinNT.LARGE_INTEGER(0L);
173 systemFreeBytes = new WinNT.LARGE_INTEGER(0L);
174
175 volume = Native.toString(aVolume);
176 Kernel32.INSTANCE.GetVolumeInformation(volume, name, BUFSIZE, null, null, pFlags, fstype, 16);
177 final int flags = pFlags.getValue();
178 Kernel32.INSTANCE.GetVolumePathNamesForVolumeName(volume, mount, BUFSIZE, null);
179
180 strMount = Native.toString(mount);
181 if (!strMount.isEmpty() && (volumeToMatch == null || volumeToMatch.equals(volume))) {
182 strName = Native.toString(name);
183 strFsType = Native.toString(fstype);
184
185 StringBuilder options = new StringBuilder((FILE_READ_ONLY_VOLUME & flags) == 0 ? "rw" : "ro");
186 String moreOptions = OPTIONS_MAP.entrySet().stream().filter(e -> (e.getKey() & flags) > 0)
187 .map(Map.Entry::getValue).collect(Collectors.joining(","));
188 if (!moreOptions.isEmpty()) {
189 options.append(',').append(moreOptions);
190 }
191 Kernel32.INSTANCE.GetDiskFreeSpaceEx(volume, userFreeBytes, totalBytes, systemFreeBytes);
192
193 String uuid = ParseUtil.parseUuidOrDefault(volume, "");
194
195 fs.add(new WindowsOSFileStore(String.format(Locale.ROOT, "%s (%s)", strName, strMount), volume,
196 strName, strMount, options.toString(), uuid, "", getDriveType(strMount), strFsType,
197 systemFreeBytes.getValue(), userFreeBytes.getValue(), totalBytes.getValue(), 0, 0));
198 }
199 } while (Kernel32.INSTANCE.FindNextVolume(hVol, aVolume, BUFSIZE));
200 return fs;
201 } finally {
202 Kernel32.INSTANCE.FindVolumeClose(hVol);
203 }
204 }
205
206
207
208
209
210
211
212
213 static List<OSFileStore> getWmiVolumes(String nameToMatch, boolean localOnly) {
214 long free;
215 long total;
216 List<OSFileStore> fs = new ArrayList<>();
217 WmiResult<LogicalDiskProperty> drives = Win32LogicalDisk.queryLogicalDisk(nameToMatch, localOnly);
218 for (int i = 0; i < drives.getResultCount(); i++) {
219 free = WmiUtil.getUint64(drives, LogicalDiskProperty.FREESPACE, i);
220 total = WmiUtil.getUint64(drives, LogicalDiskProperty.SIZE, i);
221 String description = WmiUtil.getString(drives, LogicalDiskProperty.DESCRIPTION, i);
222 String name = WmiUtil.getString(drives, LogicalDiskProperty.NAME, i);
223 String label = WmiUtil.getString(drives, LogicalDiskProperty.VOLUMENAME, i);
224 String options = WmiUtil.getUint16(drives, LogicalDiskProperty.ACCESS, i) == 1 ? "ro" : "rw";
225 int type = WmiUtil.getUint32(drives, LogicalDiskProperty.DRIVETYPE, i);
226 String volume;
227 if (type != 4) {
228 char[] chrVolume = new char[BUFSIZE];
229 Kernel32.INSTANCE.GetVolumeNameForVolumeMountPoint(name + "\\", chrVolume, BUFSIZE);
230 volume = Native.toString(chrVolume);
231 } else {
232 volume = WmiUtil.getString(drives, LogicalDiskProperty.PROVIDERNAME, i);
233 String[] split = volume.split("\\\\");
234 if (split.length > 1 && split[split.length - 1].length() > 0) {
235 description = split[split.length - 1];
236 }
237 }
238 fs.add(new WindowsOSFileStore(String.format(Locale.ROOT, "%s (%s)", description, name), volume, label,
239 name + "\\", options, "", "", getDriveType(name),
240 WmiUtil.getString(drives, LogicalDiskProperty.FILESYSTEM, i), free, free, total, 0, 0));
241 }
242 return fs;
243 }
244
245
246
247
248
249
250
251 private static String getDriveType(String drive) {
252 switch (Kernel32.INSTANCE.GetDriveType(drive)) {
253 case 2:
254 return "Removable drive";
255 case 3:
256 return "Fixed drive";
257 case 4:
258 return "Network drive";
259 case 5:
260 return "CD-ROM";
261 case 6:
262 return "RAM drive";
263 default:
264 return "Unknown drive type";
265 }
266 }
267
268 @Override
269 public long getOpenFileDescriptors() {
270 Map<HandleCountProperty, List<Long>> valueListMap = ProcessInformation.queryHandles().getB();
271 List<Long> valueList = valueListMap.get(HandleCountProperty.HANDLECOUNT);
272 long descriptors = 0L;
273 if (valueList != null) {
274 for (Long value : valueList) {
275 descriptors += value;
276 }
277 }
278 return descriptors;
279 }
280
281 @Override
282 public long getMaxFileDescriptors() {
283 return MAX_WINDOWS_HANDLES;
284 }
285
286 @Override
287 public long getMaxFileDescriptorsPerProcess() {
288 return MAX_WINDOWS_HANDLES;
289 }
290 }