github.com/mckael/restic@v0.8.3/internal/fs/file_windows.go (about)

     1  package fs
     2  
     3  import (
     4  	"io/ioutil"
     5  	"os"
     6  	"path/filepath"
     7  	"strings"
     8  	"syscall"
     9  )
    10  
    11  // fixpath returns an absolute path on windows, so restic can open long file
    12  // names.
    13  func fixpath(name string) string {
    14  	abspath, err := filepath.Abs(name)
    15  	if err == nil {
    16  		// Check if \\?\UNC\ already exist
    17  		if strings.HasPrefix(abspath, `\\?\UNC\`) {
    18  			return abspath
    19  		}
    20  		// Check if \\?\ already exist
    21  		if strings.HasPrefix(abspath, `\\?\`) {
    22  			return abspath
    23  		}
    24  		// Check if path starts with \\
    25  		if strings.HasPrefix(abspath, `\\`) {
    26  			return strings.Replace(abspath, `\\`, `\\?\UNC\`, 1)
    27  		}
    28  		// Normal path
    29  		return `\\?\` + abspath
    30  	}
    31  	return name
    32  }
    33  
    34  // MkdirAll creates a directory named path, along with any necessary parents,
    35  // and returns nil, or else returns an error. The permission bits perm are used
    36  // for all directories that MkdirAll creates. If path is already a directory,
    37  // MkdirAll does nothing and returns nil.
    38  //
    39  // Adapted from the stdlib MkdirAll, added test for volume name.
    40  func MkdirAll(path string, perm os.FileMode) error {
    41  	// Fast path: if we can tell whether path is a directory or file, stop with success or error.
    42  	dir, err := os.Stat(path)
    43  	if err == nil {
    44  		if dir.IsDir() {
    45  			return nil
    46  		}
    47  		return &os.PathError{
    48  			Op:   "mkdir",
    49  			Path: path,
    50  			Err:  syscall.ENOTDIR,
    51  		}
    52  	}
    53  
    54  	// Slow path: make sure parent exists and then call Mkdir for path.
    55  	i := len(path)
    56  	for i > 0 && os.IsPathSeparator(path[i-1]) { // Skip trailing path separator.
    57  		i--
    58  	}
    59  
    60  	j := i
    61  	for j > 0 && !os.IsPathSeparator(path[j-1]) { // Scan backward over element.
    62  		j--
    63  	}
    64  
    65  	if j > 1 {
    66  		// Create parent
    67  		parent := path[0 : j-1]
    68  		if parent != filepath.VolumeName(parent) {
    69  			err = MkdirAll(parent, perm)
    70  			if err != nil {
    71  				return err
    72  			}
    73  		}
    74  	}
    75  
    76  	// Parent now exists; invoke Mkdir and use its result.
    77  	err = os.Mkdir(path, perm)
    78  	if err != nil {
    79  		// Handle arguments like "foo/." by
    80  		// double-checking that directory doesn't exist.
    81  		dir, err1 := os.Lstat(path)
    82  		if err1 == nil && dir.IsDir() {
    83  			return nil
    84  		}
    85  		return err
    86  	}
    87  	return nil
    88  }
    89  
    90  // TempFile creates a temporary file.
    91  func TempFile(dir, prefix string) (f *os.File, err error) {
    92  	return ioutil.TempFile(dir, prefix)
    93  }
    94  
    95  // Chmod changes the mode of the named file to mode.
    96  func Chmod(name string, mode os.FileMode) error {
    97  	return os.Chmod(fixpath(name), mode)
    98  }