source: npl/system/klibc/patches/Fix-minimal-mv-to-work-across-fs @ c5c522c

gcc484ntopperl-5.22
Last change on this file since c5c522c was c5c522c, checked in by Edwin Eefting <edwin@datux.nl>, 8 years ago

initial commit, transferred from cleaned syn3 svn tree

  • Property mode set to 100644
File size: 6.3 KB
Line 
1From: maximilian attems <max@stro.at>
2Date: Mon, 4 Jul 2011 17:51:52 +0200
3Subject: [PATCH] [klibc] Fix minimal mv to work across fs
4Forwarded: not-needed
5
6This is the use case in initramfs to keep data from /run to /root/run
7before calling switch_root().
8
9copy_file() doesn't yet catch EINTR, but that seems less of an issue
10in initramfs.
11
12copy_file() and much logic out of copy() is from Ulrich Dangel.
13Thank you for the collaboration on this blocker for
14http://bugs.debian.org/627808
15
16While we are it require move to have mv at least 2 arguments passed.
17
18Signed-off-by: Ulrich Dangel <uli@spamt.net>
19Signed-off-by: maximilian attems <max@stro.at>
20[bwh: This is no longer needed by initramfs-tools starting with version 0.121,
21 so can be dropped after the stretch release]
22---
23 usr/utils/mv.c |  234 +++++++++++++++++++++++++++++++++++++++++++++++++++-----
24 1 files changed, 216 insertions(+), 18 deletions(-)
25
26Index: klibc-2.0~rc2/usr/utils/mv.c
27===================================================================
28--- klibc-2.0~rc2.orig/usr/utils/mv.c   2012-02-11 18:50:21.000000000 +0000
29+++ klibc-2.0~rc2/usr/utils/mv.c        2012-02-11 19:04:54.000000000 +0000
30@@ -1,3 +1,6 @@
31+#include <errno.h>
32+#include <dirent.h>
33+#include <fcntl.h>
34 #include <stdio.h>
35 #include <stdlib.h>
36 #include <string.h>
37@@ -7,10 +10,204 @@
38 
39 #include <linux/limits.h>
40 
41+#define BUFFER_SIZE 32768
42+
43+/* copy_file - copy a file, used on different fs mv */
44+static int copy_file(const char *src, const char *dest, mode_t mode)
45+{
46+       char buf[BUFFER_SIZE];
47+       int sfd, dfd;
48+       ssize_t len;
49+
50+       sfd = open(src, O_RDONLY);
51+       if (sfd < 0)
52+               return -1;
53+
54+       dfd = open(dest, O_WRONLY | O_CREAT, mode);
55+       if (dfd < 0) {
56+               close(sfd);
57+               return -1;
58+       }
59+
60+       while ((len = read(sfd, buf, sizeof(buf))) > 0) {
61+               len = write(dfd, buf, len);
62+               if (len < 0) {
63+                       close(sfd);
64+                       close(dfd);
65+                       return -1;
66+               }
67+       }
68+
69+       close(sfd);
70+       close(dfd);
71+       return 0;
72+}
73+
74+/* copy - recursively copy directories */
75+static int copy(char *src, const char *dest)
76+{
77+       int len;
78+       struct stat sb, sf;
79+       char target[PATH_MAX];
80+       char *p;
81+
82+       p = strrchr(src, '/');
83+       if (p) {
84+               p++;
85+               /* trailing slashes case */
86+               if (strlen(p) == 0) {
87+                       len = strlen(src) - 1;
88+                       p = src;
89+                       while (0 < len && p[len] == '/')
90+                               p[len--] = '\0';
91+                       p = strrchr(p, '/');
92+                       p++;
93+               }
94+       } else {
95+               p = src;
96+       }
97+
98+       memset(&sb, 0, sizeof(struct stat));
99+       /* might not exist yet */
100+       if (stat(dest, &sb) == 0) {
101+               if (S_ISDIR(sb.st_mode)) {
102+                       len = snprintf(target, PATH_MAX, "%s/%s", dest, p);
103+                       if (len  >= PATH_MAX)
104+                               return -1;
105+               } else {
106+                       len = snprintf(target, PATH_MAX, "%s/%s", dest, src);
107+                       if (len  >= PATH_MAX)
108+                               return -1;
109+               }
110+       } else {
111+               len = snprintf(target, PATH_MAX, "%s", dest);
112+               if (len  >= PATH_MAX)
113+                       return -1;
114+       }
115+
116+       if (rename(src, target) == 0) {
117+               return 0;
118+       } else {
119+               if (errno != EXDEV)
120+                       return -1;
121+       }
122+
123+
124+       /* cross fs copy */
125+       memset(&sf, 0, sizeof(struct stat));
126+       if (stat(src, &sf) < 0)
127+               return -1;
128+       if (!S_ISDIR(sf.st_mode)) {
129+               len = copy_file(src, target, sf.st_mode);
130+               if (len == 0)
131+                       return 0;
132+               else
133+                       return -1;
134+       }
135+
136+       DIR *dir;
137+       struct dirent *d;
138+       char path[PATH_MAX];
139+
140+       if (mkdir(target, sf.st_mode) < 0)
141+               return -1;
142+
143+       dir = opendir(src);
144+       if (!dir) {
145+               /* EACCES means we can't read it.
146+                * Might be empty and removable. */
147+               if (errno != EACCES)
148+                       return -1;
149+       }
150+       while ((d = readdir(dir))) {
151+
152+               /* Skip . and .. */
153+               if (d->d_name[0] == '.' && (d->d_name[1] == '\0'
154+                   || (d->d_name[1] == '.' && d->d_name[2] == '\0')))
155+                       continue;
156+
157+               /* skip to long path */
158+               if (strlen(src) + 1 + strlen(d->d_name) >= PATH_MAX  - 1)
159+                       continue;
160+
161+               snprintf(path, sizeof path, "%s/%s", src, d->d_name);
162+               if (len  >= sizeof path)
163+                       return -1;
164+
165+               memset(&sf, 0, sizeof(struct stat));
166+               if (stat(path, &sf) < 0) {
167+                       closedir(dir);
168+                       return -1;
169+               }
170+
171+               /* recursively copy files and directories */
172+               if (copy(path, target) < 0)
173+                       return -1;
174+       }
175+       closedir(dir);
176+       return 0;
177+}
178+
179+/* nuke - rm a file or directory recursively */
180+static int nuke(const char *src)
181+{
182+       struct stat sb;
183+       DIR *dir;
184+       struct dirent *d;
185+       char path[PATH_MAX];
186+       int len;
187+
188+       memset(&sb, 0, sizeof(struct stat));
189+       /* gone, no work */
190+       if (stat(src, &sb) < 0)
191+               return 0;
192+
193+       if (!S_ISDIR(sb.st_mode)) {
194+               if (unlink(src) == 0)
195+                       return 0;
196+               else
197+                       return 1;
198+       }
199+
200+       dir = opendir(src);
201+       if (!dir) {
202+               /* EACCES means we can't read it.
203+                * Might be empty and removable. */
204+               if (errno != EACCES)
205+                       return -1;
206+       }
207+       while ((d = readdir(dir))) {
208+
209+               /* Skip . and .. */
210+               if (d->d_name[0] == '.' && (d->d_name[1] == '\0'
211+                   || (d->d_name[1] == '.' && d->d_name[2] == '\0')))
212+                       continue;
213+
214+               /* skip to long path */
215+               if (strlen(src) + 1 + strlen(d->d_name) >= PATH_MAX  - 1)
216+                       continue;
217+
218+               len = snprintf(path, sizeof path, "%s/%s", src, d->d_name);
219+               if (len  >= sizeof path)
220+                       return -1;
221+
222+               memset(&sb, 0, sizeof(struct stat));
223+               if (stat(path, &sb) < 0) {
224+                       closedir(dir);
225+                       return -1;
226+               }
227+
228+               if (nuke(path) < 0)
229+                       return -1;
230+       }
231+       closedir(dir);
232+       rmdir(src);
233+       return 0;
234+}
235+
236 int main(int argc, char *argv[])
237 {
238        int c, f;
239-       char *p;
240        struct stat sb;
241 
242        f = 0;
243@@ -32,11 +229,13 @@
244 
245        } while (1);
246 
247-       if (optind == argc) {
248+       /* not enough arguments */
249+       if (argc - optind < 2) {
250                fprintf(stderr, "Usage: %s [-f] source dest\n", argv[0]);
251                return 1;
252        }
253 
254+       /* check on many archs if destination is a directory to mv in */
255        memset(&sb, 0, sizeof(struct stat));
256        if (stat(argv[argc - 1], &sb) < 0 && argc - optind > 2) {
257                if (!(S_ISDIR(sb.st_mode))) {
258@@ -47,23 +246,22 @@
259                }
260        }
261 
262-       for (c = optind; c < argc - 1; c++) {
263-               char target[PATH_MAX];
264-
265-               p = strrchr(argv[c], '/');
266-               p++;
267-
268-               if (S_ISDIR(sb.st_mode))
269-                       snprintf(target, PATH_MAX, "%s/%s", argv[argc - 1], p);
270-               else
271-                       snprintf(target, PATH_MAX, "%s", argv[argc - 1]);
272-
273-               if (f)
274-                       unlink(target);
275-
276-               if (rename(argv[c], target) == -1)
277-                       perror(target);
278-       }
279+       /* remove destination */
280+       if (f)
281+               nuke(argv[argc - 1]);
282+
283+       /* the mv action */
284+       for (c = optind; c < argc - 1; c++)
285+               if (copy(argv[c], argv[argc - 1]) < 0) {
286+                       perror("Could not copy file");
287+                       return -1;
288+               }
289 
290+       /* Only rm after sucessfull rename */
291+       for (c = optind; c < argc - 1; c++)
292+               if (nuke(argv[c]) < 0) {
293+                       perror("Could not rm file");
294+                       return -1;
295+               }
296        return 0;
297 }
Note: See TracBrowser for help on using the repository browser.