aboutsummaryrefslogblamecommitdiffstats
path: root/Godeps/_workspace/src/github.com/rjeczalik/notify/util.go
blob: 67e01fbbd08ecdb9474382d1fa82e91a159fb074 (plain) (tree)





















































































































































                                                                                         
// Copyright (c) 2014-2015 The Notify Authors. All rights reserved.
// Use of this source code is governed by the MIT license that can be
// found in the LICENSE file.

package notify

import (
    "errors"
    "os"
    "path/filepath"
    "strings"
)

const all = ^Event(0)
const sep = string(os.PathSeparator)

var errDepth = errors.New("exceeded allowed iteration count (circular symlink?)")

func min(i, j int) int {
    if i > j {
        return j
    }
    return i
}

func max(i, j int) int {
    if i < j {
        return j
    }
    return i
}

// must panics if err is non-nil.
func must(err error) {
    if err != nil {
        panic(err)
    }
}

// nonil gives first non-nil error from the given arguments.
func nonil(err ...error) error {
    for _, err := range err {
        if err != nil {
            return err
        }
    }
    return nil
}

func cleanpath(path string) (realpath string, isrec bool, err error) {
    if strings.HasSuffix(path, "...") {
        isrec = true
        path = path[:len(path)-3]
    }
    if path, err = filepath.Abs(path); err != nil {
        return "", false, err
    }
    if path, err = canonical(path); err != nil {
        return "", false, err
    }
    return path, isrec, nil
}

// canonical resolves any symlink in the given path and returns it in a clean form.
// It expects the path to be absolute. It fails to resolve circular symlinks by
// maintaining a simple iteration limit.
func canonical(p string) (string, error) {
    p, err := filepath.Abs(p)
    if err != nil {
        return "", err
    }
    for i, j, depth := 1, 0, 1; i < len(p); i, depth = i+1, depth+1 {
        if depth > 128 {
            return "", &os.PathError{Op: "canonical", Path: p, Err: errDepth}
        }
        if j = strings.IndexRune(p[i:], '/'); j == -1 {
            j, i = i, len(p)
        } else {
            j, i = i, i+j
        }
        fi, err := os.Lstat(p[:i])
        if err != nil {
            return "", err
        }
        if fi.Mode()&os.ModeSymlink == os.ModeSymlink {
            s, err := os.Readlink(p[:i])
            if err != nil {
                return "", err
            }
            if filepath.IsAbs(s) {
                p = "/" + s + p[i:]
            } else {
                p = p[:j] + s + p[i:]
            }
            i = 1 // no guarantee s is canonical, start all over
        }
    }
    return filepath.Clean(p), nil
}

func joinevents(events []Event) (e Event) {
    if len(events) == 0 {
        e = All
    } else {
        for _, event := range events {
            e |= event
        }
    }
    return
}

func split(s string) (string, string) {
    if i := lastIndexSep(s); i != -1 {
        return s[:i], s[i+1:]
    }
    return "", s
}

func base(s string) string {
    if i := lastIndexSep(s); i != -1 {
        return s[i+1:]
    }
    return s
}

func indexbase(root, name string) int {
    if n, m := len(root), len(name); m >= n && name[:n] == root &&
        (n == m || name[n] == os.PathSeparator) {
        return min(n+1, m)
    }
    return -1
}

func indexSep(s string) int {
    for i := 0; i < len(s); i++ {
        if s[i] == os.PathSeparator {
            return i
        }
    }
    return -1
}

func lastIndexSep(s string) int {
    for i := len(s) - 1; i >= 0; i-- {
        if s[i] == os.PathSeparator {
            return i
        }
    }
    return -1
}