diff options
author | Amaury Pouly <pamaury@rockbox.org> | 2010-01-20 21:24:19 +0000 |
---|---|---|
committer | Amaury Pouly <pamaury@rockbox.org> | 2010-01-20 21:24:19 +0000 |
commit | b5d16e79e191af7c4cb34be685770166e8dfcfa6 (patch) | |
tree | c45d27b817ad85eb1fbbc18825a32db01f829ddf | |
parent | 052812d575b5a50f086e09f26a919e01536bea31 (diff) | |
download | rockbox-b5d16e79e191af7c4cb34be685770166e8dfcfa6.tar.gz rockbox-b5d16e79e191af7c4cb34be685770166e8dfcfa6.zip |
FS#10738: fix disktidy plugin crash when dealing with very long file/directory names.
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@24300 a1c6a512-1295-4272-9138-f99709370657
-rw-r--r-- | apps/plugins/disktidy.c | 98 |
1 files changed, 70 insertions, 28 deletions
diff --git a/apps/plugins/disktidy.c b/apps/plugins/disktidy.c index ee39972f0b..3d2685f4ad 100644 --- a/apps/plugins/disktidy.c +++ b/apps/plugins/disktidy.c | |||
@@ -19,6 +19,7 @@ | |||
19 | * | 19 | * |
20 | ****************************************************************************/ | 20 | ****************************************************************************/ |
21 | #include "plugin.h" | 21 | #include "plugin.h" |
22 | #include "errno.h" | ||
22 | 23 | ||
23 | PLUGIN_HEADER | 24 | PLUGIN_HEADER |
24 | 25 | ||
@@ -172,33 +173,53 @@ void tidy_lcd_status(const char *name, int *removed) | |||
172 | rb->lcd_update(); | 173 | rb->lcd_update(); |
173 | } | 174 | } |
174 | 175 | ||
175 | void tidy_get_absolute_path(struct dirent *entry, char *fullname, | 176 | int tidy_path_append_entry(char *path, struct dirent *entry, int *path_length) |
176 | const char* name) | ||
177 | { | 177 | { |
178 | /* gets absolute path using dirent and name */ | 178 | int name_len = rb->strlen(entry->d_name); |
179 | rb->strcpy(fullname, name); | 179 | /* for the special case of path="/" this is one bigger but it's not a problem */ |
180 | if (rb->strlen(name) > 1) | 180 | int new_length = *path_length + name_len + 1; |
181 | |||
182 | /* check overflow (keep space for trailing zero) */ | ||
183 | if(new_length >= MAX_PATH) | ||
184 | return 0; | ||
185 | |||
186 | /* special case for path <> "/" */ | ||
187 | if(rb->strcmp(path, "/") != 0) | ||
181 | { | 188 | { |
182 | rb->strcat(fullname, "/"); | 189 | rb->strcat(path + *path_length, "/"); |
190 | (*path_length)++; | ||
183 | } | 191 | } |
184 | rb->strcat(fullname, entry->d_name); | 192 | /* strcat is unsafe but the previous check normally avoid any problem */ |
193 | /* use path_length to optimise */ | ||
194 | |||
195 | rb->strcat(path + *path_length, entry->d_name); | ||
196 | *path_length += name_len; | ||
197 | |||
198 | return 1; | ||
185 | } | 199 | } |
186 | 200 | ||
187 | enum tidy_return tidy_removedir(const char *name, int *removed) | 201 | void tidy_path_remove_entry(char *path, int old_path_length, int *path_length) |
202 | { | ||
203 | path[old_path_length] = '\0'; | ||
204 | *path_length = old_path_length; | ||
205 | } | ||
206 | |||
207 | /* path is assumed to be array of size MAX_PATH */ | ||
208 | enum tidy_return tidy_removedir(char *path, int *path_length, int *removed) | ||
188 | { | 209 | { |
189 | /* delete directory */ | 210 | /* delete directory */ |
190 | struct dirent *entry; | 211 | struct dirent *entry; |
191 | enum tidy_return status = TIDY_RETURN_OK; | 212 | enum tidy_return status = TIDY_RETURN_OK; |
192 | int button; | 213 | int button; |
193 | DIR *dir; | 214 | DIR *dir; |
194 | char fullname[MAX_PATH]; | 215 | int old_path_length = *path_length; |
195 | 216 | ||
196 | /* display status text */ | 217 | /* display status text */ |
197 | tidy_lcd_status(name, removed); | 218 | tidy_lcd_status(path, removed); |
198 | 219 | ||
199 | rb->yield(); | 220 | rb->yield(); |
200 | 221 | ||
201 | dir = rb->opendir(name); | 222 | dir = rb->opendir(path); |
202 | if (dir) | 223 | if (dir) |
203 | { | 224 | { |
204 | while((status == TIDY_RETURN_OK) && ((entry = rb->readdir(dir)) != 0)) | 225 | while((status == TIDY_RETURN_OK) && ((entry = rb->readdir(dir)) != 0)) |
@@ -220,7 +241,10 @@ enum tidy_return tidy_removedir(const char *name, int *removed) | |||
220 | rb->yield(); | 241 | rb->yield(); |
221 | 242 | ||
222 | /* get absolute path */ | 243 | /* get absolute path */ |
223 | tidy_get_absolute_path(entry, fullname, name); | 244 | /* returns an error if path is too long */ |
245 | if(!tidy_path_append_entry(path, entry, path_length)) | ||
246 | /* silent error */ | ||
247 | continue; | ||
224 | 248 | ||
225 | if (entry->attribute & ATTR_DIRECTORY) | 249 | if (entry->attribute & ATTR_DIRECTORY) |
226 | { | 250 | { |
@@ -228,20 +252,23 @@ enum tidy_return tidy_removedir(const char *name, int *removed) | |||
228 | if ((rb->strcmp(entry->d_name, ".") != 0) && \ | 252 | if ((rb->strcmp(entry->d_name, ".") != 0) && \ |
229 | (rb->strcmp(entry->d_name, "..") != 0)) | 253 | (rb->strcmp(entry->d_name, "..") != 0)) |
230 | { | 254 | { |
231 | tidy_removedir(fullname, removed); | 255 | tidy_removedir(path, path_length, removed); |
232 | } | 256 | } |
233 | } | 257 | } |
234 | else | 258 | else |
235 | { | 259 | { |
236 | /* file */ | 260 | /* file */ |
237 | *removed += 1; | 261 | *removed += 1; |
238 | rb->remove(fullname); | 262 | rb->remove(path); |
239 | } | 263 | } |
264 | |||
265 | /* restore path */ | ||
266 | tidy_path_remove_entry(path, old_path_length, path_length); | ||
240 | } | 267 | } |
241 | rb->closedir(dir); | 268 | rb->closedir(dir); |
242 | /* rmdir */ | 269 | /* rmdir */ |
243 | *removed += 1; | 270 | *removed += 1; |
244 | rb->rmdir(name); | 271 | rb->rmdir(path); |
245 | } | 272 | } |
246 | else | 273 | else |
247 | { | 274 | { |
@@ -250,7 +277,8 @@ enum tidy_return tidy_removedir(const char *name, int *removed) | |||
250 | return status; | 277 | return status; |
251 | } | 278 | } |
252 | 279 | ||
253 | enum tidy_return tidy_clean(const char *name, int *removed) | 280 | /* path is assumed to be array of size MAX_PATH */ |
281 | enum tidy_return tidy_clean(char *path, int *path_length, int *removed) | ||
254 | { | 282 | { |
255 | /* deletes junk files and dirs left by system */ | 283 | /* deletes junk files and dirs left by system */ |
256 | struct dirent *entry; | 284 | struct dirent *entry; |
@@ -258,14 +286,14 @@ enum tidy_return tidy_clean(const char *name, int *removed) | |||
258 | int button; | 286 | int button; |
259 | int del; /* has the item been deleted */ | 287 | int del; /* has the item been deleted */ |
260 | DIR *dir; | 288 | DIR *dir; |
261 | char fullname[MAX_PATH]; | 289 | int old_path_length = *path_length; |
262 | 290 | ||
263 | /* display status text */ | 291 | /* display status text */ |
264 | tidy_lcd_status(name, removed); | 292 | tidy_lcd_status(path, removed); |
265 | 293 | ||
266 | rb->yield(); | 294 | rb->yield(); |
267 | 295 | ||
268 | dir = rb->opendir(name); | 296 | dir = rb->opendir(path); |
269 | if (dir) | 297 | if (dir) |
270 | { | 298 | { |
271 | while((status == TIDY_RETURN_OK) && ((entry = rb->readdir(dir)) != 0)) | 299 | while((status == TIDY_RETURN_OK) && ((entry = rb->readdir(dir)) != 0)) |
@@ -295,20 +323,26 @@ enum tidy_return tidy_clean(const char *name, int *removed) | |||
295 | del = 0; | 323 | del = 0; |
296 | 324 | ||
297 | /* get absolute path */ | 325 | /* get absolute path */ |
298 | tidy_get_absolute_path(entry, fullname, name); | 326 | /* returns an error if path is too long */ |
327 | if(!tidy_path_append_entry(path, entry, path_length)) | ||
328 | /* silent error */ | ||
329 | continue; | ||
299 | 330 | ||
300 | if (tidy_remove_item(entry->d_name, entry->attribute)) | 331 | if (tidy_remove_item(entry->d_name, entry->attribute)) |
301 | { | 332 | { |
302 | /* delete dir */ | 333 | /* delete dir */ |
303 | tidy_removedir(fullname, removed); | 334 | tidy_removedir(path, path_length, removed); |
304 | del = 1; | 335 | del = 1; |
305 | } | 336 | } |
306 | 337 | ||
307 | if (del == 0) | 338 | if (del == 0) |
308 | { | 339 | { |
309 | /* dir not deleted so clean it */ | 340 | /* dir not deleted so clean it */ |
310 | status = tidy_clean(fullname, removed); | 341 | status = tidy_clean(path, path_length, removed); |
311 | } | 342 | } |
343 | |||
344 | /* restore path */ | ||
345 | tidy_path_remove_entry(path, old_path_length, path_length); | ||
312 | } | 346 | } |
313 | } | 347 | } |
314 | else | 348 | else |
@@ -317,15 +351,19 @@ enum tidy_return tidy_clean(const char *name, int *removed) | |||
317 | del = 0; | 351 | del = 0; |
318 | if (tidy_remove_item(entry->d_name, entry->attribute)) | 352 | if (tidy_remove_item(entry->d_name, entry->attribute)) |
319 | { | 353 | { |
320 | *removed += 1; /* increment removed files counter */ | ||
321 | |||
322 | /* get absolute path */ | 354 | /* get absolute path */ |
323 | char fullname[MAX_PATH]; | 355 | /* returns an error if path is too long */ |
324 | tidy_get_absolute_path(entry, fullname, name); | 356 | if(!tidy_path_append_entry(path, entry, path_length)) |
357 | /* silent error */ | ||
358 | continue; | ||
325 | 359 | ||
360 | *removed += 1; /* increment removed files counter */ | ||
326 | /* delete file */ | 361 | /* delete file */ |
327 | rb->remove(fullname); | 362 | rb->remove(path); |
328 | del = 1; | 363 | del = 1; |
364 | |||
365 | /* restore path */ | ||
366 | tidy_path_remove_entry(path, old_path_length, path_length); | ||
329 | } | 367 | } |
330 | } | 368 | } |
331 | } | 369 | } |
@@ -344,12 +382,16 @@ enum tidy_return tidy_do(void) | |||
344 | int removed = 0; | 382 | int removed = 0; |
345 | enum tidy_return status; | 383 | enum tidy_return status; |
346 | char text[24]; /* "Cleaned up nnnnn items" */ | 384 | char text[24]; /* "Cleaned up nnnnn items" */ |
385 | char path[MAX_PATH]; | ||
386 | int path_length; | ||
347 | 387 | ||
348 | #ifdef HAVE_ADJUSTABLE_CPU_FREQ | 388 | #ifdef HAVE_ADJUSTABLE_CPU_FREQ |
349 | rb->cpu_boost(true); | 389 | rb->cpu_boost(true); |
350 | #endif | 390 | #endif |
351 | 391 | ||
352 | status = tidy_clean("/", &removed); | 392 | rb->strcpy(path, "/"); |
393 | path_length = rb->strlen(path); | ||
394 | status = tidy_clean(path, &path_length, &removed); | ||
353 | 395 | ||
354 | #ifdef HAVE_ADJUSTABLE_CPU_FREQ | 396 | #ifdef HAVE_ADJUSTABLE_CPU_FREQ |
355 | rb->cpu_boost(false); | 397 | rb->cpu_boost(false); |