Skip to content

Commit 3e222f0

Browse files
CopilotJohnAmadis
andcommitted
Fix get_mount_point_for_path to select longest matching mount point
Co-authored-by: JohnAmadis <17320783+JohnAmadis@users.noreply.github.com>
1 parent d52cc73 commit 3e222f0

3 files changed

Lines changed: 263 additions & 6 deletions

File tree

src/dmvfs.c

Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -336,17 +336,29 @@ static mount_point_t* get_mount_point_for_path(const char* path)
336336
return NULL;
337337
}
338338

339+
mount_point_t* best_match = NULL;
340+
size_t best_match_length = 0;
341+
339342
for(int i = 0; i < g_max_mount_points; i++)
340343
{
341-
if(g_mount_points[i].mount_point != NULL &&
342-
strncmp(path, g_mount_points[i].mount_point, strlen(g_mount_points[i].mount_point)) == 0)
344+
if(g_mount_points[i].mount_point != NULL)
343345
{
344-
return &g_mount_points[i];
346+
size_t mount_point_length = strlen(g_mount_points[i].mount_point);
347+
if(strncmp(path, g_mount_points[i].mount_point, mount_point_length) == 0 &&
348+
mount_point_length > best_match_length)
349+
{
350+
best_match = &g_mount_points[i];
351+
best_match_length = mount_point_length;
352+
}
345353
}
346354
}
347355

348-
DMOD_LOG_WARN("No mount point found for path '%s'\n", path);
349-
return NULL;
356+
if(best_match == NULL)
357+
{
358+
DMOD_LOG_WARN("No mount point found for path '%s'\n", path);
359+
}
360+
361+
return best_match;
350362
}
351363

