opensc-explorer: add function 'get_record'
This commit is contained in:
parent
f55c4e5c93
commit
5714dbfa08
|
@ -403,6 +403,31 @@
|
||||||
</listitem>
|
</listitem>
|
||||||
</varlistentry>
|
</varlistentry>
|
||||||
|
|
||||||
|
<varlistentry>
|
||||||
|
<term>
|
||||||
|
<command>get_record</command>
|
||||||
|
<replaceable>file-id</replaceable>
|
||||||
|
<replaceable>rec-no</replaceable>
|
||||||
|
<arg choice="opt"><replaceable>output</replaceable></arg>
|
||||||
|
</term>
|
||||||
|
<listitem>
|
||||||
|
<para>
|
||||||
|
Copy a record of a record-oriented EF to a local file.
|
||||||
|
The local file is specified by
|
||||||
|
<replaceable>output</replaceable>
|
||||||
|
while the card file and the record are specified by
|
||||||
|
<replaceable>file-id</replaceable> and
|
||||||
|
<replaceable>rec-no</replaceable>,
|
||||||
|
</para>
|
||||||
|
<para>
|
||||||
|
If <replaceable>output</replaceable> is omitted,
|
||||||
|
the name of the output file will be derived from the
|
||||||
|
full card path to <replaceable>file-id</replaceable>.
|
||||||
|
and the <replaceable>rec-no</replaceable>.
|
||||||
|
</para>
|
||||||
|
</listitem>
|
||||||
|
</varlistentry>
|
||||||
|
|
||||||
<varlistentry>
|
<varlistentry>
|
||||||
<term>
|
<term>
|
||||||
<command>help</command>
|
<command>help</command>
|
||||||
|
|
|
@ -100,6 +100,7 @@ static int do_verify(int argc, char **argv);
|
||||||
static int do_change(int argc, char **argv);
|
static int do_change(int argc, char **argv);
|
||||||
static int do_unblock(int argc, char **argv);
|
static int do_unblock(int argc, char **argv);
|
||||||
static int do_get(int argc, char **argv);
|
static int do_get(int argc, char **argv);
|
||||||
|
static int do_get_record(int argc, char **argv);
|
||||||
static int do_update_binary(int argc, char **argv);
|
static int do_update_binary(int argc, char **argv);
|
||||||
static int do_update_record(int argc, char **argv);
|
static int do_update_record(int argc, char **argv);
|
||||||
static int do_put(int argc, char **argv);
|
static int do_put(int argc, char **argv);
|
||||||
|
@ -174,6 +175,9 @@ static struct command cmds[] = {
|
||||||
{ do_get,
|
{ do_get,
|
||||||
"get", "<file-id> [<output-file>]",
|
"get", "<file-id> [<output-file>]",
|
||||||
"copy an EF to a local file" },
|
"copy an EF to a local file" },
|
||||||
|
{ do_get_record,
|
||||||
|
"get_record", "<file-id> <rec-no> [<output-file>]",
|
||||||
|
"copy a record of an EF to a local file" },
|
||||||
{ do_get_data,
|
{ do_get_data,
|
||||||
"do_get", "<hex-tag> [<output-file>]",
|
"do_get", "<hex-tag> [<output-file>]",
|
||||||
"get a data object" },
|
"get a data object" },
|
||||||
|
@ -1474,6 +1478,92 @@ err:
|
||||||
return -err;
|
return -err;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int do_get_record(int argc, char **argv)
|
||||||
|
{
|
||||||
|
u8 buf[SC_MAX_EXT_APDU_RESP_SIZE];
|
||||||
|
int r, err = 1;
|
||||||
|
size_t rec, count = 0;
|
||||||
|
sc_path_t path;
|
||||||
|
sc_file_t *file = NULL;
|
||||||
|
char *filename;
|
||||||
|
FILE *outf = NULL;
|
||||||
|
|
||||||
|
if (argc < 2 || argc > 3)
|
||||||
|
return usage(do_get);
|
||||||
|
if (arg_to_path(argv[0], &path, 0) != 0)
|
||||||
|
return usage(do_get);
|
||||||
|
rec = strtoul(argv[1], NULL, 10);
|
||||||
|
|
||||||
|
filename = (argc == 3) ? argv[2] : path_to_filename(&path, '_', rec);
|
||||||
|
outf = (strcmp(filename, "-") == 0)
|
||||||
|
? stdout
|
||||||
|
: fopen(filename, "wb");
|
||||||
|
if (outf == NULL) {
|
||||||
|
perror(filename);
|
||||||
|
goto err;
|
||||||
|
}
|
||||||
|
|
||||||
|
r = sc_lock(card);
|
||||||
|
if (r == SC_SUCCESS)
|
||||||
|
r = sc_select_file(card, &path, &file);
|
||||||
|
sc_unlock(card);
|
||||||
|
if (r || file == NULL) {
|
||||||
|
check_ret(r, SC_AC_OP_SELECT, "Unable to select file", current_file);
|
||||||
|
goto err;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* fail on wrong file type */
|
||||||
|
if (file->type != SC_FILE_TYPE_WORKING_EF ||
|
||||||
|
(file->ef_structure != SC_FILE_EF_LINEAR_FIXED &&
|
||||||
|
file->ef_structure != SC_FILE_EF_LINEAR_FIXED_TLV &&
|
||||||
|
file->ef_structure != SC_FILE_EF_LINEAR_VARIABLE &&
|
||||||
|
file->ef_structure != SC_FILE_EF_LINEAR_VARIABLE_TLV)) {
|
||||||
|
fprintf(stderr, "Only record-oriented working EFs may be read\n");
|
||||||
|
goto err;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* fail on out of bound record index:
|
||||||
|
* must be > 0 and if record_count is set <= record_count */
|
||||||
|
if (rec < 1 || (file->record_count > 0 && rec > file->record_count)) {
|
||||||
|
fprintf(stderr, "Invalid record number %"SC_FORMAT_LEN_SIZE_T"u\n", rec);
|
||||||
|
goto err;
|
||||||
|
}
|
||||||
|
|
||||||
|
r = sc_read_record(card, rec, buf, sizeof(buf), SC_RECORD_BY_REC_NR);
|
||||||
|
if (r < 0) {
|
||||||
|
fprintf(stderr, "Cannot read record %"SC_FORMAT_LEN_SIZE_T"u; return %i\n", rec, r);
|
||||||
|
goto err;
|
||||||
|
}
|
||||||
|
|
||||||
|
count = r;
|
||||||
|
|
||||||
|
if (count > 0) {
|
||||||
|
size_t written = fwrite(buf, 1, (size_t) r, outf);
|
||||||
|
|
||||||
|
if (written != count) {
|
||||||
|
fprintf(stderr, "Cannot write to file %s (only %"SC_FORMAT_LEN_SIZE_T"u of %"SC_FORMAT_LEN_SIZE_T"u bytes written)",
|
||||||
|
filename, written, count);
|
||||||
|
goto err;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (outf == stdout) {
|
||||||
|
fwrite("\n", 1, 1, outf);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
printf("Total of %"SC_FORMAT_LEN_SIZE_T"u bytes read from %s and saved to %s.\n",
|
||||||
|
count, argv[0], filename);
|
||||||
|
}
|
||||||
|
|
||||||
|
err = 0;
|
||||||
|
err:
|
||||||
|
sc_file_free(file);
|
||||||
|
if (outf != NULL && outf != stdout)
|
||||||
|
fclose(outf);
|
||||||
|
select_current_path_or_die();
|
||||||
|
return -err;
|
||||||
|
}
|
||||||
|
|
||||||
static int do_update_binary(int argc, char **argv)
|
static int do_update_binary(int argc, char **argv)
|
||||||
{
|
{
|
||||||
u8 buf[SC_MAX_EXT_APDU_DATA_SIZE];
|
u8 buf[SC_MAX_EXT_APDU_DATA_SIZE];
|
||||||
|
|
Loading…
Reference in New Issue