Skip to content
techsengerPublic

About

Techsenger DriveKit – A Java library for detecting local drives, classifying their types, providing stable IDs, and monitoring changes.

Topics

Resources

Stars

2 stars

Watchers

0 watching

Forks

Latest commit

 

History

3 Commits

Folders and files

Repository files navigation

Techsenger DriveKit

Techsenger DriveKit is a Java library for detecting local drives, classifying their types, providing stable IDs, and monitoring changes. It works on Windows, Linux, and macOS.

A drive is a volume that is available in the file system: a drive letter of Windows or a mounted file system of a Unix-like system. For every drive the library gives its root path, type, label, identifier, and the flag of encryption.

Table of Contents

Features

Key features of DriveKit include:

  • Listing of the drives of the local machine on Windows, Linux, and macOS.
  • Classification of the drives: hard disk, solid state drive, removable drive, memory card, floppy, optical, network, LVM, RAID, virtual.
  • A stable identifier of a drive that the operating system keeps across reboots.
  • Detection of the encryption of a drive (dm-crypt on Linux).
  • A monitor that reports the connected and removed drives, with three modes: manual, periodic, and smart refresh.
  • Nested drives on Linux, where a volume is mounted into a directory of another one.
  • No external processes and no parsing of the output of commands.

Overview

DriveKit detects the drives with DriveDetector and keeps track of them with DriveMonitor. Every drive has a root path, a type, a label, an identifier, and the flag of encryption. The details are in the sections Drive, DriveDetector, and DriveMonitor. How the drives and their types are found, and how accurate it is, is in DriveDetector.

Quick Start

Detect Drives

To get the drives currently available on the system, call DriveDetector.detect():

for (Drive drive : DriveDetector.detect()) {
    System.out.println(drive.getRoot() + " " + drive.getType() + " "
            + drive.getLabel() + " " + drive.getId());
}

Manual Refresh

By default, DriveMonitor uses MANUAL_REFRESH mode. It searches for drives when you call refresh() and notifies listeners if the results differ from the previous search.

The listener runs in the same thread that calls refresh().

DriveListener listener = change -> {
    change.getAdded().forEach(drive -> System.out.println("Connected: " + drive));
    change.getRemoved().forEach(drive -> System.out.println("Removed: " + drive));
};
DriveMonitor.addListener(listener);

List<Drive> drives = DriveMonitor.getDrives();  // performs the initial search
// The listener is not called for the initial search.

// Later, when you want to check for changes:
DriveMonitor.refresh();                         // notifies the listener if drives have changed
drives = DriveMonitor.getDrives();              // returns the latest results

Smart Refresh

If you don't want to call refresh() yourself, switch to SMART_REFRESH mode. The monitor checks the system state periodically and searches for drives only when it detects a change.

The listener runs in the monitor's own thread. If you update a user interface, dispatch the update to the UI thread. For example, in JavaFX, use Platform.runLater():

DriveListener listener = change ->
        Platform.runLater(() -> table.getItems().setAll(change.getCurrent()));

DriveMonitor.addListener(listener);
DriveMonitor.setInterval(Duration.ofSeconds(5));  // optional; defaults to 3 seconds
DriveMonitor.setMode(MonitorMode.SMART_REFRESH);  // starts monitoring immediately

When you no longer need automatic monitoring, switch back to manual mode and remove the listener:

DriveMonitor.setMode(MonitorMode.MANUAL_REFRESH);
DriveMonitor.removeListener(listener);

Drive

Drive is an immutable description of a volume:

Method Description
getRoot() The root directory, such as E:\ or /media/user/DISK.
getType() The type of the drive.
getLabel() The label of the volume, or an empty string. On macOS it is the name of the directory of the volume in /Volumes, which differs from the name of the volume if another volume has taken it.
getId() The identifier of the volume.
isEncrypted() Whether the volume is known to be encrypted.

Two drives are equal if their roots, types, identifiers, labels and encryption flags are equal. Clients tell a drive that has changed from a drive that has not by it.

Types

Type Description
HDD A hard disk with rotating plates. An external disk is also HDD or SSD, as the systems report it as an ordinary disk.
SSD A solid state drive, including NVMe and built-in flash storage.
REMOVABLE A removable drive that has no more specific type, such as a USB flash drive or a Zip drive. A memory card is also REMOVABLE. A floppy drive is FLOPPY, an optical drive is OPTICAL.
FLOPPY A floppy disk drive.
OPTICAL A CD, DVD, or Blu-ray drive.
NETWORK A share of another machine mounted into the file system.
LVM A logical volume of LVM (Linux).
RAID A RAID array: several drives combined into one, also when it lies over other drives.
VIRTUAL A drive that has no device of its own: a mounted disk image (ISO, VHD, DMG, loop) or a RAM disk. An image is virtual whatever it holds, so a mounted ISO image is VIRTUAL, not OPTICAL.
UNKNOWN A drive whose type the system does not report, such as a disk behind a USB enclosure or in a virtual machine.

