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