From aab414b368e713ccc4491d747a14312a16aac28b Mon Sep 17 00:00:00 2001
From: Alexander Neumann <alexander@bumpern.de>
Date: Sun, 7 Jan 2018 14:50:47 +0100
Subject: [PATCH 1/3] Add test case for #1512

---
 internal/restic/restorer_test.go | 24 +++++++++++++++++++++++-
 1 file changed, 23 insertions(+), 1 deletion(-)

diff --git a/internal/restic/restorer_test.go b/internal/restic/restorer_test.go
index 9e3c5528a..ad3cf1423 100644
--- a/internal/restic/restorer_test.go
+++ b/internal/restic/restorer_test.go
@@ -29,6 +29,7 @@ type File struct {
 
 type Dir struct {
 	Nodes map[string]Node
+	Mode  os.FileMode
 }
 
 func saveFile(t testing.TB, repo restic.Repository, node File) restic.ID {
@@ -63,9 +64,15 @@ func saveDir(t testing.TB, repo restic.Repository, nodes map[string]Node) restic
 			})
 		case Dir:
 			id = saveDir(t, repo, node.Nodes)
+
+			mode := node.Mode
+			if mode == 0 {
+				mode = 0755
+			}
+
 			tree.Insert(&restic.Node{
 				Type:    "dir",
-				Mode:    0755,
+				Mode:    mode,
 				Name:    name,
 				UID:     uint32(os.Getuid()),
 				GID:     uint32(os.Getgid()),
@@ -166,6 +173,21 @@ func TestRestorer(t *testing.T) {
 				"dir/subdir/file": "file in subdir",
 			},
 		},
+		{
+			Snapshot: Snapshot{
+				Nodes: map[string]Node{
+					"dir": Dir{
+						Mode: 0444,
+						Nodes: map[string]Node{
+							"file": File{"file in dir"},
+						},
+					},
+				},
+			},
+			Files: map[string]string{
+				"dir/file": "file in dir",
+			},
+		},
 
 		// test cases with invalid/constructed names
 		{

From b8620429e27ce28c565f657359b4a93b72c42837 Mon Sep 17 00:00:00 2001
From: Alexander Neumann <alexander@bumpern.de>
Date: Sun, 7 Jan 2018 15:13:24 +0100
Subject: [PATCH 2/3] restorer: Set directory mode as last step

Closes #1512
---
 internal/restic/restorer.go      | 26 ++++++++++++--------------
 internal/restic/restorer_test.go | 13 +++++++++++++
 2 files changed, 25 insertions(+), 14 deletions(-)

diff --git a/internal/restic/restorer.go b/internal/restic/restorer.go
index 0424fdb64..69ae7c356 100644
--- a/internal/restic/restorer.go
+++ b/internal/restic/restorer.go
@@ -79,13 +79,6 @@ func (res *Restorer) restoreTo(ctx context.Context, target, location string, tre
 		selectedForRestore, childMayBeSelected := res.SelectFilter(nodeLocation, nodeTarget, node)
 		debug.Log("SelectFilter returned %v %v", selectedForRestore, childMayBeSelected)
 
-		if selectedForRestore {
-			err = res.restoreNodeTo(ctx, node, nodeTarget, nodeLocation, idx)
-			if err != nil {
-				return err
-			}
-		}
-
 		if node.Type == "dir" && childMayBeSelected {
 			if node.Subtree == nil {
 				return errors.Errorf("Dir without subtree in tree %v", treeID.Str())
@@ -98,14 +91,19 @@ func (res *Restorer) restoreTo(ctx context.Context, target, location string, tre
 					return err
 				}
 			}
+		}
 
-			if selectedForRestore {
-				// Restore directory timestamp at the end. If we would do it earlier, restoring files within
-				// the directory would overwrite the timestamp of the directory they are in.
-				err = node.RestoreTimestamps(nodeTarget)
-				if err != nil {
-					return err
-				}
+		if selectedForRestore {
+			err = res.restoreNodeTo(ctx, node, nodeTarget, nodeLocation, idx)
+			if err != nil {
+				return err
+			}
+
+			// Restore directory timestamp at the end. If we would do it earlier, restoring files within
+			// the directory would overwrite the timestamp of the directory they are in.
+			err = node.RestoreTimestamps(nodeTarget)
+			if err != nil {
+				return err
 			}
 		}
 	}
diff --git a/internal/restic/restorer_test.go b/internal/restic/restorer_test.go
index ad3cf1423..ec3282e5d 100644
--- a/internal/restic/restorer_test.go
+++ b/internal/restic/restorer_test.go
@@ -178,6 +178,19 @@ func TestRestorer(t *testing.T) {
 				Nodes: map[string]Node{
 					"dir": Dir{
 						Mode: 0444,
+					},
+					"file": File{"top-level file"},
+				},
+			},
+			Files: map[string]string{
+				"file": "top-level file",
+			},
+		},
+		{
+			Snapshot: Snapshot{
+				Nodes: map[string]Node{
+					"dir": Dir{
+						Mode: 0555,
 						Nodes: map[string]Node{
 							"file": File{"file in dir"},
 						},

From b708cfee3f39a5c6fb9e8eb3de4705a4b9638acb Mon Sep 17 00:00:00 2001
From: Alexander Neumann <alexander@bumpern.de>
Date: Sun, 7 Jan 2018 15:15:45 +0100
Subject: [PATCH 3/3] Add entry to changelog

---
 changelog/0.8.2/issue-1512 | 9 +++++++++
 1 file changed, 9 insertions(+)
 create mode 100644 changelog/0.8.2/issue-1512

diff --git a/changelog/0.8.2/issue-1512 b/changelog/0.8.2/issue-1512
new file mode 100644
index 000000000..4e30fbbf8
--- /dev/null
+++ b/changelog/0.8.2/issue-1512
@@ -0,0 +1,9 @@
+Bugfix: Restore directory permissions as the last step
+
+This change allows restoring into directories that were not writable during
+backup. Before, restic created the directory, set the read-only mode and then
+failed to create files in the directory. This change now restores the directory
+(with its permissions) as the very last step.
+
+https://github.com/restic/restic/issues/1512
+https://github.com/restic/restic/pull/1536