Added copy / copydir command. Added commandline command to dump the disc to sd

This commit is contained in:
Maschell 2016-11-13 21:21:26 +01:00
parent 020f1e185a
commit b676392315
9 changed files with 274 additions and 42 deletions

View File

@ -2,7 +2,7 @@ A port of smea's client (WUPClient.py) for the wupserver.
Open it with 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). 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) -dst <destination folder on wiiu> (sets the destination folder on your PC)
-fullpath (keeps the absolute path of the wiiu) -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. Server and smea's client.
https://github.com/smealum/iosuhax/tree/master/wupserver https://github.com/smealum/iosuhax/tree/master/wupserver

Binary file not shown.

View File

@ -4,6 +4,8 @@ import java.util.Scanner;
import de.mas.wupclient.client.WUPClient; import de.mas.wupclient.client.WUPClient;
import de.mas.wupclient.client.operations.DownloadUploadOperations; 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.SpecialOperations;
import de.mas.wupclient.client.operations.UtilOperations; import de.mas.wupclient.client.operations.UtilOperations;
@ -21,6 +23,7 @@ public class Starter {
System.out.println(); System.out.println();
System.out.print(w.getCwd() + " > "); System.out.print(w.getCwd() + " > ");
Scanner reader = new Scanner(System.in); // Reading from System.in Scanner reader = new Scanner(System.in); // Reading from System.in
while(!exit){ while(!exit){
String input = reader.nextLine(); String input = reader.nextLine();
@ -51,6 +54,8 @@ public class Starter {
UtilOperations util = UtilOperations.UtilOperationsFactory(w); UtilOperations util = UtilOperations.UtilOperationsFactory(w);
SpecialOperations special = SpecialOperations.SpecialOperationsFactory(w); SpecialOperations special = SpecialOperations.SpecialOperationsFactory(w);
DownloadUploadOperations dlul = DownloadUploadOperations.DownloadUploadOperationsFactory(w); DownloadUploadOperations dlul = DownloadUploadOperations.DownloadUploadOperationsFactory(w);
DumperOperations dump = DumperOperations.DumperOperationsFactory(w);
String[] inputs = input.split(" "); String[] inputs = input.split(" ");
switch(inputs[0]){ switch(inputs[0]){
case "ls": case "ls":
@ -117,6 +122,24 @@ public class Starter {
case "nandtickets": //download to full path case "nandtickets": //download to full path
special.parseAndDownloadTickets(); 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; break;
default: default:
System.out.println("Command not found!"); System.out.println("Command not found!");

View File

@ -106,7 +106,7 @@ public class DownloadUploadOperations extends Operations {
if(read_result.getResultValue() <= 0) if(read_result.getResultValue() <= 0)
break; break;
if((total_read /1024) % 50 == 0){ 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()); fsa.FSA_CloseFile(fsa_handle, res.getData());

View 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;
}
}

View File

@ -137,12 +137,29 @@ public class FSAOperations extends Operations {
if(result.getResultValue() == 0){ if(result.getResultValue() == 0){
stats = new FStats(result.getData()); stats = new FStats(result.getData());
} }
System.out.println(result.getResultValue());
return new Result<FStats>(result.getResultValue(), stats); 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 public Result<byte[]> FSA_ReadFilePtr(int handle, int filehandle, int size, int cnt, int ptr) throws IOException {
return null; 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]);
} }
} }

View File

@ -2,9 +2,14 @@ package de.mas.wupclient.client.operations;
import java.io.IOException; import java.io.IOException;
import java.util.HashMap; import java.util.HashMap;
import java.util.List;
import java.util.Map; 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.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.Logger;
import de.mas.wupclient.client.utils.Result; 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{ public int createDir(String path, int flags) throws IOException{
int fsa_handle = getClient().get_fsa_handle(); 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{ public boolean cp(String source, String target) throws IOException{
return copyFile(source, target); 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{ 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); Logger.logErr("copyFile error: couldn't open " + source);
return false; 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){ if(result_dst.getResultValue() != 0){
Logger.logErr("copyFile error: couldn't open " + destination); Logger.logErr("copyFile error: couldn't open " + destination);
fsa.FSA_CloseFile(fsa_handle, result_src.getData()); fsa.FSA_CloseFile(fsa_handle, result_src.getData());
return false; return false;
} }
int block_size = 0x10000; int block_size = 0x20000;
int buffer_ptr = system.alloc(block_size, 0x40); int buffer_ptr = system.alloc(block_size, 0x40);
int i =0; int i =0;
int src_handle = result_src.getData(); int src_handle = result_src.getData();
int dst_handle = result_dst.getData(); int dst_handle = result_dst.getData();
boolean result = true; 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){ while(true){
Result<Integer> result_read = fsa.FSA_ReadFilePtr(fsa_handle, src_handle, 0x1, block_size, buffer_ptr); Result<byte[]> result_read = fsa.FSA_ReadFilePtr(fsa_handle, src_handle, 0x1, block_size, buffer_ptr);
if(result_read.getResultValue() < 0){ int result_val = result_read.getResultValue();
if(result_val < 0){
Logger.log("copyFile error: reading source file failed."); Logger.log("copyFile error: reading source file failed.");
result = false; result = false;
break; 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); system.free(buffer_ptr);
fsa.FSA_CloseFile(fsa_handle, src_handle); fsa.FSA_CloseFile(fsa_handle, src_handle);
fsa.FSA_CloseFile(fsa_handle, dst_handle); fsa.FSA_CloseFile(fsa_handle, dst_handle);
return result; return result;
}*/ }
public UtilOperations getUtil() { public UtilOperations getUtil() {
return util; return util;

View File

@ -148,7 +148,7 @@ public class UtilOperations extends Operations {
fsa.FSA_CloseDir(fsa_handle, result.getData()); fsa.FSA_CloseDir(fsa_handle, result.getData());
final_result = true; final_result = true;
}else{ }else{
Logger.logErr("path does not exists"); Logger.logErr("path does not exists: error " + result.getResultValue());
final_result = false; final_result = false;
} }
getClient().FSA_Close(getClient().get_fsa_handle()); getClient().FSA_Close(getClient().get_fsa_handle());

View File

@ -35,5 +35,19 @@ public class FStats {
StringBuilder sb = new StringBuilder(); StringBuilder sb = new StringBuilder();
return sb.append("Size: " + size + " Physicalsize:" + physsize).toString(); 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;
}
} }