Identifier

The identifier is a string that the operating system keeps for the same volume across reboots and that differs for different volumes, so a drive found again can be told from a new one. Its prefix names the kind of the value, so values of different kinds never coincide:

Prefix Where Value
volguid: Windows The GUID of the volume.
net: Windows The UNC path of a network drive.
fsuuid: Linux The UUID of the file system.
partuuid: Linux, macOS The UUID of the partition.
src: Linux, macOS The source of the mount, such as host:/export.
path: all The root path, if the system gives nothing else. It is not stable: a volume mounted elsewhere gets another one.

The identifiers of the drives returned together are different: if several drives would have the same identifier, as a volume mounted into several places has, the later ones get @ and the URI of their root added to it.

Encryption

isEncrypted() is true if the whole volume is known to be encrypted. It is detected for dm-crypt on Linux (LUKS, plain, and TrueCrypt modes), including the volumes of LVM and RAID that lie over it. The encryption that the other systems do on their own, such as BitLocker and FileVault, is not detected, and isEncrypted() is false for such drives.

DriveDetector

DriveDetector.detect() searches the drives of the local machine and returns them, the root of the file system first. Its API is static and it has no state: the drives are searched again on every call, and new instances are returned.

Drive Listing

  • Windows: the roots of the file system, that is the drive letters. The identifier is the GUID of the volume, or the UNC path for a network drive.
  • Linux: the file systems that are mounted. The root is always listed. The other mounts are listed if they are made from a device, or are network shares, or ZFS. The mounts of the system and of the programs are not listed: /proc, /sys, /dev, /run (except /run/media), snap packages, containers. The layers over devices are followed: dm-crypt is passed through for the type and sets isEncrypted(), LVM and RAID give their own types.
  • macOS: the root and the volumes in /Volumes.

Type Resolution

The type of a drive is found from the signs that the operating system gives, so the accuracy depends on the type and on the system:

  • Exact — the system tells the type directly.
  • High — the type follows from the signs that the system sets reliably for ordinary hardware.
  • — — the type is not detected, or the system does not have such drives.

If none of the signs is there, the type is UNKNOWN. The cells name the signs in the order they are checked.

Type Windows Linux macOS
HDD High: seek penalty. High: rotation rate that udev knows, then the flag of rotation, which is the weakest sign. High: type of the medium in the registry of the kit.
SSD Exact: NVMe and MMC (eMMC) buses. High: no seek penalty, support of trim, name of the product. Exact: NVMe, and eMMC (the device of the card host that is not an SD card). High: rotation rate that udev knows, name of the model, flag of rotation. High: type of the medium in the registry of the kit.
REMOVABLE High: the drive that the system calls removable. Exact: SD bus. High: the flag of removable media. Exact: SD card on a card host. High: the medium that the system calls removable.
FLOPPY High: removable drives A: and B:. Exact: fd*. —
OPTICAL Exact: CD-ROM drive type, also in a USB drive. Exact: sr*, also in a USB drive. High: file systems cd9660 and udf on a device that is not an image.
NETWORK Exact: remote drive type. Exact: nfs, nfs4, cifs, smb3, fuse.sshfs. Exact: nfs, smbfs, afpfs, webdav.
LVM — Exact: volumes of LVM. —
RAID High: RAID bus of the logical drives of a controller. Exact: arrays of md. High: controllers whose drivers give arrays only (hpsa, aacraid, arcmsr, 3w-*). —
VIRTUAL Exact: RAM disk, image mounted from a file (ISO, VHD, VHDX). Exact: loop*, ram*, zram*. High: device of a disk image (DMG, ISO).

The ratings come from the documented behavior of the system interfaces. The library has not been verified on all the hardware yet, and macOS has not been verified at all. The cases where the signs are hidden, such as disks behind USB bridges, are in Limitations.

DriveMonitor

DriveMonitor keeps the current drives of the machine and reports their changes. Its API is static, as the machine has one set of drives. While a drive has not changed, the monitor gives the very same instance, and a new instance only when it has changed.

A change is described by DriveChange: the added drives, the removed drives, and all the current drives. A drive whose label or type has changed is both removed (as it was) and added (as it is now).

Modes

The mode tells how refresh() is called. refresh() searches the drives and notifies the listeners if they have changed; a client may call it in any mode, and it always searches. refresh() is synchronous: when it returns, the search is finished and getDrives() gives the drives that it found. In the periodic and smart modes the monitor calls it on its own thread.

