wok annotate linux/stuff/linux-hardlinks.u @ rev 17426

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