@@ -1181,7 +1181,6 @@ fn unpackTarball(f: *Fetch, out_dir: fs.Dir, reader: anytype) RunError!?[]const
11811181 std .tar .pipeToFileSystem (out_dir , reader , .{
11821182 .diagnostics = & diagnostics ,
11831183 .strip_components = 0 ,
1184- // https://github.com/ziglang/zig/issues/17463
11851184 .mode_mode = .ignore ,
11861185 .exclude_empty_directories = true ,
11871186 }) 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
15691568 var buf : [8000 ]u8 = undefined ;
15701569 var hasher = Manifest .Hash .init (.{});
15711570 hasher .update (hashed_file .normalized_path );
1571+
15721572 switch (hashed_file .kind ) {
15731573 .file = > {
15741574 var file = try dir .openFile (hashed_file .fs_path , .{});
15751575 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 = .{} ;
15791579 while (true ) {
15801580 const bytes_read = try file .read (& buf );
15811581 if (bytes_read == 0 ) break ;
15821582 hasher .update (buf [0.. bytes_read ]);
1583+ file_header .update (buf [0.. bytes_read ]);
1584+ }
1585+ if (file_header .isExecutable ()) {
1586+ try setExecutable (file );
15831587 }
15841588 },
15851589 .link = > {
@@ -1600,19 +1604,12 @@ fn deleteFileFallible(dir: fs.Dir, deleted_file: *DeletedFile) DeletedFile.Error
16001604 try dir .deleteFile (deleted_file .fs_path );
16011605}
16021606
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 );
16161613}
16171614
16181615const DeletedFile = struct {
@@ -1635,6 +1632,7 @@ const HashedFile = struct {
16351632 fs .File .OpenError ||
16361633 fs .File .ReadError ||
16371634 fs .File .StatError ||
1635+ fs .File .ChmodError ||
16381636 fs .Dir .ReadLinkError ;
16391637
16401638 const Kind = enum { file , link };
@@ -1746,3 +1744,37 @@ test {
17461744 _ = Filter ;
17471745 _ = FileType ;
17481746}
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+ }
0 commit comments