Gentoo Archives: gentoo-commits

From: Fabian Groffen <grobian@g.o>
To: gentoo-commits@l.g.o
Subject: [gentoo-commits] proj/portage-utils:master commit in: libq/
Date: Sun, 26 Dec 2021 14:00:04
Message-Id: 1640526529.117869a1b0d19c5e3a6b59e9e43e6849ed92efd4.grobian@gentoo
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