1+ #include " my_global.h"
2+ #include " my_backup.h"
3+
4+ #ifdef __APPLE__
5+ # include < sys/attr.h>
6+ # include < sys/clonefile.h>
7+ # include < copyfile.h>
8+ #elif defined __linux__
9+ # include < sys/sendfile.h>
10+ #elif !defined _WIN32
11+ # include < sys/mman.h>
12+ #endif
13+
14+ namespace
15+ {
16+ #if !(defined __APPLE__ || defined _WIN32)
17+
18+ using copying_step= ssize_t (int ,int ,size_t ,off_t *);
19+ template <copying_step step>
20+ static ssize_t copy (int in_fd, int out_fd, off_t c) noexcept
21+ {
22+ ssize_t ret;
23+ for (off_t offset{0 };;)
24+ {
25+ off_t count= c;
26+ if (count > INT_MAX >> 20 << 20 )
27+ count = INT_MAX >> 20 << 20 ;
28+ ret= step (in_fd, out_fd, size_t (count), &offset);
29+ if (ret < 0 )
30+ break ;
31+ c-= ret;
32+ if (!c)
33+ return 0 ;
34+ if (!ret)
35+ return -1 ;
36+ }
37+ return ret;
38+ }
39+ # if defined __linux__ || defined __FreeBSD__
40+ /* Copy between files in a single (type of) file system */
41+ static inline ssize_t
42+ copy_step (int in_fd, int out_fd, size_t count, off_t *offset) noexcept
43+ {
44+ return copy_file_range (in_fd, offset, out_fd, nullptr , count, 0 );
45+ }
46+ # define cfr (src,dst,size ) copy<copy_step>(src, dst, size)
47+ # endif
48+ # ifdef __linux__
49+ /* Copy a file to a stream or to a regular file. */
50+ static inline ssize_t
51+ send_step (int in_fd, int out_fd, size_t count, off_t *offset) noexcept
52+ {
53+ return sendfile (out_fd, in_fd, offset, count);
54+ }
55+ # else
56+ /* * Copy a file using a memory mapping.
57+ @param in_fd source file
58+ @param out_fd destination
59+ @param count number of bytes to copy
60+ @return error code
61+ @retval 0 on success
62+ @retval 1 if a memory mapping failed */
63+ static ssize_t mmap_copy (int in_fd, int out_fd, off_t count)
64+ {
65+ #if SIZEOF_SIZE_T < 8
66+ if (count != ssize_t (count))
67+ return 1 ;
68+ #endif
69+ void *p= mmap (nullptr , count, PROT_READ , MAP_SHARED , in_fd, 0 );
70+ if (p == MAP_FAILED )
71+ return 1 ;
72+ ssize_t ret;
73+ size_t c= size_t (count);
74+ for (const char *b= static_cast <const char *>(p);; b+= ret)
75+ {
76+ ret= write (out_fd, b, std::min (c, size_t (INT_MAX >> 20 << 20 )));
77+ if (ret < 0 )
78+ break ;
79+ c-= ret;
80+ if (!c)
81+ {
82+ ret= 0 ;
83+ break ;
84+ }
85+ if (!ret)
86+ {
87+ ret= -1 ;
88+ break ;
89+ }
90+ }
91+ munmap (p, count);
92+ return ret;
93+ }
94+
95+ static ssize_t pread_write (int in_fd, int out_fd, off_t count) noexcept
96+ {
97+ constexpr size_t READ_WRITE_SIZE = 65536 ;
98+ char *b= static_cast <char *>(aligned_malloc (READ_WRITE_SIZE , 4096 ));
99+ if (!b)
100+ return -1 ;
101+ ssize_t ret;
102+ for (off_t o= 0 ;; o+= ret)
103+ {
104+ ret= pread (in_fd, b, ssize_t (std::min (count, off_t {READ_WRITE_SIZE })), o);
105+ if (ret > 0 )
106+ ret= write (out_fd, b, ret);
107+ if (ret < 0 )
108+ break ;
109+ count-= ret;
110+ if (!count)
111+ {
112+ ret= 0 ;
113+ break ;
114+ }
115+ if (!ret)
116+ {
117+ ret= -1 ;
118+ break ;
119+ }
120+ }
121+ aligned_free (b);
122+ return ret;
123+ }
124+ # endif
125+ #endif
126+ }
127+
128+ namespace backup
129+ {
130+
131+ #ifndef _WIN32
132+ /* * Copy a file.
133+ @param src source file descriptor
134+ @param dst target to append src to
135+ @return error code (negative)
136+ @retval 0 on success */
137+ int copy_file (int src, int dst) noexcept
138+ {
139+ #ifdef __APPLE__
140+ return fcopyfile (src, dst, nullptr , COPYFILE_ALL | COPYFILE_CLONE );
141+ #else
142+ return copy_file (src, dst, lseek (src, 0 , SEEK_END ));
143+ #endif
144+ }
145+
146+ /* * Copy a file.
147+ @param src source file descriptor
148+ @param dst target to append src to
149+ @param size amount of data to be copied
150+ @return error code (negative)
151+ @retval 0 on success */
152+ int copy_file (int src, int dst, off_t size) noexcept
153+ {
154+ #ifdef __APPLE__
155+ return fcopyfile (src, dst, nullptr , COPYFILE_ALL | COPYFILE_CLONE );
156+ #else
157+ ssize_t ret;
158+ # ifdef cfr
159+ if (!(ret= cfr (src, dst, size)))
160+ return int (ret);
161+ # ifdef __linux__
162+ if (errno == EOPNOTSUPP )
163+ # endif
164+ # endif
165+ # ifdef __linux__ // starting with Linux 2.6.33, we can rely on sendfile(2)
166+ ret= copy<send_step>(src, dst, size);
167+ # else
168+ if ((ret= mmap_copy (src, dst, size)) == 1 )
169+ ret= pread_write (src, dst, size);
170+ # endif
171+ DBUG_ASSERT (ret <= 0 );
172+ return int (ret);
173+ #endif
174+ }
175+ #endif
176+ }
0 commit comments