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});
}

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

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

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)});
}

A more cross-platform solution: Use posix’s fstatat to determine if it is a symbolic link.
std.posix.fstatat(dirfd, pathname, std.posix.AT.SYMLINK_NOFOLLOW)