summaryrefslogtreecommitdiff
path: root/apps/fileop.c
diff options
context:
space:
mode:
Diffstat (limited to 'apps/fileop.c')
-rw-r--r--apps/fileop.c475
1 files changed, 255 insertions, 220 deletions
diff --git a/apps/fileop.c b/apps/fileop.c
index 0d2dc774b9..bcd5202cf4 100644
--- a/apps/fileop.c
+++ b/apps/fileop.c
@@ -1,10 +1,10 @@
1/*************************************************************************** 1/***************************************************************************
2 * __________ __ ___. 2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___ 3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / 4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < 5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ 6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/ 7 * \/ \/ \/ \/ \/
8 * $Id$ 8 * $Id$
9 * 9 *
10 * Copyright (C) 2002 Björn Stenberg 10 * Copyright (C) 2002 Björn Stenberg
@@ -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,38 +45,77 @@
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 bool poll_cancel_action(const char *path, int operation, int current, int total) 58static int prompt_name(char* buf, size_t bufsz)
54{ 59{
55 const char *op_str = ""; 60 if (kbd_input(buf, bufsz, NULL) < 0)
56 61 return FORC_CANCELLED;
57 clear_screen_buffer(false); 62 /* at least prevent escapes out of the base directory from keyboard-
58 63 entered filenames; the file code should reject other invalidities */
59 if (operation == FOC_COPY) 64 if (*buf != '\0' && !strchr(buf, PATH_SEPCH) && !is_dotdir_name(buf))
60 op_str = str(LANG_COPYING); 65 return FORC_SUCCESS;
61 else if (operation == FOC_MOVE) 66 return FORC_UNKNOWN_FAILURE;
62 op_str = str(LANG_MOVING); 67}
63 else if (operation == FOC_COUNT)
64 op_str = str(LANG_SCANNING_DISK);
65 else if (operation == FOC_DELETE)
66 op_str = str(LANG_DELETING);
67 68
68 path_basename(path, &path); 69static bool poll_cancel_action(int operation, struct file_op_params *param)
70{
71 static unsigned long last_tick;
69 72
70 if (total <= 0) 73 if (operation == FOC_COUNT)
71 splashf(0, "%s (%d) %s", op_str, current, path); 74 {
75 if (param->objects <= 1)
76 last_tick = current_tick;
77 else if (TIME_AFTER(current_tick, last_tick + HZ/2))
78 {
79 clear_screen_buffer(false);
80 splashf(0, "%s (%d)", str(LANG_SCANNING_DISK), param->objects);
81 last_tick = current_tick;
82 }
83 }
72 else 84 else
73 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);
74 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 }
75 return ACTION_STD_CANCEL == get_action(CONTEXT_STD, TIMEOUT_NOBLOCK); 115 return ACTION_STD_CANCEL == get_action(CONTEXT_STD, TIMEOUT_NOBLOCK);
76} 116}
77 117
78static struct file_op_params* init_file_op(struct file_op_params *param, 118static void init_file_op(struct file_op_params *param,
79 const char *basename, 119 const char *basename,
80 const char *selected_file) 120 const char *selected_file)
81{ 121{
@@ -83,15 +123,21 @@ static struct file_op_params* init_file_op(struct file_op_params *param,
83 if (selected_file == NULL) 123 if (selected_file == NULL)
84 { 124 {
85 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;
86 } 128 }
87 else 129 else
130 {
88 param->append = path_append(param->path, basename, 131 param->append = path_append(param->path, basename,
89 selected_file, sizeof (param->path)); 132 selected_file, sizeof (param->path));
133 param->toplevel_name = selected_file;
134 }
90 param->is_dir = dir_exists(param->path); 135 param->is_dir = dir_exists(param->path);
136 param->extra_len = 0;
91 param->objects = 0; /* how many files and subdirectories*/ 137 param->objects = 0; /* how many files and subdirectories*/
92 param->processed = 0; 138 param->processed = 0;
93 139 param->total_size = 0;
94 return param; 140 param->processed_size = 0;
95} 141}
96 142
97/* counts file objects, deletes file objects */ 143/* counts file objects, deletes file objects */
@@ -144,10 +190,10 @@ static int directory_fileop(struct file_op_params *param, enum file_op_current f
144 190
145 if (info.attribute & ATTR_DIRECTORY) { 191 if (info.attribute & ATTR_DIRECTORY) {
146 /* remove a subdirectory */ 192 /* remove a subdirectory */
147 rc = directory_fileop(param, fileop); 193 rc = directory_fileop(param, fileop); /* recursion */
148 } else { 194 } else {
149 /* remove a file */ 195 /* remove a file */
150 if (poll_cancel_action(param->path, FOC_DELETE, param->processed, param->objects)) 196 if (poll_cancel_action(FOC_DELETE, param))
151 { 197 {
152 rc = FORC_CANCELLED; 198 rc = FORC_CANCELLED;
153 break; 199 break;
@@ -158,21 +204,22 @@ static int directory_fileop(struct file_op_params *param, enum file_op_current f
158 else /* count objects */ 204 else /* count objects */
159 { 205 {
160 param->objects++; 206 param->objects++;
207 param->total_size += info.size;
161 208
162 if (param->append >= sizeof (param->path)) { 209 if (poll_cancel_action(FOC_COUNT, param))
210 {
211 rc = FORC_CANCELLED;
212 break;
213 }
214
215 if (param->append + param->extra_len >= sizeof (param->path)) {
163 rc = FORC_PATH_TOO_LONG; 216 rc = FORC_PATH_TOO_LONG;
164 break; /* no space left in buffer */ 217 break; /* no space left in buffer */
165 } 218 }
166 219
167 if (info.attribute & ATTR_DIRECTORY) { 220 if (info.attribute & ATTR_DIRECTORY) {
168 /* remove a subdirectory */ 221 /* enter subdirectory */
169 rc = directory_fileop(param, FOC_COUNT); 222 rc = directory_fileop(param, FOC_COUNT); /* recursion */
170 } else {
171 if (poll_cancel_action(param->path, FOC_COUNT, param->objects, 0))
172 {
173 rc = FORC_CANCELLED;
174 break;
175 }
176 } 223 }
177 } 224 }
178 param->append = append; /* other functions may use param, reset append */ 225 param->append = append; /* other functions may use param, reset append */
@@ -184,7 +231,7 @@ static int directory_fileop(struct file_op_params *param, enum file_op_current f
184 231
185 if (fileop == FOC_DELETE && rc == FORC_SUCCESS) { 232 if (fileop == FOC_DELETE && rc == FORC_SUCCESS) {
186 /* remove the now empty directory */ 233 /* remove the now empty directory */
187 if (poll_cancel_action(param->path, FOC_DELETE, param->processed, param->objects)) 234 if (poll_cancel_action(FOC_DELETE, param))
188 { 235 {
189 rc = FORC_CANCELLED; 236 rc = FORC_CANCELLED;
190 } else { 237 } else {
@@ -195,161 +242,54 @@ static int directory_fileop(struct file_op_params *param, enum file_op_current f
195 return rc; 242 return rc;
196} 243}
197 244
245/* Walk a directory tree and count the number of objects (dirs & files)
246 * also check that enough resources exist to do an operation */
198static int check_count_fileobjects(struct file_op_params *param) 247static int check_count_fileobjects(struct file_op_params *param)
199{ 248{
249 cpu_boost(true);
200 int rc = directory_fileop(param, FOC_COUNT); 250 int rc = directory_fileop(param, FOC_COUNT);
251 cpu_boost(false);
201 DEBUGF("%s res:(%d) objects %d \n", __func__, rc, param->objects); 252 DEBUGF("%s res:(%d) objects %d \n", __func__, rc, param->objects);
202 return rc; 253 return rc;
203} 254}
204 255
205static bool check_new_name(const char *basename) 256/* Attempt to just rename a file or directory */
206{ 257static int move_by_rename(struct file_op_params *src,
207 /* at least prevent escapes out of the base directory from keyboard-
208 entered filenames; the file code should reject other invalidities */
209 return *basename != '\0' && !strchr(basename, PATH_SEPCH) &&
210 !is_dotdir_name(basename);
211}
212
213int create_dir(void)
214{
215 int rc = FORC_UNKNOWN_FAILURE;
216 char dirname[MAX_PATH];
217 size_t pathlen = path_append(dirname, getcwd(NULL, 0), PA_SEP_HARD,
218 sizeof (dirname));
219 char *basename = dirname + pathlen;
220
221 if (pathlen >= sizeof (dirname)) {
222 /* Too long */
223 } else if (kbd_input(basename, sizeof (dirname) - pathlen, NULL) < 0) {
224 rc = FORC_CANCELLED;
225 } else if (check_new_name(basename)) {
226 rc = mkdir(dirname);
227 }
228
229 return rc;
230}
231
232/************************************************************************************/
233/* share code for file and directory deletion, saves space */
234static int delete_file_dir(struct file_op_params *param)
235{
236 /* Note: delete_file_dir() will happily delete whatever
237 * path is passed (after confirmation) */
238 if (confirm_delete_yesno(param->path) != YESNO_YES) {
239 return FORC_CANCELLED;
240 }
241
242 clear_screen_buffer(true);
243 poll_cancel_action(param->path, FOC_DELETE, param->processed, param->objects);
244
245 int rc = FORC_UNKNOWN_FAILURE;
246
247 if (param->is_dir) { /* if directory */
248 cpu_boost(true);
249 rc = directory_fileop(param, FOC_DELETE);
250 cpu_boost(false);
251 } else {
252 rc = remove(param->path);
253 }
254
255 return rc;
256}
257
258int delete_fileobject(const char *selected_file)
259{
260 struct file_op_params param;
261 if (init_file_op(&param, selected_file, NULL)->is_dir == true)
262 {
263 int rc = check_count_fileobjects(&param);
264 DEBUGF("%s res: %d, ct: %d, %s", __func__, rc, param.objects, param.path);
265 if (rc != FORC_SUCCESS)
266 return rc;
267 }
268
269 return delete_file_dir(&param);
270}
271
272int rename_file(const char *selected_file)
273{
274 int rc = FORC_UNKNOWN_FAILURE;
275 char newname[MAX_PATH];
276 const char *oldbase, *selection = selected_file;
277
278 path_basename(selection, &oldbase);
279 size_t pathlen = oldbase - selection;
280 char *newbase = newname + pathlen;
281
282 if (strmemccpy(newname, selection, sizeof (newname)) == NULL) {
283 /* Too long */
284 } else if (kbd_input(newbase, sizeof (newname) - pathlen, NULL) < 0) {
285 rc = FORC_CANCELLED;
286 } else if (!strcmp(oldbase, newbase)) {
287 rc = FORC_NOOP; /* No change at all */
288 } else if (check_new_name(newbase)) {
289 switch (relate(selection, newname))
290 {
291 case RELATE_DIFFERENT:
292 if (file_exists(newname)) {
293 break; /* don't overwrite */
294 }
295 /* Fall-through */
296 case RELATE_SAME:
297 rc = rename(selection, newname);
298 break;
299 case RELATE_PREFIX:
300 default:
301 break;
302 }
303 }
304
305 return rc;
306}
307
308static int move_by_rename(const char *src_path,
309 const char *dst_path, 258 const char *dst_path,
310 unsigned int *pflags) 259 unsigned int *pflags)
311{ 260{
312 unsigned int flags = *pflags; 261 unsigned int flags = *pflags;
313 int rc = FORC_UNKNOWN_FAILURE; 262 int rc = FORC_UNKNOWN_FAILURE;
314 while (!(flags & (PASTE_COPY | PASTE_EXDEV))) { 263 reset_poweroff_timer();
264 if (!(flags & (PASTE_COPY | PASTE_EXDEV))) {
315 if ((flags & PASTE_OVERWRITE) || !file_exists(dst_path)) { 265 if ((flags & PASTE_OVERWRITE) || !file_exists(dst_path)) {
316 /* Just try to move the directory / file */ 266 /* Just try to move the directory / file */
317 if (poll_cancel_action(src_path, FOC_MOVE, 0 , 0)) { 267 rc = rename(src->path, dst_path);
318 rc = FORC_CANCELLED; 268#ifdef HAVE_MULTIVOLUME
319 } else { 269 if (rc < FORC_SUCCESS && errno == EXDEV) {
320 rc = rename(src_path, dst_path); 270 /* Failed because cross volume rename doesn't work */
321 } 271 *pflags |= PASTE_EXDEV; /* force a move instead */
322
323 if (rc < 0) {
324 int errnum = errno;
325 if (errnum == ENOTEMPTY && (flags & PASTE_OVERWRITE)) {
326 /* Directory is not empty thus rename() will not do a quick
327 overwrite */
328 break;
329 }
330 #ifdef HAVE_MULTIVOLUME
331 else if (errnum == EXDEV) {
332 /* Failed because cross volume rename doesn't work; force
333 a move instead */
334 *pflags |= PASTE_EXDEV;
335 break;
336 }
337 #endif /* HAVE_MULTIVOLUME */
338 } 272 }
273#endif /* HAVE_MULTIVOLUME */
274 /* if (errno == ENOTEMPTY && (flags & PASTE_OVERWRITE)) {
275 * Directory is not empty thus rename() will not do a quick overwrite */
339 } 276 }
340 277
341 break;
342 } 278 }
343 return rc; 279 return rc;
344} 280}
345 281
346/* Paste a file */ 282/* Paste a file */
347static 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)
348{ 285{
349 /* Try renaming first */ 286 /* Try renaming first */
350 int rc = move_by_rename(src_path, dst_path, &flags); 287 int rc = move_by_rename(src, dst_path, &flags);
351 if (rc == FORC_SUCCESS) 288 if (rc == FORC_SUCCESS)
289 {
290 src->total_size = 0; /* switch from counting size to number of items */
352 return rc; 291 return rc;
292 }
353 293
354 /* 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 */
355 size_t buffersize; 295 size_t buffersize;
@@ -365,12 +305,13 @@ static int copy_move_file(const char *src_path, const char *dst_path, unsigned i
365 return FORC_NO_BUFFER_AVAIL; 305 return FORC_NO_BUFFER_AVAIL;
366 } 306 }
367 307
368 buffersize &= ~0x1ff; /* Round buffer size to multiple of sector 308 buffersize &= ~0x1ff; /* Round buffer size to multiple of sector size */
369 size */
370 309
371 int src_fd = open(src_path, O_RDONLY); 310 int src_fd = open(src->path, O_RDONLY);
372 if (src_fd >= 0) { 311 if (src_fd >= 0) {
373 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;
374 lseek(src_fd, 0, SEEK_SET); 315 lseek(src_fd, 0, SEEK_SET);
375 316
376 int oflag = O_WRONLY|O_CREAT; 317 int oflag = O_WRONLY|O_CREAT;
@@ -389,9 +330,8 @@ static int copy_move_file(const char *src_path, const char *dst_path, unsigned i
389 while (rc == FORC_SUCCESS) { 330 while (rc == FORC_SUCCESS) {
390 if (total_size >= next_cancel_test) { 331 if (total_size >= next_cancel_test) {
391 next_cancel_test = total_size + 0x10000; 332 next_cancel_test = total_size + 0x10000;
392 if (poll_cancel_action(src_path, 333 if (poll_cancel_action(!(flags & PASTE_COPY) ?
393 !(flags & PASTE_COPY) ? FOC_MOVE : FOC_COPY, 334 FOC_MOVE : FOC_COPY, src))
394 total_size, src_sz))
395 { 335 {
396 rc = FORC_CANCELLED; 336 rc = FORC_CANCELLED;
397 break; 337 break;
@@ -415,6 +355,7 @@ static int copy_move_file(const char *src_path, const char *dst_path, unsigned i
415 } 355 }
416 356
417 total_size += byteswritten; 357 total_size += byteswritten;
358 src->processed_size += byteswritten;
418 359
419 if (bytesread < (ssize_t)buffersize) { 360 if (bytesread < (ssize_t)buffersize) {
420 /* EOF with trailing bytes */ 361 /* EOF with trailing bytes */
@@ -423,9 +364,12 @@ static int copy_move_file(const char *src_path, const char *dst_path, unsigned i
423 } 364 }
424 365
425 if (rc == FORC_SUCCESS) { 366 if (rc == FORC_SUCCESS) {
426 /* If overwriting, set the correct length if original was 367 if (total_size != src_sz)
427 longer */ 368 rc = FORC_UNKNOWN_FAILURE;
428 rc = ftruncate(dst_fd, total_size) * 10; 369 else {
370 /* If overwriting, set the correct length if original was longer */
371 rc = ftruncate(dst_fd, total_size) * 10;
372 }
429 } 373 }
430 374
431 close(dst_fd); 375 close(dst_fd);
@@ -441,7 +385,7 @@ static int copy_move_file(const char *src_path, const char *dst_path, unsigned i
441 385
442 if (rc == FORC_SUCCESS && !(flags & PASTE_COPY)) { 386 if (rc == FORC_SUCCESS && !(flags & PASTE_COPY)) {
443 /* Remove the source file */ 387 /* Remove the source file */
444 rc = remove(src_path) * 10; 388 rc = remove(src->path) * 10;
445 } 389 }
446 390
447 return rc; 391 return rc;
@@ -449,20 +393,19 @@ static int copy_move_file(const char *src_path, const char *dst_path, unsigned i
449 393
450/* Paste a directory */ 394/* Paste a directory */
451static int copy_move_directory(struct file_op_params *src, 395static int copy_move_directory(struct file_op_params *src,
452 struct file_op_params *dst, 396 struct file_op_params *dst,
453 unsigned int flags) 397 unsigned int flags)
454{ 398{
455 int rc = FORC_UNKNOWN_FAILURE;
456
457 DIR *srcdir = opendir(src->path); 399 DIR *srcdir = opendir(src->path);
458 400
459 if (srcdir) { 401 if (!srcdir)
460 /* Make a directory to copy things to */ 402 return FORC_PATH_NOT_EXIST;
461 rc = mkdir(dst->path) * 10; 403
462 if (rc < 0 && errno == EEXIST && (flags & PASTE_OVERWRITE)) { 404 /* Make a directory to copy things to */
463 /* Exists and overwrite was approved */ 405 int rc = mkdir(dst->path) * 10;
464 rc = FORC_SUCCESS; 406 if (rc < 0 && errno == EEXIST && (flags & PASTE_OVERWRITE)) {
465 } 407 /* Exists and overwrite was approved */
408 rc = FORC_SUCCESS;
466 } 409 }
467 410
468 size_t srcap = src->append, dstap = dst->append; 411 size_t srcap = src->append, dstap = dst->append;
@@ -488,7 +431,7 @@ static int copy_move_directory(struct file_op_params *src,
488 /* Append names to current directories */ 431 /* Append names to current directories */
489 src->append = srcap + 432 src->append = srcap +
490 path_append(&src->path[srcap], PA_SEP_HARD, entry->d_name, 433 path_append(&src->path[srcap], PA_SEP_HARD, entry->d_name,
491 sizeof(src->path) - srcap); 434 sizeof (src->path) - srcap);
492 435
493 dst->append = dstap + 436 dst->append = dstap +
494 path_append(&dst->path[dstap], PA_SEP_HARD, entry->d_name, 437 path_append(&dst->path[dstap], PA_SEP_HARD, entry->d_name,
@@ -506,9 +449,8 @@ static int copy_move_directory(struct file_op_params *src,
506 break; 449 break;
507 } 450 }
508 451
509 if (poll_cancel_action(src->path, 452 if (poll_cancel_action(!(flags & PASTE_COPY) ?
510 !(flags & PASTE_COPY) ? FOC_MOVE : FOC_COPY, 453 FOC_MOVE : FOC_COPY, src))
511 src->processed, src->objects))
512 { 454 {
513 rc = FORC_CANCELLED; 455 rc = FORC_CANCELLED;
514 break; 456 break;
@@ -517,11 +459,12 @@ static int copy_move_directory(struct file_op_params *src,
517 DEBUGF("Copy %s to %s\n", src->path, dst->path); 459 DEBUGF("Copy %s to %s\n", src->path, dst->path);
518 460
519 if (info.attribute & ATTR_DIRECTORY) { 461 if (info.attribute & ATTR_DIRECTORY) {
462 src->processed_size += info.size;
520 /* Copy/move a subdirectory */ 463 /* Copy/move a subdirectory */
521 rc = copy_move_directory(src, dst, flags); /* recursion */; 464 rc = copy_move_directory(src, dst, flags); /* recursion */;
522 } else { 465 } else {
523 /* Copy/move a file */ 466 /* Copy/move a file */
524 rc = copy_move_file(src->path, dst->path, flags); 467 rc = copy_move_file(src, dst->path, flags);
525 } 468 }
526 469
527 /* Remove basenames we added above */ 470 /* Remove basenames we added above */
@@ -538,13 +481,16 @@ static int copy_move_directory(struct file_op_params *src,
538 return rc; 481 return rc;
539} 482}
540 483
484/************************************************************************************/
485/* PUBLIC FUNCTIONS */
486/************************************************************************************/
487
488/* Copy or move a file or directory see: file_op_flags */
541int copy_move_fileobject(const char *src_path, const char *dst_path, unsigned int flags) 489int copy_move_fileobject(const char *src_path, const char *dst_path, unsigned int flags)
542{ 490{
543 if (!src_path[0]) 491 if (!src_path[0])
544 return FORC_NOOP; 492 return FORC_NOOP;
545 493
546 int rc = FORC_UNKNOWN_FAILURE;
547
548 struct file_op_params src, dst; 494 struct file_op_params src, dst;
549 495
550 /* Figure out the name of the selection */ 496 /* Figure out the name of the selection */
@@ -553,54 +499,143 @@ int copy_move_fileobject(const char *src_path, const char *dst_path, unsigned in
553 499
554 /* Final target is current directory plus name of selection */ 500 /* Final target is current directory plus name of selection */
555 init_file_op(&dst, dst_path, nameptr); 501 init_file_op(&dst, dst_path, nameptr);
502 if (dst.append >= sizeof (dst.path))
503 return FORC_PATH_TOO_LONG;
556 504
557 switch (dst.append < sizeof (dst.path) ? 505 int rel = relate(src_path, dst.path);
558 relate(src_path, dst.path) : FORC_PATH_TOO_LONG) 506 if (rel == RELATE_SAME)
559 { 507 return FORC_NOOP;
560 case RELATE_SAME:
561 rc = FORC_NOOP;
562 break;
563 508
564 case RELATE_DIFFERENT: 509 if (rel == RELATE_DIFFERENT) {
510 int rc;
565 if (file_exists(dst.path)) { 511 if (file_exists(dst.path)) {
566 /* If user chooses not to overwrite, cancel */ 512 /* If user chooses not to overwrite, cancel */
567 if (confirm_overwrite_yesno() == YESNO_NO) { 513 if (confirm_overwrite_yesno() == YESNO_NO) {
568 rc = FORC_NOOVERWRT; 514 return FORC_NOOVERWRT;
569 break;
570 } 515 }
571 516
572 flags |= PASTE_OVERWRITE; 517 flags |= PASTE_OVERWRITE;
573 } 518 }
574 519
520 init_file_op(&src, src_path, NULL);
521 if (src.append >= sizeof (src.path))
522 return FORC_PATH_TOO_LONG;
575 /* Now figure out what we're doing */ 523 /* Now figure out what we're doing */
576 cpu_boost(true); 524 cpu_boost(true);
577
578 init_file_op(&src, src_path, NULL);
579
580 if (src.is_dir) { 525 if (src.is_dir) {
581 /* Copy or move a subdirectory */ 526 /* Copy or move a subdirectory */
582 527 /* Try renaming first */
583 if (src.append < sizeof (src.path)) { 528 rc = move_by_rename(&src, dst.path, &flags);
584 /* Try renaming first */ 529 if (rc < FORC_SUCCESS) {
585 rc = move_by_rename(src.path, dst.path, &flags); 530 int extra_len = dst.append - src.append;
586 if (rc != FORC_SUCCESS && rc != FORC_CANCELLED) { 531 if (extra_len > 0)
587 if (check_count_fileobjects(&src) == FORC_SUCCESS) { 532 src.extra_len = extra_len;
588 rc = copy_move_directory(&src, &dst, flags); 533
589 } 534 rc = check_count_fileobjects(&src);
535 if (rc == FORC_SUCCESS) {
536 rc = copy_move_directory(&src, &dst, flags);
590 } 537 }
591 } 538 }
592 } else { 539 } else {
593 /* Copy or move a file */ 540 /* Copy or move a file */
594 rc = copy_move_file(src_path, dst.path, flags); 541 rc = copy_move_file(&src, dst.path, flags);
595 } 542 }
596 543
597 cpu_boost(false); 544 cpu_boost(false);
598 break; 545 DEBUGF("%s res: %d, ct: %d/%d %s\n",
546 __func__, rc, src.objects, src.processed, src.path);
547 return rc;
548 }
549
550 /* Else Some other relation / failure */
551 DEBUGF("%s res: %d, rel: %d\n", __func__, FORC_UNKNOWN_FAILURE, rel);
552 return FORC_UNKNOWN_FAILURE;
553}
554
555int create_dir(void)
556{
557 int rc;
558 char dirname[MAX_PATH];
559 size_t pathlen = path_append(dirname, getcwd(NULL, 0), PA_SEP_HARD,
560 sizeof (dirname));
561 char *basename = dirname + pathlen;
562
563 if (pathlen >= sizeof (dirname))
564 return FORC_PATH_TOO_LONG;
565
566 rc = prompt_name(basename, sizeof (dirname) - pathlen);
567 if (rc == FORC_SUCCESS)
568 rc = mkdir(dirname) * 10;
569 return rc;
570}
571
572/* share code for file and directory deletion, saves space */
573int delete_fileobject(const char *selected_file)
574{
575 int rc;
576 struct file_op_params param;
577 init_file_op(&param, selected_file, NULL);
578 if (param.append >= sizeof (param.path))
579 return FORC_PATH_TOO_LONG;
599 580
600 case RELATE_PREFIX: 581 /* Note: delete_fileobject() will happily delete whatever
601 default: /* Some other relation / failure */ 582 * path is passed (after confirmation) */
602 break; 583 if (confirm_delete_yesno(param.path) != YESNO_YES) {
584 return FORC_CANCELLED;
585 }
586
587 if (param.is_dir) {
588 int rc = check_count_fileobjects(&param);
589 DEBUGF("%s res: %d, ct: %d, %s", __func__, rc, param.objects, param.path);
590 if (rc != FORC_SUCCESS)
591 return rc;
592 }
593
594 clear_screen_buffer(true);
595
596 if (param.is_dir) { /* if directory */
597 cpu_boost(true);
598 rc = directory_fileop(&param, FOC_DELETE);
599 cpu_boost(false);
600 } else {
601 rc = remove(param.path) * 10;
603 } 602 }
604 603
605 return rc; 604 return rc;
606} 605}
606
607int rename_file(const char *selected_file)
608{
609 int rc;
610 char newname[MAX_PATH];
611 const char *oldbase, *selection = selected_file;
612
613 path_basename(selection, &oldbase);
614 size_t pathlen = oldbase - selection;
615 char *newbase = newname + pathlen;
616
617 if (strmemccpy(newname, selection, sizeof (newname)) == NULL)
618 return FORC_PATH_TOO_LONG;
619
620 rc = prompt_name(newbase, sizeof (newname) - pathlen);
621
622 if (rc != FORC_SUCCESS)
623 return rc;
624
625 if (!strcmp(oldbase, newbase))
626 return FORC_NOOP; /* No change at all */
627
628 int rel = relate(selection, newname);
629 if (rel == RELATE_DIFFERENT)
630 {
631 if (file_exists(newname)) { /* don't overwrite */
632 return FORC_PATH_EXISTS;
633 }
634 return rename(selection, newname) * 10;
635 }
636 if (rel == RELATE_SAME)
637 return rename(selection, newname) * 10;
638
639 /* Else Some other relation / failure */
640 return FORC_UNKNOWN_FAILURE;
641}