Skip to documentation
SLOP

tiny.smg.storage.source

Reference tiny.smg storage source

Defined in storage.

API (7)

Actions

Public operations.

Types and contracts

Public types and contracts.

No direct callersNo direct callsstoragesource
Static calls · unresolved targets: unknown · external targets: unknown.

Source

Called byCallsNo direct callsprivate; no linktools.smg.src.command.check.refreshrefreshGraphstorage.sourceexecutableDigest
Static calls · unresolved targets: 2 · external targets: 4.
Called byCallstest; no linktools.smg.src.storage.sourcetest: source identity cache matches o...storage.sourceprojectForOwnerstorage.sourcematches
Static calls · unresolved targets: 0 · external targets: 0.
Called byCallsstorage.sourceprojectForOwnertest; no linktools.smg.src.storage.sourcetest: source identity cache matches o...private; no linktools.smg.src.storage.sourcecachePathstorage.sourceownerForHead
Static calls · unresolved targets: 1 · external targets: 3.
Called byCallsprivate; no linktools.smg.src.command.check.refreshrefreshGraphstorage.sourcematchesstorage.sourceownerForHeadstorage.sourceprojectForOwner
Static calls · unresolved targets: 0 · external targets: 0.
Called byCallsprivate; no linktools.smg.src.command.check.refreshupdateSourceCachestest; no linktools.smg.src.storage.sourcetest: source identity cache matches o...private; no linktools.smg.src.storage.sourcecachePathstorage.sourcewriteForHead
Static calls · unresolved targets: 1 · external targets: 5.

Source: tools/smg/src/storage/root.zig:11

zig
pub const source = @import("source.zig");

Source: tools/smg/src/storage/source.zig

