فهرست منبع

Correctly check whether parent directory is writable for current user.
"&04" was checking if file is readable by others, while "&0200" checks
if it's writable for current user.

(Fixes #904)

Vilbrekin 11 سال پیش
والد
کامیت
970e50d1f1

+ 1 - 0
CONTRIBUTORS

@@ -22,3 +22,4 @@ Phill Luby <[email protected]>
 Ryan Sullivan <[email protected]>
 Tully Robinson <[email protected]>
 Veeti Paananen <[email protected]>
+Vil Brekin <[email protected]>

+ 4 - 2
internal/model/sharedpullerstate.go

@@ -20,6 +20,7 @@ import (
 	"path/filepath"
 	"sync"
 
+	"github.com/syncthing/syncthing/internal/osutil"
 	"github.com/syncthing/syncthing/internal/protocol"
 )
 
@@ -68,7 +69,7 @@ func (s *sharedPullerState) tempFile() (*os.File, error) {
 	if info, err := os.Stat(dir); err != nil {
 		s.earlyCloseLocked("dst stat dir", err)
 		return nil, err
-	} else if info.Mode()&04 == 0 {
+	} else if info.Mode()&0200 == 0 {
 		err := os.Chmod(dir, 0755)
 		if err == nil {
 			defer func() {
@@ -136,7 +137,8 @@ func (s *sharedPullerState) earlyCloseLocked(context string, err error) {
 	s.err = err
 	if s.fd != nil {
 		s.fd.Close()
-		os.Remove(s.tempName)
+		// Delete temporary file, even if parent dir is read-only
+		osutil.InWritableDir(func(string) error { os.Remove(s.tempName); return nil }, s.tempName)
 	}
 	s.closed = true
 }

+ 25 - 1
internal/model/sharedpullerstate_test.go

@@ -15,7 +15,11 @@
 
 package model
 
-import "testing"
+import (
+	"os"
+	"path/filepath"
+	"testing"
+)
 
 func TestSourceFileOK(t *testing.T) {
 	s := sharedPullerState{
@@ -61,3 +65,23 @@ func TestSourceFileBad(t *testing.T) {
 		t.Fatal("Unexpected nil failed()")
 	}
 }
+
+// Test creating temporary file inside read-only directory
+func TestReadOnlyDir(t *testing.T) {
+	s := sharedPullerState{
+		tempName: "testdata/read_only_dir/.temp_name",
+	}
+
+	// Ensure dir is read-only (git doesn't store full permissions)
+	os.Chmod(filepath.Dir(s.tempName), 0555)
+
+	fd, err := s.tempFile()
+	if err != nil {
+		t.Fatal(err)
+	}
+	if fd == nil {
+		t.Fatal("Unexpected nil fd")
+	}
+
+	s.earlyClose("Test done", nil)
+}

+ 0 - 0
internal/model/testdata/read_only_dir/a


+ 1 - 1
internal/osutil/osutil.go

@@ -66,7 +66,7 @@ func Rename(from, to string) error {
 // containing `path` is writable for the duration of the call.
 func InWritableDir(fn func(string) error, path string) error {
 	dir := filepath.Dir(path)
-	if info, err := os.Stat(dir); err == nil && info.IsDir() && info.Mode()&04 == 0 {
+	if info, err := os.Stat(dir); err == nil && info.IsDir() && info.Mode()&0200 == 0 {
 		// A non-writeable directory (for this user; we assume that's the
 		// relevant part). Temporarily change the mode so we can delete the
 		// file or directory inside it.