#!/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)