Logo Search packages:      
Sourcecode: fatsort version File versions  Download package

FAT_fs.c

/*
      FATSort, utility for sorting FAT directory structures
      Copyright (C) 2004 Boris Leidner <fatsort(at)formenos.de>

      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.
*/

/*
      This file contains/describes functions that are used to read, write, check,
      and use FAT filesystems.
*/

#include "FAT_fs.h"

#include <assert.h>
#include "errors.h"
#include "endianness.h"

#include "fileio.h"


// ---

int32_t check_bootsector(struct sBootSector *bs) {
/*
      lazy check if this is really a FAT bootsector
*/

      assert(bs != NULL);

      if (!((bs->BS_JmpBoot[0] == 0xeb) &&
           (bs->BS_JmpBoot[2] == 0x90)) &&
            !(bs->BS_JmpBoot[0] == 0xe9)) {
            // boot sector does not begin with specific instruction
            myerror("Boot sector does not begin with jump instruction!");
            return -1;
      } else if (SwapInt16(bs->BS_EndOfBS) != 0xaa55) {
            // end of bootsector marker is missing
            myerror("End of boot sector marker is missing!");
            return -1;
      } else if (SwapInt16(bs->BS_BytesPerSec) == 0) {
            myerror("Sectors have a size of zero! Corrupt boot sector!");
            return -1;
      } else if (SwapInt16(bs->BS_SecPerClus) == 0) {
            myerror("Clusters have a size of zero! Corrupt boot sector!");
            return -1;
      }

      return 0;
}

int32_t read_bootsector(FILE *fd, struct sBootSector *bs) {
/*
      reads bootsector
*/

      assert(fd != NULL);
      assert(bs != NULL);

      if (fs_read(bs, sizeof(struct sBootSector), 1, fd) < 1) {
            if (feof(fd)) {
                  myerror("Boot sector is too short!");
            } else {
                  myerror("Failed to read from file!");
            }
            return -1;
      }

// #ifdef __WIN32__
//    // after having read the boot sector in, fix sector size
//    sector_size = SwapInt16(bs->BS_BytesPerSec);
// #endif

      if (check_bootsector(bs)) {
            myerror("This is not a FAT bootsector!");
            return -1;
      }

      return 0;
}

int32_t getCountOfClusters(struct sBootSector *bs) {
/*
      calculates count of clusters
*/

      assert(bs != NULL);

      u_int32_t RootDirSectors, FATSz, TotSec, DataSec;
      int32_t retvalue;

      RootDirSectors = ((SwapInt16(bs->BS_RootEntCnt) * DIR_ENTRY_SIZE) + (SwapInt16(bs->BS_BytesPerSec) - 1));
      RootDirSectors = RootDirSectors / SwapInt16(bs->BS_BytesPerSec);

      if (bs->BS_FATSz16 != 0) {
            FATSz = SwapInt16(bs->BS_FATSz16);
      } else {
            FATSz = SwapInt32(bs->FATxx.FAT32.BS_FATSz32);
      }
      if (SwapInt16(bs->BS_TotSec16) != 0) {
            TotSec = SwapInt16(bs->BS_TotSec16);
      } else {
            TotSec = SwapInt32(bs->BS_TotSec32);
      }
      DataSec = TotSec - (SwapInt16(bs->BS_RsvdSecCnt) + (bs->BS_NumFATs * FATSz) + RootDirSectors);

      retvalue = DataSec / bs->BS_SecPerClus;
      if (retvalue <= 0) {
            myerror("Failed to calculate count of clusters!");
            return -1;
      }
      return retvalue;
}

int32_t getFATType(struct sBootSector *bs) {
/*
      retrieves FAT type from bootsector
*/

      assert(bs != NULL);

      u_int32_t CountOfClusters;

      CountOfClusters=getCountOfClusters(bs);
      if (CountOfClusters == -1) {
            myerror("Failed to get count of clusters!");
            return -1;
      } else if (CountOfClusters < 4096) { // FAT12!
            return FATTYPE_FAT12;
      } else if (CountOfClusters < 65525) { // FAT16!
            return FATTYPE_FAT16;
      } else { // FAT32!
            return FATTYPE_FAT32;
      }
}

