SickGear/lib/hachoir/parser/file_system/linux_swap.py
2023-02-09 13:41:15 +00:00

119 lines
3.8 KiB
Python

"""
Linux swap file.
Documentation: Linux kernel source code, files:
- mm/swapfile.c
- include/linux/swap.h
Author: Victor Stinner
Creation date: 25 december 2006 (christmas ;-))
"""
from hachoir.parser import Parser
from hachoir.field import (ParserError, GenericVector,
UInt32, String,
Bytes, NullBytes, RawBytes)
from hachoir.core.endian import LITTLE_ENDIAN
from hachoir.core.tools import humanFilesize
from hachoir.core.bits import str2hex
PAGE_SIZE = 4096
# Definition of MAX_SWAP_BADPAGES in Linux kernel:
# (__swapoffset(magic.magic) - __swapoffset(info.badpages)) / sizeof(int)
MAX_SWAP_BADPAGES = ((PAGE_SIZE - 10) - 1536) // 4
class Page(RawBytes):
static_size = PAGE_SIZE * 8
def __init__(self, parent, name):
RawBytes.__init__(self, parent, name, PAGE_SIZE)
class UUID(Bytes):
static_size = 16 * 8
def __init__(self, parent, name, *args, **kwargs):
Bytes.__init__(self, parent, name, 16, *args, **kwargs)
def createDisplay(self):
text = str2hex(self.value, format=r"%02x")
return "%s-%s-%s-%s-%s" % (
text[:8], text[8:12], text[12:16], text[16:20], text[20:])
class LinuxSwapFile(Parser):
PARSER_TAGS = {
"id": "linux_swap",
"file_ext": ("",),
"category": "file_system",
"min_size": PAGE_SIZE * 8,
"description": "Linux swap file",
"magic": (
(b"SWAP-SPACE", (PAGE_SIZE - 10) * 8),
(b"SWAPSPACE2", (PAGE_SIZE - 10) * 8),
(b"S1SUSPEND\0", (PAGE_SIZE - 10) * 8),
),
}
endian = LITTLE_ENDIAN
def validate(self):
magic = self.stream.readBytes((PAGE_SIZE - 10) * 8, 10)
if magic not in (b"SWAP-SPACE", b"SWAPSPACE2", b"S1SUSPEND\0"):
return "Unknown magic string"
if MAX_SWAP_BADPAGES < self["nb_badpage"].value:
return "Invalid number of bad page (%u)" % self["nb_badpage"].value
return True
def getPageCount(self):
"""
Number of pages which can really be used for swapping:
number of page minus bad pages minus one page (used for the header)
"""
# -1 because first page is used for the header
return self["last_page"].value - self["nb_badpage"].value - 1
def createDescription(self):
if self["magic"].value == "S1SUSPEND\0":
text = "Suspend swap file version 1"
elif self["magic"].value == "SWAPSPACE2":
text = "Linux swap file version 2"
else:
text = "Linux swap file version 1"
nb_page = self.getPageCount()
return "%s, page size: %s, %s pages" % (
text, humanFilesize(PAGE_SIZE), nb_page)
def createFields(self):
# First kilobyte: boot sectors
yield RawBytes(self, "boot", 1024, "Space for disklabel etc.")
# Header
yield UInt32(self, "version")
yield UInt32(self, "last_page")
yield UInt32(self, "nb_badpage")
yield UUID(self, "sws_uuid")
yield UUID(self, "sws_volume")
yield NullBytes(self, "reserved", 117 * 4)
# Read bad pages (if any)
count = self["nb_badpage"].value
if count:
if MAX_SWAP_BADPAGES < count:
raise ParserError("Invalid number of bad page (%u)" % count)
yield GenericVector(self, "badpages", count, UInt32, "badpage")
# Read magic
padding = self.seekByte(PAGE_SIZE - 10, "padding", null=True)
if padding:
yield padding
yield String(self, "magic", 10, charset="ASCII")
# Read all pages
yield GenericVector(self, "pages", self["last_page"].value, Page, "page")
# Padding at the end
padding = self.seekBit(self.size, "end_padding", null=True)
if padding:
yield padding