github.com/coreos/mantle@v0.13.0/system/anonfile_linux.go (about) 1 // Copyright 2015 CoreOS, Inc. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package system 16 17 import ( 18 "fmt" 19 "os" 20 "path/filepath" 21 "syscall" 22 23 "golang.org/x/sys/unix" 24 ) 25 26 // LinkFile creates a new link to an open File instead of an existing 27 // name as os.Link and friends do. Particularly useful for making a file 28 // created by AnonymousFile accessible in the filesystem. As with Link the 29 // caller should ensure the new name is on the same filesystem. 30 func LinkFile(file *os.File, name string) error { 31 // The AT_EMPTY_PATH version needs CAP_DAC_READ_SEARCH but using 32 // /proc and AT_SYMLINK_FOLLOW does not and is the "normal" way. 33 //Linkat(int(a.Fd()), "", AT_FDCWD, name, AT_EMPTY_PATH) 34 err := unix.Linkat( 35 unix.AT_FDCWD, fmt.Sprintf("/proc/self/fd/%d", file.Fd()), 36 unix.AT_FDCWD, name, unix.AT_SYMLINK_FOLLOW) 37 if err != nil { 38 return &os.LinkError{ 39 Op: "linkat", 40 Old: file.Name(), 41 New: name, 42 Err: err, 43 } 44 } 45 return nil 46 } 47 48 // AnonymousFile creates an unlinked temporary file in the given directory 49 // or the default temporary directory if unspecified. Since the file has no 50 // name, the file's Name method does not return a real path. The file may 51 // be later linked into the filesystem for safe keeping using LinkFile. 52 func AnonymousFile(dir string) (*os.File, error) { 53 return tmpFile(dir, false) 54 } 55 56 // PrivateFile creates an unlinked temporary file in the given directory 57 // or the default temporary directory if unspecified. Unlike AnonymousFile, 58 // the opened file cannot be linked into the filesystem later. 59 func PrivateFile(dir string) (*os.File, error) { 60 return tmpFile(dir, true) 61 } 62 63 func tmpFile(dir string, private bool) (*os.File, error) { 64 if dir == "" { 65 dir = os.TempDir() 66 } 67 68 flags := unix.O_RDWR | unix.O_TMPFILE | unix.O_CLOEXEC 69 if private { 70 flags |= unix.O_EXCL 71 } 72 73 tmpPath := filepath.Join(dir, "(unlinked)") 74 tmpFd, err := unix.Open(dir, flags, 0600) 75 if err != nil { 76 return nil, &os.PathError{ 77 Op: "openat", 78 Path: tmpPath, 79 Err: err, 80 } 81 } 82 83 return os.NewFile(uintptr(tmpFd), tmpPath), nil 84 } 85 86 // IsOpNotSupported reports true if the underlying error was EOPNOTSUPP. 87 // Useful for checking if the host or filesystem lacks O_TMPFILE support. 88 func IsOpNotSupported(err error) bool { 89 if oserr, ok := err.(*os.PathError); ok { 90 if errno, ok := oserr.Err.(syscall.Errno); ok { 91 if errno == syscall.EOPNOTSUPP { 92 return true 93 } 94 } 95 } 96 return false 97 }