From 889b790afdf7d6b52c90ba6e972677dc207fc843 Mon Sep 17 00:00:00 2001 From: Maschell Date: Mon, 15 Apr 2019 19:39:32 +0200 Subject: [PATCH] Add support to access the original WUD if the input was compressed (WUX) or splitted (_partX.wud) --- README.md | 4 +- .../implementation/WUDToWUDContainer.java | 113 ++++++++++++++++++ .../fuse_wiiu/utils/FuseContainerWrapper.java | 6 +- 3 files changed, 121 insertions(+), 2 deletions(-) create mode 100644 src/main/java/de/mas/wiiu/jnus/fuse_wiiu/implementation/WUDToWUDContainer.java diff --git a/README.md b/README.md index 3052931..e01bc68 100644 --- a/README.md +++ b/README.md @@ -90,7 +90,7 @@ It's possible to use any directory as input, `fuse-wiiu` will scan will useable If a supported format is found and successfully mounted, a support starting with `[EMULATED] ` will be emulated, which will give you access to the files. The actual content and file layout may differ from format to format. ## Wii U disc images - WUD/WUX -Images of Wii U discs are saved `.wud` (or `.wux` if compressed). Every .wux or .wud will be emulated as two different directories (for image names `game.wux`). +Images of Wii U discs are saved `.wud` (or `.wux` if compressed, or `game_partX.wud` when dumped on FAT32). Every .wux or .wud will be emulated as up to three different directories (for image names `game.wux`). - [EMULATED] game.wux - This directory is the "normal" representation of a Wii U disc image. It'll have one subfolder for each partition. The `GM`-Partitions will be mounted and decrypted directly in the common `code, content and meta` format. The `SI` contain the ticket and tmd for `GM` partitions. All other partitions give you files in the "installable" format (tmd,app,tik). @@ -99,6 +99,8 @@ Images of Wii U discs are saved `.wud` (or `.wux` if compressed). Every .wux or - The `GM` partitions in the "installable" format. (Folders with the prefix `[ENCRYPTED] `) - Mounted and decrypted titles from all partitions. (Folder with the prefix `[DECRYPTED] [PARTITIONNAME]`) - This includes titles from the non-`GM` partitions (like updates), and installable titles from the decrypted `GM` partitions (titles from kiosk discs). +- [EMULATED] [WUD] game.wux (Only for WUX and splitted WUD) + - In this directory you can access Wii U disc image as the orginal WUD. Expected file layout: ``` diff --git a/src/main/java/de/mas/wiiu/jnus/fuse_wiiu/implementation/WUDToWUDContainer.java b/src/main/java/de/mas/wiiu/jnus/fuse_wiiu/implementation/WUDToWUDContainer.java new file mode 100644 index 0000000..939380f --- /dev/null +++ b/src/main/java/de/mas/wiiu/jnus/fuse_wiiu/implementation/WUDToWUDContainer.java @@ -0,0 +1,113 @@ +package de.mas.wiiu.jnus.fuse_wiiu.implementation; + +import java.io.File; +import java.io.IOException; +import java.util.Optional; + +import de.mas.wiiu.jnus.fuse_wiiu.interfaces.FuseContainer; +import de.mas.wiiu.jnus.fuse_wiiu.interfaces.FuseDirectory; +import de.mas.wiiu.jnus.fuse_wiiu.utils.WUDUtils; +import de.mas.wiiu.jnus.implementations.wud.WUDImage; +import de.mas.wiiu.jnus.implementations.wud.parser.WUDInfo; +import jnr.ffi.Pointer; +import ru.serce.jnrfuse.ErrorCodes; +import ru.serce.jnrfuse.FuseFillDir; +import ru.serce.jnrfuse.struct.FileStat; +import ru.serce.jnrfuse.struct.FuseFileInfo; + +public class WUDToWUDContainer implements FuseContainer { + private final String filename; + private final Optional wudInfo; + private final Optional parent; + + public WUDToWUDContainer(Optional parent, File c) { + this.wudInfo = WUDUtils.loadWUDInfo(c); + this.parent = parent; + this.filename = c.getName().replace("_part1.", ".").replace(".wux", ".wud"); + } + + @Override + public Optional getParent() { + return parent; + } + + @Override + public int getattr(String path, FileStat stat) { + if (path.equals("/")) { + stat.st_mode.set(FileStat.S_IFDIR | 0755); + stat.st_nlink.set(2); + return 0; + } + + if (path.equals("/" + filename)) { + if (stat != null) { + stat.st_mode.set(FileStat.S_IFREG | FileStat.ALL_READ); + stat.st_nlink.set(1); + stat.st_size.set(WUDImage.WUD_FILESIZE); + } + return 0; + } + + return -ErrorCodes.ENOENT(); + } + + @Override + public int open(String path, FuseFileInfo fi) { + if (path.equals("/")) { + return -ErrorCodes.EISDIR(); + } + return getattr(path, null); + } + + @Override + public int readdir(String path, Pointer buf, FuseFillDir filter, long offset, FuseFileInfo fi) { + filter.apply(buf, ".", null, 0); + if (getParent().isPresent()) { + filter.apply(buf, "..", null, 0); + } + + if (wudInfo.isPresent()) { + filter.apply(buf, filename, null, 0); + } + return 0; + } + + @Override + public int read(String path, Pointer buf, long size, long offset, FuseFileInfo fi) { + if (path.equals("/")) { + return -ErrorCodes.EISDIR(); + } + + if (!path.equals("/" + filename)) { + return -ErrorCodes.ENOENT(); + } + + if (offset >= WUDImage.WUD_FILESIZE) { + return -ErrorCodes.ENOENT(); + } + if (offset + size > WUDImage.WUD_FILESIZE) { + size = WUDImage.WUD_FILESIZE - offset; + } + + try { + byte[] data; + data = wudInfo.get().getWUDDiscReader().readEncryptedToByteArray(offset, 0, size); + buf.put(0, data, 0, data.length); + return data.length; + } catch (IOException e) { + e.printStackTrace(); + return -ErrorCodes.ENOENT(); + } + } + + @Override + public void init() { + // Not used + } + + @Override + public void deinit() { + // Not used + } + +} diff --git a/src/main/java/de/mas/wiiu/jnus/fuse_wiiu/utils/FuseContainerWrapper.java b/src/main/java/de/mas/wiiu/jnus/fuse_wiiu/utils/FuseContainerWrapper.java index 4008b6b..2c34a8a 100644 --- a/src/main/java/de/mas/wiiu/jnus/fuse_wiiu/utils/FuseContainerWrapper.java +++ b/src/main/java/de/mas/wiiu/jnus/fuse_wiiu/utils/FuseContainerWrapper.java @@ -10,6 +10,7 @@ import de.mas.wiiu.jnus.fuse_wiiu.implementation.LocalBackupNUSTitleContainer; import de.mas.wiiu.jnus.fuse_wiiu.implementation.LocalNUSTitleContainer; import de.mas.wiiu.jnus.fuse_wiiu.implementation.WUDFuseContainer; import de.mas.wiiu.jnus.fuse_wiiu.implementation.WUDMountedFuseContainer; +import de.mas.wiiu.jnus.fuse_wiiu.implementation.WUDToWUDContainer; import de.mas.wiiu.jnus.fuse_wiiu.interfaces.FuseContainer; import de.mas.wiiu.jnus.fuse_wiiu.interfaces.FuseDirectory; import de.mas.wiiu.jnus.implementations.wud.reader.WUDDiscReaderSplitted; @@ -59,7 +60,10 @@ public class FuseContainerWrapper { } result.put(prefix + c.getName(), new WUDFuseContainer(parent, c)); - result.put(prefix + "[EXTRA] " + c.getName(), new WUDMountedFuseContainer(parent, c)); + result.put(prefix + "[EXTRA] " + c.getName(), new WUDMountedFuseContainer(parent, c)); + if (c.getName().endsWith("part1.wud") || c.getName().endsWith(".wux")) { + result.put(prefix + "[WUD] " + c.getName(), new WUDToWUDContainer(parent, c)); + } return true; }