mirror of
				https://gitea.com/Lydanne/buildx.git
				synced 2025-11-04 10:03:42 +08:00 
			
		
		
		
	vendor: initial vendor
Signed-off-by: Tonis Tiigi <tonistiigi@gmail.com>
This commit is contained in:
		
							
								
								
									
										16
									
								
								vendor/github.com/containerd/continuity/AUTHORS
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										16
									
								
								vendor/github.com/containerd/continuity/AUTHORS
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,16 @@
 | 
			
		||||
Aaron Lehmann <aaron.lehmann@docker.com>
 | 
			
		||||
Akash Gupta <akagup@microsoft.com>
 | 
			
		||||
Akihiro Suda <suda.akihiro@lab.ntt.co.jp>
 | 
			
		||||
Andrew Pennebaker <apennebaker@datapipe.com>
 | 
			
		||||
Brandon Philips <brandon.philips@coreos.com>
 | 
			
		||||
Christopher Jones <tophj@linux.vnet.ibm.com>
 | 
			
		||||
Daniel, Dao Quang Minh <dqminh89@gmail.com>
 | 
			
		||||
Derek McGowan <derek@mcgstyle.net>
 | 
			
		||||
Edward Pilatowicz <edward.pilatowicz@oracle.com>
 | 
			
		||||
Ian Campbell <ijc@docker.com>
 | 
			
		||||
Justin Cormack <justin.cormack@docker.com>
 | 
			
		||||
Justin Cummins <sul3n3t@gmail.com>
 | 
			
		||||
Phil Estes <estesp@gmail.com>
 | 
			
		||||
Stephen J Day <stephen.day@docker.com>
 | 
			
		||||
Tobias Klauser <tklauser@distanz.ch>
 | 
			
		||||
Tonis Tiigi <tonistiigi@gmail.com>
 | 
			
		||||
							
								
								
									
										191
									
								
								vendor/github.com/containerd/continuity/LICENSE
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										191
									
								
								vendor/github.com/containerd/continuity/LICENSE
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,191 @@
 | 
			
		||||
 | 
			
		||||
                                 Apache License
 | 
			
		||||
                           Version 2.0, January 2004
 | 
			
		||||
                        https://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
 | 
			
		||||
 | 
			
		||||
   Copyright The containerd Authors
 | 
			
		||||
 | 
			
		||||
   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
 | 
			
		||||
 | 
			
		||||
       https://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.
 | 
			
		||||
							
								
								
									
										172
									
								
								vendor/github.com/containerd/continuity/fs/copy.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										172
									
								
								vendor/github.com/containerd/continuity/fs/copy.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,172 @@
 | 
			
		||||
