| Index: chrome/browser/chromeos/gdata/gdata_file_system.cc
|
| diff --git a/chrome/browser/chromeos/gdata/gdata_file_system.cc b/chrome/browser/chromeos/gdata/gdata_file_system.cc
|
| index fc0abd1b7718e50667aedc3bd63d22bc8b92211a..11c0434c66bbb97c3b69e60e68b9f09237d899cf 100644
|
| --- a/chrome/browser/chromeos/gdata/gdata_file_system.cc
|
| +++ b/chrome/browser/chromeos/gdata/gdata_file_system.cc
|
| @@ -57,6 +57,7 @@ const char kMimeTypeOctetStream[] = "application/octet-stream";
|
| const FilePath::CharType kGDataRootDirectory[] = FILE_PATH_LITERAL("gdata");
|
| const char kWildCard[] = "*";
|
| const char kLocallyModifiedFileExtension[] = "local";
|
| +const char kMountedArchiveFileExtension[] = "mounted";
|
|
|
| const FilePath::CharType kGDataCacheVersionDir[] = FILE_PATH_LITERAL("v1");
|
| const FilePath::CharType kGDataCacheMetaDir[] = FILE_PATH_LITERAL("meta");
|
| @@ -508,6 +509,18 @@ void RunGetFileFromCacheCallbackHelper(
|
| callback.Run(*error, resource_id, md5, gdata_file_path, *cache_file_path);
|
| }
|
|
|
| +// Ditto for SetMountedStateCallback
|
| +void RunSetMountedStateCallbackHelper(
|
| + const SetMountedStateCallback& callback,
|
| + base::PlatformFileError* error,
|
| + FilePath* cache_file_path) {
|
| + DCHECK(error);
|
| + DCHECK(cache_file_path);
|
| +
|
| + if (!callback.is_null())
|
| + callback.Run(*error, *cache_file_path);
|
| +}
|
| +
|
| void RunGetCacheStateCallbackHelper(
|
| const GetCacheStateCallback& callback,
|
| base::PlatformFileError* error,
|
| @@ -2011,6 +2024,10 @@ bool GDataFileSystem::GetFileInfoByPath(
|
| return true;
|
| }
|
|
|
| +bool GDataFileSystem::IsUnderGDataCacheDirectory(const FilePath& path) const {
|
| + return gdata_cache_path_ == path || gdata_cache_path_.IsParent(path);
|
| +}
|
| +
|
| FilePath GDataFileSystem::GetGDataCacheTmpDirectory() const {
|
| return cache_paths_[GDataRootDirectory::CACHE_TYPE_TMP];
|
| }
|
| @@ -2125,6 +2142,98 @@ void GDataFileSystem::SetPinState(const FilePath& file_path, bool to_pin,
|
| Unpin(resource_id, md5, cache_callback);
|
| }
|
|
|
| +void GDataFileSystem::SetMountedState(const FilePath& file_path, bool to_mount,
|
| + const SetMountedStateCallback& callback) {
|
| + InitializeCacheIfNecessary();
|
| +
|
| + base::PlatformFileError* error =
|
| + new base::PlatformFileError(base::PLATFORM_FILE_OK);
|
| + FilePath* cache_file_path = new FilePath;
|
| + PostBlockingPoolSequencedTaskAndReply(
|
| + kGDataFileSystemToken,
|
| + FROM_HERE,
|
| + base::Bind(&GDataFileSystem::SetMountedStateOnIOThreadPool,
|
| + base::Unretained(this),
|
| + file_path,
|
| + to_mount,
|
| + error,
|
| + cache_file_path),
|
| + base::Bind(&RunSetMountedStateCallbackHelper,
|
| + callback,
|
| + base::Owned(error),
|
| + base::Owned(cache_file_path)));
|
| +}
|
| +
|
| +void GDataFileSystem::SetMountedStateOnIOThreadPool(
|
| + const FilePath& file_path,
|
| + bool to_mount,
|
| + base::PlatformFileError *error,
|
| + FilePath* cache_file_path) {
|
| + DCHECK(error);
|
| + DCHECK(cache_file_path);
|
| +
|
| + // Lock to access cache map.
|
| + base::AutoLock lock(lock_);
|
| +
|
| + // Parse file path to obtain resource_id, md5 and extra_extension.
|
| + std::string resource_id;
|
| + std::string md5;
|
| + std::string extra_extension;
|
| + util::ParseCacheFilePath(file_path, &resource_id, &md5, &extra_extension);
|
| + // The extra_extension shall be ".mounted" iff we're unmounting.
|
| + DCHECK(!to_mount == (extra_extension == kMountedArchiveFileExtension));
|
| +
|
| + // Get cache entry associated with the resource_id and md5
|
| + GDataRootDirectory::CacheEntry* entry = root_->GetCacheEntry(resource_id,
|
| + md5);
|
| + if (!entry) {
|
| + *error = base::PLATFORM_FILE_ERROR_NOT_FOUND;
|
| + return;
|
| + }
|
| + if (to_mount == entry->IsMounted()) {
|
| + *error = base::PLATFORM_FILE_ERROR_INVALID_OPERATION;
|
| + return;
|
| + }
|
| +
|
| + // Get the subdir type and path for the unmounted state.
|
| + GDataRootDirectory::CacheSubDirectoryType unmounted_subdir =
|
| + entry->IsPinned() ? GDataRootDirectory::CACHE_TYPE_PERSISTENT :
|
| + GDataRootDirectory::CACHE_TYPE_TMP;
|
| + FilePath unmounted_path = GetCacheFilePath(resource_id, md5, unmounted_subdir,
|
| + CACHED_FILE_FROM_SERVER);
|
| +
|
| + // Get the subdir type and path for the mounted state.
|
| + GDataRootDirectory::CacheSubDirectoryType mounted_subdir =
|
| + GDataRootDirectory::CACHE_TYPE_PERSISTENT;
|
| + FilePath mounted_path = GetCacheFilePath(resource_id, md5, mounted_subdir,
|
| + CACHED_FILE_MOUNTED);
|
| +
|
| + // Determine the source and destination paths for moving the cache blob.
|
| + FilePath source_path;
|
| + GDataRootDirectory::CacheSubDirectoryType dest_subdir;
|
| + int cache_state = entry->cache_state;
|
| + if (to_mount) {
|
| + source_path = unmounted_path;
|
| + *cache_file_path = mounted_path;
|
| + dest_subdir = mounted_subdir;
|
| + cache_state = GDataFile::SetCacheMounted(cache_state);
|
| + } else {
|
| + source_path = mounted_path;
|
| + *cache_file_path = unmounted_path;
|
| + dest_subdir = unmounted_subdir;
|
| + cache_state = GDataFile::ClearCacheMounted(cache_state);
|
| + }
|
| +
|
| + // Move cache blob from source path to destination path.
|
| + *error = ModifyCacheState(source_path, *cache_file_path,
|
| + GDataFileSystem::FILE_OPERATION_MOVE,
|
| + FilePath(), false);
|
| + if (*error == base::PLATFORM_FILE_OK) {
|
| + // Now that cache operation is complete, update cache map
|
| + root_->UpdateCacheMap(resource_id, md5, dest_subdir, cache_state);
|
| + }
|
| +}
|
| +
|
| void GDataFileSystem::OnSetPinStateCompleted(
|
| const FileOperationCallback& callback,
|
| base::PlatformFileError error,
|
| @@ -3215,14 +3324,21 @@ FilePath GDataFileSystem::GetCacheFilePath(
|
| // Runs on any thread.
|
| // Filename is formatted as resource_id.md5, i.e. resource_id is the base
|
| // name and md5 is the extension.
|
| - std::string base_name = GDataEntry::EscapeUtf8FileName(resource_id);
|
| + std::string base_name = util::EscapeCacheFileName(resource_id);
|
| if (file_origin == CACHED_FILE_LOCALLY_MODIFIED) {
|
| DCHECK(sub_dir_type == GDataRootDirectory::CACHE_TYPE_PERSISTENT);
|
| base_name += FilePath::kExtensionSeparator;
|
| base_name += kLocallyModifiedFileExtension;
|
| } else if (!md5.empty()) {
|
| base_name += FilePath::kExtensionSeparator;
|
| - base_name += GDataEntry::EscapeUtf8FileName(md5);
|
| + base_name += util::EscapeCacheFileName(md5);
|
| + }
|
| + // For mounted archives the filename is formatted as resource_id.md5.mounted,
|
| + // i.e. resource_id.md5 is the base name and ".mounted" is the extension
|
| + if (file_origin == CACHED_FILE_MOUNTED) {
|
| + DCHECK(sub_dir_type == GDataRootDirectory::CACHE_TYPE_PERSISTENT);
|
| + base_name += FilePath::kExtensionSeparator;
|
| + base_name += kMountedArchiveFileExtension;
|
| }
|
| return cache_paths_[sub_dir_type].Append(base_name);
|
| }
|
| @@ -3465,12 +3581,19 @@ void GDataFileSystem::GetFileFromCacheOnIOThreadPool(
|
| GDataRootDirectory::CacheEntry* entry = root_->GetCacheEntry(resource_id,
|
| md5);
|
| if (entry && entry->IsPresent()) {
|
| + CachedFileOrigin file_origin;
|
| + if (entry->IsMounted()) {
|
| + file_origin = CACHED_FILE_MOUNTED;
|
| + } else if (entry->IsDirty()) {
|
| + file_origin = CACHED_FILE_LOCALLY_MODIFIED;
|
| + } else {
|
| + file_origin = CACHED_FILE_FROM_SERVER;
|
| + }
|
| *cache_file_path = GetCacheFilePath(
|
| resource_id,
|
| md5,
|
| entry->sub_dir_type,
|
| - entry->IsDirty() ? CACHED_FILE_LOCALLY_MODIFIED :
|
| - CACHED_FILE_FROM_SERVER);
|
| + file_origin);
|
| *error = base::PLATFORM_FILE_OK;
|
| } else {
|
| *error = base::PLATFORM_FILE_ERROR_NOT_FOUND;
|
| @@ -3527,10 +3650,11 @@ void GDataFileSystem::StoreToCacheOnIOThreadPool(
|
| // If file was previously pinned, store it in persistent dir and create
|
| // symlink in pinned dir.
|
| if (entry) { // File exists in cache.
|
| - // If file is dirty, return error.
|
| - if (entry->IsDirty()) {
|
| - LOG(WARNING) << "Can't store a file to replace a dirty file: res_id="
|
| - << resource_id
|
| + // If file is dirty or mounted, return error.
|
| + if (entry->IsDirty() || entry->IsMounted()) {
|
| + LOG(WARNING) << "Can't store a file to replace a "
|
| + << (entry->IsDirty() ? "dirty" : "mounted")
|
| + << " file: res_id=" << resource_id
|
| << ", md5=" << md5;
|
| *error = base::PLATFORM_FILE_ERROR_IN_USE;
|
| return;
|
| @@ -3629,10 +3753,10 @@ void GDataFileSystem::PinOnIOThreadPool(const std::string& resource_id,
|
|
|
| // Determine source and destination paths.
|
|
|
| - // If file is dirty, don't move it, so determine |dest_path| and set
|
| - // |source_path| the same, because ModifyCacheState only moves files if
|
| + // If file is dirty or mounted, don't move it, so determine |dest_path| and
|
| + // set |source_path| the same, because ModifyCacheState only moves files if
|
| // source and destination are different.
|
| - if (entry->IsDirty()) {
|
| + if (entry->IsDirty() || entry->IsMounted()) {
|
| DCHECK_EQ(GDataRootDirectory::CACHE_TYPE_PERSISTENT, entry->sub_dir_type);
|
| dest_path = GetCacheFilePath(resource_id,
|
| md5,
|
| @@ -3712,10 +3836,10 @@ void GDataFileSystem::UnpinOnIOThreadPool(const std::string& resource_id,
|
| GDataRootDirectory::CacheSubDirectoryType sub_dir_type =
|
| GDataRootDirectory::CACHE_TYPE_TMP;
|
|
|
| - // If file is dirty, don't move it, so determine |dest_path| and set
|
| - // |source_path| the same, because ModifyCacheState moves files if source
|
| + // If file is dirty or mounted, don't move it, so determine |dest_path| and
|
| + // set |source_path| the same, because ModifyCacheState moves files if source
|
| // and destination are different.
|
| - if (entry->IsDirty()) {
|
| + if (entry->IsDirty() || entry->IsMounted()) {
|
| sub_dir_type = GDataRootDirectory::CACHE_TYPE_PERSISTENT;
|
| DCHECK_EQ(sub_dir_type, entry->sub_dir_type);
|
| dest_path = GetCacheFilePath(resource_id,
|
| @@ -4047,9 +4171,11 @@ void GDataFileSystem::RemoveFromCacheOnIOThreadPool(
|
| GDataRootDirectory::CacheEntry* entry = root_->GetCacheEntry(
|
| resource_id, std::string());
|
|
|
| - // If entry doesn't exist or is dirty in cache, nothing to do.
|
| - if (!entry || entry->IsDirty()) {
|
| - DVLOG(1) << "Entry " << (entry ? "is dirty" : "doesn't exist")
|
| + // If entry doesn't exist or is dirty or mounted in cache, nothing to do.
|
| + if (!entry || entry->IsDirty() || entry->IsMounted()) {
|
| + DVLOG(1) << "Entry is "
|
| + << (entry ? (entry->IsDirty() ? "dirty" : "mounted") :
|
| + "non-existent")
|
| << " in cache, not removing";
|
| *error = base::PLATFORM_FILE_OK;
|
| return;
|
| @@ -4171,23 +4297,10 @@ void GDataFileSystem::ScanCacheDirectory(
|
| for (FilePath current = enumerator.Next(); !current.empty();
|
| current = enumerator.Next()) {
|
| // Extract resource_id and md5 from filename.
|
| - FilePath base_name = current.BaseName();
|
| std::string resource_id;
|
| std::string md5;
|
| -
|
| - // Pinned and outgoing symlinks have no extension.
|
| - if (sub_dir_type == GDataRootDirectory::CACHE_TYPE_PINNED ||
|
| - sub_dir_type == GDataRootDirectory::CACHE_TYPE_OUTGOING) {
|
| - resource_id = GDataEntry::UnescapeUtf8FileName(base_name.value());
|
| - } else {
|
| - FilePath::StringType extension = base_name.Extension();
|
| - if (!extension.empty()) {
|
| - // FilePath::Extension returns ".", so strip it.
|
| - md5 = GDataEntry::UnescapeUtf8FileName(extension.substr(1));
|
| - }
|
| - resource_id = GDataEntry::UnescapeUtf8FileName(
|
| - base_name.RemoveExtension().value());
|
| - }
|
| + std::string extra_extension;
|
| + util::ParseCacheFilePath(current, &resource_id, &md5, &extra_extension);
|
|
|
| // Determine cache state.
|
| int cache_state = GDataFile::CACHE_STATE_NONE;
|
| @@ -4219,6 +4332,12 @@ void GDataFileSystem::ScanCacheDirectory(
|
| NOTREACHED() << "Dirty cache file MUST have actual file blob";
|
| }
|
| continue;
|
| + } else if (extra_extension == kMountedArchiveFileExtension) {
|
| + // Mounted archives in cache should be unmounted upon logout/shutdown.
|
| + // But if we encounter a mounted file at start, delete it and create an
|
| + // entry with not PRESENT state.
|
| + DCHECK(sub_dir_type == GDataRootDirectory::CACHE_TYPE_PERSISTENT);
|
| + file_util::Delete(current, false);
|
| } else {
|
| // Scanning other directories means that cache file is actually present.
|
| cache_state = GDataFile::SetCachePresent(cache_state);
|
|
|