zig
const std = @import("std");const sql = @import("sql");const sys = @import("sys");const smg = @import("../root.zig");const storage = smg.storage;const fs_io = std.Options.debug_io;pub const Digest = [std.crypto.hash.sha2.Sha256.digest_length]u8;pub const Owner = struct { executable: Digest, project: Digest };const magic = "tiny.smg.source/v1\n";const identity_bytes = @sizeOf(sql.Hash) + 2 * @sizeOf(Digest);const payload_bytes = magic.len + identity_bytes;const file_bytes = payload_bytes + @sizeOf(Digest);const read_buffer_bytes = 64 * 1024;pub fn executableDigest(allocator: std.mem.Allocator) !Digest {    const executable = try std.process.executablePathAlloc(fs_io, allocator);    defer allocator.free(executable);    var file = try std.Io.Dir.openFileAbsolute(fs_io, executable, .{});    defer file.close(fs_io);    var reader_buffer: [read_buffer_bytes]u8 = undefined;    var file_reader = file.reader(fs_io, &reader_buffer);    var chunk: [read_buffer_bytes]u8 = undefined;    var hasher = std.crypto.hash.sha2.Sha256.init(.{});    while (true) {        const count = file_reader.interface.readSliceShort(&chunk) catch |err| switch (err) {            error.ReadFailed => return file_reader.err orelse error.ReadFailed,        };        if (count == 0) break;        hasher.update(chunk[0..count]);    }    var digest: Digest = undefined;    hasher.final(&digest);    return digest;}pub fn matches(    allocator: std.mem.Allocator,    root: []const u8,    expected_head: sql.Hash,    executable: Digest,    project: Digest,) std.mem.Allocator.Error!bool {    const stored = try projectForOwner(allocator, root, expected_head, executable) orelse return false;    return std.mem.eql(u8, &stored, &project);}pub fn projectForOwner(    allocator: std.mem.Allocator,    root: []const u8,    expected_head: sql.Hash,    executable: Digest,) std.mem.Allocator.Error!?Digest {    const owner = try ownerForHead(allocator, root, expected_head) orelse return null;    if (!std.mem.eql(u8, &owner.executable, &executable)) return null;    return owner.project;}/// Reads the checksummed scanner and project identity bound to one stored graph head.pub fn ownerForHead(    allocator: std.mem.Allocator,    root: []const u8,    expected_head: sql.Hash,) std.mem.Allocator.Error!?Owner {    const path = try cachePath(allocator, root, storage.paths.source_file_name);    defer allocator.free(path);    var file = std.Io.Dir.openFileAbsolute(fs_io, path, .{}) catch return null;    defer file.close(fs_io);    const stat = file.stat(fs_io) catch return null;    if (stat.kind != .file or stat.size != file_bytes) return null;    var encoded: [file_bytes]u8 = undefined;    const read = file.readPositionalAll(fs_io, &encoded, 0) catch return null;    if (read != encoded.len) return null;    if (!std.mem.eql(u8, encoded[0..magic.len], magic)) return null;    var computed: Digest = undefined;    std.crypto.hash.sha2.Sha256.hash(encoded[0..payload_bytes], &computed, .{});    if (!std.mem.eql(u8, &computed, encoded[payload_bytes..])) return null;    var offset: usize = magic.len;    if (!std.mem.eql(u8, expected_head[0..], encoded[offset .. offset + @sizeOf(sql.Hash)])) return null;    offset += @sizeOf(sql.Hash);    var executable: Digest = undefined;    @memcpy(&executable, encoded[offset .. offset + @sizeOf(Digest)]);    offset += @sizeOf(Digest);    var project: Digest = undefined;    @memcpy(&project, encoded[offset .. offset + @sizeOf(Digest)]);    return .{ .executable = executable, .project = project };}pub fn writeForHead(    allocator: std.mem.Allocator,    root: []const u8,    head: sql.Hash,    executable: Digest,    project: Digest,) !void {    const temporary_name = try std.fmt.allocPrint(        allocator,        "{s}.{d}",        .{ storage.paths.source_temp_file_name, try sys.process.currentProcessId() },    );    defer allocator.free(temporary_name);    const temporary = try cachePath(allocator, root, temporary_name);    defer allocator.free(temporary);    const destination = try cachePath(allocator, root, storage.paths.source_file_name);    defer allocator.free(destination);    var encoded: [file_bytes]u8 = undefined;    var offset: usize = 0;    @memcpy(encoded[offset .. offset + magic.len], magic);    offset += magic.len;    @memcpy(encoded[offset .. offset + @sizeOf(sql.Hash)], &head);    offset += @sizeOf(sql.Hash);    @memcpy(encoded[offset .. offset + @sizeOf(Digest)], &executable);    offset += @sizeOf(Digest);    @memcpy(encoded[offset .. offset + @sizeOf(Digest)], &project);    offset += @sizeOf(Digest);    std.debug.assert(offset == payload_bytes);    var digest: Digest = undefined;    std.crypto.hash.sha2.Sha256.hash(encoded[0..payload_bytes], &digest, .{});    @memcpy(encoded[payload_bytes..], &digest);    errdefer std.Io.Dir.deleteFileAbsolute(fs_io, temporary) catch {};    {        var file = try std.Io.Dir.createFileAbsolute(fs_io, temporary, .{ .truncate = true });        defer file.close(fs_io);        try file.writeStreamingAll(fs_io, &encoded);        try file.sync(fs_io);    }    try sys.fs.rename(temporary, destination);}fn cachePath(    allocator: std.mem.Allocator,    root: []const u8,    name: []const u8,) std.mem.Allocator.Error![]const u8 {    return try std.fs.path.join(        allocator,        &.{ root, storage.paths.smg_dir_name, name },    );}test "source identity cache matches only exact graph executable and project" {    var arena = std.heap.ArenaAllocator.init(std.testing.allocator);    defer arena.deinit();    const allocator = arena.allocator();    const root = try std.fmt.allocPrint(allocator, "/tmp/smg-source-identity-test-{x}", .{@intFromPtr(&arena)});    defer sys.fs.deleteTree(root) catch {};    try sys.fs.createDirPath(try std.fs.path.join(allocator, &.{ root, storage.paths.smg_dir_name }));    const head: sql.Hash = @splat(1);    const executable: Digest = @splat(2);    const project: Digest = @splat(3);    try writeForHead(allocator, root, head, executable, project);    const owner = (try ownerForHead(allocator, root, head)).?;    try std.testing.expectEqualSlices(u8, &executable, &owner.executable);    try std.testing.expectEqualSlices(u8, &project, &owner.project);    try std.testing.expect(try ownerForHead(allocator, root, @splat(4)) == null);    try std.testing.expect(try matches(allocator, root, head, executable, project));    try std.testing.expect(!try matches(allocator, root, @as(sql.Hash, @splat(4)), executable, project));    try std.testing.expect(!try matches(allocator, root, head, @as(Digest, @splat(4)), project));    try std.testing.expect(!try matches(allocator, root, head, executable, @as(Digest, @splat(4))));    const path = try cachePath(allocator, root, storage.paths.source_file_name);    var file = try std.Io.Dir.openFileAbsolute(fs_io, path, .{ .mode = .read_write });    defer file.close(fs_io);    try file.writePositionalAll(fs_io, "x", magic.len + 1);    try std.testing.expect(!try matches(allocator, root, head, executable, project));}

Audit

Definitions8
Public names8
Members2
Version26.7.0
Revisiondaab053ee433