Toggle menu
Toggle preferences menu
Toggle personal menu
Not logged in
Your IP address will be publicly visible if you make any edits.

Libusbhsfs Switch: Difference between revisions

From GameBrew
Created page with "{{Infobox Switch Homebrews |title=libusbhsfs |image=libusbhsfsswitch.png |description=USB Mass Storage Class Host + Filesystem Mounter static library for Nintendo Switch homebrew applications. |author=DarkMatterCore |lastupdated=2023/01/03 |type=Developments |version=0.2.8 |license=Mixed |download=https://dlhb.gamebrew.org/switchhomebrews/libusbhsfsswitch.7z |website=https://gbatemp.net/threads/libusbhsfs-usb-mass-storage-class-host-filesystem-mounter-static-library.5776..."
 
No edit summary
 
(4 intermediate revisions by 2 users not shown)
Line 1: Line 1:
{{Infobox Switch Homebrews
{{Infobox Switch Homebrews
|title=libusbhsfs
|title=libusbhsfs
|image=libusbhsfsswitch.png
|image=libusbhsfsnx.png
|description=USB Mass Storage Class Host + Filesystem Mounter static library for Nintendo Switch homebrew applications.
|description=USB Mass Storage Class Host + Filesystem Mounter static library for Nintendo Switch homebrew applications.
|author=DarkMatterCore
|author=DarkMatterCore, XorTroll, Rhys Koedijk
|lastupdated=2023/01/03
|lastupdated=2025/12/03
|type=Developments
|type=Developments
|version=0.2.8
|version=0.2.10
|license=Mixed
|license=Mixed
|download=https://dlhb.gamebrew.org/switchhomebrews/libusbhsfsswitch.7z
|download=https://dlhb.gamebrew.org/switchhomebrews/libusbhsfsnx.7z
|website=https://gbatemp.net/threads/libusbhsfs-usb-mass-storage-class-host-filesystem-mounter-static-library.577687/
|website=https://gbatemp.net/threads/libusbhsfs-usb-mass-storage-class-host-filesystem-mounter-static-library.577687/
|source=https://github.com/DarkMatterCore/libusbhsfs
|source=https://github.com/DarkMatterCore/libusbhsfs
|donation=
|donation=https://github.com/DarkMatterCore/libusbhsfs
}}
}}
{{#seo:
This is a static library for homebrew applications which is aimed at developers that wish to integrate USB Mass Storage (UMS) support into their projects.
|title=Switch Homebrew PC Tools (Developments) - GameBrew
 
|title_mode=append
Some homebrews that use this library:
|image=libusbhsfsswitch.png
*[[NXDumpTool Switch|nxdumptool]] (rewrite branch).
|image_alt=libusbhsfs
*[[Goldleaf Switch|Goldleaf]].
}}
*Goldleaf forks (e.g. [[TinWoo_Switch|TinWoo]], [[AtmoXL Titel Installer|AtmoXL]], etc.).
{{cleanup|article|Needs cleanup}}
*[[NX-Shell Switch|NX-Shell]].
USB Mass Storage Class Host + Filesystem Mounter static library for Nintendo Switch homebrew applications.
*[[NXMP Switch|NXMP]].
*[[DBI Switch|DBI]].
 
Note that this doesn't open any possibility whatsoever to launch Switch games from a UMS device. Something like that demands system-wide UMS support, which this library doesn't provide.
 
==Features==
*Supports USB Mass Storage (UMS) devices that implement at least one USB interface descriptor with the following properties:
**bInterfaceClass: 0x08 (USB Mass Storage Class).
**bInterfaceSubClass: 0x06 (SCSI Transparent Command Set SubClass).
**bInterfaceProtocol: 0x50 (Bulk-Only Transport [BOT] Protocol).
*Bulk-Only Transport (BOT) driver written from scratch, which implements the most common SCSI Primary Command Set (SPC) commands as well as BOT class-specific requests.
**Supported SPC commands:
***TEST UNIT READY (0x00).
***REQUEST SENSE (0x03).
***INQUIRY (0x12).
***MODE SENSE (6) (0x1A).
***START STOP UNIT (0x1B).
***PREVENT ALLOW MEDIUM REMOVAL (0x1E).
***READ CAPACITY (10) (0x25).
***READ (10) (0x28).
***WRITE (10) (0x2A).
***MODE SENSE (10) (0x5A).
***READ (16) (0x88).
***WRITE (16) (0x8A).
***SERVICE ACTION IN (0x9E).
**Supported SERVICE ACTION IN actions:
***READ CAPACITY (16) (0x10).
**Supported BOT class-specific requests:
***Get Max LUN (0xFE).
***Bulk-Only Mass Storage Reset (0xFF).
*Supports UMS devices with long logical block addresses (64-bit LBAs) and variable logical block sizes (512 - 4096 bytes).
*Background thread that takes care of starting all available logical units from each newly connected UMS device, as well as mounting the available filesystems from each one whenever possible.
**Supported partitioning schemes:
***Super Floppy Drive (SFD) (Volume Boot Record @ LBA 0).
***Master Boot Record (MBR).
***Extended Boot Record (EBR).
***GUID Partition Table (GPT) + protective MBR.
**Supported filesystems:
***FAT12/FAT16/FAT32/exFAT (via FatFs).
***NTFS (via NTFS-3G).
***EXT2/3/4 (via lwext4).
***Completely possible to add support for additional filesystems, as long as their libraries are ported over to Switch.
**Uses devoptab virtual device interface to provide a way to use standard C I/O calls (e.g. <code>fopen()</code>, <code>opendir()</code>, etc.) on mounted filesystems from the available logical units
*Easy to use library interface:
**Provides an autoclear user event that is signaled each time a status change is detected by the background thread (new device mounted, device removed).
**Painless listing of mounted partitions using a simple struct that provides the devoptab device name, as well as other interesting information (filesystem index, filesystem type, write protection, raw logical unit capacity, etc.).
**Provides a way to safely unmount UMS devices at runtime.
*Supports the usbfs service from SX OS.


==Media==
==User guide==
<youtube></youtube>
For documentation, please refer to the [https://github.com/DarkMatterCore/libusbhsfs/blob/main/README.md readme].


===Limitations===
*Bulk-Only Transport (BOT) driver:
**Up to 32 different USB Mass Storage Class interfaces can be used at the same time. Increasing this limit isn't harmful, but makes the library take up additional heap memory.
**Only a single SCSI operation can be performed at any given time per UMS device, regardless of their number of logical units. This is an official limitation of the BOT protocol. Mutexes are used to avoid multiple SCSI operations from taking place at the same time on the same UMS device.
*Filesystem libraries:
**FatFs:
***<code>fstat()</code> and <code>fchmod()</code> aren't supported. This is a limitation of FatFs itself, since it doesn't provide an easy way to perform these operations using an already open file descriptor.
**NTFS-3G:
***Crypto operations aren't supported.
***Security contexts are always ignored.
***Only partial journaling is supported, so unexpected crashes or power loss can leave the mounted NTFS volume in an inconsistent state. In cases where there has been heavy activity prior to the crash or power loss, it is recommended to plug the UMS device into a Windows PC and let it replay the journal properly before remounting with NTFS-3G, in order to prevent possible data loss and/or corruption.
***Symbolic links are transparent. This means that when a symbolic link in encountered, its hard link will be used instead.
**lwext4:
***Up to 8 EXT volumes can be mounted at the same time across all available UMS devices. This is because lwext4 uses an internal, stack-based registry of mount points and block devices, and increasing the limit can potentially exhaust the stack memory from the thread libusbhsfs runs under.
***For the rest of the limitations, please take a look at the [https://github.com/gkostka/lwext4/blob/master/README.md README] from the lwext4 repository.
*Stack and/or heap memory consumption:
**This library is *not* suitable for custom sysmodules and/or service MITM projects. It allocates a 1 MiB buffer per each UMS device, which is used for command and data transfers. It also relies heavily on libnx features, which are not always compatible with sysmodule/MITM program contexts.
*Switch-specific FS features:
**Concatenation files aren't supported.
*<code>usbfs</code> service from SX OS:
**Only a single FAT volume from a single drive can be mounted. No other filesystem types are supported.
**Relative paths aren't supported.
**<code>chdir()</code>, <code>rename()</code>, <code>dirreset()</code> and <code>utimes()</code> aren't supported.
**There are probably other limitations we don't even know about, due to the closed-source nature of this CFW.


==Screenshots==
==Screenshots==
https://dlhb.gamebrew.org/switchhomebrews/libusbhsfsswitch-01.png
https://dlhb.gamebrew.org/switchhomebrews/libusbhsfsnx.png
https://dlhb.gamebrew.org/switchhomebrews/libusbhsfsswitch-02.png
https://dlhb.gamebrew.org/switchhomebrews/libusbhsfsswitch-03.png
https://dlhb.gamebrew.org/switchhomebrews/libusbhsfsswitch-04.png
https://dlhb.gamebrew.org/switchhomebrews/libusbhsfsswitch-05.png
https://dlhb.gamebrew.org/switchhomebrews/libusbhsfsswitch-06.png
https://dlhb.gamebrew.org/switchhomebrews/libusbhsfsswitch-07.png
https://dlhb.gamebrew.org/switchhomebrews/libusbhsfsswitch-08.png


==Changelog==
==Changelog==
'''v.1.0'''
'''v0.2.10'''
* First Release.
* '''lib''':
** Add <code>usbHsFsGetDeviceByPath()</code>, which fills its output <code>UsbHsFsDevice</code> element with information about the mounted volume pointed to by the input path (e.g. <code>ums0:/switch/</code>).
** Ditch <code>FS_MAX_PATH</code> macro in favor of <code>LIBUSBHSFS_MAX_PATH</code> (set to 4096 bytes), providing better support for longer filesystem paths.
** Add support for retrieving and setting FAT/NTFS specific file attribute bitmasks via <code>stat()</code>, <code>chmod()</code>, <code>readdir()</code>, <code>fstat()</code> (NTFS only) and <code>fchmod()</code> (NTFS only). Please keep in mind that in order to preserve regular POSIX file attributes, the <code>st_spare4[0]</code> field from the <code>stat</code> struct is used to store this information.
** Add <code>UsbHsFsDosNtFileAttributes</code> enum to easily handle FAT/NTFS attribute bitmasks.
** Allow listing of dotfiles in directories whenever possible across all supported filesystems.
** Reduce the size of the dedicated transfer buffer for each UMS device from 8 MiB to 1 MiB.
** Add <code>_GNU_SOURCE</code> definition to <code>CFLAGS</code> in Makefile.
* '''devoptab''':
** Add a new header file with generic versions of the macros previously used in all devoptab interfaces.
* '''examples''':
** Use dynamically allocated buffers for the tested filesystem paths (using the LIBUSBHSFS_MAX_PATH macro).
** Reduce file copy block size to 1 MiB to match the rest of the changes.
** Print FAT/NTFS specific file attribute bitmasks during the file tests, depending on the mounted filesystem type.
** Unconditionally print full POSIX attributes bitmask during the file tests.
** Print last access and creation timestamps during the file tests.
* '''fat''':
** Update FatFs to R0.16 p2 (September 13th, 2025).
** Cherrypick specific FatFs improvements from the [https://github.com/extremscorner/fatfs-mod fork maintained by Extrems], while still retaining support for our runtime read-only flag. These include:
*** Remove internal volume management system in favor of explicitly passing FATFS objects.
*** Modify <code>ff_stat()</code> to allow its use on the origin directory.
*** Modify <code>FILINFO</code> struct to expose the cluster number and the last access timestamp.
*** Prevent automatic hiding of dotfiles in directory listings.
*** Integrate contiguous clusters patch from Wonderful Toolchain.
*** Fix file growth error on exFAT.
** Add a small optimization to <code>FAT_TIMESTAMP</code> macro.
** Update <code>get_fattime()</code> to use plain old <code>time()</code> instead.
** Fix timestamp generation in <code>get_fattime()</code> by adding previously missing time offsets to <code>timeinfo.tm_year</code> (+1900) and <code>timeinfo.tm_mon</code> (+1). Thanks to [https://github.com/ITotalJustice ITotalJustice].
** Refactor <code>ffdev_fixpath()</code> into <code>ffdev_get_fixed_path()</code>.
** Update <code>ffdev_fill_stat()</code> to store the last access and creation timestamps into the output stat struct, as well as the FAT-specific file attributes bitmask.
** Delegate timestamp conversion to the new <code>ffdev_time_posix2fat()</code> and <code>ffdev_time_fat2posix()</code> helpers.
** Implement <code>ffdev_chmod()</code>.
* '''ext''':
** Add <code>mounted</code> flag to <code>ext_vd</code>, in order to prevent unmounting an EXT volume that hasn't really been successfully mounted.
** Remove <code>extdev_fixpath()</code> in favor of <code>extdev_get_fixed_path()</code>.
** Only use full second precision in <code>extdev_utimes()</code>.
* '''ntfs''':
** Add <code>NTFS_MAX_NAME_LEN_BYTES</code> macro.
** Make <code>ntfs_path</code> struct public, remove its internal buffer and turn all strings into dynamically allocated pointers.
** Update <code>ntfs_inode_create()</code>, <code>ntfs_inode_link()</code> and <code>ntfs_inode_unlink()</code> to take in <code>ntfs_path</code> objects instead of character strings.
** Add <code>ntfs_path_destroy()</code>.
** Remove <code>ntfs_split_path()</code>.
** Refactor <code>ntfsdev_fixpath()</code> into <code>ntfsdev_get_fixed_path()</code>.
** Move path split logic from <code>ntfs_split_path()</code> into <code>ntfsdev_get_fixed_path()</code>.
** Update <code>ntfsdev_dirnext()</code> and <code>ntfsdev_dirnext_filldir()</code> to allow listing of dotfiles in directories.
** Update <code>ntfsdev_statvfs()</code> to use <code>NTFS_MAX_NAME_LEN_BYTES</code> as the value for <code>f_namemax</code>.
** Implement <code>ntfsdev_chmod()</code> and <code>ntfsdev_fchmod()</code>.
** Update <code>ntfsdev_fill_stat()</code> to store the NTFS-specific file attributes bitmask.
* '''usbfs''':
** Add <code>UsbFsMountStatus</code> enum.
** Update <code>UsbFsServiceCmd</code> enum to follow the same codestyle as the rest of the codebase.
* '''Other internal changes''':
** Use C23 strongly typed enums.
** Use forward declarations for structs whenever needed.
** '''usbhsfs_drive''':
*** Move struct definitions into their own header file.
*** Update <code>UsbHsFsDriveLogicalUnitFileSystemContext</code> to use a single <code>void*</code> pointer to represent the underlying filesystem object.
*** Update <code>UsbHsFsDriveContext</code> to use a recursive mutex instead of a regular one.
*** Update <code>usbHsFsDriveInitializeContext()</code> to return a pointer to a dynamically allocated <code>UsbHsFsDriveContext</code> object.
*** Update <code>usbHsFsDriveDestroyContext()</code> to lock the drive recursive mutex + let it take care of freeing <code>usbHsFsDriveDestroyContext</code> pointers as well.
*** Heavily simplify <code>usbHsFsDriveIsValidLogicalUnitFileSystemContext()</code>.
*** Move LUN initialization logic into <code>usbHsFsDriveInitializeLogicalUnitContext()</code>.
*** Update <code>usbHsFsDriveClearStallStatus()</code> to add small 10 ms delays after each call to <code>usbHsFsRequestClearEndpointHaltFeature()</code>.
*** Fix required conditions for an interface change in <code>usbHsFsDriveChangeInterfaceDescriptor()</code>.
*** Add <code>usbHsFsDriveDestroyLogicalUnitContext()</code>.
** '''usbhsfs_log''':
*** Define stubbed macros for public <code>usbHsFsLog*()</code> calls when the library is not built in debug mode.
** '''usbhsfs_manager''':
*** Remove <code>usbHsFsManagerGetLogicalUnitContextForFatFsDriveNumber()</code>.
*** Move Atmosphère-specific (de)initialization logic into <code>usbHsFsManagerInitializeAtmosphereDriverResources()</code> and <code>usbHsFsManagerCloseAtmosphereDriverResources()</code>.
*** Move SX OS-specific (de)initialization logic into <code>usbHsFsManagerInitializeSXOSDriverResources()</code> and <code>usbHsFsManagerCloseSXOSDriverResources()</code>.
*** Move NTFS/EXT debug logging configuration logic into <code>usbHsFsManagerSetupFileSystemDriverLogging()</code>.
*** Rename <code>usbHsFsCreateDriveManagerThread()</code> to <code>usbHsFsManagerCreateBackgroundThread()</code>.
*** Rename <code>usbHsFsCloseDriveManagerThread()</code> to <code>usbHsFsManagerDestroyBackgroundThread()</code>.
*** Rename <code>usbHsFsDriveManagerThreadFuncAtmosphere()</code> to <code>usbHsFsManagerAtmosphereThreadFunc()</code>.
*** Rename <code>usbHsFsDriveManagerThreadFuncSXOS()</code> to <code>usbHsFsManagerSXOSThreadFunc()</code>.
*** Rename <code>usbHsFsResetDrives()</code> to <code>usbHsFsManagerResetMassStorageDevices()</code>.
*** Refactor <code>usbHsFsUpdateDriveContexts()</code> into <code>usbHsFsManagerAddConnectedDriveContexts()</code>.
*** Rename <code>usbHsFsAddDriveContextToList()</code> to <code>usbHsFsManagerInitializeAndAddDriveContextToList()</code>.
*** Move drive initialization logic from <code>usbHsFsUpdateDriveContexts()</code> into <code>usbHsFsManagerInitializeAndAddDriveContextToList()</code>.
*** Add <code>usbHsFsManagerRemoveDisconnectedDriveContexts()</code>.
*** Rename <code>usbHsFsRemoveDriveContextFromListByIndex()</code> to <code>usbHsFsManagerRemoveDriveContextFromListByIndex()</code>.
*** Rename <code>usbHsFsPopulateDeviceList()</code> to <code>usbHsFsManagerPopulateDeviceList()</code>.
*** Rename <code>usbHsFsExecutePopulateCallback()</code> to <code>usbHsFsManagerExecutePopulateCallback()</code>.
*** Rename <code>usbHsFsFillDeviceElement()</code> to <code>usbHsFsManagerFillDeviceElement()</code>.
** '''usbhsfs_mount''':
*** Define new macros for all the constants used throughout the compilation unit.
*** Remove padding from the <code>GuidPartitionTableHeader</code> struct to bring the size down to <code>0x5C</code>, which actually matches the contents of its <code>header_size</code> field.
*** Move MBR partition entry parsing logic into <code>usbHsFsMountParseMasterBootRecordPartitionEntry()</code>.
*** Move GPT header parsing logic into <code>usbHsFsMountGetGuidPartitionTableHeader()</code>.
*** Move GPT entry parsing logic into <code>usbHsFsMountParseGuidPartitionTableEntry()</code>.
*** Refactor <code>usbHsFsMountRegisterVolume()</code> into <code>usbHsFsMountInitializeLogicalUnitFileSystemContext()</code>.
*** Move LUN FS deinitialization logic into <code>usbHsFsMountDestroyLogicalUnitFileSystemContext()</code>.
*** Update <code>usbHsFsMountRegisterDevoptabDevice()</code> to take in a pointer to a devoptab interface.
*** Move devoptab device unregistration logic into <code>usbHsFsMountUnregisterDevoptabDevice()</code>.
** '''usbhsfs_request''':
*** Use <code>usbHsFsUtilsAlignedAlloc()</code> instead of <code>memalign()</code>.
** '''usbhsfs_scsi''':
*** Update to reflect the changes in the rest of the codebase.
** '''usbhsfs_utils''':
*** Add <code>ALIGN_UP</code>, <code>IS_ALIGNED</code>, <code>IS_POWER_OF_TWO</code>, <code>MAX_ELEMENTS</code>, <code>SCOPED_LOCK_BASE</code>, <code>SCOPED_RLOCK</code> and <code>UTF8_MAX_CODEPOINT_SIZE</code> macros.
*** Update <code>SCOPED_LOCK</code> macro to rely on the new <code>SCOPED_LOCK_BASE</code> macro.
*** Add <code>UsbHsFsUtilsScopedRecursiveLock</code> struct.
*** Add <code>usbHsFsUtilsAlignedAlloc()</code>.
*** Rename <code>usbHsFsUtilsLockScope()</code> to <code>usbHsFsUtilsAcquireScopedLock()</code>.
*** Rename <code>usbHsFsUtilsUnlockScope()</code> to <code>usbHsFsUtilsReleaseScopedLock()</code>.
*** Add <code>usbHsFsUtilsAcquireScopedRecursiveLock()</code>.
*** Add <code>usbHsFsUtilsReleaseScopedRecursiveLock()</code>.
'''v0.2.9'''
*lib:
**Implement a callback-based population system, which can be used as an alternative to the event-based system that has been available up until now. For more information, please read the How to use section from the README.
**Add a reimplementation of libnx's usbHsEpPostBuffer(), called usbHsFsRequestEndpointDataXfer(), which calls usbHsEpPostBufferAsync() with a hardcoded timeout value of 10 seconds (using the USB_POSTBUFFER_TIMEOUT define).
**Port log handler QoL improvements from nxdumptool.
**Log result codes in unpadded hexadecimal notation.
**Reorganize UsbHsFsMountFlags enum.
**SCSI INQUIRY strings now have prevalence over USB device descriptor strings, which affects the manufacturer, product_name and serial_number strings from UsbHsFsDevice elements.
**Add LIB_ASSERT macro and update all static assertions throughout the codebase to use it.
**Use NX_IGNORE_ARG macro where needed throughout the codebase.
**SCSI driver:
***Reorganize structs and enums.
***Add missing comments/references.
***Add ScsiInquiryVitalProductDataPageCode enum and rework usbHsFsScsiSendInquiryCommand() to make it possible to request Vital Product Data pages from attached LUNs.
***Update ScsiInquiryStandardData struct to also retrieve serial number data from attached LUNs.
***Add ScsiInquiryUnitSerialNumberPageHeader struct.
***Update usbHsFsScsiStartDriveLogicalUnit() to make it read serial number information from the Unit Serial Number VPD page. Fallbacks to the serial number returned by the standard SCSI Inquiry command if not available.
***Overhaul usbHsFsScsiTransferCommand() to make it handle both unexpected CSWs and CSW data residue values in a better way.
**fs-libs: remove all build scripts for both NTFS-3G and lwext4, as well as the fs-libs Makefile target. Please use the now available devkitPro pacman packages switch-ntfs-3g and switch-lwext4. The How to install section of the README has been updated to reflect this change.
**fat: calls to ftruncate() on FAT filesystems now restore the current file position after truncation.
*P.S.: remember to remove previous installations of NTFS-3G and lwext4 *before* installing the official devkitPro pacman packages by running:
**sudo (dkp-)pacman -R switch-libntfs-3g switch-lwext4
'''v0.2.8'''
*lib: add <code>usbHsFsGetPhysicalDeviceCount()</code>, which returns the number of physical UMS devices currently connected to the console with at least one underlying filesystem mounted as a virtual device.
*fs-libs:
**Update FatFs to <code>R0.15 w/patch2</code>.
***Furthermore, FatFs is now modified to check a runtime read-only flag for any mounted filesystems, making it possible to use the <code>UsbHsFsMountFlags_ReadOnly</code> mount flag on FAT volumes for write-free access.
**Update NTFS-3G to <code>2022.10.3</code>.
**Update lwext4 to <code>58bcf89a121b72d4fb66334f1693d3b30e4cb9c5</code> with cherrypicked patches.
**Improve Makefile scripts for both NTFS-3G and lwext4 by checking if <code>makepkg</code> and <code>(dkp-)pacman</code> binaries are actually available, as well as automatically removing <code>pkg-config</code> if its available and installing <code>dkp-toolchain-vars</code> as part of the required dependencies.
 
'''v0.2.7'''
*log: use UTC timestamp generated at build time instead of <code>__DATE__</code> and <code>__TIME__ macros</code>.
*fs-libs: add missing Windows-specific dependencies to the Makefiles.
*fat: update FatFs to latest patch from 2022-04-04.
*ntfs:
**Update NTFS-3G to <code>2022.5.17</code>.
**Create LRU caches while mounting new NTFS volumes.
**Use <code>ntfs_volume_get_free_space()</code> while mounting new NTFS volumes to speed up subsequent calls to statvfs()</code> made by the user.
**Let NTFS-3G take care of filtering system files and hidden files using <code>ntfs_set_shown_files()</code>, instead of filtering them in the library's <code>dirnext()</code> implementation.
**Use <code>NVolFreeSpaceKnown()</code> in the library's <code>statvfs()</code> implementation to check if the number of free NTFS clusters has already been retrieved.
*ext: apply cherrypicked bugfixes to lwext4:
** https://github.com/cyyynthia/lwext4/commit/bf68d176d7e0a1369a0ca2b35aaad0f700f2e716
** https://github.com/wzx-ipads/lwext4/commit/06b64aabc9b445f6b28a9850ed1fcf715edad418
** https://github.com/mudita/lwext4/commit/2869807352fb7c9c2ab69e8442efa0b2ce404673
 
'''v0.2.6'''
*Updated codebase to use <code>localtime_r()</code> instead of <code>localtime()</code> to avoid possible race conditions with other threads.
*Fixed <code>fs-libs</code> building under Linux distros with pacman. Thanks to [https://github.com/ITotalJustice ITotalJustice] for reporting this issue!
*Implemented support for UMS devices that don't byteswap the Command Status Wrapper signature before sending back SCSI command responses. Thanks to [https://github.com/rdmrocha rdmrocha] for reporting this issue!
 
'''v0.2.5'''
*Updated lwext4 patch to fix mountpoint corruption issues if a mountpoint name is reused after a previous call to <code>ext4_mount</code> failed.
**This fixes a data abort discovered by [https://github.com/phisch phisch]. Thanks for the report!
**The fix is based on [https://github.com/HenriChataing HenriChataing]'s [https://github.com/gkostka/lwext4/pull/51 pull request] in lwext4's repository, but also adds an additional <code>memset</code> call to <code>ext4_umount</code> to fully clear every unmounted mountpoint.
**A note to all developers using the GPL-licensed version of the library: update the <code>switch-lwext4</code> package by running <code>make fs-libs</code> in your libusbhsfs clone before building your project.
 
'''v0.2.4'''
*Updated FatFs to R0.14b.
*The backup GPT header from a drive is now retrieved and used if the main GPT header is corrupted, as long as it's available.
*Slightly improved debug logging code.
*Rewrote mutex handling throughout the code to use a small, macro-based scoped lock implementation whenever possible.
*Removed superfluous memory operations by using dynamic pointer arrays to manage logical unit / filesystem contexts.
*Added missing <code>splInitialize</code> / <code>splExit</code> calls while checking if a service is running.
**Furthermore, the Exosphère API version, which is used to determine if TIPC serialization is needed instead of CMIF, is now saved during the first service check.
 
'''v0.2.3'''
*Improvements to the USB manager:
**Refactored USB control request functions to work with libnx USB datatypes instead of drive / logical unit contexts.
**Implemented <code>GET_DESCRIPTOR</code> control requests for configuration and string descriptors.
*Improvements to the BOT driver:
**If <code>usbHsEpPostBuffer()</code> fails, only the endpoint the library is currently working with will be cleared. Furthermore, the result from this operation no longer affects the return code.
**If <code>usbHsFsRequestPostBuffer()</code> fails, the library now tries to retrieve a CSW right away - if it succeeds, a Request Sense command will be issued immediately to the block device.
**Mode Sense (6) / Mode Sense (10) command success is no longer mandatory in <code>usbHsFsScsiStartDriveLogicalUnit()</code>.
**SPC standard version is now validated.
*Improvements to the PKGBUILD scripts for NTFS-3G and lwext4:
**Made it possible to build and install all three libraries using the Makefile - for more information, please refer to the How to install section from the README.
**Proper library path is now forced while building NTFS-3G. Fixes issues in some Linux systems. Thanks to [https://github.com/sigmaboy sigmaboy] for the correction.
**Other minor improvements.
*Library API changes:
**Added <code>vid</code> and <code>pid</code> fields to <code>UsbHsFsDevice</code>. Useful if the application needs to implement a device filter on its own.
**<code>vendor_id</code>, <code>product_id</code> and <code>product_revision</code> fields in <code>UsbHsFsDevice</code> have been replaced with <code>manufacturer</code>, <code>product_name</code> and <code>serial_number</code> fields, which represent UTF-8 conversions of string descriptors referenced by the USB device descriptor.
***Strings from SCP INQUIRY data are still used as a fallback method for <code>manufacturer</code> and <code>product_name</code> fields if the USB device descriptor holds no references to string descriptors.
*Miscellaneous changes:
**Renamed <code>ff_rename()</code> from FatFs to avoid issues fix conflicts in applications linked against FFmpeg. Thanks to Cpasjuste for letting us know.
**The <code>has_journal</code> flag from the superblock in EXT filesystems is now verified before calling journal-related functions.
**EXT filesystem version is now retrieved only once, while mounting the volume.
**The <code>AtmosphereHasService</code> sm API extension available in Atmosphère and Atmosphère-based CFWs is now being used to check if a specific service is running.
***HOS 12.0.x / AMS 0.19.x support is provided by using TIPC serialization to dispatch the IPC request, if needed.
**Improved logfile code and simplified binary data logging throughout the codebase.
*Changes under the hood (currently unused, but may change in the future):
**Implemented SYNCHRONIZE CACHE (10) and SYNCHRONIZE CACHE (16) SCP commands.
**Modified drive and logical unit contexts to prepare for UASP support.
**Added extra code to handle USB Attached SCSI Protocol (UASP) interface descriptors under both USB 2.0 and 3.0 modes.
 
'''v0.2.2'''
*By popular demand, the NTFS journal is now rebuilt by default for NTFS volumes that have not been properly unmounted, which lets the library mount them right away without having to use a Windows PC. Please bear in mind this process may cause inconsistencies - always try to safely remove your storage devices.
**Nonetheless, this should be a relatively safe operation - default behaviour in NTFS-3G changed [https://linux.die.net/man/8/mount.ntfs-3g some years ago].
**This change also affects EXT volume mounting. The EXT journal will now always try be recovered - if the process fails, the EXT volume won't be mounted.
 
'''v0.2.1'''
*Bugfix: mount name IDs are now properly freed while destroying filesystem contexts.
*Library API: added a helper preprocessor macro to generate strings based on the supported filesystem type values.
*Makefile: branch name is now retrieved using rev-parse instead of <code>symbolic-ref</code>. Fixes <code>ref HEAD is not a symbolic ref</code> errors while building the library when the repository is used as a git submodule.
 
'''v0.2.0'''
*Built using libnx v4.0.0.
*Implemented EXT2/3/4 support (GPL build only).
**This means applications using the GPL build of the library must now be linked against libusbhsfs, NTFS-3G and lwext4. Please read the How to build section from the README to know how to build both NTFS-3G and lwext4 and install them into the <code>portlibs</code> directory from devkitPro.
**Certain limitations apply. Please read the Limitations section from the README for more information.
*Dot directory entries "." and ".." are now filtered in NTFS volumes. They are no longer displayed as part of the output from readdir()</code>.
*Minor code cleanup.
*The example test application is now linked against lwext4 as well.
 
'''v0.1.0'''
*Built using libnx commit <code>c51918a</code>.
*Implemented partition table parsing (MBR/GPT/VBR). The library now takes care of looking for boot sectors and/or partition tables on its own, and just passes volume LBAs to filesystem libraries. This makes it possible to mount multiple partitions from the same logical unit as individual devoptab devices.
*Implemented NTFS support. Big thanks to [https://github.com/rhyskoedijk Rhys Koedijk]!
**You must link your application against both libusbhsfs and NTFS-3G if you wish to use NTFS support. Please read the How to build section from the README to know how to build NTFS-3G and install it into the <code>portlibs</code> directory from devkitPro.
**Certain limitations apply. Please read the Limitations section from the README for more information.
**Dual licensing (ISC / GPLv2+) is now provided as a way to allow projects that don't comply with the GPLv2+ license from NTFS-3G to keep using libusbhsfs, albeit with FAT support only. Please read the Licensing section from the readme for more information.
*Improved safety checks in all internal devoptab functions.
*Library API:
**<code>usbHsFsUnmountDevice()</code> is now provided as a way to manually/safely unmount UMS devices at runtime before disconnecting them.
***This has been always been automatically handled by <code>usbHsFsExit()</code> if there are any mounted UMS devices when the library interface is closed. So, depending on what you need, you should only call <code>usbHsFsUnmountDevice()</code> when absolutely necessary.
**<code>usbHsFsGetFileSystemMountFlags()</code> and <code>usbHsFsSetFileSystemMountFlags()</code> are now provided as a way to get/set filesystem mount flags.
***Please read <code>include/usbhsfs.h</code> for more information about these flags and what they do.
***These flags only affect NTFS volume mounting at this moment, so they have no effect under ISC licensed builds of the library.
***Furthermore, these functions have no effect at all under SX OS.
*BOT driver:
**Inquiry SCSI command is now retried if an unexpected CSW with no sense data is received.
**Both peripheral qualifier and peripheral device type values from Inquiry data are now filtered. Thanks to [https://github.com/ginkuji ginkuji] for reporting this issue.
**Logical unit startup now returns right away if an optional SCSI command fails and a <code>Medium Not Present</code> additional sense code is reported by the UMS device.
**A bus reset is now performed on all UMS devices that are already available when <code>usbHsFsInitialize()</code> is called. Fixes logical unit startup for drives that were stopped during a previous session, but not removed from the console. Thanks to [https://github.com/FlyingBananaTree FlyingBananaTree] for reporting this issue.
**Fixed potential memory corruption issues that could have taken place due to not updating LUN/FS context references after reallocating their buffers.
*Debug build:
**Implemented proper caching into debug logging code, making debug builds a lot faster now.
**The logfile is now flushed each time a public API function that generates log messages is called.
*SX OS:
**The status change user-mode event is now signaled on every <code>usbfs</code> status change.
*Example test application:
**Updated to reflect all these changes.
**Added more filesystem tests.
**Rewrote input handling to match the new <code>pad</code> API from libnx.
**Now using <code>usbHsFsUnmountDevice()</code> to safely unmount any UMS devices that have already been tested.
 
'''v0.0.3'''
*Added support for a custom event index passed to usbHsFsInitialize(), which is internally used with <code>usbHsCreateInterfaceAvailableEvent()</code> / <code>usbHsDestroyInterfaceAvailableEvent()</code>. Developers listening for other specific USB interfaces on their own should no longer have issues with the library.
*Added fsp-usb check. <code>usbHsFsInitialize()</code> will now fail on purpose if fsp-usb is running in the background.
*Renamed FatFs library functions to avoid linking errors in homebrew apps that already depend on it.
*Fixed FatFs warnings when building the library with <code>-O3</code>. Thanks to [https://github.com/ITotalJustice ITotalJustice]!
*Changes to relative path support:
**Modified FatFs to remove all references to <code>ff_chdrive()</code>, <code>ff_chdir()</code>, <code>ff_getcwd()</code> and <code>FF_FS_RPATH</code>. We take care of handling the current working directory and only pass absolute paths to FatFs. The code to resolve paths with dot entries wasn't removed.
**<code>ffdev_chdir()</code> now just opens the directory from the provided path to make sure it exists, then closes it immediately.
**The default devoptab device is now set by the <code>chdir()</code> function from devoptab interfaces, using <code>usbHsFsMountSetDefaultDevoptabDevice()</code>. This means it's effectively possible to change the current directory and the default devoptab device in one go, just by calling chdir() with an absolute path (e.g. <code>chdir("ums0:/")</code>).
**It's possible to <code>chdir()</code> back to the SD card to change the default devoptab device (e.g. <code>chdir("sdmc:/)</code>).
**If the UMS device that holds the volume set as the default devoptab device is removed from the console, the SD card will be set as the new default devoptab device.
**Removed <code>usbHsFsSetDefaultDevice()</code>, <code>usbHsFsGetDefaultDevice()</code> and <code>usbHsFsUnsetDefaultDevice()</code> - just use <code>chdir()</code> now.
**Limitations regarding <code>fsdevMount*()</code> calls from libnx still apply. Can't do anything about it.
**Please read the Relative path support section from the README for more information.
*BOT driver:
**Added support for unexpected CSWs received through an input endpoint during data transfer stages. Thanks to [https://github.com/duckbill007 duckbill007] for reporting this issue!
**Always issue a Request Sense command if an unexpected CSW is received.
**Make sure write protection is disabled before issuing any SCP WRITE commands.
**Reduced wait time if a "Not Ready" sense key is received after issuing a Request Sense command.
*Added support for the <code>usbfs</code> service from SX OS. Thanks to [https://github.com/blawar blawar] for providing the updated <code>usbfs</code> service calls!
**Please read the Limitations section from the README for more information.
*Updated test application to reflect all these changes.
**It is now also capable of performing a test file copy to the UMS filesystem if <code>test.file</code> is available at the SD card root directory.
 
'''v0.0.2'''
*Relicensed library under the ISC License. We really want you people to adopt it and freely use it in your projects.
*Fixed distribution package version string generation in <code>Makefile</code>.
*<code>LICENSE.md</code> and <code>README.md</code> are stored in the generated distribution packages.
*Added support for relative paths.
**Please read the Relative path support section from the README for more information.
*A trailing colon is now added to the returned mount names from <code>UsbHsFsDevice</code> elements.
*Fixed devoptab device unregistration.
*Bulk-Only Transport (BOT) driver:
**<code>usbHsFsRequestGetMaxLogicalUnits()</code> now clears the STALL status from both endpoints on its own if it fails.
**Likewise, <code>usbHsFsRequestPostBuffer()</code> now attempts to clear the STALL status from both endpoints if it fails.
*FatFs devoptab interface:
**Fixed error code translations for some FatFs errors.
**Created an unified <code>ffdev_fill_stat()</code> function for both <code>ffdev_stat()</code> and <code>ffdev_dirnext()</code>.
**Fixed POSIX timestamp conversions from DOS timestamps.
*Debug build:
**Debug messages from <code>usbHsFsScsiReadLogicalUnitBlocks()</code> and <code>usbHsFsScsiReadLogicalUnitBlocks()</code> now include the total number of bytes to transfer per each loop iteration.
**Added debug messages to the FatFs devoptab interface.
 
'''v0.0.1'''
*Initial release. Only capable of mounting one FAT filesystem per logical unit from each connected UMS device.
 
==Credits==
*[https://github.com/DarkMatterCore DarkMatterCore]: UMS device LUN/FS management, Bulk-Only Transport (BOT) driver, library interface, FAT support, EXT support.
*[https://github.com/XorTroll XorTroll]: FS mounting system, devoptab device (un)registration, example test application.
*[https://github.com/rhyskoedijk Rhys Koedijk]: NTFS support.
*Lots of SPC/BOT docs across the Internet - these have been referenced in multiple files from the codebase.
 
Thanks to:
*ChaN, for the [http://elm-chan.org/fsw/ff/00index_e.html FatFs module].
*Tuxera and NTFS-3G contributors, for the [https://github.com/tuxera/ntfs-3g NTFS-3G library].
*Grzegorz Kostka and lwext4 contributors, for the [https://github.com/gkostka/lwext4 lwext4 library].
*Switchbrew and libnx contributors. Code from libnx was used for devoptab device management and path handling.
*[https://github.com/blawar blawar], for providing the updated usbfs SX OS service calls.
*[https://github.com/Whovian9369 Whovian9369]. I literally would have dropped Switch homebrew development altogether some months ago, if not for you. Thanks, mate.
*[https://github.com/ITotalJustice ITotalJustice], for testing the partition table parsing algorithm.
*[https://github.com/fennectech FennecTECH], for breaking stuff on a regular basis.
*All the Alpha Testers and Super Users from the nxdumptool Discord server, for being a constant source of ideas (and memes).


== External links ==
== External links ==
* Gbatemp - https://gbatemp.net/threads/libusbhsfs-usb-mass-storage-class-host-filesystem-mounter-static-library.577687/
* GitHub - https://github.com/DarkMatterCore/libusbhsfs
* Github - https://github.com/DarkMatterCore/libusbhsfs
* GBAtemp - https://gbatemp.net/threads/libusbhsfs-usb-mass-storage-class-host-filesystem-mounter-static-library.577687/
* Reddit -

Latest revision as of 02:43, 7 December 2025

libusbhsfs
General
AuthorDarkMatterCore, XorTroll, Rhys Koedijk
TypeDevelopments
Version0.2.10
LicenseMixed
Last Updated2025/12/03
Links
Download
Website
Source
Support Author

This is a static library for homebrew applications which is aimed at developers that wish to integrate USB Mass Storage (UMS) support into their projects.

Some homebrews that use this library:

Note that this doesn't open any possibility whatsoever to launch Switch games from a UMS device. Something like that demands system-wide UMS support, which this library doesn't provide.

Features

  • Supports USB Mass Storage (UMS) devices that implement at least one USB interface descriptor with the following properties:
    • bInterfaceClass: 0x08 (USB Mass Storage Class).
    • bInterfaceSubClass: 0x06 (SCSI Transparent Command Set SubClass).
    • bInterfaceProtocol: 0x50 (Bulk-Only Transport [BOT] Protocol).
  • Bulk-Only Transport (BOT) driver written from scratch, which implements the most common SCSI Primary Command Set (SPC) commands as well as BOT class-specific requests.
    • Supported SPC commands:
      • TEST UNIT READY (0x00).
      • REQUEST SENSE (0x03).
      • INQUIRY (0x12).
      • MODE SENSE (6) (0x1A).
      • START STOP UNIT (0x1B).
      • PREVENT ALLOW MEDIUM REMOVAL (0x1E).
      • READ CAPACITY (10) (0x25).
      • READ (10) (0x28).
      • WRITE (10) (0x2A).
      • MODE SENSE (10) (0x5A).
      • READ (16) (0x88).
      • WRITE (16) (0x8A).
      • SERVICE ACTION IN (0x9E).
    • Supported SERVICE ACTION IN actions:
      • READ CAPACITY (16) (0x10).
    • Supported BOT class-specific requests:
      • Get Max LUN (0xFE).
      • Bulk-Only Mass Storage Reset (0xFF).
  • Supports UMS devices with long logical block addresses (64-bit LBAs) and variable logical block sizes (512 - 4096 bytes).
  • Background thread that takes care of starting all available logical units from each newly connected UMS device, as well as mounting the available filesystems from each one whenever possible.
    • Supported partitioning schemes:
      • Super Floppy Drive (SFD) (Volume Boot Record @ LBA 0).
      • Master Boot Record (MBR).
      • Extended Boot Record (EBR).
      • GUID Partition Table (GPT) + protective MBR.
    • Supported filesystems:
      • FAT12/FAT16/FAT32/exFAT (via FatFs).
      • NTFS (via NTFS-3G).
      • EXT2/3/4 (via lwext4).
      • Completely possible to add support for additional filesystems, as long as their libraries are ported over to Switch.
    • Uses devoptab virtual device interface to provide a way to use standard C I/O calls (e.g. fopen(), opendir(), etc.) on mounted filesystems from the available logical units
  • Easy to use library interface:
    • Provides an autoclear user event that is signaled each time a status change is detected by the background thread (new device mounted, device removed).
    • Painless listing of mounted partitions using a simple struct that provides the devoptab device name, as well as other interesting information (filesystem index, filesystem type, write protection, raw logical unit capacity, etc.).
    • Provides a way to safely unmount UMS devices at runtime.
  • Supports the usbfs service from SX OS.

User guide

For documentation, please refer to the readme.

Limitations

  • Bulk-Only Transport (BOT) driver:
    • Up to 32 different USB Mass Storage Class interfaces can be used at the same time. Increasing this limit isn't harmful, but makes the library take up additional heap memory.
    • Only a single SCSI operation can be performed at any given time per UMS device, regardless of their number of logical units. This is an official limitation of the BOT protocol. Mutexes are used to avoid multiple SCSI operations from taking place at the same time on the same UMS device.
  • Filesystem libraries:
    • FatFs:
      • fstat() and fchmod() aren't supported. This is a limitation of FatFs itself, since it doesn't provide an easy way to perform these operations using an already open file descriptor.
    • NTFS-3G:
      • Crypto operations aren't supported.
      • Security contexts are always ignored.
      • Only partial journaling is supported, so unexpected crashes or power loss can leave the mounted NTFS volume in an inconsistent state. In cases where there has been heavy activity prior to the crash or power loss, it is recommended to plug the UMS device into a Windows PC and let it replay the journal properly before remounting with NTFS-3G, in order to prevent possible data loss and/or corruption.
      • Symbolic links are transparent. This means that when a symbolic link in encountered, its hard link will be used instead.
    • lwext4:
      • Up to 8 EXT volumes can be mounted at the same time across all available UMS devices. This is because lwext4 uses an internal, stack-based registry of mount points and block devices, and increasing the limit can potentially exhaust the stack memory from the thread libusbhsfs runs under.
      • For the rest of the limitations, please take a look at the README from the lwext4 repository.
  • Stack and/or heap memory consumption:
    • This library is *not* suitable for custom sysmodules and/or service MITM projects. It allocates a 1 MiB buffer per each UMS device, which is used for command and data transfers. It also relies heavily on libnx features, which are not always compatible with sysmodule/MITM program contexts.
  • Switch-specific FS features:
    • Concatenation files aren't supported.
  • usbfs service from SX OS:
    • Only a single FAT volume from a single drive can be mounted. No other filesystem types are supported.
    • Relative paths aren't supported.
    • chdir(), rename(), dirreset() and utimes() aren't supported.
    • There are probably other limitations we don't even know about, due to the closed-source nature of this CFW.

Screenshots

libusbhsfsnx.png

Changelog

v0.2.10

  • lib:
    • Add usbHsFsGetDeviceByPath(), which fills its output UsbHsFsDevice element with information about the mounted volume pointed to by the input path (e.g. ums0:/switch/).
    • Ditch FS_MAX_PATH macro in favor of LIBUSBHSFS_MAX_PATH (set to 4096 bytes), providing better support for longer filesystem paths.
    • Add support for retrieving and setting FAT/NTFS specific file attribute bitmasks via stat(), chmod(), readdir(), fstat() (NTFS only) and fchmod() (NTFS only). Please keep in mind that in order to preserve regular POSIX file attributes, the st_spare4[0] field from the stat struct is used to store this information.
    • Add UsbHsFsDosNtFileAttributes enum to easily handle FAT/NTFS attribute bitmasks.
    • Allow listing of dotfiles in directories whenever possible across all supported filesystems.
    • Reduce the size of the dedicated transfer buffer for each UMS device from 8 MiB to 1 MiB.
    • Add _GNU_SOURCE definition to CFLAGS in Makefile.
  • devoptab:
    • Add a new header file with generic versions of the macros previously used in all devoptab interfaces.
  • examples:
    • Use dynamically allocated buffers for the tested filesystem paths (using the LIBUSBHSFS_MAX_PATH macro).
    • Reduce file copy block size to 1 MiB to match the rest of the changes.
    • Print FAT/NTFS specific file attribute bitmasks during the file tests, depending on the mounted filesystem type.
    • Unconditionally print full POSIX attributes bitmask during the file tests.
    • Print last access and creation timestamps during the file tests.
  • fat:
    • Update FatFs to R0.16 p2 (September 13th, 2025).
    • Cherrypick specific FatFs improvements from the fork maintained by Extrems, while still retaining support for our runtime read-only flag. These include:
      • Remove internal volume management system in favor of explicitly passing FATFS objects.
      • Modify ff_stat() to allow its use on the origin directory.
      • Modify FILINFO struct to expose the cluster number and the last access timestamp.
      • Prevent automatic hiding of dotfiles in directory listings.
      • Integrate contiguous clusters patch from Wonderful Toolchain.
      • Fix file growth error on exFAT.
    • Add a small optimization to FAT_TIMESTAMP macro.
    • Update get_fattime() to use plain old time() instead.
    • Fix timestamp generation in get_fattime() by adding previously missing time offsets to timeinfo.tm_year (+1900) and timeinfo.tm_mon (+1). Thanks to ITotalJustice.
    • Refactor ffdev_fixpath() into ffdev_get_fixed_path().
    • Update ffdev_fill_stat() to store the last access and creation timestamps into the output stat struct, as well as the FAT-specific file attributes bitmask.
    • Delegate timestamp conversion to the new ffdev_time_posix2fat() and ffdev_time_fat2posix() helpers.
    • Implement ffdev_chmod().
  • ext:
    • Add mounted flag to ext_vd, in order to prevent unmounting an EXT volume that hasn't really been successfully mounted.
    • Remove extdev_fixpath() in favor of extdev_get_fixed_path().
    • Only use full second precision in extdev_utimes().
  • ntfs:
    • Add NTFS_MAX_NAME_LEN_BYTES macro.
    • Make ntfs_path struct public, remove its internal buffer and turn all strings into dynamically allocated pointers.
    • Update ntfs_inode_create(), ntfs_inode_link() and ntfs_inode_unlink() to take in ntfs_path objects instead of character strings.
    • Add ntfs_path_destroy().
    • Remove ntfs_split_path().
    • Refactor ntfsdev_fixpath() into ntfsdev_get_fixed_path().
    • Move path split logic from ntfs_split_path() into ntfsdev_get_fixed_path().
    • Update ntfsdev_dirnext() and ntfsdev_dirnext_filldir() to allow listing of dotfiles in directories.
    • Update ntfsdev_statvfs() to use NTFS_MAX_NAME_LEN_BYTES as the value for f_namemax.
    • Implement ntfsdev_chmod() and ntfsdev_fchmod().
    • Update ntfsdev_fill_stat() to store the NTFS-specific file attributes bitmask.
  • usbfs:
    • Add UsbFsMountStatus enum.
    • Update UsbFsServiceCmd enum to follow the same codestyle as the rest of the codebase.
  • Other internal changes:
    • Use C23 strongly typed enums.
    • Use forward declarations for structs whenever needed.
    • usbhsfs_drive:
      • Move struct definitions into their own header file.
      • Update UsbHsFsDriveLogicalUnitFileSystemContext to use a single void* pointer to represent the underlying filesystem object.
      • Update UsbHsFsDriveContext to use a recursive mutex instead of a regular one.
      • Update usbHsFsDriveInitializeContext() to return a pointer to a dynamically allocated UsbHsFsDriveContext object.
      • Update usbHsFsDriveDestroyContext() to lock the drive recursive mutex + let it take care of freeing usbHsFsDriveDestroyContext pointers as well.
      • Heavily simplify usbHsFsDriveIsValidLogicalUnitFileSystemContext().
      • Move LUN initialization logic into usbHsFsDriveInitializeLogicalUnitContext().
      • Update usbHsFsDriveClearStallStatus() to add small 10 ms delays after each call to usbHsFsRequestClearEndpointHaltFeature().
      • Fix required conditions for an interface change in usbHsFsDriveChangeInterfaceDescriptor().
      • Add usbHsFsDriveDestroyLogicalUnitContext().
    • usbhsfs_log:
      • Define stubbed macros for public usbHsFsLog*() calls when the library is not built in debug mode.
    • usbhsfs_manager:
      • Remove usbHsFsManagerGetLogicalUnitContextForFatFsDriveNumber().
      • Move Atmosphère-specific (de)initialization logic into usbHsFsManagerInitializeAtmosphereDriverResources() and usbHsFsManagerCloseAtmosphereDriverResources().
      • Move SX OS-specific (de)initialization logic into usbHsFsManagerInitializeSXOSDriverResources() and usbHsFsManagerCloseSXOSDriverResources().
      • Move NTFS/EXT debug logging configuration logic into usbHsFsManagerSetupFileSystemDriverLogging().
      • Rename usbHsFsCreateDriveManagerThread() to usbHsFsManagerCreateBackgroundThread().
      • Rename usbHsFsCloseDriveManagerThread() to usbHsFsManagerDestroyBackgroundThread().
      • Rename usbHsFsDriveManagerThreadFuncAtmosphere() to usbHsFsManagerAtmosphereThreadFunc().
      • Rename usbHsFsDriveManagerThreadFuncSXOS() to usbHsFsManagerSXOSThreadFunc().
      • Rename usbHsFsResetDrives() to usbHsFsManagerResetMassStorageDevices().
      • Refactor usbHsFsUpdateDriveContexts() into usbHsFsManagerAddConnectedDriveContexts().
      • Rename usbHsFsAddDriveContextToList() to usbHsFsManagerInitializeAndAddDriveContextToList().
      • Move drive initialization logic from usbHsFsUpdateDriveContexts() into usbHsFsManagerInitializeAndAddDriveContextToList().
      • Add usbHsFsManagerRemoveDisconnectedDriveContexts().
      • Rename usbHsFsRemoveDriveContextFromListByIndex() to usbHsFsManagerRemoveDriveContextFromListByIndex().
      • Rename usbHsFsPopulateDeviceList() to usbHsFsManagerPopulateDeviceList().
      • Rename usbHsFsExecutePopulateCallback() to usbHsFsManagerExecutePopulateCallback().
      • Rename usbHsFsFillDeviceElement() to usbHsFsManagerFillDeviceElement().
    • usbhsfs_mount:
      • Define new macros for all the constants used throughout the compilation unit.
      • Remove padding from the GuidPartitionTableHeader struct to bring the size down to 0x5C, which actually matches the contents of its header_size field.
      • Move MBR partition entry parsing logic into usbHsFsMountParseMasterBootRecordPartitionEntry().
      • Move GPT header parsing logic into usbHsFsMountGetGuidPartitionTableHeader().
      • Move GPT entry parsing logic into usbHsFsMountParseGuidPartitionTableEntry().
      • Refactor usbHsFsMountRegisterVolume() into usbHsFsMountInitializeLogicalUnitFileSystemContext().
      • Move LUN FS deinitialization logic into usbHsFsMountDestroyLogicalUnitFileSystemContext().
      • Update usbHsFsMountRegisterDevoptabDevice() to take in a pointer to a devoptab interface.
      • Move devoptab device unregistration logic into usbHsFsMountUnregisterDevoptabDevice().
    • usbhsfs_request:
      • Use usbHsFsUtilsAlignedAlloc() instead of memalign().
    • usbhsfs_scsi:
      • Update to reflect the changes in the rest of the codebase.
    • usbhsfs_utils:
      • Add ALIGN_UP, IS_ALIGNED, IS_POWER_OF_TWO, MAX_ELEMENTS, SCOPED_LOCK_BASE, SCOPED_RLOCK and UTF8_MAX_CODEPOINT_SIZE macros.
      • Update SCOPED_LOCK macro to rely on the new SCOPED_LOCK_BASE macro.
      • Add UsbHsFsUtilsScopedRecursiveLock struct.
      • Add usbHsFsUtilsAlignedAlloc().
      • Rename usbHsFsUtilsLockScope() to usbHsFsUtilsAcquireScopedLock().
      • Rename usbHsFsUtilsUnlockScope() to usbHsFsUtilsReleaseScopedLock().
      • Add usbHsFsUtilsAcquireScopedRecursiveLock().
      • Add usbHsFsUtilsReleaseScopedRecursiveLock().

v0.2.9

  • lib:
    • Implement a callback-based population system, which can be used as an alternative to the event-based system that has been available up until now. For more information, please read the How to use section from the README.
    • Add a reimplementation of libnx's usbHsEpPostBuffer(), called usbHsFsRequestEndpointDataXfer(), which calls usbHsEpPostBufferAsync() with a hardcoded timeout value of 10 seconds (using the USB_POSTBUFFER_TIMEOUT define).
    • Port log handler QoL improvements from nxdumptool.
    • Log result codes in unpadded hexadecimal notation.
    • Reorganize UsbHsFsMountFlags enum.
    • SCSI INQUIRY strings now have prevalence over USB device descriptor strings, which affects the manufacturer, product_name and serial_number strings from UsbHsFsDevice elements.
    • Add LIB_ASSERT macro and update all static assertions throughout the codebase to use it.
    • Use NX_IGNORE_ARG macro where needed throughout the codebase.
    • SCSI driver:
      • Reorganize structs and enums.
      • Add missing comments/references.
      • Add ScsiInquiryVitalProductDataPageCode enum and rework usbHsFsScsiSendInquiryCommand() to make it possible to request Vital Product Data pages from attached LUNs.
      • Update ScsiInquiryStandardData struct to also retrieve serial number data from attached LUNs.
      • Add ScsiInquiryUnitSerialNumberPageHeader struct.
      • Update usbHsFsScsiStartDriveLogicalUnit() to make it read serial number information from the Unit Serial Number VPD page. Fallbacks to the serial number returned by the standard SCSI Inquiry command if not available.
      • Overhaul usbHsFsScsiTransferCommand() to make it handle both unexpected CSWs and CSW data residue values in a better way.
    • fs-libs: remove all build scripts for both NTFS-3G and lwext4, as well as the fs-libs Makefile target. Please use the now available devkitPro pacman packages switch-ntfs-3g and switch-lwext4. The How to install section of the README has been updated to reflect this change.
    • fat: calls to ftruncate() on FAT filesystems now restore the current file position after truncation.
  • P.S.: remember to remove previous installations of NTFS-3G and lwext4 *before* installing the official devkitPro pacman packages by running:
    • sudo (dkp-)pacman -R switch-libntfs-3g switch-lwext4

v0.2.8

  • lib: add usbHsFsGetPhysicalDeviceCount(), which returns the number of physical UMS devices currently connected to the console with at least one underlying filesystem mounted as a virtual device.
  • fs-libs:
    • Update FatFs to R0.15 w/patch2.
      • Furthermore, FatFs is now modified to check a runtime read-only flag for any mounted filesystems, making it possible to use the UsbHsFsMountFlags_ReadOnly mount flag on FAT volumes for write-free access.
    • Update NTFS-3G to 2022.10.3.
    • Update lwext4 to 58bcf89a121b72d4fb66334f1693d3b30e4cb9c5 with cherrypicked patches.
    • Improve Makefile scripts for both NTFS-3G and lwext4 by checking if makepkg and (dkp-)pacman binaries are actually available, as well as automatically removing pkg-config if its available and installing dkp-toolchain-vars as part of the required dependencies.

v0.2.7

v0.2.6

  • Updated codebase to use localtime_r() instead of localtime() to avoid possible race conditions with other threads.
  • Fixed fs-libs building under Linux distros with pacman. Thanks to ITotalJustice for reporting this issue!
  • Implemented support for UMS devices that don't byteswap the Command Status Wrapper signature before sending back SCSI command responses. Thanks to rdmrocha for reporting this issue!

v0.2.5

  • Updated lwext4 patch to fix mountpoint corruption issues if a mountpoint name is reused after a previous call to ext4_mount failed.
    • This fixes a data abort discovered by phisch. Thanks for the report!
    • The fix is based on HenriChataing's pull request in lwext4's repository, but also adds an additional memset call to ext4_umount to fully clear every unmounted mountpoint.
    • A note to all developers using the GPL-licensed version of the library: update the switch-lwext4 package by running make fs-libs in your libusbhsfs clone before building your project.

v0.2.4

  • Updated FatFs to R0.14b.
  • The backup GPT header from a drive is now retrieved and used if the main GPT header is corrupted, as long as it's available.
  • Slightly improved debug logging code.
  • Rewrote mutex handling throughout the code to use a small, macro-based scoped lock implementation whenever possible.
  • Removed superfluous memory operations by using dynamic pointer arrays to manage logical unit / filesystem contexts.
  • Added missing splInitialize / splExit calls while checking if a service is running.
    • Furthermore, the Exosphère API version, which is used to determine if TIPC serialization is needed instead of CMIF, is now saved during the first service check.

v0.2.3

  • Improvements to the USB manager:
    • Refactored USB control request functions to work with libnx USB datatypes instead of drive / logical unit contexts.
    • Implemented GET_DESCRIPTOR control requests for configuration and string descriptors.
  • Improvements to the BOT driver:
    • If usbHsEpPostBuffer() fails, only the endpoint the library is currently working with will be cleared. Furthermore, the result from this operation no longer affects the return code.
    • If usbHsFsRequestPostBuffer() fails, the library now tries to retrieve a CSW right away - if it succeeds, a Request Sense command will be issued immediately to the block device.
    • Mode Sense (6) / Mode Sense (10) command success is no longer mandatory in usbHsFsScsiStartDriveLogicalUnit().
    • SPC standard version is now validated.
  • Improvements to the PKGBUILD scripts for NTFS-3G and lwext4:
    • Made it possible to build and install all three libraries using the Makefile - for more information, please refer to the How to install section from the README.
    • Proper library path is now forced while building NTFS-3G. Fixes issues in some Linux systems. Thanks to sigmaboy for the correction.
    • Other minor improvements.
  • Library API changes:
    • Added vid and pid fields to UsbHsFsDevice. Useful if the application needs to implement a device filter on its own.
    • vendor_id, product_id and product_revision fields in UsbHsFsDevice have been replaced with manufacturer, product_name and serial_number fields, which represent UTF-8 conversions of string descriptors referenced by the USB device descriptor.
      • Strings from SCP INQUIRY data are still used as a fallback method for manufacturer and product_name fields if the USB device descriptor holds no references to string descriptors.
  • Miscellaneous changes:
    • Renamed ff_rename() from FatFs to avoid issues fix conflicts in applications linked against FFmpeg. Thanks to Cpasjuste for letting us know.
    • The has_journal flag from the superblock in EXT filesystems is now verified before calling journal-related functions.
    • EXT filesystem version is now retrieved only once, while mounting the volume.
    • The AtmosphereHasService sm API extension available in Atmosphère and Atmosphère-based CFWs is now being used to check if a specific service is running.
      • HOS 12.0.x / AMS 0.19.x support is provided by using TIPC serialization to dispatch the IPC request, if needed.
    • Improved logfile code and simplified binary data logging throughout the codebase.
  • Changes under the hood (currently unused, but may change in the future):
    • Implemented SYNCHRONIZE CACHE (10) and SYNCHRONIZE CACHE (16) SCP commands.
    • Modified drive and logical unit contexts to prepare for UASP support.
    • Added extra code to handle USB Attached SCSI Protocol (UASP) interface descriptors under both USB 2.0 and 3.0 modes.

v0.2.2

  • By popular demand, the NTFS journal is now rebuilt by default for NTFS volumes that have not been properly unmounted, which lets the library mount them right away without having to use a Windows PC. Please bear in mind this process may cause inconsistencies - always try to safely remove your storage devices.
    • Nonetheless, this should be a relatively safe operation - default behaviour in NTFS-3G changed some years ago.
    • This change also affects EXT volume mounting. The EXT journal will now always try be recovered - if the process fails, the EXT volume won't be mounted.

v0.2.1

  • Bugfix: mount name IDs are now properly freed while destroying filesystem contexts.
  • Library API: added a helper preprocessor macro to generate strings based on the supported filesystem type values.
  • Makefile: branch name is now retrieved using rev-parse instead of symbolic-ref. Fixes ref HEAD is not a symbolic ref errors while building the library when the repository is used as a git submodule.

v0.2.0

  • Built using libnx v4.0.0.
  • Implemented EXT2/3/4 support (GPL build only).
    • This means applications using the GPL build of the library must now be linked against libusbhsfs, NTFS-3G and lwext4. Please read the How to build section from the README to know how to build both NTFS-3G and lwext4 and install them into the portlibs directory from devkitPro.
    • Certain limitations apply. Please read the Limitations section from the README for more information.
  • Dot directory entries "." and ".." are now filtered in NTFS volumes. They are no longer displayed as part of the output from readdir().
  • Minor code cleanup.
  • The example test application is now linked against lwext4 as well.

v0.1.0

  • Built using libnx commit c51918a.
  • Implemented partition table parsing (MBR/GPT/VBR). The library now takes care of looking for boot sectors and/or partition tables on its own, and just passes volume LBAs to filesystem libraries. This makes it possible to mount multiple partitions from the same logical unit as individual devoptab devices.
  • Implemented NTFS support. Big thanks to Rhys Koedijk!
    • You must link your application against both libusbhsfs and NTFS-3G if you wish to use NTFS support. Please read the How to build section from the README to know how to build NTFS-3G and install it into the portlibs directory from devkitPro.
    • Certain limitations apply. Please read the Limitations section from the README for more information.
    • Dual licensing (ISC / GPLv2+) is now provided as a way to allow projects that don't comply with the GPLv2+ license from NTFS-3G to keep using libusbhsfs, albeit with FAT support only. Please read the Licensing section from the readme for more information.
  • Improved safety checks in all internal devoptab functions.
  • Library API:
    • usbHsFsUnmountDevice() is now provided as a way to manually/safely unmount UMS devices at runtime before disconnecting them.
      • This has been always been automatically handled by usbHsFsExit() if there are any mounted UMS devices when the library interface is closed. So, depending on what you need, you should only call usbHsFsUnmountDevice() when absolutely necessary.
    • usbHsFsGetFileSystemMountFlags() and usbHsFsSetFileSystemMountFlags() are now provided as a way to get/set filesystem mount flags.
      • Please read include/usbhsfs.h for more information about these flags and what they do.
      • These flags only affect NTFS volume mounting at this moment, so they have no effect under ISC licensed builds of the library.
      • Furthermore, these functions have no effect at all under SX OS.
  • BOT driver:
    • Inquiry SCSI command is now retried if an unexpected CSW with no sense data is received.
    • Both peripheral qualifier and peripheral device type values from Inquiry data are now filtered. Thanks to ginkuji for reporting this issue.
    • Logical unit startup now returns right away if an optional SCSI command fails and a Medium Not Present additional sense code is reported by the UMS device.
    • A bus reset is now performed on all UMS devices that are already available when usbHsFsInitialize() is called. Fixes logical unit startup for drives that were stopped during a previous session, but not removed from the console. Thanks to FlyingBananaTree for reporting this issue.
    • Fixed potential memory corruption issues that could have taken place due to not updating LUN/FS context references after reallocating their buffers.
  • Debug build:
    • Implemented proper caching into debug logging code, making debug builds a lot faster now.
    • The logfile is now flushed each time a public API function that generates log messages is called.
  • SX OS:
    • The status change user-mode event is now signaled on every usbfs status change.
  • Example test application:
    • Updated to reflect all these changes.
    • Added more filesystem tests.
    • Rewrote input handling to match the new pad API from libnx.
    • Now using usbHsFsUnmountDevice() to safely unmount any UMS devices that have already been tested.

v0.0.3

  • Added support for a custom event index passed to usbHsFsInitialize(), which is internally used with usbHsCreateInterfaceAvailableEvent() / usbHsDestroyInterfaceAvailableEvent(). Developers listening for other specific USB interfaces on their own should no longer have issues with the library.
  • Added fsp-usb check. usbHsFsInitialize() will now fail on purpose if fsp-usb is running in the background.
  • Renamed FatFs library functions to avoid linking errors in homebrew apps that already depend on it.
  • Fixed FatFs warnings when building the library with -O3. Thanks to ITotalJustice!
  • Changes to relative path support:
    • Modified FatFs to remove all references to ff_chdrive(), ff_chdir(), ff_getcwd() and FF_FS_RPATH. We take care of handling the current working directory and only pass absolute paths to FatFs. The code to resolve paths with dot entries wasn't removed.
    • ffdev_chdir() now just opens the directory from the provided path to make sure it exists, then closes it immediately.
    • The default devoptab device is now set by the chdir() function from devoptab interfaces, using usbHsFsMountSetDefaultDevoptabDevice(). This means it's effectively possible to change the current directory and the default devoptab device in one go, just by calling chdir() with an absolute path (e.g. chdir("ums0:/")).
    • It's possible to chdir() back to the SD card to change the default devoptab device (e.g. chdir("sdmc:/)).
    • If the UMS device that holds the volume set as the default devoptab device is removed from the console, the SD card will be set as the new default devoptab device.
    • Removed usbHsFsSetDefaultDevice(), usbHsFsGetDefaultDevice() and usbHsFsUnsetDefaultDevice() - just use chdir() now.
    • Limitations regarding fsdevMount*() calls from libnx still apply. Can't do anything about it.
    • Please read the Relative path support section from the README for more information.
  • BOT driver:
    • Added support for unexpected CSWs received through an input endpoint during data transfer stages. Thanks to duckbill007 for reporting this issue!
    • Always issue a Request Sense command if an unexpected CSW is received.
    • Make sure write protection is disabled before issuing any SCP WRITE commands.
    • Reduced wait time if a "Not Ready" sense key is received after issuing a Request Sense command.
  • Added support for the usbfs service from SX OS. Thanks to blawar for providing the updated usbfs service calls!
    • Please read the Limitations section from the README for more information.
  • Updated test application to reflect all these changes.
    • It is now also capable of performing a test file copy to the UMS filesystem if test.file is available at the SD card root directory.

v0.0.2

  • Relicensed library under the ISC License. We really want you people to adopt it and freely use it in your projects.
  • Fixed distribution package version string generation in Makefile.
  • LICENSE.md and README.md are stored in the generated distribution packages.
  • Added support for relative paths.
    • Please read the Relative path support section from the README for more information.
  • A trailing colon is now added to the returned mount names from UsbHsFsDevice elements.
  • Fixed devoptab device unregistration.
  • Bulk-Only Transport (BOT) driver:
    • usbHsFsRequestGetMaxLogicalUnits() now clears the STALL status from both endpoints on its own if it fails.
    • Likewise, usbHsFsRequestPostBuffer() now attempts to clear the STALL status from both endpoints if it fails.
  • FatFs devoptab interface:
    • Fixed error code translations for some FatFs errors.
    • Created an unified ffdev_fill_stat() function for both ffdev_stat() and ffdev_dirnext().
    • Fixed POSIX timestamp conversions from DOS timestamps.
  • Debug build:
    • Debug messages from usbHsFsScsiReadLogicalUnitBlocks() and usbHsFsScsiReadLogicalUnitBlocks() now include the total number of bytes to transfer per each loop iteration.
    • Added debug messages to the FatFs devoptab interface.

v0.0.1

  • Initial release. Only capable of mounting one FAT filesystem per logical unit from each connected UMS device.

Credits

  • DarkMatterCore: UMS device LUN/FS management, Bulk-Only Transport (BOT) driver, library interface, FAT support, EXT support.
  • XorTroll: FS mounting system, devoptab device (un)registration, example test application.
  • Rhys Koedijk: NTFS support.
  • Lots of SPC/BOT docs across the Internet - these have been referenced in multiple files from the codebase.

Thanks to:

  • ChaN, for the FatFs module.
  • Tuxera and NTFS-3G contributors, for the NTFS-3G library.
  • Grzegorz Kostka and lwext4 contributors, for the lwext4 library.
  • Switchbrew and libnx contributors. Code from libnx was used for devoptab device management and path handling.
  • blawar, for providing the updated usbfs SX OS service calls.
  • Whovian9369. I literally would have dropped Switch homebrew development altogether some months ago, if not for you. Thanks, mate.
  • ITotalJustice, for testing the partition table parsing algorithm.
  • FennecTECH, for breaking stuff on a regular basis.
  • All the Alpha Testers and Super Users from the nxdumptool Discord server, for being a constant source of ideas (and memes).

External links

Advertising: