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