From b676392315d256b87b1f5fe561b44595798d79c5 Mon Sep 17 00:00:00 2001 From: Maschell Date: Sun, 13 Nov 2016 21:21:26 +0100 Subject: [PATCH] Added copy / copydir command. Added commandline command to dump the disc to sd --- README.md | 77 ++++++++++----- jwupclient.jar | Bin 34803 -> 40137 bytes src/de/mas/wupclient/Starter.java | 25 ++++- .../operations/DownloadUploadOperations.java | 2 +- .../client/operations/DumperOperations.java | 93 ++++++++++++++++++ .../client/operations/FSAOperations.java | 25 ++++- .../client/operations/FileOperations.java | 78 +++++++++++++-- .../client/operations/UtilOperations.java | 2 +- src/de/mas/wupclient/client/utils/FStats.java | 14 +++ 9 files changed, 274 insertions(+), 42 deletions(-) create mode 100644 src/de/mas/wupclient/client/operations/DumperOperations.java diff --git a/README.md b/README.md index e2bda53..c8c1b8e 100644 --- a/README.md +++ b/README.md @@ -1,41 +1,64 @@ 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). -cd: -change directory to parent dir: -cd .. -change directory to relative dir: -cd code -change directory to absolute dir: -cd /vol/storage_mlc01 +cd: +change directory to parent dir: +cd .. +change directory to relative dir: +cd code +change directory to absolute dir: +cd /vol/storage_mlc01 -ls: -lists content of the directory +ls: +lists content of the directory -dl: -downloads a file. -dl filename [targetdir] +dl: +downloads a file. +dl filename [targetdir] -dlfp: -same as dl but keeps the absolute path of the wiiu +dlfp: +same as dl but keeps the absolute path of the wiiu -dldir: -downloads a directory +dldir: +downloads a directory -downloading the current dir -dldir -arguments: --src (sets the source folder on the wiiu) --dst (sets the destination folder on your PC) --fullpath (keeps the absolute path of the wiiu) +downloading the current dir +dldir +arguments: +-src (sets the source folder on the wiiu) +-dst (sets the destination folder on your PC) +-fullpath (keeps the absolute path of the wiiu) -Server and smea's client. -https://github.com/smealum/iosuhax/tree/master/wupserver +###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 + Everything is from Smea, I'm just porting and extending it! \ No newline at end of file diff --git a/jwupclient.jar b/jwupclient.jar index 3baa4dd54a8d605210bfa03c131826376863f9da..7bee75abd750777fe624b1f5d839208f172ab605 100644 GIT binary patch delta 21040 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 "); 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!"); diff --git a/src/de/mas/wupclient/client/operations/DownloadUploadOperations.java b/src/de/mas/wupclient/client/operations/DownloadUploadOperations.java index 862d49f..2352804 100644 --- a/src/de/mas/wupclient/client/operations/DownloadUploadOperations.java +++ b/src/de/mas/wupclient/client/operations/DownloadUploadOperations.java @@ -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()); diff --git a/src/de/mas/wupclient/client/operations/DumperOperations.java b/src/de/mas/wupclient/client/operations/DumperOperations.java new file mode 100644 index 0000000..fa7988a --- /dev/null +++ b/src/de/mas/wupclient/client/operations/DumperOperations.java @@ -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 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; + } + +} diff --git a/src/de/mas/wupclient/client/operations/FSAOperations.java b/src/de/mas/wupclient/client/operations/FSAOperations.java index 0b1832f..5072b27 100644 --- a/src/de/mas/wupclient/client/operations/FSAOperations.java +++ b/src/de/mas/wupclient/client/operations/FSAOperations.java @@ -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(result.getResultValue(), stats); } - public Result 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 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 result = system.ioctlv(handle, 0x0F, new byte[][] {inbuffer}, new int[]{0x293}, new int[0][], new int[][]{new int[]{ptr,size*cnt}}); + + return new Result(result.getResultValue(),result.getData()[0]); + } + + public Result 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 result = system.ioctlv(handle, 0x10, new byte[][] {inbuffer}, new int[]{0x293}, new int[][]{new int[]{ptr,size*cnt}},new int[0][]); + + return new Result(result.getResultValue(),result.getData()[0]); } } diff --git a/src/de/mas/wupclient/client/operations/FileOperations.java b/src/de/mas/wupclient/client/operations/FileOperations.java index ce022e5..78c6ff7 100644 --- a/src/de/mas/wupclient/client/operations/FileOperations.java +++ b/src/de/mas/wupclient/client/operations/FileOperations.java @@ -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,14 +39,45 @@ 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 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{ int fsa_handle = getClient().get_fsa_handle(); @@ -50,31 +86,57 @@ public class FileOperations extends Operations { Logger.logErr("copyFile error: couldn't open " + source); return false; } - Result result_dst = fsa.FSA_OpenFile(fsa_handle, destination, "r"); + + Result 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 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 result_read = fsa.FSA_ReadFilePtr(fsa_handle, src_handle, 0x1, block_size, buffer_ptr); - if(result_read.getResultValue() < 0){ + Result 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 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; diff --git a/src/de/mas/wupclient/client/operations/UtilOperations.java b/src/de/mas/wupclient/client/operations/UtilOperations.java index c60992f..76a18db 100644 --- a/src/de/mas/wupclient/client/operations/UtilOperations.java +++ b/src/de/mas/wupclient/client/operations/UtilOperations.java @@ -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()); diff --git a/src/de/mas/wupclient/client/utils/FStats.java b/src/de/mas/wupclient/client/utils/FStats.java index 9d7ccdd..1f5cbc9 100644 --- a/src/de/mas/wupclient/client/utils/FStats.java +++ b/src/de/mas/wupclient/client/utils/FStats.java @@ -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; + } + + }