summaryrefslogtreecommitdiffstats
path: root/fs/fdos
diff options
context:
space:
mode:
authorwdenk <wdenk>2002-11-18 00:14:45 +0000
committerwdenk <wdenk>2002-11-18 00:14:45 +0000
commit2262cfeef91458b01a1bfe3812ccbbfdf8b82807 (patch)
tree3657d48c8ce9089fc96682848859d035a1e8f115 /fs/fdos
parent1d0350ed0b1b0f63e3fb5db6b19397b84a2ea1c7 (diff)
downloadu-boot-2262cfeef91458b01a1bfe3812ccbbfdf8b82807.tar.gz
u-boot-2262cfeef91458b01a1bfe3812ccbbfdf8b82807.tar.xz
u-boot-2262cfeef91458b01a1bfe3812ccbbfdf8b82807.zip
* Patch by Daniel Engström, 13 Nov 2002:LABEL_2002_11_18_0115
Add support for i386 architecture and AMD SC520 board * Patch by Pierre Aubert, 12 Nov 2002: Add support for DOS filesystem and booting from DOS floppy disk
Diffstat (limited to 'fs/fdos')
-rw-r--r--fs/fdos/Makefile49
-rw-r--r--fs/fdos/dev.c195
-rw-r--r--fs/fdos/dos.h177
-rw-r--r--fs/fdos/fat.c145
-rw-r--r--fs/fdos/fdos.c175
-rw-r--r--fs/fdos/fdos.h117
-rw-r--r--fs/fdos/fs.c120
-rw-r--r--fs/fdos/subdir.c348
-rw-r--r--fs/fdos/vfat.c357
9 files changed, 1683 insertions, 0 deletions
diff --git a/fs/fdos/Makefile b/fs/fdos/Makefile
new file mode 100644
index 0000000000..af0fff1c84
--- /dev/null
+++ b/fs/fdos/Makefile
@@ -0,0 +1,49 @@
+#
+# (C) Copyright 2002
+# Stäubli Faverges - <www.staubli.com>
+# Pierre AUBERT p.aubert@staubli.com
+#
+#
+# See file CREDITS for list of people who contributed to this
+# project.
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License as
+# published by the Free Software Foundation; either version 2 of
+# the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+# MA 02111-1307 USA
+#
+
+include $(TOPDIR)/config.mk
+
+LIB = libfdos.a
+
+AOBJS =
+COBJS = fat.o vfat.o dev.o fdos.o fs.o subdir.o
+OBJS = $(AOBJS) $(COBJS)
+
+#CPPFLAGS +=
+
+all: $(LIB) $(AOBJS)
+
+$(LIB): .depend $(OBJS)
+ $(AR) crv $@ $(OBJS)
+
+
+#########################################################################
+
+.depend: Makefile $(AOBJS:.o=.S) $(COBJS:.o=.c)
+ $(CC) -M $(CFLAGS) $(AOBJS:.o=.S) $(COBJS:.o=.c) > $@
+
+sinclude .depend
+
+#########################################################################
diff --git a/fs/fdos/dev.c b/fs/fdos/dev.c
new file mode 100644
index 0000000000..f38d07dbd8
--- /dev/null
+++ b/fs/fdos/dev.c
@@ -0,0 +1,195 @@
+/*
+ * (C) Copyright 2002
+ * Stäubli Faverges - <www.staubli.com>
+ * Pierre AUBERT p.aubert@staubli.com
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <common.h>
+#include <config.h>
+
+#include "dos.h"
+#include "fdos.h"
+
+#if (CONFIG_COMMANDS & CFG_CMD_FDOS)
+
+#define NB_HEADS 2
+#define NB_TRACKS 80
+#define NB_SECTORS 18
+
+
+static int lastwhere;
+
+/*-----------------------------------------------------------------------------
+ * dev_open --
+ *-----------------------------------------------------------------------------
+ */
+int dev_open (void)
+{
+ lastwhere = 0;
+ return (0);
+}
+
+/*-----------------------------------------------------------------------------
+ * dev_read -- len and where are sectors number
+ *-----------------------------------------------------------------------------
+ */
+int dev_read (void *buffer, int where, int len)
+{
+ PRINTF ("dev_read (len = %d, where = %d)\n", len, where);
+
+ /* Si on ne desire pas lire a la position courante, il faut un seek */
+ if (where != lastwhere) {
+ if (!fdc_fdos_seek (where)) {
+ PRINTF ("seek error in dev_read");
+ lastwhere = -1;
+ return (-1);
+ }
+ }
+
+ if (!fdc_fdos_read (buffer, len)) {
+ PRINTF ("read error\n");
+ lastwhere = -1;
+ return (-1);
+ }
+ lastwhere = where + len;
+ return (0);
+}
+/*-----------------------------------------------------------------------------
+ * check_dev -- verify the diskette format
+ *-----------------------------------------------------------------------------
+ */
+int check_dev (BootSector_t *boot, Fs_t *fs)
+{
+ unsigned int heads, sectors, tracks;
+ int BootP, Infp0, InfpX, InfTm;
+ int sect_per_track;
+
+ /* Display Boot header */
+ PRINTF ("Jump to boot code 0x%02x 0x%02x 0x%02x\n",
+ boot -> jump [0], boot -> jump [1], boot -> jump[2]);
+ PRINTF ("OEM name & version '%*.*s'\n",
+ BANNER_LG, BANNER_LG, boot -> banner );
+ PRINTF ("Bytes per sector hopefully 512 %d\n",
+ __le16_to_cpu (boot -> secsiz));
+ PRINTF ("Cluster size in sectors %d\n",
+ boot -> clsiz);
+ PRINTF ("Number of reserved (boot) sectors %d\n",
+ __le16_to_cpu (boot -> nrsvsect));
+ PRINTF ("Number of FAT tables hopefully 2 %d\n",
+ boot -> nfat);
+ PRINTF ("Number of directory slots %d\n",
+ __le16_to_cpu (boot -> dirents));
+ PRINTF ("Total sectors on disk %d\n",
+ __le16_to_cpu (boot -> psect));
+ PRINTF ("Media descriptor=first byte of FAT %d\n",
+ boot -> descr);
+ PRINTF ("Sectors in FAT %d\n",
+ __le16_to_cpu (boot -> fatlen));
+ PRINTF ("Sectors/track %d\n",
+ __le16_to_cpu (boot -> nsect));
+ PRINTF ("Heads %d\n",
+ __le16_to_cpu (boot -> nheads));
+ PRINTF ("number of hidden sectors %d\n",
+ __le32_to_cpu (boot -> nhs));
+ PRINTF ("big total sectors %d\n",
+ __le32_to_cpu (boot -> bigsect));
+ PRINTF ("physical drive ? %d\n",
+ boot -> physdrive);
+ PRINTF ("reserved %d\n",
+ boot -> reserved);
+ PRINTF ("dos > 4.0 diskette %d\n",
+ boot -> dos4);
+ PRINTF ("serial number %d\n",
+ __le32_to_cpu (boot -> serial));
+ PRINTF ("disk label %*.*s\n",
+ LABEL_LG, LABEL_LG, boot -> label);
+ PRINTF ("FAT type %8.8s\n",
+ boot -> fat_type);
+ PRINTF ("reserved by 2M %d\n",
+ boot -> res_2m);
+ PRINTF ("2M checksum (not used) %d\n",
+ boot -> CheckSum);
+ PRINTF ("2MF format version %d\n",
+ boot -> fmt_2mf);
+ PRINTF ("1 if write track after format %d\n",
+ boot -> wt);
+ PRINTF ("data transfer rate on track 0 %d\n",
+ boot -> rate_0);
+ PRINTF ("data transfer rate on track<>0 %d\n",
+ boot -> rate_any);
+ PRINTF ("offset to boot program %d\n",
+ __le16_to_cpu (boot -> BootP));
+ PRINTF ("T1: information for track 0 %d\n",
+ __le16_to_cpu (boot -> Infp0));
+ PRINTF ("T2: information for track<>0 %d\n",
+ __le16_to_cpu (boot -> InfpX));
+ PRINTF ("T3: track sectors size table %d\n",
+ __le16_to_cpu (boot -> InfTm));
+ PRINTF ("Format date 0x%04x\n",
+ __le16_to_cpu (boot -> DateF));
+ PRINTF ("Format time 0x%04x\n",
+ __le16_to_cpu (boot -> TimeF));
+
+
+ /* informations are extracted from boot sector */
+ heads = __le16_to_cpu (boot -> nheads);
+ sectors = __le16_to_cpu (boot -> nsect);
+ fs -> tot_sectors = __le32_to_cpu (boot -> bigsect);
+ if (__le16_to_cpu (boot -> psect) != 0) {
+ fs -> tot_sectors = __le16_to_cpu (boot -> psect);
+ }
+
+ sect_per_track = heads * sectors;
+ tracks = (fs -> tot_sectors + sect_per_track - 1) / sect_per_track;
+
+ BootP = __le16_to_cpu (boot -> BootP);
+ Infp0 = __le16_to_cpu (boot -> Infp0);
+ InfpX = __le16_to_cpu (boot -> InfpX);
+ InfTm = __le16_to_cpu (boot -> InfTm);
+
+ if (boot -> dos4 == EXTENDED_BOOT &&
+ strncmp( boot->banner,"2M", 2 ) == 0 &&
+ BootP < SZ_STD_SECTOR &&
+ Infp0 < SZ_STD_SECTOR &&
+ InfpX < SZ_STD_SECTOR &&
+ InfTm < SZ_STD_SECTOR &&
+ BootP >= InfTm + 2 &&
+ InfTm >= InfpX &&
+ InfpX >= Infp0 &&
+ Infp0 >= 76 ) {
+
+ return (-1);
+ }
+
+ if (heads != NB_HEADS ||
+ tracks != NB_TRACKS ||
+ sectors != NB_SECTORS ||
+ __le16_to_cpu (boot -> secsiz) != SZ_STD_SECTOR ||
+ fs -> tot_sectors == 0 ||
+ (fs -> tot_sectors % sectors) != 0) {
+ return (-1);
+ }
+
+ return (0);
+}
+
+
+#endif
diff --git a/fs/fdos/dos.h b/fs/fdos/dos.h
new file mode 100644
index 0000000000..71701c9fb0
--- /dev/null
+++ b/fs/fdos/dos.h
@@ -0,0 +1,177 @@
+/*
+ * (C) Copyright 2002
+ * Stäubli Faverges - <www.staubli.com>
+ * Pierre AUBERT p.aubert@staubli.com
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#ifndef _DOS_H_
+#define _DOS_H_
+
+/* Definitions for Dos diskettes */
+
+/* General definitions */
+#define SZ_STD_SECTOR 512 /* Standard sector size */
+#define MDIR_SIZE 32 /* Direntry size */
+#define FAT_BITS 12 /* Diskette use 12 bits fat */
+
+#define MAX_PATH 128 /* Max size of the MSDOS PATH */
+#define MAX_DIR_SECS 64 /* Taille max d'un repertoire (en */
+ /* secteurs) */
+/* Misc. definitions */
+#define DELMARK '\xe5'
+#define EXTENDED_BOOT (0x29)
+#define MEDIA_STD (0xf0)
+#define JUMP_0_1 (0xe9)
+#define JUMP_0_2 (0xeb)
+
+/* Boot size is 256 bytes, but we need to read almost a sector, then
+ assume bootsize is 512 */
+#define BOOTSIZE 512
+
+/* Fat definitions for 12 bits fat */
+#define FAT12_MAX_NB 4086
+#define FAT12_LAST 0x0ff6
+#define FAT12_END 0x0fff
+
+/* file attributes */
+#define ATTR_READONLY 0x01
+#define ATTR_HIDDEN 0x02
+#define ATTR_SYSTEM 0x04
+#define ATTR_VOLUME 0x08
+#define ATTR_DIRECTORY 0x10
+#define ATTR_ARCHIVE 0x20
+#define ATTR_VSE 0x0f
+
+/* Name format */
+#define EXTCASE 0x10
+#define BASECASE 0x8
+
+/* Definition of the boot sector */
+#define BANNER_LG 8
+#define LABEL_LG 11
+
+typedef struct bootsector
+{
+ unsigned char jump [3]; /* 0 Jump to boot code */
+ char banner [BANNER_LG]; /* 3 OEM name & version */
+ unsigned short secsiz; /* 11 Bytes per sector hopefully 512 */
+ unsigned char clsiz; /* 13 Cluster size in sectors */
+ unsigned short nrsvsect; /* 14 Number of reserved (boot) sectors */
+ unsigned char nfat; /* 16 Number of FAT tables hopefully 2 */
+ unsigned short dirents; /* 17 Number of directory slots */
+ unsigned short psect; /* 19 Total sectors on disk */
+ unsigned char descr; /* 21 Media descriptor=first byte of FAT */
+ unsigned short fatlen; /* 22 Sectors in FAT */
+ unsigned short nsect; /* 24 Sectors/track */
+ unsigned short nheads; /* 26 Heads */
+ unsigned int nhs; /* 28 number of hidden sectors */
+ unsigned int bigsect; /* 32 big total sectors */
+ unsigned char physdrive; /* 36 physical drive ? */
+ unsigned char reserved; /* 37 reserved */
+ unsigned char dos4; /* 38 dos > 4.0 diskette */
+ unsigned int serial; /* 39 serial number */
+ char label [LABEL_LG]; /* 43 disk label */
+ char fat_type [8]; /* 54 FAT type */
+ unsigned char res_2m; /* 62 reserved by 2M */
+ unsigned char CheckSum; /* 63 2M checksum (not used) */
+ unsigned char fmt_2mf; /* 64 2MF format version */
+ unsigned char wt; /* 65 1 if write track after format */
+ unsigned char rate_0; /* 66 data transfer rate on track 0 */
+ unsigned char rate_any; /* 67 data transfer rate on track<>0 */
+ unsigned short BootP; /* 68 offset to boot program */
+ unsigned short Infp0; /* 70 T1: information for track 0 */
+ unsigned short InfpX; /* 72 T2: information for track<>0 */
+ unsigned short InfTm; /* 74 T3: track sectors size table */
+ unsigned short DateF; /* 76 Format date */
+ unsigned short TimeF; /* 78 Format time */
+ unsigned char junk [BOOTSIZE - 80]; /* 80 remaining data */
+} __attribute__ ((packed)) BootSector_t;
+
+/* Structure d'une entree de repertoire */
+typedef struct directory {
+ char name [8]; /* file name */
+ char ext [3]; /* file extension */
+ unsigned char attr; /* attribute byte */
+ unsigned char Case; /* case of short filename */
+ unsigned char reserved [9]; /* ?? */
+ unsigned char time [2]; /* time stamp */
+ unsigned char date [2]; /* date stamp */
+ unsigned short start; /* starting cluster number */
+ unsigned int size; /* size of the file */
+} __attribute__ ((packed)) Directory_t;
+
+
+
+#define MAX_VFAT_SUBENTRIES 20
+#define VSE_NAMELEN 13
+
+#define VSE1SIZE 5
+#define VSE2SIZE 6
+#define VSE3SIZE 2
+
+#define VBUFSIZE ((MAX_VFAT_SUBENTRIES * VSE_NAMELEN) + 1)
+
+#define MAX_VNAMELEN (255)
+
+#define VSE_PRESENT 0x01
+#define VSE_LAST 0x40
+#define VSE_MASK 0x1f
+
+/* Flag used by vfat_lookup */
+#define DO_OPEN 1
+#define ACCEPT_PLAIN 0x20
+#define ACCEPT_DIR 0x10
+#define ACCEPT_LABEL 0x08
+#define SINGLE 2
+#define MATCH_ANY 0x40
+
+struct vfat_subentry {
+ unsigned char id; /* VSE_LAST pour la fin, VSE_MASK */
+ /* pour un VSE */
+ char text1 [VSE1SIZE * 2]; /* Caracteres encodes sur 16 bits */
+ unsigned char attribute; /* 0x0f pour les VFAT */
+ unsigned char hash1; /* toujours 0 */
+ unsigned char sum; /* Checksum du nom court */
+ char text2 [VSE2SIZE * 2]; /* Caracteres encodes sur 16 bits */
+ unsigned char sector_l; /* 0 pour les VFAT */
+ unsigned char sector_u; /* 0 pour les VFAT */
+ char text3 [VSE3SIZE * 2]; /* Caracteres encodes sur 16 bits */
+} __attribute__ ((packed)) ;
+
+struct vfat_state {
+ char name [VBUFSIZE];
+ int status; /* is now a bit map of 32 bits */
+ int subentries;
+ unsigned char sum; /* no need to remember the sum for each */
+ /* entry, it is the same anyways */
+} __attribute__ ((packed)) ;
+
+/* Conversion macros */
+#define DOS_YEAR(dir) (((dir)->date[1] >> 1) + 1980)
+#define DOS_MONTH(dir) (((((dir)->date[1]&0x1) << 3) + ((dir)->date[0] >> 5)))
+#define DOS_DAY(dir) ((dir)->date[0] & 0x1f)
+#define DOS_HOUR(dir) ((dir)->time[1] >> 3)
+#define DOS_MINUTE(dir) (((((dir)->time[1]&0x7) << 3) + ((dir)->time[0] >> 5)))
+#define DOS_SEC(dir) (((dir)->time[0] & 0x1f) * 2)
+
+
+#endif
+
diff --git a/fs/fdos/fat.c b/fs/fdos/fat.c
new file mode 100644
index 0000000000..42df755af3
--- /dev/null
+++ b/fs/fdos/fat.c
@@ -0,0 +1,145 @@
+/*
+ * (C) Copyright 2002
+ * Stäubli Faverges - <www.staubli.com>
+ * Pierre AUBERT p.aubert@staubli.com
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <common.h>
+#include <config.h>
+#include <malloc.h>
+
+#if (CONFIG_COMMANDS & CFG_CMD_FDOS)
+
+#include "dos.h"
+#include "fdos.h"
+
+
+/*-----------------------------------------------------------------------------
+ * fat_decode --
+ *-----------------------------------------------------------------------------
+ */
+unsigned int fat_decode (Fs_t *fs, unsigned int num)
+{
+ unsigned int start = num * 3 / 2;
+ unsigned char *address = fs -> fat_buf + start;
+
+ if (num < 2 || start + 1 > (fs -> fat_len * SZ_STD_SECTOR))
+ return 1;
+
+ if (num & 1)
+ return ((address [1] & 0xff) << 4) | ((address [0] & 0xf0 ) >> 4);
+ else
+ return ((address [1] & 0xf) << 8) | (address [0] & 0xff );
+}
+/*-----------------------------------------------------------------------------
+ * check_fat --
+ *-----------------------------------------------------------------------------
+ */
+static int check_fat (Fs_t *fs)
+{
+ int i, f;
+
+ /* Cluster verification */
+ for (i = 3 ; i < fs -> num_clus; i++){
+ f = fat_decode (fs, i);
+ if (f < FAT12_LAST && f > fs -> num_clus){
+ /* Wrong cluster number detected */
+ return (-1);
+ }
+ }
+ return (0);
+}
+/*-----------------------------------------------------------------------------
+ * read_one_fat --
+ *-----------------------------------------------------------------------------
+ */
+static int read_one_fat (BootSector_t *boot, Fs_t *fs, int nfat)
+{
+ if (dev_read (fs -> fat_buf,
+ (fs -> fat_start + nfat * fs -> fat_len),
+ fs -> fat_len) < 0) {
+ return (-1);
+ }
+
+ if (fs -> fat_buf [0] || fs -> fat_buf [1] || fs -> fat_buf [2]) {
+ if ((fs -> fat_buf [0] != boot -> descr &&
+ (fs -> fat_buf [0] != 0xf9 || boot -> descr != MEDIA_STD)) ||
+ fs -> fat_buf [0] < MEDIA_STD){
+ /* Unknown Media */
+ return (-1);
+ }
+ if (fs -> fat_buf [1] != 0xff || fs -> fat_buf [2] != 0xff){
+ /* FAT doesn't start with good values */
+ return (-1);
+ }
+ }
+
+ if (fs -> num_clus >= FAT12_MAX_NB) {
+ /* Too much clusters */
+ return (-1);
+ }
+
+ return check_fat (fs);
+}
+/*-----------------------------------------------------------------------------
+ * read_fat --
+ *-----------------------------------------------------------------------------
+ */
+int read_fat (BootSector_t *boot, Fs_t *fs)
+{
+ unsigned int buflen;
+ int i;
+
+ /* Allocate Fat Buffer */
+ buflen = fs -> fat_len * SZ_STD_SECTOR;
+ if (fs -> fat_buf) {
+ free (fs -> fat_buf);
+ }
+
+ if ((fs -> fat_buf = malloc (buflen)) == NULL) {
+ return (-1);
+ }
+
+ /* Try to read each Fat */
+ for (i = 0; i< fs -> nb_fat; i++){
+ if (read_one_fat (boot, fs, i) == 0) {
+ /* Fat is OK */
+ fs -> num_fat = i;
+ break;
+ }
+ }
+
+ if (i == fs -> nb_fat){
+ return (-1);
+ }
+
+ if (fs -> fat_len > (((fs -> num_clus + 2) *
+ (FAT_BITS / 4) -1 ) / 2 /
+ SZ_STD_SECTOR + 1)) {
+ return (-1);
+ }
+ return (0);
+}
+
+
+
+
+#endif
diff --git a/fs/fdos/fdos.c b/fs/fdos/fdos.c
new file mode 100644
index 0000000000..8963f425f5
--- /dev/null
+++ b/fs/fdos/fdos.c
@@ -0,0 +1,175 @@
+/*
+ * (C) Copyright 2002
+ * Stäubli Faverges - <www.staubli.com>
+ * Pierre AUBERT p.aubert@staubli.com
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <common.h>
+#include <config.h>
+
+#if (CONFIG_COMMANDS & CFG_CMD_FDOS)
+#include <malloc.h>
+#include "dos.h"
+#include "fdos.h"
+
+
+const char *month [] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"};
+
+Fs_t fs;
+File_t file;
+
+/*-----------------------------------------------------------------------------
+ * dos_open --
+ *-----------------------------------------------------------------------------
+ */
+int dos_open(char *name)
+{
+ int lg;
+ int entry;
+ char *fname;
+
+ /* We need to suppress the " char around the name */
+ if (name [0] == '"') {
+ name ++;
+ }
+ lg = strlen (name);
+ if (name [lg - 1] == '"') {
+ name [lg - 1] = '\0';
+ }
+
+ /* Open file system */
+ if (fs_init (&fs) < 0) {
+ return -1;
+ }
+
+ /* Init the file descriptor */
+ file.name = name;
+ file.fs = &fs;
+
+ /* find the subdirectory containing the file */
+ if (open_subdir (&file) < 0) {
+ return (-1);
+ }
+
+ fname = basename (name);
+
+ /* if we try to open root directory */
+ if (*fname == '\0') {
+ file.file = file.subdir;
+ return (0);
+ }
+
+ /* find the file in the subdir */
+ entry = 0;
+ if (vfat_lookup (&file.subdir,
+ file.fs,
+ &file.file.dir,
+ &entry,
+ 0,
+ fname,
+ ACCEPT_DIR | ACCEPT_PLAIN | SINGLE | DO_OPEN,
+ 0,
+ &file.file) != 0) {
+ /* File not found */
+ printf ("File not found\n");
+ return (-1);
+ }
+
+ return 0;
+}
+
+/*-----------------------------------------------------------------------------
+ * dos_read --
+ *-----------------------------------------------------------------------------
+ */
+int dos_read (ulong addr)
+{
+ int read = 0, nb;
+
+ /* Try to boot a directory ? */
+ if (file.file.dir.attr & (ATTR_DIRECTORY | ATTR_VOLUME)) {
+ printf ("Unable to boot %s !!\n", file.name);
+ return (-1);
+ }
+ while (read < file.file.FileSize) {
+ PRINTF ("read_file (%ld)\n", (file.file.FileSize - read));
+ nb = read_file (&fs,
+ &file.file,
+ (char *)addr + read,
+ read,
+ (file.file.FileSize - read));
+ PRINTF ("read_file -> %d\n", nb);
+ if (nb < 0) {
+ printf ("read error\n");
+ return (-1);
+ }
+ read += nb;
+ }
+ return (read);
+}
+/*-----------------------------------------------------------------------------
+ * dos_dir --
+ *-----------------------------------------------------------------------------
+ */
+int dos_dir (void)
+{
+ int entry;
+ Directory_t dir;
+ char *name;
+
+
+ if ((file.file.dir.attr & ATTR_DIRECTORY) == 0) {
+ printf ("%s: not a directory !!\n", file.name);
+ return (1);
+ }
+ entry = 0;
+ if ((name = malloc (MAX_VNAMELEN + 1)) == NULL) {
+ PRINTF ("Allcation error\n");
+ return (1);
+ }
+
+ while (vfat_lookup (&file.file,
+ file.fs,
+ &dir,
+ &entry,
+ 0,
+ NULL,
+ ACCEPT_DIR | ACCEPT_PLAIN | MATCH_ANY,
+ name,
+ NULL) == 0) {
+ /* Display file info */
+ printf ("%3.3s %9d %s %02d %04d %02d:%02d:%02d %s\n",
+ (dir.attr & ATTR_DIRECTORY) ? "dir" : " ",
+ __le32_to_cpu (dir.size),
+ month [DOS_MONTH (&dir) - 1],
+ DOS_DAY (&dir),
+ DOS_YEAR (&dir),
+ DOS_HOUR (&dir),
+ DOS_MINUTE (&dir),
+ DOS_SEC (&dir),
+ name);
+
+ }
+ free (name);
+ return (0);
+}
+
+#endif
diff --git a/fs/fdos/fdos.h b/fs/fdos/fdos.h
new file mode 100644
index 0000000000..18076d8665
--- /dev/null
+++ b/fs/fdos/fdos.h
@@ -0,0 +1,117 @@
+/*
+ * (C) Copyright 2002
+ * Stäubli Faverges - <www.staubli.com>
+ * Pierre AUBERT p.aubert@staubli.com
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#ifndef _FDOS_H_
+#define _FDOS_H_
+
+
+#undef FDOS_DEBUG
+
+#ifdef FDOS_DEBUG
+#define PRINTF(fmt,args...) printf (fmt ,##args)
+#else
+#define PRINTF(fmt,args...)
+#endif
+
+/* Data structure describing media */
+typedef struct fs
+{
+ unsigned long tot_sectors;
+
+ int cluster_size;
+ int num_clus;
+
+ int fat_start;
+ int fat_len;
+ int nb_fat;
+ int num_fat;
+
+ int dir_start;
+ int dir_len;
+
+ unsigned char *fat_buf;
+
+} Fs_t;
+
+/* Data structure describing one file system slot */
+typedef struct slot {
+ int (*map) (struct fs *fs,
+ struct slot *file,
+ int where,
+ int *len);
+ unsigned long FileSize;
+
+ unsigned short int FirstAbsCluNr;
+ unsigned short int PreviousAbsCluNr;
+ unsigned short int PreviousRelCluNr;
+
+ Directory_t dir;
+} Slot_t;
+
+typedef struct file {
+ char *name;
+ int Case;
+ Fs_t *fs;
+ Slot_t subdir;
+ Slot_t file;
+} File_t;
+
+
+/* dev.c */
+int dev_read (void *buffer, int where, int len);
+int dev_open (void);
+int check_dev (BootSector_t *boot, Fs_t *fs);
+
+/* fat.c */
+unsigned int fat_decode (Fs_t *fs, unsigned int num);
+int read_fat (BootSector_t *boot, Fs_t *fs);
+
+/* vfat.c */
+int vfat_lookup (Slot_t *dir,
+ Fs_t *fs,
+ Directory_t *dirent,
+ int *entry,
+ int *vfat_start,
+ char *filename,
+ int flags,
+ char *outname,
+ Slot_t *file);
+
+/* subdir.c */
+char *basename (char *name);
+int open_subdir (File_t *desc);
+int open_file (Slot_t *file, Directory_t *dir);
+int read_file (Fs_t *fs,
+ Slot_t *file,
+ char *buf,
+ int where,
+ int len);
+void init_subdir (void);
+
+/* fs.c */
+int fs_init (Fs_t *fs);
+
+
+#endif
+
diff --git a/fs/fdos/fs.c b/fs/fdos/fs.c
new file mode 100644
index 0000000000..68bbde0e27
--- /dev/null
+++ b/fs/fdos/fs.c
@@ -0,0 +1,120 @@
+/*
+ * (C) Copyright 2002
+ * Stäubli Faverges - <www.staubli.com>
+ * Pierre AUBERT p.aubert@staubli.com
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <common.h>
+#include <config.h>
+#include <malloc.h>
+
+#if (CONFIG_COMMANDS & CFG_CMD_FDOS)
+
+#include "dos.h"
+#include "fdos.h"
+
+
+/*-----------------------------------------------------------------------------
+ * fill_fs -- Read info on file system
+ *-----------------------------------------------------------------------------
+ */
+static int fill_fs (BootSector_t *boot, Fs_t *fs)
+{
+
+ fs -> fat_start = __le16_to_cpu (boot -> nrsvsect);
+ fs -> fat_len = __le16_to_cpu (boot -> fatlen);
+ fs -> nb_fat = boot -> nfat;
+
+ fs -> dir_start = fs -> fat_start + fs -> nb_fat * fs -> fat_len;
+ fs -> dir_len = __le16_to_cpu (boot -> dirents) * MDIR_SIZE / SZ_STD_SECTOR;
+ fs -> cluster_size = boot -> clsiz;
+ fs -> num_clus = (fs -> tot_sectors - fs -> dir_start - fs -> dir_len) / fs -> cluster_size;
+
+ return (0);
+}
+
+/*-----------------------------------------------------------------------------
+ * fs_init --
+ *-----------------------------------------------------------------------------
+ */
+int fs_init (Fs_t *fs)
+{
+ BootSector_t *boot;
+
+ /* Initialize physical device */
+ if (dev_open () < 0) {
+ PRINTF ("Unable to initialize the fdc\n");
+ return (-1);
+ }
+ init_subdir ();
+
+ /* Allocate space for read the boot sector */
+ if ((boot = (BootSector_t *)malloc (sizeof (BootSector_t))) == NULL) {
+ PRINTF ("Unable to allocate space for boot sector\n");
+ return (-1);
+ }
+
+ /* read boot sector */
+ if (dev_read (boot, 0, 1)){
+ PRINTF ("Error during boot sector read\n");
+ free (boot);
+ return (-1);
+ }
+
+ /* we verify it'a a DOS diskette */
+ if (boot -> jump [0] != JUMP_0_1 && boot -> jump [0] != JUMP_0_2) {
+ PRINTF ("Not a DOS diskette\n");
+ free (boot);
+ return (-1);
+ }
+
+ if (boot -> descr < MEDIA_STD) {
+ /* We handle only recent medias (type F0) */
+ PRINTF ("unrecognized diskette type\n");
+ free (boot);
+ return (-1);
+ }
+
+ if (check_dev (boot, fs) < 0) {
+ PRINTF ("Bad diskette\n");
+ free (boot);
+ return (-1);
+ }
+
+ if (fill_fs (boot, fs) < 0) {
+ free (boot);
+
+ return (-1);
+ }
+
+ /* Read FAT */
+ if (read_fat (boot, fs) < 0) {
+ free (boot);
+ return (-1);
+ }
+
+ free (boot);
+ return (0);
+}
+
+
+
+#endif
diff --git a/fs/fdos/subdir.c b/fs/fdos/subdir.c
new file mode 100644
index 0000000000..5911f2e88f
--- /dev/null
+++ b/fs/fdos/subdir.c
@@ -0,0 +1,348 @@
+/*
+ * (C) Copyright 2002
+ * Stäubli Faverges - <www.staubli.com>
+ * Pierre AUBERT p.aubert@staubli.com
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <common.h>
+#include <config.h>
+#include <malloc.h>
+
+#if (CONFIG_COMMANDS & CFG_CMD_FDOS)
+
+#include "dos.h"
+#include "fdos.h"
+
+static int cache_sect;
+static unsigned char cache [SZ_STD_SECTOR];
+
+
+#define min(x,y) ((x)<(y)?(x):(y))
+
+static int descend (Slot_t *parent,
+ Fs_t *fs,
+ char *path);
+
+/*-----------------------------------------------------------------------------
+ * init_subdir --
+ *-----------------------------------------------------------------------------
+ */
+void init_subdir (void)
+{
+ cache_sect = -1;
+}
+/*-----------------------------------------------------------------------------
+ * basename --
+ *-----------------------------------------------------------------------------
+ */
+char *basename (char *name)
+{
+ register char *cptr;
+
+ if (!name || !*name) {
+ return ("");
+ }
+
+ for (cptr= name; *cptr++; );
+ while (--cptr >= name) {
+ if (*cptr == '/') {
+ return (cptr + 1);
+ }
+ }
+ return(name);
+}
+/*-----------------------------------------------------------------------------
+ * root_map --
+ *-----------------------------------------------------------------------------
+ */
+static int root_map (Fs_t *fs, Slot_t *file, int where, int *len)
+{
+ *len = min (*len, fs -> dir_len * SZ_STD_SECTOR - where);
+ if (*len < 0 ) {
+ *len = 0;
+ return (-1);
+ }
+ return fs -> dir_start * SZ_STD_SECTOR + where;
+}
+/*-----------------------------------------------------------------------------
+ * normal_map --
+ *-----------------------------------------------------------------------------
+ */
+static int normal_map (Fs_t *fs, Slot_t *file, int where, int *len)
+{
+ int offset;
+ int NrClu;
+ unsigned short RelCluNr;
+ unsigned short CurCluNr;
+ unsigned short NewCluNr;
+ unsigned short AbsCluNr;
+ int clus_size;
+
+ clus_size = fs -> cluster_size * SZ_STD_SECTOR;
+ offset = where % clus_size;
+
+ *len = min (*len, file -> FileSize - where);
+
+ if (*len < 0 ) {
+ *len = 0;
+ return (0);
+ }
+
+ if (file -> FirstAbsCluNr < 2){
+ *len = 0;
+ return (0);
+ }
+
+ RelCluNr = where / clus_size;
+
+ if (RelCluNr >= file -> PreviousRelCluNr){
+ CurCluNr = file -> PreviousRelCluNr;
+ AbsCluNr = file -> PreviousAbsCluNr;
+ } else {
+ CurCluNr = 0;
+ AbsCluNr = file -> FirstAbsCluNr;
+ }
+
+
+ NrClu = (offset + *len - 1) / clus_size;
+ while (CurCluNr <= RelCluNr + NrClu) {
+ if (CurCluNr == RelCluNr){
+ /* we have reached the beginning of our zone. Save
+ * coordinates */
+ file -> PreviousRelCluNr = RelCluNr;
+ file -> PreviousAbsCluNr = AbsCluNr;
+ }
+ NewCluNr = fat_decode (fs, AbsCluNr);
+ if (NewCluNr == 1 || NewCluNr == 0) {
+ PRINTF("Fat problem while decoding %d %x\n",
+ AbsCluNr, NewCluNr);
+ return (-1);
+ }
+ if (CurCluNr == RelCluNr + NrClu) {
+ break;
+ }
+
+ if (CurCluNr < RelCluNr && NewCluNr == FAT12_END) {
+ *len = 0;
+ return 0;
+ }
+
+ if (CurCluNr >= RelCluNr && NewCluNr != AbsCluNr + 1)
+ break;
+ CurCluNr++;
+ AbsCluNr = NewCluNr;
+ }
+
+ *len = min (*len, (1 + CurCluNr - RelCluNr) * clus_size - offset);
+
+ return (((file -> PreviousAbsCluNr - 2) * fs -> cluster_size +
+ fs -> dir_start + fs -> dir_len) *
+ SZ_STD_SECTOR + offset);
+}
+/*-----------------------------------------------------------------------------
+ * open_subdir -- open the subdir containing the file
+ *-----------------------------------------------------------------------------
+ */
+int open_subdir (File_t *desc)
+{
+ char *pathname;
+ char *tmp, *s, *path;
+ char terminator;
+
+ if ((pathname = (char *)malloc (MAX_PATH)) == NULL) {
+ return (-1);
+ }
+
+ strcpy (pathname, desc -> name);
+
+ /* Suppress file name */
+ tmp = basename (pathname);
+ *tmp = '\0';
+
+ /* root directory init */
+ desc -> subdir.FirstAbsCluNr = 0;
+ desc -> subdir.FileSize = -1;
+ desc -> subdir.map = root_map;
+ desc -> subdir.dir.attr = ATTR_DIRECTORY;
+
+ tmp = pathname;
+ for (s = tmp; ; ++s) {
+ if (*s == '/' || *s == '\0') {
+ path = tmp;
+ terminator = *s;
+ *s = '\0';
+ if (s != tmp && strcmp (path,".")) {
+ if (descend (&desc -> subdir, desc -> fs, path) < 0) {
+ free (pathname);
+ return (-1);
+ }
+ }
+ if (terminator == 0) {
+ break;
+ }
+ tmp = s + 1;
+ }
+ }
+ free (pathname);
+ return (0);
+}
+/*-----------------------------------------------------------------------------
+ * descend --
+ *-----------------------------------------------------------------------------
+ */
+static int descend (Slot_t *parent,
+ Fs_t *fs,
+ char *path)
+{
+ int entry;
+ Slot_t SubDir;
+
+ if(path[0] == '\0' || strcmp (path, ".") == 0) {
+ return (0);
+ }
+
+
+ entry = 0;
+ if (vfat_lookup (parent,
+ fs,
+ &(SubDir.dir),
+ &entry,
+ 0,
+ path,
+ ACCEPT_DIR | SINGLE | DO_OPEN,
+ 0,
+ &SubDir) == 0) {
+ *parent = SubDir;
+ return (0);
+ }
+
+ if (strcmp(path, "..") == 0) {
+ parent -> FileSize = -1;
+ parent -> FirstAbsCluNr = 0;
+ parent -> map = root_map;
+ return (0);
+ }
+ return (-1);
+}
+/*-----------------------------------------------------------------------------
+ * open_file --
+ *-----------------------------------------------------------------------------
+ */
+int open_file (Slot_t *file, Directory_t *dir)
+{
+ int first;
+ unsigned long size;
+
+ first = __le16_to_cpu (dir -> start);
+
+ if(first == 0 &&
+ (dir -> attr & ATTR_DIRECTORY) != 0) {
+ file -> FirstAbsCluNr = 0;
+ file -> FileSize = -1;
+ file -> map = root_map;
+ return (0);
+ }
+
+ if ((dir -> attr & ATTR_DIRECTORY) != 0) {
+ size = (1UL << 31) - 1;
+ }
+ else {
+ size = __le32_to_cpu (dir -> size);
+ }
+
+ file -> map = normal_map;
+ file -> FirstAbsCluNr = first;
+ file -> PreviousRelCluNr = 0xffff;
+ file -> FileSize = size;
+ return (0);
+}
+/*-----------------------------------------------------------------------------
+ * read_file --
+ *-----------------------------------------------------------------------------
+ */
+int read_file (Fs_t *fs,
+ Slot_t *file,
+ char *buf,
+ int where,
+ int len)
+{
+ int pos;
+ int read, nb, sect, offset;
+
+ pos = file -> map (fs, file, where, &len);
+ if (pos < 0) {
+ return -1;
+ }
+ if (len == 0) {
+ return (0);
+ }
+
+ /* Compute sector number */
+ sect = pos / SZ_STD_SECTOR;
+ offset = pos % SZ_STD_SECTOR;
+ read = 0;
+
+ if (offset) {
+ /* Read doesn't start at the sector beginning. We need to use our */
+ /* cache */
+ if (sect != cache_sect) {
+ if (dev_read (cache, sect, 1) < 0) {
+ return (-1);
+ }
+ cache_sect = sect;
+ }
+ nb = min (len, SZ_STD_SECTOR - offset);
+
+ memcpy (buf, cache + offset, nb);
+ read += nb;
+ len -= nb;
+ sect += 1;
+ }
+
+ if (len > SZ_STD_SECTOR) {
+ nb = (len - 1) / SZ_STD_SECTOR;
+ if (dev_read (buf + read, sect, nb) < 0) {
+ return ((read) ? read : -1);
+ }
+ /* update sector position */
+ sect += nb;
+
+ /* Update byte position */
+ nb *= SZ_STD_SECTOR;
+ read += nb;
+ len -= nb;
+ }
+
+ if (len) {
+ if (sect != cache_sect) {
+ if (dev_read (cache, sect, 1) < 0) {
+ return ((read) ? read : -1);
+ cache_sect = -1;
+ }
+ cache_sect = sect;
+ }
+
+ memcpy (buf + read, cache, len);
+ read += len;
+ }
+ return (read);
+}
+#endif
diff --git a/fs/fdos/vfat.c b/fs/fdos/vfat.c
new file mode 100644
index 0000000000..f8287952e1
--- /dev/null
+++ b/fs/fdos/vfat.c
@@ -0,0 +1,357 @@
+/*
+ * (C) Copyright 2002
+ * Stäubli Faverges - <www.staubli.com>
+ * Pierre AUBERT p.aubert@staubli.com
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <common.h>
+#include <config.h>
+
+#if (CONFIG_COMMANDS & CFG_CMD_FDOS)
+#include <linux/ctype.h>
+
+#include "dos.h"
+#include "fdos.h"
+
+static int dir_read (Fs_t *fs,
+ Slot_t *dir,
+ Directory_t *dirent,
+ int num,
+ struct vfat_state *v);
+
+static int unicode_read (char *in, char *out, int num);
+static int match (const char *s, const char *p);
+static unsigned char sum_shortname (char *name);
+static int check_vfat (struct vfat_state *v, Directory_t *dir);
+static char *conv_name (char *name, char *ext, char Case, char *ans);
+
+
+/*-----------------------------------------------------------------------------
+ * clear_vfat --
+ *-----------------------------------------------------------------------------
+ */
+static void clear_vfat (struct vfat_state *v)
+{
+ v -> subentries = 0;
+ v -> status = 0;
+}
+
+/*-----------------------------------------------------------------------------
+ * vfat_lookup --
+ *-----------------------------------------------------------------------------
+ */
+int vfat_lookup (Slot_t *dir,
+ Fs_t *fs,
+ Directory_t *dirent,
+ int *entry,
+ int *vfat_start,
+ char *filename,
+ int flags,
+ char *outname,
+ Slot_t *file)
+{
+ int found;
+ struct vfat_state vfat;
+ char newfile [VSE_NAMELEN];
+ int vfat_present = 0;
+
+ if (*entry == -1) {
+ return -1;
+ }
+
+ found = 0;
+ clear_vfat (&vfat);
+ while (1) {
+ if (dir_read (fs, dir, dirent, *entry, &vfat) < 0) {
+ if (vfat_start) {
+ *vfat_start = *entry;
+ }
+ break;
+ }
+ (*entry)++;
+
+ /* Empty slot */
+ if (dirent -> name[0] == '\0'){
+ if (vfat_start == 0) {
+ break;
+ }
+ continue;
+ }
+
+ if (dirent -> attr == ATTR_VSE) {
+ /* VSE entry, continue */
+ continue;
+ }
+ if ( (dirent -> name [0] == DELMARK) ||
+ ((dirent -> attr & ATTR_DIRECTORY) != 0 &&
+ (flags & ACCEPT_DIR) == 0) ||
+ ((dirent -> attr & ATTR_VOLUME) != 0 &&
+ (flags & ACCEPT_LABEL) == 0) ||
+ (((dirent -> attr & (ATTR_DIRECTORY | ATTR_VOLUME)) == 0) &&
+ (flags & ACCEPT_PLAIN) == 0)) {
+ clear_vfat (&vfat);
+ continue;
+ }
+
+ vfat_present = check_vfat (&vfat, dirent);
+ if (vfat_start) {
+ *vfat_start = *entry - 1;
+ if (vfat_present) {
+ *vfat_start -= vfat.subentries;
+ }
+ }
+
+ if (dirent -> attr & ATTR_VOLUME) {
+ strncpy (newfile, dirent -> name, 8);
+ newfile [8] = '\0';
+ strncat (newfile, dirent -> ext, 3);
+ newfile [11] = '\0';
+ }
+ else {
+ conv_name (dirent -> name, dirent -> ext, dirent -> Case, newfile);
+ }
+
+ if (flags & MATCH_ANY) {
+ found = 1;
+ break;
+ }
+
+ if ((vfat_present && match (vfat.name, filename)) ||
+ (match (newfile, filename))) {
+ found = 1;
+ break;
+ }
+ clear_vfat (&vfat);
+ }
+
+ if (found) {
+ if ((flags & DO_OPEN) && file) {
+ if (open_file (file, dirent) < 0) {
+ return (-1);
+ }
+ }
+ if (outname) {
+ if (vfat_present) {
+ strcpy (outname, vfat.name);
+ }
+ else {
+ strcpy (outname, newfile);
+ }
+ }
+ return (0); /* File found */
+ } else {
+ *entry = -1;
+ return -1; /* File not found */
+ }
+}
+
+/*-----------------------------------------------------------------------------
+ * dir_read -- Read one directory entry
+ *-----------------------------------------------------------------------------
+ */
+static int dir_read (Fs_t *fs,
+ Slot_t *dir,
+ Directory_t *dirent,
+ int num,
+ struct vfat_state *v)
+{
+
+ /* read the directory entry */
+ if (read_file (fs,
+ dir,
+ (char *)dirent,
+ num * MDIR_SIZE,
+ MDIR_SIZE) != MDIR_SIZE) {
+ return (-1);
+ }
+
+ if (v && (dirent -> attr == ATTR_VSE)) {
+ struct vfat_subentry *vse;
+ unsigned char id, last_flag;
+ char *c;
+
+ vse = (struct vfat_subentry *) dirent;
+ id = vse -> id & VSE_MASK;
+ last_flag = (vse -> id & VSE_LAST);
+ if (id > MAX_VFAT_SUBENTRIES) {
+ /* Invalid VSE entry */
+ return (-1);
+ }
+
+
+ /* Decode VSE */
+ if(v -> sum != vse -> sum) {
+ clear_vfat (v);
+ v -> sum = vse -> sum;
+ }
+
+
+ v -> status |= 1 << (id - 1);
+ if (last_flag) {
+ v -> subentries = id;
+ }
+
+ c = &(v -> name [VSE_NAMELEN * (id - 1)]);
+ c += unicode_read (vse->text1, c, VSE1SIZE);
+ c += unicode_read (vse->text2, c, VSE2SIZE);
+ c += unicode_read (vse->text3, c, VSE3SIZE);
+
+ if (last_flag) {
+ *c = '\0'; /* Null terminate long name */
+ }
+
+ }
+ return (0);
+}
+
+/*-----------------------------------------------------------------------------
+ * unicode_read --
+ *-----------------------------------------------------------------------------
+ */
+static int unicode_read (char *in, char *out, int num)
+{
+ int j;
+
+ for (j = 0; j < num; ++j) {
+ if (in [1])
+ *out = '_';
+ else
+ *out = in [0];
+ out ++;
+ in += 2;
+ }
+ return num;
+}
+
+/*-----------------------------------------------------------------------------
+ * match --
+ *-----------------------------------------------------------------------------
+ */
+static int match (const char *s, const char *p)
+{
+
+ for (; *p != '\0'; ) {
+ if (toupper (*s) != toupper (*p)) {
+ return (0);
+ }
+ p++;
+ s++;
+ }
+
+ if (*s != '\0') {
+ return (0);
+ }
+ else {
+ return (1);
+ }
+}
+/*-----------------------------------------------------------------------------
+ * sum_shortname --
+ *-----------------------------------------------------------------------------
+ */
+static unsigned char sum_shortname (char *name)
+{
+ unsigned char sum;
+ int j;
+
+ for (j = sum = 0; j < 11; ++j) {
+ sum = ((sum & 1) ? 0x80 : 0) + (sum >> 1) +
+ (name [j] ? name [j] : ' ');
+ }
+ return (sum);
+}
+/*-----------------------------------------------------------------------------
+ * check_vfat --
+ * Return 1 if long name is valid, 0 else
+ *-----------------------------------------------------------------------------
+ */
+static int check_vfat (struct vfat_state *v, Directory_t *dir)
+{
+ char name[12];
+
+ if (v -> subentries == 0) {
+ return 0;
+ }
+
+ strncpy (name, dir -> name, 8);
+ strncpy (name + 8, dir -> ext, 3);
+ name [11] = '\0';
+
+ if (v -> sum != sum_shortname (name)) {
+ return 0;
+ }
+
+ if( (v -> status & ((1 << v -> subentries) - 1)) !=
+ (1 << v -> subentries) - 1) {
+ return 0;
+ }
+ v->name [VSE_NAMELEN * v -> subentries] = 0;
+
+ return 1;
+}
+/*-----------------------------------------------------------------------------
+ * conv_name --
+ *-----------------------------------------------------------------------------
+ */
+static char *conv_name (char *name, char *ext, char Case, char *ans)
+{
+ char tname [9], text [4];
+ int i;
+
+ i = 0;
+ while (i < 8 && name [i] != ' ' && name [i] != '\0') {
+ tname [i] = name [i];
+ i++;
+ }
+ tname [i] = '\0';
+
+ if (Case & BASECASE) {
+ for (i = 0; i < 8 && tname [i]; i++) {
+ tname [i] = tolower (tname [i]);
+ }
+ }
+
+ i = 0;
+ while (i < 3 && ext [i] != ' ' && ext [i] != '\0') {
+ text [i] = ext [i];
+ i++;
+ }
+ text [i] = '\0';
+
+ if (Case & EXTCASE){
+ for (i = 0; i < 3 && text [i]; i++) {
+ text [i] = tolower (text [i]);
+ }
+ }
+
+ if (*text) {
+ strcpy (ans, tname);
+ strcat (ans, ".");
+ strcat (ans, text);
+ }
+ else {
+ strcpy(ans, tname);
+ }
+ return (ans);
+}
+
+
+#endif