diff options
Diffstat (limited to 'firmware/common')
-rw-r--r-- | firmware/common/dir.c | 83 | ||||
-rw-r--r-- | firmware/common/disk.c | 26 | ||||
-rw-r--r-- | firmware/common/file.c | 3 |
3 files changed, 97 insertions, 15 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 | ||
diff --git a/firmware/common/disk.c b/firmware/common/disk.c index b85f460a69..cfe15984f9 100644 --- a/firmware/common/disk.c +++ b/firmware/common/disk.c | |||
@@ -41,12 +41,22 @@ | |||
41 | 41 | ||
42 | static struct partinfo part[8]; | 42 | static struct partinfo part[8]; |
43 | 43 | ||
44 | struct partinfo* disk_init(void) | 44 | struct partinfo* disk_init(IF_MV_NONVOID(int drive)) |
45 | { | 45 | { |
46 | int i; | 46 | int i; |
47 | unsigned char sector[512]; | 47 | unsigned char sector[512]; |
48 | #ifdef HAVE_MULTIVOLUME | ||
49 | /* For each drive, start at a different position, in order not to destroy | ||
50 | the first entry of drive 0. | ||
51 | That one is needed to calculate config sector position. */ | ||
52 | struct partinfo* pinfo = &part[drive*4]; | ||
53 | if ((size_t)drive >= sizeof(part)/sizeof(*part)/4) | ||
54 | return NULL; /* out of space in table */ | ||
55 | #else | ||
56 | struct partinfo* pinfo = part; | ||
57 | #endif | ||
48 | 58 | ||
49 | ata_read_sectors(0,1,§or); | 59 | ata_read_sectors(IF_MV2(drive,) 0,1,§or); |
50 | 60 | ||
51 | /* check that the boot sector is initialized */ | 61 | /* check that the boot sector is initialized */ |
52 | if ( (sector[510] != 0x55) || | 62 | if ( (sector[510] != 0x55) || |
@@ -58,20 +68,20 @@ struct partinfo* disk_init(void) | |||
58 | /* parse partitions */ | 68 | /* parse partitions */ |
59 | for ( i=0; i<4; i++ ) { | 69 | for ( i=0; i<4; i++ ) { |
60 | unsigned char* ptr = sector + 0x1be + 16*i; | 70 | unsigned char* ptr = sector + 0x1be + 16*i; |
61 | part[i].type = ptr[4]; | 71 | pinfo[i].type = ptr[4]; |
62 | part[i].start = BYTES2INT32(ptr, 8); | 72 | pinfo[i].start = BYTES2INT32(ptr, 8); |
63 | part[i].size = BYTES2INT32(ptr, 12); | 73 | pinfo[i].size = BYTES2INT32(ptr, 12); |
64 | 74 | ||
65 | DEBUGF("Part%d: Type %02x, start: %08x size: %08x\n", | 75 | DEBUGF("Part%d: Type %02x, start: %08x size: %08x\n", |
66 | i,part[i].type,part[i].start,part[i].size); | 76 | i,pinfo[i].type,pinfo[i].start,pinfo[i].size); |
67 | 77 | ||
68 | /* extended? */ | 78 | /* extended? */ |
69 | if ( part[i].type == 5 ) { | 79 | if ( pinfo[i].type == 5 ) { |
70 | /* not handled yet */ | 80 | /* not handled yet */ |
71 | } | 81 | } |
72 | } | 82 | } |
73 | 83 | ||
74 | return part; | 84 | return pinfo; |
75 | } | 85 | } |
76 | 86 | ||
77 | struct partinfo* disk_partinfo(int partition) | 87 | struct partinfo* disk_partinfo(int partition) |
diff --git a/firmware/common/file.c b/firmware/common/file.c index 81b5a194c0..6714b9982c 100644 --- a/firmware/common/file.c +++ b/firmware/common/file.c | |||
@@ -132,7 +132,8 @@ int open(const char* pathname, int flags) | |||
132 | /* scan dir for name */ | 132 | /* scan dir for name */ |
133 | while ((entry = readdir(dir))) { | 133 | while ((entry = readdir(dir))) { |
134 | if ( !strcasecmp(name, entry->d_name) ) { | 134 | if ( !strcasecmp(name, entry->d_name) ) { |
135 | fat_open(entry->startcluster, | 135 | fat_open(IF_MV2(dir->fatdir.file.volume,) |
136 | entry->startcluster, | ||
136 | &(file->fatfile), | 137 | &(file->fatfile), |
137 | &(dir->fatdir)); | 138 | &(dir->fatdir)); |
138 | file->size = file->trunc ? 0 : entry->size; | 139 | file->size = file->trunc ? 0 : entry->size; |