|
| 1 | +# References: |
| 2 | +# - https://github.com/digiampietro/lzma-uncramfs/blob/master/cramfs_fs.h |
| 3 | +# - https://github.com/npitre/cramfs-tools/blob/master/linux/cramfs_fs.h |
| 4 | + |
| 5 | +from __future__ import annotations |
| 6 | + |
| 7 | +from dissect.cstruct import cstruct |
| 8 | + |
| 9 | +cramfs_def = """ |
| 10 | +#define CRAMFS_MAGIC 0x28cd3d45 /* some random number */ |
| 11 | +#define CRAMFS_SIGNATURE b"Compressed ROMFS" |
| 12 | +#define CRAMFS_BLOCK_SIZE 4096 |
| 13 | +
|
| 14 | +/* |
| 15 | + * Width of various bitfields in struct cramfs_inode. |
| 16 | + * Primarily used to generate warnings in mkcramfs. |
| 17 | + */ |
| 18 | +#define CRAMFS_MODE_WIDTH 16 |
| 19 | +#define CRAMFS_UID_WIDTH 16 |
| 20 | +#define CRAMFS_GID_WIDTH 8 |
| 21 | +#define CRAMFS_NAMELEN_WIDTH 6 |
| 22 | +#define CRAMFS_OFFSET_WIDTH 26 |
| 23 | +
|
| 24 | +/* |
| 25 | + * Since inode.namelen is a unsigned 6-bit number, the maximum cramfs |
| 26 | + * path length is 63 << 2 = 252. |
| 27 | + */ |
| 28 | +#define CRAMFS_MAXPATHLEN (((1 << CRAMFS_NAMELEN_WIDTH) - 1) << 2) |
| 29 | +#define CRAMFS_SIZE_WIDTH 24 |
| 30 | +
|
| 31 | +struct cramfs_inode { |
| 32 | + uint32 mode:16; |
| 33 | + uint32 uid:16; |
| 34 | +
|
| 35 | + /* SIZE for device files is i_rdev */ |
| 36 | + uint32 size:24; |
| 37 | + uint32 gid:8; |
| 38 | +
|
| 39 | + /* NAMELEN is the length of the file name, divided by 4 and rounded up. (cramfs doesn't support hard links.) */ |
| 40 | + /* OFFSET: For symlinks and non-empty regular files, this |
| 41 | + contains the offset (divided by 4) of the file data in |
| 42 | + compressed form (starting with an array of block pointers; |
| 43 | + see README). For non-empty directories it is the offset |
| 44 | + (divided by 4) of the inode of the first file in that |
| 45 | + directory. For anything else, offset is zero. */ |
| 46 | + uint32 namelen:6; |
| 47 | + uint32 offset:26; |
| 48 | + char name[namelen * 4]; |
| 49 | +}; |
| 50 | +
|
| 51 | +struct cramfs_info { |
| 52 | + uint32 crc; |
| 53 | + uint32 edition; |
| 54 | + uint32 blocks; |
| 55 | + uint32 files; |
| 56 | +}; |
| 57 | +
|
| 58 | +/* |
| 59 | + * Superblock information at the beginning of the FS. |
| 60 | + */ |
| 61 | +struct cramfs_super_block { |
| 62 | + uint32 magic; /* 0x28cd3d45 - random number */ |
| 63 | + uint32 size; /* length in bytes */ |
| 64 | + uint32 flags; /* feature flags */ |
| 65 | + uint32 future; /* reserved for future use */ |
| 66 | + char signature[16]; /* "Compressed ROMFS" */ |
| 67 | + cramfs_info fsid; /* unique filesystem info */ |
| 68 | + char name[16]; /* user-defined name */ |
| 69 | + cramfs_inode root; /* root inode data */ |
| 70 | +}; |
| 71 | +
|
| 72 | +/* |
| 73 | + * Feature flags |
| 74 | + * |
| 75 | + * 0x00000000 - 0x000000ff: features that work for all past kernels |
| 76 | + * 0x00000100 - 0xffffffff: features that don't work for past kernels |
| 77 | + */ |
| 78 | +#define CRAMFS_FLAG_FSID_VERSION_2 0x00000001 /* fsid version #2 */ |
| 79 | +#define CRAMFS_FLAG_SORTED_DIRS 0x00000002 /* sorted dirs */ |
| 80 | +#define CRAMFS_FLAG_HOLES 0x00000100 /* support for holes */ |
| 81 | +#define CRAMFS_FLAG_WRONG_SIGNATURE 0x00000200 /* reserved */ |
| 82 | +#define CRAMFS_FLAG_SHIFTED_ROOT_OFFSET 0x00000400 /* shifted root fs */ |
| 83 | +#define CRAMFS_FLAG_BLKSZ_MASK 0x00003800 /* block size mask */ |
| 84 | +#define CRAMFS_FLAG_COMP_METHOD_MASK 0x0000C000 /* Compression method mask */ |
| 85 | +#define CRAMFS_FLAG_EXT_BLOCK_POINTERS 0x00000800 /* block pointer extensions */ |
| 86 | +#define CRAMFS_FLAG_DIRECT_POINTER 0x40000000 /* direct pointers flag */ |
| 87 | +#define CRAMFS_FLAG_UNCOMPRESSED_BLOCK 0x80000000 /* uncompressed block flag */ |
| 88 | +
|
| 89 | +#define CRAMFS_FLAG_BLKSZ_SHIFT 11 |
| 90 | +#define CRAMFS_FLAG_COMP_METHOD_SHIFT 14 |
| 91 | +#define CRAMFS_FLAG_COMP_METHOD_NONE 0 |
| 92 | +#define CRAMFS_FLAG_COMP_METHOD_GZIP 1 |
| 93 | +#define CRAMFS_FLAG_COMP_METHOD_LZMA 2 |
| 94 | +
|
| 95 | +/* |
| 96 | + * Valid values in super.flags. Currently we refuse to mount |
| 97 | + * if (flags & ~CRAMFS_SUPPORTED_FLAGS). Maybe that should be |
| 98 | + * changed to test super.future instead. |
| 99 | + */ |
| 100 | +#define CRAMFS_SUPPORTED_FLAGS (0x000000ff | CRAMFS_FLAG_HOLES | CRAMFS_FLAG_WRONG_SIGNATURE | CRAMFS_FLAG_SHIFTED_ROOT_OFFSET | CRAMFS_FLAG_BLKSZ_MASK | CRAMFS_FLAG_COMP_METHOD_MASK) |
| 101 | +""" # noqa: E501 |
| 102 | + |
| 103 | +c_cramfs = cstruct().load(cramfs_def) |
0 commit comments