summaryrefslogtreecommitdiffstats
path: root/chrome/browser/chromeos/gdata/gdata_files.h
blob: b238bec41dc11e8b2370be3ebf1b140b702dbd8a (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
// Copyright (c) 2012 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 CHROME_BROWSER_CHROMEOS_GDATA_GDATA_FILES_H_
#define CHROME_BROWSER_CHROMEOS_GDATA_GDATA_FILES_H_

#include <map>
#include <string>

#include "base/callback.h"
#include "base/gtest_prod_util.h"
#include "base/memory/scoped_ptr.h"
#include "base/memory/singleton.h"
#include "base/memory/weak_ptr.h"
#include "base/platform_file.h"
#include "base/synchronization/lock.h"
#include "chrome/browser/chromeos/gdata/gdata_params.h"
#include "chrome/browser/chromeos/gdata/gdata_uploader.h"
#include "chrome/browser/chromeos/gdata/gdata_wapi_parser.h"
#include "chrome/browser/profiles/profile_keyed_service.h"
#include "chrome/browser/profiles/profile_keyed_service_factory.h"

namespace gdata {

class GDataFile;
class GDataDirectory;
class GDataDirectoryService;

class GDataEntryProto;
class GDataDirectoryProto;
class GDataRootDirectoryProto;
class PlatformFileInfoProto;

// The root directory content origin.
enum ContentOrigin {
  UNINITIALIZED,
  // Content is currently loading from somewhere.  Needs to wait.
  INITIALIZING,
  // Content is initialized, but during refreshing.
  REFRESHING,
  // Content is initialized from disk cache.
  FROM_CACHE,
  // Content is initialized from the direct server response.
  FROM_SERVER,
};

// File type on the gdata file system can be either a regular file or
// a hosted document.
enum GDataFileType {
  REGULAR_FILE,
  HOSTED_DOCUMENT,
};

// The root directory name used for the Google Drive file system tree. The
// name is used in URLs for the file manager, hence user-visible.
const FilePath::CharType kGDataRootDirectory[] = FILE_PATH_LITERAL("drive");

// The resource ID for the root directory is defined in the spec:
// https://developers.google.com/google-apps/documents-list/
const char kGDataRootDirectoryResourceId[] = "folder:root";

// This should be incremented when incompatibility change is made in
// gdata.proto.
const int32 kProtoVersion = 1;

// Used for file operations like removing files.
typedef base::Callback<void(GDataFileError error)>
    FileOperationCallback;

// Base class for representing files and directories in gdata virtual file
// system.
class GDataEntry {
 public:
  GDataEntry(GDataDirectory* parent, GDataDirectoryService* directory_service);
  virtual ~GDataEntry();

  virtual GDataFile* AsGDataFile();
  virtual GDataDirectory* AsGDataDirectory();

  // const versions of AsGDataFile and AsGDataDirectory.
  const GDataFile* AsGDataFileConst() const;
  const GDataDirectory* AsGDataDirectoryConst() const;

  // Converts DocumentEntry into GDataEntry.
  static GDataEntry* FromDocumentEntry(
      GDataDirectory* parent,
      DocumentEntry* doc,
      GDataDirectoryService* directory_service);

  // Serialize/Parse to/from string via proto classes.
  // TODO(achuith): Correctly set up parent_ and root_ links in
  // FromProtoString.
  void SerializeToString(std::string* serialized_proto) const;
  static scoped_ptr<GDataEntry> FromProtoString(
      const std::string& serialized_proto);

  // Converts the proto representation to the platform file.
  static void ConvertProtoToPlatformFileInfo(
      const PlatformFileInfoProto& proto,
      base::PlatformFileInfo* file_info);

  // Converts the platform file info to the proto representation.
  static void ConvertPlatformFileInfoToProto(
      const base::PlatformFileInfo& file_info,
      PlatformFileInfoProto* proto);

  // Converts to/from proto. Only handles the common part (i.e. does not
  // touch |file_specific_info| and |directory_specific_info|.
  bool FromProto(const GDataEntryProto& proto) WARN_UNUSED_RESULT;
  void ToProto(GDataEntryProto* proto) const;

  // Similar to ToProto() but this fills in |file_specific_info| and
  // |directory_specific_info| based on the actual type of the entry.
  // Used to obtain full metadata of a file or a directory as
  // GDataEntryProto.
  void ToProtoFull(GDataEntryProto* proto) const;

  // Escapes forward slashes from file names with magic unicode character
  // \u2215 pretty much looks the same in UI.
  static std::string EscapeUtf8FileName(const std::string& input);

  // Unescapes what was escaped in EScapeUtf8FileName.
  static std::string UnescapeUtf8FileName(const std::string& input);

  // Return the parent of this entry. NULL for root.
  GDataDirectory* parent() const { return parent_; }
  const base::PlatformFileInfo& file_info() const { return file_info_; }

  // This is not the full path, use GetFilePath for that.
  // Note that base_name_ gets reset by SetBaseNameFromTitle() in a number of
  // situations due to de-duplication (see AddEntry).
  const FilePath::StringType& base_name() const { return base_name_; }
  // TODO(achuith): Make this private when GDataDB no longer uses path as a key.
  void set_base_name(const FilePath::StringType& name) { base_name_ = name; }

  const FilePath::StringType& title() const { return title_; }
  void set_title(const FilePath::StringType& title) { title_ = title; }

  // The unique resource ID associated with this file system entry.
  const std::string& resource_id() const { return resource_id_; }
  void set_resource_id(const std::string& res_id) { resource_id_ = res_id; }

  // The content URL is used for downloading regular files as is.
  const GURL& content_url() const { return content_url_; }
  void set_content_url(const GURL& url) { content_url_ = url; }

  // Upload URL is used for uploading files. See gdata.proto for details.
  const GURL& upload_url() const { return upload_url_; }
  void set_upload_url(const GURL& url) { upload_url_ = url; }

  // The edit URL is used for removing files and hosted documents.
  const GURL& edit_url() const { return edit_url_; }

  // The resource id of the parent folder. This piece of information is needed
  // to pair files from change feeds with their directory parents withing the
  // existing file system snapshot (GDataDirectoryService::resource_map_).
  const std::string& parent_resource_id() const { return parent_resource_id_; }

  // True if file was deleted. Used only for instances that are generated from
  // delta feeds.
  bool is_deleted() const { return deleted_; }

  // Returns virtual file path representing this file system entry. This path
  // corresponds to file path expected by public methods of GDataFileSyste
  // class.
  FilePath GetFilePath() const;

  // Sets |base_name_| based on the value of |title_| without name
  // de-duplication (see AddEntry() for details on de-duplication).
  virtual void SetBaseNameFromTitle();

 protected:
  // For access to SetParent from AddEntry.
  friend class GDataDirectory;

  // Sets the parent directory of this file system entry.
  // It is intended to be used by GDataDirectory::AddEntry() only.
  void SetParent(GDataDirectory* parent);

  base::PlatformFileInfo file_info_;
  // Title of this file (i.e. the 'title' attribute associated with a regular
  // file, hosted document, or collection). The title is used to derive
  // |base_name_| but may be different from |base_name_|. For example,
  // |base_name_| has an added .g<something> extension for hosted documents or
  // may have an extra suffix for name de-duplication on the gdata file system.
  FilePath::StringType title_;
  std::string resource_id_;
  std::string parent_resource_id_;
  // Files with the same title will be uniquely identified with this field
  // so we can represent them with unique URLs/paths in File API layer.
  // For example, two files in the same directory with the same name "Foo"
  // will show up in the virtual directory as "Foo" and "Foo (2)".
  GURL edit_url_;
  GURL content_url_;
  GURL upload_url_;

  // Remaining fields are not serialized.

  // Name of this file in the gdata virtual file system. This can change
  // due to de-duplication (See AddEntry).
  FilePath::StringType base_name_;

  GDataDirectory* parent_;
  // Weak pointer to GDataDirectoryService.
  GDataDirectoryService* directory_service_;
  bool deleted_;

 private:
  DISALLOW_COPY_AND_ASSIGN(GDataEntry);
};

typedef std::map<FilePath::StringType, GDataFile*> GDataFileCollection;
typedef std::map<FilePath::StringType, GDataDirectory*>
    GDataDirectoryCollection;

// Represents "file" in in a GData virtual file system. On gdata feed side,
// this could be either a regular file or a server side document.
class GDataFile : public GDataEntry {
 public:
  explicit GDataFile(GDataDirectory* parent,
                     GDataDirectoryService* directory_service);
  virtual ~GDataFile();
  virtual GDataFile* AsGDataFile() OVERRIDE;

  // Converts DocumentEntry into GDataEntry.
  static GDataEntry* FromDocumentEntry(
      GDataDirectory* parent,
      DocumentEntry* doc,
      GDataDirectoryService* directory_service);

  // Converts to/from proto.
  bool FromProto(const GDataEntryProto& proto) WARN_UNUSED_RESULT;
  void ToProto(GDataEntryProto* proto) const;

  DocumentEntry::EntryKind kind() const { return kind_; }
  const GURL& thumbnail_url() const { return thumbnail_url_; }
  const GURL& alternate_url() const { return alternate_url_; }
  const std::string& content_mime_type() const { return content_mime_type_; }
  const std::string& file_md5() const { return file_md5_; }
  void set_file_md5(const std::string& file_md5) { file_md5_ = file_md5; }
  const std::string& document_extension() const { return document_extension_; }
  bool is_hosted_document() const { return is_hosted_document_; }
  void set_file_info(const base::PlatformFileInfo& info) { file_info_ = info; }

  // Overrides GDataEntry::SetBaseNameFromTitle() to set |base_name_| based
  // on the value of |title_| as well as |is_hosted_document_| and
  // |document_extension_| for hosted documents.
  virtual void SetBaseNameFromTitle() OVERRIDE;

 private:
  DocumentEntry::EntryKind kind_;  // Not saved in proto.
  GURL thumbnail_url_;
  GURL alternate_url_;
  std::string content_mime_type_;
  std::string file_md5_;
  std::string document_extension_;
  bool is_hosted_document_;

  DISALLOW_COPY_AND_ASSIGN(GDataFile);
};

// Represents "directory" in a GData virtual file system. Maps to gdata
// collection element.
class GDataDirectory : public GDataEntry {
 public:
  GDataDirectory(GDataDirectory* parent,
                 GDataDirectoryService* directory_service);
  virtual ~GDataDirectory();
  virtual GDataDirectory* AsGDataDirectory() OVERRIDE;

  // Converts DocumentEntry into GDataEntry.
  static GDataEntry* FromDocumentEntry(
      GDataDirectory* parent,
      DocumentEntry* doc,
      GDataDirectoryService* directory_service);

  // Converts to/from proto.
  bool FromProto(const GDataDirectoryProto& proto) WARN_UNUSED_RESULT;
  void ToProto(GDataDirectoryProto* proto) const;

  // Removes child elements.
  void RemoveChildren();
  void RemoveChildFiles();
  void RemoveChildDirectories();

  // Collection of children files/directories.
  const GDataFileCollection& child_files() const { return child_files_; }
  const GDataDirectoryCollection& child_directories() const {
    return child_directories_;
  }

 private:
  // TODO(satorux): Remove the friend statements. crbug.com/139649
  friend class GDataDirectoryService;
  friend class GDataFileSystem;

  // Adds child file to the directory and takes over the ownership of |file|
  // object. The method will also do name de-duplication to ensure that the
  // exposed presentation path does not have naming conflicts. Two files with
  // the same name "Foo" will be renames to "Foo (1)" and "Foo (2)".
  // TODO(satorux): Remove this. crbug.com/139649
  void AddEntry(GDataEntry* entry);

  // Removes the entry from its children list and destroys the entry instance.
  // TODO(satorux): Remove this. crbug.com/139649
  bool RemoveEntry(GDataEntry* entry);

  // Takes the ownership of |entry| from its current parent. If this directory
  // is already the current parent of |file|, this method effectively goes
  // through the name de-duplication for |file| based on the current state of
  // the file system.
  // TODO(satorux): Remove this. crbug.com/139649
  bool TakeEntry(GDataEntry* entry);

  // Takes over all entries from |dir|.
  // TODO(satorux): Remove this. crbug.com/139649
  bool TakeOverEntries(GDataDirectory* dir);

  // Find a child by its name.
  // TODO(satorux): Remove this. crbug.com/139649
  GDataEntry* FindChild(const FilePath::StringType& file_name) const;

  // Add |entry| to children.
  void AddChild(GDataEntry* entry);

  // Removes the entry from its children without destroying the
  // entry instance.
  bool RemoveChild(GDataEntry* entry);

  // Collection of children GDataEntry items.
  GDataFileCollection child_files_;
  GDataDirectoryCollection child_directories_;

  DISALLOW_COPY_AND_ASSIGN(GDataDirectory);
};

// Class to handle GDataEntry* lookups, add/remove GDataEntry*.
class GDataDirectoryService {
 public:
  // Callback for GetEntryByResourceIdAsync.
  typedef base::Callback<void(GDataEntry* entry)> GetEntryByResourceIdCallback;

  GDataDirectoryService();
  ~GDataDirectoryService();

  GDataDirectory* root() { return root_.get(); }

  // Last time when we dumped serialized file system to disk.
  const base::Time& last_serialized() const { return last_serialized_; }
  void set_last_serialized(const base::Time& time) { last_serialized_ = time; }
  // Size of serialized file system on disk in bytes.
  const size_t serialized_size() const { return serialized_size_; }
  void set_serialized_size(size_t size) { serialized_size_ = size; }

  // Largest change timestamp that was the source of content for the current
  // state of the root directory.
  const int largest_changestamp() const { return largest_changestamp_; }
  void set_largest_changestamp(int value) { largest_changestamp_ = value; }

  // The root directory content origin.
  const ContentOrigin origin() const { return origin_; }
  void set_origin(ContentOrigin value) { origin_ = value; }

  // Adds |entry| to |directory_path| asynchronously.
  // Must be called on UI thread. |callback| is called on the UI thread.
  void AddEntryToDirectory(const FilePath& directory_path,
                           GDataEntry* entry,
                           const FileOperationCallback& callback);

  // Adds the entry to resource map.
  void AddEntryToResourceMap(GDataEntry* entry);

  // Removes the entry from resource map.
  void RemoveEntryFromResourceMap(GDataEntry* entry);

  // Searches for |file_path| synchronously.
  // TODO(satorux): Replace this with an async version crbug.com/137160
  GDataEntry* FindEntryByPathSync(const FilePath& file_path);

  // Returns the GDataEntry* with the corresponding |resource_id|.
  // TODO(achuith): Get rid of this in favor of async version crbug.com/13957.
  GDataEntry* GetEntryByResourceId(const std::string& resource_id);

  // Returns the GDataEntry* in the callback with the corresponding
  // |resource_id|. TODO(achuith): Rename this to GetEntryByResourceId.
  void GetEntryByResourceIdAsync(const std::string& resource_id,
                                 const GetEntryByResourceIdCallback& callback);

  // Replaces file entry with the same resource id as |fresh_file| with its
  // fresh value |fresh_file|.
  void RefreshFile(scoped_ptr<GDataFile> fresh_file);

  // Replaces file entry |old_entry| with its fresh value |fresh_file|.
  static void RefreshFileInternal(scoped_ptr<GDataFile> fresh_file,
                                  GDataEntry* old_entry);

  // Serializes/Parses to/from string via proto classes.
  void SerializeToString(std::string* serialized_proto) const;
  bool ParseFromString(const std::string& serialized_proto);

 private:
  // A map table of file's resource string to its GDataFile* entry.
  typedef std::map<std::string, GDataEntry*> ResourceMap;

  scoped_ptr<GDataDirectory> root_;  // Stored in the serialized proto.
  ResourceMap resource_map_;

  base::Time last_serialized_;
  size_t serialized_size_;
  int largest_changestamp_;  // Stored in the serialized proto.
  ContentOrigin origin_;

  DISALLOW_COPY_AND_ASSIGN(GDataDirectoryService);
};

}  // namespace gdata

#endif  // CHROME_BROWSER_CHROMEOS_GDATA_GDATA_FILES_H_