Skip to content

Commit 61eb881

Browse files
committed
isobusfs: fix directory read and seek semantics to match ISO 11783-13
Fix directory operations to comply with ISO 11783-13:2021 (sections C.3.4.2 and C.3.5.2), which specifies that directory operations differ significantly from standard file operations: - The Count parameter in a Read File request represents the number of directory entries to read, not the number of bytes. - The Offset parameter in a Seek File request represents the logical entry index, not a byte offset. The previous implementation treated directories strictly as files, using byte-based offsets and counts. This resulted in incorrect seeking behavior and protocol violations when listing directories. Align the implementation with the standard by: 1. Server side: - Introduce isobusfs_srv_dir_entry_visible() to consistently filter out invalid (unreadable, hidden, oversized) entries. This ensures that entry indices remain stable. - Implement isobusfs_srv_dir_skip_entries() to advance the directory stream by logical visible entries rather than bytes. - Update the Read File handler to interpret count as the maximum number of entries and return the number of entries read in the response header. - Update the Seek File handler to seek by entry index. 2. Client side: - Calculate the request count based on the number of minimal-size entries that fit into the maximum data length. - Interpret the response count as the number of entries received rather than the byte length of the payload. Signed-off-by: Oleksij Rempel <linux@rempel-privat.de>
1 parent a5bd791 commit 61eb881

2 files changed

Lines changed: 281 additions & 71 deletions

File tree

isobusfs/isobusfs_cli_int.c

Lines changed: 74 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,12 @@
1616
#define MAX_COMMAND_LENGTH 256
1717

1818
#define MAX_DISPLAY_FILENAME_LENGTH 100
19+
/*
20+
* ISO 11783-13:2021 B.21 minimal directory entry payload size in bytes:
21+
* 1 (name length) + 1 (min name byte) + 1 (attributes) +
22+
* 2 (date) + 2 (time) + 4 (size).
23+
*/
24+
#define ISOBUSFS_MIN_DIR_ENTRY_SIZE (1 + 1 + 1 + 2 + 2 + 4)
1925

