github.com/haraldrudell/parl@v0.4.176/pfs/abs-eval.go (about) 1 /* 2 © 2021–present Harald Rudell <harald.rudell@gmail.com> (https://haraldrudell.github.io/haraldrudell/) 3 ISC License 4 */ 5 6 package pfs 7 8 import ( 9 "path/filepath" 10 11 "github.com/haraldrudell/parl/perrors" 12 ) 13 14 const ( 15 // do not evaluate symlinks argument to [AbsEval] 16 RetainSymlinks = true 17 ) 18 19 // AbsEval returns an absolute path with resolved symlinks 20 // - if symlinks are evaluated, the path must exist 21 // - non-existing path is checked using punix.IsENOENT(err) 22 // - if path is relative, the process’ current directory is used to make path absolute. 23 // path empty returns the process’ current directory as absolute evaled path 24 // - absPath is absolute and only empty on error 25 // - absPath is clean: 26 // - — no multiple Separators in sequence 27 // - — no “.” path name elements 28 // - — no infix or postfix “..” path name element or to path above root 29 // - when evaluating symlinks, the path is verified to exist 30 // - if retainSymlinks is RetainSymlinks, symlinks are returned 31 // - errors originate from: 32 // - — [os.Lstat] [os.Readlink] [os.Getwd] or 33 // - — infix path-segment not directory or 34 // - — encountering more than 255 symlinks 35 func AbsEval(path string, retainSymlinks ...bool) (absPath string, err error) { 36 var didClean bool 37 38 // ensure path is absolute 39 if didClean = !filepath.IsAbs(path); didClean { 40 // errors from [os.Getwd] 41 if absPath, err = filepath.Abs(path); perrors.IsPF(&err, "filepath.Abs %w", err) { 42 return 43 } 44 } else { 45 absPath = path 46 } 47 48 // evaluate symlink 49 if len(retainSymlinks) == 0 || !retainSymlinks[0] { 50 // errors from [os.Lstat] [os.Readlink] or 51 // - infix path segment not directory 52 // - or encountering more than 255 symlinks 53 if absPath, err = filepath.EvalSymlinks(absPath); perrors.IsPF(&err, "EvalSymlinks %w", err) { 54 55 // // *errorglue.errorStack *fmt.wrapError *fs.PathError syscall.Errno 56 // parl.Log("filepath.EvalSymlinks ENOT error chanin: %s", errorglue.DumpChain(err)) 57 // // os.IsNotExist fails: false 58 // parl.Log("os.IsNotExist fails: %t", os.IsNotExist(err)) 59 // if errnoValue := punix.Errno(err); errnoValue != 0 { 60 // // errno: ENOENT 2 0x2 61 // parl.Log(punix.ErrnoString("errno", errnoValue)) 62 // } 63 // // punix.IsENOENT: true 64 // parl.Log("punix.IsENOENT: %t", punix.IsENOENT(err)) 65 66 return 67 } 68 } else if !didClean { 69 absPath = filepath.Clean(absPath) 70 } 71 72 return 73 }