|
@@ -15,6 +15,7 @@ import (
|
|
"path/filepath"
|
|
"path/filepath"
|
|
"runtime"
|
|
"runtime"
|
|
"strings"
|
|
"strings"
|
|
|
|
+ "syscall"
|
|
|
|
|
|
"github.com/calmh/du"
|
|
"github.com/calmh/du"
|
|
"github.com/syncthing/syncthing/lib/sync"
|
|
"github.com/syncthing/syncthing/lib/sync"
|
|
@@ -107,6 +108,78 @@ func Remove(path string) error {
|
|
return os.Remove(path)
|
|
return os.Remove(path)
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+// RemoveAll is a copy of os.RemoveAll, but uses osutil.Remove.
|
|
|
|
+// RemoveAll removes path and any children it contains.
|
|
|
|
+// It removes everything it can but returns the first error
|
|
|
|
+// it encounters. If the path does not exist, RemoveAll
|
|
|
|
+// returns nil (no error).
|
|
|
|
+func RemoveAll(path string) error {
|
|
|
|
+ // Simple case: if Remove works, we're done.
|
|
|
|
+ err := Remove(path)
|
|
|
|
+ if err == nil || os.IsNotExist(err) {
|
|
|
|
+ return nil
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ // Otherwise, is this a directory we need to recurse into?
|
|
|
|
+ dir, serr := os.Lstat(path)
|
|
|
|
+ if serr != nil {
|
|
|
|
+ if serr, ok := serr.(*os.PathError); ok && (os.IsNotExist(serr.Err) || serr.Err == syscall.ENOTDIR) {
|
|
|
|
+ return nil
|
|
|
|
+ }
|
|
|
|
+ return serr
|
|
|
|
+ }
|
|
|
|
+ if !dir.IsDir() {
|
|
|
|
+ // Not a directory; return the error from Remove.
|
|
|
|
+ return err
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ // Directory.
|
|
|
|
+ fd, err := os.Open(path)
|
|
|
|
+ if err != nil {
|
|
|
|
+ if os.IsNotExist(err) {
|
|
|
|
+ // Race. It was deleted between the Lstat and Open.
|
|
|
|
+ // Return nil per RemoveAll's docs.
|
|
|
|
+ return nil
|
|
|
|
+ }
|
|
|
|
+ return err
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ // Remove contents & return first error.
|
|
|
|
+ err = nil
|
|
|
|
+ for {
|
|
|
|
+ names, err1 := fd.Readdirnames(100)
|
|
|
|
+ for _, name := range names {
|
|
|
|
+ err1 := RemoveAll(path + string(os.PathSeparator) + name)
|
|
|
|
+ if err == nil {
|
|
|
|
+ err = err1
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ if err1 == io.EOF {
|
|
|
|
+ break
|
|
|
|
+ }
|
|
|
|
+ // If Readdirnames returned an error, use it.
|
|
|
|
+ if err == nil {
|
|
|
|
+ err = err1
|
|
|
|
+ }
|
|
|
|
+ if len(names) == 0 {
|
|
|
|
+ break
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ // Close directory, because windows won't remove opened directory.
|
|
|
|
+ fd.Close()
|
|
|
|
+
|
|
|
|
+ // Remove directory.
|
|
|
|
+ err1 := Remove(path)
|
|
|
|
+ if err1 == nil || os.IsNotExist(err1) {
|
|
|
|
+ return nil
|
|
|
|
+ }
|
|
|
|
+ if err == nil {
|
|
|
|
+ err = err1
|
|
|
|
+ }
|
|
|
|
+ return err
|
|
|
|
+}
|
|
|
|
+
|
|
func ExpandTilde(path string) (string, error) {
|
|
func ExpandTilde(path string) (string, error) {
|
|
if path == "~" {
|
|
if path == "~" {
|
|
return getHomeDir()
|
|
return getHomeDir()
|