1 /* Copyright 2015 The TensorFlow Authors. All Rights Reserved.
2
3 Licensed under the Apache License, Version 2.0 (the "License");
4 you may not use this file except in compliance with the License.
5 You may obtain a copy of the License at
6
7 http://www.apache.org/licenses/LICENSE-2.0
8
9 Unless required by applicable law or agreed to in writing, software
10 distributed under the License is distributed on an "AS IS" BASIS,
11 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 See the License for the specific language governing permissions and
13 limitations under the License.
14 ==============================================================================*/
15
16 #include "tensorflow/core/platform/env.h"
17
18 #include <sys/stat.h>
19
20 #include <deque>
21 #include <utility>
22 #include <vector>
23
24 #include "tensorflow/core/platform/env_time.h"
25 #include "tensorflow/core/platform/errors.h"
26 #include "tensorflow/core/platform/host_info.h"
27 #include "tensorflow/core/platform/path.h"
28 #include "tensorflow/core/platform/platform.h"
29 #include "tensorflow/core/platform/protobuf.h"
30 #include "tensorflow/core/platform/stringprintf.h"
31
32 #if defined(__APPLE__)
33 #include <mach-o/dyld.h>
34 #endif
35 #if defined(__FreeBSD__)
36 #include <sys/sysctl.h>
37 #endif
38 #if defined(PLATFORM_WINDOWS)
39 #include <windows.h>
40 #undef DeleteFile
41 #undef CopyFile
42 #include "tensorflow/tsl/platform/windows/wide_char.h"
43 #define PATH_MAX MAX_PATH
44 #else
45 #include <fcntl.h>
46 #include <string.h>
47 #include <sys/types.h>
48 #include <unistd.h>
49 #endif
50
51 namespace tensorflow {
52
53 // 128KB copy buffer
54 constexpr size_t kCopyFileBufferSize = 128 * 1024;
55
56 class FileSystemRegistryImpl : public FileSystemRegistry {
57 public:
58 Status Register(const std::string& scheme, Factory factory) override;
59 Status Register(const std::string& scheme,
60 std::unique_ptr<FileSystem> filesystem) override;
61 FileSystem* Lookup(const std::string& scheme) override;
62 Status GetRegisteredFileSystemSchemes(
63 std::vector<std::string>* schemes) override;
64
65 private:
66 mutable mutex mu_;
67 mutable std::unordered_map<std::string, std::unique_ptr<FileSystem>> registry_
68 TF_GUARDED_BY(mu_);
69 };
70
Register(const std::string & scheme,FileSystemRegistry::Factory factory)71 Status FileSystemRegistryImpl::Register(const std::string& scheme,
72 FileSystemRegistry::Factory factory) {
73 mutex_lock lock(mu_);
74 if (!registry_.emplace(scheme, std::unique_ptr<FileSystem>(factory()))
75 .second) {
76 return errors::AlreadyExists("File factory for ", scheme,
77 " already registered");
78 }
79 return OkStatus();
80 }
81
Register(const std::string & scheme,std::unique_ptr<FileSystem> filesystem)82 Status FileSystemRegistryImpl::Register(
83 const std::string& scheme, std::unique_ptr<FileSystem> filesystem) {
84 mutex_lock lock(mu_);
85 if (!registry_.emplace(scheme, std::move(filesystem)).second) {
86 return errors::AlreadyExists("File system for ", scheme,
87 " already registered");
88 }
89 return OkStatus();
90 }
91
Lookup(const std::string & scheme)92 FileSystem* FileSystemRegistryImpl::Lookup(const std::string& scheme) {
93 mutex_lock lock(mu_);
94 const auto found = registry_.find(scheme);
95 if (found == registry_.end()) {
96 return nullptr;
97 }
98 return found->second.get();
99 }
100
GetRegisteredFileSystemSchemes(std::vector<std::string> * schemes)101 Status FileSystemRegistryImpl::GetRegisteredFileSystemSchemes(
102 std::vector<std::string>* schemes) {
103 mutex_lock lock(mu_);
104 for (const auto& e : registry_) {
105 schemes->push_back(e.first);
106 }
107 return OkStatus();
108 }
109
Env()110 Env::Env() : file_system_registry_(new FileSystemRegistryImpl) {}
111
GetFileSystemForFile(const std::string & fname,FileSystem ** result)112 Status Env::GetFileSystemForFile(const std::string& fname,
113 FileSystem** result) {
114 StringPiece scheme, host, path;
115 io::ParseURI(fname, &scheme, &host, &path);
116 FileSystem* file_system = file_system_registry_->Lookup(std::string(scheme));
117 if (!file_system) {
118 if (scheme.empty()) {
119 scheme = "[local]";
120 }
121
122 return errors::Unimplemented("File system scheme '", scheme,
123 "' not implemented (file: '", fname, "')");
124 }
125 *result = file_system;
126 return OkStatus();
127 }
128
GetRegisteredFileSystemSchemes(std::vector<std::string> * schemes)129 Status Env::GetRegisteredFileSystemSchemes(std::vector<std::string>* schemes) {
130 return file_system_registry_->GetRegisteredFileSystemSchemes(schemes);
131 }
132
RegisterFileSystem(const std::string & scheme,FileSystemRegistry::Factory factory)133 Status Env::RegisterFileSystem(const std::string& scheme,
134 FileSystemRegistry::Factory factory) {
135 return file_system_registry_->Register(scheme, std::move(factory));
136 }
137
RegisterFileSystem(const std::string & scheme,std::unique_ptr<FileSystem> filesystem)138 Status Env::RegisterFileSystem(const std::string& scheme,
139 std::unique_ptr<FileSystem> filesystem) {
140 return file_system_registry_->Register(scheme, std::move(filesystem));
141 }
142
SetOption(const std::string & scheme,const std::string & key,const std::string & value)143 Status Env::SetOption(const std::string& scheme, const std::string& key,
144 const std::string& value) {
145 FileSystem* file_system = file_system_registry_->Lookup(scheme);
146 if (!file_system) {
147 return errors::Unimplemented("File system scheme '", scheme,
148 "' not found to set configuration");
149 }
150 return file_system->SetOption(key, value);
151 }
152
SetOption(const std::string & scheme,const std::string & key,const std::vector<string> & values)153 Status Env::SetOption(const std::string& scheme, const std::string& key,
154 const std::vector<string>& values) {
155 FileSystem* file_system = file_system_registry_->Lookup(scheme);
156 if (!file_system) {
157 return errors::Unimplemented("File system scheme '", scheme,
158 "' not found to set configuration");
159 }
160 return file_system->SetOption(key, values);
161 }
162
SetOption(const std::string & scheme,const std::string & key,const std::vector<int64_t> & values)163 Status Env::SetOption(const std::string& scheme, const std::string& key,
164 const std::vector<int64_t>& values) {
165 FileSystem* file_system = file_system_registry_->Lookup(scheme);
166 if (!file_system) {
167 return errors::Unimplemented("File system scheme '", scheme,
168 "' not found to set configuration");
169 }
170 return file_system->SetOption(key, values);
171 }
172
SetOption(const std::string & scheme,const std::string & key,const std::vector<double> & values)173 Status Env::SetOption(const std::string& scheme, const std::string& key,
174 const std::vector<double>& values) {
175 FileSystem* file_system = file_system_registry_->Lookup(scheme);
176 if (!file_system) {
177 return errors::Unimplemented("File system scheme '", scheme,
178 "' not found to set configuration");
179 }
180 return file_system->SetOption(key, values);
181 }
182
FlushFileSystemCaches()183 Status Env::FlushFileSystemCaches() {
184 std::vector<string> schemes;
185 TF_RETURN_IF_ERROR(GetRegisteredFileSystemSchemes(&schemes));
186 for (const string& scheme : schemes) {
187 FileSystem* fs = nullptr;
188 TF_RETURN_IF_ERROR(
189 GetFileSystemForFile(io::CreateURI(scheme, "", ""), &fs));
190 fs->FlushCaches();
191 }
192 return OkStatus();
193 }
194
NewRandomAccessFile(const string & fname,std::unique_ptr<RandomAccessFile> * result)195 Status Env::NewRandomAccessFile(const string& fname,
196 std::unique_ptr<RandomAccessFile>* result) {
197 FileSystem* fs;
198 TF_RETURN_IF_ERROR(GetFileSystemForFile(fname, &fs));
199 return fs->NewRandomAccessFile(fname, result);
200 }
201
NewReadOnlyMemoryRegionFromFile(const string & fname,std::unique_ptr<ReadOnlyMemoryRegion> * result)202 Status Env::NewReadOnlyMemoryRegionFromFile(
203 const string& fname, std::unique_ptr<ReadOnlyMemoryRegion>* result) {
204 FileSystem* fs;
205 TF_RETURN_IF_ERROR(GetFileSystemForFile(fname, &fs));
206 return fs->NewReadOnlyMemoryRegionFromFile(fname, result);
207 }
208
NewWritableFile(const string & fname,std::unique_ptr<WritableFile> * result)209 Status Env::NewWritableFile(const string& fname,
210 std::unique_ptr<WritableFile>* result) {
211 FileSystem* fs;
212 TF_RETURN_IF_ERROR(GetFileSystemForFile(fname, &fs));
213 return fs->NewWritableFile(fname, result);
214 }
215
NewAppendableFile(const string & fname,std::unique_ptr<WritableFile> * result)216 Status Env::NewAppendableFile(const string& fname,
217 std::unique_ptr<WritableFile>* result) {
218 FileSystem* fs;
219 TF_RETURN_IF_ERROR(GetFileSystemForFile(fname, &fs));
220 return fs->NewAppendableFile(fname, result);
221 }
222
FileExists(const string & fname)223 Status Env::FileExists(const string& fname) {
224 FileSystem* fs;
225 TF_RETURN_IF_ERROR(GetFileSystemForFile(fname, &fs));
226 return fs->FileExists(fname);
227 }
228
FilesExist(const std::vector<string> & files,std::vector<Status> * status)229 bool Env::FilesExist(const std::vector<string>& files,
230 std::vector<Status>* status) {
231 std::unordered_map<string, std::vector<string>> files_per_fs;
232 for (const auto& file : files) {
233 StringPiece scheme, host, path;
234 io::ParseURI(file, &scheme, &host, &path);
235 files_per_fs[string(scheme)].push_back(file);
236 }
237
238 std::unordered_map<string, Status> per_file_status;
239 bool result = true;
240 for (auto itr : files_per_fs) {
241 FileSystem* file_system = file_system_registry_->Lookup(itr.first);
242 bool fs_result;
243 std::vector<Status> local_status;
244 std::vector<Status>* fs_status = status ? &local_status : nullptr;
245 if (!file_system) {
246 fs_result = false;
247 if (fs_status) {
248 Status s = errors::Unimplemented("File system scheme '", itr.first,
249 "' not implemented");
250 local_status.resize(itr.second.size(), s);
251 }
252 } else {
253 fs_result = file_system->FilesExist(itr.second, fs_status);
254 }
255 if (fs_status) {
256 result &= fs_result;
257 for (size_t i = 0; i < itr.second.size(); ++i) {
258 per_file_status[itr.second[i]] = fs_status->at(i);
259 }
260 } else if (!fs_result) {
261 // Return early
262 return false;
263 }
264 }
265
266 if (status) {
267 for (const auto& file : files) {
268 status->push_back(per_file_status[file]);
269 }
270 }
271
272 return result;
273 }
274
GetChildren(const string & dir,std::vector<string> * result)275 Status Env::GetChildren(const string& dir, std::vector<string>* result) {
276 FileSystem* fs;
277 TF_RETURN_IF_ERROR(GetFileSystemForFile(dir, &fs));
278 return fs->GetChildren(dir, result);
279 }
280
GetMatchingPaths(const string & pattern,std::vector<string> * results)281 Status Env::GetMatchingPaths(const string& pattern,
282 std::vector<string>* results) {
283 FileSystem* fs;
284 TF_RETURN_IF_ERROR(GetFileSystemForFile(pattern, &fs));
285 return fs->GetMatchingPaths(pattern, results);
286 }
287
DeleteFile(const string & fname)288 Status Env::DeleteFile(const string& fname) {
289 FileSystem* fs;
290 TF_RETURN_IF_ERROR(GetFileSystemForFile(fname, &fs));
291 return fs->DeleteFile(fname);
292 }
293
RecursivelyCreateDir(const string & dirname)294 Status Env::RecursivelyCreateDir(const string& dirname) {
295 FileSystem* fs;
296 TF_RETURN_IF_ERROR(GetFileSystemForFile(dirname, &fs));
297 return fs->RecursivelyCreateDir(dirname);
298 }
299
CreateDir(const string & dirname)300 Status Env::CreateDir(const string& dirname) {
301 FileSystem* fs;
302 TF_RETURN_IF_ERROR(GetFileSystemForFile(dirname, &fs));
303 return fs->CreateDir(dirname);
304 }
305
DeleteDir(const string & dirname)306 Status Env::DeleteDir(const string& dirname) {
307 FileSystem* fs;
308 TF_RETURN_IF_ERROR(GetFileSystemForFile(dirname, &fs));
309 return fs->DeleteDir(dirname);
310 }
311
Stat(const string & fname,FileStatistics * stat)312 Status Env::Stat(const string& fname, FileStatistics* stat) {
313 FileSystem* fs;
314 TF_RETURN_IF_ERROR(GetFileSystemForFile(fname, &fs));
315 return fs->Stat(fname, stat);
316 }
317
IsDirectory(const string & fname)318 Status Env::IsDirectory(const string& fname) {
319 FileSystem* fs;
320 TF_RETURN_IF_ERROR(GetFileSystemForFile(fname, &fs));
321 return fs->IsDirectory(fname);
322 }
323
HasAtomicMove(const string & path,bool * has_atomic_move)324 Status Env::HasAtomicMove(const string& path, bool* has_atomic_move) {
325 FileSystem* fs;
326 TF_RETURN_IF_ERROR(GetFileSystemForFile(path, &fs));
327 return fs->HasAtomicMove(path, has_atomic_move);
328 }
329
CanCreateTempFile(const string & fname,bool * can_create_temp_file)330 Status Env::CanCreateTempFile(const string& fname, bool* can_create_temp_file) {
331 FileSystem* fs;
332 TF_RETURN_IF_ERROR(GetFileSystemForFile(fname, &fs));
333 return fs->CanCreateTempFile(fname, can_create_temp_file);
334 }
335
DeleteRecursively(const string & dirname,int64_t * undeleted_files,int64_t * undeleted_dirs)336 Status Env::DeleteRecursively(const string& dirname, int64_t* undeleted_files,
337 int64_t* undeleted_dirs) {
338 FileSystem* fs;
339 TF_RETURN_IF_ERROR(GetFileSystemForFile(dirname, &fs));
340 return fs->DeleteRecursively(dirname, undeleted_files, undeleted_dirs);
341 }
342
GetFileSize(const string & fname,uint64 * file_size)343 Status Env::GetFileSize(const string& fname, uint64* file_size) {
344 FileSystem* fs;
345 TF_RETURN_IF_ERROR(GetFileSystemForFile(fname, &fs));
346 return fs->GetFileSize(fname, file_size);
347 }
348
RenameFile(const string & src,const string & target)349 Status Env::RenameFile(const string& src, const string& target) {
350 FileSystem* src_fs;
351 FileSystem* target_fs;
352 TF_RETURN_IF_ERROR(GetFileSystemForFile(src, &src_fs));
353 TF_RETURN_IF_ERROR(GetFileSystemForFile(target, &target_fs));
354 if (src_fs != target_fs) {
355 return errors::Unimplemented("Renaming ", src, " to ", target,
356 " not implemented");
357 }
358 return src_fs->RenameFile(src, target);
359 }
360
CopyFile(const string & src,const string & target)361 Status Env::CopyFile(const string& src, const string& target) {
362 FileSystem* src_fs;
363 FileSystem* target_fs;
364 TF_RETURN_IF_ERROR(GetFileSystemForFile(src, &src_fs));
365 TF_RETURN_IF_ERROR(GetFileSystemForFile(target, &target_fs));
366 if (src_fs == target_fs) {
367 return src_fs->CopyFile(src, target);
368 }
369 return FileSystemCopyFile(src_fs, src, target_fs, target);
370 }
371
GetExecutablePath()372 string Env::GetExecutablePath() {
373 char exe_path[PATH_MAX] = {0};
374 #ifdef __APPLE__
375 uint32_t buffer_size(0U);
376 _NSGetExecutablePath(nullptr, &buffer_size);
377 std::vector<char> unresolved_path(buffer_size);
378 _NSGetExecutablePath(unresolved_path.data(), &buffer_size);
379 CHECK(realpath(unresolved_path.data(), exe_path));
380 #elif defined(__FreeBSD__)
381 int mib[4] = {CTL_KERN, KERN_PROC, KERN_PROC_PATHNAME, -1};
382 size_t exe_path_size = PATH_MAX;
383
384 if (sysctl(mib, 4, exe_path, &exe_path_size, NULL, 0) != 0) {
385 // Resolution of path failed
386 return "";
387 }
388 #elif defined(PLATFORM_WINDOWS)
389 HMODULE hModule = GetModuleHandleW(NULL);
390 WCHAR wc_file_path[MAX_PATH] = {0};
391 GetModuleFileNameW(hModule, wc_file_path, MAX_PATH);
392 string file_path = WideCharToUtf8(wc_file_path);
393 std::copy(file_path.begin(), file_path.end(), exe_path);
394 #else
395 char buf[PATH_MAX] = {0};
396 int path_length = readlink("/proc/self/exe", buf, sizeof(buf) - 1);
397 CHECK_NE(-1, path_length);
398
399 if (strstr(buf, "python") != nullptr) {
400 // Discard the path of the python binary, and any flags.
401 int fd = open("/proc/self/cmdline", O_RDONLY);
402 int cmd_length = read(fd, buf, PATH_MAX - 1);
403 CHECK_NE(-1, cmd_length);
404 int token_pos = 0;
405 for (bool token_is_first_or_flag = true; token_is_first_or_flag;) {
406 // Get token length, including null
407 int token_len = strlen(&buf[token_pos]) + 1;
408 token_is_first_or_flag = false;
409 // Check if we can skip without overshooting
410 if (token_pos + token_len < cmd_length) {
411 token_pos += token_len;
412 token_is_first_or_flag = (buf[token_pos] == '-'); // token is a flag
413 }
414 }
415 snprintf(exe_path, sizeof(exe_path), "%s", &buf[token_pos]);
416 } else {
417 snprintf(exe_path, sizeof(exe_path), "%s", buf);
418 }
419
420 #endif
421 // Make sure it's null-terminated:
422 exe_path[sizeof(exe_path) - 1] = 0;
423
424 return exe_path;
425 }
426
LocalTempFilename(string * filename)427 bool Env::LocalTempFilename(string* filename) {
428 std::vector<string> dirs;
429 GetLocalTempDirectories(&dirs);
430
431 // Try each directory, as they might be full, have inappropriate
432 // permissions or have different problems at times.
433 for (const string& dir : dirs) {
434 *filename = io::JoinPath(dir, "tempfile-");
435 if (CreateUniqueFileName(filename, "")) {
436 return true;
437 }
438 }
439 return false;
440 }
441
CreateUniqueFileName(string * prefix,const string & suffix)442 bool Env::CreateUniqueFileName(string* prefix, const string& suffix) {
443 int32_t tid = GetCurrentThreadId();
444 int32_t pid = GetProcessId();
445 long long now_microsec = NowMicros(); // NOLINT
446
447 *prefix += strings::Printf("%s-%x-%d-%llx", port::Hostname().c_str(), tid,
448 pid, now_microsec);
449
450 if (!suffix.empty()) {
451 *prefix += suffix;
452 }
453 if (FileExists(*prefix).ok()) {
454 prefix->clear();
455 return false;
456 } else {
457 return true;
458 }
459 }
460
GetProcessId()461 int32 Env::GetProcessId() {
462 #ifdef PLATFORM_WINDOWS
463 return static_cast<int32>(GetCurrentProcessId());
464 #else
465 return static_cast<int32>(getpid());
466 #endif
467 }
468
~Thread()469 Thread::~Thread() {}
470
~EnvWrapper()471 EnvWrapper::~EnvWrapper() {}
472
ReadFileToString(Env * env,const string & fname,string * data)473 Status ReadFileToString(Env* env, const string& fname, string* data) {
474 uint64 file_size;
475 Status s = env->GetFileSize(fname, &file_size);
476 if (!s.ok()) {
477 return s;
478 }
479 std::unique_ptr<RandomAccessFile> file;
480 s = env->NewRandomAccessFile(fname, &file);
481 if (!s.ok()) {
482 return s;
483 }
484 data->resize(file_size);
485 char* p = &*data->begin();
486 StringPiece result;
487 s = file->Read(0, file_size, &result, p);
488 if (!s.ok()) {
489 data->clear();
490 } else if (result.size() != file_size) {
491 s = errors::Aborted("File ", fname, " changed while reading: ", file_size,
492 " vs. ", result.size());
493 data->clear();
494 } else if (result.data() == p) {
495 // Data is already in the correct location
496 } else {
497 memmove(p, result.data(), result.size());
498 }
499 return s;
500 }
501
WriteStringToFile(Env * env,const string & fname,const StringPiece & data)502 Status WriteStringToFile(Env* env, const string& fname,
503 const StringPiece& data) {
504 std::unique_ptr<WritableFile> file;
505 Status s = env->NewWritableFile(fname, &file);
506 if (!s.ok()) {
507 return s;
508 }
509 s = file->Append(data);
510 if (s.ok()) {
511 s = file->Close();
512 }
513 return s;
514 }
515
FileSystemCopyFile(FileSystem * src_fs,const string & src,FileSystem * target_fs,const string & target)516 Status FileSystemCopyFile(FileSystem* src_fs, const string& src,
517 FileSystem* target_fs, const string& target) {
518 std::unique_ptr<RandomAccessFile> src_file;
519 TF_RETURN_IF_ERROR(src_fs->NewRandomAccessFile(src, &src_file));
520
521 // When `target` points to a directory, we need to create a file within.
522 string target_name;
523 if (target_fs->IsDirectory(target).ok()) {
524 target_name = io::JoinPath(target, io::Basename(src));
525 } else {
526 target_name = target;
527 }
528
529 std::unique_ptr<WritableFile> target_file;
530 TF_RETURN_IF_ERROR(target_fs->NewWritableFile(target_name, &target_file));
531
532 uint64 offset = 0;
533 std::unique_ptr<char[]> scratch(new char[kCopyFileBufferSize]);
534 Status s = OkStatus();
535 while (s.ok()) {
536 StringPiece result;
537 s = src_file->Read(offset, kCopyFileBufferSize, &result, scratch.get());
538 if (!(s.ok() || s.code() == error::OUT_OF_RANGE)) {
539 return s;
540 }
541 TF_RETURN_IF_ERROR(target_file->Append(result));
542 offset += result.size();
543 }
544 return target_file->Close();
545 }
546
547 // A ZeroCopyInputStream on a RandomAccessFile.
548 namespace {
549 class FileStream : public protobuf::io::ZeroCopyInputStream {
550 public:
FileStream(RandomAccessFile * file)551 explicit FileStream(RandomAccessFile* file) : file_(file), pos_(0) {}
552
BackUp(int count)553 void BackUp(int count) override { pos_ -= count; }
Skip(int count)554 bool Skip(int count) override {
555 pos_ += count;
556 return true;
557 }
ByteCount() const558 int64_t ByteCount() const override { return pos_; }
status() const559 Status status() const { return status_; }
560
Next(const void ** data,int * size)561 bool Next(const void** data, int* size) override {
562 StringPiece result;
563 Status s = file_->Read(pos_, kBufSize, &result, scratch_);
564 if (result.empty()) {
565 status_ = s;
566 return false;
567 }
568 pos_ += result.size();
569 *data = result.data();
570 *size = result.size();
571 return true;
572 }
573
574 private:
575 static constexpr int kBufSize = 512 << 10;
576
577 RandomAccessFile* file_;
578 int64_t pos_;
579 Status status_;
580 char scratch_[kBufSize];
581 };
582
583 } // namespace
584
WriteBinaryProto(Env * env,const string & fname,const protobuf::MessageLite & proto)585 Status WriteBinaryProto(Env* env, const string& fname,
586 const protobuf::MessageLite& proto) {
587 string serialized;
588 proto.AppendToString(&serialized);
589 return WriteStringToFile(env, fname, serialized);
590 }
591
ReadBinaryProto(Env * env,const string & fname,protobuf::MessageLite * proto)592 Status ReadBinaryProto(Env* env, const string& fname,
593 protobuf::MessageLite* proto) {
594 std::unique_ptr<RandomAccessFile> file;
595 TF_RETURN_IF_ERROR(env->NewRandomAccessFile(fname, &file));
596 std::unique_ptr<FileStream> stream(new FileStream(file.get()));
597 protobuf::io::CodedInputStream coded_stream(stream.get());
598
599 if (!proto->ParseFromCodedStream(&coded_stream) ||
600 !coded_stream.ConsumedEntireMessage()) {
601 TF_RETURN_IF_ERROR(stream->status());
602 return errors::DataLoss("Can't parse ", fname, " as binary proto");
603 }
604 return OkStatus();
605 }
606
WriteTextProto(Env * env,const string & fname,const protobuf::Message & proto)607 Status WriteTextProto(Env* env, const string& fname,
608 const protobuf::Message& proto) {
609 string serialized;
610 if (!protobuf::TextFormat::PrintToString(proto, &serialized)) {
611 return errors::FailedPrecondition("Unable to convert proto to text.");
612 }
613 return WriteStringToFile(env, fname, serialized);
614 }
615
ReadTextProto(Env * env,const string & fname,protobuf::Message * proto)616 Status ReadTextProto(Env* env, const string& fname, protobuf::Message* proto) {
617 std::unique_ptr<RandomAccessFile> file;
618 TF_RETURN_IF_ERROR(env->NewRandomAccessFile(fname, &file));
619 std::unique_ptr<FileStream> stream(new FileStream(file.get()));
620
621 if (!protobuf::TextFormat::Parse(stream.get(), proto)) {
622 TF_RETURN_IF_ERROR(stream->status());
623 return errors::DataLoss("Can't parse ", fname, " as text proto");
624 }
625 return OkStatus();
626 }
627
ReadTextOrBinaryProto(Env * env,const string & fname,protobuf::Message * proto)628 Status ReadTextOrBinaryProto(Env* env, const string& fname,
629 protobuf::Message* proto) {
630 if (ReadTextProto(env, fname, proto).ok()) {
631 return OkStatus();
632 }
633 return ReadBinaryProto(env, fname, proto);
634 }
635
ReadTextOrBinaryProto(Env * env,const string & fname,protobuf::MessageLite * proto)636 Status ReadTextOrBinaryProto(Env* env, const string& fname,
637 protobuf::MessageLite* proto) {
638 return ReadBinaryProto(env, fname, proto);
639 }
640
641 } // namespace tensorflow
642