| 1 | const std = @import("std"); |
| 2 | const Io = std.Io; |
| 3 | const Md5 = std.crypto.hash.Md5; |
| 4 | |
| 5 | const trace = @import("../../tracy.zig").trace; |
| 6 | const Compilation = @import("../../Compilation.zig"); |
| 7 | const ParallelHasher = @import("hasher.zig").ParallelHasher; |
| 8 | |
| 9 | /// Calculates Md5 hash of each chunk in parallel and then hashes all Md5 hashes to produce |
| 10 | /// the final digest. |
| 11 | /// While this is NOT a correct MD5 hash of the contents, this methodology is used by LLVM/LLD |
| 12 | /// and we will use it too as it seems accepted by Apple OSes. |
| 13 | /// TODO LLD also hashes the output filename to disambiguate between same builds with different |
| 14 | /// output files. Should we also do that? |
| 15 | pub fn calcUuid(comp: *const Compilation, file: Io.File, file_size: u64, out: *[Md5.digest_length]u8) !void { |
| 16 | const tracy = trace(@src()); |
| 17 | defer tracy.end(); |
| 18 | |
| 19 | const gpa = comp.gpa; |
| 20 | const io = comp.io; |
| 21 | |
| 22 | const chunk_size: usize = 1024 * 1024; |
| 23 | const num_chunks: usize = std.math.cast(usize, @divTrunc(file_size, chunk_size)) orelse return error.Overflow; |
| 24 | const actual_num_chunks = if (@rem(file_size, chunk_size) > 0) num_chunks + 1 else num_chunks; |
| 25 | |
| 26 | const hashes = try gpa.alloc([Md5.digest_length]u8, actual_num_chunks); |
| 27 | defer gpa.free(hashes); |
| 28 | |
| 29 | try ParallelHasher(Md5).hash(gpa, io, file, hashes, .{ |
| 30 | .chunk_size = chunk_size, |
| 31 | .max_file_size = file_size, |
| 32 | }); |
| 33 | |
| 34 | const final_buffer = try gpa.alloc(u8, actual_num_chunks * Md5.digest_length); |
| 35 | defer gpa.free(final_buffer); |
| 36 | |
| 37 | for (hashes, 0..) |hash, i| { |
| 38 | @memcpy(final_buffer[i * Md5.digest_length ..][0..Md5.digest_length], &hash); |
| 39 | } |
| 40 | |
| 41 | Md5.hash(final_buffer, out, .{}); |
| 42 | conform(out); |
| 43 | } |
| 44 | |
| 45 | inline fn conform(out: *[Md5.digest_length]u8) void { |
| 46 | // LC_UUID uuids should conform to RFC 4122 UUID version 4 & UUID version 5 formats |
| 47 | out[6] = (out[6] & 0x0F) | (3 << 4); |
| 48 | out[8] = (out[8] & 0x3F) | 0x80; |
| 49 | } |