26
26
#include <termios.h>
27
27
#include <unistd.h>
28
28
#include <limits.h>
29
- #if HAVE_CLONEFILE
30
- #include <sys/attr.h>
31
- #include <sys/clonefile.h>
32
- #endif
33
- #if HAVE_SENDFILE_4
29
+ #if HAVE_FCOPYFILE
30
+ #include <copyfile.h>
31
+ #elif HAVE_SENDFILE_4
34
32
#include <sys/sendfile.h>
35
33
#endif
36
34
#if HAVE_INOTIFY
@@ -1020,6 +1018,7 @@ int32_t SystemNative_Write(intptr_t fd, const void* buffer, int32_t bufferSize)
1020
1018
return Common_Write (fd , buffer , bufferSize );
1021
1019
}
1022
1020
1021
+ #if !HAVE_FCOPYFILE
1023
1022
// Read all data from inFd and write it to outFd
1024
1023
static int32_t CopyFile_ReadWrite (int inFd , int outFd )
1025
1024
{
@@ -1072,90 +1071,32 @@ static int32_t CopyFile_ReadWrite(int inFd, int outFd)
1072
1071
free (buffer );
1073
1072
return 0 ;
1074
1073
}
1074
+ #endif // !HAVE_FCOPYFILE
1075
1075
1076
- int32_t SystemNative_CopyFile (intptr_t sourceFd , const char * srcPath , const char * destPath , int32_t overwrite )
1076
+ int32_t SystemNative_CopyFile (intptr_t sourceFd , intptr_t destinationFd )
1077
1077
{
1078
1078
int inFd = ToFileDescriptor (sourceFd );
1079
- int outFd ;
1079
+ int outFd = ToFileDescriptor (destinationFd );
1080
+
1081
+ #if HAVE_FCOPYFILE
1082
+ // If fcopyfile is available (OS X), try to use it, as the whole copy
1083
+ // can be performed in the kernel, without lots of unnecessary copying.
1084
+ // Copy data and metadata.
1085
+ return fcopyfile (inFd , outFd , NULL , COPYFILE_ALL ) == 0 ? 0 : -1 ;
1086
+ #else
1087
+ // Get the stats on the source file.
1080
1088
int ret ;
1081
- int tmpErrno ;
1082
- int openFlags ;
1083
1089
struct stat_ sourceStat ;
1084
-
1090
+ bool copied = false;
1091
+ #if HAVE_SENDFILE_4
1092
+ // If sendfile is available (Linux), try to use it, as the whole copy
1093
+ // can be performed in the kernel, without lots of unnecessary copying.
1085
1094
while ((ret = fstat_ (inFd , & sourceStat )) < 0 && errno == EINTR );
1086
1095
if (ret != 0 )
1087
1096
{
1088
1097
return -1 ;
1089
1098
}
1090
1099
1091
- struct stat_ destStat ;
1092
- while ((ret = stat_ (destPath , & destStat )) < 0 && errno == EINTR );
1093
- if (ret == 0 )
1094
- {
1095
- if (!overwrite )
1096
- {
1097
- errno = EEXIST ;
1098
- return -1 ;
1099
- }
1100
-
1101
- if (sourceStat .st_dev == destStat .st_dev && sourceStat .st_ino == destStat .st_ino )
1102
- {
1103
- // Attempt to copy file over itself. Fail with the same error code as
1104
- // open would.
1105
- errno = EBUSY ;
1106
- return -1 ;
1107
- }
1108
-
1109
- #if HAVE_CLONEFILE
1110
- // For clonefile we need to unlink the destination file first but we need to
1111
- // check permission first to ensure we don't try to unlink read-only file.
1112
- if (access (destPath , W_OK ) != 0 )
1113
- {
1114
- return -1 ;
1115
- }
1116
-
1117
- ret = unlink (destPath );
1118
- if (ret != 0 )
1119
- {
1120
- return ret ;
1121
- }
1122
- #endif
1123
- }
1124
-
1125
- #if HAVE_CLONEFILE
1126
- while ((ret = clonefile (srcPath , destPath , 0 )) < 0 && errno == EINTR );
1127
- // EEXIST can happen due to race condition between the stat/unlink above
1128
- // and the clonefile here. The file could be (re-)created from another
1129
- // thread or process before we have a chance to call clonefile. Handle
1130
- // it by falling back to the slow path.
1131
- if (ret == 0 || (errno != ENOTSUP && errno != EXDEV && errno != EEXIST ))
1132
- {
1133
- return ret ;
1134
- }
1135
- #else
1136
- // Unused variable
1137
- (void )srcPath ;
1138
- #endif
1139
-
1140
- openFlags = O_WRONLY | O_TRUNC | O_CREAT | (overwrite ? 0 : O_EXCL );
1141
- #if HAVE_O_CLOEXEC
1142
- openFlags |= O_CLOEXEC ;
1143
- #endif
1144
- while ((outFd = open (destPath , openFlags , sourceStat .st_mode & (S_IRWXU | S_IRWXG | S_IRWXO ))) < 0 && errno == EINTR );
1145
- if (outFd < 0 )
1146
- {
1147
- return -1 ;
1148
- }
1149
- #if !HAVE_O_CLOEXEC
1150
- fcntl (outFd , F_SETFD , FD_CLOEXEC );
1151
- #endif
1152
-
1153
- // Get the stats on the source file.
1154
- bool copied = false;
1155
-
1156
- // If sendfile is available (Linux), try to use it, as the whole copy
1157
- // can be performed in the kernel, without lots of unnecessary copying.
1158
- #if HAVE_SENDFILE_4
1159
1100
1160
1101
// On 32-bit, if you use 64-bit offsets, the last argument of `sendfile' will be a
1161
1102
// `size_t' a 32-bit integer while the `st_size' field of the stat structure will be off64_t.
@@ -1171,9 +1112,6 @@ int32_t SystemNative_CopyFile(intptr_t sourceFd, const char* srcPath, const char
1171
1112
{
1172
1113
if (errno != EINVAL && errno != ENOSYS )
1173
1114
{
1174
- tmpErrno = errno ;
1175
- close (outFd );
1176
- errno = tmpErrno ;
1177
1115
return -1 ;
1178
1116
}
1179
1117
else
@@ -1199,37 +1137,47 @@ int32_t SystemNative_CopyFile(intptr_t sourceFd, const char* srcPath, const char
1199
1137
// Manually read all data from the source and write it to the destination.
1200
1138
if (!copied && CopyFile_ReadWrite (inFd , outFd ) != 0 )
1201
1139
{
1202
- tmpErrno = errno ;
1203
- close (outFd );
1204
- errno = tmpErrno ;
1205
1140
return -1 ;
1206
1141
}
1207
1142
1208
1143
// Now that the data from the file has been copied, copy over metadata
1209
1144
// from the source file. First copy the file times.
1210
1145
// If futimes nor futimes are available on this platform, file times will
1211
1146
// not be copied over.
1147
+ while ((ret = fstat_ (inFd , & sourceStat )) < 0 && errno == EINTR );
1148
+ if (ret == 0 )
1149
+ {
1212
1150
#if HAVE_FUTIMENS
1213
- // futimens is prefered because it has a higher resolution.
1214
- struct timespec origTimes [2 ];
1215
- origTimes [0 ].tv_sec = (time_t )sourceStat .st_atime ;
1216
- origTimes [0 ].tv_nsec = ST_ATIME_NSEC (& sourceStat );
1217
- origTimes [1 ].tv_sec = (time_t )sourceStat .st_mtime ;
1218
- origTimes [1 ].tv_nsec = ST_MTIME_NSEC (& sourceStat );
1219
- while ((ret = futimens (outFd , origTimes )) < 0 && errno == EINTR );
1151
+ // futimens is prefered because it has a higher resolution.
1152
+ struct timespec origTimes [2 ];
1153
+ origTimes [0 ].tv_sec = (time_t )sourceStat .st_atime ;
1154
+ origTimes [0 ].tv_nsec = ST_ATIME_NSEC (& sourceStat );
1155
+ origTimes [1 ].tv_sec = (time_t )sourceStat .st_mtime ;
1156
+ origTimes [1 ].tv_nsec = ST_MTIME_NSEC (& sourceStat );
1157
+ while ((ret = futimens (outFd , origTimes )) < 0 && errno == EINTR );
1220
1158
#elif HAVE_FUTIMES
1221
- struct timeval origTimes [2 ];
1222
- origTimes [0 ].tv_sec = sourceStat .st_atime ;
1223
- origTimes [0 ].tv_usec = (int32_t )(ST_ATIME_NSEC (& sourceStat ) / 1000 );
1224
- origTimes [1 ].tv_sec = sourceStat .st_mtime ;
1225
- origTimes [1 ].tv_usec = (int32_t )(ST_MTIME_NSEC (& sourceStat ) / 1000 );
1226
- while ((ret = futimes (outFd , origTimes )) < 0 && errno == EINTR );
1159
+ struct timeval origTimes [2 ];
1160
+ origTimes [0 ].tv_sec = sourceStat .st_atime ;
1161
+ origTimes [0 ].tv_usec = (int32_t )(ST_ATIME_NSEC (& sourceStat ) / 1000 );
1162
+ origTimes [1 ].tv_sec = sourceStat .st_mtime ;
1163
+ origTimes [1 ].tv_usec = (int32_t )(ST_MTIME_NSEC (& sourceStat ) / 1000 );
1164
+ while ((ret = futimes (outFd , origTimes )) < 0 && errno == EINTR );
1227
1165
#endif
1166
+ }
1167
+ if (ret != 0 )
1168
+ {
1169
+ return -1 ;
1170
+ }
1171
+
1172
+ // Then copy permissions.
1173
+ while ((ret = fchmod (outFd , sourceStat .st_mode & (S_IRWXU | S_IRWXG | S_IRWXO ))) < 0 && errno == EINTR );
1174
+ if (ret != 0 )
1175
+ {
1176
+ return -1 ;
1177
+ }
1228
1178
1229
- tmpErrno = errno ;
1230
- close (outFd );
1231
- errno = tmpErrno ;
1232
1179
return 0 ;
1180
+ #endif // HAVE_FCOPYFILE
1233
1181
}
1234
1182
1235
1183
intptr_t SystemNative_INotifyInit (void )
0 commit comments