| ... | ... | @@ -1181,7 +1181,6 @@ fn unpackTarball(f: *Fetch, out_dir: fs.Dir, reader: anytype) RunError!?[]const |
| 1181 | 1181 | std.tar.pipeToFileSystem(out_dir, reader, .{ |
| 1182 | 1182 | .diagnostics = &diagnostics, |
| 1183 | 1183 | .strip_components = 0, |
| 1184 | | // https://github.com/ziglang/zig/issues/17463 |
| 1185 | 1184 | .mode_mode = .ignore, |
| 1186 | 1185 | .exclude_empty_directories = true, |
| 1187 | 1186 | }) catch |err| return f.fail(f.location_tok, try eb.printString( |
| ... | ... | @@ -1569,17 +1568,22 @@ fn hashFileFallible(dir: fs.Dir, hashed_file: *HashedFile) HashedFile.Error!void |
| 1569 | 1568 | var buf: [8000]u8 = undefined; |
| 1570 | 1569 | var hasher = Manifest.Hash.init(.{}); |
| 1571 | 1570 | hasher.update(hashed_file.normalized_path); |
| 1571 | |
| 1572 | 1572 | switch (hashed_file.kind) { |
| 1573 | 1573 | .file => { |
| 1574 | 1574 | var file = try dir.openFile(hashed_file.fs_path, .{}); |
| 1575 | 1575 | defer file.close(); |
| 1576 | | // When implementing https://github.com/ziglang/zig/issues/17463 |
| 1577 | | // this will change to hard-coded `false`. |
| 1578 | | hasher.update(&.{ 0, @intFromBool(try isExecutable(file)) }); |
| 1576 | // Hard-coded false executable bit: https://github.com/ziglang/zig/issues/17463 |
| 1577 | hasher.update(&.{ 0, 0 }); |
| 1578 | var file_header: FileHeader = .{}; |
| 1579 | 1579 | while (true) { |
| 1580 | 1580 | const bytes_read = try file.read(&buf); |
| 1581 | 1581 | if (bytes_read == 0) break; |
| 1582 | 1582 | hasher.update(buf[0..bytes_read]); |
| 1583 | file_header.update(buf[0..bytes_read]); |
| 1584 | } |
| 1585 | if (file_header.isExecutable()) { |
| 1586 | try setExecutable(file); |
| 1583 | 1587 | } |
| 1584 | 1588 | }, |
| 1585 | 1589 | .link => { |
| ... | ... | @@ -1600,19 +1604,12 @@ fn deleteFileFallible(dir: fs.Dir, deleted_file: *DeletedFile) DeletedFile.Error |
| 1600 | 1604 | try dir.deleteFile(deleted_file.fs_path); |
| 1601 | 1605 | } |
| 1602 | 1606 | |
| 1603 | | fn isExecutable(file: fs.File) !bool { |
| 1604 | | // When implementing https://github.com/ziglang/zig/issues/17463 |
| 1605 | | // this function will not check the mode but instead check if the file is an ELF |
| 1606 | | // file or has a shebang line. |
| 1607 | | if (native_os == .windows) { |
| 1608 | | // Until this is implemented, this could be a false negative on |
| 1609 | | // Windows, which is why we do not yet set executable_bit_only above |
| 1610 | | // when unpacking the tarball. |
| 1611 | | return false; |
| 1612 | | } else { |
| 1613 | | const stat = try file.stat(); |
| 1614 | | return (stat.mode & std.posix.S.IXUSR) != 0; |
| 1615 | | } |
| 1607 | fn setExecutable(file: fs.File) !void { |
| 1608 | if (!std.fs.has_executable_bit) return; |
| 1609 | |
| 1610 | const S = std.posix.S; |
| 1611 | const mode = fs.File.default_mode | S.IXUSR | S.IXGRP | S.IXOTH; |
| 1612 | try file.chmod(mode); |
| 1616 | 1613 | } |
| 1617 | 1614 | |
| 1618 | 1615 | const DeletedFile = struct { |
| ... | ... | @@ -1635,6 +1632,7 @@ const HashedFile = struct { |
| 1635 | 1632 | fs.File.OpenError || |
| 1636 | 1633 | fs.File.ReadError || |
| 1637 | 1634 | fs.File.StatError || |
| 1635 | fs.File.ChmodError || |
| 1638 | 1636 | fs.Dir.ReadLinkError; |
| 1639 | 1637 | |
| 1640 | 1638 | const Kind = enum { file, link }; |
| ... | ... | @@ -1746,3 +1744,37 @@ test { |
| 1746 | 1744 | _ = Filter; |
| 1747 | 1745 | _ = FileType; |
| 1748 | 1746 | } |
| 1747 | |
| 1748 | // Detects executable header: ELF magic header or shebang line. |
| 1749 | const FileHeader = struct { |
| 1750 | const elf_magic = std.elf.MAGIC; |
| 1751 | const shebang = "#!"; |
| 1752 | |
| 1753 | header: [@max(elf_magic.len, shebang.len)]u8 = undefined, |
| 1754 | bytes_read: usize = 0, |
| 1755 | |
| 1756 | pub fn update(self: *FileHeader, buf: []const u8) void { |
| 1757 | if (self.bytes_read >= self.header.len) return; |
| 1758 | const n = @min(self.header.len - self.bytes_read, buf.len); |
| 1759 | @memcpy(self.header[self.bytes_read..][0..n], buf[0..n]); |
| 1760 | self.bytes_read += n; |
| 1761 | } |
| 1762 | |
| 1763 | pub fn isExecutable(self: *FileHeader) bool { |
| 1764 | return std.mem.eql(u8, self.header[0..shebang.len], shebang) or |
| 1765 | std.mem.eql(u8, self.header[0..elf_magic.len], elf_magic); |
| 1766 | } |
| 1767 | }; |
| 1768 | |
| 1769 | test FileHeader { |
| 1770 | var h: FileHeader = .{}; |
| 1771 | try std.testing.expect(!h.isExecutable()); |
| 1772 | |
| 1773 | h.update(FileHeader.elf_magic[0..2]); |
| 1774 | try std.testing.expect(!h.isExecutable()); |
| 1775 | h.update(FileHeader.elf_magic[2..4]); |
| 1776 | try std.testing.expect(h.isExecutable()); |
| 1777 | |
| 1778 | h.update(FileHeader.elf_magic[2..4]); |
| 1779 | try std.testing.expect(h.isExecutable()); |
| 1780 | } |