From c146d449602dd407b9d472a6d28eb468ea7f5a31 Mon Sep 17 00:00:00 2001 From: friedkeenan Date: Sun, 7 Apr 2019 19:26:50 -0500 Subject: [PATCH 01/16] Basically a complete rewrite for the latestcommits of Goldleaf. Lackluster Windows support --- Goldtree.py | 278 +++++++++++++++++++++++++++++------------------ PFS0.py | 38 ------- requirements.txt | 2 + 3 files changed, 175 insertions(+), 143 deletions(-) delete mode 100644 PFS0.py create mode 100644 requirements.txt diff --git a/Goldtree.py b/Goldtree.py index 567a80d..5f2ddd9 100755 --- a/Goldtree.py +++ b/Goldtree.py @@ -5,138 +5,206 @@ import struct import sys import os - -from PFS0 import PFS0 +import shutil +import psutil def get_switch(): - dev=usb.core.find(idVendor=0x057e, idProduct=0x3000) + dev = usb.core.find(idVendor=0x057e, idProduct=0x3000) if dev is None: raise ValueError("Device not found") return dev + def get_ep(dev): dev.set_configuration() intf=dev.get_active_configuration()[(0,0)] return (usb.util.find_descriptor(intf, - custom_match=lambda e:usb.util.endpoint_direction(e.bEndpointAddress)==usb.util.ENDPOINT_OUT), + custom_match=lambda e:usb.util.endpoint_direction(e.bEndpointAddress)==usb.util.ENDPOINT_OUT), usb.util.find_descriptor(intf, - custom_match=lambda e:usb.util.endpoint_direction(e.bEndpointAddress)==usb.util.ENDPOINT_IN)) + custom_match=lambda e:usb.util.endpoint_direction(e.bEndpointAddress)==usb.util.ENDPOINT_IN)) + +dev=get_switch() +ep=get_ep(dev) + +def write(buffer, timeout=3000): + ep[0].write(buffer, timeout=timeout) + +def read(length, timeout=3000): + return ep[1].read(length, timeout=timeout).tobytes() + +def write_u32(x): + write(struct.pack(">= 1 + for d in sys.argv[1:]: + folder = os.path.dirname(os.path.abspath(d)) + drives[os.path.basename(folder)] = folder + print(drives) + write_u32(len(drives)) + for d in drives: + write_string(d) + write_string(d) + elif c.has_id(CommandId.GetPathType): + ptype = 0 + path = read_path() + if os.path.isfile(path): + ptype = 1 + elif os.path.isdir(path): + ptype = 2 + write_u32(ptype) + elif c.has_id(CommandId.ListDirectories): + path=read_path() + ents=[x for x in os.listdir(path) if os.path.isdir(os.path.join(path, x))] + write_u32(len(ents)) + for name in ents: + write_string(name) + elif c.has_id(CommandId.ListFiles): + path=read_path() + ents=[x for x in os.listdir(path) if os.path.isfile(os.path.join(path, x))] + write_u32(len(ents)) + for name in ents: + write_string(name) + elif c.has_id(CommandId.GetFileSize): + path = read_path() + write_u64(os.path.getsize(path)) + elif c.has_id(CommandId.FileRead): + offset = read_u64() + size = read_u64() + path = read_path() + print(f"FileRead - Path: {path}, Offset: {offset}, Size: {size}") + with open(path, "rb") as f: + f.seek(offset) + data = f.read(size) + write_u64(len(data)) + print(f"FileRead - Read bytes: {len(data)}") + write(data) + elif c.has_id(CommandId.FileWrite): + path = read_path() + read_u32() # Hardcoded to zero + offset = read_u32() + size = read_u32() + data = read(size) + print(f"FileWrite - Path: ({path}), Offset: {offset}, Size: {size}") + with open(path, "rwb") as f: + cont=bytearray(f.read()) + cont[offset:offset + size] = data + f.write(cont) + elif c.has_id(CommandId.CreateFile): + path = read_path() + open(path, "a").close() + elif c.has_id(CommandId.CreateDirectory): + path = read_path() + try: + os.mkdir(path) + except os.FileExistsError: + pass + elif c.has_id(CommandId.DeleteFile): + path = read_path() + os.remove(path) + elif c.has_id(CommandId.DeleteDirectory): + path = read_path() + shutil.rmtree(path) + elif c.has_id(CommandId.RenameFile) or c.has_id(CommandId.RenameDirectory): + path = read_path() + new_name = read_string() + os.rename(path, new_name) + elif c.has_id(CommandId.GetDriveTotalSpace): + path = read_path() + write_u64(psutil.disk_usage(path).total) + elif c.has_id(CommandId.GetDriveFreeSpace): + path = read_path() + write_u64(psutil.disk_usage(path).free) + return 0 -if __name__=="__main__": +if __name__ == "__main__": sys.exit(main()) - diff --git a/PFS0.py b/PFS0.py deleted file mode 100644 index 7dbf986..0000000 --- a/PFS0.py +++ /dev/null @@ -1,38 +0,0 @@ -import struct - -class PFS0: - class FileEntry: - def __init__(self,data): - self.file_offset=struct.unpack("0: - tor=min(chunk_size,to_read) - yield self.read_raw(cur_offset,tor) - cur_offset+=tor - to_read-=tor diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..97efee7 --- /dev/null +++ b/requirements.txt @@ -0,0 +1,2 @@ +pyusb +psutil \ No newline at end of file From d2d6afa51e07a87e6c8cf5978a38bea669751249 Mon Sep 17 00:00:00 2001 From: friedkeenan Date: Sun, 7 Apr 2019 19:39:43 -0500 Subject: [PATCH 02/16] Update README and fix small bug --- Goldtree.py | 4 +++- README.md | 6 +++++- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/Goldtree.py b/Goldtree.py index 5f2ddd9..d3652cd 100755 --- a/Goldtree.py +++ b/Goldtree.py @@ -126,7 +126,9 @@ def main(): drives[letter] = letter + ":" bitmask >>= 1 for d in sys.argv[1:]: - folder = os.path.dirname(os.path.abspath(d)) + folder = os.path.abspath(d) + if os.path.isfile(folder): + folder = os.path.dirname(folder) drives[os.path.basename(folder)] = folder print(drives) write_u32(len(drives)) diff --git a/README.md b/README.md index cfbc389..d2c6c70 100644 --- a/README.md +++ b/README.md @@ -2,4 +2,8 @@ A python port of XorTroll's [Goldtree](https://github.com/XorTroll/Goldleaf/tree/master/Goldtree) -To use, open **USB Installation** in Goldleaf, then do `sudo ./Goldtree.py [nsp file]` on your computer. It requires [pyusb](https://github.com/pyusb/pyusb). +To use, open Goldleaf, do `sudo ./Goldtree.py [...]`, and then open **Browse PC drive** in Goldleaf. The arguments will show up as separate drives in Goldleaf so that you don't have to navigate to the folders/files from the root of your computer. + +To install all the dependencies, do `pip3 install -r requirements.txt`. + +Windows support is very lackluster at the moment, and is very prone to crashing. From 13edb8a10fc623f45da3906bb7abdd4673de9649 Mon Sep 17 00:00:00 2001 From: friedkeenan Date: Fri, 17 May 2019 12:12:21 -0500 Subject: [PATCH 03/16] Some small changes for latest GL code, not wuite finished yet --- Goldtree.py | 96 ++++++++++++++++++++++++++++++----------------------- README.md | 2 +- 2 files changed, 55 insertions(+), 43 deletions(-) diff --git a/Goldtree.py b/Goldtree.py index d3652cd..3ca64af 100755 --- a/Goldtree.py +++ b/Goldtree.py @@ -16,14 +16,14 @@ def get_switch(): def get_ep(dev): dev.set_configuration() - intf=dev.get_active_configuration()[(0,0)] + intf = dev.get_active_configuration()[(0,0)] return (usb.util.find_descriptor(intf, custom_match=lambda e:usb.util.endpoint_direction(e.bEndpointAddress)==usb.util.ENDPOINT_OUT), usb.util.find_descriptor(intf, custom_match=lambda e:usb.util.endpoint_direction(e.bEndpointAddress)==usb.util.ENDPOINT_IN)) -dev=get_switch() -ep=get_ep(dev) +dev = get_switch() +ep = get_ep(dev) def write(buffer, timeout=3000): ep[0].write(buffer, timeout=timeout) @@ -50,59 +50,69 @@ def read_u64(): def read_string(): return read(read_u32() + 1)[:-1].decode() +class CommandReadResult: # Currently not used in this code, but used in original Goldtree + Success = 0 + InvalidMagic = 1 + InvalidCommandId = 2 class CommandId: ListSystemDrives = 0 - GetPathType = 1 - ListDirectories = 2 - ListFiles = 3 - GetFileSize = 4 - FileRead = 5 - FileWrite = 6 - CreateFile = 7 - CreateDirectory = 8 - DeleteFile = 9 - DeleteDirectory = 10 - RenameFile = 11 - RenameDirectory = 12 - GetDriveTotalSpace = 13 - GetDriveFreeSpace = 14 - GetNSPContents = 15 + GetEnvironmentPaths = 1 + GetPathType = 2 + ListDirectories = 3 + ListFiles = 4 + GetFileSize = 5 + FileRead = 6 + FileWrite = 7 + CreateFile = 8 + CreateDirectory = 9 + DeleteFile = 10 + DeleteDirectory = 12 + RenameFile = 13 + RenameDirectory = 13 + GetDriveTotalSpace = 14 + GetDriveFreeSpace = 15 + GetNSPContents = 16 + Max = 17 class Command: - GUCI = b"GUCI" - GUCO = b"GUCO" - def __init__(self, cmd_id=0, out=True, raw=None): - self.out = out - if raw is None: + + GLUC = b"GLUC" + + def __init__(self, cmd_id=0, out=True): + if out: self.cmd_id = cmd_id - if out: - self.magic = self.GUCO - else: - self.magic = self.GUCI + self.magic = self.GLUC else: - self.magic = raw[:4] - self.cmd_id = struct.unpack("...]`, and then open **Browse PC drive** in Goldleaf. The arguments will show up as separate drives in Goldleaf so that you don't have to navigate to the folders/files from the root of your computer. +To use, open Goldleaf, do `sudo ./Goldtree.py [...]` (`sudo` isn't required if you use udev rules), and then open **Browse PC drive** in Goldleaf. The arguments will show up as separate drives in Goldleaf so that you don't have to navigate to the folders/files from the root of your computer. To install all the dependencies, do `pip3 install -r requirements.txt`. From f6f63ce395c0bcaac8516d2a6196dbc5e51fa092 Mon Sep 17 00:00:00 2001 From: friedkeenan Date: Fri, 17 May 2019 14:26:26 -0500 Subject: [PATCH 04/16] Small, meaningless change towards paths and drives --- Goldtree.py | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/Goldtree.py b/Goldtree.py index 3ca64af..4d8eaf1 100755 --- a/Goldtree.py +++ b/Goldtree.py @@ -110,7 +110,7 @@ def read_path(): path = read_string() drive = path.split(":", 1)[0] try: - path = path.replace(drive + ":", drives[drive]) + path = path.replace(drive + ":/", drives[drive]) except KeyError: pass return path @@ -132,14 +132,13 @@ def main(): bitmask = windll.kernel32.GetLogicalDrives() for letter in string.ascii_uppercase: if bitmask & 1: - print(letter) - drives[letter] = letter + ":" + drives[letter] = letter + ":/" bitmask >>= 1 for d in sys.argv[1:]: folder = os.path.abspath(d) if os.path.isfile(folder): folder = os.path.dirname(folder) - drives[os.path.basename(folder)] = folder + drives[os.path.basename(folder)] = folder + "/" write_u32(len(drives)) for d in drives: write_string(d) From f7b1155446ba33abdab586f637477a6df0d343d5 Mon Sep 17 00:00:00 2001 From: friedkeenan Date: Fri, 17 May 2019 18:03:13 -0500 Subject: [PATCH 05/16] Fix environment paths --- Goldtree.py | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/Goldtree.py b/Goldtree.py index 4d8eaf1..6662d8e 100755 --- a/Goldtree.py +++ b/Goldtree.py @@ -123,6 +123,8 @@ def main(): break except usb.core.USBError: pass + except KeyboardInterrupt: + return 0 if c.has_id(CommandId.ListSystemDrives): if "win" not in sys.platform: drives["ROOT"] = "/" @@ -134,22 +136,25 @@ def main(): if bitmask & 1: drives[letter] = letter + ":/" bitmask >>= 1 - for d in sys.argv[1:]: - folder = os.path.abspath(d) - if os.path.isfile(folder): - folder = os.path.dirname(folder) - drives[os.path.basename(folder)] = folder + "/" write_u32(len(drives)) for d in drives: write_string(d) write_string(d) - elif c.has_id(CommandId.GetEnvironmentPaths): # Currently broken + elif c.has_id(CommandId.GetEnvironmentPaths): env_paths = {x:os.path.expanduser("~/"+x) for x in ["Desktop", "Documents"]} + + for arg in sys.argv[1:]: # Add arguments as environment paths + folder = os.path.abspath(arg) + if os.path.isfile(folder): + folder = os.path.dirname(folder) + env_paths[os.path.basename(folder)] = folder + write_u32(len(env_paths)) for env in env_paths: write_string(env) + if ":/" not in env_paths[env]: + env_paths[env] = "ROOT:" + env_paths[env] write_string(env_paths[env]) - print(env, env_paths[env]) elif c.has_id(CommandId.GetPathType): ptype = 0 path = read_path() From 312928e13db971c57902b2304379d1737e45ef37 Mon Sep 17 00:00:00 2001 From: friedkeenan Date: Fri, 17 May 2019 18:07:58 -0500 Subject: [PATCH 06/16] Forgot to update the readme --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index a7f1095..e5b1b03 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ A python port of XorTroll's [Goldtree](https://github.com/XorTroll/Goldleaf/tree/master/Goldtree) -To use, open Goldleaf, do `sudo ./Goldtree.py [...]` (`sudo` isn't required if you use udev rules), and then open **Browse PC drive** in Goldleaf. The arguments will show up as separate drives in Goldleaf so that you don't have to navigate to the folders/files from the root of your computer. +To use, open Goldleaf, do `sudo ./Goldtree.py [...]` (`sudo` isn't required if you use udev rules), and then open **Browse PC drive** in Goldleaf. The arguments will show up as environment paths in Goldleaf so that you don't have to navigate to the folders/files from the root of your computer. To install all the dependencies, do `pip3 install -r requirements.txt`. From b7ca6c8d7bc232633303e220efb635e631bbb1a4 Mon Sep 17 00:00:00 2001 From: friedkeenan Date: Fri, 17 May 2019 18:09:48 -0500 Subject: [PATCH 07/16] Give correct instructions for latest Goldleaf --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index e5b1b03..091e83d 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ A python port of XorTroll's [Goldtree](https://github.com/XorTroll/Goldleaf/tree/master/Goldtree) -To use, open Goldleaf, do `sudo ./Goldtree.py [...]` (`sudo` isn't required if you use udev rules), and then open **Browse PC drive** in Goldleaf. The arguments will show up as environment paths in Goldleaf so that you don't have to navigate to the folders/files from the root of your computer. +To use, open Goldleaf, do `sudo ./Goldtree.py [...]` (`sudo` isn't required if you use udev rules), and then open **Explore content -> PC drive (via USB)** in Goldleaf. The arguments will show up as environment paths in Goldleaf so that you don't have to navigate to the folders/files from the root of your computer. To install all the dependencies, do `pip3 install -r requirements.txt`. From 2c0f960bb4fa7b83ea3644dede6a41ca56024001 Mon Sep 17 00:00:00 2001 From: friedkeenan Date: Sat, 18 May 2019 10:22:27 -0500 Subject: [PATCH 08/16] Fix Windows support --- Goldtree.py | 27 +++++++++++++++++++++++---- README.md | 4 +--- 2 files changed, 24 insertions(+), 7 deletions(-) diff --git a/Goldtree.py b/Goldtree.py index 6662d8e..002d5b6 100755 --- a/Goldtree.py +++ b/Goldtree.py @@ -126,19 +126,37 @@ def main(): except KeyboardInterrupt: return 0 if c.has_id(CommandId.ListSystemDrives): + drive_labels = {} if "win" not in sys.platform: drives["ROOT"] = "/" else: import string - from ctypes import windll - bitmask = windll.kernel32.GetLogicalDrives() + import ctypes + kernel32 = ctypes.windll.kernel32 + bitmask = kernel32.GetLogicalDrives() for letter in string.ascii_uppercase: if bitmask & 1: drives[letter] = letter + ":/" + label_buf = ctypes.create_unicode_buffer(1024) + kernel32.GetVolumeInformationW( + ctypes.c_wchar_p(letter + ":\\"), + label_buf, + ctypes.sizeof(label_buf), + None, + None, + None, + None, + 0 + ) + if label_buf.value: + drive_labels[letter] = label_buf.value bitmask >>= 1 write_u32(len(drives)) for d in drives: - write_string(d) + try: + write_string(drive_labels[d]) + except KeyError: + write_string(d) write_string(d) elif c.has_id(CommandId.GetEnvironmentPaths): env_paths = {x:os.path.expanduser("~/"+x) for x in ["Desktop", "Documents"]} @@ -151,8 +169,9 @@ def main(): write_u32(len(env_paths)) for env in env_paths: + env_paths[env] = env_paths[env].replace("\\", "/") write_string(env) - if ":/" not in env_paths[env]: + if env_paths[env][1:3] != ":/": env_paths[env] = "ROOT:" + env_paths[env] write_string(env_paths[env]) elif c.has_id(CommandId.GetPathType): diff --git a/README.md b/README.md index 091e83d..ac5b41b 100644 --- a/README.md +++ b/README.md @@ -4,6 +4,4 @@ A python port of XorTroll's [Goldtree](https://github.com/XorTroll/Goldleaf/tree To use, open Goldleaf, do `sudo ./Goldtree.py [...]` (`sudo` isn't required if you use udev rules), and then open **Explore content -> PC drive (via USB)** in Goldleaf. The arguments will show up as environment paths in Goldleaf so that you don't have to navigate to the folders/files from the root of your computer. -To install all the dependencies, do `pip3 install -r requirements.txt`. - -Windows support is very lackluster at the moment, and is very prone to crashing. +To install all the dependencies, do `pip3 install -r requirements.txt`. \ No newline at end of file From fd9e561140d5ee005b29b9df5dc6c3422794ed45 Mon Sep 17 00:00:00 2001 From: friedkeenan Date: Sat, 18 May 2019 11:14:05 -0500 Subject: [PATCH 09/16] Fixed file writing --- Goldtree.py | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/Goldtree.py b/Goldtree.py index 002d5b6..f7b1634 100755 --- a/Goldtree.py +++ b/Goldtree.py @@ -207,13 +207,18 @@ def main(): write_u64(len(data)) write(data) elif c.has_id(CommandId.FileWrite): - path = read_path() offset = read_u64() size = read_u64() + path = read_path() data = read(size) - with open(path, "rwb") as f: - cont=bytearray(f.read()) - cont[offset:offset + size] = data + cont = bytearray() + try: + with open(path, "rb") as f: + cont=bytearray(f.read()) + except FileNotFoundError: + pass + cont[offset:offset + size] = data + with open(path, "wb") as f: f.write(cont) elif c.has_id(CommandId.CreateFile): path = read_path() @@ -222,7 +227,7 @@ def main(): path = read_path() try: os.mkdir(path) - except os.FileExistsError: + except FileExistsError: pass elif c.has_id(CommandId.DeleteFile): path = read_path() From ea0f892abcf1a19411de4b4135204c63f192d8e3 Mon Sep 17 00:00:00 2001 From: friedkeenan Date: Sat, 18 May 2019 12:15:00 -0500 Subject: [PATCH 10/16] Fixed renaming stuff --- Goldtree.py | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/Goldtree.py b/Goldtree.py index f7b1634..e347497 100755 --- a/Goldtree.py +++ b/Goldtree.py @@ -67,8 +67,8 @@ class CommandId: CreateFile = 8 CreateDirectory = 9 DeleteFile = 10 - DeleteDirectory = 12 - RenameFile = 13 + DeleteDirectory = 11 + RenameFile = 12 RenameDirectory = 13 GetDriveTotalSpace = 14 GetDriveFreeSpace = 15 @@ -235,9 +235,13 @@ def main(): elif c.has_id(CommandId.DeleteDirectory): path = read_path() shutil.rmtree(path) - elif c.has_id(CommandId.RenameFile) or c.has_id(CommandId.RenameDirectory): + elif c.has_id(CommandId.RenameFile): path = read_path() new_name = read_string() + os.rename(path, f"{os.path.dirname(path)}/{new_name}") + elif c.has_id(CommandId.RenameDirectory): + path = read_path() + new_name = read_path() os.rename(path, new_name) elif c.has_id(CommandId.GetDriveTotalSpace): path = read_path() From 3d98cbdfa2260b1c648b2be0dd538102137cb59a Mon Sep 17 00:00:00 2001 From: friedkeenan Date: Sat, 18 May 2019 12:27:06 -0500 Subject: [PATCH 11/16] Clean up code --- Goldtree.py | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/Goldtree.py b/Goldtree.py index e347497..abd824b 100755 --- a/Goldtree.py +++ b/Goldtree.py @@ -183,8 +183,8 @@ def main(): ptype = 2 write_u32(ptype) elif c.has_id(CommandId.ListDirectories): - path=read_path() - ents=[x for x in os.listdir(path) if os.path.isdir(os.path.join(path, x))] + path = read_path() + ents = [x for x in os.listdir(path) if os.path.isdir(os.path.join(path, x))] write_u32(len(ents)) for name in ents: write_string(name) @@ -211,12 +211,11 @@ def main(): size = read_u64() path = read_path() data = read(size) - cont = bytearray() try: with open(path, "rb") as f: - cont=bytearray(f.read()) + cont = bytearray(f.read()) except FileNotFoundError: - pass + cont = bytearray() cont[offset:offset + size] = data with open(path, "wb") as f: f.write(cont) From 196794ebfb3384d7f52389d4ad3e7d3c265d6470 Mon Sep 17 00:00:00 2001 From: fourminute <38321299+fourminute@users.noreply.github.com> Date: Sun, 19 May 2019 12:49:29 -0700 Subject: [PATCH 12/16] MacOS Fix. (#8) `sys.platform` on Mac OS is "darwin" which made the script think Mac OS was Windows because of the "win" --- Goldtree.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Goldtree.py b/Goldtree.py index abd824b..7815a14 100755 --- a/Goldtree.py +++ b/Goldtree.py @@ -127,9 +127,7 @@ def main(): return 0 if c.has_id(CommandId.ListSystemDrives): drive_labels = {} - if "win" not in sys.platform: - drives["ROOT"] = "/" - else: + if "win" in sys.platform[:3].lower(): import string import ctypes kernel32 = ctypes.windll.kernel32 @@ -151,6 +149,8 @@ def main(): if label_buf.value: drive_labels[letter] = label_buf.value bitmask >>= 1 + else: + drives["ROOT"] = "/" write_u32(len(drives)) for d in drives: try: From 5468b0b23d31b753c8920389f762bcb1205a5259 Mon Sep 17 00:00:00 2001 From: friedkeenan Date: Tue, 21 May 2019 10:39:24 -0500 Subject: [PATCH 13/16] Only send environment paths if they exist --- Goldtree.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Goldtree.py b/Goldtree.py index 7815a14..fb669a7 100755 --- a/Goldtree.py +++ b/Goldtree.py @@ -167,6 +167,8 @@ def main(): folder = os.path.dirname(folder) env_paths[os.path.basename(folder)] = folder + env_paths = {x:env_paths[x] for x in env_paths if os.path.exists(env_paths[x])} + write_u32(len(env_paths)) for env in env_paths: env_paths[env] = env_paths[env].replace("\\", "/") From eb10ae2026942183003c5bf89d91cffa3653a05a Mon Sep 17 00:00:00 2001 From: friedkeenan Date: Fri, 7 Jun 2019 20:10:19 -0500 Subject: [PATCH 14/16] Get rid of stupid psutil dependency --- Goldtree.py | 5 ++--- requirements.txt | 3 +-- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/Goldtree.py b/Goldtree.py index fb669a7..4c03653 100755 --- a/Goldtree.py +++ b/Goldtree.py @@ -6,7 +6,6 @@ import sys import os import shutil -import psutil def get_switch(): dev = usb.core.find(idVendor=0x057e, idProduct=0x3000) @@ -246,10 +245,10 @@ def main(): os.rename(path, new_name) elif c.has_id(CommandId.GetDriveTotalSpace): path = read_path() - write_u64(psutil.disk_usage(path).total) + write_u64(shutil.disk_usage(path).total) elif c.has_id(CommandId.GetDriveFreeSpace): path = read_path() - write_u64(psutil.disk_usage(path).free) + write_u64(shutil.disk_usage(path).free) return 0 diff --git a/requirements.txt b/requirements.txt index 97efee7..af159f1 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,2 +1 @@ -pyusb -psutil \ No newline at end of file +pyusb \ No newline at end of file From d7e280ab56d10c1e0d0bafac13dfff65f36251cc Mon Sep 17 00:00:00 2001 From: friedkeenan Date: Sat, 3 Aug 2019 14:45:09 -0500 Subject: [PATCH 15/16] Update for latest Goldleaf, drop Windows support --- Goldtree.py | 604 +++++++++++++++++++++++++++++++++------------------- README.md | 2 +- 2 files changed, 391 insertions(+), 215 deletions(-) diff --git a/Goldtree.py b/Goldtree.py index 4c03653..86df339 100755 --- a/Goldtree.py +++ b/Goldtree.py @@ -6,249 +6,425 @@ import sys import os import shutil +import io +from enum import Enum +from pathlib import Path +from collections import OrderedDict -def get_switch(): - dev = usb.core.find(idVendor=0x057e, idProduct=0x3000) - if dev is None: - raise ValueError("Device not found") - return dev - -def get_ep(dev): - dev.set_configuration() - intf = dev.get_active_configuration()[(0,0)] - return (usb.util.find_descriptor(intf, - custom_match=lambda e:usb.util.endpoint_direction(e.bEndpointAddress)==usb.util.ENDPOINT_OUT), - usb.util.find_descriptor(intf, - custom_match=lambda e:usb.util.endpoint_direction(e.bEndpointAddress)==usb.util.ENDPOINT_IN)) - -dev = get_switch() -ep = get_ep(dev) - -def write(buffer, timeout=3000): - ep[0].write(buffer, timeout=timeout) - -def read(length, timeout=3000): - return ep[1].read(length, timeout=timeout).tobytes() - -def write_u32(x): - write(struct.pack(">= 1 + + bufs = [] + + if c.has_id(CommandId.GetDriveCount): + c.handler.add_drive("ROOT", "/") + + c.write_base() + c.write("I", len(c.handler.drives)) + + elif c.has_id(CommandId.GetDriveInfo): + drive_idx = c.read("I") + + if drive_idx >= len(c.handler.drives): + c.write_base(Command.ResultInvalidInput) + + else: + info = c.handler.get_drive(drive_idx) + + c.write_base() + + c.write(info[1][1]) # Label + c.write(info[0]) # Prefix + + usage = shutil.disk_usage(info[1][0]) + c.write("II", usage.free & 0xFFFFFFFF, usage.total & 0xFFFFFFFF) # Not used by Goldleaf but still sent + + elif c.has_id(CommandId.StatPath): + path = c.read(Path) + type = 0 + file_size = 0 + + if path.is_file(): + type = 1 + file_size = path.stat().st_size + elif path.is_dir(): + type = 2 + else: + c.write_base(Command.ResultInvalidInput) + c.send() + continue + + c.write_base() + c.write("II", type, file_size) + + elif c.has_id(CommandId.GetFileCount): + path = c.read(Path) + + if path.is_dir(): + files = [x for x in path.glob("*") if x.is_file()] + c.write_base() + c.write("I", len(files)) + + else: + c.write_base(Command.ResultInvalidInput) + + elif c.has_id(CommandId.GetFile): + path = c.read(Path) + file_idx = c.read("I") + + if path.is_dir(): + files = [x for x in path.glob("*") if x.is_file()] + + if file_idx >= len(files): + c.write_base(Command.ResultInvalidInput) + + else: + c.write_base() + c.write(files[file_idx].name) + + else: + c.write_base(Command.ResultInvalidInput) + + elif c.has_id(CommandId.GetDirectoryCount): + path = c.read(Path) + + if path.is_dir(): + dirs = [x for x in path.glob("*") if x.is_dir()] + c.write_base() + c.write("I", len(dirs)) + + else: + c.write_base(Command.ResultInvalidInput) + + elif c.has_id(CommandId.GetDirectory): + path = c.read(Path) + dir_idx = c.read("I") + + if path.is_dir(): + dirs = [x for x in path.glob("*") if x.is_dir()] + + if dir_idx >= len(dirs): + c.write_base(Command.ResultInvalidInput) + + else: + c.write_base() + c.write(dirs[dir_idx].name) + else: - drives["ROOT"] = "/" - write_u32(len(drives)) - for d in drives: + c.write_base(Command.ResultInvalidInput) + + elif c.has_id(CommandId.ReadFile): + path = c.read(Path) + offset, size = c.read("II") + + try: + with path.open("rb") as f: + f.seek(offset) + bufs.append(f.read(size)) + + c.write_base() + c.write("I", size) + + except: + c.write_base(Command.ResultInvalidInput) + + elif c.has_id(CommandId.WriteFile): + path = c.read(Path) + size = c.read("I") + data = c.handler.read_raw(size) + print(path, data) + + try: + with path.open("wb") as f: + f.write(data) + + c.write_base() + + except: + c.write_base(Command.ResultInvalidInput) + + elif c.has_id(CommandId.Create): + type = c.read("I") + path = c.read(Path) + + if type == 1: try: - write_string(drive_labels[d]) - except KeyError: - write_string(d) - write_string(d) - elif c.has_id(CommandId.GetEnvironmentPaths): - env_paths = {x:os.path.expanduser("~/"+x) for x in ["Desktop", "Documents"]} - - for arg in sys.argv[1:]: # Add arguments as environment paths - folder = os.path.abspath(arg) - if os.path.isfile(folder): - folder = os.path.dirname(folder) - env_paths[os.path.basename(folder)] = folder - - env_paths = {x:env_paths[x] for x in env_paths if os.path.exists(env_paths[x])} - - write_u32(len(env_paths)) - for env in env_paths: - env_paths[env] = env_paths[env].replace("\\", "/") - write_string(env) - if env_paths[env][1:3] != ":/": - env_paths[env] = "ROOT:" + env_paths[env] - write_string(env_paths[env]) - elif c.has_id(CommandId.GetPathType): - ptype = 0 - path = read_path() - if os.path.isfile(path): - ptype = 1 - elif os.path.isdir(path): - ptype = 2 - write_u32(ptype) - elif c.has_id(CommandId.ListDirectories): - path = read_path() - ents = [x for x in os.listdir(path) if os.path.isdir(os.path.join(path, x))] - write_u32(len(ents)) - for name in ents: - write_string(name) - elif c.has_id(CommandId.ListFiles): - path=read_path() - ents=[x for x in os.listdir(path) if os.path.isfile(os.path.join(path, x))] - write_u32(len(ents)) - for name in ents: - write_string(name) - elif c.has_id(CommandId.GetFileSize): - path = read_path() - write_u64(os.path.getsize(path)) - elif c.has_id(CommandId.FileRead): - offset = read_u64() - size = read_u64() - path = read_path() - with open(path, "rb") as f: - f.seek(offset) - data = f.read(size) - write_u64(len(data)) - write(data) - elif c.has_id(CommandId.FileWrite): - offset = read_u64() - size = read_u64() - path = read_path() - data = read(size) + path.touch() + c.write_base() + + except: + c.write_base(Command.ResultInvalidInput) + + elif type == 2: + try: + path.mkdir() + c.write_base() + + except: + c.write_base(Command.ResultInvalidInput) + + else: + c.write_base(Command.ResultInvalidInput) + + elif c.has_id(CommandId.Delete): + type = c.read("I") + path = c.read(Path) + + try: + if type == 1: + os.remove(path) + c.write_base() + + elif type == 2: + shutil.rmtree(path) + c.write_base() + + else: + c.write_base(Command.ResultInvalidInput) + except: + c.write_base(Command.ResultInvalidInput) + + elif c.has_id(CommandId.Rename): + type = c.read("I") + path = c.read(Path) + new_path = c.read(Path) + try: - with open(path, "rb") as f: - cont = bytearray(f.read()) - except FileNotFoundError: - cont = bytearray() - cont[offset:offset + size] = data - with open(path, "wb") as f: - f.write(cont) - elif c.has_id(CommandId.CreateFile): - path = read_path() - open(path, "a").close() - elif c.has_id(CommandId.CreateDirectory): - path = read_path() + path.rename(new_path) + c.write_base() + + except: + c.write_base(Command.ResultInvalidInput) + + elif c.has_id(CommandId.GetSpecialPathCount): + c.write_base() + c.write("I", len(special_paths)) + + elif c.has_id(CommandId.GetSpecialPath): + spath_idx = c.read("I") + + if spath_idx >= len(special_paths): + c.write_base(Command.ResultInvalidInput) + + else: + info = list(special_paths.items())[spath_idx] + + c.write_base() + c.write(info[0]) + c.write(info[1]) + + elif c.has_id(CommandId.SelectFile): # Never used try: - os.mkdir(path) - except FileExistsError: - pass - elif c.has_id(CommandId.DeleteFile): - path = read_path() - os.remove(path) - elif c.has_id(CommandId.DeleteDirectory): - path = read_path() - shutil.rmtree(path) - elif c.has_id(CommandId.RenameFile): - path = read_path() - new_name = read_string() - os.rename(path, f"{os.path.dirname(path)}/{new_name}") - elif c.has_id(CommandId.RenameDirectory): - path = read_path() - new_name = read_path() - os.rename(path, new_name) - elif c.has_id(CommandId.GetDriveTotalSpace): - path = read_path() - write_u64(shutil.disk_usage(path).total) - elif c.has_id(CommandId.GetDriveFreeSpace): - path = read_path() - write_u64(shutil.disk_usage(path).free) + path = Path(input("Select file for Goldleaf: ")) + c.write_base() + c.write(path) + + except: + c.write_base(Command.ResultInvalidInput) + + c.send() + + for buf in bufs: + c.handler.write_raw(buf) return 0 diff --git a/README.md b/README.md index ac5b41b..30aa260 100644 --- a/README.md +++ b/README.md @@ -2,6 +2,6 @@ A python port of XorTroll's [Goldtree](https://github.com/XorTroll/Goldleaf/tree/master/Goldtree) -To use, open Goldleaf, do `sudo ./Goldtree.py [...]` (`sudo` isn't required if you use udev rules), and then open **Explore content -> PC drive (via USB)** in Goldleaf. The arguments will show up as environment paths in Goldleaf so that you don't have to navigate to the folders/files from the root of your computer. +To use, open Goldleaf, do `sudo ./Goldtree.py [...]` (`sudo` isn't required if you use udev rules), and then open **Explore content -> Remote PC (via USB)** in Goldleaf. The arguments will show up as environment paths in Goldleaf so that you don't have to navigate to the folders/files from the root of your computer. To install all the dependencies, do `pip3 install -r requirements.txt`. \ No newline at end of file From 3ccabfc0c668f154c53acec337f40203ed975ce3 Mon Sep 17 00:00:00 2001 From: friedkeenan Date: Tue, 6 Aug 2019 16:51:03 -0500 Subject: [PATCH 16/16] Update for Goldleaf v0.6.1 --- Goldtree.py | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/Goldtree.py b/Goldtree.py index 86df339..28d633e 100755 --- a/Goldtree.py +++ b/Goldtree.py @@ -12,7 +12,7 @@ from collections import OrderedDict class USBHandler: - CommandBlockLength = 0x2000 + CommandBlockLength = 0x1000 def __init__(self, idVendor=0x057e, idProduct=0x3000): super().__init__() @@ -235,8 +235,10 @@ def main(): c.write(info[1][1]) # Label c.write(info[0]) # Prefix - usage = shutil.disk_usage(info[1][0]) - c.write("II", usage.free & 0xFFFFFFFF, usage.total & 0xFFFFFFFF) # Not used by Goldleaf but still sent + #usage = shutil.disk_usage(info[1][0]) + #c.write("II", usage.free & 0xFFFFFFFF, usage.total & 0xFFFFFFFF) # Not used by Goldleaf but still sent + + c.write("II", 0, 0) # Stubbed free/total space (not used by Goldleaf) elif c.has_id(CommandId.StatPath): path = c.read(Path) @@ -254,7 +256,7 @@ def main(): continue c.write_base() - c.write("II", type, file_size) + c.write("IQ", type, file_size) elif c.has_id(CommandId.GetFileCount): path = c.read(Path) @@ -314,7 +316,7 @@ def main(): elif c.has_id(CommandId.ReadFile): path = c.read(Path) - offset, size = c.read("II") + offset, size = c.read("QQ") try: with path.open("rb") as f: @@ -322,14 +324,14 @@ def main(): bufs.append(f.read(size)) c.write_base() - c.write("I", size) + c.write("Q", size) except: c.write_base(Command.ResultInvalidInput) elif c.has_id(CommandId.WriteFile): path = c.read(Path) - size = c.read("I") + size = c.read("Q") data = c.handler.read_raw(size) print(path, data)