summaryrefslogtreecommitdiff
path: root/apps/fileop.c
diff options
context:
space:
mode:
Diffstat (limited to 'apps/fileop.c')
-rw-r--r--apps/fileop.c344
1 files changed, 168 insertions, 176 deletions
diff --git a/apps/fileop.c b/apps/fileop.c
index 0d2dc774b9..35bd9f2241 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
@@ -50,6 +50,17 @@ struct file_op_params
50 size_t append; /* Append position in 'path' for stack push */ 50 size_t append; /* Append position in 'path' for stack push */
51}; 51};
52 52
53static int prompt_name(char* buf, size_t bufsz)
54{
55 if (kbd_input(buf, bufsz, NULL) < 0)
56 return FORC_CANCELLED;
57 /* at least prevent escapes out of the base directory from keyboard-
58 entered filenames; the file code should reject other invalidities */
59 if (*buf != '\0' && !strchr(buf, PATH_SEPCH) && !is_dotdir_name(buf))
60 return FORC_SUCCESS;
61 return FORC_UNKNOWN_FAILURE;
62}
63
53static bool poll_cancel_action(const char *path, int operation, int current, int total) 64static bool poll_cancel_action(const char *path, int operation, int current, int total)
54{ 65{
55 const char *op_str = ""; 66 const char *op_str = "";
@@ -75,7 +86,7 @@ static bool poll_cancel_action(const char *path, int operation, int current, int
75 return ACTION_STD_CANCEL == get_action(CONTEXT_STD, TIMEOUT_NOBLOCK); 86 return ACTION_STD_CANCEL == get_action(CONTEXT_STD, TIMEOUT_NOBLOCK);
76} 87}
77 88
78static struct file_op_params* init_file_op(struct file_op_params *param, 89static void init_file_op(struct file_op_params *param,
79 const char *basename, 90 const char *basename,
80 const char *selected_file) 91 const char *selected_file)
81{ 92{
@@ -90,8 +101,6 @@ static struct file_op_params* init_file_op(struct file_op_params *param,
90 param->is_dir = dir_exists(param->path); 101 param->is_dir = dir_exists(param->path);
91 param->objects = 0; /* how many files and subdirectories*/ 102 param->objects = 0; /* how many files and subdirectories*/
92 param->processed = 0; 103 param->processed = 0;
93
94 return param;
95} 104}
96 105
97/* counts file objects, deletes file objects */ 106/* counts file objects, deletes file objects */
@@ -144,7 +153,7 @@ static int directory_fileop(struct file_op_params *param, enum file_op_current f
144 153
145 if (info.attribute & ATTR_DIRECTORY) { 154 if (info.attribute & ATTR_DIRECTORY) {
146 /* remove a subdirectory */ 155 /* remove a subdirectory */
147 rc = directory_fileop(param, fileop); 156 rc = directory_fileop(param, fileop); /* recursion */
148 } else { 157 } else {
149 /* remove a file */ 158 /* remove a file */
150 if (poll_cancel_action(param->path, FOC_DELETE, param->processed, param->objects)) 159 if (poll_cancel_action(param->path, FOC_DELETE, param->processed, param->objects))
@@ -165,8 +174,8 @@ static int directory_fileop(struct file_op_params *param, enum file_op_current f
165 } 174 }
166 175
167 if (info.attribute & ATTR_DIRECTORY) { 176 if (info.attribute & ATTR_DIRECTORY) {
168 /* remove a subdirectory */ 177 /* enter subdirectory */
169 rc = directory_fileop(param, FOC_COUNT); 178 rc = directory_fileop(param, FOC_COUNT); /* recursion */
170 } else { 179 } else {
171 if (poll_cancel_action(param->path, FOC_COUNT, param->objects, 0)) 180 if (poll_cancel_action(param->path, FOC_COUNT, param->objects, 0))
172 { 181 {
@@ -195,150 +204,42 @@ static int directory_fileop(struct file_op_params *param, enum file_op_current f
195 return rc; 204 return rc;
196} 205}
197 206
207/* Walk a directory tree and count the number of objects (dirs & files)
208 * also check that enough resources exist to do an operation */
198static int check_count_fileobjects(struct file_op_params *param) 209static int check_count_fileobjects(struct file_op_params *param)
199{ 210{
211 cpu_boost(true);
200 int rc = directory_fileop(param, FOC_COUNT); 212 int rc = directory_fileop(param, FOC_COUNT);
213 cpu_boost(false);
201 DEBUGF("%s res:(%d) objects %d \n", __func__, rc, param->objects); 214 DEBUGF("%s res:(%d) objects %d \n", __func__, rc, param->objects);
202 return rc; 215 return rc;
203} 216}
204 217
205static bool check_new_name(const char *basename) 218/* Attempt to just rename a file or directory */
206{
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, 219static int move_by_rename(const char *src_path,
309 const char *dst_path, 220 const char *dst_path,
310 unsigned int *pflags) 221 unsigned int *pflags)
311{ 222{
312 unsigned int flags = *pflags; 223 unsigned int flags = *pflags;
313 int rc = FORC_UNKNOWN_FAILURE; 224 int rc = FORC_UNKNOWN_FAILURE;
314 while (!(flags & (PASTE_COPY | PASTE_EXDEV))) { 225 if (!(flags & (PASTE_COPY | PASTE_EXDEV))) {
315 if ((flags & PASTE_OVERWRITE) || !file_exists(dst_path)) { 226 if ((flags & PASTE_OVERWRITE) || !file_exists(dst_path)) {
316 /* Just try to move the directory / file */ 227 /* Just try to move the directory / file */
317 if (poll_cancel_action(src_path, FOC_MOVE, 0 , 0)) { 228 if (poll_cancel_action(src_path, FOC_MOVE, 0 , 0)) {
318 rc = FORC_CANCELLED; 229 rc = FORC_CANCELLED;
319 } else { 230 } else {
320 rc = rename(src_path, dst_path); 231 rc = rename(src_path, dst_path);
321 } 232#ifdef HAVE_MULTIVOLUME
322 233 if (rc < FORC_SUCCESS && errno == EXDEV) {
323 if (rc < 0) { 234 /* Failed because cross volume rename doesn't work */
324 int errnum = errno; 235 *pflags |= PASTE_EXDEV; /* force a move instead */
325 if (errnum == ENOTEMPTY && (flags & PASTE_OVERWRITE)) {
326 /* Directory is not empty thus rename() will not do a quick
327 overwrite */
328 break;
329 } 236 }
330 #ifdef HAVE_MULTIVOLUME 237#endif /* HAVE_MULTIVOLUME */
331 else if (errnum == EXDEV) { 238 /* if (errno == ENOTEMPTY && (flags & PASTE_OVERWRITE)) {
332 /* Failed because cross volume rename doesn't work; force 239 * Directory is not empty thus rename() will not do a quick overwrite */
333 a move instead */
334 *pflags |= PASTE_EXDEV;
335 break;
336 }
337 #endif /* HAVE_MULTIVOLUME */
338 } 240 }
339 } 241 }
340 242
341 break;
342 } 243 }
343 return rc; 244 return rc;
344} 245}
@@ -365,8 +266,7 @@ static int copy_move_file(const char *src_path, const char *dst_path, unsigned i
365 return FORC_NO_BUFFER_AVAIL; 266 return FORC_NO_BUFFER_AVAIL;
366 } 267 }
367 268
368 buffersize &= ~0x1ff; /* Round buffer size to multiple of sector 269 buffersize &= ~0x1ff; /* Round buffer size to multiple of sector size */
369 size */
370 270
371 int src_fd = open(src_path, O_RDONLY); 271 int src_fd = open(src_path, O_RDONLY);
372 if (src_fd >= 0) { 272 if (src_fd >= 0) {
@@ -423,9 +323,12 @@ static int copy_move_file(const char *src_path, const char *dst_path, unsigned i
423 } 323 }
424 324
425 if (rc == FORC_SUCCESS) { 325 if (rc == FORC_SUCCESS) {
426 /* If overwriting, set the correct length if original was 326 if (total_size != src_sz)
427 longer */ 327 rc = FORC_UNKNOWN_FAILURE;
428 rc = ftruncate(dst_fd, total_size) * 10; 328 else {
329 /* If overwriting, set the correct length if original was longer */
330 rc = ftruncate(dst_fd, total_size) * 10;
331 }
429 } 332 }
430 333
431 close(dst_fd); 334 close(dst_fd);
@@ -449,20 +352,19 @@ static int copy_move_file(const char *src_path, const char *dst_path, unsigned i
449 352
450/* Paste a directory */ 353/* Paste a directory */
451static int copy_move_directory(struct file_op_params *src, 354static int copy_move_directory(struct file_op_params *src,
452 struct file_op_params *dst, 355 struct file_op_params *dst,
453 unsigned int flags) 356 unsigned int flags)
454{ 357{
455 int rc = FORC_UNKNOWN_FAILURE;
456
457 DIR *srcdir = opendir(src->path); 358 DIR *srcdir = opendir(src->path);
458 359
459 if (srcdir) { 360 if (!srcdir)
460 /* Make a directory to copy things to */ 361 return FORC_PATH_NOT_EXIST;
461 rc = mkdir(dst->path) * 10; 362
462 if (rc < 0 && errno == EEXIST && (flags & PASTE_OVERWRITE)) { 363 /* Make a directory to copy things to */
463 /* Exists and overwrite was approved */ 364 int rc = mkdir(dst->path) * 10;
464 rc = FORC_SUCCESS; 365 if (rc < 0 && errno == EEXIST && (flags & PASTE_OVERWRITE)) {
465 } 366 /* Exists and overwrite was approved */
367 rc = FORC_SUCCESS;
466 } 368 }
467 369
468 size_t srcap = src->append, dstap = dst->append; 370 size_t srcap = src->append, dstap = dst->append;
@@ -488,7 +390,7 @@ static int copy_move_directory(struct file_op_params *src,
488 /* Append names to current directories */ 390 /* Append names to current directories */
489 src->append = srcap + 391 src->append = srcap +
490 path_append(&src->path[srcap], PA_SEP_HARD, entry->d_name, 392 path_append(&src->path[srcap], PA_SEP_HARD, entry->d_name,
491 sizeof(src->path) - srcap); 393 sizeof (src->path) - srcap);
492 394
493 dst->append = dstap + 395 dst->append = dstap +
494 path_append(&dst->path[dstap], PA_SEP_HARD, entry->d_name, 396 path_append(&dst->path[dstap], PA_SEP_HARD, entry->d_name,
@@ -538,13 +440,16 @@ static int copy_move_directory(struct file_op_params *src,
538 return rc; 440 return rc;
539} 441}
540 442
443/************************************************************************************/
444/* PUBLIC FUNCTIONS */
445/************************************************************************************/
446
447/* 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) 448int copy_move_fileobject(const char *src_path, const char *dst_path, unsigned int flags)
542{ 449{
543 if (!src_path[0]) 450 if (!src_path[0])
544 return FORC_NOOP; 451 return FORC_NOOP;
545 452
546 int rc = FORC_UNKNOWN_FAILURE;
547
548 struct file_op_params src, dst; 453 struct file_op_params src, dst;
549 454
550 /* Figure out the name of the selection */ 455 /* Figure out the name of the selection */
@@ -553,40 +458,37 @@ int copy_move_fileobject(const char *src_path, const char *dst_path, unsigned in
553 458
554 /* Final target is current directory plus name of selection */ 459 /* Final target is current directory plus name of selection */
555 init_file_op(&dst, dst_path, nameptr); 460 init_file_op(&dst, dst_path, nameptr);
461 if (dst.append >= sizeof (dst.path))
462 return FORC_PATH_TOO_LONG;
556 463
557 switch (dst.append < sizeof (dst.path) ? 464 int rel = relate(src_path, dst.path);
558 relate(src_path, dst.path) : FORC_PATH_TOO_LONG) 465 if (rel == RELATE_SAME)
559 { 466 return FORC_NOOP;
560 case RELATE_SAME:
561 rc = FORC_NOOP;
562 break;
563 467
564 case RELATE_DIFFERENT: 468 if (rel == RELATE_DIFFERENT) {
469 int rc;
565 if (file_exists(dst.path)) { 470 if (file_exists(dst.path)) {
566 /* If user chooses not to overwrite, cancel */ 471 /* If user chooses not to overwrite, cancel */
567 if (confirm_overwrite_yesno() == YESNO_NO) { 472 if (confirm_overwrite_yesno() == YESNO_NO) {
568 rc = FORC_NOOVERWRT; 473 return FORC_NOOVERWRT;
569 break;
570 } 474 }
571 475
572 flags |= PASTE_OVERWRITE; 476 flags |= PASTE_OVERWRITE;
573 } 477 }
574 478
479 init_file_op(&src, src_path, NULL);
480 if (src.append >= sizeof (src.path))
481 return FORC_PATH_TOO_LONG;
575 /* Now figure out what we're doing */ 482 /* Now figure out what we're doing */
576 cpu_boost(true); 483 cpu_boost(true);
577
578 init_file_op(&src, src_path, NULL);
579
580 if (src.is_dir) { 484 if (src.is_dir) {
581 /* Copy or move a subdirectory */ 485 /* Copy or move a subdirectory */
582 486 /* Try renaming first */
583 if (src.append < sizeof (src.path)) { 487 rc = move_by_rename(src.path, dst.path, &flags);
584 /* Try renaming first */ 488 if (rc < FORC_SUCCESS) {
585 rc = move_by_rename(src.path, dst.path, &flags); 489 rc = check_count_fileobjects(&src);
586 if (rc != FORC_SUCCESS && rc != FORC_CANCELLED) { 490 if (rc == FORC_SUCCESS) {
587 if (check_count_fileobjects(&src) == FORC_SUCCESS) { 491 rc = copy_move_directory(&src, &dst, flags);
588 rc = copy_move_directory(&src, &dst, flags);
589 }
590 } 492 }
591 } 493 }
592 } else { 494 } else {
@@ -595,12 +497,102 @@ int copy_move_fileobject(const char *src_path, const char *dst_path, unsigned in
595 } 497 }
596 498
597 cpu_boost(false); 499 cpu_boost(false);
598 break; 500 DEBUGF("%s res: %d, ct: %d/%d %s\n",
501 __func__, rc, src.objects, src.processed, src.path);
502 return rc;
503 }
504
505 /* Else Some other relation / failure */
506 DEBUGF("%s res: %d, rel: %d\n", __func__, FORC_UNKNOWN_FAILURE, rel);
507 return FORC_UNKNOWN_FAILURE;
508}
509
510int create_dir(void)
511{
512 int rc;
513 char dirname[MAX_PATH];
514 size_t pathlen = path_append(dirname, getcwd(NULL, 0), PA_SEP_HARD,
515 sizeof (dirname));
516 char *basename = dirname + pathlen;
517
518 if (pathlen >= sizeof (dirname))
519 return FORC_PATH_TOO_LONG;
520
521 rc = prompt_name(basename, sizeof (dirname) - pathlen);
522 if (rc == FORC_SUCCESS)
523 rc = mkdir(dirname) * 10;
524 return rc;
525}
599 526
600 case RELATE_PREFIX: 527/* share code for file and directory deletion, saves space */
601 default: /* Some other relation / failure */ 528int delete_fileobject(const char *selected_file)
602 break; 529{
530 int rc;
531 struct file_op_params param;
532 init_file_op(&param, selected_file, NULL);
533 if (param.append >= sizeof (param.path))
534 return FORC_PATH_TOO_LONG;
535
536 if (param.is_dir) {
537 int rc = check_count_fileobjects(&param);
538 DEBUGF("%s res: %d, ct: %d, %s", __func__, rc, param.objects, param.path);
539 if (rc != FORC_SUCCESS)
540 return rc;
541 }
542
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);
550 if (poll_cancel_action(param.path, FOC_DELETE, param.processed, param.objects))
551 return FORC_CANCELLED;
552
553 if (param.is_dir) { /* if directory */
554 cpu_boost(true);
555 rc = directory_fileop(&param, FOC_DELETE);
556 cpu_boost(false);
557 } else {
558 rc = remove(param.path) * 10;
603 } 559 }
604 560
605 return rc; 561 return rc;
606} 562}
563
564int rename_file(const char *selected_file)
565{
566 int rc;
567 char newname[MAX_PATH];
568 const char *oldbase, *selection = selected_file;
569
570 path_basename(selection, &oldbase);
571 size_t pathlen = oldbase - selection;
572 char *newbase = newname + pathlen;
573
574 if (strmemccpy(newname, selection, sizeof (newname)) == NULL)
575 return FORC_PATH_TOO_LONG;
576
577 rc = prompt_name(newbase, sizeof (newname) - pathlen);
578
579 if (rc != FORC_SUCCESS)
580 return rc;
581
582 if (!strcmp(oldbase, newbase))
583 return FORC_NOOP; /* No change at all */
584
585 int rel = relate(selection, newname);
586 if (rel == RELATE_DIFFERENT)
587 {
588 if (file_exists(newname)) { /* don't overwrite */
589 return FORC_PATH_EXISTS;
590 }
591 return rename(selection, newname) * 10;
592 }
593 if (rel == RELATE_SAME)
594 return rename(selection, newname) * 10;
595
596 /* Else Some other relation / failure */
597 return FORC_UNKNOWN_FAILURE;
598}