All Downloads are FREE. Search and download functionalities are using the official Maven repository.

oshi.software.os.windows.WindowsFileSystem Maven / Gradle / Ivy

There is a newer version: 6.6.5
Show newest version
/*
 * Copyright 2016-2023 The OSHI Project Contributors
 * SPDX-License-Identifier: MIT
 */
package oshi.software.os.windows;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.stream.Collectors;

import com.sun.jna.Native;
import com.sun.jna.platform.win32.Kernel32;
import com.sun.jna.platform.win32.WinBase;
import com.sun.jna.platform.win32.WinNT;
import com.sun.jna.platform.win32.COM.WbemcliUtil.WmiResult;

import oshi.annotation.concurrent.ThreadSafe;
import oshi.driver.windows.perfmon.ProcessInformation;
import oshi.driver.windows.perfmon.ProcessInformation.HandleCountProperty;
import oshi.driver.windows.wmi.Win32LogicalDisk;
import oshi.driver.windows.wmi.Win32LogicalDisk.LogicalDiskProperty;
import oshi.jna.ByRef.CloseableIntByReference;
import oshi.software.common.AbstractFileSystem;
import oshi.software.os.OSFileStore;
import oshi.util.ParseUtil;
import oshi.util.platform.windows.WmiUtil;

/**
 * The Windows File System contains {@link oshi.software.os.OSFileStore}s which are a storage pool, device, partition,
 * volume, concrete file system or other implementation specific means of file storage. In Windows, these are
 * represented by a drive letter, e.g., "A:\" and "C:\"
 */
@ThreadSafe
public class WindowsFileSystem extends AbstractFileSystem {

    private static final int BUFSIZE = 255;

    private static final int SEM_FAILCRITICALERRORS = 0x0001;

    private static final int FILE_CASE_SENSITIVE_SEARCH = 0x00000001;
    private static final int FILE_CASE_PRESERVED_NAMES = 0x00000002;
    private static final int FILE_FILE_COMPRESSION = 0x00000010;
    private static final int FILE_DAX_VOLUME = 0x20000000;
    private static final int FILE_NAMED_STREAMS = 0x00040000;
    private static final int FILE_PERSISTENT_ACLS = 0x00000008;
    private static final int FILE_READ_ONLY_VOLUME = 0x00080000;
    private static final int FILE_SEQUENTIAL_WRITE_ONCE = 0x00100000;
    private static final int FILE_SUPPORTS_ENCRYPTION = 0x00020000;
    private static final int FILE_SUPPORTS_OBJECT_IDS = 0x00010000;
    private static final int FILE_SUPPORTS_REPARSE_POINTS = 0x00000080;
    private static final int FILE_SUPPORTS_SPARSE_FILES = 0x00000040;
    private static final int FILE_SUPPORTS_TRANSACTIONS = 0x00200000;
    private static final int FILE_SUPPORTS_USN_JOURNAL = 0x02000000;
    private static final int FILE_UNICODE_ON_DISK = 0x00000004;
    private static final int FILE_VOLUME_IS_COMPRESSED = 0x00008000;
    private static final int FILE_VOLUME_QUOTAS = 0x00000020;

    private static final Map OPTIONS_MAP = new HashMap<>();
    static {
        OPTIONS_MAP.put(FILE_CASE_PRESERVED_NAMES, "casepn");
        OPTIONS_MAP.put(FILE_CASE_SENSITIVE_SEARCH, "casess");
        OPTIONS_MAP.put(FILE_FILE_COMPRESSION, "fcomp");
        OPTIONS_MAP.put(FILE_DAX_VOLUME, "dax");
        OPTIONS_MAP.put(FILE_NAMED_STREAMS, "streams");
        OPTIONS_MAP.put(FILE_PERSISTENT_ACLS, "acls");
        OPTIONS_MAP.put(FILE_SEQUENTIAL_WRITE_ONCE, "wronce");
        OPTIONS_MAP.put(FILE_SUPPORTS_ENCRYPTION, "efs");
        OPTIONS_MAP.put(FILE_SUPPORTS_OBJECT_IDS, "oids");
        OPTIONS_MAP.put(FILE_SUPPORTS_REPARSE_POINTS, "reparse");
        OPTIONS_MAP.put(FILE_SUPPORTS_SPARSE_FILES, "sparse");
        OPTIONS_MAP.put(FILE_SUPPORTS_TRANSACTIONS, "trans");
        OPTIONS_MAP.put(FILE_SUPPORTS_USN_JOURNAL, "journaled");
        OPTIONS_MAP.put(FILE_UNICODE_ON_DISK, "unicode");
        OPTIONS_MAP.put(FILE_VOLUME_IS_COMPRESSED, "vcomp");
        OPTIONS_MAP.put(FILE_VOLUME_QUOTAS, "quota");
    }

    static final long MAX_WINDOWS_HANDLES;
    static {
        // Determine whether 32-bit or 64-bit handle limit, although both are
        // essentially infinite for practical purposes. See
        // https://blogs.technet.microsoft.com/markrussinovich/2009/09/29/pushing-the-limits-of-windows-handles/
        if (System.getenv("ProgramFiles(x86)") == null) {
            MAX_WINDOWS_HANDLES = 16_777_216L - 32_768L;
        } else {
            MAX_WINDOWS_HANDLES = 16_777_216L - 65_536L;
        }
    }

    /**
     * 

* Constructor for WindowsFileSystem. *

*/ public WindowsFileSystem() { // Set error mode to fail rather than prompt for FLoppy/CD-Rom Kernel32.INSTANCE.SetErrorMode(SEM_FAILCRITICALERRORS); } @Override public List getFileStores(boolean localOnly) { // Create list to hold results ArrayList result; // Begin with all the local volumes result = getLocalVolumes(null); // Build a map of existing mount point to OSFileStore Map volumeMap = new HashMap<>(); for (OSFileStore volume : result) { volumeMap.put(volume.getMount(), volume); } // Iterate through volumes in WMI and update description (if it exists) // or add new if it doesn't (expected for network drives) for (OSFileStore wmiVolume : getWmiVolumes(null, localOnly)) { if (volumeMap.containsKey(wmiVolume.getMount())) { // If the volume is already in our list, update the name field // using WMI's more verbose name and update label if needed OSFileStore volume = volumeMap.get(wmiVolume.getMount()); result.remove(volume); result.add(new WindowsOSFileStore(wmiVolume.getName(), volume.getVolume(), volume.getLabel().isEmpty() ? wmiVolume.getLabel() : volume.getLabel(), volume.getMount(), volume.getOptions(), volume.getUUID(), "", volume.getDescription(), volume.getType(), volume.getFreeSpace(), volume.getUsableSpace(), volume.getTotalSpace(), 0, 0)); } else if (!localOnly) { // Otherwise add the new volume in its entirety result.add(wmiVolume); } } return result; } /** * Package private method for getting all mounted local drives. * * @param volumeToMatch an optional string to filter match, null otherwise * @return A list of {@link OSFileStore} objects representing all local mounted volumes */ static ArrayList getLocalVolumes(String volumeToMatch) { ArrayList fs; String volume; String strFsType; String strName; String strMount; WinNT.HANDLE hVol; WinNT.LARGE_INTEGER userFreeBytes; WinNT.LARGE_INTEGER totalBytes; WinNT.LARGE_INTEGER systemFreeBytes; char[] aVolume; char[] fstype; char[] name; char[] mount; fs = new ArrayList<>(); aVolume = new char[BUFSIZE]; hVol = Kernel32.INSTANCE.FindFirstVolume(aVolume, BUFSIZE); if (WinBase.INVALID_HANDLE_VALUE.equals(hVol)) { return fs; } try (CloseableIntByReference pFlags = new CloseableIntByReference()) { do { fstype = new char[16]; name = new char[BUFSIZE]; mount = new char[BUFSIZE]; userFreeBytes = new WinNT.LARGE_INTEGER(0L); totalBytes = new WinNT.LARGE_INTEGER(0L); systemFreeBytes = new WinNT.LARGE_INTEGER(0L); volume = Native.toString(aVolume); Kernel32.INSTANCE.GetVolumeInformation(volume, name, BUFSIZE, null, null, pFlags, fstype, 16); final int flags = pFlags.getValue(); Kernel32.INSTANCE.GetVolumePathNamesForVolumeName(volume, mount, BUFSIZE, null); strMount = Native.toString(mount); if (!strMount.isEmpty() && (volumeToMatch == null || volumeToMatch.equals(volume))) { strName = Native.toString(name); strFsType = Native.toString(fstype); StringBuilder options = new StringBuilder((FILE_READ_ONLY_VOLUME & flags) == 0 ? "rw" : "ro"); String moreOptions = OPTIONS_MAP.entrySet().stream().filter(e -> (e.getKey() & flags) > 0) .map(Map.Entry::getValue).collect(Collectors.joining(",")); if (!moreOptions.isEmpty()) { options.append(',').append(moreOptions); } Kernel32.INSTANCE.GetDiskFreeSpaceEx(volume, userFreeBytes, totalBytes, systemFreeBytes); // Parse uuid from volume name String uuid = ParseUtil.parseUuidOrDefault(volume, ""); fs.add(new WindowsOSFileStore(String.format(Locale.ROOT, "%s (%s)", strName, strMount), volume, strName, strMount, options.toString(), uuid, "", getDriveType(strMount), strFsType, systemFreeBytes.getValue(), userFreeBytes.getValue(), totalBytes.getValue(), 0, 0)); } } while (Kernel32.INSTANCE.FindNextVolume(hVol, aVolume, BUFSIZE)); return fs; } finally { Kernel32.INSTANCE.FindVolumeClose(hVol); } } /** * Package private method for getting logical drives listed in WMI. * * @param nameToMatch an optional string to filter match, null otherwise * @param localOnly Whether to only search local drives * @return A list of {@link OSFileStore} objects representing all network mounted volumes */ static List getWmiVolumes(String nameToMatch, boolean localOnly) { long free; long total; List fs = new ArrayList<>(); WmiResult drives = Win32LogicalDisk.queryLogicalDisk(nameToMatch, localOnly); for (int i = 0; i < drives.getResultCount(); i++) { free = WmiUtil.getUint64(drives, LogicalDiskProperty.FREESPACE, i); total = WmiUtil.getUint64(drives, LogicalDiskProperty.SIZE, i); String description = WmiUtil.getString(drives, LogicalDiskProperty.DESCRIPTION, i); String name = WmiUtil.getString(drives, LogicalDiskProperty.NAME, i); String label = WmiUtil.getString(drives, LogicalDiskProperty.VOLUMENAME, i); String options = WmiUtil.getUint16(drives, LogicalDiskProperty.ACCESS, i) == 1 ? "ro" : "rw"; int type = WmiUtil.getUint32(drives, LogicalDiskProperty.DRIVETYPE, i); String volume; if (type != 4) { char[] chrVolume = new char[BUFSIZE]; Kernel32.INSTANCE.GetVolumeNameForVolumeMountPoint(name + "\\", chrVolume, BUFSIZE); volume = Native.toString(chrVolume); } else { volume = WmiUtil.getString(drives, LogicalDiskProperty.PROVIDERNAME, i); String[] split = volume.split("\\\\"); if (split.length > 1 && split[split.length - 1].length() > 0) { description = split[split.length - 1]; } } fs.add(new WindowsOSFileStore(String.format(Locale.ROOT, "%s (%s)", description, name), volume, label, name + "\\", options, "", "", getDriveType(name), WmiUtil.getString(drives, LogicalDiskProperty.FILESYSTEM, i), free, free, total, 0, 0)); } return fs; } /** * Private method for getting mounted drive type. * * @param drive Mounted drive * @return A drive type description */ private static String getDriveType(String drive) { switch (Kernel32.INSTANCE.GetDriveType(drive)) { case 2: return "Removable drive"; case 3: return "Fixed drive"; case 4: return "Network drive"; case 5: return "CD-ROM"; case 6: return "RAM drive"; default: return "Unknown drive type"; } } @Override public long getOpenFileDescriptors() { Map> valueListMap = ProcessInformation.queryHandles().getB(); List valueList = valueListMap.get(HandleCountProperty.HANDLECOUNT); long descriptors = 0L; if (valueList != null) { for (Long value : valueList) { descriptors += value; } } return descriptors; } @Override public long getMaxFileDescriptors() { return MAX_WINDOWS_HANDLES; } @Override public long getMaxFileDescriptorsPerProcess() { return MAX_WINDOWS_HANDLES; } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy