Skip to content

Commit 064de01

Browse files
authored
Add sqlite3 (#3)
1 parent 392b9ec commit 064de01

File tree

21 files changed

+1458
-20
lines changed

21 files changed

+1458
-20
lines changed

README.md

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,11 @@
11
# dissect.database
22

3-
A Dissect module implementing parsers for various database formats. For more information,
4-
please see [the documentation](https://docs.dissect.tools/en/latest/projects/dissect.database/index.html).
3+
A Dissect module implementing parsers for various database formats, including:
4+
5+
- Berkeley DB
6+
- SQLite3
7+
8+
For more information, please see [the documentation](https://docs.dissect.tools/en/latest/projects/dissect.database/index.html).
59

610
## Installation
711

dissect/database/__init__.py

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,11 @@
11
from __future__ import annotations
22

33
from dissect.database.bsd.db import DB
4+
from dissect.database.exception import Error
5+
from dissect.database.sqlite3.sqlite3 import SQLite3
46

5-
__all__ = ["DB"]
7+
__all__ = [
8+
"DB",
9+
"Error",
10+
"SQLite3",
11+
]

dissect/database/exception.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
from __future__ import annotations
2+
3+
4+
class Error(Exception):
5+
pass
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
from __future__ import annotations
2+
3+
from dissect.database.sqlite3.exception import (
4+
InvalidDatabase,
5+
InvalidPageNumber,
6+
InvalidPageType,
7+
InvalidSQL,
8+
NoCellData,
9+
NoWriteAheadLog,
10+
)
11+
from dissect.database.sqlite3.sqlite3 import WAL, Column, Row, SQLite3, Table
12+
13+
__all__ = [
14+
"WAL",
15+
"Column",
16+
"InvalidDatabase",
17+
"InvalidPageNumber",
18+
"InvalidPageType",
19+
"InvalidSQL",
20+
"NoCellData",
21+
"NoWriteAheadLog",
22+
"Row",
23+
"SQLite3",
24+
"Table",
25+
]
Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
from __future__ import annotations
2+
3+
from dissect.cstruct import cstruct
4+
5+
# Resource: https://www.sqlite.org/fileformat.html
6+
sqlite3_def = """
7+
#define PAGE_FLAG_INTKEY 0x01
8+
#define PAGE_FLAG_ZERODATA 0x02
9+
#define PAGE_FLAG_LEAFDATA 0x04
10+
#define PAGE_FLAG_LEAF 0x08
11+
12+
#define PAGE_TYPE_INTERIOR_INDEX PAGE_FLAG_ZERODATA
13+
#define PAGE_TYPE_INTERIOR_TABLE PAGE_FLAG_INTKEY | PAGE_FLAG_LEAFDATA
14+
#define PAGE_TYPE_LEAF_INDEX PAGE_FLAG_ZERODATA | PAGE_FLAG_LEAF
15+
#define PAGE_TYPE_LEAF_TABLE PAGE_FLAG_INTKEY | PAGE_FLAG_LEAFDATA | PAGE_FLAG_LEAF
16+
17+
struct header {
18+
char magic[16];
19+
uint16 page_size;
20+
uint8 write_version;
21+
uint8 read_version;
22+
uint8 reserved_size;
23+
uint8 max_embedded_payload_fraction;
24+
uint8 min_embedded_payload_fraction;
25+
uint8 leaf_payload_fraction;
26+
uint32 change_counter;
27+
uint32 page_count;
28+
uint32 first_freelist_page;
29+
uint32 freelist_page_count;
30+
uint32 schema_cookie;
31+
uint32 schema_format_number;
32+
uint32 page_cache_size;
33+
uint32 largest_root_btree_page;
34+
uint32 text_encoding;
35+
uint32 user_version;
36+
uint32 incremental_vacuum_mode;
37+
uint32 application_id;
38+
char reserved1[20];
39+
uint32 version_valid_for_number;
40+
uint32 sqlite_version_number;
41+
};
42+
43+
struct page_header {
44+
uint8 flags;
45+
uint16 first_freeblock;
46+
uint16 cell_count;
47+
uint16 cell_start;
48+
uint8 fragmented_free_bytes;
49+
};
50+
51+
struct wal_header {
52+
uint32 magic;
53+
uint32 version;
54+
uint32 page_size;
55+
uint32 checkpoint_sequence_number;
56+
uint32 salt1;
57+
uint32 salt2;
58+
uint32 checksum1;
59+
uint32 checksum2;
60+
};
61+
62+
struct wal_frame {
63+
uint32 page_number;
64+
uint32 page_count;
65+
uint32 salt1;
66+
uint32 salt2;
67+
uint32 checksum1;
68+
uint32 checksum2;
69+
};
70+
"""
71+
72+
c_sqlite3 = cstruct(endian=">").load(sqlite3_def)
Lines changed: 132 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,132 @@
1+
# Generated by cstruct-stubgen
2+
from typing import BinaryIO, Literal, TypeAlias, overload
3+
4+
import dissect.cstruct as __cs__
5+
6+
class _c_sqlite3(__cs__.cstruct):
7+
PAGE_FLAG_INTKEY: Literal[1] = ...
8+
PAGE_FLAG_ZERODATA: Literal[2] = ...
9+
PAGE_FLAG_LEAFDATA: Literal[4] = ...
10+
PAGE_FLAG_LEAF: Literal[8] = ...
11+
PAGE_TYPE_INTERIOR_INDEX: Literal[2] = ...
12+
PAGE_TYPE_INTERIOR_TABLE: Literal[5] = ...
13+
PAGE_TYPE_LEAF_INDEX: Literal[10] = ...
14+
PAGE_TYPE_LEAF_TABLE: Literal[13] = ...
15+
class header(__cs__.Structure):
16+
magic: __cs__.CharArray
17+
page_size: _c_sqlite3.uint16
18+
write_version: _c_sqlite3.uint8
19+
read_version: _c_sqlite3.uint8
20+
reserved_size: _c_sqlite3.uint8
21+
max_embedded_payload_fraction: _c_sqlite3.uint8
22+
min_embedded_payload_fraction: _c_sqlite3.uint8
23+
leaf_payload_fraction: _c_sqlite3.uint8
24+
change_counter: _c_sqlite3.uint32
25+
page_count: _c_sqlite3.uint32
26+
first_freelist_page: _c_sqlite3.uint32
27+
freelist_page_count: _c_sqlite3.uint32
28+
schema_cookie: _c_sqlite3.uint32
29+
schema_format_number: _c_sqlite3.uint32
30+
page_cache_size: _c_sqlite3.uint32
31+
largest_root_btree_page: _c_sqlite3.uint32
32+
text_encoding: _c_sqlite3.uint32
33+
user_version: _c_sqlite3.uint32
34+
incremental_vacuum_mode: _c_sqlite3.uint32
35+
application_id: _c_sqlite3.uint32
36+
reserved1: __cs__.CharArray
37+
version_valid_for_number: _c_sqlite3.uint32
38+
sqlite_version_number: _c_sqlite3.uint32
39+
@overload
40+
def __init__(
41+
self,
42+
magic: __cs__.CharArray | None = ...,
43+
page_size: _c_sqlite3.uint16 | None = ...,
44+
write_version: _c_sqlite3.uint8 | None = ...,
45+
read_version: _c_sqlite3.uint8 | None = ...,
46+
reserved_size: _c_sqlite3.uint8 | None = ...,
47+
max_embedded_payload_fraction: _c_sqlite3.uint8 | None = ...,
48+
min_embedded_payload_fraction: _c_sqlite3.uint8 | None = ...,
49+
leaf_payload_fraction: _c_sqlite3.uint8 | None = ...,
50+
change_counter: _c_sqlite3.uint32 | None = ...,
51+
page_count: _c_sqlite3.uint32 | None = ...,
52+
first_freelist_page: _c_sqlite3.uint32 | None = ...,
53+
freelist_page_count: _c_sqlite3.uint32 | None = ...,
54+
schema_cookie: _c_sqlite3.uint32 | None = ...,
55+
schema_format_number: _c_sqlite3.uint32 | None = ...,
56+
page_cache_size: _c_sqlite3.uint32 | None = ...,
57+
largest_root_btree_page: _c_sqlite3.uint32 | None = ...,
58+
text_encoding: _c_sqlite3.uint32 | None = ...,
59+
user_version: _c_sqlite3.uint32 | None = ...,
60+
incremental_vacuum_mode: _c_sqlite3.uint32 | None = ...,
61+
application_id: _c_sqlite3.uint32 | None = ...,
62+
reserved1: __cs__.CharArray | None = ...,
63+
version_valid_for_number: _c_sqlite3.uint32 | None = ...,
64+
sqlite_version_number: _c_sqlite3.uint32 | None = ...,
65+
): ...
66+
@overload
67+
def __init__(self, fh: bytes | memoryview | bytearray | BinaryIO, /): ...
68+
69+
class page_header(__cs__.Structure):
70+
flags: _c_sqlite3.uint8
71+
first_freeblock: _c_sqlite3.uint16
72+
cell_count: _c_sqlite3.uint16
73+
cell_start: _c_sqlite3.uint16
74+
fragmented_free_bytes: _c_sqlite3.uint8
75+
@overload
76+
def __init__(
77+
self,
78+
flags: _c_sqlite3.uint8 | None = ...,
79+
first_freeblock: _c_sqlite3.uint16 | None = ...,
80+
cell_count: _c_sqlite3.uint16 | None = ...,
81+
cell_start: _c_sqlite3.uint16 | None = ...,
82+
fragmented_free_bytes: _c_sqlite3.uint8 | None = ...,
83+
): ...
84+
@overload
85+
def __init__(self, fh: bytes | memoryview | bytearray | BinaryIO, /): ...
86+
87+
class wal_header(__cs__.Structure):
88+
magic: _c_sqlite3.uint32
89+
version: _c_sqlite3.uint32
90+
page_size: _c_sqlite3.uint32
91+
checkpoint_sequence_number: _c_sqlite3.uint32
92+
salt1: _c_sqlite3.uint32
93+
salt2: _c_sqlite3.uint32
94+
checksum1: _c_sqlite3.uint32
95+
checksum2: _c_sqlite3.uint32
96+
@overload
97+
def __init__(
98+
self,
99+
magic: _c_sqlite3.uint32 | None = ...,
100+
version: _c_sqlite3.uint32 | None = ...,
101+
page_size: _c_sqlite3.uint32 | None = ...,
102+
checkpoint_sequence_number: _c_sqlite3.uint32 | None = ...,
103+
salt1: _c_sqlite3.uint32 | None = ...,
104+
salt2: _c_sqlite3.uint32 | None = ...,
105+
checksum1: _c_sqlite3.uint32 | None = ...,
106+
checksum2: _c_sqlite3.uint32 | None = ...,
107+
): ...
108+
@overload
109+
def __init__(self, fh: bytes | memoryview | bytearray | BinaryIO, /): ...
110+
111+
class wal_frame(__cs__.Structure):
112+
page_number: _c_sqlite3.uint32
113+
page_count: _c_sqlite3.uint32
114+
salt1: _c_sqlite3.uint32
115+
salt2: _c_sqlite3.uint32
116+
checksum1: _c_sqlite3.uint32
117+
checksum2: _c_sqlite3.uint32
118+
@overload
119+
def __init__(
120+
self,
121+
page_number: _c_sqlite3.uint32 | None = ...,
122+
page_count: _c_sqlite3.uint32 | None = ...,
123+
salt1: _c_sqlite3.uint32 | None = ...,
124+
salt2: _c_sqlite3.uint32 | None = ...,
125+
checksum1: _c_sqlite3.uint32 | None = ...,
126+
checksum2: _c_sqlite3.uint32 | None = ...,
127+
): ...
128+
@overload
129+
def __init__(self, fh: bytes | memoryview | bytearray | BinaryIO, /): ...
130+
131+
# Technically `c_sqlite3` is an instance of `_c_sqlite3`, but then we can't use it in type hints
132+
c_sqlite3: TypeAlias = _c_sqlite3
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
from __future__ import annotations
2+
3+
from dissect.database.exception import Error
4+
5+
6+
class InvalidDatabase(Error):
7+
pass
8+
9+
10+
class InvalidPageNumber(Error):
11+
pass
12+
13+
14+
class InvalidPageType(Error):
15+
pass
16+
17+
18+
class InvalidSQL(Error):
19+
pass
20+
21+
22+
class NoCellData(Error):
23+
pass
24+
25+
26+
class NoWriteAheadLog(Error):
27+
pass

0 commit comments

Comments
 (0)