github.com/mattolenik/notify@v0.9.1/util.go (about)

     1  // Copyright (c) 2014-2015 The Notify Authors. All rights reserved.
     2  // Use of this source code is governed by the MIT license that can be
     3  // found in the LICENSE file.
     4  
     5  package notify
     6  
     7  import (
     8  	"errors"
     9  	"os"
    10  	"path/filepath"
    11  	"strings"
    12  )
    13  
    14  const all = ^Event(0)
    15  const sep = string(os.PathSeparator)
    16  
    17  var errDepth = errors.New("exceeded allowed iteration count (circular symlink?)")
    18  
    19  func min(i, j int) int {
    20  	if i > j {
    21  		return j
    22  	}
    23  	return i
    24  }
    25  
    26  func max(i, j int) int {
    27  	if i < j {
    28  		return j
    29  	}
    30  	return i
    31  }
    32  
    33  // must panics if err is non-nil.
    34  func must(err error) {
    35  	if err != nil {
    36  		panic(err)
    37  	}
    38  }
    39  
    40  // nonil gives first non-nil error from the given arguments.
    41  func nonil(err ...error) error {
    42  	for _, err := range err {
    43  		if err != nil {
    44  			return err
    45  		}
    46  	}
    47  	return nil
    48  }
    49  
    50  func cleanpath(path string) (realpath string, isrec bool, err error) {
    51  	if strings.HasSuffix(path, "...") {
    52  		isrec = true
    53  		path = path[:len(path)-3]
    54  	}
    55  	if path, err = filepath.Abs(path); err != nil {
    56  		return "", false, err
    57  	}
    58  	if path, err = canonical(path); err != nil {
    59  		return "", false, err
    60  	}
    61  	return path, isrec, nil
    62  }
    63  
    64  // canonical resolves any symlink in the given path and returns it in a clean form.
    65  // It expects the path to be absolute. It fails to resolve circular symlinks by
    66  // maintaining a simple iteration limit.
    67  func canonical(p string) (string, error) {
    68  	p, err := filepath.Abs(p)
    69  	if err != nil {
    70  		return "", err
    71  	}
    72  	for i, j, depth := 1, 0, 1; i < len(p); i, depth = i+1, depth+1 {
    73  		if depth > 128 {
    74  			return "", &os.PathError{Op: "canonical", Path: p, Err: errDepth}
    75  		}
    76  		if j = strings.IndexRune(p[i:], '/'); j == -1 {
    77  			j, i = i, len(p)
    78  		} else {
    79  			j, i = i, i+j
    80  		}
    81  		fi, err := os.Lstat(p[:i])
    82  		if err != nil {
    83  			return "", err
    84  		}
    85  		if fi.Mode()&os.ModeSymlink == os.ModeSymlink {
    86  			s, err := os.Readlink(p[:i])
    87  			if err != nil {
    88  				return "", err
    89  			}
    90  			if filepath.IsAbs(s) {
    91  				p = "/" + s + p[i:]
    92  			} else {
    93  				p = p[:j] + s + p[i:]
    94  			}
    95  			i = 1 // no guarantee s is canonical, start all over
    96  		}
    97  	}
    98  	return filepath.Clean(p), nil
    99  }
   100  
   101  func joinevents(events []Event) (e Event) {
   102  	if len(events) == 0 {
   103  		e = All
   104  	} else {
   105  		for _, event := range events {
   106  			e |= event
   107  		}
   108  	}
   109  	return
   110  }
   111  
   112  func split(s string) (string, string) {
   113  	if i := lastIndexSep(s); i != -1 {
   114  		return s[:i], s[i+1:]
   115  	}
   116  	return "", s
   117  }
   118  
   119  func base(s string) string {
   120  	if i := lastIndexSep(s); i != -1 {
   121  		return s[i+1:]
   122  	}
   123  	return s
   124  }
   125  
   126  func indexbase(root, name string) int {
   127  	if n, m := len(root), len(name); m >= n && name[:n] == root &&
   128  		(n == m || name[n] == os.PathSeparator) {
   129  		return min(n+1, m)
   130  	}
   131  	return -1
   132  }
   133  
   134  func indexSep(s string) int {
   135  	for i := 0; i < len(s); i++ {
   136  		if s[i] == os.PathSeparator {
   137  			return i
   138  		}
   139  	}
   140  	return -1
   141  }
   142  
   143  func lastIndexSep(s string) int {
   144  	for i := len(s) - 1; i >= 0; i-- {
   145  		if s[i] == os.PathSeparator {
   146  			return i
   147  		}
   148  	}
   149  	return -1
   150  }