@@ -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
+ }
0 commit comments