Skip to content

Commit 79691d9

Browse files
authored
Merge pull request #23 from choco-technologies/copilot/fix-directory-listing-issue
Fix directory listing: exact path matching and basename extraction
2 parents 944d3ae + 4c1d66a commit 79691d9

1 file changed

Lines changed: 132 additions & 16 deletions

File tree

src/dmdevfs.c

Lines changed: 132 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -77,11 +77,13 @@ static int unconfigure_drivers(dmfsi_context_t ctx);
7777
static bool is_file(const char* path);
7878
static bool is_driver( const char* name);
7979
static void read_base_name(const char* path, char* base_name, size_t name_size);
80+
static void read_dir_name_from_path(const char* path, char* dir_name, size_t name_size);
8081
static dmini_context_t read_driver_for_config(const char* config_path, char* driver_name, size_t name_size, const char* default_driver);
8182
static Dmod_Context_t* prepare_driver_module(const char* driver_name, bool* was_loaded, bool* was_enabled);
8283
static void cleanup_driver_module(const char* driver_name, bool was_loaded, bool was_enabled);
8384
static int read_driver_parent_directory( const driver_node_t* node, char* path_buffer, size_t buffer_size );
8485
static int read_driver_node_path( const driver_node_t* node, char* path_buffer, size_t buffer_size );
86+
static int compare_paths_ignore_trailing_slash( const char* path1, const char* path2 );
8587
static int compare_driver_directory( const void* data, const void* user_data );
8688
static int compare_driver_node_path( const void* data, const void* user_data );
8789
static int compare_driver(const void* data, const void* user_data );
@@ -643,10 +645,11 @@ dmod_dmfsi_dif_api_declaration( 1.0, dmdevfs, int, _readdir, (dmfsi_context_t ct
643645
return DMFSI_ERR_GENERAL;
644646
}
645647

646-
bool file_should_be_listed = strcmp(dir_node->directory_path, parent_dir) == 0;
648+
bool file_should_be_listed = compare_paths_ignore_trailing_slash(dir_node->directory_path, parent_dir) == 0;
647649
if(file_should_be_listed)
648650
{
649-
strncpy(entry->name, driver->path, sizeof(entry->name));
651+
// Extract basename from the full path for the directory entry
652+
read_base_name(driver->path, entry->name, sizeof(entry->name));
650653

651654
dmdrvi_stat_t stat;
652655
int res = driver_stat(driver, driver->path, &stat);
@@ -661,7 +664,9 @@ dmod_dmfsi_dif_api_declaration( 1.0, dmdevfs, int, _readdir, (dmfsi_context_t ct
661664
}
662665
else
663666
{
664-
strncpy(entry->name, parent_dir, sizeof(entry->name));
667+
// Extract directory name from parent path for subdirectory entries
668+
// This handles paths like "dev/" -> "dev"
669+
read_dir_name_from_path(parent_dir, entry->name, sizeof(entry->name));
665670
entry->size = 0;
666671
entry->attr = DMFSI_ATTR_DIRECTORY;
667672
}
@@ -1006,6 +1011,66 @@ static void read_base_name(const char* path, char* base_name, size_t name_size)
10061011
base_name[name_size - 1] = '\0';
10071012
}
10081013

1014+
/**
1015+
* @brief Extract directory name from a path, handling trailing slashes
1016+
* @param path Path to extract directory name from (may have trailing slash)
1017+
* @param dir_name Output buffer for directory name
1018+
* @param name_size Size of output buffer
1019+
*
1020+
* Examples:
1021+
* - "dev/" -> "dev"
1022+
* - "/dev/" -> "dev"
1023+
* - "dmspiflash0/" -> "dmspiflash0"
1024+
* - "/" -> "" (root has no name)
1025+
*/
1026+
static void read_dir_name_from_path(const char* path, char* dir_name, size_t name_size)
1027+
{
1028+
if (path == NULL || dir_name == NULL || name_size == 0)
1029+
{
1030+
if (dir_name && name_size > 0)
1031+
{
1032+
dir_name[0] = '\0';
1033+
}
1034+
return;
1035+
}
1036+
1037+
// Find the length without trailing slashes
1038+
size_t len = strlen(path);
1039+
while (len > 1 && path[len - 1] == '/')
1040+
{
1041+
len--;
1042+
}
1043+
1044+
// Special case: if path is just "/", return empty
1045+
if (len == 1 && path[0] == '/')
1046+
{
1047+
dir_name[0] = '\0';
1048+
return;
1049+
}
1050+
1051+
// Find the last slash before the directory name
1052+
const char* last_slash = NULL;
1053+
for (size_t i = 0; i < len; i++)
1054+
{
1055+
if (path[i] == '/')
1056+
{
1057+
last_slash = &path[i];
1058+
}
1059+
}
1060+
1061+
// Extract the directory name
1062+
const char* name_start = (last_slash != NULL) ? last_slash + 1 : path;
1063+
size_t name_len = len - (name_start - path);
1064+
1065+
// Use snprintf for safe copying with guaranteed null-termination
1066+
int written = Dmod_SnPrintf(dir_name, name_size, "%.*s", (int)name_len, name_start);
1067+
if (written < 0 || (size_t)written >= name_size)
1068+
{
1069+
// Truncated, but snprintf ensures null-termination
1070+
dir_name[name_size - 1] = '\0';
1071+
}
1072+
}
1073+
10091074
/**
10101075
* @brief Read driver name from configuration file
10111076
*/
@@ -1168,8 +1233,66 @@ static int read_driver_node_path( const driver_node_t* node, char* path_buffer,
11681233
return DMFSI_OK;
11691234
}
11701235

1236+
/**
1237+
* @brief Compare two paths, ignoring trailing slashes
1238+
* @param path1 First path to compare
1239+
* @param path2 Second path to compare
1240+
* @return 0 if equal, non-zero if different
1241+
*
1242+
* Note: The root path "/" is treated specially and retains its slash.
1243+
* For example, "/" and "//" are considered equal, but "dir" and "dir/" are also equal.
1244+
*/
1245+
static int compare_paths_ignore_trailing_slash( const char* path1, const char* path2 )
1246+
{
1247+
// Handle NULL pointers - both NULL is equal, one NULL is different
1248+
if (path1 == NULL && path2 == NULL)
1249+
{
1250+
return 0;
1251+
}
1252+
if (path1 == NULL || path2 == NULL)
1253+
{
1254+
return 1;
1255+
}
1256+
1257+
// Get lengths
1258+
size_t len1 = strlen(path1);
1259+
size_t len2 = strlen(path2);
1260+
1261+
// Remove trailing slashes from both paths for comparison
1262+
// Keep at least "/" if that's the entire path (len > 1 ensures we keep root "/")
1263+
while (len1 > 1 && path1[len1 - 1] == '/')
1264+
{
1265+
len1--;
1266+
}
1267+
while (len2 > 1 && path2[len2 - 1] == '/')
1268+
{
1269+
len2--;
1270+
}
1271+
1272+
// Lengths must match
1273+
if (len1 != len2)
1274+
{
1275+
return 1;
1276+
}
1277+
1278+
// Content must match
1279+
return strncmp(path1, path2, len1);
1280+
}
1281+
11711282
/**
11721283
* @brief Compare the path of a driver directory with a given path
1284+
*
1285+
* This function compares the parent directory of a driver node with a given path.
1286+
* It's used by opendir/readdir to find all driver nodes that belong to a specific directory.
1287+
*
1288+
* @param data Pointer to driver_node_t
1289+
* @param user_data Pointer to directory path string
1290+
* @return 0 if the node's parent matches the given path, non-zero otherwise
1291+
*
1292+
* Example: When listing directory "dmspiflash0", this function finds all nodes
1293+
* whose parent directory is "dmspiflash0" (e.g., nodes with path "dmspiflash0/1").
1294+
*
1295+
* Note: Trailing slashes are ignored in comparison, so "dmspiflash0" matches "dmspiflash0/".
11731296
*/
11741297
static int compare_driver_directory( const void* data, const void* user_data )
11751298
{
@@ -1180,23 +1303,16 @@ static int compare_driver_directory( const void* data, const void* user_data )
11801303
return 0;
11811304
}
11821305

1183-
char directory_path[MAX_PATH_LENGTH] = {0};
1184-
if(read_driver_parent_directory(node, directory_path, sizeof(directory_path)) != 0)
1306+
char parent_dir[MAX_PATH_LENGTH] = {0};
1307+
if(read_driver_parent_directory(node, parent_dir, sizeof(parent_dir)) != 0)
11851308
{
11861309
return -1;
11871310
}
11881311

1189-
char* driver_path = directory_path;
1190-
while(*path)
1191-
{
1192-
if(*path != *driver_path)
1193-
{
1194-
return 1;
1195-
}
1196-
path++;
1197-
driver_path++;
1198-
}
1199-
return 0;
1312+
// Use helper function to compare paths, handling optional trailing slashes
1313+
// This ensures exact path matching (not prefix matching) which is critical
1314+
// to prevent "/" from incorrectly matching subdirectories like "dmspiflash0/"
1315+
return compare_paths_ignore_trailing_slash(path, parent_dir);
12001316
}
12011317

12021318
/**

0 commit comments

Comments
 (0)