summaryrefslogtreecommitdiff
path: root/vendor/github.com/Microsoft/hcsshim/internal/safefile
diff options
context:
space:
mode:
authorValentin Rothberg <rothberg@redhat.com>2019-01-08 14:52:57 +0100
committerValentin Rothberg <rothberg@redhat.com>2019-01-11 13:38:11 +0100
commitbd40dcfc2bc7c9014ea1f33482fb63aacbcdfe87 (patch)
tree5f06e4e289f16d9164d692590a3fe6541b5384cf /vendor/github.com/Microsoft/hcsshim/internal/safefile
parent545f24421247c9f6251a634764db3f8f8070a812 (diff)
downloadpodman-bd40dcfc2bc7c9014ea1f33482fb63aacbcdfe87.tar.gz
podman-bd40dcfc2bc7c9014ea1f33482fb63aacbcdfe87.tar.bz2
podman-bd40dcfc2bc7c9014ea1f33482fb63aacbcdfe87.zip
vendor: update everything
* If possible, update each dependency to the latest available version. * Use releases over commit IDs and avoid vendoring branches. Signed-off-by: Valentin Rothberg <rothberg@redhat.com>
Diffstat (limited to 'vendor/github.com/Microsoft/hcsshim/internal/safefile')
-rw-r--r--vendor/github.com/Microsoft/hcsshim/internal/safefile/safeopen.go431
-rw-r--r--vendor/github.com/Microsoft/hcsshim/internal/safefile/zsyscall_windows.go79
2 files changed, 510 insertions, 0 deletions
diff --git a/vendor/github.com/Microsoft/hcsshim/internal/safefile/safeopen.go b/vendor/github.com/Microsoft/hcsshim/internal/safefile/safeopen.go
new file mode 100644
index 000000000..0c0b1159f
--- /dev/null
+++ b/vendor/github.com/Microsoft/hcsshim/internal/safefile/safeopen.go
@@ -0,0 +1,431 @@
+package safefile
+
+import (
+ "errors"
+ "io"
+ "os"
+ "path/filepath"
+ "strings"
+ "syscall"
+ "unicode/utf16"
+ "unsafe"
+
+ "github.com/Microsoft/hcsshim/internal/longpath"
+
+ winio "github.com/Microsoft/go-winio"
+)
+
+//go:generate go run $GOROOT\src\syscall\mksyscall_windows.go -output zsyscall_windows.go safeopen.go
+
+//sys ntCreateFile(handle *uintptr, accessMask uint32, oa *objectAttributes, iosb *ioStatusBlock, allocationSize *uint64, fileAttributes uint32, shareAccess uint32, createDisposition uint32, createOptions uint32, eaBuffer *byte, eaLength uint32) (status uint32) = ntdll.NtCreateFile
+//sys ntSetInformationFile(handle uintptr, iosb *ioStatusBlock, information uintptr, length uint32, class uint32) (status uint32) = ntdll.NtSetInformationFile
+//sys rtlNtStatusToDosError(status uint32) (winerr error) = ntdll.RtlNtStatusToDosErrorNoTeb
+//sys localAlloc(flags uint32, size int) (ptr uintptr) = kernel32.LocalAlloc
+//sys localFree(ptr uintptr) = kernel32.LocalFree
+
+type ioStatusBlock struct {
+ Status, Information uintptr
+}
+
+type objectAttributes struct {
+ Length uintptr
+ RootDirectory uintptr
+ ObjectName uintptr
+ Attributes uintptr
+ SecurityDescriptor uintptr
+ SecurityQoS uintptr
+}
+
+type unicodeString struct {
+ Length uint16
+ MaximumLength uint16
+ Buffer uintptr
+}
+
+type fileLinkInformation struct {
+ ReplaceIfExists bool
+ RootDirectory uintptr
+ FileNameLength uint32
+ FileName [1]uint16
+}
+
+type fileDispositionInformationEx struct {
+ Flags uintptr
+}
+
+const (
+ _FileLinkInformation = 11
+ _FileDispositionInformationEx = 64
+
+ FILE_READ_ATTRIBUTES = 0x0080
+ FILE_WRITE_ATTRIBUTES = 0x0100
+ DELETE = 0x10000
+
+ FILE_OPEN = 1
+ FILE_CREATE = 2
+
+ FILE_DIRECTORY_FILE = 0x00000001
+ FILE_SYNCHRONOUS_IO_NONALERT = 0x00000020
+ FILE_DELETE_ON_CLOSE = 0x00001000
+ FILE_OPEN_FOR_BACKUP_INTENT = 0x00004000
+ FILE_OPEN_REPARSE_POINT = 0x00200000
+
+ FILE_DISPOSITION_DELETE = 0x00000001
+
+ _OBJ_DONT_REPARSE = 0x1000
+
+ _STATUS_REPARSE_POINT_ENCOUNTERED = 0xC000050B
+)
+
+func OpenRoot(path string) (*os.File, error) {
+ longpath, err := longpath.LongAbs(path)
+ if err != nil {
+ return nil, err
+ }
+ return winio.OpenForBackup(longpath, syscall.GENERIC_READ, syscall.FILE_SHARE_READ|syscall.FILE_SHARE_WRITE|syscall.FILE_SHARE_DELETE, syscall.OPEN_EXISTING)
+}
+
+func ntRelativePath(path string) ([]uint16, error) {
+ path = filepath.Clean(path)
+ if strings.Contains(":", path) {
+ // Since alternate data streams must follow the file they
+ // are attached to, finding one here (out of order) is invalid.
+ return nil, errors.New("path contains invalid character `:`")
+ }
+ fspath := filepath.FromSlash(path)
+ if len(fspath) > 0 && fspath[0] == '\\' {
+ return nil, errors.New("expected relative path")
+ }
+
+ path16 := utf16.Encode(([]rune)(fspath))
+ if len(path16) > 32767 {
+ return nil, syscall.ENAMETOOLONG
+ }
+
+ return path16, nil
+}
+
+// openRelativeInternal opens a relative path from the given root, failing if
+// any of the intermediate path components are reparse points.
+func openRelativeInternal(path string, root *os.File, accessMask uint32, shareFlags uint32, createDisposition uint32, flags uint32) (*os.File, error) {
+ var (
+ h uintptr
+ iosb ioStatusBlock
+ oa objectAttributes
+ )
+
+ path16, err := ntRelativePath(path)
+ if err != nil {
+ return nil, err
+ }
+
+ if root == nil || root.Fd() == 0 {
+ return nil, errors.New("missing root directory")
+ }
+
+ upathBuffer := localAlloc(0, int(unsafe.Sizeof(unicodeString{}))+len(path16)*2)
+ defer localFree(upathBuffer)
+
+ upath := (*unicodeString)(unsafe.Pointer(upathBuffer))
+ upath.Length = uint16(len(path16) * 2)
+ upath.MaximumLength = upath.Length
+ upath.Buffer = upathBuffer + unsafe.Sizeof(*upath)
+ copy((*[32768]uint16)(unsafe.Pointer(upath.Buffer))[:], path16)
+
+ oa.Length = unsafe.Sizeof(oa)
+ oa.ObjectName = upathBuffer
+ oa.RootDirectory = uintptr(root.Fd())
+ oa.Attributes = _OBJ_DONT_REPARSE
+ status := ntCreateFile(
+ &h,
+ accessMask|syscall.SYNCHRONIZE,
+ &oa,
+ &iosb,
+ nil,
+ 0,
+ shareFlags,
+ createDisposition,
+ FILE_OPEN_FOR_BACKUP_INTENT|FILE_SYNCHRONOUS_IO_NONALERT|flags,
+ nil,
+ 0,
+ )
+ if status != 0 {
+ return nil, rtlNtStatusToDosError(status)
+ }
+
+ fullPath, err := longpath.LongAbs(filepath.Join(root.Name(), path))
+ if err != nil {
+ syscall.Close(syscall.Handle(h))
+ return nil, err
+ }
+
+ return os.NewFile(h, fullPath), nil
+}
+
+// OpenRelative opens a relative path from the given root, failing if
+// any of the intermediate path components are reparse points.
+func OpenRelative(path string, root *os.File, accessMask uint32, shareFlags uint32, createDisposition uint32, flags uint32) (*os.File, error) {
+ f, err := openRelativeInternal(path, root, accessMask, shareFlags, createDisposition, flags)
+ if err != nil {
+ err = &os.PathError{Op: "open", Path: filepath.Join(root.Name(), path), Err: err}
+ }
+ return f, err
+}
+
+// LinkRelative creates a hard link from oldname to newname (relative to oldroot
+// and newroot), failing if any of the intermediate path components are reparse
+// points.
+func LinkRelative(oldname string, oldroot *os.File, newname string, newroot *os.File) error {
+ // Open the old file.
+ oldf, err := openRelativeInternal(
+ oldname,
+ oldroot,
+ syscall.FILE_WRITE_ATTRIBUTES,
+ syscall.FILE_SHARE_READ|syscall.FILE_SHARE_WRITE|syscall.FILE_SHARE_DELETE,
+ FILE_OPEN,
+ 0,
+ )
+ if err != nil {
+ return &os.LinkError{Op: "link", Old: filepath.Join(oldroot.Name(), oldname), New: filepath.Join(newroot.Name(), newname), Err: err}
+ }
+ defer oldf.Close()
+
+ // Open the parent of the new file.
+ var parent *os.File
+ parentPath := filepath.Dir(newname)
+ if parentPath != "." {
+ parent, err = openRelativeInternal(
+ parentPath,
+ newroot,
+ syscall.GENERIC_READ,
+ syscall.FILE_SHARE_READ|syscall.FILE_SHARE_WRITE|syscall.FILE_SHARE_DELETE,
+ FILE_OPEN,
+ FILE_DIRECTORY_FILE)
+ if err != nil {
+ return &os.LinkError{Op: "link", Old: oldf.Name(), New: filepath.Join(newroot.Name(), newname), Err: err}
+ }
+ defer parent.Close()
+
+ fi, err := winio.GetFileBasicInfo(parent)
+ if err != nil {
+ return err
+ }
+ if (fi.FileAttributes & syscall.FILE_ATTRIBUTE_REPARSE_POINT) != 0 {
+ return &os.LinkError{Op: "link", Old: oldf.Name(), New: filepath.Join(newroot.Name(), newname), Err: rtlNtStatusToDosError(_STATUS_REPARSE_POINT_ENCOUNTERED)}
+ }
+
+ } else {
+ parent = newroot
+ }
+
+ // Issue an NT call to create the link. This will be safe because NT will
+ // not open any more directories to create the link, so it cannot walk any
+ // more reparse points.
+ newbase := filepath.Base(newname)
+ newbase16, err := ntRelativePath(newbase)
+ if err != nil {
+ return err
+ }
+
+ size := int(unsafe.Offsetof(fileLinkInformation{}.FileName)) + len(newbase16)*2
+ linkinfoBuffer := localAlloc(0, size)
+ defer localFree(linkinfoBuffer)
+ linkinfo := (*fileLinkInformation)(unsafe.Pointer(linkinfoBuffer))
+ linkinfo.RootDirectory = parent.Fd()
+ linkinfo.FileNameLength = uint32(len(newbase16) * 2)
+ copy((*[32768]uint16)(unsafe.Pointer(&linkinfo.FileName[0]))[:], newbase16)
+
+ var iosb ioStatusBlock
+ status := ntSetInformationFile(
+ oldf.Fd(),
+ &iosb,
+ linkinfoBuffer,
+ uint32(size),
+ _FileLinkInformation,
+ )
+ if status != 0 {
+ return &os.LinkError{Op: "link", Old: oldf.Name(), New: filepath.Join(parent.Name(), newbase), Err: rtlNtStatusToDosError(status)}
+ }
+
+ return nil
+}
+
+// deleteOnClose marks a file to be deleted when the handle is closed.
+func deleteOnClose(f *os.File) error {
+ disposition := fileDispositionInformationEx{Flags: FILE_DISPOSITION_DELETE}
+ var iosb ioStatusBlock
+ status := ntSetInformationFile(
+ f.Fd(),
+ &iosb,
+ uintptr(unsafe.Pointer(&disposition)),
+ uint32(unsafe.Sizeof(disposition)),
+ _FileDispositionInformationEx,
+ )
+ if status != 0 {
+ return rtlNtStatusToDosError(status)
+ }
+ return nil
+}
+
+// clearReadOnly clears the readonly attribute on a file.
+func clearReadOnly(f *os.File) error {
+ bi, err := winio.GetFileBasicInfo(f)
+ if err != nil {
+ return err
+ }
+ if bi.FileAttributes&syscall.FILE_ATTRIBUTE_READONLY == 0 {
+ return nil
+ }
+ sbi := winio.FileBasicInfo{
+ FileAttributes: bi.FileAttributes &^ syscall.FILE_ATTRIBUTE_READONLY,
+ }
+ if sbi.FileAttributes == 0 {
+ sbi.FileAttributes = syscall.FILE_ATTRIBUTE_NORMAL
+ }
+ return winio.SetFileBasicInfo(f, &sbi)
+}
+
+// RemoveRelative removes a file or directory relative to a root, failing if any
+// intermediate path components are reparse points.
+func RemoveRelative(path string, root *os.File) error {
+ f, err := openRelativeInternal(
+ path,
+ root,
+ FILE_READ_ATTRIBUTES|FILE_WRITE_ATTRIBUTES|DELETE,
+ syscall.FILE_SHARE_READ|syscall.FILE_SHARE_WRITE|syscall.FILE_SHARE_DELETE,
+ FILE_OPEN,
+ FILE_OPEN_REPARSE_POINT)
+ if err == nil {
+ defer f.Close()
+ err = deleteOnClose(f)
+ if err == syscall.ERROR_ACCESS_DENIED {
+ // Maybe the file is marked readonly. Clear the bit and retry.
+ clearReadOnly(f)
+ err = deleteOnClose(f)
+ }
+ }
+ if err != nil {
+ return &os.PathError{Op: "remove", Path: filepath.Join(root.Name(), path), Err: err}
+ }
+ return nil
+}
+
+// RemoveAllRelative removes a directory tree relative to a root, failing if any
+// intermediate path components are reparse points.
+func RemoveAllRelative(path string, root *os.File) error {
+ fi, err := LstatRelative(path, root)
+ if err != nil {
+ if os.IsNotExist(err) {
+ return nil
+ }
+ return err
+ }
+ fileAttributes := fi.Sys().(*syscall.Win32FileAttributeData).FileAttributes
+ if fileAttributes&syscall.FILE_ATTRIBUTE_DIRECTORY == 0 || fileAttributes&syscall.FILE_ATTRIBUTE_REPARSE_POINT != 0 {
+ // If this is a reparse point, it can't have children. Simple remove will do.
+ err := RemoveRelative(path, root)
+ if err == nil || os.IsNotExist(err) {
+ return nil
+ }
+ return err
+ }
+
+ // It is necessary to use os.Open as Readdirnames does not work with
+ // OpenRelative. This is safe because the above lstatrelative fails
+ // if the target is outside the root, and we know this is not a
+ // symlink from the above FILE_ATTRIBUTE_REPARSE_POINT check.
+ fd, err := os.Open(filepath.Join(root.Name(), path))
+ if err != nil {
+ if os.IsNotExist(err) {
+ // Race. It was deleted between the Lstat and Open.
+ // Return nil per RemoveAll's docs.
+ return nil
+ }
+ return err
+ }
+
+ // Remove contents & return first error.
+ for {
+ names, err1 := fd.Readdirnames(100)
+ for _, name := range names {
+ err1 := RemoveAllRelative(path+string(os.PathSeparator)+name, root)
+ if err == nil {
+ err = err1
+ }
+ }
+ if err1 == io.EOF {
+ break
+ }
+ // If Readdirnames returned an error, use it.
+ if err == nil {
+ err = err1
+ }
+ if len(names) == 0 {
+ break
+ }
+ }
+ fd.Close()
+
+ // Remove directory.
+ err1 := RemoveRelative(path, root)
+ if err1 == nil || os.IsNotExist(err1) {
+ return nil
+ }
+ if err == nil {
+ err = err1
+ }
+ return err
+}
+
+// MkdirRelative creates a directory relative to a root, failing if any
+// intermediate path components are reparse points.
+func MkdirRelative(path string, root *os.File) error {
+ f, err := openRelativeInternal(
+ path,
+ root,
+ 0,
+ syscall.FILE_SHARE_READ|syscall.FILE_SHARE_WRITE|syscall.FILE_SHARE_DELETE,
+ FILE_CREATE,
+ FILE_DIRECTORY_FILE)
+ if err == nil {
+ f.Close()
+ } else {
+ err = &os.PathError{Op: "mkdir", Path: filepath.Join(root.Name(), path), Err: err}
+ }
+ return err
+}
+
+// LstatRelative performs a stat operation on a file relative to a root, failing
+// if any intermediate path components are reparse points.
+func LstatRelative(path string, root *os.File) (os.FileInfo, error) {
+ f, err := openRelativeInternal(
+ path,
+ root,
+ FILE_READ_ATTRIBUTES,
+ syscall.FILE_SHARE_READ|syscall.FILE_SHARE_WRITE|syscall.FILE_SHARE_DELETE,
+ FILE_OPEN,
+ FILE_OPEN_REPARSE_POINT)
+ if err != nil {
+ return nil, &os.PathError{Op: "stat", Path: filepath.Join(root.Name(), path), Err: err}
+ }
+ defer f.Close()
+ return f.Stat()
+}
+
+// EnsureNotReparsePointRelative validates that a given file (relative to a
+// root) and all intermediate path components are not a reparse points.
+func EnsureNotReparsePointRelative(path string, root *os.File) error {
+ // Perform an open with OBJ_DONT_REPARSE but without specifying FILE_OPEN_REPARSE_POINT.
+ f, err := OpenRelative(
+ path,
+ root,
+ 0,
+ syscall.FILE_SHARE_READ|syscall.FILE_SHARE_WRITE|syscall.FILE_SHARE_DELETE,
+ FILE_OPEN,
+ 0)
+ if err != nil {
+ return err
+ }
+ f.Close()
+ return nil
+}
diff --git a/vendor/github.com/Microsoft/hcsshim/internal/safefile/zsyscall_windows.go b/vendor/github.com/Microsoft/hcsshim/internal/safefile/zsyscall_windows.go
new file mode 100644
index 000000000..709b9d347
--- /dev/null
+++ b/vendor/github.com/Microsoft/hcsshim/internal/safefile/zsyscall_windows.go
@@ -0,0 +1,79 @@
+// Code generated by 'go generate'; DO NOT EDIT.
+
+package safefile
+
+import (
+ "syscall"
+ "unsafe"
+
+ "golang.org/x/sys/windows"
+)
+
+var _ unsafe.Pointer
+
+// Do the interface allocations only once for common
+// Errno values.
+const (
+ errnoERROR_IO_PENDING = 997
+)
+
+var (
+ errERROR_IO_PENDING error = syscall.Errno(errnoERROR_IO_PENDING)
+)
+
+// errnoErr returns common boxed Errno values, to prevent
+// allocations at runtime.
+func errnoErr(e syscall.Errno) error {
+ switch e {
+ case 0:
+ return nil
+ case errnoERROR_IO_PENDING:
+ return errERROR_IO_PENDING
+ }
+ // TODO: add more here, after collecting data on the common
+ // error values see on Windows. (perhaps when running
+ // all.bat?)
+ return e
+}
+
+var (
+ modntdll = windows.NewLazySystemDLL("ntdll.dll")
+ modkernel32 = windows.NewLazySystemDLL("kernel32.dll")
+
+ procNtCreateFile = modntdll.NewProc("NtCreateFile")
+ procNtSetInformationFile = modntdll.NewProc("NtSetInformationFile")
+ procRtlNtStatusToDosErrorNoTeb = modntdll.NewProc("RtlNtStatusToDosErrorNoTeb")
+ procLocalAlloc = modkernel32.NewProc("LocalAlloc")
+ procLocalFree = modkernel32.NewProc("LocalFree")
+)
+
+func ntCreateFile(handle *uintptr, accessMask uint32, oa *objectAttributes, iosb *ioStatusBlock, allocationSize *uint64, fileAttributes uint32, shareAccess uint32, createDisposition uint32, createOptions uint32, eaBuffer *byte, eaLength uint32) (status uint32) {
+ r0, _, _ := syscall.Syscall12(procNtCreateFile.Addr(), 11, uintptr(unsafe.Pointer(handle)), uintptr(accessMask), uintptr(unsafe.Pointer(oa)), uintptr(unsafe.Pointer(iosb)), uintptr(unsafe.Pointer(allocationSize)), uintptr(fileAttributes), uintptr(shareAccess), uintptr(createDisposition), uintptr(createOptions), uintptr(unsafe.Pointer(eaBuffer)), uintptr(eaLength), 0)
+ status = uint32(r0)
+ return
+}
+
+func ntSetInformationFile(handle uintptr, iosb *ioStatusBlock, information uintptr, length uint32, class uint32) (status uint32) {
+ r0, _, _ := syscall.Syscall6(procNtSetInformationFile.Addr(), 5, uintptr(handle), uintptr(unsafe.Pointer(iosb)), uintptr(information), uintptr(length), uintptr(class), 0)
+ status = uint32(r0)
+ return
+}
+
+func rtlNtStatusToDosError(status uint32) (winerr error) {
+ r0, _, _ := syscall.Syscall(procRtlNtStatusToDosErrorNoTeb.Addr(), 1, uintptr(status), 0, 0)
+ if r0 != 0 {
+ winerr = syscall.Errno(r0)
+ }
+ return
+}
+
+func localAlloc(flags uint32, size int) (ptr uintptr) {
+ r0, _, _ := syscall.Syscall(procLocalAlloc.Addr(), 2, uintptr(flags), uintptr(size), 0)
+ ptr = uintptr(r0)
+ return
+}
+
+func localFree(ptr uintptr) {
+ syscall.Syscall(procLocalFree.Addr(), 1, uintptr(ptr), 0, 0)
+ return
+}