|  | // Copyright (c) 2015 The Chromium Authors. All rights reserved. | 
|  | // Use of this source code is governed by a BSD-style license that can be | 
|  | // found in the LICENSE file. | 
|  |  | 
|  | #ifndef STORAGE_BROWSER_BLOB_BLOB_DATA_ITEM_H_ | 
|  | #define STORAGE_BROWSER_BLOB_BLOB_DATA_ITEM_H_ | 
|  |  | 
|  | #include <stdint.h> | 
|  |  | 
|  | #include <memory> | 
|  | #include <ostream> | 
|  | #include <string> | 
|  |  | 
|  | #include "base/component_export.h" | 
|  | #include "base/containers/span.h" | 
|  | #include "base/files/file_path.h" | 
|  | #include "base/memory/ref_counted.h" | 
|  | #include "url/gurl.h" | 
|  |  | 
|  | namespace disk_cache { | 
|  | class Entry; | 
|  | } | 
|  |  | 
|  | namespace storage { | 
|  | class BlobDataBuilder; | 
|  | class BlobStorageContext; | 
|  | class FileSystemContext; | 
|  |  | 
|  | // Ref counted blob item. This class owns the backing data of the blob item. The | 
|  | // backing data is immutable, and cannot change after creation. The purpose of | 
|  | // this class is to allow the resource to stick around in the snapshot even | 
|  | // after the resource was swapped in the blob (either to disk or to memory) by | 
|  | // the BlobStorageContext. | 
|  | class COMPONENT_EXPORT(STORAGE_BROWSER) BlobDataItem | 
|  | : public base::RefCounted<BlobDataItem> { | 
|  | public: | 
|  | enum class Type { | 
|  | kBytes, | 
|  | kBytesDescription, | 
|  | kFile, | 
|  | kFileFilesystem, | 
|  | kDiskCacheEntry | 
|  | }; | 
|  |  | 
|  | // The DataHandle class is used to persist resources that are needed for | 
|  | // reading this BlobDataItem. This object will stay around while any reads are | 
|  | // pending. If all blobs with this item are deleted or the item is swapped for | 
|  | // a different backend version (mem-to-disk or the reverse), then the item | 
|  | // will be destructed after all pending reads are complete. | 
|  | class COMPONENT_EXPORT(STORAGE_BROWSER) DataHandle | 
|  | : public base::RefCounted<DataHandle> { | 
|  | public: | 
|  | virtual bool IsValid(); | 
|  |  | 
|  | protected: | 
|  | virtual ~DataHandle(); | 
|  |  | 
|  | private: | 
|  | friend class base::RefCounted<DataHandle>; | 
|  | }; | 
|  |  | 
|  | static scoped_refptr<BlobDataItem> CreateBytes(base::span<const char> bytes); | 
|  | static scoped_refptr<BlobDataItem> CreateBytesDescription(size_t length); | 
|  | static scoped_refptr<BlobDataItem> CreateFile(base::FilePath path); | 
|  | static scoped_refptr<BlobDataItem> CreateFile( | 
|  | base::FilePath path, | 
|  | uint64_t offset, | 
|  | uint64_t length, | 
|  | base::Time expected_modification_time = base::Time(), | 
|  | scoped_refptr<DataHandle> data_handle = nullptr); | 
|  | static scoped_refptr<BlobDataItem> CreateFutureFile(uint64_t offset, | 
|  | uint64_t length, | 
|  | uint64_t file_id); | 
|  | static scoped_refptr<BlobDataItem> CreateFileFilesystem( | 
|  | const GURL& url, | 
|  | uint64_t offset, | 
|  | uint64_t length, | 
|  | base::Time expected_modification_time, | 
|  | scoped_refptr<FileSystemContext> file_system_context); | 
|  | static scoped_refptr<BlobDataItem> CreateDiskCacheEntry( | 
|  | uint64_t offset, | 
|  | uint64_t length, | 
|  | scoped_refptr<DataHandle> data_handle, | 
|  | disk_cache::Entry* entry, | 
|  | int disk_cache_stream_index, | 
|  | int disk_cache_side_stream_index); | 
|  |  | 
|  | Type type() const { return type_; } | 
|  | uint64_t offset() const { return offset_; } | 
|  | uint64_t length() const { return length_; } | 
|  |  | 
|  | base::span<const char> bytes() const { | 
|  | DCHECK_EQ(type_, Type::kBytes); | 
|  | return base::make_span(bytes_); | 
|  | } | 
|  |  | 
|  | const base::FilePath& path() const { | 
|  | DCHECK_EQ(type_, Type::kFile); | 
|  | return path_; | 
|  | } | 
|  |  | 
|  | const GURL& filesystem_url() const { | 
|  | DCHECK_EQ(type_, Type::kFileFilesystem); | 
|  | return filesystem_url_; | 
|  | } | 
|  |  | 
|  | FileSystemContext* file_system_context() const { | 
|  | DCHECK_EQ(type_, Type::kFileFilesystem); | 
|  | return file_system_context_.get(); | 
|  | } | 
|  |  | 
|  | const base::Time& expected_modification_time() const { | 
|  | DCHECK(type_ == Type::kFile || type_ == Type::kFileFilesystem) | 
|  | << static_cast<int>(type_); | 
|  | return expected_modification_time_; | 
|  | } | 
|  |  | 
|  | // This can return null if the underlying disk cache entry was invalidated | 
|  | // (because the user cleared site data), so users should make sure to always | 
|  | // check for that. | 
|  | disk_cache::Entry* disk_cache_entry() const { | 
|  | DCHECK_EQ(type_, Type::kDiskCacheEntry); | 
|  | DCHECK(data_handle_); | 
|  | return data_handle_->IsValid() ? disk_cache_entry_ : nullptr; | 
|  | } | 
|  |  | 
|  | int disk_cache_stream_index() const { | 
|  | DCHECK_EQ(type_, Type::kDiskCacheEntry); | 
|  | return disk_cache_stream_index_; | 
|  | } | 
|  |  | 
|  | int disk_cache_side_stream_index() const { | 
|  | DCHECK_EQ(type_, Type::kDiskCacheEntry); | 
|  | return disk_cache_side_stream_index_; | 
|  | } | 
|  |  | 
|  | DataHandle* data_handle() const { | 
|  | DCHECK(type_ == Type::kFile || type_ == Type::kDiskCacheEntry) | 
|  | << static_cast<int>(type_); | 
|  | return data_handle_.get(); | 
|  | } | 
|  |  | 
|  | // Returns true if this item was created by CreateFutureFile. | 
|  | bool IsFutureFileItem() const; | 
|  | // Returns |file_id| given to CreateFutureFile. | 
|  | uint64_t GetFutureFileID() const; | 
|  |  | 
|  | private: | 
|  | friend class BlobBuilderFromStream; | 
|  | friend class BlobDataBuilder; | 
|  | friend class BlobStorageContext; | 
|  | friend class base::RefCounted<BlobDataItem>; | 
|  | friend COMPONENT_EXPORT(STORAGE_BROWSER) void PrintTo(const BlobDataItem& x, | 
|  | ::std::ostream* os); | 
|  |  | 
|  | BlobDataItem(Type type, uint64_t offset, uint64_t length); | 
|  | virtual ~BlobDataItem(); | 
|  |  | 
|  | base::span<char> mutable_bytes() { | 
|  | DCHECK_EQ(type_, Type::kBytes); | 
|  | return base::make_span(bytes_); | 
|  | } | 
|  |  | 
|  | void AllocateBytes(); | 
|  | void PopulateBytes(base::span<const char> data); | 
|  | void ShrinkBytes(size_t new_length); | 
|  |  | 
|  | void PopulateFile(base::FilePath path, | 
|  | base::Time expected_modification_time, | 
|  | scoped_refptr<DataHandle> data_handle); | 
|  | void ShrinkFile(uint64_t new_length); | 
|  | void GrowFile(uint64_t new_length); | 
|  | void SetFileModificationTime(base::Time time) { | 
|  | DCHECK_EQ(type_, Type::kFile); | 
|  | expected_modification_time_ = time; | 
|  | } | 
|  |  | 
|  | Type type_; | 
|  | uint64_t offset_; | 
|  | uint64_t length_; | 
|  |  | 
|  | std::vector<char> bytes_;  // For Type::kBytes. | 
|  | base::FilePath path_;      // For Type::kFile. | 
|  | GURL filesystem_url_;      // For Type::kFileFilesystem. | 
|  | base::Time | 
|  | expected_modification_time_;  // For Type::kFile and kFileFilesystem. | 
|  |  | 
|  | scoped_refptr<DataHandle> | 
|  | data_handle_;  // For Type::kFile and kDiskCacheEntry. | 
|  |  | 
|  | // This naked pointer is safe because the scope is protected by the DataHandle | 
|  | // instance for disk cache entries during the lifetime of this BlobDataItem. | 
|  | // Only valid if the DataHandle's IsValid method returns true. | 
|  | // TODO(mek): Make this part of the DataHandle and abstract away cache | 
|  | // specific logic to be part of an API exposed by DataHandle. | 
|  | disk_cache::Entry* disk_cache_entry_;  // For Type::kDiskCacheEntry. | 
|  | int disk_cache_stream_index_;          // For Type::kDiskCacheEntry. | 
|  | int disk_cache_side_stream_index_;     // For Type::kDiskCacheEntry. | 
|  |  | 
|  | scoped_refptr<FileSystemContext> | 
|  | file_system_context_;  // For Type::kFileFilesystem. | 
|  | }; | 
|  |  | 
|  | COMPONENT_EXPORT(STORAGE_BROWSER) | 
|  | bool operator==(const BlobDataItem& a, const BlobDataItem& b); | 
|  | COMPONENT_EXPORT(STORAGE_BROWSER) | 
|  | bool operator!=(const BlobDataItem& a, const BlobDataItem& b); | 
|  |  | 
|  | }  // namespace storage | 
|  |  | 
|  | #endif  // STORAGE_BROWSER_BLOB_BLOB_DATA_ITEM_H_ |