| ... | @@ -1181,7 +1181,6 @@ fn unpackTarball(f: *Fetch, out_dir: fs.Dir, reader: anytype) RunError!?[]const | ... | @@ -1181,7 +1181,6 @@ fn unpackTarball(f: *Fetch, out_dir: fs.Dir, reader: anytype) RunError!?[]const |
| 1181 | std.tar.pipeToFileSystem(out_dir, reader, .{ | 1181 | std.tar.pipeToFileSystem(out_dir, reader, .{ |
| 1182 | .diagnostics = &diagnostics, | 1182 | .diagnostics = &diagnostics, |
| 1183 | .strip_components = 0, | 1183 | .strip_components = 0, |
| 1184 | // https://github.com/ziglang/zig/issues/17463 | | |
| 1185 | .mode_mode = .ignore, | 1184 | .mode_mode = .ignore, |
| 1186 | .exclude_empty_directories = true, | 1185 | .exclude_empty_directories = true, |
| 1187 | }) catch |err| return f.fail(f.location_tok, try eb.printString( | 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,17 +1568,22 @@ fn hashFileFallible(dir: fs.Dir, hashed_file: *HashedFile) HashedFile.Error!void |
| 1569 | var buf: [8000]u8 = undefined; | 1568 | var buf: [8000]u8 = undefined; |
| 1570 | var hasher = Manifest.Hash.init(.{}); | 1569 | var hasher = Manifest.Hash.init(.{}); |
| 1571 | hasher.update(hashed_file.normalized_path); | 1570 | hasher.update(hashed_file.normalized_path); |
| | 1571 | |
| 1572 | switch (hashed_file.kind) { | 1572 | switch (hashed_file.kind) { |
| 1573 | .file => { | 1573 | .file => { |
| 1574 | var file = try dir.openFile(hashed_file.fs_path, .{}); | 1574 | var file = try dir.openFile(hashed_file.fs_path, .{}); |
| 1575 | defer file.close(); | 1575 | defer file.close(); |
| 1576 | // When implementing https://github.com/ziglang/zig/issues/17463 | 1576 | // Hard-coded false executable bit: https://github.com/ziglang/zig/issues/17463 |
| 1577 | // this will change to hard-coded `false`. | 1577 | hasher.update(&.{ 0, 0 }); |
| 1578 | hasher.update(&.{ 0, @intFromBool(try isExecutable(file)) }); | 1578 | var file_header: FileHeader = .{}; |
| 1579 | while (true) { | 1579 | while (true) { |
| 1580 | const bytes_read = try file.read(&buf); | 1580 | const bytes_read = try file.read(&buf); |
| 1581 | if (bytes_read == 0) break; | 1581 | if (bytes_read == 0) break; |
| 1582 | hasher.update(buf[0..bytes_read]); | 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 | .link => { | 1589 | .link => { |
| ... | @@ -1600,19 +1604,12 @@ fn deleteFileFallible(dir: fs.Dir, deleted_file: *DeletedFile) DeletedFile.Error | ... | @@ -1600,19 +1604,12 @@ fn deleteFileFallible(dir: fs.Dir, deleted_file: *DeletedFile) DeletedFile.Error |
| 1600 | try dir.deleteFile(deleted_file.fs_path); | 1604 | try dir.deleteFile(deleted_file.fs_path); |
| 1601 | } | 1605 | } |
| 1602 | | 1606 | |
| 1603 | fn isExecutable(file: fs.File) !bool { | 1607 | fn setExecutable(file: fs.File) !void { |
| 1604 | // When implementing https://github.com/ziglang/zig/issues/17463 | 1608 | if (!std.fs.has_executable_bit) return; |
| 1605 | // this function will not check the mode but instead check if the file is an ELF | 1609 | |
| 1606 | // file or has a shebang line. | 1610 | const S = std.posix.S; |
| 1607 | if (native_os == .windows) { | 1611 | const mode = fs.File.default_mode | S.IXUSR | S.IXGRP | S.IXOTH; |
| 1608 | // Until this is implemented, this could be a false negative on | 1612 | try file.chmod(mode); |
| 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 | } | | |
| 1616 | } | 1613 | } |
| 1617 | | 1614 | |
| 1618 | const DeletedFile = struct { | 1615 | const DeletedFile = struct { |
| ... | @@ -1635,6 +1632,7 @@ const HashedFile = struct { | ... | @@ -1635,6 +1632,7 @@ const HashedFile = struct { |
| 1635 | fs.File.OpenError || | 1632 | fs.File.OpenError || |
| 1636 | fs.File.ReadError || | 1633 | fs.File.ReadError || |
| 1637 | fs.File.StatError || | 1634 | fs.File.StatError || |
| | 1635 | fs.File.ChmodError || |
| 1638 | fs.Dir.ReadLinkError; | 1636 | fs.Dir.ReadLinkError; |
| 1639 | | 1637 | |
| 1640 | const Kind = enum { file, link }; | 1638 | const Kind = enum { file, link }; |
| ... | @@ -1746,3 +1744,37 @@ test { | ... | @@ -1746,3 +1744,37 @@ test { |
| 1746 | _ = Filter; | 1744 | _ = Filter; |
| 1747 | _ = FileType; | 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 | } |