Shaka Packager SDK
local_file.cc
1 // Copyright 2014 Google LLC. All rights reserved.
2 //
3 // Use of this source code is governed by a BSD-style
4 // license that can be found in the LICENSE file or at
5 // https://developers.google.com/open-source/licenses/bsd
6 
7 #include <packager/file/local_file.h>
8 
9 #if defined(OS_WIN)
10 #include <windows.h>
11 #else
12 #include <sys/stat.h>
13 #endif // defined(OS_WIN)
14 
15 #include <cstdio>
16 #include <filesystem>
17 
18 #include <absl/log/check.h>
19 #include <absl/log/log.h>
20 
21 #include <packager/macros/logging.h>
22 
23 namespace shaka {
24 
25 // Always open files in binary mode.
26 const char kAdditionalFileMode[] = "b";
27 
28 LocalFile::LocalFile(const char* file_name, const char* mode)
29  : File(file_name), file_mode_(mode), internal_file_(NULL) {
30  if (file_mode_.find(kAdditionalFileMode) == std::string::npos)
31  file_mode_ += kAdditionalFileMode;
32 }
33 
34 bool LocalFile::Close() {
35  bool result = true;
36  if (internal_file_) {
37  result = fclose(internal_file_) == 0;
38  internal_file_ = NULL;
39  }
40  delete this;
41  return result;
42 }
43 
44 int64_t LocalFile::Read(void* buffer, uint64_t length) {
45  DCHECK(buffer != NULL);
46  DCHECK(internal_file_ != NULL);
47  size_t bytes_read = fread(buffer, sizeof(char), length, internal_file_);
48  VLOG(2) << "Read " << length << " return " << bytes_read << " error "
49  << ferror(internal_file_);
50  if (bytes_read == 0 && ferror(internal_file_) != 0) {
51  return -1;
52  }
53  return bytes_read;
54 }
55 
56 int64_t LocalFile::Write(const void* buffer, uint64_t length) {
57  DCHECK(buffer != NULL);
58  DCHECK(internal_file_ != NULL);
59  size_t bytes_written = fwrite(buffer, sizeof(char), length, internal_file_);
60  VLOG(2) << "Write " << length << " return " << bytes_written << " error "
61  << ferror(internal_file_);
62  if (bytes_written == 0 && ferror(internal_file_) != 0) {
63  return -1;
64  }
65  return bytes_written;
66 }
67 
68 void LocalFile::CloseForWriting() {}
69 
70 int64_t LocalFile::Size() {
71  DCHECK(internal_file_ != NULL);
72 
73  // Flush any buffered data, so we get the true file size.
74  if (!Flush()) {
75  LOG(ERROR) << "Cannot flush file.";
76  return -1;
77  }
78 
79  std::error_code ec;
80  auto file_path = std::filesystem::u8path(file_name());
81  int64_t file_size = std::filesystem::file_size(file_path, ec);
82  if (ec) {
83  LOG(ERROR) << "Cannot get file size, error: " << ec;
84  return -1;
85  }
86  return file_size;
87 }
88 
89 bool LocalFile::Flush() {
90  DCHECK(internal_file_ != NULL);
91  return ((fflush(internal_file_) == 0) && !ferror(internal_file_));
92 }
93 
94 bool LocalFile::Seek(uint64_t position) {
95 #if defined(OS_WIN)
96  return _fseeki64(internal_file_, static_cast<__int64>(position), SEEK_SET) ==
97  0;
98 #else
99  return fseeko(internal_file_, position, SEEK_SET) >= 0;
100 #endif // !defined(OS_WIN)
101 }
102 
103 bool LocalFile::Tell(uint64_t* position) {
104 #if defined(OS_WIN)
105  __int64 offset = _ftelli64(internal_file_);
106 #else
107  off_t offset = ftello(internal_file_);
108 #endif // !defined(OS_WIN)
109  if (offset < 0)
110  return false;
111  *position = static_cast<uint64_t>(offset);
112  return true;
113 }
114 
115 LocalFile::~LocalFile() {}
116 
117 bool LocalFile::Open() {
118  auto file_path = std::filesystem::u8path(file_name());
119 
120  // Create upper level directories for write mode.
121  if (file_mode_.find("w") != std::string::npos) {
122  // From the return value of filesystem::create_directories, you can't tell
123  // the difference between pre-existing directories and failure. So check
124  // first if it needs to be created.
125  auto parent_path = file_path.parent_path();
126  std::error_code ec;
127  if (parent_path != "" && !std::filesystem::is_directory(parent_path, ec)) {
128  if (!std::filesystem::create_directories(parent_path, ec)) {
129  return false;
130  }
131  }
132  }
133 
134  internal_file_ = fopen(file_path.u8string().c_str(), file_mode_.c_str());
135  return (internal_file_ != NULL);
136 }
137 
138 bool LocalFile::Delete(const char* file_name) {
139  auto file_path = std::filesystem::u8path(file_name);
140  std::error_code ec;
141  // On error (ec truthy), remove() will return false anyway.
142  return std::filesystem::remove(file_path, ec);
143 }
144 
145 } // namespace shaka
LocalFile(const char *file_name, const char *mode)
Definition: local_file.cc:28
static bool Delete(const char *file_name)
Definition: local_file.cc:138
All the methods that are virtual are virtual for mocking.
Definition: crypto_flags.cc:66