aboutsummaryrefslogtreecommitdiffstats
path: root/recipes-core/swupd-client/swupd-client/0006-Backport-Use-rename-instead-of-tar-transform.patch
blob: ab3a39f974b8ba9cc7e93cc41c4c63aa8d1ec563 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
From e9ad32a273efe2d177c1bbd394ae944ae598fd50 Mon Sep 17 00:00:00 2001
From: Dmitry Rozhkov <dmitry.rozhkov@intel.com>
Date: Mon, 8 Feb 2016 18:12:48 +0200
Subject: [PATCH] Backport: Use rename instead of tar transform

This patch is a backport from swupd-client v2.88
Author: William Douglas <william.douglas@intel.com>
Subject: Use rename instead of tar transform

In order to prevent issues with transform name escaping, update logic
for moving an object from staging. First rename the object in the
staging path to its final name (in case of a directory the rename places
it in a seperate directory first to avoid hash colisions), then use tar
to update or create the object in the filesystem. Once finished rename
the object back to the hash name so it can be reused as needed.

This also fixes up some issues with the SWUPD_LINUX_ROOTFS checks not
always encapsulating variable use within the do_staging function.

Note: the SWUPD_LINUX_ROOTFS checks have been removed entirely, since
they are not used anywhere in the code at present.

Upstream-Status: Backported [v2.88]

Signed-off-by: Dmitry Rozhkov <dmitry.rozhkov@linux.intel.com>
---
 src/staging.c | 73 ++++++++++++++++++++++++++++++++++++++++++++++++++++++-----
 1 file changed, 67 insertions(+), 6 deletions(-)

diff --git a/src/staging.c b/src/staging.c
index b8545c1..16dafbb 100644
--- a/src/staging.c
+++ b/src/staging.c
@@ -36,6 +36,31 @@
 #include "swupd-build-variant.h"
 #include <swupd.h>
 
+/* clean then recreate temporary folder for tar renames */
+static int create_staging_renamedir(char *rename_tmpdir)
+{
+	int ret;
+	char *rmcommand = NULL;
+
+	string_or_die(&rmcommand, "rm -fr %s", rename_tmpdir);
+	if (!system(rmcommand)) {
+		/* Not fatal but pretty scary, likely to really fail at the
+		 * next command too. Pass for now as printing may just cause
+		 * confusion */
+		;
+	}
+	free(rmcommand);
+
+	ret = mkdir(rename_tmpdir, S_IRWXU);
+	if (ret == -1 && errno != EEXIST) {
+		ret = -errno;
+	} else {
+		ret = 0;
+	}
+
+	return ret;
+}
+
 #ifdef SWUPD_WITH_BTRFS
 static int create_staging_subvol_from(const char *version)
 {
@@ -269,6 +294,9 @@ int prepare(bool UNUSED_PARAM *is_corrupted, int UNUSED_PARAM current_version, i
 #endif
 
 /* Do the staging of new files into the filesystem */
+#warning do_staging is currently not able to be run in parallel
+/* Consider adding a remove_leftovers() that runs in verify/fix in order to
+ * allow this function to mkdtemp create folders for parallel build */
 int do_staging(struct file *file)
 {
 	char *statfile = NULL, *tmp = NULL, *tmp2 = NULL;
@@ -280,6 +308,8 @@ int do_staging(struct file *file)
 	char *targetpath = NULL;
 	char *symbase = NULL;
 #endif
+	char *rename_target = NULL;
+	char *rename_tmpdir = NULL;
 	int ret;
 	struct stat s;
 
@@ -360,12 +390,28 @@ int do_staging(struct file *file)
 		 * attributes and it includes internal logic that does the
 		 * right thing to overlay a directory onto something
 		 * pre-existing: */
-		string_or_die(&tarcommand, "tar -C %s/staged " TAR_PERM_ATTR_ARGS " -cf - %s 2> /dev/null | "
-			"tar -C %s%s " TAR_PERM_ATTR_ARGS " -xf - --transform=\"s/%s/%s/\" 2> /dev/null",
-			STATE_DIR, file->hash, path_prefix, rel_dir, file->hash, base);
+		/* In order to avoid tar transforms with directories, rename
+		 * the directory before and after the tar command */
+		string_or_die(&rename_tmpdir, "%s/tmprenamedir", STATE_DIR);
+		ret = create_staging_renamedir(rename_tmpdir);
+		if (ret) {
+			goto out;
+		}
+		string_or_die(&rename_target, "%s/%s", rename_tmpdir, base);
+		if (rename(original, rename_target)) {
+			ret = -errno;
+			goto out;
+		}
+		string_or_die(&tarcommand, "tar -C %s " TAR_PERM_ATTR_ARGS " -cf - %s 2> /dev/null | "
+			"tar -C %s%s " TAR_PERM_ATTR_ARGS " -xf - 2> /dev/null",
+			rename_tmpdir, base, path_prefix, rel_dir);
 		LOG_DEBUG(file, "directory overwrite", class_osvol_staging, "%s", tarcommand);
 		ret = system(tarcommand);
 		free(tarcommand);
+		if (rename(rename_target, original)) {
+			ret = -errno;
+			goto out;
+		}
 		if (ret < 0) {
 			LOG_ERROR(file, "Failed directory overwrite", class_osvol_staging, "%s", strerror(errno));
 			ret = -EDIR_OVERWRITE;
@@ -386,12 +432,25 @@ int do_staging(struct file *file)
 		}
 		if (ret < 0) {
 			/* either the hardlink failed, or it was undesirable (config), do a tar-tar dance */
-			string_or_die(&tarcommand, "tar -C %s/staged " TAR_PERM_ATTR_ARGS " -cf - %s 2> /dev/null | "
-				"tar -C %s%s " TAR_PERM_ATTR_ARGS " -xf - --transform=\"s/%s/.update.%s/\" 2> /dev/null",
-				STATE_DIR, file->hash, path_prefix, rel_dir, file->hash, base);
+			/* In order to avoid tar transforms, rename the file
+			 * before and after the tar command */
+			string_or_die(&rename_target, "%s/staged/.update.%s", STATE_DIR, base);
+			ret = rename(original, rename_target);
+			if (ret) {
+				ret = -errno;
+				goto out;
+			}
+			string_or_die(&tarcommand, "tar -C %s/staged " TAR_PERM_ATTR_ARGS " -cf - .update.%s 2> /dev/null | "
+				"tar -C %s%s " TAR_PERM_ATTR_ARGS " -xf - 2> /dev/null",
+				STATE_DIR, base, path_prefix, rel_dir);
 			LOG_DEBUG(file, "dotfile install", class_osvol_staging, "%s", tarcommand);
 			ret = system(tarcommand);
 			free(tarcommand);
+			ret = rename(rename_target, original);
+			if (ret) {
+				ret = -errno;
+				goto out;
+			}
 		}
 		if (ret < 0) {
 			LOG_ERROR(file, "Failed tar dotfile install", class_osvol_staging,
@@ -436,6 +495,8 @@ int do_staging(struct file *file)
 out:
 	free(target);
 	free(original);
+	free(rename_target);
+	free(rename_tmpdir);
 	free(tmp);
 	free(tmp2);
 
-- 
2.5.0