Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(109)

Side by Side Diff: chrome/browser/download/download_path_reservation_tracker.cc

Issue 12212010: Truncate the download file name if it exceeds the filesystem limit. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Created 7 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « base/sys_info_win.cc ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 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 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "chrome/browser/download/download_path_reservation_tracker.h" 5 #include "chrome/browser/download/download_path_reservation_tracker.h"
6 6
7 #include <map> 7 #include <map>
8 8
9 #include "base/bind.h" 9 #include "base/bind.h"
10 #include "base/callback.h" 10 #include "base/callback.h"
11 #include "base/file_util.h" 11 #include "base/file_util.h"
12 #include "base/logging.h" 12 #include "base/logging.h"
13 #include "base/path_service.h" 13 #include "base/path_service.h"
14 #include "base/stl_util.h" 14 #include "base/stl_util.h"
15 #include "base/string_util.h"
16 #include "base/sys_info.h"
15 #include "chrome/browser/download/download_util.h" 17 #include "chrome/browser/download/download_util.h"
16 #include "chrome/common/chrome_paths.h" 18 #include "chrome/common/chrome_paths.h"
17 #include "content/public/browser/browser_thread.h" 19 #include "content/public/browser/browser_thread.h"
18 #include "content/public/browser/download_id.h" 20 #include "content/public/browser/download_id.h"
19 #include "content/public/browser/download_item.h" 21 #include "content/public/browser/download_item.h"
20 22
21 using content::BrowserThread; 23 using content::BrowserThread;
22 using content::DownloadId; 24 using content::DownloadId;
23 using content::DownloadItem; 25 using content::DownloadItem;
24 26
(...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after
83 if (IsPathReserved(path)) 85 if (IsPathReserved(path))
84 return true; 86 return true;
85 87
86 // If the path exists in the file system, then the path is in use. 88 // If the path exists in the file system, then the path is in use.
87 if (file_util::PathExists(path)) 89 if (file_util::PathExists(path))
88 return true; 90 return true;
89 91
90 return false; 92 return false;
91 } 93 }
92 94
95 // Truncate the given name so that its becomes .size() <= limit. Returns an
96 // empty string if it is impossible due to unknown file-name encoding.
97 FilePath::StringType TruncateFileName(const FilePath::StringType& name,
98 size_t limit) {
99 FilePath::StringType truncated;
100 #if defined(OS_CHROMEOS) || defined(OS_MACOSX)
101 TruncateUTF8ToByteSize(name, limit, &truncated);
102 #elif defined(OS_WIN)
103 // TODO(kinaba): Implement for Windows, where StringType == string16.
104 #else
105 // We cannot generally assume that the file name encoding is in UTF-8 (see
106 // the comment for FilePath::AsUTF8Unsafe), hence no safe way to truncate.
Randy Smith (Not in Mondays) 2013/02/07 19:12:03 I'm inclined to think that we'll end up with a bet
107 #endif
108 return truncated;
109 }
110
93 // Called on the FILE thread to reserve a download path. This method: 111 // Called on the FILE thread to reserve a download path. This method:
94 // - Creates directory |default_download_path| if it doesn't exist. 112 // - Creates directory |default_download_path| if it doesn't exist.
95 // - Verifies that the parent directory of |suggested_path| exists and is 113 // - Verifies that the parent directory of |suggested_path| exists and is
96 // writeable. 114 // writeable.
97 // - Uniquifies |suggested_path| if |should_uniquify_path| is true. 115 // - Uniquifies |suggested_path| if |should_uniquify_path| is true.
Randy Smith (Not in Mondays) 2013/02/07 19:12:03 Should mention truncation in this comment as well.
kinaba 2013/02/08 10:46:57 Done.
98 // - Schedules |callback| on the UI thread with the reserved path and a flag 116 // - Schedules |callback| on the UI thread with the reserved path and a flag
99 // indicating whether the returned path has been successfully verified. 117 // indicating whether the returned path has been successfully verified.
100 void CreateReservation( 118 void CreateReservation(
101 DownloadId download_id, 119 DownloadId download_id,
102 const FilePath& suggested_path, 120 const FilePath& suggested_path,
103 const FilePath& default_download_path, 121 const FilePath& default_download_path,
104 bool should_uniquify, 122 bool should_uniquify,
105 const DownloadPathReservationTracker::ReservedPathCallback& callback) { 123 const DownloadPathReservationTracker::ReservedPathCallback& callback) {
106 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); 124 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
107 DCHECK(download_id.IsValid()); 125 DCHECK(download_id.IsValid());
(...skipping 24 matching lines...) Expand all
132 // to the user's "My Documents" directory. We'll prompt them in this case. 150 // to the user's "My Documents" directory. We'll prompt them in this case.
133 FilePath dir = target_path.DirName(); 151 FilePath dir = target_path.DirName();
134 FilePath filename = target_path.BaseName(); 152 FilePath filename = target_path.BaseName();
135 if (!file_util::PathIsWritable(dir)) { 153 if (!file_util::PathIsWritable(dir)) {
136 DVLOG(1) << "Unable to write to directory \"" << dir.value() << "\""; 154 DVLOG(1) << "Unable to write to directory \"" << dir.value() << "\"";
137 is_path_writeable = false; 155 is_path_writeable = false;
138 PathService::Get(chrome::DIR_USER_DOCUMENTS, &dir); 156 PathService::Get(chrome::DIR_USER_DOCUMENTS, &dir);
139 target_path = dir.Append(filename); 157 target_path = dir.Append(filename);
140 } 158 }
141 159
160 // Check the limit of file name length if it could be obtained. When the
161 // suggested name exceeds the limit, truncate or prompt the user.
162 bool name_too_long = false;
163 if (is_path_writeable) {
164 int max_length = base::SysInfo::GetMaximumPathComponentLength(dir);
165 if (max_length > 0) {
166 // The extension should not be truncated, so we split it first.
167 FilePath::StringType ext = filename.Extension();
168 FilePath::StringType name = filename.RemoveExtension().value();
169
170 // Reserve several characters we may append later.
171 const int kExtraChars = sizeof(" (100).crdownload") - 1;
Randy Smith (Not in Mondays) 2013/02/07 19:12:03 I'd rather find some way to export the amount of s
172 int limit = max_length - ext.size() - kExtraChars;
173 if (static_cast<int>(name.size()) > limit) {
174 name_too_long = true;
175 if (limit > 0) {
Randy Smith (Not in Mondays) 2013/02/07 19:12:03 I'd be inclined to reserve a few more characters h
kinaba 2013/02/08 10:46:57 Pulled out the constant (tentatively 5). IMHO we c
176 // Truncate the name to fit in |limit|.
177 FilePath::StringType truncated = TruncateFileName(name, limit);
178 if (!truncated.empty()) {
179 target_path = dir.Append(truncated + ext);
180 name_too_long = false;
181 }
182 }
183 }
184 }
185 }
186
142 if (is_path_writeable && should_uniquify && IsPathInUse(target_path)) { 187 if (is_path_writeable && should_uniquify && IsPathInUse(target_path)) {
143 has_conflicts = true; 188 has_conflicts = true;
144 for (int uniquifier = 1; 189 for (int uniquifier = 1;
145 uniquifier <= DownloadPathReservationTracker::kMaxUniqueFiles; 190 uniquifier <= DownloadPathReservationTracker::kMaxUniqueFiles;
146 ++uniquifier) { 191 ++uniquifier) {
147 FilePath path_to_check(target_path.InsertBeforeExtensionASCII( 192 FilePath path_to_check(target_path.InsertBeforeExtensionASCII(
148 StringPrintf(" (%d)", uniquifier))); 193 StringPrintf(" (%d)", uniquifier)));
149 if (!IsPathInUse(path_to_check)) { 194 if (!IsPathInUse(path_to_check)) {
150 target_path = path_to_check; 195 target_path = path_to_check;
151 has_conflicts = false; 196 has_conflicts = false;
152 break; 197 break;
153 } 198 }
154 } 199 }
155 } 200 }
156 reservations[download_id] = target_path; 201 reservations[download_id] = target_path;
157 BrowserThread::PostTask( 202 bool verified = (is_path_writeable && !has_conflicts && !name_too_long);
158 BrowserThread::UI, FROM_HERE, 203 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
159 base::Bind(callback, target_path, (is_path_writeable && !has_conflicts))); 204 base::Bind(callback, target_path, verified));
160 } 205 }
161 206
162 // Called on the FILE thread to update the path of the reservation associated 207 // Called on the FILE thread to update the path of the reservation associated
163 // with |download_id| to |new_path|. 208 // with |download_id| to |new_path|.
164 void UpdateReservation(DownloadId download_id, const FilePath& new_path) { 209 void UpdateReservation(DownloadId download_id, const FilePath& new_path) {
165 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); 210 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
166 DCHECK(g_reservation_map != NULL); 211 DCHECK(g_reservation_map != NULL);
167 ReservationMap::iterator iter = g_reservation_map->find(download_id); 212 ReservationMap::iterator iter = g_reservation_map->find(download_id);
168 if (iter != g_reservation_map->end()) { 213 if (iter != g_reservation_map->end()) {
169 iter->second = new_path; 214 iter->second = new_path;
(...skipping 97 matching lines...) Expand 10 before | Expand all | Expand 10 after
267 BrowserThread::FILE, FROM_HERE, 312 BrowserThread::FILE, FROM_HERE,
268 base::Bind(&CreateReservation, download_item.GetGlobalId(), 313 base::Bind(&CreateReservation, download_item.GetGlobalId(),
269 target_path, default_path, uniquify_path, callback)); 314 target_path, default_path, uniquify_path, callback));
270 } 315 }
271 316
272 // static 317 // static
273 bool DownloadPathReservationTracker::IsPathInUseForTesting( 318 bool DownloadPathReservationTracker::IsPathInUseForTesting(
274 const FilePath& path) { 319 const FilePath& path) {
275 return IsPathInUse(path); 320 return IsPathInUse(path);
276 } 321 }
OLDNEW
« no previous file with comments | « base/sys_info_win.cc ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698