]> git.ipfire.org Git - people/ms/u-boot.git/blame - fs/fat/fat.c
* Patch by Markus Pietrek, 24 Feb 2004:
[people/ms/u-boot.git] / fs / fat / fat.c
CommitLineData
71f95118
WD
1/*
2 * fat.c
3 *
4 * R/O (V)FAT 12/16/32 filesystem implementation by Marcus Sundberg
5 *
6 * 2002-07-28 - rjones@nexus-tech.net - ported to ppcboot v1.1.6
7 * 2003-03-10 - kharris@nexus-tech.net - ported to uboot
8 *
9 * See file CREDITS for list of people who contributed to this
10 * project.
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License as
14 * published by the Free Software Foundation; either version 2 of
15 * the License, or (at your option) any later version.
16 *
17 * This program is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU General Public License for more details.
21 *
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, write to the Free Software
24 * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
25 * MA 02111-1307 USA
26 */
27
28#include <common.h>
29#include <config.h>
30#include <fat.h>
31#include <asm/byteorder.h>
7205e407 32#include <part.h>
71f95118
WD
33
34#if (CONFIG_COMMANDS & CFG_CMD_FAT)
35
36/*
37 * Convert a string to lowercase.
38 */
39static void
40downcase(char *str)
41{
42 while (*str != '\0') {
43 TOLOWER(*str);
44 str++;
45 }
46}
47
7205e407
WD
48static block_dev_desc_t *cur_dev = NULL;
49static unsigned long part_offset = 0;
50static int cur_part = 1;
51
52#define DOS_PART_TBL_OFFSET 0x1be
53#define DOS_PART_MAGIC_OFFSET 0x1fe
54#define DOS_FS_TYPE_OFFSET 0x36
71f95118
WD
55
56int disk_read (__u32 startblock, __u32 getsize, __u8 * bufptr)
57{
7205e407
WD
58 startblock += part_offset;
59 if (cur_dev == NULL)
60 return -1;
61 if (cur_dev->block_read) {
62 return cur_dev->block_read (cur_dev->dev, startblock, getsize, (unsigned long *)bufptr);
71f95118
WD
63 }
64 return -1;
65}
66
67
68int
7205e407 69fat_register_device(block_dev_desc_t *dev_desc, int part_no)
71f95118 70{
7205e407
WD
71 unsigned char buffer[SECTOR_SIZE];
72
73 if (!dev_desc->block_read)
74 return -1;
75 cur_dev=dev_desc;
76 /* check if we have a MBR (on floppies we have only a PBR) */
77 if (dev_desc->block_read (dev_desc->dev, 0, 1, (ulong *) buffer) != 1) {
78 printf ("** Can't read from device %d **\n", dev_desc->dev);
79 return -1;
80 }
81 if (buffer[DOS_PART_MAGIC_OFFSET] != 0x55 ||
82 buffer[DOS_PART_MAGIC_OFFSET + 1] != 0xaa) {
83 /* no signature found */
84 return -1;
85 }
86 if(!strncmp(&buffer[DOS_FS_TYPE_OFFSET],"FAT",3)) {
87 /* ok, we assume we are on a PBR only */
88 cur_part = 1;
89 part_offset=0;
90 }
91 else {
80885a9d
WD
92#if (CONFIG_COMMANDS & CFG_CMD_IDE) || (CONFIG_COMMANDS & CFG_CMD_SCSI) || \
93 (CONFIG_COMMANDS & CFG_CMD_USB)
7205e407
WD
94 disk_partition_t info;
95 if(!get_partition_info(dev_desc, part_no, &info)) {
96 part_offset = info.start;
97 cur_part = part_no;
98 }
99 else {
100 printf ("** Partition %d not valid on device %d **\n",part_no,dev_desc->dev);
101 return -1;
102 }
103#else
104 /* FIXME we need to determine the start block of the
105 * partition where the DOS FS resides. This can be done
106 * by using the get_partition_info routine. For this
107 * purpose the libpart must be included.
108 */
109 part_offset=32;
110 cur_part = 1;
111#endif
112 }
71f95118
WD
113 return 0;
114}
115
116
117/*
118 * Get the first occurence of a directory delimiter ('/' or '\') in a string.
119 * Return index into string if found, -1 otherwise.
120 */
121static int
122dirdelim(char *str)
123{
124 char *start = str;
125
126 while (*str != '\0') {
127 if (ISDIRDELIM(*str)) return str - start;
128 str++;
129 }
130 return -1;
131}
132
133
134/*
135 * Match volume_info fs_type strings.
136 * Return 0 on match, -1 otherwise.
137 */
138static int
139compare_sign(char *str1, char *str2)
140{
141 char *end = str1+SIGNLEN;
142
143 while (str1 != end) {
144 if (*str1 != *str2) {
145 return -1;
146 }
147 str1++;
148 str2++;
149 }
150
151 return 0;
152}
153
154
155/*
156 * Extract zero terminated short name from a directory entry.
157 */
158static void get_name (dir_entry *dirent, char *s_name)
159{
160 char *ptr;
161
162 memcpy (s_name, dirent->name, 8);
163 s_name[8] = '\0';
164 ptr = s_name;
165 while (*ptr && *ptr != ' ')
166 ptr++;
167 if (dirent->ext[0] && dirent->ext[0] != ' ') {
168 *ptr = '.';
169 ptr++;
170 memcpy (ptr, dirent->ext, 3);
171 ptr[3] = '\0';
172 while (*ptr && *ptr != ' ')
173 ptr++;
174 }
175 *ptr = '\0';
176 if (*s_name == DELETED_FLAG)
177 *s_name = '\0';
178 else if (*s_name == aRING)
179