file_system_util.cc 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438
  1. // Copyright (c) 2012 The Chromium Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style license that can be
  3. // found in the LICENSE file.
  4. #include "storage/common/file_system/file_system_util.h"
  5. #include <stddef.h>
  6. #include <algorithm>
  7. #include "base/check.h"
  8. #include "base/notreached.h"
  9. #include "base/strings/escape.h"
  10. #include "base/strings/string_util.h"
  11. #include "base/strings/sys_string_conversions.h"
  12. #include "build/build_config.h"
  13. #include "net/base/net_errors.h"
  14. #include "storage/common/database/database_identifier.h"
  15. #include "url/gurl.h"
  16. namespace storage {
  17. const char kPersistentDir[] = "/persistent";
  18. const char kTemporaryDir[] = "/temporary";
  19. const char kIsolatedDir[] = "/isolated";
  20. const char kExternalDir[] = "/external";
  21. const char kTestDir[] = "/test";
  22. const base::FilePath::CharType VirtualPath::kRoot[] = FILE_PATH_LITERAL("/");
  23. const base::FilePath::CharType VirtualPath::kSeparator = FILE_PATH_LITERAL('/');
  24. // TODO(ericu): Consider removing support for '\', even on Windows, if possible.
  25. // There's a lot of test code that will need reworking, and we may have trouble
  26. // with base::FilePath elsewhere [e.g. DirName and other methods may also need
  27. // replacement].
  28. base::FilePath VirtualPath::BaseName(const base::FilePath& virtual_path) {
  29. base::FilePath::StringType path = virtual_path.value();
  30. // Keep everything after the final separator, but if the pathname is only
  31. // one character and it's a separator, leave it alone.
  32. while (path.size() > 1 && base::FilePath::IsSeparator(path.back()))
  33. path.resize(path.size() - 1);
  34. base::FilePath::StringType::size_type last_separator =
  35. path.find_last_of(base::FilePath::kSeparators);
  36. if (last_separator != base::FilePath::StringType::npos &&
  37. last_separator < path.size() - 1)
  38. path.erase(0, last_separator + 1);
  39. return base::FilePath(path);
  40. }
  41. base::FilePath VirtualPath::DirName(const base::FilePath& virtual_path) {
  42. using StringType = base::FilePath::StringType;
  43. StringType path = virtual_path.value();
  44. // The logic below is taken from that of base::FilePath::DirName, except
  45. // that this version never cares about '//' or drive-letters even on win32.
  46. // Strip trailing separators.
  47. while (path.size() > 1 && base::FilePath::IsSeparator(path.back()))
  48. path.resize(path.size() - 1);
  49. StringType::size_type last_separator =
  50. path.find_last_of(base::FilePath::kSeparators);
  51. if (last_separator == StringType::npos) {
  52. // path_ is in the current directory.
  53. return base::FilePath(base::FilePath::kCurrentDirectory);
  54. }
  55. if (last_separator == 0) {
  56. // path_ is in the root directory.
  57. return base::FilePath(path.substr(0, 1));
  58. }
  59. // path_ is somewhere else, trim the basename.
  60. path.resize(last_separator);
  61. // Strip trailing separators.
  62. while (path.size() > 1 && base::FilePath::IsSeparator(path.back()))
  63. path.resize(path.size() - 1);
  64. if (path.empty())
  65. return base::FilePath(base::FilePath::kCurrentDirectory);
  66. return base::FilePath(path);
  67. }
  68. std::vector<base::FilePath::StringType> VirtualPath::GetComponents(
  69. const base::FilePath& path) {
  70. using StringType = base::FilePath::StringType;
  71. std::vector<StringType> components;
  72. if (path.value().empty())
  73. return components;
  74. StringType::size_type begin = 0, end = 0;
  75. while (begin < path.value().length() && end != StringType::npos) {
  76. end = path.value().find_first_of(base::FilePath::kSeparators, begin);
  77. StringType component = path.value().substr(
  78. begin, end == StringType::npos ? StringType::npos : end - begin);
  79. if (!component.empty() && component != base::FilePath::kCurrentDirectory)
  80. components.push_back(component);
  81. begin = end + 1;
  82. }
  83. return components;
  84. }
  85. std::vector<std::string> VirtualPath::GetComponentsUTF8Unsafe(
  86. const base::FilePath& path) {
  87. std::vector<base::FilePath::StringType> stringtype_components =
  88. VirtualPath::GetComponents(path);
  89. std::vector<std::string> components;
  90. components.reserve(stringtype_components.size());
  91. for (const auto& component : stringtype_components)
  92. components.push_back(base::FilePath(component).AsUTF8Unsafe());
  93. return components;
  94. }
  95. base::FilePath::StringType VirtualPath::GetNormalizedFilePath(
  96. const base::FilePath& path) {
  97. base::FilePath::StringType normalized_path = path.value();
  98. const size_t num_separators =
  99. base::FilePath::StringType(base::FilePath::kSeparators).length();
  100. for (size_t i = 0; i < num_separators; ++i) {
  101. std::replace(normalized_path.begin(), normalized_path.end(),
  102. base::FilePath::kSeparators[i], kSeparator);
  103. }
  104. return (IsAbsolute(normalized_path))
  105. ? normalized_path
  106. : base::FilePath::StringType(kRoot) + normalized_path;
  107. }
  108. bool VirtualPath::IsAbsolute(const base::FilePath::StringType& path) {
  109. return base::StartsWith(path, kRoot, base::CompareCase::SENSITIVE);
  110. }
  111. bool VirtualPath::IsRootPath(const base::FilePath& path) {
  112. std::vector<base::FilePath::StringType> components =
  113. VirtualPath::GetComponents(path);
  114. return (path.empty() || components.empty() ||
  115. (components.size() == 1 && components[0] == VirtualPath::kRoot));
  116. }
  117. bool ParseFileSystemSchemeURL(const GURL& url,
  118. GURL* origin_url,
  119. FileSystemType* type,
  120. base::FilePath* virtual_path) {
  121. GURL origin;
  122. FileSystemType file_system_type = kFileSystemTypeUnknown;
  123. if (!url.is_valid() || !url.SchemeIsFileSystem())
  124. return false;
  125. const struct {
  126. FileSystemType type;
  127. const char* dir;
  128. } kValidTypes[] = {
  129. {kFileSystemTypePersistent, kPersistentDir},
  130. {kFileSystemTypeTemporary, kTemporaryDir},
  131. {kFileSystemTypeIsolated, kIsolatedDir},
  132. {kFileSystemTypeExternal, kExternalDir},
  133. {kFileSystemTypeTest, kTestDir},
  134. };
  135. // A path of the inner_url contains only mount type part (e.g. "/temporary").
  136. DCHECK(url.inner_url());
  137. std::string inner_path = url.inner_url()->path();
  138. for (const auto& valid_type : kValidTypes) {
  139. if (inner_path == valid_type.dir) {
  140. file_system_type = valid_type.type;
  141. break;
  142. }
  143. }
  144. if (file_system_type == kFileSystemTypeUnknown)
  145. return false;
  146. std::string path = base::UnescapeBinaryURLComponent(url.path_piece());
  147. // Ensure the path is relative.
  148. while (!path.empty() && path[0] == '/')
  149. path.erase(0, 1);
  150. base::FilePath converted_path = base::FilePath::FromUTF8Unsafe(path);
  151. // All parent references should have been resolved in the renderer.
  152. if (converted_path.ReferencesParent())
  153. return false;
  154. if (origin_url)
  155. *origin_url = url.DeprecatedGetOriginAsURL();
  156. if (type)
  157. *type = file_system_type;
  158. if (virtual_path)
  159. *virtual_path =
  160. converted_path.NormalizePathSeparators().StripTrailingSeparators();
  161. return true;
  162. }
  163. GURL GetFileSystemRootURI(const GURL& origin_url, FileSystemType type) {
  164. // origin_url is based on a security origin, so http://foo.com or file:///
  165. // instead of the corresponding filesystem URL.
  166. DCHECK(!origin_url.SchemeIsFileSystem());
  167. std::string url = "filesystem:" + origin_url.GetWithEmptyPath().spec();
  168. switch (type) {
  169. case kFileSystemTypeTemporary:
  170. url += (kTemporaryDir + 1); // We don't want the leading slash.
  171. return GURL(url + "/");
  172. case kFileSystemTypePersistent:
  173. url += (kPersistentDir + 1); // We don't want the leading slash.
  174. return GURL(url + "/");
  175. case kFileSystemTypeExternal:
  176. url += (kExternalDir + 1); // We don't want the leading slash.
  177. return GURL(url + "/");
  178. case kFileSystemTypeIsolated:
  179. url += (kIsolatedDir + 1); // We don't want the leading slash.
  180. return GURL(url + "/");
  181. case kFileSystemTypeTest:
  182. url += (kTestDir + 1); // We don't want the leading slash.
  183. return GURL(url + "/");
  184. // Internal types are always pointed via isolated or external URLs.
  185. default:
  186. NOTREACHED();
  187. }
  188. NOTREACHED();
  189. return GURL();
  190. }
  191. std::string GetFileSystemName(const GURL& origin_url, FileSystemType type) {
  192. std::string origin_identifier = storage::GetIdentifierFromOrigin(origin_url);
  193. std::string type_string = GetFileSystemTypeString(type);
  194. DCHECK(!type_string.empty());
  195. return origin_identifier + ":" + type_string;
  196. }
  197. std::string GetFileSystemTypeString(FileSystemType type) {
  198. switch (type) {
  199. case kFileSystemTypeTemporary:
  200. return "Temporary";
  201. case kFileSystemTypePersistent:
  202. return "Persistent";
  203. case kFileSystemTypeIsolated:
  204. return "Isolated";
  205. case kFileSystemTypeExternal:
  206. return "External";
  207. case kFileSystemTypeTest:
  208. return "Test";
  209. case kFileSystemTypeLocal:
  210. return "Local";
  211. case kFileSystemTypeRestrictedLocal:
  212. return "RestrictedLocal";
  213. case kFileSystemTypeDragged:
  214. return "Dragged";
  215. case kFileSystemTypeLocalMedia:
  216. return "LocalMedia";
  217. case kFileSystemTypeDeviceMedia:
  218. return "DeviceMedia";
  219. case kFileSystemTypeSyncable:
  220. case kFileSystemTypeSyncableForInternalSync:
  221. return "Syncable";
  222. case kFileSystemTypeLocalForPlatformApp:
  223. return "LocalForPlatformApp";
  224. case kFileSystemTypeForTransientFile:
  225. return "TransientFile";
  226. case kFileSystemTypeProvided:
  227. return "Provided";
  228. case kFileSystemTypeDeviceMediaAsFileStorage:
  229. return "DeviceMediaStorage";
  230. case kFileSystemTypeArcContent:
  231. return "ArcContent";
  232. case kFileSystemTypeArcDocumentsProvider:
  233. return "ArcDocumentsProvider";
  234. case kFileSystemTypeDriveFs:
  235. return "DriveFs";
  236. case kFileSystemTypeSmbFs:
  237. return "SmbFs";
  238. case kFileSystemTypeFuseBox:
  239. return "FuseBox";
  240. case kFileSystemInternalTypeEnumStart:
  241. case kFileSystemInternalTypeEnumEnd:
  242. NOTREACHED();
  243. [[fallthrough]];
  244. case kFileSystemTypeUnknown:
  245. return "Unknown";
  246. }
  247. NOTREACHED();
  248. return std::string();
  249. }
  250. std::string FilePathToString(const base::FilePath& file_path) {
  251. // TODO(pkasting): Probably this should use AsUTF8Unsafe() across platforms.
  252. #if BUILDFLAG(IS_WIN)
  253. return file_path.AsUTF8Unsafe();
  254. #elif BUILDFLAG(IS_POSIX) || BUILDFLAG(IS_FUCHSIA)
  255. return file_path.value();
  256. #endif
  257. }
  258. base::FilePath StringToFilePath(const std::string& file_path_string) {
  259. // TODO(pkasting): Probably this should use FromUTF8Unsafe() across platforms.
  260. #if BUILDFLAG(IS_WIN)
  261. return base::FilePath::FromUTF8Unsafe(file_path_string);
  262. #elif BUILDFLAG(IS_POSIX) || BUILDFLAG(IS_FUCHSIA)
  263. return base::FilePath(file_path_string);
  264. #endif
  265. }
  266. bool GetFileSystemPublicType(const std::string type_string,
  267. blink::WebFileSystemType* type) {
  268. DCHECK(type);
  269. if (type_string == "Temporary") {
  270. *type = blink::kWebFileSystemTypeTemporary;
  271. return true;
  272. }
  273. if (type_string == "Persistent") {
  274. *type = blink::kWebFileSystemTypePersistent;
  275. return true;
  276. }
  277. if (type_string == "Isolated") {
  278. *type = blink::kWebFileSystemTypeIsolated;
  279. return true;
  280. }
  281. if (type_string == "External") {
  282. *type = blink::kWebFileSystemTypeExternal;
  283. return true;
  284. }
  285. NOTREACHED();
  286. return false;
  287. }
  288. std::string GetIsolatedFileSystemName(const GURL& origin_url,
  289. const std::string& filesystem_id) {
  290. std::string name(
  291. storage::GetFileSystemName(origin_url, storage::kFileSystemTypeIsolated));
  292. name.append("_");
  293. name.append(filesystem_id);
  294. return name;
  295. }
  296. bool CrackIsolatedFileSystemName(const std::string& filesystem_name,
  297. std::string* filesystem_id) {
  298. DCHECK(filesystem_id);
  299. // |filesystem_name| is of the form {origin}:isolated_{filesystem_id}.
  300. std::string start_token(":");
  301. start_token =
  302. start_token.append(GetFileSystemTypeString(kFileSystemTypeIsolated))
  303. .append("_");
  304. // WebKit uses different case in its constant for isolated file system
  305. // names, so we do a case insensitive compare by converting both strings
  306. // to uppercase.
  307. // TODO(benwells): Remove this when WebKit uses the same constant.
  308. start_token = base::ToUpperASCII(start_token);
  309. std::string filesystem_name_upper = base::ToUpperASCII(filesystem_name);
  310. size_t pos = filesystem_name_upper.find(start_token);
  311. if (pos == std::string::npos)
  312. return false;
  313. if (pos == 0)
  314. return false;
  315. *filesystem_id =
  316. filesystem_name.substr(pos + start_token.length(), std::string::npos);
  317. if (filesystem_id->empty())
  318. return false;
  319. return true;
  320. }
  321. bool ValidateIsolatedFileSystemId(const std::string& filesystem_id) {
  322. const size_t kExpectedFileSystemIdSize = 32;
  323. if (filesystem_id.size() != kExpectedFileSystemIdSize)
  324. return false;
  325. const std::string kExpectedChars("ABCDEF0123456789");
  326. return base::ContainsOnlyChars(filesystem_id, kExpectedChars);
  327. }
  328. std::string GetIsolatedFileSystemRootURIString(
  329. const GURL& origin_url,
  330. const std::string& filesystem_id,
  331. const std::string& optional_root_name) {
  332. std::string root =
  333. GetFileSystemRootURI(origin_url, kFileSystemTypeIsolated).spec();
  334. if (base::FilePath::FromUTF8Unsafe(filesystem_id).ReferencesParent())
  335. return std::string();
  336. root.append(base::EscapePath(filesystem_id));
  337. root.append("/");
  338. if (!optional_root_name.empty()) {
  339. if (base::FilePath::FromUTF8Unsafe(optional_root_name).ReferencesParent())
  340. return std::string();
  341. root.append(base::EscapePath(optional_root_name));
  342. root.append("/");
  343. }
  344. return root;
  345. }
  346. std::string GetExternalFileSystemRootURIString(const GURL& origin_url,
  347. const std::string& mount_name) {
  348. std::string root =
  349. GetFileSystemRootURI(origin_url, kFileSystemTypeExternal).spec();
  350. if (base::FilePath::FromUTF8Unsafe(mount_name).ReferencesParent())
  351. return std::string();
  352. root.append(base::EscapePath(mount_name));
  353. root.append("/");
  354. return root;
  355. }
  356. base::File::Error NetErrorToFileError(int error) {
  357. switch (error) {
  358. case net::OK:
  359. return base::File::FILE_OK;
  360. case net::ERR_ADDRESS_IN_USE:
  361. return base::File::FILE_ERROR_IN_USE;
  362. case net::ERR_FILE_EXISTS:
  363. return base::File::FILE_ERROR_EXISTS;
  364. case net::ERR_FILE_NOT_FOUND:
  365. return base::File::FILE_ERROR_NOT_FOUND;
  366. case net::ERR_ACCESS_DENIED:
  367. return base::File::FILE_ERROR_ACCESS_DENIED;
  368. case net::ERR_OUT_OF_MEMORY:
  369. return base::File::FILE_ERROR_NO_MEMORY;
  370. case net::ERR_FILE_NO_SPACE:
  371. return base::File::FILE_ERROR_NO_SPACE;
  372. case net::ERR_INVALID_ARGUMENT:
  373. case net::ERR_INVALID_HANDLE:
  374. return base::File::FILE_ERROR_INVALID_OPERATION;
  375. case net::ERR_ABORTED:
  376. case net::ERR_CONNECTION_ABORTED:
  377. return base::File::FILE_ERROR_ABORT;
  378. case net::ERR_ADDRESS_INVALID:
  379. case net::ERR_INVALID_URL:
  380. return base::File::FILE_ERROR_INVALID_URL;
  381. default:
  382. return base::File::FILE_ERROR_FAILED;
  383. }
  384. }
  385. } // namespace storage