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