Browse Source

Merge pull request #1842 from Zillode/fix-1822

Support the creation of top-level folders on Windows (fixes #1822)
Jakob Borg 10 years ago
parent
commit
3c3db52f49

+ 2 - 2
cmd/syncthing/main.go

@@ -279,7 +279,7 @@ func main() {
 			l.Fatalln(dir, "is not a directory")
 		}
 		if err != nil && os.IsNotExist(err) {
-			err = os.MkdirAll(dir, 0700)
+			err = osutil.MkdirAll(dir, 0700)
 			if err != nil {
 				l.Fatalln("generate:", err)
 			}
@@ -882,7 +882,7 @@ func discovery(extPort int) *discover.Discoverer {
 func ensureDir(dir string, mode int) {
 	fi, err := os.Stat(dir)
 	if os.IsNotExist(err) {
-		err := os.MkdirAll(dir, 0700)
+		err := osutil.MkdirAll(dir, 0700)
 		if err != nil {
 			l.Fatalln(err)
 		}

+ 1 - 1
internal/model/model.go

@@ -1611,7 +1611,7 @@ func (m *Model) CheckFolderHealth(id string) error {
 	} else if os.IsNotExist(err) {
 		// If we don't have any files in the index, and the directory
 		// doesn't exist, try creating it.
-		err = os.MkdirAll(folder.Path(), 0700)
+		err = osutil.MkdirAll(folder.Path(), 0700)
 		if err == nil {
 			err = folder.CreateMarker()
 		}

+ 17 - 0
internal/osutil/mkdirall.go

@@ -0,0 +1,17 @@
+// Copyright (C) 2015 The Syncthing Authors.
+//
+// This Source Code Form is subject to the terms of the Mozilla Public
+// License, v. 2.0. If a copy of the MPL was not distributed with this file,
+// You can obtain one at http://mozilla.org/MPL/2.0/.
+
+// +build !windows
+
+package osutil
+
+import (
+	"os"
+)
+
+func MkdirAll(path string, perm os.FileMode) error {
+	return os.MkdirAll(path, perm)
+}

+ 65 - 0
internal/osutil/mkdirall_windows.go

@@ -0,0 +1,65 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Modified by Zillode to fix https://github.com/syncthing/syncthing/issues/1822
+// Sync with https://github.com/golang/go/blob/master/src/os/path.go
+// See https://github.com/golang/go/issues/10900
+
+package osutil
+
+import (
+	"os"
+	"path/filepath"
+	"syscall"
+)
+
+// MkdirAll creates a directory named path, along with any necessary parents,
+// and returns nil, or else returns an error.
+// The permission bits perm are used for all directories that MkdirAll creates.
+// If path is already a directory, MkdirAll does nothing and returns nil.
+func MkdirAll(path string, perm os.FileMode) error {
+	// Fast path: if we can tell whether path is a directory or file, stop with success or error.
+	dir, err := os.Stat(path)
+	if err == nil {
+		if dir.IsDir() {
+			return nil
+		}
+		return &os.PathError{"mkdir", path, syscall.ENOTDIR}
+	}
+
+	// Slow path: make sure parent exists and then call Mkdir for path.
+	i := len(path)
+	for i > 0 && os.IsPathSeparator(path[i-1]) { // Skip trailing path separator.
+		i--
+	}
+
+	j := i
+	for j > 0 && !os.IsPathSeparator(path[j-1]) { // Scan backward over element.
+		j--
+	}
+
+	if j > 1 {
+		// Create parent
+		parent := path[0 : j-1]
+		if parent != filepath.VolumeName(parent) {
+			err = MkdirAll(parent, perm)
+			if err != nil {
+				return err
+			}
+		}
+	}
+
+	// Parent now exists; invoke Mkdir and use its result.
+	err = os.Mkdir(path, perm)
+	if err != nil {
+		// Handle arguments like "foo/." by
+		// double-checking that directory doesn't exist.
+		dir, err1 := os.Lstat(path)
+		if err1 == nil && dir.IsDir() {
+			return nil
+		}
+		return err
+	}
+	return nil
+}

+ 2 - 1
internal/scanner/walk_test.go

@@ -19,6 +19,7 @@ import (
 
 	"github.com/syncthing/protocol"
 	"github.com/syncthing/syncthing/internal/ignore"
+	"github.com/syncthing/syncthing/internal/osutil"
 	"golang.org/x/text/unicode/norm"
 )
 
@@ -218,7 +219,7 @@ func TestNormalization(t *testing.T) {
 
 	for _, s1 := range tests {
 		// Create a directory for each of the interesting strings above
-		if err := os.MkdirAll(filepath.Join("testdata/normalization", s1), 0755); err != nil {
+		if err := osutil.MkdirAll(filepath.Join("testdata/normalization", s1), 0755); err != nil {
 			t.Fatal(err)
 		}
 

+ 2 - 2
internal/versioner/simple.go

@@ -61,7 +61,7 @@ func (v Simple) Archive(filePath string) error {
 			if debug {
 				l.Debugln("creating versions dir", versionsDir)
 			}
-			os.MkdirAll(versionsDir, 0755)
+			osutil.MkdirAll(versionsDir, 0755)
 			osutil.HideFile(versionsDir)
 		} else {
 			return err
@@ -79,7 +79,7 @@ func (v Simple) Archive(filePath string) error {
 	}
 
 	dir := filepath.Join(versionsDir, inFolderPath)
-	err = os.MkdirAll(dir, 0755)
+	err = osutil.MkdirAll(dir, 0755)
 	if err != nil && !os.IsExist(err) {
 		return err
 	}

+ 2 - 2
internal/versioner/staggered.go

@@ -257,7 +257,7 @@ func (v Staggered) Archive(filePath string) error {
 			if debug {
 				l.Debugln("creating versions dir", v.versionsPath)
 			}
-			os.MkdirAll(v.versionsPath, 0755)
+			osutil.MkdirAll(v.versionsPath, 0755)
 			osutil.HideFile(v.versionsPath)
 		} else {
 			return err
@@ -275,7 +275,7 @@ func (v Staggered) Archive(filePath string) error {
 	}
 
 	dir := filepath.Join(v.versionsPath, inFolderPath)
-	err = os.MkdirAll(dir, 0755)
+	err = osutil.MkdirAll(dir, 0755)
 	if err != nil && !os.IsExist(err) {
 		return err
 	}