summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--init/initramfs.c53
1 files changed, 53 insertions, 0 deletions
diff --git a/init/initramfs.c b/init/initramfs.c
index 644fc01ad5f0..4f5ba75aaa7c 100644
--- a/init/initramfs.c
+++ b/init/initramfs.c
@@ -6,6 +6,7 @@
#include <linux/delay.h>
#include <linux/string.h>
#include <linux/syscalls.h>
+#include <linux/utime.h>
static __initdata char *message;
static void __init error(char *x)
@@ -72,6 +73,49 @@ static void __init free_hash(void)
}
}
+static long __init do_utime(char __user *filename, time_t mtime)
+{
+ struct timespec t[2];
+
+ t[0].tv_sec = mtime;
+ t[0].tv_nsec = 0;
+ t[1].tv_sec = mtime;
+ t[1].tv_nsec = 0;
+
+ return do_utimes(AT_FDCWD, filename, t, AT_SYMLINK_NOFOLLOW);
+}
+
+static __initdata LIST_HEAD(dir_list);
+struct dir_entry {
+ struct list_head list;
+ char *name;
+ time_t mtime;
+};
+
+static void __init dir_add(const char *name, time_t mtime)
+{
+ struct dir_entry *de = kmalloc(sizeof(struct dir_entry), GFP_KERNEL);
+ if (!de)
+ panic("can't allocate dir_entry buffer");
+ INIT_LIST_HEAD(&de->list);
+ de->name = kstrdup(name, GFP_KERNEL);
+ de->mtime = mtime;
+ list_add(&de->list, &dir_list);
+}
+
+static void __init dir_utime(void)
+{
+ struct dir_entry *de, *tmp;
+ list_for_each_entry_safe(de, tmp, &dir_list, list) {
+ list_del(&de->list);
+ do_utime(de->name, de->mtime);
+ kfree(de->name);
+ kfree(de);
+ }
+}
+
+static __initdata time_t mtime;
+
/* cpio header parsing */
static __initdata unsigned long ino, major, minor, nlink;
@@ -97,6 +141,7 @@ static void __init parse_header(char *s)
uid = parsed[2];
gid = parsed[3];
nlink = parsed[4];
+ mtime = parsed[5];
body_len = parsed[6];
major = parsed[7];
minor = parsed[8];
@@ -130,6 +175,7 @@ static inline void __init eat(unsigned n)
count -= n;
}
+static __initdata char *vcollected;
static __initdata char *collected;
static __initdata int remains;
static __initdata char *collect;
@@ -271,6 +317,7 @@ static int __init do_name(void)
if (wfd >= 0) {
sys_fchown(wfd, uid, gid);
sys_fchmod(wfd, mode);
+ vcollected = kstrdup(collected, GFP_KERNEL);
state = CopyFile;
}
}
@@ -278,12 +325,14 @@ static int __init do_name(void)
sys_mkdir(collected, mode);
sys_chown(collected, uid, gid);
sys_chmod(collected, mode);
+ dir_add(collected, mtime);
} else if (S_ISBLK(mode) || S_ISCHR(mode) ||
S_ISFIFO(mode) || S_ISSOCK(mode)) {
if (maybe_link() == 0) {
sys_mknod(collected, mode, rdev);
sys_chown(collected, uid, gid);
sys_chmod(collected, mode);
+ do_utime(collected, mtime);
}
}
return 0;
@@ -294,6 +343,8 @@ static int __init do_copy(void)
if (count >= body_len) {
sys_write(wfd, victim, body_len);
sys_close(wfd);
+ do_utime(vcollected, mtime);
+ kfree(vcollected);
eat(body_len);
state = SkipIt;
return 0;
@@ -311,6 +362,7 @@ static int __init do_symlink(void)
clean_path(collected, 0);
sys_symlink(collected + N_ALIGN(name_len), collected);
sys_lchown(collected, uid, gid);
+ do_utime(collected, mtime);
state = SkipIt;
next_state = Reset;
return 0;
@@ -466,6 +518,7 @@ static char * __init unpack_to_rootfs(char *buf, unsigned len, int check_only)
buf += inptr;
len -= inptr;
}
+ dir_utime();
kfree(window);
kfree(name_buf);
kfree(symlink_buf);