]> git.kernelconcepts.de Git - karo-tx-uboot.git/blob - fs/fdos/subdir.c
fs/: Remove obsolete references to CONFIG_COMMANDS
[karo-tx-uboot.git] / fs / fdos / subdir.c
1 /*
2  * (C) Copyright 2002
3  * Stäubli Faverges - <www.staubli.com>
4  * Pierre AUBERT  p.aubert@staubli.com
5  *
6  * See file CREDITS for list of people who contributed to this
7  * project.
8  *
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.
13  *
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.
18  *
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,
22  * MA 02111-1307 USA
23  */
24
25 #include <common.h>
26 #include <config.h>
27 #include <malloc.h>
28
29 #if defined(CONFIG_CMD_FDOS)
30
31 #include "dos.h"
32 #include "fdos.h"
33
34 static int cache_sect;
35 static unsigned char cache [SZ_STD_SECTOR];
36
37
38 #define min(x,y) ((x)<(y)?(x):(y))
39
40 static int descend (Slot_t *parent,
41              Fs_t *fs,
42                     char *path);
43
44 /*-----------------------------------------------------------------------------
45  * init_subdir --
46  *-----------------------------------------------------------------------------
47  */
48 void init_subdir (void)
49 {
50     cache_sect = -1;
51 }
52 /*-----------------------------------------------------------------------------
53  * basename --
54  *-----------------------------------------------------------------------------
55  */
56 char *basename (char *name)
57 {
58     register char *cptr;
59
60     if (!name || !*name) {
61         return ("");
62     }
63
64     for (cptr= name; *cptr++; );
65     while (--cptr >= name) {
66         if (*cptr == '/')    {
67             return (cptr + 1);
68         }
69     }
70     return(name);
71 }
72 /*-----------------------------------------------------------------------------
73  * root_map --
74  *-----------------------------------------------------------------------------
75  */
76 static int root_map (Fs_t *fs, Slot_t *file, int where, int *len)
77 {
78     *len = min (*len, fs -> dir_len * SZ_STD_SECTOR - where);
79     if (*len < 0 ) {
80         *len = 0;
81         return (-1);
82     }
83     return fs -> dir_start * SZ_STD_SECTOR + where;
84 }
85 /*-----------------------------------------------------------------------------
86  * normal_map --
87  *-----------------------------------------------------------------------------
88  */
89 static int normal_map (Fs_t *fs, Slot_t *file, int where, int *len)
90 {
91     int offset;
92     int NrClu;
93     unsigned short RelCluNr;
94     unsigned short CurCluNr;
95     unsigned short NewCluNr;
96     unsigned short AbsCluNr;
97     int clus_size;
98
99     clus_size = fs -> cluster_size * SZ_STD_SECTOR;
100     offset = where % clus_size;
101
102     *len = min (*len, file -> FileSize - where);
103
104     if (*len < 0 ) {
105         *len = 0;
106         return (0);
107     }
108
109     if (file -> FirstAbsCluNr < 2){
110         *len = 0;
111         return (0);
112     }
113
114     RelCluNr = where / clus_size;
115
116     if (RelCluNr >= file -> PreviousRelCluNr){
117         CurCluNr = file -> PreviousRelCluNr;
118         AbsCluNr = file -> PreviousAbsCluNr;
119     } else {
120         CurCluNr = 0;
121         AbsCluNr = file -> FirstAbsCluNr;
122     }
123
124
125     NrClu = (offset + *len - 1) / clus_size;
126     while (CurCluNr <= RelCluNr + NrClu) {
127         if (CurCluNr == RelCluNr){
128             /* we have reached the beginning of our zone. Save
129              * coordinates */
130             file -> PreviousRelCluNr = RelCluNr;
131             file -> PreviousAbsCluNr = AbsCluNr;
132         }
133         NewCluNr = fat_decode (fs, AbsCluNr);
134         if (NewCluNr == 1 || NewCluNr == 0) {
135             PRINTF("Fat problem while decoding %d %x\n",
136                     AbsCluNr, NewCluNr);
137             return (-1);
138         }
139         if (CurCluNr == RelCluNr + NrClu) {
140             break;
141         }
142
143         if (CurCluNr < RelCluNr && NewCluNr == FAT12_END) {
144             *len = 0;
145             return 0;
146         }
147
148         if (CurCluNr >= RelCluNr && NewCluNr != AbsCluNr + 1)
149             break;
150         CurCluNr++;
151         AbsCluNr = NewCluNr;
152     }
153
154     *len = min (*len, (1 + CurCluNr - RelCluNr) * clus_size - offset);
155
156     return (((file -> PreviousAbsCluNr - 2) * fs -> cluster_size +
157              fs -> dir_start + fs -> dir_len) *
158             SZ_STD_SECTOR + offset);
159 }
160 /*-----------------------------------------------------------------------------
161  * open_subdir -- open the subdir containing the file
162  *-----------------------------------------------------------------------------
163  */
164 int open_subdir (File_t *desc)
165 {
166     char *pathname;
167     char *tmp, *s, *path;
168     char terminator;
169
170     if ((pathname = (char *)malloc (MAX_PATH)) == NULL) {
171         return (-1);
172     }
173
174     strcpy (pathname, desc -> name);
175
176     /* Suppress file name                                                    */
177     tmp = basename (pathname);
178     *tmp = '\0';
179
180     /* root directory  init                                                  */
181     desc -> subdir.FirstAbsCluNr = 0;
182     desc -> subdir.FileSize = -1;
183     desc -> subdir.map = root_map;
184     desc -> subdir.dir.attr = ATTR_DIRECTORY;
185
186     tmp = pathname;
187     for (s = tmp; ; ++s) {
188         if (*s == '/' || *s == '\0') {
189             path = tmp;
190             terminator = *s;
191             *s = '\0';
192             if (s != tmp && strcmp (path,".")) {
193                 if (descend (&desc -> subdir, desc -> fs, path) < 0) {
194                     free (pathname);
195                     return (-1);
196                 }
197             }
198             if (terminator == 0) {
199                 break;
200             }
201             tmp = s + 1;
202         }
203     }
204     free (pathname);
205     return (0);
206 }
207 /*-----------------------------------------------------------------------------
208  * descend --
209  *-----------------------------------------------------------------------------
210  */
211 static int descend (Slot_t *parent,
212              Fs_t *fs,
213              char *path)
214 {
215     int entry;
216     Slot_t SubDir;
217
218     if(path[0] == '\0' || strcmp (path, ".") == 0) {
219         return (0);
220     }
221
222
223     entry = 0;
224     if (vfat_lookup (parent,
225                      fs,
226                      &(SubDir.dir),
227                      &entry,
228                      0,
229                      path,
230                      ACCEPT_DIR | SINGLE | DO_OPEN,
231                      0,
232                      &SubDir) == 0) {
233         *parent = SubDir;
234         return (0);
235     }
236
237     if (strcmp(path, "..") == 0) {
238         parent -> FileSize = -1;
239         parent -> FirstAbsCluNr = 0;
240         parent -> map = root_map;
241         return (0);
242     }
243     return (-1);
244 }
245 /*-----------------------------------------------------------------------------
246  * open_file --
247  *-----------------------------------------------------------------------------
248  */
249 int open_file (Slot_t *file, Directory_t *dir)
250 {
251     int first;
252     unsigned long size;
253
254     first = __le16_to_cpu (dir -> start);
255
256     if(first == 0 &&
257        (dir -> attr & ATTR_DIRECTORY) != 0) {
258         file -> FirstAbsCluNr = 0;
259         file -> FileSize = -1;
260         file -> map = root_map;
261         return (0);
262     }
263
264     if ((dir -> attr & ATTR_DIRECTORY) != 0) {
265         size = (1UL << 31) - 1;
266     }
267     else {
268         size = __le32_to_cpu (dir -> size);
269     }
270
271     file -> map = normal_map;
272     file -> FirstAbsCluNr = first;
273     file -> PreviousRelCluNr = 0xffff;
274     file -> FileSize = size;
275     return (0);
276 }
277 /*-----------------------------------------------------------------------------
278  * read_file --
279  *-----------------------------------------------------------------------------
280  */
281 int read_file (Fs_t *fs,
282                Slot_t *file,
283                char *buf,
284                int where,
285                int len)
286 {
287     int pos;
288     int read, nb, sect, offset;
289
290     pos = file -> map (fs, file, where, &len);
291     if  (pos < 0) {
292         return -1;
293     }
294     if (len == 0) {
295         return (0);
296     }
297
298     /* Compute sector number                                                 */
299     sect = pos / SZ_STD_SECTOR;
300     offset = pos % SZ_STD_SECTOR;
301     read = 0;
302
303     if (offset) {
304         /* Read doesn't start at the sector beginning. We need to use our    */
305         /* cache                                                             */
306         if (sect != cache_sect) {
307             if (dev_read (cache, sect, 1) < 0) {
308                 return (-1);
309             }
310             cache_sect = sect;
311         }
312         nb = min (len, SZ_STD_SECTOR - offset);
313
314         memcpy (buf, cache + offset, nb);
315         read += nb;
316         len -= nb;
317         sect += 1;
318     }
319
320     if (len > SZ_STD_SECTOR) {
321         nb = (len - 1) / SZ_STD_SECTOR;
322         if (dev_read (buf + read, sect, nb) < 0) {
323             return ((read) ? read : -1);
324         }
325         /* update sector position                                            */
326         sect += nb;
327
328         /* Update byte position                                              */
329         nb *= SZ_STD_SECTOR;
330         read += nb;
331         len -= nb;
332     }
333
334     if (len) {
335         if (sect != cache_sect) {
336             if (dev_read (cache, sect, 1) < 0) {
337                 return ((read) ? read : -1);
338                 cache_sect = -1;
339             }
340             cache_sect = sect;
341         }
342
343         memcpy (buf + read, cache, len);
344         read += len;
345     }
346     return (read);
347 }
348 #endif