diff options
Diffstat (limited to 'fat.c')
-rw-r--r-- | fat.c | 997 |
1 files changed, 997 insertions, 0 deletions
@@ -0,0 +1,997 @@ +/* Copyright 1996-2006,2008,2009 Alain Knaff. + * This file is part of mtools. + * + * Mtools 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 3 of the License, or + * (at your option) any later version. + * + * Mtools 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 Mtools. If not, see <http://www.gnu.org/licenses/>. + */ + +#include "sysincludes.h" +#include "msdos.h" +#include "stream.h" +#include "mtools.h" +#include "fsP.h" +#include "file_name.h" + +#ifdef HAVE_LONG_LONG +typedef long long fatBitMask; +#else +typedef long fatBitMask; +#endif + +typedef struct FatMap_t { + unsigned char *data; + fatBitMask dirty; + fatBitMask valid; +} FatMap_t; + +#define SECT_PER_ENTRY (sizeof(fatBitMask)*8) +#define ONE ((fatBitMask) 1) + +static __inline__ int readSector(Fs_t *This, char *buf, unsigned int off, + size_t size) +{ + return READS(This->Next, buf, sectorsToBytes((Stream_t *)This, off), + size << This->sectorShift); +} + + +static __inline__ int forceReadSector(Fs_t *This, char *buf, unsigned int off, + size_t size) +{ + return force_read(This->Next, buf, sectorsToBytes((Stream_t *)This, off), + size << This->sectorShift); +} + + +static __inline__ int writeSector(Fs_t *This, char *buf, unsigned int off, + size_t size) +{ + return WRITES(This->Next, buf, sectorsToBytes((Stream_t*)This, off), + size << This->sectorShift); +} + +static __inline__ int forceWriteSector(Fs_t *This, char *buf, unsigned int off, + size_t size) +{ + return force_write(This->Next, buf, sectorsToBytes((Stream_t*)This, off), + size << This->sectorShift); +} + + +static FatMap_t *GetFatMap(Fs_t *Stream) +{ + int nr_entries,i; + FatMap_t *map; + + Stream->fat_error = 0; + nr_entries = (Stream->fat_len + SECT_PER_ENTRY - 1) / SECT_PER_ENTRY; + map = NewArray(nr_entries, FatMap_t); + if(!map) + return 0; + + for(i=0; i< nr_entries; i++) { + map[i].data = 0; + map[i].valid = 0; + map[i].dirty = 0; + } + + return map; +} + +static __inline__ int locate(Fs_t *Stream, size_t offset, int *slot, int *bit) +{ + if(offset >= Stream->fat_len) + return -1; + *slot = offset / SECT_PER_ENTRY; + *bit = offset % SECT_PER_ENTRY; + return 0; +} + +static __inline__ int fatReadSector(Fs_t *This, int sector, int slot, + int bit, int dupe, fatBitMask bitmap) +{ + int fat_start, ret; + int nr_sectors; + + dupe = (dupe + This->primaryFat) % This->num_fat; + fat_start = This->fat_start + This->fat_len * dupe; + + if(bitmap == 0) { + nr_sectors = SECT_PER_ENTRY - bit%SECT_PER_ENTRY; + } else { + nr_sectors = 1; + } + + /* first, read as much as the buffer can give us */ + ret = readSector(This, + (char *)(This->FatMap[slot].data+(bit<<This->sectorShift)), + fat_start+sector, + nr_sectors); + if(ret < 0) + return 0; + + if((unsigned int) ret < This->sector_size) { + /* if we got less than one sector's worth, insist to get at + * least one sector */ + ret = forceReadSector(This, + (char *) (This->FatMap[slot].data + + (bit << This->sectorShift)), + fat_start+sector, 1); + if(ret < (int) This->sector_size) + return 0; + return 1; + } + + return ret >> This->sectorShift; +} + + +static int fatWriteSector(Fs_t *This, int sector, int slot, int bit, int dupe) +{ + int fat_start; + + dupe = (dupe + This->primaryFat) % This->num_fat; + if(dupe && !This->writeAllFats) + return This->sector_size; + + fat_start = This->fat_start + This->fat_len * dupe; + + return forceWriteSector(This, + (char *) + (This->FatMap[slot].data + bit * This->sector_size), + fat_start+sector, 1); +} + +static unsigned char *loadSector(Fs_t *This, + unsigned int sector, fatAccessMode_t mode, + int recurs) +{ + int slot, bit, ret; + + if(locate(This,sector, &slot, &bit) < 0) + return 0; +#if 0 + if (((This->fat_len + SECT_PER_ENTRY - 1) / SECT_PER_ENTRY) <= slot) { + fprintf(stderr,"This should not happen\n"); + fprintf(stderr, "fat_len = %d\n", This->fat_len); + fprintf(stderr, "SECT_PER_ENTRY=%d\n", (int)SECT_PER_ENTRY); + fprintf(stderr, "sector = %d slot = %d bit=%d\n", + sector, slot, bit); + fprintf(stderr, "left = %d",(int) + ((This->fat_len+SECT_PER_ENTRY-1) / SECT_PER_ENTRY)); + return 0; + } +#endif + if(!This->FatMap[slot].data) { + /* allocate the storage space */ + This->FatMap[slot].data = + malloc(This->sector_size * SECT_PER_ENTRY); + if(!This->FatMap[slot].data) + return 0; + memset(This->FatMap[slot].data, 0xee, + This->sector_size * SECT_PER_ENTRY); + } + + if(! (This->FatMap[slot].valid & (ONE << bit))) { + unsigned int i; + ret = -1; + for(i=0; i< This->num_fat; i++) { + /* read the sector */ + ret = fatReadSector(This, sector, slot, bit, i, + This->FatMap[slot].valid); + + if(ret == 0) { + fprintf(stderr, + "Error reading fat number %d\n", i); + continue; + } + if(This->FatMap[slot].valid) + /* Set recurs if there have already been + * sectors loaded in this bitmap long + */ + recurs = 1; + break; + } + + /* all copies bad. Return error */ + if(ret == 0) + return 0; + + for(i=0; (int) i < ret; i++) + This->FatMap[slot].valid |= ONE << (bit + i); + + if(!recurs && ret == 1) + /* do some prefetching, if we happened to only + * get one sector */ + loadSector(This, sector+1, mode, 1); + if(!recurs && batchmode) + for(i=0; i < 1024; i++) + loadSector(This, sector+i, mode, 1); + } + + if(mode == FAT_ACCESS_WRITE) { + This->FatMap[slot].dirty |= ONE << bit; + This->fat_dirty = 1; + } + return This->FatMap[slot].data + (bit << This->sectorShift); +} + + +static unsigned char *getAddress(Fs_t *Stream, + unsigned int num, fatAccessMode_t mode) +{ + unsigned char *ret; + int sector; + int offset; + + sector = num >> Stream->sectorShift; + ret = 0; + if(sector == Stream->lastFatSectorNr && + Stream->lastFatAccessMode >= mode) + ret = Stream->lastFatSectorData; + if(!ret) { + ret = loadSector(Stream, sector, mode, 0); + if(!ret) + return 0; + Stream->lastFatSectorNr = sector; + Stream->lastFatSectorData = ret; + Stream->lastFatAccessMode = mode; + } + offset = num & Stream->sectorMask; + return ret+offset; +} + + +static int readByte(Fs_t *Stream, int start) +{ + unsigned char *address; + + address = getAddress(Stream, start, FAT_ACCESS_READ); + if(!address) + return -1; + return *address; +} + + +/* + * Fat 12 encoding: + * | byte n | byte n+1 | byte n+2 | + * |7|6|5|4|3|2|1|0|7|6|5|4|3|2|1|0|7|6|5|4|3|2|1|0| + * | | | | | | | | | | | | | | | | | | | | | | | | | + * | n+0.0 | n+0.5 | n+1.0 | n+1.5 | n+2.0 | n+2.5 | + * \_____ \____ \______/________/_____ / + * ____\______\________/ _____/ ____\_/ + * / \ \ / / \ + * | n+1.5 | n+0.0 | n+0.5 | n+2.0 | n+2.5 | n+1.0 | + * | FAT entry k | FAT entry k+1 | + */ + + /* + * Get and decode a FAT (file allocation table) entry. Returns the cluster + * number on success or 1 on failure. + */ + +static unsigned int fat12_decode(Fs_t *Stream, unsigned int num) +{ + unsigned int start = num * 3 / 2; + int byte0 = readByte(Stream, start); + int byte1 = readByte(Stream, start+1); + + if (num < 2 || byte0 < 0 || byte1 < 0 || num > Stream->num_clus+1) { + fprintf(stderr,"[1] Bad address %d\n", num); + return 1; + } + + if (num & 1) + return (byte1 << 4) | ((byte0 & 0xf0)>>4); + else + return ((byte1 & 0xf) << 8) | byte0; +} + + +/* + * Puts a code into the FAT table. Is the opposite of fat_decode(). No + * sanity checking is done on the code. Returns a 1 on error. + */ +static void fat12_encode(Fs_t *Stream, unsigned int num, unsigned int code) +{ + int start = num * 3 / 2; + unsigned char *address0 = getAddress(Stream, start, FAT_ACCESS_WRITE); + unsigned char *address1 = getAddress(Stream, start+1, FAT_ACCESS_WRITE); + + if (num & 1) { + /* (odd) not on byte boundary */ + *address0 = (*address0 & 0x0f) | ((code << 4) & 0xf0); + *address1 = (code >> 4) & 0xff; + } else { + /* (even) on byte boundary */ + *address0 = code & 0xff; + *address1 = (*address1 & 0xf0) | ((code >> 8) & 0x0f); + } +} + + +/* + * Fat 16 encoding: + * | byte n | byte n+1 | + * |7|6|5|4|3|2|1|0|7|6|5|4|3|2|1|0| + * | | | | | | | | | | | | | | | | | + * | FAT entry k | + */ + +static unsigned int fat16_decode(Fs_t *Stream, unsigned int num) +{ + unsigned char *address = getAddress(Stream, num << 1, FAT_ACCESS_READ); + if(!address) + return 1; + return _WORD(address); +} + +static void fat16_encode(Fs_t *Stream, unsigned int num, unsigned int code) +{ + unsigned char *address = getAddress(Stream, num << 1, FAT_ACCESS_WRITE); + set_word(address, code); +} + + +static unsigned int fast_fat16_decode(Fs_t *Stream, unsigned int num) +{ + unsigned short *address = + (unsigned short *) getAddress(Stream, num << 1, + FAT_ACCESS_READ); + if(!address) + return 1; + return *address; +} + +static void fast_fat16_encode(Fs_t *Stream, unsigned int num, unsigned int code) +{ + unsigned short *address = + (unsigned short *) getAddress(Stream, num << 1, + FAT_ACCESS_WRITE); + *address = code; +} + + + + +/* + * Fat 32 encoding + */ +#define FAT32_HIGH 0xf0000000 +#define FAT32_ADDR 0x0fffffff + +static unsigned int fat32_decode(Fs_t *Stream, unsigned int num) +{ + unsigned char *address = getAddress(Stream, num << 2, FAT_ACCESS_READ); + if(!address) + return 1; + return _DWORD(address) & FAT32_ADDR; +} + +static void fat32_encode(Fs_t *Stream, unsigned int num, unsigned int code) +{ + unsigned char *address = getAddress(Stream, num << 2, FAT_ACCESS_WRITE); + set_dword(address,(code&FAT32_ADDR) | (_DWORD(address)&FAT32_HIGH)); +} + + +static unsigned int fast_fat32_decode(Fs_t *Stream, unsigned int num) +{ + unsigned int *address = + (unsigned int *) getAddress(Stream, num << 2, + FAT_ACCESS_READ); + if(!address) + return 1; + return (*address) & FAT32_ADDR; +} + +static void fast_fat32_encode(Fs_t *Stream, unsigned int num, unsigned int code) +{ + unsigned int *address = + (unsigned int *) getAddress(Stream, num << 2, + FAT_ACCESS_WRITE); + *address = (*address & FAT32_HIGH) | (code & FAT32_ADDR); +} + + +/* + * Write the FAT table to the disk. Up to now the FAT manipulation has + * been done in memory. All errors are fatal. (Might not be too smart + * to wait till the end of the program to write the table. Oh well...) + */ + +void fat_write(Fs_t *This) +{ + unsigned int i, j, dups, bit, slot; + int ret; + + /*fprintf(stderr, "Fat write\n");*/ + + if (!This->fat_dirty) + return; + + dups = This->num_fat; + if (This->fat_error) + dups = 1; + + + for(i=0; i<dups; i++){ + j = 0; + for(slot=0;j<This->fat_len;slot++) { + if(!This->FatMap[slot].dirty) { + j += SECT_PER_ENTRY; + continue; + } + for(bit=0; + bit < SECT_PER_ENTRY && j<This->fat_len; + bit++,j++) { + if(!(This->FatMap[slot].dirty & (ONE << bit))) + continue; + ret = fatWriteSector(This,j,slot, bit, i); + if (ret < (int) This->sector_size){ + if (ret < 0 ){ + perror("error in fat_write"); + exit(1); + } else { + fprintf(stderr, + "end of file in fat_write\n"); + exit(1); + } + } + /* if last dupe, zero it out */ + if(i==dups-1) + This->FatMap[slot].dirty &= ~(ONE<<bit); + } + } + } + /* write the info sector, if any */ + if(This->infoSectorLoc && This->infoSectorLoc != MAX32) { + /* initialize info sector */ + InfoSector_t *infoSector; + infoSector = (InfoSector_t *) safe_malloc(This->sector_size); + set_dword(infoSector->signature1, INFOSECT_SIGNATURE1); + memset(infoSector->filler1, 0, sizeof(infoSector->filler1)); + memset(infoSector->filler2, 0, sizeof(infoSector->filler2)); + set_dword(infoSector->signature2, INFOSECT_SIGNATURE2); + set_dword(infoSector->pos, This->last); + set_dword(infoSector->count, This->freeSpace); + set_word(infoSector->signature3, 0xaa55); + if(forceWriteSector(This, (char *)infoSector, This->infoSectorLoc, 1) != + (signed int) This->sector_size) + fprintf(stderr,"Trouble writing the info sector\n"); + free(infoSector); + } + This->fat_dirty = 0; + This->lastFatAccessMode = FAT_ACCESS_READ; +} + + + +/* + * Zero-Fat + * Used by mformat. + */ +int zero_fat(Fs_t *Stream, int media_descriptor) +{ + unsigned int i, j; + unsigned int fat_start; + unsigned char *buf; + + buf = malloc(Stream->sector_size); + if(!buf) { + perror("alloc fat sector buffer"); + return -1; + } + for(i=0; i< Stream->num_fat; i++) { + fat_start = Stream->fat_start + i*Stream->fat_len; + for(j = 0; j < Stream->fat_len; j++) { + if(j <= 1) + memset(buf, 0, Stream->sector_size); + if(!j) { + buf[0] = media_descriptor; + buf[2] = buf[1] = 0xff; + if(Stream->fat_bits > 12) + buf[3] = 0xff; + if(Stream->fat_bits > 16) { + buf[4] = 0xff; + buf[5] = 0xff; + buf[6] = 0xff; + buf[7] = 0x0f; + } + } + + if(forceWriteSector(Stream, (char *)buf, + fat_start + j, 1) != + (signed int) Stream->sector_size) { + fprintf(stderr, + "Trouble initializing a FAT sector\n"); + free(buf); + return -1; + } + } + } + + free(buf); + Stream->FatMap = GetFatMap(Stream); + if (Stream->FatMap == NULL) { + perror("alloc fat map"); + return -1; + } + return 0; +} + + +void set_fat12(Fs_t *This) +{ + This->fat_bits = 12; + This->end_fat = 0xfff; + This->last_fat = 0xff6; + This->fat_decode = fat12_decode; + This->fat_encode = fat12_encode; +} + +static char word_endian_test[] = { 0x34, 0x12 }; + +void set_fat16(Fs_t *This) +{ + This->fat_bits = 16; + This->end_fat = 0xffff; + This->last_fat = 0xfff6; + + if(sizeof(unsigned short) == 2 && + * (unsigned short *) word_endian_test == 0x1234) { + This->fat_decode = fast_fat16_decode; + This->fat_encode = fast_fat16_encode; + } else { + This->fat_decode = fat16_decode; + This->fat_encode = fat16_encode; + } +} + +static char dword_endian_test[] = { 0x78, 0x56, 0x34, 0x12 }; + +void set_fat32(Fs_t *This) +{ + This->fat_bits = 32; + This->end_fat = 0xfffffff; + This->last_fat = 0xffffff6; + + if(sizeof(unsigned int) == 4 && + * (unsigned int *) dword_endian_test == 0x12345678) { + This->fat_decode = fast_fat32_decode; + This->fat_encode = fast_fat32_encode; + } else { + This->fat_decode = fat32_decode; + This->fat_encode = fat32_encode; + } +} + + +static int check_fat(Fs_t *This) +{ + /* + * This is only a sanity check. For disks with really big FATs, + * there is no point in checking the whole FAT. + */ + + unsigned int i, f; + unsigned int tocheck; + if(mtools_skip_check) + return 0; + + /* too few sectors in the FAT */ + if(This->fat_len < NEEDED_FAT_SIZE(This)) + return -1; + /* we do not warn about too much sectors in FAT, which may + * happen when a partition has been shrunk using FIPS, or on + * other occurrences */ + + tocheck = This->num_clus; + if (tocheck + 1 >= This->last_fat) { + fprintf(stderr, "Too many clusters in FAT\n"); + return -1; + } + + if(tocheck > 4096) + tocheck = 4096; + + for ( i= 3 ; i < tocheck; i++){ + f = This->fat_decode(This,i); + if (f == 1 || (f < This->last_fat && f > This->num_clus)){ + fprintf(stderr, + "Cluster # at %d too big(%#x)\n", i,f); + fprintf(stderr,"Probably non MS-DOS disk\n"); + return -1; + } + } + return 0; +} + + +/* + * Read the first sector of FAT table into memory. Crude error detection on + * wrong FAT encoding scheme. + */ +static int check_media_type(Fs_t *This, union bootsector *boot, + unsigned int tot_sectors) +{ + unsigned char *address; + + This->num_clus = (tot_sectors - This->clus_start) / This->cluster_size; + + This->FatMap = GetFatMap(This); + if (This->FatMap == NULL) { + perror("alloc fat map"); + return -1; + } + + address = getAddress(This, 0, FAT_ACCESS_READ); + if(!address) { + fprintf(stderr, + "Could not read first FAT sector\n"); + return -1; + } + + if(mtools_skip_check) + return 0; + + if(!address[0] && !address[1] && !address[2]) + /* Some Atari disks have zeroes where Dos has media descriptor + * and 0xff. Do not consider this as an error */ + return 0; + + if((address[0] != boot->boot.descr && boot->boot.descr >= 0xf0 && + ((address[0] != 0xf9 && address[0] != 0xf7) + || boot->boot.descr != 0xf0)) || address[0] < 0xf0) { + fprintf(stderr, + "Bad media types %02x/%02x, probably non-MSDOS disk\n", + address[0], + boot->boot.descr); + return -1; + } + + if(address[1] != 0xff || address[2] != 0xff){ + fprintf(stderr,"Initial byte of fat is not 0xff\n"); + return -1; + } + + return 0; +} + +static int fat_32_read(Fs_t *This, union bootsector *boot, + unsigned int tot_sectors) +{ + int size; + + This->fat_len = DWORD(ext.fat32.bigFat); + This->writeAllFats = !(boot->boot.ext.fat32.extFlags[0] & 0x80); + This->primaryFat = boot->boot.ext.fat32.extFlags[0] & 0xf; + This->rootCluster = DWORD(ext.fat32.rootCluster); + This->clus_start = This->fat_start + This->num_fat * This->fat_len; + + /* read the info sector */ + size = This->sector_size; + This->infoSectorLoc = WORD(ext.fat32.infoSector); + if(This->sector_size >= 512 && + This->infoSectorLoc && This->infoSectorLoc != MAX32) { + InfoSector_t *infoSector; + infoSector = (InfoSector_t *) safe_malloc(size); + if(forceReadSector(This, (char *)infoSector, + This->infoSectorLoc, 1) == + (signed int) This->sector_size && + _DWORD(infoSector->signature1) == INFOSECT_SIGNATURE1 && + _DWORD(infoSector->signature2) == INFOSECT_SIGNATURE2) { + This->freeSpace = _DWORD(infoSector->count); + This->last = _DWORD(infoSector->pos); + } + free(infoSector); + } + + set_fat32(This); + return(check_media_type(This, boot, tot_sectors) || + check_fat(This)); +} + + +static int old_fat_read(Fs_t *This, union bootsector *boot, + size_t tot_sectors, int nodups) +{ + This->writeAllFats = 1; + This->primaryFat = 0; + This->dir_start = This->fat_start + This->num_fat * This->fat_len; + This->clus_start = This->dir_start + This->dir_len; + This->infoSectorLoc = MAX32; + + if(nodups) + This->num_fat = 1; + + if(check_media_type(This,boot, tot_sectors)) + return -1; + + if(This->num_clus >= FAT12) { + set_fat16(This); + /* third FAT byte must be 0xff */ + if(!mtools_skip_check && readByte(This, 3) != 0xff) + return -1; + } else + set_fat12(This); + + return check_fat(This); +} + +/* + * Read the first sector of the FAT table into memory and initialize + * structures. + */ +int fat_read(Fs_t *This, union bootsector *boot, + size_t tot_sectors, int nodups) +{ + This->fat_error = 0; + This->fat_dirty = 0; + This->last = MAX32; + This->freeSpace = MAX32; + This->lastFatSectorNr = 0; + This->lastFatSectorData = 0; + + if(This->fat_len) + return old_fat_read(This, boot, tot_sectors, nodups); + else + return fat_32_read(This, boot, tot_sectors); +} + + +unsigned int fatDecode(Fs_t *This, unsigned int pos) +{ + unsigned int ret; + + ret = This->fat_decode(This, pos); + if(ret && (ret < 2 || ret > This->num_clus+1) && ret < This->last_fat) { + fprintf(stderr, "Bad FAT entry %d at %d\n", ret, pos); + This->fat_error++; + } + return ret; +} + +/* append a new cluster */ +void fatAppend(Fs_t *This, unsigned int pos, unsigned int newpos) +{ + This->fat_encode(This, pos, newpos); + This->fat_encode(This, newpos, This->end_fat); + if(This->freeSpace != MAX32) + This->freeSpace--; +} + +/* de-allocates the given cluster */ +void fatDeallocate(Fs_t *This, unsigned int pos) +{ + This->fat_encode(This, pos, 0); + if(This->freeSpace != MAX32) + This->freeSpace++; +} + +/* allocate a new cluster */ +void fatAllocate(Fs_t *This, unsigned int pos, unsigned int value) +{ + This->fat_encode(This, pos, value); + if(This->freeSpace != MAX32) + This->freeSpace--; +} + +void fatEncode(Fs_t *This, unsigned int pos, unsigned int value) +{ + unsigned int oldvalue = This->fat_decode(This, pos); + This->fat_encode(This, pos, value); + if(This->freeSpace != MAX32) { + if(oldvalue) + This->freeSpace++; + if(value) + This->freeSpace--; + } +} + +unsigned int get_next_free_cluster(Fs_t *This, unsigned int last) +{ + unsigned int i; + + if(This->last != MAX32) + last = This->last; + + if (last < 2 || + last >= This->num_clus+1) + last = 1; + + for (i=last+1; i< This->num_clus+2; i++) { + unsigned int r = fatDecode(This, i); + if(r == 1) + goto exit_0; + if (!r) { + This->last = i; + return i; + } + } + + for(i=2; i < last+1; i++) { + unsigned int r = fatDecode(This, i); + if(r == 1) + goto exit_0; + if (!r) { + This->last = i; + return i; + } + } + + + fprintf(stderr,"No free cluster %d %d\n", This->preallocatedClusters, + This->last); + return 1; + exit_0: + fprintf(stderr, "FAT error\n"); + return 1; +} + +int fat_error(Stream_t *Dir) +{ + Stream_t *Stream = GetFs(Dir); + DeclareThis(Fs_t); + + if(This->fat_error) + fprintf(stderr,"Fat error detected\n"); + + return This->fat_error; +} + +int fat32RootCluster(Stream_t *Dir) +{ + Stream_t *Stream = GetFs(Dir); + DeclareThis(Fs_t); + + if(This->fat_bits == 32) + return This->rootCluster; + else + return 0; +} + + +/* + * Get the amount of free space on the diskette + */ + +mt_size_t getfree(Stream_t *Dir) +{ + Stream_t *Stream = GetFs(Dir); + DeclareThis(Fs_t); + + if(This->freeSpace == MAX32 || This->freeSpace == 0) { + register unsigned int i; + size_t total; + + total = 0L; + for (i = 2; i < This->num_clus + 2; i++) { + unsigned int r = fatDecode(This,i); + if(r == 1) { + return -1; + } + if (!r) + total++; + } + This->freeSpace = total; + } + return sectorsToBytes((Stream_t*)This, + This->freeSpace * This->cluster_size); +} + + +/* + * Ensure that there is a minimum of total sectors free + */ +int getfreeMinClusters(Stream_t *Dir, size_t size) +{ + Stream_t *Stream = GetFs(Dir); + DeclareThis(Fs_t); + register unsigned int i, last; + size_t total; + + if(batchmode && This->freeSpace == MAX32) + getfree(Stream); + + if(This->freeSpace != MAX32) { + if(This->freeSpace >= size) + return 1; + else { + fprintf(stderr, "Disk full\n"); + got_signal = 1; + return 0; + } + } + + total = 0L; + + /* we start at the same place where we'll start later to actually + * allocate the sectors. That way, the same sectors of the FAT, which + * are already loaded during getfreeMin will be able to be reused + * during get_next_free_cluster */ + last = This->last; + + if ( last < 2 || last >= This->num_clus + 2) + last = 1; + for (i=last+1; i< This->num_clus+2; i++){ + unsigned int r = fatDecode(This, i); + if(r == 1) { + goto exit_0; + } + if (!r) + total++; + if(total >= size) + return 1; + } + for(i=2; i < last+1; i++){ + unsigned int r = fatDecode(This, i); + if(r == 1) { + goto exit_0; + } + if (!r) + total++; + if(total >= size) + return 1; + } + fprintf(stderr, "Disk full\n"); + got_signal = 1; + return 0; + exit_0: + fprintf(stderr, "FAT error\n"); + return 0; +} + + +int getfreeMinBytes(Stream_t *Dir, mt_size_t size) +{ + Stream_t *Stream = GetFs(Dir); + DeclareThis(Fs_t); + size_t size2; + + size2 = size / (This->sector_size * This->cluster_size); + if(size % (This->sector_size * This->cluster_size)) + size2++; + return getfreeMinClusters(Dir, size2); +} + + +unsigned int getStart(Stream_t *Dir, struct directory *dir) +{ + Stream_t *Stream = GetFs(Dir); + unsigned int first; + + first = START(dir); + if(fat32RootCluster(Stream)) + first |= STARTHI(dir) << 16; + return first; +} + +int fs_free(Stream_t *Stream) +{ + DeclareThis(Fs_t); + + if(This->FatMap) { + int i, nr_entries; + nr_entries = (This->fat_len + SECT_PER_ENTRY - 1) / + SECT_PER_ENTRY; + for(i=0; i< nr_entries; i++) + if(This->FatMap[i].data) + free(This->FatMap[i].data); + free(This->FatMap); + } + if(This->cp) + cp_close(This->cp); + return 0; +} |