wok-next diff linux-uml/stuff/linux-hardlinks.u @ rev 19916
shake: tiny patch
author | Pascal Bellard <pascal.bellard@slitaz.org> |
---|---|
date | Fri Oct 13 18:15:08 2017 +0200 (2017-10-13) |
parents | |
children |
line diff
1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/linux-uml/stuff/linux-hardlinks.u Fri Oct 13 18:15:08 2017 +0200 1.3 @@ -0,0 +1,244 @@ 1.4 +Fix hardlink on fifos, sockets, char & block devices and symlinks 1.5 +--- linux-3.2.53/init/initramfs.c 1.6 ++++ linux-3.2.53/init/initramfs.c 1.7 +@@ -20,10 +20,24 @@ 1.8 + 1.9 + #define N_ALIGN(len) ((((len) + 1) & ~3) + 2) 1.10 + 1.11 ++static __initdata unsigned long ino, major, minor, nlink; 1.12 ++static __initdata time_t mtime; 1.13 ++static __initdata mode_t mode; 1.14 ++static __initdata unsigned long body_len, name_len; 1.15 ++static __initdata uid_t uid; 1.16 ++static __initdata gid_t gid; 1.17 ++static __initdata unsigned rdev; 1.18 ++ 1.19 ++struct names { 1.20 ++ struct names *next; 1.21 ++ char name[1]; 1.22 ++}; 1.23 ++ 1.24 + static __initdata struct hash { 1.25 +- int ino, minor, major; 1.26 ++ int ino, nlink, minor, major; 1.27 + mode_t mode; 1.28 + struct hash *next; 1.29 ++ struct names *next_name; 1.30 + char name[N_ALIGN(PATH_MAX)]; 1.31 + } *head[32]; 1.32 + 1.33 +@@ -34,8 +48,7 @@ 1.34 + return tmp & 31; 1.35 + } 1.36 + 1.37 +-static char __init *find_link(int major, int minor, int ino, 1.38 +- mode_t mode, char *name) 1.39 ++static struct hash __init *find_link(char *name) 1.40 + { 1.41 + struct hash **p, *q; 1.42 + for (p = head + hash(major, minor, ino); *p; p = &(*p)->next) { 1.43 +@@ -47,7 +60,16 @@ 1.44 + continue; 1.45 + if (((*p)->mode ^ mode) & S_IFMT) 1.46 + continue; 1.47 +- return (*p)->name; 1.48 ++ if (--(*p)->nlink) { 1.49 ++ struct names **n; 1.50 ++ for (n = &(*p)->next_name; *n; n = &(*n)->next); 1.51 ++ *n = kmalloc(sizeof(struct names) + strlen(name), GFP_KERNEL); 1.52 ++ if (!*n) 1.53 ++ panic("can't allocate link name entry"); 1.54 ++ strcpy((*n)->name, name); 1.55 ++ (*n)->next = NULL; 1.56 ++ } 1.57 ++ return *p; 1.58 + } 1.59 + q = kmalloc(sizeof(struct hash), GFP_KERNEL); 1.60 + if (!q) 1.61 +@@ -55,11 +77,13 @@ 1.62 + q->major = major; 1.63 + q->minor = minor; 1.64 + q->ino = ino; 1.65 ++ q->nlink = nlink; 1.66 + q->mode = mode; 1.67 + strcpy(q->name, name); 1.68 ++ q->next_name = NULL; 1.69 + q->next = NULL; 1.70 + *p = q; 1.71 +- return NULL; 1.72 ++ return q; 1.73 + } 1.74 + 1.75 + static void __init free_hash(void) 1.76 +@@ -115,17 +139,8 @@ 1.77 + } 1.78 + } 1.79 + 1.80 +-static __initdata time_t mtime; 1.81 +- 1.82 + /* cpio header parsing */ 1.83 + 1.84 +-static __initdata unsigned long ino, major, minor, nlink; 1.85 +-static __initdata mode_t mode; 1.86 +-static __initdata unsigned long body_len, name_len; 1.87 +-static __initdata uid_t uid; 1.88 +-static __initdata gid_t gid; 1.89 +-static __initdata unsigned rdev; 1.90 +- 1.91 + static void __init parse_header(char *s) 1.92 + { 1.93 + unsigned long parsed[12]; 1.94 +@@ -193,7 +208,7 @@ 1.95 + } 1.96 + } 1.97 + 1.98 +-static __initdata char *header_buf, *symlink_buf, *name_buf; 1.99 ++static __initdata char *header_buf, *name_buf; 1.100 + 1.101 + static int __init do_start(void) 1.102 + { 1.103 +@@ -231,17 +246,9 @@ 1.104 + state = SkipIt; 1.105 + if (name_len <= 0 || name_len > PATH_MAX) 1.106 + return 0; 1.107 +- if (S_ISLNK(mode)) { 1.108 +- if (body_len > PATH_MAX) 1.109 +- return 0; 1.110 +- collect = collected = symlink_buf; 1.111 +- remains = N_ALIGN(name_len) + body_len; 1.112 +- next_state = GotSymlink; 1.113 +- state = Collect; 1.114 ++ if (S_ISLNK(mode) && (body_len > PATH_MAX)) 1.115 + return 0; 1.116 +- } 1.117 +- if (S_ISREG(mode) || !body_len) 1.118 +- read_into(name_buf, N_ALIGN(name_len), GotName); 1.119 ++ read_into(name_buf, N_ALIGN(name_len), GotName); 1.120 + return 0; 1.121 + } 1.122 + 1.123 +@@ -269,13 +276,34 @@ 1.124 + static int __init maybe_link(void) 1.125 + { 1.126 + if (nlink >= 2) { 1.127 +- char *old = find_link(major, minor, ino, mode, collected); 1.128 +- if (old) 1.129 +- return (sys_link(old, collected) < 0) ? -1 : 1; 1.130 ++ struct hash *p = find_link(collected); 1.131 ++ if (p->nlink >= 2) 1.132 ++ return 1; 1.133 + } 1.134 + return 0; 1.135 + } 1.136 + 1.137 ++static void __init walk_names(struct names *p, char *name) 1.138 ++{ 1.139 ++ if (!p) 1.140 ++ return; 1.141 ++ walk_names(p->next, name); 1.142 ++ sys_link(name, p->name); 1.143 ++ kfree(p); 1.144 ++} 1.145 ++ 1.146 ++static void __init make_links(char *name) 1.147 ++{ 1.148 ++ if (nlink >= 2) { 1.149 ++ struct hash *p = find_link(name); 1.150 ++ if (!p->nlink) { 1.151 ++ walk_names(p->next_name, name); 1.152 ++ sys_link(name, p->name); 1.153 ++ p->next_name = NULL; 1.154 ++ } 1.155 ++ } 1.156 ++} 1.157 ++ 1.158 + static void __init clean_path(char *path, mode_t mode) 1.159 + { 1.160 + struct stat st; 1.161 +@@ -300,11 +328,8 @@ 1.162 + } 1.163 + clean_path(collected, mode); 1.164 + if (S_ISREG(mode)) { 1.165 +- int ml = maybe_link(); 1.166 +- if (ml >= 0) { 1.167 +- int openflags = O_WRONLY|O_CREAT; 1.168 +- if (ml != 1) 1.169 +- openflags |= O_TRUNC; 1.170 ++ if (maybe_link() == 0) { 1.171 ++ int openflags = O_WRONLY|O_CREAT|O_TRUNC; 1.172 + wfd = sys_open(collected, openflags, mode); 1.173 + 1.174 + if (wfd >= 0) { 1.175 +@@ -316,6 +341,11 @@ 1.176 + state = CopyFile; 1.177 + } 1.178 + } 1.179 ++ } else if (S_ISLNK(mode)) { 1.180 ++ if (maybe_link() == 0) { 1.181 ++ vcollected = kstrdup(collected, GFP_KERNEL); 1.182 ++ state = GotSymlink; 1.183 ++ } 1.184 + } else if (S_ISDIR(mode)) { 1.185 + sys_mkdir(collected, mode); 1.186 + sys_chown(collected, uid, gid); 1.187 +@@ -328,6 +358,7 @@ 1.188 + sys_chown(collected, uid, gid); 1.189 + sys_chmod(collected, mode); 1.190 + do_utime(collected, mtime); 1.191 ++ make_links(collected); 1.192 + } 1.193 + } 1.194 + return 0; 1.195 +@@ -339,6 +370,7 @@ 1.196 + sys_write(wfd, victim, body_len); 1.197 + sys_close(wfd); 1.198 + do_utime(vcollected, mtime); 1.199 ++ make_links(vcollected); 1.200 + kfree(vcollected); 1.201 + eat(body_len); 1.202 + state = SkipIt; 1.203 +@@ -353,13 +385,18 @@ 1.204 + 1.205 + static int __init do_symlink(void) 1.206 + { 1.207 +- collected[N_ALIGN(name_len) + body_len] = '\0'; 1.208 +- clean_path(collected, 0); 1.209 +- sys_symlink(collected + N_ALIGN(name_len), collected); 1.210 +- sys_lchown(collected, uid, gid); 1.211 +- do_utime(collected, mtime); 1.212 ++ char c = victim[body_len]; 1.213 ++ 1.214 ++ victim[body_len] = '\0'; 1.215 ++ clean_path(vcollected, 0); 1.216 ++ sys_symlink(victim, vcollected); 1.217 ++ victim[body_len] = c; 1.218 ++ sys_lchown(vcollected, uid, gid); 1.219 ++ do_utime(vcollected, mtime); 1.220 ++ make_links(vcollected); 1.221 ++ kfree(vcollected); 1.222 ++ eat(body_len); 1.223 + state = SkipIt; 1.224 +- next_state = Reset; 1.225 + return 0; 1.226 + } 1.227 + 1.228 +@@ -419,10 +456,9 @@ 1.229 + static __initdata char msg_buf[64]; 1.230 + 1.231 + header_buf = kmalloc(110, GFP_KERNEL); 1.232 +- symlink_buf = kmalloc(PATH_MAX + N_ALIGN(PATH_MAX) + 1, GFP_KERNEL); 1.233 + name_buf = kmalloc(N_ALIGN(PATH_MAX), GFP_KERNEL); 1.234 + 1.235 +- if (!header_buf || !symlink_buf || !name_buf) 1.236 ++ if (!header_buf || !name_buf) 1.237 + panic("can't allocate buffers"); 1.238 + 1.239 + state = Start; 1.240 +@@ -467,7 +503,6 @@ 1.241 + } 1.242 + dir_utime(); 1.243 + kfree(name_buf); 1.244 +- kfree(symlink_buf); 1.245 + kfree(header_buf); 1.246 + return message; 1.247 + }