3 * Stäubli Faverges - <www.staubli.com>
6 * See file CREDITS for list of people who contributed to this
9 * This program is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU General Public License as
11 * published by the Free Software Foundation; either version 2 of
12 * the License, or (at your option) any later version.
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
32 static int cache_sect;
33 static unsigned char cache [SZ_STD_SECTOR];
36 #define min(x,y) ((x)<(y)?(x):(y))
38 static int descend (Slot_t *parent,
42 /*-----------------------------------------------------------------------------
44 *-----------------------------------------------------------------------------
46 void init_subdir (void)
50 /*-----------------------------------------------------------------------------
52 *-----------------------------------------------------------------------------
54 char *basename (char *name)
58 if (!name || !*name) {
62 for (cptr= name; *cptr++; );
63 while (--cptr >= name) {
70 /*-----------------------------------------------------------------------------
72 *-----------------------------------------------------------------------------
74 static int root_map (Fs_t *fs, Slot_t *file, int where, int *len)
76 *len = min (*len, fs -> dir_len * SZ_STD_SECTOR - where);
81 return fs -> dir_start * SZ_STD_SECTOR + where;
83 /*-----------------------------------------------------------------------------
85 *-----------------------------------------------------------------------------
87 static int normal_map (Fs_t *fs, Slot_t *file, int where, int *len)
91 unsigned short RelCluNr;
92 unsigned short CurCluNr;
93 unsigned short NewCluNr;
94 unsigned short AbsCluNr;
97 clus_size = fs -> cluster_size * SZ_STD_SECTOR;
98 offset = where % clus_size;
100 *len = min (*len, file -> FileSize - where);
107 if (file -> FirstAbsCluNr < 2){
112 RelCluNr = where / clus_size;
114 if (RelCluNr >= file -> PreviousRelCluNr){
115 CurCluNr = file -> PreviousRelCluNr;
116 AbsCluNr = file -> PreviousAbsCluNr;
119 AbsCluNr = file -> FirstAbsCluNr;
123 NrClu = (offset + *len - 1) / clus_size;
124 while (CurCluNr <= RelCluNr + NrClu) {
125 if (CurCluNr == RelCluNr){
126 /* we have reached the beginning of our zone. Save
128 file -> PreviousRelCluNr = RelCluNr;
129 file -> PreviousAbsCluNr = AbsCluNr;
131 NewCluNr = fat_decode (fs, AbsCluNr);
132 if (NewCluNr == 1 || NewCluNr == 0) {
133 PRINTF("Fat problem while decoding %d %x\n",
137 if (CurCluNr == RelCluNr + NrClu) {
141 if (CurCluNr < RelCluNr && NewCluNr == FAT12_END) {
146 if (CurCluNr >= RelCluNr && NewCluNr != AbsCluNr + 1)
152 *len = min (*len, (1 + CurCluNr - RelCluNr) * clus_size - offset);
154 return (((file -> PreviousAbsCluNr - 2) * fs -> cluster_size +
155 fs -> dir_start + fs -> dir_len) *
156 SZ_STD_SECTOR + offset);
158 /*-----------------------------------------------------------------------------
159 * open_subdir -- open the subdir containing the file
160 *-----------------------------------------------------------------------------
162 int open_subdir (File_t *desc)
165 char *tmp, *s, *path;
168 if ((pathname = (char *)malloc (MAX_PATH)) == NULL) {
172 strcpy (pathname, desc -> name);
174 /* Suppress file name */
175 tmp = basename (pathname);
178 /* root directory init */
179 desc -> subdir.FirstAbsCluNr = 0;
180 desc -> subdir.FileSize = -1;
181 desc -> subdir.map = root_map;
182 desc -> subdir.dir.attr = ATTR_DIRECTORY;
185 for (s = tmp; ; ++s) {
186 if (*s == '/' || *s == '\0') {
190 if (s != tmp && strcmp (path,".")) {
191 if (descend (&desc -> subdir, desc -> fs, path) < 0) {
196 if (terminator == 0) {
205 /*-----------------------------------------------------------------------------
207 *-----------------------------------------------------------------------------
209 static int descend (Slot_t *parent,
216 if(path[0] == '\0' || strcmp (path, ".") == 0) {
222 if (vfat_lookup (parent,
228 ACCEPT_DIR | SINGLE | DO_OPEN,
235 if (strcmp(path, "..") == 0) {
236 parent -> FileSize = -1;
237 parent -> FirstAbsCluNr = 0;
238 parent -> map = root_map;
243 /*-----------------------------------------------------------------------------
245 *-----------------------------------------------------------------------------
247 int open_file (Slot_t *file, Directory_t *dir)
252 first = __le16_to_cpu (dir -> start);
255 (dir -> attr & ATTR_DIRECTORY) != 0) {
256 file -> FirstAbsCluNr = 0;
257 file -> FileSize = -1;
258 file -> map = root_map;
262 if ((dir -> attr & ATTR_DIRECTORY) != 0) {
263 size = (1UL << 31) - 1;
266 size = __le32_to_cpu (dir -> size);
269 file -> map = normal_map;
270 file -> FirstAbsCluNr = first;
271 file -> PreviousRelCluNr = 0xffff;
272 file -> FileSize = size;
275 /*-----------------------------------------------------------------------------
277 *-----------------------------------------------------------------------------
279 int read_file (Fs_t *fs,
286 int read, nb, sect, offset;
288 pos = file -> map (fs, file, where, &len);
296 /* Compute sector number */
297 sect = pos / SZ_STD_SECTOR;
298 offset = pos % SZ_STD_SECTOR;
302 /* Read doesn't start at the sector beginning. We need to use our */
304 if (sect != cache_sect) {
305 if (dev_read (cache, sect, 1) < 0) {
310 nb = min (len, SZ_STD_SECTOR - offset);
312 memcpy (buf, cache + offset, nb);
318 if (len > SZ_STD_SECTOR) {
319 nb = (len - 1) / SZ_STD_SECTOR;
320 if (dev_read (buf + read, sect, nb) < 0) {
321 return ((read) ? read : -1);
323 /* update sector position */
326 /* Update byte position */
333 if (sect != cache_sect) {
334 if (dev_read (cache, sect, 1) < 0) {
335 return ((read) ? read : -1);
341 memcpy (buf + read, cache, len);