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  }