7 #include "packager/file/file.h" 9 #include <gflags/gflags.h> 13 #include "packager/base/files/file_util.h" 14 #include "packager/base/logging.h" 15 #include "packager/base/strings/string_number_conversions.h" 16 #include "packager/base/strings/string_piece.h" 17 #include "packager/base/strings/stringprintf.h" 18 #include "packager/file/callback_file.h" 19 #include "packager/file/file_util.h" 20 #include "packager/file/local_file.h" 21 #include "packager/file/memory_file.h" 22 #include "packager/file/threaded_io_file.h" 23 #include "packager/file/udp_file.h" 25 DEFINE_uint64(io_cache_size,
27 "Size of the threaded I/O cache, in bytes. Specify 0 to disable " 29 DEFINE_uint64(io_block_size,
31 "Size of the block size used for threaded I/O, in bytes.");
40 const char* kCallbackFilePrefix =
"callback://";
41 const char* kLocalFilePrefix =
"file://";
42 const char* kMemoryFilePrefix =
"memory://";
43 const char* kUdpFilePrefix =
"udp://";
47 typedef File* (*FileFactoryFunction)(
const char* file_name,
const char* mode);
48 typedef bool (*FileDeleteFunction)(
const char* file_name);
49 typedef bool (*FileAtomicWriteFunction)(
const char* file_name,
50 const std::string& contents);
54 const FileFactoryFunction factory_function;
55 const FileDeleteFunction delete_function;
56 const FileAtomicWriteFunction atomic_write_function;
59 File* CreateCallbackFile(
const char* file_name,
const char* mode) {
60 return new CallbackFile(file_name, mode);
63 File* CreateLocalFile(
const char* file_name,
const char* mode) {
64 return new LocalFile(file_name, mode);
67 bool DeleteLocalFile(
const char* file_name) {
71 bool WriteLocalFileAtomically(
const char* file_name,
72 const std::string& contents) {
73 const base::FilePath file_path = base::FilePath::FromUTF8Unsafe(file_name);
74 const std::string dir_name = file_path.DirName().AsUTF8Unsafe();
75 std::string temp_file_name;
80 base::File::Error replace_file_error = base::File::FILE_OK;
81 if (!base::ReplaceFile(base::FilePath::FromUTF8Unsafe(temp_file_name),
82 file_path, &replace_file_error)) {
83 LOG(ERROR) <<
"Failed to replace file '" << file_name <<
"' with '" 84 << temp_file_name <<
"', error: " << replace_file_error;
90 File* CreateUdpFile(
const char* file_name,
const char* mode) {
91 if (strcmp(mode,
"r")) {
92 NOTIMPLEMENTED() <<
"UdpFile only supports read (receive) mode.";
95 return new UdpFile(file_name);
98 File* CreateMemoryFile(
const char* file_name,
const char* mode) {
99 return new MemoryFile(file_name, mode);
102 bool DeleteMemoryFile(
const char* file_name) {
107 static const FileTypeInfo kFileTypeInfo[] = {
112 &WriteLocalFileAtomically,
114 {kUdpFilePrefix, &CreateUdpFile,
nullptr,
nullptr},
115 {kMemoryFilePrefix, &CreateMemoryFile, &DeleteMemoryFile,
nullptr},
116 {kCallbackFilePrefix, &CreateCallbackFile,
nullptr,
nullptr},
119 base::StringPiece GetFileTypePrefix(base::StringPiece file_name) {
120 size_t pos = file_name.find(
"://");
121 return (pos == std::string::npos) ?
"" : file_name.substr(0, pos + 3);
124 const FileTypeInfo* GetFileTypeInfo(base::StringPiece file_name,
125 base::StringPiece* real_file_name) {
126 base::StringPiece file_type_prefix = GetFileTypePrefix(file_name);
127 for (
const FileTypeInfo& file_type : kFileTypeInfo) {
128 if (file_type_prefix == file_type.type) {
129 *real_file_name = file_name.substr(file_type_prefix.size());
134 *real_file_name = file_name;
135 return &kFileTypeInfo[0];
140 File* File::Create(
const char* file_name,
const char* mode) {
141 std::unique_ptr<File, FileCloser> internal_file(
142 CreateInternalFile(file_name, mode));
144 base::StringPiece file_type_prefix = GetFileTypePrefix(file_name);
145 if (file_type_prefix == kMemoryFilePrefix ||
146 file_type_prefix == kCallbackFilePrefix) {
148 return internal_file.release();
151 if (FLAGS_io_cache_size) {
153 if (!strcmp(mode,
"r")) {
154 return new ThreadedIoFile(std::move(internal_file),
155 ThreadedIoFile::kInputMode, FLAGS_io_cache_size,
156 FLAGS_io_block_size);
157 }
else if (!strcmp(mode,
"w") || !strcmp(mode,
"a")) {
158 return new ThreadedIoFile(std::move(internal_file),
159 ThreadedIoFile::kOutputMode,
160 FLAGS_io_cache_size, FLAGS_io_block_size);
165 DLOG(WARNING) <<
"Threaded I/O is disabled. Performance may be decreased.";
166 return internal_file.release();
169 File* File::CreateInternalFile(
const char* file_name,
const char* mode) {
170 base::StringPiece real_file_name;
171 const FileTypeInfo* file_type = GetFileTypeInfo(file_name, &real_file_name);
173 return file_type->factory_function(real_file_name.data(), mode);
177 File* file = File::Create(file_name, mode);
188 File* file = File::CreateInternalFile(file_name, mode);
199 base::StringPiece real_file_name;
200 const FileTypeInfo* file_type = GetFileTypeInfo(file_name, &real_file_name);
202 return file_type->delete_function
203 ? file_type->delete_function(real_file_name.data())
211 int64_t res = file->
Size();
223 const size_t kBufferSize = 0x40000;
224 std::unique_ptr<char[]> buf(
new char[kBufferSize]);
227 while ((len = file->
Read(buf.get(), kBufferSize)) > 0)
228 contents->append(buf.get(), len);
235 const std::string& contents) {
236 std::unique_ptr<File, FileCloser> file(
File::Open(file_name,
"w"));
238 LOG(ERROR) <<
"Failed to open file " << file_name;
241 int64_t bytes_written = file->Write(contents.data(), contents.size());
242 if (bytes_written < 0) {
243 LOG(ERROR) <<
"Failed to write to file '" << file_name <<
"' (" 244 << bytes_written <<
").";
247 if (static_cast<size_t>(bytes_written) != contents.size()) {
248 LOG(ERROR) <<
"Failed to write the whole file to " << file_name
249 <<
". Wrote " << bytes_written <<
" but expecting " 250 << contents.size() <<
" bytes.";
253 if (!file.release()->Close()) {
255 <<
"Failed to close file '" << file_name
256 <<
"', possibly file permission issue or running out of disk space.";
263 const std::string& contents) {
264 base::StringPiece real_file_name;
265 const FileTypeInfo* file_type = GetFileTypeInfo(file_name, &real_file_name);
267 if (file_type->atomic_write_function)
268 return file_type->atomic_write_function(real_file_name.data(), contents);
274 if (strncmp(file_name, kMemoryFilePrefix, strlen(kMemoryFilePrefix)) != 0) {
275 LOG(WARNING) <<
"Writing to " << file_name
276 <<
" is not guaranteed to be atomic.";
278 return WriteStringToFile(file_name, contents);
281 bool File::Copy(
const char* from_file_name,
const char* to_file_name) {
283 if (!ReadFileToString(from_file_name, &content)) {
284 LOG(ERROR) <<
"Failed to open file " << from_file_name;
288 std::unique_ptr<File, FileCloser> output_file(
File::Open(to_file_name,
"w"));
290 LOG(ERROR) <<
"Failed to write to " << to_file_name;
294 uint64_t bytes_left = content.size();
295 uint64_t total_bytes_written = 0;
296 const char* content_cstr = content.c_str();
297 while (bytes_left > total_bytes_written) {
298 const int64_t bytes_written =
299 output_file->Write(content_cstr + total_bytes_written, bytes_left);
300 if (bytes_written < 0) {
301 LOG(ERROR) <<
"Failure while writing to " << to_file_name;
305 total_bytes_written += bytes_written;
307 if (!output_file.release()->Close()) {
309 <<
"Failed to close file '" << to_file_name
310 <<
"', possibly file permission issue or running out of disk space.";
317 return CopyFile(source, destination, kWholeFile);
324 max_copy = std::numeric_limits<int64_t>::max();
326 const int64_t kBufferSize = 0x40000;
327 std::unique_ptr<uint8_t[]> buffer(
new uint8_t[kBufferSize]);
328 int64_t bytes_copied = 0;
329 while (bytes_copied < max_copy) {
330 const int64_t size = std::min(kBufferSize, max_copy - bytes_copied);
331 const int64_t bytes_read = source->
Read(buffer.get(), size);
337 int64_t total_bytes_written = 0;
338 while (total_bytes_written < bytes_read) {
339 const int64_t bytes_written = destination->
Write(
340 buffer.get() + total_bytes_written, bytes_read - total_bytes_written);
341 if (bytes_written < 0)
342 return bytes_written;
344 total_bytes_written += bytes_written;
347 DCHECK_EQ(total_bytes_written, bytes_read);
348 bytes_copied += bytes_read;
356 const std::string& name) {
359 return base::StringPrintf(
"%s%" PRIdPTR
"/%s", kCallbackFilePrefix,
360 reinterpret_cast<intptr_t>(&callback_params),
367 size_t pos = callback_file_name.find(
"/");
368 int64_t callback_address = 0;
369 if (pos == std::string::npos ||
370 !base::StringToInt64(callback_file_name.substr(0, pos),
371 &callback_address)) {
372 LOG(ERROR) <<
"Expecting CallbackFile with name like " 373 "'<callback address>/<entity name>', but seeing " 374 << callback_file_name;
378 *name = callback_file_name.substr(pos + 1);
virtual int64_t Write(const void *buffer, uint64_t length)=0
static void Delete(const std::string &file_name)
static File * Open(const char *file_name, const char *mode)
static bool Delete(const char *file_name)
Define an abstract file interface.
static bool Copy(const char *from_file_name, const char *to_file_name)
static int64_t CopyFile(File *source, File *destination)
static bool ReadFileToString(const char *file_name, std::string *contents)
virtual int64_t Read(void *buffer, uint64_t length)=0
bool TempFilePath(const std::string &temp_dir, std::string *temp_file_path)
All the methods that are virtual are virtual for mocking.
static int64_t GetFileSize(const char *file_name)
static bool WriteStringToFile(const char *file_name, const std::string &contents)
static std::string MakeCallbackFileName(const BufferCallbackParams &callback_params, const std::string &name)
static bool Delete(const char *file_name)
static File * OpenWithNoBuffering(const char *file_name, const char *mode)
static bool WriteFileAtomically(const char *file_name, const std::string &contents)
static bool ParseCallbackFileName(const std::string &callback_file_name, const BufferCallbackParams **callback_params, std::string *name)
virtual bool Open()=0
Internal open. Should not be used directly.