rev |
line source |
pascal@17423
|
1 Fix hardlink on fifos, sockets, char & block devices and symlinks
|
pascal@17423
|
2 --- linux-3.2.53/init/initramfs.c
|
pascal@17423
|
3 +++ linux-3.2.53/init/initramfs.c
|
pascal@17423
|
4 @@ -20,10 +20,24 @@
|
pascal@17423
|
5
|
pascal@17423
|
6 #define N_ALIGN(len) ((((len) + 1) & ~3) + 2)
|
pascal@17423
|
7
|
pascal@17423
|
8 +static __initdata unsigned long ino, major, minor, nlink;
|
pascal@17423
|
9 +static __initdata time_t mtime;
|
pascal@17423
|
10 +static __initdata mode_t mode;
|
pascal@17423
|
11 +static __initdata unsigned long body_len, name_len;
|
pascal@17423
|
12 +static __initdata uid_t uid;
|
pascal@17423
|
13 +static __initdata gid_t gid;
|
pascal@17423
|
14 +static __initdata unsigned rdev;
|
pascal@17423
|
15 +
|
pascal@17423
|
16 +struct names {
|
pascal@17423
|
17 + struct names *next;
|
pascal@17423
|
18 + char name[1];
|
pascal@17423
|
19 +};
|
pascal@17423
|
20 +
|
pascal@17423
|
21 static __initdata struct hash {
|
pascal@17423
|
22 - int ino, minor, major;
|
pascal@17423
|
23 + int ino, nlink, minor, major;
|
pascal@17423
|
24 mode_t mode;
|
pascal@17423
|
25 struct hash *next;
|
pascal@17423
|
26 + struct names *next_name;
|
pascal@17423
|
27 char name[N_ALIGN(PATH_MAX)];
|
pascal@17423
|
28 } *head[32];
|
pascal@17423
|
29
|
pascal@17423
|
30 @@ -34,8 +48,7 @@
|
pascal@17423
|
31 return tmp & 31;
|
pascal@17423
|
32 }
|
pascal@17423
|
33
|
pascal@17423
|
34 -static char __init *find_link(int major, int minor, int ino,
|
pascal@17423
|
35 - mode_t mode, char *name)
|
pascal@17423
|
36 +static struct hash __init *find_link(char *name)
|
pascal@17423
|
37 {
|
pascal@17423
|
38 struct hash **p, *q;
|
pascal@17423
|
39 for (p = head + hash(major, minor, ino); *p; p = &(*p)->next) {
|
pascal@17423
|
40 @@ -47,7 +60,16 @@
|
pascal@17423
|
41 continue;
|
pascal@17423
|
42 if (((*p)->mode ^ mode) & S_IFMT)
|
pascal@17423
|
43 continue;
|
pascal@17423
|
44 - return (*p)->name;
|
pascal@17423
|
45 + if (--(*p)->nlink) {
|
pascal@17423
|
46 + struct names **n;
|
pascal@17423
|
47 + for (n = &(*p)->next_name; *n; n = &(*n)->next);
|
pascal@17423
|
48 + *n = kmalloc(sizeof(struct names) + strlen(name), GFP_KERNEL);
|
pascal@17423
|
49 + if (!*n)
|
pascal@17423
|
50 + panic("can't allocate link name entry");
|
pascal@17423
|
51 + strcpy((*n)->name, name);
|
pascal@17423
|
52 + (*n)->next = NULL;
|
pascal@17423
|
53 + }
|
pascal@17423
|
54 + return *p;
|
pascal@17423
|
55 }
|
pascal@17423
|
56 q = kmalloc(sizeof(struct hash), GFP_KERNEL);
|
pascal@17423
|
57 if (!q)
|
pascal@17423
|
58 @@ -55,11 +77,13 @@
|
pascal@17423
|
59 q->major = major;
|
pascal@17423
|
60 q->minor = minor;
|
pascal@17423
|
61 q->ino = ino;
|
pascal@17423
|
62 + q->nlink = nlink;
|
pascal@17423
|
63 q->mode = mode;
|
pascal@17423
|
64 strcpy(q->name, name);
|
pascal@17423
|
65 + q->next_name = NULL;
|
pascal@17423
|
66 q->next = NULL;
|
pascal@17423
|
67 *p = q;
|
pascal@17423
|
68 - return NULL;
|
pascal@17423
|
69 + return q;
|
pascal@17423
|
70 }
|
pascal@17423
|
71
|
pascal@17423
|
72 static void __init free_hash(void)
|
pascal@17423
|
73 @@ -115,17 +139,8 @@
|
pascal@17423
|
74 }
|
pascal@17423
|
75 }
|
pascal@17423
|
76
|
pascal@17423
|
77 -static __initdata time_t mtime;
|
pascal@17423
|
78 -
|
pascal@17423
|
79 /* cpio header parsing */
|
pascal@17423
|
80
|
pascal@17423
|
81 -static __initdata unsigned long ino, major, minor, nlink;
|
pascal@17423
|
82 -static __initdata mode_t mode;
|
pascal@17423
|
83 -static __initdata unsigned long body_len, name_len;
|
pascal@17423
|
84 -static __initdata uid_t uid;
|
pascal@17423
|
85 -static __initdata gid_t gid;
|
pascal@17423
|
86 -static __initdata unsigned rdev;
|
pascal@17423
|
87 -
|
pascal@17423
|
88 static void __init parse_header(char *s)
|
pascal@17423
|
89 {
|
pascal@17423
|
90 unsigned long parsed[12];
|
pascal@17423
|
91 @@ -193,7 +208,7 @@
|
pascal@17423
|
92 }
|
pascal@17423
|
93 }
|
pascal@17423
|
94
|
pascal@17423
|
95 -static __initdata char *header_buf, *symlink_buf, *name_buf;
|
pascal@17423
|
96 +static __initdata char *header_buf, *name_buf;
|
pascal@17423
|
97
|
pascal@17423
|
98 static int __init do_start(void)
|
pascal@17423
|
99 {
|
pascal@17423
|
100 @@ -231,17 +246,9 @@
|
pascal@17423
|
101 state = SkipIt;
|
pascal@17423
|
102 if (name_len <= 0 || name_len > PATH_MAX)
|
pascal@17423
|
103 return 0;
|
pascal@17423
|
104 - if (S_ISLNK(mode)) {
|
pascal@17423
|
105 - if (body_len > PATH_MAX)
|
pascal@17423
|
106 - return 0;
|
pascal@17423
|
107 - collect = collected = symlink_buf;
|
pascal@17423
|
108 - remains = N_ALIGN(name_len) + body_len;
|
pascal@17423
|
109 - next_state = GotSymlink;
|
pascal@17423
|
110 - state = Collect;
|
pascal@17423
|
111 + if (S_ISLNK(mode) && (body_len > PATH_MAX))
|
pascal@17423
|
112 return 0;
|
pascal@17423
|
113 - }
|
pascal@17423
|
114 - if (S_ISREG(mode) || !body_len)
|
pascal@17423
|
115 - read_into(name_buf, N_ALIGN(name_len), GotName);
|
pascal@17423
|
116 + read_into(name_buf, N_ALIGN(name_len), GotName);
|
pascal@17423
|
117 return 0;
|
pascal@17423
|
118 }
|
pascal@17423
|
119
|
pascal@17423
|
120 @@ -269,13 +276,34 @@
|
pascal@17423
|
121 static int __init maybe_link(void)
|
pascal@17423
|
122 {
|
pascal@17423
|
123 if (nlink >= 2) {
|
pascal@17423
|
124 - char *old = find_link(major, minor, ino, mode, collected);
|
pascal@17423
|
125 - if (old)
|
pascal@17423
|
126 - return (sys_link(old, collected) < 0) ? -1 : 1;
|
pascal@17423
|
127 + struct hash *p = find_link(collected);
|
pascal@17423
|
128 + if (p->nlink >= 2)
|
pascal@17423
|
129 + return 1;
|
pascal@17423
|
130 }
|
pascal@17423
|
131 return 0;
|
pascal@17423
|
132 }
|
pascal@17423
|
133
|
pascal@17423
|
134 +static void __init walk_names(struct names *p, char *name)
|
pascal@17423
|
135 +{
|
pascal@17423
|
136 + if (!p)
|
pascal@17423
|
137 + return;
|
pascal@17423
|
138 + walk_names(p->next, name);
|
pascal@17423
|
139 + sys_link(name, p->name);
|
pascal@17423
|
140 + kfree(p);
|
pascal@17423
|
141 +}
|
pascal@17423
|
142 +
|
pascal@17423
|
143 +static void __init make_links(char *name)
|
pascal@17423
|
144 +{
|
pascal@17423
|
145 + if (nlink >= 2) {
|
pascal@17423
|
146 + struct hash *p = find_link(name);
|
pascal@17423
|
147 + if (!p->nlink) {
|
pascal@17423
|
148 + walk_names(p->next_name, name);
|
pascal@17423
|
149 + sys_link(name, p->name);
|
pascal@17423
|
150 + p->next_name = NULL;
|
pascal@17423
|
151 + }
|
pascal@17423
|
152 + }
|
pascal@17423
|
153 +}
|
pascal@17423
|
154 +
|
pascal@17423
|
155 static void __init clean_path(char *path, mode_t mode)
|
pascal@17423
|
156 {
|
pascal@17423
|
157 struct stat st;
|
pascal@17423
|
158 @@ -300,11 +328,8 @@
|
pascal@17423
|
159 }
|
pascal@17423
|
160 clean_path(collected, mode);
|
pascal@17423
|
161 if (S_ISREG(mode)) {
|
pascal@17423
|
162 - int ml = maybe_link();
|
pascal@17423
|
163 - if (ml >= 0) {
|
pascal@17423
|
164 - int openflags = O_WRONLY|O_CREAT;
|
pascal@17423
|
165 - if (ml != 1)
|
pascal@17423
|
166 - openflags |= O_TRUNC;
|
pascal@17423
|
167 + if (maybe_link() == 0) {
|
pascal@17423
|
168 + int openflags = O_WRONLY|O_CREAT|O_TRUNC;
|
pascal@17423
|
169 wfd = sys_open(collected, openflags, mode);
|
pascal@17423
|
170
|
pascal@17423
|
171 if (wfd >= 0) {
|
pascal@17423
|
172 @@ -316,6 +341,11 @@
|
pascal@17423
|
173 state = CopyFile;
|
pascal@17423
|
174 }
|
pascal@17423
|
175 }
|
pascal@17423
|
176 + } else if (S_ISLNK(mode)) {
|
pascal@17423
|
177 + if (maybe_link() == 0) {
|
pascal@17423
|
178 + vcollected = kstrdup(collected, GFP_KERNEL);
|
pascal@17423
|
179 + state = GotSymlink;
|
pascal@17423
|
180 + }
|
pascal@17423
|
181 } else if (S_ISDIR(mode)) {
|
pascal@17423
|
182 sys_mkdir(collected, mode);
|
pascal@17423
|
183 sys_chown(collected, uid, gid);
|
pascal@17423
|
184 @@ -328,6 +358,7 @@
|
pascal@17423
|
185 sys_chown(collected, uid, gid);
|
pascal@17423
|
186 sys_chmod(collected, mode);
|
pascal@17423
|
187 do_utime(collected, mtime);
|
pascal@17423
|
188 + make_links(collected);
|
pascal@17423
|
189 }
|
pascal@17423
|
190 }
|
pascal@17423
|
191 return 0;
|
pascal@17423
|
192 @@ -339,6 +370,7 @@
|
pascal@17423
|
193 sys_write(wfd, victim, body_len);
|
pascal@17423
|
194 sys_close(wfd);
|
pascal@17423
|
195 do_utime(vcollected, mtime);
|
pascal@17423
|
196 + make_links(vcollected);
|
pascal@17423
|
197 kfree(vcollected);
|
pascal@17423
|
198 eat(body_len);
|
pascal@17423
|
199 state = SkipIt;
|
pascal@17423
|
200 @@ -353,13 +385,18 @@
|
pascal@17423
|
201
|
pascal@17423
|
202 static int __init do_symlink(void)
|
pascal@17423
|
203 {
|
pascal@17423
|
204 - collected[N_ALIGN(name_len) + body_len] = '\0';
|
pascal@17423
|
205 - clean_path(collected, 0);
|
pascal@17423
|
206 - sys_symlink(collected + N_ALIGN(name_len), collected);
|
pascal@17423
|
207 - sys_lchown(collected, uid, gid);
|
pascal@17423
|
208 - do_utime(collected, mtime);
|
pascal@17423
|
209 + char c = victim[body_len];
|
pascal@17423
|
210 +
|
pascal@17423
|
211 + victim[body_len] = '\0';
|
pascal@17423
|
212 + clean_path(vcollected, 0);
|
pascal@17423
|
213 + sys_symlink(victim, vcollected);
|
pascal@17423
|
214 + victim[body_len] = c;
|
pascal@17423
|
215 + sys_lchown(vcollected, uid, gid);
|
pascal@17423
|
216 + do_utime(vcollected, mtime);
|
pascal@17423
|
217 + make_links(vcollected);
|
pascal@17423
|
218 + kfree(vcollected);
|
pascal@17423
|
219 + eat(body_len);
|
pascal@17423
|
220 state = SkipIt;
|
pascal@17423
|
221 - next_state = Reset;
|
pascal@17423
|
222 return 0;
|
pascal@17423
|
223 }
|
pascal@17423
|
224
|
pascal@17423
|
225 @@ -419,10 +456,9 @@
|
pascal@17423
|
226 static __initdata char msg_buf[64];
|
pascal@17423
|
227
|
pascal@17423
|
228 header_buf = kmalloc(110, GFP_KERNEL);
|
pascal@17423
|
229 - symlink_buf = kmalloc(PATH_MAX + N_ALIGN(PATH_MAX) + 1, GFP_KERNEL);
|
pascal@17423
|
230 name_buf = kmalloc(N_ALIGN(PATH_MAX), GFP_KERNEL);
|
pascal@17423
|
231
|
pascal@17423
|
232 - if (!header_buf || !symlink_buf || !name_buf)
|
pascal@17423
|
233 + if (!header_buf || !name_buf)
|
pascal@17423
|
234 panic("can't allocate buffers");
|
pascal@17423
|
235
|
pascal@17423
|
236 state = Start;
|
pascal@17423
|
237 @@ -467,7 +503,6 @@
|
pascal@17423
|
238 }
|
pascal@17423
|
239 dir_utime();
|
pascal@17423
|
240 kfree(name_buf);
|
pascal@17423
|
241 - kfree(symlink_buf);
|
pascal@17423
|
242 kfree(header_buf);
|
pascal@17423
|
243 return message;
|
pascal@17423
|
244 }
|