PFS
Jump to navigation
Jump to search
PFS (Playstation File System) is the file system used by (at least) downloadable content and games on the PS4. It is loosely based on the UFS (Unix File System) used in FreeBSD. PFS typically uses a 64kB block size, although the block size is configurable and specified in the file system header.
Structure
There are four main sections in a Playstation File System:
- Header (superblock)
- Inode blocks
- Directory blocks
- Data blocks
Header/Superblock
Offset | Value | Size | Notes |
---|---|---|---|
0x00 | version | 0x8 | Should be 1 |
0x08 | magic | 0x8 | Should be 20130315 |
0x10 | id | 0x8 | |
0x18 | fmode | 0x1 | |
0x19 | clean | 0x1 | |
0x1A | ronly | 0x1 | If 1, this is a readonly filesystem |
0x1B | rsv | 0x1 | |
0x1C | mode | 0x2 | |
0x1E | unknown | 0x2 | |
0x20 | blocksz | 0x4 | The size of each block in the filesystem. |
0x24 | nbackup | 0x4 | |
0x28 | nblock | 0x8 | |
0x30 | ndinode | 0x8 | Number of inodes in the inode blocks |
0x38 | ndblock | 0x8 | Number of data blocks |
0x40 | ndinodeblock | 0x8 | Number of inode blocks |
0x48 | superroot_ino | 0x8 |
typedef struct {
int64 version;
int64 magic;
int32 id[2];
char fmode;
char clean;
char ronly;
char rsv;
int16 mode;
int16 unk1;
int32 blocksz;
int32 nbackup;
int64 nblock;
int64 ndinode;
int64 ndblock;
int64 ndinodeblock;
int64 superroot_ino;
} PFS_HDR;
Inodes
Inode table starts at the second block and continues for ndinodeblock blocks.
Offset | Value | Size | Notes |
---|---|---|---|
0x00 | mode | 0x2 | Inode mode (bitwise OR of flags; file=0x8000, directory=0x4000) |
0x02 | nlink | 0x2 | |
0x04 | flags | 0x4 | |
0x08 | size | 0x8 | |
0x10 | unknown | 0x38 | |
0x48 | uid | 0x4 | |
0x4C | gid | 0x4 | |
0x50 | unknown | 0x10 | |
0x60 | blocks | 0x4 | Number of blocks occupied |
0x64 | db | 0x30 | Direct blocks |
0x94 | ib | 0x14 | Indirect blocks |
typedef struct {
uint16 mode;
uint16 nlink;
uint16 flags[2];
uint64 size;
char unk1[56];
uint32 uid;
uint32 gid;
uint64 unk2[2];
uint32 blocks;
int32 db[12];
int32 ib[5];
} di_d32;
Dirents
Dirents are 8-byte aligned. The entsize value will say the total length of this dirent. There is typically padding after name which can just be skipped.
Offset | Value | Size | Notes |
---|---|---|---|
0x00 | ino | 0x4 | Inode index |
0x04 | type | 0x4 | Type of entry. 2=file, 3=directory |
0x08 | namelen | 0x4 | Length of filename (add 1 for 0-terminator) |
0x10 | name | namelen + 1 | Filename and 0-terminator |
0x11 + namelen | padding | variable | Padding so this structure is exactly entsize bytes. |
typedef struct {
int32 ino;
int32 type;
int32 namelen;
int32 entsize;
char name[namelen+1];
} dirent;
Tools
- GameArchives/ArchiveExplorer library/tool that supports opening and extracting from PFS images