Mode Refreshed by Cost Accuracy
MANUAL_REFRESH A client. This is the default. None until it is called. The state of the last refresh().
PERIODIC_REFRESH The monitor, every interval. It reads the drives every interval, which may wake a sleeping device or load a network share. The most accurate: every change is noticed within an interval.
SMART_REFRESH The monitor, only when the state of the system has changed. It checks the state every interval, which does not read the drives, and searches only on a change. A drive that is connected or disconnected, or whose volume is replaced, is noticed within an interval. A change that the state does not show is noticed at the next refresh(), see the table below.

setMode starts the periodic and smart modes with a refresh() right away. setInterval changes the interval of the periodic and smart modes, three seconds by default, and getInterval returns it. getDrives() returns the drives that the last refresh() has found, without a new search; if there was no search yet, it makes the first one.

The monitor of each system checks its own state in the smart mode, without reading the drives:

System State Noticed Not noticed until refresh()
Windows The letters of the drives and the identifiers of their volumes. A drive that is connected or disconnected, a card or a disc put into a reader that keeps its letter. A new label of a drive. Another share behind the same letter of a network drive.
Linux The lines of the mounts that are listed. A mount, an unmount, a mount of another device to the same place. A new label of a mounted file system.
macOS The volumes in /Volumes and the numbers of their devices. A volume that is connected or disconnected, another device under the same name, a new name of a volume. A change of the type of a drive that stays where it is.

Listeners

The listeners are added by addListener and are notified in all the modes. A listener is called by the refresh() that has found the changes, in the thread that calls it: the thread of the monitor when the monitor calls refresh() in the periodic and smart modes, and the thread of a client when the client calls it. That thread waits for the listener, so a listener must not block, and a user interface is updated through its own thread.

Limitations

  • A hard disk is told from a solid state drive by the signs the system gives. Some bridges between a disk and the machine, such as USB enclosures and the disks of virtual machines, hide the technology. On Windows and macOS the type is then UNKNOWN. On Linux the system takes a disk for a rotating one unless it is told otherwise, so a solid state drive behind such a bridge is an HDD, unless the name of its model contains SSD.
  • A drive is REMOVABLE only if the system calls it removable. A flash drive that reports itself as fixed is an HDD or an SSD (or UNKNOWN), as the system shows it as a disk too. Conversely, an external disk whose enclosure reports removable media is REMOVABLE.
  • A device on the MMC bus is always an SSD. Nowadays it is almost always eMMC, the flash storage that is soldered into the machine, and the systems show it as an ordinary disk. The systems give the same bus and type to a removable MMC card, so it cannot be told from eMMC. Such cards are practically extinct, so a removable MMC card is also an SSD. An SD card is not affected: it is REMOVABLE.
  • A USB floppy drive is REMOVABLE, as the system shows it as a removable disk. On Windows only A: and B: are FLOPPY.
  • A disc with a file system other than cd9660 and udf is not detected as OPTICAL on macOS.
  • The arrays of Windows (dynamic disks, Storage Spaces) and of Linux controllers such as MegaRAID are seen as ordinary disks.
  • On Windows a network share without a drive letter is not listed.
  • On Linux only the mounted file systems are listed. Unmounted partitions and swap are not.
  • On Linux the shares that are opened through the file manager (GVfs) are not listed.
  • On Linux a ZFS dataset is listed with the type UNKNOWN.
  • The encryption is detected on Linux only.
  • Other systems than Windows, Linux, and macOS are not supported: DriveDetector and DriveMonitor fail to initialize with an UnsupportedOperationException as the cause.
  • The library is young: the classification on Windows and macOS is based on the documented interfaces of the systems and has not been verified on all the hardware.

Requirements

The library requires Java 21. The demo also requires JavaFX 21.

Dependencies

Minimal dependency:

<dependency>
    <groupId>com.techsenger.drivekit</groupId>
    <artifactId>drivekit-core</artifactId>
    <version>${drivekit.version}</version>
</dependency>

Code Building

To build the library use standard Git and Maven commands:

git clone https://github.com/techsenger/drivekit
cd drivekit
mvn clean install

Running Demo

To run the demo, execute the following commands in the project root:

cd drivekit-demo
mvn javafx:run

The window has a drop-down list with the mode of the monitor and the Refresh button. The table shows all the drives with their identifiers.

License

Techsenger DriveKit is licensed under the Apache License, Version 2.0.

Contributing

We welcome all contributions. You can help by reporting bugs, suggesting improvements, or submitting pull requests with fixes and new features. If you have any questions, feel free to reach out — we’ll be happy to assist you.

Support Us

You can support our open-source work through GitHub Sponsors. Your contribution helps us maintain projects, develop new features, and provide ongoing improvements. Multiple sponsorship tiers are available, each offering different levels of recognition and benefits.

About

Techsenger DriveKit – A Java library for detecting local drives, classifying their types, providing stable IDs, and monitoring changes.

Topics

Resources

Stars

2 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages