Task 551: .PIT File Format
Task 551: .PIT File Format
.PIT File Format Specifications
The .PIT file format is used by Samsung for the Partition Information Table in Android devices, primarily for defining the layout of partitions on the device's internal storage (eMMC or UFS). It is a binary format flashed via tools like Odin or Heimdall to configure or repair the partition table. The file starts with a 28-byte header, followed by a variable number of 132-byte partition entries. All integers are little-endian.
- Magic Number: 4 bytes (uint32), always 0x12349876 (hex) or 3054539046 (decimal).
- Entry Count: 4 bytes (uint32), number of partition entries.
- Unknown1: 4 bytes (uint32), purpose unknown (often 0xFFFFFFFF or device-specific).
- Unknown2: 4 bytes (uint32), purpose unknown (often 0xFFFFFFFF or device-specific).
- Unknown3: 2 bytes (uint16), purpose unknown (often 0).
- Unknown4: 2 bytes (uint16), purpose unknown (often 0).
- Unknown5: 2 bytes (uint16), purpose unknown (often 0).
- Unknown6: 2 bytes (uint16), purpose unknown (often 0).
- Unknown7: 2 bytes (uint16), purpose unknown (often 0).
- Unknown8: 2 bytes (uint16), purpose unknown (often 0, padding?).
Each partition entry (132 bytes) follows the header sequentially:
- Binary Type: 4 bytes (uint32), type of binary (0 = Application Processor, 1 = Communication Processor).
- Device Type: 4 bytes (uint32), storage type (0 = OneNAND, 1 = File/FAT, 2 = MMC, 3 = All).
- Identifier: 4 bytes (uint32), unique partition ID (e.g., 1 for EFS, incremental).
- Attributes: 4 bytes (uint32), flags (1 = Read-Only, 2 = Read-Write, 4 = STL).
- Update Attributes: 4 bytes (uint32), update flags (1 = FOTA, 2 = Secure).
- Block Size or Offset: 4 bytes (uint32), starting block offset (in 512-byte sectors).
- Block Count: 4 bytes (uint32), number of blocks (size in sectors).
- File Offset: 4 bytes (uint32), unused/reserved (often 0).
- File Size: 4 bytes (uint32), unused/reserved (often 0).
- Partition Name: 32 bytes (null-terminated string), e.g., "EFS", "FACTORYFS".
- Flash File Name: 32 bytes (null-terminated string), filename for flashing, e.g., "efs.rfs".
- FOTA File Name: 32 bytes (null-terminated string), FOTA update filename (often empty).
The file ends after the last entry; no footer. Block sizes refer to the device's storage geometry (typically 512 bytes per block). This format is intrinsic to Samsung's file system partitioning for Android devices, defining how storage is divided for system, data, cache, etc.
List of Properties Intrinsic to the File Format:
- Magic Number (fixed identifier for validity).
- Entry Count (number of partitions defined).
- Unknown1 (reserved or device-specific metadata).
- Unknown2 (reserved or device-specific metadata).
- Unknown3 (reserved short metadata).
- Unknown4 (reserved short metadata).
- Unknown5 (reserved short metadata).
- Unknown6 (reserved short metadata).
- Unknown7 (reserved short metadata).
- Unknown8 (reserved short metadata).
- For each partition: Binary Type, Device Type, Identifier, Attributes, Update Attributes, Block Size/Offset, Block Count, File Offset, File Size, Partition Name, Flash File Name, FOTA File Name.
Two Direct Download Links for .PIT Files:
- https://androidfilehost.com/?fid=95916177934550098 (SM-T800.pit for Samsung Galaxy Tab S 10.5 Wi-Fi 16GB USA).
- https://www.dropbox.com/s/35sp8pyudjxwibi/SM-T700.pit?dl=1 (SM-T700.pit for Samsung Galaxy Tab S 8.4 Wi-Fi 16GB; dl=1 for direct download).
HTML/JavaScript for Drag-and-Drop .PIT File Dumper (Embeddable in a Ghost Blog Post):
Python Class for .PIT Handling:
import struct
import sys
class PitFile:
def __init__(self, filename):
self.filename = filename
self.header = {}
self.entries = []
def read(self):
with open(self.filename, 'rb') as f:
data = f.read()
offset = 0
self.header['magic'], = struct.unpack('<I', data[offset:offset+4]); offset += 4
if self.header['magic'] != 0x12349876:
raise ValueError("Invalid .PIT magic")
self.header['entry_count'], = struct.unpack('<I', data[offset:offset+4]); offset += 4
self.header['unknown1'], = struct.unpack('<I', data[offset:offset+4]); offset += 4
self.header['unknown2'], = struct.unpack('<I', data[offset:offset+4]); offset += 4
self.header['unknown3'], = struct.unpack('<H', data[offset:offset+2]); offset += 2
self.header['unknown4'], = struct.unpack('<H', data[offset:offset+2]); offset += 2
self.header['unknown5'], = struct.unpack('<H', data[offset:offset+2]); offset += 2
self.header['unknown6'], = struct.unpack('<H', data[offset:offset+2]); offset += 2
self.header['unknown7'], = struct.unpack('<H', data[offset:offset+2]); offset += 2
self.header['unknown8'], = struct.unpack('<H', data[offset:offset+2]); offset += 2
for _ in range(self.header['entry_count']):
entry = {}
entry['binary_type'], = struct.unpack('<I', data[offset:offset+4]); offset += 4
entry['device_type'], = struct.unpack('<I', data[offset:offset+4]); offset += 4
entry['identifier'], = struct.unpack('<I', data[offset:offset+4]); offset += 4
entry['attributes'], = struct.unpack('<I', data[offset:offset+4]); offset += 4
entry['update_attributes'], = struct.unpack('<I', data[offset:offset+4]); offset += 4
entry['block_size_or_offset'], = struct.unpack('<I', data[offset:offset+4]); offset += 4
entry['block_count'], = struct.unpack('<I', data[offset:offset+4]); offset += 4
entry['file_offset'], = struct.unpack('<I', data[offset:offset+4]); offset += 4
entry['file_size'], = struct.unpack('<I', data[offset:offset+4]); offset += 4
entry['partition_name'] = data[offset:offset+32].decode('utf-8').rstrip('\x00'); offset += 32
entry['flash_file_name'] = data[offset:offset+32].decode('utf-8').rstrip('\x00'); offset += 32
entry['fota_file_name'] = data[offset:offset+32].decode('utf-8').rstrip('\x00'); offset += 32
self.entries.append(entry)
def print_properties(self):
print("Header:")
for k, v in self.header.items():
print(f" {k}: {v}")
print("\nPartitions:")
for i, entry in enumerate(self.entries):
print(f"Partition {i+1}:")
for k, v in entry.items():
print(f" {k}: {v}")
def write(self, output_filename):
with open(output_filename, 'wb') as f:
f.write(struct.pack('<I', self.header['magic']))
f.write(struct.pack('<I', self.header['entry_count']))
f.write(struct.pack('<I', self.header['unknown1']))
f.write(struct.pack('<I', self.header['unknown2']))
f.write(struct.pack('<H', self.header['unknown3']))
f.write(struct.pack('<H', self.header['unknown4']))
f.write(struct.pack('<H', self.header['unknown5']))
f.write(struct.pack('<H', self.header['unknown6']))
f.write(struct.pack('<H', self.header['unknown7']))
f.write(struct.pack('<H', self.header['unknown8']))
for entry in self.entries:
f.write(struct.pack('<I', entry['binary_type']))
f.write(struct.pack('<I', entry['device_type']))
f.write(struct.pack('<I', entry['identifier']))
f.write(struct.pack('<I', entry['attributes']))
f.write(struct.pack('<I', entry['update_attributes']))
f.write(struct.pack('<I', entry['block_size_or_offset']))
f.write(struct.pack('<I', entry['block_count']))
f.write(struct.pack('<I', entry['file_offset']))
f.write(struct.pack('<I', entry['file_size']))
f.write(entry['partition_name'].encode('utf-8').ljust(32, b'\x00'))
f.write(entry['flash_file_name'].encode('utf-8').ljust(32, b'\x00'))
f.write(entry['fota_file_name'].encode('utf-8').ljust(32, b'\x00'))
# Example usage: pit = PitFile('example.pit'); pit.read(); pit.print_properties(); pit.write('output.pit')
Java Class for .PIT Handling:
import java.io.*;
import java.nio.*;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class PitFile {
private String filename;
private Map<String, Integer> header = new HashMap<>();
private List<Map<String, Object>> entries = new ArrayList<>();
public PitFile(String filename) {
this.filename = filename;
}
public void read() throws IOException {
try (RandomAccessFile raf = new RandomAccessFile(filename, "r")) {
ByteBuffer buffer = ByteBuffer.allocate((int) raf.length()).order(ByteOrder.LITTLE_ENDIAN);
raf.getChannel().read(buffer);
buffer.flip();
header.put("magic", buffer.getInt());
if (header.get("magic") != 0x12349876) {
throw new IllegalArgumentException("Invalid .PIT magic");
}
header.put("entry_count", buffer.getInt());
header.put("unknown1", buffer.getInt());
header.put("unknown2", buffer.getInt());
header.put("unknown3", (int) buffer.getShort());
header.put("unknown4", (int) buffer.getShort());
header.put("unknown5", (int) buffer.getShort());
header.put("unknown6", (int) buffer.getShort());
header.put("unknown7", (int) buffer.getShort());
header.put("unknown8", (int) buffer.getShort());
for (int i = 0; i < header.get("entry_count"); i++) {
Map<String, Object> entry = new HashMap<>();
entry.put("binary_type", buffer.getInt());
entry.put("device_type", buffer.getInt());
entry.put("identifier", buffer.getInt());
entry.put("attributes", buffer.getInt());
entry.put("update_attributes", buffer.getInt());
entry.put("block_size_or_offset", buffer.getInt());
entry.put("block_count", buffer.getInt());
entry.put("file_offset", buffer.getInt());
entry.put("file_size", buffer.getInt());
byte[] nameBytes = new byte[32]; buffer.get(nameBytes);
entry.put("partition_name", new String(nameBytes, StandardCharsets.UTF_8).trim());
byte[] flashBytes = new byte[32]; buffer.get(flashBytes);
entry.put("flash_file_name", new String(flashBytes, StandardCharsets.UTF_8).trim());
byte[] fotaBytes = new byte[32]; buffer.get(fotaBytes);
entry.put("fota_file_name", new String(fotaBytes, StandardCharsets.UTF_8).trim());
entries.add(entry);
}
}
}
public void printProperties() {
System.out.println("Header:");
header.forEach((k, v) -> System.out.println(" " + k + ": " + v));
System.out.println("\nPartitions:");
for (int i = 0; i < entries.size(); i++) {
System.out.println("Partition " + (i + 1) + ":");
entries.get(i).forEach((k, v) -> System.out.println(" " + k + ": " + v));
}
}
public void write(String outputFilename) throws IOException {
try (RandomAccessFile raf = new RandomAccessFile(outputFilename, "rw")) {
ByteBuffer buffer = ByteBuffer.allocate(28 + entries.size() * 132).order(ByteOrder.LITTLE_ENDIAN);
buffer.putInt(header.get("magic"));
buffer.putInt(header.get("entry_count"));
buffer.putInt(header.get("unknown1"));
buffer.putInt(header.get("unknown2"));
buffer.putShort(header.get("unknown3").shortValue());
buffer.putShort(header.get("unknown4").shortValue());
buffer.putShort(header.get("unknown5").shortValue());
buffer.putShort(header.get("unknown6").shortValue());
buffer.putShort(header.get("unknown7").shortValue());
buffer.putShort(header.get("unknown8").shortValue());
for (Map<String, Object> entry : entries) {
buffer.putInt((Integer) entry.get("binary_type"));
buffer.putInt((Integer) entry.get("device_type"));
buffer.putInt((Integer) entry.get("identifier"));
buffer.putInt((Integer) entry.get("attributes"));
buffer.putInt((Integer) entry.get("update_attributes"));
buffer.putInt((Integer) entry.get("block_size_or_offset"));
buffer.putInt((Integer) entry.get("block_count"));
buffer.putInt((Integer) entry.get("file_offset"));
buffer.putInt((Integer) entry.get("file_size"));
buffer.put(((String) entry.get("partition_name")).getBytes(StandardCharsets.UTF_8));
buffer.position(buffer.position() + (32 - ((String) entry.get("partition_name")).length()));
buffer.put(((String) entry.get("flash_file_name")).getBytes(StandardCharsets.UTF_8));
buffer.position(buffer.position() + (32 - ((String) entry.get("flash_file_name")).length()));
buffer.put(((String) entry.get("fota_file_name")).getBytes(StandardCharsets.UTF_8));
buffer.position(buffer.position() + (32 - ((String) entry.get("fota_file_name")).length()));
}
buffer.flip();
raf.getChannel().write(buffer);
}
}
// Example usage: PitFile pit = new PitFile("example.pit"); pit.read(); pit.printProperties(); pit.write("output.pit");
}
JavaScript Class for .PIT Handling (Node.js, uses fs module):
const fs = require('fs');
class PitFile {
constructor(filename) {
this.filename = filename;
this.header = {};
this.entries = [];
}
read() {
const data = fs.readFileSync(this.filename);
const view = new DataView(data.buffer);
let offset = 0;
this.header.magic = view.getUint32(offset, true); offset += 4;
if (this.header.magic !== 0x12349876) {
throw new Error('Invalid .PIT magic');
}
this.header.entry_count = view.getUint32(offset, true); offset += 4;
this.header.unknown1 = view.getUint32(offset, true); offset += 4;
this.header.unknown2 = view.getUint32(offset, true); offset += 4;
this.header.unknown3 = view.getUint16(offset, true); offset += 2;
this.header.unknown4 = view.getUint16(offset, true); offset += 2;
this.header.unknown5 = view.getUint16(offset, true); offset += 2;
this.header.unknown6 = view.getUint16(offset, true); offset += 2;
this.header.unknown7 = view.getUint16(offset, true); offset += 2;
this.header.unknown8 = view.getUint16(offset, true); offset += 2;
for (let i = 0; i < this.header.entry_count; i++) {
const entry = {};
entry.binary_type = view.getUint32(offset, true); offset += 4;
entry.device_type = view.getUint32(offset, true); offset += 4;
entry.identifier = view.getUint32(offset, true); offset += 4;
entry.attributes = view.getUint32(offset, true); offset += 4;
entry.update_attributes = view.getUint32(offset, true); offset += 4;
entry.block_size_or_offset = view.getUint32(offset, true); offset += 4;
entry.block_count = view.getUint32(offset, true); offset += 4;
entry.file_offset = view.getUint32(offset, true); offset += 4;
entry.file_size = view.getUint32(offset, true); offset += 4;
entry.partition_name = ''; for (let j = 0; j < 32; j++) { const char = view.getUint8(offset); if (char === 0) break; entry.partition_name += String.fromCharCode(char); offset++; } offset += 32 - entry.partition_name.length;
entry.flash_file_name = ''; for (let j = 0; j < 32; j++) { const char = view.getUint8(offset); if (char === 0) break; entry.flash_file_name += String.fromCharCode(char); offset++; } offset += 32 - entry.flash_file_name.length;
entry.fota_file_name = ''; for (let j = 0; j < 32; j++) { const char = view.getUint8(offset); if (char === 0) break; entry.fota_file_name += String.fromCharCode(char); offset++; } offset += 32 - entry.fota_file_name.length;
this.entries.push(entry);
}
}
printProperties() {
console.log('Header:');
for (const [key, value] of Object.entries(this.header)) {
console.log(` ${key}: ${value}`);
}
console.log('\nPartitions:');
this.entries.forEach((entry, i) => {
console.log(`Partition ${i + 1}:`);
for (const [key, value] of Object.entries(entry)) {
console.log(` ${key}: ${value}`);
}
});
}
write(outputFilename) {
const buffer = new ArrayBuffer(28 + this.entries.length * 132);
const view = new DataView(buffer);
let offset = 0;
view.setUint32(offset, this.header.magic, true); offset += 4;
view.setUint32(offset, this.header.entry_count, true); offset += 4;
view.setUint32(offset, this.header.unknown1, true); offset += 4;
view.setUint32(offset, this.header.unknown2, true); offset += 4;
view.setUint16(offset, this.header.unknown3, true); offset += 2;
view.setUint16(offset, this.header.unknown4, true); offset += 2;
view.setUint16(offset, this.header.unknown5, true); offset += 2;
view.setUint16(offset, this.header.unknown6, true); offset += 2;
view.setUint16(offset, this.header.unknown7, true); offset += 2;
view.setUint16(offset, this.header.unknown8, true); offset += 2;
this.entries.forEach(entry => {
view.setUint32(offset, entry.binary_type, true); offset += 4;
view.setUint32(offset, entry.device_type, true); offset += 4;
view.setUint32(offset, entry.identifier, true); offset += 4;
view.setUint32(offset, entry.attributes, true); offset += 4;
view.setUint32(offset, entry.update_attributes, true); offset += 4;
view.setUint32(offset, entry.block_size_or_offset, true); offset += 4;
view.setUint32(offset, entry.block_count, true); offset += 4;
view.setUint32(offset, entry.file_offset, true); offset += 4;
view.setUint32(offset, entry.file_size, true); offset += 4;
for (let char of entry.partition_name) { view.setUint8(offset, char.charCodeAt(0)); offset++; } offset += 32 - entry.partition_name.length;
for (let char of entry.flash_file_name) { view.setUint8(offset, char.charCodeAt(0)); offset++; } offset += 32 - entry.flash_file_name.length;
for (let char of entry.fota_file_name) { view.setUint8(offset, char.charCodeAt(0)); offset++; } offset += 32 - entry.fota_file_name.length;
});
fs.writeFileSync(outputFilename, new Uint8Array(buffer));
}
}
// Example usage: const pit = new PitFile('example.pit'); pit.read(); pit.printProperties(); pit.write('output.pit');
C Struct and Functions for .PIT Handling (Not a "class" since C lacks classes; uses struct and functions):
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
typedef struct {
uint32_t magic;
uint32_t entry_count;
uint32_t unknown1;
uint32_t unknown2;
uint16_t unknown3;
uint16_t unknown4;
uint16_t unknown5;
uint16_t unknown6;
uint16_t unknown7;
uint16_t unknown8;
} pit_header_t;
typedef struct {
uint32_t binary_type;
uint32_t device_type;
uint32_t identifier;
uint32_t attributes;
uint32_t update_attributes;
uint32_t block_size_or_offset;
uint32_t block_count;
uint32_t file_offset;
uint32_t file_size;
char partition_name[32];
char flash_file_name[32];
char fota_file_name[32];
} pit_entry_t;
typedef struct {
pit_header_t header;
pit_entry_t *entries;
} pit_file_t;
void pit_read(const char *filename, pit_file_t *pit) {
FILE *fp = fopen(filename, "rb");
if (!fp) {
perror("Failed to open file");
exit(1);
}
fseek(fp, 0, SEEK_END);
long size = ftell(fp);
fseek(fp, 0, SEEK_SET);
uint8_t *data = malloc(size);
fread(data, 1, size, fp);
fclose(fp);
uint8_t *ptr = data;
memcpy(&pit->header, ptr, sizeof(pit_header_t));
ptr += sizeof(pit_header_t);
if (pit->header.magic != 0x12349876) {
fprintf(stderr, "Invalid .PIT magic\n");
free(data);
exit(1);
}
pit->entries = malloc(pit->header.entry_count * sizeof(pit_entry_t));
memcpy(pit->entries, ptr, pit->header.entry_count * sizeof(pit_entry_t));
free(data);
}
void pit_print_properties(const pit_file_t *pit) {
printf("Header:\n");
printf(" magic: 0x%x\n", pit->header.magic);
printf(" entry_count: %u\n", pit->header.entry_count);
printf(" unknown1: %u\n", pit->header.unknown1);
printf(" unknown2: %u\n", pit->header.unknown2);
printf(" unknown3: %u\n", pit->header.unknown3);
printf(" unknown4: %u\n", pit->header.unknown4);
printf(" unknown5: %u\n", pit->header.unknown5);
printf(" unknown6: %u\n", pit->header.unknown6);
printf(" unknown7: %u\n", pit->header.unknown7);
printf(" unknown8: %u\n", pit->header.unknown8);
printf("\nPartitions:\n");
for (uint32_t i = 0; i < pit->header.entry_count; i++) {
pit_entry_t *e = &pit->entries[i];
printf("Partition %u:\n", i + 1);
printf(" binary_type: %u\n", e->binary_type);
printf(" device_type: %u\n", e->device_type);
printf(" identifier: %u\n", e->identifier);
printf(" attributes: %u\n", e->attributes);
printf(" update_attributes: %u\n", e->update_attributes);
printf(" block_size_or_offset: %u\n", e->block_size_or_offset);
printf(" block_count: %u\n", e->block_count);
printf(" file_offset: %u\n", e->file_offset);
printf(" file_size: %u\n", e->file_size);
printf(" partition_name: %s\n", e->partition_name);
printf(" flash_file_name: %s\n", e->flash_file_name);
printf(" fota_file_name: %s\n", e->fota_file_name);
}
}
void pit_write(const char *output_filename, const pit_file_t *pit) {
FILE *fp = fopen(output_filename, "wb");
if (!fp) {
perror("Failed to open output file");
exit(1);
}
fwrite(&pit->header, sizeof(pit_header_t), 1, fp);
fwrite(pit->entries, sizeof(pit_entry_t), pit->header.entry_count, fp);
fclose(fp);
}
void pit_free(pit_file_t *pit) {
free(pit->entries);
}
// Example usage: int main() { pit_file_t pit; pit_read("example.pit", &pit); pit_print_properties(&pit); pit_write("output.pit", &pit); pit_free(&pit); return 0; }