mirror of
https://github.com/drakmor/ShadowMountPlus.git
synced 2026-10-19 21:29:58 -05:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
851c269647 | ||
|
|
c9b3415048 | ||
|
|
11b32a97cf | ||
|
|
a43401391d | ||
|
|
0f7bc24928 | ||
|
|
1db534cf82 | ||
|
|
3f81ae589f | ||
|
|
32ae0c9c50 | ||
|
|
5564b4396d | ||
|
|
abe6bbb92b | ||
|
|
896e5af0fd | ||
|
|
15776edb8b | ||
|
|
1bc6477ea7 | ||
|
|
eb2a4c1036 |
No files matched your search
@@ -1,21 +1,22 @@
|
||||
PS5_PAYLOAD_SDK ?= /opt/ps5-payload-sdk
|
||||
include $(PS5_PAYLOAD_SDK)/toolchain/prospero.mk
|
||||
|
||||
# Standard Flags (No extra libraries)
|
||||
PS5_PAYLOAD_SDK ?= /opt/ps5-payload-sdk
|
||||
include $(PS5_PAYLOAD_SDK)/toolchain/prospero.mk
|
||||
|
||||
# Standard Flags (No extra libraries)
|
||||
CFLAGS := -O2 -Wall -D_BSD_SOURCE -std=gnu11 -Isrc
|
||||
|
||||
# Linker
|
||||
LDFLAGS :=
|
||||
|
||||
# Standard Libraries Only
|
||||
|
||||
# Standard Libraries Only
|
||||
LIBS := -lkernel_sys -lSceSystemService -lSceUserService -lSceAppInstUtil -lsqlite3
|
||||
|
||||
# Targets
|
||||
all: shadowmountplus.elf
|
||||
|
||||
# Build Daemon
|
||||
shadowmountplus.elf: src/main.c
|
||||
$(CC) $(CFLAGS) $(LDFLAGS) -o $@ $< $(LIBS)
|
||||
|
||||
clean:
|
||||
|
||||
# Targets
|
||||
all: shadowmountplus.elf
|
||||
|
||||
# Build Daemon
|
||||
shadowmountplus.elf: src/main.c
|
||||
$(CC) $(CFLAGS) $(LDFLAGS) -o $@ $< $(LIBS)
|
||||
$(PS5_PAYLOAD_SDK)/bin/prospero-strip --strip-debug $@
|
||||
|
||||
clean:
|
||||
rm -f shadowmountplus.elf kill.elf src/*.o
|
||||
+16
-35
@@ -3,7 +3,7 @@
|
||||
PURPOSE
|
||||
-------
|
||||
Create a RAW image file, mount it via OSFMount as a logical volume,
|
||||
auto-select FAT32/exFAT by image size, and either:
|
||||
format it as exFAT, and either:
|
||||
- format + copy + dismount (default), or
|
||||
- create + mount only for manual steps.
|
||||
|
||||
@@ -45,11 +45,10 @@
|
||||
NOTES
|
||||
-----
|
||||
- This script does NOT auto-elevate. Start PowerShell as Administrator.
|
||||
- FS selection is automatic by image size:
|
||||
* < 4 GB -> FAT32, cluster 65536
|
||||
* >= 4 GB -> exFAT, cluster auto-selected:
|
||||
- large-file sets: 65536
|
||||
- small/mixed-file sets: 32768
|
||||
- Filesystem is always exFAT.
|
||||
- Cluster size is auto-selected:
|
||||
- large-file sets: 65536
|
||||
- small/mixed-file sets: 32768
|
||||
#>
|
||||
|
||||
[CmdletBinding()]
|
||||
@@ -89,9 +88,9 @@ function Find-OSFMountCom {
|
||||
if ($cmd) { return $cmd.Source }
|
||||
|
||||
$candidates = @(
|
||||
"$env:ProgramFiles\OSFMount\osfmount.com",
|
||||
"${env:ProgramFiles}\OSFMount\osfmount.com",
|
||||
"${env:ProgramFiles(x86)}\OSFMount\osfmount.com",
|
||||
"$env:ProgramFiles\PassMark\OSFMount\osfmount.com",
|
||||
"${env:ProgramFiles}\PassMark\OSFMount\osfmount.com",
|
||||
"${env:ProgramFiles(x86)}\PassMark\OSFMount\osfmount.com"
|
||||
) | Where-Object { $_ -and (Test-Path $_) }
|
||||
|
||||
@@ -245,11 +244,9 @@ function Dismount-OsfVolume([string]$osfPath, [string]$mountPoint, [int]$maxAtte
|
||||
return $false
|
||||
}
|
||||
|
||||
function Invoke-FormatVolume([string]$driveLetter, [string]$fileSystem, [int]$clusterSize, [string]$label) {
|
||||
function Invoke-FormatVolume([string]$driveLetter, [int]$clusterSize, [string]$label) {
|
||||
$target = "${driveLetter}:"
|
||||
if ($fileSystem -notin @("FAT32", "exFAT")) {
|
||||
throw "Unsupported file system '$fileSystem'. Expected FAT32 or exFAT."
|
||||
}
|
||||
$fileSystem = "exFAT"
|
||||
$clusterArg = Format-AllocationUnitArg -clusterSize $clusterSize
|
||||
$attempts = @(
|
||||
@{ Name = "$fileSystem quick with requested allocation unit"; Args = @($target, "/FS:$fileSystem", "/A:$clusterArg", "/Q", "/V:$label", "/X", "/Y") }
|
||||
@@ -311,40 +308,23 @@ if (Test-Path $ImagePath) {
|
||||
|
||||
[Int64]$expectedBytes = 0
|
||||
[string]$osfSizeArg = $null
|
||||
[Int64]$FsSwitchThresholdBytes = 4GB
|
||||
[int]$Fat32ClusterSize = 65536
|
||||
[int]$ExfatClusterSize = 65536
|
||||
[int]$ExfatClusterSize = Get-OptimalExfatClusterSize -dir $SourceDir
|
||||
[bool]$sizeProvided = -not [string]::IsNullOrWhiteSpace($Size)
|
||||
[string]$TargetFs = ""
|
||||
[int]$TargetClusterSize = 0
|
||||
[int]$TargetClusterSize = $ExfatClusterSize
|
||||
|
||||
if (-not $sizeProvided) {
|
||||
Write-Host "[Info] Size not provided. Computing an optimal image size from '$SourceDir'..."
|
||||
$fat32Candidate = Get-OptimalImageSizeBytes -dir $SourceDir -clusterBytes $Fat32ClusterSize
|
||||
if ($fat32Candidate -lt $FsSwitchThresholdBytes) {
|
||||
$expectedBytes = $fat32Candidate
|
||||
} else {
|
||||
$ExfatClusterSize = Get-OptimalExfatClusterSize -dir $SourceDir
|
||||
$expectedBytes = Get-OptimalImageSizeBytes -dir $SourceDir -clusterBytes $ExfatClusterSize
|
||||
}
|
||||
$expectedBytes = Get-OptimalImageSizeBytes -dir $SourceDir -clusterBytes $TargetClusterSize
|
||||
$osfSizeArg = "$expectedBytes"
|
||||
} else {
|
||||
$expectedBytes = Parse-SizeToBytes $Size
|
||||
$osfSizeArg = $Size
|
||||
}
|
||||
|
||||
if ($expectedBytes -lt $FsSwitchThresholdBytes) {
|
||||
$TargetFs = "FAT32"
|
||||
$TargetClusterSize = $Fat32ClusterSize
|
||||
} else {
|
||||
$TargetFs = "exFAT"
|
||||
$ExfatClusterSize = Get-OptimalExfatClusterSize -dir $SourceDir
|
||||
$TargetClusterSize = $ExfatClusterSize
|
||||
}
|
||||
if (-not $sizeProvided) {
|
||||
Write-Host "[Info] Computed image size: $(Format-Bytes $expectedBytes) ($expectedBytes bytes)."
|
||||
}
|
||||
Write-Host "[Info] Selected filesystem: $TargetFs (cluster=$TargetClusterSize) for image size $(Format-Bytes $expectedBytes)."
|
||||
Write-Host "[Info] Selected filesystem: exFAT (cluster=$TargetClusterSize) for image size $(Format-Bytes $expectedBytes)."
|
||||
|
||||
$osf = Find-OSFMountCom
|
||||
|
||||
@@ -380,8 +360,8 @@ try {
|
||||
return
|
||||
}
|
||||
|
||||
Write-Host "[2/4] Formatting $dest as $TargetFs (cluster=$TargetClusterSize, label='$Label') via format.com ..."
|
||||
Invoke-FormatVolume -driveLetter $DriveLetter -fileSystem $TargetFs -clusterSize $TargetClusterSize -label $Label
|
||||
Write-Host "[2/4] Formatting $dest as exFAT (cluster=$TargetClusterSize, label='$Label') via format.com ..."
|
||||
Invoke-FormatVolume -driveLetter $DriveLetter -clusterSize $TargetClusterSize -label $Label
|
||||
|
||||
if (-not (Test-Path $dest)) { throw "Drive $dest is not accessible after formatting." }
|
||||
|
||||
@@ -390,6 +370,7 @@ try {
|
||||
$SourceDir, $dest,
|
||||
"/E", "/COPY:DAT", "/DCOPY:DAT",
|
||||
"/R:1", "/W:1",
|
||||
"/NFL", "/NDL",
|
||||
"/ETA"
|
||||
)
|
||||
& robocopy.exe @roboArgs
|
||||
|
||||
@@ -1,9 +1,11 @@
|
||||
# ShadowMountPlus (PS5)
|
||||
|
||||
**Version:** `1.5beta3`
|
||||
**Version:** `1.6beta1`
|
||||
|
||||
**Repository:** https://github.com/drakmor/shadowMountPlus
|
||||
|
||||
**Warning! Mounting images can cause shutdown problems and data corruption on internal drives! This depends on many factors, but is more common with older firmware versions. Please take this into account when testing.**
|
||||
|
||||
|
||||
**ShadowMountPlus** is a fully automated, background "Auto-Mounter" payload for Jailbroken PlayStation 5 consoles. It streamlines the game mounting process by eliminating the need for manual configuration or external tools (such as DumpRunner or Itemzflow). ShadowMountPlus automatically detects, mounts, and installs game dumps from both **internal and external storage**.
|
||||
|
||||
@@ -17,19 +19,19 @@
|
||||
|
||||
| Extension | Mounted FS | Attach backend | Status |
|
||||
| --- | --- | --- | --- |
|
||||
| `.exfat` | `exfatfs` | `LVD` or `MD` (configurable) | Stable |
|
||||
| `.ffpkg` | `ufs` | `LVD` or `MD` (configurable) | High performance |
|
||||
| `.exfat` | `exfatfs` | `LVD` or `MD` (configurable) | Optimal |
|
||||
| `.ffpkg` | `ufs` | `LVD` or `MD` (configurable) | Legacy |
|
||||
| `.ffpfs` | `pfs` | `LVD` | Experimental |
|
||||
|
||||
Notes:
|
||||
- Backend, read-only mode, and sector size can be configured via `/data/shadowmount/config.ini`.
|
||||
- Debug logging is enabled by default (`debug=1`) and writes to console plus `/data/shadowmount/debug.log` (set `debug=0` to disable).
|
||||
- **On 4.xx firmware, shutting down the console may not work correctly when using image files.**
|
||||
- **exFAT is the preferred image filesystem, including on 4.xx firmware, with no known reboot/shutdown issues in typical use.**
|
||||
|
||||
## Recommended FS choice
|
||||
|
||||
- Prefer **UFS (`.ffpkg`)** for games that work correctly on UFS: it is generally more performant (~1.5-2.5 x exFAT).
|
||||
- Use **exFAT (`.exfat`)** for games that only work from external-disk style layouts, because exFAT is case-insensitive.
|
||||
- Prefer **exFAT (`.exfat`)** in most cases: it is generally more performant, case-insensitive, and does not have reboot/shutdown issues in typical use.
|
||||
- Use **UFS (`.ffpkg`)** only when specifically needed for compatibility with your game/setup.
|
||||
|
||||
## Runtime config (`/data/shadowmount/config.ini`)
|
||||
|
||||
@@ -38,7 +40,13 @@ This file is optional. If it does not exist, built-in defaults are used.
|
||||
Supported keys (all optional):
|
||||
- `debug=1|0` (`1` enables `log_debug` output to console + `/data/shadowmount/debug.log`; default is `1`)
|
||||
- `mount_read_only=1|0` (default: `1`)
|
||||
- `force_mount=1|0` (mounting even damaged file systems; default: `0`)
|
||||
- `image_ro=<image_filename>` (repeatable; force read-only mode for this image filename)
|
||||
- `image_rw=<image_filename>` (repeatable; force read-write mode for this image filename)
|
||||
- `recursive_scan=1|0` (`0` = scan only first-level subfolders, `1` = recursive scan without depth limit; default: `0`)
|
||||
- `backports_path=<absolute_path>` (default: `/data/backports`; if `<backports_path>/<TITLE_ID>` exists, it is overlaid on mounted image via `unionfs`)
|
||||
- `scan_interval_seconds=<1..3600>` (full scan loop interval; default: `10`)
|
||||
- `stability_wait_seconds=<0..3600>` (minimum source age before processing; default: `10`)
|
||||
- `exfat_backend=lvd|md` (default: `lvd`)
|
||||
- `ufs_backend=lvd|md` (default: `lvd`)
|
||||
- `scanpath=<absolute_path>` (can be repeated on multiple lines; default: built-in scan path list below)
|
||||
@@ -48,12 +56,30 @@ Supported keys (all optional):
|
||||
- `md_exfat_sector_size=<value>` (default: `512`)
|
||||
- `md_ufs_sector_size=<value>` (default: `512`)
|
||||
|
||||
Per-image mode override behavior:
|
||||
- Match is done by image file name (without path).
|
||||
- File names with spaces are supported.
|
||||
- If multiple rules target the same file name, the last one in config wins.
|
||||
- If no rule matches, global `mount_read_only` is used.
|
||||
- Example:
|
||||
```ini
|
||||
mount_read_only=1
|
||||
image_rw=PPSA1234-my-image.ffpfs
|
||||
image_rw=MYGame 123.exfat
|
||||
image_ro=legacy_dump.ffpkg
|
||||
```
|
||||
|
||||
Scan path behavior:
|
||||
- If at least one `scanpath=...` is present, only those custom paths are used.
|
||||
- `/data/ufsmnt` is always added automatically, even with custom paths.
|
||||
- `/data/imgmnt/{ufsmnt,exfatmnt,pfsmnt}` are always added automatically, even with custom paths.
|
||||
- With `recursive_scan=0` (default), only first-level subfolders are checked.
|
||||
- With `recursive_scan=1`, subfolders are scanned recursively.
|
||||
- Full scan loop runs every 10 seconds.
|
||||
- Full scan loop runs every `scan_interval_seconds` (default: `10`).
|
||||
- Sources newer than `stability_wait_seconds` are deferred until stable (default: `10`).
|
||||
|
||||
Backport overlay behavior:
|
||||
- If `${backports_path}/${TITLE_ID}` exists, ShadowMount+ mounts it over the game root with `unionfs`.
|
||||
- Files from backport folder override files from the mounted image.
|
||||
|
||||
Validation:
|
||||
- See `config.ini.example` for a ready-to-use template.
|
||||
@@ -62,7 +88,9 @@ Validation:
|
||||
|
||||
Image mountpoints are created under:
|
||||
|
||||
`/data/ufsmnt/<image_name>-<fs_suffix>`
|
||||
`/data/imgmnt/<fs>/<image_name>`
|
||||
|
||||
Where `<fs>` is one of: `ufsmnt`, `exfatmnt`, `pfsmnt`.
|
||||
|
||||
Image layout requirement (`.ffpkg`, `.exfat`, `.ffpfs`):
|
||||
- Game files must be placed at the image root.
|
||||
@@ -84,7 +112,7 @@ Default scan locations:
|
||||
- `/mnt/usb0` .. `/mnt/usb7`
|
||||
- `/mnt/ext0`
|
||||
- `/mnt/ext1`
|
||||
- `/data/ufsmnt` (mounted image content scan)
|
||||
- `/data/imgmnt/ufsmnt`, `/data/imgmnt/exfatmnt`, `/data/imgmnt/pfsmnt` (mounted image content scan)
|
||||
|
||||
You can override scan roots with `scanpath=...` entries in `/data/shadowmount/config.ini`.
|
||||
|
||||
@@ -148,7 +176,9 @@ FreeBSD:
|
||||
|
||||
Windows:
|
||||
- You can create UFS2 images with **UFS2Tool** https://github.com/SvenGDK/UFS2Tool.
|
||||
- Recommended output format for this project is `.ffpkg`.
|
||||
- Example:
|
||||
- `UFS2Tool.exe newfs -O 2 -b 32768 -f 4096 -m 0 -i 262144 -D ./APPXXXX ./PPSA12345.ffpkg`
|
||||
|
||||
|
||||
## Installation and usage
|
||||
|
||||
@@ -167,11 +197,13 @@ Add ShadowMountPlus to your `autoload.txt` for **plk-autoloader** to ensure it s
|
||||
**Sample Configuration:**
|
||||
```ini
|
||||
!1000
|
||||
kstuff.elf
|
||||
!1000
|
||||
notify.elf ; Optional - Remove this line if you do not want Rich Toasts
|
||||
!1000
|
||||
shadowmountplus.elf
|
||||
!3000
|
||||
ps5-backpork.elf
|
||||
!1000
|
||||
kstuff.elf
|
||||
```
|
||||
|
||||
---
|
||||
@@ -183,14 +215,15 @@ If a game is not mounted:
|
||||
- Check `/data/shadowmount/debug.log` and system notifications from ShadowMount+.
|
||||
- Verify scan roots:
|
||||
- if `scanpath=...` is set, only these paths are scanned;
|
||||
- `/data/ufsmnt` is always scanned.
|
||||
- `/data/imgmnt/{ufsmnt,exfatmnt,pfsmnt}` are always scanned.
|
||||
- Verify scan depth:
|
||||
- `recursive_scan=0` scans only first-level subfolders;
|
||||
- `recursive_scan=1` scans recursively.
|
||||
- If logs show `source not stable yet`, adjust `stability_wait_seconds` (or wait for source copy/write to finish).
|
||||
- Verify game structure:
|
||||
- folder game: `<GAME_DIR>/sce_sys/param.json`;
|
||||
- image game (`.ffpkg` / `.exfat` / `.ffpfs`): `sce_sys/param.json` must be at image root (no extra top-level folder).
|
||||
- If you see `missing/invalid param.json` for an image, check via FTP that `/data/ufsmnt/<TITLE_ID>/` contains full game files and `sce_sys/param.json`.
|
||||
- If you see `missing/invalid param.json` for an image, check via FTP that files are present under `/data/imgmnt/<fs>/<image_name>/` and include `sce_sys/param.json`.
|
||||
- If you see image mount failure, check image integrity and filesystem type (`.ffpkg`=UFS, `.exfat`=exFAT, `.ffpfs`=PFS).
|
||||
- If you see duplicate titleId notification, keep only one source per `<TITLE_ID>`.
|
||||
|
||||
|
||||
+23
-1
@@ -14,11 +14,33 @@ debug=1
|
||||
# 0/false/no/off/rw -> read-write mounts
|
||||
mount_read_only=1
|
||||
|
||||
# Mounting even damaged file systems
|
||||
# 1/true/yes/on -> include force option
|
||||
# 0/false/no/off -> default mount options (default)
|
||||
force_mount=0
|
||||
|
||||
# Per-image mount mode override by file name (can be repeated many times):
|
||||
# image_ro=<image_filename>
|
||||
# image_rw=<image_filename>
|
||||
# image_ro=PPSA12345.ffpfs
|
||||
# image_rw=My Game Dump.exfat
|
||||
|
||||
# Recursive scan mode:
|
||||
# 1/true/yes/on -> scan subdirectories recursively (no depth limit)
|
||||
# 0/false/no/off -> scan only first-level subdirectories (default)
|
||||
recursive_scan=0
|
||||
|
||||
# Optional backport overlay root:
|
||||
# If "<backports_path>/<TITLE_ID>" exists, it is mounted over image root via unionfs.
|
||||
backports_path=/data/backports
|
||||
|
||||
# Full scan loop interval (seconds), range: 1..3600
|
||||
scan_interval_seconds=10
|
||||
|
||||
# Source stabilization wait window (seconds), range: 0..3600
|
||||
# If source mtime is newer than this window, it will be deferred to next scan.
|
||||
stability_wait_seconds=10
|
||||
|
||||
# Backend selection per filesystem:
|
||||
# lvd -> /dev/lvdctl -> /dev/lvdN
|
||||
# md -> /dev/mdctl -> /dev/mdN
|
||||
@@ -34,6 +56,6 @@ ufs_backend=lvd
|
||||
|
||||
# Optional custom scan roots (can be repeated):
|
||||
# If at least one scanpath=... is present, only these paths are used.
|
||||
# "/data/ufsmnt" is always added automatically.
|
||||
# "/data/imgmnt/{ufsmnt,exfatmnt,pfsmnt}" are always added automatically.
|
||||
# scanpath=/data/homebrew
|
||||
# scanpath=/data/etaHEN/games
|
||||
+1063
-523
File diff suppressed because it is too large.
Load diff
Reference in new issue
Block a user