File file_helpers.cc
File List > deps > file_helpers.cc
Go to the documentation of this file
// Copyright 2019 The MediaPipe Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "mediapipe/framework/deps/file_helpers.h"
#include "absl/strings/str_cat.h"
#ifdef _WIN32
#include <Windows.h>
#include <direct.h>
#include <codecvt>
#include <locale>
#else
#include <dirent.h>
#endif // _WIN32
#include <stdio.h>
#include <string.h>
#include <sys/stat.h>
#include <cerrno>
#include <string>
#include "absl/status/status.h"
#include "mediapipe/framework/deps/file_path.h"
#include "mediapipe/framework/port/canonical_errors.h"
#include "mediapipe/framework/port/status.h"
#include "mediapipe/framework/port/status_builder.h"
#include "mediapipe/framework/port/status_macros.h"
namespace mediapipe {
namespace file {
namespace {
// Helper class that returns all entries (files, directories) in a directory,
// except "." and "..". Example usage:
//
// DirectoryListing listing("/tmp");
// while (listing.HasNextEntry()) {
// std::cout << listing.NextEntry() << std::endl;
// }
#ifndef _WIN32
class DirectoryListing {
public:
explicit DirectoryListing(const std::string& directory) {
dir_ = opendir(directory.c_str());
if (dir_) {
ReadNextEntry();
}
}
~DirectoryListing() {
if (dir_) {
closedir(dir_);
}
}
// Returns true if another entry in this directory listing is available.
bool HasNextEntry() { return dir_ != nullptr && next_entry_ != nullptr; }
// Returns the next entry in this directory listing and advances to the entry
// after the one that is returned, if it exists.
std::string NextEntry() {
if (HasNextEntry()) {
std::string result = std::string(next_entry_->d_name);
ReadNextEntry();
return result;
} else {
return std::string();
}
}
private:
void ReadNextEntry() {
next_entry_ = readdir(dir_);
while (next_entry_ && (std::string(next_entry_->d_name) == "." ||
std::string(next_entry_->d_name) == "..")) {
next_entry_ = readdir(dir_);
}
}
DIR* dir_ = nullptr;
struct dirent* next_entry_ = nullptr;
};
#else
#if defined(UNICODE)
using PathString = std::wstring;
PathString Utf8ToNative(const std::string& string) {
std::wstring_convert<std::codecvt_utf8_utf16<wchar_t>, wchar_t> converter;
return converter.from_bytes(string.data(), string.data() + string.size());
}
std::string NativeToUtf8(const PathString& string) {
std::wstring_convert<std::codecvt_utf8_utf16<wchar_t>, wchar_t> converter;
return converter.to_bytes(string.data(), string.data() + string.size());
}
#define FILE_PATH_LITERAL_INTERNAL(x) L##x
#define FILE_PATH_LITERAL(x) FILE_PATH_LITERAL_INTERNAL(x)
#else
using PathString = std::string;
PathString Utf8ToNative(const std::string& string) { return string; }
std::string NativeToUtf8(const PathString& string) { return string; }
#define FILE_PATH_LITERAL(x) x
#endif
class DirectoryListing {
public:
explicit DirectoryListing(const std::string& directory)
: directory_(Utf8ToNative(directory)) {
PathString search_string = directory_ + Utf8ToNative("\\*.*");
find_handle_ = FindFirstFile(search_string.c_str(), &find_data_);
}
~DirectoryListing() {
if (find_handle_ != INVALID_HANDLE_VALUE) {
FindClose(find_handle_);
}
}
// Returns true if another entry in this directory listing is available.
bool HasNextEntry() { return find_handle_ != INVALID_HANDLE_VALUE; }
// Returns the next entry in this directory listing and advances to the entry
// after the one that is returned, if it exists.
std::string NextEntry() {
if (HasNextEntry()) {
PathString result =
directory_ + Utf8ToNative("\\") + PathString(find_data_.cFileName);
ReadNextEntry();
return NativeToUtf8(result);
} else {
return std::string();
}
}
private:
void ReadNextEntry() {
int find_result = FindNextFile(find_handle_, &find_data_);
while (find_result != 0 &&
(PathString(find_data_.cFileName) == FILE_PATH_LITERAL(".") ||
PathString(find_data_.cFileName) == FILE_PATH_LITERAL(".."))) {
find_result = FindNextFile(find_handle_, &find_data_);
}
if (find_result == 0) {
FindClose(find_handle_);
find_handle_ = INVALID_HANDLE_VALUE;
}
}
const PathString directory_;
HANDLE find_handle_ = INVALID_HANDLE_VALUE;
WIN32_FIND_DATA find_data_;
};
#endif // _WIN32
} // namespace
absl::Status GetContents(absl::string_view file_name, std::string* output,
bool read_as_binary) {
FILE* fp = fopen(file_name.data(), read_as_binary ? "rb" : "r");
if (fp == NULL) {
return mediapipe::InvalidArgumentErrorBuilder(MEDIAPIPE_LOC)
<< "Can't find file: " << file_name;
}
output->clear();
while (!feof(fp)) {
char buf[4096];
size_t ret = fread(buf, 1, 4096, fp);
if (ret == 0 && ferror(fp)) {
return mediapipe::InternalErrorBuilder(MEDIAPIPE_LOC)
<< "Error while reading file: " << file_name;
}
output->append(std::string(buf, ret));
}
fclose(fp);
return absl::OkStatus();
}
absl::Status SetContents(absl::string_view file_name,
absl::string_view content) {
FILE* fp = fopen(file_name.data(), "wb");
if (fp == NULL) {
return mediapipe::InvalidArgumentErrorBuilder(MEDIAPIPE_LOC)
<< "Can't open file: " << file_name;
}
fwrite(content.data(), sizeof(char), content.size(), fp);
size_t write_error = ferror(fp);
if (fclose(fp) != 0 || write_error) {
return mediapipe::InternalErrorBuilder(MEDIAPIPE_LOC)
<< "Error while writing file: " << file_name
<< ". Error message: " << strerror(write_error);
}
return absl::OkStatus();
}
absl::Status AppendStringToFile(absl::string_view file_name,
absl::string_view contents) {
FILE* fp = fopen(file_name.data(), "ab");
if (!fp) {
return mediapipe::InvalidArgumentErrorBuilder(MEDIAPIPE_LOC)
<< "Can't open file: " << file_name;
}
fwrite(contents.data(), sizeof(char), contents.size(), fp);
size_t write_error = ferror(fp);
if (fclose(fp) != 0 || write_error) {
return mediapipe::InternalErrorBuilder(MEDIAPIPE_LOC)
<< "Error while writing file: " << file_name
<< ". Error message: " << strerror(write_error);
}
return absl::OkStatus();
}
absl::Status MatchInTopSubdirectories(const std::string& parent_directory,
const std::string& file_name,
std::vector<std::string>* results) {
DirectoryListing parent_listing(parent_directory);
while (parent_listing.HasNextEntry()) {
std::string subdirectory =
JoinPath(parent_directory, parent_listing.NextEntry());
DirectoryListing subdirectory_listing(subdirectory);
while (subdirectory_listing.HasNextEntry()) {
std::string next_entry = subdirectory_listing.NextEntry();
if (absl::EndsWith(next_entry, file_name)) {
results->push_back(JoinPath(subdirectory, next_entry));
}
}
}
return absl::OkStatus();
}
absl::Status MatchFileTypeInDirectory(const std::string& directory,
const std::string& file_suffix,
std::vector<std::string>* results) {
DirectoryListing directory_listing(directory);
while (directory_listing.HasNextEntry()) {
std::string next_entry = directory_listing.NextEntry();
if (absl::EndsWith(next_entry, file_suffix)) {
results->push_back(JoinPath(directory, next_entry));
}
}
return absl::OkStatus();
}
absl::Status Exists(absl::string_view file_name) {
struct stat buffer;
int status;
status = stat(std::string(file_name).c_str(), &buffer);
if (status == 0) {
return absl::OkStatus();
}
switch (errno) {
case EACCES:
return mediapipe::PermissionDeniedError("Insufficient permissions.");
default:
return absl::NotFoundError(
absl::StrCat("The path does not exist: ", file_name));
}
}
absl::Status IsDirectory(absl::string_view file_name) {
struct stat buffer;
int status;
status = stat(std::string(file_name).c_str(), &buffer);
if (status == 0) {
if ((buffer.st_mode & S_IFMT) == S_IFDIR) {
return absl::OkStatus();
}
return absl::FailedPreconditionError("The path is not a directory.");
}
switch (errno) {
case EACCES:
return absl::PermissionDeniedError("Insufficient permissions.");
default:
return absl::NotFoundError("The path does not exist.");
}
}
#ifndef _WIN32
int mkdir(std::string path) {
return ::mkdir(path.c_str(), S_IRWXU | S_IRWXG | S_IRWXO);
}
#else
int mkdir(std::string path) { return _mkdir(path.c_str()); }
#endif
absl::Status RecursivelyCreateDir(absl::string_view path) {
if (path.empty() || Exists(path).ok()) {
return absl::OkStatus();
}
auto split_path = file::SplitPath(path);
MP_RETURN_IF_ERROR(RecursivelyCreateDir(split_path.first));
if (mkdir(std::string(path)) != 0) {
switch (errno) {
case EACCES:
return mediapipe::PermissionDeniedError("Insufficient permissions.");
default:
return absl::UnavailableError("Failed to create directory.");
}
}
return absl::OkStatus();
}
} // namespace file
} // namespace mediapipe