| @@ -0,0 +1,297 @@ | ||
| #include <stdio.h> | ||
| #include <sys/types.h> | ||
| #include <string.h> | ||
| #include "directory_entries.h" | ||
| #include "fat_entries.h" | ||
|
|
||
| fileData getFileData(FILE* filePtr, uint64_t byteAddress) { | ||
| fileData thisFileData; | ||
|
|
||
| // 1. jump to where the file data is | ||
| fseek(filePtr, byteAddress, SEEK_SET); | ||
|
|
||
| // 2. get the directory name | ||
| fread(&(thisFileData.fileName), READ_RESOLUTION, DN_SIZE, filePtr); | ||
| thisFileData.fileName[SH_DIRNAME_SIZE] = '\0'; | ||
|
|
||
| // 3. get the file attributes | ||
| fread(&(thisFileData.fileAttributes), READ_RESOLUTION, DA_SIZE, filePtr); | ||
|
|
||
| // 4. get the create time | ||
| fseek(filePtr, DCT_OFFSET - (DA_OFFSET + DA_SIZE), SEEK_CUR); | ||
| fread(&(thisFileData.createTime), READ_RESOLUTION, DCT_SIZE, filePtr); | ||
| thisFileData.createTime = le16toh(thisFileData.createTime); | ||
|
|
||
| // 5. get the create date | ||
| fread(&(thisFileData.createDate), READ_RESOLUTION, DCD_SIZE, filePtr); | ||
| thisFileData.createDate = le16toh(thisFileData.createDate); | ||
|
|
||
| // 6. get the last access date | ||
| fread(&(thisFileData.lastAccessDate), READ_RESOLUTION, DLAD_SIZE, filePtr); | ||
| thisFileData.lastAccessDate = le16toh(thisFileData.lastAccessDate); | ||
|
|
||
| // 7. get the first cluster number high order word | ||
| fread(&(thisFileData.firstClusterNumHI), READ_RESOLUTION, DFCH_SIZE, filePtr); | ||
| thisFileData.firstClusterNumHI = le16toh(thisFileData.firstClusterNumHI); | ||
|
|
||
| // 8. get the last write time | ||
| fread(&(thisFileData.writeTime), READ_RESOLUTION, DWT_SIZE, filePtr); | ||
| thisFileData.writeTime = le16toh(thisFileData.writeTime); | ||
|
|
||
| // 9. get the last write date | ||
| fread(&(thisFileData.writeDate), READ_RESOLUTION, DWD_SIZE, filePtr); | ||
| thisFileData.writeDate = le16toh(thisFileData.writeDate); | ||
|
|
||
| // 10. get the first cluster number low order word | ||
| fread(&(thisFileData.firstClusterNumLO), READ_RESOLUTION, DFCL_SIZE, filePtr); | ||
| thisFileData.firstClusterNumLO = le16toh(thisFileData.firstClusterNumLO); | ||
|
|
||
| // 11. get the file size | ||
| fread(&(thisFileData.fileSize), READ_RESOLUTION, DFS_SIZE, filePtr); | ||
| thisFileData.fileSize = le32toh(thisFileData.fileSize); | ||
|
|
||
| return thisFileData; | ||
| } | ||
|
|
||
| BOOL isReadOnly(fileData thisFileData) { | ||
| if (((thisFileData.fileAttributes & 1) == 1) && (thisFileData.fileAttributes & 15) != 15) { | ||
| return TRUE; | ||
| } | ||
| else { | ||
| return FALSE; | ||
| } | ||
| } | ||
|
|
||
| BOOL isSystemFile(fileData thisFileData) { | ||
| if (((thisFileData.fileAttributes & 2) == 2) && (thisFileData.fileAttributes & 15) != 15) { | ||
| return TRUE; | ||
| } | ||
| else { | ||
| return FALSE; | ||
| } | ||
| } | ||
|
|
||
| BOOL isHiddenFile(fileData thisFileData) { | ||
| if (((thisFileData.fileAttributes & 4) == 4) && (thisFileData.fileAttributes & 15) != 15) { | ||
| return TRUE; | ||
| } | ||
| else { | ||
| return FALSE; | ||
| } | ||
| } | ||
|
|
||
| BOOL isVolumeLabel(fileData thisFileData) { | ||
| if (((thisFileData.fileAttributes & 8) == 8) && (thisFileData.fileAttributes & 15) != 15) { | ||
| return TRUE; | ||
| } | ||
| else { | ||
| return FALSE; | ||
| } | ||
| } | ||
|
|
||
|
|
||
| BOOL isLongName(fileData thisFileData) { | ||
| if ((thisFileData.fileAttributes & 15) == 15) { | ||
| return TRUE; | ||
| } | ||
| else { | ||
| return FALSE; | ||
| } | ||
| } | ||
|
|
||
| BOOL isDirectory(fileData thisFileData) { | ||
| if ((thisFileData.fileAttributes & 16) == 16) { | ||
| return TRUE; | ||
| } | ||
| else { | ||
| return FALSE; | ||
| } | ||
| } | ||
|
|
||
| BOOL isFile(fileData thisFileData) { | ||
| if ((thisFileData.fileAttributes & 32) == 32) { | ||
| return TRUE; | ||
| } | ||
| else { | ||
| return FALSE; | ||
| } | ||
| } | ||
|
|
||
| BOOL isEndOfDirectory(fileData thisFileData) { | ||
| if (thisFileData.fileName[0] == '\0') { | ||
| return TRUE; | ||
| } | ||
| else { | ||
| return FALSE; | ||
| } | ||
| } | ||
|
|
||
| BOOL isEmptyDirectoryEntry(fileData thisFileData) { | ||
| if (thisFileData.fileName[0] == -27) { | ||
| return TRUE; | ||
| } | ||
| else { | ||
| return FALSE; | ||
| } | ||
| } | ||
|
|
||
| uint64_t checkFileExists(FILE* filePtr, bootSector thisBootSector, char* fileName, uint32_t currentClusterNumber) { | ||
| fileData thisFileData; // | ||
| FATEntry thisFATEntry; | ||
| uint32_t firstSectorOfCluster; // the first sector of the current cluster we're on | ||
| uint32_t sectorNumber; | ||
| uint64_t sectorNumberInBytes; | ||
| uint64_t currentByteAddress; | ||
|
|
||
| printf("checkFile gets %s\n", fileName); | ||
| printf("checkFile gets %d\n", currentClusterNumber); | ||
|
|
||
| while (currentClusterNumber != EOC) { | ||
| firstSectorOfCluster = getFirstSectorOfCluster(thisBootSector, currentClusterNumber); | ||
|
|
||
| for (sectorNumber = firstSectorOfCluster; sectorNumber < (firstSectorOfCluster + thisBootSector.sectorsPerCluster); sectorNumber++) { | ||
| sectorNumberInBytes = convertSectorNumToBytes(thisBootSector, sectorNumber); | ||
|
|
||
| for (currentByteAddress = sectorNumberInBytes; currentByteAddress < (sectorNumberInBytes + thisBootSector.bytesPerSector); currentByteAddress += DIR_ENTRY_SIZE) { | ||
| thisFileData = getFileData(filePtr, currentByteAddress); | ||
|
|
||
| if (isEndOfDirectory(thisFileData)) { | ||
| return -1; | ||
| } | ||
|
|
||
| // if this is not a volume lable, long name, or deleted entry | ||
| if (!isVolumeLabel(thisFileData) && !isLongName(thisFileData) && !isEmptyDirectoryEntry(thisFileData)) { | ||
| // check to see if the current directory matches our search and return byte address of entry if it does | ||
| //TODO: fix this | ||
| /** | ||
| FIX THIS strlen or strcmp | ||
| */ | ||
| if (strncmp(thisFileData.fileName, fileName, strlen(fileName) - 1) == 0) | ||
| { | ||
| return currentByteAddress; | ||
| } | ||
| } | ||
| } | ||
| } | ||
|
|
||
| // determine the next currentClusterNumber | ||
| thisFATEntry = getFATEntry(filePtr, thisBootSector, currentClusterNumber); | ||
| currentClusterNumber = thisFATEntry.nextClusterNumber; | ||
| } | ||
| } | ||
|
|
||
| uint32_t getFirstClusterOfEntry(bootSector thisBootSector, fileData thisFileData) { | ||
|
|
||
| uint32_t firstClusterEntry; | ||
|
|
||
| //Get the high word from the file and shift it left 16 bits | ||
| firstClusterEntry = thisFileData.firstClusterNumHI; | ||
| firstClusterEntry = firstClusterEntry << 16; | ||
|
|
||
| //Get the low word from the file and add it to the first cluster entry | ||
| firstClusterEntry += thisFileData.firstClusterNumLO; | ||
|
|
||
| return firstClusterEntry; | ||
| } | ||
|
|
||
| time getCreateTime(fileData thisFileData) { | ||
| time thisTime; | ||
| thisTime = convertToTimeStruct(thisFileData.createTime); | ||
| return thisTime; | ||
| } | ||
|
|
||
| date getCreateDate(fileData thisFileData) { | ||
| date thisDate; | ||
| thisDate = convertToDateStruct(thisFileData.createDate); | ||
| return thisDate; | ||
| } | ||
|
|
||
| date getLastAccessDate(fileData thisFileData) { | ||
| date thisDate; | ||
| thisDate = convertToDateStruct(thisFileData.lastAccessDate); | ||
| return thisDate; | ||
| } | ||
|
|
||
| time getWriteTime(fileData thisFileData) { | ||
| time thisTime; | ||
| thisTime = convertToTimeStruct(thisFileData.writeTime); | ||
| return thisTime; | ||
| } | ||
|
|
||
| date getWriteDate(fileData thisFileData) { | ||
| date thisDate; | ||
| thisDate = convertToDateStruct(thisFileData.writeDate); | ||
| return thisDate; | ||
| } | ||
|
|
||
| date convertToDateStruct(uint16_t machineRepresentation) { | ||
| date thisDate; | ||
| uint16_t mask; | ||
|
|
||
| // 1. make a bit mask for bits 5-15 | ||
| mask = ~(~0 << 5); | ||
|
|
||
| // 2. take bitwise AND of this and the machine represenation | ||
| thisDate.day = mask & machineRepresentation; | ||
|
|
||
| // 3. shift 5 bits to the right to put month in the lowest order | ||
| machineRepresentation = machineRepresentation >> 5; | ||
|
|
||
| // 4. make a bit mask for bits 4-15 | ||
| mask = ~(~0 << 4); | ||
|
|
||
| // 5. take bitwise AND of this and the machine represenation | ||
| thisDate.month = mask & machineRepresentation; | ||
|
|
||
| // 6. shift 4 bits to the right to put year in lowest order | ||
| machineRepresentation = machineRepresentation >> 4; | ||
|
|
||
| // 7. make a bit mask for 7-15 | ||
| mask = ~(~0 << 7); | ||
|
|
||
| // 8. take bitwise AND of this and the machine representation | ||
| thisDate.year = mask & machineRepresentation; | ||
|
|
||
| // 9. add epoch to the calculated year | ||
| thisDate.year += EPOCH_YEAR; | ||
|
|
||
| return thisDate; | ||
| } | ||
|
|
||
| time convertToTimeStruct(uint16_t machineRepresentation) { | ||
| time thisTime; | ||
| uint16_t mask; | ||
|
|
||
| // 1. make a bit mask for bits 5-15 | ||
| mask = ~(~0 << 5); | ||
|
|
||
| // 2. take a bitwise AND of this and the machine representation | ||
| thisTime.seconds = mask & machineRepresentation; | ||
|
|
||
| // 3. multiply seconds by 2 (because granularity is 2 seconds) | ||
| thisTime.seconds *= 2; | ||
|
|
||
| // 4. shift 5 bits to the right to put minutes in lowest order | ||
| machineRepresentation = machineRepresentation >> 5; | ||
|
|
||
| // 5. make a bit mask for 6-15 | ||
| mask = ~(~0 << 6); | ||
|
|
||
| // 6. take a bitwise AND of this and the machine representation | ||
| thisTime.minutes = mask & machineRepresentation; | ||
|
|
||
| // 7. shift 6 bits to the right to put hours in the lowest order | ||
| machineRepresentation = machineRepresentation >> 6; | ||
|
|
||
| // 8. make a bit mask for 5-15 | ||
| mask = ~(~0 << 5); | ||
|
|
||
| // 9. take a bitwise AND of this and the machine representation | ||
| thisTime.hours = mask & machineRepresentation; | ||
|
|
||
| return thisTime; | ||
| } | ||
|
|
||
|
|
||
|
|
||
|
|
| @@ -0,0 +1,205 @@ | ||
| #ifndef DIRECTORY_ENTRIES_H | ||
| #define DIRECTORY_ENTRIES_H | ||
| //////////////////////////////////////////////////////////////////////////// | ||
| // INCLUDES //////////////////////////////////////////////////////////////// | ||
| //////////////////////////////////////////////////////////////////////////// | ||
|
|
||
| #include <stdint.h> | ||
| #include "boot_sector.h" | ||
| //////////////////////////////////////////////////////////////////////////// | ||
| // MACROS ////////////////////////////////////////////////////////////////// | ||
| //////////////////////////////////////////////////////////////////////////// | ||
|
|
||
| #ifndef BOOL | ||
| #define BOOL int | ||
| #endif | ||
|
|
||
| #ifndef TRUE | ||
| #define TRUE 1 | ||
| #endif | ||
|
|
||
| #ifndef FALSE | ||
| #define FALSE 0 | ||
| #endif | ||
|
|
||
| #define DN_OFFSET 0 // directory name | ||
| #define DN_SIZE 11 | ||
| #define DA_OFFSET 11 // directory attributes | ||
| #define DA_SIZE 1 | ||
| #define DCT_OFFSET 14 // create time | ||
| #define DCT_SIZE 2 | ||
| #define DCD_OFFSET 16 // create date | ||
| #define DCD_SIZE 2 | ||
| #define DLAD_OFFSET 18 // last access date | ||
| #define DLAD_SIZE 2 | ||
| #define DFCH_OFFSET 20 // first cluster number high order word | ||
| #define DFCH_SIZE 2 | ||
| #define DWT_OFFSET 22 // write time | ||
| #define DWT_SIZE 2 | ||
| #define DWD_OFFSET 24 // write date | ||
| #define DWD_SIZE 2 | ||
| #define DFCL_OFFSET 26 // first cluster number low order word | ||
| #define DFCL_SIZE 2 | ||
| #define DFS_OFFSET 28 // file size | ||
| #define DFS_SIZE 4 | ||
| #define SH_FILE_NAME 11 // short file name size in characters | ||
|
|
||
| #define READ_RESOLUTION 1 // the resolution we want to read at in bytes | ||
| #define SH_DIRNAME_SIZE 11 // the number of characters in a short directory name | ||
| #define DIR_ENTRY_SIZE 32 // the size of each entry within a directory in bytes | ||
| #define EPOCH_YEAR 1980 // the year that all years are calculated from in fat32 | ||
|
|
||
| ///////////////////////////////////////////////////////////////////////////// | ||
| // TYPE DEFINITONS ////////////////////////////////////////////////////////// | ||
| ///////////////////////////////////////////////////////////////////////////// | ||
|
|
||
| typedef struct { | ||
| char fileName[SH_FILE_NAME+1]; // the name of the file | ||
| uint8_t fileAttributes; // all attributes associated with file | ||
| uint16_t createTime; // time file was created | ||
| uint16_t createDate; // date file was created | ||
| uint16_t lastAccessDate; // date file was last accessed | ||
| uint16_t firstClusterNumHI; // the higher value word of the first cluster number | ||
| uint16_t writeTime; // time file was last written to | ||
| uint16_t writeDate; // date file was last written to | ||
| uint16_t firstClusterNumLO; // the lower value word of the first cluster number | ||
| uint32_t fileSize; // the size of the file in bytes | ||
| uint64_t byteAddress; // holds the byte address of the directory entry structure | ||
| } fileData; | ||
|
|
||
| typedef struct { | ||
| int day; | ||
| int month; | ||
| int year; | ||
| } date; | ||
|
|
||
| typedef struct { | ||
| int hours; | ||
| int minutes; | ||
| int seconds; | ||
| } time; | ||
|
|
||
| ////////////////////////////////////////////////////////////////////////////// | ||
| // FUNCTION DECLARATIONS ///////////////////////////////////////////////////// | ||
| ////////////////////////////////////////////////////////////////////////////// | ||
|
|
||
| // In: byteAddress (uint64_t) | ||
| // Out: thisFileData (fileData (struct)) | ||
| // Purpose: to place all file metadata based on a byte address in a struct and return it | ||
| // Note: handles file metadata blocks that are 32 bits (4 bytes) in size | ||
| fileData getFileData(FILE* filePtr, uint64_t byteAddress); | ||
|
|
||
| // In: thisFileData (fileData (struct)) | ||
| // Out: boolean | ||
| // Purpose: to determine if the file is read only | ||
| // Notes: | ||
| BOOL isReadOnly(fileData thisFileData); | ||
|
|
||
| // In: thisFileData (fileData (struct)) | ||
| // Out: boolean | ||
| // Purpose: to determine if the current file directory is a system file | ||
| // Notes: | ||
| BOOL isSystemFile(fileData thisFileData); | ||
|
|
||
| // In: thisFileData (fileData (struct)) | ||
| // Out: boolean | ||
| // Purpose: to determine if the current file directory is a hidden file/directory | ||
| // Notes: | ||
| BOOL isHiddenFile(fileData thisFileData); | ||
|
|
||
| // In: thisFileData (fileData (struct)) | ||
| // Out: boolean | ||
| // Purpose: to determine if the current file directory is the volume label of the volume | ||
| // Notes: | ||
| BOOL isVolumeLabel(fileData thisFileData); | ||
|
|
||
| // In: thisFileData (fileData (struct)) | ||
| // Out: boolean | ||
| // Purpose: to determine if the current file directory is part of a long name | ||
| // Notes: fileAttributes is really a byte we are representing as an int | ||
| BOOL isLongName(fileData thisFileData); | ||
|
|
||
| // In: thisFileData (fileData (struct)) | ||
| // Out: boolean | ||
| // Purpose: to determine if the current file directory is a directory | ||
| // Notes: | ||
| BOOL isDirectory(fileData thisFileData); | ||
|
|
||
| // In: thisFileData (fileData (struct)) | ||
| // Out: boolean | ||
| // Purpose: to determine if the current file directory is a file | ||
| // Notes: | ||
| BOOL isFile(fileData thisFileData); | ||
|
|
||
| // In: thisFileData (fileData (struct)) | ||
| // Out: boolean | ||
| // Purpose: to detemine if we have reached the end of the directory (no more entries left) | ||
| // Notes: | ||
| BOOL isEndOfDirectory(fileData thisFileData); | ||
|
|
||
| // In: thisFileData (fileData (struct)) | ||
| // Out: boolean | ||
| // Purpose: to determine if a given directory entry is empty | ||
| // Notes: this applies to directories/files that were deleted | ||
| BOOL isEmptyDirectoryEntry(fileData thisFileData); | ||
|
|
||
| // In: filePtr (FILE*), fileName (char*), currentByteAddress (uint64_t) | ||
| // Out: directoryEntryAddress (uint64_t) | ||
| // Purpose: to determine if a file exists in the current directory | ||
| // Notes: this applies to directories/files that were deleted; it should be noted | ||
| // that the address returned is the address oof the directory entry NOT the | ||
| // actual file contents; -1 is returned if the file doesn't exist | ||
| uint64_t checkFileExists(FILE* filePtr, bootSector thisBootSector, char* fileName, uint32_t currentClusterNumber); | ||
|
|
||
| // In: thisFileData (fileData (struct)) | ||
| // Out: boolean | ||
| // Purpose: to determine if the current file directory is a file | ||
| // Notes: fileAttributes is really a byte we are representing as an int | ||
| uint32_t getFirstClusterOfEntry(bootSector thisBootSector, fileData thisFileData); | ||
|
|
||
| // In: thisFileData (fileData (struct)) | ||
| // Out: thisTime (time (struct)) | ||
| // Purpose: to get the create time of the directory entry | ||
| // Notes: | ||
| time getCreateTime(fileData thisFileData); | ||
|
|
||
| // In: thisFileData (fileData (struct)) | ||
| // Out: thisDate (date (struct)) | ||
| // Purpose: to get the create date of the directory entry | ||
| // Notes: | ||
| date getCreateDate(fileData thisFileData); | ||
|
|
||
| // In: thisFileData (fileData (struct)) | ||
| // Out: thisDate (date (struct)) | ||
| // Purpose: to get the last access date of the directory entry | ||
| // Notes: | ||
| date getLastAccessDate(fileData thisFileData); | ||
|
|
||
| // In: thisFileData (fileData (struct)) | ||
| // Out: thisTime (time (struct)) | ||
| // Purpose: to get the last write time of the directory entry | ||
| // Notes: | ||
| time getWriteTime(fileData thisFileData); | ||
|
|
||
| // In: thisFileData (fileData (struct)) | ||
| // Out: thisDate (date (struct)) | ||
| // Purpose: to get the last write date of the directory entry | ||
| // Notes: | ||
| date getWriteDate(fileData thisFileData); | ||
|
|
||
| // In: machineRepresentation (uint16_t) | ||
| // Out: thisDate (date (struct)) | ||
| // Purpose: to convert the machine representation of the date into a human readable date | ||
| // Notes: specific bits are extracted through shifting and using & for masking | ||
| date convertToDateStruct(uint16_t machineRepresentation); | ||
|
|
||
| // In: machineRepresentation (uint16_t) | ||
| // Out: thisTime (time (struct)) | ||
| // Purpose: to convert the machine representation of a time to a human-readable version | ||
| // Notes: same logic as convertToDateStruct | ||
| time convertToTimeStruct(uint16_t machineRepresentation); | ||
|
|
||
| #endif /* DIRECTORY_ENTRIES_H */ | ||
|
|
||
|
|
||
|
|
| @@ -0,0 +1,44 @@ | ||
| #include "equations.h" | ||
|
|
||
| uint32_t getRootDirectorySectors(bootSector thisBootSector) { | ||
| return (((thisBootSector.rootEntryCount * 32) + (thisBootSector.bytesPerSector - 1)) / thisBootSector.bytesPerSector); | ||
| } | ||
|
|
||
| uint32_t getFirstDataSector(bootSector thisBootSector) { | ||
| return (thisBootSector.reservedSectorCount + (thisBootSector.numOfFATs * thisBootSector.fatSize) + thisBootSector.rootDirectorySectors); | ||
| } | ||
|
|
||
| uint32_t getFirstSectorOfCluster(bootSector thisBootSector, uint32_t numOfCluster) { | ||
| return (((numOfCluster - 2) * thisBootSector.sectorsPerCluster) + thisBootSector.firstDataSector); | ||
| } | ||
|
|
||
| uint32_t getThisFATSectorNumber(bootSector thisBootSector, uint32_t numOfCluster) { | ||
| uint64_t fatOffset; | ||
| fatOffset = numOfCluster * 4; | ||
| return (thisBootSector.reservedSectorCount + (fatOffset / thisBootSector.bytesPerSector)); | ||
| } | ||
|
|
||
| uint16_t getThisFATEntryOffset(bootSector thisBootSector, uint32_t numOfCluster) { | ||
| uint64_t fatOffset; | ||
| fatOffset = numOfCluster * 4; | ||
| return (fatOffset % thisBootSector.bytesPerSector); | ||
| } | ||
|
|
||
| uint64_t convertSectorNumToBytes(bootSector thisBootSector, uint32_t sectorNumber) { | ||
| return sectorNumber * thisBootSector.bytesPerSector; | ||
| } | ||
|
|
||
| uint64_t convertClusterNumToBytes(bootSector thisBootSector, uint32_t clusterNumber) { | ||
| uint32_t firstSectorOfCluster; | ||
| uint64_t clusterNumberInBytes; | ||
|
|
||
| firstSectorOfCluster = getFirstSectorOfCluster(thisBootSector, clusterNumber); | ||
| clusterNumberInBytes = convertSectorNumToBytes(thisBootSector, firstSectorOfCluster); | ||
| return clusterNumberInBytes; | ||
| } | ||
|
|
||
| uint32_t convertBytesToClusterNum(bootSector thisBootSector, uint64_t byteAddress) { | ||
| uint32_t firstDataSector; | ||
| firstDataSector = getFirstDataSector(thisBootSector); | ||
| return ((((byteAddress / thisBootSector.bytesPerSector) - firstDataSector) / thisBootSector.sectorsPerCluster) + 2); | ||
| } |
| @@ -0,0 +1,63 @@ | ||
| #ifndef EQUATIONS_H | ||
| #define EQUATIONS_H | ||
| /////////////////////////////////////////////////////////////// | ||
| // INCLUDES /////////////////////////////////////////////////// | ||
| /////////////////////////////////////////////////////////////// | ||
|
|
||
| #include <stdint.h> | ||
| #include "boot_sector.h" | ||
|
|
||
| /////////////////////////////////////////////////////////////// | ||
| // FUNCTION DECLARATIONS ////////////////////////////////////// | ||
| /////////////////////////////////////////////////////////////// | ||
|
|
||
| // In: thisBootSector (bootSector (struct)) | ||
| // Out: numOfSectors (uint32_t) | ||
| // Purpose: to get the number of sectors in the root directory | ||
| // Notes: | ||
| uint32_t getRootDirectorySectors(bootSector thisBootSector); | ||
|
|
||
| // In: thisBootSector (bootSector (struct)) | ||
| // Out: sectorNumber (uint32_t) | ||
| // Purpose: to get the first sector number of the data region | ||
| // Notes: | ||
| uint32_t getFirstDataSector(bootSector thisBootSector); | ||
|
|
||
| // In: thisBootSector (bootSector (struct)) | ||
| // Out: sectorNumber (uint32_t) | ||
| // Purpose: to get the first sector number of a cluster | ||
| // Notes: this is automatically adjusted based on the first data sector number | ||
| uint32_t getFirstSectorOfCluster(bootSector thisBootSector, uint32_t numOfCluster); | ||
|
|
||
| // In: thisBootSector (bootSector (struct)), numOfCluster (uint32_t) | ||
| // Out: sectorNumber (uint32_t) | ||
| // Purpose: to get the sector number of the FAT entry for this cluster | ||
| // Notes: this applies to the FAT REGION not the data region | ||
| uint32_t getThisFATSectorNumber(bootSector thisBootSector, uint32_t numOfCluster); | ||
|
|
||
| // In: thisBootSector (bootSector (struct)), numOfCluster (uint32_t) | ||
| // Out: fatByteOffset (uint16_t) | ||
| // Purpose: to get the byte address offset within the sector number when determining the FAT entry location | ||
| // Notes: | ||
| uint16_t getThisFATEntryOffset(bootSector thisBootSector, uint32_t numOfCluster); | ||
|
|
||
| // In: thisBootSector (bootSector (struct)), sectorNumber (uint32_t) | ||
| // Out: sectorNumInBytes (uint64_t) | ||
| // Purpose: to return the byte address of a given sector number | ||
| // Notes: | ||
| uint64_t convertSectorNumToBytes(bootSector thisBootSector, uint32_t sectorNumber); | ||
|
|
||
| // In: thisBootSector (bootSector (struct)), clusterNumber (uint32_t) | ||
| // Out: clusterNumInBytes (uint64_t) | ||
| // Purpose: to return the byte address of a given cluster number | ||
| // Notes: | ||
| uint64_t convertClusterNumToBytes(bootSector thisBootSector, uint32_t clusterNumber); | ||
|
|
||
|
|
||
| // In: thisBootSector (bootSector (struct)), clusterNumber (uint32_t) | ||
| // Out: clusterNumInBytes (uint64_t) | ||
| // Purpose: to return the byte address of a given cluster number | ||
| // Notes: | ||
| uint32_t convertBytesToClusterNum(bootSector thisBootSector, uint64_t byteAddress); | ||
|
|
||
| #endif /* EQUATIONS_H */ |
| @@ -0,0 +1,41 @@ | ||
| /////////////////////////////////////////////////////////////////////////// | ||
| // INCLUDES /////////////////////////////////////////////////////////////// | ||
| /////////////////////////////////////////////////////////////////////////// | ||
| #include "fat_entries.h" | ||
| #include <sys/types.h> | ||
|
|
||
| /////////////////////////////////////////////////////////////////////////// | ||
| // FUNCTION DEFINITIONS /////////////////////////////////////////////////// | ||
| /////////////////////////////////////////////////////////////////////////// | ||
| FATEntry getFATEntry(FILE* filePtr, bootSector thisBootSector, uint32_t clusterNumber) { | ||
| uint32_t thisFATEntrySectorNumber; // the sector number of thisFATEntry | ||
| uint16_t thisFATEntryByteOffset; // the byte offset within the sector of thisFATentry | ||
| uint64_t thisFATEntryByteAddress; // the byte address of the fat entry | ||
| uint32_t nextClusterNumber; // the next cluster number in the cluster chain | ||
| FATEntry thisFATEntry; // the FAT entry structure we create and return | ||
|
|
||
| // 1. determine the sector number index of the FAT for clusterNumber | ||
| thisFATEntrySectorNumber = getThisFATSectorNumber(thisBootSector, clusterNumber); | ||
|
|
||
| // 2. determine the byte offset into the determined sector number | ||
| thisFATEntryByteOffset = getThisFATEntryOffset(thisBootSector, clusterNumber); | ||
|
|
||
| // 3. convert sector number and offset into byte address | ||
| thisFATEntryByteAddress = convertSectorNumToBytes(thisBootSector, thisFATEntrySectorNumber) + thisFATEntryByteOffset; | ||
|
|
||
| // 3. read the 4-byte entry | ||
| fseek(filePtr, thisFATEntryByteAddress, SEEK_SET); | ||
| fread(&nextClusterNumber, READ_RESOLUTION, FAT_ENTRY_SIZE, filePtr); | ||
| nextClusterNumber = le32toh(nextClusterNumber); | ||
|
|
||
| // 4. build and return the FAT entry | ||
| thisFATEntry.currentClusterNumber = clusterNumber; | ||
| thisFATEntry.nextClusterNumber = nextClusterNumber; | ||
| thisFATEntry.FATEntrySectorNumber = thisFATEntrySectorNumber; | ||
| thisFATEntry.FATEntryByteOffset = thisFATEntryByteOffset; | ||
| thisFATEntry.FATEntryByteAddress = thisFATEntryByteAddress; | ||
|
|
||
| return thisFATEntry; | ||
|
|
||
| } | ||
|
|
| @@ -0,0 +1,36 @@ | ||
| #ifndef FAT_ENTRIES_H | ||
| #define FAT_ENTRIES_H | ||
|
|
||
| /////////////////////////////////////////////////////////////////////////// | ||
| // INCLUDES /////////////////////////////////////////////////////////////// | ||
| /////////////////////////////////////////////////////////////////////////// | ||
| #include "equations.h" | ||
|
|
||
| /////////////////////////////////////////////////////////////////////////// | ||
| // MACROS ///////////////////////////////////////////////////////////////// | ||
| /////////////////////////////////////////////////////////////////////////// | ||
| #define EOC 268435448 // hex: 0x0FFFFFF8 | ||
| #define FAT_ENTRY_SIZE 4 | ||
|
|
||
| /////////////////////////////////////////////////////////////////////////// | ||
| // TYPE DEFINITIONS /////////////////////////////////////////////////////// | ||
| /////////////////////////////////////////////////////////////////////////// | ||
| typedef struct { | ||
| uint32_t currentClusterNumber; // consists of the current cluster number we are on | ||
| uint32_t nextClusterNumber; // consists of the next cluster number in the cluster chain | ||
| uint32_t FATEntrySectorNumber; // holds the sector number of the FAT entry | ||
| uint16_t FATEntryByteOffset; // holds the byte offset FROM the sector number of the FAT entry | ||
| uint64_t FATEntryByteAddress; // the byte address of the FAT entry | ||
| } FATEntry; | ||
|
|
||
| /////////////////////////////////////////////////////////////////////////// | ||
| // FUNCTION DECLARATIONS ////////////////////////////////////////////////// | ||
| /////////////////////////////////////////////////////////////////////////// | ||
|
|
||
| // In: thisBootSector (bootSector (struct)), clusterNumber (uint32_t) | ||
| // Out: thisFatEntry (fatEntry (struct)) | ||
| // Purpose: to create a fatEntry struct for convenienve in moving through clusters and to abstract cluster chain logic | ||
| // Notes: | ||
| FATEntry getFATEntry(FILE* filePtr, bootSector thisBootSector, uint32_t clusterNumber); | ||
|
|
||
| #endif /* FAT_ENTRIES_H */ |
| @@ -0,0 +1,29 @@ | ||
| #include <string.h> | ||
| #include <stdio.h> | ||
| #include "format.h" | ||
|
|
||
| char* formatFileName(fileData thisFileData) { | ||
| char* name; | ||
| char* ext; | ||
| static char* toReturn; | ||
|
|
||
| name = strtok(thisFileData.fileName, " "); | ||
| if (isFile(thisFileData)) | ||
| { | ||
| ext = strtok(NULL, " "); | ||
| } | ||
|
|
||
| strcpy(toReturn, name); | ||
| if (isFile(thisFileData)) | ||
| { | ||
| strcat(toReturn, "."); | ||
| strcat(toReturn, ext); | ||
| } | ||
|
|
||
| return toReturn; | ||
|
|
||
| } | ||
|
|
||
| //char* formatDirectoryName(char* directoryName) { | ||
|
|
||
| //} |
| @@ -0,0 +1,12 @@ | ||
| #include "directory_entries.h" | ||
| // In: filename (char*) | ||
| // Out: formattedFileName (char*) | ||
| // Purpose: to get the first sector number of the data region | ||
| // Notes: | ||
| char* formatFileName(fileData thisFileData); | ||
|
|
||
| // In: reservedSectorCount (uint16_t), numOfFATs (uint8_t), fatSize (uint32_t), rootDirectorySectors (uint32_t) | ||
| // Out: formatterDirName (char*) | ||
| // Purpose: to get the first sector number of the data region | ||
| // Notes: | ||
| //char* formatDirectoryName(char* directoryName); |
| @@ -0,0 +1,4 @@ | ||
| #!/bin/bash | ||
| gcc -o fat32_reader fat32_reader.c directory_entries.c equations.c boot_sector.c fat_entries.c | ||
| ./fat32_reader fat32.img | ||
| rm fat32_reader |
| @@ -0,0 +1,48 @@ | ||
| ////////////////////////////////////////////////////////////// | ||
| // INCLUDES ////////////////////////////////////////////////// | ||
| ////////////////////////////////////////////////////////////// | ||
| #include "equations.h" | ||
|
|
||
| ////////////////////////////////////////////////////////////// | ||
| // GLOBAL VARIABLES ////////////////////////////////////////// | ||
| ////////////////////////////////////////////////////////////// | ||
| bootSector thisBootSector; | ||
| FILE* filePtr; | ||
|
|
||
| ////////////////////////////////////////////////////////////// | ||
| // FUNCTION DECLARATIONS ///////////////////////////////////// | ||
| ////////////////////////////////////////////////////////////// | ||
| void testSetUpBootSector(int testNumber); | ||
|
|
||
| ////////////////////////////////////////////////////////////// | ||
| // MAIN PROGRAM ////////////////////////////////////////////// | ||
| ////////////////////////////////////////////////////////////// | ||
| int main(int argc, char** argv) { | ||
|
|
||
| if (argc != 2) { | ||
| printf("You entered an incorrect amount of arguments for this program. <USAGE: ./fat32_reader fat32.img>\n"); | ||
| return -1; | ||
| } | ||
|
|
||
| if ((filePtr = fopen(argv[1], "rb")) == 0) { | ||
| perror(argv[1]); | ||
| return -1; | ||
| } | ||
|
|
||
| testSetUpBootSector(4); | ||
| } | ||
|
|
||
| void testSetUpBootSector(int testNumber) { | ||
| thisBootSector = setUpBootSector(filePtr); | ||
|
|
||
| printf("bytesPerSector: Expected = 512, Actual = %d\n", thisBootSector.bytesPerSector); | ||
| printf("sectorsPerCluster: Expected = 1, Actual = %d\n", thisBootSector.sectorsPerCluster); | ||
| printf("reservedSectorCount: Expected = 32, Actual = %d\n", thisBootSector.reservedSectorCount); | ||
| printf("numOfFATs: Expected = 2, Actual = %d\n", thisBootSector.numOfFATs); | ||
| printf("fatSize: Expected = 1009, Actual = %d\n", thisBootSector.fatSize); | ||
| printf("rootClusterNum: Expected = 2, Actual = %d\n", thisBootSector.rootClusterNum); | ||
| printf("rootEntryCount: Expected = 0, Actual = %d\n", thisBootSector.rootEntryCount); | ||
| printf("totalSectors: Expected = 131072, Actual = %d\n", thisBootSector.totalSectors); | ||
| printf("rootDirectorySectors: Expected = 0, Actual = %d\n", thisBootSector.rootDirectorySectors); | ||
| printf("firstDataSector: Expected = 2050, Actual = %d\n", thisBootSector.firstDataSector); | ||
| } |
| @@ -0,0 +1,366 @@ | ||
| //////////////////////////////////////////////////////////// | ||
| // INCLUDES ////////////////////////////////////////////////// | ||
| ////////////////////////////////////////////////////////////// | ||
| #include <stdio.h> | ||
| #include "directory_entries.h" | ||
| #include <string.h> | ||
| #include "equations.h" | ||
| ///////////////////////////////////////////////////////////// | ||
| // MACROS /////////////////////////////////////////////////// | ||
| ///////////////////////////////////////////////////////////// | ||
| #define ENTRIES_COUNT 6 | ||
|
|
||
| ////////////////////////////////////////////////////////////// | ||
| // FUNCTION DECLARATIONS ///////////////////////////////////// | ||
| ////////////////////////////////////////////////////////////// | ||
| void testEndOfDirectory(int testNumber); | ||
| void setUpSystem(); | ||
| void testSetUp(); | ||
| void testIsEmptyDirectoryEntry(int testNumber); | ||
| void testIsLongName(int testNumber); | ||
| void testIsDirectory(int testNumber); | ||
| void testIsFile(int testNumber); | ||
| void testIsVolumeLabel(int testNumber); | ||
| void testIsReadOnly(int testNumber); | ||
| void testCheckFileExists(int testNumber); | ||
| void testGetFirstClusterOfEntry(int testNumber); | ||
| void testConvertToDateStruct(int testNumber); | ||
| void testConvertToTimeStruct(int testNumber); | ||
|
|
||
| ////////////////////////////////////////////////////////////// | ||
| // GLOBAL VARIABLES ////////////////////////////////////////// | ||
| ////////////////////////////////////////////////////////////// | ||
| fileData directoryEntry_1; | ||
| fileData directoryEntry_2; | ||
| fileData directoryEntry_3; | ||
| fileData directoryEntry_4; | ||
| fileData directoryEntry_5; | ||
| fileData directoryEntry_6; | ||
|
|
||
| fileData system[ENTRIES_COUNT]; | ||
|
|
||
| FILE* filePtr; | ||
| bootSector thisBootSector; | ||
|
|
||
| ////////////////////////////////////////////////////////////// | ||
| // MAIN PROGRAM ////////////////////////////////////////////// | ||
| ////////////////////////////////////////////////////////////// | ||
| int main(int argc, char** argv) { | ||
|
|
||
| if (argc != 2) { | ||
| printf("You entered an incorrect amount of arguments for this program. <USAGE: ./fat32_reader fat32.img>\n"); | ||
| return -1; | ||
| } | ||
|
|
||
| if ((filePtr = fopen(argv[1], "rb")) == 0) { | ||
| perror(argv[1]); | ||
| return -1; | ||
| } | ||
|
|
||
| thisBootSector = setUpBootSector(filePtr); | ||
|
|
||
| setUpSystem(); | ||
| testIsReadOnly(2); | ||
| testIsFile(3); | ||
| testIsDirectory(5); | ||
| testIsEmptyDirectoryEntry(5); | ||
| testIsVolumeLabel(1); | ||
| testIsLongName(2); | ||
| testConvertToDateStruct(1); | ||
| testConvertToDateStruct(2); | ||
| testConvertToTimeStruct(1); | ||
| testConvertToTimeStruct(2); | ||
| testCheckFileExists(1); | ||
| testCheckFileExists(2); | ||
| testCheckFileExists(3); | ||
| testCheckFileExists(4); | ||
| testCheckFileExists(5); | ||
| testGetFirstClusterOfEntry(1); | ||
|
|
||
|
|
||
| fclose(filePtr); | ||
| } | ||
|
|
||
| ////////////////////////////////////////////////////////////// | ||
| // FUNCTION DEFINITIONS ////////////////////////////////////// | ||
| ////////////////////////////////////////////////////////////// | ||
|
|
||
| void setUpSystem() { | ||
| // initialize directoryEntry_1 | ||
| char fileName1[SH_FILE_NAME + 1] = "CHUCKLES"; | ||
| strcpy(directoryEntry_1.fileName, fileName1); | ||
| directoryEntry_1.fileAttributes = 8; // 00001000 | ||
| directoryEntry_1.createTime = 0; | ||
| directoryEntry_1.createDate = 0; | ||
| directoryEntry_1.lastAccessDate = 0; | ||
| directoryEntry_1.firstClusterNumHI = 0; | ||
| directoryEntry_1.firstClusterNumLO = 0; | ||
| directoryEntry_1.writeTime = 0; | ||
| directoryEntry_1.writeDate = 0; | ||
| directoryEntry_1.fileSize = 0; | ||
|
|
||
| // initialize directoryEntry_2 | ||
| char fileName2[SH_FILE_NAME + 1] = "POOP"; | ||
| strcpy(directoryEntry_2.fileName, fileName2); | ||
| directoryEntry_2.fileAttributes = 16; // 00010000 | ||
| directoryEntry_2.createTime = 0; | ||
| directoryEntry_2.createDate = 0; | ||
| directoryEntry_2.lastAccessDate = 0; | ||
| directoryEntry_2.firstClusterNumHI = 2; | ||
| directoryEntry_2.firstClusterNumLO = 43; | ||
| directoryEntry_2.writeTime = 0; | ||
| directoryEntry_2.writeDate = 0; | ||
| directoryEntry_2.fileSize = 0; | ||
|
|
||
| // initialize directoryEntry_3 | ||
| char fileName3[SH_FILE_NAME + 1] = "GHOST.TXT"; | ||
| strcpy(directoryEntry_3.fileName, fileName3); | ||
| directoryEntry_3.fileName[0] = -27; | ||
| directoryEntry_3.fileAttributes = 32; // 0010 0000 | ||
| directoryEntry_3.createTime = 43195; // 1010 1000 1011 1011 | ||
| directoryEntry_3.createDate = 18613; // 0100 1000 1011 0101 | ||
| directoryEntry_3.lastAccessDate = 0; | ||
| directoryEntry_3.firstClusterNumHI = 0; | ||
| directoryEntry_3.firstClusterNumLO = 0; | ||
| directoryEntry_3.writeTime = 0; | ||
| directoryEntry_3.writeDate = 0; | ||
| directoryEntry_3.fileSize = 0; | ||
|
|
||
| // initialize directoryEntry_4 | ||
| char fileName4[SH_FILE_NAME + 1] = "BANANA.TXT"; | ||
| strcpy(directoryEntry_4.fileName, fileName4); | ||
| directoryEntry_4.fileAttributes = 33; // 0010 0001 | ||
| directoryEntry_4.createTime = 12157; // 0010 1111 0111 1101 | ||
| directoryEntry_4.createDate = 10830; // 0010 1010 0100 1110 | ||
| directoryEntry_4.lastAccessDate = 0; | ||
| directoryEntry_4.firstClusterNumHI = 0; | ||
| directoryEntry_4.firstClusterNumLO = 54; | ||
| directoryEntry_4.writeTime = 0; | ||
| directoryEntry_4.writeDate = 0; | ||
| directoryEntry_4.fileSize = 342; | ||
|
|
||
| // initialize directoryEntry_5 | ||
| char fileName5[SH_FILE_NAME + 1] = "\0"; | ||
| strcpy(directoryEntry_5.fileName, fileName5); | ||
| directoryEntry_5.fileAttributes = 0; | ||
| directoryEntry_5.createTime = 0; | ||
| directoryEntry_5.createDate = 0; | ||
| directoryEntry_5.lastAccessDate = 0; | ||
| directoryEntry_5.firstClusterNumHI = 0; | ||
| directoryEntry_5.firstClusterNumLO = 0; | ||
| directoryEntry_5.writeTime = 0; | ||
| directoryEntry_5.writeDate = 0; | ||
| directoryEntry_5.fileSize = 0; | ||
|
|
||
| // initialize directoryEntry_6 | ||
| char fileName6[SH_FILE_NAME + 5] = "POOPOO"; | ||
| strcpy(directoryEntry_6.fileName, fileName6); | ||
| directoryEntry_6.fileAttributes = 15; | ||
| directoryEntry_6.createTime = 0; | ||
| directoryEntry_6.createDate = 0; | ||
| directoryEntry_6.lastAccessDate = 0; | ||
| directoryEntry_6.firstClusterNumHI = 0; | ||
| directoryEntry_6.firstClusterNumLO = 0; | ||
| directoryEntry_6.writeTime = 0; | ||
| directoryEntry_6.writeDate = 0; | ||
| directoryEntry_6.fileSize = 0; | ||
|
|
||
| system[0] = directoryEntry_1; | ||
| system[1] = directoryEntry_2; | ||
| system[2] = directoryEntry_3; | ||
| system[3] = directoryEntry_4; | ||
| system[4] = directoryEntry_5; | ||
| system[5] = directoryEntry_6; | ||
| } | ||
|
|
||
| // tests: setUpSystem() | ||
| // from: here | ||
| void testSetUp() { | ||
| int i; | ||
| fileData thisFileData; | ||
|
|
||
| printf("Testing set up...\n"); | ||
| for (i = 0; i < ENTRIES_COUNT; i++) { | ||
| thisFileData = system[i]; | ||
| printf("%s\n", thisFileData.fileName); | ||
| printf("%d\n", thisFileData.fileAttributes); | ||
| printf("%d\n", thisFileData.createTime); | ||
| printf("%d\n", thisFileData.createDate); | ||
| printf("%d\n", thisFileData.lastAccessDate); | ||
| printf("%d\n", thisFileData.firstClusterNumHI); | ||
| printf("%d\n", thisFileData.firstClusterNumLO); | ||
| printf("%d\n", thisFileData.writeTime); | ||
| printf("%d\n", thisFileData.writeDate); | ||
| printf("%d\n", thisFileData.fileSize); | ||
| printf("\n\n"); | ||
| } | ||
| } | ||
|
|
||
| // tests: isEndOfDirectory() | ||
| // from: booleans.h | ||
| void testEndOfDirectory(int testNumber) { | ||
| int i; // looping variable | ||
|
|
||
| printf("Testing end of directory...\n"); | ||
| for (i = 0; i < ENTRIES_COUNT; i++) { | ||
| if (isEndOfDirectory(system[i])) { | ||
| printf("HOLY CRAP! IT IS THE END!\n"); | ||
| } | ||
| else { | ||
| printf("Nope... it's not over yet.\n"); | ||
| } | ||
| } | ||
| } | ||
|
|
||
| void testIsDirectory(int testNumber) { | ||
| int expectedValues[ENTRIES_COUNT] = {0, 1, 0, 0, 0, 0}; | ||
| int actualValue; | ||
| int i; | ||
|
|
||
| printf("Testing is directory...\n"); | ||
| for (i = 0; i < ENTRIES_COUNT; i++) { | ||
| actualValue = isDirectory(system[i]); | ||
| printf("Expected Value = %d; Actual Value = %d\n", expectedValues[i], actualValue); | ||
| } | ||
| } | ||
|
|
||
| void testIsFile(int testNumber) { | ||
| int expectedValues[ENTRIES_COUNT] = {0, 0, 1, 1, 0, 0}; | ||
| int actualValue; | ||
| int i; | ||
|
|
||
| printf("Testing is file...\n"); | ||
| for (i = 0; i < ENTRIES_COUNT; i++) { | ||
| actualValue = isFile(system[i]); | ||
| printf("Expected Value = %d; Actual Value = %d\n", expectedValues[i], actualValue); | ||
|
|
||
| } | ||
| } | ||
|
|
||
| void testIsEmptyDirectoryEntry(int testNumber) { | ||
| int expectedValues[ENTRIES_COUNT] = {0, 0, 1, 0, 0, 0}; | ||
| int actualValue; | ||
| int i; | ||
|
|
||
| printf("Testing is empty directory entry...\n"); | ||
| for (i = 0; i < ENTRIES_COUNT; i++) { | ||
| actualValue = isEmptyDirectoryEntry(system[i]); | ||
| printf("Expected Value = %d; Actual Value = %d\n", expectedValues[i], actualValue); | ||
|
|
||
| } | ||
| } | ||
|
|
||
| void testIsReadOnly(int testNumber) { | ||
| int expectedValues[ENTRIES_COUNT] = {0, 0, 0, 1, 0, 0}; | ||
| int actualValue; | ||
| int i; | ||
|
|
||
|
|
||
| printf("Testing is read only...\n"); | ||
| for (i = 0; i < ENTRIES_COUNT; i++) { | ||
| actualValue = isReadOnly(system[i]); | ||
| printf("Expected Value = %d; Actual Value = %d\n", expectedValues[i], actualValue); | ||
|
|
||
| } | ||
| } | ||
|
|
||
| void testIsVolumeLabel(int testNumber) { | ||
| int expectedValues[ENTRIES_COUNT] = {1, 0, 0, 0, 0, 0}; | ||
| int actualValue; | ||
| int i; | ||
|
|
||
| printf("Testing is volume label...\n"); | ||
| for (i = 0; i < ENTRIES_COUNT; i++) { | ||
| actualValue = isVolumeLabel(system[i]); | ||
| printf("Expected Value = %d; Actual Value = %d\n", expectedValues[i], actualValue); | ||
|
|
||
| } | ||
| } | ||
|
|
||
| void testIsLongName(int testNumber) { | ||
| int expectedValues[ENTRIES_COUNT] = {0, 0, 0, 0, 0, 1}; | ||
| int actualValue; | ||
| int i; | ||
|
|
||
| printf("Testing is long name...\n"); | ||
| for (i = 0; i < ENTRIES_COUNT; i++) { | ||
| actualValue = isLongName(system[i]); | ||
| printf("Expected Value = %d; Actual Value = %d\n", expectedValues[i], actualValue); | ||
| } | ||
| } | ||
|
|
||
| void testCheckFileExists(int testNumber) { | ||
| int directoryEntryAddress; | ||
|
|
||
| printf("Testing checkFileExists()...\n"); | ||
|
|
||
| if (testNumber == 1) { | ||
| printf("Running test 1...\n"); | ||
| directoryEntryAddress = checkFileExists(filePtr, thisBootSector, "FSINFO TXT", thisBootSector.rootClusterNum); | ||
| printf("Expected Value = 1049664; Actual Value = %d\n", directoryEntryAddress); | ||
| } | ||
| else if (testNumber == 2) { | ||
| printf("Running test 2...\n"); | ||
| directoryEntryAddress = checkFileExists(filePtr, thisBootSector, "DIR", thisBootSector.rootClusterNum); | ||
| printf("Expected Value = 1049920; Actual Value = %d\n", directoryEntryAddress); | ||
| } | ||
| else if (testNumber == 3) { | ||
| printf("Running test 3...\n"); | ||
| directoryEntryAddress = checkFileExists(filePtr, thisBootSector, ".ECRET TXT", thisBootSector.rootClusterNum); | ||
| printf("Expected Value = -1; Actual Value = %d\n", directoryEntryAddress); | ||
| } | ||
| else if (testNumber == 4) { | ||
| printf("Running test 4...\n"); | ||
| directoryEntryAddress = checkFileExists(filePtr, thisBootSector, "CHUCKLES", thisBootSector.rootClusterNum); | ||
| printf("Expected Value = -1; Actual Value = %d\n", directoryEntryAddress); | ||
| } | ||
| else if (testNumber == 5) { | ||
| printf("Running test 5...\n"); | ||
| directoryEntryAddress = checkFileExists(filePtr, thisBootSector, "POOPOOBA", thisBootSector.rootClusterNum); | ||
| printf("Expected Value = -1; Actual Value = %d\n", directoryEntryAddress); | ||
| } | ||
| } | ||
|
|
||
| void testGetFirstClusterOfEntry(int testNumber) { | ||
| int i; | ||
| int expectedValues[ENTRIES_COUNT] = {0, 131115, 0, 54, 0, 0}; | ||
| uint32_t actualValue; | ||
|
|
||
| printf("Testing getFirstClusterOfEntry()...\n"); | ||
| for (i = 0; i < ENTRIES_COUNT; i++) { | ||
| actualValue = getFirstClusterOfEntry(thisBootSector, system[i]); | ||
| printf("Expected Value = %d; Actual Value = %d\n", expectedValues[i], actualValue); | ||
| } | ||
| } | ||
|
|
||
| void testConvertToDateStruct(int testNumber) { | ||
| date thisDate; | ||
|
|
||
| printf("Testing convertToDateStruct()...\n"); | ||
| if (testNumber == 1) { | ||
| printf("Running test 1...\n"); | ||
| thisDate = convertToDateStruct(directoryEntry_3.createDate); | ||
| printf("Expected = 05-21-2016; Actual = %02d-%02d-%02d\n", thisDate.month, thisDate.day, thisDate.year); | ||
| } | ||
| else if (testNumber == 2) { | ||
| printf("Running test 2...\n"); | ||
| thisDate = convertToDateStruct(directoryEntry_4.createDate); | ||
| printf("Expected = 02-14-2001; Actual = %02d-%02d-%02d\n", thisDate.month, thisDate.day, thisDate.year); | ||
| } | ||
| } | ||
|
|
||
| void testConvertToTimeStruct(int testNumber) { | ||
| time thisTime; | ||
|
|
||
| printf("Testing convertToTimeStruct()... \n"); | ||
| if (testNumber == 1) { | ||
| printf("Running test 1...\n"); | ||
| thisTime = convertToTimeStruct(directoryEntry_3.createTime); | ||
| printf("Expected = 21:05:54; Actual = %02d:%02d:%02d\n", thisTime.hours, thisTime.minutes, thisTime.seconds); | ||
| } | ||
| else if (testNumber == 2) { | ||
| printf("Running test 2...\n"); | ||
| thisTime = convertToTimeStruct(directoryEntry_4.createTime); | ||
| printf("Expected = 05:59:58; Actual = %02d:%2d:%02d\n", thisTime.hours, thisTime.minutes, thisTime.seconds); | ||
| } | ||
| } |
| @@ -0,0 +1,129 @@ | ||
| #include <stdio.h> | ||
| #include <stdint.h> | ||
| #include "equations.h" | ||
| //#include "boot_sector.h" INHERITED FROM EQUATIONS | ||
|
|
||
| //////////////////////////////////////////////////////////////// | ||
| // GLOBAL VARIABLES //////////////////////////////////////////// | ||
| //////////////////////////////////////////////////////////////// | ||
| FILE* filePtr; | ||
| bootSector thisBootSector; | ||
|
|
||
| //////////////////////////////////////////////////////////////// | ||
| // FUNCTION DELCARATIONS /////////////////////////////////////// | ||
| //////////////////////////////////////////////////////////////// | ||
| void testGetRootDirectorySectors(int testNumber); | ||
| void testGetFirstDataSector(int testNumber); | ||
| void testGetFirstSectorOfCluster(int testNumber); | ||
| void testGetThisFATSectorNumber(int testNumber); | ||
| void testGetThisFATEntryOffset(int testNumber); | ||
| void testConvertSectorNumToBytes(int testNumber); | ||
| void testConvertClusterNumToBytes(int testNumber); | ||
|
|
||
| //////////////////////////////////////////////////////////////// | ||
| // MAIN PROGRAM //////////////////////////////////////////////// | ||
| //////////////////////////////////////////////////////////////// | ||
| int main(int argc, char** argv) { | ||
|
|
||
| // set up file pointer | ||
| if (argc != 2) { | ||
| printf("You entered an incorrect amount of arguments for this program. <USAGE: ./fat32_reader fat32.img>\n"); | ||
| return -1; | ||
| } | ||
|
|
||
| if ((filePtr = fopen(argv[1], "rb")) == 0) { | ||
| perror(argv[1]); | ||
| return -1; | ||
| } | ||
|
|
||
| // set up the boot sector | ||
| thisBootSector = setUpBootSector(filePtr); | ||
|
|
||
| // run the actual tests! | ||
| testGetRootDirectorySectors(1); | ||
| testGetFirstDataSector(1); | ||
| testGetFirstSectorOfCluster(1); | ||
| testGetThisFATSectorNumber(1); | ||
| testGetThisFATEntryOffset(1); | ||
| testConvertSectorNumToBytes(1); | ||
| testConvertClusterNumToBytes(1); | ||
| testConvertClusterNumToBytes(2); | ||
|
|
||
| return 0; | ||
| } | ||
|
|
||
| //////////////////////////////////////////////////////////////// | ||
| // FUNCTION DEFINITIONS //////////////////////////////////////// | ||
| //////////////////////////////////////////////////////////////// | ||
|
|
||
| // tests: getRootDirectorySectors() | ||
| // from: equations.c | ||
| void testGetRootDirectorySectors(int testNumber) { | ||
| uint32_t rootDirectorySectors; | ||
| printf("Testing getRootDirectorySectors()...\n"); | ||
| rootDirectorySectors = getRootDirectorySectors(thisBootSector); | ||
| printf("Expected Value = 0; Actual Value = %d\n", rootDirectorySectors); | ||
| } | ||
|
|
||
| // tests: getGetFirstDataSector() | ||
| // from: equations.void testGetFirstDataSector(int testNumber) { | ||
| void testGetFirstDataSector(int testNumber) { | ||
| uint32_t firstDataSectorNumber; | ||
| printf("Testing getFirstDataSector()...\n"); | ||
| firstDataSectorNumber = getFirstDataSector(thisBootSector); | ||
| printf("Expected Value = 2050; Actual Value = %d\n", firstDataSectorNumber); | ||
|
|
||
| } | ||
|
|
||
| // tests: getFirstSectorOfCluster() | ||
| // from: equations.c | ||
| void testGetFirstSectorOfCluster(int testNumber) { | ||
| uint32_t firstSectorOfCluster; | ||
| printf("Testing getFirstSectorOfCluster()...\n"); | ||
| firstSectorOfCluster = getFirstSectorOfCluster(thisBootSector, 4); | ||
| printf("Expected Value = 2052; Actual Value = %d\n", firstSectorOfCluster); | ||
| } | ||
|
|
||
| // tests: getThisFATSectorNumber() | ||
| // from: equations.c | ||
| void testGetThisFATSectorNumber(int testNumber) { | ||
| uint32_t thisFATSectorNumber; | ||
| printf("Testing getThisFATSectorNumber()...\n"); | ||
| thisFATSectorNumber = getThisFATSectorNumber(thisBootSector, 150); | ||
| printf("Expected Value = 33; Actual Value = %d\n", thisFATSectorNumber); | ||
|
|
||
| } | ||
|
|
||
| // tests: getThisFATEntryOffset() | ||
| // from: equations.c | ||
| void testGetThisFATEntryOffset(int testNumber) { | ||
| uint16_t thisFATEntryOffset; | ||
| printf("Testing getThisFATEntryOffset()...\n"); | ||
| thisFATEntryOffset = getThisFATEntryOffset(thisBootSector, 150); | ||
| printf("Expected Value = 88; Actual Value = %d\n", thisFATEntryOffset); | ||
|
|
||
| } | ||
|
|
||
| // tests: ConvertSectorNumToBytes() | ||
| // from: equations.c | ||
| void testConvertSectorNumToBytes(int testNumber) { | ||
| uint64_t sectorNumberInBytes; | ||
| printf("Testing convertSectorNumToBytes()...\n"); | ||
| sectorNumberInBytes = convertSectorNumToBytes(thisBootSector, 45); | ||
| printf("Expected Value = 23040; Actual Value = %d\n", sectorNumberInBytes); | ||
|
|
||
| } | ||
|
|
||
| void testConvertClusterNumToBytes(int testNumber) { | ||
| uint64_t clusterNumberInBytes; | ||
|
|
||
| printf("Testing convertClusterNumToBytes()...\n"); | ||
| if (testNumber == 1) { | ||
| clusterNumberInBytes = convertClusterNumToBytes(thisBootSector, 403); | ||
| printf("Expected Value = 1254912; Actual Value = %d\n", clusterNumberInBytes); | ||
| } | ||
| else if (testNumber == 2) { | ||
| clusterNumberInBytes = convertClusterNumToBytes(thisBootSector, 2); | ||
| printf("Expected Value = 1049600; Actual Value = %d\n", clusterNumberInBytes); | ||
| } | ||
| } |
| @@ -0,0 +1,77 @@ | ||
| /////////////////////////////////////////////////////////////////////////// | ||
| // INCLUDES /////////////////////////////////////////////////////////////// | ||
| /////////////////////////////////////////////////////////////////////////// | ||
| #include "fat_entries.h" | ||
|
|
||
| /////////////////////////////////////////////////////////////////////////// | ||
| // GLOBAL VARIABLES /////////////////////////////////////////////////////// | ||
| /////////////////////////////////////////////////////////////////////////// | ||
| FILE* filePtr; | ||
| bootSector thisBootSector; | ||
|
|
||
| /////////////////////////////////////////////////////////////////////////// | ||
| // FUNCTION DECLARATIONS ////////////////////////////////////////////////// | ||
| /////////////////////////////////////////////////////////////////////////// | ||
|
|
||
| // In: thisBootSector (bootSector (struct)), clusterNumber (uint32_t) | ||
| // Out: thisFatEntry (fatEntry (struct)) | ||
| // Purpose: to create a fatEntry struct for convenienve in moving through clusters and to abstract cluster chain logic | ||
| // Notes: | ||
| void testGetFATEntry(int testNumber); | ||
|
|
||
| /////////////////////////////////////////////////////////////////////////// | ||
| // MAIN PROGRAM /////////////////////////////////////////////////////////// | ||
| /////////////////////////////////////////////////////////////////////////// | ||
| int main(int argc, char** argv) { | ||
|
|
||
| if (argc != 2) { | ||
| printf("You entered an incorrect amount of arguments for this program. <USAGE: ./fat32_reader fat32.img>\n"); | ||
| return -1; | ||
| } | ||
|
|
||
| if ((filePtr = fopen(argv[1], "rb")) == 0) { | ||
| perror(argv[1]); | ||
| return -1; | ||
| } | ||
|
|
||
| thisBootSector = setUpBootSector(filePtr); | ||
|
|
||
| testGetFATEntry(1); | ||
| testGetFATEntry(2); | ||
| testGetFATEntry(3); | ||
| testGetFATEntry(4); | ||
|
|
||
| return 0; | ||
| } | ||
|
|
||
| /////////////////////////////////////////////////////////////////////////// | ||
| // FUNCTION DEFINITONS //////////////////////////////////////////////////// | ||
| /////////////////////////////////////////////////////////////////////////// | ||
| void testGetFATEntry(int testNumber) { | ||
| FATEntry thisFATEntry; | ||
|
|
||
|
|
||
| printf("Testing getFATEntry()...\n"); | ||
|
|
||
| if (testNumber == 1) { | ||
| printf("Running test 1...\n"); | ||
| thisFATEntry = getFATEntry(filePtr, thisBootSector, 4); | ||
| printf("Cluster Number: 4 | Expected = 5; Actual = %d\n", thisFATEntry.nextClusterNumber); | ||
| } | ||
| else if (testNumber == 2) { | ||
| printf("Running test 2...\n"); | ||
| thisFATEntry = getFATEntry(filePtr, thisBootSector, 13); | ||
| printf("Cluster Number: 13 | Expected = 14; Actual = %d\n", thisFATEntry.nextClusterNumber); | ||
| } | ||
| else if (testNumber == 3 ) { | ||
| printf("Running test 3...\n"); | ||
| thisFATEntry = getFATEntry(filePtr, thisBootSector, 514); | ||
| printf("Cluster Number: 514 | Expected = 515; Actual = %d\n", thisFATEntry.nextClusterNumber); | ||
| } | ||
| else if (testNumber == 4) { | ||
| printf("Running test 4...\n"); | ||
| thisFATEntry = getFATEntry(filePtr, thisBootSector, 2); | ||
| printf("Cluster Number: 2 | Expected = %d; Actual = %d\n", EOC, thisFATEntry.nextClusterNumber); | ||
| } | ||
| } | ||
|
|