Skip to content

Instantly share code, notes, and snippets.

@aadityabhatia
Created February 21, 2017 22:53
Show Gist options
  • Select an option

  • Save aadityabhatia/544fdcd5c83ffd7e4ff67b8b5cfea641 to your computer and use it in GitHub Desktop.

Select an option

Save aadityabhatia/544fdcd5c83ffd7e4ff67b8b5cfea641 to your computer and use it in GitHub Desktop.
node library for analyzing FAT16 filesystems
fs = require 'fs'
fatReader = require './fatReader'
fd = fs.openSync 'fatFilesystem.fat', 'r'
fat = fatReader.getFS(fd)
fatReader.log fat
console.log "\nReading root directory"
dirEntries = fatReader.dirRoot fat
for entry in dirEntries
location = fatReader.getAddress fat, entry.cluster
hex = "0x" + ("00000000" + location.toString(16)).substr(-8)
console.log hex, entry.name, "Size: #{entry.size}, Directory: #{entry.directory}"
firstDir = dirEntries[0]
address = fatReader.getAddress fat, firstDir.cluster
console.log "\nReading #{firstDir.name} at cluster #{firstDir.cluster}, address #{address.toString(16)}"
dirEntries = fatReader.dir fat, location
for entry in dirEntries
location = fatReader.getAddress fat, entry.cluster
hex = "0x" + ("00000000" + location.toString(16)).substr(-8)
console.log hex, entry.name, "Size: #{entry.size}, Directory: #{entry.directory}"
exports = module.exports = {}
fs = require 'fs'
exports.getFS = (fd) ->
fat = {fd: fd}
buffer = Buffer.alloc 64
fs.readSync fd, buffer, 0, 64, 0
fat.bytesPerSector = buffer.readUInt16LE 0xB
fat.sectorsPerCluster = buffer.readUInt8 0xD
fat.reservedSectors = buffer.readUInt16LE 0xE
fat.numFATs = buffer.readUInt8 0x10
fat.numRootEntries = buffer.readUInt16LE 0x11
fat.totalSectors = buffer.readUInt16LE 0x13
if fat.totalSectors is 0 then fat.totalSectors = buffer.readUInt32LE 0x20
fat.sectorsPerFAT = buffer.readUInt16LE 0x16
fat.volumeLabel = buffer.toString('ascii', 0x2B, 0x36)
fat.rootDirOffset = (fat.reservedSectors + fat.numFATs * fat.sectorsPerFAT) * fat.bytesPerSector
fat.sectorsRootDir = Math.floor(((fat.numRootEntries * 32) + fat.bytesPerSector - 1) / fat.bytesPerSector)
fat.dataSectors = fat.totalSectors - (fat.reservedSectors + (fat.numFATs * fat.sectorsPerFAT) + fat.sectorsRootDir)
fat.totalClusters = fat.dataSectors / fat.sectorsPerCluster
fat
exports.getAddress = (fat, cluster) ->
offsetBytes = (cluster - 2) * fat.bytesPerSector * fat.sectorsPerCluster
fat.rootDirOffset + (fat.numRootEntries * 32) + offsetBytes
exports.getCluster = (fat, location) ->
offsetBytes = location - fat.rootDirOffset - (fat.numRootEntries * 32)
cluster = offsetBytes / fat.bytesPerSector * fat.sectorsPerCluster
cluster += 2
exports.dirRoot = (fat) ->
exports.dir fat, fat.rootDirOffset, fat.numRootEntries
exports.dir = (fat, location, maxEntries = 0) ->
if not maxEntries
maxEntries = fat.bytesPerSector * fat.sectorsPerCluster / 32
dirEntries = []
dirBuffer = Buffer.alloc 32
for i in [0..maxEntries-1]
fs.readSync(fat.fd, dirBuffer, 0, 32, location + i*32)
if dirBuffer.readUInt8(0x0) is 0 then break
itemType = dirBuffer.readUInt8(0xB)
if itemType is 0xF then continue
name = dirBuffer.toString('ascii', 0, 8).trim()
ext = dirBuffer.toString('ascii', 8, 11).trim()
directory = (itemType & 0x10) isnt 0
name += "." + ext if ext and not directory
dirEntries.push
name: name
directory: directory
size: dirBuffer.readUInt32LE(0x1C)
cluster: dirBuffer.readUInt16LE(0x1A)
dirEntries
exports.log = (fat) ->
console.log "Volumne Label:", fat.volumeLabel
console.log "Bytes per sector:", fat.bytesPerSector
console.log "Sectors per cluster:", fat.sectorsPerCluster
console.log "Reserved sectors:", fat.reservedSectors
console.log "Total sectors:", fat.totalSectors
console.log "Total clusters:", fat.totalClusters
console.log "Number of FATs:", fat.numFATs
console.log "Sectors per FAT:", fat.sectorsPerFAT, "sectors"
console.log "Root offset = ", fat.rootDirOffset.toString(16)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment