pySim-shell: improve fsdump

In the previous patch we have improved the export command. Since
the implementation of the fsdump command is very similar to the
implementation of the export command we can now apply the same
improvements to the fsdump command as well.

Change-Id: I4d2ef7b383025a5bbf122f18ecd51b7d73aaba14
Related: OS#6092
This commit is contained in:
Philipp Maier
2024-08-08 15:41:10 +02:00
parent c421645ba6
commit 526fdae6e5

View File

@@ -633,118 +633,80 @@ class PySimCommands(CommandSet):
raise RuntimeError( raise RuntimeError(
"unable to export %i dedicated files(s)%s" % (context['ERR'], exception_str_add)) "unable to export %i dedicated files(s)%s" % (context['ERR'], exception_str_add))
def fsdump_df(self, filename, context, as_json): def __dump_file(self, filename, context, as_json):
"""Dump information about currently selected [A]DF""" """ Select and dump a single file (EF, DF or ADF) """
df = self._cmd.lchan.selected_file file = self._cmd.lchan.get_file_by_name(filename)
df_path_list = df.fully_qualified_path(True) if file:
df_path = df.fully_qualified_path_str(True) res = {
'path': file.fully_qualified_path(True)
res = {
'path': df_path_list,
}
try:
if not self._cmd.lchan.selected_file_fcp_hex:
# An application without a real ADF (like ADF.ARA-M) / filesystem
return
fcp_dec = self._cmd.lchan.selected_file_fcp
res['fcp_raw'] = str(self._cmd.lchan.selected_file_fcp_hex)
res['fcp'] = fcp_dec
except SwMatchError as e:
res['error'] = {
'sw_actual': e.sw_actual,
'sw_expected': e.sw_expected,
'message': e.description,
} }
except Exception as e: else:
raise(e) # If this is called from self.__walk(), then it is ensured that the file exists.
res['error'] = { raise RuntimeError("cannot dump, file %s does not exist in the file system tree" % filename)
'message': str(e)
}
context['result']['files'][df_path] = res
def fsdump_ef(self, filename, context, as_json):
"""Select and dump a single elementary file (EF) """
# TODO: this is very similar to export_ef(), but I couldn't really come up with a way to share
# code between the two. They only hypothetical option could be turn "export" into a mere
# post-processing / printing function that works on the fsdump-generated dict/json?
df = self._cmd.lchan.selected_file
# The currently selected file (not the file we are going to export)
# must always be an ADF or DF. From this starting point we select
# the EF we want to export.
if not isinstance(df, CardDF):
raise RuntimeError("currently selected file %s is not a DF or ADF" % str(df))
df_path_list = df.fully_qualified_path(True)
df_path = df.fully_qualified_path_str(True)
df_path_fid = df.fully_qualified_path_str(False)
file_str = df_path + "/" + str(filename)
res = {
'path': df_path_list + [str(filename)],
}
try: try:
fcp_dec = self._cmd.lchan.select(filename, self._cmd) fcp_dec = self._cmd.lchan.select(filename, self._cmd)
# File control parameters (common for EF, DF and ADF files)
if not self._cmd.lchan.selected_file_fcp_hex:
# An application without a real ADF (like ADF.ARA-M) / filesystem
return
res['fcp_raw'] = str(self._cmd.lchan.selected_file_fcp_hex) res['fcp_raw'] = str(self._cmd.lchan.selected_file_fcp_hex)
res['fcp'] = fcp_dec res['fcp'] = fcp_dec
structure = self._cmd.lchan.selected_file_structure() # File structure and contents (EF only)
if structure == 'transparent': if isinstance(self._cmd.lchan.selected_file, CardEF):
if as_json: structure = self._cmd.lchan.selected_file_structure()
result = self._cmd.lchan.read_binary_dec() if structure == 'transparent':
body = result[0] if as_json:
else: result = self._cmd.lchan.read_binary_dec()
result = self._cmd.lchan.read_binary() body = result[0]
body = str(result[0]) else:
elif structure == 'cyclic' or structure == 'linear_fixed': result = self._cmd.lchan.read_binary()
body = [] body = str(result[0])
# Use number of records specified in select response elif structure == 'cyclic' or structure == 'linear_fixed':
num_of_rec = self._cmd.lchan.selected_file_num_of_rec() body = []
if num_of_rec: # Use number of records specified in select response
for r in range(1, num_of_rec + 1): num_of_rec = self._cmd.lchan.selected_file_num_of_rec()
if as_json: if num_of_rec:
result = self._cmd.lchan.read_record_dec(r) for r in range(1, num_of_rec + 1):
body.append(result[0])
else:
result = self._cmd.lchan.read_record(r)
body.append(str(result[0]))
# When the select response does not return the number of records, read until we hit the
# first record that cannot be read.
else:
r = 1
while True:
try:
if as_json: if as_json:
result = self._cmd.lchan.read_record_dec(r) result = self._cmd.lchan.read_record_dec(r)
body.append(result[0]) body.append(result[0])
else: else:
result = self._cmd.lchan.read_record(r) result = self._cmd.lchan.read_record(r)
body.append(str(result[0])) body.append(str(result[0]))
except SwMatchError as e:
# We are past the last valid record - stop # When the select response does not return the number of records, read until we hit the
if e.sw_actual == "9402": # first record that cannot be read.
break else:
# Some other problem occurred r = 1
raise e while True:
r = r + 1 try:
elif structure == 'ber_tlv': if as_json:
tags = self._cmd.lchan.retrieve_tags() result = self._cmd.lchan.read_record_dec(r)
body = {} body.append(result[0])
for t in tags: else:
result = self._cmd.lchan.retrieve_data(t) result = self._cmd.lchan.read_record(r)
(tag, l, val, remainer) = bertlv_parse_one(h2b(result[0])) body.append(str(result[0]))
body[t] = b2h(val) except SwMatchError as e:
else: # We are past the last valid record - stop
raise RuntimeError('Unsupported structure "%s" of file "%s"' % (structure, filename)) if e.sw_actual == "9402":
res['body'] = body break
# Some other problem occurred
raise e
r = r + 1
elif structure == 'ber_tlv':
tags = self._cmd.lchan.retrieve_tags()
body = {}
for t in tags:
result = self._cmd.lchan.retrieve_data(t)
(tag, l, val, remainer) = bertlv_parse_one(h2b(result[0]))
body[t] = b2h(val)
else:
raise RuntimeError('Unsupported structure "%s" of file "%s"' % (structure, filename))
res['body'] = body
except SwMatchError as e: except SwMatchError as e:
res['error'] = { res['error'] = {
@@ -758,7 +720,7 @@ class PySimCommands(CommandSet):
'message': str(e) 'message': str(e)
} }
context['result']['files'][file_str] = res context['result']['files'][file.fully_qualified_path_str(True)] = res
fsdump_parser = argparse.ArgumentParser() fsdump_parser = argparse.ArgumentParser()
fsdump_parser.add_argument( fsdump_parser.add_argument(
@@ -785,11 +747,11 @@ class PySimCommands(CommandSet):
exception_str_add = "" exception_str_add = ""
if opts.filename: if opts.filename:
self.__walk_action(self.fsdump_ef, opts.filename, context, **kwargs_export) self.__walk_action(self.__dump_file, opts.filename, context, **kwargs_export)
else: else:
# export an entire subtree # export an entire subtree
try: try:
self.__walk(0, self.fsdump_ef, self.fsdump_df, context, **kwargs_export) self.__walk(0, self.__dump_file, self.__dump_file, context, **kwargs_export)
except Exception as e: except Exception as e:
print("# Stopping early here due to exception: " + str(e)) print("# Stopping early here due to exception: " + str(e))
print("#") print("#")