| /* |
| * (C) Copyright 2002 |
| * Stäubli Faverges - <www.staubli.com> |
| * Pierre AUBERT p.aubert@staubli.com |
| * |
| * SPDX-License-Identifier: GPL-2.0+ |
| */ |
| |
| #include <common.h> |
| #include <config.h> |
| #include <malloc.h> |
| |
| #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); |
| } |