352364
/**

tests/CMakeLists.txt

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,4 +36,10 @@ include_directories(${PROJECT_SOURCE_DIR})
3636
target_link_libraries(${PROJECT_NAME} dmod dmvfs dmlist)
3737

3838
target_link_options(${PROJECT_NAME} PRIVATE -L ${DMOD_DIR}/scripts)
39-
target_link_options(${PROJECT_NAME} PRIVATE -T ${CMAKE_CURRENT_SOURCE_DIR}/main.ld)
39+
target_link_options(${PROJECT_NAME} PRIVATE -T ${CMAKE_CURRENT_SOURCE_DIR}/main.ld)
40+
41+
# Add mount point selection test
42+
add_executable(mount_point_test test_mount_point_selection.c)
43+
target_link_libraries(mount_point_test dmod dmvfs)
44+
target_link_options(mount_point_test PRIVATE -L ${DMOD_DIR}/scripts)
45+
target_link_options(mount_point_test PRIVATE -T ${CMAKE_CURRENT_SOURCE_DIR}/main.ld)

tests/test_mount_point_selection.c

Lines changed: 239 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,239 @@
1+
/*
2+
* Test program to verify correct mount point selection
3+
* Tests the fix for: get_mount_point_for_path should return the longest matching mount point
4+
*/
5+
6+
#define DMOD_ENABLE_REGISTRATION
7+
#include <stdio.h>
8+
#include <string.h>
9+
#include <stdbool.h>
10+
#include "dmod.h"
11+
#include "dmvfs.h"
12+
13+
static int test_passed = 0;
14+
static int test_failed = 0;
15+
16+
#define TEST_PASS(msg) do { \
17+
printf("✓ PASS: %s\n", msg); \
18+
test_passed++; \
19+
} while(0)
20+
21+
#define TEST_FAIL(msg) do { \
22+
printf("✗ FAIL: %s\n", msg); \
23+
test_failed++; \
24+
} while(0)
25+
26+
int main(int argc, char *argv[])
27+
{
28+
if (argc < 3) {
29+
printf("Usage: %s <fs1_module.dmf> <fs2_module.dmf>\n", argv[0]);
30+
printf("This test requires two filesystem modules to test mount point selection.\n");
31+
return 1;
32+
}
33+
34+
const char* fs1_path = argv[1];
35+
const char* fs2_path = argv[2];
36+
37+
printf("========================================\n");
38+
printf(" Mount Point Selection Test\n");
39+
printf("========================================\n\n");
40+
41+
// Load first filesystem module
42+
Dmod_Context_t* context1 = Dmod_LoadFile(fs1_path);
43+
if (context1 == NULL) {
44+
printf("✗ Cannot load module: %s\n", fs1_path);
45+
return -1;
46+
}
47+
48+
if (!Dmod_Enable(context1, false, NULL)) {
49+
printf("✗ Cannot enable module: %s\n", fs1_path);
50+
Dmod_Unload(context1, false);
51+
return -1;
52+
}
53+
54+
// Load second filesystem module
55+
Dmod_Context_t* context2 = Dmod_LoadFile(fs2_path);
56+
if (context2 == NULL) {
57+
printf("✗ Cannot load module: %s\n", fs2_path);
58+
Dmod_Unload(context1, false);
59+
return -1;
60+
}
61+
62+
if (!Dmod_Enable(context2, false, NULL)) {
63+
printf("✗ Cannot enable module: %s\n", fs2_path);
64+
Dmod_Unload(context2, false);
65+
Dmod_Unload(context1, false);
66+
return -1;
67+
}
68+
69+
const char* fs1_name = Dmod_GetName(context1);
70+
const char* fs2_name = Dmod_GetName(context2);
71+
72+
printf("Loaded filesystems:\n");
73+
printf(" FS1: %s\n", fs1_name);
74+
printf(" FS2: %s\n", fs2_name);
75+
printf("\n");
76+
77+
// Initialize DMVFS
78+
if (!dmvfs_init(16, 32)) {
79+
printf("✗ Cannot initialize DMVFS\n");
80+
return -1;
81+
}
82+
83+
printf("Test scenario: Mount FS1 at '/' and FS2 at '/configs'\n");
84+
printf("Expected behavior: Paths under '/configs' should use FS2, not FS1\n\n");
85+
86+
// Mount first filesystem at root
87+
if (!dmvfs_mount_fs(fs1_name, "/", NULL)) {
88+
printf("✗ Cannot mount %s at /\n", fs1_name);
89+
dmvfs_deinit();
90+
return -1;
91+
}
92+
printf("✓ Mounted %s at /\n", fs1_name);
93+
94+
// Mount second filesystem at /configs
95+
if (!dmvfs_mount_fs(fs2_name, "/configs", NULL)) {
96+
printf("✗ Cannot mount %s at /configs\n", fs2_name);
97+
dmvfs_unmount_fs("/");
98+
dmvfs_deinit();
99+
return -1;
100+
}
101+
printf("✓ Mounted %s at /configs\n\n", fs2_name);
102+
103+
printf("Running tests...\n\n");
104+
105+
// Test 1: Create file at /test.txt (should use FS1)
106+
printf("Test 1: Create /test.txt (should use %s at /)\n", fs1_name);
107+
void* fp1 = NULL;
108+
int ret = dmvfs_fopen(&fp1, "/test.txt", DMFSI_O_CREAT | DMFSI_O_WRONLY, 0, 0);
109+
if (ret == DMFSI_OK && fp1 != NULL) {
110+
const char* data = "Root filesystem";
111+
size_t written = 0;
112+
dmvfs_fwrite(fp1, data, strlen(data), &written);
113+
dmvfs_fclose(fp1);
114+
TEST_PASS("Created file at root mount point");
115+
} else {
116+
TEST_FAIL("Cannot create file at root mount point");
117+
}
118+
119+
// Test 2: Create file at /configs/app.conf (should use FS2, not FS1)
120+
printf("Test 2: Create /configs/app.conf (should use %s at /configs)\n", fs2_name);
121+
void* fp2 = NULL;
122+
ret = dmvfs_fopen(&fp2, "/configs/app.conf", DMFSI_O_CREAT | DMFSI_O_WRONLY, 0, 0);
123+
if (ret == DMFSI_OK && fp2 != NULL) {
124+
const char* data = "Config filesystem";
125+
size_t written = 0;
126+
dmvfs_fwrite(fp2, data, strlen(data), &written);
127+
dmvfs_fclose(fp2);
128+
TEST_PASS("Created file at /configs mount point");
129+
} else {
130+
TEST_FAIL("Cannot create file at /configs mount point");
131+
}
132+
133+
// Test 3: Read back the files to verify they're in different filesystems
134+
printf("Test 3: Verify files can be read back\n");
135+
136+
// Read /test.txt
137+
ret = dmvfs_fopen(&fp1, "/test.txt", DMFSI_O_RDONLY, 0, 0);
138+
if (ret == DMFSI_OK && fp1 != NULL) {
139+
char buffer[64] = {0};
140+
size_t read_bytes = 0;
141+
dmvfs_fread(fp1, buffer, sizeof(buffer), &read_bytes);
142+
dmvfs_fclose(fp1);
143+
if (strcmp(buffer, "Root filesystem") == 0) {
144+
TEST_PASS("Read /test.txt successfully");
145+
} else {
146+
TEST_FAIL("Content mismatch in /test.txt");
147+
}
148+
} else {
149+
TEST_FAIL("Cannot read /test.txt");
150+
}
151+
152+
// Read /configs/app.conf
153+
ret = dmvfs_fopen(&fp2, "/configs/app.conf", DMFSI_O_RDONLY, 0, 0);
154+
if (ret == DMFSI_OK && fp2 != NULL) {
155+
char buffer[64] = {0};
156+
size_t read_bytes = 0;
157+
dmvfs_fread(fp2, buffer, sizeof(buffer), &read_bytes);
158+
dmvfs_fclose(fp2);
159+
if (strcmp(buffer, "Config filesystem") == 0) {
160+
TEST_PASS("Read /configs/app.conf successfully");
161+
} else {
162+
TEST_FAIL("Content mismatch in /configs/app.conf");
163+
}
164+
} else {
165+
TEST_FAIL("Cannot read /configs/app.conf");
166+
}
167+
168+
// Test 4: List files in both mount points
169+
printf("Test 4: Directory listing verification\n");
170+
171+
// List root
172+
void* dp = NULL;
173+
ret = dmvfs_opendir(&dp, "/");
174+
if (ret == DMFSI_OK && dp != NULL) {
175+
printf(" Files in /:\n");
176+
dmfsi_dir_entry_t entry;
177+
bool found_test_txt = false;
178+
while (dmvfs_readdir(dp, &entry) == DMFSI_OK) {
179+
printf(" - %s\n", entry.name);
180+
if (strcmp(entry.name, "test.txt") == 0) {
181+
found_test_txt = true;
182+
}
183+
}
184+
dmvfs_closedir(dp);
185+
if (found_test_txt) {
186+
TEST_PASS("Found test.txt in root directory");
187+
} else {
188+
TEST_FAIL("test.txt not found in root directory");
189+
}
190+
} else {
191+
TEST_FAIL("Cannot list root directory");
192+
}
193+
194+
// List /configs
195+
ret = dmvfs_opendir(&dp, "/configs");
196+
if (ret == DMFSI_OK && dp != NULL) {
197+
printf(" Files in /configs:\n");
198+
dmfsi_dir_entry_t entry;
199+
bool found_app_conf = false;
200+
while (dmvfs_readdir(dp, &entry) == DMFSI_OK) {
201+
printf(" - %s\n", entry.name);
202+
if (strcmp(entry.name, "app.conf") == 0) {
203+
found_app_conf = true;
204+
}
205+
}
206+
dmvfs_closedir(dp);
207+
if (found_app_conf) {
208+
TEST_PASS("Found app.conf in /configs directory");
209+
} else {
210+
TEST_FAIL("app.conf not found in /configs directory");
211+
}
212+
} else {
213+
TEST_FAIL("Cannot list /configs directory");
214+
}
215+
216+
// Cleanup
217+
printf("\nCleaning up...\n");
218+
dmvfs_unmount_fs("/configs");
219+
dmvfs_unmount_fs("/");
220+
dmvfs_deinit();
221+
222+
// Print summary
223+
printf("\n========================================\n");
224+
printf(" Test Summary\n");
225+
printf("========================================\n");
226+
printf("Total tests: %d\n", test_passed + test_failed);
227+
printf("Passed: %d\n", test_passed);
228+
printf("Failed: %d\n", test_failed);
229+
printf("========================================\n");
230+
231+
if (test_failed == 0) {
232+
printf("\n✓ ALL TESTS PASSED\n");
233+
printf("The fix correctly selects the longest matching mount point!\n\n");
234+
return 0;
235+
} else {
236+
printf("\n✗ SOME TESTS FAILED\n\n");
237+
return 1;
238+
}
239+
}

0 commit comments

Comments
 (0)