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#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
23namespace shaka {
24
25// Always open files in binary mode.
26const char kAdditionalFileMode[] = "b";
27
28LocalFile::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
34bool 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
44int64_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
56int64_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
68void LocalFile::CloseForWriting() {}
69
70int64_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
89bool LocalFile::Flush() {
90 DCHECK(internal_file_ != NULL);
91 return ((fflush(internal_file_) == 0) && !ferror(internal_file_));
92}
93
94bool 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
103bool 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
115LocalFile::~LocalFile() {}
116
117bool 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
138bool 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)
All the methods that are virtual are virtual for mocking.