// Copyright 2013 Google Inc. All Rights Reserved. // // File class - provides a simple android specific file implementation #include "file_store.h" #include #include #include #include #include #include #include #include #include "file_utils.h" #include "log.h" #include "string_conversions.h" #include #include 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 hash(MD5_DIGEST_LENGTH); const unsigned char* input_ptr = reinterpret_cast(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* file, const std::string& file_path) : file_(file), file_path_(file_path) {} virtual ~Impl() {} FILE* file_; std::string file_path_; }; File::File(Impl* impl) : impl_(impl) {} File::~File() { Close(); delete impl_; } void File::Close() { if (impl_ && impl_->file_) { fflush(impl_->file_); fsync(fileno(impl_->file_)); fclose(impl_->file_); impl_->file_ = NULL; } } ssize_t File::Read(char* buffer, size_t bytes) { if (impl_ && impl_->file_) { size_t len = fread(buffer, sizeof(char), bytes, impl_->file_); if (len == 0) { LOGW("File::Read: fread failed: %d", errno); } return len; } LOGW("File::Read: file not open"); return -1; } ssize_t File::Write(const char* buffer, size_t bytes) { if (impl_ && impl_->file_) { size_t len = fwrite(buffer, sizeof(char), bytes, impl_->file_); if (len == 0) { LOGW("File::Write: fwrite failed: %d", errno); } return len; } LOGW("File::Write: file not open"); return -1; } class FileSystem::Impl {}; FileSystem::FileSystem() : FileSystem("", NULL) {} FileSystem::FileSystem(const std::string& origin, void* /* extra_data */) : origin_(origin) { FileUtils::SecurityLevelPathBackwardCompatibility(kSecurityLevelL1); FileUtils::SecurityLevelPathBackwardCompatibility(kSecurityLevelL3); } FileSystem::~FileSystem() {} File* FileSystem::Open(const std::string& in_name, int flags) { std::string open_flags; std::string name = GetFileNameForOrigin(in_name, origin_); // 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); } // 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); } } open_flags = (flags & FileSystem::kReadOnly) ? "rb" : "rb+"; FILE* file = fopen(name.c_str(), open_flags.c_str()); umask(old_mask); if (!file) { LOGW("File::Open: fopen failed: %d", errno); return NULL; } return new File(new File::Impl(file, name)); } bool FileSystem::Exists(const std::string& path) { return FileUtils::Exists(GetFileNameForOrigin(path, origin_)); } bool FileSystem::Remove(const std::string& path) { return FileUtils::Remove(GetFileNameForOrigin(path, origin_)); } 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; else return -1; } void FileSystem::SetOrigin(const std::string& origin) { origin_ = origin; } } // namespace wvcdm