Blame | Last modification | View Log | RSS feed
////// Copyright 2010 TheSeven////// This file is part of emBIOS.//// emBIOS 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.//// emBIOS 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 emBIOS. If not, see <http://www.gnu.org/licenses/>.////#include "global.h"#include "storage.h"#include "fat32.h"#include "util.h"uint32_t fat32_ok;uint32_t fat32_startsector;uint32_t fat32_secperclus;uint32_t fat32_database;uint32_t fat32_fatbase;uint32_t fat32_fatsize;uint32_t fat32_fatcount;uint32_t fat32_sectorcount;uint32_t fat32_clustercount;uint32_t fat32_rootdirclus;uint32_t fat32_buf1[0x200] __attribute__((aligned(16)));uint32_t fat32_buf2[0x200] __attribute__((aligned(16)));uint32_t fat32_get_root(){return fat32_rootdirclus;}uint32_t fat32_get_clusterchain(uint32_t clusterchain, uint32_t maxsize, void* buffer){uint32_t i;for (i = 0; i < (maxsize >> 11); ){uint32_t sector = (clusterchain - 2) * fat32_secperclus + fat32_database;uint32_t count = fat32_secperclus;if (count + i > (maxsize >> 11)) count = (maxsize >> 11) - i;uint32_t fatsector = fat32_fatbase + (clusterchain >> 9);if (storage_read(fatsector, 1, &((uint32_t*)buffer)[i << 9])) return 1;clusterchain = ((uint32_t*)buffer)[(i << 9) + (clusterchain & 0x1FF)];if (storage_read(sector, count, &((uint32_t*)buffer)[i << 9])) return 1;i += count;if (clusterchain >= 0x0ffffff0) return 0;}return clusterchain;}uint32_t fat32_get_direntry(uint32_t clusterchain, const char* filename, uint32_t* filesize){uint32_t i, j;while (clusterchain > 1 && clusterchain < 0x0ffffff0){uint32_t sector = (clusterchain - 2) * fat32_secperclus + fat32_database;for (j = 0; j < fat32_secperclus; j++){if (storage_read(sector + j, 1, fat32_buf1)) return 1;for (i = 0; i < 0x200; i += 8)if (((uint8_t*)fat32_buf1)[i << 2] == 0) return 0;else if (((uint8_t*)fat32_buf1)[i << 2] == 0xe5) continue;else if (memcmp(&fat32_buf1[i], filename, 11) == 0){*filesize = fat32_buf1[i + 7];return (((uint16_t*)fat32_buf1)[(i << 1) + 0xA] << 16)| ((uint16_t*)fat32_buf1)[(i << 1) + 0xD];}}uint32_t fatsector = fat32_fatbase + (clusterchain >> 9);if (storage_read(fatsector, 1, fat32_buf1)) return 1;clusterchain = fat32_buf1[(i << 9) + (clusterchain & 0x1FF)];}return 0;}uint32_t fat32_delete_clusterchain(uint32_t clusterchain){while (1){uint32_t fatsector = fat32_fatbase + (clusterchain >> 9);if (storage_read(fatsector, 1, fat32_buf1)) return 1;clusterchain = fat32_buf1[clusterchain & 0x1FF];fat32_buf1[(clusterchain & 0x1FF)] = 0;if (storage_write(fatsector, 1, fat32_buf1)) return 1;if (clusterchain >= 0x0ffffff0) return 0;}}uint32_t fat32_delete_direntry(uint32_t clusterchain, const char* filename){uint32_t i, j;while (clusterchain > 1 && clusterchain < 0x0ffffff0){uint32_t sector = (clusterchain - 2) * fat32_secperclus + fat32_database;for (j = 0; j < fat32_secperclus; j++){if (storage_read(sector + j, 1, fat32_buf1)) return 1;for (i = 0; i < 0x200; i += 8)if (((uint8_t*)fat32_buf1)[i << 2] == 0) return 0;else if (((uint8_t*)fat32_buf1)[i << 2] == 0xe5) continue;else if (memcmp(&fat32_buf1[i], filename, 11) == 0){((uint8_t*)fat32_buf1)[i << 2] = 0xe5;if (storage_write(sector + j, 1, fat32_buf1)) return 1;return 0;}}uint32_t fatsector = fat32_fatbase + (clusterchain >> 9);if (storage_read(fatsector, 1, fat32_buf1)) return 1;clusterchain = fat32_buf1[(i << 9) + (clusterchain & 0x1FF)];}return 0;}uint32_t fat32_store_stream(void* buffer, uint32_t size){uint32_t i;uint32_t clusterchain = 0;uint32_t scanidx = 2;uint32_t scansect = 0xffffffff;uint32_t lastidx;uint32_t lastsect = 0xffffffff;uint32_t dirty = 0;while (size){while (scanidx < fat32_clustercount + 2){if ((scanidx >> 9) != scansect){scansect = scanidx >> 9;if (storage_read(fat32_fatbase + scansect, 1, fat32_buf1)) return 0;}if (!fat32_buf1[scanidx & 0x1ff]) break;scanidx++;}if (scanidx >= fat32_clustercount + 2) return 0;if (!clusterchain) clusterchain = scanidx;else{fat32_buf2[lastidx & 0x1ff] = scanidx;dirty = 1;}lastidx = scanidx;if ((lastidx >> 9) != lastsect){if (dirty)if (storage_write(fat32_fatbase + lastsect, 1, fat32_buf2)) return 0;dirty = 0;lastsect = lastidx >> 9;memcpy(fat32_buf2, fat32_buf1, 0x800);}uint32_t sector = (scanidx - 2) * fat32_secperclus + fat32_database;uint32_t count = (size + 0x7ff) >> 11;if (count > fat32_secperclus) count = fat32_secperclus;if (storage_write(sector, count, &((uint32_t*)buffer)[i << 9])) return 0;if ((count << 11) >= size){fat32_buf2[lastidx & 0x1ff] = 0x0fffffff;if (storage_write(fat32_fatbase + lastsect, 1, fat32_buf2)) return 0;break;}size -= count << 11;buffer = (void*)((uint32_t)buffer + (count << 11));scanidx++;}return clusterchain;}void fat32_set_direntry(uint32_t* ptr, const char* filename, uint32_t filechain,uint32_t filesize, uint32_t flags){memcpy(ptr, filename, 11);((uint16_t*)ptr)[0xa] = filechain >> 16;((uint8_t*)ptr)[0xb] = flags;((uint16_t*)ptr)[0xa] = filechain >> 16;((uint16_t*)ptr)[0xd] = filechain & 0xffff;ptr[7] = filesize;}uint32_t fat32_store_direntry(uint32_t dirchain, const char* filename,uint32_t filechain, uint32_t filesize, uint32_t flags){uint32_t i, j;uint32_t lastidx;while (dirchain > 1 && dirchain < 0x0ffffff0){uint32_t sector = (dirchain - 2) * fat32_secperclus + fat32_database;for (j = 0; j < fat32_secperclus; j++){if (storage_read(sector + j, 1, fat32_buf1)) return 1;for (i = 0; i < 0x200; i += 8)if (((uint8_t*)fat32_buf1)[i << 2] == 0|| ((uint8_t*)fat32_buf1)[i << 2] == 0xe5){fat32_set_direntry(&fat32_buf1[i], filename, filechain, filesize, flags);if (storage_write(sector + j, 1, fat32_buf1)) return 1;return 0;}}uint32_t fatsector = fat32_fatbase + (dirchain >> 9);if (storage_read(fatsector, 1, fat32_buf1)) return 1;lastidx = dirchain;dirchain = fat32_buf1[(i << 9) + (dirchain & 0x1FF)];}uint32_t scanidx = 2;uint32_t scansect = 0xffffffff;while (scanidx < fat32_clustercount + 2){if ((scanidx >> 9) != scansect){scansect = scanidx >> 9;if (storage_read(fat32_fatbase + scansect, 1, fat32_buf1)) return 1;}if (!fat32_buf1[scanidx & 0x1ff]) break;scanidx++;}if (scanidx >= fat32_clustercount + 2) return 1;fat32_buf1[scanidx & 0x1ff] = 0x0fffffff;if (storage_write(fat32_fatbase + scansect, 1, fat32_buf1)) return 1;if (storage_read(fat32_fatbase + (lastidx >> 9), 1, fat32_buf1)) return 1;fat32_buf1[lastidx & 0x1ff] = scanidx;if (storage_write(fat32_fatbase + scansect, 1, fat32_buf1)) return 1;uint32_t sector = (scanidx - 2) * fat32_secperclus + fat32_database;for (i = 0; i < fat32_secperclus; i++){memset(fat32_buf1, 0, 0x800);if (!i) fat32_set_direntry(fat32_buf1, filename, filechain, filesize, flags);if (storage_write(sector + i, 1, fat32_buf1)) return 1;}return 0;}uint32_t fat32_create_dir(uint32_t parent, const char* dirname){uint32_t i;uint32_t scanidx = 2;uint32_t scansect = 0xffffffff;while (scanidx < fat32_clustercount + 2){if ((scanidx >> 9) != scansect){scansect = scanidx >> 9;if (storage_read(fat32_fatbase + scansect, 1, fat32_buf1)) return 0;}if (!fat32_buf1[scanidx & 0x1ff]) break;scanidx++;}if (scanidx >= fat32_clustercount + 2) return 0;fat32_buf1[scanidx & 0x1ff] = 0x0fffffff;if (storage_write(fat32_fatbase + scansect, 1, fat32_buf1)) return 0;fat32_store_direntry(parent, dirname, scanidx, 0, 0x10);uint32_t sector = (scanidx - 2) * fat32_secperclus + fat32_database;for (i = 0; i < fat32_secperclus; i++){memset(fat32_buf1, 0, 0x800);if (!i){fat32_set_direntry(fat32_buf1, ". ", scanidx, 0, 0x10);if (parent == fat32_rootdirclus) parent = 0;fat32_set_direntry(&fat32_buf1[8], ".. ", parent, 0, 0x10);}if (storage_write(sector + i, 1, fat32_buf1)) return 0;}return scanidx;}uint32_t fat32_read_file(const char* filename, uint32_t maxsize, void* buffer, uint32_t* filesize){}uint32_t fat32_get_partition_start(){return fat32_startsector;}uint32_t fat32_init(){uint32_t i;fat32_ok = 0;fat32_startsector = 0xFFFFFFFF;if (storage_init()) return 1;if (storage_read(0, 1, fat32_buf1)) return 1;if (*((uint16_t*)((uint32_t)fat32_buf1 + 0x1FE)) != 0xAA55){return 1;}for (i = 0x1C2; i < 0x200; i += 0x10)if (((uint8_t*)fat32_buf1)[i] == 0xB){fat32_startsector = *((uint16_t*)((uint32_t)fat32_buf1 + i + 4))| (*((uint16_t*)((uint32_t)fat32_buf1 + i + 6)) << 16);break;}if (fat32_startsector == 0xFFFFFFFF&& *((uint16_t*)((uint32_t)fat32_buf1 + 0x52)) == 0x4146&& *((uint8_t*)((uint32_t)fat32_buf1 + 0x54)) == 0x54)fat32_startsector = 0;if (fat32_startsector == 0xFFFFFFFF) return 1;if (storage_read(fat32_startsector, 1, fat32_buf1)) return 1;if (*((uint16_t*)((uint32_t)fat32_buf1 + 0x1FE)) != 0xAA55) return 1;if (((uint8_t*)fat32_buf1)[0xB] != 0 || ((uint8_t*)fat32_buf1)[0xC] != 8) return 1;fat32_secperclus = ((uint8_t*)fat32_buf1)[0xD];uint32_t reserved = ((uint16_t*)fat32_buf1)[0x7];fat32_fatcount = ((uint8_t*)fat32_buf1)[0x10];if (((uint8_t*)fat32_buf1)[0x11] != 0) return 1;fat32_sectorcount = fat32_buf1[8];fat32_fatsize = fat32_buf1[9];if (((uint16_t*)fat32_buf1)[0x15] != 0) return 1;fat32_rootdirclus = fat32_buf1[0xB];fat32_clustercount = (fat32_sectorcount - reserved- fat32_fatcount * fat32_fatsize) / fat32_secperclus;fat32_fatbase = fat32_startsector + reserved;fat32_database = fat32_fatbase + fat32_fatcount * fat32_fatsize;fat32_ok = 1;return 0;}