Explorar o código

Verify Windows support, report appropriate errors when unsupported

Jakob Borg %!s(int64=11) %!d(string=hai) anos
pai
achega
5af6cbae2c
Modificáronse 1 ficheiros con 57 adicións e 1 borrados
  1. 57 1
      internal/symlinks/symlink.go

+ 57 - 1
internal/symlinks/symlink.go

@@ -16,7 +16,9 @@
 package symlinks
 
 import (
+	"errors"
 	"os"
+	"path/filepath"
 	"runtime"
 
 	"github.com/syncthing/syncthing/internal/osutil"
@@ -24,10 +26,19 @@ import (
 )
 
 var (
-	Supported = true
+	Supported      = false
+	ErrUnsupported = errors.New("symlinks not supported")
 )
 
+func init() {
+	Supported = symlinksSupported()
+}
+
 func Read(path string) (string, uint32, error) {
+	if !Supported {
+		return "", 0, ErrUnsupported
+	}
+
 	var mode uint32
 	stat, err := os.Stat(path)
 	if err != nil {
@@ -41,6 +52,10 @@ func Read(path string) (string, uint32, error) {
 }
 
 func IsSymlink(path string) (bool, error) {
+	if !Supported {
+		return false, ErrUnsupported
+	}
+
 	lstat, err := os.Lstat(path)
 	if err != nil {
 		return false, err
@@ -49,6 +64,10 @@ func IsSymlink(path string) (bool, error) {
 }
 
 func Create(target, source string, flags uint32) error {
+	if !Supported {
+		return ErrUnsupported
+	}
+
 	return os.Symlink(osutil.NativeFilename(target), source)
 }
 
@@ -58,6 +77,10 @@ func ChangeType(path string, flags uint32) error {
 		return nil
 	}
 
+	if !Supported {
+		return ErrUnsupported
+	}
+
 	target, cflags, err := Read(path)
 	if err != nil {
 		return err
@@ -80,3 +103,36 @@ func ChangeType(path string, flags uint32) error {
 		return Create(target, path, flags)
 	}, path)
 }
+
+func symlinksSupported() bool {
+	if runtime.GOOS != "windows" {
+		// Symlinks are supported. In practice there may be deviations (FAT
+		// filesystems etc), but these get handled and reported as the errors
+		// they are when they happen.
+		return true
+	}
+
+	// We try to create a symlink and verify that it looks like we expected.
+	// Needs administrator priviledges and a version higher than XP.
+
+	base := os.TempDir()
+	path := filepath.Join(base, "syncthing-symlink-test")
+	defer os.Remove(path)
+
+	err := Create(base, path, protocol.FlagDirectory)
+	if err != nil {
+		return false
+	}
+
+	isLink, err := IsSymlink(path)
+	if err != nil || !isLink {
+		return false
+	}
+
+	target, flags, err := Read(path)
+	if err != nil || osutil.NativeFilename(target) != base || flags&protocol.FlagDirectory == 0 {
+		return false
+	}
+
+	return true
+}