2026
struct command_mapping {
2127
const char *command;
@@ -510,8 +516,12 @@ isobusfs_cli_ls_handle_open_dir_sent(struct isobusfs_priv *priv,
510516

511517
ctx->handle = res->handle;
512518

519+
ctx->offset = 0;
520+
ctx->entry_count = 0;
521+
513522
ret = isobusfs_cli_send_and_register_fa_sf_event(priv, ctx->handle,
514-
0, ctx->entry_count,
523+
ISOBUSFS_FA_SEEK_SET,
524+
ctx->offset,
515525
cb, ctx);
516526
if (ret)
517527
pr_int("Failed to send seek file request: %i\n", ret);
@@ -530,7 +540,7 @@ isobusfs_cli_ls_handle_seek_dir_sent(struct isobusfs_priv *priv,
530540
{
531541
isobusfs_event_callback cb = isobusfs_cli_ls_event_callback;
532542
struct isobusfs_fa_seekf_res *res =
533-
(struct isobusfs_fa_seekf_res *)msg;
543+
(struct isobusfs_fa_seekf_res *)msg->buf;
534544
uint16_t count;
535545
int ret;
536546

@@ -543,8 +553,10 @@ isobusfs_cli_ls_handle_seek_dir_sent(struct isobusfs_priv *priv,
543553
goto error;
544554
}
545555

546-
/* set max possible number fitting in to 16bits */
547-
count = UINT16_MAX;
556+
/* ISO 11783-13:2021 C.3.5.2: count is number of directory entries. */
557+
count = ISOBUSFS_MAX_DATA_LENGH / ISOBUSFS_MIN_DIR_ENTRY_SIZE;
558+
if (!count)
559+
count = 1;
548560
ctx->request_count = count;
549561

550562
ret = isobusfs_cli_send_and_register_fa_rf_event(priv, ctx->handle,
@@ -616,8 +628,8 @@ static bool isobusfs_cli_extract_directory_entry(const uint8_t *buffer,
616628
uint16_t *file_time,
617629
uint32_t *file_size)
618630
{
631+
size_t entry_total_len, copy_len;
619632
uint8_t filename_length;
620-
size_t entry_total_len;
621633

622634
if (*pos + 2 > buffer_length) {
623635
pr_int("Error: Incomplete data in buffer\n");
@@ -633,8 +645,14 @@ static bool isobusfs_cli_extract_directory_entry(const uint8_t *buffer,
633645
}
634646

635647
(*pos)++;
636-
strncpy(filename, (const char *)buffer + *pos, filename_length);
637-
filename[filename_length] = '\0';
648+
649+
if (filename_length > ISOBUSFS_MAX_DIR_ENTRY_NAME_LENGTH)
650+
copy_len = ISOBUSFS_MAX_DIR_ENTRY_NAME_LENGTH;
651+
else
652+
copy_len = filename_length;
653+
654+
strncpy(filename, (const char *)buffer + *pos, copy_len);
655+
filename[copy_len] = '\0';
638656
*pos += filename_length;
639657
if (filename_length > MAX_DISPLAY_FILENAME_LENGTH) {
640658
/* Truncate the filename and replace the last character
@@ -688,15 +706,17 @@ isobusfs_cli_print_directory_entry(struct isobusfs_cli_ls_context *ctx,
688706
static void
689707
isobusfs_cli_print_directory_entries(struct isobusfs_cli_ls_context *ctx,
690708
const uint8_t *buffer,
691-
size_t buffer_length)
709+
size_t buffer_length,
710+
uint16_t max_entries)
692711
{
693712
char filename[ISOBUSFS_MAX_DIR_ENTRY_NAME_LENGTH + 1];
694713
uint16_t file_date, file_time;
695714
uint32_t file_size;
696715
uint8_t attributes;
697716
size_t pos = 0;
717+
uint16_t entries = 0;
698718

699-
while (pos < buffer_length) {
719+
while (pos < buffer_length && entries < max_entries) {
700720
if (!isobusfs_cli_extract_directory_entry(buffer, buffer_length,
701721
&pos, filename,
702722
&attributes,
@@ -709,6 +729,7 @@ isobusfs_cli_print_directory_entries(struct isobusfs_cli_ls_context *ctx,
709729
file_date, file_time,
710730
file_size);
711731
ctx->entry_count++;
732+
entries++;
712733
}
713734
}
714735

@@ -721,26 +742,42 @@ isobusfs_cli_ls_handle_read_dir_sent(struct isobusfs_priv *priv,
721742
(struct isobusfs_read_file_response *)msg->buf;
722743
size_t buffer_length = msg->len - sizeof(*res);
723744
isobusfs_event_callback cb;
745+
size_t entries_before;
746+
size_t entries_in_message;
724747
uint16_t count;
725748
int ret;
726749

727750
pr_debug("< rx: Read File Response. Error code: %i", res->error_code);
751+
728752
if (isobusfs_cli_int_is_error(priv, 0, res->error_code, res->tan))
729753
goto error;
730754

731755
count = le16toh(res->count);
732-
if (count && count != buffer_length) {
733-
pr_int("Buffer length mismatch: %u != %zu\n", count,
734-
buffer_length);
735-
goto error;
756+
if (count && buffer_length) {
757+
entries_before = ctx->entry_count;
758+
isobusfs_cli_print_directory_entries(ctx, res->data,
759+
buffer_length, count);
760+
entries_in_message = ctx->entry_count - entries_before;
761+
} else {
762+
entries_in_message = 0;
736763
}
737764

738-
if (count)
739-
isobusfs_cli_print_directory_entries(ctx, res->data,
740-
buffer_length);
765+
if (count != entries_in_message) {
766+
pr_warn("Directory entry count mismatch: server sent %u, parsed %zu\n",
767+
count, entries_in_message);
768+
/* Continue processing if we parsed at least some entries.
769+
* Strict validation would reject valid responses if parsing
770+
* fails partway through due to corruption.
771+
*/
772+
if (entries_in_message == 0 && count > 0) {
773+
pr_int("Error: Failed to parse any directory entries\n");
774+
goto error;
775+
}
776+
}
741777

742778
cb = isobusfs_cli_ls_event_callback;
743-
if (count) {
779+
780+
if (res->error_code == ISOBUSFS_ERR_END_OF_FILE) {
744781
ret = isobusfs_cli_send_and_register_fa_cf_event(priv,
745782
ctx->handle,
746783
cb, ctx);
@@ -750,21 +787,31 @@ isobusfs_cli_ls_handle_read_dir_sent(struct isobusfs_priv *priv,
750787
}
751788

752789
ctx->state = ISOBUSFS_CLI_LS_STATE_CLOSE_DIR_SENT;
753-
} else {
754-
ctx->offset = ctx->entry_count;
755-
ret = isobusfs_cli_send_and_register_fa_sf_event(priv,
756-
ctx->handle, 0,
757-
ctx->offset,
758-
cb, ctx);
759-
if (ret)
760-
pr_int("Failed to send seek file request: %i\n", ret);
790+
return;
791+
}
761792

762-
ctx->state = ISOBUSFS_CLI_LS_STATE_SEEK_DIR_SENT;
793+
if (!count) {
794+
pr_int("Error: zero-length read without EOF\n");
795+
goto error;
763796
}
764797

798+
/*
799+
* Directory seek offset is entry index, not byte offset.
800+
* Server side seek rewinds and skips "offset" entries.
801+
*/
802+
ctx->offset = ctx->entry_count;
803+
804+
ret = isobusfs_cli_send_and_register_fa_sf_event(priv,
805+
ctx->handle, 0,
806+
ctx->offset,
807+
cb, ctx);
808+
if (ret)
809+
pr_int("Failed to send seek file request: %i\n", ret);
810+
811+
ctx->state = ISOBUSFS_CLI_LS_STATE_SEEK_DIR_SENT;
812+
765813
return;
766814
error:
767-
768815
ctx->state = ISOBUSFS_CLI_LS_STATE_ERROR;
769816
}
770817

0 commit comments

Comments
 (0)