15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved.
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file.
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#ifndef CHROME_BROWSER_DOWNLOAD_DOWNLOAD_PATH_RESERVATION_TRACKER_H_
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#define CHROME_BROWSER_DOWNLOAD_DOWNLOAD_PATH_RESERVATION_TRACKER_H_
75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/callback_forward.h"
95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)namespace base {
112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)class FilePath;
122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace content {
155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class DownloadItem;
165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
18c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// Chrome attempts to uniquify filenames that are assigned to downloads in order
19c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// to avoid overwriting files that already exist on the file system. Downloads
20c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// that are considered potentially dangerous use random intermediate filenames.
21c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// Therefore only considering files that exist on the filesystem is
22c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// insufficient. This class tracks files that are assigned to active downloads
23c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// so that uniquification can take those into account as well.
245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class DownloadPathReservationTracker {
255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) public:
265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Callback used with |GetReservedPath|. |target_path| specifies the target
275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // path for the download. |target_path_verified| is true if all of the
285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // following is true:
295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // - |requested_target_path| (passed into GetReservedPath()) was writeable.
305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // - |target_path| was verified as being unique if uniqueness was
315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  //   required.
325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  //
335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // If |requested_target_path| was not writeable, then the parent directory of
345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // |target_path| may be different from that of |requested_target_path|.
352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  typedef base::Callback<void(const base::FilePath& target_path,
365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                              bool target_path_verified)> ReservedPathCallback;
375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // The largest index for the uniquification suffix that we will try while
395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // attempting to come up with a unique path.
405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  static const int kMaxUniqueFiles = 100;
415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
42c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  enum FilenameConflictAction {
43c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    UNIQUIFY,
44c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    OVERWRITE,
45c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    PROMPT,
46c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  };
47c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
48c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // When a path needs to be assigned to a download, this method is called on
49c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // the UI thread along with a reference to the download item that will
50c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // eventually receive the reserved path. This method creates a path
51c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // reservation that will live until |download_item| is interrupted, cancelled,
52c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // completes or is removed. This method will not modify |download_item|.
53c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  //
54c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // The process of issuing a reservation happens on the FILE thread, and
55c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // involves:
56c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  //
57c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // - Creating |requested_target_path.DirName()| if it doesn't already exist
58c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  //   and either |create_directory| or |requested_target_path.DirName() ==
59c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  //   default_download_path|.
60c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  //
61c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // - Verifying that |requested_target_path| is writeable. If not, the user's
62c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  //   documents folder is used instead.
63c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  //
64c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // - Uniquifying |requested_target_path| by suffixing the filename with a
65c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  //   uniquifier (e.g. "foo.txt" -> "foo (1).txt") in order to avoid conflicts
66c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  //   with files that already exist on the file system or other download path
67c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  //   reservations. Uniquifying is only done if |conflict_action| is UNIQUIFY.
68c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  //
69c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // - Posting a task back to the UI thread to invoke |completion_callback| with
70c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  //   the reserved path and a bool indicating whether the returned path was
71c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  //   verified as being writeable and unique.
72c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  //
73c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // In addition, if the target path of |download_item| is changed to a path
74c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // other than the reserved path, then the reservation will be updated to
75c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // match. Such changes can happen if a "Save As" dialog was displayed and the
76c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // user chose a different path. The new target path is not checked against
77c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // active paths to enforce uniqueness. It is only used for uniquifying new
78c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // reservations.
79c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  //
80c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // Once |completion_callback| is invoked, it is the caller's responsibility to
81c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // handle cases where the target path could not be verified and set the target
82c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // path of the |download_item| appropriately.
835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  //
84c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // The current implementation doesn't look at symlinks/mount points. E.g.: It
85c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // considers 'foo/bar/x.pdf' and 'foo/baz/x.pdf' to be two different paths,
86c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // even though 'bar' might be a symlink to 'baz'.
87c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  static void GetReservedPath(
88868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      content::DownloadItem* download_item,
89c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      const base::FilePath& requested_target_path,
90c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      const base::FilePath& default_download_path,
91c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      bool create_directory,
92c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      FilenameConflictAction conflict_action,
93c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      const ReservedPathCallback& callback);
945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Returns true if |path| is in use by an existing path reservation. Should
965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // only be called on the FILE thread. Currently only used by tests.
972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  static bool IsPathInUseForTesting(const base::FilePath& path);
985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif  // CHROME_BROWSER_DOWNLOAD_DOWNLOAD_PATH_RESERVATION_TRACKER_H_
101