diff options
Diffstat (limited to 'firmware/common/dir.c')
-rw-r--r-- | firmware/common/dir.c | 83 |
1 files changed, 77 insertions, 6 deletions
diff --git a/firmware/common/dir.c b/firmware/common/dir.c index 1bad9327f6..5fa5f9db6e 100644 --- a/firmware/common/dir.c +++ b/firmware/common/dir.c | |||
@@ -23,11 +23,48 @@ | |||
23 | #include "fat.h" | 23 | #include "fat.h" |
24 | #include "dir.h" | 24 | #include "dir.h" |
25 | #include "debug.h" | 25 | #include "debug.h" |
26 | #include "atoi.h" | ||
26 | 27 | ||
27 | #define MAX_OPEN_DIRS 8 | 28 | #define MAX_OPEN_DIRS 8 |
28 | 29 | ||
29 | static DIR opendirs[MAX_OPEN_DIRS]; | 30 | static DIR opendirs[MAX_OPEN_DIRS]; |
30 | 31 | ||
32 | #ifdef HAVE_MULTIVOLUME | ||
33 | |||
34 | /* how to name volumes, first char must be outside of legal file names, | ||
35 | a number gets appended to enumerate, if applicable */ | ||
36 | #ifdef HAVE_MMC | ||
37 | static const char* vol_names = ":MMC"; | ||
38 | #else | ||
39 | static const char* vol_names = ":HD"; | ||
40 | #endif | ||
41 | |||
42 | /* returns on which volume this is, and copies the reduced name | ||
43 | (sortof a preprocessor for volume-decorated pathnames) */ | ||
44 | static int strip_volume(const char* name, char* namecopy) | ||
45 | { | ||
46 | int volume = 0; | ||
47 | |||
48 | if (name[1] == vol_names[0] ) /* a colon identifies our volumes */ | ||
49 | { | ||
50 | const char* temp; | ||
51 | temp = name + 1 + strlen(vol_names); /* behind special name */ | ||
52 | volume = atoi(temp); /* number is following */ | ||
53 | temp = strchr(temp, '/'); /* search for slash behind */ | ||
54 | if (temp != NULL) | ||
55 | name = temp; /* use the part behind the volume */ | ||
56 | else | ||
57 | name = "/"; /* else this must be the root dir */ | ||
58 | } | ||
59 | |||
60 | strncpy(namecopy, name, MAX_PATH); | ||
61 | namecopy[MAX_PATH-1] = '\0'; | ||
62 | |||
63 | return volume; | ||
64 | } | ||
65 | #endif /* #ifdef HAVE_MULTIVOLUME */ | ||
66 | |||
67 | |||
31 | DIR* opendir(const char* name) | 68 | DIR* opendir(const char* name) |
32 | { | 69 | { |
33 | char namecopy[MAX_PATH]; | 70 | char namecopy[MAX_PATH]; |
@@ -35,6 +72,9 @@ DIR* opendir(const char* name) | |||
35 | char* end; | 72 | char* end; |
36 | struct fat_direntry entry; | 73 | struct fat_direntry entry; |
37 | int dd; | 74 | int dd; |
75 | #ifdef HAVE_MULTIVOLUME | ||
76 | int volume; | ||
77 | #endif | ||
38 | 78 | ||
39 | /* find a free dir descriptor */ | 79 | /* find a free dir descriptor */ |
40 | for ( dd=0; dd<MAX_OPEN_DIRS; dd++ ) | 80 | for ( dd=0; dd<MAX_OPEN_DIRS; dd++ ) |
@@ -55,15 +95,21 @@ DIR* opendir(const char* name) | |||
55 | return NULL; | 95 | return NULL; |
56 | } | 96 | } |
57 | 97 | ||
58 | if ( fat_opendir(&(opendirs[dd].fatdir), 0, NULL) < 0 ) { | 98 | #ifdef HAVE_MULTIVOLUME |
99 | /* try to extract a heading volume name, if present */ | ||
100 | volume = strip_volume(name, namecopy); | ||
101 | opendirs[dd].volumecounter = 0; | ||
102 | #else | ||
103 | strncpy(namecopy,name,sizeof(namecopy)); /* just copy */ | ||
104 | namecopy[sizeof(namecopy)-1] = '\0'; | ||
105 | #endif | ||
106 | |||
107 | if ( fat_opendir(IF_MV2(volume,) &(opendirs[dd].fatdir), 0, NULL) < 0 ) { | ||
59 | DEBUGF("Failed opening root dir\n"); | 108 | DEBUGF("Failed opening root dir\n"); |
60 | opendirs[dd].busy = false; | 109 | opendirs[dd].busy = false; |
61 | return NULL; | 110 | return NULL; |
62 | } | 111 | } |
63 | 112 | ||
64 | strncpy(namecopy,name,sizeof(namecopy)); | ||
65 | namecopy[sizeof(namecopy)-1] = 0; | ||
66 | |||
67 | for ( part = strtok_r(namecopy, "/", &end); part; | 113 | for ( part = strtok_r(namecopy, "/", &end); part; |
68 | part = strtok_r(NULL, "/", &end)) { | 114 | part = strtok_r(NULL, "/", &end)) { |
69 | /* scan dir for name */ | 115 | /* scan dir for name */ |
@@ -76,7 +122,8 @@ DIR* opendir(const char* name) | |||
76 | if ( (entry.attr & FAT_ATTR_DIRECTORY) && | 122 | if ( (entry.attr & FAT_ATTR_DIRECTORY) && |
77 | (!strcasecmp(part, entry.name)) ) { | 123 | (!strcasecmp(part, entry.name)) ) { |
78 | opendirs[dd].parent_dir = opendirs[dd].fatdir; | 124 | opendirs[dd].parent_dir = opendirs[dd].fatdir; |
79 | if ( fat_opendir(&(opendirs[dd].fatdir), | 125 | if ( fat_opendir(IF_MV2(volume,) |
126 | &(opendirs[dd].fatdir), | ||
80 | entry.firstcluster, | 127 | entry.firstcluster, |
81 | &(opendirs[dd].parent_dir)) < 0 ) { | 128 | &(opendirs[dd].parent_dir)) < 0 ) { |
82 | DEBUGF("Failed opening dir '%s' (%d)\n", | 129 | DEBUGF("Failed opening dir '%s' (%d)\n", |
@@ -84,6 +131,9 @@ DIR* opendir(const char* name) | |||
84 | opendirs[dd].busy = false; | 131 | opendirs[dd].busy = false; |
85 | return NULL; | 132 | return NULL; |
86 | } | 133 | } |
134 | #ifdef HAVE_MULTIVOLUME | ||
135 | opendirs[dd].volumecounter = -1; /* n.a. to subdirs */ | ||
136 | #endif | ||
87 | break; | 137 | break; |
88 | } | 138 | } |
89 | } | 139 | } |
@@ -102,7 +152,28 @@ struct dirent* readdir(DIR* dir) | |||
102 | { | 152 | { |
103 | struct fat_direntry entry; | 153 | struct fat_direntry entry; |
104 | struct dirent* theent = &(dir->theent); | 154 | struct dirent* theent = &(dir->theent); |
105 | 155 | #ifdef HAVE_MULTIVOLUME | |
156 | /* Volumes (secondary file systems) get inserted into the root directory | ||
157 | of the first volume, since we have no separate top level. */ | ||
158 | if (dir->volumecounter >= 0 /* on a root dir */ | ||
159 | && dir->volumecounter < NUM_VOLUMES /* in range */ | ||
160 | && dir->fatdir.file.volume == 0) /* at volume 0 */ | ||
161 | { /* fake special directories, which don't really exist, but | ||
162 | will get redirected upon opendir() */ | ||
163 | while (++dir->volumecounter < NUM_VOLUMES) | ||
164 | { | ||
165 | if (fat_ismounted(dir->volumecounter)) | ||
166 | { | ||
167 | memset(theent, 0, sizeof(*theent)); | ||
168 | theent->attribute = FAT_ATTR_DIRECTORY | FAT_ATTR_VOLUME; | ||
169 | snprintf(theent->d_name, sizeof(theent->d_name), | ||
170 | "%s%d", vol_names, dir->volumecounter); | ||
171 | return theent; | ||
172 | } | ||
173 | } | ||
174 | } | ||
175 | #endif | ||
176 | /* normal directory entry fetching follows here */ | ||
106 | if (fat_getnext(&(dir->fatdir),&entry) < 0) | 177 | if (fat_getnext(&(dir->fatdir),&entry) < 0) |
107 | return NULL; | 178 | return NULL; |
108 | 179 | ||