mirror of
https://github.com/Maschell/JWUPClient.git
synced 2024-11-24 17:06:51 +01:00
Added copy / copydir command. Added commandline command to dump the disc to sd
This commit is contained in:
parent
020f1e185a
commit
b676392315
25
README.md
25
README.md
@ -2,7 +2,7 @@ A port of smea's client (WUPClient.py) for the wupserver.
|
||||
|
||||
Open it with
|
||||
```
|
||||
java -jar jwupclient 192.168.x.x
|
||||
java -jar jwupclient.jar 192.168.x.x
|
||||
```
|
||||
|
||||
The following commands are supported (in my ulgy written shell).
|
||||
@ -35,6 +35,29 @@ arguments:
|
||||
-dst <destination folder on wiiu> (sets the destination folder on your PC)
|
||||
-fullpath (keeps the absolute path of the wiiu)
|
||||
|
||||
|
||||
###dumping a disc###
|
||||
Command to dump the whole disc (code, content and meta folder) to sd
|
||||
```
|
||||
dumpdisc
|
||||
```
|
||||
|
||||
The result will be stored on sd:/dumps/[TITLEID]
|
||||
|
||||
You can set a regular expression all files and dir will be checked to.
|
||||
*Examples*
|
||||
To dump only the code folder
|
||||
```
|
||||
dumpdisc -file /code/.*
|
||||
```
|
||||
|
||||
To disable the check on dir (and so check the pattern on ALL files of the disc) use the -deepSearch parameter
|
||||
|
||||
Example: to dump all .szs files
|
||||
```
|
||||
dumpdisc -file .*.szs -deepSearch
|
||||
```
|
||||
|
||||
Server and smea's client.
|
||||
https://github.com/smealum/iosuhax/tree/master/wupserver
|
||||
|
||||
|
BIN
jwupclient.jar
BIN
jwupclient.jar
Binary file not shown.
@ -4,6 +4,8 @@ import java.util.Scanner;
|
||||
|
||||
import de.mas.wupclient.client.WUPClient;
|
||||
import de.mas.wupclient.client.operations.DownloadUploadOperations;
|
||||
import de.mas.wupclient.client.operations.DumperOperations;
|
||||
import de.mas.wupclient.client.operations.FileOperations;
|
||||
import de.mas.wupclient.client.operations.SpecialOperations;
|
||||
import de.mas.wupclient.client.operations.UtilOperations;
|
||||
|
||||
@ -21,6 +23,7 @@ public class Starter {
|
||||
System.out.println();
|
||||
System.out.print(w.getCwd() + " > ");
|
||||
Scanner reader = new Scanner(System.in); // Reading from System.in
|
||||
|
||||
while(!exit){
|
||||
|
||||
String input = reader.nextLine();
|
||||
@ -51,6 +54,8 @@ public class Starter {
|
||||
UtilOperations util = UtilOperations.UtilOperationsFactory(w);
|
||||
SpecialOperations special = SpecialOperations.SpecialOperationsFactory(w);
|
||||
DownloadUploadOperations dlul = DownloadUploadOperations.DownloadUploadOperationsFactory(w);
|
||||
DumperOperations dump = DumperOperations.DumperOperationsFactory(w);
|
||||
|
||||
String[] inputs = input.split(" ");
|
||||
switch(inputs[0]){
|
||||
case "ls":
|
||||
@ -117,6 +122,24 @@ public class Starter {
|
||||
case "nandtickets": //download to full path
|
||||
special.parseAndDownloadTickets();
|
||||
|
||||
break;
|
||||
case "dumpdisc":
|
||||
String pattern = ".*";
|
||||
boolean deepSearch = false;
|
||||
if(inputs.length > 1){
|
||||
for(int i = 1;i < inputs.length;i++){
|
||||
if(inputs[i].equals("-file")){
|
||||
if(inputs.length >= i+1){
|
||||
pattern = inputs[i+1];
|
||||
i++;
|
||||
}
|
||||
}
|
||||
if(inputs[i].equals("-deepSearch")){
|
||||
deepSearch = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
dump.dumpDisc(pattern,deepSearch);
|
||||
break;
|
||||
default:
|
||||
System.out.println("Command not found!");
|
||||
|
@ -106,7 +106,7 @@ public class DownloadUploadOperations extends Operations {
|
||||
if(read_result.getResultValue() <= 0)
|
||||
break;
|
||||
if((total_read /1024) % 50 == 0){
|
||||
System.out.println(String.format("%.3f", (double)(total_read /1024.0)) + " kb done");
|
||||
System.out.print("Downloading file: " + String.format("%.3f", (double)(total_read /1024.0)) + " kb done\r");
|
||||
}
|
||||
}
|
||||
fsa.FSA_CloseFile(fsa_handle, res.getData());
|
||||
|
93
src/de/mas/wupclient/client/operations/DumperOperations.java
Normal file
93
src/de/mas/wupclient/client/operations/DumperOperations.java
Normal file
@ -0,0 +1,93 @@
|
||||
package de.mas.wupclient.client.operations;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
|
||||
import de.mas.wupclient.client.WUPClient;
|
||||
import de.mas.wupclient.client.utils.FEntry;
|
||||
import de.mas.wupclient.client.utils.Logger;
|
||||
import de.mas.wupclient.client.utils.MetaInformation;
|
||||
import de.mas.wupclient.client.utils.Utils;
|
||||
|
||||
public class DumperOperations extends Operations {
|
||||
private static Map<WUPClient,DumperOperations> instances = new HashMap<>();
|
||||
public static DumperOperations DumperOperationsFactory(WUPClient client){
|
||||
if(!instances.containsKey(client)){
|
||||
instances.put(client, new DumperOperations(client));
|
||||
}
|
||||
return instances.get(client);
|
||||
}
|
||||
UtilOperations util = null;
|
||||
FileOperations file = null;
|
||||
DownloadUploadOperations dlul = null;
|
||||
|
||||
private DumperOperations(WUPClient client) {
|
||||
super(client);
|
||||
setUtil(UtilOperations.UtilOperationsFactory(client));
|
||||
setDLUL(DownloadUploadOperations.DownloadUploadOperationsFactory(client));
|
||||
setFile(FileOperations.FileOperationsFactory(client));
|
||||
}
|
||||
|
||||
public boolean dumpDisc(String pattern,boolean deepSearch) throws IOException{
|
||||
try{
|
||||
util.mount_sdcard();
|
||||
int res = util.mount("/dev/odd03", "/vol/storage_odd_content_dump", 2);
|
||||
if(res != 0){
|
||||
//throw new MountingFailedException();
|
||||
}
|
||||
System.out.println("Grabbing meta information!");
|
||||
byte[] metafile = dlul.downloadFileToByteArray("/vol/storage_odd_content_dump/meta/meta.xml");
|
||||
if(metafile == null){
|
||||
throw new LoadMetaFailedException();
|
||||
}
|
||||
MetaInformation title = Utils.readMeta(new ByteArrayInputStream(metafile));
|
||||
Logger.log("Dumping " + title.getLongnameEN() + "(" + title.getTitleIDAsString() + ")");
|
||||
file.mkdir("/vol/storage_sdcard/dumps", 0x600);
|
||||
file.mkdir("/vol/storage_sdcard/dumps/" + title.getTitleIDAsString(), 0x600);
|
||||
if(pattern != ".*"){
|
||||
System.out.println("Searching matching files. This could take a while");
|
||||
}
|
||||
file.cpdir("/vol/storage_odd_content_dump","/vol/storage_sdcard/dumps/" + title.getTitleIDAsString(),"",pattern,deepSearch);
|
||||
|
||||
//}catch (MountingFailedException e) {
|
||||
// Logger.logErr("Mounting failed");
|
||||
}catch (LoadMetaFailedException e){
|
||||
Logger.logErr("Loading meta.xml failed");
|
||||
}finally{
|
||||
util.unmount("/vol/storage_odd_content_dump", 2);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public UtilOperations getUtil() {
|
||||
return util;
|
||||
}
|
||||
|
||||
public void setUtil(UtilOperations util) {
|
||||
this.util = util;
|
||||
}
|
||||
|
||||
public DownloadUploadOperations getDLUL() {
|
||||
return dlul;
|
||||
}
|
||||
|
||||
public void setDLUL(DownloadUploadOperations dlul) {
|
||||
this.dlul = dlul;
|
||||
}
|
||||
|
||||
public FileOperations getFile() {
|
||||
return file;
|
||||
}
|
||||
|
||||
public void setFile(FileOperations file) {
|
||||
this.file = file;
|
||||
}
|
||||
|
||||
}
|
@ -137,12 +137,29 @@ public class FSAOperations extends Operations {
|
||||
if(result.getResultValue() == 0){
|
||||
stats = new FStats(result.getData());
|
||||
}
|
||||
System.out.println(result.getResultValue());
|
||||
return new Result<FStats>(result.getResultValue(), stats);
|
||||
}
|
||||
|
||||
public Result<Integer> FSA_ReadFilePtr(int fsa_handle, int src_handle, int i, int block_size, int buffer_ptr) {
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
|
||||
public Result<byte[]> FSA_ReadFilePtr(int handle, int filehandle, int size, int cnt, int ptr) throws IOException {
|
||||
byte[] inbuffer = new byte[0x520];
|
||||
Utils.writeIntToByteArray(inbuffer, size, 0x08);
|
||||
Utils.writeIntToByteArray(inbuffer, cnt, 0x0C);
|
||||
Utils.writeIntToByteArray(inbuffer, filehandle, 0x14);
|
||||
|
||||
Result<byte[][]> result = system.ioctlv(handle, 0x0F, new byte[][] {inbuffer}, new int[]{0x293}, new int[0][], new int[][]{new int[]{ptr,size*cnt}});
|
||||
|
||||
return new Result<byte[]>(result.getResultValue(),result.getData()[0]);
|
||||
}
|
||||
|
||||
public Result<byte[]> FSA_WriteFilePtr(int handle, int file_handle, int size, int cnt, int ptr) throws IOException {
|
||||
byte[] inbuffer = new byte[0x520];
|
||||
Utils.writeIntToByteArray(inbuffer, size, 0x08);
|
||||
Utils.writeIntToByteArray(inbuffer, cnt, 0x0C);
|
||||
Utils.writeIntToByteArray(inbuffer, file_handle, 0x14);
|
||||
|
||||
Result<byte[][]> result = system.ioctlv(handle, 0x10, new byte[][] {inbuffer}, new int[]{0x293}, new int[][]{new int[]{ptr,size*cnt}},new int[0][]);
|
||||
|
||||
return new Result<byte[]>(result.getResultValue(),result.getData()[0]);
|
||||
}
|
||||
}
|
||||
|
@ -2,9 +2,14 @@ package de.mas.wupclient.client.operations;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import de.mas.wupclient.client.WUPClient;
|
||||
import de.mas.wupclient.client.utils.FEntry;
|
||||
import de.mas.wupclient.client.utils.FStats;
|
||||
import de.mas.wupclient.client.utils.Logger;
|
||||
import de.mas.wupclient.client.utils.Result;
|
||||
|
||||
@ -34,13 +39,44 @@ public class FileOperations extends Operations {
|
||||
}
|
||||
public int createDir(String path, int flags) throws IOException{
|
||||
int fsa_handle = getClient().get_fsa_handle();
|
||||
return fsa.FSA_MakeDir(fsa_handle, path, 2);
|
||||
return fsa.FSA_MakeDir(fsa_handle, path, flags);
|
||||
}
|
||||
|
||||
/* FSA_ReadFilePtr needs to be implemented
|
||||
|
||||
public boolean cp(String source, String target) throws IOException{
|
||||
return copyFile(source, target);
|
||||
}
|
||||
public boolean cpdir(String source, String destination)throws IOException{
|
||||
return cpdir(source, destination,"",".*",false);
|
||||
}
|
||||
public boolean cpdir(String source, String destination,boolean deepSearch)throws IOException{
|
||||
return cpdir(source, destination,"",".*",deepSearch);
|
||||
}
|
||||
public boolean cpdir(String source, String destination,String relativePath,String pattern,boolean deepSearch)throws IOException{
|
||||
System.out.println("Copying folder " +source + " to " + destination);
|
||||
List<FEntry> entries = util.ls(source,true);
|
||||
for(FEntry entry : entries){
|
||||
String new_relativePath = relativePath+ "/" + entry.getFilename();
|
||||
String src_filename = source + "/" + entry.getFilename();
|
||||
String dst_filename = destination + "/" + entry.getFilename();
|
||||
Pattern p = Pattern.compile(pattern);
|
||||
Matcher m = p.matcher(new_relativePath);
|
||||
Matcher m1 = p.matcher(new_relativePath + "/");
|
||||
boolean matches = m.matches() || m1.matches();
|
||||
if(matches || deepSearch){
|
||||
if(entry.isFile()){
|
||||
if(matches){
|
||||
boolean result = cp(src_filename,dst_filename);
|
||||
if(!result) break;
|
||||
}
|
||||
}else{
|
||||
mkdir(dst_filename, 0x600);
|
||||
cpdir(src_filename, dst_filename,new_relativePath,pattern,deepSearch);
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
public boolean copyFile(String source, String destination) throws IOException{
|
||||
@ -50,31 +86,57 @@ public class FileOperations extends Operations {
|
||||
Logger.logErr("copyFile error: couldn't open " + source);
|
||||
return false;
|
||||
}
|
||||
Result<Integer> result_dst = fsa.FSA_OpenFile(fsa_handle, destination, "r");
|
||||
|
||||
Result<Integer> result_dst = fsa.FSA_OpenFile(fsa_handle, destination, "w");
|
||||
if(result_dst.getResultValue() != 0){
|
||||
Logger.logErr("copyFile error: couldn't open " + destination);
|
||||
fsa.FSA_CloseFile(fsa_handle, result_src.getData());
|
||||
return false;
|
||||
}
|
||||
int block_size = 0x10000;
|
||||
int block_size = 0x20000;
|
||||
int buffer_ptr = system.alloc(block_size, 0x40);
|
||||
int i =0;
|
||||
int src_handle = result_src.getData();
|
||||
int dst_handle = result_dst.getData();
|
||||
boolean result = true;
|
||||
|
||||
Result<FStats> result_stat = fsa.FSA_StatFile(fsa_handle, src_handle);
|
||||
if(result_stat.getResultValue() < 0){
|
||||
Logger.log("copyFile error: FSA_StatFile failed.");
|
||||
return false;
|
||||
}
|
||||
long file_size = result_stat.getData().getPhyssize();
|
||||
System.out.println("Copying " + source + " to " + destination + " ("+ (file_size /1024.0f) +" kb)");
|
||||
long startTime = System.currentTimeMillis();
|
||||
while(true){
|
||||
Result<Integer> result_read = fsa.FSA_ReadFilePtr(fsa_handle, src_handle, 0x1, block_size, buffer_ptr);
|
||||
if(result_read.getResultValue() < 0){
|
||||
Result<byte[]> result_read = fsa.FSA_ReadFilePtr(fsa_handle, src_handle, 0x1, block_size, buffer_ptr);
|
||||
int result_val = result_read.getResultValue();
|
||||
if(result_val < 0){
|
||||
Logger.log("copyFile error: reading source file failed.");
|
||||
result = false;
|
||||
break;
|
||||
}
|
||||
i += result_val;
|
||||
Result<byte[]> result_write = fsa.FSA_WriteFilePtr(fsa_handle, dst_handle, 0x1, result_val, buffer_ptr);
|
||||
int result_write_val = result_read.getResultValue();
|
||||
if(result_write_val < 0){
|
||||
Logger.log("copyFile error: writing destination file failed.");
|
||||
result = false;
|
||||
break;
|
||||
}
|
||||
long diff_time = System.currentTimeMillis() - startTime;
|
||||
|
||||
System.out.print("" + String.format("Writing File: progress %08X bytes (%02.02f", i,(i*1.0/file_size*1.0)*100) + "%) (" + String.format("%04d", (int)((i*1.0f) /(diff_time*1.0f)))+" kb/s)\r");
|
||||
if(result_val < block_size){
|
||||
break;
|
||||
}
|
||||
}
|
||||
System.out.println("Wrote " + source + " to " + destination + " ("+ (file_size /1024.0f) +" kb)");
|
||||
system.free(buffer_ptr);
|
||||
fsa.FSA_CloseFile(fsa_handle, src_handle);
|
||||
fsa.FSA_CloseFile(fsa_handle, dst_handle);
|
||||
return result;
|
||||
}*/
|
||||
}
|
||||
|
||||
public UtilOperations getUtil() {
|
||||
return util;
|
||||
|
@ -148,7 +148,7 @@ public class UtilOperations extends Operations {
|
||||
fsa.FSA_CloseDir(fsa_handle, result.getData());
|
||||
final_result = true;
|
||||
}else{
|
||||
Logger.logErr("path does not exists");
|
||||
Logger.logErr("path does not exists: error " + result.getResultValue());
|
||||
final_result = false;
|
||||
}
|
||||
getClient().FSA_Close(getClient().get_fsa_handle());
|
||||
|
@ -35,5 +35,19 @@ public class FStats {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
return sb.append("Size: " + size + " Physicalsize:" + physsize).toString();
|
||||
}
|
||||
public int getSize() {
|
||||
return size;
|
||||
}
|
||||
public void setSize(int size) {
|
||||
this.size = size;
|
||||
}
|
||||
public int getPhyssize() {
|
||||
return physsize;
|
||||
}
|
||||
public void setPhyssize(int physsize) {
|
||||
this.physsize = physsize;
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user