diff options
| -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; |
