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 }