mirror of https://github.com/k3d-io/k3d
parent
b4c910b729
commit
6499704223
@ -1,40 +0,0 @@ |
|||||||
Aaron Lehmann <aaron.lehmann@docker.com> |
|
||||||
Akash Gupta <akagup@microsoft.com> |
|
||||||
Akihiro Suda <akihiro.suda.cz@hco.ntt.co.jp> |
|
||||||
Akihiro Suda <suda.akihiro@lab.ntt.co.jp> |
|
||||||
Akihiro Suda <suda.kyoto@gmail.com> |
|
||||||
Andrew Pennebaker <apennebaker@datapipe.com> |
|
||||||
Brandon Philips <brandon.philips@coreos.com> |
|
||||||
Brian Goff <cpuguy83@gmail.com> |
|
||||||
Christopher Jones <tophj@linux.vnet.ibm.com> |
|
||||||
Daniel, Dao Quang Minh <dqminh89@gmail.com> |
|
||||||
Darren Stahl <darst@microsoft.com> |
|
||||||
Derek McGowan <derek@mcg.dev> |
|
||||||
Derek McGowan <derek@mcgstyle.net> |
|
||||||
Edward Pilatowicz <edward.pilatowicz@oracle.com> |
|
||||||
Ian Campbell <ijc@docker.com> |
|
||||||
Ivan Markin <sw@nogoegst.net> |
|
||||||
Justin Cormack <justin.cormack@docker.com> |
|
||||||
Justin Cummins <sul3n3t@gmail.com> |
|
||||||
Kasper Fabæch Brandt <poizan@poizan.dk> |
|
||||||
Kir Kolyshkin <kolyshkin@gmail.com> |
|
||||||
Michael Crosby <crosbymichael@gmail.com> |
|
||||||
Michael Crosby <michael@thepasture.io> |
|
||||||
Michael Wan <zirenwan@gmail.com> |
|
||||||
Mike Brown <brownwm@us.ibm.com> |
|
||||||
Niels de Vos <ndevos@redhat.com> |
|
||||||
Phil Estes <estesp@gmail.com> |
|
||||||
Phil Estes <estesp@linux.vnet.ibm.com> |
|
||||||
Samuel Karp <me@samuelkarp.com> |
|
||||||
Sam Whited <sam@samwhited.com> |
|
||||||
Sebastiaan van Stijn <github@gone.nl> |
|
||||||
Shengjing Zhu <zhsj@debian.org> |
|
||||||
Stephen J Day <stephen.day@docker.com> |
|
||||||
Tibor Vass <tibor@docker.com> |
|
||||||
Tobias Klauser <tklauser@distanz.ch> |
|
||||||
Tom Faulhaber <tffaulha@amazon.com> |
|
||||||
Tonis Tiigi <tonistiigi@gmail.com> |
|
||||||
Trevor Porter <trkporter@ucdavis.edu> |
|
||||||
Wei Fu <fuweid89@gmail.com> |
|
||||||
Wilbert van de Ridder <wilbert.ridder@gmail.com> |
|
||||||
Xiaodong Ye <xiaodongy@vmware.com> |
|
@ -1,191 +0,0 @@ |
|||||||
|
|
||||||
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. |
|
@ -1,176 +0,0 @@ |
|||||||
/* |
|
||||||
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 %s is not directory", src) |
|
||||||
} |
|
||||||
|
|
||||||
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) |
|
||||||
} |
|
||||||
|
|
||||||
if err := copyXAttrs(dst, src, o.xeh); err != nil { |
|
||||||
return errors.Wrap(err, "failed to copy xattrs") |
|
||||||
} |
|
||||||
|
|
||||||
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) |
|
||||||
} |
|
@ -1,40 +0,0 @@ |
|||||||
// +build darwin openbsd solaris
|
|
||||||
|
|
||||||
/* |
|
||||||
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" |
|
||||||
|
|
||||||
"github.com/pkg/errors" |
|
||||||
"golang.org/x/sys/unix" |
|
||||||
) |
|
||||||
|
|
||||||
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)) |
|
||||||
} |
|
||||||
|
|
||||||
func utimesNano(name string, atime, mtime syscall.Timespec) error { |
|
||||||
timespec := []syscall.Timespec{atime, mtime} |
|
||||||
return syscall.UtimesNano(name, timespec) |
|
||||||
} |
|
@ -1,42 +0,0 @@ |
|||||||
// +build 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 ( |
|
||||||
"os" |
|
||||||
"syscall" |
|
||||||
|
|
||||||
"github.com/pkg/errors" |
|
||||||
"golang.org/x/sys/unix" |
|
||||||
) |
|
||||||
|
|
||||||
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()), st.Rdev) |
|
||||||
} |
|
||||||
|
|
||||||
func utimesNano(name string, atime, mtime syscall.Timespec) error { |
|
||||||
at := unix.NsecToTimespec(atime.Nano()) |
|
||||||
mt := unix.NsecToTimespec(mtime.Nano()) |
|
||||||
utimes := [2]unix.Timespec{at, mt} |
|
||||||
return unix.UtimesNanoAt(unix.AT_FDCWD, name, utimes[0:], unix.AT_SYMLINK_NOFOLLOW) |
|
||||||
} |
|
@ -1,147 +0,0 @@ |
|||||||
/* |
|
||||||
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.NsecToTimespec(syscall.TimespecToNsec(StatAtime(st))), |
|
||||||
unix.NsecToTimespec(syscall.TimespecToNsec(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)) |
|
||||||
} |
|
@ -1,102 +0,0 @@ |
|||||||
// +build darwin freebsd openbsd solaris
|
|
||||||
|
|
||||||
/* |
|
||||||
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" |
|
||||||
) |
|
||||||
|
|
||||||
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) |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
if err := utimesNano(name, StatAtime(st), StatMtime(st)); 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 |
|
||||||
} |
|
@ -1,49 +0,0 @@ |
|||||||
/* |
|
||||||
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") |
|
||||||
} |
|
@ -1,326 +0,0 @@ |
|||||||
/* |
|
||||||
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() |
|
||||||
} |
|
@ -1,74 +0,0 @@ |
|||||||
// +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 |
|
||||||
} |
|
@ -1,48 +0,0 @@ |
|||||||
/* |
|
||||||
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 |
|
||||||
} |
|
@ -1,103 +0,0 @@ |
|||||||
// +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 |
|
||||||
} |
|
@ -1,38 +0,0 @@ |
|||||||
/* |
|
||||||
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) |
|
||||||
} |
|
@ -1,120 +0,0 @@ |
|||||||
// +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" |
|
||||||
) |
|
||||||
|
|
||||||
// blocksUnitSize is the unit used by `st_blocks` in `stat` in bytes.
|
|
||||||
// See https://man7.org/linux/man-pages/man2/stat.2.html
|
|
||||||
// st_blocks
|
|
||||||
// This field indicates the number of blocks allocated to the
|
|
||||||
// file, in 512-byte units. (This may be smaller than
|
|
||||||
// st_size/512 when the file has holes.)
|
|
||||||
const blocksUnitSize = 512 |
|
||||||
|
|
||||||
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/freebsd
|
|
||||||
dev: uint64(stat.Dev), // nolint: unconvert
|
|
||||||
// Ino is uint32 on bsd, uint64 on darwin/linux/solaris/freebsd
|
|
||||||
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: |
|
||||||
} |
|
||||||
|
|
||||||
stat := fi.Sys().(*syscall.Stat_t) |
|
||||||
inoKey := newInode(stat) |
|
||||||
if _, ok := inodes[inoKey]; !ok { |
|
||||||
inodes[inoKey] = struct{}{} |
|
||||||
size += stat.Blocks * blocksUnitSize |
|
||||||
} |
|
||||||
|
|
||||||
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 { |
|
||||||
stat := fi.Sys().(*syscall.Stat_t) |
|
||||||
inoKey := newInode(stat) |
|
||||||
if _, ok := inodes[inoKey]; !ok { |
|
||||||
inodes[inoKey] = struct{}{} |
|
||||||
size += stat.Blocks * blocksUnitSize |
|
||||||
} |
|
||||||
|
|
||||||
return nil |
|
||||||
|
|
||||||
} |
|
||||||
return nil |
|
||||||
}); err != nil { |
|
||||||
return Usage{}, err |
|
||||||
} |
|
||||||
|
|
||||||
return Usage{ |
|
||||||
Inodes: int64(len(inodes)), |
|
||||||
Size: size, |
|
||||||
}, nil |
|
||||||
} |
|
@ -1,82 +0,0 @@ |
|||||||
// +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 |
|
||||||
} |
|
@ -1,43 +0,0 @@ |
|||||||
/* |
|
||||||
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 |
|
||||||
} |
|
@ -1,34 +0,0 @@ |
|||||||
// +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
|
|
||||||
} |
|
@ -1,23 +0,0 @@ |
|||||||
/* |
|
||||||
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 |
|
||||||
} |
|
@ -1,311 +0,0 @@ |
|||||||
/* |
|
||||||
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" |
|
||||||
|
|
||||||
"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 |
|
||||||
} |
|
||||||
|
|
||||||
switch i := directoryCompare(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 directoryCompare(a, b string) int { |
|
||||||
l := len(a) |
|
||||||
if len(b) < l { |
|
||||||
l = len(b) |
|
||||||
} |
|
||||||
for i := 0; i < l; i++ { |
|
||||||
c1, c2 := a[i], b[i] |
|
||||||
if c1 == filepath.Separator { |
|
||||||
c1 = byte(0) |
|
||||||
} |
|
||||||
if c2 == filepath.Separator { |
|
||||||
c2 = byte(0) |
|
||||||
} |
|
||||||
if c1 < c2 { |
|
||||||
return -1 |
|
||||||
} |
|
||||||
if c1 > c2 { |
|
||||||
return +1 |
|
||||||
} |
|
||||||
} |
|
||||||
if len(a) < len(b) { |
|
||||||
return -1 |
|
||||||
} |
|
||||||
if len(a) > len(b) { |
|
||||||
return +1 |
|
||||||
} |
|
||||||
return 0 |
|
||||||
} |
|
||||||
|
|
||||||
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 { |
|
||||||
if (f1.f.Mode() & os.ModeSymlink) == os.ModeSymlink { |
|
||||||
return compareSymlinkTarget(f1.fullPath, f2.fullPath) |
|
||||||
} |
|
||||||
if f1.f.Size() == 0 { // if file sizes are zero length, the files are the same by definition
|
|
||||||
return true, nil |
|
||||||
} |
|
||||||
return compareFileContent(f1.fullPath, f2.fullPath) |
|
||||||
} 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 |
|
||||||
} |
|
||||||
} |
|
@ -1,44 +0,0 @@ |
|||||||
// +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
|
|
||||||
} |
|
@ -1,45 +0,0 @@ |
|||||||
// +build linux openbsd
|
|
||||||
|
|
||||||
/* |
|
||||||
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
|
|
||||||
} |
|
@ -1,29 +0,0 @@ |
|||||||
/* |
|
||||||
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)) |
|
||||||
} |
|
@ -1,3 +0,0 @@ |
|||||||
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). |
|
@ -1,52 +0,0 @@ |
|||||||
#!/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 |
|
||||||
|
|
@ -1,23 +0,0 @@ |
|||||||
/* |
|
||||||
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 |
|
@ -1,24 +0,0 @@ |
|||||||
/* |
|
||||||
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 |
|
@ -1,25 +0,0 @@ |
|||||||
// +build darwin freebsd openbsd
|
|
||||||
|
|
||||||
/* |
|
||||||
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 |
|
@ -1,117 +0,0 @@ |
|||||||
// +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" |
|
||||||
|
|
||||||
"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 = 128 |
|
||||||
|
|
||||||
type listxattrFunc func(path string, dest []byte) (int, error) |
|
||||||
|
|
||||||
func listxattrAll(path string, listFunc listxattrFunc) ([]string, error) { |
|
||||||
buf := make([]byte, defaultXattrBufferSize) |
|
||||||
n, err := listFunc(path, buf) |
|
||||||
for err == unix.ERANGE { |
|
||||||
// Buffer too small, use zero-sized buffer to get the actual size
|
|
||||||
n, err = listFunc(path, []byte{}) |
|
||||||
if err != nil { |
|
||||||
return nil, err |
|
||||||
} |
|
||||||
buf = make([]byte, n) |
|
||||||
n, err = listFunc(path, buf) |
|
||||||
} |
|
||||||
if err != nil { |
|
||||||
return nil, err |
|
||||||
} |
|
||||||
|
|
||||||
ps := bytes.Split(bytes.TrimSuffix(buf[:n], []byte{0}), []byte{0}) |
|
||||||
var entries []string |
|
||||||
for _, p := range ps { |
|
||||||
if len(p) > 0 { |
|
||||||
entries = append(entries, string(p)) |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
return entries, nil |
|
||||||
} |
|
||||||
|
|
||||||
type getxattrFunc func(string, string, []byte) (int, error) |
|
||||||
|
|
||||||
func getxattrAll(path, attr string, getFunc getxattrFunc) ([]byte, error) { |
|
||||||
buf := make([]byte, defaultXattrBufferSize) |
|
||||||
n, err := getFunc(path, attr, buf) |
|
||||||
for err == unix.ERANGE { |
|
||||||
// Buffer too small, use zero-sized buffer to get the actual size
|
|
||||||
n, err = getFunc(path, attr, []byte{}) |
|
||||||
if err != nil { |
|
||||||
return nil, err |
|
||||||
} |
|
||||||
buf = make([]byte, n) |
|
||||||
n, err = getFunc(path, attr, buf) |
|
||||||
} |
|
||||||
if err != nil { |
|
||||||
return nil, err |
|
||||||
} |
|
||||||
return buf[:n], nil |
|
||||||
} |
|
@ -1,67 +0,0 @@ |
|||||||
// +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 errUnsupported = 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 errUnsupported |
|
||||||
} |
|
||||||
|
|
||||||
// Setxattr calls syscall setxattr
|
|
||||||
func Setxattr(path string, attr string, data []byte, flags int) (err error) { |
|
||||||
return errUnsupported |
|
||||||
} |
|
||||||
|
|
||||||
// Getxattr calls syscall getxattr
|
|
||||||
func Getxattr(path, attr string) ([]byte, error) { |
|
||||||
return []byte{}, errUnsupported |
|
||||||
} |
|
||||||
|
|
||||||
// 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 errUnsupported |
|
||||||
} |
|
||||||
|
|
||||||
// LSetxattr sets an xattr, not following symlinks
|
|
||||||
func LSetxattr(path string, attr string, data []byte, flags int) (err error) { |
|
||||||
return errUnsupported |
|
||||||
} |
|
||||||
|
|
||||||
// LGetxattr gets an xattr, not following symlinks
|
|
||||||
func LGetxattr(path, attr string) ([]byte, error) { |
|
||||||
return []byte{}, nil |
|
||||||
} |
|
@ -0,0 +1,51 @@ |
|||||||
|
/* |
||||||
|
Copyright 2020 The logr 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 logr |
||||||
|
|
||||||
|
// Discard returns a valid Logger that discards all messages logged to it.
|
||||||
|
// It can be used whenever the caller is not interested in the logs.
|
||||||
|
func Discard() Logger { |
||||||
|
return DiscardLogger{} |
||||||
|
} |
||||||
|
|
||||||
|
// DiscardLogger is a Logger that discards all messages.
|
||||||
|
type DiscardLogger struct{} |
||||||
|
|
||||||
|
func (l DiscardLogger) Enabled() bool { |
||||||
|
return false |
||||||
|
} |
||||||
|
|
||||||
|
func (l DiscardLogger) Info(msg string, keysAndValues ...interface{}) { |
||||||
|
} |
||||||
|
|
||||||
|
func (l DiscardLogger) Error(err error, msg string, keysAndValues ...interface{}) { |
||||||
|
} |
||||||
|
|
||||||
|
func (l DiscardLogger) V(level int) Logger { |
||||||
|
return l |
||||||
|
} |
||||||
|
|
||||||
|
func (l DiscardLogger) WithValues(keysAndValues ...interface{}) Logger { |
||||||
|
return l |
||||||
|
} |
||||||
|
|
||||||
|
func (l DiscardLogger) WithName(name string) Logger { |
||||||
|
return l |
||||||
|
} |
||||||
|
|
||||||
|
// Verify that it actually implements the interface
|
||||||
|
var _ Logger = DiscardLogger{} |
@ -0,0 +1,8 @@ |
|||||||
|
// Copyright 2014 The Go Authors. All rights reserved. |
||||||
|
// Use of this source code is governed by a BSD-style |
||||||
|
// license that can be found in the LICENSE file. |
||||||
|
|
||||||
|
#include "textflag.h" |
||||||
|
|
||||||
|
TEXT ·use(SB),NOSPLIT,$0 |
||||||
|
RET |
@ -0,0 +1,30 @@ |
|||||||
|
// Copyright 2009 The Go Authors. All rights reserved. |
||||||
|
// Use of this source code is governed by a BSD-style |
||||||
|
// license that can be found in the LICENSE file. |
||||||
|
|
||||||
|
#include "textflag.h" |
||||||
|
|
||||||
|
// |
||||||
|
// System call support for 386, Plan 9 |
||||||
|
// |
||||||
|
|
||||||
|
// Just jump to package syscall's implementation for all these functions. |
||||||
|
// The runtime may know about them. |
||||||
|
|
||||||
|
TEXT ·Syscall(SB),NOSPLIT,$0-32 |
||||||
|
JMP syscall·Syscall(SB) |
||||||
|
|
||||||
|
TEXT ·Syscall6(SB),NOSPLIT,$0-44 |
||||||
|
JMP syscall·Syscall6(SB) |
||||||
|
|
||||||
|
TEXT ·RawSyscall(SB),NOSPLIT,$0-28 |
||||||
|
JMP syscall·RawSyscall(SB) |
||||||
|
|
||||||
|
TEXT ·RawSyscall6(SB),NOSPLIT,$0-40 |
||||||
|
JMP syscall·RawSyscall6(SB) |
||||||
|
|
||||||
|
TEXT ·seek(SB),NOSPLIT,$0-36 |
||||||
|
JMP syscall·seek(SB) |
||||||
|
|
||||||
|
TEXT ·exit(SB),NOSPLIT,$4-4 |
||||||
|
JMP syscall·exit(SB) |
@ -0,0 +1,30 @@ |
|||||||
|
// Copyright 2009 The Go Authors. All rights reserved. |
||||||
|
// Use of this source code is governed by a BSD-style |
||||||
|
// license that can be found in the LICENSE file. |
||||||
|
|
||||||
|
#include "textflag.h" |
||||||
|
|
||||||
|
// |
||||||
|
// System call support for amd64, Plan 9 |
||||||
|
// |
||||||
|
|
||||||
|
// Just jump to package syscall's implementation for all these functions. |
||||||
|
// The runtime may know about them. |
||||||
|
|
||||||
|
TEXT ·Syscall(SB),NOSPLIT,$0-64 |
||||||
|
JMP syscall·Syscall(SB) |
||||||
|
|
||||||
|
TEXT ·Syscall6(SB),NOSPLIT,$0-88 |
||||||
|
JMP syscall·Syscall6(SB) |
||||||
|
|
||||||
|
TEXT ·RawSyscall(SB),NOSPLIT,$0-56 |
||||||
|
JMP syscall·RawSyscall(SB) |
||||||
|
|
||||||
|
TEXT ·RawSyscall6(SB),NOSPLIT,$0-80 |
||||||
|
JMP syscall·RawSyscall6(SB) |
||||||
|
|
||||||
|
TEXT ·seek(SB),NOSPLIT,$0-56 |
||||||
|
JMP syscall·seek(SB) |
||||||
|
|
||||||
|
TEXT ·exit(SB),NOSPLIT,$8-8 |
||||||
|
JMP syscall·exit(SB) |
@ -0,0 +1,25 @@ |
|||||||
|
// Copyright 2009 The Go Authors. All rights reserved. |
||||||
|
// Use of this source code is governed by a BSD-style |
||||||
|
// license that can be found in the LICENSE file. |
||||||
|
|
||||||
|
#include "textflag.h" |
||||||
|
|
||||||
|
// System call support for plan9 on arm |
||||||
|
|
||||||
|
// Just jump to package syscall's implementation for all these functions. |
||||||
|
// The runtime may know about them. |
||||||
|
|
||||||
|
TEXT ·Syscall(SB),NOSPLIT,$0-32 |
||||||
|
JMP syscall·Syscall(SB) |
||||||
|
|
||||||
|
TEXT ·Syscall6(SB),NOSPLIT,$0-44 |
||||||
|
JMP syscall·Syscall6(SB) |
||||||
|
|
||||||
|
TEXT ·RawSyscall(SB),NOSPLIT,$0-28 |
||||||
|
JMP syscall·RawSyscall(SB) |
||||||
|
|
||||||
|
TEXT ·RawSyscall6(SB),NOSPLIT,$0-40 |
||||||
|
JMP syscall·RawSyscall6(SB) |
||||||
|
|
||||||
|
TEXT ·seek(SB),NOSPLIT,$0-36 |
||||||
|
JMP syscall·exit(SB) |
@ -0,0 +1,70 @@ |
|||||||
|
package plan9 |
||||||
|
|
||||||
|
// Plan 9 Constants
|
||||||
|
|
||||||
|
// Open modes
|
||||||
|
const ( |
||||||
|
O_RDONLY = 0 |
||||||
|
O_WRONLY = 1 |
||||||
|
O_RDWR = 2 |
||||||
|
O_TRUNC = 16 |
||||||
|
O_CLOEXEC = 32 |
||||||
|
O_EXCL = 0x1000 |
||||||
|
) |
||||||
|
|
||||||
|
// Rfork flags
|
||||||
|
const ( |
||||||
|
RFNAMEG = 1 << 0 |
||||||
|
RFENVG = 1 << 1 |
||||||
|
RFFDG = 1 << 2 |
||||||
|
RFNOTEG = 1 << 3 |
||||||
|
RFPROC = 1 << 4 |
||||||
|
RFMEM = 1 << 5 |
||||||
|
RFNOWAIT = 1 << 6 |
||||||
|
RFCNAMEG = 1 << 10 |
||||||
|
RFCENVG = 1 << 11 |
||||||
|
RFCFDG = 1 << 12 |
||||||
|
RFREND = 1 << 13 |
||||||
|
RFNOMNT = 1 << 14 |
||||||
|
) |
||||||
|
|
||||||
|
// Qid.Type bits
|
||||||
|
const ( |
||||||
|
QTDIR = 0x80 |
||||||
|
QTAPPEND = 0x40 |
||||||
|
QTEXCL = 0x20 |
||||||
|
QTMOUNT = 0x10 |
||||||
|
QTAUTH = 0x08 |
||||||
|
QTTMP = 0x04 |
||||||
|
QTFILE = 0x00 |
||||||
|
) |
||||||
|
|
||||||
|
// Dir.Mode bits
|
||||||
|
const ( |
||||||
|
DMDIR = 0x80000000 |
||||||
|
DMAPPEND = 0x40000000 |
||||||
|
DMEXCL = 0x20000000 |
||||||
|
DMMOUNT = 0x10000000 |
||||||
|
DMAUTH = 0x08000000 |
||||||
|
DMTMP = 0x04000000 |
||||||
|
DMREAD = 0x4 |
||||||
|
DMWRITE = 0x2 |
||||||
|
DMEXEC = 0x1 |
||||||
|
) |
||||||
|
|
||||||
|
const ( |
||||||
|
STATMAX = 65535 |
||||||
|
ERRMAX = 128 |
||||||
|
STATFIXLEN = 49 |
||||||
|
) |
||||||
|
|
||||||
|
// Mount and bind flags
|
||||||
|
const ( |
||||||
|
MREPL = 0x0000 |
||||||
|
MBEFORE = 0x0001 |
||||||
|
MAFTER = 0x0002 |
||||||
|
MORDER = 0x0003 |
||||||
|
MCREATE = 0x0004 |
||||||
|
MCACHE = 0x0010 |
||||||
|
MMASK = 0x0017 |
||||||
|
) |
@ -0,0 +1,212 @@ |
|||||||
|
// Copyright 2012 The Go Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
// Plan 9 directory marshalling. See intro(5).
|
||||||
|
|
||||||
|
package plan9 |
||||||
|
|
||||||
|
import "errors" |
||||||
|
|
||||||
|
var ( |
||||||
|
ErrShortStat = errors.New("stat buffer too short") |
||||||
|
ErrBadStat = errors.New("malformed stat buffer") |
||||||
|
ErrBadName = errors.New("bad character in file name") |
||||||
|
) |
||||||
|
|
||||||
|
// A Qid represents a 9P server's unique identification for a file.
|
||||||
|
type Qid struct { |
||||||
|
Path uint64 // the file server's unique identification for the file
|
||||||
|
Vers uint32 // version number for given Path
|
||||||
|
Type uint8 // the type of the file (plan9.QTDIR for example)
|
||||||
|
} |
||||||
|
|
||||||
|
// A Dir contains the metadata for a file.
|
||||||
|
type Dir struct { |
||||||
|
// system-modified data
|
||||||
|
Type uint16 // server type
|
||||||
|
Dev uint32 // server subtype
|
||||||
|
|
||||||
|
// file data
|
||||||
|
Qid Qid // unique id from server
|
||||||
|
Mode uint32 // permissions
|
||||||
|
Atime uint32 // last read time
|
||||||
|
Mtime uint32 // last write time
|
||||||
|
Length int64 // file length
|
||||||
|
Name string // last element of path
|
||||||
|
Uid string // owner name
|
||||||
|
Gid string // group name
|
||||||
|
Muid string // last modifier name
|
||||||
|
} |
||||||
|
|
||||||
|
var nullDir = Dir{ |
||||||
|
Type: ^uint16(0), |
||||||
|
Dev: ^uint32(0), |
||||||
|
Qid: Qid{ |
||||||
|
Path: ^uint64(0), |
||||||
|
Vers: ^uint32(0), |
||||||
|
Type: ^uint8(0), |
||||||
|
}, |
||||||
|
Mode: ^uint32(0), |
||||||
|
Atime: ^uint32(0), |
||||||
|
Mtime: ^uint32(0), |
||||||
|
Length: ^int64(0), |
||||||
|
} |
||||||
|
|
||||||
|
// Null assigns special "don't touch" values to members of d to
|
||||||
|
// avoid modifying them during plan9.Wstat.
|
||||||
|
func (d *Dir) Null() { *d = nullDir } |
||||||
|
|
||||||
|
// Marshal encodes a 9P stat message corresponding to d into b
|
||||||
|
//
|
||||||
|
// If there isn't enough space in b for a stat message, ErrShortStat is returned.
|
||||||
|
func (d *Dir) Marshal(b []byte) (n int, err error) { |
||||||
|
n = STATFIXLEN + len(d.Name) + len(d.Uid) + len(d.Gid) + len(d.Muid) |
||||||
|
if n > len(b) { |
||||||
|
return n, ErrShortStat |
||||||
|
} |
||||||
|
|
||||||
|
for _, c := range d.Name { |
||||||
|
if c == '/' { |
||||||
|
return n, ErrBadName |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
b = pbit16(b, uint16(n)-2) |
||||||
|
b = pbit16(b, d.Type) |
||||||
|
b = pbit32(b, d.Dev) |
||||||
|
b = pbit8(b, d.Qid.Type) |
||||||
|
b = pbit32(b, d.Qid.Vers) |
||||||
|
b = pbit64(b, d.Qid.Path) |
||||||
|
b = pbit32(b, d.Mode) |
||||||
|
b = pbit32(b, d.Atime) |
||||||
|
b = pbit32(b, d.Mtime) |
||||||
|
b = pbit64(b, uint64(d.Length)) |
||||||
|
b = pstring(b, d.Name) |
||||||
|
b = pstring(b, d.Uid) |
||||||
|
b = pstring(b, d.Gid) |
||||||
|
b = pstring(b, d.Muid) |
||||||
|
|
||||||
|
return n, nil |
||||||
|
} |
||||||
|
|
||||||
|
// UnmarshalDir decodes a single 9P stat message from b and returns the resulting Dir.
|
||||||
|
//
|
||||||
|
// If b is too small to hold a valid stat message, ErrShortStat is returned.
|
||||||
|
//
|
||||||
|
// If the stat message itself is invalid, ErrBadStat is returned.
|
||||||
|
func UnmarshalDir(b []byte) (*Dir, error) { |
||||||
|
if len(b) < STATFIXLEN { |
||||||
|
return nil, ErrShortStat |
||||||
|
} |
||||||
|
size, buf := gbit16(b) |
||||||
|
if len(b) != int(size)+2 { |
||||||
|
return nil, ErrBadStat |
||||||
|
} |
||||||
|
b = buf |
||||||
|
|
||||||
|
var d Dir |
||||||
|
d.Type, b = gbit16(b) |
||||||
|
d.Dev, b = gbit32(b) |
||||||
|
d.Qid.Type, b = gbit8(b) |
||||||
|
d.Qid.Vers, b = gbit32(b) |
||||||
|
d.Qid.Path, b = gbit64(b) |
||||||
|
d.Mode, b = gbit32(b) |
||||||
|
d.Atime, b = gbit32(b) |
||||||
|
d.Mtime, b = gbit32(b) |
||||||
|
|
||||||
|
n, b := gbit64(b) |
||||||
|
d.Length = int64(n) |
||||||
|
|
||||||
|
var ok bool |
||||||
|
if d.Name, b, ok = gstring(b); !ok { |
||||||
|
return nil, ErrBadStat |
||||||
|
} |
||||||
|
if d.Uid, b, ok = gstring(b); !ok { |
||||||
|
return nil, ErrBadStat |
||||||
|
} |
||||||
|
if d.Gid, b, ok = gstring(b); !ok { |
||||||
|
return nil, ErrBadStat |
||||||
|
} |
||||||
|
if d.Muid, b, ok = gstring(b); !ok { |
||||||
|
return nil, ErrBadStat |
||||||
|
} |
||||||
|
|
||||||
|
return &d, nil |
||||||
|
} |
||||||
|
|
||||||
|
// pbit8 copies the 8-bit number v to b and returns the remaining slice of b.
|
||||||
|
func pbit8(b []byte, v uint8) []byte { |
||||||
|
b[0] = byte(v) |
||||||
|
return b[1:] |
||||||
|
} |
||||||
|
|
||||||
|
// pbit16 copies the 16-bit number v to b in little-endian order and returns the remaining slice of b.
|
||||||
|
func pbit16(b []byte, v uint16) []byte { |
||||||
|
b[0] = byte(v) |
||||||
|
b[1] = byte(v >> 8) |
||||||
|
return b[2:] |
||||||
|
} |
||||||
|
|
||||||
|
// pbit32 copies the 32-bit number v to b in little-endian order and returns the remaining slice of b.
|
||||||
|
func pbit32(b []byte, v uint32) []byte { |
||||||
|
b[0] = byte(v) |
||||||
|
b[1] = byte(v >> 8) |
||||||
|
b[2] = byte(v >> 16) |
||||||
|
b[3] = byte(v >> 24) |
||||||
|
return b[4:] |
||||||
|
} |
||||||
|
|
||||||
|
// pbit64 copies the 64-bit number v to b in little-endian order and returns the remaining slice of b.
|
||||||
|
func pbit64(b []byte, v uint64) []byte { |
||||||
|
b[0] = byte(v) |
||||||
|
b[1] = byte(v >> 8) |
||||||
|
b[2] = byte(v >> 16) |
||||||
|
b[3] = byte(v >> 24) |
||||||
|
b[4] = byte(v >> 32) |
||||||
|
b[5] = byte(v >> 40) |
||||||
|
b[6] = byte(v >> 48) |
||||||
|
b[7] = byte(v >> 56) |
||||||
|
return b[8:] |
||||||
|
} |
||||||
|
|
||||||
|
// pstring copies the string s to b, prepending it with a 16-bit length in little-endian order, and
|
||||||
|
// returning the remaining slice of b..
|
||||||
|
func pstring(b []byte, s string) []byte { |
||||||
|
b = pbit16(b, uint16(len(s))) |
||||||
|
n := copy(b, s) |
||||||
|
return b[n:] |
||||||
|
} |
||||||
|
|
||||||
|
// gbit8 reads an 8-bit number from b and returns it with the remaining slice of b.
|
||||||
|
func gbit8(b []byte) (uint8, []byte) { |
||||||
|
return uint8(b[0]), b[1:] |
||||||
|
} |
||||||
|
|
||||||
|
// gbit16 reads a 16-bit number in little-endian order from b and returns it with the remaining slice of b.
|
||||||
|
func gbit16(b []byte) (uint16, []byte) { |
||||||
|
return uint16(b[0]) | uint16(b[1])<<8, b[2:] |
||||||
|
} |
||||||
|
|
||||||
|
// gbit32 reads a 32-bit number in little-endian order from b and returns it with the remaining slice of b.
|
||||||
|
func gbit32(b []byte) (uint32, []byte) { |
||||||
|
return uint32(b[0]) | uint32(b[1])<<8 | uint32(b[2])<<16 | uint32(b[3])<<24, b[4:] |
||||||
|
} |
||||||
|
|
||||||
|
// gbit64 reads a 64-bit number in little-endian order from b and returns it with the remaining slice of b.
|
||||||
|
func gbit64(b []byte) (uint64, []byte) { |
||||||
|
lo := uint32(b[0]) | uint32(b[1])<<8 | uint32(b[2])<<16 | uint32(b[3])<<24 |
||||||
|
hi := uint32(b[4]) | uint32(b[5])<<8 | uint32(b[6])<<16 | uint32(b[7])<<24 |
||||||
|
return uint64(lo) | uint64(hi)<<32, b[8:] |
||||||
|
} |
||||||
|
|
||||||
|
// gstring reads a string from b, prefixed with a 16-bit length in little-endian order.
|
||||||
|
// It returns the string with the remaining slice of b and a boolean. If the length is
|
||||||
|
// greater than the number of bytes in b, the boolean will be false.
|
||||||
|
func gstring(b []byte) (string, []byte, bool) { |
||||||
|
n, b := gbit16(b) |
||||||
|
if int(n) > len(b) { |
||||||
|
return "", b, false |
||||||
|
} |
||||||
|
return string(b[:n]), b[n:], true |
||||||
|
} |
@ -0,0 +1,31 @@ |
|||||||
|
// Copyright 2011 The Go Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
// Plan 9 environment variables.
|
||||||
|
|
||||||
|
package plan9 |
||||||
|
|
||||||
|
import ( |
||||||
|
"syscall" |
||||||
|
) |
||||||
|
|
||||||
|
func Getenv(key string) (value string, found bool) { |
||||||
|
return syscall.Getenv(key) |
||||||
|
} |
||||||
|
|
||||||
|
func Setenv(key, value string) error { |
||||||
|
return syscall.Setenv(key, value) |
||||||
|
} |
||||||
|
|
||||||
|
func Clearenv() { |
||||||
|
syscall.Clearenv() |
||||||
|
} |
||||||
|
|
||||||
|
func Environ() []string { |
||||||
|
return syscall.Environ() |
||||||
|
} |
||||||
|
|
||||||
|
func Unsetenv(key string) error { |
||||||
|
return syscall.Unsetenv(key) |
||||||
|
} |
@ -0,0 +1,50 @@ |
|||||||
|
// Copyright 2011 The Go Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
package plan9 |
||||||
|
|
||||||
|
import "syscall" |
||||||
|
|
||||||
|
// Constants
|
||||||
|
const ( |
||||||
|
// Invented values to support what package os expects.
|
||||||
|
O_CREAT = 0x02000 |
||||||
|
O_APPEND = 0x00400 |
||||||
|
O_NOCTTY = 0x00000 |
||||||
|
O_NONBLOCK = 0x00000 |
||||||
|
O_SYNC = 0x00000 |
||||||
|
O_ASYNC = 0x00000 |
||||||
|
|
||||||
|
S_IFMT = 0x1f000 |
||||||
|
S_IFIFO = 0x1000 |
||||||
|
S_IFCHR = 0x2000 |
||||||
|
S_IFDIR = 0x4000 |
||||||
|
S_IFBLK = 0x6000 |
||||||
|
S_IFREG = 0x8000 |
||||||
|
S_IFLNK = 0xa000 |
||||||
|
S_IFSOCK = 0xc000 |
||||||
|
) |
||||||
|
|
||||||
|
// Errors
|
||||||
|
var ( |
||||||
|
EINVAL = syscall.NewError("bad arg in system call") |
||||||
|
ENOTDIR = syscall.NewError("not a directory") |
||||||
|
EISDIR = syscall.NewError("file is a directory") |
||||||
|
ENOENT = syscall.NewError("file does not exist") |
||||||
|
EEXIST = syscall.NewError("file already exists") |
||||||
|
EMFILE = syscall.NewError("no free file descriptors") |
||||||
|
EIO = syscall.NewError("i/o error") |
||||||
|
ENAMETOOLONG = syscall.NewError("file name too long") |
||||||
|
EINTR = syscall.NewError("interrupted") |
||||||
|
EPERM = syscall.NewError("permission denied") |
||||||
|
EBUSY = syscall.NewError("no free devices") |
||||||
|
ETIMEDOUT = syscall.NewError("connection timed out") |
||||||
|
EPLAN9 = syscall.NewError("not supported by plan 9") |
||||||
|
|
||||||
|
// The following errors do not correspond to any
|
||||||
|
// Plan 9 system messages. Invented to support
|
||||||
|
// what package os and others expect.
|
||||||
|
EACCES = syscall.NewError("access permission denied") |
||||||
|
EAFNOSUPPORT = syscall.NewError("address family not supported by protocol") |
||||||
|
) |
@ -0,0 +1,150 @@ |
|||||||
|
#!/usr/bin/env bash |
||||||
|
# Copyright 2009 The Go Authors. All rights reserved. |
||||||
|
# Use of this source code is governed by a BSD-style |
||||||
|
# license that can be found in the LICENSE file. |
||||||
|
|
||||||
|
# The plan9 package provides access to the raw system call |
||||||
|
# interface of the underlying operating system. Porting Go to |
||||||
|
# a new architecture/operating system combination requires |
||||||
|
# some manual effort, though there are tools that automate |
||||||
|
# much of the process. The auto-generated files have names |
||||||
|
# beginning with z. |
||||||
|
# |
||||||
|
# This script runs or (given -n) prints suggested commands to generate z files |
||||||
|
# for the current system. Running those commands is not automatic. |
||||||
|
# This script is documentation more than anything else. |
||||||
|
# |
||||||
|
# * asm_${GOOS}_${GOARCH}.s |
||||||
|
# |
||||||
|
# This hand-written assembly file implements system call dispatch. |
||||||
|
# There are three entry points: |
||||||
|
# |
||||||
|
# func Syscall(trap, a1, a2, a3 uintptr) (r1, r2, err uintptr); |
||||||
|
# func Syscall6(trap, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2, err uintptr); |
||||||
|
# func RawSyscall(trap, a1, a2, a3 uintptr) (r1, r2, err uintptr); |
||||||
|
# |
||||||
|
# The first and second are the standard ones; they differ only in |
||||||
|
# how many arguments can be passed to the kernel. |
||||||
|
# The third is for low-level use by the ForkExec wrapper; |
||||||
|
# unlike the first two, it does not call into the scheduler to |
||||||
|
# let it know that a system call is running. |
||||||
|
# |
||||||
|
# * syscall_${GOOS}.go |
||||||
|
# |
||||||
|
# This hand-written Go file implements system calls that need |
||||||
|
# special handling and lists "//sys" comments giving prototypes |
||||||
|
# for ones that can be auto-generated. Mksyscall reads those |
||||||
|
# comments to generate the stubs. |
||||||
|
# |
||||||
|
# * syscall_${GOOS}_${GOARCH}.go |
||||||
|
# |
||||||
|
# Same as syscall_${GOOS}.go except that it contains code specific |
||||||
|
# to ${GOOS} on one particular architecture. |
||||||
|
# |
||||||
|
# * types_${GOOS}.c |
||||||
|
# |
||||||
|
# This hand-written C file includes standard C headers and then |
||||||
|
# creates typedef or enum names beginning with a dollar sign |
||||||
|
# (use of $ in variable names is a gcc extension). The hardest |
||||||
|
# part about preparing this file is figuring out which headers to |
||||||
|
# include and which symbols need to be #defined to get the |
||||||
|
# actual data structures that pass through to the kernel system calls. |
||||||
|
# Some C libraries present alternate versions for binary compatibility |
||||||
|
# and translate them on the way in and out of system calls, but |
||||||
|
# there is almost always a #define that can get the real ones. |
||||||
|
# See types_darwin.c and types_linux.c for examples. |
||||||
|
# |
||||||
|
# * zerror_${GOOS}_${GOARCH}.go |
||||||
|
# |
||||||
|
# This machine-generated file defines the system's error numbers, |
||||||
|
# error strings, and signal numbers. The generator is "mkerrors.sh". |
||||||
|
# Usually no arguments are needed, but mkerrors.sh will pass its |
||||||
|
# arguments on to godefs. |
||||||
|
# |
||||||
|
# * zsyscall_${GOOS}_${GOARCH}.go |
||||||
|
# |
||||||
|
# Generated by mksyscall.pl; see syscall_${GOOS}.go above. |
||||||
|
# |
||||||
|
# * zsysnum_${GOOS}_${GOARCH}.go |
||||||
|
# |
||||||
|
# Generated by mksysnum_${GOOS}. |
||||||
|
# |
||||||
|
# * ztypes_${GOOS}_${GOARCH}.go |
||||||
|
# |
||||||
|
# Generated by godefs; see types_${GOOS}.c above. |
||||||
|
|
||||||
|
GOOSARCH="${GOOS}_${GOARCH}" |
||||||
|
|
||||||
|
# defaults |
||||||
|
mksyscall="go run mksyscall.go" |
||||||
|
mkerrors="./mkerrors.sh" |
||||||
|
zerrors="zerrors_$GOOSARCH.go" |
||||||
|
mksysctl="" |
||||||
|
zsysctl="zsysctl_$GOOSARCH.go" |
||||||
|
mksysnum= |
||||||
|
mktypes= |
||||||
|
run="sh" |
||||||
|
|
||||||
|
case "$1" in |
||||||
|
-syscalls) |
||||||
|
for i in zsyscall*go |
||||||
|
do |
||||||
|
sed 1q $i | sed 's;^// ;;' | sh > _$i && gofmt < _$i > $i |
||||||
|
rm _$i |
||||||
|
done |
||||||
|
exit 0 |
||||||
|
;; |
||||||
|
-n) |
||||||
|
run="cat" |
||||||
|
shift |
||||||
|
esac |
||||||
|
|
||||||
|
case "$#" in |
||||||
|
0) |
||||||
|
;; |
||||||
|
*) |
||||||
|
echo 'usage: mkall.sh [-n]' 1>&2 |
||||||
|
exit 2 |
||||||
|
esac |
||||||
|
|
||||||
|
case "$GOOSARCH" in |
||||||
|
_* | *_ | _) |
||||||
|
echo 'undefined $GOOS_$GOARCH:' "$GOOSARCH" 1>&2 |
||||||
|
exit 1 |
||||||
|
;; |
||||||
|
plan9_386) |
||||||
|
mkerrors= |
||||||
|
mksyscall="go run mksyscall.go -l32 -plan9 -tags plan9,386" |
||||||
|
mksysnum="./mksysnum_plan9.sh /n/sources/plan9/sys/src/libc/9syscall/sys.h" |
||||||
|
mktypes="XXX" |
||||||
|
;; |
||||||
|
plan9_amd64) |
||||||
|
mkerrors= |
||||||
|
mksyscall="go run mksyscall.go -l32 -plan9 -tags plan9,amd64" |
||||||
|
mksysnum="./mksysnum_plan9.sh /n/sources/plan9/sys/src/libc/9syscall/sys.h" |
||||||
|
mktypes="XXX" |
||||||
|
;; |
||||||
|
plan9_arm) |
||||||
|
mkerrors= |
||||||
|
mksyscall="go run mksyscall.go -l32 -plan9 -tags plan9,arm" |
||||||
|
mksysnum="./mksysnum_plan9.sh /n/sources/plan9/sys/src/libc/9syscall/sys.h" |
||||||
|
mktypes="XXX" |
||||||
|
;; |
||||||
|
*) |
||||||
|
echo 'unrecognized $GOOS_$GOARCH: ' "$GOOSARCH" 1>&2 |
||||||
|
exit 1 |
||||||
|
;; |
||||||
|
esac |
||||||
|
|
||||||
|
( |
||||||
|
if [ -n "$mkerrors" ]; then echo "$mkerrors |gofmt >$zerrors"; fi |
||||||
|
case "$GOOS" in |
||||||
|
plan9) |
||||||
|
syscall_goos="syscall_$GOOS.go" |
||||||
|
if [ -n "$mksyscall" ]; then echo "$mksyscall $syscall_goos |gofmt >zsyscall_$GOOSARCH.go"; fi |
||||||
|
;; |
||||||
|
esac |
||||||
|
if [ -n "$mksysctl" ]; then echo "$mksysctl |gofmt >$zsysctl"; fi |
||||||
|
if [ -n "$mksysnum" ]; then echo "$mksysnum |gofmt >zsysnum_$GOOSARCH.go"; fi |
||||||
|
if [ -n "$mktypes" ]; then echo "$mktypes types_$GOOS.go |gofmt >ztypes_$GOOSARCH.go"; fi |
||||||
|
) | $run |
@ -0,0 +1,246 @@ |
|||||||
|
#!/usr/bin/env bash |
||||||
|
# Copyright 2009 The Go Authors. All rights reserved. |
||||||
|
# Use of this source code is governed by a BSD-style |
||||||
|
# license that can be found in the LICENSE file. |
||||||
|
|
||||||
|
# Generate Go code listing errors and other #defined constant |
||||||
|
# values (ENAMETOOLONG etc.), by asking the preprocessor |
||||||
|
# about the definitions. |
||||||
|
|
||||||
|
unset LANG |
||||||
|
export LC_ALL=C |
||||||
|
export LC_CTYPE=C |
||||||
|
|
||||||
|
CC=${CC:-gcc} |
||||||
|
|
||||||
|
uname=$(uname) |
||||||
|
|
||||||
|
includes=' |
||||||
|
#include <sys/types.h> |
||||||
|
#include <sys/file.h> |
||||||
|
#include <fcntl.h> |
||||||
|
#include <dirent.h> |
||||||
|
#include <sys/socket.h> |
||||||
|
#include <netinet/in.h> |
||||||
|
#include <netinet/ip.h> |
||||||
|
#include <netinet/ip6.h> |
||||||
|
#include <netinet/tcp.h> |
||||||
|
#include <errno.h> |
||||||
|
#include <sys/signal.h> |
||||||
|
#include <signal.h> |
||||||
|
#include <sys/resource.h> |
||||||
|
' |
||||||
|
|
||||||
|
ccflags="$@" |
||||||
|
|
||||||
|
# Write go tool cgo -godefs input. |
||||||
|
( |
||||||
|
echo package plan9 |
||||||
|
echo |
||||||
|
echo '/*' |
||||||
|
indirect="includes_$(uname)" |
||||||
|
echo "${!indirect} $includes" |
||||||
|
echo '*/' |
||||||
|
echo 'import "C"' |
||||||
|
echo |
||||||
|
echo 'const (' |
||||||
|
|
||||||
|
# The gcc command line prints all the #defines |
||||||
|
# it encounters while processing the input |
||||||
|
echo "${!indirect} $includes" | $CC -x c - -E -dM $ccflags | |
||||||
|
awk ' |
||||||
|
$1 != "#define" || $2 ~ /\(/ || $3 == "" {next} |
||||||
|
|
||||||
|
$2 ~ /^E([ABCD]X|[BIS]P|[SD]I|S|FL)$/ {next} # 386 registers |
||||||
|
$2 ~ /^(SIGEV_|SIGSTKSZ|SIGRT(MIN|MAX))/ {next} |
||||||
|
$2 ~ /^(SCM_SRCRT)$/ {next} |
||||||
|
$2 ~ /^(MAP_FAILED)$/ {next} |
||||||
|
|
||||||
|
$2 !~ /^ETH_/ && |
||||||
|
$2 !~ /^EPROC_/ && |
||||||
|
$2 !~ /^EQUIV_/ && |
||||||
|
$2 !~ /^EXPR_/ && |
||||||
|
$2 ~ /^E[A-Z0-9_]+$/ || |
||||||
|
$2 ~ /^B[0-9_]+$/ || |
||||||
|
$2 ~ /^V[A-Z0-9]+$/ || |
||||||
|
$2 ~ /^CS[A-Z0-9]/ || |
||||||
|
$2 ~ /^I(SIG|CANON|CRNL|EXTEN|MAXBEL|STRIP|UTF8)$/ || |
||||||
|
$2 ~ /^IGN/ || |
||||||
|
$2 ~ /^IX(ON|ANY|OFF)$/ || |
||||||
|
$2 ~ /^IN(LCR|PCK)$/ || |
||||||
|
$2 ~ /(^FLU?SH)|(FLU?SH$)/ || |
||||||
|
$2 ~ /^C(LOCAL|READ)$/ || |
||||||
|
$2 == "BRKINT" || |
||||||
|
$2 == "HUPCL" || |
||||||
|
$2 == "PENDIN" || |
||||||
|
$2 == "TOSTOP" || |
||||||
|
$2 ~ /^PAR/ || |
||||||
|
$2 ~ /^SIG[^_]/ || |
||||||
|
$2 ~ /^O[CNPFP][A-Z]+[^_][A-Z]+$/ || |
||||||
|
$2 ~ /^IN_/ || |
||||||
|
$2 ~ /^LOCK_(SH|EX|NB|UN)$/ || |
||||||
|
$2 ~ /^(AF|SOCK|SO|SOL|IPPROTO|IP|IPV6|ICMP6|TCP|EVFILT|NOTE|EV|SHUT|PROT|MAP|PACKET|MSG|SCM|MCL|DT|MADV|PR)_/ || |
||||||
|
$2 == "ICMPV6_FILTER" || |
||||||
|
$2 == "SOMAXCONN" || |
||||||
|
$2 == "NAME_MAX" || |
||||||
|
$2 == "IFNAMSIZ" || |
||||||
|
$2 ~ /^CTL_(MAXNAME|NET|QUERY)$/ || |
||||||
|
$2 ~ /^SYSCTL_VERS/ || |
||||||
|
$2 ~ /^(MS|MNT)_/ || |
||||||
|
$2 ~ /^TUN(SET|GET|ATTACH|DETACH)/ || |
||||||
|
$2 ~ /^(O|F|FD|NAME|S|PTRACE|PT)_/ || |
||||||
|
$2 ~ /^LINUX_REBOOT_CMD_/ || |
||||||
|
$2 ~ /^LINUX_REBOOT_MAGIC[12]$/ || |
||||||
|
$2 !~ "NLA_TYPE_MASK" && |
||||||
|
$2 ~ /^(NETLINK|NLM|NLMSG|NLA|IFA|IFAN|RT|RTCF|RTN|RTPROT|RTNH|ARPHRD|ETH_P)_/ || |
||||||
|
$2 ~ /^SIOC/ || |
||||||
|
$2 ~ /^TIOC/ || |
||||||
|
$2 !~ "RTF_BITS" && |
||||||
|
$2 ~ /^(IFF|IFT|NET_RT|RTM|RTF|RTV|RTA|RTAX)_/ || |
||||||
|
$2 ~ /^BIOC/ || |
||||||
|
$2 ~ /^RUSAGE_(SELF|CHILDREN|THREAD)/ || |
||||||
|
$2 ~ /^RLIMIT_(AS|CORE|CPU|DATA|FSIZE|NOFILE|STACK)|RLIM_INFINITY/ || |
||||||
|
$2 ~ /^PRIO_(PROCESS|PGRP|USER)/ || |
||||||
|
$2 ~ /^CLONE_[A-Z_]+/ || |
||||||
|
$2 !~ /^(BPF_TIMEVAL)$/ && |
||||||
|
$2 ~ /^(BPF|DLT)_/ || |
||||||
|
$2 !~ "WMESGLEN" && |
||||||
|
$2 ~ /^W[A-Z0-9]+$/ {printf("\t%s = C.%s\n", $2, $2)} |
||||||
|
$2 ~ /^__WCOREFLAG$/ {next} |
||||||
|
$2 ~ /^__W[A-Z0-9]+$/ {printf("\t%s = C.%s\n", substr($2,3), $2)} |
||||||
|
|
||||||
|
{next} |
||||||
|
' | sort |
||||||
|
|
||||||
|
echo ')' |
||||||
|
) >_const.go |
||||||
|
|
||||||
|
# Pull out the error names for later. |
||||||
|
errors=$( |
||||||
|
echo '#include <errno.h>' | $CC -x c - -E -dM $ccflags | |
||||||
|
awk '$1=="#define" && $2 ~ /^E[A-Z0-9_]+$/ { print $2 }' | |
||||||
|
sort |
||||||
|
) |
||||||
|
|
||||||
|
# Pull out the signal names for later. |
||||||
|
signals=$( |
||||||
|
echo '#include <signal.h>' | $CC -x c - -E -dM $ccflags | |
||||||
|
awk '$1=="#define" && $2 ~ /^SIG[A-Z0-9]+$/ { print $2 }' | |
||||||
|
egrep -v '(SIGSTKSIZE|SIGSTKSZ|SIGRT)' | |
||||||
|
sort |
||||||
|
) |
||||||
|
|
||||||
|
# Again, writing regexps to a file. |
||||||
|
echo '#include <errno.h>' | $CC -x c - -E -dM $ccflags | |
||||||
|
awk '$1=="#define" && $2 ~ /^E[A-Z0-9_]+$/ { print "^\t" $2 "[ \t]*=" }' | |
||||||
|
sort >_error.grep |
||||||
|
echo '#include <signal.h>' | $CC -x c - -E -dM $ccflags | |
||||||
|
awk '$1=="#define" && $2 ~ /^SIG[A-Z0-9]+$/ { print "^\t" $2 "[ \t]*=" }' | |
||||||
|
egrep -v '(SIGSTKSIZE|SIGSTKSZ|SIGRT)' | |
||||||
|
sort >_signal.grep |
||||||
|
|
||||||
|
echo '// mkerrors.sh' "$@" |
||||||
|
echo '// Code generated by the command above; DO NOT EDIT.' |
||||||
|
echo |
||||||
|
go tool cgo -godefs -- "$@" _const.go >_error.out |
||||||
|
cat _error.out | grep -vf _error.grep | grep -vf _signal.grep |
||||||
|
echo |
||||||
|
echo '// Errors' |
||||||
|
echo 'const (' |
||||||
|
cat _error.out | grep -f _error.grep | sed 's/=\(.*\)/= Errno(\1)/' |
||||||
|
echo ')' |
||||||
|
|
||||||
|
echo |
||||||
|
echo '// Signals' |
||||||
|
echo 'const (' |
||||||
|
cat _error.out | grep -f _signal.grep | sed 's/=\(.*\)/= Signal(\1)/' |
||||||
|
echo ')' |
||||||
|
|
||||||
|
# Run C program to print error and syscall strings. |
||||||
|
( |
||||||
|
echo -E " |
||||||
|
#include <stdio.h> |
||||||
|
#include <stdlib.h> |
||||||
|
#include <errno.h> |
||||||
|
#include <ctype.h> |
||||||
|
#include <string.h> |
||||||
|
#include <signal.h> |
||||||
|
|
||||||
|
#define nelem(x) (sizeof(x)/sizeof((x)[0])) |
||||||
|
|
||||||
|
enum { A = 'A', Z = 'Z', a = 'a', z = 'z' }; // avoid need for single quotes below |
||||||
|
|
||||||
|
int errors[] = { |
||||||
|
" |
||||||
|
for i in $errors |
||||||
|
do |
||||||
|
echo -E ' '$i, |
||||||
|
done |
||||||
|
|
||||||
|
echo -E " |
||||||
|
}; |
||||||
|
|
||||||
|
int signals[] = { |
||||||
|
" |
||||||
|
for i in $signals |
||||||
|
do |
||||||
|
echo -E ' '$i, |
||||||
|
done |
||||||
|
|
||||||
|
# Use -E because on some systems bash builtin interprets \n itself. |
||||||
|
echo -E ' |
||||||
|
}; |
||||||
|
|
||||||
|
static int |
||||||
|
intcmp(const void *a, const void *b) |
||||||
|
{ |
||||||
|
return *(int*)a - *(int*)b; |
||||||
|
} |
||||||
|
|
||||||
|
int |
||||||
|
main(void) |
||||||
|
{ |
||||||
|
int i, j, e; |
||||||
|
char buf[1024], *p; |
||||||
|
|
||||||
|
printf("\n\n// Error table\n"); |
||||||
|
printf("var errors = [...]string {\n"); |
||||||
|
qsort(errors, nelem(errors), sizeof errors[0], intcmp); |
||||||
|
for(i=0; i<nelem(errors); i++) { |
||||||
|
e = errors[i]; |
||||||
|
if(i > 0 && errors[i-1] == e) |
||||||
|
continue; |
||||||
|
strcpy(buf, strerror(e)); |
||||||
|
// lowercase first letter: Bad -> bad, but STREAM -> STREAM. |
||||||
|
if(A <= buf[0] && buf[0] <= Z && a <= buf[1] && buf[1] <= z) |
||||||
|
buf[0] += a - A; |
||||||
|
printf("\t%d: \"%s\",\n", e, buf); |
||||||
|
} |
||||||
|
printf("}\n\n"); |
||||||
|
|
||||||
|
printf("\n\n// Signal table\n"); |
||||||
|
printf("var signals = [...]string {\n"); |
||||||
|
qsort(signals, nelem(signals), sizeof signals[0], intcmp); |
||||||
|
for(i=0; i<nelem(signals); i++) { |
||||||
|
e = signals[i]; |
||||||
|
if(i > 0 && signals[i-1] == e) |
||||||
|
continue; |
||||||
|
strcpy(buf, strsignal(e)); |
||||||
|
// lowercase first letter: Bad -> bad, but STREAM -> STREAM. |
||||||
|
if(A <= buf[0] && buf[0] <= Z && a <= buf[1] && buf[1] <= z) |
||||||
|
buf[0] += a - A; |
||||||
|
// cut trailing : number. |
||||||
|
p = strrchr(buf, ":"[0]); |
||||||
|
if(p) |
||||||
|
*p = '\0'; |
||||||
|
printf("\t%d: \"%s\",\n", e, buf); |
||||||
|
} |
||||||
|
printf("}\n\n"); |
||||||
|
|
||||||
|
return 0; |
||||||
|
} |
||||||
|
|
||||||
|
' |
||||||
|
) >_errors.c |
||||||
|
|
||||||
|
$CC $ccflags -o _errors _errors.c && $GORUN ./_errors && rm -f _errors.c _errors _const.go _error.grep _signal.grep _error.out |
@ -0,0 +1,23 @@ |
|||||||
|
#!/bin/sh |
||||||
|
# Copyright 2009 The Go Authors. All rights reserved. |
||||||
|
# Use of this source code is governed by a BSD-style |
||||||
|
# license that can be found in the LICENSE file. |
||||||
|
|
||||||
|
COMMAND="mksysnum_plan9.sh $@" |
||||||
|
|
||||||
|
cat <<EOF |
||||||
|
// $COMMAND |
||||||
|
// MACHINE GENERATED BY THE ABOVE COMMAND; DO NOT EDIT |
||||||
|
|
||||||
|
package plan9 |
||||||
|
|
||||||
|
const( |
||||||
|
EOF |
||||||
|
|
||||||
|
SP='[ ]' # space or tab |
||||||
|
sed "s/^#define${SP}\\([A-Z0-9_][A-Z0-9_]*\\)${SP}${SP}*\\([0-9][0-9]*\\)/SYS_\\1=\\2/g" \ |
||||||
|
< $1 | grep -v SYS__ |
||||||
|
|
||||||
|
cat <<EOF |
||||||
|
) |
||||||
|
EOF |
@ -0,0 +1,21 @@ |
|||||||
|
// Copyright 2015 The Go Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
// +build go1.5
|
||||||
|
|
||||||
|
package plan9 |
||||||
|
|
||||||
|
import "syscall" |
||||||
|
|
||||||
|
func fixwd() { |
||||||
|
syscall.Fixwd() |
||||||
|
} |
||||||
|
|
||||||
|
func Getwd() (wd string, err error) { |
||||||
|
return syscall.Getwd() |
||||||
|
} |
||||||
|
|
||||||
|
func Chdir(path string) error { |
||||||
|
return syscall.Chdir(path) |
||||||
|
} |
@ -0,0 +1,23 @@ |
|||||||
|
// Copyright 2015 The Go Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
// +build !go1.5
|
||||||
|
|
||||||
|
package plan9 |
||||||
|
|
||||||
|
func fixwd() { |
||||||
|
} |
||||||
|
|
||||||
|
func Getwd() (wd string, err error) { |
||||||
|
fd, err := open(".", O_RDONLY) |
||||||
|
if err != nil { |
||||||
|
return "", err |
||||||
|
} |
||||||
|
defer Close(fd) |
||||||
|
return Fd2path(fd) |
||||||
|
} |
||||||
|
|
||||||
|
func Chdir(path string) error { |
||||||
|
return chdir(path) |
||||||
|
} |
@ -0,0 +1,30 @@ |
|||||||
|
// Copyright 2012 The Go Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
// +build plan9,race
|
||||||
|
|
||||||
|
package plan9 |
||||||
|
|
||||||
|
import ( |
||||||
|
"runtime" |
||||||
|
"unsafe" |
||||||
|
) |
||||||
|
|
||||||
|
const raceenabled = true |
||||||
|
|
||||||
|
func raceAcquire(addr unsafe.Pointer) { |
||||||
|
runtime.RaceAcquire(addr) |
||||||
|
} |
||||||
|
|
||||||
|
func raceReleaseMerge(addr unsafe.Pointer) { |
||||||
|
runtime.RaceReleaseMerge(addr) |
||||||
|
} |
||||||
|
|
||||||
|
func raceReadRange(addr unsafe.Pointer, len int) { |
||||||
|
runtime.RaceReadRange(addr, len) |
||||||
|
} |
||||||
|
|
||||||
|
func raceWriteRange(addr unsafe.Pointer, len int) { |
||||||
|
runtime.RaceWriteRange(addr, len) |
||||||
|
} |
@ -0,0 +1,25 @@ |
|||||||
|
// Copyright 2012 The Go Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
// +build plan9,!race
|
||||||
|
|
||||||
|
package plan9 |
||||||
|
|
||||||
|
import ( |
||||||
|
"unsafe" |
||||||
|
) |
||||||
|
|
||||||
|
const raceenabled = false |
||||||
|
|
||||||
|
func raceAcquire(addr unsafe.Pointer) { |
||||||
|
} |
||||||
|
|
||||||
|
func raceReleaseMerge(addr unsafe.Pointer) { |
||||||
|
} |
||||||
|
|
||||||
|
func raceReadRange(addr unsafe.Pointer, len int) { |
||||||
|
} |
||||||
|
|
||||||
|
func raceWriteRange(addr unsafe.Pointer, len int) { |
||||||
|
} |
@ -0,0 +1,22 @@ |
|||||||
|
// Copyright 2009 The Go Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
// +build plan9
|
||||||
|
|
||||||
|
package plan9 |
||||||
|
|
||||||
|
func itoa(val int) string { // do it here rather than with fmt to avoid dependency
|
||||||
|
if val < 0 { |
||||||
|
return "-" + itoa(-val) |
||||||
|
} |
||||||
|
var buf [32]byte // big enough for int64
|
||||||
|
i := len(buf) - 1 |
||||||
|
for val >= 10 { |
||||||
|
buf[i] = byte(val%10 + '0') |
||||||
|
i-- |
||||||
|
val /= 10 |
||||||
|
} |
||||||
|
buf[i] = byte(val + '0') |
||||||
|
return string(buf[i:]) |
||||||
|
} |
@ -0,0 +1,116 @@ |
|||||||
|
// Copyright 2009 The Go Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
// +build plan9
|
||||||
|
|
||||||
|
// Package plan9 contains an interface to the low-level operating system
|
||||||
|
// primitives. OS details vary depending on the underlying system, and
|
||||||
|
// by default, godoc will display the OS-specific documentation for the current
|
||||||
|
// system. If you want godoc to display documentation for another
|
||||||
|
// system, set $GOOS and $GOARCH to the desired system. For example, if
|
||||||
|
// you want to view documentation for freebsd/arm on linux/amd64, set $GOOS
|
||||||
|
// to freebsd and $GOARCH to arm.
|
||||||
|
//
|
||||||
|
// The primary use of this package is inside other packages that provide a more
|
||||||
|
// portable interface to the system, such as "os", "time" and "net". Use
|
||||||
|
// those packages rather than this one if you can.
|
||||||
|
//
|
||||||
|
// For details of the functions and data types in this package consult
|
||||||
|
// the manuals for the appropriate operating system.
|
||||||
|
//
|
||||||
|
// These calls return err == nil to indicate success; otherwise
|
||||||
|
// err represents an operating system error describing the failure and
|
||||||
|
// holds a value of type syscall.ErrorString.
|
||||||
|
package plan9 // import "golang.org/x/sys/plan9"
|
||||||
|
|
||||||
|
import ( |
||||||
|
"bytes" |
||||||
|
"strings" |
||||||
|
"unsafe" |
||||||
|
|
||||||
|
"golang.org/x/sys/internal/unsafeheader" |
||||||
|
) |
||||||
|
|
||||||
|
// ByteSliceFromString returns a NUL-terminated slice of bytes
|
||||||
|
// containing the text of s. If s contains a NUL byte at any
|
||||||
|
// location, it returns (nil, EINVAL).
|
||||||
|
func ByteSliceFromString(s string) ([]byte, error) { |
||||||
|
if strings.IndexByte(s, 0) != -1 { |
||||||
|
return nil, EINVAL |
||||||
|
} |
||||||
|
a := make([]byte, len(s)+1) |
||||||
|
copy(a, s) |
||||||
|
return a, nil |
||||||
|
} |
||||||
|
|
||||||
|
// BytePtrFromString returns a pointer to a NUL-terminated array of
|
||||||
|
// bytes containing the text of s. If s contains a NUL byte at any
|
||||||
|
// location, it returns (nil, EINVAL).
|
||||||
|
func BytePtrFromString(s string) (*byte, error) { |
||||||
|
a, err := ByteSliceFromString(s) |
||||||
|
if err != nil { |
||||||
|
return nil, err |
||||||
|
} |
||||||
|
return &a[0], nil |
||||||
|
} |
||||||
|
|
||||||
|
// ByteSliceToString returns a string form of the text represented by the slice s, with a terminating NUL and any
|
||||||
|
// bytes after the NUL removed.
|
||||||
|
func ByteSliceToString(s []byte) string { |
||||||
|
if i := bytes.IndexByte(s, 0); i != -1 { |
||||||
|
s = s[:i] |
||||||
|
} |
||||||
|
return string(s) |
||||||
|
} |
||||||
|
|
||||||
|
// BytePtrToString takes a pointer to a sequence of text and returns the corresponding string.
|
||||||
|
// If the pointer is nil, it returns the empty string. It assumes that the text sequence is terminated
|
||||||
|
// at a zero byte; if the zero byte is not present, the program may crash.
|
||||||
|
func BytePtrToString(p *byte) string { |
||||||
|
if p == nil { |
||||||
|
return "" |
||||||
|
} |
||||||
|
if *p == 0 { |
||||||
|
return "" |
||||||
|
} |
||||||
|
|
||||||
|
// Find NUL terminator.
|
||||||
|
n := 0 |
||||||
|
for ptr := unsafe.Pointer(p); *(*byte)(ptr) != 0; n++ { |
||||||
|
ptr = unsafe.Pointer(uintptr(ptr) + 1) |
||||||
|
} |
||||||
|
|
||||||
|
var s []byte |
||||||
|
h := (*unsafeheader.Slice)(unsafe.Pointer(&s)) |
||||||
|
h.Data = unsafe.Pointer(p) |
||||||
|
h.Len = n |
||||||
|
h.Cap = n |
||||||
|
|
||||||
|
return string(s) |
||||||
|
} |
||||||
|
|
||||||
|
// Single-word zero for use when we need a valid pointer to 0 bytes.
|
||||||
|
// See mksyscall.pl.
|
||||||
|
var _zero uintptr |
||||||
|
|
||||||
|
func (ts *Timespec) Unix() (sec int64, nsec int64) { |
||||||
|
return int64(ts.Sec), int64(ts.Nsec) |
||||||
|
} |
||||||
|
|
||||||
|
func (tv *Timeval) Unix() (sec int64, nsec int64) { |
||||||
|
return int64(tv.Sec), int64(tv.Usec) * 1000 |
||||||
|
} |
||||||
|
|
||||||
|
func (ts *Timespec) Nano() int64 { |
||||||
|
return int64(ts.Sec)*1e9 + int64(ts.Nsec) |
||||||
|
} |
||||||
|
|
||||||
|
func (tv *Timeval) Nano() int64 { |
||||||
|
return int64(tv.Sec)*1e9 + int64(tv.Usec)*1000 |
||||||
|
} |
||||||
|
|
||||||
|
// use is a no-op, but the compiler cannot see that it is.
|
||||||
|
// Calling use(p) ensures that p is kept live until that point.
|
||||||
|
//go:noescape
|
||||||
|
func use(p unsafe.Pointer) |
@ -0,0 +1,349 @@ |
|||||||
|
// Copyright 2011 The Go Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
// Plan 9 system calls.
|
||||||
|
// This file is compiled as ordinary Go code,
|
||||||
|
// but it is also input to mksyscall,
|
||||||
|
// which parses the //sys lines and generates system call stubs.
|
||||||
|
// Note that sometimes we use a lowercase //sys name and
|
||||||
|
// wrap it in our own nicer implementation.
|
||||||
|
|
||||||
|
package plan9 |
||||||
|
|
||||||
|
import ( |
||||||
|
"bytes" |
||||||
|
"syscall" |
||||||
|
"unsafe" |
||||||
|
) |
||||||
|
|
||||||
|
// A Note is a string describing a process note.
|
||||||
|
// It implements the os.Signal interface.
|
||||||
|
type Note string |
||||||
|
|
||||||
|
func (n Note) Signal() {} |
||||||
|
|
||||||
|
func (n Note) String() string { |
||||||
|
return string(n) |
||||||
|
} |
||||||
|
|
||||||
|
var ( |
||||||
|
Stdin = 0 |
||||||
|
Stdout = 1 |
||||||
|
Stderr = 2 |
||||||
|
) |
||||||
|
|
||||||
|
// For testing: clients can set this flag to force
|
||||||
|
// creation of IPv6 sockets to return EAFNOSUPPORT.
|
||||||
|
var SocketDisableIPv6 bool |
||||||
|
|
||||||
|
func Syscall(trap, a1, a2, a3 uintptr) (r1, r2 uintptr, err syscall.ErrorString) |
||||||
|
func Syscall6(trap, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2 uintptr, err syscall.ErrorString) |
||||||
|
func RawSyscall(trap, a1, a2, a3 uintptr) (r1, r2, err uintptr) |
||||||
|
func RawSyscall6(trap, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2, err uintptr) |
||||||
|
|
||||||
|
func atoi(b []byte) (n uint) { |
||||||
|
n = 0 |
||||||
|
for i := 0; i < len(b); i++ { |
||||||
|
n = n*10 + uint(b[i]-'0') |
||||||
|
} |
||||||
|
return |
||||||
|
} |
||||||
|
|
||||||
|
func cstring(s []byte) string { |
||||||
|
i := bytes.IndexByte(s, 0) |
||||||
|
if i == -1 { |
||||||
|
i = len(s) |
||||||
|
} |
||||||
|
return string(s[:i]) |
||||||
|
} |
||||||
|
|
||||||
|
func errstr() string { |
||||||
|
var buf [ERRMAX]byte |
||||||
|
|
||||||
|
RawSyscall(SYS_ERRSTR, uintptr(unsafe.Pointer(&buf[0])), uintptr(len(buf)), 0) |
||||||
|
|
||||||
|
buf[len(buf)-1] = 0 |
||||||
|
return cstring(buf[:]) |
||||||
|
} |
||||||
|
|
||||||
|
// Implemented in assembly to import from runtime.
|
||||||
|
func exit(code int) |
||||||
|
|
||||||
|
func Exit(code int) { exit(code) } |
||||||
|
|
||||||
|
func readnum(path string) (uint, error) { |
||||||
|
var b [12]byte |
||||||
|
|
||||||
|
fd, e := Open(path, O_RDONLY) |
||||||
|
if e != nil { |
||||||
|
return 0, e |
||||||
|
} |
||||||
|
defer Close(fd) |
||||||
|
|
||||||
|
n, e := Pread(fd, b[:], 0) |
||||||
|
|
||||||
|
if e != nil { |
||||||
|
return 0, e |
||||||
|
} |
||||||
|
|
||||||
|
m := 0 |
||||||
|
for ; m < n && b[m] == ' '; m++ { |
||||||
|
} |
||||||
|
|
||||||
|
return atoi(b[m : n-1]), nil |
||||||
|
} |
||||||
|
|
||||||
|
func Getpid() (pid int) { |
||||||
|
n, _ := readnum("#c/pid") |
||||||
|
return int(n) |
||||||
|
} |
||||||
|
|
||||||
|
func Getppid() (ppid int) { |
||||||
|
n, _ := readnum("#c/ppid") |
||||||
|
return int(n) |
||||||
|
} |
||||||
|
|
||||||
|
func Read(fd int, p []byte) (n int, err error) { |
||||||
|
return Pread(fd, p, -1) |
||||||
|
} |
||||||
|
|
||||||
|
func Write(fd int, p []byte) (n int, err error) { |
||||||
|
return Pwrite(fd, p, -1) |
||||||
|
} |
||||||
|
|
||||||
|
var ioSync int64 |
||||||
|
|
||||||
|
//sys fd2path(fd int, buf []byte) (err error)
|
||||||
|
func Fd2path(fd int) (path string, err error) { |
||||||
|
var buf [512]byte |
||||||
|
|
||||||
|
e := fd2path(fd, buf[:]) |
||||||
|
if e != nil { |
||||||
|
return "", e |
||||||
|
} |
||||||
|
return cstring(buf[:]), nil |
||||||
|
} |
||||||
|
|
||||||
|
//sys pipe(p *[2]int32) (err error)
|
||||||
|
func Pipe(p []int) (err error) { |
||||||
|
if len(p) != 2 { |
||||||
|
return syscall.ErrorString("bad arg in system call") |
||||||
|
} |
||||||
|
var pp [2]int32 |
||||||
|
err = pipe(&pp) |
||||||
|
p[0] = int(pp[0]) |
||||||
|
p[1] = int(pp[1]) |
||||||
|
return |
||||||
|
} |
||||||
|
|
||||||
|
// Underlying system call writes to newoffset via pointer.
|
||||||
|
// Implemented in assembly to avoid allocation.
|
||||||
|
func seek(placeholder uintptr, fd int, offset int64, whence int) (newoffset int64, err string) |
||||||
|
|
||||||
|
func Seek(fd int, offset int64, whence int) (newoffset int64, err error) { |
||||||
|
newoffset, e := seek(0, fd, offset, whence) |
||||||
|
|
||||||
|
if newoffset == -1 { |
||||||
|
err = syscall.ErrorString(e) |
||||||
|
} |
||||||
|
return |
||||||
|
} |
||||||
|
|
||||||
|
func Mkdir(path string, mode uint32) (err error) { |
||||||
|
fd, err := Create(path, O_RDONLY, DMDIR|mode) |
||||||
|
|
||||||
|
if fd != -1 { |
||||||
|
Close(fd) |
||||||
|
} |
||||||
|
|
||||||
|
return |
||||||
|
} |
||||||
|
|
||||||
|
type Waitmsg struct { |
||||||
|
Pid int |
||||||
|
Time [3]uint32 |
||||||
|
Msg string |
||||||
|
} |
||||||
|
|
||||||
|
func (w Waitmsg) Exited() bool { return true } |
||||||
|
func (w Waitmsg) Signaled() bool { return false } |
||||||
|
|
||||||
|
func (w Waitmsg) ExitStatus() int { |
||||||
|
if len(w.Msg) == 0 { |
||||||
|
// a normal exit returns no message
|
||||||
|
return 0 |
||||||
|
} |
||||||
|
return 1 |
||||||
|
} |
||||||
|
|
||||||
|
//sys await(s []byte) (n int, err error)
|
||||||
|
func Await(w *Waitmsg) (err error) { |
||||||
|
var buf [512]byte |
||||||
|
var f [5][]byte |
||||||
|
|
||||||
|
n, err := await(buf[:]) |
||||||
|
|
||||||
|
if err != nil || w == nil { |
||||||
|
return |
||||||
|
} |
||||||
|
|
||||||
|
nf := 0 |
||||||
|
p := 0 |
||||||
|
for i := 0; i < n && nf < len(f)-1; i++ { |
||||||
|
if buf[i] == ' ' { |
||||||
|
f[nf] = buf[p:i] |
||||||
|
p = i + 1 |
||||||
|
nf++ |
||||||
|
} |
||||||
|
} |
||||||
|
f[nf] = buf[p:] |
||||||
|
nf++ |
||||||
|
|
||||||
|
if nf != len(f) { |
||||||
|
return syscall.ErrorString("invalid wait message") |
||||||
|
} |
||||||
|
w.Pid = int(atoi(f[0])) |
||||||
|
w.Time[0] = uint32(atoi(f[1])) |
||||||
|
w.Time[1] = uint32(atoi(f[2])) |
||||||
|
w.Time[2] = uint32(atoi(f[3])) |
||||||
|
w.Msg = cstring(f[4]) |
||||||
|
if w.Msg == "''" { |
||||||
|
// await() returns '' for no error
|
||||||
|
w.Msg = "" |
||||||
|
} |
||||||
|
return |
||||||
|
} |
||||||
|
|
||||||
|
func Unmount(name, old string) (err error) { |
||||||
|
fixwd() |
||||||
|
oldp, err := BytePtrFromString(old) |
||||||
|
if err != nil { |
||||||
|
return err |
||||||
|
} |
||||||
|
oldptr := uintptr(unsafe.Pointer(oldp)) |
||||||
|
|
||||||
|
var r0 uintptr |
||||||
|
var e syscall.ErrorString |
||||||
|
|
||||||
|
// bind(2) man page: If name is zero, everything bound or mounted upon old is unbound or unmounted.
|
||||||
|
if name == "" { |
||||||
|
r0, _, e = Syscall(SYS_UNMOUNT, _zero, oldptr, 0) |
||||||
|
} else { |
||||||
|
namep, err := BytePtrFromString(name) |
||||||
|
if err != nil { |
||||||
|
return err |
||||||
|
} |
||||||
|
r0, _, e = Syscall(SYS_UNMOUNT, uintptr(unsafe.Pointer(namep)), oldptr, 0) |
||||||
|
} |
||||||
|
|
||||||
|
if int32(r0) == -1 { |
||||||
|
err = e |
||||||
|
} |
||||||
|
return |
||||||
|
} |
||||||
|
|
||||||
|
func Fchdir(fd int) (err error) { |
||||||
|
path, err := Fd2path(fd) |
||||||
|
|
||||||
|
if err != nil { |
||||||
|
return |
||||||
|
} |
||||||
|
|
||||||
|
return Chdir(path) |
||||||
|
} |
||||||
|
|
||||||
|
type Timespec struct { |
||||||
|
Sec int32 |
||||||
|
Nsec int32 |
||||||
|
} |
||||||
|
|
||||||
|
type Timeval struct { |
||||||
|
Sec int32 |
||||||
|
Usec int32 |
||||||
|
} |
||||||
|
|
||||||
|
func NsecToTimeval(nsec int64) (tv Timeval) { |
||||||
|
nsec += 999 // round up to microsecond
|
||||||
|
tv.Usec = int32(nsec % 1e9 / 1e3) |
||||||
|
tv.Sec = int32(nsec / 1e9) |
||||||
|
return |
||||||
|
} |
||||||
|
|
||||||
|
func nsec() int64 { |
||||||
|
var scratch int64 |
||||||
|
|
||||||
|
r0, _, _ := Syscall(SYS_NSEC, uintptr(unsafe.Pointer(&scratch)), 0, 0) |
||||||
|
// TODO(aram): remove hack after I fix _nsec in the pc64 kernel.
|
||||||
|
if r0 == 0 { |
||||||
|
return scratch |
||||||
|
} |
||||||
|
return int64(r0) |
||||||
|
} |
||||||
|
|
||||||
|
func Gettimeofday(tv *Timeval) error { |
||||||
|
nsec := nsec() |
||||||
|
*tv = NsecToTimeval(nsec) |
||||||
|
return nil |
||||||
|
} |
||||||
|
|
||||||
|
func Getpagesize() int { return 0x1000 } |
||||||
|
|
||||||
|
func Getegid() (egid int) { return -1 } |
||||||
|
func Geteuid() (euid int) { return -1 } |
||||||
|
func Getgid() (gid int) { return -1 } |
||||||
|
func Getuid() (uid int) { return -1 } |
||||||
|
|
||||||
|
func Getgroups() (gids []int, err error) { |
||||||
|
return make([]int, 0), nil |
||||||
|
} |
||||||
|
|
||||||
|
//sys open(path string, mode int) (fd int, err error)
|
||||||
|
func Open(path string, mode int) (fd int, err error) { |
||||||
|
fixwd() |
||||||
|
return open(path, mode) |
||||||
|
} |
||||||
|
|
||||||
|
//sys create(path string, mode int, perm uint32) (fd int, err error)
|
||||||
|
func Create(path string, mode int, perm uint32) (fd int, err error) { |
||||||
|
fixwd() |
||||||
|
return create(path, mode, perm) |
||||||
|
} |
||||||
|
|
||||||
|
//sys remove(path string) (err error)
|
||||||
|
func Remove(path string) error { |
||||||
|
fixwd() |
||||||
|
return remove(path) |
||||||
|
} |
||||||
|
|
||||||
|
//sys stat(path string, edir []byte) (n int, err error)
|
||||||
|
func Stat(path string, edir []byte) (n int, err error) { |
||||||
|
fixwd() |
||||||
|
return stat(path, edir) |
||||||
|
} |
||||||
|
|
||||||
|
//sys bind(name string, old string, flag int) (err error)
|
||||||
|
func Bind(name string, old string, flag int) (err error) { |
||||||
|
fixwd() |
||||||
|
return bind(name, old, flag) |
||||||
|
} |
||||||
|
|
||||||
|
//sys mount(fd int, afd int, old string, flag int, aname string) (err error)
|
||||||
|
func Mount(fd int, afd int, old string, flag int, aname string) (err error) { |
||||||
|
fixwd() |
||||||
|
return mount(fd, afd, old, flag, aname) |
||||||
|
} |
||||||
|
|
||||||
|
//sys wstat(path string, edir []byte) (err error)
|
||||||
|
func Wstat(path string, edir []byte) (err error) { |
||||||
|
fixwd() |
||||||
|
return wstat(path, edir) |
||||||
|
} |
||||||
|
|
||||||
|
//sys chdir(path string) (err error)
|
||||||
|
//sys Dup(oldfd int, newfd int) (fd int, err error)
|
||||||
|
//sys Pread(fd int, p []byte, offset int64) (n int, err error)
|
||||||
|
//sys Pwrite(fd int, p []byte, offset int64) (n int, err error)
|
||||||
|
//sys Close(fd int) (err error)
|
||||||
|
//sys Fstat(fd int, edir []byte) (n int, err error)
|
||||||
|
//sys Fwstat(fd int, edir []byte) (err error)
|
@ -0,0 +1,284 @@ |
|||||||
|
// go run mksyscall.go -l32 -plan9 -tags plan9,386 syscall_plan9.go
|
||||||
|
// Code generated by the command above; see README.md. DO NOT EDIT.
|
||||||
|
|
||||||
|
// +build plan9,386
|
||||||
|
|
||||||
|
package plan9 |
||||||
|
|
||||||
|
import "unsafe" |
||||||
|
|
||||||
|
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
|
||||||
|
|
||||||
|
func fd2path(fd int, buf []byte) (err error) { |
||||||
|
var _p0 unsafe.Pointer |
||||||
|
if len(buf) > 0 { |
||||||
|
_p0 = unsafe.Pointer(&buf[0]) |
||||||
|
} else { |
||||||
|
_p0 = unsafe.Pointer(&_zero) |
||||||
|
} |
||||||
|
r0, _, e1 := Syscall(SYS_FD2PATH, uintptr(fd), uintptr(_p0), uintptr(len(buf))) |
||||||
|
if int32(r0) == -1 { |
||||||
|
err = e1 |
||||||
|
} |
||||||
|
return |
||||||
|
} |
||||||
|
|
||||||
|
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
|
||||||
|
|
||||||
|
func pipe(p *[2]int32) (err error) { |
||||||
|
r0, _, e1 := Syscall(SYS_PIPE, uintptr(unsafe.Pointer(p)), 0, 0) |
||||||
|
if int32(r0) == -1 { |
||||||
|
err = e1 |
||||||
|
} |
||||||
|
return |
||||||
|
} |
||||||
|
|
||||||
|
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
|
||||||
|
|
||||||
|
func await(s []byte) (n int, err error) { |
||||||
|
var _p0 unsafe.Pointer |
||||||
|
if len(s) > 0 { |
||||||
|
_p0 = unsafe.Pointer(&s[0]) |
||||||
|
} else { |
||||||
|
_p0 = unsafe.Pointer(&_zero) |
||||||
|
} |
||||||
|
r0, _, e1 := Syscall(SYS_AWAIT, uintptr(_p0), uintptr(len(s)), 0) |
||||||
|
n = int(r0) |
||||||
|
if int32(r0) == -1 { |
||||||
|
err = e1 |
||||||
|
} |
||||||
|
return |
||||||
|
} |
||||||
|
|
||||||
|
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
|
||||||
|
|
||||||
|
func open(path string, mode int) (fd int, err error) { |
||||||
|
var _p0 *byte |
||||||
|
_p0, err = BytePtrFromString(path) |
||||||
|
if err != nil { |
||||||
|
return |
||||||
|
} |
||||||
|
r0, _, e1 := Syscall(SYS_OPEN, uintptr(unsafe.Pointer(_p0)), uintptr(mode), 0) |
||||||
|
fd = int(r0) |
||||||
|
if int32(r0) == -1 { |
||||||
|
err = e1 |
||||||
|
} |
||||||
|
return |
||||||
|
} |
||||||
|
|
||||||
|
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
|
||||||
|
|
||||||
|
func create(path string, mode int, perm uint32) (fd int, err error) { |
||||||
|
var _p0 *byte |
||||||
|
_p0, err = BytePtrFromString(path) |
||||||
|
if err != nil { |
||||||
|
return |
||||||
|
} |
||||||
|
r0, _, e1 := Syscall(SYS_CREATE, uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(perm)) |
||||||
|
fd = int(r0) |
||||||
|
if int32(r0) == -1 { |
||||||
|
err = e1 |
||||||
|
} |
||||||
|
return |
||||||
|
} |
||||||
|
|
||||||
|
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
|
||||||
|
|
||||||
|
func remove(path string) (err error) { |
||||||
|
var _p0 *byte |
||||||
|
_p0, err = BytePtrFromString(path) |
||||||
|
if err != nil { |
||||||
|
return |
||||||
|
} |
||||||
|
r0, _, e1 := Syscall(SYS_REMOVE, uintptr(unsafe.Pointer(_p0)), 0, 0) |
||||||
|
if int32(r0) == -1 { |
||||||
|
err = e1 |
||||||
|
} |
||||||
|
return |
||||||
|
} |
||||||
|
|
||||||
|
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
|
||||||
|
|
||||||
|
func stat(path string, edir []byte) (n int, err error) { |
||||||
|
var _p0 *byte |
||||||
|
_p0, err = BytePtrFromString(path) |
||||||
|
if err != nil { |
||||||
|
return |
||||||
|
} |
||||||
|
var _p1 unsafe.Pointer |
||||||
|
if len(edir) > 0 { |
||||||
|
_p1 = unsafe.Pointer(&edir[0]) |
||||||
|
} else { |
||||||
|
_p1 = unsafe.Pointer(&_zero) |
||||||
|
} |
||||||
|
r0, _, e1 := Syscall(SYS_STAT, uintptr(unsafe.Pointer(_p0)), uintptr(_p1), uintptr(len(edir))) |
||||||
|
n = int(r0) |
||||||
|
if int32(r0) == -1 { |
||||||
|
err = e1 |
||||||
|
} |
||||||
|
return |
||||||
|
} |
||||||
|
|
||||||
|
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
|
||||||
|
|
||||||
|
func bind(name string, old string, flag int) (err error) { |
||||||
|
var _p0 *byte |
||||||
|
_p0, err = BytePtrFromString(name) |
||||||
|
if err != nil { |
||||||
|
return |
||||||
|
} |
||||||
|
var _p1 *byte |
||||||
|
_p1, err = BytePtrFromString(old) |
||||||
|
if err != nil { |
||||||
|
return |
||||||
|
} |
||||||
|
r0, _, e1 := Syscall(SYS_BIND, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), uintptr(flag)) |
||||||
|
if int32(r0) == -1 { |
||||||
|
err = e1 |
||||||
|
} |
||||||
|
return |
||||||
|
} |
||||||
|
|
||||||
|
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
|
||||||
|
|
||||||
|
func mount(fd int, afd int, old string, flag int, aname string) (err error) { |
||||||
|
var _p0 *byte |
||||||
|
_p0, err = BytePtrFromString(old) |
||||||
|
if err != nil { |
||||||
|
return |
||||||
|
} |
||||||
|
var _p1 *byte |
||||||
|
_p1, err = BytePtrFromString(aname) |
||||||
|
if err != nil { |
||||||
|
return |
||||||
|
} |
||||||
|
r0, _, e1 := Syscall6(SYS_MOUNT, uintptr(fd), uintptr(afd), uintptr(unsafe.Pointer(_p0)), uintptr(flag), uintptr(unsafe.Pointer(_p1)), 0) |
||||||
|
if int32(r0) == -1 { |
||||||
|
err = e1 |
||||||
|
} |
||||||
|
return |
||||||
|
} |
||||||
|
|
||||||
|
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
|
||||||
|
|
||||||
|
func wstat(path string, edir []byte) (err error) { |
||||||
|
var _p0 *byte |
||||||
|
_p0, err = BytePtrFromString(path) |
||||||
|
if err != nil { |
||||||
|
return |
||||||
|
} |
||||||
|
var _p1 unsafe.Pointer |
||||||
|
if len(edir) > 0 { |
||||||
|
_p1 = unsafe.Pointer(&edir[0]) |
||||||
|
} else { |
||||||
|
_p1 = unsafe.Pointer(&_zero) |
||||||
|
} |
||||||
|
r0, _, e1 := Syscall(SYS_WSTAT, uintptr(unsafe.Pointer(_p0)), uintptr(_p1), uintptr(len(edir))) |
||||||
|
if int32(r0) == -1 { |
||||||
|
err = e1 |
||||||
|
} |
||||||
|
return |
||||||
|
} |
||||||
|
|
||||||
|
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
|
||||||
|
|
||||||
|
func chdir(path string) (err error) { |
||||||
|
var _p0 *byte |
||||||
|
_p0, err = BytePtrFromString(path) |
||||||
|
if err != nil { |
||||||
|
return |
||||||
|
} |
||||||
|
r0, _, e1 := Syscall(SYS_CHDIR, uintptr(unsafe.Pointer(_p0)), 0, 0) |
||||||
|
if int32(r0) == -1 { |
||||||
|
err = e1 |
||||||
|
} |
||||||
|
return |
||||||
|
} |
||||||
|
|
||||||
|
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
|
||||||
|
|
||||||
|
func Dup(oldfd int, newfd int) (fd int, err error) { |
||||||
|
r0, _, e1 := Syscall(SYS_DUP, uintptr(oldfd), uintptr(newfd), 0) |
||||||
|
fd = int(r0) |
||||||
|
if int32(r0) == -1 { |
||||||
|
err = e1 |
||||||
|
} |
||||||
|
return |
||||||
|
} |
||||||
|
|
||||||
|
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
|
||||||
|
|
||||||
|
func Pread(fd int, p []byte, offset int64) (n int, err error) { |
||||||
|
var _p0 unsafe.Pointer |
||||||
|
if len(p) > 0 { |
||||||
|
_p0 = unsafe.Pointer(&p[0]) |
||||||
|
} else { |
||||||
|
_p0 = unsafe.Pointer(&_zero) |
||||||
|
} |
||||||
|
r0, _, e1 := Syscall6(SYS_PREAD, uintptr(fd), uintptr(_p0), uintptr(len(p)), uintptr(offset), uintptr(offset>>32), 0) |
||||||
|
n = int(r0) |
||||||
|
if int32(r0) == -1 { |
||||||
|
err = e1 |
||||||
|
} |
||||||
|
return |
||||||
|
} |
||||||
|
|
||||||
|
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
|
||||||
|
|
||||||
|
func Pwrite(fd int, p []byte, offset int64) (n int, err error) { |
||||||
|
var _p0 unsafe.Pointer |
||||||
|
if len(p) > 0 { |
||||||
|
_p0 = unsafe.Pointer(&p[0]) |
||||||
|
} else { |
||||||
|
_p0 = unsafe.Pointer(&_zero) |
||||||
|
} |
||||||
|
r0, _, e1 := Syscall6(SYS_PWRITE, uintptr(fd), uintptr(_p0), uintptr(len(p)), uintptr(offset), uintptr(offset>>32), 0) |
||||||
|
n = int(r0) |
||||||
|
if int32(r0) == -1 { |
||||||
|
err = e1 |
||||||
|
} |
||||||
|
return |
||||||
|
} |
||||||
|
|
||||||
|
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
|
||||||
|
|
||||||
|
func Close(fd int) (err error) { |
||||||
|
r0, _, e1 := Syscall(SYS_CLOSE, uintptr(fd), 0, 0) |
||||||
|
if int32(r0) == -1 { |
||||||
|
err = e1 |
||||||
|
} |
||||||
|
return |
||||||
|
} |
||||||
|
|
||||||
|
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
|
||||||
|
|
||||||
|
func Fstat(fd int, edir []byte) (n int, err error) { |
||||||
|
var _p0 unsafe.Pointer |
||||||
|
if len(edir) > 0 { |
||||||
|
_p0 = unsafe.Pointer(&edir[0]) |
||||||
|
} else { |
||||||
|
_p0 = unsafe.Pointer(&_zero) |
||||||
|
} |
||||||
|
r0, _, e1 := Syscall(SYS_FSTAT, uintptr(fd), uintptr(_p0), uintptr(len(edir))) |
||||||
|
n = int(r0) |
||||||
|
if int32(r0) == -1 { |
||||||
|
err = e1 |
||||||
|
} |
||||||
|
return |
||||||
|
} |
||||||
|
|
||||||
|
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
|
||||||
|
|
||||||
|
func Fwstat(fd int, edir []byte) (err error) { |
||||||
|
var _p0 unsafe.Pointer |
||||||
|
if len(edir) > 0 { |
||||||
|
_p0 = unsafe.Pointer(&edir[0]) |
||||||
|
} else { |
||||||
|
_p0 = unsafe.Pointer(&_zero) |
||||||
|
} |
||||||
|
r0, _, e1 := Syscall(SYS_FWSTAT, uintptr(fd), uintptr(_p0), uintptr(len(edir))) |
||||||
|
if int32(r0) == -1 { |
||||||
|
err = e1 |
||||||
|
} |
||||||
|
return |
||||||
|
} |
@ -0,0 +1,284 @@ |
|||||||
|
// go run mksyscall.go -l32 -plan9 -tags plan9,amd64 syscall_plan9.go
|
||||||
|
// Code generated by the command above; see README.md. DO NOT EDIT.
|
||||||
|
|
||||||
|
// +build plan9,amd64
|
||||||
|
|
||||||
|
package plan9 |
||||||
|
|
||||||
|
import "unsafe" |
||||||
|
|
||||||
|
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
|
||||||
|
|
||||||
|
func fd2path(fd int, buf []byte) (err error) { |
||||||
|
var _p0 unsafe.Pointer |
||||||
|
if len(buf) > 0 { |
||||||
|
_p0 = unsafe.Pointer(&buf[0]) |
||||||
|
} else { |
||||||
|
_p0 = unsafe.Pointer(&_zero) |
||||||
|
} |
||||||
|
r0, _, e1 := Syscall(SYS_FD2PATH, uintptr(fd), uintptr(_p0), uintptr(len(buf))) |
||||||
|
if int32(r0) == -1 { |
||||||
|
err = e1 |
||||||
|
} |
||||||
|
return |
||||||
|
} |
||||||
|
|
||||||
|
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
|
||||||
|
|
||||||
|
func pipe(p *[2]int32) (err error) { |
||||||
|
r0, _, e1 := Syscall(SYS_PIPE, uintptr(unsafe.Pointer(p)), 0, 0) |
||||||
|
if int32(r0) == -1 { |
||||||
|
err = e1 |
||||||
|
} |
||||||
|
return |
||||||
|
} |
||||||
|
|
||||||
|
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
|
||||||
|
|
||||||
|
func await(s []byte) (n int, err error) { |
||||||
|
var _p0 unsafe.Pointer |
||||||
|
if len(s) > 0 { |
||||||
|
_p0 = unsafe.Pointer(&s[0]) |
||||||
|
} else { |
||||||
|
_p0 = unsafe.Pointer(&_zero) |
||||||
|
} |
||||||
|
r0, _, e1 := Syscall(SYS_AWAIT, uintptr(_p0), uintptr(len(s)), 0) |
||||||
|
n = int(r0) |
||||||
|
if int32(r0) == -1 { |
||||||
|
err = e1 |
||||||
|
} |
||||||
|
return |
||||||
|
} |
||||||
|
|
||||||
|
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
|
||||||
|
|
||||||
|
func open(path string, mode int) (fd int, err error) { |
||||||
|
var _p0 *byte |
||||||
|
_p0, err = BytePtrFromString(path) |
||||||
|
if err != nil { |
||||||
|
return |
||||||
|
} |
||||||
|
r0, _, e1 := Syscall(SYS_OPEN, uintptr(unsafe.Pointer(_p0)), uintptr(mode), 0) |
||||||
|
fd = int(r0) |
||||||
|
if int32(r0) == -1 { |
||||||
|
err = e1 |
||||||
|
} |
||||||
|
return |
||||||
|
} |
||||||
|
|
||||||
|
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
|
||||||
|
|
||||||
|
func create(path string, mode int, perm uint32) (fd int, err error) { |
||||||
|
var _p0 *byte |
||||||
|
_p0, err = BytePtrFromString(path) |
||||||
|
if err != nil { |
||||||
|
return |
||||||
|
} |
||||||
|
r0, _, e1 := Syscall(SYS_CREATE, uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(perm)) |
||||||
|
fd = int(r0) |
||||||
|
if int32(r0) == -1 { |
||||||
|
err = e1 |
||||||
|
} |
||||||
|
return |
||||||
|
} |
||||||
|
|
||||||
|
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
|
||||||
|
|
||||||
|
func remove(path string) (err error) { |
||||||
|
var _p0 *byte |
||||||
|
_p0, err = BytePtrFromString(path) |
||||||
|
if err != nil { |
||||||
|
return |
||||||
|
} |
||||||
|
r0, _, e1 := Syscall(SYS_REMOVE, uintptr(unsafe.Pointer(_p0)), 0, 0) |
||||||
|
if int32(r0) == -1 { |
||||||
|
err = e1 |
||||||
|
} |
||||||
|
return |
||||||
|
} |
||||||
|
|
||||||
|
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
|
||||||
|
|
||||||
|
func stat(path string, edir []byte) (n int, err error) { |
||||||
|
var _p0 *byte |
||||||
|
_p0, err = BytePtrFromString(path) |
||||||
|
if err != nil { |
||||||
|
return |
||||||
|
} |
||||||
|
var _p1 unsafe.Pointer |
||||||
|
if len(edir) > 0 { |
||||||
|
_p1 = unsafe.Pointer(&edir[0]) |
||||||
|
} else { |
||||||
|
_p1 = unsafe.Pointer(&_zero) |
||||||
|
} |
||||||
|
r0, _, e1 := Syscall(SYS_STAT, uintptr(unsafe.Pointer(_p0)), uintptr(_p1), uintptr(len(edir))) |
||||||
|
n = int(r0) |
||||||
|
if int32(r0) == -1 { |
||||||
|
err = e1 |
||||||
|
} |
||||||
|
return |
||||||
|
} |
||||||
|
|
||||||
|
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
|
||||||
|
|
||||||
|
func bind(name string, old string, flag int) (err error) { |
||||||
|
var _p0 *byte |
||||||
|
_p0, err = BytePtrFromString(name) |
||||||
|
if err != nil { |
||||||
|
return |
||||||
|
} |
||||||
|
var _p1 *byte |
||||||
|
_p1, err = BytePtrFromString(old) |
||||||
|
if err != nil { |
||||||
|
return |
||||||
|
} |
||||||
|
r0, _, e1 := Syscall(SYS_BIND, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), uintptr(flag)) |
||||||
|
if int32(r0) == -1 { |
||||||
|
err = e1 |
||||||
|
} |
||||||
|
return |
||||||
|
} |
||||||
|
|
||||||
|
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
|
||||||
|
|
||||||
|
func mount(fd int, afd int, old string, flag int, aname string) (err error) { |
||||||
|
var _p0 *byte |
||||||
|
_p0, err = BytePtrFromString(old) |
||||||
|
if err != nil { |
||||||
|
return |
||||||
|
} |
||||||
|
var _p1 *byte |
||||||
|
_p1, err = BytePtrFromString(aname) |
||||||
|
if err != nil { |
||||||
|
return |
||||||
|
} |
||||||
|
r0, _, e1 := Syscall6(SYS_MOUNT, uintptr(fd), uintptr(afd), uintptr(unsafe.Pointer(_p0)), uintptr(flag), uintptr(unsafe.Pointer(_p1)), 0) |
||||||
|
if int32(r0) == -1 { |
||||||
|
err = e1 |
||||||
|
} |
||||||
|
return |
||||||
|
} |
||||||
|
|
||||||
|
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
|
||||||
|
|
||||||
|
func wstat(path string, edir []byte) (err error) { |
||||||
|
var _p0 *byte |
||||||
|
_p0, err = BytePtrFromString(path) |
||||||
|
if err != nil { |
||||||
|
return |
||||||
|
} |
||||||
|
var _p1 unsafe.Pointer |
||||||
|
if len(edir) > 0 { |
||||||
|
_p1 = unsafe.Pointer(&edir[0]) |
||||||
|
} else { |
||||||
|
_p1 = unsafe.Pointer(&_zero) |
||||||
|
} |
||||||
|
r0, _, e1 := Syscall(SYS_WSTAT, uintptr(unsafe.Pointer(_p0)), uintptr(_p1), uintptr(len(edir))) |
||||||
|
if int32(r0) == -1 { |
||||||
|
err = e1 |
||||||
|
} |
||||||
|
return |
||||||
|
} |
||||||
|
|
||||||
|
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
|
||||||
|
|
||||||
|
func chdir(path string) (err error) { |
||||||
|
var _p0 *byte |
||||||
|
_p0, err = BytePtrFromString(path) |
||||||
|
if err != nil { |
||||||
|
return |
||||||
|
} |
||||||
|
r0, _, e1 := Syscall(SYS_CHDIR, uintptr(unsafe.Pointer(_p0)), 0, 0) |
||||||
|
if int32(r0) == -1 { |
||||||
|
err = e1 |
||||||
|
} |
||||||
|
return |
||||||
|
} |
||||||
|
|
||||||
|
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
|
||||||
|
|
||||||
|
func Dup(oldfd int, newfd int) (fd int, err error) { |
||||||
|
r0, _, e1 := Syscall(SYS_DUP, uintptr(oldfd), uintptr(newfd), 0) |
||||||
|
fd = int(r0) |
||||||
|
if int32(r0) == -1 { |
||||||
|
err = e1 |
||||||
|
} |
||||||
|
return |
||||||
|
} |
||||||
|
|
||||||
|
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
|
||||||
|
|
||||||
|
func Pread(fd int, p []byte, offset int64) (n int, err error) { |
||||||
|
var _p0 unsafe.Pointer |
||||||
|
if len(p) > 0 { |
||||||
|
_p0 = unsafe.Pointer(&p[0]) |
||||||
|
} else { |
||||||
|
_p0 = unsafe.Pointer(&_zero) |
||||||
|
} |
||||||
|
r0, _, e1 := Syscall6(SYS_PREAD, uintptr(fd), uintptr(_p0), uintptr(len(p)), uintptr(offset), uintptr(offset>>32), 0) |
||||||
|
n = int(r0) |
||||||
|
if int32(r0) == -1 { |
||||||
|
err = e1 |
||||||
|
} |
||||||
|
return |
||||||
|
} |
||||||
|
|
||||||
|
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
|
||||||
|
|
||||||
|
func Pwrite(fd int, p []byte, offset int64) (n int, err error) { |
||||||
|
var _p0 unsafe.Pointer |
||||||
|
if len(p) > 0 { |
||||||
|
_p0 = unsafe.Pointer(&p[0]) |
||||||
|
} else { |
||||||
|
_p0 = unsafe.Pointer(&_zero) |
||||||
|
} |
||||||
|
r0, _, e1 := Syscall6(SYS_PWRITE, uintptr(fd), uintptr(_p0), uintptr(len(p)), uintptr(offset), uintptr(offset>>32), 0) |
||||||
|
n = int(r0) |
||||||
|
if int32(r0) == -1 { |
||||||
|
err = e1 |
||||||
|
} |
||||||
|
return |
||||||
|
} |
||||||
|
|
||||||
|
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
|
||||||
|
|
||||||
|
func Close(fd int) (err error) { |
||||||
|
r0, _, e1 := Syscall(SYS_CLOSE, uintptr(fd), 0, 0) |
||||||
|
if int32(r0) == -1 { |
||||||
|
err = e1 |
||||||
|
} |
||||||
|
return |
||||||
|
} |
||||||
|
|
||||||
|
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
|
||||||
|
|
||||||
|
func Fstat(fd int, edir []byte) (n int, err error) { |
||||||
|
var _p0 unsafe.Pointer |
||||||
|
if len(edir) > 0 { |
||||||
|
_p0 = unsafe.Pointer(&edir[0]) |
||||||
|
} else { |
||||||
|
_p0 = unsafe.Pointer(&_zero) |
||||||
|
} |
||||||
|
r0, _, e1 := Syscall(SYS_FSTAT, uintptr(fd), uintptr(_p0), uintptr(len(edir))) |
||||||
|
n = int(r0) |
||||||
|
if int32(r0) == -1 { |
||||||
|
err = e1 |
||||||
|
} |
||||||
|
return |
||||||
|
} |
||||||
|
|
||||||
|
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
|
||||||
|
|
||||||
|
func Fwstat(fd int, edir []byte) (err error) { |
||||||
|
var _p0 unsafe.Pointer |
||||||
|
if len(edir) > 0 { |
||||||
|
_p0 = unsafe.Pointer(&edir[0]) |
||||||
|
} else { |
||||||
|
_p0 = unsafe.Pointer(&_zero) |
||||||
|
} |
||||||
|
r0, _, e1 := Syscall(SYS_FWSTAT, uintptr(fd), uintptr(_p0), uintptr(len(edir))) |
||||||
|
if int32(r0) == -1 { |
||||||
|
err = e1 |
||||||
|
} |
||||||
|
return |
||||||
|
} |
@ -0,0 +1,284 @@ |
|||||||
|
// go run mksyscall.go -l32 -plan9 -tags plan9,arm syscall_plan9.go
|
||||||
|
// Code generated by the command above; see README.md. DO NOT EDIT.
|
||||||
|
|
||||||
|
// +build plan9,arm
|
||||||
|
|
||||||
|
package plan9 |
||||||
|
|
||||||
|
import "unsafe" |
||||||
|
|
||||||
|
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
|
||||||
|
|
||||||
|
func fd2path(fd int, buf []byte) (err error) { |
||||||
|
var _p0 unsafe.Pointer |
||||||
|
if len(buf) > 0 { |
||||||
|
_p0 = unsafe.Pointer(&buf[0]) |
||||||
|
} else { |
||||||
|
_p0 = unsafe.Pointer(&_zero) |
||||||
|
} |
||||||
|
r0, _, e1 := Syscall(SYS_FD2PATH, uintptr(fd), uintptr(_p0), uintptr(len(buf))) |
||||||
|
if int32(r0) == -1 { |
||||||
|
err = e1 |
||||||
|
} |
||||||
|
return |
||||||
|
} |
||||||
|
|
||||||
|
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
|
||||||
|
|
||||||
|
func pipe(p *[2]int32) (err error) { |
||||||
|
r0, _, e1 := Syscall(SYS_PIPE, uintptr(unsafe.Pointer(p)), 0, 0) |
||||||
|
if int32(r0) == -1 { |
||||||
|
err = e1 |
||||||
|
} |
||||||
|
return |
||||||
|
} |
||||||
|
|
||||||
|
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
|
||||||
|
|
||||||
|
func await(s []byte) (n int, err error) { |
||||||
|
var _p0 unsafe.Pointer |
||||||
|
if len(s) > 0 { |
||||||
|
_p0 = unsafe.Pointer(&s[0]) |
||||||
|
} else { |
||||||
|
_p0 = unsafe.Pointer(&_zero) |
||||||
|
} |
||||||
|
r0, _, e1 := Syscall(SYS_AWAIT, uintptr(_p0), uintptr(len(s)), 0) |
||||||
|
n = int(r0) |
||||||
|
if int32(r0) == -1 { |
||||||
|
err = e1 |
||||||
|
} |
||||||
|
return |
||||||
|
} |
||||||
|
|
||||||
|
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
|
||||||
|
|
||||||
|
func open(path string, mode int) (fd int, err error) { |
||||||
|
var _p0 *byte |
||||||
|
_p0, err = BytePtrFromString(path) |
||||||
|
if err != nil { |
||||||
|
return |
||||||
|
} |
||||||
|
r0, _, e1 := Syscall(SYS_OPEN, uintptr(unsafe.Pointer(_p0)), uintptr(mode), 0) |
||||||
|
fd = int(r0) |
||||||
|
if int32(r0) == -1 { |
||||||
|
err = e1 |
||||||
|
} |
||||||
|
return |
||||||
|
} |
||||||
|
|
||||||
|
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
|
||||||
|
|
||||||
|
func create(path string, mode int, perm uint32) (fd int, err error) { |
||||||
|
var _p0 *byte |
||||||
|
_p0, err = BytePtrFromString(path) |
||||||
|
if err != nil { |
||||||
|
return |
||||||
|
} |
||||||
|
r0, _, e1 := Syscall(SYS_CREATE, uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(perm)) |
||||||
|
fd = int(r0) |
||||||
|
if int32(r0) == -1 { |
||||||
|
err = e1 |
||||||
|
} |
||||||
|
return |
||||||
|
} |
||||||
|
|
||||||
|
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
|
||||||
|
|
||||||
|
func remove(path string) (err error) { |
||||||
|
var _p0 *byte |
||||||
|
_p0, err = BytePtrFromString(path) |
||||||
|
if err != nil { |
||||||
|
return |
||||||
|
} |
||||||
|
r0, _, e1 := Syscall(SYS_REMOVE, uintptr(unsafe.Pointer(_p0)), 0, 0) |
||||||
|
if int32(r0) == -1 { |
||||||
|
err = e1 |
||||||
|
} |
||||||
|
return |
||||||
|
} |
||||||
|
|
||||||
|
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
|
||||||
|
|
||||||
|
func stat(path string, edir []byte) (n int, err error) { |
||||||
|
var _p0 *byte |
||||||
|
_p0, err = BytePtrFromString(path) |
||||||
|
if err != nil { |
||||||
|
return |
||||||
|
} |
||||||
|
var _p1 unsafe.Pointer |
||||||
|
if len(edir) > 0 { |
||||||
|
_p1 = unsafe.Pointer(&edir[0]) |
||||||
|
} else { |
||||||
|
_p1 = unsafe.Pointer(&_zero) |
||||||
|
} |
||||||
|
r0, _, e1 := Syscall(SYS_STAT, uintptr(unsafe.Pointer(_p0)), uintptr(_p1), uintptr(len(edir))) |
||||||
|
n = int(r0) |
||||||
|
if int32(r0) == -1 { |
||||||
|
err = e1 |
||||||
|
} |
||||||
|
return |
||||||
|
} |
||||||
|
|
||||||
|
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
|
||||||
|
|
||||||
|
func bind(name string, old string, flag int) (err error) { |
||||||
|
var _p0 *byte |
||||||
|
_p0, err = BytePtrFromString(name) |
||||||
|
if err != nil { |
||||||
|
return |
||||||
|
} |
||||||
|
var _p1 *byte |
||||||
|
_p1, err = BytePtrFromString(old) |
||||||
|
if err != nil { |
||||||
|
return |
||||||
|
} |
||||||
|
r0, _, e1 := Syscall(SYS_BIND, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), uintptr(flag)) |
||||||
|
if int32(r0) == -1 { |
||||||
|
err = e1 |
||||||
|
} |
||||||
|
return |
||||||
|
} |
||||||
|
|
||||||
|
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
|
||||||
|
|
||||||
|
func mount(fd int, afd int, old string, flag int, aname string) (err error) { |
||||||
|
var _p0 *byte |
||||||
|
_p0, err = BytePtrFromString(old) |
||||||
|
if err != nil { |
||||||
|
return |
||||||
|
} |
||||||
|
var _p1 *byte |
||||||
|
_p1, err = BytePtrFromString(aname) |
||||||
|
if err != nil { |
||||||
|
return |
||||||
|
} |
||||||
|
r0, _, e1 := Syscall6(SYS_MOUNT, uintptr(fd), uintptr(afd), uintptr(unsafe.Pointer(_p0)), uintptr(flag), uintptr(unsafe.Pointer(_p1)), 0) |
||||||
|
if int32(r0) == -1 { |
||||||
|
err = e1 |
||||||
|
} |
||||||
|
return |
||||||
|
} |
||||||
|
|
||||||
|
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
|
||||||
|
|
||||||
|
func wstat(path string, edir []byte) (err error) { |
||||||
|
var _p0 *byte |
||||||
|
_p0, err = BytePtrFromString(path) |
||||||
|
if err != nil { |
||||||
|
return |
||||||
|
} |
||||||
|
var _p1 unsafe.Pointer |
||||||
|
if len(edir) > 0 { |
||||||
|
_p1 = unsafe.Pointer(&edir[0]) |
||||||
|
} else { |
||||||
|
_p1 = unsafe.Pointer(&_zero) |
||||||
|
} |
||||||
|
r0, _, e1 := Syscall(SYS_WSTAT, uintptr(unsafe.Pointer(_p0)), uintptr(_p1), uintptr(len(edir))) |
||||||
|
if int32(r0) == -1 { |
||||||
|
err = e1 |
||||||
|
} |
||||||
|
return |
||||||
|
} |
||||||
|
|
||||||
|
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
|
||||||
|
|
||||||
|
func chdir(path string) (err error) { |
||||||
|
var _p0 *byte |
||||||
|
_p0, err = BytePtrFromString(path) |
||||||
|
if err != nil { |
||||||
|
return |
||||||
|
} |
||||||
|
r0, _, e1 := Syscall(SYS_CHDIR, uintptr(unsafe.Pointer(_p0)), 0, 0) |
||||||
|
if int32(r0) == -1 { |
||||||
|
err = e1 |
||||||
|
} |
||||||
|
return |
||||||
|
} |
||||||
|
|
||||||
|
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
|
||||||
|
|
||||||
|
func Dup(oldfd int, newfd int) (fd int, err error) { |
||||||
|
r0, _, e1 := Syscall(SYS_DUP, uintptr(oldfd), uintptr(newfd), 0) |
||||||
|
fd = int(r0) |
||||||
|
if int32(r0) == -1 { |
||||||
|
err = e1 |
||||||
|
} |
||||||
|
return |
||||||
|
} |
||||||
|
|
||||||
|
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
|
||||||
|
|
||||||
|
func Pread(fd int, p []byte, offset int64) (n int, err error) { |
||||||
|
var _p0 unsafe.Pointer |
||||||
|
if len(p) > 0 { |
||||||
|
_p0 = unsafe.Pointer(&p[0]) |
||||||
|
} else { |
||||||
|
_p0 = unsafe.Pointer(&_zero) |
||||||
|
} |
||||||
|
r0, _, e1 := Syscall6(SYS_PREAD, uintptr(fd), uintptr(_p0), uintptr(len(p)), uintptr(offset), uintptr(offset>>32), 0) |
||||||
|
n = int(r0) |
||||||
|
if int32(r0) == -1 { |
||||||
|
err = e1 |
||||||
|
} |
||||||
|
return |
||||||
|
} |
||||||
|
|
||||||
|
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
|
||||||
|
|
||||||
|
func Pwrite(fd int, p []byte, offset int64) (n int, err error) { |
||||||
|
var _p0 unsafe.Pointer |
||||||
|
if len(p) > 0 { |
||||||
|
_p0 = unsafe.Pointer(&p[0]) |
||||||
|
} else { |
||||||
|
_p0 = unsafe.Pointer(&_zero) |
||||||
|
} |
||||||
|
r0, _, e1 := Syscall6(SYS_PWRITE, uintptr(fd), uintptr(_p0), uintptr(len(p)), uintptr(offset), uintptr(offset>>32), 0) |
||||||
|
n = int(r0) |
||||||
|
if int32(r0) == -1 { |
||||||
|
err = e1 |
||||||
|
} |
||||||
|
return |
||||||
|
} |
||||||
|
|
||||||
|
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
|
||||||
|
|
||||||
|
func Close(fd int) (err error) { |
||||||
|
r0, _, e1 := Syscall(SYS_CLOSE, uintptr(fd), 0, 0) |
||||||
|
if int32(r0) == -1 { |
||||||
|
err = e1 |
||||||
|
} |
||||||
|
return |
||||||
|
} |
||||||
|
|
||||||
|
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
|
||||||
|
|
||||||
|
func Fstat(fd int, edir []byte) (n int, err error) { |
||||||
|
var _p0 unsafe.Pointer |
||||||
|
if len(edir) > 0 { |
||||||
|
_p0 = unsafe.Pointer(&edir[0]) |
||||||
|
} else { |
||||||
|
_p0 = unsafe.Pointer(&_zero) |
||||||
|
} |
||||||
|
r0, _, e1 := Syscall(SYS_FSTAT, uintptr(fd), uintptr(_p0), uintptr(len(edir))) |
||||||
|
n = int(r0) |
||||||
|
if int32(r0) == -1 { |
||||||
|
err = e1 |
||||||
|
} |
||||||
|
return |
||||||
|
} |
||||||
|
|
||||||
|
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
|
||||||
|
|
||||||
|
func Fwstat(fd int, edir []byte) (err error) { |
||||||
|
var _p0 unsafe.Pointer |
||||||
|
if len(edir) > 0 { |
||||||
|
_p0 = unsafe.Pointer(&edir[0]) |
||||||
|
} else { |
||||||
|
_p0 = unsafe.Pointer(&_zero) |
||||||
|
} |
||||||
|
r0, _, e1 := Syscall(SYS_FWSTAT, uintptr(fd), uintptr(_p0), uintptr(len(edir))) |
||||||
|
if int32(r0) == -1 { |
||||||
|
err = e1 |
||||||
|
} |
||||||
|
return |
||||||
|
} |
@ -0,0 +1,49 @@ |
|||||||
|
// mksysnum_plan9.sh /opt/plan9/sys/src/libc/9syscall/sys.h
|
||||||
|
// MACHINE GENERATED BY THE ABOVE COMMAND; DO NOT EDIT
|
||||||
|
|
||||||
|
package plan9 |
||||||
|
|
||||||
|
const ( |
||||||
|
SYS_SYSR1 = 0 |
||||||
|
SYS_BIND = 2 |
||||||
|
SYS_CHDIR = 3 |
||||||
|
SYS_CLOSE = 4 |
||||||
|
SYS_DUP = 5 |
||||||
|
SYS_ALARM = 6 |
||||||
|
SYS_EXEC = 7 |
||||||
|
SYS_EXITS = 8 |
||||||
|
SYS_FAUTH = 10 |
||||||
|
SYS_SEGBRK = 12 |
||||||
|
SYS_OPEN = 14 |
||||||
|
SYS_OSEEK = 16 |
||||||
|
SYS_SLEEP = 17 |
||||||
|
SYS_RFORK = 19 |
||||||
|
SYS_PIPE = 21 |
||||||
|
SYS_CREATE = 22 |
||||||
|
SYS_FD2PATH = 23 |
||||||
|
SYS_BRK_ = 24 |
||||||
|
SYS_REMOVE = 25 |
||||||
|
SYS_NOTIFY = 28 |
||||||
|
SYS_NOTED = 29 |
||||||
|
SYS_SEGATTACH = 30 |
||||||
|
SYS_SEGDETACH = 31 |
||||||
|
SYS_SEGFREE = 32 |
||||||
|
SYS_SEGFLUSH = 33 |
||||||
|
SYS_RENDEZVOUS = 34 |
||||||
|
SYS_UNMOUNT = 35 |
||||||
|
SYS_SEMACQUIRE = 37 |
||||||
|
SYS_SEMRELEASE = 38 |
||||||
|
SYS_SEEK = 39 |
||||||
|
SYS_FVERSION = 40 |
||||||
|
SYS_ERRSTR = 41 |
||||||
|
SYS_STAT = 42 |
||||||
|
SYS_FSTAT = 43 |
||||||
|
SYS_WSTAT = 44 |
||||||
|
SYS_FWSTAT = 45 |
||||||
|
SYS_MOUNT = 46 |
||||||
|
SYS_AWAIT = 47 |
||||||
|
SYS_PREAD = 50 |
||||||
|
SYS_PWRITE = 51 |
||||||
|
SYS_TSEMACQUIRE = 52 |
||||||
|
SYS_NSEC = 53 |
||||||
|
) |
@ -1,3 +1,3 @@ |
|||||||
# This source code refers to The Go Authors for copyright purposes. |
# This source code refers to The Go Authors for copyright purposes. |
||||||
# The master list of authors is in the main Go distribution, |
# The master list of authors is in the main Go distribution, |
||||||
# visible at https://tip.golang.org/AUTHORS. |
# visible at http://tip.golang.org/AUTHORS. |
@ -0,0 +1,26 @@ |
|||||||
|
# Contributing to Go |
||||||
|
|
||||||
|
Go is an open source project. |
||||||
|
|
||||||
|
It is the work of hundreds of contributors. We appreciate your help! |
||||||
|
|
||||||
|
## Filing issues |
||||||
|
|
||||||
|
When [filing an issue](https://golang.org/issue/new), make sure to answer these five questions: |
||||||
|
|
||||||
|
1. What version of Go are you using (`go version`)? |
||||||
|
2. What operating system and processor architecture are you using? |
||||||
|
3. What did you do? |
||||||
|
4. What did you expect to see? |
||||||
|
5. What did you see instead? |
||||||
|
|
||||||
|
General questions should go to the [golang-nuts mailing list](https://groups.google.com/group/golang-nuts) instead of the issue tracker. |
||||||
|
The gophers there will answer or ask you to file an issue if you've tripped over a bug. |
||||||
|
|
||||||
|
## Contributing code |
||||||
|
|
||||||
|
Please read the [Contribution Guidelines](https://golang.org/doc/contribute.html) |
||||||
|
before sending patches. |
||||||
|
|
||||||
|
Unless otherwise noted, the Go source files are distributed under |
||||||
|
the BSD-style license found in the LICENSE file. |
2
vendor/golang.org/x/crypto/CONTRIBUTORS → vendor/golang.org/x/term/CONTRIBUTORS
generated
vendored
2
vendor/golang.org/x/crypto/CONTRIBUTORS → vendor/golang.org/x/term/CONTRIBUTORS
generated
vendored
@ -1,3 +1,3 @@ |
|||||||
# This source code was written by the Go contributors. |
# This source code was written by the Go contributors. |
||||||
# The master list of contributors is in the main Go distribution, |
# The master list of contributors is in the main Go distribution, |
||||||
# visible at https://tip.golang.org/CONTRIBUTORS. |
# visible at http://tip.golang.org/CONTRIBUTORS. |
@ -0,0 +1,19 @@ |
|||||||
|
# Go terminal/console support |
||||||
|
|
||||||
|
[![Go Reference](https://pkg.go.dev/badge/golang.org/x/term.svg)](https://pkg.go.dev/golang.org/x/term) |
||||||
|
|
||||||
|
This repository provides Go terminal and console support packages. |
||||||
|
|
||||||
|
## Download/Install |
||||||
|
|
||||||
|
The easiest way to install is to run `go get -u golang.org/x/term`. You can |
||||||
|
also manually git clone the repository to `$GOPATH/src/golang.org/x/term`. |
||||||
|
|
||||||
|
## Report Issues / Send Patches |
||||||
|
|
||||||
|
This repository uses Gerrit for code changes. To learn how to submit changes to |
||||||
|
this repository, see https://golang.org/doc/contribute.html. |
||||||
|
|
||||||
|
The main issue tracker for the term repository is located at |
||||||
|
https://github.com/golang/go/issues. Prefix your issue with "x/term:" in the |
||||||
|
subject line, so it is easy to find. |
@ -0,0 +1,5 @@ |
|||||||
|
module golang.org/x/term |
||||||
|
|
||||||
|
go 1.11 |
||||||
|
|
||||||
|
require golang.org/x/sys v0.0.0-20201119102817-f84b799fce68 |
@ -0,0 +1,2 @@ |
|||||||
|
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68 h1:nxC68pudNYkKU6jWhgrqdreuFiOQWj1Fs7T3VrH4Pjw= |
||||||
|
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= |
40
vendor/golang.org/x/crypto/ssh/terminal/util_plan9.go → vendor/golang.org/x/term/term.go
generated
vendored
40
vendor/golang.org/x/crypto/ssh/terminal/util_plan9.go → vendor/golang.org/x/term/term.go
generated
vendored
@ -1,58 +1,58 @@ |
|||||||
// Copyright 2016 The Go Authors. All rights reserved.
|
// Copyright 2019 The Go Authors. All rights reserved.
|
||||||
// Use of this source code is governed by a BSD-style
|
// Use of this source code is governed by a BSD-style
|
||||||
// license that can be found in the LICENSE file.
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
// Package terminal provides support functions for dealing with terminals, as
|
// Package term provides support functions for dealing with terminals, as
|
||||||
// commonly found on UNIX systems.
|
// commonly found on UNIX systems.
|
||||||
//
|
//
|
||||||
// Putting a terminal into raw mode is the most common requirement:
|
// Putting a terminal into raw mode is the most common requirement:
|
||||||
//
|
//
|
||||||
// oldState, err := terminal.MakeRaw(0)
|
// oldState, err := term.MakeRaw(0)
|
||||||
// if err != nil {
|
// if err != nil {
|
||||||
// panic(err)
|
// panic(err)
|
||||||
// }
|
// }
|
||||||
// defer terminal.Restore(0, oldState)
|
// defer term.Restore(0, oldState)
|
||||||
package terminal |
package term |
||||||
|
|
||||||
import ( |
// State contains the state of a terminal.
|
||||||
"fmt" |
type State struct { |
||||||
"runtime" |
state |
||||||
) |
} |
||||||
|
|
||||||
type State struct{} |
|
||||||
|
|
||||||
// IsTerminal returns whether the given file descriptor is a terminal.
|
// IsTerminal returns whether the given file descriptor is a terminal.
|
||||||
func IsTerminal(fd int) bool { |
func IsTerminal(fd int) bool { |
||||||
return false |
return isTerminal(fd) |
||||||
} |
} |
||||||
|
|
||||||
// MakeRaw put the terminal connected to the given file descriptor into raw
|
// MakeRaw puts the terminal connected to the given file descriptor into raw
|
||||||
// mode and returns the previous state of the terminal so that it can be
|
// mode and returns the previous state of the terminal so that it can be
|
||||||
// restored.
|
// restored.
|
||||||
func MakeRaw(fd int) (*State, error) { |
func MakeRaw(fd int) (*State, error) { |
||||||
return nil, fmt.Errorf("terminal: MakeRaw not implemented on %s/%s", runtime.GOOS, runtime.GOARCH) |
return makeRaw(fd) |
||||||
} |
} |
||||||
|
|
||||||
// GetState returns the current state of a terminal which may be useful to
|
// GetState returns the current state of a terminal which may be useful to
|
||||||
// restore the terminal after a signal.
|
// restore the terminal after a signal.
|
||||||
func GetState(fd int) (*State, error) { |
func GetState(fd int) (*State, error) { |
||||||
return nil, fmt.Errorf("terminal: GetState not implemented on %s/%s", runtime.GOOS, runtime.GOARCH) |
return getState(fd) |
||||||
} |
} |
||||||
|
|
||||||
// Restore restores the terminal connected to the given file descriptor to a
|
// Restore restores the terminal connected to the given file descriptor to a
|
||||||
// previous state.
|
// previous state.
|
||||||
func Restore(fd int, state *State) error { |
func Restore(fd int, oldState *State) error { |
||||||
return fmt.Errorf("terminal: Restore not implemented on %s/%s", runtime.GOOS, runtime.GOARCH) |
return restore(fd, oldState) |
||||||
} |
} |
||||||
|
|
||||||
// GetSize returns the dimensions of the given terminal.
|
// GetSize returns the visible dimensions of the given terminal.
|
||||||
|
//
|
||||||
|
// These dimensions don't include any scrollback buffer height.
|
||||||
func GetSize(fd int) (width, height int, err error) { |
func GetSize(fd int) (width, height int, err error) { |
||||||
return 0, 0, fmt.Errorf("terminal: GetSize not implemented on %s/%s", runtime.GOOS, runtime.GOARCH) |
return getSize(fd) |
||||||
} |
} |
||||||
|
|
||||||
// ReadPassword reads a line of input from a terminal without local echo. This
|
// ReadPassword reads a line of input from a terminal without local echo. This
|
||||||
// is commonly used for inputting passwords and other sensitive data. The slice
|
// is commonly used for inputting passwords and other sensitive data. The slice
|
||||||
// returned does not include the \n.
|
// returned does not include the \n.
|
||||||
func ReadPassword(fd int) ([]byte, error) { |
func ReadPassword(fd int) ([]byte, error) { |
||||||
return nil, fmt.Errorf("terminal: ReadPassword not implemented on %s/%s", runtime.GOOS, runtime.GOARCH) |
return readPassword(fd) |
||||||
} |
} |
@ -0,0 +1,42 @@ |
|||||||
|
// Copyright 2019 The Go Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
package term |
||||||
|
|
||||||
|
import ( |
||||||
|
"fmt" |
||||||
|
"runtime" |
||||||
|
|
||||||
|
"golang.org/x/sys/plan9" |
||||||
|
) |
||||||
|
|
||||||
|
type state struct{} |
||||||
|
|
||||||
|
func isTerminal(fd int) bool { |
||||||
|
path, err := plan9.Fd2path(fd) |
||||||
|
if err != nil { |
||||||
|
return false |
||||||
|
} |
||||||
|
return path == "/dev/cons" || path == "/mnt/term/dev/cons" |
||||||
|
} |
||||||
|
|
||||||
|
func makeRaw(fd int) (*State, error) { |
||||||
|
return nil, fmt.Errorf("terminal: MakeRaw not implemented on %s/%s", runtime.GOOS, runtime.GOARCH) |
||||||
|
} |
||||||
|
|
||||||
|
func getState(fd int) (*State, error) { |
||||||
|
return nil, fmt.Errorf("terminal: GetState not implemented on %s/%s", runtime.GOOS, runtime.GOARCH) |
||||||
|
} |
||||||
|
|
||||||
|
func restore(fd int, state *State) error { |
||||||
|
return fmt.Errorf("terminal: Restore not implemented on %s/%s", runtime.GOOS, runtime.GOARCH) |
||||||
|
} |
||||||
|
|
||||||
|
func getSize(fd int) (width, height int, err error) { |
||||||
|
return 0, 0, fmt.Errorf("terminal: GetSize not implemented on %s/%s", runtime.GOOS, runtime.GOARCH) |
||||||
|
} |
||||||
|
|
||||||
|
func readPassword(fd int) ([]byte, error) { |
||||||
|
return nil, fmt.Errorf("terminal: ReadPassword not implemented on %s/%s", runtime.GOOS, runtime.GOARCH) |
||||||
|
} |
48
vendor/golang.org/x/crypto/ssh/terminal/util.go → vendor/golang.org/x/term/term_unix.go
generated
vendored
48
vendor/golang.org/x/crypto/ssh/terminal/util.go → vendor/golang.org/x/term/term_unix.go
generated
vendored
@ -1,8 +1,8 @@ |
|||||||
// Copyright 2013 The Go Authors. All rights reserved.
|
// Copyright 2019 The Go Authors. All rights reserved.
|
||||||
// Use of this source code is governed by a BSD-style
|
// Use of this source code is governed by a BSD-style
|
||||||
// license that can be found in the LICENSE file.
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
package terminal |
package term |
||||||
|
|
||||||
import "golang.org/x/sys/unix" |
import "golang.org/x/sys/unix" |
||||||
|
|
@ -1,10 +1,8 @@ |
|||||||
// Copyright 2018 The Go Authors. All rights reserved.
|
// Copyright 2019 The Go Authors. All rights reserved.
|
||||||
// Use of this source code is governed by a BSD-style
|
// Use of this source code is governed by a BSD-style
|
||||||
// license that can be found in the LICENSE file.
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
// +build aix
|
package term |
||||||
|
|
||||||
package terminal |
|
||||||
|
|
||||||
import "golang.org/x/sys/unix" |
import "golang.org/x/sys/unix" |
||||||
|
|
@ -0,0 +1,10 @@ |
|||||||
|
// Copyright 2020 The Go Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
package term |
||||||
|
|
||||||
|
import "golang.org/x/sys/unix" |
||||||
|
|
||||||
|
const ioctlReadTermios = unix.TCGETS |
||||||
|
const ioctlWriteTermios = unix.TCSETS |
@ -0,0 +1,39 @@ |
|||||||
|
// Copyright 2019 The Go Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
//go:build !aix && !darwin && !dragonfly && !freebsd && !linux && !netbsd && !openbsd && !zos && !windows && !solaris && !plan9
|
||||||
|
// +build !aix,!darwin,!dragonfly,!freebsd,!linux,!netbsd,!openbsd,!zos,!windows,!solaris,!plan9
|
||||||
|
|
||||||
|
package term |
||||||
|
|
||||||
|
import ( |
||||||
|
"fmt" |
||||||
|
"runtime" |
||||||
|
) |
||||||
|
|
||||||
|
type state struct{} |
||||||
|
|
||||||
|
func isTerminal(fd int) bool { |
||||||
|
return false |
||||||
|
} |
||||||
|
|
||||||
|
func makeRaw(fd int) (*State, error) { |
||||||
|
return nil, fmt.Errorf("terminal: MakeRaw not implemented on %s/%s", runtime.GOOS, runtime.GOARCH) |
||||||
|
} |
||||||
|
|
||||||
|
func getState(fd int) (*State, error) { |
||||||
|
return nil, fmt.Errorf("terminal: GetState not implemented on %s/%s", runtime.GOOS, runtime.GOARCH) |
||||||
|
} |
||||||
|
|
||||||
|
func restore(fd int, state *State) error { |
||||||
|
return fmt.Errorf("terminal: Restore not implemented on %s/%s", runtime.GOOS, runtime.GOARCH) |
||||||
|
} |
||||||
|
|
||||||
|
func getSize(fd int) (width, height int, err error) { |
||||||
|
return 0, 0, fmt.Errorf("terminal: GetSize not implemented on %s/%s", runtime.GOOS, runtime.GOARCH) |
||||||
|
} |
||||||
|
|
||||||
|
func readPassword(fd int) ([]byte, error) { |
||||||
|
return nil, fmt.Errorf("terminal: ReadPassword not implemented on %s/%s", runtime.GOOS, runtime.GOARCH) |
||||||
|
} |
@ -1,3 +1,3 @@ |
|||||||
[submodule "corpus"] |
[submodule "corpus"] |
||||||
path = corpus |
path = corpus |
||||||
url = git@github.com:inetaf/netaddr-corpus.git |
url = https://github.com/inetaf/netaddr-corpus.git |
||||||
|
@ -1,12 +1,33 @@ |
|||||||
github.com/dvyukov/go-fuzz v0.0.0-20201127111758-49e582c6c23d h1:e1v4V9Heb+c4xQCCONROFvlzNs6Gq8aRZRwt+WzSEqY= |
github.com/dvyukov/go-fuzz v0.0.0-20210103155950-6a8e9d1f2415 h1:q1oJaUPdmpDm/VyXosjgPgr6wS7c5iV2p0PwJD73bUI= |
||||||
github.com/dvyukov/go-fuzz v0.0.0-20201127111758-49e582c6c23d/go.mod h1:11Gm+ccJnvAhCNLlf5+cS9KjtbaD5I5zaZpFMsTHWTw= |
github.com/dvyukov/go-fuzz v0.0.0-20210103155950-6a8e9d1f2415/go.mod h1:11Gm+ccJnvAhCNLlf5+cS9KjtbaD5I5zaZpFMsTHWTw= |
||||||
go4.org/intern v0.0.0-20201223054237-ef8cbcb8edd7 h1:yeDrXaQ3VRXbTN7lHj70DxW4LdPow83MVwPPRjpP70U= |
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= |
||||||
go4.org/intern v0.0.0-20201223054237-ef8cbcb8edd7/go.mod h1:vLqJ+12kCw61iCWsPto0EOHhBS+o4rO5VIucbc9g2Cc= |
|
||||||
go4.org/intern v0.0.0-20210101010959-7cab76ca296a h1:28p852HIWWaOS019DYK/A3yTmpm1HJaUce63pvll4C8= |
|
||||||
go4.org/intern v0.0.0-20210101010959-7cab76ca296a/go.mod h1:vLqJ+12kCw61iCWsPto0EOHhBS+o4rO5VIucbc9g2Cc= |
|
||||||
go4.org/intern v0.0.0-20210108033219-3eb7198706b2 h1:VFTf+jjIgsldaz/Mr00VaCSswHJrI2hIjQygE/W4IMg= |
go4.org/intern v0.0.0-20210108033219-3eb7198706b2 h1:VFTf+jjIgsldaz/Mr00VaCSswHJrI2hIjQygE/W4IMg= |
||||||
go4.org/intern v0.0.0-20210108033219-3eb7198706b2/go.mod h1:vLqJ+12kCw61iCWsPto0EOHhBS+o4rO5VIucbc9g2Cc= |
go4.org/intern v0.0.0-20210108033219-3eb7198706b2/go.mod h1:vLqJ+12kCw61iCWsPto0EOHhBS+o4rO5VIucbc9g2Cc= |
||||||
go4.org/unsafe/assume-no-moving-gc v0.0.0-20201222175341-b30ae309168e h1:ExUmGi0ZsQmiVo9giDQqXkr7vreeXPMkOGIusfsfbzI= |
|
||||||
go4.org/unsafe/assume-no-moving-gc v0.0.0-20201222175341-b30ae309168e/go.mod h1:FftLjUGFEDu5k8lt0ddY+HcrH/qU/0qk+H8j9/nTl3E= |
go4.org/unsafe/assume-no-moving-gc v0.0.0-20201222175341-b30ae309168e/go.mod h1:FftLjUGFEDu5k8lt0ddY+HcrH/qU/0qk+H8j9/nTl3E= |
||||||
go4.org/unsafe/assume-no-moving-gc v0.0.0-20201222180813-1025295fd063 h1:1tk03FUNpulq2cuWpXZWj649rwJpk0d20rxWiopKRmc= |
go4.org/unsafe/assume-no-moving-gc v0.0.0-20201222180813-1025295fd063 h1:1tk03FUNpulq2cuWpXZWj649rwJpk0d20rxWiopKRmc= |
||||||
go4.org/unsafe/assume-no-moving-gc v0.0.0-20201222180813-1025295fd063/go.mod h1:FftLjUGFEDu5k8lt0ddY+HcrH/qU/0qk+H8j9/nTl3E= |
go4.org/unsafe/assume-no-moving-gc v0.0.0-20201222180813-1025295fd063/go.mod h1:FftLjUGFEDu5k8lt0ddY+HcrH/qU/0qk+H8j9/nTl3E= |
||||||
|
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= |
||||||
|
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= |
||||||
|
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= |
||||||
|
golang.org/x/mod v0.3.0 h1:RM4zey1++hCTbCVQfnWeKs9/IEsaBLA8vTkd0WVtmH4= |
||||||
|
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= |
||||||
|
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= |
||||||
|
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= |
||||||
|
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= |
||||||
|
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= |
||||||
|
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= |
||||||
|
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= |
||||||
|
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= |
||||||
|
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= |
||||||
|
golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4 h1:myAQVi0cGEoqQVR5POX+8RR2mrocKqNN1hmeMqhX27k= |
||||||
|
golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= |
||||||
|
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= |
||||||
|
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= |
||||||
|
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= |
||||||
|
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= |
||||||
|
golang.org/x/tools v0.1.0 h1:po9/4sTYwZU9lPhi1tOrb4hCv3qrhiQ77LZfGa2OjwY= |
||||||
|
golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0= |
||||||
|
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= |
||||||
|
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= |
||||||
|
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE= |
||||||
|
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= |
||||||
|
File diff suppressed because it is too large
Load Diff
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in new issue