os.Stat() and os.Lstat() are both functions provided by the package os for retrieving information about files or directories. However, they behave slightly differently, especially when dealing with symbolic links.

Let us create new files and directory like:

Bash:
1
2
3
4
5
6
7
8
# mkdir /tmp/test
# cd /tmp/test/
# echo golangnote > file
# ln -s /tmp/test link_to_tmp
# ls -l
total 4
-rw-r--r-- 1 root root 11 May 19 22:21 file
lrwxrwxrwx 1 root root  9 May 19 22:21 link_to_tmp -> /tmp/test

And then write two functions to print detailed information about the file, such as file name, file mode, size and so on.

Go:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
// With os.Stat
func WithStat(path string) error {
        info, err := os.Stat(path)
        if err != nil {
                return err
        }

        fmt.Printf("File %s from funcstion os.Stat:\n", path)
        fmt.Printf("Name:     %v\n", info.Name())
        fmt.Printf("Size:     %v\n", info.Size())
        fmt.Printf("Mode:     %v\n", info.Mode())
        fmt.Printf("ModeTime: %v\n", info.ModTime())
        fmt.Printf("IsDir   : %v\n", info.IsDir())

        return nil
}

// With os.Lstat
func WithLstat(path string) error {
        info, err := os.Lstat(path)
        if err != nil {
                return err
        }

        fmt.Printf("File %s from funcstion os.Lstat:\n", path)
        fmt.Printf("Name:     %v\n", info.Name())
        fmt.Printf("Size:     %v\n", info.Size())
        fmt.Printf("Mode:     %v\n", info.Mode())
        fmt.Printf("ModeTime: %v\n", info.ModTime())
        fmt.Printf("IsDir   : %v\n", info.IsDir())

        return nil
}

Run with the regular file

Go:
1
2
WithStat("/tmp/test/file")
WithLstat("/tmp/test/file")

Output:

plaintext:
1
2
3
4
5
6
7
8
9
10
11
12
File /tmp/test/file from funcstion os.Stat:
Name:     file
Size:     11
Mode:     -rw-r--r--
ModeTime: 2024-05-19 22:21:27.699862372 +0800 HKT
IsDir   : false
File /tmp/test/file from funcstion os.Lstat:
Name:     file
Size:     11
Mode:     -rw-r--r--
ModeTime: 2024-05-19 22:21:27.699862372 +0800 HKT
IsDir   : false

Run with the soft link file

Go:
1
2
WithStat("/tmp/test/link_to_tmp")
WithLstat("/tmp/test/link_to_tmp")

Output:

plaintext:
1
2
3
4
5
6
7
8
9
10
11
12
File /tmp/test/link_to_tmp from funcstion os.Stat:
Name:     link_to_tmp
Size:     4096
Mode:     drwxr-xr-x
ModeTime: 2024-05-19 22:21:42.159864114 +0800 HKT
IsDir   : true
File /tmp/test/link_to_tmp from funcstion os.Lstat:
Name:     link_to_tmp
Size:     9
Mode:     Lrwxrwxrwx
ModeTime: 2024-05-19 22:21:42.159864114 +0800 HKT
IsDir   : false

That means there is not any difference between os.Stat() and os.Lstat() for hard link file.

In summary, when working with the file system, os.Stat() is used when we want information about the target of a symbolic link, while os.Lstat() is used when we want information about the symbolic link itself.