diff --git a/pySim-shell.py b/pySim-shell.py index a8471ff5..9468444a 100755 --- a/pySim-shell.py +++ b/pySim-shell.py @@ -67,11 +67,17 @@ class PysimApp(cmd2.Cmd): self.numeric_path = False self.add_settable(cmd2.Settable('numeric_path', bool, 'Print File IDs instead of names', onchange_cb=self._onchange_numeric_path)) + self.conserve_write = True + self.add_settable(cmd2.Settable('conserve_write', bool, 'Read and compare before write', + onchange_cb=self._onchange_conserve_write)) self.update_prompt() def _onchange_numeric_path(self, param_name, old, new): self.update_prompt() + def _onchange_conserve_write(self, param_name, old, new): + self.rs.conserve_write = new + def update_prompt(self): path_list = self.rs.selected_file.fully_qualified_path(not self.numeric_path) self.prompt = 'pySIM-shell (%s)> ' % ('/'.join(path_list)) diff --git a/pySim/commands.py b/pySim/commands.py index 9aed5882..65c38915 100644 --- a/pySim/commands.py +++ b/pySim/commands.py @@ -144,9 +144,17 @@ class SimCardCommands(object): raise ValueError('Failed to read (offset %d)' % (offset)) return total_data, sw - def update_binary(self, ef, data, offset=0, verify=False): + def update_binary(self, ef, data, offset=0, verify=False, conserve=False): + data_length = len(data) // 2 + + # Save write cycles by reading+comparing before write + if conserve: + data_current, sw = self.read_binary(ef, data_length, offset) + if data_current == data: + return None, sw + self.select_path(ef) - pdu = self.cla_byte + 'd6%04x%02x' % (offset, len(data) // 2) + data + pdu = self.cla_byte + 'd6%04x%02x' % (offset, data_length) + data res = self._tp.send_apdu_checksw(pdu) if verify: self.verify_binary(ef, data, offset) @@ -163,7 +171,7 @@ class SimCardCommands(object): pdu = self.cla_byte + 'b2%02x04%02x' % (rec_no, rec_length) return self._tp.send_apdu(pdu) - def update_record(self, ef, rec_no, data, force_len=False, verify=False): + def update_record(self, ef, rec_no, data, force_len=False, verify=False, conserve=False): r = self.select_path(ef) if not force_len: rec_length = self.__record_len(r) @@ -171,6 +179,14 @@ class SimCardCommands(object): raise ValueError('Invalid data length (expected %d, got %d)' % (rec_length, len(data) // 2)) else: rec_length = len(data) // 2 + + # Save write cycles by reading+comparing before write + if conserve: + data_current, sw = self.read_record(ef, rec_no) + data_current = data_current[0:rec_length*2] + if data_current == data: + return None, sw + pdu = (self.cla_byte + 'dc%02x04%02x' % (rec_no, rec_length)) + data res = self._tp.send_apdu_checksw(pdu) if verify: diff --git a/pySim/filesystem.py b/pySim/filesystem.py index cd08699d..e959c525 100644 --- a/pySim/filesystem.py +++ b/pySim/filesystem.py @@ -566,6 +566,7 @@ class RuntimeState(object): self.mf.add_application(a) for f in self.profile.files_in_mf: self.mf.add_file(f) + self.conserve_write = True def _match_applications(self): """match the applications from the profile with applications on the card""" @@ -699,7 +700,7 @@ class RuntimeState(object): def update_binary(self, data_hex, offset=0): if not isinstance(self.selected_file, TransparentEF): raise TypeError("Only works with TransparentEF") - return self.card._scc.update_binary(self.selected_file.fid, data_hex, offset) + return self.card._scc.update_binary(self.selected_file.fid, data_hex, offset, conserve=self.conserve_write) def update_binary_dec(self, data): data_hex = self.selected_file.encode_hex(data) @@ -719,7 +720,7 @@ class RuntimeState(object): def update_record(self, rec_nr, data_hex): if not isinstance(self.selected_file, LinFixedEF): raise TypeError("Only works with Linear Fixed EF") - return self.card._scc.update_record(self.selected_file.fid, rec_nr, data_hex) + return self.card._scc.update_record(self.selected_file.fid, rec_nr, data_hex, conserve=self.conserve_write) def update_record_dec(self, rec_nr, data): hex_data = self.selected_file.encode_record_hex(data)