diff options
Diffstat (limited to 'apps/fileop.c')
-rw-r--r-- | apps/fileop.c | 149 |
1 files changed, 92 insertions, 57 deletions
diff --git a/apps/fileop.c b/apps/fileop.c index 35bd9f2241..1aaee3bb64 100644 --- a/apps/fileop.c +++ b/apps/fileop.c | |||
@@ -44,9 +44,12 @@ | |||
44 | struct file_op_params | 44 | struct file_op_params |
45 | { | 45 | { |
46 | char path[MAX_PATH]; /* Buffer for full path */ | 46 | char path[MAX_PATH]; /* Buffer for full path */ |
47 | const char* toplevel_name; | ||
47 | bool is_dir; | 48 | bool is_dir; |
48 | int objects; /* how many files and subdirectories*/ | 49 | int objects; /* how many files and subdirectories*/ |
49 | int processed; | 50 | int processed; |
51 | unsigned long long total_size; | ||
52 | unsigned long long processed_size; | ||
50 | size_t append; /* Append position in 'path' for stack push */ | 53 | size_t append; /* Append position in 'path' for stack push */ |
51 | }; | 54 | }; |
52 | 55 | ||
@@ -61,28 +64,52 @@ static int prompt_name(char* buf, size_t bufsz) | |||
61 | return FORC_UNKNOWN_FAILURE; | 64 | return FORC_UNKNOWN_FAILURE; |
62 | } | 65 | } |
63 | 66 | ||
64 | static bool poll_cancel_action(const char *path, int operation, int current, int total) | 67 | static bool poll_cancel_action(int operation, struct file_op_params *param) |
65 | { | 68 | { |
66 | const char *op_str = ""; | 69 | static unsigned long last_tick; |
67 | 70 | ||
68 | clear_screen_buffer(false); | 71 | if (operation == FOC_COUNT) |
69 | 72 | { | |
70 | if (operation == FOC_COPY) | 73 | if (param->objects <= 1) |
71 | op_str = str(LANG_COPYING); | 74 | last_tick = current_tick; |
72 | else if (operation == FOC_MOVE) | 75 | else if (TIME_AFTER(current_tick, last_tick + HZ/2)) |
73 | op_str = str(LANG_MOVING); | 76 | { |
74 | else if (operation == FOC_COUNT) | 77 | clear_screen_buffer(false); |
75 | op_str = str(LANG_SCANNING_DISK); | 78 | splashf(0, "%s (%d)", str(LANG_SCANNING_DISK), param->objects); |
76 | else if (operation == FOC_DELETE) | 79 | last_tick = current_tick; |
77 | op_str = str(LANG_DELETING); | 80 | } |
78 | 81 | } | |
79 | path_basename(path, &path); | ||
80 | |||
81 | if (total <= 0) | ||
82 | splashf(0, "%s (%d) %s", op_str, current, path); | ||
83 | else | 82 | else |
84 | splash_progress(current, total, "%s %s", op_str, path); | 83 | { |
84 | const char *op_str = (operation == FOC_DELETE) ? str(LANG_DELETING) : | ||
85 | (operation == FOC_COPY) ? str(LANG_COPYING) : | ||
86 | str(LANG_MOVING); | ||
85 | 87 | ||
88 | if ((operation == FOC_DELETE || !param->total_size) && | ||
89 | param->objects > 0) | ||
90 | { | ||
91 | splash_progress(param->processed, param->objects, | ||
92 | "%s %s", op_str, param->toplevel_name); | ||
93 | } | ||
94 | else if (param->total_size >= 10 * 1024 * 1024) | ||
95 | { | ||
96 | int total_shft = (int) (param->total_size >> 15); | ||
97 | int current_shft = (int) (param->processed_size >> 15); | ||
98 | splash_progress(current_shft, total_shft, | ||
99 | "%s %s (%d MiB)\n%d MiB", | ||
100 | op_str, param->toplevel_name, | ||
101 | total_shft >> 5, current_shft >> 5); | ||
102 | } | ||
103 | else if (param->total_size >= 1024) | ||
104 | { | ||
105 | int total_kib = (int) (param->total_size >> 10); | ||
106 | int current_kib = (int) (param->processed_size >> 10); | ||
107 | splash_progress(current_kib, total_kib, | ||
108 | "%s %s (%d KiB)\n%d KiB", | ||
109 | op_str, param->toplevel_name, | ||
110 | total_kib, current_kib); | ||
111 | } | ||
112 | } | ||
86 | return ACTION_STD_CANCEL == get_action(CONTEXT_STD, TIMEOUT_NOBLOCK); | 113 | return ACTION_STD_CANCEL == get_action(CONTEXT_STD, TIMEOUT_NOBLOCK); |
87 | } | 114 | } |
88 | 115 | ||
@@ -94,13 +121,20 @@ static void init_file_op(struct file_op_params *param, | |||
94 | if (selected_file == NULL) | 121 | if (selected_file == NULL) |
95 | { | 122 | { |
96 | param->append = strlcpy(param->path, basename, sizeof (param->path)); | 123 | param->append = strlcpy(param->path, basename, sizeof (param->path)); |
124 | path_basename(basename, &basename); | ||
125 | param->toplevel_name = basename; | ||
97 | } | 126 | } |
98 | else | 127 | else |
128 | { | ||
99 | param->append = path_append(param->path, basename, | 129 | param->append = path_append(param->path, basename, |
100 | selected_file, sizeof (param->path)); | 130 | selected_file, sizeof (param->path)); |
131 | param->toplevel_name = selected_file; | ||
132 | } | ||
101 | param->is_dir = dir_exists(param->path); | 133 | param->is_dir = dir_exists(param->path); |
102 | param->objects = 0; /* how many files and subdirectories*/ | 134 | param->objects = 0; /* how many files and subdirectories*/ |
103 | param->processed = 0; | 135 | param->processed = 0; |
136 | param->total_size = 0; | ||
137 | param->processed_size = 0; | ||
104 | } | 138 | } |
105 | 139 | ||
106 | /* counts file objects, deletes file objects */ | 140 | /* counts file objects, deletes file objects */ |
@@ -156,7 +190,7 @@ static int directory_fileop(struct file_op_params *param, enum file_op_current f | |||
156 | rc = directory_fileop(param, fileop); /* recursion */ | 190 | rc = directory_fileop(param, fileop); /* recursion */ |
157 | } else { | 191 | } else { |
158 | /* remove a file */ | 192 | /* remove a file */ |
159 | if (poll_cancel_action(param->path, FOC_DELETE, param->processed, param->objects)) | 193 | if (poll_cancel_action(FOC_DELETE, param)) |
160 | { | 194 | { |
161 | rc = FORC_CANCELLED; | 195 | rc = FORC_CANCELLED; |
162 | break; | 196 | break; |
@@ -167,6 +201,13 @@ static int directory_fileop(struct file_op_params *param, enum file_op_current f | |||
167 | else /* count objects */ | 201 | else /* count objects */ |
168 | { | 202 | { |
169 | param->objects++; | 203 | param->objects++; |
204 | param->total_size += info.size; | ||
205 | |||
206 | if (poll_cancel_action(FOC_COUNT, param)) | ||
207 | { | ||
208 | rc = FORC_CANCELLED; | ||
209 | break; | ||
210 | } | ||
170 | 211 | ||
171 | if (param->append >= sizeof (param->path)) { | 212 | if (param->append >= sizeof (param->path)) { |
172 | rc = FORC_PATH_TOO_LONG; | 213 | rc = FORC_PATH_TOO_LONG; |
@@ -176,12 +217,6 @@ static int directory_fileop(struct file_op_params *param, enum file_op_current f | |||
176 | if (info.attribute & ATTR_DIRECTORY) { | 217 | if (info.attribute & ATTR_DIRECTORY) { |
177 | /* enter subdirectory */ | 218 | /* enter subdirectory */ |
178 | rc = directory_fileop(param, FOC_COUNT); /* recursion */ | 219 | rc = directory_fileop(param, FOC_COUNT); /* recursion */ |
179 | } else { | ||
180 | if (poll_cancel_action(param->path, FOC_COUNT, param->objects, 0)) | ||
181 | { | ||
182 | rc = FORC_CANCELLED; | ||
183 | break; | ||
184 | } | ||
185 | } | 220 | } |
186 | } | 221 | } |
187 | param->append = append; /* other functions may use param, reset append */ | 222 | param->append = append; /* other functions may use param, reset append */ |
@@ -193,7 +228,7 @@ static int directory_fileop(struct file_op_params *param, enum file_op_current f | |||
193 | 228 | ||
194 | if (fileop == FOC_DELETE && rc == FORC_SUCCESS) { | 229 | if (fileop == FOC_DELETE && rc == FORC_SUCCESS) { |
195 | /* remove the now empty directory */ | 230 | /* remove the now empty directory */ |
196 | if (poll_cancel_action(param->path, FOC_DELETE, param->processed, param->objects)) | 231 | if (poll_cancel_action(FOC_DELETE, param)) |
197 | { | 232 | { |
198 | rc = FORC_CANCELLED; | 233 | rc = FORC_CANCELLED; |
199 | } else { | 234 | } else { |
@@ -216,7 +251,7 @@ static int check_count_fileobjects(struct file_op_params *param) | |||
216 | } | 251 | } |
217 | 252 | ||
218 | /* Attempt to just rename a file or directory */ | 253 | /* Attempt to just rename a file or directory */ |
219 | static int move_by_rename(const char *src_path, | 254 | static int move_by_rename(struct file_op_params *src, |
220 | const char *dst_path, | 255 | const char *dst_path, |
221 | unsigned int *pflags) | 256 | unsigned int *pflags) |
222 | { | 257 | { |
@@ -225,19 +260,15 @@ static int move_by_rename(const char *src_path, | |||
225 | if (!(flags & (PASTE_COPY | PASTE_EXDEV))) { | 260 | if (!(flags & (PASTE_COPY | PASTE_EXDEV))) { |
226 | if ((flags & PASTE_OVERWRITE) || !file_exists(dst_path)) { | 261 | if ((flags & PASTE_OVERWRITE) || !file_exists(dst_path)) { |
227 | /* Just try to move the directory / file */ | 262 | /* Just try to move the directory / file */ |
228 | if (poll_cancel_action(src_path, FOC_MOVE, 0 , 0)) { | 263 | rc = rename(src->path, dst_path); |
229 | rc = FORC_CANCELLED; | ||
230 | } else { | ||
231 | rc = rename(src_path, dst_path); | ||
232 | #ifdef HAVE_MULTIVOLUME | 264 | #ifdef HAVE_MULTIVOLUME |
233 | if (rc < FORC_SUCCESS && errno == EXDEV) { | 265 | if (rc < FORC_SUCCESS && errno == EXDEV) { |
234 | /* Failed because cross volume rename doesn't work */ | 266 | /* Failed because cross volume rename doesn't work */ |
235 | *pflags |= PASTE_EXDEV; /* force a move instead */ | 267 | *pflags |= PASTE_EXDEV; /* force a move instead */ |
236 | } | 268 | } |
237 | #endif /* HAVE_MULTIVOLUME */ | 269 | #endif /* HAVE_MULTIVOLUME */ |
238 | /* if (errno == ENOTEMPTY && (flags & PASTE_OVERWRITE)) { | 270 | /* if (errno == ENOTEMPTY && (flags & PASTE_OVERWRITE)) { |
239 | * Directory is not empty thus rename() will not do a quick overwrite */ | 271 | * Directory is not empty thus rename() will not do a quick overwrite */ |
240 | } | ||
241 | } | 272 | } |
242 | 273 | ||
243 | } | 274 | } |
@@ -245,12 +276,16 @@ static int move_by_rename(const char *src_path, | |||
245 | } | 276 | } |
246 | 277 | ||
247 | /* Paste a file */ | 278 | /* Paste a file */ |
248 | static int copy_move_file(const char *src_path, const char *dst_path, unsigned int flags) | 279 | static int copy_move_file(struct file_op_params *src, const char *dst_path, |
280 | unsigned int flags) | ||
249 | { | 281 | { |
250 | /* Try renaming first */ | 282 | /* Try renaming first */ |
251 | int rc = move_by_rename(src_path, dst_path, &flags); | 283 | int rc = move_by_rename(src, dst_path, &flags); |
252 | if (rc == FORC_SUCCESS) | 284 | if (rc == FORC_SUCCESS) |
285 | { | ||
286 | src->total_size = 0; /* switch from counting size to number of items */ | ||
253 | return rc; | 287 | return rc; |
288 | } | ||
254 | 289 | ||
255 | /* See if we can get the plugin buffer for the file copy buffer */ | 290 | /* See if we can get the plugin buffer for the file copy buffer */ |
256 | size_t buffersize; | 291 | size_t buffersize; |
@@ -268,9 +303,11 @@ static int copy_move_file(const char *src_path, const char *dst_path, unsigned i | |||
268 | 303 | ||
269 | buffersize &= ~0x1ff; /* Round buffer size to multiple of sector size */ | 304 | buffersize &= ~0x1ff; /* Round buffer size to multiple of sector size */ |
270 | 305 | ||
271 | int src_fd = open(src_path, O_RDONLY); | 306 | int src_fd = open(src->path, O_RDONLY); |
272 | if (src_fd >= 0) { | 307 | if (src_fd >= 0) { |
273 | off_t src_sz = lseek(src_fd, 0, SEEK_END); | 308 | off_t src_sz = lseek(src_fd, 0, SEEK_END); |
309 | if (!src->total_size && !src->processed) /* single file copy */ | ||
310 | src->total_size = src_sz; | ||
274 | lseek(src_fd, 0, SEEK_SET); | 311 | lseek(src_fd, 0, SEEK_SET); |
275 | 312 | ||
276 | int oflag = O_WRONLY|O_CREAT; | 313 | int oflag = O_WRONLY|O_CREAT; |
@@ -289,9 +326,8 @@ static int copy_move_file(const char *src_path, const char *dst_path, unsigned i | |||
289 | while (rc == FORC_SUCCESS) { | 326 | while (rc == FORC_SUCCESS) { |
290 | if (total_size >= next_cancel_test) { | 327 | if (total_size >= next_cancel_test) { |
291 | next_cancel_test = total_size + 0x10000; | 328 | next_cancel_test = total_size + 0x10000; |
292 | if (poll_cancel_action(src_path, | 329 | if (poll_cancel_action(!(flags & PASTE_COPY) ? |
293 | !(flags & PASTE_COPY) ? FOC_MOVE : FOC_COPY, | 330 | FOC_MOVE : FOC_COPY, src)) |
294 | total_size, src_sz)) | ||
295 | { | 331 | { |
296 | rc = FORC_CANCELLED; | 332 | rc = FORC_CANCELLED; |
297 | break; | 333 | break; |
@@ -315,6 +351,7 @@ static int copy_move_file(const char *src_path, const char *dst_path, unsigned i | |||
315 | } | 351 | } |
316 | 352 | ||
317 | total_size += byteswritten; | 353 | total_size += byteswritten; |
354 | src->processed_size += byteswritten; | ||
318 | 355 | ||
319 | if (bytesread < (ssize_t)buffersize) { | 356 | if (bytesread < (ssize_t)buffersize) { |
320 | /* EOF with trailing bytes */ | 357 | /* EOF with trailing bytes */ |
@@ -344,7 +381,7 @@ static int copy_move_file(const char *src_path, const char *dst_path, unsigned i | |||
344 | 381 | ||
345 | if (rc == FORC_SUCCESS && !(flags & PASTE_COPY)) { | 382 | if (rc == FORC_SUCCESS && !(flags & PASTE_COPY)) { |
346 | /* Remove the source file */ | 383 | /* Remove the source file */ |
347 | rc = remove(src_path) * 10; | 384 | rc = remove(src->path) * 10; |
348 | } | 385 | } |
349 | 386 | ||
350 | return rc; | 387 | return rc; |
@@ -408,9 +445,8 @@ static int copy_move_directory(struct file_op_params *src, | |||
408 | break; | 445 | break; |
409 | } | 446 | } |
410 | 447 | ||
411 | if (poll_cancel_action(src->path, | 448 | if (poll_cancel_action(!(flags & PASTE_COPY) ? |
412 | !(flags & PASTE_COPY) ? FOC_MOVE : FOC_COPY, | 449 | FOC_MOVE : FOC_COPY, src)) |
413 | src->processed, src->objects)) | ||
414 | { | 450 | { |
415 | rc = FORC_CANCELLED; | 451 | rc = FORC_CANCELLED; |
416 | break; | 452 | break; |
@@ -419,11 +455,12 @@ static int copy_move_directory(struct file_op_params *src, | |||
419 | DEBUGF("Copy %s to %s\n", src->path, dst->path); | 455 | DEBUGF("Copy %s to %s\n", src->path, dst->path); |
420 | 456 | ||
421 | if (info.attribute & ATTR_DIRECTORY) { | 457 | if (info.attribute & ATTR_DIRECTORY) { |
458 | src->processed_size += info.size; | ||
422 | /* Copy/move a subdirectory */ | 459 | /* Copy/move a subdirectory */ |
423 | rc = copy_move_directory(src, dst, flags); /* recursion */; | 460 | rc = copy_move_directory(src, dst, flags); /* recursion */; |
424 | } else { | 461 | } else { |
425 | /* Copy/move a file */ | 462 | /* Copy/move a file */ |
426 | rc = copy_move_file(src->path, dst->path, flags); | 463 | rc = copy_move_file(src, dst->path, flags); |
427 | } | 464 | } |
428 | 465 | ||
429 | /* Remove basenames we added above */ | 466 | /* Remove basenames we added above */ |
@@ -484,7 +521,7 @@ int copy_move_fileobject(const char *src_path, const char *dst_path, unsigned in | |||
484 | if (src.is_dir) { | 521 | if (src.is_dir) { |
485 | /* Copy or move a subdirectory */ | 522 | /* Copy or move a subdirectory */ |
486 | /* Try renaming first */ | 523 | /* Try renaming first */ |
487 | rc = move_by_rename(src.path, dst.path, &flags); | 524 | rc = move_by_rename(&src, dst.path, &flags); |
488 | if (rc < FORC_SUCCESS) { | 525 | if (rc < FORC_SUCCESS) { |
489 | rc = check_count_fileobjects(&src); | 526 | rc = check_count_fileobjects(&src); |
490 | if (rc == FORC_SUCCESS) { | 527 | if (rc == FORC_SUCCESS) { |
@@ -493,7 +530,7 @@ int copy_move_fileobject(const char *src_path, const char *dst_path, unsigned in | |||
493 | } | 530 | } |
494 | } else { | 531 | } else { |
495 | /* Copy or move a file */ | 532 | /* Copy or move a file */ |
496 | rc = copy_move_file(src_path, dst.path, flags); | 533 | rc = copy_move_file(&src, dst.path, flags); |
497 | } | 534 | } |
498 | 535 | ||
499 | cpu_boost(false); | 536 | cpu_boost(false); |
@@ -533,6 +570,12 @@ int delete_fileobject(const char *selected_file) | |||
533 | if (param.append >= sizeof (param.path)) | 570 | if (param.append >= sizeof (param.path)) |
534 | return FORC_PATH_TOO_LONG; | 571 | return FORC_PATH_TOO_LONG; |
535 | 572 | ||
573 | /* Note: delete_fileobject() will happily delete whatever | ||
574 | * path is passed (after confirmation) */ | ||
575 | if (confirm_delete_yesno(param.path) != YESNO_YES) { | ||
576 | return FORC_CANCELLED; | ||
577 | } | ||
578 | |||
536 | if (param.is_dir) { | 579 | if (param.is_dir) { |
537 | int rc = check_count_fileobjects(¶m); | 580 | int rc = check_count_fileobjects(¶m); |
538 | DEBUGF("%s res: %d, ct: %d, %s", __func__, rc, param.objects, param.path); | 581 | DEBUGF("%s res: %d, ct: %d, %s", __func__, rc, param.objects, param.path); |
@@ -540,15 +583,7 @@ int delete_fileobject(const char *selected_file) | |||
540 | return rc; | 583 | return rc; |
541 | } | 584 | } |
542 | 585 | ||
543 | /* Note: delete_fileobject() will happily delete whatever | ||
544 | * path is passed (after confirmation) */ | ||
545 | if (confirm_delete_yesno(param.path) != YESNO_YES) { | ||
546 | return FORC_CANCELLED; | ||
547 | } | ||
548 | |||
549 | clear_screen_buffer(true); | 586 | clear_screen_buffer(true); |
550 | if (poll_cancel_action(param.path, FOC_DELETE, param.processed, param.objects)) | ||
551 | return FORC_CANCELLED; | ||
552 | 587 | ||
553 | if (param.is_dir) { /* if directory */ | 588 | if (param.is_dir) { /* if directory */ |
554 | cpu_boost(true); | 589 | cpu_boost(true); |