# Unable to detect symlink

**URL:** <https://ziggit.dev/t/unable-to-detect-symlink/7857>\
**Category:** Help\
**Tags:** standard-library\
**Created:** [January 14, 2025, 11:45am UTC](https://ziggit.dev/t/unable-to-detect-symlink/7857 "2025-01-14T11:45:45Z")\
**Posts on this page:** 9\
**Page:** 1

<div class="post-metadata">

**Author:** ![dafi](https://ziggit.dev/user_avatar/ziggit.dev/dafi/32/4208_2.png) [@dafi](https://ziggit.dev/u/dafi)\
**Post date:** [January 14, 2025, 11:45am UTC](https://ziggit.dev/t/unable-to-detect-symlink/7857/1 "2025-01-14T11:45:45Z")

</div>

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

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

```

---

<div class="post-metadata">

**Author:** ![yataro](https://ziggit.dev/letter_avatar_proxy/v4/letter/y/6de8d8/32.png) [@yataro](https://ziggit.dev/u/yataro)\
**Post date:** [January 14, 2025, 12:01pm UTC](https://ziggit.dev/t/unable-to-detect-symlink/7857/2 "2025-01-14T12:01:52Z")

</div>

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

---

<div class="post-metadata">

**Author:** ![dafi](https://ziggit.dev/user_avatar/ziggit.dev/dafi/32/4208_2.png) [@dafi](https://ziggit.dev/u/dafi)\
**Post date:** [January 14, 2025, 12:40pm UTC](https://ziggit.dev/t/unable-to-detect-symlink/7857/3 "2025-01-14T12:40:54Z")

</div>

Thanks for your reply but using `fstatat` doesn’t work

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

```

---

<div class="post-metadata">

**Author:** ![dimdin](https://ziggit.dev/user_avatar/ziggit.dev/dimdin/32/1457_2.png) [@dimdin](https://ziggit.dev/u/dimdin)\
**Post date:** [January 14, 2025, 12:42pm UTC](https://ziggit.dev/t/unable-to-detect-symlink/7857/4 "2025-01-14T12:42:47Z")

</div>

Check if [std.os.linux.S.IFLNK](https://ziglang.org/documentation/master/std/#std.os.linux.S.IFLNK) bit is set in [mode](https://ziglang.org/documentation/master/std/#std.os.linux.x86_64.Stat) using [std.os.linux.S.ISLNK](https://ziglang.org/documentation/master/std/#std.os.linux.S.ISLNK)

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

```

See: [man inode(7)](https://man7.org/linux/man-pages/man7/inode.7.html)

---

<div class="post-metadata">

**Author:** ![dafi](https://ziggit.dev/user_avatar/ziggit.dev/dafi/32/4208_2.png) [@dafi](https://ziggit.dev/u/dafi)\
**Post date:** [January 14, 2025, 12:51pm UTC](https://ziggit.dev/t/unable-to-detect-symlink/7857/5 "2025-01-14T12:51:03Z")

</div>

It’s the same code I posted using fstatat

PS  
I’m on macOS

---

<div class="post-metadata">

**Author:** ![squeek502](https://ziggit.dev/user_avatar/ziggit.dev/squeek502/32/409_2.png) [@squeek502](https://ziggit.dev/u/squeek502)\
**Post date:** [January 14, 2025, 12:53pm UTC](https://ziggit.dev/t/unable-to-detect-symlink/7857/6 "2025-01-14T12:53:52Z")

</div>

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)](https://man7.org/linux/man-pages/man2/openat.2.html):

> 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`](https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man2/open.2.html)

Side note: there’s actually [a test for this in the Zig standard library fs tests](https://github.com/ziglang/zig/blob/8019694e17b6e6b6d3f9cab91233deea7c39a301/lib/std/fs/test.zig#L220), but right now it only tests Linux and Windows

---

<div class="post-metadata">

**Author:** ![dimdin](https://ziggit.dev/user_avatar/ziggit.dev/dimdin/32/1457_2.png) [@dimdin](https://ziggit.dev/u/dimdin)\
**Post date:** [January 14, 2025, 12:54pm UTC](https://ziggit.dev/t/unable-to-detect-symlink/7857/7 "2025-01-14T12:54:15Z")

</div>

It is the same, use the package `std.posix` instead of `std.os.linux`.  
(For macos zig uses `ISLNK` from [std.c.S](https://ziglang.org/documentation/master/std/#std.c.S))

---

<div class="post-metadata">

**Author:** ![dafi](https://ziggit.dev/user_avatar/ziggit.dev/dafi/32/4208_2.png) [@dafi](https://ziggit.dev/u/dafi)\
**Post date:** [January 14, 2025, 1:32pm UTC](https://ziggit.dev/t/unable-to-detect-symlink/7857/8 "2025-01-14T13:32:04Z")

</div>

GREAT!!!

The working code on macOS

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

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

```

---

<div class="post-metadata">

**Author:** ![npc1054657282](https://ziggit.dev/user_avatar/ziggit.dev/npc1054657282/32/5790_2.png) [@npc1054657282](https://ziggit.dev/u/npc1054657282)\
**Post date:** [October 7, 2025, 3:50pm UTC](https://ziggit.dev/t/unable-to-detect-symlink/7857/9 "2025-10-07T15:50:24Z")

</div>

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)`