/*
 | 
			
		||||
   Copyright The containerd Authors.
 | 
			
		||||
 | 
			
		||||
   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.
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
package fs
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"io/ioutil"
 | 
			
		||||
	"os"
 | 
			
		||||
	"path/filepath"
 | 
			
		||||
	"sync"
 | 
			
		||||
 | 
			
		||||
	"github.com/pkg/errors"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
var bufferPool = &sync.Pool{
 | 
			
		||||
	New: func() interface{} {
 | 
			
		||||
		buffer := make([]byte, 32*1024)
 | 
			
		||||
		return &buffer
 | 
			
		||||
	},
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// XAttrErrorHandlers transform a non-nil xattr error.
 | 
			
		||||
// Return nil to ignore an error.
 | 
			
		||||
// xattrKey can be empty for listxattr operation.
 | 
			
		||||
type XAttrErrorHandler func(dst, src, xattrKey string, err error) error
 | 
			
		||||
 | 
			
		||||
type copyDirOpts struct {
 | 
			
		||||
	xeh XAttrErrorHandler
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type CopyDirOpt func(*copyDirOpts) error
 | 
			
		||||
 | 
			
		||||
// WithXAttrErrorHandler allows specifying XAttrErrorHandler
 | 
			
		||||
// If nil XAttrErrorHandler is specified (default), CopyDir stops
 | 
			
		||||
// on a non-nil xattr error.
 | 
			
		||||
func WithXAttrErrorHandler(xeh XAttrErrorHandler) CopyDirOpt {
 | 
			
		||||
	return func(o *copyDirOpts) error {
 | 
			
		||||
		o.xeh = xeh
 | 
			
		||||
		return nil
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// WithAllowXAttrErrors allows ignoring xattr errors.
 | 
			
		||||
func WithAllowXAttrErrors() CopyDirOpt {
 | 
			
		||||
	xeh := func(dst, src, xattrKey string, err error) error {
 | 
			
		||||
		return nil
 | 
			
		||||
	}
 | 
			
		||||
	return WithXAttrErrorHandler(xeh)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// CopyDir copies the directory from src to dst.
 | 
			
		||||
// Most efficient copy of files is attempted.
 | 
			
		||||
func CopyDir(dst, src string, opts ...CopyDirOpt) error {
 | 
			
		||||
	var o copyDirOpts
 | 
			
		||||
	for _, opt := range opts {
 | 
			
		||||
		if err := opt(&o); err != nil {
 | 
			
		||||
			return err
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	inodes := map[uint64]string{}
 | 
			
		||||
	return copyDirectory(dst, src, inodes, &o)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func copyDirectory(dst, src string, inodes map[uint64]string, o *copyDirOpts) error {
 | 
			
		||||
	stat, err := os.Stat(src)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return errors.Wrapf(err, "failed to stat %s", src)
 | 
			
		||||
	}
 | 
			
		||||
	if !stat.IsDir() {
 | 
			
		||||
		return errors.Errorf("source is not directory")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if st, err := os.Stat(dst); err != nil {
 | 
			
		||||
		if err := os.Mkdir(dst, stat.Mode()); err != nil {
 | 
			
		||||
			return errors.Wrapf(err, "failed to mkdir %s", dst)
 | 
			
		||||
		}
 | 
			
		||||
	} else if !st.IsDir() {
 | 
			
		||||
		return errors.Errorf("cannot copy to non-directory: %s", dst)
 | 
			
		||||
	} else {
 | 
			
		||||
		if err := os.Chmod(dst, stat.Mode()); err != nil {
 | 
			
		||||
			return errors.Wrapf(err, "failed to chmod on %s", dst)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	fis, err := ioutil.ReadDir(src)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return errors.Wrapf(err, "failed to read %s", src)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if err := copyFileInfo(stat, dst); err != nil {
 | 
			
		||||
		return errors.Wrapf(err, "failed to copy file info for %s", dst)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	for _, fi := range fis {
 | 
			
		||||
		source := filepath.Join(src, fi.Name())
 | 
			
		||||
		target := filepath.Join(dst, fi.Name())
 | 
			
		||||
 | 
			
		||||
		switch {
 | 
			
		||||
		case fi.IsDir():
 | 
			
		||||
			if err := copyDirectory(target, source, inodes, o); err != nil {
 | 
			
		||||
				return err
 | 
			
		||||
			}
 | 
			
		||||
			continue
 | 
			
		||||
		case (fi.Mode() & os.ModeType) == 0:
 | 
			
		||||
			link, err := getLinkSource(target, fi, inodes)
 | 
			
		||||
			if err != nil {
 | 
			
		||||
				return errors.Wrap(err, "failed to get hardlink")
 | 
			
		||||
			}
 | 
			
		||||
			if link != "" {
 | 
			
		||||
				if err := os.Link(link, target); err != nil {
 | 
			
		||||
					return errors.Wrap(err, "failed to create hard link")
 | 
			
		||||
				}
 | 
			
		||||
			} else if err := CopyFile(target, source); err != nil {
 | 
			
		||||
				return errors.Wrap(err, "failed to copy files")
 | 
			
		||||
			}
 | 
			
		||||
		case (fi.Mode() & os.ModeSymlink) == os.ModeSymlink:
 | 
			
		||||
			link, err := os.Readlink(source)
 | 
			
		||||
			if err != nil {
 | 
			
		||||
				return errors.Wrapf(err, "failed to read link: %s", source)
 | 
			
		||||
			}
 | 
			
		||||
			if err := os.Symlink(link, target); err != nil {
 | 
			
		||||
				return errors.Wrapf(err, "failed to create symlink: %s", target)
 | 
			
		||||
			}
 | 
			
		||||
		case (fi.Mode() & os.ModeDevice) == os.ModeDevice:
 | 
			
		||||
			if err := copyDevice(target, fi); err != nil {
 | 
			
		||||
				return errors.Wrapf(err, "failed to create device")
 | 
			
		||||
			}
 | 
			
		||||
		default:
 | 
			
		||||
			// TODO: Support pipes and sockets
 | 
			
		||||
			return errors.Wrapf(err, "unsupported mode %s", fi.Mode())
 | 
			
		||||
		}
 | 
			
		||||
		if err := copyFileInfo(fi, target); err != nil {
 | 
			
		||||
			return errors.Wrap(err, "failed to copy file info")
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if err := copyXAttrs(target, source, o.xeh); err != nil {
 | 
			
		||||
			return errors.Wrap(err, "failed to copy xattrs")
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// CopyFile copies the source file to the target.
 | 
			
		||||
// The most efficient means of copying is used for the platform.
 | 
			
		||||
func CopyFile(target, source string) error {
 | 
			
		||||
	src, err := os.Open(source)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return errors.Wrapf(err, "failed to open source %s", source)
 | 
			
		||||
	}
 | 
			
		||||
	defer src.Close()
 | 
			
		||||
	tgt, err := os.Create(target)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return errors.Wrapf(err, "failed to open target %s", target)
 | 
			
		||||
	}
 | 
			
		||||
	defer tgt.Close()
 | 
			
		||||
 | 
			
		||||
	return copyFileContent(tgt, src)
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										144
									
								
								vendor/github.com/containerd/continuity/fs/copy_linux.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										144
									
								
								vendor/github.com/containerd/continuity/fs/copy_linux.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,144 @@
 | 
			
		||||
/*
 | 
			
		||||
   Copyright The containerd Authors.
 | 
			
		||||
 | 
			
		||||
   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.
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
package fs
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"io"
 | 
			
		||||
	"os"
 | 
			
		||||
	"syscall"
 | 
			
		||||
 | 
			
		||||
	"github.com/containerd/continuity/sysx"
 | 
			
		||||
	"github.com/pkg/errors"
 | 
			
		||||
	"golang.org/x/sys/unix"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func copyFileInfo(fi os.FileInfo, name string) error {
 | 
			
		||||
	st := fi.Sys().(*syscall.Stat_t)
 | 
			
		||||
	if err := os.Lchown(name, int(st.Uid), int(st.Gid)); err != nil {
 | 
			
		||||
		if os.IsPermission(err) {
 | 
			
		||||
			// Normally if uid/gid are the same this would be a no-op, but some
 | 
			
		||||
			// filesystems may still return EPERM... for instance NFS does this.
 | 
			
		||||
			// In such a case, this is not an error.
 | 
			
		||||
			if dstStat, err2 := os.Lstat(name); err2 == nil {
 | 
			
		||||
				st2 := dstStat.Sys().(*syscall.Stat_t)
 | 
			
		||||
				if st.Uid == st2.Uid && st.Gid == st2.Gid {
 | 
			
		||||
					err = nil
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return errors.Wrapf(err, "failed to chown %s", name)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (fi.Mode() & os.ModeSymlink) != os.ModeSymlink {
 | 
			
		||||
		if err := os.Chmod(name, fi.Mode()); err != nil {
 | 
			
		||||
			return errors.Wrapf(err, "failed to chmod %s", name)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	timespec := []unix.Timespec{unix.Timespec(StatAtime(st)), unix.Timespec(StatMtime(st))}
 | 
			
		||||
	if err := unix.UtimesNanoAt(unix.AT_FDCWD, name, timespec, unix.AT_SYMLINK_NOFOLLOW); err != nil {
 | 
			
		||||
		return errors.Wrapf(err, "failed to utime %s", name)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const maxSSizeT = int64(^uint(0) >> 1)
 | 
			
		||||
 | 
			
		||||
func copyFileContent(dst, src *os.File) error {
 | 
			
		||||
	st, err := src.Stat()
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return errors.Wrap(err, "unable to stat source")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	size := st.Size()
 | 
			
		||||
	first := true
 | 
			
		||||
	srcFd := int(src.Fd())
 | 
			
		||||
	dstFd := int(dst.Fd())
 | 
			
		||||
 | 
			
		||||
	for size > 0 {
 | 
			
		||||
		// Ensure that we are never trying to copy more than SSIZE_MAX at a
 | 
			
		||||
		// time and at the same time avoids overflows when the file is larger
 | 
			
		||||
		// than 4GB on 32-bit systems.
 | 
			
		||||
		var copySize int
 | 
			
		||||
		if size > maxSSizeT {
 | 
			
		||||
			copySize = int(maxSSizeT)
 | 
			
		||||
		} else {
 | 
			
		||||
			copySize = int(size)
 | 
			
		||||
		}
 | 
			
		||||
		n, err := unix.CopyFileRange(srcFd, nil, dstFd, nil, copySize, 0)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			if (err != unix.ENOSYS && err != unix.EXDEV) || !first {
 | 
			
		||||
				return errors.Wrap(err, "copy file range failed")
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			buf := bufferPool.Get().(*[]byte)
 | 
			
		||||
			_, err = io.CopyBuffer(dst, src, *buf)
 | 
			
		||||
			bufferPool.Put(buf)
 | 
			
		||||
			return errors.Wrap(err, "userspace copy failed")
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		first = false
 | 
			
		||||
		size -= int64(n)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func copyXAttrs(dst, src string, xeh XAttrErrorHandler) error {
 | 
			
		||||
	xattrKeys, err := sysx.LListxattr(src)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		e := errors.Wrapf(err, "failed to list xattrs on %s", src)
 | 
			
		||||
		if xeh != nil {
 | 
			
		||||
			e = xeh(dst, src, "", e)
 | 
			
		||||
		}
 | 
			
		||||
		return e
 | 
			
		||||
	}
 | 
			
		||||
	for _, xattr := range xattrKeys {
 | 
			
		||||
		data, err := sysx.LGetxattr(src, xattr)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			e := errors.Wrapf(err, "failed to get xattr %q on %s", xattr, src)
 | 
			
		||||
			if xeh != nil {
 | 
			
		||||
				if e = xeh(dst, src, xattr, e); e == nil {
 | 
			
		||||
					continue
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
			return e
 | 
			
		||||
		}
 | 
			
		||||
		if err := sysx.LSetxattr(dst, xattr, data, 0); err != nil {
 | 
			
		||||
			e := errors.Wrapf(err, "failed to set xattr %q on %s", xattr, dst)
 | 
			
		||||
			if xeh != nil {
 | 
			
		||||
				if e = xeh(dst, src, xattr, e); e == nil {
 | 
			
		||||
					continue
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
			return e
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func copyDevice(dst string, fi os.FileInfo) error {
 | 
			
		||||
	st, ok := fi.Sys().(*syscall.Stat_t)
 | 
			
		||||
	if !ok {
 | 
			
		||||
		return errors.New("unsupported stat type")
 | 
			
		||||
	}
 | 
			
		||||
	return unix.Mknod(dst, uint32(fi.Mode()), int(st.Rdev))
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										112
									
								
								vendor/github.com/containerd/continuity/fs/copy_unix.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										112
									
								
								vendor/github.com/containerd/continuity/fs/copy_unix.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,112 @@
 | 
			
		||||
// +build solaris darwin freebsd
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
   Copyright The containerd Authors.
 | 
			
		||||
 | 
			
		||||
   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.
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
package fs
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"io"
 | 
			
		||||
	"os"
 | 
			
		||||
	"syscall"
 | 
			
		||||
 | 
			
		||||
	"github.com/containerd/continuity/sysx"
 | 
			
		||||
	"github.com/pkg/errors"
 | 
			
		||||
	"golang.org/x/sys/unix"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func copyFileInfo(fi os.FileInfo, name string) error {
 | 
			
		||||
	st := fi.Sys().(*syscall.Stat_t)
 | 
			
		||||
	if err := os.Lchown(name, int(st.Uid), int(st.Gid)); err != nil {
 | 
			
		||||
		if os.IsPermission(err) {
 | 
			
		||||
			// Normally if uid/gid are the same this would be a no-op, but some
 | 
			
		||||
			// filesystems may still return EPERM... for instance NFS does this.
 | 
			
		||||
			// In such a case, this is not an error.
 | 
			
		||||
			if dstStat, err2 := os.Lstat(name); err2 == nil {
 | 
			
		||||
				st2 := dstStat.Sys().(*syscall.Stat_t)
 | 
			
		||||
				if st.Uid == st2.Uid && st.Gid == st2.Gid {
 | 
			
		||||
					err = nil
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return errors.Wrapf(err, "failed to chown %s", name)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (fi.Mode() & os.ModeSymlink) != os.ModeSymlink {
 | 
			
		||||
		if err := os.Chmod(name, fi.Mode()); err != nil {
 | 
			
		||||
			return errors.Wrapf(err, "failed to chmod %s", name)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	timespec := []syscall.Timespec{StatAtime(st), StatMtime(st)}
 | 
			
		||||
	if err := syscall.UtimesNano(name, timespec); err != nil {
 | 
			
		||||
		return errors.Wrapf(err, "failed to utime %s", name)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func copyFileContent(dst, src *os.File) error {
 | 
			
		||||
	buf := bufferPool.Get().(*[]byte)
 | 
			
		||||
	_, err := io.CopyBuffer(dst, src, *buf)
 | 
			
		||||
	bufferPool.Put(buf)
 | 
			
		||||
 | 
			
		||||
	return err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func copyXAttrs(dst, src string, xeh XAttrErrorHandler) error {
 | 
			
		||||
	xattrKeys, err := sysx.LListxattr(src)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		e := errors.Wrapf(err, "failed to list xattrs on %s", src)
 | 
			
		||||
		if xeh != nil {
 | 
			
		||||
			e = xeh(dst, src, "", e)
 | 
			
		||||
		}
 | 
			
		||||
		return e
 | 
			
		||||
	}
 | 
			
		||||
	for _, xattr := range xattrKeys {
 | 
			
		||||
		data, err := sysx.LGetxattr(src, xattr)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			e := errors.Wrapf(err, "failed to get xattr %q on %s", xattr, src)
 | 
			
		||||
			if xeh != nil {
 | 
			
		||||
				if e = xeh(dst, src, xattr, e); e == nil {
 | 
			
		||||
					continue
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
			return e
 | 
			
		||||
		}
 | 
			
		||||
		if err := sysx.LSetxattr(dst, xattr, data, 0); err != nil {
 | 
			
		||||
			e := errors.Wrapf(err, "failed to set xattr %q on %s", xattr, dst)
 | 
			
		||||
			if xeh != nil {
 | 
			
		||||
				if e = xeh(dst, src, xattr, e); e == nil {
 | 
			
		||||
					continue
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
			return e
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func copyDevice(dst string, fi os.FileInfo) error {
 | 
			
		||||
	st, ok := fi.Sys().(*syscall.Stat_t)
 | 
			
		||||
	if !ok {
 | 
			
		||||
		return errors.New("unsupported stat type")
 | 
			
		||||
	}
 | 
			
		||||
	return unix.Mknod(dst, uint32(fi.Mode()), int(st.Rdev))
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										49
									
								
								vendor/github.com/containerd/continuity/fs/copy_windows.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										49
									
								
								vendor/github.com/containerd/continuity/fs/copy_windows.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,49 @@
 | 
			
		||||
/*
 | 
			
		||||
   Copyright The containerd Authors.
 | 
			
		||||
 | 
			
		||||
   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.
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
package fs
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"io"
 | 
			
		||||
	"os"
 | 
			
		||||
 | 
			
		||||
	"github.com/pkg/errors"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func copyFileInfo(fi os.FileInfo, name string) error {
 | 
			
		||||
	if err := os.Chmod(name, fi.Mode()); err != nil {
 | 
			
		||||
		return errors.Wrapf(err, "failed to chmod %s", name)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// TODO: copy windows specific metadata
 | 
			
		||||
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func copyFileContent(dst, src *os.File) error {
 | 
			
		||||
	buf := bufferPool.Get().(*[]byte)
 | 
			
		||||
	_, err := io.CopyBuffer(dst, src, *buf)
 | 
			
		||||
	bufferPool.Put(buf)
 | 
			
		||||
	return err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func copyXAttrs(dst, src string, xeh XAttrErrorHandler) error {
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func copyDevice(dst string, fi os.FileInfo) error {
 | 
			
		||||
	return errors.New("device copy not supported")
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										326
									
								
								vendor/github.com/containerd/continuity/fs/diff.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										326
									
								
								vendor/github.com/containerd/continuity/fs/diff.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,326 @@
 | 
			
		||||
/*
 | 
			
		||||
   Copyright The containerd Authors.
 | 
			
		||||
 | 
			
		||||
   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.
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
package fs
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"context"
 | 
			
		||||
	"os"
 | 
			
		||||
	"path/filepath"
 | 
			
		||||
	"strings"
 | 
			
		||||
 | 
			
		||||
	"golang.org/x/sync/errgroup"
 | 
			
		||||
 | 
			
		||||
	"github.com/sirupsen/logrus"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// ChangeKind is the type of modification that
 | 
			
		||||
// a change is making.
 | 
			
		||||
type ChangeKind int
 | 
			
		||||
 | 
			
		||||
const (
 | 
			
		||||
	// ChangeKindUnmodified represents an unmodified
 | 
			
		||||
	// file
 | 
			
		||||
	ChangeKindUnmodified = iota
 | 
			
		||||
 | 
			
		||||
	// ChangeKindAdd represents an addition of
 | 
			
		||||
	// a file
 | 
			
		||||
	ChangeKindAdd
 | 
			
		||||
 | 
			
		||||
	// ChangeKindModify represents a change to
 | 
			
		||||
	// an existing file
 | 
			
		||||
	ChangeKindModify
 | 
			
		||||
 | 
			
		||||
	// ChangeKindDelete represents a delete of
 | 
			
		||||
	// a file
 | 
			
		||||
	ChangeKindDelete
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func (k ChangeKind) String() string {
 | 
			
		||||
	switch k {
 | 
			
		||||
	case ChangeKindUnmodified:
 | 
			
		||||
		return "unmodified"
 | 
			
		||||
	case ChangeKindAdd:
 | 
			
		||||
		return "add"
 | 
			
		||||
	case ChangeKindModify:
 | 
			
		||||
		return "modify"
 | 
			
		||||
	case ChangeKindDelete:
 | 
			
		||||
		return "delete"
 | 
			
		||||
	default:
 | 
			
		||||
		return ""
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Change represents single change between a diff and its parent.
 | 
			
		||||
type Change struct {
 | 
			
		||||
	Kind ChangeKind
 | 
			
		||||
	Path string
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// ChangeFunc is the type of function called for each change
 | 
			
		||||
// computed during a directory changes calculation.
 | 
			
		||||
type ChangeFunc func(ChangeKind, string, os.FileInfo, error) error
 | 
			
		||||
 | 
			
		||||
// Changes computes changes between two directories calling the
 | 
			
		||||
// given change function for each computed change. The first
 | 
			
		||||
// directory is intended to the base directory and second
 | 
			
		||||
// directory the changed directory.
 | 
			
		||||
//
 | 
			
		||||
// The change callback is called by the order of path names and
 | 
			
		||||
// should be appliable in that order.
 | 
			
		||||
//  Due to this apply ordering, the following is true
 | 
			
		||||
//  - Removed directory trees only create a single change for the root
 | 
			
		||||
//    directory removed. Remaining changes are implied.
 | 
			
		||||
//  - A directory which is modified to become a file will not have
 | 
			
		||||
//    delete entries for sub-path items, their removal is implied
 | 
			
		||||
//    by the removal of the parent directory.
 | 
			
		||||
//
 | 
			
		||||
// Opaque directories will not be treated specially and each file
 | 
			
		||||
// removed from the base directory will show up as a removal.
 | 
			
		||||
//
 | 
			
		||||
// File content comparisons will be done on files which have timestamps
 | 
			
		||||
// which may have been truncated. If either of the files being compared
 | 
			
		||||
// has a zero value nanosecond value, each byte will be compared for
 | 
			
		||||
// differences. If 2 files have the same seconds value but different
 | 
			
		||||
// nanosecond values where one of those values is zero, the files will
 | 
			
		||||
// be considered unchanged if the content is the same. This behavior
 | 
			
		||||
// is to account for timestamp truncation during archiving.
 | 
			
		||||
func Changes(ctx context.Context, a, b string, changeFn ChangeFunc) error {
 | 
			
		||||
	if a == "" {
 | 
			
		||||
		logrus.Debugf("Using single walk diff for %s", b)
 | 
			
		||||
		return addDirChanges(ctx, changeFn, b)
 | 
			
		||||
	} else if diffOptions := detectDirDiff(b, a); diffOptions != nil {
 | 
			
		||||
		logrus.Debugf("Using single walk diff for %s from %s", diffOptions.diffDir, a)
 | 
			
		||||
		return diffDirChanges(ctx, changeFn, a, diffOptions)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	logrus.Debugf("Using double walk diff for %s from %s", b, a)
 | 
			
		||||
	return doubleWalkDiff(ctx, changeFn, a, b)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func addDirChanges(ctx context.Context, changeFn ChangeFunc, root string) error {
 | 
			
		||||
	return filepath.Walk(root, func(path string, f os.FileInfo, err error) error {
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return err
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		// Rebase path
 | 
			
		||||
		path, err = filepath.Rel(root, path)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return err
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		path = filepath.Join(string(os.PathSeparator), path)
 | 
			
		||||
 | 
			
		||||
		// Skip root
 | 
			
		||||
		if path == string(os.PathSeparator) {
 | 
			
		||||
			return nil
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		return changeFn(ChangeKindAdd, path, f, nil)
 | 
			
		||||
	})
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// diffDirOptions is used when the diff can be directly calculated from
 | 
			
		||||
// a diff directory to its base, without walking both trees.
 | 
			
		||||
type diffDirOptions struct {
 | 
			
		||||
	diffDir      string
 | 
			
		||||
	skipChange   func(string) (bool, error)
 | 
			
		||||
	deleteChange func(string, string, os.FileInfo) (string, error)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// diffDirChanges walks the diff directory and compares changes against the base.
 | 
			
		||||
func diffDirChanges(ctx context.Context, changeFn ChangeFunc, base string, o *diffDirOptions) error {
 | 
			
		||||
	changedDirs := make(map[string]struct{})
 | 
			
		||||
	return filepath.Walk(o.diffDir, func(path string, f os.FileInfo, err error) error {
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return err
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		// Rebase path
 | 
			
		||||
		path, err = filepath.Rel(o.diffDir, path)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return err
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		path = filepath.Join(string(os.PathSeparator), path)
 | 
			
		||||
 | 
			
		||||
		// Skip root
 | 
			
		||||
		if path == string(os.PathSeparator) {
 | 
			
		||||
			return nil
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		// TODO: handle opaqueness, start new double walker at this
 | 
			
		||||
		// location to get deletes, and skip tree in single walker
 | 
			
		||||
 | 
			
		||||
		if o.skipChange != nil {
 | 
			
		||||
			if skip, err := o.skipChange(path); skip {
 | 
			
		||||
				return err
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		var kind ChangeKind
 | 
			
		||||
 | 
			
		||||
		deletedFile, err := o.deleteChange(o.diffDir, path, f)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return err
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		// Find out what kind of modification happened
 | 
			
		||||
		if deletedFile != "" {
 | 
			
		||||
			path = deletedFile
 | 
			
		||||
			kind = ChangeKindDelete
 | 
			
		||||
			f = nil
 | 
			
		||||
		} else {
 | 
			
		||||
			// Otherwise, the file was added
 | 
			
		||||
			kind = ChangeKindAdd
 | 
			
		||||
 | 
			
		||||
			// ...Unless it already existed in a base, in which case, it's a modification
 | 
			
		||||
			stat, err := os.Stat(filepath.Join(base, path))
 | 
			
		||||
			if err != nil && !os.IsNotExist(err) {
 | 
			
		||||
				return err
 | 
			
		||||
			}
 | 
			
		||||
			if err == nil {
 | 
			
		||||
				// The file existed in the base, so that's a modification
 | 
			
		||||
 | 
			
		||||
				// However, if it's a directory, maybe it wasn't actually modified.
 | 
			
		||||
				// If you modify /foo/bar/baz, then /foo will be part of the changed files only because it's the parent of bar
 | 
			
		||||
				if stat.IsDir() && f.IsDir() {
 | 
			
		||||
					if f.Size() == stat.Size() && f.Mode() == stat.Mode() && sameFsTime(f.ModTime(), stat.ModTime()) {
 | 
			
		||||
						// Both directories are the same, don't record the change
 | 
			
		||||
						return nil
 | 
			
		||||
					}
 | 
			
		||||
				}
 | 
			
		||||
				kind = ChangeKindModify
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		// If /foo/bar/file.txt is modified, then /foo/bar must be part of the changed files.
 | 
			
		||||
		// This block is here to ensure the change is recorded even if the
 | 
			
		||||
		// modify time, mode and size of the parent directory in the rw and ro layers are all equal.
 | 
			
		||||
		// Check https://github.com/docker/docker/pull/13590 for details.
 | 
			
		||||
		if f.IsDir() {
 | 
			
		||||
			changedDirs[path] = struct{}{}
 | 
			
		||||
		}
 | 
			
		||||
		if kind == ChangeKindAdd || kind == ChangeKindDelete {
 | 
			
		||||
			parent := filepath.Dir(path)
 | 
			
		||||
			if _, ok := changedDirs[parent]; !ok && parent != "/" {
 | 
			
		||||
				pi, err := os.Stat(filepath.Join(o.diffDir, parent))
 | 
			
		||||
				if err := changeFn(ChangeKindModify, parent, pi, err); err != nil {
 | 
			
		||||
					return err
 | 
			
		||||
				}
 | 
			
		||||
				changedDirs[parent] = struct{}{}
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		return changeFn(kind, path, f, nil)
 | 
			
		||||
	})
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// doubleWalkDiff walks both directories to create a diff
 | 
			
		||||
func doubleWalkDiff(ctx context.Context, changeFn ChangeFunc, a, b string) (err error) {
 | 
			
		||||
	g, ctx := errgroup.WithContext(ctx)
 | 
			
		||||
 | 
			
		||||
	var (
 | 
			
		||||
		c1 = make(chan *currentPath)
 | 
			
		||||
		c2 = make(chan *currentPath)
 | 
			
		||||
 | 
			
		||||
		f1, f2 *currentPath
 | 
			
		||||
		rmdir  string
 | 
			
		||||
	)
 | 
			
		||||
	g.Go(func() error {
 | 
			
		||||
		defer close(c1)
 | 
			
		||||
		return pathWalk(ctx, a, c1)
 | 
			
		||||
	})
 | 
			
		||||
	g.Go(func() error {
 | 
			
		||||
		defer close(c2)
 | 
			
		||||
		return pathWalk(ctx, b, c2)
 | 
			
		||||
	})
 | 
			
		||||
	g.Go(func() error {
 | 
			
		||||
		for c1 != nil || c2 != nil {
 | 
			
		||||
			if f1 == nil && c1 != nil {
 | 
			
		||||
				f1, err = nextPath(ctx, c1)
 | 
			
		||||
				if err != nil {
 | 
			
		||||
					return err
 | 
			
		||||
				}
 | 
			
		||||
				if f1 == nil {
 | 
			
		||||
					c1 = nil
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			if f2 == nil && c2 != nil {
 | 
			
		||||
				f2, err = nextPath(ctx, c2)
 | 
			
		||||
				if err != nil {
 | 
			
		||||
					return err
 | 
			
		||||
				}
 | 
			
		||||
				if f2 == nil {
 | 
			
		||||
					c2 = nil
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
			if f1 == nil && f2 == nil {
 | 
			
		||||
				continue
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			var f os.FileInfo
 | 
			
		||||
			k, p := pathChange(f1, f2)
 | 
			
		||||
			switch k {
 | 
			
		||||
			case ChangeKindAdd:
 | 
			
		||||
				if rmdir != "" {
 | 
			
		||||
					rmdir = ""
 | 
			
		||||
				}
 | 
			
		||||
				f = f2.f
 | 
			
		||||
				f2 = nil
 | 
			
		||||
			case ChangeKindDelete:
 | 
			
		||||
				// Check if this file is already removed by being
 | 
			
		||||
				// under of a removed directory
 | 
			
		||||
				if rmdir != "" && strings.HasPrefix(f1.path, rmdir) {
 | 
			
		||||
					f1 = nil
 | 
			
		||||
					continue
 | 
			
		||||
				} else if f1.f.IsDir() {
 | 
			
		||||
					rmdir = f1.path + string(os.PathSeparator)
 | 
			
		||||
				} else if rmdir != "" {
 | 
			
		||||
					rmdir = ""
 | 
			
		||||
				}
 | 
			
		||||
				f1 = nil
 | 
			
		||||
			case ChangeKindModify:
 | 
			
		||||
				same, err := sameFile(f1, f2)
 | 
			
		||||
				if err != nil {
 | 
			
		||||
					return err
 | 
			
		||||
				}
 | 
			
		||||
				if f1.f.IsDir() && !f2.f.IsDir() {
 | 
			
		||||
					rmdir = f1.path + string(os.PathSeparator)
 | 
			
		||||
				} else if rmdir != "" {
 | 
			
		||||
					rmdir = ""
 | 
			
		||||
				}
 | 
			
		||||
				f = f2.f
 | 
			
		||||
				f1 = nil
 | 
			
		||||
				f2 = nil
 | 
			
		||||
				if same {
 | 
			
		||||
					if !isLinked(f) {
 | 
			
		||||
						continue
 | 
			
		||||
					}
 | 
			
		||||
					k = ChangeKindUnmodified
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
			if err := changeFn(k, p, f, nil); err != nil {
 | 
			
		||||
				return err
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		return nil
 | 
			
		||||
	})
 | 
			
		||||
 | 
			
		||||
	return g.Wait()
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										74
									
								
								vendor/github.com/containerd/continuity/fs/diff_unix.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										74
									
								
								vendor/github.com/containerd/continuity/fs/diff_unix.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,74 @@
 | 
			
		||||
// +build !windows
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
   Copyright The containerd Authors.
 | 
			
		||||
 | 
			
		||||
   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.
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
package fs
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"bytes"
 | 
			
		||||
	"os"
 | 
			
		||||
	"syscall"
 | 
			
		||||
 | 
			
		||||
	"github.com/containerd/continuity/sysx"
 | 
			
		||||
	"github.com/pkg/errors"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// detectDirDiff returns diff dir options if a directory could
 | 
			
		||||
// be found in the mount info for upper which is the direct
 | 
			
		||||
// diff with the provided lower directory
 | 
			
		||||
func detectDirDiff(upper, lower string) *diffDirOptions {
 | 
			
		||||
	// TODO: get mount options for upper
 | 
			
		||||
	// TODO: detect AUFS
 | 
			
		||||
	// TODO: detect overlay
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// compareSysStat returns whether the stats are equivalent,
 | 
			
		||||
// whether the files are considered the same file, and
 | 
			
		||||
// an error
 | 
			
		||||
func compareSysStat(s1, s2 interface{}) (bool, error) {
 | 
			
		||||
	ls1, ok := s1.(*syscall.Stat_t)
 | 
			
		||||
	if !ok {
 | 
			
		||||
		return false, nil
 | 
			
		||||
	}
 | 
			
		||||
	ls2, ok := s2.(*syscall.Stat_t)
 | 
			
		||||
	if !ok {
 | 
			
		||||
		return false, nil
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return ls1.Mode == ls2.Mode && ls1.Uid == ls2.Uid && ls1.Gid == ls2.Gid && ls1.Rdev == ls2.Rdev, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func compareCapabilities(p1, p2 string) (bool, error) {
 | 
			
		||||
	c1, err := sysx.LGetxattr(p1, "security.capability")
 | 
			
		||||
	if err != nil && err != sysx.ENODATA {
 | 
			
		||||
		return false, errors.Wrapf(err, "failed to get xattr for %s", p1)
 | 
			
		||||
	}
 | 
			
		||||
	c2, err := sysx.LGetxattr(p2, "security.capability")
 | 
			
		||||
	if err != nil && err != sysx.ENODATA {
 | 
			
		||||
		return false, errors.Wrapf(err, "failed to get xattr for %s", p2)
 | 
			
		||||
	}
 | 
			
		||||
	return bytes.Equal(c1, c2), nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func isLinked(f os.FileInfo) bool {
 | 
			
		||||
	s, ok := f.Sys().(*syscall.Stat_t)
 | 
			
		||||
	if !ok {
 | 
			
		||||
		return false
 | 
			
		||||
	}
 | 
			
		||||
	return !f.IsDir() && s.Nlink > 1
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										48
									
								
								vendor/github.com/containerd/continuity/fs/diff_windows.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										48
									
								
								vendor/github.com/containerd/continuity/fs/diff_windows.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,48 @@
 | 
			
		||||
/*
 | 
			
		||||
   Copyright The containerd Authors.
 | 
			
		||||
 | 
			
		||||
   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.
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
package fs
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"os"
 | 
			
		||||
 | 
			
		||||
	"golang.org/x/sys/windows"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func detectDirDiff(upper, lower string) *diffDirOptions {
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func compareSysStat(s1, s2 interface{}) (bool, error) {
 | 
			
		||||
	f1, ok := s1.(windows.Win32FileAttributeData)
 | 
			
		||||
	if !ok {
 | 
			
		||||
		return false, nil
 | 
			
		||||
	}
 | 
			
		||||
	f2, ok := s2.(windows.Win32FileAttributeData)
 | 
			
		||||
	if !ok {
 | 
			
		||||
		return false, nil
 | 
			
		||||
	}
 | 
			
		||||
	return f1.FileAttributes == f2.FileAttributes, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func compareCapabilities(p1, p2 string) (bool, error) {
 | 
			
		||||
	// TODO: Use windows equivalent
 | 
			
		||||
	return true, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func isLinked(os.FileInfo) bool {
 | 
			
		||||
	return false
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										103
									
								
								vendor/github.com/containerd/continuity/fs/dtype_linux.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										103
									
								
								vendor/github.com/containerd/continuity/fs/dtype_linux.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,103 @@
 | 
			
		||||
// +build linux
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
   Copyright The containerd Authors.
 | 
			
		||||
 | 
			
		||||
   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.
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
package fs
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"io/ioutil"
 | 
			
		||||
	"os"
 | 
			
		||||
	"syscall"
 | 
			
		||||
	"unsafe"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func locateDummyIfEmpty(path string) (string, error) {
 | 
			
		||||
	children, err := ioutil.ReadDir(path)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return "", err
 | 
			
		||||
	}
 | 
			
		||||
	if len(children) != 0 {
 | 
			
		||||
		return "", nil
 | 
			
		||||
	}
 | 
			
		||||
	dummyFile, err := ioutil.TempFile(path, "fsutils-dummy")
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return "", err
 | 
			
		||||
	}
 | 
			
		||||
	name := dummyFile.Name()
 | 
			
		||||
	err = dummyFile.Close()
 | 
			
		||||
	return name, err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// SupportsDType returns whether the filesystem mounted on path supports d_type
 | 
			
		||||
func SupportsDType(path string) (bool, error) {
 | 
			
		||||
	// locate dummy so that we have at least one dirent
 | 
			
		||||
	dummy, err := locateDummyIfEmpty(path)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return false, err
 | 
			
		||||
	}
 | 
			
		||||
	if dummy != "" {
 | 
			
		||||
		defer os.Remove(dummy)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	visited := 0
 | 
			
		||||
	supportsDType := true
 | 
			
		||||
	fn := func(ent *syscall.Dirent) bool {
 | 
			
		||||
		visited++
 | 
			
		||||
		if ent.Type == syscall.DT_UNKNOWN {
 | 
			
		||||
			supportsDType = false
 | 
			
		||||
			// stop iteration
 | 
			
		||||
			return true
 | 
			
		||||
		}
 | 
			
		||||
		// continue iteration
 | 
			
		||||
		return false
 | 
			
		||||
	}
 | 
			
		||||
	if err = iterateReadDir(path, fn); err != nil {
 | 
			
		||||
		return false, err
 | 
			
		||||
	}
 | 
			
		||||
	if visited == 0 {
 | 
			
		||||
		return false, fmt.Errorf("did not hit any dirent during iteration %s", path)
 | 
			
		||||
	}
 | 
			
		||||
	return supportsDType, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func iterateReadDir(path string, fn func(*syscall.Dirent) bool) error {
 | 
			
		||||
	d, err := os.Open(path)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
	defer d.Close()
 | 
			
		||||
	fd := int(d.Fd())
 | 
			
		||||
	buf := make([]byte, 4096)
 | 
			
		||||
	for {
 | 
			
		||||
		nbytes, err := syscall.ReadDirent(fd, buf)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return err
 | 
			
		||||
		}
 | 
			
		||||
		if nbytes == 0 {
 | 
			
		||||
			break
 | 
			
		||||
		}
 | 
			
		||||
		for off := 0; off < nbytes; {
 | 
			
		||||
			ent := (*syscall.Dirent)(unsafe.Pointer(&buf[off]))
 | 
			
		||||
			if stop := fn(ent); stop {
 | 
			
		||||
				return nil
 | 
			
		||||
			}
 | 
			
		||||
			off += int(ent.Reclen)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										38
									
								
								vendor/github.com/containerd/continuity/fs/du.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										38
									
								
								vendor/github.com/containerd/continuity/fs/du.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,38 @@
 | 
			
		||||
/*
 | 
			
		||||
   Copyright The containerd Authors.
 | 
			
		||||
 | 
			
		||||
   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.
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
package fs
 | 
			
		||||
 | 
			
		||||
import "context"
 | 
			
		||||
 | 
			
		||||
// Usage of disk information
 | 
			
		||||
type Usage struct {
 | 
			
		||||
	Inodes int64
 | 
			
		||||
	Size   int64
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// DiskUsage counts the number of inodes and disk usage for the resources under
 | 
			
		||||
// path.
 | 
			
		||||
func DiskUsage(ctx context.Context, roots ...string) (Usage, error) {
 | 
			
		||||
	return diskUsage(ctx, roots...)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// DiffUsage counts the numbers of inodes and disk usage in the
 | 
			
		||||
// diff between the 2 directories. The first path is intended
 | 
			
		||||
// as the base directory and the second as the changed directory.
 | 
			
		||||
func DiffUsage(ctx context.Context, a, b string) (Usage, error) {
 | 
			
		||||
	return diffUsage(ctx, a, b)
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										110
									
								
								vendor/github.com/containerd/continuity/fs/du_unix.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										110
									
								
								vendor/github.com/containerd/continuity/fs/du_unix.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,110 @@
 | 
			
		||||
// +build !windows
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
   Copyright The containerd Authors.
 | 
			
		||||
 | 
			
		||||
   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.
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
package fs
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"context"
 | 
			
		||||
	"os"
 | 
			
		||||
	"path/filepath"
 | 
			
		||||
	"syscall"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
type inode struct {
 | 
			
		||||
	// TODO(stevvooe): Can probably reduce memory usage by not tracking
 | 
			
		||||
	// device, but we can leave this right for now.
 | 
			
		||||
	dev, ino uint64
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func newInode(stat *syscall.Stat_t) inode {
 | 
			
		||||
	return inode{
 | 
			
		||||
		// Dev is uint32 on darwin/bsd, uint64 on linux/solaris
 | 
			
		||||
		dev: uint64(stat.Dev), // nolint: unconvert
 | 
			
		||||
		// Ino is uint32 on bsd, uint64 on darwin/linux/solaris
 | 
			
		||||
		ino: uint64(stat.Ino), // nolint: unconvert
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func diskUsage(ctx context.Context, roots ...string) (Usage, error) {
 | 
			
		||||
 | 
			
		||||
	var (
 | 
			
		||||
		size   int64
 | 
			
		||||
		inodes = map[inode]struct{}{} // expensive!
 | 
			
		||||
	)
 | 
			
		||||
 | 
			
		||||
	for _, root := range roots {
 | 
			
		||||
		if err := filepath.Walk(root, func(path string, fi os.FileInfo, err error) error {
 | 
			
		||||
			if err != nil {
 | 
			
		||||
				return err
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			select {
 | 
			
		||||
			case <-ctx.Done():
 | 
			
		||||
				return ctx.Err()
 | 
			
		||||
			default:
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			inoKey := newInode(fi.Sys().(*syscall.Stat_t))
 | 
			
		||||
			if _, ok := inodes[inoKey]; !ok {
 | 
			
		||||
				inodes[inoKey] = struct{}{}
 | 
			
		||||
				size += fi.Size()
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			return nil
 | 
			
		||||
		}); err != nil {
 | 
			
		||||
			return Usage{}, err
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return Usage{
 | 
			
		||||
		Inodes: int64(len(inodes)),
 | 
			
		||||
		Size:   size,
 | 
			
		||||
	}, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func diffUsage(ctx context.Context, a, b string) (Usage, error) {
 | 
			
		||||
	var (
 | 
			
		||||
		size   int64
 | 
			
		||||
		inodes = map[inode]struct{}{} // expensive!
 | 
			
		||||
	)
 | 
			
		||||
 | 
			
		||||
	if err := Changes(ctx, a, b, func(kind ChangeKind, _ string, fi os.FileInfo, err error) error {
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return err
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if kind == ChangeKindAdd || kind == ChangeKindModify {
 | 
			
		||||
			inoKey := newInode(fi.Sys().(*syscall.Stat_t))
 | 
			
		||||
			if _, ok := inodes[inoKey]; !ok {
 | 
			
		||||
				inodes[inoKey] = struct{}{}
 | 
			
		||||
				size += fi.Size()
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			return nil
 | 
			
		||||
 | 
			
		||||
		}
 | 
			
		||||
		return nil
 | 
			
		||||
	}); err != nil {
 | 
			
		||||
		return Usage{}, err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return Usage{
 | 
			
		||||
		Inodes: int64(len(inodes)),
 | 
			
		||||
		Size:   size,
 | 
			
		||||
	}, nil
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										82
									
								
								vendor/github.com/containerd/continuity/fs/du_windows.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										82
									
								
								vendor/github.com/containerd/continuity/fs/du_windows.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,82 @@
 | 
			
		||||
// +build windows
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
   Copyright The containerd Authors.
 | 
			
		||||
 | 
			
		||||
   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.
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
package fs
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"context"
 | 
			
		||||
	"os"
 | 
			
		||||
	"path/filepath"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func diskUsage(ctx context.Context, roots ...string) (Usage, error) {
 | 
			
		||||
	var (
 | 
			
		||||
		size int64
 | 
			
		||||
	)
 | 
			
		||||
 | 
			
		||||
	// TODO(stevvooe): Support inodes (or equivalent) for windows.
 | 
			
		||||
 | 
			
		||||
	for _, root := range roots {
 | 
			
		||||
		if err := filepath.Walk(root, func(path string, fi os.FileInfo, err error) error {
 | 
			
		||||
			if err != nil {
 | 
			
		||||
				return err
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			select {
 | 
			
		||||
			case <-ctx.Done():
 | 
			
		||||
				return ctx.Err()
 | 
			
		||||
			default:
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			size += fi.Size()
 | 
			
		||||
			return nil
 | 
			
		||||
		}); err != nil {
 | 
			
		||||
			return Usage{}, err
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return Usage{
 | 
			
		||||
		Size: size,
 | 
			
		||||
	}, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func diffUsage(ctx context.Context, a, b string) (Usage, error) {
 | 
			
		||||
	var (
 | 
			
		||||
		size int64
 | 
			
		||||
	)
 | 
			
		||||
 | 
			
		||||
	if err := Changes(ctx, a, b, func(kind ChangeKind, _ string, fi os.FileInfo, err error) error {
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return err
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if kind == ChangeKindAdd || kind == ChangeKindModify {
 | 
			
		||||
			size += fi.Size()
 | 
			
		||||
 | 
			
		||||
			return nil
 | 
			
		||||
 | 
			
		||||
		}
 | 
			
		||||
		return nil
 | 
			
		||||
	}); err != nil {
 | 
			
		||||
		return Usage{}, err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return Usage{
 | 
			
		||||
		Size: size,
 | 
			
		||||
	}, nil
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										43
									
								
								vendor/github.com/containerd/continuity/fs/hardlink.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										43
									
								
								vendor/github.com/containerd/continuity/fs/hardlink.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,43 @@
 | 
			
		||||
/*
 | 
			
		||||
   Copyright The containerd Authors.
 | 
			
		||||
 | 
			
		||||
   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.
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
package fs
 | 
			
		||||
 | 
			
		||||
import "os"
 | 
			
		||||
 | 
			
		||||
// GetLinkInfo returns an identifier representing the node a hardlink is pointing
 | 
			
		||||
// to. If the file is not hard linked then 0 will be returned.
 | 
			
		||||
func GetLinkInfo(fi os.FileInfo) (uint64, bool) {
 | 
			
		||||
	return getLinkInfo(fi)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// getLinkSource returns a path for the given name and
 | 
			
		||||
// file info to its link source in the provided inode
 | 
			
		||||
// map. If the given file name is not in the map and
 | 
			
		||||
// has other links, it is added to the inode map
 | 
			
		||||
// to be a source for other link locations.
 | 
			
		||||
func getLinkSource(name string, fi os.FileInfo, inodes map[uint64]string) (string, error) {
 | 
			
		||||
	inode, isHardlink := getLinkInfo(fi)
 | 
			
		||||
	if !isHardlink {
 | 
			
		||||
		return "", nil
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	path, ok := inodes[inode]
 | 
			
		||||
	if !ok {
 | 
			
		||||
		inodes[inode] = name
 | 
			
		||||
	}
 | 
			
		||||
	return path, nil
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										34
									
								
								vendor/github.com/containerd/continuity/fs/hardlink_unix.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										34
									
								
								vendor/github.com/containerd/continuity/fs/hardlink_unix.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,34 @@
 | 
			
		||||
// +build !windows
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
   Copyright The containerd Authors.
 | 
			
		||||
 | 
			
		||||
   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.
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
package fs
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"os"
 | 
			
		||||
	"syscall"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func getLinkInfo(fi os.FileInfo) (uint64, bool) {
 | 
			
		||||
	s, ok := fi.Sys().(*syscall.Stat_t)
 | 
			
		||||
	if !ok {
 | 
			
		||||
		return 0, false
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Ino is uint32 on bsd, uint64 on darwin/linux/solaris
 | 
			
		||||
	return uint64(s.Ino), !fi.IsDir() && s.Nlink > 1 // nolint: unconvert
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										23
									
								
								vendor/github.com/containerd/continuity/fs/hardlink_windows.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										23
									
								
								vendor/github.com/containerd/continuity/fs/hardlink_windows.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,23 @@
 | 
			
		||||
/*
 | 
			
		||||
   Copyright The containerd Authors.
 | 
			
		||||
 | 
			
		||||
   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.
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
package fs
 | 
			
		||||
 | 
			
		||||
import "os"
 | 
			
		||||
 | 
			
		||||
func getLinkInfo(fi os.FileInfo) (uint64, bool) {
 | 
			
		||||
	return 0, false
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										286
									
								
								vendor/github.com/containerd/continuity/fs/path.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										286
									
								
								vendor/github.com/containerd/continuity/fs/path.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,286 @@
 | 
			
		||||
/*
 | 
			
		||||
   Copyright The containerd Authors.
 | 
			
		||||
 | 
			
		||||
   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.
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
package fs
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"bytes"
 | 
			
		||||
	"context"
 | 
			
		||||
	"io"
 | 
			
		||||
	"os"
 | 
			
		||||
	"path/filepath"
 | 
			
		||||
	"strings"
 | 
			
		||||
 | 
			
		||||
	"github.com/pkg/errors"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
var (
 | 
			
		||||
	errTooManyLinks = errors.New("too many links")
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
type currentPath struct {
 | 
			
		||||
	path     string
 | 
			
		||||
	f        os.FileInfo
 | 
			
		||||
	fullPath string
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func pathChange(lower, upper *currentPath) (ChangeKind, string) {
 | 
			
		||||
	if lower == nil {
 | 
			
		||||
		if upper == nil {
 | 
			
		||||
			panic("cannot compare nil paths")
 | 
			
		||||
		}
 | 
			
		||||
		return ChangeKindAdd, upper.path
 | 
			
		||||
	}
 | 
			
		||||
	if upper == nil {
 | 
			
		||||
		return ChangeKindDelete, lower.path
 | 
			
		||||
	}
 | 
			
		||||
	// TODO: compare by directory
 | 
			
		||||
 | 
			
		||||
	switch i := strings.Compare(lower.path, upper.path); {
 | 
			
		||||
	case i < 0:
 | 
			
		||||
		// File in lower that is not in upper
 | 
			
		||||
		return ChangeKindDelete, lower.path
 | 
			
		||||
	case i > 0:
 | 
			
		||||
		// File in upper that is not in lower
 | 
			
		||||
		return ChangeKindAdd, upper.path
 | 
			
		||||
	default:
 | 
			
		||||
		return ChangeKindModify, upper.path
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func sameFile(f1, f2 *currentPath) (bool, error) {
 | 
			
		||||
	if os.SameFile(f1.f, f2.f) {
 | 
			
		||||
		return true, nil
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	equalStat, err := compareSysStat(f1.f.Sys(), f2.f.Sys())
 | 
			
		||||
	if err != nil || !equalStat {
 | 
			
		||||
		return equalStat, err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if eq, err := compareCapabilities(f1.fullPath, f2.fullPath); err != nil || !eq {
 | 
			
		||||
		return eq, err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// If not a directory also check size, modtime, and content
 | 
			
		||||
	if !f1.f.IsDir() {
 | 
			
		||||
		if f1.f.Size() != f2.f.Size() {
 | 
			
		||||
			return false, nil
 | 
			
		||||
		}
 | 
			
		||||
		t1 := f1.f.ModTime()
 | 
			
		||||
		t2 := f2.f.ModTime()
 | 
			
		||||
 | 
			
		||||
		if t1.Unix() != t2.Unix() {
 | 
			
		||||
			return false, nil
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		// If the timestamp may have been truncated in both of the
 | 
			
		||||
		// files, check content of file to determine difference
 | 
			
		||||
		if t1.Nanosecond() == 0 && t2.Nanosecond() == 0 {
 | 
			
		||||
			var eq bool
 | 
			
		||||
			if (f1.f.Mode() & os.ModeSymlink) == os.ModeSymlink {
 | 
			
		||||
				eq, err = compareSymlinkTarget(f1.fullPath, f2.fullPath)
 | 
			
		||||
			} else if f1.f.Size() > 0 {
 | 
			
		||||
				eq, err = compareFileContent(f1.fullPath, f2.fullPath)
 | 
			
		||||
			}
 | 
			
		||||
			if err != nil || !eq {
 | 
			
		||||
				return eq, err
 | 
			
		||||
			}
 | 
			
		||||
		} else if t1.Nanosecond() != t2.Nanosecond() {
 | 
			
		||||
			return false, nil
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return true, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func compareSymlinkTarget(p1, p2 string) (bool, error) {
 | 
			
		||||
	t1, err := os.Readlink(p1)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return false, err
 | 
			
		||||
	}
 | 
			
		||||
	t2, err := os.Readlink(p2)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return false, err
 | 
			
		||||
	}
 | 
			
		||||
	return t1 == t2, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const compareChuckSize = 32 * 1024
 | 
			
		||||
 | 
			
		||||
// compareFileContent compares the content of 2 same sized files
 | 
			
		||||
// by comparing each byte.
 | 
			
		||||
func compareFileContent(p1, p2 string) (bool, error) {
 | 
			
		||||
	f1, err := os.Open(p1)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return false, err
 | 
			
		||||
	}
 | 
			
		||||
	defer f1.Close()
 | 
			
		||||
	f2, err := os.Open(p2)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return false, err
 | 
			
		||||
	}
 | 
			
		||||
	defer f2.Close()
 | 
			
		||||
 | 
			
		||||
	b1 := make([]byte, compareChuckSize)
 | 
			
		||||
	b2 := make([]byte, compareChuckSize)
 | 
			
		||||
	for {
 | 
			
		||||
		n1, err1 := f1.Read(b1)
 | 
			
		||||
		if err1 != nil && err1 != io.EOF {
 | 
			
		||||
			return false, err1
 | 
			
		||||
		}
 | 
			
		||||
		n2, err2 := f2.Read(b2)
 | 
			
		||||
		if err2 != nil && err2 != io.EOF {
 | 
			
		||||
			return false, err2
 | 
			
		||||
		}
 | 
			
		||||
		if n1 != n2 || !bytes.Equal(b1[:n1], b2[:n2]) {
 | 
			
		||||
			return false, nil
 | 
			
		||||
		}
 | 
			
		||||
		if err1 == io.EOF && err2 == io.EOF {
 | 
			
		||||
			return true, nil
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func pathWalk(ctx context.Context, root string, pathC chan<- *currentPath) error {
 | 
			
		||||
	return filepath.Walk(root, func(path string, f os.FileInfo, err error) error {
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return err
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		// Rebase path
 | 
			
		||||
		path, err = filepath.Rel(root, path)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return err
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		path = filepath.Join(string(os.PathSeparator), path)
 | 
			
		||||
 | 
			
		||||
		// Skip root
 | 
			
		||||
		if path == string(os.PathSeparator) {
 | 
			
		||||
			return nil
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		p := ¤tPath{
 | 
			
		||||
			path:     path,
 | 
			
		||||
			f:        f,
 | 
			
		||||
			fullPath: filepath.Join(root, path),
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		select {
 | 
			
		||||
		case <-ctx.Done():
 | 
			
		||||
			return ctx.Err()
 | 
			
		||||
		case pathC <- p:
 | 
			
		||||
			return nil
 | 
			
		||||
		}
 | 
			
		||||
	})
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func nextPath(ctx context.Context, pathC <-chan *currentPath) (*currentPath, error) {
 | 
			
		||||
	select {
 | 
			
		||||
	case <-ctx.Done():
 | 
			
		||||
		return nil, ctx.Err()
 | 
			
		||||
	case p := <-pathC:
 | 
			
		||||
		return p, nil
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// RootPath joins a path with a root, evaluating and bounding any
 | 
			
		||||
// symlink to the root directory.
 | 
			
		||||
func RootPath(root, path string) (string, error) {
 | 
			
		||||
	if path == "" {
 | 
			
		||||
		return root, nil
 | 
			
		||||
	}
 | 
			
		||||
	var linksWalked int // to protect against cycles
 | 
			
		||||
	for {
 | 
			
		||||
		i := linksWalked
 | 
			
		||||
		newpath, err := walkLinks(root, path, &linksWalked)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return "", err
 | 
			
		||||
		}
 | 
			
		||||
		path = newpath
 | 
			
		||||
		if i == linksWalked {
 | 
			
		||||
			newpath = filepath.Join("/", newpath)
 | 
			
		||||
			if path == newpath {
 | 
			
		||||
				return filepath.Join(root, newpath), nil
 | 
			
		||||
			}
 | 
			
		||||
			path = newpath
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func walkLink(root, path string, linksWalked *int) (newpath string, islink bool, err error) {
 | 
			
		||||
	if *linksWalked > 255 {
 | 
			
		||||
		return "", false, errTooManyLinks
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	path = filepath.Join("/", path)
 | 
			
		||||
	if path == "/" {
 | 
			
		||||
		return path, false, nil
 | 
			
		||||
	}
 | 
			
		||||
	realPath := filepath.Join(root, path)
 | 
			
		||||
 | 
			
		||||
	fi, err := os.Lstat(realPath)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		// If path does not yet exist, treat as non-symlink
 | 
			
		||||
		if os.IsNotExist(err) {
 | 
			
		||||
			return path, false, nil
 | 
			
		||||
		}
 | 
			
		||||
		return "", false, err
 | 
			
		||||
	}
 | 
			
		||||
	if fi.Mode()&os.ModeSymlink == 0 {
 | 
			
		||||
		return path, false, nil
 | 
			
		||||
	}
 | 
			
		||||
	newpath, err = os.Readlink(realPath)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return "", false, err
 | 
			
		||||
	}
 | 
			
		||||
	*linksWalked++
 | 
			
		||||
	return newpath, true, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func walkLinks(root, path string, linksWalked *int) (string, error) {
 | 
			
		||||
	switch dir, file := filepath.Split(path); {
 | 
			
		||||
	case dir == "":
 | 
			
		||||
		newpath, _, err := walkLink(root, file, linksWalked)
 | 
			
		||||
		return newpath, err
 | 
			
		||||
	case file == "":
 | 
			
		||||
		if os.IsPathSeparator(dir[len(dir)-1]) {
 | 
			
		||||
			if dir == "/" {
 | 
			
		||||
				return dir, nil
 | 
			
		||||
			}
 | 
			
		||||
			return walkLinks(root, dir[:len(dir)-1], linksWalked)
 | 
			
		||||
		}
 | 
			
		||||
		newpath, _, err := walkLink(root, dir, linksWalked)
 | 
			
		||||
		return newpath, err
 | 
			
		||||
	default:
 | 
			
		||||
		newdir, err := walkLinks(root, dir, linksWalked)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return "", err
 | 
			
		||||
		}
 | 
			
		||||
		newpath, islink, err := walkLink(root, filepath.Join(newdir, file), linksWalked)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return "", err
 | 
			
		||||
		}
 | 
			
		||||
		if !islink {
 | 
			
		||||
			return newpath, nil
 | 
			
		||||
		}
 | 
			
		||||
		if filepath.IsAbs(newpath) {
 | 
			
		||||
			return newpath, nil
 | 
			
		||||
		}
 | 
			
		||||
		return filepath.Join(newdir, newpath), nil
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										44
									
								
								vendor/github.com/containerd/continuity/fs/stat_bsd.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										44
									
								
								vendor/github.com/containerd/continuity/fs/stat_bsd.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,44 @@
 | 
			
		||||
// +build darwin freebsd
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
   Copyright The containerd Authors.
 | 
			
		||||
 | 
			
		||||
   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.
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
package fs
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"syscall"
 | 
			
		||||
	"time"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// StatAtime returns the access time from a stat struct
 | 
			
		||||
func StatAtime(st *syscall.Stat_t) syscall.Timespec {
 | 
			
		||||
	return st.Atimespec
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// StatCtime returns the created time from a stat struct
 | 
			
		||||
func StatCtime(st *syscall.Stat_t) syscall.Timespec {
 | 
			
		||||
	return st.Ctimespec
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// StatMtime returns the modified time from a stat struct
 | 
			
		||||
func StatMtime(st *syscall.Stat_t) syscall.Timespec {
 | 
			
		||||
	return st.Mtimespec
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// StatATimeAsTime returns the access time as a time.Time
 | 
			
		||||
func StatATimeAsTime(st *syscall.Stat_t) time.Time {
 | 
			
		||||
	return time.Unix(int64(st.Atimespec.Sec), int64(st.Atimespec.Nsec)) // nolint: unconvert
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										43
									
								
								vendor/github.com/containerd/continuity/fs/stat_linux.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										43
									
								
								vendor/github.com/containerd/continuity/fs/stat_linux.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,43 @@
 | 
			
		||||
/*
 | 
			
		||||
   Copyright The containerd Authors.
 | 
			
		||||
 | 
			
		||||
   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.
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
package fs
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"syscall"
 | 
			
		||||
	"time"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// StatAtime returns the Atim
 | 
			
		||||
func StatAtime(st *syscall.Stat_t) syscall.Timespec {
 | 
			
		||||
	return st.Atim
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// StatCtime returns the Ctim
 | 
			
		||||
func StatCtime(st *syscall.Stat_t) syscall.Timespec {
 | 
			
		||||
	return st.Ctim
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// StatMtime returns the Mtim
 | 
			
		||||
func StatMtime(st *syscall.Stat_t) syscall.Timespec {
 | 
			
		||||
	return st.Mtim
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// StatATimeAsTime returns st.Atim as a time.Time
 | 
			
		||||
func StatATimeAsTime(st *syscall.Stat_t) time.Time {
 | 
			
		||||
	// The int64 conversions ensure the line compiles for 32-bit systems as well.
 | 
			
		||||
	return time.Unix(int64(st.Atim.Sec), int64(st.Atim.Nsec)) // nolint: unconvert
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										29
									
								
								vendor/github.com/containerd/continuity/fs/time.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										29
									
								
								vendor/github.com/containerd/continuity/fs/time.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,29 @@
 | 
			
		||||
/*
 | 
			
		||||
   Copyright The containerd Authors.
 | 
			
		||||
 | 
			
		||||
   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.
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
package fs
 | 
			
		||||
 | 
			
		||||
import "time"
 | 
			
		||||
 | 
			
		||||
// Gnu tar and the go tar writer don't have sub-second mtime
 | 
			
		||||
// precision, which is problematic when we apply changes via tar
 | 
			
		||||
// files, we handle this by comparing for exact times, *or* same
 | 
			
		||||
// second count and either a or b having exactly 0 nanoseconds
 | 
			
		||||
func sameFsTime(a, b time.Time) bool {
 | 
			
		||||
	return a == b ||
 | 
			
		||||
		(a.Unix() == b.Unix() &&
 | 
			
		||||
			(a.Nanosecond() == 0 || b.Nanosecond() == 0))
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										101
									
								
								vendor/github.com/containerd/continuity/pathdriver/path_driver.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										101
									
								
								vendor/github.com/containerd/continuity/pathdriver/path_driver.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,101 @@
 | 
			
		||||
/*
 | 
			
		||||
   Copyright The containerd Authors.
 | 
			
		||||
 | 
			
		||||
   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.
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
package pathdriver
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"path/filepath"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// PathDriver provides all of the path manipulation functions in a common
 | 
			
		||||
// interface. The context should call these and never use the `filepath`
 | 
			
		||||
// package or any other package to manipulate paths.
 | 
			
		||||
type PathDriver interface {
 | 
			
		||||
	Join(paths ...string) string
 | 
			
		||||
	IsAbs(path string) bool
 | 
			
		||||
	Rel(base, target string) (string, error)
 | 
			
		||||
	Base(path string) string
 | 
			
		||||
	Dir(path string) string
 | 
			
		||||
	Clean(path string) string
 | 
			
		||||
	Split(path string) (dir, file string)
 | 
			
		||||
	Separator() byte
 | 
			
		||||
	Abs(path string) (string, error)
 | 
			
		||||
	Walk(string, filepath.WalkFunc) error
 | 
			
		||||
	FromSlash(path string) string
 | 
			
		||||
	ToSlash(path string) string
 | 
			
		||||
	Match(pattern, name string) (matched bool, err error)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// pathDriver is a simple default implementation calls the filepath package.
 | 
			
		||||
type pathDriver struct{}
 | 
			
		||||
 | 
			
		||||
// LocalPathDriver is the exported pathDriver struct for convenience.
 | 
			
		||||
var LocalPathDriver PathDriver = &pathDriver{}
 | 
			
		||||
 | 
			
		||||
func (*pathDriver) Join(paths ...string) string {
 | 
			
		||||
	return filepath.Join(paths...)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (*pathDriver) IsAbs(path string) bool {
 | 
			
		||||
	return filepath.IsAbs(path)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (*pathDriver) Rel(base, target string) (string, error) {
 | 
			
		||||
	return filepath.Rel(base, target)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (*pathDriver) Base(path string) string {
 | 
			
		||||
	return filepath.Base(path)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (*pathDriver) Dir(path string) string {
 | 
			
		||||
	return filepath.Dir(path)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (*pathDriver) Clean(path string) string {
 | 
			
		||||
	return filepath.Clean(path)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (*pathDriver) Split(path string) (dir, file string) {
 | 
			
		||||
	return filepath.Split(path)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (*pathDriver) Separator() byte {
 | 
			
		||||
	return filepath.Separator
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (*pathDriver) Abs(path string) (string, error) {
 | 
			
		||||
	return filepath.Abs(path)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Note that filepath.Walk calls os.Stat, so if the context wants to
 | 
			
		||||
// to call Driver.Stat() for Walk, they need to create a new struct that
 | 
			
		||||
// overrides this method.
 | 
			
		||||
func (*pathDriver) Walk(root string, walkFn filepath.WalkFunc) error {
 | 
			
		||||
	return filepath.Walk(root, walkFn)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (*pathDriver) FromSlash(path string) string {
 | 
			
		||||
	return filepath.FromSlash(path)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (*pathDriver) ToSlash(path string) string {
 | 
			
		||||
	return filepath.ToSlash(path)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (*pathDriver) Match(pattern, name string) (bool, error) {
 | 
			
		||||
	return filepath.Match(pattern, name)
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										26
									
								
								vendor/github.com/containerd/continuity/syscallx/syscall_unix.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										26
									
								
								vendor/github.com/containerd/continuity/syscallx/syscall_unix.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,26 @@
 | 
			
		||||
// +build !windows
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
   Copyright The containerd Authors.
 | 
			
		||||
 | 
			
		||||
   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.
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
package syscallx
 | 
			
		||||
 | 
			
		||||
import "syscall"
 | 
			
		||||
 | 
			
		||||
// Readlink returns the destination of the named symbolic link.
 | 
			
		||||
func Readlink(path string, buf []byte) (n int, err error) {
 | 
			
		||||
	return syscall.Readlink(path, buf)
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										112
									
								
								vendor/github.com/containerd/continuity/syscallx/syscall_windows.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										112
									
								
								vendor/github.com/containerd/continuity/syscallx/syscall_windows.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,112 @@
 | 
			
		||||
/*
 | 
			
		||||
   Copyright The containerd Authors.
 | 
			
		||||
 | 
			
		||||
   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.
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
package syscallx
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"syscall"
 | 
			
		||||
	"unsafe"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
type reparseDataBuffer struct {
 | 
			
		||||
	ReparseTag        uint32
 | 
			
		||||
	ReparseDataLength uint16
 | 
			
		||||
	Reserved          uint16
 | 
			
		||||
 | 
			
		||||
	// GenericReparseBuffer
 | 
			
		||||
	reparseBuffer byte
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type mountPointReparseBuffer struct {
 | 
			
		||||
	SubstituteNameOffset uint16
 | 
			
		||||
	SubstituteNameLength uint16
 | 
			
		||||
	PrintNameOffset      uint16
 | 
			
		||||
	PrintNameLength      uint16
 | 
			
		||||
	PathBuffer           [1]uint16
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type symbolicLinkReparseBuffer struct {
 | 
			
		||||
	SubstituteNameOffset uint16
 | 
			
		||||
	SubstituteNameLength uint16
 | 
			
		||||
	PrintNameOffset      uint16
 | 
			
		||||
	PrintNameLength      uint16
 | 
			
		||||
	Flags                uint32
 | 
			
		||||
	PathBuffer           [1]uint16
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const (
 | 
			
		||||
	_IO_REPARSE_TAG_MOUNT_POINT = 0xA0000003
 | 
			
		||||
	_SYMLINK_FLAG_RELATIVE      = 1
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// Readlink returns the destination of the named symbolic link.
 | 
			
		||||
func Readlink(path string, buf []byte) (n int, err error) {
 | 
			
		||||
	fd, err := syscall.CreateFile(syscall.StringToUTF16Ptr(path), syscall.GENERIC_READ, 0, nil, syscall.OPEN_EXISTING,
 | 
			
		||||
		syscall.FILE_FLAG_OPEN_REPARSE_POINT|syscall.FILE_FLAG_BACKUP_SEMANTICS, 0)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return -1, err
 | 
			
		||||
	}
 | 
			
		||||
	defer syscall.CloseHandle(fd)
 | 
			
		||||
 | 
			
		||||
	rdbbuf := make([]byte, syscall.MAXIMUM_REPARSE_DATA_BUFFER_SIZE)
 | 
			
		||||
	var bytesReturned uint32
 | 
			
		||||
	err = syscall.DeviceIoControl(fd, syscall.FSCTL_GET_REPARSE_POINT, nil, 0, &rdbbuf[0], uint32(len(rdbbuf)), &bytesReturned, nil)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return -1, err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	rdb := (*reparseDataBuffer)(unsafe.Pointer(&rdbbuf[0]))
 | 
			
		||||
	var s string
 | 
			
		||||
	switch rdb.ReparseTag {
 | 
			
		||||
	case syscall.IO_REPARSE_TAG_SYMLINK:
 | 
			
		||||
		data := (*symbolicLinkReparseBuffer)(unsafe.Pointer(&rdb.reparseBuffer))
 | 
			
		||||
		p := (*[0xffff]uint16)(unsafe.Pointer(&data.PathBuffer[0]))
 | 
			
		||||
		s = syscall.UTF16ToString(p[data.SubstituteNameOffset/2 : (data.SubstituteNameOffset+data.SubstituteNameLength)/2])
 | 
			
		||||
		if data.Flags&_SYMLINK_FLAG_RELATIVE == 0 {
 | 
			
		||||
			if len(s) >= 4 && s[:4] == `\??\` {
 | 
			
		||||
				s = s[4:]
 | 
			
		||||
				switch {
 | 
			
		||||
				case len(s) >= 2 && s[1] == ':': // \??\C:\foo\bar
 | 
			
		||||
					// do nothing
 | 
			
		||||
				case len(s) >= 4 && s[:4] == `UNC\`: // \??\UNC\foo\bar
 | 
			
		||||
					s = `\\` + s[4:]
 | 
			
		||||
				default:
 | 
			
		||||
					// unexpected; do nothing
 | 
			
		||||
				}
 | 
			
		||||
			} else {
 | 
			
		||||
				// unexpected; do nothing
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	case _IO_REPARSE_TAG_MOUNT_POINT:
 | 
			
		||||
		data := (*mountPointReparseBuffer)(unsafe.Pointer(&rdb.reparseBuffer))
 | 
			
		||||
		p := (*[0xffff]uint16)(unsafe.Pointer(&data.PathBuffer[0]))
 | 
			
		||||
		s = syscall.UTF16ToString(p[data.SubstituteNameOffset/2 : (data.SubstituteNameOffset+data.SubstituteNameLength)/2])
 | 
			
		||||
		if len(s) >= 4 && s[:4] == `\??\` { // \??\C:\foo\bar
 | 
			
		||||
			if len(s) < 48 || s[:11] != `\??\Volume{` {
 | 
			
		||||
				s = s[4:]
 | 
			
		||||
			}
 | 
			
		||||
		} else {
 | 
			
		||||
			// unexpected; do nothing
 | 
			
		||||
		}
 | 
			
		||||
	default:
 | 
			
		||||
		// the path is not a symlink or junction but another type of reparse
 | 
			
		||||
		// point
 | 
			
		||||
		return -1, syscall.ENOENT
 | 
			
		||||
	}
 | 
			
		||||
	n = copy(buf, []byte(s))
 | 
			
		||||
 | 
			
		||||
	return n, nil
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										3
									
								
								vendor/github.com/containerd/continuity/sysx/README.md
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										3
									
								
								vendor/github.com/containerd/continuity/sysx/README.md
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,3 @@
 | 
			
		||||
This package is for internal use only. It is intended to only have
 | 
			
		||||
temporary changes before they are upstreamed to golang.org/x/sys/
 | 
			
		||||
(a.k.a. https://github.com/golang/sys).
 | 
			
		||||
							
								
								
									
										128
									
								
								vendor/github.com/containerd/continuity/sysx/file_posix.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										128
									
								
								vendor/github.com/containerd/continuity/sysx/file_posix.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,128 @@
 | 
			
		||||
/*
 | 
			
		||||
   Copyright The containerd Authors.
 | 
			
		||||
 | 
			
		||||
   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.
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
package sysx
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"os"
 | 
			
		||||
	"path/filepath"
 | 
			
		||||
 | 
			
		||||
	"github.com/containerd/continuity/syscallx"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// Readlink returns the destination of the named symbolic link.
 | 
			
		||||
// If there is an error, it will be of type *PathError.
 | 
			
		||||
func Readlink(name string) (string, error) {
 | 
			
		||||
	for len := 128; ; len *= 2 {
 | 
			
		||||
		b := make([]byte, len)
 | 
			
		||||
		n, e := fixCount(syscallx.Readlink(fixLongPath(name), b))
 | 
			
		||||
		if e != nil {
 | 
			
		||||
			return "", &os.PathError{Op: "readlink", Path: name, Err: e}
 | 
			
		||||
		}
 | 
			
		||||
		if n < len {
 | 
			
		||||
			return string(b[0:n]), nil
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Many functions in package syscall return a count of -1 instead of 0.
 | 
			
		||||
// Using fixCount(call()) instead of call() corrects the count.
 | 
			
		||||
func fixCount(n int, err error) (int, error) {
 | 
			
		||||
	if n < 0 {
 | 
			
		||||
		n = 0
 | 
			
		||||
	}
 | 
			
		||||
	return n, err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// fixLongPath returns the extended-length (\\?\-prefixed) form of
 | 
			
		||||
// path when needed, in order to avoid the default 260 character file
 | 
			
		||||
// path limit imposed by Windows. If path is not easily converted to
 | 
			
		||||
// the extended-length form (for example, if path is a relative path
 | 
			
		||||
// or contains .. elements), or is short enough, fixLongPath returns
 | 
			
		||||
// path unmodified.
 | 
			
		||||
//
 | 
			
		||||
// See https://msdn.microsoft.com/en-us/library/windows/desktop/aa365247(v=vs.85).aspx#maxpath
 | 
			
		||||
func fixLongPath(path string) string {
 | 
			
		||||
	// Do nothing (and don't allocate) if the path is "short".
 | 
			
		||||
	// Empirically (at least on the Windows Server 2013 builder),
 | 
			
		||||
	// the kernel is arbitrarily okay with < 248 bytes. That
 | 
			
		||||
	// matches what the docs above say:
 | 
			
		||||
	// "When using an API to create a directory, the specified
 | 
			
		||||
	// path cannot be so long that you cannot append an 8.3 file
 | 
			
		||||
	// name (that is, the directory name cannot exceed MAX_PATH
 | 
			
		||||
	// minus 12)." Since MAX_PATH is 260, 260 - 12 = 248.
 | 
			
		||||
	//
 | 
			
		||||
	// The MSDN docs appear to say that a normal path that is 248 bytes long
 | 
			
		||||
	// will work; empirically the path must be less then 248 bytes long.
 | 
			
		||||
	if len(path) < 248 {
 | 
			
		||||
		// Don't fix. (This is how Go 1.7 and earlier worked,
 | 
			
		||||
		// not automatically generating the \\?\ form)
 | 
			
		||||
		return path
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// The extended form begins with \\?\, as in
 | 
			
		||||
	// \\?\c:\windows\foo.txt or \\?\UNC\server\share\foo.txt.
 | 
			
		||||
	// The extended form disables evaluation of . and .. path
 | 
			
		||||
	// elements and disables the interpretation of / as equivalent
 | 
			
		||||
	// to \. The conversion here rewrites / to \ and elides
 | 
			
		||||
	// . elements as well as trailing or duplicate separators. For
 | 
			
		||||
	// simplicity it avoids the conversion entirely for relative
 | 
			
		||||
	// paths or paths containing .. elements. For now,
 | 
			
		||||
	// \\server\share paths are not converted to
 | 
			
		||||
	// \\?\UNC\server\share paths because the rules for doing so
 | 
			
		||||
	// are less well-specified.
 | 
			
		||||
	if len(path) >= 2 && path[:2] == `\\` {
 | 
			
		||||
		// Don't canonicalize UNC paths.
 | 
			
		||||
		return path
 | 
			
		||||
	}
 | 
			
		||||
	if !filepath.IsAbs(path) {
 | 
			
		||||
		// Relative path
 | 
			
		||||
		return path
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	const prefix = `\\?`
 | 
			
		||||
 | 
			
		||||
	pathbuf := make([]byte, len(prefix)+len(path)+len(`\`))
 | 
			
		||||
	copy(pathbuf, prefix)
 | 
			
		||||
	n := len(path)
 | 
			
		||||
	r, w := 0, len(prefix)
 | 
			
		||||
	for r < n {
 | 
			
		||||
		switch {
 | 
			
		||||
		case os.IsPathSeparator(path[r]):
 | 
			
		||||
			// empty block
 | 
			
		||||
			r++
 | 
			
		||||
		case path[r] == '.' && (r+1 == n || os.IsPathSeparator(path[r+1])):
 | 
			
		||||
			// /./
 | 
			
		||||
			r++
 | 
			
		||||
		case r+1 < n && path[r] == '.' && path[r+1] == '.' && (r+2 == n || os.IsPathSeparator(path[r+2])):
 | 
			
		||||
			// /../ is currently unhandled
 | 
			
		||||
			return path
 | 
			
		||||
		default:
 | 
			
		||||
			pathbuf[w] = '\\'
 | 
			
		||||
			w++
 | 
			
		||||
			for ; r < n && !os.IsPathSeparator(path[r]); r++ {
 | 
			
		||||
				pathbuf[w] = path[r]
 | 
			
		||||
				w++
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	// A drive's root directory needs a trailing \
 | 
			
		||||
	if w == len(`\\?\c:`) {
 | 
			
		||||
		pathbuf[w] = '\\'
 | 
			
		||||
		w++
 | 
			
		||||
	}
 | 
			
		||||
	return string(pathbuf[:w])
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										52
									
								
								vendor/github.com/containerd/continuity/sysx/generate.sh
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										52
									
								
								vendor/github.com/containerd/continuity/sysx/generate.sh
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,52 @@
 | 
			
		||||
#!/bin/bash
 | 
			
		||||
 | 
			
		||||
#   Copyright The containerd Authors.
 | 
			
		||||
 | 
			
		||||
#   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.
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
set -e
 | 
			
		||||
 | 
			
		||||
mksyscall="$(go env GOROOT)/src/syscall/mksyscall.pl"
 | 
			
		||||
 | 
			
		||||
fix() {
 | 
			
		||||
	sed 's,^package syscall$,package sysx,' \
 | 
			
		||||
		| sed 's,^import "unsafe"$,import (\n\t"syscall"\n\t"unsafe"\n),' \
 | 
			
		||||
		| gofmt -r='BytePtrFromString -> syscall.BytePtrFromString' \
 | 
			
		||||
		| gofmt -r='Syscall6 -> syscall.Syscall6' \
 | 
			
		||||
		| gofmt -r='Syscall -> syscall.Syscall' \
 | 
			
		||||
		| gofmt -r='SYS_GETXATTR -> syscall.SYS_GETXATTR' \
 | 
			
		||||
		| gofmt -r='SYS_LISTXATTR -> syscall.SYS_LISTXATTR' \
 | 
			
		||||
		| gofmt -r='SYS_SETXATTR -> syscall.SYS_SETXATTR' \
 | 
			
		||||
		| gofmt -r='SYS_REMOVEXATTR -> syscall.SYS_REMOVEXATTR' \
 | 
			
		||||
		| gofmt -r='SYS_LGETXATTR -> syscall.SYS_LGETXATTR' \
 | 
			
		||||
		| gofmt -r='SYS_LLISTXATTR -> syscall.SYS_LLISTXATTR' \
 | 
			
		||||
		| gofmt -r='SYS_LSETXATTR -> syscall.SYS_LSETXATTR' \
 | 
			
		||||
		| gofmt -r='SYS_LREMOVEXATTR -> syscall.SYS_LREMOVEXATTR'
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
if [ "$GOARCH" == "" ] || [ "$GOOS" == "" ]; then
 | 
			
		||||
	echo "Must specify \$GOARCH and \$GOOS"
 | 
			
		||||
	exit 1
 | 
			
		||||
fi
 | 
			
		||||
 | 
			
		||||
mkargs=""
 | 
			
		||||
 | 
			
		||||
if [ "$GOARCH" == "386" ] || [ "$GOARCH" == "arm" ]; then
 | 
			
		||||
	mkargs="-l32"
 | 
			
		||||
fi
 | 
			
		||||
 | 
			
		||||
for f in "$@"; do
 | 
			
		||||
	$mksyscall $mkargs "${f}_${GOOS}.go" | fix > "${f}_${GOOS}_${GOARCH}.go"
 | 
			
		||||
done
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										23
									
								
								vendor/github.com/containerd/continuity/sysx/nodata_linux.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										23
									
								
								vendor/github.com/containerd/continuity/sysx/nodata_linux.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,23 @@
 | 
			
		||||
/*
 | 
			
		||||
   Copyright The containerd Authors.
 | 
			
		||||
 | 
			
		||||
   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.
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
package sysx
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"syscall"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
const ENODATA = syscall.ENODATA
 | 
			
		||||
							
								
								
									
										24
									
								
								vendor/github.com/containerd/continuity/sysx/nodata_solaris.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										24
									
								
								vendor/github.com/containerd/continuity/sysx/nodata_solaris.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,24 @@
 | 
			
		||||
/*
 | 
			
		||||
   Copyright The containerd Authors.
 | 
			
		||||
 | 
			
		||||
   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.
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
package sysx
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"syscall"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// This should actually be a set that contains ENOENT and EPERM
 | 
			
		||||
const ENODATA = syscall.ENOENT
 | 
			
		||||
							
								
								
									
										25
									
								
								vendor/github.com/containerd/continuity/sysx/nodata_unix.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										25
									
								
								vendor/github.com/containerd/continuity/sysx/nodata_unix.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,25 @@
 | 
			
		||||
// +build darwin freebsd
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
   Copyright The containerd Authors.
 | 
			
		||||
 | 
			
		||||
   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.
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
package sysx
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"syscall"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
const ENODATA = syscall.ENOATTR
 | 
			
		||||
							
								
								
									
										125
									
								
								vendor/github.com/containerd/continuity/sysx/xattr.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										125
									
								
								vendor/github.com/containerd/continuity/sysx/xattr.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,125 @@
 | 
			
		||||
// +build linux darwin
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
   Copyright The containerd Authors.
 | 
			
		||||
 | 
			
		||||
   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.
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
package sysx
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"bytes"
 | 
			
		||||
	"syscall"
 | 
			
		||||
 | 
			
		||||
	"golang.org/x/sys/unix"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// Listxattr calls syscall listxattr and reads all content
 | 
			
		||||
// and returns a string array
 | 
			
		||||
func Listxattr(path string) ([]string, error) {
 | 
			
		||||
	return listxattrAll(path, unix.Listxattr)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Removexattr calls syscall removexattr
 | 
			
		||||
func Removexattr(path string, attr string) (err error) {
 | 
			
		||||
	return unix.Removexattr(path, attr)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Setxattr calls syscall setxattr
 | 
			
		||||
func Setxattr(path string, attr string, data []byte, flags int) (err error) {
 | 
			
		||||
	return unix.Setxattr(path, attr, data, flags)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Getxattr calls syscall getxattr
 | 
			
		||||
func Getxattr(path, attr string) ([]byte, error) {
 | 
			
		||||
	return getxattrAll(path, attr, unix.Getxattr)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// LListxattr lists xattrs, not following symlinks
 | 
			
		||||
func LListxattr(path string) ([]string, error) {
 | 
			
		||||
	return listxattrAll(path, unix.Llistxattr)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// LRemovexattr removes an xattr, not following symlinks
 | 
			
		||||
func LRemovexattr(path string, attr string) (err error) {
 | 
			
		||||
	return unix.Lremovexattr(path, attr)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// LSetxattr sets an xattr, not following symlinks
 | 
			
		||||
func LSetxattr(path string, attr string, data []byte, flags int) (err error) {
 | 
			
		||||
	return unix.Lsetxattr(path, attr, data, flags)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// LGetxattr gets an xattr, not following symlinks
 | 
			
		||||
func LGetxattr(path, attr string) ([]byte, error) {
 | 
			
		||||
	return getxattrAll(path, attr, unix.Lgetxattr)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const defaultXattrBufferSize = 5
 | 
			
		||||
 | 
			
		||||
type listxattrFunc func(path string, dest []byte) (int, error)
 | 
			
		||||
 | 
			
		||||
func listxattrAll(path string, listFunc listxattrFunc) ([]string, error) {
 | 
			
		||||
	var p []byte // nil on first execution
 | 
			
		||||
 | 
			
		||||
	for {
 | 
			
		||||
		n, err := listFunc(path, p) // first call gets buffer size.
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return nil, err
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if n > len(p) {
 | 
			
		||||
			p = make([]byte, n)
 | 
			
		||||
			continue
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		p = p[:n]
 | 
			
		||||
 | 
			
		||||
		ps := bytes.Split(bytes.TrimSuffix(p, []byte{0}), []byte{0})
 | 
			
		||||
		var entries []string
 | 
			
		||||
		for _, p := range ps {
 | 
			
		||||
			s := string(p)
 | 
			
		||||
			if s != "" {
 | 
			
		||||
				entries = append(entries, s)
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		return entries, nil
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type getxattrFunc func(string, string, []byte) (int, error)
 | 
			
		||||
 | 
			
		||||
func getxattrAll(path, attr string, getFunc getxattrFunc) ([]byte, error) {
 | 
			
		||||
	p := make([]byte, defaultXattrBufferSize)
 | 
			
		||||
	for {
 | 
			
		||||
		n, err := getFunc(path, attr, p)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			if errno, ok := err.(syscall.Errno); ok && errno == syscall.ERANGE {
 | 
			
		||||
				p = make([]byte, len(p)*2) // this can't be ideal.
 | 
			
		||||
				continue                   // try again!
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			return nil, err
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		// realloc to correct size and repeat
 | 
			
		||||
		if n > len(p) {
 | 
			
		||||
			p = make([]byte, n)
 | 
			
		||||
			continue
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		return p[:n], nil
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										67
									
								
								vendor/github.com/containerd/continuity/sysx/xattr_unsupported.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										67
									
								
								vendor/github.com/containerd/continuity/sysx/xattr_unsupported.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,67 @@
 | 
			
		||||
// +build !linux,!darwin
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
   Copyright The containerd Authors.
 | 
			
		||||
 | 
			
		||||
   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.
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
package sysx
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"errors"
 | 
			
		||||
	"runtime"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
var unsupported = errors.New("extended attributes unsupported on " + runtime.GOOS)
 | 
			
		||||
 | 
			
		||||
// Listxattr calls syscall listxattr and reads all content
 | 
			
		||||
// and returns a string array
 | 
			
		||||
func Listxattr(path string) ([]string, error) {
 | 
			
		||||
	return []string{}, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Removexattr calls syscall removexattr
 | 
			
		||||
func Removexattr(path string, attr string) (err error) {
 | 
			
		||||
	return unsupported
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Setxattr calls syscall setxattr
 | 
			
		||||
func Setxattr(path string, attr string, data []byte, flags int) (err error) {
 | 
			
		||||
	return unsupported
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Getxattr calls syscall getxattr
 | 
			
		||||
func Getxattr(path, attr string) ([]byte, error) {
 | 
			
		||||
	return []byte{}, unsupported
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// LListxattr lists xattrs, not following symlinks
 | 
			
		||||
func LListxattr(path string) ([]string, error) {
 | 
			
		||||
	return []string{}, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// LRemovexattr removes an xattr, not following symlinks
 | 
			
		||||
func LRemovexattr(path string, attr string) (err error) {
 | 
			
		||||
	return unsupported
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// LSetxattr sets an xattr, not following symlinks
 | 
			
		||||
func LSetxattr(path string, attr string, data []byte, flags int) (err error) {
 | 
			
		||||
	return unsupported
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// LGetxattr gets an xattr, not following symlinks
 | 
			
		||||
func LGetxattr(path, attr string) ([]byte, error) {
 | 
			
		||||
	return []byte{}, nil
 | 
			
		||||
}
 | 
			
		||||
		Reference in New Issue
	
	Block a user