- apply http://lkml.org/lkml/2006/4/7/149
authorMark Huang <mlhuang@cs.princeton.edu>
Thu, 4 May 2006 14:32:21 +0000 (14:32 +0000)
committerMark Huang <mlhuang@cs.princeton.edu>
Thu, 4 May 2006 14:32:21 +0000 (14:32 +0000)
Unlink files, symlinks, FIFOs, devices etc. (except directories) before
writing them when extracting CPIOs.  This stops weird behaviour like:
  1) writing through symlinks created in earlier CPIOs. eg foo->bar in
     the first CPIO.  Having foo as a non-link in a subsequent CPIO,
     results in bar being written and foo remaining as a symlink.
  2) if the first version of file foo is larger than foo in a
     subsequent CPIO, we end up with a mix of the two.  ie. neither
     the first or second version of /foo.
  3) special files like devices, fifo etc. can't be overwritten in
     subsequent CPIOS.

With this, the kernel will more closely replicate
   for i in *.cpio; do cpio --extract --unconditional < $i ; done

This is a change but it's regarded as fixing broken functionality.

Signed-off-by: Michael Neuling <mikey@neuling.org>
Signed-off-by: H. Peter Anvin <hpa@zytor.com>
init/initramfs.c

index 6d70d82..be7f53c 100644 (file)
@@ -249,6 +249,7 @@ static int __init do_name(void)
        if (dry_run)
                return 0;
        if (S_ISREG(mode)) {
+               sys_unlink(collected);
                if (maybe_link() >= 0) {
                        wfd = sys_open(collected, O_WRONLY|O_CREAT, mode);
                        if (wfd >= 0) {
@@ -263,6 +264,7 @@ static int __init do_name(void)
                sys_chmod(collected, mode);
        } else if (S_ISBLK(mode) || S_ISCHR(mode) ||
                   S_ISFIFO(mode) || S_ISSOCK(mode)) {
+               sys_unlink(collected);
                if (maybe_link() == 0) {
                        sys_mknod(collected, mode, rdev);
                        sys_chown(collected, uid, gid);
@@ -291,6 +293,7 @@ static int __init do_copy(void)
 static int __init do_symlink(void)
 {
        collected[N_ALIGN(name_len) + body_len] = '\0';
+       sys_unlink(collected);
        sys_symlink(collected + N_ALIGN(name_len), collected);
        sys_lchown(collected, uid, gid);
        state = SkipIt;