-
Notifications
You must be signed in to change notification settings - Fork 2
/
file_copy.cc
61 lines (52 loc) · 1.46 KB
/
file_copy.cc
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
#include "file_copy.h"
#include <fcntl.h>
#include <sys/sendfile.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <string>
#include "scoped_fd.h"
using std::string;
bool FileCopyInternal(int dirfd, int from_fd, const struct stat& st,
const string& target) {
ScopedFd to_fd(openat(dirfd, target.c_str(), O_WRONLY | O_CREAT | O_CLOEXEC,
st.st_mode));
if (to_fd.get() == -1) {
perror(("open " + target).c_str());
return false;
}
if (-1 == posix_fallocate(to_fd.get(), 0, st.st_size)) {
perror("posix_fallocate");
return false;
}
ssize_t read_bytes = sendfile(to_fd.get(), from_fd, nullptr, st.st_size);
if (read_bytes == -1) {
perror("sendfile");
return false;
}
if (read_bytes != st.st_size) {
return false;
}
if (-1 == fchmod(to_fd.get(), st.st_mode)) {
perror("fchmod");
return false;
}
if (-1 == futimens(to_fd.get(), &st.st_mtim)) {
perror("futimens");
return false;
}
if (-1 == fchown(to_fd.get(), st.st_uid, st.st_gid)) {
perror("fchown");
return false;
}
return true;
}
bool FileCopy(int dirfd, const std::string& source, const std::string& target) {
ScopedFd from_fd(openat(dirfd, source.c_str(), O_RDONLY | O_CLOEXEC, 0));
struct stat st {};
if (-1 == fstat(from_fd.get(), &st)) {
// I wonder why fstat can fail here.
perror("fstat");
return false;
}
return FileCopyInternal(dirfd, from_fd.get(), st, target);
}