github.com/u-root/u-root@v7.0.1-0.20200915234505-ad7babab0a8e+incompatible/pkg/upath/symlink.go (about) 1 // Copyright 2014-2017 the u-root Authors. All rights reserved 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 // Package upath contains utilities for dealing with symlinked paths. 6 package upath 7 8 import ( 9 "log" 10 "os" 11 "path/filepath" 12 ) 13 14 // AbsSymlink returns an absolute path for the link from a file to a target. 15 func AbsSymlink(originalFile, target string) string { 16 if !filepath.IsAbs(originalFile) { 17 var err error 18 originalFile, err = filepath.Abs(originalFile) 19 if err != nil { 20 // This should not happen on Unix systems, or you're 21 // already royally screwed. 22 log.Fatalf("could not determine absolute path for %v: %v", originalFile, err) 23 } 24 } 25 // Relative symlinks are resolved relative to the original file's 26 // parent directory. 27 // 28 // E.g. /bin/defaultsh -> ../bbin/elvish 29 if !filepath.IsAbs(target) { 30 return filepath.Join(filepath.Dir(originalFile), target) 31 } 32 return target 33 } 34 35 // IsTargetSymlink returns true if a target of a symlink is also a symlink. 36 func IsTargetSymlink(originalFile, target string) bool { 37 s, err := os.Lstat(AbsSymlink(originalFile, target)) 38 if err != nil { 39 return false 40 } 41 return (s.Mode() & os.ModeSymlink) == os.ModeSymlink 42 } 43 44 // ResolveUntilLastSymlink resolves until the last symlink. 45 // 46 // This is needed when we have a chain of symlinks and want the last 47 // symlink, not the file pointed to (which is why we don't use 48 // filepath.EvalSymlinks) 49 // 50 // I.e. 51 // 52 // /foo/bar -> ../baz/foo 53 // /baz/foo -> bla 54 // 55 // ResolveUntilLastSymlink(/foo/bar) returns /baz/foo. 56 func ResolveUntilLastSymlink(p string) string { 57 for target, err := os.Readlink(p); err == nil && IsTargetSymlink(p, target); target, err = os.Readlink(p) { 58 p = AbsSymlink(p, target) 59 } 60 return p 61 }