diff options
Diffstat (limited to 'init/initramfs.c')
-rw-r--r-- | init/initramfs.c | 36 |
1 files changed, 30 insertions, 6 deletions
diff --git a/init/initramfs.c b/init/initramfs.c index f81cfa40a719..d28c1094d7e5 100644 --- a/init/initramfs.c +++ b/init/initramfs.c | |||
@@ -30,6 +30,7 @@ static void __init free(void *where) | |||
30 | 30 | ||
31 | static __initdata struct hash { | 31 | static __initdata struct hash { |
32 | int ino, minor, major; | 32 | int ino, minor, major; |
33 | mode_t mode; | ||
33 | struct hash *next; | 34 | struct hash *next; |
34 | char name[N_ALIGN(PATH_MAX)]; | 35 | char name[N_ALIGN(PATH_MAX)]; |
35 | } *head[32]; | 36 | } *head[32]; |
@@ -41,7 +42,8 @@ static inline int hash(int major, int minor, int ino) | |||
41 | return tmp & 31; | 42 | return tmp & 31; |
42 | } | 43 | } |
43 | 44 | ||
44 | static char __init *find_link(int major, int minor, int ino, char *name) | 45 | static char __init *find_link(int major, int minor, int ino, |
46 | mode_t mode, char *name) | ||
45 | { | 47 | { |
46 | struct hash **p, *q; | 48 | struct hash **p, *q; |
47 | for (p = head + hash(major, minor, ino); *p; p = &(*p)->next) { | 49 | for (p = head + hash(major, minor, ino); *p; p = &(*p)->next) { |
@@ -51,14 +53,17 @@ static char __init *find_link(int major, int minor, int ino, char *name) | |||
51 | continue; | 53 | continue; |
52 | if ((*p)->major != major) | 54 | if ((*p)->major != major) |
53 | continue; | 55 | continue; |
56 | if (((*p)->mode ^ mode) & S_IFMT) | ||
57 | continue; | ||
54 | return (*p)->name; | 58 | return (*p)->name; |
55 | } | 59 | } |
56 | q = (struct hash *)malloc(sizeof(struct hash)); | 60 | q = (struct hash *)malloc(sizeof(struct hash)); |
57 | if (!q) | 61 | if (!q) |
58 | panic("can't allocate link hash entry"); | 62 | panic("can't allocate link hash entry"); |
59 | q->ino = ino; | ||
60 | q->minor = minor; | ||
61 | q->major = major; | 63 | q->major = major; |
64 | q->minor = minor; | ||
65 | q->ino = ino; | ||
66 | q->mode = mode; | ||
62 | strcpy(q->name, name); | 67 | strcpy(q->name, name); |
63 | q->next = NULL; | 68 | q->next = NULL; |
64 | *p = q; | 69 | *p = q; |
@@ -229,13 +234,25 @@ static int __init do_reset(void) | |||
229 | static int __init maybe_link(void) | 234 | static int __init maybe_link(void) |
230 | { | 235 | { |
231 | if (nlink >= 2) { | 236 | if (nlink >= 2) { |
232 | char *old = find_link(major, minor, ino, collected); | 237 | char *old = find_link(major, minor, ino, mode, collected); |
233 | if (old) | 238 | if (old) |
234 | return (sys_link(old, collected) < 0) ? -1 : 1; | 239 | return (sys_link(old, collected) < 0) ? -1 : 1; |
235 | } | 240 | } |
236 | return 0; | 241 | return 0; |
237 | } | 242 | } |
238 | 243 | ||
244 | static void __init clean_path(char *path, mode_t mode) | ||
245 | { | ||
246 | struct stat st; | ||
247 | |||
248 | if (!sys_newlstat(path, &st) && (st.st_mode^mode) & S_IFMT) { | ||
249 | if (S_ISDIR(st.st_mode)) | ||
250 | sys_rmdir(path); | ||
251 | else | ||
252 | sys_unlink(path); | ||
253 | } | ||
254 | } | ||
255 | |||
239 | static __initdata int wfd; | 256 | static __initdata int wfd; |
240 | 257 | ||
241 | static int __init do_name(void) | 258 | static int __init do_name(void) |
@@ -248,9 +265,15 @@ static int __init do_name(void) | |||
248 | } | 265 | } |
249 | if (dry_run) | 266 | if (dry_run) |
250 | return 0; | 267 | return 0; |
268 | clean_path(collected, mode); | ||
251 | if (S_ISREG(mode)) { | 269 | if (S_ISREG(mode)) { |
252 | if (maybe_link() >= 0) { | 270 | int ml = maybe_link(); |
253 | wfd = sys_open(collected, O_WRONLY|O_CREAT, mode); | 271 | if (ml >= 0) { |
272 | int openflags = O_WRONLY|O_CREAT; | ||
273 | if (ml != 1) | ||
274 | openflags |= O_TRUNC; | ||
275 | wfd = sys_open(collected, openflags, mode); | ||
276 | |||
254 | if (wfd >= 0) { | 277 | if (wfd >= 0) { |
255 | sys_fchown(wfd, uid, gid); | 278 | sys_fchown(wfd, uid, gid); |
256 | sys_fchmod(wfd, mode); | 279 | sys_fchmod(wfd, mode); |
@@ -291,6 +314,7 @@ static int __init do_copy(void) | |||
291 | static int __init do_symlink(void) | 314 | static int __init do_symlink(void) |
292 | { | 315 | { |
293 | collected[N_ALIGN(name_len) + body_len] = '\0'; | 316 | collected[N_ALIGN(name_len) + body_len] = '\0'; |
317 | clean_path(collected, 0); | ||
294 | sys_symlink(collected + N_ALIGN(name_len), collected); | 318 | sys_symlink(collected + N_ALIGN(name_len), collected); |
295 | sys_lchown(collected, uid, gid); | 319 | sys_lchown(collected, uid, gid); |
296 | state = SkipIt; | 320 | state = SkipIt; |