github.com/DiversionCompany/notify@v0.9.9/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  // indexrel returns the index of the first char of name that is
   127  // below/relative to root. It returns -1 if name is not a child of root.
   128  func indexrel(root, name string) int {
   129  	if n, m := len(root), len(name); m > n && name[:n] == root &&
   130  		name[n] == os.PathSeparator {
   131  		return n + 1
   132  	}
   133  	return -1
   134  }
   135  
   136  func indexSep(s string) int {
   137  	for i := 0; i < len(s); i++ {
   138  		if s[i] == os.PathSeparator {
   139  			return i
   140  		}
   141  	}
   142  	return -1
   143  }
   144  
   145  func lastIndexSep(s string) int {
   146  	for i := len(s) - 1; i >= 0; i-- {
   147  		if s[i] == os.PathSeparator {
   148  			return i
   149  		}
   150  	}
   151  	return -1
   152  }