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,
29 #if (CONFIG_COMMANDS & CFG_CMD_FDOS) || defined(CONFIG_CMD_FDOS)
34 static int cache_sect;
35 static unsigned char cache [SZ_STD_SECTOR];
38 #define min(x,y) ((x)<(y)?(x):(y))
40 static int descend (Slot_t *parent,
44 /*-----------------------------------------------------------------------------
46 *-----------------------------------------------------------------------------
48 void init_subdir (void)
52 /*-----------------------------------------------------------------------------
54 *-----------------------------------------------------------------------------
56 char *basename (char *name)
60 if (!name || !*name) {
64 for (cptr= name; *cptr++; );
65 while (--cptr >= name) {
72 /*-----------------------------------------------------------------------------
74 *-----------------------------------------------------------------------------
76 static int root_map (Fs_t *fs, Slot_t *file, int where, int *len)
78 *len = min (*len, fs -> dir_len * SZ_STD_SECTOR - where);
83 return fs -> dir_start * SZ_STD_SECTOR + where;
85 /*-----------------------------------------------------------------------------
87 *-----------------------------------------------------------------------------
89 static int normal_map (Fs_t *fs, Slot_t *file, int where, int *len)
93 unsigned short RelCluNr;
94 unsigned short CurCluNr;
95 unsigned short NewCluNr;
96 unsigned short AbsCluNr;
99 clus_size = fs -> cluster_size * SZ_STD_SECTOR;
100 offset = where % clus_size;
102 *len = min (*len, file -> FileSize - where);
109 if (file -> FirstAbsCluNr < 2){
114 RelCluNr = where / clus_size;
116 if (RelCluNr >= file -> PreviousRelCluNr){
117 CurCluNr = file -> PreviousRelCluNr;
118 AbsCluNr = file -> PreviousAbsCluNr;
121 AbsCluNr = file -> FirstAbsCluNr;
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
130 file -> PreviousRelCluNr = RelCluNr;
131 file -> PreviousAbsCluNr = AbsCluNr;
133 NewCluNr = fat_decode (fs, AbsCluNr);
134 if (NewCluNr == 1 || NewCluNr == 0) {
135 PRINTF("Fat problem while decoding %d %x\n",
139 if (CurCluNr == RelCluNr + NrClu) {
143 if (CurCluNr < RelCluNr && NewCluNr == FAT12_END) {
148 if (CurCluNr >= RelCluNr && NewCluNr != AbsCluNr + 1)
154 *len = min (*len, (1 + CurCluNr - RelCluNr) * clus_size - offset);
156 return (((file -> PreviousAbsCluNr - 2) * fs -> cluster_size +
157 fs -> dir_start + fs -> dir_len) *
158 SZ_STD_SECTOR + offset);
160 /*-----------------------------------------------------------------------------
161 * open_subdir -- open the subdir containing the file
162 *-----------------------------------------------------------------------------
164 int open_subdir (File_t *desc)
167 char *tmp, *s, *path;
170 if ((pathname = (char *)malloc (MAX_PATH)) == NULL) {
174 strcpy (pathname, desc -> name);
176 /* Suppress file name */
177 tmp = basename (pathname);
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;
187 for (s = tmp; ; ++s) {
188 if (*s == '/' || *s == '\0') {
192 if (s != tmp && strcmp (path,".")) {
193 if (descend (&desc -> subdir, desc -> fs, path) < 0) {
198 if (terminator == 0) {
207 /*-----------------------------------------------------------------------------
209 *-----------------------------------------------------------------------------
211 static int descend (Slot_t *parent,
218 if(path[0] == '\0' || strcmp (path, ".") == 0) {
224 if (vfat_lookup (parent,
230 ACCEPT_DIR | SINGLE | DO_OPEN,
237 if (strcmp(path, "..") == 0) {
238 parent -> FileSize = -1;
239 parent -> FirstAbsCluNr = 0;
240 parent -> map = root_map;
245 /*-----------------------------------------------------------------------------
247 *-----------------------------------------------------------------------------
249 int open_file (Slot_t *file, Directory_t *dir)
254 first = __le16_to_cpu (dir -> start);
257 (dir -> attr & ATTR_DIRECTORY) != 0) {
258 file -> FirstAbsCluNr = 0;
259 file -> FileSize = -1;
260 file -> map = root_map;
264 if ((dir -> attr & ATTR_DIRECTORY) != 0) {
265 size = (1UL << 31) - 1;
268 size = __le32_to_cpu (dir -> size);
271 file -> map = normal_map;
272 file -> FirstAbsCluNr = first;
273 file -> PreviousRelCluNr = 0xffff;
274 file -> FileSize = size;
277 /*-----------------------------------------------------------------------------
279 *-----------------------------------------------------------------------------
281 int read_file (Fs_t *fs,
288 int read, nb, sect, offset;
290 pos = file -> map (fs, file, where, &len);
298 /* Compute sector number */
299 sect = pos / SZ_STD_SECTOR;
300 offset = pos % SZ_STD_SECTOR;
304 /* Read doesn't start at the sector beginning. We need to use our */
306 if (sect != cache_sect) {
307 if (dev_read (cache, sect, 1) < 0) {
312 nb = min (len, SZ_STD_SECTOR - offset);
314 memcpy (buf, cache + offset, nb);
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);
325 /* update sector position */
328 /* Update byte position */
335 if (sect != cache_sect) {
336 if (dev_read (cache, sect, 1) < 0) {
337 return ((read) ? read : -1);
343 memcpy (buf + read, cache, len);