Unable to detect symlink

Hi,

I created a symlink file from unix shell with the command ln -s and I want from zig to determine its kind but doesn’t work, the kind type is always file

May you help me?

Below my code

test "SymLink" {
    const file = try std.fs.cwd().openFile("./file_size/left/sym_f010.txt", .{ });
    const stat = try file.stat();
    const metadata = try file.metadata();

    print("Using stat {}\n", .{stat.kind == std.fs.File.Kind.sym_link});
    print("Using metadata {any}\n", .{metadata.kind() == std.fs.File.Kind.sym_link});
}

1 Like

Symlink is followed when you open it. You need to stick with std.posix

Thanks for your reply but using fstatat doesn’t work

    const file_fd = try std.posix.open("./file_size/left", .{}, 0o600);
    const stat = try std.posix.fstatat(file_fd, "sym_f010.txt", 0);

    print("posix {}", .{stat});
    print("posix {}", .{std.posix.S.ISLNK(stat.mode)});

Check if std.os.linux.S.IFLNK bit is set in mode using std.os.linux.S.ISLNK

    const stat = ...;
    if (std.os.linux.S.ISLNK(stat.mode)) {
    }

See: man inode(7)

It’s the same code I posted using fstatat

PS
I’m on macOS

On Linux, to get a file descriptor of a symbolic link, both O_NOFOLLOW and O_PATH have to be set. See the O_PATH docs for open(2):

If pathname is a symbolic link and the O_NOFOLLOW flag is also specified, then the call returns a file descriptor referring to the symbolic link.

On Mac, it looks like the relevant flag is O_SYMLINK and possibly also O_NOFOLLOW

Side note: there’s actually a test for this in the Zig standard library fs tests, but right now it only tests Linux and Windows

2 Likes

It is the same, use the package std.posix instead of std.os.linux.
(For macos zig uses ISLNK from std.c.S)

2 Likes

GREAT!!!

The working code on macOS

The program crashes when NOFOLLOW is set, using SYMLINK is enough

test "SymLink" {
    const flags: std.posix.O = .{
        .SYMLINK = true,
    };
    const file_fd = try std.posix.open("./file_size/left/sym_f010.txt", flags, 0o600);
    const stat = try std.posix.fstat(file_fd);

    print("posix is symlink? {}\n", .{std.posix.S.ISLNK(stat.mode)});
}
1 Like