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  }