I want my Go program to resolve the targets of a few symlinks. The only trouble is these symlinks will be pointing to destinations that do not actually exist, which is fine because I do some filepath manipulations afterwards. Is this even possible? If I do a "readlink -f ", I do get a nil result with exit code 1.
// path is the filepath of a symlink
// this symlink will most likely be pointing to a non-existent file/location
// this is fine and is handled elsewhere
func handleSymlink(path *string) (bool, error) {
f, err := os.Lstat(*path)
if err != nil {
return false, err
}
// if f is nil, then this is not a symlink
if f == nil {
return false, nil
}
ln, err := os.Readlink(*path)
//ln, err := filepath.EvalSymlinks(*path)
// ignore IsNotExist errors...this is expected
if !os.IsNotExist(err) {
return false, err
}
path = &ln
return true, nil
}
Use os.Lstat func:
Lstat returns a FileInfo describing the named file. If the file is a symbolic link, the returned FileInfo describes the symbolic link. Lstat makes no attempt to follow the link. If there is an error, it will be of type *PathError.
So you can use returned os.FileInfo
value to check whether it's a symlink or not.
fileInfo.Mode()&os.ModeSymlink != 0
At this point you know that given path is symlink.
If you would like to get the actual path of symlink that is pointing to, use
filepath.EvalSymlinks(path)
Your updated code:
func handleSymlink(path *string) (bool, error) {
fileInfo, err := os.Lstat(*path)
if os.IsNotExist(err) || err != nil {
return false, err
}
// Check path is symlink or not
if fileInfo.Mode()&os.ModeSymlink != 0 {
actualPath, err := filepath.EvalSymlinks(*path)
if err != nil {
// Extract actual path from error msg
apath := strings.Split(err.Error(), ":")[0]
*path = strings.Split(apath, " ")[1]
return false, err
}
*path = actualPath
return true, nil
}
return false, nil
}
func main() {
path := "/Users/jeeva/test1"
result, err := handleSymlink(&path)
fmt.Println("Error:", err)
fmt.Println("Result:", result)
fmt.Println("Actual Path:", path)
}
Let's say we have following paths:
/Users/jeeva/test1 (symlink, pointing to /Users/jeeva/actualpath)
/Users/jeeva/actualpath
/Users/jeeva/actualpath2
If given path exists and it's a symlink:
#Input:
/Users/jeeva/test1
#Output:
Error: <nil>
Result: true
Actual Path: /Users/jeeva/actualpath
If given path is not exists:
#Input:
/Users/jeeva/test1
#Output:
Error lstat /Users/jeeva/notexists: no such file or directory
Result: false
Actual Path: /Users/jeeva/notexists
If given path is exists and it's not a symlink:
#Input:
/Users/jeeva/actualpath2
#Output:
Error <nil>
Result: false
Actual Path: /Users/jeeva/actualpath2
You want the Unix system call readlink
, which is exported in Go as os.Readlink
. It reads the content of a symlink and does no further processing — no checking for existence or recursive processing.
target, err := os.Readlink("test1")
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.