Commit ea6e0e33a7
Changed files (3)
src
lib/std/fs/file.zig
@@ -179,7 +179,7 @@ pub const File = struct {
lock_nonblocking: bool = false,
/// For POSIX systems this is the file system mode the file will
- /// be created with.
+ /// be created with. On other systems this is always 0.
mode: Mode = default_mode,
/// Setting this to `.blocking` prevents `O.NONBLOCK` from being passed even
@@ -307,6 +307,7 @@ pub const File = struct {
/// is unique to each filesystem.
inode: INode,
size: u64,
+ /// This is available on POSIX systems and is always 0 otherwise.
mode: Mode,
kind: Kind,
lib/std/tar.zig
@@ -1,6 +1,18 @@
pub const Options = struct {
/// Number of directory levels to skip when extracting files.
strip_components: u32 = 0,
+ /// How to handle the "mode" property of files from within the tar file.
+ mode_mode: ModeMode = .executable_bit_only,
+
+ const ModeMode = enum {
+ /// The mode from the tar file is completely ignored. Files are created
+ /// with the default mode when creating files.
+ ignore,
+ /// The mode from the tar file is inspected for the owner executable bit
+ /// only. This bit is copied to the group and other executable bits.
+ /// Other bits of the mode are left as the default when creating files.
+ executable_bit_only,
+ };
};
pub const Header = struct {
@@ -72,6 +84,17 @@ pub const Header = struct {
};
pub fn pipeToFileSystem(dir: std.fs.Dir, reader: anytype, options: Options) !void {
+ switch (options.mode_mode) {
+ .ignore => {},
+ .executable_bit_only => {
+ // This code does not look at the mode bits yet. To implement this feature,
+ // the implementation must be adjusted to look at the mode, and check the
+ // user executable bit, then call fchmod on newly created files when
+ // the executable bit is supposed to be set.
+ // It also needs to properly deal with ACLs on Windows.
+ @panic("TODO: unimplemented: tar ModeMode.executable_bit_only");
+ },
+ }
var file_name_buffer: [255]u8 = undefined;
var buffer: [512 * 8]u8 = undefined;
var start: usize = 0;
src/Package.zig
@@ -1,5 +1,6 @@
const Package = @This();
+const builtin = @import("builtin");
const std = @import("std");
const fs = std.fs;
const mem = std.mem;
@@ -440,6 +441,12 @@ fn unpackTarball(
try std.tar.pipeToFileSystem(out_dir, decompress.reader(), .{
.strip_components = 1,
+ // TODO: we would like to set this to executable_bit_only, but two
+ // things need to happen before that:
+ // 1. the tar implementation needs to support it
+ // 2. the hashing algorithm here needs to support detecting the is_executable
+ // bit on Windows from the ACLs (see the isExecutable function).
+ .mode_mode = .ignore,
});
}
@@ -468,7 +475,7 @@ const HashedFile = struct {
hash: [Hash.digest_length]u8,
failure: Error!void,
- const Error = fs.File.OpenError || fs.File.ReadError;
+ const Error = fs.File.OpenError || fs.File.ReadError || fs.File.StatError;
fn lessThan(context: void, lhs: *const HashedFile, rhs: *const HashedFile) bool {
_ = context;
@@ -544,6 +551,8 @@ fn hashFileFallible(dir: fs.Dir, hashed_file: *HashedFile) HashedFile.Error!void
var buf: [8000]u8 = undefined;
var file = try dir.openFile(hashed_file.path, .{});
var hasher = Hash.init(.{});
+ hasher.update(hashed_file.path);
+ hasher.update(&.{ 0, @boolToInt(try isExecutable(file)) });
while (true) {
const bytes_read = try file.read(&buf);
if (bytes_read == 0) break;
@@ -552,6 +561,19 @@ fn hashFileFallible(dir: fs.Dir, hashed_file: *HashedFile) HashedFile.Error!void
hasher.final(&hashed_file.hash);
}
+fn isExecutable(file: fs.File) !bool {
+ if (builtin.os.tag == .windows) {
+ // TODO check the ACL on Windows.
+ // Until this is implemented, this could be a false negative on
+ // 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.os.S.IXUSR) != 0;
+ }
+}
+
const hex_charset = "0123456789abcdef";
fn hex64(x: u64) [16]u8 {