| 238 | } |
| 239 | |
| 240 | Status CopyFile(Env* env, const string& source_path, const string& dest_path, |
| 241 | WritableFileOptions opts) { |
| 242 | unique_ptr<SequentialFile> source; |
| 243 | SequentialFileOptions source_opts; |
| 244 | source_opts.is_sensitive = opts.is_sensitive; |
| 245 | RETURN_NOT_OK(env->NewSequentialFile(source_opts, source_path, &source)); |
| 246 | uint64_t size; |
| 247 | RETURN_NOT_OK(env->GetFileSize(source_path, &size)); |
| 248 | |
| 249 | unique_ptr<WritableFile> dest; |
| 250 | RETURN_NOT_OK(env->NewWritableFile(opts, dest_path, &dest)); |
| 251 | if (size > 0) { |
| 252 | RETURN_NOT_OK(dest->PreAllocate(size)); |
| 253 | |
| 254 | const int32_t kBufferSize = 1024 * 1024; |
| 255 | unique_ptr<uint8_t[]> scratch(new uint8_t[kBufferSize]); |
| 256 | |
| 257 | uint64_t bytes_read = 0; |
| 258 | while (bytes_read < size) { |
| 259 | uint64_t max_bytes_to_read = std::min<uint64_t>(size - bytes_read, kBufferSize); |
| 260 | Slice data(scratch.get(), max_bytes_to_read); |
| 261 | RETURN_NOT_OK(source->Read(&data)); |
| 262 | RETURN_NOT_OK(dest->Append(data)); |
| 263 | bytes_read += data.size(); |
| 264 | } |
| 265 | } |
| 266 | return Status::OK(); |
| 267 | } |
| 268 | |
| 269 | Status CopyDirectory(Env* env, const std::string& source_path, const std::string& dest_path, |
| 270 | WritableFileOptions opts) { |