| ... | @@ -1789,12 +1789,9 @@ test { | ... | @@ -1789,12 +1789,9 @@ test { |
| 1789 | _ = UnpackResult; | 1789 | _ = UnpackResult; |
| 1790 | } | 1790 | } |
| 1791 | | 1791 | |
| 1792 | // Detects executable header: ELF magic header or shebang line. | 1792 | // Detects executable header: ELF or Macho-O magic header or shebang line. |
| 1793 | const FileHeader = struct { | 1793 | const FileHeader = struct { |
| 1794 | const elf_magic = std.elf.MAGIC; | 1794 | header: [4]u8 = undefined, |
| 1795 | const shebang = "#!"; | | |
| 1796 | | | |
| 1797 | header: [@max(elf_magic.len, shebang.len)]u8 = undefined, | | |
| 1798 | bytes_read: usize = 0, | 1795 | bytes_read: usize = 0, |
| 1799 | | 1796 | |
| 1800 | pub fn update(self: *FileHeader, buf: []const u8) void { | 1797 | pub fn update(self: *FileHeader, buf: []const u8) void { |
| ... | @@ -1804,9 +1801,27 @@ const FileHeader = struct { | ... | @@ -1804,9 +1801,27 @@ const FileHeader = struct { |
| 1804 | self.bytes_read += n; | 1801 | self.bytes_read += n; |
| 1805 | } | 1802 | } |
| 1806 | | 1803 | |
| | 1804 | fn isScript(self: *FileHeader) bool { |
| | 1805 | const shebang = "#!"; |
| | 1806 | return std.mem.eql(u8, self.header[0..@min(self.bytes_read, shebang.len)], shebang); |
| | 1807 | } |
| | 1808 | |
| | 1809 | fn isElf(self: *FileHeader) bool { |
| | 1810 | const elf_magic = std.elf.MAGIC; |
| | 1811 | return std.mem.eql(u8, self.header[0..@min(self.bytes_read, elf_magic.len)], elf_magic); |
| | 1812 | } |
| | 1813 | |
| | 1814 | fn isMachO(self: *FileHeader) bool { |
| | 1815 | if (self.bytes_read < 4) return false; |
| | 1816 | const magic_number = std.mem.readInt(u32, &self.header, builtin.cpu.arch.endian()); |
| | 1817 | return magic_number == std.macho.MH_MAGIC or |
| | 1818 | magic_number == std.macho.MH_MAGIC_64 or |
| | 1819 | magic_number == std.macho.FAT_MAGIC or |
| | 1820 | magic_number == std.macho.FAT_MAGIC_64; |
| | 1821 | } |
| | 1822 | |
| 1807 | pub fn isExecutable(self: *FileHeader) bool { | 1823 | pub fn isExecutable(self: *FileHeader) bool { |
| 1808 | return std.mem.eql(u8, self.header[0..@min(self.bytes_read, shebang.len)], shebang) or | 1824 | return self.isScript() or self.isElf() or self.isMachO(); |
| 1809 | std.mem.eql(u8, self.header[0..@min(self.bytes_read, elf_magic.len)], elf_magic); | | |
| 1810 | } | 1825 | } |
| 1811 | }; | 1826 | }; |
| 1812 | | 1827 | |
| ... | @@ -1814,12 +1829,18 @@ test FileHeader { | ... | @@ -1814,12 +1829,18 @@ test FileHeader { |
| 1814 | var h: FileHeader = .{}; | 1829 | var h: FileHeader = .{}; |
| 1815 | try std.testing.expect(!h.isExecutable()); | 1830 | try std.testing.expect(!h.isExecutable()); |
| 1816 | | 1831 | |
| 1817 | h.update(FileHeader.elf_magic[0..2]); | 1832 | const elf_magic = std.elf.MAGIC; |
| | 1833 | h.update(elf_magic[0..2]); |
| 1818 | try std.testing.expect(!h.isExecutable()); | 1834 | try std.testing.expect(!h.isExecutable()); |
| 1819 | h.update(FileHeader.elf_magic[2..4]); | 1835 | h.update(elf_magic[2..4]); |
| | 1836 | try std.testing.expect(h.isExecutable()); |
| | 1837 | |
| | 1838 | h.update(elf_magic[2..4]); |
| 1820 | try std.testing.expect(h.isExecutable()); | 1839 | try std.testing.expect(h.isExecutable()); |
| 1821 | | 1840 | |
| 1822 | h.update(FileHeader.elf_magic[2..4]); | 1841 | const macho64_magic_bytes = [_]u8{ 0xCF, 0xFA, 0xED, 0xFE }; |
| | 1842 | h.bytes_read = 0; |
| | 1843 | h.update(&macho64_magic_bytes); |
| 1823 | try std.testing.expect(h.isExecutable()); | 1844 | try std.testing.expect(h.isExecutable()); |
| 1824 | } | 1845 | } |
| 1825 | | 1846 | |