github.com/weiwenhao/getter@v1.30.1/get_file_windows.go (about) 1 // +build windows 2 3 package getter 4 5 import ( 6 "fmt" 7 "net/url" 8 "os" 9 "os/exec" 10 "path/filepath" 11 "strings" 12 "syscall" 13 ) 14 15 func (g *FileGetter) Get(dst string, u *url.URL) error { 16 ctx := g.Context() 17 path := u.Path 18 if u.RawPath != "" { 19 path = u.RawPath 20 } 21 22 // The source path must exist and be a directory to be usable. 23 if fi, err := os.Stat(path); err != nil { 24 return fmt.Errorf("source path error: %s", err) 25 } else if !fi.IsDir() { 26 return fmt.Errorf("source path must be a directory") 27 } 28 29 fi, err := os.Lstat(dst) 30 if err != nil && !os.IsNotExist(err) { 31 return err 32 } 33 34 // If the destination already exists, it must be a symlink 35 if err == nil { 36 mode := fi.Mode() 37 if mode&os.ModeSymlink == 0 { 38 return fmt.Errorf("destination exists and is not a symlink") 39 } 40 41 // Remove the destination 42 if err := os.Remove(dst); err != nil { 43 return err 44 } 45 } 46 47 // Create all the parent directories 48 if err := os.MkdirAll(filepath.Dir(dst), g.client.mode(0755)); err != nil { 49 return err 50 } 51 52 sourcePath := toBackslash(path) 53 54 // Use mklink to create a junction point 55 output, err := exec.CommandContext(ctx, "cmd", "/c", "mklink", "/J", dst, sourcePath).CombinedOutput() 56 if err != nil { 57 return fmt.Errorf("failed to run mklink %v %v: %v %q", dst, sourcePath, err, output) 58 } 59 60 return nil 61 } 62 63 func (g *FileGetter) GetFile(dst string, u *url.URL) error { 64 ctx := g.Context() 65 path := u.Path 66 if u.RawPath != "" { 67 path = u.RawPath 68 } 69 70 // The source path must exist and be a directory to be usable. 71 if fi, err := os.Stat(path); err != nil { 72 return fmt.Errorf("source path error: %s", err) 73 } else if fi.IsDir() { 74 return fmt.Errorf("source path must be a file") 75 } 76 77 _, err := os.Lstat(dst) 78 if err != nil && !os.IsNotExist(err) { 79 return err 80 } 81 82 // If the destination already exists, it must be a symlink 83 if err == nil { 84 // Remove the destination 85 if err := os.Remove(dst); err != nil { 86 return err 87 } 88 } 89 90 // Create all the parent directories 91 if err := os.MkdirAll(filepath.Dir(dst), g.client.mode(0755)); err != nil { 92 return err 93 } 94 95 // If we're not copying, just symlink and we're done 96 if !g.Copy { 97 if err = os.Symlink(path, dst); err == nil { 98 return err 99 } 100 lerr, ok := err.(*os.LinkError) 101 if !ok { 102 return err 103 } 104 switch lerr.Err { 105 case syscall.ERROR_PRIVILEGE_NOT_HELD: 106 // no symlink privilege, let's 107 // fallback to a copy to avoid an error. 108 break 109 default: 110 return err 111 } 112 } 113 114 // Copy 115 _, err = copyFile(ctx, dst, path, 0666, g.client.umask()) 116 return err 117 } 118 119 // toBackslash returns the result of replacing each slash character 120 // in path with a backslash ('\') character. Multiple separators are 121 // replaced by multiple backslashes. 122 func toBackslash(path string) string { 123 return strings.Replace(path, "/", "\\", -1) 124 }