• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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/core/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 Status::OK();
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 Status::OK();
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 Status::OK();
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 Status::OK();
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::vector<string> & values)143 Status Env::SetOption(const std::string& scheme, const std::string& key,
144                       const std::vector<string>& values) {
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, values);
151 }
152 
SetOption(const std::string & scheme,const std::string & key,const std::vector<int64> & values)153 Status Env::SetOption(const std::string& scheme, const std::string& key,
154                       const std::vector<int64>& 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<double> & values)163 Status Env::SetOption(const std::string& scheme, const std::string& key,
164                       const std::vector<double>& 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 
FlushFileSystemCaches()173 Status Env::FlushFileSystemCaches() {
174   std::vector<string> schemes;
175   TF_RETURN_IF_ERROR(GetRegisteredFileSystemSchemes(&schemes));
176   for (const string& scheme : schemes) {
177     FileSystem* fs = nullptr;
178     TF_RETURN_IF_ERROR(
179         GetFileSystemForFile(io::CreateURI(scheme, "", ""), &fs));
180     fs->FlushCaches();
181   }
182   return Status::OK();
183 }
184 
NewRandomAccessFile(const string & fname,std::unique_ptr<RandomAccessFile> * result)185 Status Env::NewRandomAccessFile(const string& fname,
186                                 std::unique_ptr<RandomAccessFile>* result) {
187   FileSystem* fs;
188   TF_RETURN_IF_ERROR(GetFileSystemForFile(fname, &fs));
189   return fs->NewRandomAccessFile(fname, result);
190 }
191 
NewReadOnlyMemoryRegionFromFile(const string & fname,std::unique_ptr<ReadOnlyMemoryRegion> * result)192 Status Env::NewReadOnlyMemoryRegionFromFile(
193     const string& fname, std::unique_ptr<ReadOnlyMemoryRegion>* result) {
194   FileSystem* fs;
195   TF_RETURN_IF_ERROR(GetFileSystemForFile(fname, &fs));
196   return fs->NewReadOnlyMemoryRegionFromFile(fname, result);
197 }
198 
NewWritableFile(const string & fname,std::unique_ptr<WritableFile> * result)199 Status Env::NewWritableFile(const string& fname,
200                             std::unique_ptr<WritableFile>* result) {
201   FileSystem* fs;
202   TF_RETURN_IF_ERROR(GetFileSystemForFile(fname, &fs));
203   return fs->NewWritableFile(fname, result);
204 }
205 
NewAppendableFile(const string & fname,std::unique_ptr<WritableFile> * result)206 Status Env::NewAppendableFile(const string& fname,
207                               std::unique_ptr<WritableFile>* result) {
208   FileSystem* fs;
209   TF_RETURN_IF_ERROR(GetFileSystemForFile(fname, &fs));
210   return fs->NewAppendableFile(fname, result);
211 }
212 
FileExists(const string & fname)213 Status Env::FileExists(const string& fname) {
214   FileSystem* fs;
215   TF_RETURN_IF_ERROR(GetFileSystemForFile(fname, &fs));
216   return fs->FileExists(fname);
217 }
218 
FilesExist(const std::vector<string> & files,std::vector<Status> * status)219 bool Env::FilesExist(const std::vector<string>& files,
220                      std::vector<Status>* status) {
221   std::unordered_map<string, std::vector<string>> files_per_fs;
222   for (const auto& file : files) {
223     StringPiece scheme, host, path;
224     io::ParseURI(file, &scheme, &host, &path);
225     files_per_fs[string(scheme)].push_back(file);
226   }
227 
228   std::unordered_map<string, Status> per_file_status;
229   bool result = true;
230   for (auto itr : files_per_fs) {
231     FileSystem* file_system = file_system_registry_->Lookup(itr.first);
232     bool fs_result;
233     std::vector<Status> local_status;
234     std::vector<Status>* fs_status = status ? &local_status : nullptr;
235     if (!file_system) {
236       fs_result = false;
237       if (fs_status) {
238         Status s = errors::Unimplemented("File system scheme '", itr.first,
239                                          "' not implemented");
240         local_status.resize(itr.second.size(), s);
241       }
242     } else {
243       fs_result = file_system->FilesExist(itr.second, fs_status);
244     }
245     if (fs_status) {
246       result &= fs_result;
247       for (size_t i = 0; i < itr.second.size(); ++i) {
248         per_file_status[itr.second[i]] = fs_status->at(i);
249       }
250     } else if (!fs_result) {
251       // Return early
252       return false;
253     }
254   }
255 
256   if (status) {
257     for (const auto& file : files) {
258       status->push_back(per_file_status[file]);
259     }
260   }
261 
262   return result;
263 }
264 
GetChildren(const string & dir,std::vector<string> * result)265 Status Env::GetChildren(const string& dir, std::vector<string>* result) {
266   FileSystem* fs;
267   TF_RETURN_IF_ERROR(GetFileSystemForFile(dir, &fs));
268   return fs->GetChildren(dir, result);
269 }
270 
GetMatchingPaths(const string & pattern,std::vector<string> * results)271 Status Env::GetMatchingPaths(const string& pattern,
272                              std::vector<string>* results) {
273   FileSystem* fs;
274   TF_RETURN_IF_ERROR(GetFileSystemForFile(pattern, &fs));
275   return fs->GetMatchingPaths(pattern, results);
276 }
277 
DeleteFile(const string & fname)278 Status Env::DeleteFile(const string& fname) {
279   FileSystem* fs;
280   TF_RETURN_IF_ERROR(GetFileSystemForFile(fname, &fs));
281   return fs->DeleteFile(fname);
282 }
283 
RecursivelyCreateDir(const string & dirname)284 Status Env::RecursivelyCreateDir(const string& dirname) {
285   FileSystem* fs;
286   TF_RETURN_IF_ERROR(GetFileSystemForFile(dirname, &fs));
287   return fs->RecursivelyCreateDir(dirname);
288 }
289 
CreateDir(const string & dirname)290 Status Env::CreateDir(const string& dirname) {
291   FileSystem* fs;
292   TF_RETURN_IF_ERROR(GetFileSystemForFile(dirname, &fs));
293   return fs->CreateDir(dirname);
294 }
295 
DeleteDir(const string & dirname)296 Status Env::DeleteDir(const string& dirname) {
297   FileSystem* fs;
298   TF_RETURN_IF_ERROR(GetFileSystemForFile(dirname, &fs));
299   return fs->DeleteDir(dirname);
300 }
301 
Stat(const string & fname,FileStatistics * stat)302 Status Env::Stat(const string& fname, FileStatistics* stat) {
303   FileSystem* fs;
304   TF_RETURN_IF_ERROR(GetFileSystemForFile(fname, &fs));
305   return fs->Stat(fname, stat);
306 }
307 
IsDirectory(const string & fname)308 Status Env::IsDirectory(const string& fname) {
309   FileSystem* fs;
310   TF_RETURN_IF_ERROR(GetFileSystemForFile(fname, &fs));
311   return fs->IsDirectory(fname);
312 }
313 
HasAtomicMove(const string & path,bool * has_atomic_move)314 Status Env::HasAtomicMove(const string& path, bool* has_atomic_move) {
315   FileSystem* fs;
316   TF_RETURN_IF_ERROR(GetFileSystemForFile(path, &fs));
317   return fs->HasAtomicMove(path, has_atomic_move);
318 }
319 
DeleteRecursively(const string & dirname,int64 * undeleted_files,int64 * undeleted_dirs)320 Status Env::DeleteRecursively(const string& dirname, int64* undeleted_files,
321                               int64* undeleted_dirs) {
322   FileSystem* fs;
323   TF_RETURN_IF_ERROR(GetFileSystemForFile(dirname, &fs));
324   return fs->DeleteRecursively(dirname, undeleted_files, undeleted_dirs);
325 }
326 
GetFileSize(const string & fname,uint64 * file_size)327 Status Env::GetFileSize(const string& fname, uint64* file_size) {
328   FileSystem* fs;
329   TF_RETURN_IF_ERROR(GetFileSystemForFile(fname, &fs));
330   return fs->GetFileSize(fname, file_size);
331 }
332 
RenameFile(const string & src,const string & target)333 Status Env::RenameFile(const string& src, const string& target) {
334   FileSystem* src_fs;
335   FileSystem* target_fs;
336   TF_RETURN_IF_ERROR(GetFileSystemForFile(src, &src_fs));
337   TF_RETURN_IF_ERROR(GetFileSystemForFile(target, &target_fs));
338   if (src_fs != target_fs) {
339     return errors::Unimplemented("Renaming ", src, " to ", target,
340                                  " not implemented");
341   }
342   return src_fs->RenameFile(src, target);
343 }
344 
CopyFile(const string & src,const string & target)345 Status Env::CopyFile(const string& src, const string& target) {
346   FileSystem* src_fs;
347   FileSystem* target_fs;
348   TF_RETURN_IF_ERROR(GetFileSystemForFile(src, &src_fs));
349   TF_RETURN_IF_ERROR(GetFileSystemForFile(target, &target_fs));
350   if (src_fs == target_fs) {
351     return src_fs->CopyFile(src, target);
352   }
353   return FileSystemCopyFile(src_fs, src, target_fs, target);
354 }
355 
GetExecutablePath()356 string Env::GetExecutablePath() {
357   char exe_path[PATH_MAX] = {0};
358 #ifdef __APPLE__
359   uint32_t buffer_size(0U);
360   _NSGetExecutablePath(nullptr, &buffer_size);
361   std::vector<char> unresolved_path(buffer_size);
362   _NSGetExecutablePath(unresolved_path.data(), &buffer_size);
363   CHECK(realpath(unresolved_path.data(), exe_path));
364 #elif defined(__FreeBSD__)
365   int mib[4] = {CTL_KERN, KERN_PROC, KERN_PROC_PATHNAME, -1};
366   size_t exe_path_size = PATH_MAX;
367 
368   if (sysctl(mib, 4, exe_path, &exe_path_size, NULL, 0) != 0) {
369     // Resolution of path failed
370     return "";
371   }
372 #elif defined(PLATFORM_WINDOWS)
373   HMODULE hModule = GetModuleHandleW(NULL);
374   WCHAR wc_file_path[MAX_PATH] = {0};
375   GetModuleFileNameW(hModule, wc_file_path, MAX_PATH);
376   string file_path = WideCharToUtf8(wc_file_path);
377   std::copy(file_path.begin(), file_path.end(), exe_path);
378 #else
379   char buf[PATH_MAX] = {0};
380   int path_length = readlink("/proc/self/exe", buf, sizeof(buf) - 1);
381   CHECK_NE(-1, path_length);
382 
383   if (strstr(buf, "python") != nullptr) {
384     // Discard the path of the python binary, and any flags.
385     int fd = open("/proc/self/cmdline", O_RDONLY);
386     int cmd_length = read(fd, buf, PATH_MAX - 1);
387     CHECK_NE(-1, cmd_length);
388     int token_pos = 0;
389     for (bool token_is_first_or_flag = true; token_is_first_or_flag;) {
390       // Get token length, including null
391       int token_len = strlen(&buf[token_pos]) + 1;
392       token_is_first_or_flag = false;
393       // Check if we can skip without overshooting
394       if (token_pos + token_len < cmd_length) {
395         token_pos += token_len;
396         token_is_first_or_flag = (buf[token_pos] == '-');  // token is a flag
397       }
398     }
399     snprintf(exe_path, sizeof(exe_path), "%s", &buf[token_pos]);
400   } else {
401     snprintf(exe_path, sizeof(exe_path), "%s", buf);
402   }
403 
404 #endif
405   // Make sure it's null-terminated:
406   exe_path[sizeof(exe_path) - 1] = 0;
407 
408   return exe_path;
409 }
410 
LocalTempFilename(string * filename)411 bool Env::LocalTempFilename(string* filename) {
412   std::vector<string> dirs;
413   GetLocalTempDirectories(&dirs);
414 
415   // Try each directory, as they might be full, have inappropriate
416   // permissions or have different problems at times.
417   for (const string& dir : dirs) {
418     *filename = io::JoinPath(dir, "tempfile-");
419     if (CreateUniqueFileName(filename, "")) {
420       return true;
421     }
422   }
423   return false;
424 }
425 
CreateUniqueFileName(string * prefix,const string & suffix)426 bool Env::CreateUniqueFileName(string* prefix, const string& suffix) {
427   int32_t tid = GetCurrentThreadId();
428   int32_t pid = GetProcessId();
429   long long now_microsec = NowMicros();  // NOLINT
430 
431   *prefix += strings::Printf("%s-%x-%d-%llx", port::Hostname().c_str(), tid,
432                              pid, now_microsec);
433 
434   if (!suffix.empty()) {
435     *prefix += suffix;
436   }
437   if (FileExists(*prefix).ok()) {
438     prefix->clear();
439     return false;
440   } else {
441     return true;
442   }
443 }
444 
GetProcessId()445 int32 Env::GetProcessId() {
446 #ifdef PLATFORM_WINDOWS
447   return static_cast<int32>(GetCurrentProcessId());
448 #else
449   return static_cast<int32>(getpid());
450 #endif
451 }
452 
~Thread()453 Thread::~Thread() {}
454 
~EnvWrapper()455 EnvWrapper::~EnvWrapper() {}
456 
ReadFileToString(Env * env,const string & fname,string * data)457 Status ReadFileToString(Env* env, const string& fname, string* data) {
458   uint64 file_size;
459   Status s = env->GetFileSize(fname, &file_size);
460   if (!s.ok()) {
461     return s;
462   }
463   std::unique_ptr<RandomAccessFile> file;
464   s = env->NewRandomAccessFile(fname, &file);
465   if (!s.ok()) {
466     return s;
467   }
468   data->resize(file_size);
469   char* p = &*data->begin();
470   StringPiece result;
471   s = file->Read(0, file_size, &result, p);
472   if (!s.ok()) {
473     data->clear();
474   } else if (result.size() != file_size) {
475     s = errors::Aborted("File ", fname, " changed while reading: ", file_size,
476                         " vs. ", result.size());
477     data->clear();
478   } else if (result.data() == p) {
479     // Data is already in the correct location
480   } else {
481     memmove(p, result.data(), result.size());
482   }
483   return s;
484 }
485 
WriteStringToFile(Env * env,const string & fname,const StringPiece & data)486 Status WriteStringToFile(Env* env, const string& fname,
487                          const StringPiece& data) {
488   std::unique_ptr<WritableFile> file;
489   Status s = env->NewWritableFile(fname, &file);
490   if (!s.ok()) {
491     return s;
492   }
493   s = file->Append(data);
494   if (s.ok()) {
495     s = file->Close();
496   }
497   return s;
498 }
499 
FileSystemCopyFile(FileSystem * src_fs,const string & src,FileSystem * target_fs,const string & target)500 Status FileSystemCopyFile(FileSystem* src_fs, const string& src,
501                           FileSystem* target_fs, const string& target) {
502   std::unique_ptr<RandomAccessFile> src_file;
503   TF_RETURN_IF_ERROR(src_fs->NewRandomAccessFile(src, &src_file));
504 
505   // When `target` points to a directory, we need to create a file within.
506   string target_name;
507   if (target_fs->IsDirectory(target).ok()) {
508     target_name = io::JoinPath(target, io::Basename(src));
509   } else {
510     target_name = target;
511   }
512 
513   std::unique_ptr<WritableFile> target_file;
514   TF_RETURN_IF_ERROR(target_fs->NewWritableFile(target_name, &target_file));
515 
516   uint64 offset = 0;
517   std::unique_ptr<char[]> scratch(new char[kCopyFileBufferSize]);
518   Status s = Status::OK();
519   while (s.ok()) {
520     StringPiece result;
521     s = src_file->Read(offset, kCopyFileBufferSize, &result, scratch.get());
522     if (!(s.ok() || s.code() == error::OUT_OF_RANGE)) {
523       return s;
524     }
525     TF_RETURN_IF_ERROR(target_file->Append(result));
526     offset += result.size();
527   }
528   return target_file->Close();
529 }
530 
531 // A ZeroCopyInputStream on a RandomAccessFile.
532 namespace {
533 class FileStream : public protobuf::io::ZeroCopyInputStream {
534  public:
FileStream(RandomAccessFile * file)535   explicit FileStream(RandomAccessFile* file) : file_(file), pos_(0) {}
536 
BackUp(int count)537   void BackUp(int count) override { pos_ -= count; }
Skip(int count)538   bool Skip(int count) override {
539     pos_ += count;
540     return true;
541   }
ByteCount() const542   int64_t ByteCount() const override { return pos_; }
status() const543   Status status() const { return status_; }
544 
Next(const void ** data,int * size)545   bool Next(const void** data, int* size) override {
546     StringPiece result;
547     Status s = file_->Read(pos_, kBufSize, &result, scratch_);
548     if (result.empty()) {
549       status_ = s;
550       return false;
551     }
552     pos_ += result.size();
553     *data = result.data();
554     *size = result.size();
555     return true;
556   }
557 
558  private:
559   static constexpr int kBufSize = 512 << 10;
560 
561   RandomAccessFile* file_;
562   int64 pos_;
563   Status status_;
564   char scratch_[kBufSize];
565 };
566 
567 }  // namespace
568 
WriteBinaryProto(Env * env,const string & fname,const protobuf::MessageLite & proto)569 Status WriteBinaryProto(Env* env, const string& fname,
570                         const protobuf::MessageLite& proto) {
571   string serialized;
572   proto.AppendToString(&serialized);
573   return WriteStringToFile(env, fname, serialized);
574 }
575 
ReadBinaryProto(Env * env,const string & fname,protobuf::MessageLite * proto)576 Status ReadBinaryProto(Env* env, const string& fname,
577                        protobuf::MessageLite* proto) {
578   std::unique_ptr<RandomAccessFile> file;
579   TF_RETURN_IF_ERROR(env->NewRandomAccessFile(fname, &file));
580   std::unique_ptr<FileStream> stream(new FileStream(file.get()));
581   protobuf::io::CodedInputStream coded_stream(stream.get());
582 
583   if (!proto->ParseFromCodedStream(&coded_stream) ||
584       !coded_stream.ConsumedEntireMessage()) {
585     TF_RETURN_IF_ERROR(stream->status());
586     return errors::DataLoss("Can't parse ", fname, " as binary proto");
587   }
588   return Status::OK();
589 }
590 
WriteTextProto(Env * env,const string & fname,const protobuf::Message & proto)591 Status WriteTextProto(Env* env, const string& fname,
592                       const protobuf::Message& proto) {
593   string serialized;
594   if (!protobuf::TextFormat::PrintToString(proto, &serialized)) {
595     return errors::FailedPrecondition("Unable to convert proto to text.");
596   }
597   return WriteStringToFile(env, fname, serialized);
598 }
599 
ReadTextProto(Env * env,const string & fname,protobuf::Message * proto)600 Status ReadTextProto(Env* env, const string& fname, protobuf::Message* proto) {
601   std::unique_ptr<RandomAccessFile> file;
602   TF_RETURN_IF_ERROR(env->NewRandomAccessFile(fname, &file));
603   std::unique_ptr<FileStream> stream(new FileStream(file.get()));
604 
605   if (!protobuf::TextFormat::Parse(stream.get(), proto)) {
606     TF_RETURN_IF_ERROR(stream->status());
607     return errors::DataLoss("Can't parse ", fname, " as text proto");
608   }
609   return Status::OK();
610 }
611 
ReadTextOrBinaryProto(Env * env,const string & fname,protobuf::Message * proto)612 Status ReadTextOrBinaryProto(Env* env, const string& fname,
613                              protobuf::Message* proto) {
614   if (ReadTextProto(env, fname, proto).ok()) {
615     return Status::OK();
616   }
617   return ReadBinaryProto(env, fname, proto);
618 }
619 
ReadTextOrBinaryProto(Env * env,const string & fname,protobuf::MessageLite * proto)620 Status ReadTextOrBinaryProto(Env* env, const string& fname,
621                              protobuf::MessageLite* proto) {
622   return ReadBinaryProto(env, fname, proto);
623 }
624 
625 }  // namespace tensorflow
626