From 5c9702863a8570d25988ba22a857cba567e4aa28 Mon Sep 17 00:00:00 2001 From: Matthias Urlichs Date: Sun, 13 Jan 2019 18:39:05 +0100 Subject: [PATCH 1/4] Add resume to dumping --- partitions.py | 29 +++++++++++++++++++++-------- 1 file changed, 21 insertions(+), 8 deletions(-) diff --git a/partitions.py b/partitions.py index 190512f..f9d4ec8 100755 --- a/partitions.py +++ b/partitions.py @@ -11,6 +11,7 @@ import argparse, logging, os, io, struct, sys import lglaf import gpt +import os _logger = logging.getLogger("partitions") @@ -95,10 +96,20 @@ def laf_write(comm, fd_num, offset, data): def open_local_writable(path): if path == '-': - try: return sys.stdout.buffer - except: return sys.stdout + try: return (sys.stdout.buffer,0) + except: return (sys.stdout,0) else: - return open(path, "wb") + try: + s = os.stat(path) + except OSError: + s = 0 + f = open(path, "wb") + else: + s = s.st_size + assert not s%BLOCK_SIZE + f = open(path, "ab") + return (f,s) + def open_local_readable(path): if path == '-': @@ -136,12 +147,14 @@ def dump_partition(comm, disk_fd, local_path, part_offset, part_size): # Read offsets must be a multiple of 512 bytes, enforce this read_offset = BLOCK_SIZE * (part_offset // BLOCK_SIZE) end_offset = part_offset + part_size - unaligned_bytes = part_offset % BLOCK_SIZE - _logger.debug("Will read %d bytes at disk offset %d", part_size, part_offset) - if unaligned_bytes: - _logger.debug("Unaligned read, read will start at %d", read_offset) - with open_local_writable(local_path) as f: + _f,s = open_local_writable(local_path) + with _f as f: + read_offset += s + unaligned_bytes = read_offset % BLOCK_SIZE + if unaligned_bytes: + _logger.debug("Unaligned read, read will start at %d", read_offset) + _logger.debug("Will read %d bytes at disk offset %d", part_size, part_offset) # Offset should be aligned to block size. If not, read at most a # whole block and drop the leading bytes. if unaligned_bytes: From 5319018fed1cf25ad70dea8fb377a1f8f1b2b510 Mon Sep 17 00:00:00 2001 From: Mathnerd314 Date: Fri, 8 Apr 2016 19:28:36 -0600 Subject: [PATCH 2/4] Error handling for overflow and timeouts cherry pick from https://github.com/Mathnerd314/lglaf --- lglaf.lua | 6 +++--- lglaf.py | 2 +- partitions.py | 44 ++++++++++++++++++++++++++++++++++++++------ 3 files changed, 42 insertions(+), 10 deletions(-) diff --git a/lglaf.lua b/lglaf.lua index e2dc58a..572913d 100644 --- a/lglaf.lua +++ b/lglaf.lua @@ -42,9 +42,9 @@ function lglaf.dissector(tvb, pinfo, tree) local endpoint = usb_endpoint().value -- Process only bulk packets from (EP 5) and to the device (EP 3) - if not ((endpoint == 0x85 or endpoint == 3) and transfer_type == 3) then - return 0 - end + -- if not ((endpoint == 0x85 or endpoint == 3) and transfer_type == 3) then + -- return 0 + -- end pinfo.cols.protocol = lglaf.name diff --git a/lglaf.py b/lglaf.py index 3bef64d..10d9d5f 100755 --- a/lglaf.py +++ b/lglaf.py @@ -273,7 +273,7 @@ def close(self): class USBCommunication(Communication): VENDOR_ID_LG = 0x1004 # Read timeout. Set to 0 to disable timeouts - READ_TIMEOUT_MS = 60000 + READ_TIMEOUT_MS = 6000 def __init__(self): super(USBCommunication, self).__init__() # Match device using heuristics on the interface/endpoint descriptors, diff --git a/partitions.py b/partitions.py index 190512f..2fd79b4 100755 --- a/partitions.py +++ b/partitions.py @@ -8,9 +8,10 @@ from __future__ import print_function from collections import OrderedDict from contextlib import closing, contextmanager -import argparse, logging, os, io, struct, sys +import argparse, logging, os, io, struct, sys, time import lglaf import gpt +import usb.core, usb.util _logger = logging.getLogger("partitions") @@ -37,7 +38,7 @@ def get_partitions(comm, fd_num): table_data = b'' while read_offset < end_offset: chunksize = min(end_offset - read_offset, BLOCK_SIZE * MAX_BLOCK_SIZE) - data = laf_read(comm, fd_num, read_offset // BLOCK_SIZE, chunksize) + data, fd_num = laf_read(comm, fd_num, read_offset // BLOCK_SIZE, chunksize) table_data += data read_offset += chunksize @@ -67,11 +68,42 @@ def laf_open_disk(comm): def laf_read(comm, fd_num, offset, size): """Read size bytes at the given block offset.""" read_cmd = lglaf.make_request(b'READ', args=[fd_num, offset, size]) - header, response = comm.call(read_cmd) + for attempt in range(3): + try: + header, response = comm.call(read_cmd) + break + except usb.core.USBError as e: + if e.strerror == 'Overflow': + _logger.debug("Overflow on READ %d %d %d", fd_num, offset, size) + for attempt in range(3): + try: + comm.reset() + comm._read(-1) # clear line + break + except usb.core.USBError: pass + continue + elif e.strerror == 'Operation timed out': + _logger.debug("Timeout on READ %d %d %d", fd_num, offset, size) + comm.close() + time.sleep(3) + comm.__init__() + try: + lglaf.try_hello(comm) + except usb.core.USBError: pass + close_cmd = lglaf.make_request(b'CLSE', args=[fd_num]) + comm.call(close_cmd) + open_cmd = lglaf.make_request(b'OPEN', body=b'\0') + open_header = comm.call(open_cmd)[0] + fd_num = read_uint32(open_header, 4) + read_cmd = lglaf.make_request(b'READ', args=[fd_num, offset, size]) + continue + else: + raise # rethrow + # Ensure that response fd, offset and length are sane (match the request) assert read_cmd[4:4+12] == header[4:4+12], "Unexpected read response" assert len(response) == size - return response + return response, fd_num def laf_erase(comm, fd_num, sector_start, sector_count): """TRIM some sectors.""" @@ -146,13 +178,13 @@ def dump_partition(comm, disk_fd, local_path, part_offset, part_size): # whole block and drop the leading bytes. if unaligned_bytes: chunksize = min(end_offset - read_offset, BLOCK_SIZE) - data = laf_read(comm, disk_fd, read_offset // BLOCK_SIZE, chunksize) + data, disk_fd = laf_read(comm, disk_fd, read_offset // BLOCK_SIZE, chunksize) f.write(data[unaligned_bytes:]) read_offset += BLOCK_SIZE while read_offset < end_offset: chunksize = min(end_offset - read_offset, BLOCK_SIZE * MAX_BLOCK_SIZE) - data = laf_read(comm, disk_fd, read_offset // BLOCK_SIZE, chunksize) + data, disk_fd = laf_read(comm, disk_fd, read_offset // BLOCK_SIZE, chunksize) f.write(data) read_offset += chunksize _logger.info("Wrote %d bytes to %s", part_size, local_path) From 1172e23235dfb25b96457bf4d6b270fcf165994b Mon Sep 17 00:00:00 2001 From: Matthias Urlichs Date: Sun, 13 Jan 2019 18:48:22 +0100 Subject: [PATCH 3/4] Raise error on last attempt --- partitions.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/partitions.py b/partitions.py index 42c1c89..af468f3 100755 --- a/partitions.py +++ b/partitions.py @@ -11,6 +11,7 @@ import argparse, logging, os, io, struct, sys, time import lglaf import gpt +import usb.core, usb.util _logger = logging.getLogger("partitions") @@ -72,6 +73,8 @@ def laf_read(comm, fd_num, offset, size): header, response = comm.call(read_cmd) break except usb.core.USBError as e: + if attempt == 2: + raise if e.strerror == 'Overflow': _logger.debug("Overflow on READ %d %d %d", fd_num, offset, size) for attempt in range(3): From 358595c430b6e0255a89ebe58b48a85a5251bbb4 Mon Sep 17 00:00:00 2001 From: Matthias Urlichs Date: Sun, 13 Jan 2019 18:48:48 +0100 Subject: [PATCH 4/4] re-indent --- partitions.py | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/partitions.py b/partitions.py index af468f3..bd68d1b 100755 --- a/partitions.py +++ b/partitions.py @@ -74,15 +74,16 @@ def laf_read(comm, fd_num, offset, size): break except usb.core.USBError as e: if attempt == 2: - raise + raise # last attempt if e.strerror == 'Overflow': _logger.debug("Overflow on READ %d %d %d", fd_num, offset, size) for attempt in range(3): - try: - comm.reset() - comm._read(-1) # clear line - break - except usb.core.USBError: pass + try: + comm.reset() + comm._read(-1) # clear line + break + except usb.core.USBError: + pass continue elif e.strerror == 'Operation timed out': _logger.debug("Timeout on READ %d %d %d", fd_num, offset, size) @@ -90,8 +91,9 @@ def laf_read(comm, fd_num, offset, size): time.sleep(3) comm.__init__() try: - lglaf.try_hello(comm) - except usb.core.USBError: pass + lglaf.try_hello(comm) + except usb.core.USBError: + pass close_cmd = lglaf.make_request(b'CLSE', args=[fd_num]) comm.call(close_cmd) open_cmd = lglaf.make_request(b'OPEN', body=b'\0')