summaryrefslogtreecommitdiffstats
path: root/vendor/gopkg.in/src-d/go-billy.v4
diff options
context:
space:
mode:
authorLauris BH <lauris@nix.lv>2018-11-27 23:52:20 +0200
committertechknowlogick <hello@techknowlogick.com>2018-11-27 16:52:20 -0500
commit08bf443016bae30690417b4835076709ef36e3b0 (patch)
treeece591d95416dd85e726dce15e0ab52872a17b06 /vendor/gopkg.in/src-d/go-billy.v4
parent294904321cb6de535237a6a156d5c4ec462bc117 (diff)
downloadgitea-08bf443016bae30690417b4835076709ef36e3b0.tar.gz
gitea-08bf443016bae30690417b4835076709ef36e3b0.zip
Implement git refs API for listing references (branches, tags and other) (#5354)
* Inital routes to git refs api * Git refs API implementation * Update swagger * Fix copyright * Make swagger happy add basic test * Fix test * Fix test again :)
Diffstat (limited to 'vendor/gopkg.in/src-d/go-billy.v4')
-rw-r--r--vendor/gopkg.in/src-d/go-billy.v4/LICENSE201
-rw-r--r--vendor/gopkg.in/src-d/go-billy.v4/fs.go202
-rw-r--r--vendor/gopkg.in/src-d/go-billy.v4/helper/chroot/chroot.go242
-rw-r--r--vendor/gopkg.in/src-d/go-billy.v4/helper/polyfill/polyfill.go105
-rw-r--r--vendor/gopkg.in/src-d/go-billy.v4/osfs/os.go139
-rw-r--r--vendor/gopkg.in/src-d/go-billy.v4/osfs/os_posix.go21
-rw-r--r--vendor/gopkg.in/src-d/go-billy.v4/osfs/os_windows.go57
-rw-r--r--vendor/gopkg.in/src-d/go-billy.v4/util/glob.go111
-rw-r--r--vendor/gopkg.in/src-d/go-billy.v4/util/util.go224
9 files changed, 1302 insertions, 0 deletions
diff --git a/vendor/gopkg.in/src-d/go-billy.v4/LICENSE b/vendor/gopkg.in/src-d/go-billy.v4/LICENSE
new file mode 100644
index 0000000000..9d60756894
--- /dev/null
+++ b/vendor/gopkg.in/src-d/go-billy.v4/LICENSE
@@ -0,0 +1,201 @@
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+ 1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+ 2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+ 3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+ 4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+ 6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+ 7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+ 8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+ 9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+ END OF TERMS AND CONDITIONS
+
+ APPENDIX: How to apply the Apache License to your work.
+
+ To apply the Apache License to your work, attach the following
+ boilerplate notice, with the fields enclosed by brackets "{}"
+ replaced with your own identifying information. (Don't include
+ the brackets!) The text should be enclosed in the appropriate
+ comment syntax for the file format. We also recommend that a
+ file or class name and description of purpose be included on the
+ same "printed page" as the copyright notice for easier
+ identification within third-party archives.
+
+ Copyright 2017 Sourced Technologies S.L.
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
diff --git a/vendor/gopkg.in/src-d/go-billy.v4/fs.go b/vendor/gopkg.in/src-d/go-billy.v4/fs.go
new file mode 100644
index 0000000000..a9efccdeb2
--- /dev/null
+++ b/vendor/gopkg.in/src-d/go-billy.v4/fs.go
@@ -0,0 +1,202 @@
+package billy
+
+import (
+ "errors"
+ "io"
+ "os"
+ "time"
+)
+
+var (
+ ErrReadOnly = errors.New("read-only filesystem")
+ ErrNotSupported = errors.New("feature not supported")
+ ErrCrossedBoundary = errors.New("chroot boundary crossed")
+)
+
+// Capability holds the supported features of a billy filesystem. This does
+// not mean that the capability has to be supported by the underlying storage.
+// For example, a billy filesystem may support WriteCapability but the
+// storage be mounted in read only mode.
+type Capability uint64
+
+const (
+ // WriteCapability means that the fs is writable.
+ WriteCapability Capability = 1 << iota
+ // ReadCapability means that the fs is readable.
+ ReadCapability
+ // ReadAndWriteCapability is the ability to open a file in read and write mode.
+ ReadAndWriteCapability
+ // SeekCapability means it is able to move position inside the file.
+ SeekCapability
+ // TruncateCapability means that a file can be truncated.
+ TruncateCapability
+ // LockCapability is the ability to lock a file.
+ LockCapability
+
+ // DefaultCapabilities lists all capable features supported by filesystems
+ // without Capability interface. This list should not be changed until a
+ // major version is released.
+ DefaultCapabilities Capability = WriteCapability | ReadCapability |
+ ReadAndWriteCapability | SeekCapability | TruncateCapability |
+ LockCapability
+
+ // AllCapabilities lists all capable features.
+ AllCapabilities Capability = WriteCapability | ReadCapability |
+ ReadAndWriteCapability | SeekCapability | TruncateCapability |
+ LockCapability
+)
+
+// Filesystem abstract the operations in a storage-agnostic interface.
+// Each method implementation mimics the behavior of the equivalent functions
+// at the os package from the standard library.
+type Filesystem interface {
+ Basic
+ TempFile
+ Dir
+ Symlink
+ Chroot
+}
+
+// Basic abstract the basic operations in a storage-agnostic interface as
+// an extension to the Basic interface.
+type Basic interface {
+ // Create creates the named file with mode 0666 (before umask), truncating
+ // it if it already exists. If successful, methods on the returned File can
+ // be used for I/O; the associated file descriptor has mode O_RDWR.
+ Create(filename string) (File, error)
+ // Open opens the named file for reading. If successful, methods on the
+ // returned file can be used for reading; the associated file descriptor has
+ // mode O_RDONLY.
+ Open(filename string) (File, error)
+ // OpenFile is the generalized open call; most users will use Open or Create
+ // instead. It opens the named file with specified flag (O_RDONLY etc.) and
+ // perm, (0666 etc.) if applicable. If successful, methods on the returned
+ // File can be used for I/O.
+ OpenFile(filename string, flag int, perm os.FileMode) (File, error)
+ // Stat returns a FileInfo describing the named file.
+ Stat(filename string) (os.FileInfo, error)
+ // Rename renames (moves) oldpath to newpath. If newpath already exists and
+ // is not a directory, Rename replaces it. OS-specific restrictions may
+ // apply when oldpath and newpath are in different directories.
+ Rename(oldpath, newpath string) error
+ // Remove removes the named file or directory.
+ Remove(filename string) error
+ // Join joins any number of path elements into a single path, adding a
+ // Separator if necessary. Join calls filepath.Clean on the result; in
+ // particular, all empty strings are ignored. On Windows, the result is a
+ // UNC path if and only if the first path element is a UNC path.
+ Join(elem ...string) string
+}
+
+type TempFile interface {
+ // TempFile creates a new temporary file in the directory dir with a name
+ // beginning with prefix, opens the file for reading and writing, and
+ // returns the resulting *os.File. If dir is the empty string, TempFile
+ // uses the default directory for temporary files (see os.TempDir).
+ // Multiple programs calling TempFile simultaneously will not choose the
+ // same file. The caller can use f.Name() to find the pathname of the file.
+ // It is the caller's responsibility to remove the file when no longer
+ // needed.
+ TempFile(dir, prefix string) (File, error)
+}
+
+// Dir abstract the dir related operations in a storage-agnostic interface as
+// an extension to the Basic interface.
+type Dir interface {
+ // ReadDir reads the directory named by dirname and returns a list of
+ // directory entries sorted by filename.
+ ReadDir(path string) ([]os.FileInfo, error)
+ // MkdirAll creates a directory named path, along with any necessary
+ // parents, and returns nil, or else returns an error. The permission bits
+ // perm are used for all directories that MkdirAll creates. If path is/
+ // already a directory, MkdirAll does nothing and returns nil.
+ MkdirAll(filename string, perm os.FileMode) error
+}
+
+// Symlink abstract the symlink related operations in a storage-agnostic
+// interface as an extension to the Basic interface.
+type Symlink interface {
+ // Lstat returns a FileInfo describing the named file. If the file is a
+ // symbolic link, the returned FileInfo describes the symbolic link. Lstat
+ // makes no attempt to follow the link.
+ Lstat(filename string) (os.FileInfo, error)
+ // Symlink creates a symbolic-link from link to target. target may be an
+ // absolute or relative path, and need not refer to an existing node.
+ // Parent directories of link are created as necessary.
+ Symlink(target, link string) error
+ // Readlink returns the target path of link.
+ Readlink(link string) (string, error)
+}
+
+// Change abstract the FileInfo change related operations in a storage-agnostic
+// interface as an extension to the Basic interface
+type Change interface {
+ // Chmod changes the mode of the named file to mode. If the file is a
+ // symbolic link, it changes the mode of the link's target.
+ Chmod(name string, mode os.FileMode) error
+ // Lchown changes the numeric uid and gid of the named file. If the file is
+ // a symbolic link, it changes the uid and gid of the link itself.
+ Lchown(name string, uid, gid int) error
+ // Chown changes the numeric uid and gid of the named file. If the file is a
+ // symbolic link, it changes the uid and gid of the link's target.
+ Chown(name string, uid, gid int) error
+ // Chtimes changes the access and modification times of the named file,
+ // similar to the Unix utime() or utimes() functions.
+ //
+ // The underlying filesystem may truncate or round the values to a less
+ // precise time unit.
+ Chtimes(name string, atime time.Time, mtime time.Time) error
+}
+
+// Chroot abstract the chroot related operations in a storage-agnostic interface
+// as an extension to the Basic interface.
+type Chroot interface {
+ // Chroot returns a new filesystem from the same type where the new root is
+ // the given path. Files outside of the designated directory tree cannot be
+ // accessed.
+ Chroot(path string) (Filesystem, error)
+ // Root returns the root path of the filesystem.
+ Root() string
+}
+
+// File represent a file, being a subset of the os.File
+type File interface {
+ // Name returns the name of the file as presented to Open.
+ Name() string
+ io.Writer
+ io.Reader
+ io.ReaderAt
+ io.Seeker
+ io.Closer
+ // Lock locks the file like e.g. flock. It protects against access from
+ // other processes.
+ Lock() error
+ // Unlock unlocks the file.
+ Unlock() error
+ // Truncate the file.
+ Truncate(size int64) error
+}
+
+// Capable interface can return the available features of a filesystem.
+type Capable interface {
+ // Capabilities returns the capabilities of a filesystem in bit flags.
+ Capabilities() Capability
+}
+
+// Capabilities returns the features supported by a filesystem. If the FS
+// does not implement Capable interface it returns all features.
+func Capabilities(fs Basic) Capability {
+ capable, ok := fs.(Capable)
+ if !ok {
+ return DefaultCapabilities
+ }
+
+ return capable.Capabilities()
+}
+
+// CapabilityCheck tests the filesystem for the provided capabilities and
+// returns true in case it supports all of them.
+func CapabilityCheck(fs Basic, capabilities Capability) bool {
+ fsCaps := Capabilities(fs)
+ return fsCaps&capabilities == capabilities
+}
diff --git a/vendor/gopkg.in/src-d/go-billy.v4/helper/chroot/chroot.go b/vendor/gopkg.in/src-d/go-billy.v4/helper/chroot/chroot.go
new file mode 100644
index 0000000000..44ddb3db53
--- /dev/null
+++ b/vendor/gopkg.in/src-d/go-billy.v4/helper/chroot/chroot.go
@@ -0,0 +1,242 @@
+package chroot
+
+import (
+ "os"
+ "path/filepath"
+ "strings"
+
+ "gopkg.in/src-d/go-billy.v4"
+ "gopkg.in/src-d/go-billy.v4/helper/polyfill"
+)
+
+// ChrootHelper is a helper to implement billy.Chroot.
+type ChrootHelper struct {
+ underlying billy.Filesystem
+ base string
+}
+
+// New creates a new filesystem wrapping up the given 'fs'.
+// The created filesystem has its base in the given ChrootHelperectory of the
+// underlying filesystem.
+func New(fs billy.Basic, base string) billy.Filesystem {
+ return &ChrootHelper{
+ underlying: polyfill.New(fs),
+ base: base,
+ }
+}
+
+func (fs *ChrootHelper) underlyingPath(filename string) (string, error) {
+ if isCrossBoundaries(filename) {
+ return "", billy.ErrCrossedBoundary
+ }
+
+ return fs.Join(fs.Root(), filename), nil
+}
+
+func isCrossBoundaries(path string) bool {
+ path = filepath.ToSlash(path)
+ path = filepath.Clean(path)
+
+ return strings.HasPrefix(path, ".."+string(filepath.Separator))
+}
+
+func (fs *ChrootHelper) Create(filename string) (billy.File, error) {
+ fullpath, err := fs.underlyingPath(filename)
+ if err != nil {
+ return nil, err
+ }
+
+ f, err := fs.underlying.Create(fullpath)
+ if err != nil {
+ return nil, err
+ }
+
+ return newFile(fs, f, filename), nil
+}
+
+func (fs *ChrootHelper) Open(filename string) (billy.File, error) {
+ fullpath, err := fs.underlyingPath(filename)
+ if err != nil {
+ return nil, err
+ }
+
+ f, err := fs.underlying.Open(fullpath)
+ if err != nil {
+ return nil, err
+ }
+
+ return newFile(fs, f, filename), nil
+}
+
+func (fs *ChrootHelper) OpenFile(filename string, flag int, mode os.FileMode) (billy.File, error) {
+ fullpath, err := fs.underlyingPath(filename)
+ if err != nil {
+ return nil, err
+ }
+
+ f, err := fs.underlying.OpenFile(fullpath, flag, mode)
+ if err != nil {
+ return nil, err
+ }
+
+ return newFile(fs, f, filename), nil
+}
+
+func (fs *ChrootHelper) Stat(filename string) (os.FileInfo, error) {
+ fullpath, err := fs.underlyingPath(filename)
+ if err != nil {
+ return nil, err
+ }
+
+ return fs.underlying.Stat(fullpath)
+}
+
+func (fs *ChrootHelper) Rename(from, to string) error {
+ var err error
+ from, err = fs.underlyingPath(from)
+ if err != nil {
+ return err
+ }
+
+ to, err = fs.underlyingPath(to)
+ if err != nil {
+ return err
+ }
+
+ return fs.underlying.Rename(from, to)
+}
+
+func (fs *ChrootHelper) Remove(path string) error {
+ fullpath, err := fs.underlyingPath(path)
+ if err != nil {
+ return err
+ }
+
+ return fs.underlying.Remove(fullpath)
+}
+
+func (fs *ChrootHelper) Join(elem ...string) string {
+ return fs.underlying.Join(elem...)
+}
+
+func (fs *ChrootHelper) TempFile(dir, prefix string) (billy.File, error) {
+ fullpath, err := fs.underlyingPath(dir)
+ if err != nil {
+ return nil, err
+ }
+
+ f, err := fs.underlying.(billy.TempFile).TempFile(fullpath, prefix)
+ if err != nil {
+ return nil, err
+ }
+
+ return newFile(fs, f, fs.Join(dir, filepath.Base(f.Name()))), nil
+}
+
+func (fs *ChrootHelper) ReadDir(path string) ([]os.FileInfo, error) {
+ fullpath, err := fs.underlyingPath(path)
+ if err != nil {
+ return nil, err
+ }
+
+ return fs.underlying.(billy.Dir).ReadDir(fullpath)
+}
+
+func (fs *ChrootHelper) MkdirAll(filename string, perm os.FileMode) error {
+ fullpath, err := fs.underlyingPath(filename)
+ if err != nil {
+ return err
+ }
+
+ return fs.underlying.(billy.Dir).MkdirAll(fullpath, perm)
+}
+
+func (fs *ChrootHelper) Lstat(filename string) (os.FileInfo, error) {
+ fullpath, err := fs.underlyingPath(filename)
+ if err != nil {
+ return nil, err
+ }
+
+ return fs.underlying.(billy.Symlink).Lstat(fullpath)
+}
+
+func (fs *ChrootHelper) Symlink(target, link string) error {
+ target = filepath.FromSlash(target)
+
+ // only rewrite target if it's already absolute
+ if filepath.IsAbs(target) || strings.HasPrefix(target, string(filepath.Separator)) {
+ target = fs.Join(fs.Root(), target)
+ target = filepath.Clean(filepath.FromSlash(target))
+ }
+
+ link, err := fs.underlyingPath(link)
+ if err != nil {
+ return err
+ }
+
+ return fs.underlying.(billy.Symlink).Symlink(target, link)
+}
+
+func (fs *ChrootHelper) Readlink(link string) (string, error) {
+ fullpath, err := fs.underlyingPath(link)
+ if err != nil {
+ return "", err
+ }
+
+ target, err := fs.underlying.(billy.Symlink).Readlink(fullpath)
+ if err != nil {
+ return "", err
+ }
+
+ if !filepath.IsAbs(target) && !strings.HasPrefix(target, string(filepath.Separator)) {
+ return target, nil
+ }
+
+ target, err = filepath.Rel(fs.base, target)
+ if err != nil {
+ return "", err
+ }
+
+ return string(os.PathSeparator) + target, nil
+}
+
+func (fs *ChrootHelper) Chroot(path string) (billy.Filesystem, error) {
+ fullpath, err := fs.underlyingPath(path)
+ if err != nil {
+ return nil, err
+ }
+
+ return New(fs.underlying, fullpath), nil
+}
+
+func (fs *ChrootHelper) Root() string {
+ return fs.base
+}
+
+func (fs *ChrootHelper) Underlying() billy.Basic {
+ return fs.underlying
+}
+
+// Capabilities implements the Capable interface.
+func (fs *ChrootHelper) Capabilities() billy.Capability {
+ return billy.Capabilities(fs.underlying)
+}
+
+type file struct {
+ billy.File
+ name string
+}
+
+func newFile(fs billy.Filesystem, f billy.File, filename string) billy.File {
+ filename = fs.Join(fs.Root(), filename)
+ filename, _ = filepath.Rel(fs.Root(), filename)
+
+ return &file{
+ File: f,
+ name: filename,
+ }
+}
+
+func (f *file) Name() string {
+ return f.name
+}
diff --git a/vendor/gopkg.in/src-d/go-billy.v4/helper/polyfill/polyfill.go b/vendor/gopkg.in/src-d/go-billy.v4/helper/polyfill/polyfill.go
new file mode 100644
index 0000000000..f613c255d9
--- /dev/null
+++ b/vendor/gopkg.in/src-d/go-billy.v4/helper/polyfill/polyfill.go
@@ -0,0 +1,105 @@
+package polyfill
+
+import (
+ "os"
+ "path/filepath"
+
+ "gopkg.in/src-d/go-billy.v4"
+)
+
+// Polyfill is a helper that implements all missing method from billy.Filesystem.
+type Polyfill struct {
+ billy.Basic
+ c capabilities
+}
+
+type capabilities struct{ tempfile, dir, symlink, chroot bool }
+
+// New creates a new filesystem wrapping up 'fs' the intercepts all the calls
+// made and errors if fs doesn't implement any of the billy interfaces.
+func New(fs billy.Basic) billy.Filesystem {
+ if original, ok := fs.(billy.Filesystem); ok {
+ return original
+ }
+
+ h := &Polyfill{Basic: fs}
+
+ _, h.c.tempfile = h.Basic.(billy.TempFile)
+ _, h.c.dir = h.Basic.(billy.Dir)
+ _, h.c.symlink = h.Basic.(billy.Symlink)
+ _, h.c.chroot = h.Basic.(billy.Chroot)
+ return h
+}
+
+func (h *Polyfill) TempFile(dir, prefix string) (billy.File, error) {
+ if !h.c.tempfile {
+ return nil, billy.ErrNotSupported
+ }
+
+ return h.Basic.(billy.TempFile).TempFile(dir, prefix)
+}
+
+func (h *Polyfill) ReadDir(path string) ([]os.FileInfo, error) {
+ if !h.c.dir {
+ return nil, billy.ErrNotSupported
+ }
+
+ return h.Basic.(billy.Dir).ReadDir(path)
+}
+
+func (h *Polyfill) MkdirAll(filename string, perm os.FileMode) error {
+ if !h.c.dir {
+ return billy.ErrNotSupported
+ }
+
+ return h.Basic.(billy.Dir).MkdirAll(filename, perm)
+}
+
+func (h *Polyfill) Symlink(target, link string) error {
+ if !h.c.symlink {
+ return billy.ErrNotSupported
+ }
+
+ return h.Basic.(billy.Symlink).Symlink(target, link)
+}
+
+func (h *Polyfill) Readlink(link string) (string, error) {
+ if !h.c.symlink {
+ return "", billy.ErrNotSupported
+ }
+
+ return h.Basic.(billy.Symlink).Readlink(link)
+}
+
+func (h *Polyfill) Lstat(path string) (os.FileInfo, error) {
+ if !h.c.symlink {
+ return nil, billy.ErrNotSupported
+ }
+
+ return h.Basic.(billy.Symlink).Lstat(path)
+}
+
+func (h *Polyfill) Chroot(path string) (billy.Filesystem, error) {
+ if !h.c.chroot {
+ return nil, billy.ErrNotSupported
+ }
+
+ return h.Basic.(billy.Chroot).Chroot(path)
+}
+
+func (h *Polyfill) Root() string {
+ if !h.c.chroot {
+ return string(filepath.Separator)
+ }
+
+ return h.Basic.(billy.Chroot).Root()
+}
+
+func (h *Polyfill) Underlying() billy.Basic {
+ return h.Basic
+}
+
+// Capabilities implements the Capable interface.
+func (h *Polyfill) Capabilities() billy.Capability {
+ return billy.Capabilities(h.Basic)
+}
diff --git a/vendor/gopkg.in/src-d/go-billy.v4/osfs/os.go b/vendor/gopkg.in/src-d/go-billy.v4/osfs/os.go
new file mode 100644
index 0000000000..ff35a3ba96
--- /dev/null
+++ b/vendor/gopkg.in/src-d/go-billy.v4/osfs/os.go
@@ -0,0 +1,139 @@
+// Package osfs provides a billy filesystem for the OS.
+package osfs // import "gopkg.in/src-d/go-billy.v4/osfs"
+
+import (
+ "io/ioutil"
+ "os"
+ "path/filepath"
+ "sync"
+
+ "gopkg.in/src-d/go-billy.v4"
+ "gopkg.in/src-d/go-billy.v4/helper/chroot"
+)
+
+const (
+ defaultDirectoryMode = 0755
+ defaultCreateMode = 0666
+)
+
+// OS is a filesystem based on the os filesystem.
+type OS struct{}
+
+// New returns a new OS filesystem.
+func New(baseDir string) billy.Filesystem {
+ return chroot.New(&OS{}, baseDir)
+}
+
+func (fs *OS) Create(filename string) (billy.File, error) {
+ return fs.OpenFile(filename, os.O_RDWR|os.O_CREATE|os.O_TRUNC, defaultCreateMode)
+}
+
+func (fs *OS) OpenFile(filename string, flag int, perm os.FileMode) (billy.File, error) {
+ if flag&os.O_CREATE != 0 {
+ if err := fs.createDir(filename); err != nil {
+ return nil, err
+ }
+ }
+
+ f, err := os.OpenFile(filename, flag, perm)
+ if err != nil {
+ return nil, err
+ }
+ return &file{File: f}, err
+}
+
+func (fs *OS) createDir(fullpath string) error {
+ dir := filepath.Dir(fullpath)
+ if dir != "." {
+ if err := os.MkdirAll(dir, defaultDirectoryMode); err != nil {
+ return err
+ }
+ }
+
+ return nil
+}
+
+func (fs *OS) ReadDir(path string) ([]os.FileInfo, error) {
+ l, err := ioutil.ReadDir(path)
+ if err != nil {
+ return nil, err
+ }
+
+ var s = make([]os.FileInfo, len(l))
+ for i, f := range l {
+ s[i] = f
+ }
+
+ return s, nil
+}
+
+func (fs *OS) Rename(from, to string) error {
+ if err := fs.createDir(to); err != nil {
+ return err
+ }
+
+ return os.Rename(from, to)
+}
+
+func (fs *OS) MkdirAll(path string, perm os.FileMode) error {
+ return os.MkdirAll(path, defaultDirectoryMode)
+}
+
+func (fs *OS) Open(filename string) (billy.File, error) {
+ return fs.OpenFile(filename, os.O_RDONLY, 0)
+}
+
+func (fs *OS) Stat(filename string) (os.FileInfo, error) {
+ return os.Stat(filename)
+}
+
+func (fs *OS) Remove(filename string) error {
+ return os.Remove(filename)
+}
+
+func (fs *OS) TempFile(dir, prefix string) (billy.File, error) {
+ if err := fs.createDir(dir + string(os.PathSeparator)); err != nil {
+ return nil, err
+ }
+
+ f, err := ioutil.TempFile(dir, prefix)
+ if err != nil {
+ return nil, err
+ }
+ return &file{File: f}, nil
+}
+
+func (fs *OS) Join(elem ...string) string {
+ return filepath.Join(elem...)
+}
+
+func (fs *OS) RemoveAll(path string) error {
+ return os.RemoveAll(filepath.Clean(path))
+}
+
+func (fs *OS) Lstat(filename string) (os.FileInfo, error) {
+ return os.Lstat(filepath.Clean(filename))
+}
+
+func (fs *OS) Symlink(target, link string) error {
+ if err := fs.createDir(link); err != nil {
+ return err
+ }
+
+ return os.Symlink(target, link)
+}
+
+func (fs *OS) Readlink(link string) (string, error) {
+ return os.Readlink(link)
+}
+
+// Capabilities implements the Capable interface.
+func (fs *OS) Capabilities() billy.Capability {
+ return billy.DefaultCapabilities
+}
+
+// file is a wrapper for an os.File which adds support for file locking.
+type file struct {
+ *os.File
+ m sync.Mutex
+}
diff --git a/vendor/gopkg.in/src-d/go-billy.v4/osfs/os_posix.go b/vendor/gopkg.in/src-d/go-billy.v4/osfs/os_posix.go
new file mode 100644
index 0000000000..0eda3bd300
--- /dev/null
+++ b/vendor/gopkg.in/src-d/go-billy.v4/osfs/os_posix.go
@@ -0,0 +1,21 @@
+// +build !windows
+
+package osfs
+
+import (
+ "syscall"
+)
+
+func (f *file) Lock() error {
+ f.m.Lock()
+ defer f.m.Unlock()
+
+ return syscall.Flock(int(f.File.Fd()), syscall.LOCK_EX)
+}
+
+func (f *file) Unlock() error {
+ f.m.Lock()
+ defer f.m.Unlock()
+
+ return syscall.Flock(int(f.File.Fd()), syscall.LOCK_UN)
+}
diff --git a/vendor/gopkg.in/src-d/go-billy.v4/osfs/os_windows.go b/vendor/gopkg.in/src-d/go-billy.v4/osfs/os_windows.go
new file mode 100644
index 0000000000..5eb98829d0
--- /dev/null
+++ b/vendor/gopkg.in/src-d/go-billy.v4/osfs/os_windows.go
@@ -0,0 +1,57 @@
+// +build windows
+
+package osfs
+
+import (
+ "os"
+ "runtime"
+ "unsafe"
+
+ "golang.org/x/sys/windows"
+)
+
+type fileInfo struct {
+ os.FileInfo
+ name string
+}
+
+func (fi *fileInfo) Name() string {
+ return fi.name
+}
+
+var (
+ kernel32DLL = windows.NewLazySystemDLL("kernel32.dll")
+ lockFileExProc = kernel32DLL.NewProc("LockFileEx")
+ unlockFileProc = kernel32DLL.NewProc("UnlockFile")
+)
+
+const (
+ lockfileExclusiveLock = 0x2
+)
+
+func (f *file) Lock() error {
+ f.m.Lock()
+ defer f.m.Unlock()
+
+ var overlapped windows.Overlapped
+ // err is always non-nil as per sys/windows semantics.
+ ret, _, err := lockFileExProc.Call(f.File.Fd(), lockfileExclusiveLock, 0, 0xFFFFFFFF, 0,
+ uintptr(unsafe.Pointer(&overlapped)))
+ runtime.KeepAlive(&overlapped)
+ if ret == 0 {
+ return err
+ }
+ return nil
+}
+
+func (f *file) Unlock() error {
+ f.m.Lock()
+ defer f.m.Unlock()
+
+ // err is always non-nil as per sys/windows semantics.
+ ret, _, err := unlockFileProc.Call(f.File.Fd(), 0, 0, 0xFFFFFFFF, 0)
+ if ret == 0 {
+ return err
+ }
+ return nil
+}
diff --git a/vendor/gopkg.in/src-d/go-billy.v4/util/glob.go b/vendor/gopkg.in/src-d/go-billy.v4/util/glob.go
new file mode 100644
index 0000000000..fdcb3e5f0a
--- /dev/null
+++ b/vendor/gopkg.in/src-d/go-billy.v4/util/glob.go
@@ -0,0 +1,111 @@
+package util
+
+import (
+ "path/filepath"
+ "sort"
+ "strings"
+
+ "gopkg.in/src-d/go-billy.v4"
+)
+
+// Glob returns the names of all files matching pattern or nil
+// if there is no matching file. The syntax of patterns is the same
+// as in Match. The pattern may describe hierarchical names such as
+// /usr/*/bin/ed (assuming the Separator is '/').
+//
+// Glob ignores file system errors such as I/O errors reading directories.
+// The only possible returned error is ErrBadPattern, when pattern
+// is malformed.
+//
+// Function originally from https://golang.org/src/path/filepath/match_test.go
+func Glob(fs billy.Filesystem, pattern string) (matches []string, err error) {
+ if !hasMeta(pattern) {
+ if _, err = fs.Lstat(pattern); err != nil {
+ return nil, nil
+ }
+ return []string{pattern}, nil
+ }
+
+ dir, file := filepath.Split(pattern)
+ // Prevent infinite recursion. See issue 15879.
+ if dir == pattern {
+ return nil, filepath.ErrBadPattern
+ }
+
+ var m []string
+ m, err = Glob(fs, cleanGlobPath(dir))
+ if err != nil {
+ return
+ }
+ for _, d := range m {
+ matches, err = glob(fs, d, file, matches)
+ if err != nil {
+ return
+ }
+ }
+ return
+}
+
+// cleanGlobPath prepares path for glob matching.
+func cleanGlobPath(path string) string {
+ switch path {
+ case "":
+ return "."
+ case string(filepath.Separator):
+ // do nothing to the path
+ return path
+ default:
+ return path[0 : len(path)-1] // chop off trailing separator
+ }
+}
+
+// glob searches for files matching pattern in the directory dir
+// and appends them to matches. If the directory cannot be
+// opened, it returns the existing matches. New matches are
+// added in lexicographical order.
+func glob(fs billy.Filesystem, dir, pattern string, matches []string) (m []string, e error) {
+ m = matches
+ fi, err := fs.Stat(dir)
+ if err != nil {
+ return
+ }
+
+ if !fi.IsDir() {
+ return
+ }
+
+ names, _ := readdirnames(fs, dir)
+ sort.Strings(names)
+
+ for _, n := range names {
+ matched, err := filepath.Match(pattern, n)
+ if err != nil {
+ return m, err
+ }
+ if matched {
+ m = append(m, filepath.Join(dir, n))
+ }
+ }
+ return
+}
+
+// hasMeta reports whether path contains any of the magic characters
+// recognized by Match.
+func hasMeta(path string) bool {
+ // TODO(niemeyer): Should other magic characters be added here?
+ return strings.ContainsAny(path, "*?[")
+}
+
+func readdirnames(fs billy.Filesystem, dir string) ([]string, error) {
+ files, err := fs.ReadDir(dir)
+ if err != nil {
+ return nil, err
+ }
+
+ var names []string
+ for _, file := range files {
+ names = append(names, file.Name())
+ }
+
+ return names, nil
+}
diff --git a/vendor/gopkg.in/src-d/go-billy.v4/util/util.go b/vendor/gopkg.in/src-d/go-billy.v4/util/util.go
new file mode 100644
index 0000000000..cf7fb57f75
--- /dev/null
+++ b/vendor/gopkg.in/src-d/go-billy.v4/util/util.go
@@ -0,0 +1,224 @@
+package util
+
+import (
+ "io"
+ "os"
+ "path/filepath"
+ "strconv"
+ "sync"
+ "time"
+
+ "gopkg.in/src-d/go-billy.v4"
+)
+
+// RemoveAll removes path and any children it contains. It removes everything it
+// can but returns the first error it encounters. If the path does not exist,
+// RemoveAll returns nil (no error).
+func RemoveAll(fs billy.Basic, path string) error {
+ fs, path = getUnderlyingAndPath(fs, path)
+
+ if r, ok := fs.(removerAll); ok {
+ return r.RemoveAll(path)
+ }
+
+ return removeAll(fs, path)
+}
+
+type removerAll interface {
+ RemoveAll(string) error
+}
+
+func removeAll(fs billy.Basic, path string) error {
+ // This implementation is adapted from os.RemoveAll.
+
+ // Simple case: if Remove works, we're done.
+ err := fs.Remove(path)
+ if err == nil || os.IsNotExist(err) {
+ return nil
+ }
+
+ // Otherwise, is this a directory we need to recurse into?
+ dir, serr := fs.Stat(path)
+ if serr != nil {
+ if os.IsNotExist(serr) {
+ return nil
+ }
+
+ return serr
+ }
+
+ if !dir.IsDir() {
+ // Not a directory; return the error from Remove.
+ return err
+ }
+
+ dirfs, ok := fs.(billy.Dir)
+ if !ok {
+ return billy.ErrNotSupported
+ }
+
+ // Directory.
+ fis, err := dirfs.ReadDir(path)
+ if err != nil {
+ if os.IsNotExist(err) {
+ // Race. It was deleted between the Lstat and Open.
+ // Return nil per RemoveAll's docs.
+ return nil
+ }
+
+ return err
+ }
+
+ // Remove contents & return first error.
+ err = nil
+ for _, fi := range fis {
+ cpath := fs.Join(path, fi.Name())
+ err1 := removeAll(fs, cpath)
+ if err == nil {
+ err = err1
+ }
+ }
+
+ // Remove directory.
+ err1 := fs.Remove(path)
+ if err1 == nil || os.IsNotExist(err1) {
+ return nil
+ }
+
+ if err == nil {
+ err = err1
+ }
+
+ return err
+
+}
+
+// WriteFile writes data to a file named by filename in the given filesystem.
+// If the file does not exist, WriteFile creates it with permissions perm;
+// otherwise WriteFile truncates it before writing.
+func WriteFile(fs billy.Basic, filename string, data []byte, perm os.FileMode) error {
+ f, err := fs.OpenFile(filename, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, perm)
+ if err != nil {
+ return err
+ }
+
+ n, err := f.Write(data)
+ if err == nil && n < len(data) {
+ err = io.ErrShortWrite
+ }
+
+ if err1 := f.Close(); err == nil {
+ err = err1
+ }
+
+ return err
+}
+
+// Random number state.
+// We generate random temporary file names so that there's a good
+// chance the file doesn't exist yet - keeps the number of tries in
+// TempFile to a minimum.
+var rand uint32
+var randmu sync.Mutex
+
+func reseed() uint32 {
+ return uint32(time.Now().UnixNano() + int64(os.Getpid()))
+}
+
+func nextSuffix() string {
+ randmu.Lock()
+ r := rand
+ if r == 0 {
+ r = reseed()
+ }
+ r = r*1664525 + 1013904223 // constants from Numerical Recipes
+ rand = r
+ randmu.Unlock()
+ return strconv.Itoa(int(1e9 + r%1e9))[1:]
+}
+
+// TempFile creates a new temporary file in the directory dir with a name
+// beginning with prefix, opens the file for reading and writing, and returns
+// the resulting *os.File. If dir is the empty string, TempFile uses the default
+// directory for temporary files (see os.TempDir). Multiple programs calling
+// TempFile simultaneously will not choose the same file. The caller can use
+// f.Name() to find the pathname of the file. It is the caller's responsibility
+// to remove the file when no longer needed.
+func TempFile(fs billy.Basic, dir, prefix string) (f billy.File, err error) {
+ // This implementation is based on stdlib ioutil.TempFile.
+
+ if dir == "" {
+ dir = os.TempDir()
+ }
+
+ nconflict := 0
+ for i := 0; i < 10000; i++ {
+ name := filepath.Join(dir, prefix+nextSuffix())
+ f, err = fs.OpenFile(name, os.O_RDWR|os.O_CREATE|os.O_EXCL, 0600)
+ if os.IsExist(err) {
+ if nconflict++; nconflict > 10 {
+ randmu.Lock()
+ rand = reseed()
+ randmu.Unlock()
+ }
+ continue
+ }
+ break
+ }
+ return
+}
+
+// TempDir creates a new temporary directory in the directory dir
+// with a name beginning with prefix and returns the path of the
+// new directory. If dir is the empty string, TempDir uses the
+// default directory for temporary files (see os.TempDir).
+// Multiple programs calling TempDir simultaneously
+// will not choose the same directory. It is the caller's responsibility
+// to remove the directory when no longer needed.
+func TempDir(fs billy.Dir, dir, prefix string) (name string, err error) {
+ // This implementation is based on stdlib ioutil.TempDir
+
+ if dir == "" {
+ dir = os.TempDir()
+ }
+
+ nconflict := 0
+ for i := 0; i < 10000; i++ {
+ try := filepath.Join(dir, prefix+nextSuffix())
+ err = fs.MkdirAll(try, 0700)
+ if os.IsExist(err) {
+ if nconflict++; nconflict > 10 {
+ randmu.Lock()
+ rand = reseed()
+ randmu.Unlock()
+ }
+ continue
+ }
+ if os.IsNotExist(err) {
+ if _, err := os.Stat(dir); os.IsNotExist(err) {
+ return "", err
+ }
+ }
+ if err == nil {
+ name = try
+ }
+ break
+ }
+ return
+}
+
+type underlying interface {
+ Underlying() billy.Basic
+}
+
+func getUnderlyingAndPath(fs billy.Basic, path string) (billy.Basic, string) {
+ u, ok := fs.(underlying)
+ if !ok {
+ return fs, path
+ }
+ if ch, ok := fs.(billy.Chroot); ok {
+ path = fs.Join(ch.Root(), path)
+ }
+
+ return u.Underlying(), path
+}