Skip to content

Commit b24ae10

Browse files
authored
Get FileStore options (oshi#1100)
1 parent 0d2b9e8 commit b24ae10

File tree

8 files changed

+169
-26
lines changed

8 files changed

+169
-26
lines changed

CHANGELOG.md

+1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
4.4.0 (in progress)
22
================
33
* [#1098](https://github.com/oshi/oshi/pull/1098): Option to limit FileStore list to local file systems. - [@Space2Man](https://github.com/Space2Man).
4+
* [#1100](https://github.com/oshi/oshi/pull/1100): Get FileStore options. - [@dbwiddis](https://github.com/dbwiddis).
45
* Your contribution here.
56

67
4.3.0 (1/2/2020), 4.3.1 (2/5/2020)

oshi-core/src/main/java/oshi/software/os/OSFileStore.java

+25-4
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@ public class OSFileStore {
4848
private String mount;
4949
private String description;
5050
private String fsType;
51+
private String options;
5152
private String uuid;
5253
private long freeSpace;
5354
private long usableSpace;
@@ -76,6 +77,7 @@ public OSFileStore(OSFileStore fileStore) {
7677
setMount(fileStore.getMount());
7778
setDescription(fileStore.getDescription());
7879
setType(fileStore.getType());
80+
setType(fileStore.getOptions());
7981
setUUID(fileStore.getUUID());
8082
setFreeSpace(fileStore.getFreeSpace());
8183
setUsableSpace(fileStore.getUsableSpace());
@@ -202,6 +204,25 @@ public void setType(String value) {
202204
this.fsType = value;
203205
}
204206

207+
/**
208+
* Filesystem options
209+
*
210+
* @return A comma-deimited string of options
211+
*/
212+
public String getOptions() {
213+
return options;
214+
}
215+
216+
/**
217+
* Sets the File System options
218+
*
219+
* @param value
220+
* The options
221+
*/
222+
public void setOptions(String value) {
223+
this.options = value;
224+
}
225+
205226
/**
206227
* UUID/GUID of the File System
207228
*
@@ -345,12 +366,12 @@ public boolean updateAtrributes() {
345366
}
346367
return false;
347368
}
348-
369+
349370
@Override
350371
public String toString() {
351372
return "OSFileStore [name=" + name + ", volume=" + volume + ", logicalVolume=" + logicalVolume + ", mount="
352-
+ mount + ", description=" + description + ", fsType=" + fsType + ", uuid=" + uuid + ", freeSpace="
353-
+ freeSpace + ", usableSpace=" + usableSpace + ", totalSpace=" + totalSpace + ", freeInodes="
354-
+ freeInodes + ", totalInodes=" + totalInodes + "]";
373+
+ mount + ", description=" + description + ", fsType=" + fsType + ", options=\"" + options + "\", uuid="
374+
+ uuid + ", freeSpace=" + freeSpace + ", usableSpace=" + usableSpace + ", totalSpace=" + totalSpace
375+
+ ", freeInodes=" + freeInodes + ", totalInodes=" + totalInodes + "]";
355376
}
356377
}

oshi-core/src/main/java/oshi/software/os/linux/LinuxFileSystem.java

+6-3
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@
4444
import oshi.software.os.OSFileStore;
4545
import oshi.util.FileUtil;
4646
import oshi.util.ParseUtil;
47+
import oshi.util.platform.linux.ProcUtil;
4748

4849
/**
4950
* The Linux File System contains {@link oshi.software.os.OSFileStore}s which
@@ -118,15 +119,15 @@ private static List<OSFileStore> getFileStoreMatching(String nameToMatch, Map<St
118119
boolean localOnly) {
119120
List<OSFileStore> fsList = new ArrayList<>();
120121

121-
// Parse /proc/self/mounts to get fs types
122-
List<String> mounts = FileUtil.readFile("/proc/self/mounts");
122+
// Parse /proc/mounts to get fs types
123+
List<String> mounts = FileUtil.readFile(ProcUtil.getProcPath() + "/mounts");
123124
for (String mount : mounts) {
124125
String[] split = mount.split(" ");
125126
// As reported in fstab(5) manpage, struct is:
126127
// 1st field is volume name
127128
// 2nd field is path with spaces escaped as \040
128129
// 3rd field is fs type
129-
// 4th field is mount options (ignored)
130+
// 4th field is mount options
130131
// 5th field is used by dump(8) (ignored)
131132
// 6th field is fsck order (ignored)
132133
if (split.length < 6) {
@@ -144,6 +145,7 @@ private static List<OSFileStore> getFileStoreMatching(String nameToMatch, Map<St
144145
) {
145146
continue;
146147
}
148+
String options = split[3];
147149

148150
String name = split[0].replaceAll("\\\\040", " ");
149151
if (path.equals("/")) {
@@ -218,6 +220,7 @@ private static List<OSFileStore> getFileStoreMatching(String nameToMatch, Map<St
218220
osStore.setMount(path);
219221
osStore.setDescription(description);
220222
osStore.setType(type);
223+
osStore.setOptions(options);
221224
osStore.setUUID(uuid);
222225
osStore.setFreeSpace(freeSpace);
223226
osStore.setUsableSpace(usableSpace);

oshi-core/src/main/java/oshi/software/os/mac/MacFileSystem.java

+62-6
Original file line numberDiff line numberDiff line change
@@ -26,8 +26,11 @@
2626
import java.io.File;
2727
import java.nio.charset.StandardCharsets;
2828
import java.util.ArrayList;
29+
import java.util.HashMap;
2930
import java.util.List;
31+
import java.util.Map;
3032
import java.util.regex.Pattern;
33+
import java.util.stream.Collectors;
3134

3235
import org.slf4j.Logger;
3336
import org.slf4j.LoggerFactory;
@@ -64,7 +67,54 @@ public class MacFileSystem extends AbstractFileSystem {
6467
// Regexp matcher for /dev/disk1 etc.
6568
private static final Pattern LOCAL_DISK = Pattern.compile("/dev/disk\\d");
6669

70+
// User specifiable flags.
71+
private static final int MNT_RDONLY = 0x00000001;
72+
private static final int MNT_SYNCHRONOUS = 0x00000002;
73+
private static final int MNT_NOEXEC = 0x00000004;
74+
private static final int MNT_NOSUID = 0x00000008;
75+
private static final int MNT_NODEV = 0x00000010;
76+
private static final int MNT_UNION = 0x00000020;
77+
private static final int MNT_ASYNC = 0x00000040;
78+
private static final int MNT_CPROTECT = 0x00000080;
79+
private static final int MNT_EXPORTED = 0x00000100;
80+
private static final int MNT_QUARANTINE = 0x00000400;
6781
private static final int MNT_LOCAL = 0x00001000;
82+
private static final int MNT_QUOTA = 0x00002000;
83+
private static final int MNT_ROOTFS = 0x00004000;
84+
private static final int MNT_DOVOLFS = 0x00008000;
85+
private static final int MNT_DONTBROWSE = 0x00100000;
86+
private static final int MNT_IGNORE_OWNERSHIP = 0x00200000;
87+
private static final int MNT_AUTOMOUNTED = 0x00400000;
88+
private static final int MNT_JOURNALED = 0x00800000;
89+
private static final int MNT_NOUSERXATTR = 0x01000000;
90+
private static final int MNT_DEFWRITE = 0x02000000;
91+
private static final int MNT_MULTILABEL = 0x04000000;
92+
private static final int MNT_NOATIME = 0x10000000;
93+
94+
private static final Map<Integer, String> OPTIONS_MAP = new HashMap<>();
95+
static {
96+
OPTIONS_MAP.put(MNT_SYNCHRONOUS, "synchronous");
97+
OPTIONS_MAP.put(MNT_NOEXEC, "noexec");
98+
OPTIONS_MAP.put(MNT_NOSUID, "nosuid");
99+
OPTIONS_MAP.put(MNT_NODEV, "nodev");
100+
OPTIONS_MAP.put(MNT_UNION, "union");
101+
OPTIONS_MAP.put(MNT_ASYNC, "asynchronous");
102+
OPTIONS_MAP.put(MNT_CPROTECT, "content-protection");
103+
OPTIONS_MAP.put(MNT_EXPORTED, "exported");
104+
OPTIONS_MAP.put(MNT_QUARANTINE, "quarantined");
105+
OPTIONS_MAP.put(MNT_LOCAL, "local");
106+
OPTIONS_MAP.put(MNT_QUOTA, "quotas");
107+
OPTIONS_MAP.put(MNT_ROOTFS, "rootfs");
108+
OPTIONS_MAP.put(MNT_DOVOLFS, "volfs");
109+
OPTIONS_MAP.put(MNT_DONTBROWSE, "nobrowse");
110+
OPTIONS_MAP.put(MNT_IGNORE_OWNERSHIP, "noowners");
111+
OPTIONS_MAP.put(MNT_AUTOMOUNTED, "automounted");
112+
OPTIONS_MAP.put(MNT_JOURNALED, "journaled");
113+
OPTIONS_MAP.put(MNT_NOUSERXATTR, "nouserxattr");
114+
OPTIONS_MAP.put(MNT_DEFWRITE, "defwrite");
115+
OPTIONS_MAP.put(MNT_MULTILABEL, "multilabel");
116+
OPTIONS_MAP.put(MNT_NOATIME, "noatime");
117+
}
68118

69119
@Override
70120
public OSFileStore[] getFileStores(boolean localOnly) {
@@ -104,12 +154,10 @@ private static List<OSFileStore> getFileStoreMatching(String nameToMatch, boolea
104154

105155
// Get volume name
106156
String volume = new String(fs[f].f_mntfromname, StandardCharsets.UTF_8).trim();
107-
// Skip system types
108-
if (volume.equals("devfs") || volume.startsWith("map ")) {
109-
continue;
110-
}
111-
// Skip non-local drives if requested
112-
if (localOnly && (fs[f].f_flags & MNT_LOCAL) == 0) {
157+
// Skip non-local drives if requested, skip system types
158+
final int flags = fs[f].f_flags;
159+
if ((localOnly && (flags & MNT_LOCAL) == 0) || volume.equals("devfs")
160+
|| volume.startsWith("map ")) {
113161
continue;
114162
}
115163

@@ -135,6 +183,13 @@ private static List<OSFileStore> getFileStoreMatching(String nameToMatch, boolea
135183
continue;
136184
}
137185

186+
StringBuilder options = new StringBuilder((MNT_RDONLY & flags) == 0 ? "rw" : "ro");
187+
String moreOptions = OPTIONS_MAP.entrySet().stream().filter(e -> (e.getKey() & flags) > 0)
188+
.map(Map.Entry::getValue).collect(Collectors.joining(","));
189+
if (!moreOptions.isEmpty()) {
190+
options.append(',').append(moreOptions);
191+
}
192+
138193
String uuid = "";
139194
// Use volume to find DiskArbitration volume name and search for
140195
// the registry entry for UUID
@@ -187,6 +242,7 @@ private static List<OSFileStore> getFileStoreMatching(String nameToMatch, boolea
187242
osStore.setMount(path);
188243
osStore.setDescription(description);
189244
osStore.setType(type);
245+
osStore.setOptions(options.toString());
190246
osStore.setUUID(uuid == null ? "" : uuid);
191247
osStore.setFreeSpace(file.getFreeSpace());
192248
osStore.setUsableSpace(file.getUsableSpace());

oshi-core/src/main/java/oshi/software/os/unix/freebsd/FreeBsdFileSystem.java

+5-1
Original file line numberDiff line numberDiff line change
@@ -114,13 +114,16 @@ public OSFileStore[] getFileStores(boolean localOnly) {
114114
// 1st field is volume name
115115
// 2nd field is mount point
116116
// 3rd field is fs type
117+
// 4th field is options
117118
// other fields ignored
118119
String volume = split[0];
119120
String path = split[1];
120121
String type = split[2];
122+
String options = split[3];
121123

122124
// Skip non-local drives if requested, and exclude pseudo file systems
123-
if ((localOnly && NETWORK_FS_TYPES.contains(type)) || PSEUDO_FS.contains(type) || path.equals("/dev") || ParseUtil.filePathStartsWith(TMP_FS_PATHS, path)
125+
if ((localOnly && NETWORK_FS_TYPES.contains(type)) || PSEUDO_FS.contains(type) || path.equals("/dev")
126+
|| ParseUtil.filePathStartsWith(TMP_FS_PATHS, path)
124127
|| volume.startsWith("rpool") && !path.equals("/")) {
125128
continue;
126129
}
@@ -155,6 +158,7 @@ public OSFileStore[] getFileStores(boolean localOnly) {
155158
osStore.setMount(path);
156159
osStore.setDescription(description);
157160
osStore.setType(type);
161+
osStore.setOptions(options);
158162
osStore.setUUID(uuid);
159163
osStore.setFreeSpace(freeSpace);
160164
osStore.setUsableSpace(usableSpace);

oshi-core/src/main/java/oshi/software/os/unix/solaris/SolarisFileSystem.java

+3
Original file line numberDiff line numberDiff line change
@@ -117,10 +117,12 @@ private static List<OSFileStore> getFileStoreMatching(String nameToMatch, boolea
117117
// 1st field is volume name
118118
// 2nd field is mount point
119119
// 3rd field is fs type
120+
// 4th field is options
120121
// other fields ignored
121122
String volume = split[0];
122123
String path = split[1];
123124
String type = split[2];
125+
String options = split[3];
124126

125127
// Skip non-local drives if requested, and exclude pseudo file systems
126128
if ((localOnly && NETWORK_FS_TYPES.contains(type)) || PSEUDO_FS.contains(type) || path.equals("/dev")
@@ -161,6 +163,7 @@ private static List<OSFileStore> getFileStoreMatching(String nameToMatch, boolea
161163
osStore.setMount(path);
162164
osStore.setDescription(description);
163165
osStore.setType(type);
166+
osStore.setOptions(options);
164167
osStore.setUUID(""); // No UUID info on Solaris
165168
osStore.setFreeSpace(freeSpace);
166169
osStore.setUsableSpace(usableSpace);

oshi-core/src/main/java/oshi/software/os/windows/WindowsFileSystem.java

+64-11
Original file line numberDiff line numberDiff line change
@@ -27,12 +27,14 @@
2727
import java.util.HashMap;
2828
import java.util.List;
2929
import java.util.Map;
30+
import java.util.stream.Collectors;
3031

3132
import com.sun.jna.platform.win32.Kernel32; //NOSONAR
3233
import com.sun.jna.platform.win32.WinBase;
3334
import com.sun.jna.platform.win32.WinNT;
3435
import com.sun.jna.platform.win32.COM.WbemcliUtil.WmiQuery;
3536
import com.sun.jna.platform.win32.COM.WbemcliUtil.WmiResult;
37+
import com.sun.jna.ptr.IntByReference;
3638

3739
import oshi.software.common.AbstractFileSystem;
3840
import oshi.software.os.OSFileStore;
@@ -55,6 +57,44 @@ public class WindowsFileSystem extends AbstractFileSystem {
5557

5658
private static final int SEM_FAILCRITICALERRORS = 0x0001;
5759

60+
private static final int FILE_CASE_SENSITIVE_SEARCH = 0x00000001;
61+
private static final int FILE_CASE_PRESERVED_NAMES = 0x00000002;
62+
private static final int FILE_FILE_COMPRESSION = 0x00000010;
63+
private static final int FILE_DAX_VOLUME = 0x20000000;
64+
private static final int FILE_NAMED_STREAMS = 0x00040000;
65+
private static final int FILE_PERSISTENT_ACLS = 0x00000008;
66+
private static final int FILE_READ_ONLY_VOLUME = 0x00080000;
67+
private static final int FILE_SEQUENTIAL_WRITE_ONCE = 0x00100000;
68+
private static final int FILE_SUPPORTS_ENCRYPTION = 0x00020000;
69+
private static final int FILE_SUPPORTS_OBJECT_IDS = 0x00010000;
70+
private static final int FILE_SUPPORTS_REPARSE_POINTS = 0x00000080;
71+
private static final int FILE_SUPPORTS_SPARSE_FILES = 0x00000040;
72+
private static final int FILE_SUPPORTS_TRANSACTIONS = 0x00200000;
73+
private static final int FILE_SUPPORTS_USN_JOURNAL = 0x02000000;
74+
private static final int FILE_UNICODE_ON_DISK = 0x00000004;
75+
private static final int FILE_VOLUME_IS_COMPRESSED = 0x00008000;
76+
private static final int FILE_VOLUME_QUOTAS = 0x00000020;
77+
78+
private static final Map<Integer, String> OPTIONS_MAP = new HashMap<>();
79+
static {
80+
OPTIONS_MAP.put(FILE_CASE_PRESERVED_NAMES, "casepn");
81+
OPTIONS_MAP.put(FILE_CASE_SENSITIVE_SEARCH, "casess");
82+
OPTIONS_MAP.put(FILE_FILE_COMPRESSION, "fcomp");
83+
OPTIONS_MAP.put(FILE_DAX_VOLUME, "dax");
84+
OPTIONS_MAP.put(FILE_NAMED_STREAMS, "streams");
85+
OPTIONS_MAP.put(FILE_PERSISTENT_ACLS, "acls");
86+
OPTIONS_MAP.put(FILE_SEQUENTIAL_WRITE_ONCE, "wronce");
87+
OPTIONS_MAP.put(FILE_SUPPORTS_ENCRYPTION, "efs");
88+
OPTIONS_MAP.put(FILE_SUPPORTS_OBJECT_IDS, "oids");
89+
OPTIONS_MAP.put(FILE_SUPPORTS_REPARSE_POINTS, "reparse");
90+
OPTIONS_MAP.put(FILE_SUPPORTS_SPARSE_FILES, "sparse");
91+
OPTIONS_MAP.put(FILE_SUPPORTS_TRANSACTIONS, "trans");
92+
OPTIONS_MAP.put(FILE_SUPPORTS_USN_JOURNAL, "journaled");
93+
OPTIONS_MAP.put(FILE_UNICODE_ON_DISK, "unicode");
94+
OPTIONS_MAP.put(FILE_VOLUME_IS_COMPRESSED, "vcomp");
95+
OPTIONS_MAP.put(FILE_VOLUME_QUOTAS, "quota");
96+
}
97+
5898
enum LogicalDiskProperty {
5999
DESCRIPTION, DRIVETYPE, FILESYSTEM, FREESPACE, NAME, PROVIDERNAME, SIZE;
60100
}
@@ -157,6 +197,7 @@ private static ArrayList<OSFileStore> getLocalVolumes(String nameToMatch) {
157197
char[] fstype;
158198
char[] name;
159199
char[] mount;
200+
IntByReference pFlags;
160201

161202
fs = new ArrayList<>();
162203
aVolume = new char[BUFSIZE];
@@ -170,36 +211,47 @@ private static ArrayList<OSFileStore> getLocalVolumes(String nameToMatch) {
170211
fstype = new char[16];
171212
name = new char[BUFSIZE];
172213
mount = new char[BUFSIZE];
214+
pFlags = new IntByReference();
173215

174216
userFreeBytes = new WinNT.LARGE_INTEGER(0L);
175217
totalBytes = new WinNT.LARGE_INTEGER(0L);
176218
systemFreeBytes = new WinNT.LARGE_INTEGER(0L);
177219

178220
volume = new String(aVolume).trim();
179-
Kernel32.INSTANCE.GetVolumeInformation(volume, name, BUFSIZE, null, null, null, fstype, 16);
221+
Kernel32.INSTANCE.GetVolumeInformation(volume, name, BUFSIZE, null, null, pFlags, fstype, 16);
222+
final int flags = pFlags.getValue();
180223
Kernel32.INSTANCE.GetVolumePathNamesForVolumeName(volume, mount, BUFSIZE, null);
181224

182225
strMount = new String(mount).trim();
183-
strName = new String(name).trim();
184-
strFsType = new String(fstype).trim();
185-
String osName = String.format("%s (%s)", strName, strMount);
186-
if (nameToMatch == null || nameToMatch.equals(osName)) {
187-
Kernel32.INSTANCE.GetDiskFreeSpaceEx(volume, userFreeBytes, totalBytes, systemFreeBytes);
188-
// Parse uuid from volume name
189-
String uuid = ParseUtil.parseUuidOrDefault(volume, "");
190-
191-
if (!strMount.isEmpty()) {
226+
if (!strMount.isEmpty()) {
227+
strName = new String(name).trim();
228+
strFsType = new String(fstype).trim();
229+
230+
StringBuilder options = new StringBuilder((FILE_READ_ONLY_VOLUME & flags) == 0 ? "rw" : "ro");
231+
String moreOptions = OPTIONS_MAP.entrySet().stream().filter(e -> (e.getKey() & flags) > 0)
232+
.map(Map.Entry::getValue).collect(Collectors.joining(","));
233+
if (!moreOptions.isEmpty()) {
234+
options.append(',').append(moreOptions);
235+
}
236+
String osName = String.format("%s (%s)", strName, strMount);
237+
if (nameToMatch == null || nameToMatch.equals(osName)) {
238+
Kernel32.INSTANCE.GetDiskFreeSpaceEx(volume, userFreeBytes, totalBytes, systemFreeBytes);
239+
// Parse uuid from volume name
240+
String uuid = ParseUtil.parseUuidOrDefault(volume, "");
241+
192242
// Volume is mounted
193243
OSFileStore osStore = new OSFileStore();
194244
osStore.setName(osName);
195245
osStore.setVolume(volume);
196246
osStore.setMount(strMount);
197247
osStore.setDescription(getDriveType(strMount));
198248
osStore.setType(strFsType);
249+
osStore.setOptions(options.toString());
199250
osStore.setUUID(uuid);
200251
osStore.setFreeSpace(systemFreeBytes.getValue());
201252
osStore.setUsableSpace(userFreeBytes.getValue());
202253
osStore.setTotalSpace(totalBytes.getValue());
254+
System.out.println(osStore.toString());
203255
fs.add(osStore);
204256
}
205257
}
@@ -238,7 +290,8 @@ private static List<OSFileStore> getWmiVolumes(String nameToMatch, boolean local
238290
wmiClassName.append(where ? " WHERE" : " AND").append(" Name=\"").append(nameToMatch).append('\"');
239291
}
240292
WmiQueryHandler wmiQueryHandler = WmiQueryHandler.createInstance();
241-
WmiQuery<LogicalDiskProperty> logicalDiskQuery = new WmiQuery<>(wmiClassName.toString(), LogicalDiskProperty.class);
293+
WmiQuery<LogicalDiskProperty> logicalDiskQuery = new WmiQuery<>(wmiClassName.toString(),
294+
LogicalDiskProperty.class);
242295
WmiResult<LogicalDiskProperty> drives = wmiQueryHandler.queryWMI(logicalDiskQuery);
243296

244297
for (int i = 0; i < drives.getResultCount(); i++) {

0 commit comments

Comments
 (0)