From 020f1e185a6cbce1cb74a6db9ea419ba2e2c03a7 Mon Sep 17 00:00:00 2001 From: Maschell Date: Thu, 10 Nov 2016 23:39:18 +0100 Subject: [PATCH] created a little command line version Added new features (FSGetStats, cd with "." or "..") refactored some parts (file operations now in own operations file) maybe serveral small bug fixes/improvements I don't remember limiting read buffer instead of crashing the console --- .gitignore | 1 + README.md | 38 +++++- jwupclient.jar | Bin 0 -> 34803 bytes src/de/mas/wupclient/Starter.java | 117 +++++++++++++++--- src/de/mas/wupclient/client/WUPClient.java | 17 ++- .../operations/DownloadUploadOperations.java | 95 ++++++++++---- .../client/operations/FSAOperations.java | 26 ++++ .../client/operations/FileOperations.java | 100 +++++++++++++++ .../client/operations/UtilOperations.java | 49 ++++++-- src/de/mas/wupclient/client/utils/FStats.java | 39 ++++++ src/de/mas/wupclient/client/utils/Logger.java | 2 +- src/de/mas/wupclient/client/utils/Utils.java | 19 ++- 12 files changed, 448 insertions(+), 55 deletions(-) create mode 100644 jwupclient.jar create mode 100644 src/de/mas/wupclient/client/operations/FileOperations.java create mode 100644 src/de/mas/wupclient/client/utils/FStats.java diff --git a/.gitignore b/.gitignore index 11ddb8b..9391d15 100644 --- a/.gitignore +++ b/.gitignore @@ -46,3 +46,4 @@ Network Trash Folder Temporary Items .apdisk *.class +tickets/* diff --git a/README.md b/README.md index d2a501a..e2bda53 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,41 @@ A port of smea's client (WUPClient.py) for the wupserver. +Open it with +``` +java -jar jwupclient 192.168.x.x +``` + +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 + +ls: +lists content of the directory + +dl: +downloads a file. +dl filename [targetdir] + +dlfp: +same as dl but keeps the absolute path of the wiiu + +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) + +Server and smea's client. https://github.com/smealum/iosuhax/tree/master/wupserver -Everything is from Smea, I'm just porting it! \ No newline at end of file +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 new file mode 100644 index 0000000000000000000000000000000000000000..3baa4dd54a8d605210bfa03c131826376863f9da GIT binary patch literal 34803 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 literal 0 HcmV?d00001 diff --git a/src/de/mas/wupclient/Starter.java b/src/de/mas/wupclient/Starter.java index fbd48b6..861980f 100644 --- a/src/de/mas/wupclient/Starter.java +++ b/src/de/mas/wupclient/Starter.java @@ -1,10 +1,11 @@ package de.mas.wupclient; import java.io.IOException; +import java.util.Scanner; import de.mas.wupclient.client.WUPClient; import de.mas.wupclient.client.operations.DownloadUploadOperations; +import de.mas.wupclient.client.operations.SpecialOperations; import de.mas.wupclient.client.operations.UtilOperations; -import de.mas.wupclient.client.utils.Logger; public class Starter { public static void main(String args[]){ @@ -13,26 +14,114 @@ public class Starter { ip = args[0]; } WUPClient w = new WUPClient(ip); - try { - UtilOperations util = UtilOperations.UtilOperationsFactory(w); - DownloadUploadOperations dlul = DownloadUploadOperations.DownloadUploadOperationsFactory(w); - util.dump_syslog(); - - Logger.logCmd("Lets into the " + w.getCwd() + "/sys/title/00050010/10040200/" + " folder!"); - util.lsRecursive(w.getCwd() + "/sys/title/00050010/10040200/"); - Logger.logCmd("And download the /code/app.xml to /test/app.xml"); - dlul.downloadFile(w.getCwd() + "/sys/title/00050010/10040200/code", "app.xml", "test", null); - Logger.logCmd("done!"); + try { + boolean exit = false; + + System.out.println("JWUPClient. Please enter a command. Enter \"exit\" to exit."); + System.out.println(); + System.out.print(w.getCwd() + " > "); + Scanner reader = new Scanner(System.in); // Reading from System.in + while(!exit){ + + String input = reader.nextLine(); + if(input.equals("exit")){ + exit = true; + break; + } + processCommand(input,w); + System.out.println(); + System.out.print(w.getCwd() + " > "); + } + reader.close(); } catch (IOException e) { e.printStackTrace(); }finally { try { w.FSA_Close(w.get_fsa_handle()); - } catch (IOException e) { - // TODO Auto-generated catch block - e.printStackTrace(); + } catch (IOException e) { } w.closeSocket(); } } + + private static void processCommand(String input,WUPClient w) throws IOException { + if(input == null || input.isEmpty()){ + return; + } + UtilOperations util = UtilOperations.UtilOperationsFactory(w); + SpecialOperations special = SpecialOperations.SpecialOperationsFactory(w); + DownloadUploadOperations dlul = DownloadUploadOperations.DownloadUploadOperationsFactory(w); + String[] inputs = input.split(" "); + switch(inputs[0]){ + case "ls": + if(inputs.length > 1){ + util.ls(inputs[1]); + }else{ + util.ls(); + } + break; + case "lsr": + util.lsRecursive(); + break; + case "sysdump": + util.dump_syslog(); + break; + case "cd": + if(inputs.length > 1){ + util.cd(inputs[1]); + }else{ + util.cd(); + } + + break; + case "dldir": + String destination = null; + String source = w.getCwd(); + boolean fullpath = false; + if(inputs.length > 1){ + for(int i = 1;i < inputs.length;i++){ + if(inputs[i].equals("-dst")){ + if(inputs.length >= i+1){ + destination = inputs[i+1]; + i++; + } + }else if(inputs[i].equals("-src")){ + if(inputs.length >= i+1){ + source = inputs[i+1]; + i++; + } + }else if(inputs[i].equals("-fullpath")){ + fullpath = true; + } + } + } + dlul.downloadFolder(source,destination,fullpath); + + break; + case "dl": + if(inputs.length == 2){ + dlul.downloadFile("", inputs[1]); + }else if(inputs.length == 3){ + dlul.downloadFile("", inputs[1], inputs[2]); + } + + break; + case "dlfp": //download to full path + if(inputs.length == 2){ + dlul.downloadFile("", inputs[1],w.getCwd()); + }else if(inputs.length == 3){ + dlul.downloadFile("", inputs[1],inputs[2] + "/" + w.getCwd()); + } + + break; + case "nandtickets": //download to full path + special.parseAndDownloadTickets(); + + break; + default: + System.out.println("Command not found!"); + break; + } + + } } diff --git a/src/de/mas/wupclient/client/WUPClient.java b/src/de/mas/wupclient/client/WUPClient.java index e637a6c..1112e73 100644 --- a/src/de/mas/wupclient/client/WUPClient.java +++ b/src/de/mas/wupclient/client/WUPClient.java @@ -13,6 +13,7 @@ import de.mas.wupclient.client.utils.Result; import de.mas.wupclient.client.utils.Utils; public class WUPClient { + public static final int MAX_READ_SIZE = 0x400; private String IP; private int fsaHandle = -1; private String cwd = ""; @@ -33,15 +34,19 @@ public class WUPClient { Logger.logErr("send failed"); e.printStackTrace(); } - ByteBuffer destByteBuffer = ByteBuffer.allocate(0x600); + byte[] result = new byte[0x0600]; int size = getSocket().getInputStream().read(result); - destByteBuffer.put(result, 0, size); - int returnValue = destByteBuffer.getInt(); - return new Result(returnValue,Arrays.copyOfRange(result, 4,result.length)); + ByteBuffer destByteBuffer = ByteBuffer.allocate(0x04); + destByteBuffer.put(Arrays.copyOfRange(result, 0, 4)); + int returnValue = destByteBuffer.getInt(0); + return new Result(returnValue,Arrays.copyOfRange(result, 4,size)); } public byte[] read(int addr, int len) throws IOException{ + if(len > WUPClient.MAX_READ_SIZE){ + throw new IOException("read length > " + WUPClient.MAX_READ_SIZE); + } Result result = send(1, Utils.m_packBE(addr,len)); if(result.getResultValue() == 0){ return result.getData(); @@ -126,7 +131,7 @@ public class WUPClient { e.printStackTrace(); } setSocket(clientSocket); - Logger.log("Connected"); + Logger.log("Connected to " + ip); return clientSocket; } @@ -151,7 +156,7 @@ public class WUPClient { public String getCwd() { return cwd; } - private void setCwd(String cwd) { + public void setCwd(String cwd) { this.cwd = cwd; } public Socket getSocket() { diff --git a/src/de/mas/wupclient/client/operations/DownloadUploadOperations.java b/src/de/mas/wupclient/client/operations/DownloadUploadOperations.java index 3bcb5d9..862d49f 100644 --- a/src/de/mas/wupclient/client/operations/DownloadUploadOperations.java +++ b/src/de/mas/wupclient/client/operations/DownloadUploadOperations.java @@ -32,31 +32,57 @@ public class DownloadUploadOperations extends Operations { setFSA(FSAOperations.FSAOperationsFactory(client)); } - public boolean downloadFolder(String path) throws IOException{ - return downloadFolder(path,null,false); - } - - public boolean downloadFolder(String sourcePath,String targetPath) throws IOException{ - return downloadFolder(sourcePath,targetPath,false); - } - - public boolean downloadFolder(String sourcePath, String targetPath,boolean useRelativPath) throws IOException { - List files = util.ls(sourcePath,true); - if(targetPath == null || targetPath.isEmpty()){ - targetPath = sourcePath; + public boolean downloadFolder(String sourcePath) throws IOException{ + return downloadFolder(sourcePath,null,false); + } + public boolean downloadFolder(String sourcePath, String targetPath,boolean fullpath) throws IOException { + String new_source_path = sourcePath; + + if(!sourcePath.isEmpty() && !sourcePath.startsWith("/")){ + new_source_path = getClient().getCwd() + "/"+ sourcePath; + }else if(sourcePath == null || sourcePath.isEmpty()){ + new_source_path = getClient().getCwd(); } + + if(targetPath == null || targetPath.isEmpty()){ + if(fullpath){ + targetPath = new_source_path; + }else{ + targetPath = ""; + if(!sourcePath.isEmpty() && !sourcePath.startsWith("/")){ + targetPath = sourcePath; + } + } + }else{ + if(fullpath){ + targetPath += new_source_path; + }else{ + if(!sourcePath.isEmpty() && !sourcePath.startsWith("/")){ + targetPath += "/" + sourcePath; + } + } + } + return _downloadFolder(new_source_path,targetPath); + } + private boolean _downloadFolder(String sourcePath, String targetPath) throws IOException { + Logger.logCmd("Downloading folder " + sourcePath); + + List files = util.ls(sourcePath,true); + + Utils.createSubfolder(targetPath); + for(FEntry f: files){ if(f.isFile()){ + //System.out.println(targetPath); downloadFile(sourcePath, f.getFilename(),targetPath); }else{ - downloadFolder(sourcePath + "/" + f.getFilename(), targetPath,useRelativPath); + _downloadFolder(sourcePath + "/" + f.getFilename(), targetPath + "/" + f.getFilename()); } } return false; } - public byte[] downloadFileToByteArray(String path) throws IOException{ - Logger.logCmd("Downloading " + path); + public byte[] downloadFileToByteArray(String path) throws IOException{ int fsa_handle = getClient().get_fsa_handle(); Result res = fsa.FSA_OpenFile(fsa_handle, path, "r"); boolean success = false; @@ -65,38 +91,50 @@ public class DownloadUploadOperations extends Operations { int block_size = 0x400; ByteArrayOutputStream out = new ByteArrayOutputStream(); success = true; + int total_read = 0; while(true){ Result read_result= fsa.FSA_ReadFile(fsa_handle, res.getData(), 0x1, block_size); - + if(read_result.getResultValue() <0){ Logger.logErr("FSA_ReadFile returned " + read_result.getResultValue()); success = false; break; } - + total_read += read_result.getResultValue(); out.write(Arrays.copyOf(read_result.getData(), read_result.getResultValue())); 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"); + } + } fsa.FSA_CloseFile(fsa_handle, res.getData()); if(success){ + System.out.println("Download done: " + total_read+ " bytes"); result = out.toByteArray(); } } return result; } + + public boolean downloadFile(String sourcePath, String filename) throws IOException { + return downloadFile(sourcePath, filename, ""); + } public boolean downloadFile(String sourcePath, String filename, String targetPath) throws IOException { return downloadFile(sourcePath, filename, targetPath,null); } public boolean downloadFile(String sourcePath,String sourceFilename,String targetPath,String targetFileName) throws IOException { - byte[] data = downloadFileToByteArray(sourcePath + "/" + sourceFilename); - if(data == null){ - System.out.println("failed"); - return false; + + if(sourcePath == null || sourcePath.isEmpty()){ + sourcePath = getClient().getCwd(); } + if(targetPath == null || targetPath.isEmpty()){ + targetPath = ""; + } + String subdir = ""; if(targetFileName == null){ @@ -107,8 +145,17 @@ public class DownloadUploadOperations extends Operations { if(subdir.startsWith("/")){ subdir = subdir.substring(1); } + if(!targetPath.isEmpty()){ + Utils.createSubfolder(subdir); + } + Logger.logCmd("Downloading " + sourcePath + "/" + sourceFilename + " to " + subdir); + + byte[] data = downloadFileToByteArray(sourcePath + "/" + sourceFilename); + if(data == null){ + System.out.println("failed"); + return false; + } - Utils.createSubfolder(subdir); FileOutputStream stream = new FileOutputStream(subdir); try { stream.write(data); @@ -132,5 +179,5 @@ public class DownloadUploadOperations extends Operations { public void setFSA(FSAOperations fsa) { this.fsa = fsa; - } + } } diff --git a/src/de/mas/wupclient/client/operations/FSAOperations.java b/src/de/mas/wupclient/client/operations/FSAOperations.java index 25bfca9..0b1832f 100644 --- a/src/de/mas/wupclient/client/operations/FSAOperations.java +++ b/src/de/mas/wupclient/client/operations/FSAOperations.java @@ -7,6 +7,7 @@ import java.util.Map; 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; import de.mas.wupclient.client.utils.Utils; @@ -95,6 +96,9 @@ public class FSAOperations extends Operations { } public Result FSA_OpenFile(int handle, String path, String mode) throws IOException{ + if(!path.startsWith("/")){ + path = getClient().getCwd() + "/" + path; + } byte[] inbuffer = new byte[0x520]; Utils.writeNullTerminatedStringToByteArray(inbuffer, path, 0x04); Utils.writeNullTerminatedStringToByteArray(inbuffer, mode, 0x284); @@ -111,6 +115,10 @@ public class FSAOperations extends Operations { } public Result FSA_ReadFile(int handle, int file_handle, int size, int cnt) throws IOException{ + if(size * cnt > WUPClient.MAX_READ_SIZE){ + Logger.logErr("FSA_ReadFile error: size*cnt > " + WUPClient.MAX_READ_SIZE +"(" + (size * cnt) + ")"); + return new Result(-228,new byte[0]); + } byte[] inbuffer = new byte[0x520]; Utils.writeIntToByteArray(inbuffer, size, 0x08); Utils.writeIntToByteArray(inbuffer, cnt, 0x0C); @@ -119,4 +127,22 @@ public class FSAOperations extends Operations { return new Result(result.getResultValue(),result.getData()[0]); } + + public Result FSA_StatFile(int fsa_handle, int handle) throws IOException{ + byte[] inbuffer = new byte[0x520]; + Utils.writeIntToByteArray(inbuffer, handle, 0x04); + + Result result = system.ioctl(fsa_handle, 0x14, inbuffer, 0x293); + FStats stats = null; + 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; + } } diff --git a/src/de/mas/wupclient/client/operations/FileOperations.java b/src/de/mas/wupclient/client/operations/FileOperations.java new file mode 100644 index 0000000..ce022e5 --- /dev/null +++ b/src/de/mas/wupclient/client/operations/FileOperations.java @@ -0,0 +1,100 @@ +package de.mas.wupclient.client.operations; + +import java.io.IOException; +import java.util.HashMap; +import java.util.Map; + +import de.mas.wupclient.client.WUPClient; +import de.mas.wupclient.client.utils.Logger; +import de.mas.wupclient.client.utils.Result; + +public class FileOperations extends Operations { + + + private static Map instances = new HashMap<>(); + public static FileOperations FileOperationsFactory(WUPClient client){ + if(!instances.containsKey(client)){ + instances.put(client, new FileOperations(client)); + } + return instances.get(client); + } + + private UtilOperations util = null; + private FSAOperations fsa = null; + private SystemOperations system = null; + + public FileOperations(WUPClient client) { + super(client); + setUtil(UtilOperations.UtilOperationsFactory(client)); + setFsa(FSAOperations.FSAOperationsFactory(client)); + setSystem(SystemOperations.SystemOperationsFactory(client)); + } + public int mkdir(String path, int flags) throws IOException{ + return createDir(path, flags); + } + public int createDir(String path, int flags) throws IOException{ + int fsa_handle = getClient().get_fsa_handle(); + return fsa.FSA_MakeDir(fsa_handle, path, 2); + } + + /* FSA_ReadFilePtr needs to be implemented + public boolean cp(String source, String target) throws IOException{ + return copyFile(source, target); + } + + + public boolean copyFile(String source, String destination) throws IOException{ + int fsa_handle = getClient().get_fsa_handle(); + Result result_src = fsa.FSA_OpenFile(fsa_handle, source, "r"); + if(result_src.getResultValue() != 0){ + Logger.logErr("copyFile error: couldn't open " + source); + return false; + } + Result result_dst = fsa.FSA_OpenFile(fsa_handle, destination, "r"); + 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 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; + while(true){ + Result result_read = fsa.FSA_ReadFilePtr(fsa_handle, src_handle, 0x1, block_size, buffer_ptr); + if(result_read.getResultValue() < 0){ + Logger.log("copyFile error: reading source file failed."); + result = false; + break; + } + } + 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; + } + + public void setUtil(UtilOperations util) { + this.util = util; + } + + public FSAOperations getFsa() { + return fsa; + } + + public void setFsa(FSAOperations fsa) { + this.fsa = fsa; + } + public SystemOperations getSystem() { + return system; + } + public void setSystem(SystemOperations system) { + this.system = system; + } +} diff --git a/src/de/mas/wupclient/client/operations/UtilOperations.java b/src/de/mas/wupclient/client/operations/UtilOperations.java index e1dc694..c60992f 100644 --- a/src/de/mas/wupclient/client/operations/UtilOperations.java +++ b/src/de/mas/wupclient/client/operations/UtilOperations.java @@ -39,11 +39,12 @@ public class UtilOperations extends Operations { return ls(targetPath,false); } public List ls(String targetPath,boolean return_data) throws IOException{ + if(!return_data){ if(targetPath != null){ - Logger.logCmd("ls(" + targetPath + ")"); + //Logger.logCmd("ls(" + targetPath + ")"); }else{ - Logger.logCmd("ls()"); + //Logger.logCmd("ls()"); } } List results = new ArrayList<>(); @@ -51,6 +52,8 @@ public class UtilOperations extends Operations { String path = targetPath; if(targetPath == null || targetPath.isEmpty()){ path = getClient().getCwd(); + }else if(!targetPath.startsWith("/")){ + path = getClient().getCwd() + "/" + targetPath; } Result res = fsa.FSA_OpenDir(fsa_handle, path); @@ -82,6 +85,7 @@ public class UtilOperations extends Operations { if((result = fsa.FSA_CloseDir(fsa_handle, dirhandle)) != 0){ Logger.logErr("CloseDir failed!" + result); } + getClient().FSA_Close(getClient().get_fsa_handle()); return results; } @@ -89,7 +93,7 @@ public class UtilOperations extends Operations { lsRecursive(getClient().getCwd() + "/"); } - public void lsRecursive(String path) throws IOException{ + public void lsRecursive(String path) throws IOException{ List result = ls(path,true); for(FEntry entry : result){ if(entry.isFile()){ @@ -101,6 +105,7 @@ public class UtilOperations extends Operations { } } } + public void dump_syslog() throws IOException { int syslog_address = Utils.bigEndianByteArrayToInt(getClient().read(0x05095ECC, 4)) + 0x10; int block_size = 0x400; @@ -113,12 +118,42 @@ public class UtilOperations extends Operations { break; } } + getClient().FSA_Close(getClient().get_fsa_handle()); } - - public int mkdir(String path, int flags) throws IOException{ + public boolean cd() throws IOException { + return cd(""); + } + public boolean cd(String path) throws IOException { + if(path.equals(".")){ + return true; + } + if(path.equals("..")){ + path = Utils.getParentDir(getClient().getCwd()); + } + if(!path.startsWith("/")&& getClient().getCwd().startsWith("/")){ + return cd(getClient().getCwd() + "/" + path); + } int fsa_handle = getClient().get_fsa_handle(); - return fsa.FSA_MakeDir(fsa_handle, path, 2); - } + String usedPath = path; + if(path.equals("..")){ + usedPath = Utils.getParentDir(getClient().getCwd()); + System.out.println(usedPath +" dd"); + }else if (path.isEmpty()){ + usedPath = getClient().getCwd(); + } + boolean final_result = false; + Result result = fsa.FSA_OpenDir(fsa_handle,usedPath); + if(result.getResultValue() == 0){ + getClient().setCwd(usedPath); + fsa.FSA_CloseDir(fsa_handle, result.getData()); + final_result = true; + }else{ + Logger.logErr("path does not exists"); + final_result = false; + } + getClient().FSA_Close(getClient().get_fsa_handle()); + return final_result; + } public int mount(String device_path, String volume_path, int flags) throws IOException{ int fsa_handle = getClient().get_fsa_handle(); diff --git a/src/de/mas/wupclient/client/utils/FStats.java b/src/de/mas/wupclient/client/utils/FStats.java new file mode 100644 index 0000000..9d7ccdd --- /dev/null +++ b/src/de/mas/wupclient/client/utils/FStats.java @@ -0,0 +1,39 @@ +package de.mas.wupclient.client.utils; + +import java.nio.ByteBuffer; +import java.util.Arrays; + +public class FStats { + int[] unk1 = new int[0x4]; + int size; // size in bytes + int physsize; // physical size on disk in bytes + int[] unk2 = new int[0x13]; + + public FStats(byte[] data) { + if(data == null || data.length < 0x64){ + return; + } + ByteBuffer buffer = ByteBuffer.allocate(0x64); + buffer.put(Arrays.copyOfRange(data, 0x00, 0x64)); + int offset = 0x00; + for(int i = 0;i>>" + log); + log("" + log); } public static void logErr(String log){ System.err.println("> Error: " + log); diff --git a/src/de/mas/wupclient/client/utils/Utils.java b/src/de/mas/wupclient/client/utils/Utils.java index 758ed91..5d57ec8 100644 --- a/src/de/mas/wupclient/client/utils/Utils.java +++ b/src/de/mas/wupclient/client/utils/Utils.java @@ -44,7 +44,7 @@ public class Utils { public static String getStringFromByteArray(byte[] data){ int i = 0; - while(data[i] != 0 && (i) < data.length){ + while(data[i] != 0 && (i) < data.length-1){ i++; } String string = ""; @@ -145,8 +145,23 @@ public class Utils { return null; } - public static void createSubfolder(String folder){ + public static String getParentDir(String path){ + if(path == null || path.isEmpty() || path.equals("/")){ + return "/"; + } + String new_path = ""; + String [] pathpath = path.split("/"); + for(int i = 0;i