(** Low-level I/O operations for database files *) let magic = "LITHOS\x00\x00" let version = 1 let create_database path page_size = try let fd = Unix.openfile path [ Unix.O_RDWR; Unix.O_CREAT; Unix.O_EXCL ] 0o644 in let buf = Bytes.create page_size in Bytes.blit_string magic 0 buf 0 (String.length magic); Bytes.set_int32_le buf 8 (Int32.of_int version); Bytes.set_int32_le buf 12 (Int32.of_int page_size); Bytes.set_int64_le buf 16 Int64.zero; let written = Unix.write fd buf 0 page_size in Unix.close fd; if written = page_size then Ok () else Error (Error.IO_error "Failed to write complete header") with | Unix.Unix_error (err, _, _) -> Error (Error.of_unix_error err path) ;; let read_header path = try let fd = Unix.openfile path [ Unix.O_RDONLY ] 0o644 in let buf = Bytes.create 256 in let read_bytes = Unix.read fd buf 0 256 in Unix.close fd; if read_bytes < 24 then Error (Error.Invalid_database "File too small") else ( let magic_read = Bytes.sub_string buf 0 8 in if magic_read <> magic then Error (Error.Invalid_database "Invalid magic number") else ( let ver = Int32.to_int (Bytes.get_int32_le buf 8) in let page_size = Int32.to_int (Bytes.get_int32_le buf 12) in let root = Bytes.get_int64_le buf 16 in let root_bucket = if root = Int64.zero then None else Some root in Ok { Types.version = ver; page_size; root_bucket })) with | Unix.Unix_error (err, _, _) -> Error (Error.of_unix_error err path) ;; let write_header path metadata = try let fd = Unix.openfile path [ Unix.O_RDWR ] 0o644 in let buf = Bytes.create 256 in Bytes.blit_string magic 0 buf 0 (String.length magic); Bytes.set_int32_le buf 8 (Int32.of_int metadata.Types.version); Bytes.set_int32_le buf 12 (Int32.of_int metadata.Types.page_size); let root = match metadata.Types.root_bucket with | None -> Int64.zero | Some id -> id in Bytes.set_int64_le buf 16 root; let written = Unix.write fd buf 0 256 in Unix.close fd; if written = 256 then Ok () else Error (Error.IO_error "Failed to write header") with | Unix.Unix_error (err, _, _) -> Error (Error.of_unix_error err path) ;;