1 |
commit: 117869a1b0d19c5e3a6b59e9e43e6849ed92efd4 |
2 |
Author: Fabian Groffen <grobian <AT> gentoo <DOT> org> |
3 |
AuthorDate: Sun Dec 26 13:48:49 2021 +0000 |
4 |
Commit: Fabian Groffen <grobian <AT> gentoo <DOT> org> |
5 |
CommitDate: Sun Dec 26 13:48:49 2021 +0000 |
6 |
URL: https://gitweb.gentoo.org/proj/portage-utils.git/commit/?id=117869a1 |
7 |
|
8 |
libq/move_file: code to move a file or copy+remove it |
9 |
|
10 |
This code originated from qmerge.c, it was adapted to be more generic in |
11 |
a function. |
12 |
|
13 |
Signed-off-by: Fabian Groffen <grobian <AT> gentoo.org> |
14 |
|
15 |
libq/Makefile.am | 1 + |
16 |
libq/move_file.c | 105 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
17 |
libq/move_file.h | 21 +++++++++++ |
18 |
3 files changed, 127 insertions(+) |
19 |
|
20 |
diff --git a/libq/Makefile.am b/libq/Makefile.am |
21 |
index da100b6..c0402a4 100644 |
22 |
--- a/libq/Makefile.am |
23 |
+++ b/libq/Makefile.am |
24 |
@@ -11,6 +11,7 @@ QFILES = \ |
25 |
hash.c hash.h \ |
26 |
human_readable.c human_readable.h \ |
27 |
i18n.h \ |
28 |
+ move_file.c move_file.h \ |
29 |
prelink.c prelink.h \ |
30 |
profile.c profile.h \ |
31 |
rmspace.c rmspace.h \ |
32 |
|
33 |
diff --git a/libq/move_file.c b/libq/move_file.c |
34 |
new file mode 100644 |
35 |
index 0000000..07cf69f |
36 |
--- /dev/null |
37 |
+++ b/libq/move_file.c |
38 |
@@ -0,0 +1,105 @@ |
39 |
+/* |
40 |
+ * Copyright 2005-2021 Gentoo Authors |
41 |
+ * Distributed under the terms of the GNU General Public License v2 |
42 |
+ * |
43 |
+ * Copyright 2005-2010 Ned Ludd - <solar@g.o> |
44 |
+ * Copyright 2005-2014 Mike Frysinger - <vapier@g.o> |
45 |
+ * Copyright 2018- Fabian Groffen - <grobian@g.o> |
46 |
+ */ |
47 |
+ |
48 |
+#include "main.h" |
49 |
+ |
50 |
+#include <unistd.h> |
51 |
+#include <fcntl.h> |
52 |
+#include <sys/types.h> |
53 |
+#include <sys/stat.h> |
54 |
+#include "stat-time.h" |
55 |
+ |
56 |
+#include "copy_file.h" |
57 |
+#include "move_file.h" |
58 |
+ |
59 |
+int |
60 |
+move_file(int rootfd_src, const char *name_src, |
61 |
+ int rootfd_dst, const char *name_dst, |
62 |
+ struct stat *stat_src) |
63 |
+{ |
64 |
+ /* first try fast path -- src/dst are same device, else |
65 |
+ * fall back to slow path -- manual read/write */ |
66 |
+ if (renameat(rootfd_src, name_src, rootfd_dst, name_dst) != 0) { |
67 |
+ int fd_src; |
68 |
+ int fd_dst; |
69 |
+ char tmpname_dst[_Q_PATH_MAX]; |
70 |
+ struct stat st; |
71 |
+ struct timespec times[2]; |
72 |
+ |
73 |
+ fd_src = openat(rootfd_src, name_src, O_RDONLY|O_CLOEXEC); |
74 |
+ if (fd_src < 0) { |
75 |
+ warnp("could not read source file %s", name_src); |
76 |
+ return fd_src; |
77 |
+ } |
78 |
+ |
79 |
+ if (stat_src == NULL) { |
80 |
+ if (fstat(fd_src, &st) != 0) { |
81 |
+ warnp("could not stat source file %s", name_src); |
82 |
+ return -1; |
83 |
+ } |
84 |
+ |
85 |
+ stat_src = &st; |
86 |
+ } |
87 |
+ |
88 |
+ /* do not write the file in place ... |
89 |
+ * will fail with files that are in use |
90 |
+ * plus it isn't atomic, so we could leave a mess */ |
91 |
+ snprintf(tmpname_dst, sizeof(tmpname_dst), ".%u.%s", |
92 |
+ getpid(), name_dst); |
93 |
+ fd_dst = openat(rootfd_dst, tmpname_dst, |
94 |
+ O_WRONLY|O_CLOEXEC|O_CREAT|O_TRUNC, |
95 |
+ stat_src->st_mode); |
96 |
+ if (fd_dst < 0) { |
97 |
+ warnp("could not open destination file %s (for %s)", |
98 |
+ tmpname_dst, name_dst); |
99 |
+ close(fd_src); |
100 |
+ return fd_dst; |
101 |
+ } |
102 |
+ |
103 |
+ /* make sure owner/mode is sane before we write out data */ |
104 |
+ if (fchown(fd_dst, stat_src->st_uid, stat_src->st_gid) != 0) { |
105 |
+ warnp("could not set ownership (%zu/%zu) for %s", |
106 |
+ (size_t)stat_src->st_uid, (size_t)stat_src->st_gid, name_dst); |
107 |
+ return -1; |
108 |
+ } |
109 |
+ if (fchmod(fd_dst, stat_src->st_mode) != 0) { |
110 |
+ warnp("could not set permission (%u) for %s", |
111 |
+ (int)stat_src->st_mode, name_dst); |
112 |
+ return -1; |
113 |
+ } |
114 |
+ |
115 |
+ /* do the actual data copy */ |
116 |
+ if (copy_file_fd(fd_src, fd_dst)) { |
117 |
+ warnp("could not write to file %s", name_dst); |
118 |
+ if (unlinkat(rootfd_dst, tmpname_dst, 0) != 0) { |
119 |
+ /* don't care */; |
120 |
+ } |
121 |
+ close(fd_src); |
122 |
+ close(fd_dst); |
123 |
+ return -1; |
124 |
+ } |
125 |
+ |
126 |
+ /* Preserve the file times */ |
127 |
+ times[0] = get_stat_atime(&st); |
128 |
+ times[1] = get_stat_mtime(&st); |
129 |
+ futimens(fd_dst, times); |
130 |
+ |
131 |
+ close(fd_src); |
132 |
+ close(fd_dst); |
133 |
+ |
134 |
+ /* finally move the new tmp dst file to the right place, which |
135 |
+ * should be on the same FS/device now */ |
136 |
+ if (renameat(rootfd_dst, tmpname_dst, rootfd_dst, name_dst)) { |
137 |
+ warnp("could not rename %s to %s", tmpname_dst, name_dst); |
138 |
+ return -1; |
139 |
+ } |
140 |
+ } |
141 |
+ |
142 |
+ return 0; |
143 |
+} |
144 |
|
145 |
diff --git a/libq/move_file.h b/libq/move_file.h |
146 |
new file mode 100644 |
147 |
index 0000000..a454165 |
148 |
--- /dev/null |
149 |
+++ b/libq/move_file.h |
150 |
@@ -0,0 +1,21 @@ |
151 |
+/* |
152 |
+ * Copyright 2005-2021 Gentoo Authors |
153 |
+ * Distributed under the terms of the GNU General Public License v2 |
154 |
+ * |
155 |
+ * Copyright 2005-2010 Ned Ludd - <solar@g.o> |
156 |
+ * Copyright 2005-2014 Mike Frysinger - <vapier@g.o> |
157 |
+ * Copyright 2018- Fabian Groffen - <grobian@g.o> |
158 |
+ */ |
159 |
+ |
160 |
+#ifndef _MOVE_FILE_H |
161 |
+ |
162 |
+#define _MOVE_FILE_H 1 |
163 |
+ |
164 |
+#include <sys/types.h> |
165 |
+#include <sys/stat.h> |
166 |
+ |
167 |
+int move_file(int rootfd_src, const char *name_src, |
168 |
+ int rootfd_dst, const char *name_dst, |
169 |
+ struct stat *stat_src); |
170 |
+ |
171 |
+#endif |