@@ -80,6 +80,7 @@ static bool is_file(const char* path);
8080static bool is_driver ( const char * name );
8181static void read_base_name (const char * path , char * base_name , size_t name_size );
8282static void read_dir_name_from_path (const char * path , char * dir_name , size_t name_size );
83+ static void read_next_subdir_name (const char * base_path , const char * full_path , char * dir_name , size_t name_size );
8384static dmini_context_t read_driver_for_config (const char * config_path , char * driver_name , size_t name_size , const char * default_driver );
8485static Dmod_Context_t * prepare_driver_module (const char * driver_name , bool * was_loaded , bool * was_enabled );
8586static void cleanup_driver_module (const char * driver_name , bool was_loaded , bool was_enabled );
@@ -675,9 +676,9 @@ dmod_dmfsi_dif_api_declaration( 1.0, dmdevfs, int, _readdir, (dmfsi_context_t ct
675676 }
676677 else
677678 {
678- // Extract directory name from parent path for subdirectory entries
679- // This handles paths like "dev /" -> "dev"
680- read_dir_name_from_path ( parent_dir , entry -> name , sizeof (entry -> name ));
679+ // Extract the immediate subdirectory name relative to the listing directory.
680+ // E.g. listing "/" with a driver whose parent is "dmgpio8 /" yields "dmgpio8".
681+ read_next_subdir_name ( dir_node -> directory_path , parent_dir , entry -> name , sizeof (entry -> name ));
681682 entry -> size = 0 ;
682683 entry -> attr = DMFSI_ATTR_DIRECTORY ;
683684 }
@@ -1158,6 +1159,73 @@ static void read_dir_name_from_path(const char* path, char* dir_name, size_t nam
11581159 }
11591160}
11601161
1162+ /**
1163+ * @brief Extract the first path component of full_path that comes after base_path
1164+ * @param base_path The directory currently being listed (e.g., "/" or "foo/")
1165+ * @param full_path The driver's parent directory path (e.g., "foo/bar/")
1166+ * @param dir_name Output buffer for the immediate subdirectory name
1167+ * @param name_size Size of the output buffer
1168+ *
1169+ * Examples:
1170+ * - base="/", full="dmgpio8/" -> "dmgpio8"
1171+ * - base="/", full="a/b/c/" -> "a"
1172+ * - base="a/", full="a/b/c/" -> "b"
1173+ * - base="a/b/", full="a/b/c/" -> "c"
1174+ */
1175+ static void read_next_subdir_name (const char * base_path , const char * full_path , char * dir_name , size_t name_size )
1176+ {
1177+ if (base_path == NULL || full_path == NULL || dir_name == NULL || name_size == 0 )
1178+ {
1179+ if (dir_name && name_size > 0 )
1180+ {
1181+ dir_name [0 ] = '\0' ;
1182+ }
1183+ return ;
1184+ }
1185+
1186+ // Compute effective length of base_path without trailing slashes
1187+ size_t base_len = strlen (base_path );
1188+ while (base_len > 1 && base_path [base_len - 1 ] == '/' )
1189+ {
1190+ base_len -- ;
1191+ }
1192+
1193+ const char * start ;
1194+ if (base_len == 1 && base_path [0 ] == '/' )
1195+ {
1196+ // Base is the root directory; full_path has no leading slash
1197+ start = full_path ;
1198+ }
1199+ else
1200+ {
1201+ // Skip past the base_path prefix and the separator '/'
1202+ if (strncmp (full_path , base_path , base_len ) == 0 && full_path [base_len ] == '/' )
1203+ {
1204+ start = full_path + base_len + 1 ;
1205+ }
1206+ else
1207+ {
1208+ // Fallback: return the first component of full_path
1209+ start = full_path ;
1210+ }
1211+ }
1212+
1213+ // Copy up to the next '/' (or end of string)
1214+ const char * end = start ;
1215+ while (* end != '\0' && * end != '/' )
1216+ {
1217+ end ++ ;
1218+ }
1219+
1220+ size_t len = (size_t )(end - start );
1221+ if (len >= name_size )
1222+ {
1223+ len = name_size - 1 ;
1224+ }
1225+ strncpy (dir_name , start , len );
1226+ dir_name [len ] = '\0' ;
1227+ }
1228+
11611229/**
11621230 * @brief Read driver name from configuration file
11631231 */
@@ -1369,17 +1437,20 @@ static int compare_paths_ignore_trailing_slash( const char* path1, const char* p
13691437/**
13701438 * @brief Compare the path of a driver directory with a given path
13711439 *
1372- * This function compares the parent directory of a driver node with a given path.
1373- * It's used by opendir/readdir to find all driver nodes that belong to a specific directory.
1440+ * This function checks whether a driver node is reachable from the given path,
1441+ * either directly (its parent directory exactly matches path) or indirectly
1442+ * (its parent directory is a subdirectory of path).
13741443 *
13751444 * @param data Pointer to driver_node_t
13761445 * @param user_data Pointer to directory path string
1377- * @return 0 if the node's parent matches the given path, non-zero otherwise
1446+ * @return 0 if the node is reachable from the given path, non-zero otherwise
13781447 *
1379- * Example: When listing directory "dmspiflash0", this function finds all nodes
1380- * whose parent directory is "dmspiflash0" (e.g., nodes with path "dmspiflash0/1").
1448+ * Example: When listing directory "/", this function returns 0 for any driver
1449+ * node, including those with parent "dmspiflash0/" or deeper paths.
1450+ * When listing "dmspiflash0", it returns 0 for nodes whose parent starts with
1451+ * "dmspiflash0/", enabling both direct files and nested subdirectories.
13811452 *
1382- * Note: Trailing slashes are ignored in comparison, so "dmspiflash0" matches "dmspiflash0/" .
1453+ * Note: Trailing slashes are ignored in comparison.
13831454 */
13841455static int compare_driver_directory ( const void * data , const void * user_data )
13851456{
@@ -1396,10 +1467,33 @@ static int compare_driver_directory( const void* data, const void* user_data )
13961467 return -1 ;
13971468 }
13981469
1399- // Use helper function to compare paths, handling optional trailing slashes
1400- // This ensures exact path matching (not prefix matching) which is critical
1401- // to prevent "/" from incorrectly matching subdirectories like "dmspiflash0/"
1402- return compare_paths_ignore_trailing_slash (path , parent_dir );
1470+ // Check for exact match (driver is directly in this directory)
1471+ if (compare_paths_ignore_trailing_slash (path , parent_dir ) == 0 )
1472+ {
1473+ return 0 ;
1474+ }
1475+
1476+ // Check if the driver is in a subdirectory of path.
1477+ // Determine the effective length of path without trailing slashes.
1478+ size_t path_len = strlen (path );
1479+ while (path_len > 1 && path [path_len - 1 ] == '/' )
1480+ {
1481+ path_len -- ;
1482+ }
1483+
1484+ // Root directory "/" is an ancestor of every path
1485+ if (path_len == 1 && path [0 ] == '/' )
1486+ {
1487+ return 0 ;
1488+ }
1489+
1490+ // parent_dir must start with path followed by '/' to be a subdirectory
1491+ if (strncmp (parent_dir , path , path_len ) == 0 && parent_dir [path_len ] == '/' )
1492+ {
1493+ return 0 ;
1494+ }
1495+
1496+ return 1 ;
14031497}
14041498
14051499/**
0 commit comments