blob: 5911f2e88f48bb296a5730d8e93bfe64a402ef86 [file] [log] [blame]
wdenk2262cfe2002-11-18 00:14:45 +00001/*
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 (CONFIG_COMMANDS & CFG_CMD_FDOS)
30
31#include "dos.h"
32#include "fdos.h"
33
34static int cache_sect;
35static unsigned char cache [SZ_STD_SECTOR];
36
37
38#define min(x,y) ((x)<(y)?(x):(y))
39
40static int descend (Slot_t *parent,
41 Fs_t *fs,
42 char *path);
43
44/*-----------------------------------------------------------------------------
45 * init_subdir --
46 *-----------------------------------------------------------------------------
47 */
48void init_subdir (void)
49{
50 cache_sect = -1;
51}
52/*-----------------------------------------------------------------------------
53 * basename --
54 *-----------------------------------------------------------------------------
55 */
56char *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 */
76static 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 */
89static 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 */
164int 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 */
211static 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 */
249int 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 */
281int 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