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 5 #ifndef CHROME_BROWSER_DOWNLOAD_DOWNLOAD_PATH_RESERVATION_TRACKER_H_ 6 #define CHROME_BROWSER_DOWNLOAD_DOWNLOAD_PATH_RESERVATION_TRACKER_H_ 7 8 #include "base/callback_forward.h" 9 10 namespace base { 11 class FilePath; 12 } 13 14 namespace content { 15 class DownloadItem; 16 } 17 18 // Chrome attempts to uniquify filenames that are assigned to downloads in order 19 // to avoid overwriting files that already exist on the file system. Downloads 20 // that are considered potentially dangerous use random intermediate filenames. 21 // Therefore only considering files that exist on the filesystem is 22 // insufficient. This class tracks files that are assigned to active downloads 23 // so that uniquification can take those into account as well. 24 class DownloadPathReservationTracker { 25 public: 26 // Callback used with |GetReservedPath|. |target_path| specifies the target 27 // path for the download. |target_path_verified| is true if all of the 28 // following is true: 29 // - |requested_target_path| (passed into GetReservedPath()) was writeable. 30 // - |target_path| was verified as being unique if uniqueness was 31 // required. 32 // 33 // If |requested_target_path| was not writeable, then the parent directory of 34 // |target_path| may be different from that of |requested_target_path|. 35 typedef base::Callback<void(const base::FilePath& target_path, 36 bool target_path_verified)> ReservedPathCallback; 37 38 // The largest index for the uniquification suffix that we will try while 39 // attempting to come up with a unique path. 40 static const int kMaxUniqueFiles = 100; 41 42 enum FilenameConflictAction { 43 UNIQUIFY, 44 OVERWRITE, 45 PROMPT, 46 }; 47 48 // When a path needs to be assigned to a download, this method is called on 49 // the UI thread along with a reference to the download item that will 50 // eventually receive the reserved path. This method creates a path 51 // reservation that will live until |download_item| is interrupted, cancelled, 52 // completes or is removed. This method will not modify |download_item|. 53 // 54 // The process of issuing a reservation happens on the FILE thread, and 55 // involves: 56 // 57 // - Creating |requested_target_path.DirName()| if it doesn't already exist 58 // and either |create_directory| or |requested_target_path.DirName() == 59 // default_download_path|. 60 // 61 // - Verifying that |requested_target_path| is writeable. If not, the user's 62 // documents folder is used instead. 63 // 64 // - Uniquifying |requested_target_path| by suffixing the filename with a 65 // uniquifier (e.g. "foo.txt" -> "foo (1).txt") in order to avoid conflicts 66 // with files that already exist on the file system or other download path 67 // reservations. Uniquifying is only done if |conflict_action| is UNIQUIFY. 68 // 69 // - Posting a task back to the UI thread to invoke |completion_callback| with 70 // the reserved path and a bool indicating whether the returned path was 71 // verified as being writeable and unique. 72 // 73 // In addition, if the target path of |download_item| is changed to a path 74 // other than the reserved path, then the reservation will be updated to 75 // match. Such changes can happen if a "Save As" dialog was displayed and the 76 // user chose a different path. The new target path is not checked against 77 // active paths to enforce uniqueness. It is only used for uniquifying new 78 // reservations. 79 // 80 // Once |completion_callback| is invoked, it is the caller's responsibility to 81 // handle cases where the target path could not be verified and set the target 82 // path of the |download_item| appropriately. 83 // 84 // The current implementation doesn't look at symlinks/mount points. E.g.: It 85 // considers 'foo/bar/x.pdf' and 'foo/baz/x.pdf' to be two different paths, 86 // even though 'bar' might be a symlink to 'baz'. 87 static void GetReservedPath( 88 content::DownloadItem* download_item, 89 const base::FilePath& requested_target_path, 90 const base::FilePath& default_download_path, 91 bool create_directory, 92 FilenameConflictAction conflict_action, 93 const ReservedPathCallback& callback); 94 95 // Returns true if |path| is in use by an existing path reservation. Should 96 // only be called on the FILE thread. Currently only used by tests. 97 static bool IsPathInUseForTesting(const base::FilePath& path); 98 }; 99 100 #endif // CHROME_BROWSER_DOWNLOAD_DOWNLOAD_PATH_RESERVATION_TRACKER_H_ 101