#include "storage/browser/database/database_util.h"
#include <stddef.h>
#include "base/strings/utf_string_conversions.h"
#include "storage/browser/database/database_tracker.h"
#include "storage/browser/database/vfs_backend.h"
#include "storage/common/database/database_identifier.h"
namespace storage {
namespace {
bool IsSafeSuffix(const std::u16string& suffix) {
char16_t prev_c = 0;
for (const char16_t c : suffix) {
if (!(base::IsAsciiAlpha(c) || base::IsAsciiDigit(c) || c == '-' ||
c == '.' || c == '_')) {
return false;
}
if (c == '.' && prev_c == '.')
return false;
prev_c = c;
}
return true;
}
}
const char DatabaseUtil::kJournalFileSuffix[] = "-journal";
bool DatabaseUtil::CrackVfsFileName(const std::u16string& vfs_file_name,
std::string* origin_identifier,
std::u16string* database_name,
std::u16string* sqlite_suffix) {
DCHECK(!vfs_file_name.empty());
#if defined(OHOS_WEBSTORAGE)
size_t first_slash_index = vfs_file_name.rfind('/');
if (first_slash_index == std::u16string::npos) {
LOG(ERROR) << "DatabaseUtil::CrackVfsFileName not find /";
return false;
}
std::u16string dbnameAndSuffix = vfs_file_name.substr(
first_slash_index + 1, vfs_file_name.length() - first_slash_index - 1);
size_t last_pound_index = dbnameAndSuffix.rfind('.');
if (last_pound_index == std::u16string::npos) {
LOG(ERROR) << "DatabaseUtil::CrackVfsFileName not find .";
return false;
}
std::u16string suffix = dbnameAndSuffix.substr(
last_pound_index, dbnameAndSuffix.length() - last_pound_index);
if (!IsSafeSuffix(suffix)) {
LOG(ERROR) << "DatabaseUtil::CrackVfsFileName IsSafeSuffix failed";
return false;
}
std::u16string path = vfs_file_name.substr(0, first_slash_index);
first_slash_index = path.rfind('/');
if (first_slash_index == std::u16string::npos) {
LOG(ERROR) << "DatabaseUtil::CrackVfsFileName not find /";
return false;
}
std::u16string name = dbnameAndSuffix.substr(0, last_pound_index);
std::string origin_id = base::UTF16ToASCII(path.substr(
first_slash_index + 1, path.length() - first_slash_index - 1));
if (!IsValidOriginIdentifier(origin_id)) {
LOG(ERROR)
<< "DatabaseUtil::CrackVfsFileName IsValidOriginIdentifier failed";
return false;
}
if (sqlite_suffix)
*sqlite_suffix = suffix;
if (database_name)
*database_name = name;
if (origin_identifier)
*origin_identifier = origin_id;
return true;
#else
size_t first_slash_index = vfs_file_name.find('/');
size_t last_pound_index = vfs_file_name.rfind('#');
if ((first_slash_index == std::u16string::npos) ||
(last_pound_index == std::u16string::npos) || (first_slash_index == 0) ||
(first_slash_index > last_pound_index)) {
return false;
}
std::string origin_id = base::UTF16ToASCII(
vfs_file_name.substr(0, first_slash_index));
if (!IsValidOriginIdentifier(origin_id))
return false;
std::u16string suffix = vfs_file_name.substr(
last_pound_index + 1, vfs_file_name.length() - last_pound_index - 1);
if (!IsSafeSuffix(suffix))
return false;
if (origin_identifier)
*origin_identifier = origin_id;
if (database_name) {
*database_name = vfs_file_name.substr(
first_slash_index + 1, last_pound_index - first_slash_index - 1);
}
if (sqlite_suffix)
*sqlite_suffix = suffix;
return true;
#endif
}
base::FilePath DatabaseUtil::GetFullFilePathForVfsFile(
DatabaseTracker* db_tracker,
const std::u16string& vfs_file_name) {
std::string origin_identifier;
std::u16string database_name;
std::u16string sqlite_suffix;
if (!CrackVfsFileName(vfs_file_name, &origin_identifier,
&database_name, &sqlite_suffix)) {
return base::FilePath();
}
base::FilePath full_path = db_tracker->GetFullDBFilePath(
origin_identifier, database_name);
if (!full_path.empty() && !sqlite_suffix.empty()) {
DCHECK(full_path.Extension().empty());
full_path = full_path.InsertBeforeExtensionASCII(
base::UTF16ToASCII(sqlite_suffix));
}
if (full_path.value().find(FILE_PATH_LITERAL("..")) !=
base::FilePath::StringType::npos)
return base::FilePath();
return full_path;
}
}