File util, generic crypto, and key query
This CL merges several CLs from the widevine repo: http://go/wvgerrit/18012 Add support for querying allowed usage for key. http://go/wvgerrit/17971 Add per-origin storage. http://go/wvgerrit/18152 Add OEMCrypto's generic crypto operations to CDM. http://go/wvgerrit/17911 QueryKeyControlInfo => QueryOemCryptoSessionId Note: numbering in wv_cdm_types.h was added in this CL and will be back ported to wvgerrit in a future CL. Change-Id: Idb9e9a67e94f62f25dc16c5307f75a08b3430b64
This commit is contained in:
@@ -13,68 +13,69 @@
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "file_utils.h"
|
||||
#include "log.h"
|
||||
#include "string_conversions.h"
|
||||
|
||||
namespace {
|
||||
const char kCurrentDirectory[] = ".";
|
||||
const char kParentDirectory[] = "..";
|
||||
const char kDirectoryDelimiter = '/';
|
||||
const char kWildcard[] = "*";
|
||||
bool IsCurrentOrParentDirectory(char* dir) {
|
||||
return strcmp(dir, kCurrentDirectory) == 0 ||
|
||||
strcmp(dir, kParentDirectory) == 0;
|
||||
}
|
||||
} // namespace
|
||||
#include <openssl/md5.h>
|
||||
#include <openssl/sha.h>
|
||||
|
||||
namespace wvcdm {
|
||||
|
||||
namespace {
|
||||
const char kCertificateFileNamePrefix[] = "cert";
|
||||
const char kCertificateFileNameExt[] = ".bin";
|
||||
const char kCertificateFileName[] = "cert.bin";
|
||||
|
||||
std::string GetFileNameSafeHash(const std::string& input) {
|
||||
std::vector<uint8_t> hash(MD5_DIGEST_LENGTH);
|
||||
const unsigned char* input_ptr =
|
||||
reinterpret_cast<const unsigned char*>(input.data());
|
||||
MD5(input_ptr, input.size(), &hash[0]);
|
||||
return wvcdm::Base64SafeEncode(hash);
|
||||
}
|
||||
|
||||
std::string GetFileNameForOrigin(const std::string path,
|
||||
const std::string origin) {
|
||||
std::string file_name = path;
|
||||
std::string dir_path;
|
||||
const size_t delimiter_pos = path.rfind(kDirectoryDelimiter);
|
||||
if (delimiter_pos != std::string::npos) {
|
||||
dir_path = file_name.substr(0, delimiter_pos);
|
||||
file_name = path.substr(delimiter_pos + 1);
|
||||
}
|
||||
|
||||
if (file_name == kCertificateFileName && !origin.empty()) {
|
||||
const std::string hash = GetFileNameSafeHash(origin);
|
||||
file_name = kCertificateFileNamePrefix + hash + kCertificateFileNameExt;
|
||||
}
|
||||
|
||||
if (dir_path.empty())
|
||||
return file_name;
|
||||
else
|
||||
return dir_path + kDirectoryDelimiter + file_name;
|
||||
}
|
||||
} // namespace
|
||||
|
||||
class File::Impl {
|
||||
public:
|
||||
Impl() : file_(NULL) {}
|
||||
Impl(const std::string& file_path) : file_(NULL), file_path_(file_path) {}
|
||||
Impl(FILE* file, const std::string& file_path)
|
||||
: file_(file), file_path_(file_path) {}
|
||||
virtual ~Impl() {}
|
||||
|
||||
FILE* file_;
|
||||
std::string file_path_;
|
||||
};
|
||||
|
||||
File::File() : impl_(new File::Impl()) {}
|
||||
File::File(Impl* impl) : impl_(impl) {}
|
||||
|
||||
File::~File() {
|
||||
Close();
|
||||
delete impl_;
|
||||
}
|
||||
|
||||
bool File::Open(const std::string& name, int flags) {
|
||||
std::string open_flags;
|
||||
|
||||
// ensure only owners has access
|
||||
mode_t old_mask = umask(077);
|
||||
if (((flags & File::kTruncate) && Exists(name)) ||
|
||||
((flags & File::kCreate) && !Exists(name))) {
|
||||
FILE* fp = fopen(name.c_str(), "w+");
|
||||
if (fp) {
|
||||
fclose(fp);
|
||||
}
|
||||
}
|
||||
|
||||
if (flags & File::kBinary) {
|
||||
open_flags = (flags & File::kReadOnly) ? "rb" : "rb+";
|
||||
} else {
|
||||
open_flags = (flags & File::kReadOnly) ? "r" : "r+";
|
||||
}
|
||||
|
||||
impl_->file_ = fopen(name.c_str(), open_flags.c_str());
|
||||
if (!impl_->file_) {
|
||||
LOGW("File::Open: fopen failed: %d", errno);
|
||||
}
|
||||
impl_->file_path_ = name;
|
||||
umask(old_mask);
|
||||
return impl_->file_ != NULL;
|
||||
}
|
||||
|
||||
void File::Close() {
|
||||
if (impl_->file_){
|
||||
if (impl_ && impl_->file_) {
|
||||
fflush(impl_->file_);
|
||||
fsync(fileno(impl_->file_));
|
||||
fclose(impl_->file_);
|
||||
@@ -83,7 +84,7 @@ void File::Close() {
|
||||
}
|
||||
|
||||
ssize_t File::Read(char* buffer, size_t bytes) {
|
||||
if (impl_->file_) {
|
||||
if (impl_ && impl_->file_) {
|
||||
size_t len = fread(buffer, sizeof(char), bytes, impl_->file_);
|
||||
if (len == 0) {
|
||||
LOGW("File::Read: fread failed: %d", errno);
|
||||
@@ -95,7 +96,7 @@ ssize_t File::Read(char* buffer, size_t bytes) {
|
||||
}
|
||||
|
||||
ssize_t File::Write(const char* buffer, size_t bytes) {
|
||||
if (impl_->file_) {
|
||||
if (impl_ && impl_->file_) {
|
||||
size_t len = fwrite(buffer, sizeof(char), bytes, impl_->file_);
|
||||
if (len == 0) {
|
||||
LOGW("File::Write: fwrite failed: %d", errno);
|
||||
@@ -106,194 +107,62 @@ ssize_t File::Write(const char* buffer, size_t bytes) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
bool File::Exists(const std::string& path) {
|
||||
struct stat buf;
|
||||
int res = stat(path.c_str(), &buf) == 0;
|
||||
if (!res) {
|
||||
LOGV("File::Exists: stat failed: %d", errno);
|
||||
}
|
||||
return res;
|
||||
class FileSystem::Impl {};
|
||||
|
||||
FileSystem::FileSystem() : FileSystem("", NULL) {}
|
||||
FileSystem::FileSystem(const std::string& origin, void* /* extra_data */)
|
||||
: origin_(origin) {
|
||||
FileUtils::SecurityLevelPathBackwardCompatibility(kSecurityLevelL1);
|
||||
FileUtils::SecurityLevelPathBackwardCompatibility(kSecurityLevelL3);
|
||||
}
|
||||
|
||||
bool File::Remove(const std::string& path) {
|
||||
if (IsDirectory(path)) {
|
||||
// Handle directory deletion
|
||||
DIR* dir;
|
||||
if ((dir = opendir(path.c_str())) != NULL) {
|
||||
// first remove files and dir within it
|
||||
struct dirent* entry;
|
||||
while ((entry = readdir(dir)) != NULL) {
|
||||
if (!IsCurrentOrParentDirectory(entry->d_name)) {
|
||||
std::string path_to_remove = path + kDirectoryDelimiter;
|
||||
path_to_remove += entry->d_name;
|
||||
if (!Remove(path_to_remove)) {
|
||||
closedir(dir);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
closedir(dir);
|
||||
}
|
||||
if (rmdir(path.c_str())) {
|
||||
LOGW("File::Remove: rmdir failed: %d", errno);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
} else {
|
||||
size_t wildcard_pos = path.find(kWildcard);
|
||||
if (wildcard_pos == std::string::npos) {
|
||||
// Handle file deletion
|
||||
if (unlink(path.c_str()) && (errno != ENOENT)) {
|
||||
LOGW("File::Remove: unlink failed: %d", errno);
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
// Handle wildcard specified file deletion
|
||||
size_t delimiter_pos = path.rfind(kDirectoryDelimiter, wildcard_pos);
|
||||
if (delimiter_pos == std::string::npos) {
|
||||
LOGW("File::Remove: unable to find path delimiter before wildcard");
|
||||
return false;
|
||||
}
|
||||
FileSystem::~FileSystem() {}
|
||||
|
||||
DIR* dir;
|
||||
std::string dir_path = path.substr(0, delimiter_pos);
|
||||
if ((dir = opendir(dir_path.c_str())) == NULL) {
|
||||
LOGW("File::Remove: directory open failed for wildcard");
|
||||
return false;
|
||||
}
|
||||
File* FileSystem::Open(const std::string& in_name, int flags) {
|
||||
std::string open_flags;
|
||||
|
||||
struct dirent* entry;
|
||||
std::string ext = path.substr(wildcard_pos + 1);
|
||||
std::string name = GetFileNameForOrigin(in_name, origin_);
|
||||
|
||||
while ((entry = readdir(dir)) != NULL) {
|
||||
size_t filename_len = strlen(entry->d_name);
|
||||
if (filename_len > ext.size()) {
|
||||
if (strcmp(entry->d_name + filename_len - ext.size(), ext.c_str()) ==
|
||||
0) {
|
||||
std::string file_path_to_remove =
|
||||
dir_path + kDirectoryDelimiter + entry->d_name;
|
||||
if (!Remove(file_path_to_remove)) {
|
||||
closedir(dir);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
closedir(dir);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
bool File::Copy(const std::string& src, const std::string& dest) {
|
||||
struct stat stat_buf;
|
||||
if (stat(src.c_str(), &stat_buf)) {
|
||||
LOGV("File::Copy: file %s stat error: %d", src.c_str(), errno);
|
||||
return false;
|
||||
// create the enclosing directory if it does not exist
|
||||
size_t delimiter_pos = name.rfind(kDirectoryDelimiter);
|
||||
if (delimiter_pos != std::string::npos) {
|
||||
std::string dir_path = name.substr(0, delimiter_pos);
|
||||
if ((flags & FileSystem::kCreate) && !Exists(dir_path))
|
||||
FileUtils::CreateDirectory(dir_path);
|
||||
}
|
||||
|
||||
int fd_src = open(src.c_str(), O_RDONLY);
|
||||
if (fd_src < 0) {
|
||||
LOGW("File::Copy: unable to open file %s: %d", src.c_str(), errno);
|
||||
return false;
|
||||
}
|
||||
|
||||
int fd_dest = open(dest.c_str(), O_WRONLY | O_CREAT, stat_buf.st_mode);
|
||||
if (fd_dest < 0) {
|
||||
LOGW("File::Copy: unable to open file %s: %d", dest.c_str(), errno);
|
||||
close(fd_src);
|
||||
return false;
|
||||
}
|
||||
|
||||
off_t offset = 0;
|
||||
bool status = true;
|
||||
if (sendfile(fd_dest, fd_src, &offset, stat_buf.st_size) < 0) {
|
||||
LOGV("File::Copy: unable to copy %s to %s: %d", src.c_str(), dest.c_str(),
|
||||
errno);
|
||||
status = false;
|
||||
}
|
||||
|
||||
close(fd_src);
|
||||
close(fd_dest);
|
||||
return status;
|
||||
}
|
||||
|
||||
bool File::List(const std::string& path, std::vector<std::string>* files) {
|
||||
if (NULL == files) {
|
||||
LOGV("File::List: files destination not provided");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!Exists(path)) {
|
||||
LOGV("File::List: path %s does not exist: %d", path.c_str(), errno);
|
||||
return false;
|
||||
}
|
||||
|
||||
DIR* dir = opendir(path.c_str());
|
||||
if (dir == NULL) {
|
||||
LOGW("File::List: unable to open directory %s: %d", path.c_str(), errno);
|
||||
return false;
|
||||
}
|
||||
|
||||
files->clear();
|
||||
struct dirent* entry;
|
||||
while ((entry = readdir(dir)) != NULL) {
|
||||
if (!IsCurrentOrParentDirectory(entry->d_name)) {
|
||||
files->push_back(entry->d_name);
|
||||
// ensure only owners has access
|
||||
mode_t old_mask = umask(077);
|
||||
if (((flags & FileSystem::kTruncate) && Exists(name)) ||
|
||||
((flags & FileSystem::kCreate) && !Exists(name))) {
|
||||
FILE* fp = fopen(name.c_str(), "w+");
|
||||
if (fp) {
|
||||
fclose(fp);
|
||||
}
|
||||
}
|
||||
closedir(dir);
|
||||
|
||||
return true;
|
||||
}
|
||||
open_flags = (flags & FileSystem::kReadOnly) ? "rb" : "rb+";
|
||||
|
||||
bool File::CreateDirectory(std::string path) {
|
||||
size_t size = path.size();
|
||||
if ((size == 1) && (path[0] == kDirectoryDelimiter)) return true;
|
||||
|
||||
if (size <= 1) return false;
|
||||
|
||||
size_t pos = path.find(kDirectoryDelimiter, 1);
|
||||
while (pos < size) {
|
||||
path[pos] = '\0';
|
||||
if (mkdir(path.c_str(), 0700) != 0) {
|
||||
if (errno != EEXIST) {
|
||||
LOGW("File::CreateDirectory: mkdir failed: %d\n", errno);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
path[pos] = kDirectoryDelimiter;
|
||||
pos = path.find(kDirectoryDelimiter, pos + 1);
|
||||
FILE* file = fopen(name.c_str(), open_flags.c_str());
|
||||
umask(old_mask);
|
||||
if (!file) {
|
||||
LOGW("File::Open: fopen failed: %d", errno);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (path[size - 1] != kDirectoryDelimiter) {
|
||||
if (mkdir(path.c_str(), 0700) != 0) {
|
||||
if (errno != EEXIST) {
|
||||
LOGW("File::CreateDirectory: mkdir failed: %d\n", errno);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
return new File(new File::Impl(file, name));
|
||||
}
|
||||
|
||||
bool File::IsDirectory(const std::string& path) {
|
||||
struct stat buf;
|
||||
if (stat(path.c_str(), &buf) == 0)
|
||||
return buf.st_mode & S_IFDIR;
|
||||
else
|
||||
return false;
|
||||
bool FileSystem::Exists(const std::string& path) {
|
||||
return FileUtils::Exists(GetFileNameForOrigin(path, origin_));
|
||||
}
|
||||
|
||||
bool File::IsRegularFile(const std::string& path) {
|
||||
struct stat buf;
|
||||
if (stat(path.c_str(), &buf) == 0)
|
||||
return buf.st_mode & S_IFREG;
|
||||
else
|
||||
return false;
|
||||
bool FileSystem::Remove(const std::string& path) {
|
||||
return FileUtils::Remove(GetFileNameForOrigin(path, origin_));
|
||||
}
|
||||
|
||||
ssize_t File::FileSize(const std::string& path) {
|
||||
ssize_t FileSystem::FileSize(const std::string& in_path) {
|
||||
std::string path = GetFileNameForOrigin(in_path, origin_);
|
||||
struct stat buf;
|
||||
if (stat(path.c_str(), &buf) == 0)
|
||||
return buf.st_size;
|
||||
@@ -301,4 +170,6 @@ ssize_t File::FileSize(const std::string& path) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
void FileSystem::SetOrigin(const std::string& origin) { origin_ = origin; }
|
||||
|
||||
} // namespace wvcdm
|
||||
|
||||
Reference in New Issue
Block a user