|
| 1 | +#include "furi/log.h" |
1 | 2 | #include <furi/record.h> |
2 | 3 | #include <m-string.h> |
3 | 4 | #include "storage.h" |
4 | 5 | #include "storage_i.h" |
5 | 6 | #include "storage_message.h" |
6 | 7 | #include <toolbox/stream/file_stream.h> |
7 | 8 | #include <toolbox/dir_walk.h> |
| 9 | +#include "toolbox/path.h" |
8 | 10 |
|
9 | 11 | #define MAX_NAME_LENGTH 256 |
| 12 | +#define MAX_EXT_LEN 16 |
10 | 13 |
|
11 | 14 | #define TAG "StorageAPI" |
12 | 15 |
|
@@ -436,6 +439,131 @@ FS_Error storage_common_copy(Storage* storage, const char* old_path, const char* |
436 | 439 | return error; |
437 | 440 | } |
438 | 441 |
|
| 442 | +static FS_Error |
| 443 | + storage_merge_recursive(Storage* storage, const char* old_path, const char* new_path) { |
| 444 | + FS_Error error = storage_common_mkdir(storage, new_path); |
| 445 | + DirWalk* dir_walk = dir_walk_alloc(storage); |
| 446 | + string_t path; |
| 447 | + string_t tmp_new_path; |
| 448 | + string_t tmp_old_path; |
| 449 | + FileInfo fileinfo; |
| 450 | + string_init(path); |
| 451 | + string_init(tmp_new_path); |
| 452 | + string_init(tmp_old_path); |
| 453 | + |
| 454 | + do { |
| 455 | + if((error != FSE_OK) && (error != FSE_EXIST)) break; |
| 456 | + |
| 457 | + if(!dir_walk_open(dir_walk, old_path)) { |
| 458 | + error = dir_walk_get_error(dir_walk); |
| 459 | + break; |
| 460 | + } |
| 461 | + |
| 462 | + while(1) { |
| 463 | + DirWalkResult res = dir_walk_read(dir_walk, path, &fileinfo); |
| 464 | + |
| 465 | + if(res == DirWalkError) { |
| 466 | + error = dir_walk_get_error(dir_walk); |
| 467 | + break; |
| 468 | + } else if(res == DirWalkLast) { |
| 469 | + break; |
| 470 | + } else { |
| 471 | + string_set(tmp_old_path, path); |
| 472 | + string_right(path, strlen(old_path)); |
| 473 | + string_printf(tmp_new_path, "%s%s", new_path, string_get_cstr(path)); |
| 474 | + |
| 475 | + if(fileinfo.flags & FSF_DIRECTORY) { |
| 476 | + if(storage_common_stat(storage, string_get_cstr(tmp_new_path), &fileinfo) == |
| 477 | + FSE_OK) { |
| 478 | + if(fileinfo.flags & FSF_DIRECTORY) { |
| 479 | + error = storage_common_mkdir(storage, string_get_cstr(tmp_new_path)); |
| 480 | + } |
| 481 | + } |
| 482 | + } else { |
| 483 | + error = storage_common_merge( |
| 484 | + storage, string_get_cstr(tmp_old_path), string_get_cstr(tmp_new_path)); |
| 485 | + } |
| 486 | + |
| 487 | + if(error != FSE_OK) break; |
| 488 | + } |
| 489 | + } |
| 490 | + |
| 491 | + } while(false); |
| 492 | + |
| 493 | + string_clear(tmp_new_path); |
| 494 | + string_clear(tmp_old_path); |
| 495 | + string_clear(path); |
| 496 | + dir_walk_free(dir_walk); |
| 497 | + return error; |
| 498 | +} |
| 499 | + |
| 500 | +FS_Error storage_common_merge(Storage* storage, const char* old_path, const char* new_path) { |
| 501 | + FS_Error error; |
| 502 | + const char* new_path_tmp; |
| 503 | + string_t new_path_next; |
| 504 | + string_init(new_path_next); |
| 505 | + |
| 506 | + FileInfo fileinfo; |
| 507 | + error = storage_common_stat(storage, old_path, &fileinfo); |
| 508 | + |
| 509 | + if(error == FSE_OK) { |
| 510 | + if(fileinfo.flags & FSF_DIRECTORY) { |
| 511 | + error = storage_merge_recursive(storage, old_path, new_path); |
| 512 | + } else { |
| 513 | + error = storage_common_stat(storage, new_path, &fileinfo); |
| 514 | + if(error == FSE_OK) { |
| 515 | + string_set_str(new_path_next, new_path); |
| 516 | + string_t dir_path; |
| 517 | + string_t filename; |
| 518 | + char extension[MAX_EXT_LEN]; |
| 519 | + |
| 520 | + string_init(dir_path); |
| 521 | + string_init(filename); |
| 522 | + |
| 523 | + path_extract_filename(new_path_next, filename, true); |
| 524 | + path_extract_dirname(new_path, dir_path); |
| 525 | + path_extract_extension(new_path_next, extension, MAX_EXT_LEN); |
| 526 | + |
| 527 | + storage_get_next_filename( |
| 528 | + storage, |
| 529 | + string_get_cstr(dir_path), |
| 530 | + string_get_cstr(filename), |
| 531 | + extension, |
| 532 | + new_path_next, |
| 533 | + 255); |
| 534 | + string_cat_printf(dir_path, "/%s%s", string_get_cstr(new_path_next), extension); |
| 535 | + string_set(new_path_next, dir_path); |
| 536 | + |
| 537 | + string_clear(dir_path); |
| 538 | + string_clear(filename); |
| 539 | + new_path_tmp = string_get_cstr(new_path_next); |
| 540 | + } else { |
| 541 | + new_path_tmp = new_path; |
| 542 | + } |
| 543 | + Stream* stream_from = file_stream_alloc(storage); |
| 544 | + Stream* stream_to = file_stream_alloc(storage); |
| 545 | + |
| 546 | + do { |
| 547 | + if(!file_stream_open(stream_from, old_path, FSAM_READ, FSOM_OPEN_EXISTING)) break; |
| 548 | + if(!file_stream_open(stream_to, new_path_tmp, FSAM_WRITE, FSOM_CREATE_NEW)) break; |
| 549 | + stream_copy_full(stream_from, stream_to); |
| 550 | + } while(false); |
| 551 | + |
| 552 | + error = file_stream_get_error(stream_from); |
| 553 | + if(error == FSE_OK) { |
| 554 | + error = file_stream_get_error(stream_to); |
| 555 | + } |
| 556 | + |
| 557 | + stream_free(stream_from); |
| 558 | + stream_free(stream_to); |
| 559 | + } |
| 560 | + } |
| 561 | + |
| 562 | + string_clear(new_path_next); |
| 563 | + |
| 564 | + return error; |
| 565 | +} |
| 566 | + |
439 | 567 | FS_Error storage_common_mkdir(Storage* storage, const char* path) { |
440 | 568 | S_API_PROLOGUE; |
441 | 569 | S_API_DATA_PATH; |
|
0 commit comments