int32_t getFATEntry(FILE *fd, struct sBootSector *bs, u_int32_t cluster, u_int32_t *data) {
/*
      retrieves FAT entry for a cluster number
*/

      assert(fd != NULL);
      assert(bs != NULL);
      assert(data != NULL);

      off_t FATOffset, FATSz, BSOffset;
      int32_t FATType;

      *data=0;

      if (bs->BS_FATSz16 != 0) {
            FATSz = SwapInt16(bs->BS_FATSz16);
      } else {
            FATSz = SwapInt32(bs->FATxx.FAT32.BS_FATSz32);
      }

      FATType = getFATType(bs);

      if (FATType == FATTYPE_FAT16) {
            FATOffset = (off_t)cluster * 2;
            BSOffset = (off_t)SwapInt16(bs->BS_RsvdSecCnt) * SwapInt16(bs->BS_BytesPerSec) + FATOffset;
            if (fs_seek(fd, BSOffset, SEEK_SET) == -1) {
                  myerror("Seek error!");
                  return -1;
            }
            if (fs_read(data, 2, 1, fd)<1) {
                  myerror("Failed to read from file!");
                  return -1;
            }
            *data=SwapInt32(*data);
      } else if (FATType == FATTYPE_FAT32) {
            FATOffset = (off_t)cluster * 4;
            BSOffset = (off_t)SwapInt16(bs->BS_RsvdSecCnt) * SwapInt16(bs->BS_BytesPerSec) + FATOffset;
            if (fs_seek(fd, BSOffset, SEEK_SET) == -1) {
                  myerror("Seek error!");
                  return -1;
            }
            if (fs_read(data, 4, 1, fd) < 1) {
                  myerror("Failed to read from file!");
                  return -1;
            }
            *data=SwapInt32(*data);
            *data = *data & 0x0fffffff;
      } else if (FATType == FATTYPE_FAT12) {
            myerror("FAT12 is not supported!");
            return -1;
      } else {
            myerror("Failed to get FAT type!");
            return -1;
      }

      return 0;

}

int32_t putFATEntry(FILE *fd, struct sBootSector *bs, u_int32_t cluster, u_int32_t data) {
/*
      write a FAT entry
*/

      assert(fd != NULL);
      assert(bs != NULL);

      off_t FATOffset, FATSz, BSOffset;
      u_int32_t value, i;
      int32_t FATType;

      if (bs->BS_FATSz16 != 0) {
            FATSz = SwapInt16(bs->BS_FATSz16);
      } else {
            FATSz = SwapInt32(bs->FATxx.FAT32.BS_FATSz32);
      }

      FATType = getFATType(bs);

      if (FATType == FATTYPE_FAT16) {
            FATOffset = (off_t)cluster * 2;
            BSOffset = (off_t)SwapInt16(bs->BS_RsvdSecCnt) * SwapInt16(bs->BS_BytesPerSec) + FATOffset;
            fs_seek(fd, BSOffset, SEEK_SET);
            data=SwapInt32(data);
            if (fs_write(&data, 2, 1, fd)<1) {
                  myerror("Failed to write to file!");
                  return -1;
            }
      } else if (FATType == FATTYPE_FAT32) {
            FATOffset = (off_t)cluster * 4;
            BSOffset = (off_t)SwapInt16(bs->BS_RsvdSecCnt) * SwapInt16(bs->BS_BytesPerSec) + FATOffset;
            if (getFATEntry(fd, bs, cluster, &value)==-1) {
                  myerror("Failed to get FAT entry!");
                  return -1;
            }
            value = (value & 0xf0000000) | (data & 0x0fffffff);
            for(i=0; i<bs->BS_NumFATs; i++) {
                  fs_seek(fd, BSOffset+i*FATSz*bs->BS_BytesPerSec, SEEK_SET);
                  value=SwapInt32(value);
                  if (fs_write(&value, 4, 1, fd) < 1) {
                        myerror("Failed to write to file!");
                        return -1;
                  }
            }
      } else if (FATType == FATTYPE_FAT12) {
            myerror("FAT12 is not supported!");
            return -1;
      } else {
            myerror("Failed to get FAT type!");
            return -1;
      }

      return 0;

}

off_t getClusterOffset(struct sBootSector *bs, u_int32_t cluster) {
/*
      returns the offset of a specific cluster in the
      data region of the file system
*/

      assert(bs != NULL);
      assert(cluster > 1);

      u_int32_t FATSz, RootDirSectors, FirstDataSector;

      if (bs->BS_FATSz16 != 0) {
            FATSz = SwapInt16(bs->BS_FATSz16);
      } else {
            FATSz = SwapInt32(bs->FATxx.FAT32.BS_FATSz32);
      }

      RootDirSectors = ((SwapInt16(bs->BS_RootEntCnt) * DIR_ENTRY_SIZE) + (SwapInt16(bs->BS_BytesPerSec) - 1)) / SwapInt16(bs->BS_BytesPerSec);
      FirstDataSector = (SwapInt16(bs->BS_RsvdSecCnt) + (bs->BS_NumFATs * FATSz) + RootDirSectors);

      return (((off_t)(cluster - 2) * bs->BS_SecPerClus) + FirstDataSector) * SwapInt16(bs->BS_BytesPerSec);

}

int32_t parseEntry(FILE *fd, union sDirEntry *de) {
/*
      parses one directory entry
*/

      assert(fd != NULL);
      assert(de != NULL);

      if ((fs_read(de, DIR_ENTRY_SIZE, 1, fd)<1)) {
            myerror("Failed to read from file!");
            return -1;
      }

      if (de->LongDirEntry.LDIR_Attr == 0) return 0; // no more entries

      // long dir entry
      if ((de->LongDirEntry.LDIR_Attr & ATTR_LONG_NAME_MASK) == ATTR_LONG_NAME) return 2;

      return 1; // short dir entry
}

Generated by  Doxygen 1.6.0   Back to index