Skip to content

Instantly share code, notes, and snippets.

@kobuki
Last active April 25, 2026 09:27
Show Gist options
  • Select an option

  • Save kobuki/48bb83b71f2768b7fea22ce2393b9f23 to your computer and use it in GitHub Desktop.

Select an option

Save kobuki/48bb83b71f2768b7fea22ce2393b9f23 to your computer and use it in GitHub Desktop.
Create file hierarchy from a Proxmox pmxcfs/pve-cluster SQLite config database
#!/usr/bin/env python3
# Simple Python 3 script to create a browsable file tree from a Proxmox pmxcfs config.db.
# Can be used for restore tasks or other investigation purposes.
import sqlite3
import os
import argparse
def create_hierarchy(db_file, output_dir):
# Connect to the SQLite database
conn = sqlite3.connect(db_file)
cursor = conn.cursor()
# Fetch all entries from the table
cursor.execute("SELECT inode, parent, type, name, data, mtime FROM tree")
entries = cursor.fetchall()
# Close the connection
conn.close()
# Dictionary to map inodes to paths
inode_map = {}
os.makedirs(output_dir, exist_ok=True)
# Function to resolve parent directory path recursively
def get_parent_path(parent):
if parent == 0:
return output_dir
if parent not in inode_map:
parent_entry = next((e for e in entries if e[0] == parent), None)
if parent_entry:
inode_map[parent] = os.path.join(get_parent_path(parent_entry[1]), parent_entry[3])
os.makedirs(inode_map[parent], exist_ok=True)
return inode_map.get(parent, output_dir)
# Process directories first to ensure they exist
for inode, parent, obj_type, name, data, mtime in entries:
if obj_type == 4: # Directory
parent_path = get_parent_path(parent)
dir_path = os.path.join(parent_path, name)
os.makedirs(dir_path, exist_ok=True)
inode_map[inode] = dir_path
os.utime(dir_path, (mtime, mtime))
# Process files
for inode, parent, obj_type, name, data, mtime in entries:
if obj_type == 8: # File
parent_path = get_parent_path(parent)
file_path = os.path.join(parent_path, name)
with open(file_path, "wb") as f:
f.write(data if data is not None else b"")
os.utime(file_path, (mtime, mtime))
if __name__ == "__main__":
parser = argparse.ArgumentParser(description="Reconstruct filesystem from SQLite database")
parser.add_argument("db_file", help="Path to the SQLite database file")
parser.add_argument("output_dir", help="Path to the output directory")
args = parser.parse_args()
create_hierarchy(args.db_file, args.output_dir)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment