mirror of
https://github.com/ziglang/zig.git
synced 2025-12-16 03:03:09 +00:00
package manager: set executable bit
Based on file content. Detects elf magic header or shebang line.
Executable bit is ignored in hash calculation, as it was before this. So
packages hashes are not changed.
Reference:
https://github.com/ziglang/zig/issues/17463#issuecomment-1984798880
Fixes: 17463
Test is here:
7c4600d7bb/src/main.zig (L307)
(if #19500 got accepted I'll move this test to the Fetch.zig)
This commit is contained in:
parent
4a8121c1ab
commit
34bb670bb6
@ -1181,7 +1181,6 @@ fn unpackTarball(f: *Fetch, out_dir: fs.Dir, reader: anytype) RunError!?[]const
|
|||||||
std.tar.pipeToFileSystem(out_dir, reader, .{
|
std.tar.pipeToFileSystem(out_dir, reader, .{
|
||||||
.diagnostics = &diagnostics,
|
.diagnostics = &diagnostics,
|
||||||
.strip_components = 0,
|
.strip_components = 0,
|
||||||
// https://github.com/ziglang/zig/issues/17463
|
|
||||||
.mode_mode = .ignore,
|
.mode_mode = .ignore,
|
||||||
.exclude_empty_directories = true,
|
.exclude_empty_directories = true,
|
||||||
}) catch |err| return f.fail(f.location_tok, try eb.printString(
|
}) 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
|
|||||||
var buf: [8000]u8 = undefined;
|
var buf: [8000]u8 = undefined;
|
||||||
var hasher = Manifest.Hash.init(.{});
|
var hasher = Manifest.Hash.init(.{});
|
||||||
hasher.update(hashed_file.normalized_path);
|
hasher.update(hashed_file.normalized_path);
|
||||||
|
|
||||||
switch (hashed_file.kind) {
|
switch (hashed_file.kind) {
|
||||||
.file => {
|
.file => {
|
||||||
var file = try dir.openFile(hashed_file.fs_path, .{});
|
var file = try dir.openFile(hashed_file.fs_path, .{});
|
||||||
defer file.close();
|
defer file.close();
|
||||||
// When implementing https://github.com/ziglang/zig/issues/17463
|
// Hard-coded false executable bit: https://github.com/ziglang/zig/issues/17463
|
||||||
// this will change to hard-coded `false`.
|
hasher.update(&.{ 0, 0 });
|
||||||
hasher.update(&.{ 0, @intFromBool(try isExecutable(file)) });
|
var file_header: FileHeader = .{};
|
||||||
while (true) {
|
while (true) {
|
||||||
const bytes_read = try file.read(&buf);
|
const bytes_read = try file.read(&buf);
|
||||||
if (bytes_read == 0) break;
|
if (bytes_read == 0) break;
|
||||||
hasher.update(buf[0..bytes_read]);
|
hasher.update(buf[0..bytes_read]);
|
||||||
|
file_header.update(buf[0..bytes_read]);
|
||||||
|
}
|
||||||
|
if (file_header.isExecutable()) {
|
||||||
|
try setExecutable(file);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
.link => {
|
.link => {
|
||||||
@ -1600,19 +1604,12 @@ fn deleteFileFallible(dir: fs.Dir, deleted_file: *DeletedFile) DeletedFile.Error
|
|||||||
try dir.deleteFile(deleted_file.fs_path);
|
try dir.deleteFile(deleted_file.fs_path);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn isExecutable(file: fs.File) !bool {
|
fn setExecutable(file: fs.File) !void {
|
||||||
// When implementing https://github.com/ziglang/zig/issues/17463
|
if (!std.fs.has_executable_bit) return;
|
||||||
// this function will not check the mode but instead check if the file is an ELF
|
|
||||||
// file or has a shebang line.
|
const S = std.posix.S;
|
||||||
if (native_os == .windows) {
|
const mode = fs.File.default_mode | S.IXUSR | S.IXGRP | S.IXOTH;
|
||||||
// Until this is implemented, this could be a false negative on
|
try file.chmod(mode);
|
||||||
// Windows, which is why we do not yet set executable_bit_only above
|
|
||||||
// when unpacking the tarball.
|
|
||||||
return false;
|
|
||||||
} else {
|
|
||||||
const stat = try file.stat();
|
|
||||||
return (stat.mode & std.posix.S.IXUSR) != 0;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const DeletedFile = struct {
|
const DeletedFile = struct {
|
||||||
@ -1635,6 +1632,7 @@ const HashedFile = struct {
|
|||||||
fs.File.OpenError ||
|
fs.File.OpenError ||
|
||||||
fs.File.ReadError ||
|
fs.File.ReadError ||
|
||||||
fs.File.StatError ||
|
fs.File.StatError ||
|
||||||
|
fs.File.ChmodError ||
|
||||||
fs.Dir.ReadLinkError;
|
fs.Dir.ReadLinkError;
|
||||||
|
|
||||||
const Kind = enum { file, link };
|
const Kind = enum { file, link };
|
||||||
@ -1746,3 +1744,37 @@ test {
|
|||||||
_ = Filter;
|
_ = Filter;
|
||||||
_ = FileType;
|
_ = FileType;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Detects executable header: ELF magic header or shebang line.
|
||||||
|
const FileHeader = struct {
|
||||||
|
const elf_magic = std.elf.MAGIC;
|
||||||
|
const shebang = "#!";
|
||||||
|
|
||||||
|
header: [@max(elf_magic.len, shebang.len)]u8 = undefined,
|
||||||
|
bytes_read: usize = 0,
|
||||||
|
|
||||||
|
pub fn update(self: *FileHeader, buf: []const u8) void {
|
||||||
|
if (self.bytes_read >= self.header.len) return;
|
||||||
|
const n = @min(self.header.len - self.bytes_read, buf.len);
|
||||||
|
@memcpy(self.header[self.bytes_read..][0..n], buf[0..n]);
|
||||||
|
self.bytes_read += n;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn isExecutable(self: *FileHeader) bool {
|
||||||
|
return std.mem.eql(u8, self.header[0..shebang.len], shebang) or
|
||||||
|
std.mem.eql(u8, self.header[0..elf_magic.len], elf_magic);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
test FileHeader {
|
||||||
|
var h: FileHeader = .{};
|
||||||
|
try std.testing.expect(!h.isExecutable());
|
||||||
|
|
||||||
|
h.update(FileHeader.elf_magic[0..2]);
|
||||||
|
try std.testing.expect(!h.isExecutable());
|
||||||
|
h.update(FileHeader.elf_magic[2..4]);
|
||||||
|
try std.testing.expect(h.isExecutable());
|
||||||
|
|
||||||
|
h.update(FileHeader.elf_magic[2..4]);
|
||||||
|
try std.testing.expect(h.isExecutable());
|
||||||
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user