mirror of
https://github.com/AsahiLinux/u-boot
synced 2024-12-26 13:03:40 +00:00
dd60d1223b
Signed-off-by: Jon Loeliger <jdl@freescale.com>
348 lines
8.2 KiB
C
348 lines
8.2 KiB
C
/*
|
|
* (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 defined(CONFIG_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
|