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