From 88a2d0007db222c339f0b6a17794a2014a241892 Mon Sep 17 00:00:00 2001 From: Daniel Wilhelm Date: Fri, 18 Apr 2014 17:16:21 +0200 Subject: 4.3 --- Application.cpp | 2 +- BUILD/Changelog.txt | 17 +- BUILD/FreeFileSync.chm | Bin 671768 -> 672005 bytes BUILD/Help/html/CmpSettings.png | Bin 28812 -> 0 bytes BUILD/Help/html/CompareButton.png | Bin 4856 -> 0 bytes BUILD/Help/html/ComparisonSettings.html | 10 +- BUILD/Help/html/ErrorHandling.png | Bin 28680 -> 0 bytes BUILD/Help/html/FreeFileSync.html | 18 +- BUILD/Help/html/MainDialog.png | Bin 76362 -> 0 bytes BUILD/Help/html/RealtimeSync.html | 6 +- BUILD/Help/html/RealtimeSync.png | Bin 32699 -> 0 bytes BUILD/Help/html/RunAsService.html | 12 +- BUILD/Help/html/RunAsService_html_17e8fbfe.png | Bin 9916 -> 0 bytes BUILD/Help/html/RunAsService_html_4f230a46.png | Bin 16072 -> 0 bytes BUILD/Help/html/RunAsService_html_68e0fe53.png | Bin 7391 -> 0 bytes BUILD/Help/html/RunAsService_html_7aa44556.png | Bin 101229 -> 0 bytes BUILD/Help/html/RunAsService_html_bf02de4e.png | Bin 13958 -> 0 bytes BUILD/Help/html/RunAsService_html_m3be0f332.png | Bin 16574 -> 0 bytes BUILD/Help/html/RunAsService_html_m3e56d901.png | Bin 72687 -> 0 bytes BUILD/Help/html/RunMinimized.png | Bin 41946 -> 0 bytes BUILD/Help/html/ScheduleBatch.html | 10 +- BUILD/Help/html/ScheduleBatch_html_372f0f3.gif | Bin 20148 -> 0 bytes BUILD/Help/html/ScheduleBatch_html_m10bf0d36.gif | Bin 21107 -> 0 bytes BUILD/Help/html/ShadowCopy.html | 2 +- BUILD/Help/html/SourceTarget.png | Bin 4857 -> 0 bytes BUILD/Help/html/SyncConfigButton.png | Bin 2813 -> 0 bytes BUILD/Help/html/SynchronizeButton.png | Bin 5109 -> 0 bytes BUILD/Help/html/VariableDrive.html | 2 +- BUILD/Help/html/VolumeName.png | Bin 5553 -> 0 bytes BUILD/Help/html/WatchUsbInsert.png | Bin 34801 -> 0 bytes BUILD/Help/html/ffsicon.png | Bin 7709 -> 0 bytes BUILD/Help/html/menuAdv.png | Bin 2711 -> 0 bytes BUILD/Help/html/menuFile.png | Bin 5574 -> 0 bytes BUILD/Help/html/menuHelp.png | Bin 1823 -> 0 bytes BUILD/Help/html/rtsicon.png | Bin 7462 -> 0 bytes BUILD/Help/html/scheduleBatch_html_13615436.gif | Bin 27319 -> 0 bytes BUILD/Help/html/scheduleBatch_html_28bb3203.gif | Bin 28325 -> 0 bytes BUILD/Help/html/scheduleBatch_html_m22c860a2.gif | Bin 27294 -> 0 bytes BUILD/Help/html/ubuntuScheduler.png | Bin 53376 -> 0 bytes BUILD/Help/html/win7scheduler.png | Bin 29311 -> 0 bytes BUILD/Help/img/CmpSettings.png | Bin 0 -> 28854 bytes BUILD/Help/img/CompareButton.png | Bin 0 -> 4856 bytes BUILD/Help/img/ErrorHandling.png | Bin 0 -> 28680 bytes BUILD/Help/img/MainDialog.png | Bin 0 -> 76362 bytes BUILD/Help/img/RealtimeSync.png | Bin 0 -> 32699 bytes BUILD/Help/img/RunAsService_html_17e8fbfe.png | Bin 0 -> 9916 bytes BUILD/Help/img/RunAsService_html_4f230a46.png | Bin 0 -> 16072 bytes BUILD/Help/img/RunAsService_html_68e0fe53.png | Bin 0 -> 7391 bytes BUILD/Help/img/RunAsService_html_7aa44556.png | Bin 0 -> 101229 bytes BUILD/Help/img/RunAsService_html_bf02de4e.png | Bin 0 -> 13958 bytes BUILD/Help/img/RunAsService_html_m3be0f332.png | Bin 0 -> 16574 bytes BUILD/Help/img/RunAsService_html_m3e56d901.png | Bin 0 -> 72687 bytes BUILD/Help/img/RunMinimized.png | Bin 0 -> 41946 bytes BUILD/Help/img/ScheduleBatch_html_m10bf0d36.gif | Bin 0 -> 21107 bytes BUILD/Help/img/SourceTarget.png | Bin 0 -> 4857 bytes BUILD/Help/img/SyncConfigButton.png | Bin 0 -> 2813 bytes BUILD/Help/img/SynchronizeButton.png | Bin 0 -> 5109 bytes BUILD/Help/img/VolumeName.png | Bin 0 -> 5553 bytes BUILD/Help/img/WatchUsbInsert.png | Bin 0 -> 34801 bytes BUILD/Help/img/ffsicon.png | Bin 0 -> 7709 bytes BUILD/Help/img/menuAdv.png | Bin 0 -> 2711 bytes BUILD/Help/img/menuFile.png | Bin 0 -> 5574 bytes BUILD/Help/img/menuHelp.png | Bin 0 -> 1823 bytes BUILD/Help/img/rtsicon.png | Bin 0 -> 7462 bytes BUILD/Help/img/ubuntuScheduler.png | Bin 0 -> 53376 bytes BUILD/Help/img/win7scheduler.png | Bin 0 -> 29311 bytes BUILD/Languages/chinese_simple.lng | 426 +++---- BUILD/Languages/chinese_traditional.lng | 438 ++++--- BUILD/Languages/croatian.lng | 1490 ++++++++++++++++++++++ BUILD/Languages/czech.lng | 448 ++++--- BUILD/Languages/danish.lng | 442 ++++--- BUILD/Languages/dutch.lng | 432 +++---- BUILD/Languages/english_uk.lng | 442 ++++--- BUILD/Languages/finnish.lng | 98 +- BUILD/Languages/french.lng | 432 +++---- BUILD/Languages/german.lng | 76 +- BUILD/Languages/greek.lng | 78 +- BUILD/Languages/hebrew.lng | 444 ++++--- BUILD/Languages/hungarian.lng | 76 +- BUILD/Languages/italian.lng | 442 ++++--- BUILD/Languages/japanese.lng | 104 +- BUILD/Languages/korean.lng | 436 ++++--- BUILD/Languages/polish.lng | 448 ++++--- BUILD/Languages/portuguese.lng | 432 +++---- BUILD/Languages/portuguese_br.lng | 448 ++++--- BUILD/Languages/romanian.lng | 464 ++++--- BUILD/Languages/russian.lng | 438 ++++--- BUILD/Languages/slovenian.lng | 454 ++++--- BUILD/Languages/spanish.lng | 444 ++++--- BUILD/Languages/swedish.lng | 442 ++++--- BUILD/Languages/turkish.lng | 98 +- BUILD/Languages/ukrainian.lng | 438 ++++--- BUILD/Resources.zip | Bin 250353 -> 272977 bytes FreeFileSync.cbp | 6 +- RealtimeSync/RealtimeSync.cbp | 4 +- RealtimeSync/watcher.cpp | 13 +- algorithm.cpp | 185 ++- algorithm.h | 4 +- comparison.cpp | 127 +- comparison.h | 2 +- file_hierarchy.cpp | 227 +++- file_hierarchy.h | 191 +-- lib/FindFilePlus/FindFilePlus.vcxproj | 245 ---- lib/FindFilePlus/dll_main.cpp | 30 - lib/FindFilePlus/find_file_plus.cpp | 298 ----- lib/FindFilePlus/find_file_plus.h | 78 -- lib/FindFilePlus/init_dll_binding.h | 16 - lib/FindFilePlus/load_dll.cpp | 23 - lib/FindFilePlus/load_dll.h | 46 - lib/custom_grid.cpp | 169 +-- lib/db_file.cpp | 476 +++---- lib/db_file.h | 5 +- lib/detect_renaming.cpp | 285 ----- lib/detect_renaming.h | 26 - lib/dir_exist_async.h | 4 +- lib/dir_lock.cpp | 16 +- lib/dir_name.cpp | 2 +- lib/localization.cpp | 1 + lib/parallel_scan.cpp | 15 +- lib/status_handler.h | 18 +- structures.cpp | 126 +- structures.h | 56 +- synchronization.cpp | 1423 +++++++++++++-------- synchronization.h | 49 +- ui/batch_status_handler.cpp | 10 +- ui/batch_status_handler.h | 10 +- ui/grid_view.cpp | 4 + ui/gui_generated.cpp | 369 +++--- ui/gui_generated.h | 99 +- ui/gui_status_handler.cpp | 20 +- ui/gui_status_handler.h | 20 +- ui/main_dlg.cpp | 81 +- ui/progress_indicator.cpp | 75 +- ui/small_dlgs.cpp | 16 +- ui/sync_cfg.cpp | 41 +- ui/wx_form_build_hide_warnings.h | 6 +- version/version.h | 2 +- version/version.rc | 4 +- wx+/format_unit.cpp | 2 +- wx+/format_unit.h | 2 +- wx+/serialize.h | 114 +- zen/FindFilePlus/FindFilePlus.vcxproj | 245 ++++ zen/FindFilePlus/dll_main.cpp | 30 + zen/FindFilePlus/find_file_plus.cpp | 298 +++++ zen/FindFilePlus/find_file_plus.h | 78 ++ zen/FindFilePlus/init_dll_binding.h | 16 + zen/FindFilePlus/load_dll.cpp | 23 + zen/FindFilePlus/load_dll.h | 46 + zen/dir_watcher.cpp | 54 +- zen/dir_watcher.h | 3 +- zen/file_handling.cpp | 84 +- zen/file_handling.h | 7 +- zen/file_id.cpp | 13 +- zen/file_id.h | 5 +- zen/file_id_def.h | 65 + zen/file_id_internal.h | 48 - zen/file_traverser.cpp | 767 +++++------ zen/file_traverser.h | 7 + zen/guid.h | 2 +- zen/int64.h | 4 +- zen/long_path_prefix.h | 1 + zen/notify_removal.cpp | 41 +- zen/privilege.cpp | 80 +- zen/privilege.h | 47 +- zen/process_status.h | 40 +- zen/stl_tools.h | 46 +- zen/symlink_target.h | 2 +- zen/time.h | 5 +- 168 files changed, 9616 insertions(+), 7971 deletions(-) delete mode 100644 BUILD/Help/html/CmpSettings.png delete mode 100644 BUILD/Help/html/CompareButton.png delete mode 100644 BUILD/Help/html/ErrorHandling.png delete mode 100644 BUILD/Help/html/MainDialog.png delete mode 100644 BUILD/Help/html/RealtimeSync.png delete mode 100644 BUILD/Help/html/RunAsService_html_17e8fbfe.png delete mode 100644 BUILD/Help/html/RunAsService_html_4f230a46.png delete mode 100644 BUILD/Help/html/RunAsService_html_68e0fe53.png delete mode 100644 BUILD/Help/html/RunAsService_html_7aa44556.png delete mode 100644 BUILD/Help/html/RunAsService_html_bf02de4e.png delete mode 100644 BUILD/Help/html/RunAsService_html_m3be0f332.png delete mode 100644 BUILD/Help/html/RunAsService_html_m3e56d901.png delete mode 100644 BUILD/Help/html/RunMinimized.png delete mode 100644 BUILD/Help/html/ScheduleBatch_html_372f0f3.gif delete mode 100644 BUILD/Help/html/ScheduleBatch_html_m10bf0d36.gif delete mode 100644 BUILD/Help/html/SourceTarget.png delete mode 100644 BUILD/Help/html/SyncConfigButton.png delete mode 100644 BUILD/Help/html/SynchronizeButton.png delete mode 100644 BUILD/Help/html/VolumeName.png delete mode 100644 BUILD/Help/html/WatchUsbInsert.png delete mode 100644 BUILD/Help/html/ffsicon.png delete mode 100644 BUILD/Help/html/menuAdv.png delete mode 100644 BUILD/Help/html/menuFile.png delete mode 100644 BUILD/Help/html/menuHelp.png delete mode 100644 BUILD/Help/html/rtsicon.png delete mode 100644 BUILD/Help/html/scheduleBatch_html_13615436.gif delete mode 100644 BUILD/Help/html/scheduleBatch_html_28bb3203.gif delete mode 100644 BUILD/Help/html/scheduleBatch_html_m22c860a2.gif delete mode 100644 BUILD/Help/html/ubuntuScheduler.png delete mode 100644 BUILD/Help/html/win7scheduler.png create mode 100644 BUILD/Help/img/CmpSettings.png create mode 100644 BUILD/Help/img/CompareButton.png create mode 100644 BUILD/Help/img/ErrorHandling.png create mode 100644 BUILD/Help/img/MainDialog.png create mode 100644 BUILD/Help/img/RealtimeSync.png create mode 100644 BUILD/Help/img/RunAsService_html_17e8fbfe.png create mode 100644 BUILD/Help/img/RunAsService_html_4f230a46.png create mode 100644 BUILD/Help/img/RunAsService_html_68e0fe53.png create mode 100644 BUILD/Help/img/RunAsService_html_7aa44556.png create mode 100644 BUILD/Help/img/RunAsService_html_bf02de4e.png create mode 100644 BUILD/Help/img/RunAsService_html_m3be0f332.png create mode 100644 BUILD/Help/img/RunAsService_html_m3e56d901.png create mode 100644 BUILD/Help/img/RunMinimized.png create mode 100644 BUILD/Help/img/ScheduleBatch_html_m10bf0d36.gif create mode 100644 BUILD/Help/img/SourceTarget.png create mode 100644 BUILD/Help/img/SyncConfigButton.png create mode 100644 BUILD/Help/img/SynchronizeButton.png create mode 100644 BUILD/Help/img/VolumeName.png create mode 100644 BUILD/Help/img/WatchUsbInsert.png create mode 100644 BUILD/Help/img/ffsicon.png create mode 100644 BUILD/Help/img/menuAdv.png create mode 100644 BUILD/Help/img/menuFile.png create mode 100644 BUILD/Help/img/menuHelp.png create mode 100644 BUILD/Help/img/rtsicon.png create mode 100644 BUILD/Help/img/ubuntuScheduler.png create mode 100644 BUILD/Help/img/win7scheduler.png create mode 100644 BUILD/Languages/croatian.lng delete mode 100644 lib/FindFilePlus/FindFilePlus.vcxproj delete mode 100644 lib/FindFilePlus/dll_main.cpp delete mode 100644 lib/FindFilePlus/find_file_plus.cpp delete mode 100644 lib/FindFilePlus/find_file_plus.h delete mode 100644 lib/FindFilePlus/init_dll_binding.h delete mode 100644 lib/FindFilePlus/load_dll.cpp delete mode 100644 lib/FindFilePlus/load_dll.h delete mode 100644 lib/detect_renaming.cpp delete mode 100644 lib/detect_renaming.h create mode 100644 zen/FindFilePlus/FindFilePlus.vcxproj create mode 100644 zen/FindFilePlus/dll_main.cpp create mode 100644 zen/FindFilePlus/find_file_plus.cpp create mode 100644 zen/FindFilePlus/find_file_plus.h create mode 100644 zen/FindFilePlus/init_dll_binding.h create mode 100644 zen/FindFilePlus/load_dll.cpp create mode 100644 zen/FindFilePlus/load_dll.h create mode 100644 zen/file_id_def.h delete mode 100644 zen/file_id_internal.h diff --git a/Application.cpp b/Application.cpp index 24763493..e15b3db0 100644 --- a/Application.cpp +++ b/Application.cpp @@ -369,7 +369,7 @@ void Application::runBatchMode(const wxString& filename, xmlAccess::XmlGlobalSet syncProc.startSynchronizationProcess(syncProcessCfg, folderCmp); - //play (optional) sound notification after sync has completed + //play (optional) sound notification after sync has completed -> don't play in silent mode, consider RealtimeSync! if (!batchCfg.silent) { const wxString soundFile = toWx(getResourceDir()) + wxT("Sync_Complete.wav"); diff --git a/BUILD/Changelog.txt b/BUILD/Changelog.txt index dbe9bd75..7116b447 100644 --- a/BUILD/Changelog.txt +++ b/BUILD/Changelog.txt @@ -2,8 +2,19 @@ |FreeFileSync| -------------- +Changelog v4.3 +-------------- +Detection of moved and renamed files +New database format for mode: a full sync is suggested before upgrading +Fixed overwrite symlink with regular file +Fixed synchronization result dialog GUI glitch (Windows XP) +Fixed macro %weekday% +RealtimeSync: Fixed support for manual volume unmount (Windows) +Added Croatian language + + Changelog v4.2 ---------------- +-------------- Implemented workaround for compiler bug leading to uncaught exceptions (Windows 32 bit) Shadow Copy Service: Native support for Windows7/Server 2008 Fixed reference by volume name parsing issue @@ -17,7 +28,7 @@ New option in GlobalSettings.xml: "RunWithBackgroundPriority" (Windows Vista and Changelog v4.1 ---------------- +-------------- Improved synchronization progress dialog Show all available aliases in directory history list Show password prompt when connecting to mapped network share @@ -31,7 +42,7 @@ Allow passing multiple directory names via command line Changelog v4.0 ---------------- +-------------- Thumbnail list view Option to specify comparison settings at folder pair level Correctly update parent-child relationship when changing sync directions diff --git a/BUILD/FreeFileSync.chm b/BUILD/FreeFileSync.chm index 7a38d187..cc0d3174 100644 Binary files a/BUILD/FreeFileSync.chm and b/BUILD/FreeFileSync.chm differ diff --git a/BUILD/Help/html/CmpSettings.png b/BUILD/Help/html/CmpSettings.png deleted file mode 100644 index eb0c83ab..00000000 Binary files a/BUILD/Help/html/CmpSettings.png and /dev/null differ diff --git a/BUILD/Help/html/CompareButton.png b/BUILD/Help/html/CompareButton.png deleted file mode 100644 index bab3780b..00000000 Binary files a/BUILD/Help/html/CompareButton.png and /dev/null differ diff --git a/BUILD/Help/html/ComparisonSettings.html b/BUILD/Help/html/ComparisonSettings.html index 069a7fd0..15fffaaf 100644 --- a/BUILD/Help/html/ComparisonSettings.html +++ b/BUILD/Help/html/ComparisonSettings.html @@ -5,7 +5,7 @@ - + @@ -25,7 +25,7 @@

Comparison Settings

-

+

I. Compare by "File time and size"

This @@ -131,9 +131,9 @@ handling offers three options to configure processing of symbolic links (also called symlinks or soft links):

    -
  1. Ignore: - excludes symbolic links while - scanning input directories.
     

    +
  2. Exclude: + skips symbolic links while scanning + input directories.
     

  3. Direct: configures synchronization of the symbolic link object itself and not its target. symbolic links will diff --git a/BUILD/Help/html/ErrorHandling.png b/BUILD/Help/html/ErrorHandling.png deleted file mode 100644 index 628fac9c..00000000 Binary files a/BUILD/Help/html/ErrorHandling.png and /dev/null differ diff --git a/BUILD/Help/html/FreeFileSync.html b/BUILD/Help/html/FreeFileSync.html index 0b81ac64..762445b4 100644 --- a/BUILD/Help/html/FreeFileSync.html +++ b/BUILD/Help/html/FreeFileSync.html @@ -24,23 +24,23 @@ -

    +

    FreeFileSync
    - Folder Comparison and Synchronization -

    Usage:

    1. Choose - left and right directories.

      + left and right directories.

       

    2. "Compare" - them.

      + them.

       

    3. Select - synchronization settings.

      + synchronization settings.

       

    4. Press "Synchronize..." - to begin synchronization.

      + to begin synchronization.


    @@ -50,7 +50,7 @@ Folder Comparison and Synchronization -

    Main Dialog:

      -

      +


    @@ -127,7 +127,7 @@ bar: -

    +

    @@ -158,7 +158,7 @@ bar: -

    +

    @@ -181,7 +181,7 @@ bar: -

    +

    diff --git a/BUILD/Help/html/MainDialog.png b/BUILD/Help/html/MainDialog.png deleted file mode 100644 index ab6a6f7c..00000000 Binary files a/BUILD/Help/html/MainDialog.png and /dev/null differ diff --git a/BUILD/Help/html/RealtimeSync.html b/BUILD/Help/html/RealtimeSync.html index fc0a2054..3468bc76 100644 --- a/BUILD/Help/html/RealtimeSync.html +++ b/BUILD/Help/html/RealtimeSync.html @@ -23,7 +23,7 @@ -

    +

    RealtimeSync
    - Automated Synchronization -



    @@ -53,7 +53,7 @@ but also sets up the command-line to execute the Start" to begin monitoring.

      -

      +


    @@ -95,7 +95,7 @@ the relevant configuration on the USB stick's root directory to have it called when the stick is mounted. Then configure RealtimeSync as shown in the following:

      -

      +


    diff --git a/BUILD/Help/html/RealtimeSync.png b/BUILD/Help/html/RealtimeSync.png deleted file mode 100644 index 20d582c6..00000000 Binary files a/BUILD/Help/html/RealtimeSync.png and /dev/null differ diff --git a/BUILD/Help/html/RunAsService.html b/BUILD/Help/html/RunAsService.html index c347a4fa..8b5e0d42 100644 --- a/BUILD/Help/html/RunAsService.html +++ b/BUILD/Help/html/RunAsService.html @@ -49,7 +49,7 @@ Create and register a new Service via command line:

    instsrv <ServiceName> <PathToResourceKit>\srvany.exe

    -
     

    +
     


    @@ -60,10 +60,10 @@ the new Service with RealtimeSync:

    the Registry editor (Regedit.exe) and navigate to key "HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\<ServiceName>"

  4. Add - a new key "Parameters".

    + a new key "Parameters".

  5. Add a new String value named "Application" - and specify a command line that shall be executed as value.

    + and specify a command line that shall be executed as value.


    @@ -97,7 +97,7 @@ administration:

    net start <ServiceName>

    -
     

     

    +
     

     


    @@ -111,7 +111,7 @@ administration:

    Service administration.



    -

    +



    @@ -122,7 +122,7 @@ Service shall be removed from the system, enter via command line:

    instsrv <ServiceName> remove

    -
     

    +
     


    diff --git a/BUILD/Help/html/RunAsService_html_17e8fbfe.png b/BUILD/Help/html/RunAsService_html_17e8fbfe.png deleted file mode 100644 index 23eb6083..00000000 Binary files a/BUILD/Help/html/RunAsService_html_17e8fbfe.png and /dev/null differ diff --git a/BUILD/Help/html/RunAsService_html_4f230a46.png b/BUILD/Help/html/RunAsService_html_4f230a46.png deleted file mode 100644 index a32a442d..00000000 Binary files a/BUILD/Help/html/RunAsService_html_4f230a46.png and /dev/null differ diff --git a/BUILD/Help/html/RunAsService_html_68e0fe53.png b/BUILD/Help/html/RunAsService_html_68e0fe53.png deleted file mode 100644 index 5639a21c..00000000 Binary files a/BUILD/Help/html/RunAsService_html_68e0fe53.png and /dev/null differ diff --git a/BUILD/Help/html/RunAsService_html_7aa44556.png b/BUILD/Help/html/RunAsService_html_7aa44556.png deleted file mode 100644 index b37fe6e4..00000000 Binary files a/BUILD/Help/html/RunAsService_html_7aa44556.png and /dev/null differ diff --git a/BUILD/Help/html/RunAsService_html_bf02de4e.png b/BUILD/Help/html/RunAsService_html_bf02de4e.png deleted file mode 100644 index 2bdac2db..00000000 Binary files a/BUILD/Help/html/RunAsService_html_bf02de4e.png and /dev/null differ diff --git a/BUILD/Help/html/RunAsService_html_m3be0f332.png b/BUILD/Help/html/RunAsService_html_m3be0f332.png deleted file mode 100644 index 5ad45cfa..00000000 Binary files a/BUILD/Help/html/RunAsService_html_m3be0f332.png and /dev/null differ diff --git a/BUILD/Help/html/RunAsService_html_m3e56d901.png b/BUILD/Help/html/RunAsService_html_m3e56d901.png deleted file mode 100644 index 860d1543..00000000 Binary files a/BUILD/Help/html/RunAsService_html_m3e56d901.png and /dev/null differ diff --git a/BUILD/Help/html/RunMinimized.png b/BUILD/Help/html/RunMinimized.png deleted file mode 100644 index 145a7568..00000000 Binary files a/BUILD/Help/html/RunMinimized.png and /dev/null differ diff --git a/BUILD/Help/html/ScheduleBatch.html b/BUILD/Help/html/ScheduleBatch.html index 4bd0c8ad..9594ec3d 100644 --- a/BUILD/Help/html/ScheduleBatch.html +++ b/BUILD/Help/html/ScheduleBatch.html @@ -31,12 +31,12 @@ Job for example, as "C:\SyncJob.ffs_batch".
     

  6. Enable checkbox "Run miminized" to avoid blocking while - showing a status dialog at the end of the process.

    + showing a status dialog at the end of the process.

     

  7. In order to prevent error or warning popup messages from stopping progress, set "Error handling" to either "Ignore - errors" or "Exit instantly".

    + errors" or "Exit instantly".

     

  8. Setup your operating system's scheduler

    @@ -63,7 +63,7 @@ Job
    • Use quotes if any paths contain spaces, e.g.: "C:\some - folder\SyncJob.ffs_batch"

       

      + folder\SyncJob.ffs_batch"

       

@@ -80,7 +80,7 @@ Job
  • Make sure "Run:" is specified as: <FreeFileSync installation directory>\FreeFileSync.exe <ffs_batch - file>

     

    + file>

     

  • Ubuntu Linux Gnome-schedule:

    @@ -105,7 +105,7 @@ Job
    • Specify the command as: <FreeFileSync - installation directory>\FreeFileSync <ffs_batch file>

      + installation directory>\FreeFileSync <ffs_batch file>

    diff --git a/BUILD/Help/html/ScheduleBatch_html_372f0f3.gif b/BUILD/Help/html/ScheduleBatch_html_372f0f3.gif deleted file mode 100644 index 4cddbc19..00000000 Binary files a/BUILD/Help/html/ScheduleBatch_html_372f0f3.gif and /dev/null differ diff --git a/BUILD/Help/html/ScheduleBatch_html_m10bf0d36.gif b/BUILD/Help/html/ScheduleBatch_html_m10bf0d36.gif deleted file mode 100644 index 20d27d6d..00000000 Binary files a/BUILD/Help/html/ScheduleBatch_html_m10bf0d36.gif and /dev/null differ diff --git a/BUILD/Help/html/ShadowCopy.html b/BUILD/Help/html/ShadowCopy.html index d8286285..ce66ccee 100644 --- a/BUILD/Help/html/ShadowCopy.html +++ b/BUILD/Help/html/ShadowCopy.html @@ -39,7 +39,7 @@ Copy of the source drive. To enable this feature go to Creating Volume Snapshots using VSS requires the application to be started - with Administrator rights.

    + with administrator rights.



    diff --git a/BUILD/Help/html/SourceTarget.png b/BUILD/Help/html/SourceTarget.png deleted file mode 100644 index 2a3a834e..00000000 Binary files a/BUILD/Help/html/SourceTarget.png and /dev/null differ diff --git a/BUILD/Help/html/SyncConfigButton.png b/BUILD/Help/html/SyncConfigButton.png deleted file mode 100644 index 2ac5c94e..00000000 Binary files a/BUILD/Help/html/SyncConfigButton.png and /dev/null differ diff --git a/BUILD/Help/html/SynchronizeButton.png b/BUILD/Help/html/SynchronizeButton.png deleted file mode 100644 index a8b8002b..00000000 Binary files a/BUILD/Help/html/SynchronizeButton.png and /dev/null differ diff --git a/BUILD/Help/html/VariableDrive.html b/BUILD/Help/html/VariableDrive.html index ebf80b8d..3e0ea71e 100644 --- a/BUILD/Help/html/VariableDrive.html +++ b/BUILD/Help/html/VariableDrive.html @@ -42,7 +42,7 @@ name>]\<path>

    It is not required to look up and enter the volume name manually. Just -select the corresponding entry in the drop down menu.

    +select the corresponding entry in the drop down menu.


    Option diff --git a/BUILD/Help/html/VolumeName.png b/BUILD/Help/html/VolumeName.png deleted file mode 100644 index 9d1b9201..00000000 Binary files a/BUILD/Help/html/VolumeName.png and /dev/null differ diff --git a/BUILD/Help/html/WatchUsbInsert.png b/BUILD/Help/html/WatchUsbInsert.png deleted file mode 100644 index 9d106fb8..00000000 Binary files a/BUILD/Help/html/WatchUsbInsert.png and /dev/null differ diff --git a/BUILD/Help/html/ffsicon.png b/BUILD/Help/html/ffsicon.png deleted file mode 100644 index 7ff53bb6..00000000 Binary files a/BUILD/Help/html/ffsicon.png and /dev/null differ diff --git a/BUILD/Help/html/menuAdv.png b/BUILD/Help/html/menuAdv.png deleted file mode 100644 index 3626c1f0..00000000 Binary files a/BUILD/Help/html/menuAdv.png and /dev/null differ diff --git a/BUILD/Help/html/menuFile.png b/BUILD/Help/html/menuFile.png deleted file mode 100644 index 7e6844d5..00000000 Binary files a/BUILD/Help/html/menuFile.png and /dev/null differ diff --git a/BUILD/Help/html/menuHelp.png b/BUILD/Help/html/menuHelp.png deleted file mode 100644 index db51f82f..00000000 Binary files a/BUILD/Help/html/menuHelp.png and /dev/null differ diff --git a/BUILD/Help/html/rtsicon.png b/BUILD/Help/html/rtsicon.png deleted file mode 100644 index dabaa256..00000000 Binary files a/BUILD/Help/html/rtsicon.png and /dev/null differ diff --git a/BUILD/Help/html/scheduleBatch_html_13615436.gif b/BUILD/Help/html/scheduleBatch_html_13615436.gif deleted file mode 100644 index 23d7bda9..00000000 Binary files a/BUILD/Help/html/scheduleBatch_html_13615436.gif and /dev/null differ diff --git a/BUILD/Help/html/scheduleBatch_html_28bb3203.gif b/BUILD/Help/html/scheduleBatch_html_28bb3203.gif deleted file mode 100644 index 45c8b1c2..00000000 Binary files a/BUILD/Help/html/scheduleBatch_html_28bb3203.gif and /dev/null differ diff --git a/BUILD/Help/html/scheduleBatch_html_m22c860a2.gif b/BUILD/Help/html/scheduleBatch_html_m22c860a2.gif deleted file mode 100644 index 1f8da914..00000000 Binary files a/BUILD/Help/html/scheduleBatch_html_m22c860a2.gif and /dev/null differ diff --git a/BUILD/Help/html/ubuntuScheduler.png b/BUILD/Help/html/ubuntuScheduler.png deleted file mode 100644 index 82bf329f..00000000 Binary files a/BUILD/Help/html/ubuntuScheduler.png and /dev/null differ diff --git a/BUILD/Help/html/win7scheduler.png b/BUILD/Help/html/win7scheduler.png deleted file mode 100644 index 29fa1f36..00000000 Binary files a/BUILD/Help/html/win7scheduler.png and /dev/null differ diff --git a/BUILD/Help/img/CmpSettings.png b/BUILD/Help/img/CmpSettings.png new file mode 100644 index 00000000..d2548891 Binary files /dev/null and b/BUILD/Help/img/CmpSettings.png differ diff --git a/BUILD/Help/img/CompareButton.png b/BUILD/Help/img/CompareButton.png new file mode 100644 index 00000000..bab3780b Binary files /dev/null and b/BUILD/Help/img/CompareButton.png differ diff --git a/BUILD/Help/img/ErrorHandling.png b/BUILD/Help/img/ErrorHandling.png new file mode 100644 index 00000000..628fac9c Binary files /dev/null and b/BUILD/Help/img/ErrorHandling.png differ diff --git a/BUILD/Help/img/MainDialog.png b/BUILD/Help/img/MainDialog.png new file mode 100644 index 00000000..ab6a6f7c Binary files /dev/null and b/BUILD/Help/img/MainDialog.png differ diff --git a/BUILD/Help/img/RealtimeSync.png b/BUILD/Help/img/RealtimeSync.png new file mode 100644 index 00000000..20d582c6 Binary files /dev/null and b/BUILD/Help/img/RealtimeSync.png differ diff --git a/BUILD/Help/img/RunAsService_html_17e8fbfe.png b/BUILD/Help/img/RunAsService_html_17e8fbfe.png new file mode 100644 index 00000000..23eb6083 Binary files /dev/null and b/BUILD/Help/img/RunAsService_html_17e8fbfe.png differ diff --git a/BUILD/Help/img/RunAsService_html_4f230a46.png b/BUILD/Help/img/RunAsService_html_4f230a46.png new file mode 100644 index 00000000..a32a442d Binary files /dev/null and b/BUILD/Help/img/RunAsService_html_4f230a46.png differ diff --git a/BUILD/Help/img/RunAsService_html_68e0fe53.png b/BUILD/Help/img/RunAsService_html_68e0fe53.png new file mode 100644 index 00000000..5639a21c Binary files /dev/null and b/BUILD/Help/img/RunAsService_html_68e0fe53.png differ diff --git a/BUILD/Help/img/RunAsService_html_7aa44556.png b/BUILD/Help/img/RunAsService_html_7aa44556.png new file mode 100644 index 00000000..b37fe6e4 Binary files /dev/null and b/BUILD/Help/img/RunAsService_html_7aa44556.png differ diff --git a/BUILD/Help/img/RunAsService_html_bf02de4e.png b/BUILD/Help/img/RunAsService_html_bf02de4e.png new file mode 100644 index 00000000..2bdac2db Binary files /dev/null and b/BUILD/Help/img/RunAsService_html_bf02de4e.png differ diff --git a/BUILD/Help/img/RunAsService_html_m3be0f332.png b/BUILD/Help/img/RunAsService_html_m3be0f332.png new file mode 100644 index 00000000..5ad45cfa Binary files /dev/null and b/BUILD/Help/img/RunAsService_html_m3be0f332.png differ diff --git a/BUILD/Help/img/RunAsService_html_m3e56d901.png b/BUILD/Help/img/RunAsService_html_m3e56d901.png new file mode 100644 index 00000000..860d1543 Binary files /dev/null and b/BUILD/Help/img/RunAsService_html_m3e56d901.png differ diff --git a/BUILD/Help/img/RunMinimized.png b/BUILD/Help/img/RunMinimized.png new file mode 100644 index 00000000..145a7568 Binary files /dev/null and b/BUILD/Help/img/RunMinimized.png differ diff --git a/BUILD/Help/img/ScheduleBatch_html_m10bf0d36.gif b/BUILD/Help/img/ScheduleBatch_html_m10bf0d36.gif new file mode 100644 index 00000000..20d27d6d Binary files /dev/null and b/BUILD/Help/img/ScheduleBatch_html_m10bf0d36.gif differ diff --git a/BUILD/Help/img/SourceTarget.png b/BUILD/Help/img/SourceTarget.png new file mode 100644 index 00000000..2a3a834e Binary files /dev/null and b/BUILD/Help/img/SourceTarget.png differ diff --git a/BUILD/Help/img/SyncConfigButton.png b/BUILD/Help/img/SyncConfigButton.png new file mode 100644 index 00000000..2ac5c94e Binary files /dev/null and b/BUILD/Help/img/SyncConfigButton.png differ diff --git a/BUILD/Help/img/SynchronizeButton.png b/BUILD/Help/img/SynchronizeButton.png new file mode 100644 index 00000000..a8b8002b Binary files /dev/null and b/BUILD/Help/img/SynchronizeButton.png differ diff --git a/BUILD/Help/img/VolumeName.png b/BUILD/Help/img/VolumeName.png new file mode 100644 index 00000000..9d1b9201 Binary files /dev/null and b/BUILD/Help/img/VolumeName.png differ diff --git a/BUILD/Help/img/WatchUsbInsert.png b/BUILD/Help/img/WatchUsbInsert.png new file mode 100644 index 00000000..9d106fb8 Binary files /dev/null and b/BUILD/Help/img/WatchUsbInsert.png differ diff --git a/BUILD/Help/img/ffsicon.png b/BUILD/Help/img/ffsicon.png new file mode 100644 index 00000000..7ff53bb6 Binary files /dev/null and b/BUILD/Help/img/ffsicon.png differ diff --git a/BUILD/Help/img/menuAdv.png b/BUILD/Help/img/menuAdv.png new file mode 100644 index 00000000..3626c1f0 Binary files /dev/null and b/BUILD/Help/img/menuAdv.png differ diff --git a/BUILD/Help/img/menuFile.png b/BUILD/Help/img/menuFile.png new file mode 100644 index 00000000..7e6844d5 Binary files /dev/null and b/BUILD/Help/img/menuFile.png differ diff --git a/BUILD/Help/img/menuHelp.png b/BUILD/Help/img/menuHelp.png new file mode 100644 index 00000000..db51f82f Binary files /dev/null and b/BUILD/Help/img/menuHelp.png differ diff --git a/BUILD/Help/img/rtsicon.png b/BUILD/Help/img/rtsicon.png new file mode 100644 index 00000000..dabaa256 Binary files /dev/null and b/BUILD/Help/img/rtsicon.png differ diff --git a/BUILD/Help/img/ubuntuScheduler.png b/BUILD/Help/img/ubuntuScheduler.png new file mode 100644 index 00000000..82bf329f Binary files /dev/null and b/BUILD/Help/img/ubuntuScheduler.png differ diff --git a/BUILD/Help/img/win7scheduler.png b/BUILD/Help/img/win7scheduler.png new file mode 100644 index 00000000..29fa1f36 Binary files /dev/null and b/BUILD/Help/img/win7scheduler.png differ diff --git a/BUILD/Languages/chinese_simple.lng b/BUILD/Languages/chinese_simple.lng index fc37aac5..65887d4f 100644 --- a/BUILD/Languages/chinese_simple.lng +++ b/BUILD/Languages/chinese_simple.lng @@ -22,39 +22,6 @@ RealtimeSync - Automated Synchronization 实时同步 - 自动同步 -Browse -浏览 - -Windows Error Code %x: -Windows错误代码 %x: - -Linux Error Code %x: -Linux错误代码 %x: - -Invalid command line: %x -无效的命令行: %x - -Error resolving symbolic link: -解决符号链接出错: - -Show pop-up -显示弹出对话框 - -Show pop-up on errors or warnings -在错误或警告时显示弹出对话框 - -Ignore errors -忽略错误 - -Hide all error and warning messages -隐藏所有错误与警告信息 - -Exit instantly -立即退出 - -Abort synchronization immediately -立即中止同步 - Select alternate comparison settings 选择替换的比较设置 @@ -115,6 +82,45 @@ Select time span 选择时间跨度 +Show pop-up +显示弹出对话框 + +Show pop-up on errors or warnings +在错误或警告时显示弹出对话框 + +Ignore errors +忽略错误 + +Hide all error and warning messages +隐藏所有错误与警告信息 + +Exit instantly +立即退出 + +Abort synchronization immediately +立即中止同步 + +Browse +浏览 + +Error reading from synchronization database: +从同步数据库中读取时出错: + +Error writing to synchronization database: +向同步数据库中写入时出错: + +Invalid command line: %x +无效的命令行: %x + +Windows Error Code %x: +Windows错误代码 %x: + +Linux Error Code %x: +Linux错误代码 %x: + +Error resolving symbolic link: +解决符号链接出错: + %x MB %x MB @@ -162,17 +168,14 @@ Comparison Result 比较结果 -Incompatible synchronization database format: -不兼容的同步数据库格式: - Initial synchronization: 初始化同步: One of the FreeFileSync database files is not yet existing: FreeFileSync数据库文件其中一个不存在: -Error reading from synchronization database: -从同步数据库中读取时出错: +Incompatible synchronization database format: +不兼容的同步数据库格式: Database files do not share a common synchronization session: 数据库文件没不共享一个公共的同步段 @@ -197,12 +200,18 @@ %x 秒 +Drag && drop +拖放 + Info 信息 Fatal Error 致命错误 +Error reading file: +读取文件出错: + Scanning: 扫描中: @@ -220,15 +229,36 @@ Invalid FreeFileSync config file! 无效的 FreeFileSync 配置文件! -File does not exist: -文件不存在: - Error parsing configuration file: 分析配置文件出错: +Error moving to Recycle Bin: +移动到回收站出错: + +Could not load a required DLL: +不能加载所需的动态连接库: + +Error accessing Volume Shadow Copy Service! +使用卷影复制服务时出错! + +Making shadow copies on WOW64 is not supported. Please use FreeFileSync 64-bit version. +不支持在WOW64上使用卷影复制. 请使用 FreeFileSync 64位版本. + +Could not determine volume name for file: +不能确定此文件的卷名称: + +Volume name %x not part of filename %y! +卷名 %x 并非文件名 %y 的一部分! + /sec /秒 +File does not exist: +文件不存在: + +Could not read values for the following XML nodes: +不能从如下XML节点读取数值: + S&ave configuration... 保存配置(&A)... @@ -321,138 +351,6 @@ The command line is executed each time: A directory input field is empty. 有一个目录输入字段是空的. -Drag && drop -拖放 - -Could not initialize directory monitoring: -不能初始化目录监视: - -Error when monitoring directories. -监视目录时出错. - -Conversion error: -转换错误: - -Error deleting file: -删除文件出错: - -Error moving file: -移动文件时出错: - -Target file already existing! -目标文件已经存在! - -Error moving directory: -移动目录时出错: - -Target directory already existing! -目标目录已经存在! - -Error deleting directory: -删除目录出错: - -Error changing modification time: -改变修改时间时出错: - -Error loading library function: -加载库函数出错: - -Error reading security context: -读取安全上下文时出错: - -Error writing security context: -写入安全上下文时出错: - -Error copying file permissions: -复制文件权限时出错: - -Error creating directory: -创建目录出错: - -Error copying symbolic link: -复制符号链接时出错: - -Error copying file: -复制文件出错: - -Error opening file: -打开文件出错: - -Error writing file: -写入文件出错: - -Error reading file: -读取文件出错: - -Operation aborted! -操作已取消! - -Endless loop when traversing directory: -遍历目录时出现无限循环: - -Error traversing directory: -遍历目录出错: - -Error setting privilege: -设置权限时出错: - -Error moving to Recycle Bin: -移动到回收站出错: - -Could not load a required DLL: -不能加载所需的动态连接库: - -Error writing to synchronization database: -向同步数据库中写入时出错: - -Error accessing Volume Shadow Copy Service! -使用卷影复制服务时出错! - -Making shadow copies on WOW64 is not supported. Please use FreeFileSync 64-bit version. -不支持在WOW64上使用卷影复制. 请使用 FreeFileSync 64位版本. - -Could not determine volume name for file: -不能确定此文件的卷名称: - -Volume name %x not part of filename %y! -卷名 %x 并非文件名 %y 的一部分! - -%x TB -%x TB - -%x PB -%x PB - -%x% -%x% - - -1 min -%x min - - -%x 分 - - - -1 hour -%x hours - - -%x 小时 - - - -1 day -%x days - - -%x 天 - - -Could not read values for the following XML nodes: -不能从如下XML节点读取数值: - Logging 记录 @@ -471,9 +369,6 @@ The command line is executed each time: Batch execution 批处理执行 -Log-messages: -日志信息: - Stop 停止 @@ -600,6 +495,24 @@ The command line is executed each time: Total amount of data that will be transferred 将被转移的总数据 +Operation: +操作: + +Items found: +已找到的元素: + +Items remaining: +剩余的元素: + +Speed: +速度: + +Time remaining: +剩余时间: + +Time elapsed: +已用时间: + Batch job 批处理作业 @@ -648,32 +561,14 @@ The command line is executed each time: &Cancel 取消(&C) -Operation: -操作: - -Items found: -已找到的元素: - -Items remaining: -剩余的元素: - -Speed: -速度: - -Time remaining: -剩余时间: - -Time elapsed: -已用时间: - Select variant: 选择变化的: <自动> -Identify and propagate changes on both sides using a database. Deletions and conflicts are detected automatically. -使用数据库来识别和传送两边的改变. 自动检测删除和冲突状态. +Identify and propagate changes on both sides using a database. Deletions, renaming and conflicts are detected automatically. + Mirror ->> 镜像 ->> @@ -900,22 +795,14 @@ Exclude: \stuff\temp\* Copy locked files 复制被锁定的文件 - -Copy shared or locked files using Volume Shadow Copy Service (Requires Administrator rights) - - -通过卷影复制服务复制共享或锁定的文件(需要管理员权限) - +Copy shared or locked files using Volume Shadow Copy Service (Requires Administrator rights) +通过卷影复制服务复制共享或锁定的文件(需要管理员权限) Copy file access permissions 复制文件存取权限 - -Transfer file and directory permissions (Requires Administrator rights) - - -转移文件和目录的权限(需要管理员权限) - +Transfer file and directory permissions (Requires Administrator rights) +转移文件和目录的权限(需要管理员权限) Hidden dialogs: 隐藏对话框: @@ -947,6 +834,9 @@ Transfer file and directory permissions (Requires Administrator rights) &Find next 查找下一个(&F) +Operation aborted! +操作已取消! + Main bar 主工具条 @@ -1124,6 +1014,9 @@ Transfer file and directory permissions (Requires Administrator rights) File list exported! 文件清单已经导出! +Error writing file: +写入文件出错: + Batch file created successfully! 批处理文件创建成功! @@ -1219,9 +1112,6 @@ Transfer file and directory permissions (Requires Administrator rights) Filter: Single pair 过滤器:单一的配对 -Ignore -忽略 - Direct 直接 @@ -1283,6 +1173,102 @@ Transfer file and directory permissions (Requires Administrator rights) Move files into a time-stamped subdirectory 移动文件到时间标记子目录 +%x TB +%x TB + +%x PB +%x PB + +%x% +%x% + + +1 min +%x min + + +%x 分 + + + +1 hour +%x hours + + +%x 小时 + + + +1 day +%x days + + +%x 天 + + +Could not initialize directory monitoring: +不能初始化目录监视: + +Error when monitoring directories. +监视目录时出错. + +Conversion error: +转换错误: + +Error deleting file: +删除文件出错: + +Error moving file: +移动文件时出错: + +Target file already existing! +目标文件已经存在! + +Error moving directory: +移动目录时出错: + +Target directory already existing! +目标目录已经存在! + +Error deleting directory: +删除目录出错: + +Error changing modification time: +改变修改时间时出错: + +Error loading library function: +加载库函数出错: + +Error reading security context: +读取安全上下文时出错: + +Error writing security context: +写入安全上下文时出错: + +Error copying file permissions: +复制文件权限时出错: + +Error creating directory: +创建目录出错: + +Error copying symbolic link: +复制符号链接时出错: + +Error copying file: +复制文件出错: + +Error opening file: +打开文件出错: + +Error traversing directory: +遍历目录出错: + +Endless loop when traversing directory: +遍历目录时出现无限循环: + +Error setting privilege: +设置权限时出错: + Both sides have changed since last synchronization! 在最后的同步之后两边均已改变! @@ -1313,9 +1299,6 @@ Transfer file and directory permissions (Requires Administrator rights) Directories are dependent! Be careful when setting up synchronization rules: 目录有依赖性!在设立同步规则时请小心: -Comparing content of files %x -正在比较文件 %x 的内容 - Memory allocation failed! 内存分配失败! @@ -1331,15 +1314,15 @@ Transfer file and directory permissions (Requires Administrator rights) Symlinks %x have the same date but a different target! 符号连接 %x 有相同的日期但目标不同! +Comparing content of files %x +正在比较文件 %x 的内容 + Comparing files by content failed. 按文件内容比较失败. Generating file list... 生成文件列表... -Multiple... -并联... - Both sides are equal 两侧相等 @@ -1358,6 +1341,12 @@ Transfer file and directory permissions (Requires Administrator rights) Delete right file/folder 删除右侧文件/文件夹 +Move file on left + + +Move file on right + + Overwrite left file/folder with right one 从右侧覆盖左侧的文件/文件夹 @@ -1373,6 +1362,9 @@ Transfer file and directory permissions (Requires Administrator rights) Copy file attributes only to right 仅复制文件属性到右侧 +Multiple... +并联... + Deleting file %x 正删除文件 %x diff --git a/BUILD/Languages/chinese_traditional.lng b/BUILD/Languages/chinese_traditional.lng index f872c6aa..380d2c9b 100644 --- a/BUILD/Languages/chinese_traditional.lng +++ b/BUILD/Languages/chinese_traditional.lng @@ -22,39 +22,6 @@ RealtimeSync - Automated Synchronization 即時同步 - 自動同步 -Browse -瀏覽 - -Windows Error Code %x: -Windows 錯誤代碼 %x: - -Linux Error Code %x: -Linux 錯誤代碼 %x: - -Invalid command line: %x -無效的命令列:%x - -Error resolving symbolic link: -解析錯誤的符號連結: - -Show pop-up -顯示彈出視窗 - -Show pop-up on errors or warnings -在彈出視窗上顯示錯誤或警告訊息 - -Ignore errors -忽略錯誤 - -Hide all error and warning messages -隱藏所有錯誤和警告訊息 - -Exit instantly -立即退出 - -Abort synchronization immediately -立即中止同步 - Select alternate comparison settings 選擇替代的比對設定 @@ -115,6 +82,45 @@ Select time span 選擇時間範圍 +Show pop-up +顯示彈出視窗 + +Show pop-up on errors or warnings +在彈出視窗上顯示錯誤或警告訊息 + +Ignore errors +忽略錯誤 + +Hide all error and warning messages +隱藏所有錯誤和警告訊息 + +Exit instantly +立即退出 + +Abort synchronization immediately +立即中止同步 + +Browse +瀏覽 + +Error reading from synchronization database: +讀取同步資料庫錯誤: + +Error writing to synchronization database: +寫入同步資料庫錯誤: + +Invalid command line: %x +無效的命令列:%x + +Windows Error Code %x: +Windows 錯誤代碼 %x: + +Linux Error Code %x: +Linux 錯誤代碼 %x: + +Error resolving symbolic link: +解析錯誤的符號連結: + %x MB %x MB @@ -162,17 +168,14 @@ Comparison Result 比對結果 -Incompatible synchronization database format: -同步資料庫格式不相容: - Initial synchronization: 初始化同步: One of the FreeFileSync database files is not yet existing: 其中一個 FreeFileSync 資料庫檔案不存在: -Error reading from synchronization database: -讀取同步資料庫錯誤: +Incompatible synchronization database format: +同步資料庫格式不相容: Database files do not share a common synchronization session: 資料庫檔案不共享一個共同的同步連線: @@ -197,12 +200,18 @@ %x 秒 +Drag && drop +拖放 + Info 訊息 Fatal Error 嚴重錯誤 +Error reading file: +讀取檔案錯誤: + Scanning: 正在掃瞄: @@ -220,15 +229,36 @@ Invalid FreeFileSync config file! 無效的 FreeFileSync 配置檔案! -File does not exist: -檔案不存在: - Error parsing configuration file: 分析配置檔案錯誤: +Error moving to Recycle Bin: +移動到資源回收筒錯誤: + +Could not load a required DLL: +無法載入一個所需的DLL: + +Error accessing Volume Shadow Copy Service! +讀取卷影複製服務時錯誤! + +Making shadow copies on WOW64 is not supported. Please use FreeFileSync 64-bit version. +不支援製作 WOW64 上的卷影副本。請使用 FreeFileSync 64位元版本。 + +Could not determine volume name for file: +無法判斷此檔案的卷標名稱: + +Volume name %x not part of filename %y! +卷名 %x 並非檔名 %y 的一部份! + /sec /秒 +File does not exist: +檔案不存在: + +Could not read values for the following XML nodes: +無法讀取 XML 之後節點的值: + S&ave configuration... 儲存配置(&A)... @@ -321,138 +351,6 @@ The command line is executed each time: A directory input field is empty. 目錄輸入的欄位為空 -Drag && drop -拖放 - -Could not initialize directory monitoring: -無法初始化目錄監測: - -Error when monitoring directories. -監測目錄錯誤。 - -Conversion error: -轉換錯誤: - -Error deleting file: -刪除檔案錯誤: - -Error moving file: -移動檔案錯誤: - -Target file already existing! -目標檔案已存在! - -Error moving directory: -移動目錄錯誤: - -Target directory already existing! -目標目錄已存在! - -Error deleting directory: -刪除目錄錯誤: - -Error changing modification time: -變更修改時間錯誤: - -Error loading library function: -載入函數庫錯誤: - -Error reading security context: -讀取安全內文錯誤: - -Error writing security context: -寫入安全性內容錯誤: - -Error copying file permissions: -複製檔案權限錯誤: - -Error creating directory: -新建目錄錯誤: - -Error copying symbolic link: -複製符號連結錯誤: - -Error copying file: -複製檔案錯誤: - -Error opening file: -開啟檔案錯誤: - -Error writing file: -寫入檔案錯誤: - -Error reading file: -讀取檔案錯誤: - -Operation aborted! -中止操作! - -Endless loop when traversing directory: -當遍歷目錄時無限循環: - -Error traversing directory: -遍歷目錄錯誤: - -Error setting privilege: -設定權限錯誤: - -Error moving to Recycle Bin: -移動到資源回收筒錯誤: - -Could not load a required DLL: -無法載入一個所需的DLL: - -Error writing to synchronization database: -寫入同步資料庫錯誤: - -Error accessing Volume Shadow Copy Service! -讀取卷影複製服務時錯誤! - -Making shadow copies on WOW64 is not supported. Please use FreeFileSync 64-bit version. -不支援製作 WOW64 上的卷影副本。請使用 FreeFileSync 64位元版本。 - -Could not determine volume name for file: -無法判斷此檔案的卷標名稱: - -Volume name %x not part of filename %y! -卷名 %x 並非檔名 %y 的一部份! - -%x TB -%x TB - -%x PB -%x PB - -%x% -%x% - - -1 min -%x min - - -%x 分 - - - -1 hour -%x hours - - -%x 小時 - - - -1 day -%x days - - -%x 天 - - -Could not read values for the following XML nodes: -無法讀取 XML 之後節點的值: - Logging 日誌記錄 @@ -471,9 +369,6 @@ The command line is executed each time: Batch execution 批次處理執行 -Log-messages: -日誌訊息: - Stop 停止 @@ -600,6 +495,24 @@ The command line is executed each time: Total amount of data that will be transferred 將要傳輸的全部資料量 +Operation: +操作: + +Items found: +尋找要素: + +Items remaining: +剩餘要素: + +Speed: +速度: + +Time remaining: +剩餘時間: + +Time elapsed: +經過時間: + Batch job 批次處理作業 @@ -648,31 +561,13 @@ The command line is executed each time: &Cancel 取消(&C) -Operation: -操作: - -Items found: -尋找要素: - -Items remaining: -剩餘要素: - -Speed: -速度: - -Time remaining: -剩餘時間: - -Time elapsed: -經過時間: - Select variant: 選擇變數: <自動> -Identify and propagate changes on both sides using a database. Deletions and conflicts are detected automatically. +Identify and propagate changes on both sides using a database. Deletions, renaming and conflicts are detected automatically. 對兩邊使用同一個資料庫的識別和傳送更改。自動檢測刪除和衝突部份。 Mirror ->> @@ -886,27 +781,19 @@ Exclude: \stuff\temp\* 異動檔案副本 Write to a temporary file (*.ffs_tmp) first then rename it. This guarantees a consistent state even in case of fatal error. - +第一次將檔寫入到一個暫存 (*.ffs_tmp) 順便將它們重新命名。即使在嚴重錯誤的情況下,還可確保一致的狀態。 Copy locked files 複製被鎖定的檔案 - -Copy shared or locked files using Volume Shadow Copy Service (Requires Administrator rights) - - -複製共用或鎖定檔案使用使用卷影複製服務(需要管理員權限) - +Copy shared or locked files using Volume Shadow Copy Service (Requires Administrator rights) +複製共用或鎖定檔案使用使用卷影複製服務(需要管理員權限) Copy file access permissions 複製檔案系統權限 - -Transfer file and directory permissions (Requires Administrator rights) - - -傳輸檔案和目錄權限(需要管理員權限) - +Transfer file and directory permissions (Requires Administrator rights) +傳輸檔案和目錄權限(需要管理員權限) Hidden dialogs: 隱藏對話框: @@ -938,6 +825,9 @@ Transfer file and directory permissions (Requires Administrator rights) &Find next 找下一個(&F) +Operation aborted! +中止操作! + Main bar 主欄位 @@ -978,16 +868,16 @@ Transfer file and directory permissions (Requires Administrator rights) 自動調整欄寬 Icon size: - +圖示大小: Small - + Medium - + Large - + Include all rows 包括所有行 @@ -1115,6 +1005,9 @@ Transfer file and directory permissions (Requires Administrator rights) File list exported! 檔案清單已匯出! +Error writing file: +寫入檔案錯誤: + Batch file created successfully! 批次檔新建成功! @@ -1131,7 +1024,7 @@ Transfer file and directory permissions (Requires Administrator rights) %x directories -%x 目錄 +%x 個目錄 @@ -1139,7 +1032,7 @@ Transfer file and directory permissions (Requires Administrator rights) %x files -%x 檔案 +%x 個檔案 @@ -1210,9 +1103,6 @@ Transfer file and directory permissions (Requires Administrator rights) Filter: Single pair 篩選器:單對 -Ignore -忽略 - Direct 直接 @@ -1274,6 +1164,102 @@ Transfer file and directory permissions (Requires Administrator rights) Move files into a time-stamped subdirectory 移動檔案到一個時間標記的子目錄 +%x TB +%x TB + +%x PB +%x PB + +%x% +%x% + + +1 min +%x min + + +%x 分 + + + +1 hour +%x hours + + +%x 小時 + + + +1 day +%x days + + +%x 天 + + +Could not initialize directory monitoring: +無法初始化目錄監測: + +Error when monitoring directories. +監測目錄錯誤。 + +Conversion error: +轉換錯誤: + +Error deleting file: +刪除檔案錯誤: + +Error moving file: +移動檔案錯誤: + +Target file already existing! +目標檔案已存在! + +Error moving directory: +移動目錄錯誤: + +Target directory already existing! +目標目錄已存在! + +Error deleting directory: +刪除目錄錯誤: + +Error changing modification time: +變更修改時間錯誤: + +Error loading library function: +載入函數庫錯誤: + +Error reading security context: +讀取安全內文錯誤: + +Error writing security context: +寫入安全性內容錯誤: + +Error copying file permissions: +複製檔案權限錯誤: + +Error creating directory: +新建目錄錯誤: + +Error copying symbolic link: +複製符號連結錯誤: + +Error copying file: +複製檔案錯誤: + +Error opening file: +開啟檔案錯誤: + +Error traversing directory: +遍歷目錄錯誤: + +Endless loop when traversing directory: +當遍歷目錄時無限循環: + +Error setting privilege: +設定權限錯誤: + Both sides have changed since last synchronization! 自上次同步後,兩邊均已更改過! @@ -1304,9 +1290,6 @@ Transfer file and directory permissions (Requires Administrator rights) Directories are dependent! Be careful when setting up synchronization rules: 目錄有依靠性!請小心設定同步規則: -Comparing content of files %x -正在比對檔案内容的百分比 %x - Memory allocation failed! 記憶體分配失敗! @@ -1322,15 +1305,15 @@ Transfer file and directory permissions (Requires Administrator rights) Symlinks %x have the same date but a different target! 符號連結 %x 有相同日期但是不同目標! +Comparing content of files %x +正在比對檔案内容的百分比 %x + Comparing files by content failed. 比對檔案內容失敗。 Generating file list... 產生檔案清單... -Multiple... -多個... - Both sides are equal 兩邊都相同 @@ -1349,6 +1332,12 @@ Transfer file and directory permissions (Requires Administrator rights) Delete right file/folder 刪除右邊檔案/資料夾 +Move file on left +移動左邊的檔案 + +Move file on right +移動右邊的檔案 + Overwrite left file/folder with right one 用適合檔案/資料夾覆蓋左邊檔案/資料夾 @@ -1364,6 +1353,9 @@ Transfer file and directory permissions (Requires Administrator rights) Copy file attributes only to right 只複製檔案屬性到右邊 +Multiple... +多個... + Deleting file %x 正在刪除檔案 %x diff --git a/BUILD/Languages/croatian.lng b/BUILD/Languages/croatian.lng new file mode 100644 index 00000000..cba3663a --- /dev/null +++ b/BUILD/Languages/croatian.lng @@ -0,0 +1,1490 @@ +

    + Hrvatski + Slavko Blažević + hr_HR + croatia.png + 3 + n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2 +
    + +Searching for directory %x... +Tražim direktorij %x... + +Show in Explorer +Prikaži u Exploreru + +Open with default application +Otvori s zadanom aplikacijom + +Browse directory +Odaberi direktorij + +RealtimeSync - Automated Synchronization +RealtimeSync - Automatska Sinkronizacija + +Select alternate comparison settings +Izaberite alternativne postavke usporedbe + +Select alternate synchronization settings +Izaberite alternativne postavke sinkronizacije + +No filter selected +Nijedan filter odabran + +Filter is active +Filter je aktivan + +Remove alternate settings +Ukloni alternativne postavke + +Clear filter settings +Počisti postavke filtera + +Create a batch job +Izradi batch zadatak + +Synchronization settings +Postavke sinkronizacije + +Comparison settings +Postavke usporedbe + +About +O programu + +Error +Greška + +Warning +Oprez + +Question +Pitanje + +Confirm +Potvrdi + +Configure filter +Konfiguriraj filter + +Customize columns +Uredi stupce + +Global settings +Globalne postavke + +Synchronization Preview +Pregled sinkronizacije + +Find +Pronađi + +Select time span +Izaberite mjerni raspon + +Show pop-up +Prikaži skočni prozor + +Show pop-up on errors or warnings +Prikaži skočni prozor pri greškama i upozorenjima + +Ignore errors +Ignoriraj greške + +Hide all error and warning messages +Sakrij sve greške i upozorenja + +Exit instantly +Izađi trenutno + +Abort synchronization immediately +Odmah prekini sinkronizaciju + +Browse +Odaberi + +Error reading from synchronization database: +Greška pri čitanju iz sinkronizacijske baze: + +Error writing to synchronization database: +Greška pri pisanju u sinkronizacijsku bazu: + +Invalid command line: %x +Netočna naredba: %x + +Windows Error Code %x: +Windows greška %x: + +Linux Error Code %x: +Linux greška %x: + +Error resolving symbolic link: +Pogreška pri otvaranju poveznice simbola: + +%x MB +%x MB + +%x KB +%x KB + +%x GB +%x GB + + +1 Byte +%x Bytes + + +%x Bajt +%x Bajta +%x Bajtova + + + + + + + + +Size +Veličina + +Date +Datum + +Full path +Puna putanja + +Filename +Ime datoteke + +Relative path +Relativna Putanja + +Directory +Direktorij + +Extension +Ekstenzija + +Comparison Result +Rezultati usporedbe + +Initial synchronization: +Početna sinkronizacija: + +One of the FreeFileSync database files is not yet existing: +Jedna od FreeFileSync datoteka podatkovne baze još ne postoji: + +Incompatible synchronization database format: +Nekompatibilan format sinkronizacijske podatkovne baze: + +Database files do not share a common synchronization session: +Datoteke podatkovne baze ne dijele zajedničke sinkronizacijske sesije: + +An exception occurred! +Dogodilo se izuzeće! + +Error reading file attributes: +Greška pri čitanju atributa datoteke: + +Waiting while directory is locked (%x)... +Čekam dok se direktorij zaključava (%x)... + +Error setting directory lock: +Greška pri postavljanju zaključenja direktorija: + + +1 sec +%x sec + + +%x sek +%x sek +%x sek + + +Drag && drop +Povuci && ispusti + +Info +Info + +Fatal Error +Kritična greška + +Error reading file: +Greška pri čitanju datoteke: + +Scanning: +Pretražujem: + +Encoding extended time information: %x +:Spremam informacije o vremenu %x + + +[1 Thread] +[%x Threads] + + +%x Stavka +%x Stavke +% Stavki + + +Invalid FreeFileSync config file! +Nevaljana FreeFileSync konfiguracijska datoteka! + +Error parsing configuration file: +Greška pri raščlanjivanju datoteke postavki: + +Error moving to Recycle Bin: +Greška pri premještanju u Koš za smeće: + +Could not load a required DLL: +Nemože se pokrenuti potrebni DLL: + +Error accessing Volume Shadow Copy Service! +Greška pri pristupu servisu particijskog kopiranja! + +Making shadow copies on WOW64 is not supported. Please use FreeFileSync 64-bit version. +Stvaranje sjeničnih kopija na WOW63 nije podržano. Molimo koristite 64-bitnu FreeFileSync inačnicu. + +Could not determine volume name for file: +Nemože se odrediti naziv particije za datoteku: + +Volume name %x not part of filename %y! +Naziv particije %x dio naziva datoteke %y! + +/sec +/sek + +File does not exist: +Datoteka ne postoji: + +Could not read values for the following XML nodes: +Nemogu pročitati vrijednosti iz slijedećih XML središta: + +S&ave configuration... +&Spremi postavke... + +&Load configuration... +&Uvezi postavke... + +&Quit +&Izlaz + +&File +&Datoteka + +&Content +&Sadržaj + +&About... +&O programu... + +&Help +&Pomoć + +Usage: +Uporaba: + +1. Select directories to monitor. +1. Izaberite mape za nadziranje + +2. Enter a command line. +2. Unesite naredbu. + +3. Press 'Start'. +3. Pretisnite 'Start'. + + +The command line is executed each time: +- all directories become available (e.g. USB stick insert) +- files within these directories or subdirectories are modified + + +Naredba će biti izvršena kada: +- sve mape postanu dostupne (npr. USB stick je umetnut) +- datoteke unutar tih mapa ili podmapa budu mijenjane + + +Directories to watch +Mape za nadziranje + +Add folder +Dodaj mapu + +Remove folder +Ukloni mapu + +Select a folder +Izaberite mapu + +Command line +Naredbena linija + +Minimum Idle Time [seconds] +Minimalno vrijeme pripravnosti [sekunde] + +Idle time between detection of last change and execution of command line in seconds +Vrijeme pripravnosti između pronalaska zadnje promjene i izvršenja naredbe u sekundama + +Start +Start + +(Build: %x) +(Inačnica: %x) + +RealtimeSync configuration +RealtimeSync postavke + +File already exists. Overwrite? +Datoteka već postoji. Prepisati? + +&Restore +&Vrati + +&Exit +&Izlaz + +Monitoring active... +Nadziranje aktivno... + +Waiting for missing directories... +Čekam nedostajuće direktorije... + +A directory input field is empty. +Upisno polje za direktorij je prazno. + +Logging +Zapisivanje + +FreeFileSync batch file +FreeFileSync batch datoteka + +FreeFileSync configuration +FreeFileSync postavke + +FreeFileSync Batch Job +FreeFileSync Batch zadatak + +Unable to create logfile! +Nemogu napraviti zapisnik! + +Batch execution +Batch izvršavanje + +Stop +Zaustavi + +Total time: +Ukupno vrijeme: + +Synchronization aborted! +Sinkronizacija prekinuta! + +Synchronization completed with errors! +Sinkronizacija završena s greškama! + +Synchronization completed successfully! +Sinkronizacija uspješno završena! + +Press "Switch" to open FreeFileSync GUI mode. +Pretisnite "Zamjena", da otvorite FreeFileSync GUI način. + +Switching to FreeFileSync GUI mode... +Prelazim na FreeFileSync GUI način... + +Unable to connect to sourceforge.net! +Ne mogu se povezati na sourceforge.net! + +A newer version of FreeFileSync is available: +Dostupna je nova verzija FreeFileSync: + +Download now? +Preuzeti sada? + +Information +Informacija + +FreeFileSync is up to date! +FreeFileSync je ažuriran! + +Do you want FreeFileSync to automatically check for updates every week? +Dali želite da FreeFileSync automatski traži ažuriranja svaki tjedan? + +(Requires an Internet connection!) +(Zahtjeva vezu na Internet!) + +1. &Compare +1. &Usporedi + +2. &Synchronize... +2. &Sinkroniziraj... + +S&witch view +Pr&omjeni pogled + +&New +&Novo + +&Program +&Program + +&Language +&Jezik + +&Global settings... +&Globalne postavke... + +&Create batch job... +&Izradi batch zadatak... + +&Export file list... +&Izvoz liste datoteka... + +&Advanced +&Napredno + +&Check for new version +&Provjeri za novu verziju + +Compare +Usporedi + +Compare both sides +Usporedi obje strane + +&Abort +&Odustani + +Synchronize... +Sinkroniziraj... + +Start synchronization +Započni sinkronizaciju + +Add folder pair +Dodaj mapu + +Remove folder pair +Odstrani mapu + +Swap sides +Zamjeni strane + +Save current configuration to file +Spremi sadašnje postavke u datoteku + +Load configuration from file +Uvezi postavke iz datoteke + +Last used configurations (press DEL to remove from list) +Zadnje korištene postavke (pretisite DEL za ukloniti s liste) + +Hide excluded items +Sakrij isključene stavke + +Hide filtered or temporarily excluded files +Sakrij filtrirane ili trenutno isključene datoteke + +Number of files and directories that will be created +Broj datoteka i direktorija koji će biti napravljeni + +Number of files that will be overwritten +Broj datoteka koje će biti prepisane + +Number of files and directories that will be deleted +Broj datoteka i direktorija koji će biti izbrisani + +Total amount of data that will be transferred +Ukupna količina podataka koja će biti prebečana + +Operation: +Operacija: + +Items found: +Pronađene stavke: + +Items remaining: +Preostale stavke: + +Speed: +Brzina: + +Time remaining: +Vremena preostalo: + +Time elapsed: +Vremena prošlo: + +Batch job +Batch zadatak + +Create a batch file for automated synchronization. To start in batch mode simply double-click the file or execute via command line: FreeFileSync.exe . This can also be scheduled in your operating system's task planner. +Napravite batch datoteku za automatsku sinkronizaciju. Da bi započeli batch mod dvostruki-klik na fajl ili izvršite pomoću komandne linije: FreeFileSync.exe . Ovo se također može zadati u planeru operacijskog sustava. + +Help +Pomoć + +Filter files +Filtriraj datoteke + +Error handling +Greška pri obradi + +Left +Lijevo + +Right +Desno + +Overview +Pregled + +Status feedback +Status veze + +Run minimized +Pokreni minimizirano + +Maximum number of logfiles: +Maksimalan broj izvješća: + +Select logfile directory: +Odaberite direktorij izvješća: + +Batch settings +Batch postavke + +&Save +&Spremi + +&Load +&Uvezi + +&Cancel +&Odustani + +Select variant: +Izaberite varijantu: + + + + +Identify and propagate changes on both sides using a database. Deletions, renaming and conflicts are detected automatically. +Identificiraj i izvedi promjene na obje strane koristeći bazu podataka. Brisanja, preimenovanja i sukobi se automatski detektiraju + +Mirror ->> +Zrcalno ->> + +Mirror backup of left folder. Right folder is modified to exactly match left folder after synchronization. +Zrcalna pričuva lijeve mape. Desna mapa je uređena da bi bila jednaka lijevom folderu nakon sinkronizacije. + +Update -> +Ažuriraj -> + +Copy new or updated files to right folder. +Kopiraj nove ili ažurirane datoteke u desnu mapu. + +Custom +Uobičajeno + +Configure your own synchronization rules. +Konfigurirajte vaša vlastita sinkronizacijska pravila. + +Deletion handling +Upravljanje pri brisanju + +&OK +&U redu + +Configuration +Postavke + +Category +Kategorija + +Action +Radnja + +File/folder exists on left side only +Datoteka/mapa postoji samo na lijevoj strani + +File/folder exists on right side only +Datoteka/mapa postoji samo na desnoj strani + +Left file is newer +Lijeva datoteka je novija + +Right file is newer +Desna datoteka je novija + +Files have different content +Datoteke imaju različit sadržaj + +Conflict/file cannot be categorized +Konflikt/datoteka ne more biti kategorizirana + +Compare by... +Usporedi prema... + + +Files are found equal if + - last write time and date + - file size +are the same + + +Datoteke se smatraju jednake ako su im + - vrijeme zadnje promjene i datum + - veličina datoteke +jednaki + + +File time and size +Vrijeme i veličina datoteke + + +Files are found equal if + - file content +is the same + + +Datoteke se smatraju jednake ako im je + - sadržaj datoteke +jednak + + +File content +Sadržaj datoteke + +Symbolic Link handling +Upravljanje simboličnim poveznicama + +Synchronizing... +Sinkroniziram... + +Items processed: +Obrađeni elementi: + +&Pause +&Pauziraj + +Source code written in C++ utilizing: +Izvorni kod napisan u C++ uz korištenje: + +Big thanks for localizing FreeFileSync goes out to: +Zahvale za prijevod FreeFileSync idu: + +Feedback and suggestions are welcome at: +Povratne informacije i prijedlozi su dobrodošli na: + +FreeFileSync at Sourceforge +FreeFileSync na Sourceforge + +Homepage +Početna stranica + +If you like FFS +Ako volite FFS + +Donate with PayPal +Doniraj s PayPal + +Email +Email + +Report translation error +Prijavi grešku u prijevodu + +Published under the GNU General Public License: +Objavljeno pod licencom GNU General Public: + +Ignore subsequent errors +Ignoriraj naknadne greške + +Hide further error messages during the current process +Sakrij iduće poruke grešaka tokom slijedećeg procesa + +&Ignore +&Ignoriraj + +&Retry +&Ponovi + +Do not show this dialog again +Ne prikazuj ovaj prozor ponovno + +&Switch +&Zamjeni + +&Yes +&Da + +&No +&Ne + +Delete on both sides +Izbriši na obje strane + +Delete on both sides even if the file is selected on one side only +Izbriši na obje strane iako je označena datoteka samo na jednoj strani + +Use Recycle Bin +Uporabi Koš za smeće + + +Only files/directories that match all filter settings will be selected for synchronization. +Note: The name filter must be specified relative(!) to main synchronization directories. + + +Samo datoteke/direktorije koji odgovaraju svim filterskim postavkama će biti odabrane za sinkronizaciju. +Napomena: Ime filtra mora biti određeno relativno(!) prema glavnim sinkronizacijskim direktorijima. + + +Hints: +Savjeti: + +1. Enter relative file or directory names separated by ';' or a new line. +1. Unesite relativno ime datoteke ili naziva direktorija odvojeno ';' ili novim redom. + +2. Use wildcard characters '*' and '?'. +2. Uporabite znakove poput '*' ili '?'. + +3. Exclude files directly on main grid via context menu. +3. Isključite datoteke neposredno na glavnoj mreži s kontekstnog menija. + +Example +Primjer + + +Include: *.doc;*.zip;*.exe +Exclude: \stuff\temp\* + + +Uključi: *.doc;*.zip;*.exe +Isključi: \stuff\temp\* + + +Synchronize all .doc, .zip and .exe files except everything in subfolder "temp". +Sinkroniziraj sve .doc, .zip i .exe datoteke, izuzev svega iz podmape "temp". + +Include +Uključi + +Exclude +Isključi + +Minimum file size +Minimalna veličina datoteke + +Maximum file size +Maksimalna veličina datoteke + +&Default +&Zadano + +Move column up +Premakni stupac gore + +Move column down +Premakni stupac dolje + +Transactional file copy +Transakcijsko kopiranje datoteke + +Write to a temporary file (*.ffs_tmp) first then rename it. This guarantees a consistent state even in case of fatal error. +Zapiši u privremenu datoteku (*.ffs_tmp) najprije a onda ju preimenuj. Ovo garantira nepromjenjivost čak u slučaju kritične greške. + +Copy locked files +Kopiraj zaključane datoteke + +Copy shared or locked files using Volume Shadow Copy Service (Requires Administrator rights) +Kopiraj zajedničke ili zaključane datoteke koristeći Volume Shadow Copy Servis(Zahtjeva Administratorske ovlasti) + +Copy file access permissions +Kopiraj datotečna dopuštenja + +Transfer file and directory permissions (Requires Administrator rights) +Prebaci datotečna dopuštenja (Zahtjeva Administratorske ovlasti) + +Hidden dialogs: +Skriveni prozori: + +Reset +Resetiraj + +Show hidden dialogs +Prikaži skrivene prozore + +External applications +Vanjske aplikacije + +Description +Opis + +Variant +Način + +Statistics +Statistika + +Find what: +Nađi što + +Match case +Poklopi se + +&Find next +&Nađi slijedeće + +Operation aborted! +Operacija otkazana! + +Main bar +Glavna traka + +Folder pairs +Par mape + +Select view +Izaberite pogled + +Set direction: +Odaberi smijer: + +Exclude temporarily +Trenutno izključi + +Include temporarily +Trenutno uključi + +Exclude via filter: +Isključi preko filtra: + + + + +D-Click +D-Klik + +Delete +Izbriši + +Customize... +Prilagodi... + +Select time span... +Izaberite vremenski raspon... + +Auto-adjust columns +Samo-prilagodi stupce + +Icon size: +Veličina Ikone + +Small +Malo + +Medium +Srednje + +Large +Veliko + +Include all rows +Uključi sve redove + +Exclude all rows +Isključi sve redove + +Reset view +Resetiraj pogled + +Show "%x" +Prikaži "%x" + + + + +Configuration saved! +Postavke spremljene! + +Save changes to current configuration? +Spremiti promjene na trenutne postavke? + +Configuration loaded! +Postavke učitane! + +Folder Comparison and Synchronization +Usporedba i sinkronizacija mapa + +Hide files that exist on left side only +Sakrij datoteke koje postoje samo na lijevoj strani + +Show files that exist on left side only +Prikaži datoteke koje postoje samo na lijevoj strani + +Hide files that exist on right side only +Sakrij datoteke koje koje postoje samo na desnoj strani + +Show files that exist on right side only +Prikaži datoteke koje postoje samo na desnoj strani + +Hide files that are newer on left +Sakrij datoteke koje su novije lijevo + +Show files that are newer on left +Prikaži datoteke koje su novije lijevo + +Hide files that are newer on right +Skrij datoteke koje su novije desno + +Show files that are newer on right +Prikaži datoteke koje su novije desno + +Hide files that are equal +Skrij jednake datoteke + +Show files that are equal +Prikaži jednake datoteke + +Hide files that are different +Sakrij datoteke koje su različite + +Show files that are different +Prikaži datoteke koje su različite + +Hide conflicts +Sakrij sukobe + +Show conflicts +Prikaži spore + +Hide files that will be created on the left side +Sakrij datoteke koje će biti napravljene na lijevoj strani + +Show files that will be created on the left side +Prikaži datoteke koje će biti napravljene na lijevoj strani + +Hide files that will be created on the right side +Sakrij datoteke koje će biti napravljene na desnoj strani + +Show files that will be created on the right side +Prikaži datoteke koje će biti napravljene na desnoj strani + +Hide files that will be deleted on the left side +Sakrij datoteke koje će biti izbrisane na lijevoj strani + +Show files that will be deleted on the left side +Prikaži datoteke koje će biti izbrisane na lijevoj strani + +Hide files that will be deleted on the right side +Skrij datoteke koje će biti izbrisane na desnoj strani + +Show files that will be deleted on the right side +Prikaži datoteke koje će biti izbrisane na desnoj strani + +Hide files that will be overwritten on left side +Skrij datoteke koje će biti prepisane na lijevoj strani + +Show files that will be overwritten on left side +Prikaži datoteke koje će biti prepisane na lijevoj strani + +Hide files that will be overwritten on right side +Skrij datoteke koje će biti prepisane na desnoj strani + +Show files that will be overwritten on right side +Prikaži datoteke koje će biti prepisane na desnoj strani + +Hide files that won't be copied +Sakrij datoteke koje neće biti kopirane + +Show files that won't be copied +Prikaži datoteke koje neće biti kopirane + +All directories in sync! +Svi direktoriji su sinkronizirani! + +Please run a Compare first before synchronizing! +Molmo pokrenite Usporedbu prije sinkronizacije! + +Comma separated list +Zarezom odvojene liste + +Legend +Legenda + +File list exported! +Datotečna lista izvezena! + +Error writing file: +Napaka pri pisanju datoteke: + +Batch file created successfully! +Batch datoteka uspješno izrađena! + + +Object deleted successfully! +%x objects deleted successfully! + + +%x Objekt uspješno izbrisan! +%x objekta uspješno izbrisana! +%x objekata uspješno izbrisano! + + + +1 directory +%x directories + + +%x direktorij +%x direktorija +%x direktorija + + + +1 file +%x files + + +%x datoteka +%x datoteke +%x datoteka + + + +%x of 1 row in view +%x of %y rows in view + + +%x od %y red u prikazu +%x od %y reda u prikazu +%x od %y redova u prikazu + + +Scanning... +Pregledajem... + +Comparing content... +Uspoređujem sadržaj... + +Paused +Pauzirano + +Aborted +Prekinuto + +Completed +Završeno + +Abort requested: Waiting for current operation to finish... +Prekid zahtjevan: čekam da se trenutna akcija završi... + +Continue +Nastavi + +Pause +Pauziraj + +Cannot find %x +Nemogu pronać %x + +Inactive +Neaktivno + +Last x hours +Zadnjih x sati + +Today +Danas + +This week +Ovaj tjedan + +This month +Ovaj mjesec + +This year +Ove godine + +Byte +Bajt + +KB +KB + +MB +MB + +Filter: All pairs +Filtriraj: Sve parove + +Filter: Single pair +Filtriraj: Sam par + +Direct +Neposredno + +Follow +Slijedi + +Copy NTFS permissions +Kopiraj NTFS dopuštenja + +Integrate external applications into context menu. The following macros are available: +Integriraj vanjske aplikacije u kontekstni meni. Sljedeći makroi su dostupni: + +- full file or directory name +- puno ime datoteke ili direktorija + +- directory part only +- samo dio direktorija + +- Other side's counterpart to %name +- Duplikat s druge strane k %name + +- Other side's counterpart to %dir +- Duplikat s druge strane k %dir + +Restore all hidden dialogs? +Vrati sve skrivene prozore? + + +Do you really want to move the following object to the Recycle Bin? +Do you really want to move the following %x objects to the Recycle Bin? + + +Dali zaista želite prebaciti navedeni %x objekt u Koš za smeće? +Dali zaista želite prebaciti navedena %x objekta u Koš za smeće? +Dali zaista želite prebaciti navedenih %x objekata u Koš za smeće? + + + +Do you really want to delete the following object? +Do you really want to delete the following %x objects? + + +Dali zaista želite izbrisati navedeni %x objekt? +Dali zaista želite izbrisati navedena %x objekta? +Dali zaista želite izbrisati navedenih %x objekata? + + +Leave as unresolved conflict +Ostavi kao neriješeni sukob + +Delete permanently +Trajno izbriši + +Delete or overwrite files permanently +Trajno izbriši ili prepiši datoteke + +Use Recycle Bin when deleting or overwriting files +Koristi Koš za smeće pri brisanju ili prepisivanju datoteka + +Versioning +Verzija + +Move files into a time-stamped subdirectory +Premjesti datoteke u vremenski-označen podfolder + +%x TB +%x TB + +%x PB +%x PB + +%x% +%x% + + +1 min +%x min + + +%x min +%x min +%x min + + + +1 hour +%x hours + + +%x sat +%x sata +%x sati + + + +1 day +%x days + + +%x dan +%x dana +%x dana + + +Could not initialize directory monitoring: +Ne mogu započeti nadziranje direktorija: + +Error when monitoring directories. +Greška pri nadziranju direktorija. + +Conversion error: +Greška pri pretvorbi: + +Error deleting file: +Greška pri brisanju datoteke: + +Error moving file: +Greška pri premještanju datoteke: + +Target file already existing! +Ciljna datoteka već postoji! + +Error moving directory: +Greška pri premještanju direktorija: + +Target directory already existing! +Ciljni direktorij već postoji! + +Error deleting directory: +Greška pri brisanju direktorija: + +Error changing modification time: +Greška pri promjeni vremena izmjene: + +Error loading library function: +Greška pri zadavanju funkcije iz knjižnice: + +Error reading security context: +Greška pri čitanju zaštićenog sadržaja: + +Error writing security context: +Greška pri pisanju zaštićenog sadržaja: + +Error copying file permissions: +Greška pri kopiranju datotečnih dopuštenja: + +Error creating directory: +Greška pri izradi direktorija: + +Error copying symbolic link: +Greška pri kopiranju poveznice simbola: + +Error copying file: +Greška pri kopiranju datoteke: + +Error opening file: +Greška pri otvaranju datoteke: + +Error traversing directory: +Greška pri prelasku direktorija: + +Endless loop when traversing directory: +Beskonačna petlja pri prelasku direktorija: + +Error setting privilege: +Greška pri postavljanju dopuštenja: + +Both sides have changed since last synchronization! +Obje su strane promjenjene od posljednje sinkronizacije! + +Cannot determine sync-direction: +Ne mogu odrediti smijer sinkronizacije. + +No change since last synchronization! +Nema promjena od zadnje sinkronizacije! + +Filter settings have changed! +Filterske postavke su promjenjene! + +The file was not processed by last synchronization! +Datoteka nije procesirana tokom prošle sinkronizacije ! + +Setting default synchronization directions: Old files will be overwritten with newer files. +Postavljam zadani sinkronizacijski smijer: Stare datoteke će biti prepisane novim datotekama. + +The file does not contain a valid configuration: +Datoteka ne sadrži ispravne postavke: + +You can ignore this error to consider the directory as empty. +Možete ignorirati ovu grešku uzimajući datoteku kao praznu . + +Directory does not exist: +Direktorij ne postoji: + +Directories are dependent! Be careful when setting up synchronization rules: +Direktoriji su u ovisnosti! Budite oprezni pri postavljanju sinkronizacijskih pravila: + +Memory allocation failed! +Neuspješno dodjeljivanje memorije! + +File %x has an invalid date! +Datoteka %x ima nevaljan datum! + +Conflict detected: +Sukob pronađen: + +Files %x have the same date but a different size! +Datoteke %x imaju isti datum ali drugačiju veličinu! + +Symlinks %x have the same date but a different target! +Simbolične poveznice %x imaju isti datum ali drugačiji cilj! + +Comparing content of files %x +Uspoređujem sadržaj datoteka %x + +Comparing files by content failed. +Usporedba datoteka prema sadržaju nije uspjela. + +Generating file list... +Generiram listu datoteka... + +Both sides are equal +Obje strane su jednake + +Files/folders differ in attributes only +Datoteke/mape se razlikuju samo u atributima + +Copy new file/folder to left +Kopiraj novu datoteku/mapu na lijevo + +Copy new file/folder to right +Kopiraj novu datoteku/mapu na desno + +Delete left file/folder +Izbriši lijevu datoteku/mapu + +Delete right file/folder +Izbriši desnu datoteku/mapu + +Move file on left +Premjesti datoteku lijevo + +Move file on right +Premjest datoteku desno + +Overwrite left file/folder with right one +Prepiši lijevu datoteku/mapu s onom sa desne strane + +Overwrite right file/folder with left one +Prepiši desnu datoteku/mapu s onom sa lijeve strane + +Do nothing +Ne radi ništa + +Copy file attributes only to left +Kopiraj atribute datoteke samo na levo + +Copy file attributes only to right +Kopiraj atribute datoteke samo na desno + +Multiple... +Mnogostruko... + +Deleting file %x +Brisanje datoteke %x + +Deleting folder %x +Brisanje mape %x + +Deleting symbolic link %x +Brisanje simboličnih poveznica %x + +Moving file %x to recycle bin +Premještam datoteku %x u Koš za smeće + +Moving folder %x to recycle bin +Premještam mapu %x u Koš za smeće + +Moving symbolic link %x to recycle bin +Premještam simboličnu poveznicu %x u Koš za smeće + +Moving file %x to %y +Premještam datoteku %x u %y + +Moving folder %x to %y +Premještam mapu %x u %y + +Moving symbolic link %x to %y +Premještam simboličnu poveznicu %x u %y + +Creating file %x +Izrađujem datoteku %x + +Creating symbolic link %x +Izrađujem simboličnu poveznicu %x + +Creating folder %x +Izrađujem mapu %x + +Overwriting file %x +Prepisujem datoteku %x + +Overwriting symbolic link %x +Prepisujem simboličnu poveznicu %x + +Verifying file %x +Provjeravam datoteku %x + +Updating attributes of %x +Obnavljam atribute od %x + +Target directory name must not be empty! +Ime ciljnog direktorija ne smije biti prazno! + +User-defined directory for deletion was not specified! +Korisnički definiran direktorij za brisanje nije definiran! + +Source directory does not exist anymore: +Izvorni direktorij više ne postoji: + +Unresolved conflicts existing! +Nerješivi sukob postoji! + +You can ignore conflicts and continue synchronization. +Možete ignorirati sukob i nastaviti s sinkronizacijom. + +Significant difference detected: +Značajna razlika opažena: + +More than 50% of the total number of files will be copied or deleted! +Više od 50% od ukupnog broja datoteka će biti kopirano ili izbrisano! + +Not enough free disk space available in: +Nedovoljno prostora na disku: + +Free disk space required: +Potreban prostor na disku: + +Free disk space available: +Prostor na disku dostupan: + +Recycle Bin is not available for the following paths! Files will be deleted permanently instead: +Koš za smeće nije dostupan za navedene putanje! Umjesto toga datoteke će biti trajno izbrisane: + +A directory will be modified which is part of multiple folder pairs! Please review synchronization settings! +Direktorij će biti mjenjan koji je dio više parova mapa! Molimo pogledajte postavke sinkronizacije! + +Processing folder pair: +Obrađujem parove mapa: + +Generating database... +Izrađujem bazu podataka... + +Nothing to synchronize according to configuration! +Po trenutnim postavkama nema ništa za sinkroniziranje! + +Error copying locked file %x! +Greška pri kopiranju zaključane datoteke %x! + +Data verification error: Source and target file have different content! +Greška pri provjeravanju podataka: Izvorna i ciljna datoteka imaju različit sadržaj! + diff --git a/BUILD/Languages/czech.lng b/BUILD/Languages/czech.lng index d3dd805e..fb72c119 100644 --- a/BUILD/Languages/czech.lng +++ b/BUILD/Languages/czech.lng @@ -22,39 +22,6 @@ RealtimeSync - Automated Synchronization RealtimeSync - Automatická synchronizace -Browse -Procházet - -Windows Error Code %x: -Chybový kód Windows %x: - -Linux Error Code %x: -Chybový kód Linux %x: - -Invalid command line: %x -Neplatný příkaz: %x - -Error resolving symbolic link: -Chyba odkazu zástupce: - -Show pop-up -Zobrazit okno - -Show pop-up on errors or warnings -Zobrazit hlášení při chybě nebo varování - -Ignore errors -Přeskočit chyby - -Hide all error and warning messages -Skrýt všechny chyby a varování - -Exit instantly -Ukončit ihned - -Abort synchronization immediately -Přerušit synchronizaci ihned - Select alternate comparison settings Změnit nastavení porovnání @@ -115,6 +82,45 @@ Select time span Časové rozmezí +Show pop-up +Zobrazit okno + +Show pop-up on errors or warnings +Zobrazit hlášení při chybě nebo varování + +Ignore errors +Přeskočit chyby + +Hide all error and warning messages +Skrýt všechny chyby a varování + +Exit instantly +Ukončit ihned + +Abort synchronization immediately +Přerušit synchronizaci ihned + +Browse +Procházet + +Error reading from synchronization database: +Chyba čtení synchronizační databáze: + +Error writing to synchronization database: +Chyba zápisu synchronizační databáze: + +Invalid command line: %x +Neplatný příkaz: %x + +Windows Error Code %x: +Chybový kód Windows %x: + +Linux Error Code %x: +Chybový kód Linux %x: + +Error resolving symbolic link: +Chyba odkazu zástupce: + %x MB %x MB @@ -164,17 +170,14 @@ Comparison Result Výsledek porovnání -Incompatible synchronization database format: -Chyba formátu synchronizační databáze: - Initial synchronization: Prvotní synchronizace: One of the FreeFileSync database files is not yet existing: Některý z databázových souborů FreeFileSync neexistuje: -Error reading from synchronization database: -Chyba čtení synchronizační databáze: +Incompatible synchronization database format: +Chyba formátu synchronizační databáze: Database files do not share a common synchronization session: Databázové soubory nejsou navzájem komplementární @@ -201,12 +204,18 @@ %x sekund +Drag && drop +Drag && Drop + Info Info Fatal Error Závažná chyba +Error reading file: +Chyba čtení souboru: + Scanning: Zpracováváno: @@ -226,15 +235,36 @@ Invalid FreeFileSync config file! Chybný konfigurační soubor FreeFileSync! -File does not exist: -Soubor neexistuje: - Error parsing configuration file: Chyba zpracování konfigurace: +Error moving to Recycle Bin: +Chyba přesunu do Koše: + +Could not load a required DLL: +Nelze načíst požadovanou knihovnu DLL: + +Error accessing Volume Shadow Copy Service! +Chyba přístupu ke službě Volume Shadow Copy Service! + +Making shadow copies on WOW64 is not supported. Please use FreeFileSync 64-bit version. +Vytváření stínových kopií na WOW64 není podporováno. Prosím použijte 64 bitovou verzi FreeFileSync. + +Could not determine volume name for file: +Není možné zjistit jméno jednotky souboru: + +Volume name %x not part of filename %y! +Disk %x není součástí jména souboru %y! + /sec /s +File does not exist: +Soubor neexistuje: + +Could not read values for the following XML nodes: +Nelze načíst hodnoty následujících XML elementy: + S&ave configuration... &Uložení konfigurace... @@ -327,144 +357,6 @@ Příkazová řádka je spuštěna pokaždé když: A directory input field is empty. Není zadán vstupní adresář. -Drag && drop -Drag && Drop - -Could not initialize directory monitoring: -Nelze nastavit monitorování adresáře: - -Error when monitoring directories. -Chyba při sledování adresářů. - -Conversion error: -Chyba konverze: - -Error deleting file: -Chyba mazání souboru: - -Error moving file: -Chyba přesouvání souboru: - -Target file already existing! -Cílový soubor již existuje! - -Error moving directory: -Chyba přesouvání adresáře: - -Target directory already existing! -Cílový adresář již existuje! - -Error deleting directory: -Chyba mazání adresáře: - -Error changing modification time: -Chyba nastavení času změny: - -Error loading library function: -Chyba načtení knihovny funkcí: - -Error reading security context: -Chyba při čtení přístupových práv: - -Error writing security context: -Chyba při zápisu přístupových práv: - -Error copying file permissions: -Chyba kopírování oprávnění souborů: - -Error creating directory: -Chyba vytvoření adresáře: - -Error copying symbolic link: -Chyba kopírování zástupce: - -Error copying file: -Chyba kopírování souboru: - -Error opening file: -Chyba otevření souboru: - -Error writing file: -Chyba zápisu souboru: - -Error reading file: -Chyba čtení souboru: - -Operation aborted! -Operace zrušena! - -Endless loop when traversing directory: -Zacyklení při procházení adresáře: - -Error traversing directory: -Chyba procházení adresáře: - -Error setting privilege: -Chyba nastavení práv: - -Error moving to Recycle Bin: -Chyba přesunu do Koše: - -Could not load a required DLL: -Nelze načíst požadovanou knihovnu DLL: - -Error writing to synchronization database: -Chyba zápisu synchronizační databáze: - -Error accessing Volume Shadow Copy Service! -Chyba přístupu ke službě Volume Shadow Copy Service! - -Making shadow copies on WOW64 is not supported. Please use FreeFileSync 64-bit version. -Vytváření stínových kopií na WOW64 není podporováno. Prosím použijte 64 bitovou verzi FreeFileSync. - -Could not determine volume name for file: -Není možné zjistit jméno jednotky souboru: - -Volume name %x not part of filename %y! -Disk %x není součástí jména souboru %y! - -%x TB -%x TB - -%x PB -%x PB - -%x% -%x% - - -1 min -%x min - - -1 minuta -%x minuty -%x minut - - - -1 hour -%x hours - - -1 hodina -%x hodiny -%x hodin - - - -1 day -%x days - - -1 den -%x dny -%x dnů - - -Could not read values for the following XML nodes: -Nelze načíst hodnoty následujících XML elementy: - Logging Zaznamenávání @@ -483,9 +375,6 @@ Příkazová řádka je spuštěna pokaždé když: Batch execution Spuštění dávky -Log-messages: -Záznamy: - Stop Stop @@ -612,6 +501,24 @@ Příkazová řádka je spuštěna pokaždé když: Total amount of data that will be transferred Celkový objem dat, který bude přenesen +Operation: +Operace: + +Items found: +Nalezeno položek: + +Items remaining: +Zbývá položek: + +Speed: +Rychlost: + +Time remaining: +Zbývající čas: + +Time elapsed: +Uplynulý čas: + Batch job Dávkový soubor @@ -660,32 +567,14 @@ Příkazová řádka je spuštěna pokaždé když: &Cancel &Zrušit -Operation: -Operace: - -Items found: -Nalezeno položek: - -Items remaining: -Zbývá položek: - -Speed: -Rychlost: - -Time remaining: -Zbývající čas: - -Time elapsed: -Uplynulý čas: - Select variant: Vyberte variantu: <- Automaticky -> -Identify and propagate changes on both sides using a database. Deletions and conflicts are detected automatically. -Rozpoznat a provést změny na obou stranách pomocí databáze. Odstraněné soubory a konflikty budou detekovány automaticky. +Identify and propagate changes on both sides using a database. Deletions, renaming and conflicts are detected automatically. +Rozpoznat a provést změny na obou stranách pomocí databáze. Odstraněné nebo přejmenované soubory a konflikty budou detekovány automaticky. Mirror ->> Zrcadlení ->> @@ -907,27 +796,19 @@ Vynechat: \někde\něco\* Bezpečné kopírování souborů Write to a temporary file (*.ffs_tmp) first then rename it. This guarantees a consistent state even in case of fatal error. - +Kopíruje data nejprve do pomocného souboru (*.ffs_tmp) a poté teprve soubor přejmenuje. Tento postup zajišťuje bezpečné chování i v případě chyby během přenosu Copy locked files Kopírovat zamčené soubory - -Copy shared or locked files using Volume Shadow Copy Service (Requires Administrator rights) - - -Kopírovat sdílené nebo zamčené soubory pomocí Volume Shadow Copy Service (Vyžaduje administrátorské oprávnění) - +Copy shared or locked files using Volume Shadow Copy Service (Requires Administrator rights) +Kopírovat sdílené nebo zamčené soubory pomocí Volume Shadow Copy Service (Vyžaduje administrátorské oprávnění) Copy file access permissions Kopírovat přístupová oprávnění k souborům - -Transfer file and directory permissions (Requires Administrator rights) - - -Přenést přístupová oprávnění souborů a adresářů (Vyžaduje administrátorké oprávnění) - +Transfer file and directory permissions (Requires Administrator rights) +Přenést přístupová oprávnění souborů a adresářů (Vyžaduje administrátorké oprávnění) Hidden dialogs: Skryté dialogy: @@ -959,6 +840,9 @@ Přenést přístupová oprávnění souborů a adresářů (Vyžaduje administr &Find next &Najít další +Operation aborted! +Operace zrušena! + Main bar Hlavní lišta @@ -999,16 +883,16 @@ Přenést přístupová oprávnění souborů a adresářů (Vyžaduje administr Automaticky přizpůsobit šířku Icon size: - +Velikost ikon: Small - +Malé Medium - +Střední Large - +Velké Include all rows Použít všechny řádky @@ -1136,6 +1020,9 @@ Přenést přístupová oprávnění souborů a adresářů (Vyžaduje administr File list exported! Seznam souborů exportován! +Error writing file: +Chyba zápisu souboru: + Batch file created successfully! Dávka úspěšně vytvořena! @@ -1239,9 +1126,6 @@ Přenést přístupová oprávnění souborů a adresářů (Vyžaduje administr Filter: Single pair Filtr: Jeden pár -Ignore -Přeskočit - Direct Zachovat @@ -1307,6 +1191,108 @@ Přenést přístupová oprávnění souborů a adresářů (Vyžaduje administr Move files into a time-stamped subdirectory Přesunout soubory do časově označeného podadresáře +%x TB +%x TB + +%x PB +%x PB + +%x% +%x% + + +1 min +%x min + + +1 minuta +%x minuty +%x minut + + + +1 hour +%x hours + + +1 hodina +%x hodiny +%x hodin + + + +1 day +%x days + + +1 den +%x dny +%x dnů + + +Could not initialize directory monitoring: +Nelze nastavit monitorování adresáře: + +Error when monitoring directories. +Chyba při sledování adresářů. + +Conversion error: +Chyba konverze: + +Error deleting file: +Chyba mazání souboru: + +Error moving file: +Chyba přesouvání souboru: + +Target file already existing! +Cílový soubor již existuje! + +Error moving directory: +Chyba přesouvání adresáře: + +Target directory already existing! +Cílový adresář již existuje! + +Error deleting directory: +Chyba mazání adresáře: + +Error changing modification time: +Chyba nastavení času změny: + +Error loading library function: +Chyba načtení knihovny funkcí: + +Error reading security context: +Chyba při čtení přístupových práv: + +Error writing security context: +Chyba při zápisu přístupových práv: + +Error copying file permissions: +Chyba kopírování oprávnění souborů: + +Error creating directory: +Chyba vytvoření adresáře: + +Error copying symbolic link: +Chyba kopírování zástupce: + +Error copying file: +Chyba kopírování souboru: + +Error opening file: +Chyba otevření souboru: + +Error traversing directory: +Chyba procházení adresáře: + +Endless loop when traversing directory: +Zacyklení při procházení adresáře: + +Error setting privilege: +Chyba nastavení práv: + Both sides have changed since last synchronization! Došlo ke změně obou stran od poslední synchronizace! @@ -1337,9 +1323,6 @@ Přenést přístupová oprávnění souborů a adresářů (Vyžaduje administr Directories are dependent! Be careful when setting up synchronization rules: Adresáře jsou závislé! Buďte opatrní s definicí synchronizačních pravidel: -Comparing content of files %x -Porovnávání obsahu souborů %x - Memory allocation failed! Chyba přidělení paměti! @@ -1355,15 +1338,15 @@ Přenést přístupová oprávnění souborů a adresářů (Vyžaduje administr Symlinks %x have the same date but a different target! Symbolický odkaz %x má stejné datum ale jiný cíl! +Comparing content of files %x +Porovnávání obsahu souborů %x + Comparing files by content failed. Porovnání obsahu souborů se nezdařilo. Generating file list... Vytváření seznamu souborů... -Multiple... -Různé... - Both sides are equal Obě strany jsou shodné @@ -1382,6 +1365,12 @@ Přenést přístupová oprávnění souborů a adresářů (Vyžaduje administr Delete right file/folder Smazat soubor/adresáře z prava +Move file on left +Přesunout soubor nalevo + +Move file on right +Přesunout soubor napravo + Overwrite left file/folder with right one Přepsat levý soubor/adresář tím z prava @@ -1397,6 +1386,9 @@ Přenést přístupová oprávnění souborů a adresářů (Vyžaduje administr Copy file attributes only to right Kopírovat vlastnosti souboru pouze do prava +Multiple... +Různé... + Deleting file %x Mazání souboru %x diff --git a/BUILD/Languages/danish.lng b/BUILD/Languages/danish.lng index d13de994..cc3d8536 100644 --- a/BUILD/Languages/danish.lng +++ b/BUILD/Languages/danish.lng @@ -22,39 +22,6 @@ RealtimeSync - Automated Synchronization RealtimeSynk - Automatisk Synkronisering -Browse -Gennemse - -Windows Error Code %x: -Windows Fejl kode %x: - -Linux Error Code %x: -Linux Fejl kode %x: - -Invalid command line: %x -Ugyldig kommando: %x - -Error resolving symbolic link: -Fejl i at finde link: - -Show pop-up -Vis pop-up - -Show pop-up on errors or warnings -Vis pop-up ved fejl eller advarsler - -Ignore errors -Ignorer fejl - -Hide all error and warning messages -Skjul beskeder om fejl og advarsler - -Exit instantly -Afslut med det samme - -Abort synchronization immediately -Abort synkronisering med det samme - Select alternate comparison settings Vælg alternative sammenlignings indstillinger @@ -115,6 +82,45 @@ Select time span Vælg tids område +Show pop-up +Vis pop-up + +Show pop-up on errors or warnings +Vis pop-up ved fejl eller advarsler + +Ignore errors +Ignorer fejl + +Hide all error and warning messages +Skjul beskeder om fejl og advarsler + +Exit instantly +Afslut med det samme + +Abort synchronization immediately +Abort synkronisering med det samme + +Browse +Gennemse + +Error reading from synchronization database: +Fejl i læsning fra synkroniserings databasen: + +Error writing to synchronization database: +Fejl i skrivning til synkroniserings databasen: + +Invalid command line: %x +Ugyldig kommando: %x + +Windows Error Code %x: +Windows Fejl kode %x: + +Linux Error Code %x: +Linux Fejl kode %x: + +Error resolving symbolic link: +Fejl i at finde link: + %x MB %x MB @@ -163,17 +169,14 @@ Comparison Result Sammenlignings Resultat -Incompatible synchronization database format: -Ukompatibelt synkroniserings database format: - Initial synchronization: Indledende synkronisering: One of the FreeFileSync database files is not yet existing: En af FreeFileSync database filerne findes ikke endnu: -Error reading from synchronization database: -Fejl i læsning fra synkroniserings databasen: +Incompatible synchronization database format: +Ukompatibelt synkroniserings database format: Database files do not share a common synchronization session: Database filer deler ikke en fælles synkroniserings session @@ -199,12 +202,18 @@ %x sek +Drag && drop +Træk && slip + Info Info Fatal Error Uoprettelig Fejl +Error reading file: +Fejl i læsning af fil: + Scanning: Skanner: @@ -223,15 +232,36 @@ Invalid FreeFileSync config file! Ugyldig FreeFileSync config fil! -File does not exist: -Filen findes ikke: - Error parsing configuration file: Fejl i at lave konfigurations filen: +Error moving to Recycle Bin: +Fejl i at flytte til skraldespand: + +Could not load a required DLL: +Kunne ikke hente en krævet DLL: + +Error accessing Volume Shadow Copy Service! +Fejl i adgang til Enhedens Kopi Service + +Making shadow copies on WOW64 is not supported. Please use FreeFileSync 64-bit version. +At lave spejl kopier af WOW64 er ikke understøttet. Brug venligst FreeFileSync 64-bit version. + +Could not determine volume name for file: +Kunne ikke finde drev navn til filen: + +Volume name %x not part of filename %y! +Drev navn %x ikke en del af filnavn %y! + /sec /sek +File does not exist: +Filen findes ikke: + +Could not read values for the following XML nodes: +Kunne ikke læse værdierne for følgende XML punkter: + S&ave configuration... G&em konfiguration... @@ -324,141 +354,6 @@ Kommando linjen bliver afviklet hver gang: A directory input field is empty. Et biblioteks felt er tomt. -Drag && drop -Træk && slip - -Could not initialize directory monitoring: -Kunne ikke initialiserer biblioteks overvågningen: - -Error when monitoring directories. -Fejl i overvågning af biblioteker. - -Conversion error: -Konverterings fejl: - -Error deleting file: -Fejl i sletning af fil: - -Error moving file: -Fejl i flytning af fil: - -Target file already existing! -Filen findes i forvejen! - -Error moving directory: -Fejl i flytning af bibliotek: - -Target directory already existing! -Bibliotek findes i forvejen! - -Error deleting directory: -Fejl i sletning af bibliotek: - -Error changing modification time: -Fejl i ændring af modificerings tiden: - -Error loading library function: -Fejl i biblioteks funktionen: - -Error reading security context: -Fejl i læsning af sikkerhedstilladelser: - -Error writing security context: -Fejl i skrivning af sikkerhedstilladelser: - -Error copying file permissions: -Fejl i kopiering af filtilladelser: - -Error creating directory: -Fejl i oprettelse af bibliotek: - -Error copying symbolic link: -Fejl i kopiering af link: - -Error copying file: -Fejl i kopiering af fil: - -Error opening file: -Fejl i åbning af fil: - -Error writing file: -Fejl i at skrive fil: - -Error reading file: -Fejl i læsning af fil: - -Operation aborted! -Operation afbrudt! - -Endless loop when traversing directory: -Uendelig løkke ved gennemgang af bibliotek: - -Error traversing directory: -Fejl i gennemgang af bibliotek: - -Error setting privilege: -Fejl i at sætte privilegier: - -Error moving to Recycle Bin: -Fejl i at flytte til skraldespand: - -Could not load a required DLL: -Kunne ikke hente en krævet DLL: - -Error writing to synchronization database: -Fejl i skrivning til synkroniserings databasen: - -Error accessing Volume Shadow Copy Service! -Fejl i adgang til Enhedens Kopi Service - -Making shadow copies on WOW64 is not supported. Please use FreeFileSync 64-bit version. -At lave spejl kopier af WOW64 er ikke understøttet. Brug venligst FreeFileSync 64-bit version. - -Could not determine volume name for file: -Kunne ikke finde drev navn til filen: - -Volume name %x not part of filename %y! -Drev navn %x ikke en del af filnavn %y! - -%x TB -%x TB - -%x PB -%x PB - -%x% -%x% - - -1 min -%x min - - -1 min -%x min - - - -1 hour -%x hours - - -1 timer -%x timer - - - -1 day -%x days - - -1 dag -%x dage - - -Could not read values for the following XML nodes: -Kunne ikke læse værdierne for følgende XML punkter: - Logging Logger @@ -477,9 +372,6 @@ Kommando linjen bliver afviklet hver gang: Batch execution Batch afvikling -Log-messages: -Log-beskeder: - Stop Stop @@ -606,6 +498,24 @@ Kommando linjen bliver afviklet hver gang: Total amount of data that will be transferred Samlet antal data der vil blive overført +Operation: +Igang: + +Items found: +Enheder fundet: + +Items remaining: +Enheder tilbage: + +Speed: +Hastighed: + +Time remaining: +Tid tilbage: + +Time elapsed: +Tid gået: + Batch job Batch job @@ -654,32 +564,14 @@ Kommando linjen bliver afviklet hver gang: &Cancel &Anuller -Operation: -Igang: - -Items found: -Enheder fundet: - -Items remaining: -Enheder tilbage: - -Speed: -Hastighed: - -Time remaining: -Tid tilbage: - -Time elapsed: -Tid gået: - Select variant: Vælg variant: -Identify and propagate changes on both sides using a database. Deletions and conflicts are detected automatically. -Indentifiser og udbred ændringer på begge sider via. database. Sletninger og konflikter opdages automatisk. +Identify and propagate changes on both sides using a database. Deletions, renaming and conflicts are detected automatically. +find ændringer på begge sider via. database. Sletninger, omdøbninger og konflikter bliver automatisk fundet. Mirror ->> Spejl ->> @@ -901,27 +793,19 @@ Udeluk: \ting\temp\* Transaktionel fil kopiering Write to a temporary file (*.ffs_tmp) first then rename it. This guarantees a consistent state even in case of fatal error. - +Skriv til en midlertidig fil (*.ffs_tmp) først så omdøb den. Dette garanterer sikkerheden selv ved en kritisk fejl. Copy locked files Kopier låste filer - -Copy shared or locked files using Volume Shadow Copy Service (Requires Administrator rights) - - -Kopier delte eller låste filer ved hjælp af Drev Kopi Servicen (Kræver Administrator rettigheder) - +Copy shared or locked files using Volume Shadow Copy Service (Requires Administrator rights) +Kopier delte eller låste filer ved hjælp af Drev Kopi Servicen (Kræver Administrator rettigheder) Copy file access permissions Kopier fil adgangs tilladelser - -Transfer file and directory permissions (Requires Administrator rights) - - -Overfør fil og biblioteks tilladelser (Kræver Administrator rettigheder) - +Transfer file and directory permissions (Requires Administrator rights) +Overfør fil og biblioteks tilladelser (Kræver Administrator rettigheder) Hidden dialogs: Skjulte dialoger: @@ -953,6 +837,9 @@ Overfør fil og biblioteks tilladelser (Kræver Administrator rettigheder) &Find next &Find næste +Operation aborted! +Operation afbrudt! + Main bar Hoved værktøjslinjen @@ -993,16 +880,16 @@ Overfør fil og biblioteks tilladelser (Kræver Administrator rettigheder) Auto-juster kolonner Icon size: - +Ikon størrelse: Small - +Lille Medium - +Mellem Large - +Stor Include all rows Inkluder alle rækker @@ -1130,6 +1017,9 @@ Overfør fil og biblioteks tilladelser (Kræver Administrator rettigheder) File list exported! Fil listen er eksporteret! +Error writing file: +Fejl i at skrive fil: + Batch file created successfully! Batch fil oprettet! @@ -1229,9 +1119,6 @@ Overfør fil og biblioteks tilladelser (Kræver Administrator rettigheder) Filter: Single pair Filter: Par -Ignore -Ignorer - Direct Direkte @@ -1295,6 +1182,105 @@ Overfør fil og biblioteks tilladelser (Kræver Administrator rettigheder) Move files into a time-stamped subdirectory Flyt filer til et datomærket underbibliotek +%x TB +%x TB + +%x PB +%x PB + +%x% +%x% + + +1 min +%x min + + +1 min +%x min + + + +1 hour +%x hours + + +1 timer +%x timer + + + +1 day +%x days + + +1 dag +%x dage + + +Could not initialize directory monitoring: +Kunne ikke initialiserer biblioteks overvågningen: + +Error when monitoring directories. +Fejl i overvågning af biblioteker. + +Conversion error: +Konverterings fejl: + +Error deleting file: +Fejl i sletning af fil: + +Error moving file: +Fejl i flytning af fil: + +Target file already existing! +Filen findes i forvejen! + +Error moving directory: +Fejl i flytning af bibliotek: + +Target directory already existing! +Bibliotek findes i forvejen! + +Error deleting directory: +Fejl i sletning af bibliotek: + +Error changing modification time: +Fejl i ændring af modificerings tiden: + +Error loading library function: +Fejl i biblioteks funktionen: + +Error reading security context: +Fejl i læsning af sikkerhedstilladelser: + +Error writing security context: +Fejl i skrivning af sikkerhedstilladelser: + +Error copying file permissions: +Fejl i kopiering af filtilladelser: + +Error creating directory: +Fejl i oprettelse af bibliotek: + +Error copying symbolic link: +Fejl i kopiering af link: + +Error copying file: +Fejl i kopiering af fil: + +Error opening file: +Fejl i åbning af fil: + +Error traversing directory: +Fejl i gennemgang af bibliotek: + +Endless loop when traversing directory: +Uendelig løkke ved gennemgang af bibliotek: + +Error setting privilege: +Fejl i at sætte privilegier: + Both sides have changed since last synchronization! Begge sider er ændret siden sidste synkronisering! @@ -1325,9 +1311,6 @@ Overfør fil og biblioteks tilladelser (Kræver Administrator rettigheder) Directories are dependent! Be careful when setting up synchronization rules: Biblioteker er afhængige! Vær forsigtig når du laver synkroniserings reglerne: -Comparing content of files %x -Sammenligner indhold af filer %x - Memory allocation failed! Hukommelses fejl! @@ -1343,15 +1326,15 @@ Overfør fil og biblioteks tilladelser (Kræver Administrator rettigheder) Symlinks %x have the same date but a different target! Links %x har den samme dato men forskellige destinationerl! +Comparing content of files %x +Sammenligner indhold af filer %x + Comparing files by content failed. Fejl i sammenligning af filernes indhold. Generating file list... Laver fil liste... -Multiple... -Flere... - Both sides are equal Begge sider er ens @@ -1370,6 +1353,12 @@ Overfør fil og biblioteks tilladelser (Kræver Administrator rettigheder) Delete right file/folder Slet højre fil/mappe +Move file on left +Flyt filen til venstre + +Move file on right +flyt filen til højre + Overwrite left file/folder with right one Overskriv venstre fil/mappe med højre @@ -1385,6 +1374,9 @@ Overfør fil og biblioteks tilladelser (Kræver Administrator rettigheder) Copy file attributes only to right Kopiere fil attributter kun til højre +Multiple... +Flere... + Deleting file %x Sletter fil %x diff --git a/BUILD/Languages/dutch.lng b/BUILD/Languages/dutch.lng index 17519715..8c9d8a33 100644 --- a/BUILD/Languages/dutch.lng +++ b/BUILD/Languages/dutch.lng @@ -22,39 +22,6 @@ RealtimeSync - Automated Synchronization RealtimeSync - Geautomatiseerde Synchronisatie -Browse -Verkennen - -Windows Error Code %x: -Windows Fout Code %x: - -Linux Error Code %x: -Linux Fout Code %x: - -Invalid command line: %x - - -Error resolving symbolic link: -Fout tijdens opzoeken van symbolische koppeling: - -Show pop-up - - -Show pop-up on errors or warnings - - -Ignore errors -Negeer foutmeldingen - -Hide all error and warning messages -Verberg alle fout- en waarschuwingsberichten - -Exit instantly -Sluit meteen af - -Abort synchronization immediately -Stop synchronisatie onmiddelijk - Select alternate comparison settings @@ -115,6 +82,45 @@ Select time span +Show pop-up + + +Show pop-up on errors or warnings + + +Ignore errors +Negeer foutmeldingen + +Hide all error and warning messages +Verberg alle fout- en waarschuwingsberichten + +Exit instantly +Sluit meteen af + +Abort synchronization immediately +Stop synchronisatie onmiddelijk + +Browse +Verkennen + +Error reading from synchronization database: +Fout tijdens uitlezen van synchronisatie-database: + +Error writing to synchronization database: +Fout tijdens schrijven naar synchronisatie-database: + +Invalid command line: %x + + +Windows Error Code %x: +Windows Fout Code %x: + +Linux Error Code %x: +Linux Fout Code %x: + +Error resolving symbolic link: +Fout tijdens opzoeken van symbolische koppeling: + %x MB %x MB @@ -163,17 +169,14 @@ Comparison Result Resultaat vergelijken -Incompatible synchronization database format: -Opmaak van synchronisatie-database komt niet overeen: - Initial synchronization: Initiële synchronisatie: One of the FreeFileSync database files is not yet existing: Eén van de FreeFileSync database bestanden bestaat nog niet: -Error reading from synchronization database: -Fout tijdens uitlezen van synchronisatie-database: +Incompatible synchronization database format: +Opmaak van synchronisatie-database komt niet overeen: Database files do not share a common synchronization session: @@ -199,12 +202,18 @@ %x sec +Drag && drop +Drag en drop + Info Info Fatal Error Fatale fout +Error reading file: +Fout tijdens lezen van bestand: + Scanning: Doorzoekt: @@ -220,15 +229,36 @@ Invalid FreeFileSync config file! Foutief FreeFileSync configuratiebestand! -File does not exist: -Bestand bestaat niet: - Error parsing configuration file: Fout tijdens verwerking configuratiebestand: +Error moving to Recycle Bin: +Fout tijdens verplaatsen naar prullenbak: + +Could not load a required DLL: +Kon een benodigde DLL niet laden: + +Error accessing Volume Shadow Copy Service! + + +Making shadow copies on WOW64 is not supported. Please use FreeFileSync 64-bit version. +Het aanmaken van schaduwkopieën op WOW64 wordt niet ondersteund. Gebruik alstublieft de 64-bit versie van FreeFileSync. + +Could not determine volume name for file: +Kon de schijfnaam niet vaststellen van bestand: + +Volume name %x not part of filename %y! +Schijfnaam %x maakt geen deel uit van bestandsnaam %y! + /sec /sec +File does not exist: +Bestand bestaat niet: + +Could not read values for the following XML nodes: +Kon geen waarden inlezen voor de volgende XML punten: + S&ave configuration... Sl&a configuratie op... @@ -321,141 +351,6 @@ De opdrachtregel wordt telkens uitgevoerd indien: A directory input field is empty. Een tekstveld over de map is leeg. -Drag && drop -Drag en drop - -Could not initialize directory monitoring: -Initaliseren van map-observatie niet mogelijk: - -Error when monitoring directories. -Fout tijdens observeren van mappen. - -Conversion error: -Converteer fout: - -Error deleting file: -Fout tijdens verwijderen van bestand: - -Error moving file: -Fout tijdens verplaatsen van bestand: - -Target file already existing! -Doelbestand bestaat al! - -Error moving directory: -Fout tijdens verplaatsen van map: - -Target directory already existing! -Doelmap bestaat al! - -Error deleting directory: -Fout tijdens het verwijderen van map: - -Error changing modification time: -Fout tijdens aanpassing van de wijzigingstijd: - -Error loading library function: -Fout tijdens laden van bibliotheek functie: - -Error reading security context: -Fout tijdens lezen van beveiligingscontext: - -Error writing security context: -Fout tijdens schrijven van beveiligingscontext: - -Error copying file permissions: -Fout tijdens kopiëren van bestandspermissies: - -Error creating directory: -Fout tijdens het aanmaken van map: - -Error copying symbolic link: -Fout tijdens kopiëren van symbolische koppeling: - -Error copying file: -Fout tijdens kopiëren van bestand: - -Error opening file: -Fout tijdens openen van bestand: - -Error writing file: -Fout tijdens schrijven van bestand: - -Error reading file: -Fout tijdens lezen van bestand: - -Operation aborted! -Bewerking afgebroken! - -Endless loop when traversing directory: -Oneindige lus bij het doorlopen van map: - -Error traversing directory: -Fout tijdens doorzoeken van map: - -Error setting privilege: -Fout tijdens instellen van privileges: - -Error moving to Recycle Bin: -Fout tijdens verplaatsen naar prullenbak: - -Could not load a required DLL: -Kon een benodigde DLL niet laden: - -Error writing to synchronization database: -Fout tijdens schrijven naar synchronisatie-database: - -Error accessing Volume Shadow Copy Service! - - -Making shadow copies on WOW64 is not supported. Please use FreeFileSync 64-bit version. -Het aanmaken van schaduwkopieën op WOW64 wordt niet ondersteund. Gebruik alstublieft de 64-bit versie van FreeFileSync. - -Could not determine volume name for file: -Kon de schijfnaam niet vaststellen van bestand: - -Volume name %x not part of filename %y! -Schijfnaam %x maakt geen deel uit van bestandsnaam %y! - -%x TB -%x TB - -%x PB -%x PB - -%x% -%x% - - -1 min -%x min - - -1 min -%x min - - - -1 hour -%x hours - - -1 uur -%x uren - - - -1 day -%x days - - -1 dag -%x dagen - - -Could not read values for the following XML nodes: -Kon geen waarden inlezen voor de volgende XML punten: - Logging Loggen @@ -474,9 +369,6 @@ De opdrachtregel wordt telkens uitgevoerd indien: Batch execution Taak uitvoeren -Log-messages: -Logberichten: - Stop Stop @@ -603,6 +495,24 @@ De opdrachtregel wordt telkens uitgevoerd indien: Total amount of data that will be transferred Totale hoeveelheid data die verplaatst wordt +Operation: +Bewerking: + +Items found: +Onderdelen gevonden: + +Items remaining: +Onderdelen te gaan: + +Speed: +Snelheid: + +Time remaining: +Benodigde tijd: + +Time elapsed: +Verstreken tijd: + Batch job Taaklijst @@ -651,32 +561,14 @@ De opdrachtregel wordt telkens uitgevoerd indien: &Cancel &Annuleren -Operation: -Bewerking: - -Items found: -Onderdelen gevonden: - -Items remaining: -Onderdelen te gaan: - -Speed: -Snelheid: - -Time remaining: -Benodigde tijd: - -Time elapsed: -Verstreken tijd: - Select variant: Selecteer een variant: -Identify and propagate changes on both sides using a database. Deletions and conflicts are detected automatically. -Identificeer en verwerk veranderingen aan beide zijdes dmv een database. Verwijderingen en conflicten worden automatisch gedetecteerd. +Identify and propagate changes on both sides using a database. Deletions, renaming and conflicts are detected automatically. + Mirror ->> Spiegelen ->> @@ -898,22 +790,14 @@ Uitsluiten: \stuff\temp\* Copy locked files Kopieer vergrendelde bestanden - -Copy shared or locked files using Volume Shadow Copy Service (Requires Administrator rights) - - -Kopieer gedeelde of vergrendelde bestanden met Volume Shadow Copy Service (Vereist Administrator rechten) - +Copy shared or locked files using Volume Shadow Copy Service (Requires Administrator rights) +Kopieer gedeelde of vergrendelde bestanden met Volume Shadow Copy Service (Vereist Administrator rechten) Copy file access permissions - -Transfer file and directory permissions (Requires Administrator rights) - - -Zet bestand en map permissies over (Vereist Administrator rechten) - +Transfer file and directory permissions (Requires Administrator rights) +Zet bestand en map permissies over (Vereist Administrator rechten) Hidden dialogs: Verborgen dialogen: @@ -945,6 +829,9 @@ Zet bestand en map permissies over (Vereist Administrator rechten) &Find next &Vind volgende +Operation aborted! +Bewerking afgebroken! + Main bar Hoofdbalk @@ -1122,6 +1009,9 @@ Zet bestand en map permissies over (Vereist Administrator rechten) File list exported! Bestandslijst geëxporteerd! +Error writing file: +Fout tijdens schrijven van bestand: + Batch file created successfully! Taakbestand is succesvol aangemaakt! @@ -1221,9 +1111,6 @@ Zet bestand en map permissies over (Vereist Administrator rechten) Filter: Single pair Filter: Enkel paar -Ignore -Negeer - Direct Direct @@ -1287,6 +1174,105 @@ Zet bestand en map permissies over (Vereist Administrator rechten) Move files into a time-stamped subdirectory Verplaats de bestanden naar een tijd-gemarkeerde submap +%x TB +%x TB + +%x PB +%x PB + +%x% +%x% + + +1 min +%x min + + +1 min +%x min + + + +1 hour +%x hours + + +1 uur +%x uren + + + +1 day +%x days + + +1 dag +%x dagen + + +Could not initialize directory monitoring: +Initaliseren van map-observatie niet mogelijk: + +Error when monitoring directories. +Fout tijdens observeren van mappen. + +Conversion error: +Converteer fout: + +Error deleting file: +Fout tijdens verwijderen van bestand: + +Error moving file: +Fout tijdens verplaatsen van bestand: + +Target file already existing! +Doelbestand bestaat al! + +Error moving directory: +Fout tijdens verplaatsen van map: + +Target directory already existing! +Doelmap bestaat al! + +Error deleting directory: +Fout tijdens het verwijderen van map: + +Error changing modification time: +Fout tijdens aanpassing van de wijzigingstijd: + +Error loading library function: +Fout tijdens laden van bibliotheek functie: + +Error reading security context: +Fout tijdens lezen van beveiligingscontext: + +Error writing security context: +Fout tijdens schrijven van beveiligingscontext: + +Error copying file permissions: +Fout tijdens kopiëren van bestandspermissies: + +Error creating directory: +Fout tijdens het aanmaken van map: + +Error copying symbolic link: +Fout tijdens kopiëren van symbolische koppeling: + +Error copying file: +Fout tijdens kopiëren van bestand: + +Error opening file: +Fout tijdens openen van bestand: + +Error traversing directory: +Fout tijdens doorzoeken van map: + +Endless loop when traversing directory: +Oneindige lus bij het doorlopen van map: + +Error setting privilege: +Fout tijdens instellen van privileges: + Both sides have changed since last synchronization! Beide zijdes zijn veranderd sinds de laatste synchronisatie! @@ -1317,9 +1303,6 @@ Zet bestand en map permissies over (Vereist Administrator rechten) Directories are dependent! Be careful when setting up synchronization rules: Mappen zijn afhankelijk van elkaar! Wees voorzichtig met het maken van synchronisatieregels: -Comparing content of files %x -De inhoud van %x bestanden wordt vergeleken - Memory allocation failed! RAM geheugen error! @@ -1335,15 +1318,15 @@ Zet bestand en map permissies over (Vereist Administrator rechten) Symlinks %x have the same date but a different target! Symbolische koppeling %x heeft dezelfde datum maar een ander doel! +Comparing content of files %x +De inhoud van %x bestanden wordt vergeleken + Comparing files by content failed. Bestand-inhoudvergelijking mislukt. Generating file list... Genereren van bestandslijst... -Multiple... -Meerdere... - Both sides are equal Beide kanten zijn gelijk @@ -1362,6 +1345,12 @@ Zet bestand en map permissies over (Vereist Administrator rechten) Delete right file/folder Verwijder rechter bestand/map +Move file on left + + +Move file on right + + Overwrite left file/folder with right one Overschrijf linker bestand/map met de rechter @@ -1377,6 +1366,9 @@ Zet bestand en map permissies over (Vereist Administrator rechten) Copy file attributes only to right Kopieer bestandsattributen allen naar rechts +Multiple... +Meerdere... + Deleting file %x Verwijderen van bestand %x diff --git a/BUILD/Languages/english_uk.lng b/BUILD/Languages/english_uk.lng index a562a229..bea82597 100644 --- a/BUILD/Languages/english_uk.lng +++ b/BUILD/Languages/english_uk.lng @@ -22,39 +22,6 @@ RealtimeSync - Automated Synchronization RealtimeSync - Automated Synchronisation -Browse -Browse - -Windows Error Code %x: -Windows Error Code %x: - -Linux Error Code %x: -Linux Error Code %x: - -Invalid command line: %x -Invalid command line: %x - -Error resolving symbolic link: -Error resolving symbolic link: - -Show pop-up -Show pop-up - -Show pop-up on errors or warnings -Show pop-up on errors or warnings - -Ignore errors -Ignore errors - -Hide all error and warning messages -Hide all error and warning messages - -Exit instantly -Exit instantly - -Abort synchronization immediately -Abort synchronisation immediately - Select alternate comparison settings Select alternate comparison settings @@ -115,6 +82,45 @@ Select time span Select time span +Show pop-up +Show pop-up + +Show pop-up on errors or warnings +Show pop-up on errors or warnings + +Ignore errors +Ignore errors + +Hide all error and warning messages +Hide all error and warning messages + +Exit instantly +Exit instantly + +Abort synchronization immediately +Abort synchronisation immediately + +Browse +Browse + +Error reading from synchronization database: +Error reading from synchronisation database: + +Error writing to synchronization database: +Error writing to synchronisation database: + +Invalid command line: %x +Invalid command line: %x + +Windows Error Code %x: +Windows Error Code %x: + +Linux Error Code %x: +Linux Error Code %x: + +Error resolving symbolic link: +Error resolving symbolic link: + %x MB %x MB @@ -163,17 +169,14 @@ Comparison Result Comparison Result -Incompatible synchronization database format: -Incompatible synchronisation database format: - Initial synchronization: Initial synchronisation: One of the FreeFileSync database files is not yet existing: One of the FreeFileSync database files is not yet existing: -Error reading from synchronization database: -Error reading from synchronisation database: +Incompatible synchronization database format: +Incompatible synchronisation database format: Database files do not share a common synchronization session: Database files do not share a common synchronisation session: @@ -199,12 +202,18 @@ %x sec +Drag && drop +Drag && drop + Info Info Fatal Error Fatal Error +Error reading file: +Error reading file: + Scanning: Scanning: @@ -223,15 +232,36 @@ Invalid FreeFileSync config file! Invalid FreeFileSync config file! -File does not exist: -File does not exist: - Error parsing configuration file: Error parsing configuration file: +Error moving to Recycle Bin: +Error moving to Recycle Bin: + +Could not load a required DLL: +Could not load a required DLL: + +Error accessing Volume Shadow Copy Service! +Error accessing Volume Shadow Copy Service! + +Making shadow copies on WOW64 is not supported. Please use FreeFileSync 64-bit version. +Making shadow copies on WOW64 is not supported. Please use FreeFileSync 64-bit version. + +Could not determine volume name for file: +Could not determine volume name for file: + +Volume name %x not part of filename %y! +Volume name %x not part of filename %y! + /sec /sec +File does not exist: +File does not exist: + +Could not read values for the following XML nodes: +Could not read values for the following XML nodes: + S&ave configuration... S&ave configuration... @@ -324,141 +354,6 @@ The command line is executed each time: A directory input field is empty. A directory input field is empty. -Drag && drop -Drag && drop - -Could not initialize directory monitoring: -Could not initialise directory monitoring: - -Error when monitoring directories. -Error when monitoring directories. - -Conversion error: -Conversion error: - -Error deleting file: -Error deleting file: - -Error moving file: -Error moving file: - -Target file already existing! -Target file already existing! - -Error moving directory: -Error moving directory: - -Target directory already existing! -Target directory already existing! - -Error deleting directory: -Error deleting directory: - -Error changing modification time: -Error changing modification time: - -Error loading library function: -Error loading library function: - -Error reading security context: -Error reading security context: - -Error writing security context: -Error writing security context: - -Error copying file permissions: -Error copying file permissions: - -Error creating directory: -Error creating directory: - -Error copying symbolic link: -Error copying symbolic link: - -Error copying file: -Error copying file: - -Error opening file: -Error opening file: - -Error writing file: -Error writing file: - -Error reading file: -Error reading file: - -Operation aborted! -Operation aborted! - -Endless loop when traversing directory: -Endless loop when traversing directory: - -Error traversing directory: -Error traversing directory: - -Error setting privilege: -Error setting privilege: - -Error moving to Recycle Bin: -Error moving to Recycle Bin: - -Could not load a required DLL: -Could not load a required DLL: - -Error writing to synchronization database: -Error writing to synchronisation database: - -Error accessing Volume Shadow Copy Service! -Error accessing Volume Shadow Copy Service! - -Making shadow copies on WOW64 is not supported. Please use FreeFileSync 64-bit version. -Making shadow copies on WOW64 is not supported. Please use FreeFileSync 64-bit version. - -Could not determine volume name for file: -Could not determine volume name for file: - -Volume name %x not part of filename %y! -Volume name %x not part of filename %y! - -%x TB -%x TB - -%x PB -%x PB - -%x% -%x% - - -1 min -%x min - - -1 min -%x min - - - -1 hour -%x hours - - -1 hour -%x hours - - - -1 day -%x days - - -1 day -%x days - - -Could not read values for the following XML nodes: -Could not read values for the following XML nodes: - Logging Logging @@ -477,9 +372,6 @@ The command line is executed each time: Batch execution Batch execution -Log-messages: -Log-messages: - Stop Stop @@ -606,6 +498,24 @@ The command line is executed each time: Total amount of data that will be transferred Total amount of data that will be transferred +Operation: +Operation: + +Items found: +Elements found: + +Items remaining: +Elements remaining: + +Speed: +Speed: + +Time remaining: +Time remaining: + +Time elapsed: +Time elapsed: + Batch job Batch job @@ -654,32 +564,14 @@ The command line is executed each time: &Cancel &Cancel -Operation: -Operation: - -Items found: -Elements found: - -Items remaining: -Elements remaining: - -Speed: -Speed: - -Time remaining: -Time remaining: - -Time elapsed: -Time elapsed: - Select variant: Select variant: -Identify and propagate changes on both sides using a database. Deletions and conflicts are detected automatically. -Identify and propagate changes on both sides using a database. Deletions and conflicts are detected automatically. +Identify and propagate changes on both sides using a database. Deletions, renaming and conflicts are detected automatically. +Identify and propagate changes on both sides using a database. Deletions, renaming and conflicts are detected automatically. Mirror ->> Mirror ->> @@ -901,27 +793,19 @@ Exclude: \stuff\temp\* Transactional file copy Write to a temporary file (*.ffs_tmp) first then rename it. This guarantees a consistent state even in case of fatal error. - +Write to a temporary file (*.ffs_tmp) first then rename it. This guarantees a consistent state even in case of fatal error. Copy locked files Copy locked files - -Copy shared or locked files using Volume Shadow Copy Service (Requires Administrator rights) - - -Copy shared or locked files using Volume Shadow Copy Service (Requires Administrator rights) - +Copy shared or locked files using Volume Shadow Copy Service (Requires Administrator rights) +Copy shared or locked files using Volume Shadow Copy Service (Requires Administrator rights) Copy file access permissions Copy file access permissions - -Transfer file and directory permissions (Requires Administrator rights) - - -Transfer file and directory permissions (Requires Administrator rights) - +Transfer file and directory permissions (Requires Administrator rights) +Transfer file and directory permissions (Requires Administrator rights) Hidden dialogs: Hidden dialogues: @@ -953,6 +837,9 @@ Transfer file and directory permissions (Requires Administrator rights) &Find next &Find next +Operation aborted! +Operation aborted! + Main bar Main bar @@ -993,16 +880,16 @@ Transfer file and directory permissions (Requires Administrator rights) Auto-adjust columns Icon size: - +Icon size: Small - +Small Medium - +Medium Large - +Large Include all rows Include all rows @@ -1130,6 +1017,9 @@ Transfer file and directory permissions (Requires Administrator rights) File list exported! File list exported! +Error writing file: +Error writing file: + Batch file created successfully! Batch file created successfully! @@ -1229,9 +1119,6 @@ Transfer file and directory permissions (Requires Administrator rights) Filter: Single pair Filter: Single pair -Ignore -Ignore - Direct Direct @@ -1295,6 +1182,105 @@ Transfer file and directory permissions (Requires Administrator rights) Move files into a time-stamped subdirectory Move files into a time-stamped subdirectory +%x TB +%x TB + +%x PB +%x PB + +%x% +%x% + + +1 min +%x min + + +1 min +%x min + + + +1 hour +%x hours + + +1 hour +%x hours + + + +1 day +%x days + + +1 day +%x days + + +Could not initialize directory monitoring: +Could not initialise directory monitoring: + +Error when monitoring directories. +Error when monitoring directories. + +Conversion error: +Conversion error: + +Error deleting file: +Error deleting file: + +Error moving file: +Error moving file: + +Target file already existing! +Target file already existing! + +Error moving directory: +Error moving directory: + +Target directory already existing! +Target directory already existing! + +Error deleting directory: +Error deleting directory: + +Error changing modification time: +Error changing modification time: + +Error loading library function: +Error loading library function: + +Error reading security context: +Error reading security context: + +Error writing security context: +Error writing security context: + +Error copying file permissions: +Error copying file permissions: + +Error creating directory: +Error creating directory: + +Error copying symbolic link: +Error copying symbolic link: + +Error copying file: +Error copying file: + +Error opening file: +Error opening file: + +Error traversing directory: +Error traversing directory: + +Endless loop when traversing directory: +Endless loop when traversing directory: + +Error setting privilege: +Error setting privilege: + Both sides have changed since last synchronization! Both sides have changed since last synchronisation! @@ -1325,9 +1311,6 @@ Transfer file and directory permissions (Requires Administrator rights) Directories are dependent! Be careful when setting up synchronization rules: Directories are dependent! Be careful when setting up synchronisation rules: -Comparing content of files %x -Comparing content of files %x - Memory allocation failed! Memory allocation failed! @@ -1343,15 +1326,15 @@ Transfer file and directory permissions (Requires Administrator rights) Symlinks %x have the same date but a different target! Symlinks %x have the same date but a different target! +Comparing content of files %x +Comparing content of files %x + Comparing files by content failed. Comparing files by content failed. Generating file list... Generating file list... -Multiple... -Multiple... - Both sides are equal Both sides are equal @@ -1370,6 +1353,12 @@ Transfer file and directory permissions (Requires Administrator rights) Delete right file/folder Delete right file/folder +Move file on left +Move file on left + +Move file on right +Move file on right + Overwrite left file/folder with right one Overwrite left file/folder with right one @@ -1385,6 +1374,9 @@ Transfer file and directory permissions (Requires Administrator rights) Copy file attributes only to right Copy file attributes only to right +Multiple... +Multiple... + Deleting file %x Deleting file %x diff --git a/BUILD/Languages/finnish.lng b/BUILD/Languages/finnish.lng index 8b2012f6..942fbc33 100644 --- a/BUILD/Languages/finnish.lng +++ b/BUILD/Languages/finnish.lng @@ -169,15 +169,15 @@ Comparison Result Vertailun tulos -Incompatible synchronization database format: -Täsmäytyksen tietokannan muoto on virheellinen: - Initial synchronization: Ensi täsmäytys: One of the FreeFileSync database files is not yet existing: Jokin FreeFileSynk tietokannan tiedostoista puuttuu vielä: +Incompatible synchronization database format: +Täsmäytyksen tietokannan muoto on virheellinen: + Database files do not share a common synchronization session: Kannan tiedostot ovat eri sessioista: @@ -232,9 +232,6 @@ Invalid FreeFileSync config file! Virheellinen FreeFileSync asetustiedosto! -File does not exist: -Tiedosto puuttuu: - Error parsing configuration file: Virhe jäsentäessä asetustiedostoa: @@ -259,6 +256,9 @@ /sec /s +File does not exist: +Tiedosto puuttuu: + Could not read values for the following XML nodes: Tietoja lukeminen epäonnistui, XML jäsen: @@ -372,9 +372,6 @@ Komento suoritetaan kun: Batch execution Eräajon suoritus -Log-messages: -Lokin viestit: - Stop Seis @@ -501,6 +498,24 @@ Komento suoritetaan kun: Total amount of data that will be transferred Siirrettävän datan määrä +Operation: +Toiminto: + +Items found: +Osia löytyi: + +Items remaining: +Osia jäljellä: + +Speed: +Nopeus: + +Time remaining: +Aikaa jäljellä: + +Time elapsed: +Kulunut aika: + Batch job Eräajo @@ -549,32 +564,14 @@ Komento suoritetaan kun: &Cancel &Lopeta -Operation: -Toiminto: - -Items found: -Osia löytyi: - -Items remaining: -Osia jäljellä: - -Speed: -Nopeus: - -Time remaining: -Aikaa jäljellä: - -Time elapsed: -Kulunut aika: - Select variant: Valitse vaihtoehto: <- Automaattinen -> -Identify and propagate changes on both sides using a database. Deletions and conflicts are detected automatically. -Tunnista ja monista muutokset molemmilla puolilla tietokannalla. Poistot ja ristiriidat hoidetaan automaattisesti. +Identify and propagate changes on both sides using a database. Deletions, renaming and conflicts are detected automatically. + Mirror ->> Peilaava ->> @@ -801,22 +798,14 @@ Sulje pois: \stuff\temp\* Copy locked files Kopioi lukitut tiedostot - -Copy shared or locked files using Volume Shadow Copy Service (Requires Administrator rights) - - -Kopioi jaetut/lukitut tiedostot Volume Shadow Copy prosessilla (Vaatii Järjestelmävalvojan oikeuksia) - +Copy shared or locked files using Volume Shadow Copy Service (Requires Administrator rights) +Kopioi jaetut/lukitut tiedostot Volume Shadow Copy prosessilla (Vaatii Järjestelmävalvojan oikeuksia) Copy file access permissions Kopioi tiedoston käyttöoikeuksia - -Transfer file and directory permissions (Requires Administrator rights) - - -Siirrä tiedosto- ja hakemisto-oikeuksia (Vaatii Järjestelmävalvojan oikeuksia) - +Transfer file and directory permissions (Requires Administrator rights) +Siirrä tiedosto- ja hakemisto-oikeuksia (Vaatii Järjestelmävalvojan oikeuksia) Hidden dialogs: Piilotetut ikkunat: @@ -1130,9 +1119,6 @@ Siirrä tiedosto- ja hakemisto-oikeuksia (Vaatii Järjestelmävalvojan oikeuksia Filter: Single pair Suodata: Yksi pari -Ignore -Sivuta - Direct Suoraan @@ -1286,12 +1272,12 @@ Siirrä tiedosto- ja hakemisto-oikeuksia (Vaatii Järjestelmävalvojan oikeuksia Error opening file: Virhe avatessa tiedostoa: -Endless loop when traversing directory: -Suorita hakemiston läpikulku jatkuvana: - Error traversing directory: Virhe hakemistoa läpikäydessä: +Endless loop when traversing directory: +Suorita hakemiston läpikulku jatkuvana: + Error setting privilege: Virhe, asettaessa oikeuksia: @@ -1325,9 +1311,6 @@ Siirrä tiedosto- ja hakemisto-oikeuksia (Vaatii Järjestelmävalvojan oikeuksia Directories are dependent! Be careful when setting up synchronization rules: Hakemistot riippuvuussuhteessa! Aseta täsmäyssääntöjä varovasti: -Comparing content of files %x -Vertaa tiedostojen %x tietosisältöä - Memory allocation failed! Muistin varaus epäonnistui! @@ -1343,15 +1326,15 @@ Siirrä tiedosto- ja hakemisto-oikeuksia (Vaatii Järjestelmävalvojan oikeuksia Symlinks %x have the same date but a different target! Pikakuvakkeilla %x on sama päiväys mutta kohde on toinen! +Comparing content of files %x +Vertaa tiedostojen %x tietosisältöä + Comparing files by content failed. Tietosisällön vertailu epäonnistui. Generating file list... Luodaan tiedostolista... -Multiple... -Moninkertainen... - Both sides are equal Puolet ovat denttiset @@ -1370,6 +1353,12 @@ Siirrä tiedosto- ja hakemisto-oikeuksia (Vaatii Järjestelmävalvojan oikeuksia Delete right file/folder Poista tiedosto/hakemisto oikealta +Move file on left + + +Move file on right + + Overwrite left file/folder with right one Ylikirjoita oikea tiedosto/hakemista vasemanpuolisella @@ -1385,6 +1374,9 @@ Siirrä tiedosto- ja hakemisto-oikeuksia (Vaatii Järjestelmävalvojan oikeuksia Copy file attributes only to right Monista tiedosto-ominaisuudet oikealle +Multiple... +Moninkertainen... + Deleting file %x Poista tiedosto %x diff --git a/BUILD/Languages/french.lng b/BUILD/Languages/french.lng index 0fc97f8c..c81fa341 100644 --- a/BUILD/Languages/french.lng +++ b/BUILD/Languages/french.lng @@ -22,39 +22,6 @@ RealtimeSync - Automated Synchronization RealtimeSync - Synchronisation Automatisée -Browse -Parcourir - -Windows Error Code %x: -Code erreur Windows %x: - -Linux Error Code %x: -Code erreur Linux %x: - -Invalid command line: %x -Ligne de commande incorrecte : %x - -Error resolving symbolic link: -Erreur lors de la résolution du lien symbolique : - -Show pop-up -Montrer les boîtes de dialogue - -Show pop-up on errors or warnings -Montrer les messages d'avertissement ou d'erreur - -Ignore errors -Ignorer les erreurs - -Hide all error and warning messages -Masquer tous les messages d'erreurs et les avertissements - -Exit instantly -Sortie immédiate - -Abort synchronization immediately -Abandon immédiat de la synchronisation - Select alternate comparison settings Choisir d'autres paramètres de comparaison @@ -115,6 +82,45 @@ Select time span choisir un intervalle de temps +Show pop-up +Montrer les boîtes de dialogue + +Show pop-up on errors or warnings +Montrer les messages d'avertissement ou d'erreur + +Ignore errors +Ignorer les erreurs + +Hide all error and warning messages +Masquer tous les messages d'erreurs et les avertissements + +Exit instantly +Sortie immédiate + +Abort synchronization immediately +Abandon immédiat de la synchronisation + +Browse +Parcourir + +Error reading from synchronization database: +Erreur lors de la lecture de la base de données de synchro : + +Error writing to synchronization database: +Erreur lors de l'écriture de la base de données de synchro : + +Invalid command line: %x +Ligne de commande incorrecte : %x + +Windows Error Code %x: +Code erreur Windows %x: + +Linux Error Code %x: +Code erreur Linux %x: + +Error resolving symbolic link: +Erreur lors de la résolution du lien symbolique : + %x MB %x Mo @@ -163,17 +169,14 @@ Comparison Result Résultat de la comparaison -Incompatible synchronization database format: -Format de la base de données de synchro incompatible : - Initial synchronization: Première synchronisation : One of the FreeFileSync database files is not yet existing: L'un des fichiers de la base de données FreeFileSync n'existe plus : -Error reading from synchronization database: -Erreur lors de la lecture de la base de données de synchro : +Incompatible synchronization database format: +Format de la base de données de synchro incompatible : Database files do not share a common synchronization session: Les fichiers de la base de données ne font pas partie de la même session de synchronisation @@ -199,12 +202,18 @@ %x sec +Drag && drop +Glisser && Déposer + Info Info Fatal Error Erreur Fatale +Error reading file: +Erreur lors de la lecture du fichier : + Scanning: Lecture en cours : @@ -223,15 +232,36 @@ Invalid FreeFileSync config file! Fichier de configuration FreeFileSync invalide ! -File does not exist: -Le fichier n'existe pas : - Error parsing configuration file: Erreur lors de l'analyse du fichier de configuration : +Error moving to Recycle Bin: +Erreur lors du déplacement dans la Corbeille : + +Could not load a required DLL: +Impossible de charger une DLL : + +Error accessing Volume Shadow Copy Service! +Erreur lors de l'accès au Volume Shadow Copy Service ! + +Making shadow copies on WOW64 is not supported. Please use FreeFileSync 64-bit version. +La copie en tâche de fond sur WOW64 n'est pas possible. Utilisez pour cela la version 64 bits de FreeFileSync. + +Could not determine volume name for file: +Impossible de trouver le nom de volume pour le fichier : + +Volume name %x not part of filename %y! +Le nom de volume %x ne fait pas partie du nom de fichier %y ! + /sec /sec +File does not exist: +Le fichier n'existe pas : + +Could not read values for the following XML nodes: +Impossible de lire les valeurs des noeuds XML suivants : + S&ave configuration... S&auvegarder la configuration... @@ -324,141 +354,6 @@ La ligne de commande est exécutée chaque fois que : A directory input field is empty. Un champ répertoire est vide -Drag && drop -Glisser && Déposer - -Could not initialize directory monitoring: -Impossible d'initialiser la surveillance des dossiers : - -Error when monitoring directories. -Erreur lors de la surveillance des répertoires. - -Conversion error: -Erreur de conversion : - -Error deleting file: -Erreur lors de la suppression d'un fichier : - -Error moving file: -Erreur lors du déplacement du fichier : - -Target file already existing! -Le fichier de destination existe déjà ! - -Error moving directory: -Erreur lors du déplacement du répertoire : - -Target directory already existing! -Le répertoire de destination existe déjà ! - -Error deleting directory: -Erreur lors de la suppression d'un répertoire : - -Error changing modification time: -Erreur lors du changement de la date de modification : - -Error loading library function: -Erreur lors du chargement de la bibliothèque de fonctions : - -Error reading security context: -Erreur de lecture du contexte de sécurité: - -Error writing security context: -Erreur d'écriture du contexte de sécurité: - -Error copying file permissions: -Erreur lors de la copie des attributs système - -Error creating directory: -Erreur lors de la création d'un répertoire : - -Error copying symbolic link: -Erreur lors de la copie du lien symbolique : - -Error copying file: -Erreur lors de la copie du fichier : - -Error opening file: -Erreur lors de l'ouverture du fichier : - -Error writing file: -Erreur lors de l'écriture du fichier : - -Error reading file: -Erreur lors de la lecture du fichier : - -Operation aborted! -Opération abandonnée ! - -Endless loop when traversing directory: -Boucle sans fin lors du parcours du répertoire : - -Error traversing directory: -Erreur lors du parcours du répertoire : - -Error setting privilege: -Erreur de paramétrage de privilège - -Error moving to Recycle Bin: -Erreur lors du déplacement dans la Corbeille : - -Could not load a required DLL: -Impossible de charger une DLL : - -Error writing to synchronization database: -Erreur lors de l'écriture de la base de données de synchro : - -Error accessing Volume Shadow Copy Service! -Erreur lors de l'accès au Volume Shadow Copy Service ! - -Making shadow copies on WOW64 is not supported. Please use FreeFileSync 64-bit version. -La copie en tâche de fond sur WOW64 n'est pas possible. Utilisez pour cela la version 64 bits de FreeFileSync. - -Could not determine volume name for file: -Impossible de trouver le nom de volume pour le fichier : - -Volume name %x not part of filename %y! -Le nom de volume %x ne fait pas partie du nom de fichier %y ! - -%x TB -%x To - -%x PB -%x Po - -%x% -%x % - - -1 min -%x min - - -%x min -%x min - - - -1 hour -%x hours - - -%x heure -%x heures - - - -1 day -%x days - - -%x jour -%x jours - - -Could not read values for the following XML nodes: -Impossible de lire les valeurs des noeuds XML suivants : - Logging Connexion @@ -477,9 +372,6 @@ La ligne de commande est exécutée chaque fois que : Batch execution Exécution du traitement batch -Log-messages: -Messages log : - Stop Arrêt @@ -606,6 +498,24 @@ La ligne de commande est exécutée chaque fois que : Total amount of data that will be transferred Volume de données à transférer +Operation: +Opération : + +Items found: +Elements trouvés : + +Items remaining: +Elements restants : + +Speed: +Vitesse : + +Time remaining: +Temps restant : + +Time elapsed: +Temps écoulé : + Batch job Fichier de commandes @@ -654,32 +564,14 @@ La ligne de commande est exécutée chaque fois que : &Cancel &Annuler -Operation: -Opération : - -Items found: -Elements trouvés : - -Items remaining: -Elements restants : - -Speed: -Vitesse : - -Time remaining: -Temps restant : - -Time elapsed: -Temps écoulé : - Select variant: Choisissez une variante : -Identify and propagate changes on both sides using a database. Deletions and conflicts are detected automatically. -Identifier et propager les modifications des deux côtés en utilisant une base de données. Les suppressions et les conflits sont détectés automatiquement. +Identify and propagate changes on both sides using a database. Deletions, renaming and conflicts are detected automatically. + Mirror ->> Miroir ->> @@ -906,22 +798,14 @@ Exclude: \stuff\temp\* Copy locked files Copier les fichiers verrouillés - -Copy shared or locked files using Volume Shadow Copy Service (Requires Administrator rights) - - -La copie des fichiers partagés ou verrouillés nécessite le Service Volume Shadow Copy (avec les droits administrateur) - +Copy shared or locked files using Volume Shadow Copy Service (Requires Administrator rights) +La copie des fichiers partagés ou verrouillés nécessite le Service Volume Shadow Copy (avec les droits administrateur) Copy file access permissions Copie des droits d'accès aux fichiers - -Transfer file and directory permissions (Requires Administrator rights) - - -Transfert des attributs système des fichiers et des répertoires (avec les droits administrateur) - +Transfer file and directory permissions (Requires Administrator rights) +Transfert des attributs système des fichiers et des répertoires (avec les droits administrateur) Hidden dialogs: Boîtes de dialogue masquées : @@ -953,6 +837,9 @@ Transfert des attributs système des fichiers et des répertoires (avec les droi &Find next &Chercher le suivant +Operation aborted! +Opération abandonnée ! + Main bar Barre principale @@ -1130,6 +1017,9 @@ Transfert des attributs système des fichiers et des répertoires (avec les droi File list exported! Liste des fichiers exportée ! +Error writing file: +Erreur lors de l'écriture du fichier : + Batch file created successfully! Fichier de traitement batch créé avec succès ! @@ -1229,9 +1119,6 @@ Transfert des attributs système des fichiers et des répertoires (avec les droi Filter: Single pair Filtre : Une seule paire -Ignore -Ignorer - Direct Direct @@ -1295,6 +1182,105 @@ Transfert des attributs système des fichiers et des répertoires (avec les droi Move files into a time-stamped subdirectory Déplacer les fichiers vers un sous-répertoire daté +%x TB +%x To + +%x PB +%x Po + +%x% +%x % + + +1 min +%x min + + +%x min +%x min + + + +1 hour +%x hours + + +%x heure +%x heures + + + +1 day +%x days + + +%x jour +%x jours + + +Could not initialize directory monitoring: +Impossible d'initialiser la surveillance des dossiers : + +Error when monitoring directories. +Erreur lors de la surveillance des répertoires. + +Conversion error: +Erreur de conversion : + +Error deleting file: +Erreur lors de la suppression d'un fichier : + +Error moving file: +Erreur lors du déplacement du fichier : + +Target file already existing! +Le fichier de destination existe déjà ! + +Error moving directory: +Erreur lors du déplacement du répertoire : + +Target directory already existing! +Le répertoire de destination existe déjà ! + +Error deleting directory: +Erreur lors de la suppression d'un répertoire : + +Error changing modification time: +Erreur lors du changement de la date de modification : + +Error loading library function: +Erreur lors du chargement de la bibliothèque de fonctions : + +Error reading security context: +Erreur de lecture du contexte de sécurité: + +Error writing security context: +Erreur d'écriture du contexte de sécurité: + +Error copying file permissions: +Erreur lors de la copie des attributs système + +Error creating directory: +Erreur lors de la création d'un répertoire : + +Error copying symbolic link: +Erreur lors de la copie du lien symbolique : + +Error copying file: +Erreur lors de la copie du fichier : + +Error opening file: +Erreur lors de l'ouverture du fichier : + +Error traversing directory: +Erreur lors du parcours du répertoire : + +Endless loop when traversing directory: +Boucle sans fin lors du parcours du répertoire : + +Error setting privilege: +Erreur de paramétrage de privilège + Both sides have changed since last synchronization! Les deux côtés ont changé depuis la dernière synchronisation ! @@ -1325,9 +1311,6 @@ Transfert des attributs système des fichiers et des répertoires (avec les droi Directories are dependent! Be careful when setting up synchronization rules: Les répertoires sont imbriqués ! Attention à la mise à jour des règles de synchronisation : -Comparing content of files %x -Comparaison du contenu des fichiers %x - Memory allocation failed! Erreur d'allocation de mémoire! @@ -1343,15 +1326,15 @@ Transfert des attributs système des fichiers et des répertoires (avec les droi Symlinks %x have the same date but a different target! Le lien symbolique %x a la même date mais une destination différente ! +Comparing content of files %x +Comparaison du contenu des fichiers %x + Comparing files by content failed. La comparaison des fichiers par leur contenu a échoué. Generating file list... Génération de la liste des fichiers... -Multiple... -Multiple... - Both sides are equal Les deux cotés sont identiques @@ -1370,6 +1353,12 @@ Transfert des attributs système des fichiers et des répertoires (avec les droi Delete right file/folder Supprimer les fichiers/dossiers de droite +Move file on left + + +Move file on right + + Overwrite left file/folder with right one Remplacer le fichier/dossier de gauche avec celui de droite @@ -1385,6 +1374,9 @@ Transfert des attributs système des fichiers et des répertoires (avec les droi Copy file attributes only to right Copier seulement les attributs du fichier à droite +Multiple... +Multiple... + Deleting file %x Suppression du fichier %x diff --git a/BUILD/Languages/german.lng b/BUILD/Languages/german.lng index 78c9ee8f..3b260354 100644 --- a/BUILD/Languages/german.lng +++ b/BUILD/Languages/german.lng @@ -169,15 +169,15 @@ Comparison Result Ergebnis des Vergleichs -Incompatible synchronization database format: -Inkompatibles Datenbankformat: - Initial synchronization: Erstmalige Synchronisation: One of the FreeFileSync database files is not yet existing: Eine der FreeFileSync Datenbankdateien existiert noch nicht: +Incompatible synchronization database format: +Inkompatibles Datenbankformat: + Database files do not share a common synchronization session: Die Datenbankdateien enthalten keine gemeinsame Synchronisationssitzung: @@ -372,9 +372,6 @@ Die Befehlszeile wird ausgeführt wenn: Batch execution Batchlauf -Log-messages: -Meldungen: - Stop Stop @@ -501,6 +498,24 @@ Die Befehlszeile wird ausgeführt wenn: Total amount of data that will be transferred Gesamtmenge der zu übertragenden Daten +Operation: +Vorgang: + +Items found: +Gefundene Elemente: + +Items remaining: +Verbleibende Elemente: + +Speed: +Geschwindigkeit: + +Time remaining: +Verbleibende Zeit: + +Time elapsed: +Vergangene Zeit: + Batch job Batch-Job @@ -549,32 +564,14 @@ Die Befehlszeile wird ausgeführt wenn: &Cancel &Abbrechen -Operation: -Vorgang: - -Items found: -Gefundene Elemente: - -Items remaining: -Verbleibende Elemente: - -Speed: -Geschwindigkeit: - -Time remaining: -Verbleibende Zeit: - -Time elapsed: -Vergangene Zeit: - Select variant: Variante auswählen: -Identify and propagate changes on both sides using a database. Deletions and conflicts are detected automatically. -Identifiziere und propagiere Änderungen auf beiden Seiten mit Hilfe einer Datenbank. Löschungen und Konflikte werden automatisch erkannt. +Identify and propagate changes on both sides using a database. Deletions, renaming and conflicts are detected automatically. +Identifiziere und propagiere Änderungen auf beiden Seiten mit Hilfe einer Datenbank. Löschungen, Umbenennungen und Konflikte werden automatisch erkannt. Mirror ->> Spiegeln ->> @@ -1122,9 +1119,6 @@ Ausschließen: \stuff\temp\* Filter: Single pair Filter: Einzelnes Verzeichnispaar -Ignore -Ignorieren - Direct Direkt @@ -1278,12 +1272,12 @@ Ausschließen: \stuff\temp\* Error opening file: Fehler beim Öffnen der Datei: -Endless loop when traversing directory: -Endlosschleife beim Lesen des Verzeichnisses: - Error traversing directory: Fehler beim Durchsuchen des Verzeichnisses: +Endless loop when traversing directory: +Endlosschleife beim Lesen des Verzeichnisses: + Error setting privilege: Fehler beim Setzen des Privilegs: @@ -1317,9 +1311,6 @@ Ausschließen: \stuff\temp\* Directories are dependent! Be careful when setting up synchronization rules: Die Verzeichnisse sind voneinander abhängig! Achtung beim Festlegen der Synchronisationseinstellungen: -Comparing content of files %x -Vergleiche Inhalt der Dateien %x - Memory allocation failed! Speicherallokation fehlgeschlagen! @@ -1335,15 +1326,15 @@ Ausschließen: \stuff\temp\* Symlinks %x have the same date but a different target! Die Symbolischen Links %x haben dasselbe Datum, aber ein unterschiedliches Ziel! +Comparing content of files %x +Vergleiche Inhalt der Dateien %x + Comparing files by content failed. Vergleich nach Dateiinhalt ist fehlgeschlagen. Generating file list... Erzeuge Dateiliste... -Multiple... -Verschiedene... - Both sides are equal Beide Seiten sind gleich @@ -1362,6 +1353,12 @@ Ausschließen: \stuff\temp\* Delete right file/folder Lösche rechte Datei +Move file on left +Verschiebe linke Datei + +Move file on right +Verschiebe rechte Datei + Overwrite left file/folder with right one Überschreibe linke Datei mit rechter @@ -1377,6 +1374,9 @@ Ausschließen: \stuff\temp\* Copy file attributes only to right Kopiere nur die Dateiattribute nach rechts +Multiple... +Verschiedene... + Deleting file %x Lösche Datei %x diff --git a/BUILD/Languages/greek.lng b/BUILD/Languages/greek.lng index c3a9a44a..1b883921 100644 --- a/BUILD/Languages/greek.lng +++ b/BUILD/Languages/greek.lng @@ -169,15 +169,15 @@ Comparison Result Αποτέλεσμα της σύγκρισης -Incompatible synchronization database format: -Η μορφή της βάσης δεδομένων συγχρονισμού δεν είναι συμβατή: - Initial synchronization: Αρχικός συγχρονισμός: One of the FreeFileSync database files is not yet existing: Μια από τις βάσεις δεδομένων του FreeFileSync δεν υπάρχει ακόμα: +Incompatible synchronization database format: +Η μορφή της βάσης δεδομένων συγχρονισμού δεν είναι συμβατή: + Database files do not share a common synchronization session: Οι βάσεις δεδομένων δεν έχουν δημιουργηθεί από τον ίδιο συγχρονισμό: @@ -206,7 +206,7 @@ Μεταφορά && Απόθεση Info -Πληροφορίες +Πληροφορία Fatal Error Σημαντικό Σφάλμα @@ -372,9 +372,6 @@ The command line is executed each time: Batch execution Εκτέλεση δέσμης ενεργειών -Log-messages: -Αποθηκευμένα μηνύματα: - Stop Λήξη @@ -501,6 +498,24 @@ The command line is executed each time: Total amount of data that will be transferred Συνολικός όγκος δεδομένων που θα μεταφερθούν +Operation: +Λειτουργία: + +Items found: +Βρέθηκαν στοιχεία: + +Items remaining: +Περισσεύουν στοιχεία: + +Speed: +Ταχύτητα: + +Time remaining: +Απομένει χρόνος: + +Time elapsed: +Πέρασε χρόνος: + Batch job Δέσμη ενεργειών @@ -549,32 +564,14 @@ The command line is executed each time: &Cancel &Άκυρο -Operation: -Λειτουργία: - -Items found: -Βρέθηκαν στοιχεία: - -Items remaining: -Περισσεύουν στοιχεία: - -Speed: -Ταχύτητα: - -Time remaining: -Απομένει χρόνος: - -Time elapsed: -Πέρασε χρόνος: - Select variant: Επιλέξτε μια μέθοδο: <Αυτόματα> -Identify and propagate changes on both sides using a database. Deletions and conflicts are detected automatically. -Ανίχνευση και εφαρμογή των αλλαγών και στις δυο πλευρές με τη χρήση βάσης δεδομένων. Διαγραφές και διενέξεις ανιχνεύονται αυτόματα. +Identify and propagate changes on both sides using a database. Deletions, renaming and conflicts are detected automatically. +Αναγνώριση και αναπαραγωγή των αλλαγών και στις δύο πλευρές με τη χρήση μιας βάσης δεδομένων. Διαγραφές, μετονομασίες και διενέξεις ανιχνεύονται αυτόματα. Mirror ->> Κατοπτρισμός ->> @@ -1122,9 +1119,6 @@ Exclude: \stuff\temp\* Filter: Single pair Φίλτρο: Ένα ζεύγος -Ignore -Παράβλεψη - Direct Ως δεσμό @@ -1278,12 +1272,12 @@ Exclude: \stuff\temp\* Error opening file: Σφάλμα κατά το άνοιγμα του αρχείου: -Endless loop when traversing directory: -Ατέρμονος βρόχος κατά την την ανάλυση του υποκαταλόγου: - Error traversing directory: Σφάλμα κατά την ανάλυση του υποκαταλόγου: +Endless loop when traversing directory: +Ατέρμονος βρόχος κατά την την ανάλυση του υποκαταλόγου: + Error setting privilege: Σφάλμα κατά τον ορισμό δικαιωμάτων: @@ -1317,9 +1311,6 @@ Exclude: \stuff\temp\* Directories are dependent! Be careful when setting up synchronization rules: Οι υποκατάλογοι είναι εξαρτώμενοι. Προσοχή κατά την εισαγωγή των κανόνων συγχρονισμού: -Comparing content of files %x -Σύγκριση του περιεχομένου των αρχείων %x - Memory allocation failed! Η δέσμευση χώρου μνήμης απέτυχε! @@ -1335,15 +1326,15 @@ Exclude: \stuff\temp\* Symlinks %x have the same date but a different target! Οι συμβολικοί δεσμοί %x έχουν την ίδια ημερομηνία αλλά διαφορετικό προορισμό! +Comparing content of files %x +Σύγκριση του περιεχομένου των αρχείων %x + Comparing files by content failed. Η σύγκριση του περιεχομένου των αρχείων απέτυχε. Generating file list... Δημιουργία καταλόγου αρχείων... -Multiple... -Πολλαπλές ρυθμίσεις... - Both sides are equal Οι δυο πλευρές είναι ίδιες @@ -1362,6 +1353,12 @@ Exclude: \stuff\temp\* Delete right file/folder Διαγραφή του αρχείου/υποκαταλόγου στα δεξιά +Move file on left +Μεταφορά του αρχείου που βρίσκεται αριστερά + +Move file on right +Μεταφορά του αρχείου που βρίσκεται δεξιά + Overwrite left file/folder with right one Αντικατάσταση του αρχείου/υποκαταλόγου στα αριστερά από το(ν) αντίστοιχο στα δεξιά @@ -1377,6 +1374,9 @@ Exclude: \stuff\temp\* Copy file attributes only to right Αντιγραφή μόνο των χαρακτηριστικών του αρχείου στα δεξιά +Multiple... +Πολλαπλές ρυθμίσεις... + Deleting file %x Διαγραφή του αρχείου %x diff --git a/BUILD/Languages/hebrew.lng b/BUILD/Languages/hebrew.lng index 40b6721a..b15dfc56 100644 --- a/BUILD/Languages/hebrew.lng +++ b/BUILD/Languages/hebrew.lng @@ -2,7 +2,7 @@ עברית nitnit he_IL - isreal.png + israel.png 2 n == 1 ? 0 : 1 @@ -22,39 +22,6 @@ RealtimeSync - Automated Synchronization RealtimeSync - סינכרון אוטומטי -Browse -עיין - -Windows Error Code %x: -קוד שגיאת חלונות %x: - -Linux Error Code %x: -קוד שגיאת לינוקס %x: - -Invalid command line: %x -שורת פקודה בלתי חוקית: %x - -Error resolving symbolic link: -שגיאה בפענוח קישור סימבולי (Symbolic Link) - -Show pop-up -הראה חלונות מוקפצים - -Show pop-up on errors or warnings -הראה חלונות מוקפצים עבור שגיאות או אזהרות - -Ignore errors -התעלם מטעויות - -Hide all error and warning messages -הסתר את כל הודעות ההזהרה והשגיאה - -Exit instantly -צא מידית - -Abort synchronization immediately -הפסק סנכרון מידית - Select alternate comparison settings בחר הגדרות השוואה חליפיות @@ -115,6 +82,45 @@ Select time span בחר תחום זמן +Show pop-up +הראה חלונות מוקפצים + +Show pop-up on errors or warnings +הראה חלונות מוקפצים עבור שגיאות או אזהרות + +Ignore errors +התעלם מטעויות + +Hide all error and warning messages +הסתר את כל הודעות ההזהרה והשגיאה + +Exit instantly +צא מידית + +Abort synchronization immediately +הפסק סנכרון מידית + +Browse +עיין + +Error reading from synchronization database: +שגיאה בקריאה מבסיס הנתונים של הסנכרון: + +Error writing to synchronization database: +שגיאה ברישום לבסיס נתוני סנכרון: + +Invalid command line: %x +שורת פקודה בלתי חוקית: %x + +Windows Error Code %x: +קוד שגיאת חלונות %x: + +Linux Error Code %x: +קוד שגיאת לינוקס %x: + +Error resolving symbolic link: +שגיאה בפענוח קישור סימבולי (Symbolic Link) + %x MB %x מגה בייט @@ -163,17 +169,14 @@ Comparison Result תוצאות ההשוואה -Incompatible synchronization database format: -מסד נתונים של הסנכרון לא תואם: - Initial synchronization: סנכרון ראשוני: One of the FreeFileSync database files is not yet existing: אחד מקובצי בסיס הנתונים הבא עדיין לא קיים -Error reading from synchronization database: -שגיאה בקריאה מבסיס הנתונים של הסנכרון: +Incompatible synchronization database format: +מסד נתונים של הסנכרון לא תואם: Database files do not share a common synchronization session: קבצי בסיס הנתונים אינם חולקים ארוע סנכרון משותף: @@ -199,12 +202,18 @@ %x שניות +Drag && drop +גרור והשלך + Info מידע Fatal Error שגיאה פטלית +Error reading file: +שגיאה בקריאת קובץ: + Scanning: סורק: @@ -223,15 +232,36 @@ Invalid FreeFileSync config file! קובץ תצורה בלתי חוקי! -File does not exist: -קובץ לא קיים: - Error parsing configuration file: שגיאה בניתוח קובץ תצורה: +Error moving to Recycle Bin: +שגיאה בהעברה לסל המיחזור: + +Could not load a required DLL: +:נדרש DLL לא יכל לטעון + +Error accessing Volume Shadow Copy Service! +שגיאה בגישה לשרות Volume Shadow Copy Service + +Making shadow copies on WOW64 is not supported. Please use FreeFileSync 64-bit version. +לא נתמכת בגרסה זאת אנא התקן גרסה 64 WOW64 העתקת צל ב + +Could not determine volume name for file: +לא יכול לקבוע שם כרך לקובץ: + +Volume name %x not part of filename %y! +כנונן %x לא בנתיב של קובץ %y! + /sec /שנ +File does not exist: +קובץ לא קיים: + +Could not read values for the following XML nodes: +XML לא יכול לקרא ערכים מצמתי : + S&ave configuration... &שמור תצורה... @@ -324,141 +354,6 @@ The command line is executed each time: A directory input field is empty. שדה כניסת מחיצה ריק. -Drag && drop -גרור והשלך - -Could not initialize directory monitoring: -לא יכול לאתחל ניטור מחיצה: - -Error when monitoring directories. -שגיאה בזמן ניטור מחיצות. - -Conversion error: -שגיאה בהסבה: - -Error deleting file: -שגיאה במחיקת קובץ: - -Error moving file: -שגיאה בהעברת קובץ: - -Target file already existing! -קובץ מטרה כבר קיים! - -Error moving directory: -שגיאה בהעברת מחיצה: - -Target directory already existing! -מחיצת מטרה כבר קיימת! - -Error deleting directory: -שגיאה במחיקת מחיצה: - -Error changing modification time: -שגיאה בשינוי זמן: - -Error loading library function: -שגיאה בטעינת ספרית פונקציות: - -Error reading security context: -שגיאה בכתיבת הקשר בטיחות: - -Error writing security context: -שגיאה בכתיבת הקשר בטיחות: - -Error copying file permissions: -שגיאה בהעתקת הרשאות קובץ: - -Error creating directory: -שגיאה ביצירת מחיצה: - -Error copying symbolic link: -שגיאה בהעתקת קישור : - -Error copying file: -שגיאה בהעתקת קובץ: - -Error opening file: -שגיאה בפתיחת קובץ: - -Error writing file: -שגיאה בכתיבת קובץ: - -Error reading file: -שגיאה בקריאת קובץ: - -Operation aborted! -הפעולה בוטלה! - -Endless loop when traversing directory: -נוצרת לולאה אינסופית בחצית מחיצות - -Error traversing directory: -שגיאה בהצלבת מחיצות - -Error setting privilege: -שגיאה בהשמת פריווילגיה - -Error moving to Recycle Bin: -שגיאה בהעברה לסל המיחזור: - -Could not load a required DLL: -:נדרש DLL לא יכל לטעון - -Error writing to synchronization database: -שגיאה ברישום לבסיס נתוני סנכרון: - -Error accessing Volume Shadow Copy Service! -שגיאה בגישה לשרות Volume Shadow Copy Service - -Making shadow copies on WOW64 is not supported. Please use FreeFileSync 64-bit version. -לא נתמכת בגרסה זאת אנא התקן גרסה 64 WOW64 העתקת צל ב - -Could not determine volume name for file: -לא יכול לקבוע שם כרך לקובץ: - -Volume name %x not part of filename %y! -כנונן %x לא בנתיב של קובץ %y! - -%x TB -%x טרה בייט - -%x PB -%x פטה בייט - -%x% -%x% - - -1 min -%x min - - -1 דקה -%x דקות - - - -1 hour -%x hours - - -1 שעה -%x שעות - - - -1 day -%x days - - -1 יום -%x ימים - - -Could not read values for the following XML nodes: -XML לא יכול לקרא ערכים מצמתי : - Logging רישום ביומן @@ -477,9 +372,6 @@ The command line is executed each time: Batch execution פעולת אצווה -Log-messages: -הודעת יומן: - Stop עצור @@ -606,6 +498,24 @@ The command line is executed each time: Total amount of data that will be transferred סך הכל נתונים להעברה +Operation: +פעולה: + +Items found: +אלמנטים נמצאו: + +Items remaining: +אלמנתים נותרו: + +Speed: +מהירות: + +Time remaining: +זמן נותר: + +Time elapsed: +זמן עבר: + Batch job עבודת אצווה @@ -654,32 +564,14 @@ The command line is executed each time: &Cancel &בטל -Operation: -פעולה: - -Items found: -אלמנטים נמצאו: - -Items remaining: -אלמנתים נותרו: - -Speed: -מהירות: - -Time remaining: -זמן נותר: - -Time elapsed: -זמן עבר: - Select variant: בחר משתנה: <אוטומטי> -Identify and propagate changes on both sides using a database. Deletions and conflicts are detected automatically. -זהה והפץ שינויים בשני הצדדים בעזרת בסיס נתונים. מחיקות וקונפליקטים מזוהים באופן אוטומטי. +Identify and propagate changes on both sides using a database. Deletions, renaming and conflicts are detected automatically. +זהה והפץ שינויים בשני הצדדים באמצעות שימוש בבסיס נתונים. מחיקות, שינויי שמות וסתירות מתגלים באופן אוטומטי. Mirror ->> <<- מראה @@ -901,27 +793,19 @@ Exclude: \stuff\temp\* העתקת קובץ בעסקה Write to a temporary file (*.ffs_tmp) first then rename it. This guarantees a consistent state even in case of fatal error. - +רשום לקובץ זמני (*.ffs_tmp) תחילה ושנה שם. פעולה זו מבטיחה עקביות המצב גם במקרה של שגיאה חמורה. Copy locked files העתק קבצים נעולים - -Copy shared or locked files using Volume Shadow Copy Service (Requires Administrator rights) - - -העתק קבצים בשיתוף או נעולים באמצעות שרות Volume Shadow Copy Service (דורש הרשאות מנהל מערכת) - +Copy shared or locked files using Volume Shadow Copy Service (Requires Administrator rights) +העתק קבצים בשיתוף או נעולים באמצעות שרות Volume Shadow Copy Service (דורש הרשאות מנהל מערכת) Copy file access permissions העתק הרשאות גישה של הקובץ - -Transfer file and directory permissions (Requires Administrator rights) - - -העבר הרשאות קבצים ומחיצות (דורש הרשאות מנהל מערכת) - +Transfer file and directory permissions (Requires Administrator rights) +העבר הרשאות קבצים ומחיצות (דורש הרשאות מנהל מערכת) Hidden dialogs: דיאלוגים מוסתרים: @@ -953,6 +837,9 @@ Transfer file and directory permissions (Requires Administrator rights) &Find next &מצא הבא +Operation aborted! +הפעולה בוטלה! + Main bar סרגל ראשי @@ -993,16 +880,16 @@ Transfer file and directory permissions (Requires Administrator rights) עימוד אוטומטי Icon size: - +גודל סמל: Small - +קטן Medium - +בינוני Large - +גדול Include all rows כלול את כל השורות @@ -1130,6 +1017,9 @@ Transfer file and directory permissions (Requires Administrator rights) File list exported! רשימת קבצים יוצאה! +Error writing file: +שגיאה בכתיבת קובץ: + Batch file created successfully! קובץ אצווה נוצר בהצלחה! @@ -1229,9 +1119,6 @@ Transfer file and directory permissions (Requires Administrator rights) Filter: Single pair זוג אחד :מסונן -Ignore -התעלם - Direct כוון @@ -1295,6 +1182,105 @@ Transfer file and directory permissions (Requires Administrator rights) Move files into a time-stamped subdirectory העבר קבצים לתוך מחיצות עם שם המכיל טביעת זמן ותאריך +%x TB +%x טרה בייט + +%x PB +%x פטה בייט + +%x% +%x% + + +1 min +%x min + + +1 דקה +%x דקות + + + +1 hour +%x hours + + +1 שעה +%x שעות + + + +1 day +%x days + + +1 יום +%x ימים + + +Could not initialize directory monitoring: +לא יכול לאתחל ניטור מחיצה: + +Error when monitoring directories. +שגיאה בזמן ניטור מחיצות. + +Conversion error: +שגיאה בהסבה: + +Error deleting file: +שגיאה במחיקת קובץ: + +Error moving file: +שגיאה בהעברת קובץ: + +Target file already existing! +קובץ מטרה כבר קיים! + +Error moving directory: +שגיאה בהעברת מחיצה: + +Target directory already existing! +מחיצת מטרה כבר קיימת! + +Error deleting directory: +שגיאה במחיקת מחיצה: + +Error changing modification time: +שגיאה בשינוי זמן: + +Error loading library function: +שגיאה בטעינת ספרית פונקציות: + +Error reading security context: +שגיאה בכתיבת הקשר בטיחות: + +Error writing security context: +שגיאה בכתיבת הקשר בטיחות: + +Error copying file permissions: +שגיאה בהעתקת הרשאות קובץ: + +Error creating directory: +שגיאה ביצירת מחיצה: + +Error copying symbolic link: +שגיאה בהעתקת קישור : + +Error copying file: +שגיאה בהעתקת קובץ: + +Error opening file: +שגיאה בפתיחת קובץ: + +Error traversing directory: +שגיאה בהצלבת מחיצות + +Endless loop when traversing directory: +נוצרת לולאה אינסופית בחצית מחיצות + +Error setting privilege: +שגיאה בהשמת פריווילגיה + Both sides have changed since last synchronization! שני הצדדים שונו מאז הסנכרון האחרון! @@ -1325,9 +1311,6 @@ Transfer file and directory permissions (Requires Administrator rights) Directories are dependent! Be careful when setting up synchronization rules: מחיצות תלויות! זהירות בהגדרת כללי סנכרון: -Comparing content of files %x -השווה תכולה של קבצים %x - Memory allocation failed! הקצאת זכרון נכשלה! @@ -1343,15 +1326,15 @@ Transfer file and directory permissions (Requires Administrator rights) Symlinks %x have the same date but a different target! קשור סימבולי %x בעל תאריך זהה אך מטרה שונה! +Comparing content of files %x +השווה תכולה של קבצים %x + Comparing files by content failed. השוואת קבצים באמצעות תכולה נכשלה. Generating file list... מייצר רשימת קבצים... -Multiple... -הכפל... - Both sides are equal שני הצדדים שווים @@ -1370,6 +1353,12 @@ Transfer file and directory permissions (Requires Administrator rights) Delete right file/folder מחק קובץ\מחיצה בצד ימין +Move file on left +העבר קובץ בצד שמאל + +Move file on right +העבר קובץ בצד ימין + Overwrite left file/folder with right one העתק ודרוס קובץ\מחיצה מימין לשמאל @@ -1385,6 +1374,9 @@ Transfer file and directory permissions (Requires Administrator rights) Copy file attributes only to right העתק תכונות קובץ בלבד משמאל לימין +Multiple... +הכפל... + Deleting file %x מוחק קובץ %x diff --git a/BUILD/Languages/hungarian.lng b/BUILD/Languages/hungarian.lng index b5a14889..c21d5efd 100644 --- a/BUILD/Languages/hungarian.lng +++ b/BUILD/Languages/hungarian.lng @@ -169,15 +169,15 @@ Comparison Result Az összehasonlítás eredménye -Incompatible synchronization database format: -Inkompatibilis szinkronizációs adatbázis formátum: - Initial synchronization: Első szinkronizáció: One of the FreeFileSync database files is not yet existing: A FreeFileSync egyik adatbázisfájlja nem létezik: +Incompatible synchronization database format: +Inkompatibilis szinkronizációs adatbázis formátum: + Database files do not share a common synchronization session: Az adatbázisfájlok nem osztoznak egy közös szinkronizációs munkameneten: @@ -372,9 +372,6 @@ A parancssor végrehajtódik minden alkalommal, ha: Batch execution Kötegelt végrehajtás -Log-messages: -Naplóbejegyzések: - Stop Megállítás @@ -501,6 +498,24 @@ A parancssor végrehajtódik minden alkalommal, ha: Total amount of data that will be transferred A mozgatandó adatok összmérete +Operation: +Művelet: + +Items found: +Talált elemek száma: + +Items remaining: +Hátralévő elemek száma: + +Speed: +Sebesség: + +Time remaining: +Hátralévő idő: + +Time elapsed: +Eltelt idő: + Batch job Kötegelt feladat @@ -549,32 +564,14 @@ A parancssor végrehajtódik minden alkalommal, ha: &Cancel &Mégsem -Operation: -Művelet: - -Items found: -Talált elemek száma: - -Items remaining: -Hátralévő elemek száma: - -Speed: -Sebesség: - -Time remaining: -Hátralévő idő: - -Time elapsed: -Eltelt idő: - Select variant: Változat kiválasztása: -Identify and propagate changes on both sides using a database. Deletions and conflicts are detected automatically. -Mindkét oldal változásainak azonosítása és tárolása adatbázis segítségével. A törlések és ütközések automatikusan észlelődnek. +Identify and propagate changes on both sides using a database. Deletions, renaming and conflicts are detected automatically. + Mirror ->> Tükrözés ->> @@ -1123,9 +1120,6 @@ Kizárni: \stuff\temp\* Filter: Single pair Szűrő: Egy pár -Ignore -Figyelmen kívül hagy - Direct Közvetlen @@ -1279,12 +1273,12 @@ Kizárni: \stuff\temp\* Error opening file: A fájl megnyitása sikertelen: -Endless loop when traversing directory: -Végtelen hurok a mappák bejárásakor: - Error traversing directory: A mappa átnézése sikertelen: +Endless loop when traversing directory: +Végtelen hurok a mappák bejárásakor: + Error setting privilege: Hiba történt a jogok beállítása közben: @@ -1318,9 +1312,6 @@ Kizárni: \stuff\temp\* Directories are dependent! Be careful when setting up synchronization rules: A mappák függenek egymástól! Legyen óvatos, amikor megadja a szinkronizálási szabályokat: -Comparing content of files %x -%x fájlok tartalmának összehasonlítása - Memory allocation failed! Sikertelen memóriafoglalás! @@ -1336,15 +1327,15 @@ Kizárni: \stuff\temp\* Symlinks %x have the same date but a different target! A(z) %x symlinknek megegyezik a dátuma, de a célpontja nem! +Comparing content of files %x +%x fájlok tartalmának összehasonlítása + Comparing files by content failed. Sikertelen a fájlok összehasonlítása tartalom alapján. Generating file list... Fájllista generálása... -Multiple... -Sokszorosítás - Both sides are equal Mindkét oldal egyforma @@ -1363,6 +1354,12 @@ Kizárni: \stuff\temp\* Delete right file/folder Jobb oldali fájl/mappa törlése +Move file on left + + +Move file on right + + Overwrite left file/folder with right one Bal oldali fájl/mappa felülírása a jobb oldalival @@ -1378,6 +1375,9 @@ Kizárni: \stuff\temp\* Copy file attributes only to right Fájl attribútumok másolása csak a jobb oldalra +Multiple... +Sokszorosítás + Deleting file %x Fájl törlése %x diff --git a/BUILD/Languages/italian.lng b/BUILD/Languages/italian.lng index cdf4ef83..97aff271 100644 --- a/BUILD/Languages/italian.lng +++ b/BUILD/Languages/italian.lng @@ -22,39 +22,6 @@ RealtimeSync - Automated Synchronization RealtimeSync - Sincronizzazione Automatizzata -Browse -Sfoglia - -Windows Error Code %x: -Errore Windows Codice %x: - -Linux Error Code %x: -Errore Linux Codice %x: - -Invalid command line: %x -Linea di comando non valida: %x - -Error resolving symbolic link: -Errore nella risoluzione di collegamento simbolico: - -Show pop-up -Mostra pop-up - -Show pop-up on errors or warnings -Mostra pop-up di errori o avvisi - -Ignore errors -Ignora gli errori - -Hide all error and warning messages -Nascondi tutti gli errori e i messaggi d'avviso - -Exit instantly -Esci istantaneamente - -Abort synchronization immediately -Interrompi immediatamente la sincronizzazione - Select alternate comparison settings Seleziona impostazioni di comparazione alternative @@ -115,6 +82,45 @@ Select time span Seleziona intervallo di tempo +Show pop-up +Mostra pop-up + +Show pop-up on errors or warnings +Mostra pop-up di errori o avvisi + +Ignore errors +Ignora gli errori + +Hide all error and warning messages +Nascondi tutti gli errori e i messaggi d'avviso + +Exit instantly +Esci istantaneamente + +Abort synchronization immediately +Interrompi immediatamente la sincronizzazione + +Browse +Sfoglia + +Error reading from synchronization database: +Errore in lettura dal database di sincronizzione: + +Error writing to synchronization database: +Errore in scrittura sul database di sincronizzazione: + +Invalid command line: %x +Linea di comando non valida: %x + +Windows Error Code %x: +Errore Windows Codice %x: + +Linux Error Code %x: +Errore Linux Codice %x: + +Error resolving symbolic link: +Errore nella risoluzione di collegamento simbolico: + %x MB %x MB @@ -163,17 +169,14 @@ Comparison Result Risultato della comparazione -Incompatible synchronization database format: -Formato database di sincronizzazione incompatibile: - Initial synchronization: Prima sincronizzazione: One of the FreeFileSync database files is not yet existing: Un file database di FreeFileSync non è ancora stato creato: -Error reading from synchronization database: -Errore in lettura dal database di sincronizzione: +Incompatible synchronization database format: +Formato database di sincronizzazione incompatibile: Database files do not share a common synchronization session: I file database non condividono una comune sessione di sincronizzazione: @@ -199,12 +202,18 @@ %x sec +Drag && drop +Drag && drop + Info Info Fatal Error Errore Fatale +Error reading file: +Errore durante la lettura del file: + Scanning: Analisi in corso: @@ -223,15 +232,36 @@ Invalid FreeFileSync config file! File di configurazione FreeFileSync non valido! -File does not exist: -Il file non esiste: - Error parsing configuration file: Errore nell'analisi del file di configurazione: +Error moving to Recycle Bin: +Errore durante lo spostamento nel Cestino: + +Could not load a required DLL: +Impossibile caricare una DLL richiesta: + +Error accessing Volume Shadow Copy Service! +Errore in accesso al Servizio Volume Shadow Copy + +Making shadow copies on WOW64 is not supported. Please use FreeFileSync 64-bit version. +La creazione di copie shadow su WOW64 non e' supportata. Utilizzare FreeFileSync in versione 64-bit. + +Could not determine volume name for file: +Impossibile determinare il nome volume per il file: + +Volume name %x not part of filename %y! +Il nome volume %x non è parte del nome file %y! + /sec /sec +File does not exist: +Il file non esiste: + +Could not read values for the following XML nodes: +Impossibile leggere i valori per i seguenti nodi XML: + S&ave configuration... S&alva la configurazione... @@ -324,141 +354,6 @@ La linea di comando è eseguita ogni volta che: A directory input field is empty. Un campo directory di input è vuoto. -Drag && drop -Drag && drop - -Could not initialize directory monitoring: -Monitoraggio directory non inizializzabile: - -Error when monitoring directories. -Errore durante il monitoraggio directory. - -Conversion error: -Errore di conversione: - -Error deleting file: -Errore durante l'eliminazione del file: - -Error moving file: -Errore nello spostamento file: - -Target file already existing! -File destinazione già esistente! - -Error moving directory: -Errore nello spostamento directory: - -Target directory already existing! -Directory di destinazione già esistente! - -Error deleting directory: -Errore durante l'eliminazione delle directory: - -Error changing modification time: -Errore durante la modifica della data: - -Error loading library function: -Errore nel caricamento della funzione libreria: - -Error reading security context: -Errore in lettura del contesto di sicurezza: - -Error writing security context: -Errore in scrittura del contesto di sicurezza: - -Error copying file permissions: -Errore durante la copia dei permessi su file: - -Error creating directory: -Errore durante la creazione della directory: - -Error copying symbolic link: -Errore durante la copia del link simbolico: - -Error copying file: -Errore durante la copia del file: - -Error opening file: -Errore in apertura file: - -Error writing file: -Errore durante la scrittura del file: - -Error reading file: -Errore durante la lettura del file: - -Operation aborted! -Operazione abortita! - -Endless loop when traversing directory: -Loop senza fine attraverso le directory: - -Error traversing directory: -Errore nel percorso della directory: - -Error setting privilege: -Errore nell'impostazione dei privilegi: - -Error moving to Recycle Bin: -Errore durante lo spostamento nel Cestino: - -Could not load a required DLL: -Impossibile caricare una DLL richiesta: - -Error writing to synchronization database: -Errore in scrittura sul database di sincronizzazione: - -Error accessing Volume Shadow Copy Service! -Errore in accesso al Servizio Volume Shadow Copy - -Making shadow copies on WOW64 is not supported. Please use FreeFileSync 64-bit version. -La creazione di copie shadow su WOW64 non e' supportata. Utilizzare FreeFileSync in versione 64-bit. - -Could not determine volume name for file: -Impossibile determinare il nome volume per il file: - -Volume name %x not part of filename %y! -Il nome volume %x non è parte del nome file %y! - -%x TB -%x TB - -%x PB -%x PB - -%x% -%x% - - -1 min -%x min - - -1 min -%x min - - - -1 hour -%x hours - - -1 ora -%x ore - - - -1 day -%x days - - -1 giorno -%x giorni - - -Could not read values for the following XML nodes: -Impossibile leggere i valori per i seguenti nodi XML: - Logging Logging @@ -477,9 +372,6 @@ La linea di comando è eseguita ogni volta che: Batch execution Esecuzione in batch -Log-messages: -Log-messages: - Stop Stop @@ -606,6 +498,24 @@ La linea di comando è eseguita ogni volta che: Total amount of data that will be transferred Volume dei dati che verranno trasferiti +Operation: +Operazione: + +Items found: +Elementi trovati: + +Items remaining: +Elementi rimanenti: + +Speed: +Velocita': + +Time remaining: +Tempo rimanente: + +Time elapsed: +Tempo trascorso: + Batch job Batch job @@ -654,32 +564,14 @@ La linea di comando è eseguita ogni volta che: &Cancel &Annulla -Operation: -Operazione: - -Items found: -Elementi trovati: - -Items remaining: -Elementi rimanenti: - -Speed: -Velocita': - -Time remaining: -Tempo rimanente: - -Time elapsed: -Tempo trascorso: - Select variant: Selezionare una variante: -Identify and propagate changes on both sides using a database. Deletions and conflicts are detected automatically. -Identifica e propaga cambiamenti su entrambi i lati usando un database. Cancellazioni e conflitti sono riconosciuti automaticamente. +Identify and propagate changes on both sides using a database. Deletions, renaming and conflicts are detected automatically. +Identifica e propaga modifiche su entrambi i lati usando un database. Cancellazioni, ridenominazioni e conflitti sono rilevati automaticamente. Mirror ->> Mirror ->> @@ -901,27 +793,19 @@ Escludi: \stuff\temp\* Copia transazionale file Write to a temporary file (*.ffs_tmp) first then rename it. This guarantees a consistent state even in case of fatal error. - +Scrivi su un file temporaneo (*.ffs_tmp) prima di rinominarlo. Ciò garantisce uno stato consistente anche in caso di errore fatale. Copy locked files Copia file bloccati - -Copy shared or locked files using Volume Shadow Copy Service (Requires Administrator rights) - - -Copia file condivisi o bloccati usando il Servizio Volume Shadow Copy (Richiede diritti di Administrator) - +Copy shared or locked files using Volume Shadow Copy Service (Requires Administrator rights) +Copia file condivisi o bloccati usando il Servizio Volume Shadow Copy (Richiede diritti di Administrator) Copy file access permissions Copia permessi di accesso file - -Transfer file and directory permissions (Requires Administrator rights) - - -Trasferisci file e permessi sulle cartelle (Richiede diritti di Administrator) - +Transfer file and directory permissions (Requires Administrator rights) +Trasferisci file e permessi sulle cartelle (Richiede diritti di Administrator) Hidden dialogs: Messaggi nascosti: @@ -953,6 +837,9 @@ Trasferisci file e permessi sulle cartelle (Richiede diritti di Administrator) &Find next &Trova successivo +Operation aborted! +Operazione abortita! + Main bar Barra principale @@ -993,16 +880,16 @@ Trasferisci file e permessi sulle cartelle (Richiede diritti di Administrator) Larghezza automatica colonne Icon size: - +Dimensione icona: Small - +Piccola Medium - +Media Large - +Grande Include all rows Includi tutte le righe @@ -1130,6 +1017,9 @@ Trasferisci file e permessi sulle cartelle (Richiede diritti di Administrator) File list exported! Lista dei file esportata! +Error writing file: +Errore durante la scrittura del file: + Batch file created successfully! Creazione batch file riuscita! @@ -1229,9 +1119,6 @@ Trasferisci file e permessi sulle cartelle (Richiede diritti di Administrator) Filter: Single pair Filtro: Singola coppia -Ignore -Ignora - Direct Diretto @@ -1295,6 +1182,105 @@ Trasferisci file e permessi sulle cartelle (Richiede diritti di Administrator) Move files into a time-stamped subdirectory Sposta file in una sotto-cartella datata +%x TB +%x TB + +%x PB +%x PB + +%x% +%x% + + +1 min +%x min + + +1 min +%x min + + + +1 hour +%x hours + + +1 ora +%x ore + + + +1 day +%x days + + +1 giorno +%x giorni + + +Could not initialize directory monitoring: +Monitoraggio directory non inizializzabile: + +Error when monitoring directories. +Errore durante il monitoraggio directory. + +Conversion error: +Errore di conversione: + +Error deleting file: +Errore durante l'eliminazione del file: + +Error moving file: +Errore nello spostamento file: + +Target file already existing! +File destinazione già esistente! + +Error moving directory: +Errore nello spostamento directory: + +Target directory already existing! +Directory di destinazione già esistente! + +Error deleting directory: +Errore durante l'eliminazione delle directory: + +Error changing modification time: +Errore durante la modifica della data: + +Error loading library function: +Errore nel caricamento della funzione libreria: + +Error reading security context: +Errore in lettura del contesto di sicurezza: + +Error writing security context: +Errore in scrittura del contesto di sicurezza: + +Error copying file permissions: +Errore durante la copia dei permessi su file: + +Error creating directory: +Errore durante la creazione della directory: + +Error copying symbolic link: +Errore durante la copia del link simbolico: + +Error copying file: +Errore durante la copia del file: + +Error opening file: +Errore in apertura file: + +Error traversing directory: +Errore nel percorso della directory: + +Endless loop when traversing directory: +Loop senza fine attraverso le directory: + +Error setting privilege: +Errore nell'impostazione dei privilegi: + Both sides have changed since last synchronization! Entrambi i lati sono cambiati dall'ultima sincronizzazione! @@ -1325,9 +1311,6 @@ Trasferisci file e permessi sulle cartelle (Richiede diritti di Administrator) Directories are dependent! Be careful when setting up synchronization rules: Le directory sono dipendenti! Fai attenzione quando configuri le regole di sincronizzazione: -Comparing content of files %x -Comparazione contenuto del file %x - Memory allocation failed! Allocazione di memoria fallita! @@ -1343,15 +1326,15 @@ Trasferisci file e permessi sulle cartelle (Richiede diritti di Administrator) Symlinks %x have the same date but a different target! Symlinks %x hanno stessa data ma differente target! +Comparing content of files %x +Comparazione contenuto del file %x + Comparing files by content failed. Comparazione file in base al contenuto fallita. Generating file list... Generazione lista dei file... -Multiple... -Multiplo... - Both sides are equal Entrambi i lati sono uguali @@ -1370,6 +1353,12 @@ Trasferisci file e permessi sulle cartelle (Richiede diritti di Administrator) Delete right file/folder Cancella file/cartella di destra +Move file on left +Sposta il file a sinistra + +Move file on right +Sposta il file a destra + Overwrite left file/folder with right one Sovrascrivi file/cartella di sinistra con quello di destra @@ -1385,6 +1374,9 @@ Trasferisci file e permessi sulle cartelle (Richiede diritti di Administrator) Copy file attributes only to right Copia i soli attributi file verso destra +Multiple... +Multiplo... + Deleting file %x Eliminazione file %x diff --git a/BUILD/Languages/japanese.lng b/BUILD/Languages/japanese.lng index fb788c8d..b3f3e1d1 100644 --- a/BUILD/Languages/japanese.lng +++ b/BUILD/Languages/japanese.lng @@ -80,7 +80,7 @@ 検索 Select time span - +タイムスパンを選択 Show pop-up ポップアップ表示 @@ -148,7 +148,7 @@ サイズ Date -データ +日付 Full path フルパス @@ -168,15 +168,15 @@ Comparison Result 比較結果 -Incompatible synchronization database format: -同期データベースの書式に互換性がありません: - Initial synchronization: 同期処理の初期化: One of the FreeFileSync database files is not yet existing: FreeFileSync データベースファイルが存在しません: +Incompatible synchronization database format: +同期データベースの書式に互換性がありません: + Database files do not share a common synchronization session: データベースファイルは一般的な同期セッションを共有しません: @@ -239,7 +239,7 @@ 必要なDLLを読み込めません: Error accessing Volume Shadow Copy Service! - +ボリュームシャドウ・コピーサービスにアクセス出来ません! Making shadow copies on WOW64 is not supported. Please use FreeFileSync 64-bit version. WOW64 では、ボリュームシャドウコピーに対応していません、FreeFileSync 64-bit 版をお試しください。 @@ -369,9 +369,6 @@ The command line is executed each time: Batch execution 一括処理を実行 -Log-messages: -ログメッセージ: - Stop 停止 @@ -498,6 +495,24 @@ The command line is executed each time: Total amount of data that will be transferred 転送されたデータの総量 +Operation: +操作: + +Items found: +見つかった要素: + +Items remaining: +残りの要素: + +Speed: +速度: + +Time remaining: +残り時間: + +Time elapsed: +経過時間: + Batch job 一括処理 @@ -546,32 +561,14 @@ The command line is executed each time: &Cancel キャンセル(&C) -Operation: -操作: - -Items found: -見つかった要素: - -Items remaining: -残りの要素: - -Speed: -速度: - -Time remaining: -残り時間: - -Time elapsed: -経過時間: - Select variant: 変数を選択: <自動> -Identify and propagate changes on both sides using a database. Deletions and conflicts are detected automatically. -データベースを使用して、両側アイテムの変更を特定します。 削除、競合は自動的に検出することができます。 +Identify and propagate changes on both sides using a database. Deletions, renaming and conflicts are detected automatically. +両側の識別、プロパティの変更特定にデータベースを使用します。削除、リネーム及び競合などは自動的に検出されます Mirror ->> ミラー >> @@ -790,30 +787,22 @@ Exclude: \stuff\temp\* 列を下に移動 Transactional file copy -Transactional ファイルコピー +トランザクション・コピーを使用 Write to a temporary file (*.ffs_tmp) first then rename it. This guarantees a consistent state even in case of fatal error. 最初に一時ファイル(*.ffs_tmp)に書き込み、それをリネームします。これにより、致命的なエラーが起こっても状態は保証されます Copy locked files -ロックされたファイルをコピー +ロックされたファイルをコピーする - -Copy shared or locked files using Volume Shadow Copy Service (Requires Administrator rights) - - -ボリュームシャドーコピーを使用して共有/ロックされたファイルをコピー(管理者権限が必要) - +Copy shared or locked files using Volume Shadow Copy Service (Requires Administrator rights) +ボリュームシャドーコピーを使用して共有/ロックされたファイルをコピー(管理者権限が必要) Copy file access permissions -ファイルのアクセスパーミッションをコピー +ファイルのアクセスパーミッションをコピーする - -Transfer file and directory permissions (Requires Administrator rights) - - -ファイルとディレクトリのパーミッション転送(管理者権限が必要) - +Transfer file and directory permissions (Requires Administrator rights) +ファイルとディレクトリのパーミッション転送(管理者権限が必要) Hidden dialogs: ダイアログを隠す @@ -1123,9 +1112,6 @@ Transfer file and directory permissions (Requires Administrator rights) Filter: Single pair フィルター:単一ペア -Ignore -無視 - Direct 方向 @@ -1274,12 +1260,12 @@ Transfer file and directory permissions (Requires Administrator rights) Error opening file: ファイルのオープンに失敗: -Endless loop when traversing directory: -ディレクトリ移動中に無限ループが発生: - Error traversing directory: ディレクトリの移動エラー: +Endless loop when traversing directory: +ディレクトリ移動中に無限ループが発生: + Error setting privilege: 特権の設定エラー: @@ -1313,9 +1299,6 @@ Transfer file and directory permissions (Requires Administrator rights) Directories are dependent! Be careful when setting up synchronization rules: ディレクトリが依存関係にあります! 同期規則の設定時には注意してください: -Comparing content of files %x -ファイル %x の内容を比較中 - Memory allocation failed! メモリ割り当てに失敗! @@ -1331,15 +1314,15 @@ Transfer file and directory permissions (Requires Administrator rights) Symlinks %x have the same date but a different target! シンボリックリンク %x の日付は同一ですが、異なる対象があります! +Comparing content of files %x +ファイル %x の内容を比較中 + Comparing files by content failed. ファイル内容の比較に失敗しました Generating file list... ファイル一覧を作成中... -Multiple... -複数処理... - Both sides are equal 両側とも等しく @@ -1358,6 +1341,12 @@ Transfer file and directory permissions (Requires Administrator rights) Delete right file/folder 右側のファイル/フォルダを削除 +Move file on left +ファイルを左に移動 + +Move file on right +ファイルを右に移動 + Overwrite left file/folder with right one 右側のものを左側のファイル/フォルダに上書き @@ -1373,6 +1362,9 @@ Transfer file and directory permissions (Requires Administrator rights) Copy file attributes only to right ファイル属性のみ右側にコピー +Multiple... +複数処理... + Deleting file %x ファイル %x を削除中 diff --git a/BUILD/Languages/korean.lng b/BUILD/Languages/korean.lng index 561c10cd..653fb7e9 100644 --- a/BUILD/Languages/korean.lng +++ b/BUILD/Languages/korean.lng @@ -22,39 +22,6 @@ RealtimeSync - Automated Synchronization 실시간 동기화 - 자동 동기화 -Browse -찾아보기 - -Windows Error Code %x: -윈도우 에러 코드 %x: - -Linux Error Code %x: -리눅스 에러 코드 %x: - -Invalid command line: %x -잘못된 명령줄 : %x - -Error resolving symbolic link: -심볼릭 링크를 해결하던 중 발생한 오류 : - -Show pop-up -팝업 보이기 - -Show pop-up on errors or warnings -오류 또는 경고에 대한 팝업 보이기 - -Ignore errors -오류 무시 - -Hide all error and warning messages -모든 오류/경고 메세지 숨기기 - -Exit instantly -즉시 종료 - -Abort synchronization immediately -동기화 작업 즉시 중단 - Select alternate comparison settings 대체 비교 설정 선택 @@ -115,6 +82,45 @@ Select time span 시간간격(타임스팬) 선택 +Show pop-up +팝업 보이기 + +Show pop-up on errors or warnings +오류 또는 경고에 대한 팝업 보이기 + +Ignore errors +오류 무시 + +Hide all error and warning messages +모든 오류/경고 메세지 숨기기 + +Exit instantly +즉시 종료 + +Abort synchronization immediately +동기화 작업 즉시 중단 + +Browse +찾아보기 + +Error reading from synchronization database: +동기화 데이터베이스로부터 읽어 들이던 중 발생한 오류 : + +Error writing to synchronization database: +동기화 데이터베이스에 쓰던 중 발생한 오류 : + +Invalid command line: %x +잘못된 명령줄 : %x + +Windows Error Code %x: +윈도우 에러 코드 %x: + +Linux Error Code %x: +리눅스 에러 코드 %x: + +Error resolving symbolic link: +심볼릭 링크를 해결하던 중 발생한 오류 : + %x MB %x MB @@ -162,17 +168,14 @@ Comparison Result 비교 결과 -Incompatible synchronization database format: -호환되지 않는 동기화 데이터베이스 형식 : - Initial synchronization: 초기 동기화 : One of the FreeFileSync database files is not yet existing: FreeFileSync 데이터베이스 파일 중 하나가 아직 존재하지 않습니다 : -Error reading from synchronization database: -동기화 데이터베이스로부터 읽어 들이던 중 발생한 오류 : +Incompatible synchronization database format: +호환되지 않는 동기화 데이터베이스 형식 : Database files do not share a common synchronization session: 데이터베이스 파일이 공통 동기화 세션을 공유하지 않습니다 : @@ -197,12 +200,18 @@ %x초 +Drag && drop +드래그 && 드랍 (마우스로 파일 끌어다 놓기) + Info 정보 Fatal Error 치명적 오류 +Error reading file: +파일을 읽던 중 발생한 오류 : + Scanning: 스캔 : @@ -220,15 +229,36 @@ Invalid FreeFileSync config file! 잘못된 FreeFileSync 설정 파일! -File does not exist: -파일이 존재하지 않습니다 : - Error parsing configuration file: 설정파일 분석 중 발생한 오류 : +Error moving to Recycle Bin: +휴지통으로 이동 중 발생한 오류 : + +Could not load a required DLL: +필요한 DLL을 로드할 수 없습니다 : + +Error accessing Volume Shadow Copy Service! +볼륨 섀도 복사본 서비스에 액세스하던 중 오류 발생! + +Making shadow copies on WOW64 is not supported. Please use FreeFileSync 64-bit version. +WOW64 에서의 Shadow Copy 는 지원하지 않습니다. FreeFileSync 64-bit 버전을 사용하세요. + +Could not determine volume name for file: +파일 볼륨 이름을 결정할 수 없습니다 : + +Volume name %x not part of filename %y! +볼륨 이름 %x 이(가) 파일 이름 %y 의 일부가 아닙니다! + /sec /초 +File does not exist: +파일이 존재하지 않습니다 : + +Could not read values for the following XML nodes: +다음 XML 노드 값을 읽어 들일 수 없습니다 : + S&ave configuration... 설정 저장 @@ -321,138 +351,6 @@ The command line is executed each time: A directory input field is empty. 디렉토리 입력 필드가 비어 있습니다. -Drag && drop -드래그 && 드랍 - -Could not initialize directory monitoring: -디렉토리 모니터링을 초기화 할 수 없습니다 : - -Error when monitoring directories. -디렉토리 모니터링 중 발생한 오류 : - -Conversion error: -변환 오류 : - -Error deleting file: -파일 삭제 중 발생한 오류 : - -Error moving file: -파일 이동 중 발생한 오류 : - -Target file already existing! -대상 파일이 이미 존재합니다! - -Error moving directory: -디렉토리 이동 중 발생한 오류 : - -Target directory already existing! -대상 디렉토리가 이미 존재합니다! - -Error deleting directory: -디렉토리 삭제 중 발생한 오류 : - -Error changing modification time: -시간 수정 중 발생한 오류 : - -Error loading library function: -라이브러리 기능 로드 중 발생한 오류 : - -Error reading security context: -보안 컨텍스트를 읽던 중 발생한 오류 : - -Error writing security context: -보안 컨텍스트를 쓰던 중 발생한 오류 : - -Error copying file permissions: -파일 권한 복사 중 발생한 오류 : - -Error creating directory: -디렉토리 생성 중 발생한 오류 : - -Error copying symbolic link: -심볼릭 링크 복사 중 발생한 오류 : - -Error copying file: -파일 복사 중 발생한 오류 : - -Error opening file: -파일을 열던 중 발생한 오류 : - -Error writing file: -파일을 쓰던 중 발생한 오류 : - -Error reading file: -파일을 읽던 중 발생한 오류 : - -Operation aborted! -작업 중단! - -Endless loop when traversing directory: -디렉토리 이동 중 무한 루프 발생 : - -Error traversing directory: -디렉토리 이동 중 발생한 오류 : - -Error setting privilege: -권한 설정 중 발생한 오류 : - -Error moving to Recycle Bin: -휴지통으로 이동 중 발생한 오류 : - -Could not load a required DLL: -필요한 DLL을 로드할 수 없습니다 : - -Error writing to synchronization database: -동기화 데이터베이스에 쓰던 중 발생한 오류 : - -Error accessing Volume Shadow Copy Service! -볼륨 섀도 복사본 서비스에 액세스하던 중 오류 발생! - -Making shadow copies on WOW64 is not supported. Please use FreeFileSync 64-bit version. -WOW64 에서의 Shadow Copy 는 지원하지 않습니다. FreeFileSync 64-bit 버전을 사용하세요. - -Could not determine volume name for file: -파일 볼륨 이름을 결정할 수 없습니다 : - -Volume name %x not part of filename %y! -볼륨 이름 %x 이(가) 파일 이름 %y 의 일부가 아닙니다! - -%x TB -%x TB - -%x PB -%x PB - -%x% -%x% - - -1 min -%x min - - -%x분 - - - -1 hour -%x hours - - -%x시간 - - - -1 day -%x days - - -%x일 - - -Could not read values for the following XML nodes: -다음 XML 노드 값을 읽어 들일 수 없습니다 : - Logging 로그 중 @@ -471,9 +369,6 @@ The command line is executed each time: Batch execution 일괄 실행 -Log-messages: -로그 메세지 : - Stop 정지 @@ -600,6 +495,24 @@ The command line is executed each time: Total amount of data that will be transferred 전송하게 될 전체 데이터 용량 +Operation: +작업 : + +Items found: +발견된 요소 : + +Items remaining: +남은 요소 : + +Speed: +속도 : + +Time remaining: +남은 시간 : + +Time elapsed: +경과 시간 : + Batch job 일괄 작업 @@ -648,32 +561,14 @@ The command line is executed each time: &Cancel 취소(&C) -Operation: -작업 : - -Items found: -발견된 요소 : - -Items remaining: -남은 요소 : - -Speed: -속도 : - -Time remaining: -남은 시간 : - -Time elapsed: -경과 시간 : - Select variant: 옵션 선택 : <자동> -Identify and propagate changes on both sides using a database. Deletions and conflicts are detected automatically. -데이터베이스를 사용하여, 양측 변경사항을 확인합니다. 삭제 및 충돌 내역은 자동 감지됩니다. +Identify and propagate changes on both sides using a database. Deletions, renaming and conflicts are detected automatically. +데이터베이스를 활용하여 양측의 변경사항을 확인하고 반영합니다. 파일 삭제/명칭 변경/충돌은 자동으로 감지됩니다. Mirror ->> 미러 ->> @@ -895,27 +790,19 @@ Exclude: \stuff\temp\* 트랜잭션 파일 복사 Write to a temporary file (*.ffs_tmp) first then rename it. This guarantees a consistent state even in case of fatal error. - +임시 파일 (*.ffs_tmp)로 우선 작성 후, 파일명을 변경합니다. 이러면 치명적인 오류가 발생하더라도 일관된 상태를 보장할 수 있습니다. Copy locked files 락 걸린 파일 복사 - -Copy shared or locked files using Volume Shadow Copy Service (Requires Administrator rights) - - -Volume Shadow Copy를 사용하여 공유 또는 락 걸린 파일을 복사 (관리자 권한 필요) - +Copy shared or locked files using Volume Shadow Copy Service (Requires Administrator rights) +Volume Shadow Copy를 사용하여 공유 또는 락 걸린 파일을 복사 (관리자 권한 필요) Copy file access permissions 파일 접근 권한 복사 - -Transfer file and directory permissions (Requires Administrator rights) - - -파일 및 디렉토리 권한 전송 (관리자 권한이 필요함) - +Transfer file and directory permissions (Requires Administrator rights) +파일 및 디렉토리 권한 전송 (관리자 권한이 필요함) Hidden dialogs: 다이얼로그 숨기기 @@ -947,6 +834,9 @@ Transfer file and directory permissions (Requires Administrator rights) &Find next 다음 검색(&F) +Operation aborted! +작업 중단! + Main bar 메인 바 @@ -987,16 +877,16 @@ Transfer file and directory permissions (Requires Administrator rights) 열 자동정렬 Icon size: - +아이콘 크기 Small - +작게 Medium - +중간 Large - +크게 Include all rows 모든 행 포함 @@ -1124,6 +1014,9 @@ Transfer file and directory permissions (Requires Administrator rights) File list exported! 파일 리스트 내보내기 완료! +Error writing file: +파일을 쓰던 중 발생한 오류 : + Batch file created successfully! 일괄 파일이 성공적으로 생성 됐습니다! @@ -1219,9 +1112,6 @@ Transfer file and directory permissions (Requires Administrator rights) Filter: Single pair 필터 : 단일 페어(짝) -Ignore -무시 - Direct 다이렉트 @@ -1283,6 +1173,102 @@ Transfer file and directory permissions (Requires Administrator rights) Move files into a time-stamped subdirectory 파일을 타임스탬프 된 서브 폴더로 이동 +%x TB +%x TB + +%x PB +%x PB + +%x% +%x% + + +1 min +%x min + + +%x분 + + + +1 hour +%x hours + + +%x시간 + + + +1 day +%x days + + +%x일 + + +Could not initialize directory monitoring: +디렉토리 모니터링을 초기화 할 수 없습니다 : + +Error when monitoring directories. +디렉토리 모니터링 중 발생한 오류 : + +Conversion error: +변환 오류 : + +Error deleting file: +파일 삭제 중 발생한 오류 : + +Error moving file: +파일 이동 중 발생한 오류 : + +Target file already existing! +대상 파일이 이미 존재합니다! + +Error moving directory: +디렉토리 이동 중 발생한 오류 : + +Target directory already existing! +대상 디렉토리가 이미 존재합니다! + +Error deleting directory: +디렉토리 삭제 중 발생한 오류 : + +Error changing modification time: +시간 수정 중 발생한 오류 : + +Error loading library function: +라이브러리 기능 로드 중 발생한 오류 : + +Error reading security context: +보안 컨텍스트를 읽던 중 발생한 오류 : + +Error writing security context: +보안 컨텍스트를 쓰던 중 발생한 오류 : + +Error copying file permissions: +파일 권한 복사 중 발생한 오류 : + +Error creating directory: +디렉토리 생성 중 발생한 오류 : + +Error copying symbolic link: +심볼릭 링크 복사 중 발생한 오류 : + +Error copying file: +파일 복사 중 발생한 오류 : + +Error opening file: +파일을 열던 중 발생한 오류 : + +Error traversing directory: +디렉토리 이동 중 발생한 오류 : + +Endless loop when traversing directory: +디렉토리 이동 중 무한 루프 발생 : + +Error setting privilege: +권한 설정 중 발생한 오류 : + Both sides have changed since last synchronization! 마지막 동기화 작업 이후, 양측 모두 변경 되었습니다! @@ -1313,9 +1299,6 @@ Transfer file and directory permissions (Requires Administrator rights) Directories are dependent! Be careful when setting up synchronization rules: 디렉토리가 의존 관계에 있습니다. 동기화 규칙 설정시 주의하십시오. -Comparing content of files %x -파일 %x 내용 별 비교 중 - Memory allocation failed! 메모리 할당 실패! @@ -1331,15 +1314,15 @@ Transfer file and directory permissions (Requires Administrator rights) Symlinks %x have the same date but a different target! 심링크 %x 의 날짜는 같으나, 대상이 다릅니다! +Comparing content of files %x +파일 %x 내용 별 비교 중 + Comparing files by content failed. 내용 별 파일 비교 실패 Generating file list... 파일 리스트 생성 중... -Multiple... -다중처리 (멀티플) 작업... - Both sides are equal 양측이 같음 @@ -1358,6 +1341,12 @@ Transfer file and directory permissions (Requires Administrator rights) Delete right file/folder 우측 파일/폴더 삭제 +Move file on left +좌측 파일 이동 + +Move file on right +우측 파일 이동 + Overwrite left file/folder with right one 우측 파일/폴더로 좌측 파일/폴더 덮어쓰기 @@ -1373,6 +1362,9 @@ Transfer file and directory permissions (Requires Administrator rights) Copy file attributes only to right 파일 속성만 우측으로 복사 +Multiple... +다중처리 (멀티플) 작업... + Deleting file %x 파일 %x 삭제 중 diff --git a/BUILD/Languages/polish.lng b/BUILD/Languages/polish.lng index 6ce2e79b..5c874c53 100644 --- a/BUILD/Languages/polish.lng +++ b/BUILD/Languages/polish.lng @@ -22,39 +22,6 @@ RealtimeSync - Automated Synchronization RealtimeSync - Automatyczna Synchronizacja -Browse -Przeglądaj - -Windows Error Code %x: -Błąd systemu Windows %x: - -Linux Error Code %x: -Błąd systemu linux %x: - -Invalid command line: %x -Nieprawidłowa komenda: %x - -Error resolving symbolic link: -Błąd odczytu dowiązania symbolicznego: - -Show pop-up -Pokazuj okna pop-up - -Show pop-up on errors or warnings -Pokazuj okna pop-up dla błędów i ostrzeżeń - -Ignore errors -Ignoruj błędy - -Hide all error and warning messages -Ukryj wszystkie informacje błędach i ostrzeżeniach - -Exit instantly -Wyjdź natychmiast - -Abort synchronization immediately -Natychmiast zakończ synchronizację - Select alternate comparison settings Określ alternatywne ustawienia porównywania @@ -115,6 +82,45 @@ Select time span Określ przedział czasowy +Show pop-up +Pokazuj okna pop-up + +Show pop-up on errors or warnings +Pokazuj okna pop-up dla błędów i ostrzeżeń + +Ignore errors +Ignoruj błędy + +Hide all error and warning messages +Ukryj wszystkie informacje błędach i ostrzeżeniach + +Exit instantly +Wyjdź natychmiast + +Abort synchronization immediately +Natychmiast zakończ synchronizację + +Browse +Przeglądaj + +Error reading from synchronization database: +Błąd odczytu z bazy danych synchronizacji: + +Error writing to synchronization database: +Błąd zapisu do bazy danych synchronizacji: + +Invalid command line: %x +Nieprawidłowa komenda: %x + +Windows Error Code %x: +Błąd systemu Windows %x: + +Linux Error Code %x: +Błąd systemu linux %x: + +Error resolving symbolic link: +Błąd odczytu dowiązania symbolicznego: + %x MB %x MB @@ -164,17 +170,14 @@ Comparison Result Rezultat porównywania -Incompatible synchronization database format: -Niepoprawny format bazy danych dla synchronizacji: - Initial synchronization: Wstępna synchronizacja: One of the FreeFileSync database files is not yet existing: Jeden z plików bazy danych FreeFileSync nie istnieje: -Error reading from synchronization database: -Błąd odczytu z bazy danych synchronizacji: +Incompatible synchronization database format: +Niepoprawny format bazy danych dla synchronizacji: Database files do not share a common synchronization session: Pliki danych nie współdzielą wspólnej sesji synchronizacji: @@ -201,12 +204,18 @@ %x sekund +Drag && drop +Drag && Drop + Info Info Fatal Error Błąd krytyczny +Error reading file: +Błąd odczytu pliku: + Scanning: Skanowanie: @@ -226,15 +235,36 @@ Invalid FreeFileSync config file! Nieprawidłowy plik konfiguracyjny! -File does not exist: -Plik nie istnieje: - Error parsing configuration file: Błąd parsowania pliku konfiguracyjnego: +Error moving to Recycle Bin: +Błąd podczas przenoszenia do kosza: + +Could not load a required DLL: +Nie można załadować wymaganej biblioteki DLL: + +Error accessing Volume Shadow Copy Service! +Błąd podczas dostępdu do usługi Volume Shadow Copy! + +Making shadow copies on WOW64 is not supported. Please use FreeFileSync 64-bit version. +Tworzenie Shadow Copies dla WOW64 nie jest obsługiwane. Zainstaluj 64 bitową wersję FreeFileSync. + +Could not determine volume name for file: +Nie można określić nazwy dysku dla pliku: + +Volume name %x not part of filename %y! +Dysk %x nie jest częścią pliku %y! + /sec /sekundę +File does not exist: +Plik nie istnieje: + +Could not read values for the following XML nodes: +Nie można odczytać wartości dla danych gałęzi XML: + S&ave configuration... Z&apisz konfigurację... @@ -327,144 +357,6 @@ Komenda jest wykonwywana za każdym razem gdy: A directory input field is empty. Pole ze ścieżką katalogu jest puste. -Drag && drop -Drag && Drop - -Could not initialize directory monitoring: -Nie można uruchomić monitora katalogów: - -Error when monitoring directories. -Błąd podczas monitorowania katalogów. - -Conversion error: -Błąd konwersji: - -Error deleting file: -Błąd podczas usuwania pliku: - -Error moving file: -Błąd podczas przenoszenia pliku: - -Target file already existing! -Plik docelowy już istnieje! - -Error moving directory: -Błąd podczas przenoszenia katalogu: - -Target directory already existing! -Katalog docelowy już istnieje! - -Error deleting directory: -Błąd podczas usuwania katalogu: - -Error changing modification time: -Błąd zmiany godziny modyfikacji: - -Error loading library function: -Błąd wczytywania funkcji: - -Error reading security context: -Błąd odczytu kontekstu bezpieczeństwa: - -Error writing security context: -Błąd zapisu kontekstu bezpieczeństwa: - -Error copying file permissions: -Błąd podczas kopiowania uprawnień pliku: - -Error creating directory: -Błąd podczas tworzenia katalogu: - -Error copying symbolic link: -Błąd podczas kopiowania dowiązania symbolicznego (symlink) - -Error copying file: -Błąd podczas kopiowania pliku: - -Error opening file: -Błąd odczytu pliku: - -Error writing file: -Błąd zapisu pliku: - -Error reading file: -Błąd odczytu pliku: - -Operation aborted! -Operacja przerwana! - -Endless loop when traversing directory: -Zapętlenie podczas przeglądania katalogu: - -Error traversing directory: -Błąd podczas odczytywania katalogu: - -Error setting privilege: -Błąd ustawiania uprawnień: - -Error moving to Recycle Bin: -Błąd podczas przenoszenia do kosza: - -Could not load a required DLL: -Nie można załadować wymaganej biblioteki DLL: - -Error writing to synchronization database: -Błąd zapisu do bazy danych synchronizacji: - -Error accessing Volume Shadow Copy Service! -Błąd podczas dostępdu do usługi Volume Shadow Copy! - -Making shadow copies on WOW64 is not supported. Please use FreeFileSync 64-bit version. -Tworzenie Shadow Copies dla WOW64 nie jest obsługiwane. Zainstaluj 64 bitową wersję FreeFileSync. - -Could not determine volume name for file: -Nie można określić nazwy dysku dla pliku: - -Volume name %x not part of filename %y! -Dysk %x nie jest częścią pliku %y! - -%x TB -%x TB - -%x PB -%x PB - -%x% -%x% - - -1 min -%x min - - -1 minuta -%x minuty -%x minut - - - -1 hour -%x hours - - -1 godzina -%x godziny -%x godzin - - - -1 day -%x days - - -1 dzień -%x dni -%x dni - - -Could not read values for the following XML nodes: -Nie można odczytać wartości dla danych gałęzi XML: - Logging Tworzenie logów @@ -483,9 +375,6 @@ Komenda jest wykonwywana za każdym razem gdy: Batch execution Uruchomienie pliku wsadowego -Log-messages: -Logi: - Stop Zatrzymaj @@ -612,6 +501,24 @@ Komenda jest wykonwywana za każdym razem gdy: Total amount of data that will be transferred Liczba danych do przekopiowania +Operation: +Operacja: + +Items found: +Znalezione elementy: + +Items remaining: +Pozostałe elementy: + +Speed: +Prędkość: + +Time remaining: +Pozostały czas: + +Time elapsed: +Czas: + Batch job Plik wsadowy @@ -660,32 +567,14 @@ Komenda jest wykonwywana za każdym razem gdy: &Cancel &Anuluj -Operation: -Operacja: - -Items found: -Znalezione elementy: - -Items remaining: -Pozostałe elementy: - -Speed: -Prędkość: - -Time remaining: -Pozostały czas: - -Time elapsed: -Czas: - Select variant: Wybierz wariant: -Identify and propagate changes on both sides using a database. Deletions and conflicts are detected automatically. -Wykryj i zastosuj zmiany po obu stronach używając bazy danych. Usunięcia i konflikty są wykrywane automatycznie. +Identify and propagate changes on both sides using a database. Deletions, renaming and conflicts are detected automatically. +Znajdź i zastosuj zmiany po obu stronach przy pomocy bazy danych. Usunięnia, zmiany nazwy plików oraz konflikty są usuwane automatycznie. Mirror ->> Lustrzana ->> @@ -907,27 +796,19 @@ Wyklucz: \moje\temp\* Transakcyjne kopiowanie pliku Write to a temporary file (*.ffs_tmp) first then rename it. This guarantees a consistent state even in case of fatal error. - +Stwórz tymczasowy plik (*.ffs_tmp) następnie zamień jego nazwę. Gwarantuje to spójność nawet po wystąpieniu błędu. Copy locked files Kopiuj zablokowane pliki - -Copy shared or locked files using Volume Shadow Copy Service (Requires Administrator rights) - - -Kopiuj pliki udostępnione i zablokowane używając usługi Volume Shadow Copy (Wymaga uprawnień administratora) - +Copy shared or locked files using Volume Shadow Copy Service (Requires Administrator rights) +Kopiuj pliki udostępnione i zablokowane używając usługi Volume Shadow Copy (Wymaga uprawnień administratora) Copy file access permissions Kopiuj uprawnienia plików - -Transfer file and directory permissions (Requires Administrator rights) - - -Transfer uprawnień plików i katalogów (Wymaga uprawnień Administratora) - +Transfer file and directory permissions (Requires Administrator rights) +Transfer uprawnień plików i katalogów (Wymaga uprawnień Administratora) Hidden dialogs: Ukryte dialogi: @@ -959,6 +840,9 @@ Transfer uprawnień plików i katalogów (Wymaga uprawnień Administratora) &Find next &Znajdź następny +Operation aborted! +Operacja przerwana! + Main bar Główny pasek @@ -999,16 +883,16 @@ Transfer uprawnień plików i katalogów (Wymaga uprawnień Administratora) Autodopasowanie kolumn Icon size: - +Rozmiar ikony: Small - +Mały Medium - +Średni Large - +Duży Include all rows Dołącz wszystkie rzędy @@ -1136,6 +1020,9 @@ Transfer uprawnień plików i katalogów (Wymaga uprawnień Administratora) File list exported! Lista plików wyeksportowana! +Error writing file: +Błąd zapisu pliku: + Batch file created successfully! Plik wsadowy utworzony pomyślnie! @@ -1239,9 +1126,6 @@ Transfer uprawnień plików i katalogów (Wymaga uprawnień Administratora) Filter: Single pair Filtr: Pojedyńcza para -Ignore -Ignoruj - Direct Bezpośrednio @@ -1307,6 +1191,108 @@ Transfer uprawnień plików i katalogów (Wymaga uprawnień Administratora) Move files into a time-stamped subdirectory Przenieś pliki do oznaczonego podkatalogu +%x TB +%x TB + +%x PB +%x PB + +%x% +%x% + + +1 min +%x min + + +1 minuta +%x minuty +%x minut + + + +1 hour +%x hours + + +1 godzina +%x godziny +%x godzin + + + +1 day +%x days + + +1 dzień +%x dni +%x dni + + +Could not initialize directory monitoring: +Nie można uruchomić monitora katalogów: + +Error when monitoring directories. +Błąd podczas monitorowania katalogów. + +Conversion error: +Błąd konwersji: + +Error deleting file: +Błąd podczas usuwania pliku: + +Error moving file: +Błąd podczas przenoszenia pliku: + +Target file already existing! +Plik docelowy już istnieje! + +Error moving directory: +Błąd podczas przenoszenia katalogu: + +Target directory already existing! +Katalog docelowy już istnieje! + +Error deleting directory: +Błąd podczas usuwania katalogu: + +Error changing modification time: +Błąd zmiany godziny modyfikacji: + +Error loading library function: +Błąd wczytywania funkcji: + +Error reading security context: +Błąd odczytu kontekstu bezpieczeństwa: + +Error writing security context: +Błąd zapisu kontekstu bezpieczeństwa: + +Error copying file permissions: +Błąd podczas kopiowania uprawnień pliku: + +Error creating directory: +Błąd podczas tworzenia katalogu: + +Error copying symbolic link: +Błąd podczas kopiowania dowiązania symbolicznego (symlink) + +Error copying file: +Błąd podczas kopiowania pliku: + +Error opening file: +Błąd odczytu pliku: + +Error traversing directory: +Błąd podczas odczytywania katalogu: + +Endless loop when traversing directory: +Zapętlenie podczas przeglądania katalogu: + +Error setting privilege: +Błąd ustawiania uprawnień: + Both sides have changed since last synchronization! Obie strony uległy zmianie od ostatniej synchronizacji! @@ -1337,9 +1323,6 @@ Transfer uprawnień plików i katalogów (Wymaga uprawnień Administratora) Directories are dependent! Be careful when setting up synchronization rules: Katalogi są zależne! Pamiętaj o tym podczas ustawiania zasad synchronizacji: -Comparing content of files %x -Porównywanie zawartości plików %x - Memory allocation failed! Błąd alokacji zasobów! @@ -1355,15 +1338,15 @@ Transfer uprawnień plików i katalogów (Wymaga uprawnień Administratora) Symlinks %x have the same date but a different target! Dowiązanie symboliczne %x ma te same dane, ale inny cel! +Comparing content of files %x +Porównywanie zawartości plików %x + Comparing files by content failed. Porównywanie przez zawartość zakończone niepowodzeniem. Generating file list... Generowanie listy plików... -Multiple... -Wiele... - Both sides are equal Obie strony są równe @@ -1382,6 +1365,12 @@ Transfer uprawnień plików i katalogów (Wymaga uprawnień Administratora) Delete right file/folder Usuń plik/katalog po prawej stronie +Move file on left +Przenieś plik na lewą stronę + +Move file on right +Przenieś plik na prawą stronę + Overwrite left file/folder with right one Nadpisz plik/katalog po lewej stronie tym po prawej @@ -1397,6 +1386,9 @@ Transfer uprawnień plików i katalogów (Wymaga uprawnień Administratora) Copy file attributes only to right Kopiuj atrybuty plików tylko na prawą stronę +Multiple... +Wiele... + Deleting file %x Usuwanie pliku %x diff --git a/BUILD/Languages/portuguese.lng b/BUILD/Languages/portuguese.lng index 97603be2..a108cdc3 100644 --- a/BUILD/Languages/portuguese.lng +++ b/BUILD/Languages/portuguese.lng @@ -22,39 +22,6 @@ RealtimeSync - Automated Synchronization RealtimeSync - Sincronização Automática -Browse -Procurar - -Windows Error Code %x: -Código de erro do Windows %x: - -Linux Error Code %x: -Código de erro do Linux %x: - -Invalid command line: %x -Linha de comando inválida: %x - -Error resolving symbolic link: -Erro na resolução do link simbólico: - -Show pop-up -Mostrar popup - -Show pop-up on errors or warnings -Mostrar popup em caso de erros ou avisos - -Ignore errors -Ignorar erros - -Hide all error and warning messages -Ocultar todas as mensagens de erro/aviso - -Exit instantly -Sair imediatamente - -Abort synchronization immediately -Abortar sincronização imediatamente - Select alternate comparison settings Selecionar opções alternativas de comparação @@ -115,6 +82,45 @@ Select time span Selecionar intervalo de tempo +Show pop-up +Mostrar popup + +Show pop-up on errors or warnings +Mostrar popup em caso de erros ou avisos + +Ignore errors +Ignorar erros + +Hide all error and warning messages +Ocultar todas as mensagens de erro/aviso + +Exit instantly +Sair imediatamente + +Abort synchronization immediately +Abortar sincronização imediatamente + +Browse +Procurar + +Error reading from synchronization database: +Erro ao ler a base de dados de sincronização: + +Error writing to synchronization database: +Erro na escrita da base de dados de sincronização: + +Invalid command line: %x +Linha de comando inválida: %x + +Windows Error Code %x: +Código de erro do Windows %x: + +Linux Error Code %x: +Código de erro do Linux %x: + +Error resolving symbolic link: +Erro na resolução do link simbólico: + %x MB %x MB @@ -163,17 +169,14 @@ Comparison Result Resultados da comparação -Incompatible synchronization database format: -Formato de base de dados de sincronização incompatível: - Initial synchronization: Sincronização inicial: One of the FreeFileSync database files is not yet existing: Um dos ficheiros da base de dados não existe: -Error reading from synchronization database: -Erro ao ler a base de dados de sincronização: +Incompatible synchronization database format: +Formato de base de dados de sincronização incompatível: Database files do not share a common synchronization session: Bases de dados não partilham a mesma sessão de sincronização: @@ -199,12 +202,18 @@ %x segs +Drag && drop +Arrastar && Largar + Info Info Fatal Error Erro crítico +Error reading file: +Erro de leitura de ficheiro: + Scanning: A pesquisar: @@ -223,15 +232,36 @@ Invalid FreeFileSync config file! Ficheiro de configuração inválido! -File does not exist: -O ficheiro não existe: - Error parsing configuration file: Erro de leitura do ficheiro de configuração: +Error moving to Recycle Bin: +Erro ao mover para a Reciclagem: + +Could not load a required DLL: +Não foi possível carregar a DLL: + +Error accessing Volume Shadow Copy Service! +Erro no acesso ao serviço Volume Shadow Copy! + +Making shadow copies on WOW64 is not supported. Please use FreeFileSync 64-bit version. +Fazer cópias fantasma em WOW64 não é suportado. Por favor usar a versão 64-bit. + +Could not determine volume name for file: +Não é possível determinar o nome do volume para o ficheiro: + +Volume name %x not part of filename %y! +Nome do volume %x não faz parte do ficheiro %y! + /sec /seg +File does not exist: +O ficheiro não existe: + +Could not read values for the following XML nodes: +Não foi possível ler os valores dos seguintes nós XML: + S&ave configuration... G&uardar a configuração... @@ -324,141 +354,6 @@ A linha de comandos é executada cada vez que: A directory input field is empty. Um campo de directório está vazio. -Drag && drop -Arrastar && Largar - -Could not initialize directory monitoring: -Não é possível iniciar monitorização do directório: - -Error when monitoring directories. -Erro ao monitorizar os directórios. - -Conversion error: -Erro de conversão: - -Error deleting file: -Erro ao eliminar o ficheiro: - -Error moving file: -Erro ao mover o ficheiro: - -Target file already existing! -Ficheiro de destino já existe! - -Error moving directory: -Erro ao mover o directório: - -Target directory already existing! -Directório de destino já existe! - -Error deleting directory: -Erro ao eliminar a pasta: - -Error changing modification time: -Erro ao mudar a hora de modificação: - -Error loading library function: -Erro ao carregar a livraria: - -Error reading security context: -Erro ao ler contexto de segurança: - -Error writing security context: -Erro de escrita no contexto de segurança: - -Error copying file permissions: -Erro ao copiar permissões dos ficheiros: - -Error creating directory: -Erro ao criar a pasta: - -Error copying symbolic link: -Erro ao copiar o link: - -Error copying file: -Erro ao copiar ficheiro: - -Error opening file: -Erro ao abrir ficheiro: - -Error writing file: -Erro de escrita no ficheiro: - -Error reading file: -Erro de leitura de ficheiro: - -Operation aborted! -Operação abortada! - -Endless loop when traversing directory: -Loop infinito ao percorrer directório: - -Error traversing directory: -Erro ao percorrer a pasta: - -Error setting privilege: -Erro ao estabelecer privilégios: - -Error moving to Recycle Bin: -Erro ao mover para a Reciclagem: - -Could not load a required DLL: -Não foi possível carregar a DLL: - -Error writing to synchronization database: -Erro na escrita da base de dados de sincronização: - -Error accessing Volume Shadow Copy Service! -Erro no acesso ao serviço Volume Shadow Copy! - -Making shadow copies on WOW64 is not supported. Please use FreeFileSync 64-bit version. -Fazer cópias fantasma em WOW64 não é suportado. Por favor usar a versão 64-bit. - -Could not determine volume name for file: -Não é possível determinar o nome do volume para o ficheiro: - -Volume name %x not part of filename %y! -Nome do volume %x não faz parte do ficheiro %y! - -%x TB -%x TB - -%x PB -%x PB - -%x% -%x% - - -1 min -%x min - - -1 min -%x mins - - - -1 hour -%x hours - - -1 hora -%x horas - - - -1 day -%x days - - -1 dia -%x dias - - -Could not read values for the following XML nodes: -Não foi possível ler os valores dos seguintes nós XML: - Logging A escrever em log @@ -477,9 +372,6 @@ A linha de comandos é executada cada vez que: Batch execution Execução do batch -Log-messages: -Log de mensagens: - Stop Parar @@ -606,6 +498,24 @@ A linha de comandos é executada cada vez que: Total amount of data that will be transferred Volume de dados a ser transferido +Operation: +Operação: + +Items found: +Elementos encontrados: + +Items remaining: +Elementos restantes: + +Speed: +Velocidade: + +Time remaining: +Tempo restante: + +Time elapsed: +Tempo passado: + Batch job Ficheiro Batch @@ -654,32 +564,14 @@ A linha de comandos é executada cada vez que: &Cancel &Cancelar -Operation: -Operação: - -Items found: -Elementos encontrados: - -Items remaining: -Elementos restantes: - -Speed: -Velocidade: - -Time remaining: -Tempo restante: - -Time elapsed: -Tempo passado: - Select variant: Selecione uma variante: -Identify and propagate changes on both sides using a database. Deletions and conflicts are detected automatically. -Identificar e propagar as mudanças usando base de dados. Eliminações e conflitos serão detectados automaticamente. +Identify and propagate changes on both sides using a database. Deletions, renaming and conflicts are detected automatically. + Mirror ->> Espelhar ->> @@ -905,22 +797,14 @@ Excluir: \stuff\temp\* Copy locked files Copiar ficheiros bloqueados - -Copy shared or locked files using Volume Shadow Copy Service (Requires Administrator rights) - - -Copiar ficheiros partilhados ou bloqueados usando o serviço Volume Shadow Copy (Requer direitos de administrador) - +Copy shared or locked files using Volume Shadow Copy Service (Requires Administrator rights) +Copiar ficheiros partilhados ou bloqueados usando o serviço Volume Shadow Copy (Requer direitos de administrador) Copy file access permissions Copiar permissões de acesso do ficheiro - -Transfer file and directory permissions (Requires Administrator rights) - - -Transferir ficheiro e permissões (Requer direitos de administrador) - +Transfer file and directory permissions (Requires Administrator rights) +Transferir ficheiro e permissões (Requer direitos de administrador) Hidden dialogs: Diálogos ocultos: @@ -952,6 +836,9 @@ Transferir ficheiro e permissões (Requer direitos de administrador) &Find next &Procurar seguinte +Operation aborted! +Operação abortada! + Main bar Barra principal @@ -1129,6 +1016,9 @@ Transferir ficheiro e permissões (Requer direitos de administrador) File list exported! Lista dos ficheiros exportada! +Error writing file: +Erro de escrita no ficheiro: + Batch file created successfully! Ficheiro batch criado com sucesso! @@ -1228,9 +1118,6 @@ Transferir ficheiro e permissões (Requer direitos de administrador) Filter: Single pair Filtro: Par simples -Ignore -Ignorar - Direct Direto @@ -1294,6 +1181,105 @@ Transferir ficheiro e permissões (Requer direitos de administrador) Move files into a time-stamped subdirectory Mover ficheiros para uma subpasta datada +%x TB +%x TB + +%x PB +%x PB + +%x% +%x% + + +1 min +%x min + + +1 min +%x mins + + + +1 hour +%x hours + + +1 hora +%x horas + + + +1 day +%x days + + +1 dia +%x dias + + +Could not initialize directory monitoring: +Não é possível iniciar monitorização do directório: + +Error when monitoring directories. +Erro ao monitorizar os directórios. + +Conversion error: +Erro de conversão: + +Error deleting file: +Erro ao eliminar o ficheiro: + +Error moving file: +Erro ao mover o ficheiro: + +Target file already existing! +Ficheiro de destino já existe! + +Error moving directory: +Erro ao mover o directório: + +Target directory already existing! +Directório de destino já existe! + +Error deleting directory: +Erro ao eliminar a pasta: + +Error changing modification time: +Erro ao mudar a hora de modificação: + +Error loading library function: +Erro ao carregar a livraria: + +Error reading security context: +Erro ao ler contexto de segurança: + +Error writing security context: +Erro de escrita no contexto de segurança: + +Error copying file permissions: +Erro ao copiar permissões dos ficheiros: + +Error creating directory: +Erro ao criar a pasta: + +Error copying symbolic link: +Erro ao copiar o link: + +Error copying file: +Erro ao copiar ficheiro: + +Error opening file: +Erro ao abrir ficheiro: + +Error traversing directory: +Erro ao percorrer a pasta: + +Endless loop when traversing directory: +Loop infinito ao percorrer directório: + +Error setting privilege: +Erro ao estabelecer privilégios: + Both sides have changed since last synchronization! Ambos os lados tiveram alterações desde a última sincronização! @@ -1324,9 +1310,6 @@ Transferir ficheiro e permissões (Requer direitos de administrador) Directories are dependent! Be careful when setting up synchronization rules: Directórios são dependentes! Cuidado ao definir as regras de sincronização: -Comparing content of files %x -A comparar o conteúdo do ficheiro %x - Memory allocation failed! Alocação de memória falhou! @@ -1342,15 +1325,15 @@ Transferir ficheiro e permissões (Requer direitos de administrador) Symlinks %x have the same date but a different target! Links simbólicos %x tem a mesma data mas diferente destino! +Comparing content of files %x +A comparar o conteúdo do ficheiro %x + Comparing files by content failed. A comparação de ficheiros por conteúdo falhou. Generating file list... A gerar lista ficheiros... -Multiple... -Multiplo... - Both sides are equal Ambos os lados iguais @@ -1369,6 +1352,12 @@ Transferir ficheiro e permissões (Requer direitos de administrador) Delete right file/folder Eliminar ficheiro/pasta à direita +Move file on left + + +Move file on right + + Overwrite left file/folder with right one Substituir ficheiro/pasta da esquerda (pelo da direita) @@ -1384,6 +1373,9 @@ Transferir ficheiro e permissões (Requer direitos de administrador) Copy file attributes only to right Copiar apenas atributos de ficheiro para a direita +Multiple... +Multiplo... + Deleting file %x Apagar ficheiro %x diff --git a/BUILD/Languages/portuguese_br.lng b/BUILD/Languages/portuguese_br.lng index 5489adeb..b6ec4d95 100644 --- a/BUILD/Languages/portuguese_br.lng +++ b/BUILD/Languages/portuguese_br.lng @@ -22,39 +22,6 @@ RealtimeSync - Automated Synchronization RealtimeSync - Sincronização Automatizada -Browse -Procurar - -Windows Error Code %x: -Código de Erro do Windows %x: - -Linux Error Code %x: -Código de Erro do Linux %x: - -Invalid command line: %x -Linha de comando inválida: %x - -Error resolving symbolic link: -Erro na resolução de link simbólico: - -Show pop-up -Mostrar pop-up - -Show pop-up on errors or warnings -Mostrar pop-up em erros e avisos - -Ignore errors -Ignorar erros - -Hide all error and warning messages -Ocultar todas as mensagens de erro ou aviso - -Exit instantly -Sair instantaneamente - -Abort synchronization immediately -Cancelar a sincronização imediatamente - Select alternate comparison settings Selecionar configuração de comparação alternativa @@ -89,7 +56,7 @@ Erro Warning -Atenção +Avisos Question Questão @@ -115,6 +82,45 @@ Select time span Selecionar período de tempo +Show pop-up +Mostrar pop-up + +Show pop-up on errors or warnings +Mostrar pop-up em erros e avisos + +Ignore errors +Ignorar erros + +Hide all error and warning messages +Ocultar todas as mensagens de erro ou aviso + +Exit instantly +Sair instantaneamente + +Abort synchronization immediately +Cancelar a sincronização imediatamente + +Browse +Procurar + +Error reading from synchronization database: +Erro ao ler do banco de dados de sincronização: + +Error writing to synchronization database: +Erro ao escrever no banco de dados de sincronização: + +Invalid command line: %x +Linha de comando inválida: %x + +Windows Error Code %x: +Código de Erro do Windows %x: + +Linux Error Code %x: +Código de Erro do Linux %x: + +Error resolving symbolic link: +Erro na resolução de link simbólico: + %x MB %x MB @@ -163,17 +169,14 @@ Comparison Result Resultado da Comparação -Incompatible synchronization database format: -Formato de banco de dados de sincronização incompatível: - Initial synchronization: Sincronização inicial: One of the FreeFileSync database files is not yet existing: Um dos arquivos de banco de dados do FreeFileSync ainda não existe: -Error reading from synchronization database: -Erro ao ler do banco de dados de sincronização: +Incompatible synchronization database format: +Formato de banco de dados de sincronização incompatível: Database files do not share a common synchronization session: Arquivos de banco de dados não compartilham uma sessão de sincronização comum: @@ -199,12 +202,18 @@ %x seg +Drag && drop +Arrastar && Soltar + Info -Info +Informações Fatal Error Erro fatal +Error reading file: +Erro ao ler arquivo: + Scanning: Pesquisando: @@ -223,15 +232,36 @@ Invalid FreeFileSync config file! Arquivo de configuração do FreeFileSync inválido! -File does not exist: -O arquivo não existe: - Error parsing configuration file: Erro de leitura do arquivo de configuração: +Error moving to Recycle Bin: +Erro ao mover para a Lixeira: + +Could not load a required DLL: +Não foi possível carregar uma DLL requerida: + +Error accessing Volume Shadow Copy Service! +Erro ao acessar o Serviço de Cópia de Sombra de Volume! + +Making shadow copies on WOW64 is not supported. Please use FreeFileSync 64-bit version. +Cópias de sombra no WOW64 não são suportadas. Por favor use a versão 64-bits do FreeFileSync. + +Could not determine volume name for file: +Não foi possível determinar o nome do volume para o arquivo: + +Volume name %x not part of filename %y! +Nome do volume %x não é parte do arquivo %y! + /sec /seg +File does not exist: +O arquivo não existe: + +Could not read values for the following XML nodes: +Não foi possível ler os valores para os seguintes nós XML: + S&ave configuration... S&alvar configuração... @@ -324,143 +354,8 @@ A linha de comando é executada cada vez que: A directory input field is empty. Um campo de entrada de diretório está vazio. -Drag && drop -Arrastar && Soltar - -Could not initialize directory monitoring: -Não foi possível inicializar o monitoramento de diretórios: - -Error when monitoring directories. -Erro ao monitorar os diretórios. - -Conversion error: -Erro de conversão: - -Error deleting file: -Erro ao apagar arquivo: - -Error moving file: -Erro ao mover arquivo: - -Target file already existing! -Arquivo de destino já existe! - -Error moving directory: -Erro ao mover diretório: - -Target directory already existing! -Diretório de destino já existe! - -Error deleting directory: -Erro ao apagar diretório: - -Error changing modification time: -Erro ao mudar a hora de modificação: - -Error loading library function: -Erro ao carregar a biblioteca de funções: - -Error reading security context: -Erro ao ler contexto de segurança: - -Error writing security context: -Erro ao escrever contexto de segurança: - -Error copying file permissions: -Erro ao copiar permissões do arquivo: - -Error creating directory: -Erro ao criar diretório: - -Error copying symbolic link: -Erro ao copiar links simbólicos: - -Error copying file: -Erro ao copiar arquivo: - -Error opening file: -Erro ao abrir arquivo: - -Error writing file: -Erro ao escrever arquivo: - -Error reading file: -Erro ao ler arquivo: - -Operation aborted! -Operação cancelada! - -Endless loop when traversing directory: -Loop infinito quando percorrendo diretório: - -Error traversing directory: -Erro ao percorrer diretório: - -Error setting privilege: -Erro ao definir privilégio: - -Error moving to Recycle Bin: -Erro ao mover para a Lixeira: - -Could not load a required DLL: -Não foi possível carregar uma DLL requerida: - -Error writing to synchronization database: -Erro ao escrever no banco de dados de sincronização: - -Error accessing Volume Shadow Copy Service! -Erro ao acessar o Serviço de Cópia de Sombra de Volume! - -Making shadow copies on WOW64 is not supported. Please use FreeFileSync 64-bit version. -Cópias de sombra no WOW64 não são suportadas. Por favor use a versão 64-bits do FreeFileSync. - -Could not determine volume name for file: -Não foi possível determinar o nome do volume para o arquivo: - -Volume name %x not part of filename %y! -Nome do volume %x não é parte do arquivo %y! - -%x TB -%x TB - -%x PB -%x PB - -%x% -%x% - - -1 min -%x min - - -1 min -%x min - - - -1 hour -%x hours - - -1 hora -%x horas - - - -1 day -%x days - - -1 dia -%x dias - - -Could not read values for the following XML nodes: -Não foi possível ler os valores para os seguintes nós XML: - Logging -Gravando log +Log FreeFileSync batch file FreeFileSync arquivo batch @@ -477,9 +372,6 @@ A linha de comando é executada cada vez que: Batch execution Execução do batch -Log-messages: -Log de mensagens: - Stop Parar @@ -606,6 +498,24 @@ A linha de comando é executada cada vez que: Total amount of data that will be transferred Volume total de dados que será transferido +Operation: +Operação: + +Items found: +Elementos encontrados: + +Items remaining: +Elementos faltantes: + +Speed: +Velocidade: + +Time remaining: +Tempo restante: + +Time elapsed: +Tempo decorrido: + Batch job Arquivo Batch @@ -654,32 +564,14 @@ A linha de comando é executada cada vez que: &Cancel &Cancelar -Operation: -Operação: - -Items found: -Elementos encontrados: - -Items remaining: -Elementos faltantes: - -Speed: -Velocidade: - -Time remaining: -Tempo restante: - -Time elapsed: -Tempo passado: - Select variant: Selecione um modo: -Identify and propagate changes on both sides using a database. Deletions and conflicts are detected automatically. -Identifica e propaga mudanças em ambos os lados utilizando um banco de dados. Exclusões e conflitos serão detectados automaticamente. +Identify and propagate changes on both sides using a database. Deletions, renaming and conflicts are detected automatically. +Identifica e propaga as mudanças em ambos os lados usando um banco de dados. Arquivos apagados, renomeados e conflitantes são detectados automaticamente. Mirror ->> Espelhar ->> @@ -901,27 +793,19 @@ Excluir: \stuff\temp\* Cópia de arquivo transacional Write to a temporary file (*.ffs_tmp) first then rename it. This guarantees a consistent state even in case of fatal error. - +Escreve para um arquivo temporário primeiro (*.ffs_tmp) e depois o renomeia. Isto garante um estado consistente mesmo em caso de erro fatal. Copy locked files Copiar arquivos bloqueados (em uso) - -Copy shared or locked files using Volume Shadow Copy Service (Requires Administrator rights) - - -Copia os arquivos compartilhados ou bloqueados (em uso) usando o Serviço de Cópia de Sombra de Volume (Requer direitos de Administrador) - +Copy shared or locked files using Volume Shadow Copy Service (Requires Administrator rights) +Copia os arquivos compartilhados ou bloqueados (em uso) usando o Serviço de Cópia de Sombra de Volume (Requer direitos de Administrador) Copy file access permissions Copiar permissões de acesso aos arquivos - -Transfer file and directory permissions (Requires Administrator rights) - - -Transfere as permissões de arquivos e diretórios (Requer direitos de Administrador) - +Transfer file and directory permissions (Requires Administrator rights) +Transfere as permissões de arquivos e diretórios (Requer direitos de Administrador) Hidden dialogs: Diálogos ocultados: @@ -953,6 +837,9 @@ Transfere as permissões de arquivos e diretórios (Requer direitos de Administr &Find next &Localizar próxima +Operation aborted! +Operação cancelada! + Main bar Barra principal @@ -993,16 +880,16 @@ Transfere as permissões de arquivos e diretórios (Requer direitos de Administr Autoajustar colunas Icon size: - +Tamanho do ícone: Small - +Pequeno Medium - +Médio Large - +Grande Include all rows Incluir todas as linhas @@ -1130,6 +1017,9 @@ Transfere as permissões de arquivos e diretórios (Requer direitos de Administr File list exported! Lista de arquivos exportada! +Error writing file: +Erro ao escrever arquivo: + Batch file created successfully! Arquivo batch criado com sucesso! @@ -1229,9 +1119,6 @@ Transfere as permissões de arquivos e diretórios (Requer direitos de Administr Filter: Single pair Filtro: Apenas um par -Ignore -Ignorar - Direct Direcionar @@ -1295,6 +1182,105 @@ Transfere as permissões de arquivos e diretórios (Requer direitos de Administr Move files into a time-stamped subdirectory Mover arquivos para um subdiretório com carimbo de tempo +%x TB +%x TB + +%x PB +%x PB + +%x% +%x% + + +1 min +%x min + + +1 min +%x min + + + +1 hour +%x hours + + +1 hora +%x horas + + + +1 day +%x days + + +1 dia +%x dias + + +Could not initialize directory monitoring: +Não foi possível inicializar o monitoramento de diretórios: + +Error when monitoring directories. +Erro ao monitorar os diretórios. + +Conversion error: +Erro de conversão: + +Error deleting file: +Erro ao apagar arquivo: + +Error moving file: +Erro ao mover arquivo: + +Target file already existing! +Arquivo de destino já existe! + +Error moving directory: +Erro ao mover diretório: + +Target directory already existing! +Diretório de destino já existe! + +Error deleting directory: +Erro ao apagar diretório: + +Error changing modification time: +Erro ao mudar a hora de modificação: + +Error loading library function: +Erro ao carregar a biblioteca de funções: + +Error reading security context: +Erro ao ler contexto de segurança: + +Error writing security context: +Erro ao escrever contexto de segurança: + +Error copying file permissions: +Erro ao copiar permissões do arquivo: + +Error creating directory: +Erro ao criar diretório: + +Error copying symbolic link: +Erro ao copiar links simbólicos: + +Error copying file: +Erro ao copiar arquivo: + +Error opening file: +Erro ao abrir arquivo: + +Error traversing directory: +Erro ao percorrer diretório: + +Endless loop when traversing directory: +Loop infinito quando percorrendo diretório: + +Error setting privilege: +Erro ao definir privilégio: + Both sides have changed since last synchronization! Ambos os lados foram alterados desde a última sincronização! @@ -1325,9 +1311,6 @@ Transfere as permissões de arquivos e diretórios (Requer direitos de Administr Directories are dependent! Be careful when setting up synchronization rules: Diretórios são dependentes! Cuidado ao definir as regras de sincronização: -Comparing content of files %x -Comparando conteúdo do arquivo %x - Memory allocation failed! Alocação de memória falhou! @@ -1343,15 +1326,15 @@ Transfere as permissões de arquivos e diretórios (Requer direitos de Administr Symlinks %x have the same date but a different target! Links Simbólicos %x têm a mesma data mas um destino diferente! +Comparing content of files %x +Comparando conteúdo do arquivo %x + Comparing files by content failed. Comparação de arquivos pelo conteúdo falhou. Generating file list... Gerando lista de arquivos... -Multiple... -Múltiplos... - Both sides are equal Ambos os lados são iguais @@ -1370,6 +1353,12 @@ Transfere as permissões de arquivos e diretórios (Requer direitos de Administr Delete right file/folder Apagar arquivos/pastas da direita +Move file on left +Mover arquivo da esquerda + +Move file on right +Mover arquivo da direita + Overwrite left file/folder with right one Substituir arquivos/pastas da esquerda pelos da direita @@ -1385,6 +1374,9 @@ Transfere as permissões de arquivos e diretórios (Requer direitos de Administr Copy file attributes only to right Copiar apenas os atributos do arquivo para a direita +Multiple... +Múltiplos... + Deleting file %x Apagando arquivo %x diff --git a/BUILD/Languages/romanian.lng b/BUILD/Languages/romanian.lng index f9e85c0e..c7b8958c 100644 --- a/BUILD/Languages/romanian.lng +++ b/BUILD/Languages/romanian.lng @@ -22,39 +22,6 @@ RealtimeSync - Automated Synchronization RealtimeSync - Sincronizare Inteligentă -Browse -Explorează - -Windows Error Code %x: -Codul Erorii Windows %x: - -Linux Error Code %x: -Codul Erorii Linux %x: - -Invalid command line: %x -Linie de comandă nevalidă: %x - -Error resolving symbolic link: -Eroare la rezolvarea legăturii simbolice: - -Show pop-up -Este arătat un popîc - -Show pop-up on errors or warnings -Se afișează o fereastră popîc [popup] la erori sau avertizări - -Ignore errors -Erorile sînt ignorate - -Hide all error and warning messages -Sînt ascunse toate mesajele de eroare și de avertizare - -Exit instantly -Ieși imediat - -Abort synchronization immediately -Abandonează imediat sincronizarea - Select alternate comparison settings Selectează setările alternative de comparare @@ -101,7 +68,7 @@ Configurează Filtrul Customize columns -Personalizează coloanele +Bifează coloanele de afișat Global settings Setări Globale @@ -115,6 +82,45 @@ Select time span Selectează intervalul de timp +Show pop-up +Este arătat un popîc + +Show pop-up on errors or warnings +Se afișează o fereastră popîc [popup] la erori sau avertizări + +Ignore errors +Erorile sînt ignorate + +Hide all error and warning messages +Sînt ascunse toate mesajele de eroare și de avertizare + +Exit instantly +Ieși imediat + +Abort synchronization immediately +Abandonează imediat sincronizarea + +Browse +Explorează + +Error reading from synchronization database: +Eroare la citirea din baza de date a sincronizării: + +Error writing to synchronization database: +Eroare la scrierea în baza de date a sincronizării: + +Invalid command line: %x +Linie de comandă nevalidă: %x + +Windows Error Code %x: +Codul Erorii Windows %x: + +Linux Error Code %x: +Codul Erorii Linux %x: + +Error resolving symbolic link: +Eroare la rezolvarea legăturii simbolice: + %x MB %x MB @@ -147,7 +153,7 @@ Dată Full path -Cale completă +Calea Completă Filename Numele Elementului @@ -164,17 +170,14 @@ Comparison Result Rezultatul Comparării -Incompatible synchronization database format: -Format al bazei de date necompatibil cu versiunea softului: - Initial synchronization: Sincronizare inițială: One of the FreeFileSync database files is not yet existing: Una dintre părți nu are o filă de tip bază de date FreeFileSync: -Error reading from synchronization database: -Eroare la citirea din baza de date a sincronizării: +Incompatible synchronization database format: +Format al bazei de date necompatibil cu versiunea softului: Database files do not share a common synchronization session: Filele bază de date nu partajează o sesiune comună de sincronizare @@ -201,17 +204,23 @@ %x de sec +Drag && drop +Trage și pune un dosar peste compartimentul de mai jos sau selectează-l cu butonul de explorare + Info Informații Fatal Error Eroare Fatală +Error reading file: +Eroare la citirea filei: + Scanning: Scanez: Encoding extended time information: %x -Codarea informațiilor timpului extins: %x +Codez informațiile extinse despre timp: %x [1 Thread] @@ -226,15 +235,36 @@ Invalid FreeFileSync config file! Filă de configurare FreeFileSync nevalidă! -File does not exist: -Fila nu există: - Error parsing configuration file: Eroare la parsarea filei de configurare: +Error moving to Recycle Bin: +Eroare la mutarea în Reciclator: + +Could not load a required DLL: +Nu pot încărca o filă DLL necesară: + +Error accessing Volume Shadow Copy Service! +Eroare la accesarea Serviciului de Conservare a Volumelor [Volume Shadow Copy]! + +Making shadow copies on WOW64 is not supported. Please use FreeFileSync 64-bit version. +Realizarea de conservări (copii de rezervă) prin sistemul WOW64 nu este suportată. Folosește versiunea pe 64-biți a FreeFileSync. + +Could not determine volume name for file: +Nu pot determina numele volumului pentru fila: + +Volume name %x not part of filename %y! +Numele volumului %x nu face parte din numele filei %y ! + /sec /sec +File does not exist: +Fila nu există: + +Could not read values for the following XML nodes: +Nu pot citi valorile pentru următoarele noduri XML: + S&ave configuration... S&alvează Configurația... @@ -327,146 +357,8 @@ Linia de comandă este executată de fiecare dată cînd: A directory input field is empty. Cel puțin unul din dosarele de comparat este nespecificat. -Drag && drop -Trage și lasă un dosar peste compartimentul de mai jos sau selectează-l cu butonul de explorare - -Could not initialize directory monitoring: -Nu pot inițializa monitorizarea dosarelor: - -Error when monitoring directories. -Eroare la monitorizarea dosarelor. - -Conversion error: -Eroare de convertire: - -Error deleting file: -Eroare la ștergerea filei: - -Error moving file: -Eroare la mutarea filei: - -Target file already existing! -Fila țintă există deja! - -Error moving directory: -Eroare la mutarea dosarului: - -Target directory already existing! -Dosarul țintă există deja! - -Error deleting directory: -Eroare la ștergerea dosarului: - -Error changing modification time: -Eroare la schimbarea datei de modificare: - -Error loading library function: -Eroare la încărcarea bibliotecii de funcții: - -Error reading security context: -Eroare la citirea contextului de securitate: - -Error writing security context: -Eroare la scrierea contextului de securitate: - -Error copying file permissions: -Eroare la copierea permisiunilor filei: - -Error creating directory: -Eroare la crearea dosarului: - -Error copying symbolic link: -Eroare la copierea legăturii simbolice: - -Error copying file: -Eroare la copierea filei: - -Error opening file: -Eroare la deschiderea filei: - -Error writing file: -Eroare la scrierea filei: - -Error reading file: -Eroare la citirea filei: - -Operation aborted! -Operație abandonată! - -Endless loop when traversing directory: -Buclă infinită la parcurgerea dosarului: - -Error traversing directory: -Eroare la parcurgerea dosarului: - -Error setting privilege: -Eroare la setarea privilegiului: - -Error moving to Recycle Bin: -Eroare la mutarea în Reciclator: - -Could not load a required DLL: -Nu pot încărca o filă DLL necesară: - -Error writing to synchronization database: -Eroare la scrierea în baza de date a sincronizării: - -Error accessing Volume Shadow Copy Service! -Eroare la accesarea Serviciului de Conservare a Volumelor [Volume Shadow Copy]! - -Making shadow copies on WOW64 is not supported. Please use FreeFileSync 64-bit version. -Realizarea de conservări (copii de rezervă) prin sistemul WOW64 nu este suportată. Folosește versiunea pe 64-biți a FreeFileSync. - -Could not determine volume name for file: -Nu pot determina numele volumului pentru fila: - -Volume name %x not part of filename %y! -Numele volumului %x nu face parte din numele filei %y ! - -%x TB -%x TB - -%x PB -%x PB - -%x% -%x% - - -1 min -%x min - - -1 min -%x min -%x de min - - - -1 hour -%x hours - - -1 oră -%x ore -%x de ore - - - -1 day -%x days - - -1 zi -%x zile -%x de zile - - -Could not read values for the following XML nodes: -Nu pot citi valorile pentru următoarele noduri XML: - Logging -Jurnalizez +Jurnal FreeFileSync batch file Filă cu set de comenzi FreeFileSync @@ -483,9 +375,6 @@ Linia de comandă este executată de fiecare dată cînd: Batch execution Execută Fila Set -Log-messages: -Mesaje de jurnalizare: - Stop Oprește @@ -612,6 +501,24 @@ Linia de comandă este executată de fiecare dată cînd: Total amount of data that will be transferred Volumul total de date care va fi transferat +Operation: +Operație: + +Items found: +Elemente Găsite: + +Items remaining: +Elemente Rămase: + +Speed: +Viteză: + +Time remaining: +Timp Rămas: + +Time elapsed: +Timp Scurs: + Batch job Sarcină Set @@ -660,32 +567,14 @@ Linia de comandă este executată de fiecare dată cînd: &Cancel &Anulează -Operation: -Operație: - -Items found: -Elemente Găsite: - -Items remaining: -Elemente Rămase: - -Speed: -Viteză: - -Time remaining: -Timp Rămas: - -Time elapsed: -Timp Scurs: - Select variant: Selectează Varianta de Sincronizare: -Identify and propagate changes on both sides using a database. Deletions and conflicts are detected automatically. -Modificările din ambele părți sînt identificate și propagate folosind o bază de date. Ștergerile și conflictele sînt detectate automat. +Identify and propagate changes on both sides using a database. Deletions, renaming and conflicts are detected automatically. +Identificare și propagare a modificărilor din ambele părți folosind o bază de date. Ștergerile, renumirile și conflictele sînt detectate automat Mirror ->> Clonare =>> @@ -697,7 +586,7 @@ Linia de comandă este executată de fiecare dată cînd: Actualizare => Copy new or updated files to right folder. -Copiază în dosarul din dreapta filele actualizate sau noi. +Copiere în dosarul din dreapta a filelor actualizate sau noi. Custom Sincronizare Personalizată @@ -907,27 +796,19 @@ Excluse: \stuff\temp\* Copiere tranzacțională a filelor Write to a temporary file (*.ffs_tmp) first then rename it. This guarantees a consistent state even in case of fatal error. - +Scrierea se face mai întîi într-o filă temporară (*.ffs_tmp), care e apoi renumită. Se garantează astfel consecvența stării filelor chiar și în cazul apariției de erori fatale. Copy locked files -Copiere și a filelor zăvorîte [locked] +Copiere a filelor partajate [shared] sau zăvorîte [locked] - -Copy shared or locked files using Volume Shadow Copy Service (Requires Administrator rights) - - -Copiază filele partajate sau zăvorîte folosind Serviciul de Conservare a Volumelor [Volume Shadow Copy] (Necesită drepturi de Administrator) - +Copy shared or locked files using Volume Shadow Copy Service (Requires Administrator rights) +Filele partajate sau zăvorîte sînt copiate folosind Serviciul de Conservare a Volumelor din Windows [Volume Shadow Copy] (necesită drepturi de Administrator) Copy file access permissions Copiază permisiunile de acces ale filelor - -Transfer file and directory permissions (Requires Administrator rights) - - -Transferă permisiunile filelor și dosarelor (Necesită drepturi de Administrator) - +Transfer file and directory permissions (Requires Administrator rights) +Transferă permisiunile filelor și dosarelor (necesită drepturi de Administrator) Hidden dialogs: Casete de dialog ascunse: @@ -948,7 +829,7 @@ Transferă permisiunile filelor și dosarelor (Necesită drepturi de Administrat Varianta Sincronizării Statistics -Statistici +Statis. Find what: Găsește Asta: @@ -959,6 +840,9 @@ Transferă permisiunile filelor și dosarelor (Necesită drepturi de Administrat &Find next &Găsește Următorul +Operation aborted! +Operație abandonată! + Main bar Bara Principală @@ -996,19 +880,19 @@ Transferă permisiunile filelor și dosarelor (Necesită drepturi de Administrat Selectează intervalul de timp... Auto-adjust columns -Autoajustează Coloanele +Ajustează Automat Coloanele Icon size: - +Mărimea Icoanelor Elementelor: Small - +Mică Medium - +Medie Large - +Mare Include all rows Include Toate Rîndurile @@ -1136,6 +1020,9 @@ Transferă permisiunile filelor și dosarelor (Necesită drepturi de Administrat File list exported! Lista de file a fost exportată! +Error writing file: +Eroare la scrierea filei: + Batch file created successfully! Fila cu setul de comenzi a fost creată cu succces ! @@ -1239,9 +1126,6 @@ Transferă permisiunile filelor și dosarelor (Necesită drepturi de Administrat Filter: Single pair Filtru: O singură pereche -Ignore -Ignoră - Direct Direcționează @@ -1307,6 +1191,108 @@ Transferă permisiunile filelor și dosarelor (Necesită drepturi de Administrat Move files into a time-stamped subdirectory Filele sînt mutate într-un subdosar cu marcaj de timp +%x TB +%x TB + +%x PB +%x PB + +%x% +%x% + + +1 min +%x min + + +1 min +%x min +%x de min + + + +1 hour +%x hours + + +1 oră +%x ore +%x de ore + + + +1 day +%x days + + +1 zi +%x zile +%x de zile + + +Could not initialize directory monitoring: +Nu pot inițializa monitorizarea dosarelor: + +Error when monitoring directories. +Eroare la monitorizarea dosarelor. + +Conversion error: +Eroare de convertire: + +Error deleting file: +Eroare la ștergerea filei: + +Error moving file: +Eroare la mutarea filei: + +Target file already existing! +Fila țintă există deja! + +Error moving directory: +Eroare la mutarea dosarului: + +Target directory already existing! +Dosarul țintă există deja! + +Error deleting directory: +Eroare la ștergerea dosarului: + +Error changing modification time: +Eroare la schimbarea datei de modificare: + +Error loading library function: +Eroare la încărcarea bibliotecii de funcții: + +Error reading security context: +Eroare la citirea contextului de securitate: + +Error writing security context: +Eroare la scrierea contextului de securitate: + +Error copying file permissions: +Eroare la copierea permisiunilor filei: + +Error creating directory: +Eroare la crearea dosarului: + +Error copying symbolic link: +Eroare la copierea legăturii simbolice: + +Error copying file: +Eroare la copierea filei: + +Error opening file: +Eroare la deschiderea filei: + +Error traversing directory: +Eroare la parcurgerea dosarului: + +Endless loop when traversing directory: +Buclă infinită la parcurgerea dosarului: + +Error setting privilege: +Eroare la setarea privilegiului: + Both sides have changed since last synchronization! Ambele părți s-au modificat de la ultima sincronizare! @@ -1337,9 +1323,6 @@ Transferă permisiunile filelor și dosarelor (Necesită drepturi de Administrat Directories are dependent! Be careful when setting up synchronization rules: Dosarele sînt interdependente! Atenție la setarea regulilor de sincronizare: -Comparing content of files %x -Compar conținutul filelor %x - Memory allocation failed! Alocarea memoriei a eșuat! @@ -1355,15 +1338,15 @@ Transferă permisiunile filelor și dosarelor (Necesită drepturi de Administrat Symlinks %x have the same date but a different target! Simlegăturile %x au dată identică, dar ținte diferite! +Comparing content of files %x +Compar conținutul filelor %x + Comparing files by content failed. Compararea filelor după conținut a eșuat. Generating file list... Generez lista de file... -Multiple... -Multiplu... - Both sides are equal Ambele părți sînt identice @@ -1382,6 +1365,12 @@ Transferă permisiunile filelor și dosarelor (Necesită drepturi de Administrat Delete right file/folder Șterge elementul drept +Move file on left +Mută fila în stînga + +Move file on right +Mută fila în dreapta + Overwrite left file/folder with right one Suprascrie elementul stîng (fila/dosarul) cu cel drept @@ -1397,6 +1386,9 @@ Transferă permisiunile filelor și dosarelor (Necesită drepturi de Administrat Copy file attributes only to right Copiază atributele filelor doar înspre dreapta +Multiple... +Multiplu... + Deleting file %x Șterg fila %x diff --git a/BUILD/Languages/russian.lng b/BUILD/Languages/russian.lng index 1a4965e8..75da2588 100644 --- a/BUILD/Languages/russian.lng +++ b/BUILD/Languages/russian.lng @@ -22,39 +22,6 @@ RealtimeSync - Automated Synchronization RealtimeSync - Автоматическая синхронизация -Browse -Обзор - -Windows Error Code %x: -Код ошибки Windows %x: - -Linux Error Code %x: -Код ошибки Linux %x: - -Invalid command line: %x -Неверная командная строка: %x - -Error resolving symbolic link: -Ошибка при решении символической ссылки: - -Show pop-up -Показывать всплывающие окна - -Show pop-up on errors or warnings -Показывать всплывающие окна при ошибках и замечаниях - -Ignore errors -Игнорировать ошибки - -Hide all error and warning messages -Скрывать все ошибки и сообщения с предупреждениями - -Exit instantly -Выйти немедленно - -Abort synchronization immediately -Отменить синхронизацию немедленно - Select alternate comparison settings Выбрать альтернативные настройки сравнения @@ -115,6 +82,45 @@ Select time span Выберите промежуток времени +Show pop-up +Показывать всплывающие окна + +Show pop-up on errors or warnings +Показывать всплывающие окна при ошибках и замечаниях + +Ignore errors +Игнорировать ошибки + +Hide all error and warning messages +Скрывать все ошибки и сообщения с предупреждениями + +Exit instantly +Выйти немедленно + +Abort synchronization immediately +Отменить синхронизацию немедленно + +Browse +Обзор + +Error reading from synchronization database: +Ошибка при чтении из базы данных синхронизации: + +Error writing to synchronization database: +Ошибка при записи в базу данных синхронизации: + +Invalid command line: %x +Неверная командная строка: %x + +Windows Error Code %x: +Код ошибки Windows %x: + +Linux Error Code %x: +Код ошибки Linux %x: + +Error resolving symbolic link: +Ошибка при решении символической ссылки: + %x MB %x МБ @@ -164,17 +170,14 @@ Comparison Result Результаты сравнения -Incompatible synchronization database format: -Несовместимый формат базы данных синхронизации: - Initial synchronization: Первоначальная синхронизация: One of the FreeFileSync database files is not yet existing: Одного из файлов баз данных FreeFileSync еще не существует: -Error reading from synchronization database: -Ошибка при чтении из базы данных синхронизации: +Incompatible synchronization database format: +Несовместимый формат базы данных синхронизации: Database files do not share a common synchronization session: Файлы баз данных не имеют общей сессии синхронизации: @@ -201,12 +204,18 @@ %x секунд +Drag && drop +Drag && drop + Info Информация Fatal Error Критическая ошибка +Error reading file: +Ошибка при чтении файла: + Scanning: Сканирую: @@ -226,15 +235,36 @@ Invalid FreeFileSync config file! Неверный файл конфигурации FreeFileSync! -File does not exist: -Файл не существует: - Error parsing configuration file: Ошибка при анализе файла настроек синхронизации: +Error moving to Recycle Bin: +Ошибка при перемещении в "Корзину": + +Could not load a required DLL: +Не удалось загрузить необходимые DLL: + +Error accessing Volume Shadow Copy Service! +Ошибка доступа к службе Теневого Копирования Тома! + +Making shadow copies on WOW64 is not supported. Please use FreeFileSync 64-bit version. +Создание теневых копий на WOW64 не поддерживается. Пожалуйста, используйте FreeFileSync 64-разрядной версии. + +Could not determine volume name for file: +Не удалось определить название тома для файла: + +Volume name %x not part of filename %y! +Имя тома %x не является частью имени файла %y! + /sec +File does not exist: +Файл не существует: + +Could not read values for the following XML nodes: +Не удалось прочитать значения для следующих XML записей: + S&ave configuration... Сохранить настройки синхронизации... @@ -327,144 +357,6 @@ The command line is executed each time: A directory input field is empty. Поле ввода пути папки пустое. -Drag && drop -Drag && drop - -Could not initialize directory monitoring: -Не удалось инициализировать папку для мониторинга: - -Error when monitoring directories. -Ошибка при мониторинге папок. - -Conversion error: -Ошибка преобразования: - -Error deleting file: -Ошибка при удалении файла: - -Error moving file: -Ошибка перемещения файла: - -Target file already existing! -Конечный файл уже существует! - -Error moving directory: -Ошибка перемещения папки: - -Target directory already existing! -Конечная папка уже существует! - -Error deleting directory: -Ошибка при удалении папки: - -Error changing modification time: -Ошибка при изменении времени модификации файла: - -Error loading library function: -Ошибка при загрузке функции библиотеки: - -Error reading security context: -Ошибка при чтении контекста безобасности: - -Error writing security context: -Ошибка при записи контекста безобасности: - -Error copying file permissions: -Ошибка при копировании прав доступа: - -Error creating directory: -Ошибка при создании папки: - -Error copying symbolic link: -Ошибка при копировании символьной ссылки: - -Error copying file: -Ошибка при копировании файла: - -Error opening file: -Ошибка при открытии файла: - -Error writing file: -Ошибка при записи файла: - -Error reading file: -Ошибка при чтении файла: - -Operation aborted! -Операция отменена! - -Endless loop when traversing directory: -Зацикливание при встрече пересекающихся путей: - -Error traversing directory: -Ошибка при пересечении папок: - -Error setting privilege: -Ошибка установки привилегий: - -Error moving to Recycle Bin: -Ошибка при перемещении в "Корзину": - -Could not load a required DLL: -Не удалось загрузить необходимые DLL: - -Error writing to synchronization database: -Ошибка при записи в базу данных синхронизации: - -Error accessing Volume Shadow Copy Service! -Ошибка доступа к службе Теневого Копирования Тома! - -Making shadow copies on WOW64 is not supported. Please use FreeFileSync 64-bit version. -Создание теневых копий на WOW64 не поддерживается. Пожалуйста, используйте FreeFileSync 64-разрядной версии. - -Could not determine volume name for file: -Не удалось определить название тома для файла: - -Volume name %x not part of filename %y! -Имя тома %x не является частью имени файла %y! - -%x TB -%x ТБ - -%x PB -%x ПБ - -%x% -%x% - - -1 min -%x min - - -%x минута -%x минуты -%x минут - - - -1 hour -%x hours - - -%x час -%x часа -%x часов - - - -1 day -%x days - - -%x день -%x дня -%x дней - - -Could not read values for the following XML nodes: -Не удалось прочитать значения для следующих XML записей: - Logging Лог-файлы @@ -483,9 +375,6 @@ The command line is executed each time: Batch execution Выполнение пакетного задания -Log-messages: -Лог-сообщения: - Stop Стоп @@ -615,6 +504,24 @@ The command line is executed each time: Total amount of data that will be transferred Общий объем данных, который будет передаваться +Operation: +Операция: + +Items found: +Элементов найдено: + +Items remaining: +Элементов осталось: + +Speed: +Скорость: + +Time remaining: +Времени осталось: + +Time elapsed: +Времени прошло: + Batch job Пакетное задание @@ -663,32 +570,14 @@ The command line is executed each time: &Cancel &Отмена -Operation: -Операция: - -Items found: -Элементов найдено: - -Items remaining: -Элементов осталось: - -Speed: -Скорость: - -Time remaining: -Времени осталось: - -Time elapsed: -Времени прошло: - Select variant: Выберите вариант: <Автоматический> -Identify and propagate changes on both sides using a database. Deletions and conflicts are detected automatically. -Выявление и распространение изменений на обеих сторонах с использованием базы данных. Удаленные файлы и конфликты определяются автоматически. +Identify and propagate changes on both sides using a database. Deletions, renaming and conflicts are detected automatically. +Выявление и распространение изменений на обе стороны, используя базу данных. Удаленные, переименованные и конфликтные файлы определяются автоматически. Mirror ->> Зеркало ->> @@ -910,22 +799,14 @@ Exclude: \stuff\temp\* Copy locked files Копирование заблокированных файлов - -Copy shared or locked files using Volume Shadow Copy Service (Requires Administrator rights) - - -Копирование общих или заблокированных файлов с использованием службы Теневого Копирования Тома (требуются права Администратора) - +Copy shared or locked files using Volume Shadow Copy Service (Requires Administrator rights) +Копирование общих или заблокированных файлов с использованием службы Теневого Копирования Тома (требуются права Администратора) Copy file access permissions Копирование прав доступа к файлам - -Transfer file and directory permissions (Requires Administrator rights) - - -Передача прав доступа к файлам/папкам (требуются права Администратора) - +Transfer file and directory permissions (Requires Administrator rights) +Передача прав доступа к файлам/папкам (требуются права Администратора) Hidden dialogs: Скрытые диалоги @@ -957,6 +838,9 @@ Transfer file and directory permissions (Requires Administrator rights) &Find next &Найти далее +Operation aborted! +Операция отменена! + Main bar Главная панель @@ -1134,6 +1018,9 @@ Transfer file and directory permissions (Requires Administrator rights) File list exported! Список файлов экспортирован! +Error writing file: +Ошибка при записи файла: + Batch file created successfully! Файл пакетного задания создан успешно! @@ -1237,9 +1124,6 @@ Transfer file and directory permissions (Requires Administrator rights) Filter: Single pair Фильтр: Одна пара -Ignore -Игнорировать - Direct Прямое @@ -1308,6 +1192,108 @@ Transfer file and directory permissions (Requires Administrator rights) Move files into a time-stamped subdirectory Перемещать файлы в заданную папку (можно создавать архивные версии удаленных файлов) +%x TB +%x ТБ + +%x PB +%x ПБ + +%x% +%x% + + +1 min +%x min + + +%x минута +%x минуты +%x минут + + + +1 hour +%x hours + + +%x час +%x часа +%x часов + + + +1 day +%x days + + +%x день +%x дня +%x дней + + +Could not initialize directory monitoring: +Не удалось инициализировать папку для мониторинга: + +Error when monitoring directories. +Ошибка при мониторинге папок. + +Conversion error: +Ошибка преобразования: + +Error deleting file: +Ошибка при удалении файла: + +Error moving file: +Ошибка перемещения файла: + +Target file already existing! +Конечный файл уже существует! + +Error moving directory: +Ошибка перемещения папки: + +Target directory already existing! +Конечная папка уже существует! + +Error deleting directory: +Ошибка при удалении папки: + +Error changing modification time: +Ошибка при изменении времени модификации файла: + +Error loading library function: +Ошибка при загрузке функции библиотеки: + +Error reading security context: +Ошибка при чтении контекста безобасности: + +Error writing security context: +Ошибка при записи контекста безобасности: + +Error copying file permissions: +Ошибка при копировании прав доступа: + +Error creating directory: +Ошибка при создании папки: + +Error copying symbolic link: +Ошибка при копировании символьной ссылки: + +Error copying file: +Ошибка при копировании файла: + +Error opening file: +Ошибка при открытии файла: + +Error traversing directory: +Ошибка при пересечении папок: + +Endless loop when traversing directory: +Зацикливание при встрече пересекающихся путей: + +Error setting privilege: +Ошибка установки привилегий: + Both sides have changed since last synchronization! Со времени последней синхронизации с обеих сторон произошли изменения! @@ -1341,9 +1327,6 @@ Transfer file and directory permissions (Requires Administrator rights) Directories are dependent! Be careful when setting up synchronization rules: Зависимые папки! Будьте внимательны при настройке правил синхронизации: -Comparing content of files %x -Сравнение содержания файлов %x - Memory allocation failed! Ошибка выделения памяти! (Не хватает памяти) @@ -1359,15 +1342,15 @@ Transfer file and directory permissions (Requires Administrator rights) Symlinks %x have the same date but a different target! Символьная ссылка %x имеет ту же дату, но различное содержание! +Comparing content of files %x +Сравнение содержания файлов %x + Comparing files by content failed. Сравнение файлов по содержимому провалено. Generating file list... Создание списка файлов... -Multiple... -Различные варианты синхронизации - Both sides are equal Обе стороны равны @@ -1386,6 +1369,12 @@ Transfer file and directory permissions (Requires Administrator rights) Delete right file/folder Удалить файл/папку справа +Move file on left +Переместить файл налево + +Move file on right +Переместить файл направо + Overwrite left file/folder with right one Перезаписать файл/папку слева на аналогичную из правой части @@ -1401,6 +1390,9 @@ Transfer file and directory permissions (Requires Administrator rights) Copy file attributes only to right Скопировать только атрибуты файла направо +Multiple... +Различные варианты синхронизации + Deleting file %x Удаление файла %x diff --git a/BUILD/Languages/slovenian.lng b/BUILD/Languages/slovenian.lng index bf917426..4e6683db 100644 --- a/BUILD/Languages/slovenian.lng +++ b/BUILD/Languages/slovenian.lng @@ -22,39 +22,6 @@ RealtimeSync - Automated Synchronization RealtimeSync - Avtomatizirana sinhronizacija -Browse -Brskaj - -Windows Error Code %x: -Windows koda napake %x: - -Linux Error Code %x: -Linux koda napake %x: - -Invalid command line: %x -Napačna ukazna vrstica: %x - -Error resolving symbolic link: -Napaka pri razreševanju simbolične povezave: - -Show pop-up -Prikaži pojavno okno - -Show pop-up on errors or warnings -Prikaži pojavne napaka ali opozorila - -Ignore errors -Ignoriraj napake - -Hide all error and warning messages -Skrij vsa obvestila o napakah in opozorilih - -Exit instantly -Zapusti v trenutku - -Abort synchronization immediately -Takoj prekini sinhronizacijo - Select alternate comparison settings Izberite alternativne nastavitve primerjanja @@ -115,6 +82,45 @@ Select time span Izberite časovni okvir +Show pop-up +Prikaži pojavno okno + +Show pop-up on errors or warnings +Prikaži pojavne napaka ali opozorila + +Ignore errors +Ignoriraj napake + +Hide all error and warning messages +Skrij vsa obvestila o napakah in opozorilih + +Exit instantly +Zapusti v trenutku + +Abort synchronization immediately +Takoj prekini sinhronizacijo + +Browse +Brskaj + +Error reading from synchronization database: +Napaka pri branju iz sinhronizacijske podatkovne baze: + +Error writing to synchronization database: +Napaka pri pisanju v sinhronizacijsko podatkovno bazo: + +Invalid command line: %x +Napačna ukazna vrstica: %x + +Windows Error Code %x: +Windows koda napake %x: + +Linux Error Code %x: +Linux koda napake %x: + +Error resolving symbolic link: +Napaka pri razreševanju simbolične povezave: + %x MB %x MB @@ -165,17 +171,14 @@ Comparison Result Rezultati primerjave -Incompatible synchronization database format: -Nekompatibilen format sinhronizacijske podatkovne baze: - Initial synchronization: Začetna sinhronizacija: One of the FreeFileSync database files is not yet existing: Ena od FreeFileSync datotek podatkovne baze še en obstaja: -Error reading from synchronization database: -Napaka pri branju iz sinhronizacijske podatkovne baze: +Incompatible synchronization database format: +Nekompatibilen format sinhronizacijske podatkovne baze: Database files do not share a common synchronization session: Datoteke podatkovne baze si ne delijo skupne sinhronizacijske seje: @@ -203,12 +206,18 @@ %x sek +Drag && drop +Povleci && spusti + Info Info Fatal Error Usodna napaka +Error reading file: +Napaka pri branju datoteke: + Scanning: Pregledujem: @@ -229,15 +238,36 @@ Invalid FreeFileSync config file! Neveljavna FreeFileSync nastavitvena datoteka! -File does not exist: -Datoteka ne obstaja: - Error parsing configuration file: Napaka pri preverjanju konfiguracijske datoteke: +Error moving to Recycle Bin: +Napaka pri premikanju v Koš: + +Could not load a required DLL: +Ne morem naložiti zahtevano DLL: + +Error accessing Volume Shadow Copy Service! +Napaka pri dostopu do servisa senčnih kopij! + +Making shadow copies on WOW64 is not supported. Please use FreeFileSync 64-bit version. +Ustvarjanje senčnih kopij na WOW63 ni podprto. Prosimo uporabite 64-bitno FreeFileSync različico. + +Could not determine volume name for file: +Ne morem določiti imena volumna za datoteko: + +Volume name %x not part of filename %y! +Ime volumna %x ni del imena datoteke %y! + /sec /sek +File does not exist: +Datoteka ne obstaja: + +Could not read values for the following XML nodes: +Ne morem brati vrednosti za naslednja XML vozlišča: + S&ave configuration... Shr&ani konfiguracijo... @@ -330,147 +360,6 @@ Ukazna vrstica se izvrši vsakič ko: A directory input field is empty. Vpisno polje za imenik je prazno. -Drag && drop -Povleci && spusti - -Could not initialize directory monitoring: -Ne morem začeti nadzorovanja imenikov: - -Error when monitoring directories. -Napaka pri nadzorovanju imenikov. - -Conversion error: -Napaka pri pretvorbi: - -Error deleting file: -Napaka pri brisanju datoteke: - -Error moving file: -Napaka pri premikanju datoteke: - -Target file already existing! -Ciljna datoteka že obstaja! - -Error moving directory: -Napaka pri premikanju imenika: - -Target directory already existing! -Ciljni imenik že obstaja! - -Error deleting directory: -Napaka pri brisanju imenika: - -Error changing modification time: -Napaka pri spreminjanju časa modifikacije: - -Error loading library function: -Napaka pri nalaganju funkcije iz knjižnice: - -Error reading security context: -Napaka pri branju varnostne skladnosti: - -Error writing security context: -Napaka pri pisanju varnostne skladnosti: - -Error copying file permissions: -Napaka pri kopiranju datotečnih dovoljenj: - -Error creating directory: -Napaka pri ustvarjanju imenika: - -Error copying symbolic link: -Napaka pri kopiranju simboličnih povezav: - -Error copying file: -Napaka pri kopiranju datoteke: - -Error opening file: -Napaka pri odpiranju datoteke: - -Error writing file: -Napaka pri pisanju datoteke: - -Error reading file: -Napaka pri branju datoteke: - -Operation aborted! -Operacija prekinjena! - -Endless loop when traversing directory: -Neskončna zanka pri prehodu imenika: - -Error traversing directory: -Napaka pri prehajanju imenika: - -Error setting privilege: -Napaka pri nastavljanju privilegija: - -Error moving to Recycle Bin: -Napaka pri premikanju v Koš: - -Could not load a required DLL: -Ne morem naložiti zahtevano DLL: - -Error writing to synchronization database: -Napaka pri pisanju v sinhronizacijsko podatkovno bazo: - -Error accessing Volume Shadow Copy Service! -Napaka pri dostopu do servisa senčnih kopij! - -Making shadow copies on WOW64 is not supported. Please use FreeFileSync 64-bit version. -Ustvarjanje senčnih kopij na WOW63 ni podprto. Prosimo uporabite 64-bitno FreeFileSync različico. - -Could not determine volume name for file: -Ne morem določiti imena volumna za datoteko: - -Volume name %x not part of filename %y! -Ime volumna %x ni del imena datoteke %y! - -%x TB -%x TB - -%x PB -%x PB - -%x% -%x% - - -1 min -%x min - - -1 min -%x min -%x min -%x min - - - -1 hour -%x hours - - -1 ura -%x uri -%x ure -%x ur - - - -1 day -%x days - - -1 dan -%x dni -%x dni -%x dni - - -Could not read values for the following XML nodes: -Ne morem brati vrednosti za naslednja XML vozlišča: - Logging Beleženje @@ -489,9 +378,6 @@ Ukazna vrstica se izvrši vsakič ko: Batch execution Paketno izvajanje -Log-messages: -Sporočila beleženja: - Stop Ustavi @@ -618,6 +504,24 @@ Ukazna vrstica se izvrši vsakič ko: Total amount of data that will be transferred Količina podatkov, ki bo prenešena +Operation: +Operacija: + +Items found: +Najdenih elementov: + +Items remaining: +Preostalih elementov: + +Speed: +Hitrost: + +Time remaining: +Preostali čas: + +Time elapsed: +Pretečen čas: + Batch job Paketno opravilo @@ -666,32 +570,14 @@ Ukazna vrstica se izvrši vsakič ko: &Cancel &Prekliči -Operation: -Operacija: - -Items found: -Najdenih elementov: - -Items remaining: -Preostalih elementov: - -Speed: -Hitrost: - -Time remaining: -Preostali čas: - -Time elapsed: -Pretečen čas: - Select variant: Izberite varianto: -Identify and propagate changes on both sides using a database. Deletions and conflicts are detected automatically. -Prepoznaj in širi spremembe na obeh straneh z uporabo podatkovne baze. Izbrisi in spori so zaznani samodejno. +Identify and propagate changes on both sides using a database. Deletions, renaming and conflicts are detected automatically. +Identificiraj in promoviraj spremembe na obeh straneh z uporabo podatkovne baze. Izbrisi, preimenovanja in spori so samodejno zaznani. Mirror ->> Zrcalno ->> @@ -913,27 +799,19 @@ Izključi: \stuff\temp\* Transakcijsko kopiranje datotek Write to a temporary file (*.ffs_tmp) first then rename it. This guarantees a consistent state even in case of fatal error. - +Najprej zapisuj v začasno datoteko (*.ffs_tmp) in nato preimenuj. To zagotavlja dosledno stanje celo v primeru usodne napake. Copy locked files Kopiraj zaklenjene datoteke - -Copy shared or locked files using Volume Shadow Copy Service (Requires Administrator rights) - - -Kopiraj deljene ali zaklenjene datoteke z uporabo servisa Shadow Copy (Zahteva pravice skrbnika) - +Copy shared or locked files using Volume Shadow Copy Service (Requires Administrator rights) +Kopiraj deljene ali zaklenjene datoteke z uporabo servisa Shadow Copy (Zahteva pravice skrbnika) Copy file access permissions Kopiraj dovoljenja dostopov datoteke - -Transfer file and directory permissions (Requires Administrator rights) - - -Prenesi dovoljenja datotek in imenikov (Zahteva pravice skrbnika) - +Transfer file and directory permissions (Requires Administrator rights) +Prenesi dovoljenja datotek in imenikov (Zahteva pravice skrbnika) Hidden dialogs: Skriti pogovori: @@ -965,6 +843,9 @@ Prenesi dovoljenja datotek in imenikov (Zahteva pravice skrbnika) &Find next &Najdi naslednje +Operation aborted! +Operacija prekinjena! + Main bar Glavna vrstica @@ -1005,16 +886,16 @@ Prenesi dovoljenja datotek in imenikov (Zahteva pravice skrbnika) Samo-prilagodi stolpce Icon size: - +Velikost ikone: Small - +Majhna Medium - +Srednja Large - +Velika Include all rows Vključi se vrstice @@ -1142,6 +1023,9 @@ Prenesi dovoljenja datotek in imenikov (Zahteva pravice skrbnika) File list exported! Seznam datotek je bil izvožen! +Error writing file: +Napaka pri pisanju datoteke: + Batch file created successfully! Paketna datoteka je bila uspešno ustvarjena! @@ -1249,9 +1133,6 @@ Prenesi dovoljenja datotek in imenikov (Zahteva pravice skrbnika) Filter: Single pair Filtriraj: En sam par -Ignore -Ignoriraj - Direct Neposredno @@ -1319,6 +1200,111 @@ Prenesi dovoljenja datotek in imenikov (Zahteva pravice skrbnika) Move files into a time-stamped subdirectory Premakni datoteke v časovno-označen podimenik +%x TB +%x TB + +%x PB +%x PB + +%x% +%x% + + +1 min +%x min + + +1 min +%x min +%x min +%x min + + + +1 hour +%x hours + + +1 ura +%x uri +%x ure +%x ur + + + +1 day +%x days + + +1 dan +%x dni +%x dni +%x dni + + +Could not initialize directory monitoring: +Ne morem začeti nadzorovanja imenikov: + +Error when monitoring directories. +Napaka pri nadzorovanju imenikov. + +Conversion error: +Napaka pri pretvorbi: + +Error deleting file: +Napaka pri brisanju datoteke: + +Error moving file: +Napaka pri premikanju datoteke: + +Target file already existing! +Ciljna datoteka že obstaja! + +Error moving directory: +Napaka pri premikanju imenika: + +Target directory already existing! +Ciljni imenik že obstaja! + +Error deleting directory: +Napaka pri brisanju imenika: + +Error changing modification time: +Napaka pri spreminjanju časa modifikacije: + +Error loading library function: +Napaka pri nalaganju funkcije iz knjižnice: + +Error reading security context: +Napaka pri branju varnostne skladnosti: + +Error writing security context: +Napaka pri pisanju varnostne skladnosti: + +Error copying file permissions: +Napaka pri kopiranju datotečnih dovoljenj: + +Error creating directory: +Napaka pri ustvarjanju imenika: + +Error copying symbolic link: +Napaka pri kopiranju simboličnih povezav: + +Error copying file: +Napaka pri kopiranju datoteke: + +Error opening file: +Napaka pri odpiranju datoteke: + +Error traversing directory: +Napaka pri prehajanju imenika: + +Endless loop when traversing directory: +Neskončna zanka pri prehodu imenika: + +Error setting privilege: +Napaka pri nastavljanju privilegija: + Both sides have changed since last synchronization! Obe strani sta se spremenili od zadnje sinhronizacije! @@ -1349,9 +1335,6 @@ Prenesi dovoljenja datotek in imenikov (Zahteva pravice skrbnika) Directories are dependent! Be careful when setting up synchronization rules: Imeniki so v odvisnosti! Bodite pozorni, ko nastavljate sinhronizacijska pravila: -Comparing content of files %x -Primerjam vsebino datotek %x - Memory allocation failed! Neuspešno dodeljevanje pomnilnika! @@ -1367,15 +1350,15 @@ Prenesi dovoljenja datotek in imenikov (Zahteva pravice skrbnika) Symlinks %x have the same date but a different target! Simbolične povezave %x imajo isti datum, vendar različni cilj! +Comparing content of files %x +Primerjam vsebino datotek %x + Comparing files by content failed. Primerjava datotek po vsebini ni uspela. Generating file list... Ustvarjam seznam datotek... -Multiple... -Večkratno... - Both sides are equal Obe strani sta enaki @@ -1394,6 +1377,12 @@ Prenesi dovoljenja datotek in imenikov (Zahteva pravice skrbnika) Delete right file/folder Izbriši desno datoteko/mapo +Move file on left +Premakni datoteko na levo + +Move file on right +Premakni datoteko na desno + Overwrite left file/folder with right one Prepiši levo datoteko/mapo s tisto na desni @@ -1409,6 +1398,9 @@ Prenesi dovoljenja datotek in imenikov (Zahteva pravice skrbnika) Copy file attributes only to right Kopiraj atribute datoteke samo na desno +Multiple... +Večkratno... + Deleting file %x Brisanje datoteke %x diff --git a/BUILD/Languages/spanish.lng b/BUILD/Languages/spanish.lng index f1072972..574aeca1 100644 --- a/BUILD/Languages/spanish.lng +++ b/BUILD/Languages/spanish.lng @@ -22,39 +22,6 @@ RealtimeSync - Automated Synchronization RealtimeSync - Sincronización Automática -Browse -Examinar - -Windows Error Code %x: -Código de error de Windows %x: - -Linux Error Code %x: -Código de error de Linux %x: - -Invalid command line: %x -Línea de comandos errónea: %x - -Error resolving symbolic link: -Error al resolver enlace simbólico: - -Show pop-up -Mostrar ventana emergente - -Show pop-up on errors or warnings -Mostrar ventana emergente de errores o avisos - -Ignore errors -Ignorar errores - -Hide all error and warning messages -Ocultar todos los mensajes de error y aviso - -Exit instantly -Salir inmediatamente - -Abort synchronization immediately -Abortar sincronización inmediatamente - Select alternate comparison settings Seleccionar opciones alternativas de comparación @@ -113,7 +80,46 @@ Buscar Select time span - +Seleccionar duración + +Show pop-up +Mostrar ventana emergente + +Show pop-up on errors or warnings +Mostrar ventana emergente de errores o avisos + +Ignore errors +Ignorar errores + +Hide all error and warning messages +Ocultar todos los mensajes de error y aviso + +Exit instantly +Salir inmediatamente + +Abort synchronization immediately +Abortar sincronización inmediatamente + +Browse +Examinar + +Error reading from synchronization database: +Error al leer de la base de datos de sincronización: + +Error writing to synchronization database: +Error al escribir en la base de datos de sincronización: + +Invalid command line: %x +Línea de comandos errónea: %x + +Windows Error Code %x: +Código de error de Windows %x: + +Linux Error Code %x: +Código de error de Linux %x: + +Error resolving symbolic link: +Error al resolver enlace simbólico: %x MB %x MB @@ -163,17 +169,14 @@ Comparison Result Resultado de la comparación -Incompatible synchronization database format: -Formato de base de datos de sincronización incompatible: - Initial synchronization: Sincronización inicial: One of the FreeFileSync database files is not yet existing: Uno de los archivos de la base de datos de FreeFileSync aún no existe: -Error reading from synchronization database: -Error al leer de la base de datos de sincronización: +Incompatible synchronization database format: +Formato de base de datos de sincronización incompatible: Database files do not share a common synchronization session: Archivos de base de datos no comparten la misma sesión de sincronización: @@ -199,12 +202,18 @@ %x segundos +Drag && drop +Arrastrar y soltar + Info Info Fatal Error Error fatal +Error reading file: +Error al leer archivo: + Scanning: Escanear: @@ -223,15 +232,36 @@ Invalid FreeFileSync config file! ¡Archivo de configuración de FreeFileSync inválido! -File does not exist: -El archivo no existe: - Error parsing configuration file: Error al analizar el archivo de configuración: +Error moving to Recycle Bin: +Error al mover a la Papelera de Reciclaje: + +Could not load a required DLL: +No se ha podido cargar el DLL solicitado: + +Error accessing Volume Shadow Copy Service! +¡Error al acceder al servicio Volume Shadow Copy! + +Making shadow copies on WOW64 is not supported. Please use FreeFileSync 64-bit version. +La realización de copias shadow en WOW64 no está soportado. Por favor, use la versión 64-bit de FreeFileSync. + +Could not determine volume name for file: +No se ha podido determinar el nombre del volumen para el archivo: + +Volume name %x not part of filename %y! +El nombre del volumen %x no es una parte del nombre de archivo %y + /sec /seg +File does not exist: +El archivo no existe: + +Could not read values for the following XML nodes: +No se ha podido leer los valores para los siguientes nodos XML: + S&ave configuration... G&uardar configuración... @@ -324,141 +354,6 @@ La línea de comandos se ejecuta cada vez: A directory input field is empty. Un campo de directorio está vacío. -Drag && drop -Arrastrar y soltar - -Could not initialize directory monitoring: -No se ha podido inicializar la visualización de directorios: - -Error when monitoring directories. -Error al visualizar los directorios. - -Conversion error: -Error de conversión: - -Error deleting file: -Error al borrar archivo: - -Error moving file: -Error al mover archivo: - -Target file already existing! -¡El archivo de destino ya existe! - -Error moving directory: -Error al mover directorio: - -Target directory already existing! -¡El directorio de destino ya existe! - -Error deleting directory: -Error al borrar directorio: - -Error changing modification time: -Error al cambiar hora de modificación: - -Error loading library function: -Error al cargar la función de biblioteca: - -Error reading security context: -Error al leer en contexto de seguridad: - -Error writing security context: -Error al escribir en contexto de seguridad: - -Error copying file permissions: -Error al copiar permisos del fichero: - -Error creating directory: -Error al crear directorio: - -Error copying symbolic link: -Error al copiar enlace simbólico: - -Error copying file: -Error al copiar archivo: - -Error opening file: -Error al abrir archivo: - -Error writing file: -Error al escribir archivo: - -Error reading file: -Error al leer archivo: - -Operation aborted! -¡Operación abortada! - -Endless loop when traversing directory: -Bucle infinito al buscar en el directorio: - -Error traversing directory: -Error al buscar en el directorio: - -Error setting privilege: -Error al establecer privilegios: - -Error moving to Recycle Bin: -Error al mover a la Papelera de Reciclaje: - -Could not load a required DLL: -No se ha podido cargar el DLL solicitado: - -Error writing to synchronization database: -Error al escribir en la base de datos de sincronización: - -Error accessing Volume Shadow Copy Service! -¡Error al acceder al servicio Volume Shadow Copy! - -Making shadow copies on WOW64 is not supported. Please use FreeFileSync 64-bit version. -La realización de copias shadow en WOW64 no está soportado. Por favor, use la versión 64-bit de FreeFileSync. - -Could not determine volume name for file: -No se ha podido determinar el nombre del volumen para el archivo: - -Volume name %x not part of filename %y! -El nombre del volumen %x no es una parte del nombre de archivo %y - -%x TB -%x TB - -%x PB -%x PB - -%x% -%x% - - -1 min -%x min - - -1 minuto -%x minutos - - - -1 hour -%x hours - - -1 hora -%x horas - - - -1 day -%x days - - -1 día -%x días - - -Could not read values for the following XML nodes: -No se ha podido leer los valores para los siguientes nodos XML: - Logging Iniciando sesión @@ -477,9 +372,6 @@ La línea de comandos se ejecuta cada vez: Batch execution Ejecución batch -Log-messages: -Registro de mensajes: - Stop Detener @@ -606,6 +498,24 @@ La línea de comandos se ejecuta cada vez: Total amount of data that will be transferred Cantidad total de datos que serán transferidos +Operation: +Operación: + +Items found: +Elementos encontrados: + +Items remaining: +Elementos restantes: + +Speed: +Velocidad: + +Time remaining: +Tiempo restante: + +Time elapsed: +Tiempo transcurrido: + Batch job Tarea batch @@ -654,32 +564,14 @@ La línea de comandos se ejecuta cada vez: &Cancel &Cancelar -Operation: -Operación: - -Items found: -Elementos encontrados: - -Items remaining: -Elementos restantes: - -Speed: -Velocidad: - -Time remaining: -Tiempo restante: - -Time elapsed: -Tiempo transcurrido: - Select variant: Seleccione un tipo: -Identify and propagate changes on both sides using a database. Deletions and conflicts are detected automatically. -Identificar y aplicar cambios en ambos lados usando una base de datos. Las eliminaciones y los conflictos se detectan automáticamente. +Identify and propagate changes on both sides using a database. Deletions, renaming and conflicts are detected automatically. +Identificar y propagar cambios en ambos lados usando una base de datos. Borrados, renombraciones y conflictos son detectados automáticamente. Mirror ->> Espejo ->> @@ -901,27 +793,19 @@ Excluir: \stuff\temp\* Copia de archivos transaccionales Write to a temporary file (*.ffs_tmp) first then rename it. This guarantees a consistent state even in case of fatal error. - +Escribir en archivo temporal (*.ffs_tmp) primero y después renombrarlo. Esto garantiza un estado consistente incluso en caso de error fatal. Copy locked files Copiar archivos bloqueados - -Copy shared or locked files using Volume Shadow Copy Service (Requires Administrator rights) - - -Copiar archivos compartidos o bloqueados usando el servicio "Volume Shadow Copy" (Requiere derechos de administrador) - +Copy shared or locked files using Volume Shadow Copy Service (Requires Administrator rights) +Copiar archivos compartidos o bloqueados usando el servicio "Volume Shadow Copy" (Requiere derechos de administrador) Copy file access permissions Copiar permisos de acceso al archivo - -Transfer file and directory permissions (Requires Administrator rights) - - -Transferir permisos de archivo y directorio (Requiere derechos de administrador) - +Transfer file and directory permissions (Requires Administrator rights) +Transferir permisos de archivo y directorio (Requiere derechos de administrador) Hidden dialogs: Diálogos ocultos: @@ -953,6 +837,9 @@ Transferir permisos de archivo y directorio (Requiere derechos de administrador) &Find next &Buscar siguiente +Operation aborted! +¡Operación abortada! + Main bar Barra principal @@ -993,16 +880,16 @@ Transferir permisos de archivo y directorio (Requiere derechos de administrador) Ajustar automáticamente las columnas Icon size: - +Tamaño del icono: Small - +Pequeño Medium - +Medio Large - +Grande Include all rows Incluir todas las filas @@ -1130,6 +1017,9 @@ Transferir permisos de archivo y directorio (Requiere derechos de administrador) File list exported! ¡Lista de archivos exportada! +Error writing file: +Error al escribir archivo: + Batch file created successfully! ¡El archivo batch ha sido creado correctamente! @@ -1229,9 +1119,6 @@ Transferir permisos de archivo y directorio (Requiere derechos de administrador) Filter: Single pair Filtro: Sólo un par -Ignore -Ignorar - Direct Enviar @@ -1295,6 +1182,105 @@ Transferir permisos de archivo y directorio (Requiere derechos de administrador) Move files into a time-stamped subdirectory Mover archivos a un subdirectorio con marca de tiempo +%x TB +%x TB + +%x PB +%x PB + +%x% +%x% + + +1 min +%x min + + +1 minuto +%x minutos + + + +1 hour +%x hours + + +1 hora +%x horas + + + +1 day +%x days + + +1 día +%x días + + +Could not initialize directory monitoring: +No se ha podido inicializar la visualización de directorios: + +Error when monitoring directories. +Error al visualizar los directorios. + +Conversion error: +Error de conversión: + +Error deleting file: +Error al borrar archivo: + +Error moving file: +Error al mover archivo: + +Target file already existing! +¡El archivo de destino ya existe! + +Error moving directory: +Error al mover directorio: + +Target directory already existing! +¡El directorio de destino ya existe! + +Error deleting directory: +Error al borrar directorio: + +Error changing modification time: +Error al cambiar hora de modificación: + +Error loading library function: +Error al cargar la función de biblioteca: + +Error reading security context: +Error al leer en contexto de seguridad: + +Error writing security context: +Error al escribir en contexto de seguridad: + +Error copying file permissions: +Error al copiar permisos del fichero: + +Error creating directory: +Error al crear directorio: + +Error copying symbolic link: +Error al copiar enlace simbólico: + +Error copying file: +Error al copiar archivo: + +Error opening file: +Error al abrir archivo: + +Error traversing directory: +Error al buscar en el directorio: + +Endless loop when traversing directory: +Bucle infinito al buscar en el directorio: + +Error setting privilege: +Error al establecer privilegios: + Both sides have changed since last synchronization! ¡Ambos lados han cambiado desde la última sincronizacion! @@ -1325,9 +1311,6 @@ Transferir permisos de archivo y directorio (Requiere derechos de administrador) Directories are dependent! Be careful when setting up synchronization rules: ¡Los directorios son dependientes! Tenga cuidado al establecer las reglas de sincronización: -Comparing content of files %x -Comparación del contenido de los archivos %x - Memory allocation failed! ¡La asignación de memoria ha fallado! @@ -1343,15 +1326,15 @@ Transferir permisos de archivo y directorio (Requiere derechos de administrador) Symlinks %x have the same date but a different target! ¡Los enlaces simbólicos %x tienen la misma fecha pero un destino diferente! +Comparing content of files %x +Comparación del contenido de los archivos %x + Comparing files by content failed. La comparación de archivos por el contenido ha fallado. Generating file list... Generando lista de archivos... -Multiple... -Múltiple... - Both sides are equal Ambos lados son iguales @@ -1370,6 +1353,12 @@ Transferir permisos de archivo y directorio (Requiere derechos de administrador) Delete right file/folder Eliminar archivo/carpeta de la derecha +Move file on left +Mover archivo a la izquierda + +Move file on right +Mover archivo a la derecha + Overwrite left file/folder with right one Sobreescribir archivo/carpeta de la izquierda por el de la derecha @@ -1385,6 +1374,9 @@ Transferir permisos de archivo y directorio (Requiere derechos de administrador) Copy file attributes only to right Copiar sólo atributos del archivo a la derecha +Multiple... +Múltiple... + Deleting file %x Borrar archivo %x diff --git a/BUILD/Languages/swedish.lng b/BUILD/Languages/swedish.lng index acd17992..07d20948 100644 --- a/BUILD/Languages/swedish.lng +++ b/BUILD/Languages/swedish.lng @@ -22,39 +22,6 @@ RealtimeSync - Automated Synchronization RealtimeSync - Automatiserad synkronisering -Browse -Bläddra - -Windows Error Code %x: -Windows Felkod %x: - -Linux Error Code %x: -Linux Felkod %x: - -Invalid command line: %x -Ogiltig kommandorad: %x - -Error resolving symbolic link: -Kan inte tyda symbolisk länk: - -Show pop-up -Visa pop-up - -Show pop-up on errors or warnings -Visa pop-up vid fel och varningar - -Ignore errors -Ignorera fel - -Hide all error and warning messages -Visa inte fel- och varningsmeddelanden - -Exit instantly -Avsluta omedelbart - -Abort synchronization immediately -Avbryt synkronisering omedelbart - Select alternate comparison settings Välj alternativa jämförelseinställningar @@ -115,6 +82,45 @@ Select time span Välj tidsintervall +Show pop-up +Visa pop-up + +Show pop-up on errors or warnings +Visa pop-up vid fel och varningar + +Ignore errors +Ignorera fel + +Hide all error and warning messages +Visa inte fel- och varningsmeddelanden + +Exit instantly +Avsluta omedelbart + +Abort synchronization immediately +Avbryt synkronisering omedelbart + +Browse +Bläddra + +Error reading from synchronization database: +Kan inte läsa från databasen: + +Error writing to synchronization database: +Kan inte skriva till databas: + +Invalid command line: %x +Ogiltig kommandorad: %x + +Windows Error Code %x: +Windows Felkod %x: + +Linux Error Code %x: +Linux Felkod %x: + +Error resolving symbolic link: +Kan inte tyda symbolisk länk: + %x MB %x MB @@ -163,17 +169,14 @@ Comparison Result Jämförelseresultat -Incompatible synchronization database format: -Inkompatibelt databasformat: - Initial synchronization: Initial synkronisering: One of the FreeFileSync database files is not yet existing: En av FreeFileSyncs databasfiler saknas: -Error reading from synchronization database: -Kan inte läsa från databasen: +Incompatible synchronization database format: +Inkompatibelt databasformat: Database files do not share a common synchronization session: Databasfiler delar inte en gemensam synkroniseringssession: @@ -199,12 +202,18 @@ %x sek +Drag && drop +Dra && släpp + Info Info Fatal Error Allvarligt fel +Error reading file: +Kan inte läsa fil: + Scanning: Skannar: @@ -223,15 +232,36 @@ Invalid FreeFileSync config file! Felaktig FreeFileSync konfigurationsfil! -File does not exist: -Filen finns inte: - Error parsing configuration file: Kan inte läsa in konfigurationsfil: +Error moving to Recycle Bin: +Kan inte flytta till papperskorgen: + +Could not load a required DLL: +Kan inte läsa in nödvändig DLL: + +Error accessing Volume Shadow Copy Service! +Kunde inte starta tjänsten Volume Shadow Copy (VSS) + +Making shadow copies on WOW64 is not supported. Please use FreeFileSync 64-bit version. +Skuggkopior av wow64 stöds ej. Använd FreeFileSync x64 istället! + +Could not determine volume name for file: +Kan inte bestämma volym för fil: + +Volume name %x not part of filename %y! +Volymnamn %x saknas i filnamn %y! + /sec /s +File does not exist: +Filen finns inte: + +Could not read values for the following XML nodes: +Kan inte läsa värden för följande XML-noder: + S&ave configuration... S¶ inställningar... @@ -324,141 +354,6 @@ Kommandot verkställes när: A directory input field is empty. Ett katalogfält är tomt -Drag && drop -Dra && släpp - -Could not initialize directory monitoring: -Kan inte initiera katalogskanner: - -Error when monitoring directories. -Fel vid övervakning av kataloger. - -Conversion error: -Konversionsfel: - -Error deleting file: -Kan inte ta bort fil: - -Error moving file: -Kan inte flytta fil: - -Target file already existing! -Filen finns redan! - -Error moving directory: -Kan inte flytta katalog: - -Target directory already existing! -Målkatalogen finns redan! - -Error deleting directory: -Kan inte ta bort katalog: - -Error changing modification time: -Kan inte modifiera tidsstämpel: - -Error loading library function: -Kan inte starta biblioteksfunktion: - -Error reading security context: -Kan inte läsa säkerhetskontext: - -Error writing security context: -Kan inte skriva säkerhetskontext: - -Error copying file permissions: -Kan inte kopiera filsystembehörighet: - -Error creating directory: -Kan inte skapa katalog: - -Error copying symbolic link: -Kan inte kopiera symbolisk länk: - -Error copying file: -Kan inte kopiera fil: - -Error opening file: -Kan inte öppna fil: - -Error writing file: -Kan inte skriva fil: - -Error reading file: -Kan inte läsa fil: - -Operation aborted! -Processen avbruten! - -Endless loop when traversing directory: -Oändlig loop vid accessförsök på katalog: - -Error traversing directory: -Accessfel på katalog: - -Error setting privilege: -Kan inte ange privilegie: - -Error moving to Recycle Bin: -Kan inte flytta till papperskorgen: - -Could not load a required DLL: -Kan inte läsa in nödvändig DLL: - -Error writing to synchronization database: -Kan inte skriva till databas: - -Error accessing Volume Shadow Copy Service! -Kunde inte starta tjänsten Volume Shadow Copy (VSS) - -Making shadow copies on WOW64 is not supported. Please use FreeFileSync 64-bit version. -Skuggkopior av wow64 stöds ej. Använd FreeFileSync x64 istället! - -Could not determine volume name for file: -Kan inte bestämma volym för fil: - -Volume name %x not part of filename %y! -Volymnamn %x saknas i filnamn %y! - -%x TB -%x TB - -%x PB -%x PB - -%x% -%x% - - -1 min -%x min - - -1 min -%x min - - - -1 hour -%x hours - - -1 timma -%x timmar - - - -1 day -%x days - - -1 dag -%x dagar - - -Could not read values for the following XML nodes: -Kan inte läsa värden för följande XML-noder: - Logging Loggar @@ -477,9 +372,6 @@ Kommandot verkställes när: Batch execution Batch-körning -Log-messages: -Logg-meddelanden: - Stop Stopp @@ -606,6 +498,24 @@ Kommandot verkställes när: Total amount of data that will be transferred Total mängd data som kommer att överföras +Operation: +Arbetsuppgift: + +Items found: +Funna poster: + +Items remaining: +Återstående poster: + +Speed: +Hastighet: + +Time remaining: +Kvarvarande tid: + +Time elapsed: +Förfluten tid: + Batch job Batch-jobb @@ -654,32 +564,14 @@ Kommandot verkställes när: &Cancel &Avbryt -Operation: -Arbetsuppgift: - -Items found: -Funna poster: - -Items remaining: -Återstående poster: - -Speed: -Hastighet: - -Time remaining: -Kvarvarande tid: - -Time elapsed: -Förfluten tid: - Select variant: Välj variant: -Identify and propagate changes on both sides using a database. Deletions and conflicts are detected automatically. -Identifiera och visa förändringar på båda sidor via databas. Borttagningar och konflikter upptäcks automatiskt. +Identify and propagate changes on both sides using a database. Deletions, renaming and conflicts are detected automatically. +Använd en databas för att identifiera och sprida ändringar på båda sidor. Borttagning, namnbyte och konflikter upptäcks automatiskt Mirror ->> Spegla ->> @@ -901,27 +793,19 @@ Undanta: \stuff\temp\* Transaktionell filkopiering Write to a temporary file (*.ffs_tmp) first then rename it. This guarantees a consistent state even in case of fatal error. - +Skriv först till en temporär fil (*.ffs_tmp) och byt sedan namn på den. Detta garanterar en konsistent status även vid allvarliga fel Copy locked files Kopiera låsta filer - -Copy shared or locked files using Volume Shadow Copy Service (Requires Administrator rights) - - -Kopiera delade eller låsta filer med hjälp av Volume Shadow Copy Service (Kräver administratörsrättighet) - +Copy shared or locked files using Volume Shadow Copy Service (Requires Administrator rights) +Kopiera delade eller låsta filer med hjälp av Volume Shadow Copy Service (Kräver administratörsrättighet) Copy file access permissions Kopiera filåtkomstbehörigheter - -Transfer file and directory permissions (Requires Administrator rights) - - -Överför fil- och katalogrättigheter (Kräver administratörsrättigheter) - +Transfer file and directory permissions (Requires Administrator rights) +Överför fil- och katalogrättigheter (Kräver administratörsrättigheter) Hidden dialogs: Dolda meddelanden: @@ -953,6 +837,9 @@ Transfer file and directory permissions (Requires Administrator rights) &Find next &Sök nästa +Operation aborted! +Processen avbruten! + Main bar Huvudfält @@ -993,16 +880,16 @@ Transfer file and directory permissions (Requires Administrator rights) Autojustera kollumner Icon size: - +Ikonstorlek: Small - +Liten Medium - +Normal Large - +Stor Include all rows Inkludera alla rader @@ -1130,6 +1017,9 @@ Transfer file and directory permissions (Requires Administrator rights) File list exported! Fillista exporterad! +Error writing file: +Kan inte skriva fil: + Batch file created successfully! Batch-filen skapades korrekt! @@ -1229,9 +1119,6 @@ Transfer file and directory permissions (Requires Administrator rights) Filter: Single pair Filter: Enstaka undantag -Ignore -Ignorera - Direct Direkt @@ -1295,6 +1182,105 @@ Transfer file and directory permissions (Requires Administrator rights) Move files into a time-stamped subdirectory Flytta filer till en tidsstämplad underkatalog +%x TB +%x TB + +%x PB +%x PB + +%x% +%x% + + +1 min +%x min + + +1 min +%x min + + + +1 hour +%x hours + + +1 timma +%x timmar + + + +1 day +%x days + + +1 dag +%x dagar + + +Could not initialize directory monitoring: +Kan inte initiera katalogskanner: + +Error when monitoring directories. +Fel vid övervakning av kataloger. + +Conversion error: +Konversionsfel: + +Error deleting file: +Kan inte ta bort fil: + +Error moving file: +Kan inte flytta fil: + +Target file already existing! +Filen finns redan! + +Error moving directory: +Kan inte flytta katalog: + +Target directory already existing! +Målkatalogen finns redan! + +Error deleting directory: +Kan inte ta bort katalog: + +Error changing modification time: +Kan inte modifiera tidsstämpel: + +Error loading library function: +Kan inte starta biblioteksfunktion: + +Error reading security context: +Kan inte läsa säkerhetskontext: + +Error writing security context: +Kan inte skriva säkerhetskontext: + +Error copying file permissions: +Kan inte kopiera filsystembehörighet: + +Error creating directory: +Kan inte skapa katalog: + +Error copying symbolic link: +Kan inte kopiera symbolisk länk: + +Error copying file: +Kan inte kopiera fil: + +Error opening file: +Kan inte öppna fil: + +Error traversing directory: +Accessfel på katalog: + +Endless loop when traversing directory: +Oändlig loop vid accessförsök på katalog: + +Error setting privilege: +Kan inte ange privilegie: + Both sides have changed since last synchronization! Båda sidor har ändrats sedan senaste synkroniseringen! @@ -1325,9 +1311,6 @@ Transfer file and directory permissions (Requires Administrator rights) Directories are dependent! Be careful when setting up synchronization rules: Kataloger är beroende! Var försiktig när du sätter upp synkroniseringsregler: -Comparing content of files %x -Jämför filinnehåll för %x - Memory allocation failed! Minnesallokering misslyckades! @@ -1343,15 +1326,15 @@ Transfer file and directory permissions (Requires Administrator rights) Symlinks %x have the same date but a different target! Symbolisk länk %x har samma datum, men annat mål! +Comparing content of files %x +Jämför filinnehåll för %x + Comparing files by content failed. Kunde inte jämföra filinnehåll. Generating file list... Skapar fillista... -Multiple... -Multipla... - Both sides are equal Bägge sidor är lika @@ -1370,6 +1353,12 @@ Transfer file and directory permissions (Requires Administrator rights) Delete right file/folder Ta bort höger fil/katalog +Move file on left +Flytta fil på vänster sida + +Move file on right +Flytta fil på höger sida + Overwrite left file/folder with right one Skriv över vänster fil/katalog med den högra @@ -1385,6 +1374,9 @@ Transfer file and directory permissions (Requires Administrator rights) Copy file attributes only to right Kopiera endast filattribut åt höger +Multiple... +Multipla... + Deleting file %x Tar bort filen %x diff --git a/BUILD/Languages/turkish.lng b/BUILD/Languages/turkish.lng index a360bcd1..2e0622d4 100644 --- a/BUILD/Languages/turkish.lng +++ b/BUILD/Languages/turkish.lng @@ -169,15 +169,15 @@ Comparison Result Karşılaştırma sonucu -Incompatible synchronization database format: -Uyumsuz eşleştirme veritabanı biçimi: - Initial synchronization: Başlangıç eşleştirmesi: One of the FreeFileSync database files is not yet existing: FreeFileSync veritabanı dosyalarından biri henüz yok: +Incompatible synchronization database format: +Uyumsuz eşleştirme veritabanı biçimi: + Database files do not share a common synchronization session: Veritabanıdosyaları ortak bir eşleştirmeoturumunu paylaşmıyor: @@ -232,9 +232,6 @@ Invalid FreeFileSync config file! Geçersiz FreeFileSync yapılandırma dosyası! -File does not exist: -Dosya bulunamadı: - Error parsing configuration file: Yapılandırma dosyası çözümlenirken hata: @@ -259,6 +256,9 @@ /sec /san +File does not exist: +Dosya bulunamadı: + Could not read values for the following XML nodes: Şu XML düğümlerindeki değerler okunamadı: @@ -372,9 +372,6 @@ Her seferinde çalıştırılacak komut satırı: Batch execution Toplu komut yürütme -Log-messages: -Günlük iletileri: - Stop Durdur @@ -501,6 +498,24 @@ Her seferinde çalıştırılacak komut satırı: Total amount of data that will be transferred Aktarılacak toplam veri miktarı +Operation: +İşlem: + +Items found: +Bulunan bileşenler: + +Items remaining: +Kalan bileşenler: + +Speed: +Hız: + +Time remaining: +Kalan zaman: + +Time elapsed: +Geçen zaman: + Batch job Toplu iş @@ -549,32 +564,14 @@ Her seferinde çalıştırılacak komut satırı: &Cancel İ&ptal -Operation: -İşlem: - -Items found: -Bulunan bileşenler: - -Items remaining: -Kalan bileşenler: - -Speed: -Hız: - -Time remaining: -Kalan zaman: - -Time elapsed: -Geçen zaman: - Select variant: Davranışı seçin: -Identify and propagate changes on both sides using a database. Deletions and conflicts are detected automatically. -Bir veritabanı kullanarak iki yandaki değişiklikleri belirler ve günceller. Silinme ve tutarsızlıklar kendiliğinden algılanır. +Identify and propagate changes on both sides using a database. Deletions, renaming and conflicts are detected automatically. +İki yandaki değişiklikleri bir veritabanı kullanarak belirle ve sakla. Silme, yeniden adlandırma ve çakışma işlemleri kendiliğinden algılanır. Mirror ->> Yansı ->> @@ -801,22 +798,14 @@ Katma: \stuff\temp\* Copy locked files Kilitli dosyaları da kopyala - -Copy shared or locked files using Volume Shadow Copy Service (Requires Administrator rights) - - -Paylaşılan ya da kilitli dosyaları Gölge Kopya Hizmetini kullanarak kopyalar (Yönetici izinlerine gerek duyar) - +Copy shared or locked files using Volume Shadow Copy Service (Requires Administrator rights) +Paylaşılan ya da kilitli dosyaları Gölge Kopya Hizmetini kullanarak kopyalar (Yönetici izinlerine gerek duyar) Copy file access permissions Dosya erişim izinlerini kopyala - -Transfer file and directory permissions (Requires Administrator rights) - - -Dosya ve klasör izinlerini de aktarır (Yönetici izinlerine gerek duyar) - +Transfer file and directory permissions (Requires Administrator rights) +Dosya ve klasör izinlerini de aktarır (Yönetici izinlerine gerek duyar) Hidden dialogs: Gizlenmiş iletiler: @@ -1130,9 +1119,6 @@ Dosya ve klasör izinlerini de aktarır (Yönetici izinlerine gerek duyar) Filter: Single pair Süzgeç: Tek çift -Ignore -Yoksay - Direct Doğrudan @@ -1286,12 +1272,12 @@ Dosya ve klasör izinlerini de aktarır (Yönetici izinlerine gerek duyar) Error opening file: Dosya açılırken hata: -Endless loop when traversing directory: -Klasörlerde dolaşırken sonsuz döngü: - Error traversing directory: Klasörde dolaşırken hata: +Endless loop when traversing directory: +Klasörlerde dolaşırken sonsuz döngü: + Error setting privilege: İzinler ayarlanırken hata: @@ -1325,9 +1311,6 @@ Dosya ve klasör izinlerini de aktarır (Yönetici izinlerine gerek duyar) Directories are dependent! Be careful when setting up synchronization rules: Klasörler bağımlı! Eşleştirme kurallarını koyarken dikkatli olun: -Comparing content of files %x -%x dosyalarının içeriği karşılaştırılıyor - Memory allocation failed! Bellek ayrılamadı! @@ -1343,15 +1326,15 @@ Dosya ve klasör izinlerini de aktarır (Yönetici izinlerine gerek duyar) Symlinks %x have the same date but a different target! Sembolik bağlantılar %x aynı tarihli fakat hedefleri farklı! +Comparing content of files %x +%x dosyalarının içeriği karşılaştırılıyor + Comparing files by content failed. Dosyaların içerikleri karşılaştırılamadı. Generating file list... Dosya listesi oluşturuluyor... -Multiple... -Çoklu... - Both sides are equal İki tarafta aynı @@ -1370,6 +1353,12 @@ Dosya ve klasör izinlerini de aktarır (Yönetici izinlerine gerek duyar) Delete right file/folder Sağdaki dosya/klasörleri sil +Move file on left +Soldaki dosyayı taşı + +Move file on right +Sağdaki dosyayı taşı + Overwrite left file/folder with right one Soldaki dosya/klasörlerin üzerine sağdakileri yaz @@ -1385,6 +1374,9 @@ Dosya ve klasör izinlerini de aktarır (Yönetici izinlerine gerek duyar) Copy file attributes only to right Dosya özniteliklerini yalnız sağa kopyalaya +Multiple... +Çoklu... + Deleting file %x %x dosyası siliniyor diff --git a/BUILD/Languages/ukrainian.lng b/BUILD/Languages/ukrainian.lng index 4973cf06..cfe7e92d 100644 --- a/BUILD/Languages/ukrainian.lng +++ b/BUILD/Languages/ukrainian.lng @@ -22,39 +22,6 @@ RealtimeSync - Automated Synchronization RealtimeSync - Автоматична синхронізація -Browse -Переглянути - -Windows Error Code %x: -Код помилки Windows %x: - -Linux Error Code %x: -Код помилки Linux %x: - -Invalid command line: %x -Неправильний командний рядок: %x - -Error resolving symbolic link: -Помилка при вирішені символічного посилання: - -Show pop-up -Показувати виринаючі вікна - -Show pop-up on errors or warnings -Показувати виринаючі вікна при помилках та попередженнях - -Ignore errors -Ігнорувати помилки - -Hide all error and warning messages -Приховати всі помилки і повідомлення з попередженнями - -Exit instantly -Вийти негайно - -Abort synchronization immediately -Перервати синхронізацію негайно - Select alternate comparison settings Вибрати альтернативні налаштування порівняння @@ -115,6 +82,45 @@ Select time span Виберіть часовий інтервал +Show pop-up +Показувати виринаючі вікна + +Show pop-up on errors or warnings +Показувати виринаючі вікна при помилках та попередженнях + +Ignore errors +Ігнорувати помилки + +Hide all error and warning messages +Приховати всі помилки і повідомлення з попередженнями + +Exit instantly +Вийти негайно + +Abort synchronization immediately +Перервати синхронізацію негайно + +Browse +Переглянути + +Error reading from synchronization database: +Помилка при читанні з бази даних синхронізації: + +Error writing to synchronization database: +Помилка при записі у базу данних синхронізації: + +Invalid command line: %x +Неправильний командний рядок: %x + +Windows Error Code %x: +Код помилки Windows %x: + +Linux Error Code %x: +Код помилки Linux %x: + +Error resolving symbolic link: +Помилка при вирішені символічного посилання: + %x MB %x МБ @@ -164,17 +170,14 @@ Comparison Result Результати порівнювання -Incompatible synchronization database format: -Несумісний формат бази даних синхронізації: - Initial synchronization: Вступна синхронізація: One of the FreeFileSync database files is not yet existing: Файлу бази даних FreeFileSync ще не існує: -Error reading from synchronization database: -Помилка при читанні з бази даних синхронізації: +Incompatible synchronization database format: +Несумісний формат бази даних синхронізації: Database files do not share a common synchronization session: Файли бази даних не мають спільної сесії синхронізації @@ -201,12 +204,18 @@ %x сек +Drag && drop +Drag && drop + Info Інформація Fatal Error Критична помилка +Error reading file: +Помилка при читанні файлу: + Scanning: Сканую: @@ -226,15 +235,36 @@ Invalid FreeFileSync config file! Неправильний файл конфігурації FreeFileSync! -File does not exist: -Файл не існує: - Error parsing configuration file: Помилка при анализі файлу налаштувань синхронізації: +Error moving to Recycle Bin: +Помилка переміщення в "Корзину": + +Could not load a required DLL: +Не вдалося завантажити необхідні DLL: + +Error accessing Volume Shadow Copy Service! +Помилка доступу до послуги Тіньового Копіювання Тому + +Making shadow copies on WOW64 is not supported. Please use FreeFileSync 64-bit version. +Створення тіньових копій на WOW64 не підтримується. Будь ласка, використайте FreeFileSync 64-розрядної версії. + +Could not determine volume name for file: +Не вдалося визначити назву тому для файлу: + +Volume name %x not part of filename %y! +Ім’я тому %x не є частиною імені файлу %y! + /sec /сек +File does not exist: +Файл не існує: + +Could not read values for the following XML nodes: +Не вдалося прочитати значення таких XML записів: + S&ave configuration... Зберегти налаштування... @@ -327,144 +357,6 @@ The command line is executed each time: A directory input field is empty. Поле введення шляху каталога порожнє. -Drag && drop -Drag && drop - -Could not initialize directory monitoring: -Не вдалося ініціювати каталог для моніторингу: - -Error when monitoring directories. -Помилка моніторингу каталогу. - -Conversion error: -Помилка перетворення: - -Error deleting file: -Помилка при вилученні файлу: - -Error moving file: -Помилка переміщення файлу: - -Target file already existing! -Кінцевий файл уже існує! - -Error moving directory: -Помилка переміщення каталогу: - -Target directory already existing! -Кінцевий каталог вже існує! - -Error deleting directory: -Помилка при вилученні каталогу: - -Error changing modification time: -Помилка при зміні часу модификації файлу: - -Error loading library function: -Помилка при завантаженні функції бібліотеки: - -Error reading security context: -Помилка при читанні контексту безпеки: - -Error writing security context: -Помилка при записі контексту безпеки: - -Error copying file permissions: -Помилка при копіюванні прав доступу: - -Error creating directory: -Помилка при створенні каталогу: - -Error copying symbolic link: -Помилка при копіюванні символьного посилання: - -Error copying file: -Помилка при копіюванні файлу: - -Error opening file: -Помилка при відкриванні файлу: - -Error writing file: -Помилка при записі файлу: - -Error reading file: -Помилка при читанні файлу: - -Operation aborted! -Операція відмінена! - -Endless loop when traversing directory: -Зациклюванння при обході каталогу: - -Error traversing directory: -Помилка обходу каталогу: - -Error setting privilege: -Помилка встановлення привилеїв: - -Error moving to Recycle Bin: -Помилка переміщення в "Корзину": - -Could not load a required DLL: -Не вдалося завантажити необхідні DLL: - -Error writing to synchronization database: -Помилка при записі у базу данних синхронізації: - -Error accessing Volume Shadow Copy Service! -Помилка доступу до послуги Тіньового Копіювання Тому - -Making shadow copies on WOW64 is not supported. Please use FreeFileSync 64-bit version. -Створення тіньових копій на WOW64 не підтримується. Будь ласка, використайте FreeFileSync 64-розрядної версії. - -Could not determine volume name for file: -Не вдалося визначити назву тому для файлу: - -Volume name %x not part of filename %y! -Ім’я тому %x не є частиною імені файлу %y! - -%x TB -%x ТБ - -%x PB -%x ПБ - -%x% -%x% - - -1 min -%x min - - -%x хв -%x хв -%x хв - - - -1 hour -%x hours - - -%x година -%x години -%x годин - - - -1 day -%x days - - -%x день -%x дні -%x днів - - -Could not read values for the following XML nodes: -Не вдалося прочитати значення таких XML записів: - Logging Лог-файли @@ -483,9 +375,6 @@ The command line is executed each time: Batch execution Виконання пакетного завдання -Log-messages: -Лог-повідомлення: - Stop Стоп @@ -615,6 +504,24 @@ The command line is executed each time: Total amount of data that will be transferred Загальний об’єм даних, які будуть передаватися +Operation: +Операція: + +Items found: +Елементів знайдено: + +Items remaining: +Елементів залишилось: + +Speed: +Швидкість: + +Time remaining: +Залишилось часу: + +Time elapsed: +Пройшло часу: + Batch job Пакетне завдання @@ -663,32 +570,14 @@ The command line is executed each time: &Cancel &Відмінити -Operation: -Операція: - -Items found: -Елементів знайдено: - -Items remaining: -Елементів залишилось: - -Speed: -Швидкість: - -Time remaining: -Залишилось часу: - -Time elapsed: -Пройшло часу: - Select variant: Виберіть варіант: <Автоматичний> -Identify and propagate changes on both sides using a database. Deletions and conflicts are detected automatically. -Виявлення і поширення змін на обох сторінах з використанням бази даних. Вилучені файли і конфлікти визначаються автоматично. +Identify and propagate changes on both sides using a database. Deletions, renaming and conflicts are detected automatically. +Виявити та поширити зміни на обидві сторони використовуючи базу даних. Видалення, перейменування та конфлікти визначаються автоматично. Mirror ->> Дзеркало ->> @@ -911,22 +800,14 @@ Exclude: \stuff\temp\* Copy locked files Копіювати заблоковані файли - -Copy shared or locked files using Volume Shadow Copy Service (Requires Administrator rights) - - -Копіювати спільних чи заблокованих файлів з використанням послуги Тіньового Копіювання Тому (потрібні права Адміністратора) - +Copy shared or locked files using Volume Shadow Copy Service (Requires Administrator rights) +Копіювати спільних чи заблокованих файлів з використанням послуги Тіньового Копіювання Тому (потрібні права Адміністратора) Copy file access permissions Копіювати права доступу до файлу - -Transfer file and directory permissions (Requires Administrator rights) - - -Передача прав доступу файлу/каталогу (потрібні права Адміністратора) - +Transfer file and directory permissions (Requires Administrator rights) +Передача прав доступу файлу/каталогу (потрібні права Адміністратора) Hidden dialogs: Приховані діалоги @@ -958,6 +839,9 @@ Transfer file and directory permissions (Requires Administrator rights) &Find next &Знайти наступний +Operation aborted! +Операція відмінена! + Main bar Головна панель @@ -1135,6 +1019,9 @@ Transfer file and directory permissions (Requires Administrator rights) File list exported! Список файлів експортовано! +Error writing file: +Помилка при записі файлу: + Batch file created successfully! Файл завдання успішно створений! @@ -1238,9 +1125,6 @@ Transfer file and directory permissions (Requires Administrator rights) Filter: Single pair Фільтр: Одна пара -Ignore -Ігнорувати - Direct Прямо @@ -1306,6 +1190,108 @@ Transfer file and directory permissions (Requires Administrator rights) Move files into a time-stamped subdirectory Переміщати файли в підкатлог з часовою міткою +%x TB +%x ТБ + +%x PB +%x ПБ + +%x% +%x% + + +1 min +%x min + + +%x хв +%x хв +%x хв + + + +1 hour +%x hours + + +%x година +%x години +%x годин + + + +1 day +%x days + + +%x день +%x дні +%x днів + + +Could not initialize directory monitoring: +Не вдалося ініціювати каталог для моніторингу: + +Error when monitoring directories. +Помилка моніторингу каталогу. + +Conversion error: +Помилка перетворення: + +Error deleting file: +Помилка при вилученні файлу: + +Error moving file: +Помилка переміщення файлу: + +Target file already existing! +Кінцевий файл уже існує! + +Error moving directory: +Помилка переміщення каталогу: + +Target directory already existing! +Кінцевий каталог вже існує! + +Error deleting directory: +Помилка при вилученні каталогу: + +Error changing modification time: +Помилка при зміні часу модификації файлу: + +Error loading library function: +Помилка при завантаженні функції бібліотеки: + +Error reading security context: +Помилка при читанні контексту безпеки: + +Error writing security context: +Помилка при записі контексту безпеки: + +Error copying file permissions: +Помилка при копіюванні прав доступу: + +Error creating directory: +Помилка при створенні каталогу: + +Error copying symbolic link: +Помилка при копіюванні символьного посилання: + +Error copying file: +Помилка при копіюванні файлу: + +Error opening file: +Помилка при відкриванні файлу: + +Error traversing directory: +Помилка обходу каталогу: + +Endless loop when traversing directory: +Зациклюванння при обході каталогу: + +Error setting privilege: +Помилка встановлення привилеїв: + Both sides have changed since last synchronization! З моменту останньої синхронізації з обох сторін відбулися зміни! @@ -1339,9 +1325,6 @@ Transfer file and directory permissions (Requires Administrator rights) Directories are dependent! Be careful when setting up synchronization rules: Залежні каталоги! Будьте уважні при налаштуванні правил синхронізації: -Comparing content of files %x -Порівнювання вмісту файлів %x - Memory allocation failed! Помилка виділення пам’яті! (Не хватает памяти) @@ -1357,15 +1340,15 @@ Transfer file and directory permissions (Requires Administrator rights) Symlinks %x have the same date but a different target! Символьне посиланння %x має таку ж дату, але різний вміст! +Comparing content of files %x +Порівнювання вмісту файлів %x + Comparing files by content failed. Порівнювання файлів за вмістом не вдалося. Generating file list... Створення списку файлів... -Multiple... -Різні варіанти... - Both sides are equal Сторони ідентичні @@ -1384,6 +1367,12 @@ Transfer file and directory permissions (Requires Administrator rights) Delete right file/folder Вилучити файл/папку праворуч +Move file on left +Перемістити файли ліворуч + +Move file on right +Перемістити файли праворуч + Overwrite left file/folder with right one Перезаписати файл/папку ліворуч відповідником зправа @@ -1399,6 +1388,9 @@ Transfer file and directory permissions (Requires Administrator rights) Copy file attributes only to right Зкопіювати праворуч лише атрибути файлу +Multiple... +Різні варіанти... + Deleting file %x Вилучення файлу %x diff --git a/BUILD/Resources.zip b/BUILD/Resources.zip index d1f7ca37..9ad96f71 100644 Binary files a/BUILD/Resources.zip and b/BUILD/Resources.zip differ diff --git a/FreeFileSync.cbp b/FreeFileSync.cbp index 14c02576..a81cea63 100644 --- a/FreeFileSync.cbp +++ b/FreeFileSync.cbp @@ -23,7 +23,7 @@ - + @@ -50,7 +50,7 @@ - + @@ -77,7 +77,7 @@ - + diff --git a/RealtimeSync/RealtimeSync.cbp b/RealtimeSync/RealtimeSync.cbp index c842e6bb..1f6c8049 100644 --- a/RealtimeSync/RealtimeSync.cbp +++ b/RealtimeSync/RealtimeSync.cbp @@ -27,7 +27,7 @@ - + @@ -51,7 +51,7 @@ - + diff --git a/RealtimeSync/watcher.cpp b/RealtimeSync/watcher.cpp index 97ad480a..52dead7a 100644 --- a/RealtimeSync/watcher.cpp +++ b/RealtimeSync/watcher.cpp @@ -8,6 +8,7 @@ #include #include #include +#include #include #include "../lib/resolve_path.h" #include @@ -22,12 +23,14 @@ using namespace zen; bool rts::updateUiIsAllowed() { - static wxLongLong lastExec; - const wxLongLong newExec = wxGetLocalTimeMillis(); + const std::clock_t CLOCK_UPDATE_INTERVAL = UI_UPDATE_INTERVAL * CLOCKS_PER_SEC / 1000; - if (newExec - lastExec >= rts::UI_UPDATE_INTERVAL) //perform ui updates not more often than necessary + static std::clock_t lastExec = 0; + const std::clock_t now = std::clock(); //this is quite fast: 2 * 10^-5 + + if (now - lastExec >= CLOCK_UPDATE_INTERVAL) //perform ui updates not more often than necessary { - lastExec = newExec; + lastExec = now; return true; } return false; @@ -105,7 +108,7 @@ rts::WaitResult rts::waitForChanges(const std::vector& dirNamesNonFmt, try { - std::vector changedFiles = watcher.getChanges(); //throw FileError, ErrorNotExisting + std::vector changedFiles = watcher.getChanges([&] { statusHandler->requestUiRefresh(); }); //throw FileError, ErrorNotExisting //remove to be ignored changes vector_remove_if(changedFiles, [](const Zstring& name) diff --git a/algorithm.cpp b/algorithm.cpp index 7c6dc5d9..9a3b46f0 100644 --- a/algorithm.cpp +++ b/algorithm.cpp @@ -7,6 +7,7 @@ #include "algorithm.h" #include #include +#include #include "lib/resources.h" #include #include "lib/recycler.h" @@ -34,9 +35,15 @@ void zen::swapGrids(const MainConfiguration& config, FolderComparison& folderCmp class Redetermine { public: + static void execute(const DirectionSet& dirCfgIn, HierarchyObject& hierObj) + { + Redetermine(dirCfgIn).recurse(hierObj); + } + +private: Redetermine(const DirectionSet& dirCfgIn) : dirCfg(dirCfgIn) {} - void execute(HierarchyObject& hierObj) const + void recurse(HierarchyObject& hierObj) const { std::for_each(hierObj.refSubFiles().begin(), hierObj.refSubFiles().end(), [&](FileMapping& fileMap) { (*this)(fileMap); }); std::for_each(hierObj.refSubLinks().begin(), hierObj.refSubLinks().end(), [&](SymLinkMapping& linkMap) { (*this)(linkMap); }); @@ -136,11 +143,9 @@ public: break; } - //recursion - execute(dirObj); + recurse(dirObj); } -private: const DirectionSet dirCfg; }; @@ -242,6 +247,8 @@ private: Zstring shortName; //empty if object not existing zen::Int64 lastWriteTime; zen::UInt64 fileSize; + + //note: we do *not* consider FileId here, but are only interested in *visual* changes. Consider user moving data to some other medium, this is not a change! }; @@ -392,6 +399,12 @@ std::pair retrieveDataSetDir(const Zstring& obj class RedetermineAuto { public: + static void execute(BaseDirMapping& baseDirectory, DeterminationProblem* handler) + { + RedetermineAuto(baseDirectory, handler); + } + +private: RedetermineAuto(BaseDirMapping& baseDirectory, DeterminationProblem* handler) : txtBothSidesChanged(_("Both sides have changed since last synchronization!")), @@ -411,7 +424,7 @@ public: //set conservative "two-way" directions DirectionSet twoWayCfg = getTwoWaySet(); - Redetermine(twoWayCfg).execute(baseDirectory); + Redetermine::execute(twoWayCfg, baseDirectory); return; } @@ -428,13 +441,20 @@ public: if (respectFiltering(baseDirectory, dirInfoRight)) dbFilterRight = dirInfoRight.filter.get(); */ - execute(baseDirectory, + recurse(baseDirectory, &dirInfoLeft.baseDirContainer, &dirInfoRight.baseDirContainer); - } + //----------- detect renamed files ----------------- + if (!exLeftOnly.empty() && !exRightOnly.empty()) + { + findEqualDbEntries(dirInfoLeft.baseDirContainer, //fill map "onceEqual" + dirInfoRight.baseDirContainer); + + detectRenamedFiles(); + } + } -private: /* static bool respectFiltering(const BaseDirMapping& baseDirectory, const DirInformation& dirInfo) { @@ -454,7 +474,7 @@ private: catch (FileErrorDatabaseNotExisting&) {} //let's ignore these errors for now... catch (FileError& error) //e.g. incompatible database version { - if (handler_) handler_->reportWarning(error.toString() + wxT(" \n\n") + + if (handler_) handler_->reportWarning(error.toString() + L" \n\n" + _("Setting default synchronization directions: Old files will be overwritten with newer files.")); } return std::pair(); //NULL @@ -477,7 +497,7 @@ private: } */ - void execute(HierarchyObject& hierObj, + void recurse(HierarchyObject& hierObj, const DirContainer* dbDirectoryLeft, const DirContainer* dbDirectoryRight) { @@ -499,6 +519,18 @@ private: if (cat == FILE_EQUAL) return; + //----------------- prepare detection of renamed files ----------------- + if (cat == FILE_LEFT_SIDE_ONLY) + { + if (fileObj.getFileId() != FileId()) + exLeftOnly.push_back(&fileObj); + } + else if (cat == FILE_RIGHT_SIDE_ONLY) + { + if (fileObj.getFileId() != FileId()) + exRightOnly.insert(std::make_pair(getAssocKey(fileObj), &fileObj)); + } + //---------------------------------------------------------------------- //##################### schedule potentially existing temporary files for deletion #################### if (cat == FILE_LEFT_SIDE_ONLY && endsWith(fileObj.getFullName(), zen::TEMP_FILE_ENDING)) @@ -530,14 +562,14 @@ private: const DataSetFile dataDbLeft = retrieveDataSetFile(fileObj.getObjShortName(), dbDirectoryLeft); const DataSetFile dataDbRight = retrieveDataSetFile(fileObj.getObjShortName(), dbDirectoryRight); - const DataSetFile dataCurrentLeft( fileObj, Int2Type()); + const DataSetFile dataCurrentLeft (fileObj, Int2Type()); const DataSetFile dataCurrentRight(fileObj, Int2Type()); //evaluation const bool changeOnLeft = dataDbLeft != dataCurrentLeft; const bool changeOnRight = dataDbRight != dataCurrentRight; - if (dataDbLeft == dataDbRight) //last sync seems to have been successful + if (dataDbLeft == dataDbRight) //we have a "last synchronous state" => last sync seems to have been successful { if (changeOnLeft) { @@ -651,7 +683,7 @@ private: ; } - SetDirChangedFilter().execute(dirObj); //filter issue for this directory => treat subfiles/-dirs the same + SetDirChangedFilter().recurse(dirObj); //filter issue for this directory => treat subfiles/-dirs the same return; } */ @@ -711,18 +743,133 @@ private: } } - execute(dirObj, dataDbLeftStuff.second, dataDbRightStuff.second); //recursion + recurse(dirObj, dataDbLeftStuff.second, dataDbRightStuff.second); //recursion } + + void findEqualDbEntries(const DirContainer& dbDirectoryLeft, + const DirContainer& dbDirectoryRight) + { + //note: we cannot integrate this traversal into "recurse()" since it may take a *slightly* different path: e.g. file renamed on both sides + + std::for_each(dbDirectoryLeft.files.begin(), dbDirectoryLeft.files.end(), + [&](const DirContainer::FileList::value_type& entryLeft) + { + auto iterRight = dbDirectoryRight.files.find(entryLeft.first); + if (iterRight != dbDirectoryRight.files.end()) + { + if (entryLeft. second.id != FileId() && + iterRight->second.id != FileId() && + DataSetFile(entryLeft.first, entryLeft.second) == DataSetFile(iterRight->first, iterRight->second)) + onceEqual.insert(std::make_pair(getAssocKey(entryLeft.second), getAssocKey(iterRight->second))); + } + }); + + std::for_each(dbDirectoryLeft.dirs.begin(), dbDirectoryLeft.dirs.end(), + [&](const DirContainer::DirList::value_type& entryLeft) + { + auto iterRight = dbDirectoryRight.dirs.find(entryLeft.first); + if (iterRight != dbDirectoryRight.dirs.end()) + findEqualDbEntries(entryLeft.second, iterRight->second); + }); + } + + typedef std::tuple AssocKey; //(date, size, file ID) + + + //modification date is *not* considered as part of container key, so check here! + template + static typename Container::const_iterator findValue(const Container& cnt, const AssocKey& key) + { + auto iterPair = cnt.equal_range(key); //since file id is already unique, we expect a single-element range at most + auto iter = std::find_if(iterPair.first, iterPair.second, + [&](const typename Container::value_type& item) + { + return sameFileTime(std::get<0>(item.first), std::get<0>(key), 2); //respect 2 second FAT/FAT32 precision + }); + return iter == iterPair.second ? cnt.end() : iter; + } + + void detectRenamedFiles() const + { + std::for_each(exLeftOnly.begin(), exLeftOnly.end(), + [&](FileMapping* fileLeftOnly) + { + const AssocKey& keyLeft = RedetermineAuto::getAssocKey(*fileLeftOnly); + + auto iter = findValue(onceEqual, keyLeft); + if (iter != onceEqual.end()) + { + const AssocKey& keyRight = iter->second; + + auto iter2 = findValue(exRightOnly, keyRight); + if (iter2 != exRightOnly.end()) + { + FileMapping* fileRightOnly = iter2->second; + + //found a pair, mark it! + fileLeftOnly ->setMoveRef(fileRightOnly->getId()); + fileRightOnly->setMoveRef(fileLeftOnly ->getId()); + } + } + }); + } + + const std::wstring txtBothSidesChanged; const std::wstring txtNoSideChanged; const std::wstring txtFilterChanged; const std::wstring txtLastSyncFail; - //const HardFilter* dbFilterLeft; //optional - //const HardFilter* dbFilterRight; //optional - DeterminationProblem* const handler_; + + //detection of renamed files + template + static AssocKey getAssocKey(const FileMapping& fsObj) { return std::make_tuple(fsObj.getLastWriteTime(), fsObj.getFileSize(), fsObj.getFileId()); } + static AssocKey getAssocKey(const FileDescriptor& fileDescr) { return std::make_tuple(fileDescr.lastWriteTimeRaw, fileDescr.fileSize, fileDescr.id); } + + struct LessAssocKey + { + bool operator()(const AssocKey& lhs, const AssocKey& rhs) const + { + //caveat: *don't* allow 2 sec tolerance as container predicate!! + // => no strict weak ordering relation! reason: no transitivity of equivalence! + + //-> bad: if (!sameFileTime(std::get<0>(lhs), std::get<0>(rhs), 2)) + // return std::get<0>(lhs) < std::get<0>(rhs); + + if (std::get<1>(lhs) != std::get<1>(rhs)) //file size + return std::get<1>(lhs) < std::get<1>(rhs); + + return std::get<2>(lhs) < std::get<2>(rhs); //file id + } + }; + + std::vector exLeftOnly; + + std::multimap onceEqual; //keys for left and right files which are considered "equal" by database + + std::multimap exRightOnly; + + /* + detect renamed files + + X -> |_| Create right + |_| -> Y Delete right + + is detected as: + + Rename Y to X on right + + Algorithm: + ---------- + DB-file left --- name, size, date ---> DB-file right + /|\ | + | file ID, size, date + file ID, size, date | + | \|/ + X Y + */ }; @@ -750,11 +897,11 @@ std::vector zen::extractDirectionCfg(const MainConfiguration& m void zen::redetermineSyncDirection(const DirectionConfig& directConfig, BaseDirMapping& baseDirectory, DeterminationProblem* handler) { if (directConfig.var == DirectionConfig::AUTOMATIC) - RedetermineAuto(baseDirectory, handler); + RedetermineAuto::execute(baseDirectory, handler); else { DirectionSet dirCfg = extractDirections(directConfig); - Redetermine(dirCfg).execute(baseDirectory); + Redetermine::execute(dirCfg, baseDirectory); } } diff --git a/algorithm.h b/algorithm.h index 6eb9f24d..96ff6b1a 100644 --- a/algorithm.h +++ b/algorithm.h @@ -17,7 +17,7 @@ void swapGrids(const MainConfiguration& config, FolderComparison& folderCmp); struct DeterminationProblem //callback { virtual ~DeterminationProblem() {} - virtual void reportWarning(const wxString& text) = 0; + virtual void reportWarning(const std::wstring& text) = 0; }; std::vector extractDirectionCfg(const MainConfiguration& mainCfg); @@ -56,7 +56,7 @@ public: IGNORE_ERROR = 10, RETRY }; - virtual Response reportError(const wxString& errorMessage) = 0; + virtual Response reportError(const std::wstring& errorMessage) = 0; //virtual void totalFilesToDelete(int objectsTotal) = 0; //informs about the total number of files to be deleted virtual void notifyDeletion(const Zstring& currentObject) = 0; //called for each file/folder that has been deleted diff --git a/comparison.cpp b/comparison.cpp index 79b18ae9..f66c291e 100644 --- a/comparison.cpp +++ b/comparison.cpp @@ -5,16 +5,16 @@ // ************************************************************************** #include "comparison.h" +#include +#include +#include +#include #include "lib/parallel_scan.h" #include "lib/resolve_path.h" -#include #include "lib/dir_exist_async.h" -#include -#include #include "lib/binary.h" -#include "algorithm.h" -#include #include "lib/cmp_filetime.h" +#include "algorithm.h" #ifdef FFS_WIN #include @@ -120,39 +120,33 @@ void checkDirectoryExistence(const std::set& dirnames, } -namespace -{ -struct EqualDependentDirectory : public std::binary_function -{ - bool operator()(const Zstring& lhs, const Zstring& rhs) const - { - return EqualFilename()(Zstring(lhs.c_str(), std::min(lhs.length(), rhs.length())), - Zstring(rhs.c_str(), std::min(lhs.length(), rhs.length()))); - } -}; -} - //check whether one side is subdirectory of other side (folder pair wise!) //similar check if one directory is read/written by multiple pairs not before beginning of synchronization -wxString checkFolderDependency(const std::vector& folderPairsForm) //returns warning message, empty if all ok +std::wstring checkFolderDependency(const std::vector& folderPairsForm) //returns warning message, empty if all ok { - typedef std::vector > DirDirList; + typedef std::vector > DirDirList; DirDirList dependentDirs; + auto dependentDir = [](const Zstring& lhs, const Zstring& rhs) + { + return EqualFilename()(Zstring(lhs.c_str(), std::min(lhs.length(), rhs.length())), //note: this is NOT an equivalence relation! + Zstring(rhs.c_str(), std::min(lhs.length(), rhs.length()))); + }; + for (std::vector::const_iterator i = folderPairsForm.begin(); i != folderPairsForm.end(); ++i) if (!i->leftDirectoryFmt.empty() && !i->rightDirectoryFmt.empty()) //empty folders names may be accepted by user { - if (EqualDependentDirectory()(i->leftDirectoryFmt, i->rightDirectoryFmt)) //test wheter leftDirectory begins with rightDirectory or the other way round - dependentDirs.push_back(std::make_pair(toWx(i->leftDirectoryFmt), toWx(i->rightDirectoryFmt))); + if (dependentDir(i->leftDirectoryFmt, i->rightDirectoryFmt)) //test wheter leftDirectory begins with rightDirectory or the other way round + dependentDirs.push_back(std::make_pair(utf8CvrtTo(i->leftDirectoryFmt), utf8CvrtTo(i->rightDirectoryFmt))); } - wxString warningMsg; + std::wstring warningMsg; if (!dependentDirs.empty()) { warningMsg = _("Directories are dependent! Be careful when setting up synchronization rules:"); for (auto i = dependentDirs.begin(); i != dependentDirs.end(); ++i) - warningMsg += wxString(L"\n\n") + + warningMsg += std::wstring(L"\n\n") + L"\"" + i->first + L"\"\n" + L"\"" + i->second + L"\""; } @@ -214,17 +208,17 @@ CompareProcess::CompareProcess(size_t fileTimeTol, m_warnings(warnings), allowUserInteraction_(allowUserInteraction), procCallback(handler) - { -if (runWithBackgroundPriority) -procBackground.reset(new ScheduleForBackgroundProcessing); - } +{ + if (runWithBackgroundPriority) + procBackground.reset(new ScheduleForBackgroundProcessing); +} void CompareProcess::startCompareProcess(const std::vector& cfgList, FolderComparison& output) { - //prevent shutdown while (binary) comparison is in progress - DisableStandby dummy2; - (void)dummy2; + //prevent shutdown while (binary) comparison is in progress + PreventStandby dummy2; + (void)dummy2; /* #ifdef NDEBUG @@ -257,9 +251,9 @@ void CompareProcess::startCompareProcess(const std::vector& cfgLi { //check if folders have dependencies - wxString warningMessage = checkFolderDependency(cfgList); + std::wstring warningMessage = checkFolderDependency(cfgList); if (!warningMessage.empty()) - procCallback.reportWarning(warningMessage.c_str(), m_warnings.warningDependentFolders); + procCallback.reportWarning(warningMessage, m_warnings.warningDependentFolders); } //-------------------end of basic checks------------------------------------------ @@ -364,7 +358,7 @@ void CompareProcess::startCompareProcess(const std::vector& cfgLi warningSyncDatabase_(warningSyncDatabase), procCallback_(procCallback) {} - virtual void reportWarning(const wxString& text) + virtual void reportWarning(const std::wstring& text) { procCallback_.reportWarning(text, warningSyncDatabase_); } @@ -404,25 +398,14 @@ std::wstring getConflictInvalidDate(const Zstring& fileNameFull, Int64 utcTime) namespace { -inline -void makeSameLength(wxString& first, wxString& second) -{ - const size_t maxPref = std::max(first.length(), second.length()); - first.Pad(maxPref - first.length(), wxT(' '), true); - second.Pad(maxPref - second.length(), wxT(' '), true); -} - - //check for changed files with same modification date std::wstring getConflictSameDateDiffSize(const FileMapping& fileObj) { std::wstring msg = _("Files %x have the same date but a different size!"); replace(msg, L"%x", std::wstring(L"\"") + fileObj.getRelativeName() + L"\""); msg += L"\n\n"; - msg += L"<-- \t" + _("Date") + L": " + utcToLocalTimeString(fileObj.getLastWriteTime()) + - L" \t" + _("Size") + L": " + toStringSep(fileObj.getFileSize()) + L"\n"; - msg += L"--> \t" + _("Date") + L": " + utcToLocalTimeString(fileObj.getLastWriteTime()) + - L" \t" + _("Size") + L": " + toStringSep(fileObj.getFileSize()); + msg += L"<-- " + _("Date") + L": " + utcToLocalTimeString(fileObj.getLastWriteTime()) + L" " + _("Size") + L": " + toStringSep(fileObj.getFileSize()) + L"\n"; + msg += L"--> " + _("Date") + L": " + utcToLocalTimeString(fileObj.getLastWriteTime()) + L" " + _("Size") + L": " + toStringSep(fileObj.getFileSize()); return _("Conflict detected:") + L"\n" + msg; } } @@ -625,7 +608,7 @@ void CompareProcess::compareByContent(std::vector -void MergeSides::fillOneSide(const DirContainer& dirCont, HierarchyObject& output) -{ - for (DirContainer::FileList::const_iterator i = dirCont.files.begin(); i != dirCont.files.end(); ++i) - output.addSubFile(i->second, i->first); - - for (DirContainer::LinkList::const_iterator i = dirCont.links.begin(); i != dirCont.links.end(); ++i) - output.addSubLink(i->second, i->first); - - for (DirContainer::DirList::const_iterator i = dirCont.dirs.begin(); i != dirCont.dirs.end(); ++i) - { - DirMapping& newDirMap = output.addSubDir(i->first, Zstring()); - fillOneSide(i->second, newDirMap); //recurse into subdirectories - } -} - - -template <> -void MergeSides::fillOneSide(const DirContainer& dirCont, HierarchyObject& output) +template +void MergeSides::fillOneSide(const DirContainer& dirCont, HierarchyObject& output) { - for (DirContainer::FileList::const_iterator i = dirCont.files.begin(); i != dirCont.files.end(); ++i) - output.addSubFile(i->first, i->second); + for (auto iter = dirCont.files.cbegin(); iter != dirCont.files.cend(); ++iter) + output.addSubFile(iter->first, iter->second); - for (DirContainer::LinkList::const_iterator i = dirCont.links.begin(); i != dirCont.links.end(); ++i) - output.addSubLink(i->first, i->second); + for (auto iter = dirCont.links.cbegin(); iter != dirCont.links.cend(); ++iter) + output.addSubLink(iter->first, iter->second); - for (DirContainer::DirList::const_iterator i = dirCont.dirs.begin(); i != dirCont.dirs.end(); ++i) + for (auto iter = dirCont.dirs.cbegin(); iter != dirCont.dirs.cend(); ++iter) { - DirMapping& newDirMap = output.addSubDir(Zstring(), i->first); - fillOneSide(i->second, newDirMap); //recurse into subdirectories + DirMapping& newDirMap = output.addSubDir(iter->first); + fillOneSide(iter->second, newDirMap); //recurse } } @@ -777,8 +743,8 @@ void MergeSides::execute(const DirContainer& leftSide, const DirContainer& right typedef const DirContainer::FileList::value_type FileData; linearMerge(leftSide.files, rightSide.files, - [&](const FileData& fileLeft) { output.addSubFile(fileLeft.second, fileLeft.first); }, //left only - [&](const FileData& fileRight) { output.addSubFile(fileRight.first, fileRight.second); }, //right only + [&](const FileData& fileLeft) { output.addSubFile (fileLeft.first, fileLeft.second); }, //left only + [&](const FileData& fileRight) { output.addSubFile(fileRight.first, fileRight.second); }, //right only [&](const FileData& fileLeft, const FileData& fileRight) //both sides { @@ -794,8 +760,8 @@ void MergeSides::execute(const DirContainer& leftSide, const DirContainer& right typedef const DirContainer::LinkList::value_type LinkData; linearMerge(leftSide.links, rightSide.links, - [&](const LinkData& linkLeft) { output.addSubLink(linkLeft.second, linkLeft.first); }, //left only - [&](const LinkData& linkRight) { output.addSubLink(linkRight.first, linkRight.second); }, //right only + [&](const LinkData& linkLeft) { output.addSubLink(linkLeft.first, linkLeft.second); }, //left only + [&](const LinkData& linkRight) { output.addSubLink(linkRight.first, linkRight.second); }, //right only [&](const LinkData& linkLeft, const LinkData& linkRight) //both sides { @@ -813,12 +779,12 @@ void MergeSides::execute(const DirContainer& leftSide, const DirContainer& right linearMerge(leftSide.dirs, rightSide.dirs, [&](const DirData& dirLeft) //left only { - DirMapping& newDirMap = output.addSubDir(dirLeft.first, Zstring()); + DirMapping& newDirMap = output.addSubDir(dirLeft.first); this->fillOneSide(dirLeft.second, newDirMap); //recurse into subdirectories }, [&](const DirData& dirRight) //right only { - DirMapping& newDirMap = output.addSubDir(Zstring(), dirRight.first); + DirMapping& newDirMap = output.addSubDir(dirRight.first); this->fillOneSide(dirRight.second, newDirMap); //recurse into subdirectories }, @@ -839,7 +805,7 @@ void processFilteredDirs(HierarchyObject& hierObj, const HardFilter& filterProc) std::for_each(subDirs.begin(), subDirs.end(), [&](DirMapping& dirObj) { - dirObj.setActive(filterProc.passDirFilter(dirObj.getObjRelativeName().c_str(), NULL)); //subObjMightMatch is always true in this context! + dirObj.setActive(filterProc.passDirFilter(dirObj.getObjRelativeName(), NULL)); //subObjMightMatch is always true in this context! processFilteredDirs(dirObj, filterProc); }); @@ -878,7 +844,6 @@ void CompareProcess::performComparison(const FolderPairCfg& fpCfg, const DirectoryValue& bufValueRight = getDirValue(fpCfg.rightDirectoryFmt); procCallback.reportStatus(_("Generating file list...")); - procCallback.forceUiRefresh(); //keep total number of scanned files up to date //PERF_START; MergeSides(undefinedFiles, undefinedLinks).execute(bufValueLeft.dirCont, bufValueRight.dirCont, output); diff --git a/comparison.h b/comparison.h index 3928f44e..f3226e90 100644 --- a/comparison.h +++ b/comparison.h @@ -7,11 +7,11 @@ #ifndef COMPARISON_H_INCLUDED #define COMPARISON_H_INCLUDED +#include #include "file_hierarchy.h" #include "lib/process_xml.h" #include "lib/status_handler.h" #include "structures.h" -#include #include "lib/norm_filter.h" #include "lib/parallel_scan.h" diff --git a/file_hierarchy.cpp b/file_hierarchy.cpp index cfe1b6a0..39b789fd 100644 --- a/file_hierarchy.cpp +++ b/file_hierarchy.cpp @@ -5,6 +5,8 @@ // ************************************************************************** #include "file_hierarchy.h" +#include +#include using namespace zen; @@ -31,12 +33,12 @@ void HierarchyObject::removeEmptyRec() std::for_each(refSubDirs().begin(), refSubDirs().end(), std::mem_fun_ref(&HierarchyObject::removeEmptyRec)); } - -SyncOperation FileSystemObject::getSyncOperation( - CompareFilesResult cmpResult, - bool selectedForSynchronization, - SyncDirection syncDir, - const std::wstring& syncDirConflict) +namespace +{ +SyncOperation proposedSyncOperation(CompareFilesResult cmpResult, + bool selectedForSynchronization, + SyncDirection syncDir, + const std::wstring& syncDirConflict) { if (!selectedForSynchronization) return cmpResult == FILE_EQUAL ? @@ -105,8 +107,6 @@ SyncOperation FileSystemObject::getSyncOperation( } -namespace -{ template inline bool hasDirectChild(const HierarchyObject& hierObj, Predicate p) { @@ -117,6 +117,22 @@ bool hasDirectChild(const HierarchyObject& hierObj, Predicate p) } +SyncOperation FileSystemObject::testSyncOperation(SyncDirection testSyncDir) const +{ + return proposedSyncOperation(getCategory(), selectedForSynchronization, testSyncDir, syncDirConflict); +} + + +SyncOperation FileSystemObject::getSyncOperation() const +{ + return FileSystemObject::testSyncOperation(syncDir); + //no *not* make a virtual call to testSyncOperation()! See FileMapping::testSyncOperation()! +} + + +//SyncOperation DirMapping::testSyncOperation() const -> not required: we do NOT want to consider child elements when testing! + + SyncOperation DirMapping::getSyncOperation() const { if (!syncOpUpToDate) @@ -124,7 +140,7 @@ SyncOperation DirMapping::getSyncOperation() const syncOpUpToDate = true; //redetermine... - //suggested operation for directory only + //suggested operation *not* considering child elements syncOpBuffered = FileSystemObject::getSyncOperation(); //action for child elements may occassionally have to overwrite parent task: @@ -132,6 +148,10 @@ SyncOperation DirMapping::getSyncOperation() const { case SO_OVERWRITE_LEFT: case SO_OVERWRITE_RIGHT: + case SO_MOVE_LEFT_SOURCE: + case SO_MOVE_LEFT_TARGET: + case SO_MOVE_RIGHT_SOURCE: + case SO_MOVE_RIGHT_TARGET: assert(false); case SO_CREATE_NEW_LEFT: case SO_CREATE_NEW_RIGHT: @@ -149,19 +169,32 @@ SyncOperation DirMapping::getSyncOperation() const //1. if at least one child-element is to be created, make sure parent folder is created also //note: this automatically fulfills "create parent folders even if excluded"; //see http://sourceforge.net/tracker/index.php?func=detail&aid=2628943&group_id=234430&atid=1093080 - if (hasDirectChild(*this, [](const FileSystemObject& fsObj) { return fsObj.getSyncOperation() == SO_CREATE_NEW_LEFT; })) - syncOpBuffered = SO_CREATE_NEW_LEFT; + if (hasDirectChild(*this, + [](const FileSystemObject& fsObj) -> bool { const SyncOperation op = fsObj.getSyncOperation(); return op == SO_CREATE_NEW_LEFT || op == SO_MOVE_LEFT_TARGET; })) + syncOpBuffered = SO_CREATE_NEW_LEFT; //2. cancel parent deletion if only a single child is not also scheduled for deletion else if (syncOpBuffered == SO_DELETE_RIGHT && - hasDirectChild(*this, [](const FileSystemObject& fsObj) { return fsObj.getSyncOperation() != SO_DELETE_RIGHT; })) + hasDirectChild(*this, + [](const FileSystemObject& fsObj) -> bool + { + if (fsObj.isEmpty()) return false; //fsObj may already be empty because it once contained a "move source" + const SyncOperation op = fsObj.getSyncOperation(); return op != SO_DELETE_RIGHT && op != SO_MOVE_RIGHT_SOURCE; + })) syncOpBuffered = SO_DO_NOTHING; } else if (isEmpty()) { - if (hasDirectChild(*this, [](const FileSystemObject& fsObj) { return fsObj.getSyncOperation() == SO_CREATE_NEW_RIGHT; })) - syncOpBuffered = SO_CREATE_NEW_RIGHT; + if (hasDirectChild(*this, + [](const FileSystemObject& fsObj) -> bool { const SyncOperation op = fsObj.getSyncOperation(); return op == SO_CREATE_NEW_RIGHT || op == SO_MOVE_RIGHT_TARGET; })) + syncOpBuffered = SO_CREATE_NEW_RIGHT; else if (syncOpBuffered == SO_DELETE_LEFT && - hasDirectChild(*this, [](const FileSystemObject& fsObj) { return fsObj.getSyncOperation() != SO_DELETE_LEFT; })) + hasDirectChild(*this, + [](const FileSystemObject& fsObj) -> bool + { + if (fsObj.isEmpty()) return false; + const SyncOperation op = fsObj.getSyncOperation(); + return op != SO_DELETE_LEFT && op != SO_MOVE_LEFT_SOURCE; + })) syncOpBuffered = SO_DO_NOTHING; } } @@ -170,3 +203,167 @@ SyncOperation DirMapping::getSyncOperation() const } return syncOpBuffered; } + + +SyncOperation FileMapping::testSyncOperation(SyncDirection testSyncDir) const +{ + SyncOperation op = FileSystemObject::testSyncOperation(testSyncDir); + + /* + check whether we can optimize "create + delete" via "move": + note: as long as we consider "create + delete" cases only, detection of renamed files, should be fine even for "binary" comparison variant! + */ + if (const FileMapping* refFile = dynamic_cast(FileSystemObject::retrieve(moveFileRef))) + { + SyncOperation opRef = refFile->FileSystemObject::getSyncOperation(); //do *not* make a virtual call! + + if (op == SO_CREATE_NEW_LEFT && + opRef == SO_DELETE_LEFT) + op = SO_MOVE_LEFT_TARGET; + else if (op == SO_DELETE_LEFT && + opRef == SO_CREATE_NEW_LEFT) + op = SO_MOVE_LEFT_SOURCE; + else if (op == SO_CREATE_NEW_RIGHT && + opRef == SO_DELETE_RIGHT) + op = SO_MOVE_RIGHT_TARGET; + else if (op == SO_DELETE_RIGHT && + opRef == SO_CREATE_NEW_RIGHT) + op = SO_MOVE_RIGHT_SOURCE; + } + return op; +} + + +SyncOperation FileMapping::getSyncOperation() const +{ + return FileMapping::testSyncOperation(getSyncDir()); +} + + +std::wstring zen::getCategoryDescription(CompareFilesResult cmpRes) +{ + switch (cmpRes) + { + case FILE_LEFT_SIDE_ONLY: + return _("File/folder exists on left side only"); + case FILE_RIGHT_SIDE_ONLY: + return _("File/folder exists on right side only"); + case FILE_LEFT_NEWER: + return _("Left file is newer"); + case FILE_RIGHT_NEWER: + return _("Right file is newer"); + case FILE_DIFFERENT: + return _("Files have different content"); + case FILE_EQUAL: + return _("Both sides are equal"); + case FILE_DIFFERENT_METADATA: + return _("Files/folders differ in attributes only"); + case FILE_CONFLICT: + return _("Conflict/file cannot be categorized"); + } + assert(false); + return std::wstring(); +} + + +std::wstring zen::getCategoryDescription(const FileSystemObject& fsObj) +{ + const CompareFilesResult cmpRes = fsObj.getCategory(); + if (cmpRes == FILE_CONFLICT) + return fsObj.getCatConflict(); + + return getCategoryDescription(cmpRes); +} + + +std::wstring zen::getSyncOpDescription(SyncOperation op) +{ + switch (op) + { + case SO_CREATE_NEW_LEFT: + return _("Copy new file/folder to left"); + case SO_CREATE_NEW_RIGHT: + return _("Copy new file/folder to right"); + case SO_DELETE_LEFT: + return _("Delete left file/folder"); + case SO_DELETE_RIGHT: + return _("Delete right file/folder"); + case SO_MOVE_LEFT_SOURCE: + case SO_MOVE_LEFT_TARGET: + return _("Move file on left"); + case SO_MOVE_RIGHT_SOURCE: + case SO_MOVE_RIGHT_TARGET: + return _("Move file on right"); + case SO_OVERWRITE_LEFT: + return _("Overwrite left file/folder with right one"); + case SO_OVERWRITE_RIGHT: + return _("Overwrite right file/folder with left one"); + case SO_DO_NOTHING: + return _("Do nothing"); + case SO_EQUAL: + return _("Both sides are equal"); + case SO_COPY_METADATA_TO_LEFT: + return _("Copy file attributes only to left"); + case SO_COPY_METADATA_TO_RIGHT: + return _("Copy file attributes only to right"); + case SO_UNRESOLVED_CONFLICT: //not used on GUI, but in .csv + _("Conflict/file cannot be categorized"); + } + assert(false); + return std::wstring(); +} + + +std::wstring zen::getSyncOpDescription(const FileSystemObject& fsObj) +{ + const SyncOperation op = fsObj.getSyncOperation(); + switch (op) + { + case SO_CREATE_NEW_LEFT: + case SO_CREATE_NEW_RIGHT: + case SO_DELETE_LEFT: + case SO_DELETE_RIGHT: + case SO_OVERWRITE_LEFT: + case SO_OVERWRITE_RIGHT: + case SO_DO_NOTHING: + case SO_EQUAL: + case SO_COPY_METADATA_TO_LEFT: + case SO_COPY_METADATA_TO_RIGHT: + return getSyncOpDescription(op); //use generic description + + case SO_MOVE_LEFT_SOURCE: + case SO_MOVE_LEFT_TARGET: + case SO_MOVE_RIGHT_SOURCE: + case SO_MOVE_RIGHT_TARGET: + if (const FileMapping* sourceFile = dynamic_cast(&fsObj)) + if (const FileMapping* targetFile = dynamic_cast(FileSystemObject::retrieve(sourceFile->getMoveRef()))) + { + const bool onLeft = op == SO_MOVE_LEFT_SOURCE || op == SO_MOVE_LEFT_TARGET; + const bool isSource = op == SO_MOVE_LEFT_SOURCE || op == SO_MOVE_RIGHT_SOURCE; + + if (!isSource) + std::swap(sourceFile, targetFile); + + auto getRelName = [&](const FileSystemObject& fso, bool leftSide) { return leftSide ? fso.getRelativeName() : fso.getRelativeName(); }; + + const Zstring relSource = getRelName(*sourceFile, onLeft); + const Zstring relTarget = getRelName(*targetFile, !onLeft); + + return getSyncOpDescription(op) + L"\n" + + (EqualFilename()(beforeLast(relSource, FILE_NAME_SEPARATOR), beforeLast(relTarget, FILE_NAME_SEPARATOR)) ? //returns empty string if ch not found + //detected pure "rename" + L"\"" + utf8CvrtTo(afterLast(relSource, FILE_NAME_SEPARATOR)) + L"\"" + L" ->\n" + //show short name only + L"\"" + utf8CvrtTo(afterLast(relTarget, FILE_NAME_SEPARATOR)) + L"\"" : + //"move" or "move + rename" + L"\"" + utf8CvrtTo(relSource) + L"\"" + L" ->\n" + + L"\"" + utf8CvrtTo(relTarget) + L"\""); + //attention: ::SetWindowText() doesn't handle tab characters correctly in combination with certain file names, so don't use them + } + break; + case SO_UNRESOLVED_CONFLICT: + return fsObj.getSyncOpConflict(); + } + + assert(false); + return std::wstring(); +} diff --git a/file_hierarchy.h b/file_hierarchy.h index 6ea9d244..cfa71ab2 100644 --- a/file_hierarchy.h +++ b/file_hierarchy.h @@ -15,6 +15,7 @@ #include #include "structures.h" #include +#include #include "structures.h" #include "lib/hard_filter.h" @@ -24,13 +25,16 @@ namespace zen struct FileDescriptor { FileDescriptor() {} - FileDescriptor(zen::Int64 lastWriteTimeRawIn, - zen::UInt64 fileSizeIn) : + FileDescriptor(Int64 lastWriteTimeRawIn, + UInt64 fileSizeIn, + const FileId& idIn) : lastWriteTimeRaw(lastWriteTimeRawIn), - fileSize(fileSizeIn) {} + fileSize(fileSizeIn), + id(idIn) {} - zen::Int64 lastWriteTimeRaw; //number of seconds since Jan. 1st 1970 UTC, same semantics like time_t (== signed long) - zen::UInt64 fileSize; + Int64 lastWriteTimeRaw; //number of seconds since Jan. 1st 1970 UTC, same semantics like time_t (== signed long) + UInt64 fileSize; + FileId id; //optional! (however, always set on Linux, and *generally* available on Windows) }; @@ -43,16 +47,16 @@ struct LinkDescriptor }; LinkDescriptor() : type(TYPE_FILE) {} - LinkDescriptor(zen::Int64 lastWriteTimeRawIn, + LinkDescriptor(Int64 lastWriteTimeRawIn, const Zstring& targetPathIn, LinkType lt) : lastWriteTimeRaw(lastWriteTimeRawIn), targetPath(targetPathIn), type(lt) {} - zen::Int64 lastWriteTimeRaw; //number of seconds since Jan. 1st 1970 UTC, same semantics like time_t (== signed long) - Zstring targetPath; //symlink "content", may be empty if determination failed - LinkType type; //type is required for Windows only! On Linux there is no such thing => consider this when comparing Symbolic Links! + Int64 lastWriteTimeRaw; //number of seconds since Jan. 1st 1970 UTC, same semantics like time_t (== signed long) + Zstring targetPath; //symlink "content", may be empty if determination failed + LinkType type; //type is required for Windows only! On Linux there is no such thing => consider this when comparing Symbolic Links! }; @@ -119,6 +123,9 @@ struct DirContainer //------------------------------------------------------------------ /* inheritance diagram: + ObjectMgr + /|\ + | FileSystemObject HierarchyObject /|\ /|\ _______________|______________ ______|______ @@ -133,32 +140,36 @@ class HierarchyObject friend class FileSystemObject; typedef zen::FixedList SubFileVec; //MergeSides::execute() requires a structure that doesn't invalidate pointers after push_back() - typedef zen::FixedList SubLinkVec; //Note: deque<> has circular reference in VCPP! + typedef zen::FixedList SubLinkVec; //Note: deque<> has circular dependency in VCPP! typedef zen::FixedList SubDirVec; public: DirMapping& addSubDir(const Zstring& shortNameLeft, const Zstring& shortNameRight); + template + DirMapping& addSubDir(const Zstring& shortName); //dir exists on one side only + + FileMapping& addSubFile(const Zstring& shortNameLeft, const FileDescriptor& left, //file exists on both sides CompareFilesResult defaultCmpResult, const Zstring& shortNameRight, const FileDescriptor& right); - void addSubFile(const FileDescriptor& left, //file exists on left side only - const Zstring& shortNameLeft); - void addSubFile(const Zstring& shortNameRight, //file exists on right side only - const FileDescriptor& right); + + template + FileMapping& addSubFile(const Zstring& shortNameRight, //file exists on one side only + const FileDescriptor& right); SymLinkMapping& addSubLink(const Zstring& shortNameLeft, const LinkDescriptor& left, //link exists on both sides CompareSymlinkResult defaultCmpResult, const Zstring& shortNameRight, const LinkDescriptor& right); - void addSubLink(const LinkDescriptor& left, //link exists on left side only - const Zstring& shortNameLeft); - void addSubLink(const Zstring& shortNameRight, //link exists on right side only - const LinkDescriptor& right); + + template + SymLinkMapping& addSubLink(const Zstring& shortName, //link exists on one side only + const LinkDescriptor& descr); const SubFileVec& refSubFiles() const { return subFiles; } /**/ SubFileVec& refSubFiles() { return subFiles; } @@ -225,7 +236,7 @@ public: virtual void flip(); private: - BaseDirMapping(const BaseDirMapping&); //this class is referenced by HierarchyObject => make it non-copyable/movable! + BaseDirMapping(const BaseDirMapping&); //this class is referenced by HierarchyObject => make it non-copyable/movable! BaseDirMapping& operator=(const BaseDirMapping&); // //this member is currently not used by the business logic -> may be removed! @@ -286,7 +297,7 @@ public: virtual void visit(const DirMapping& dirObj) = 0; }; -//inherit from this class to allow safe access by id instead of unsafe raw pointer +//inherit from this class to allow safe random access by id instead of unsafe raw pointer //allow for similar semantics like std::weak_ptr without having to use std::shared_ptr template class ObjectMgr @@ -296,9 +307,9 @@ public: ObjectID getId() { activeObjects().insert(this); return this; } //unfortunately we need to keep this method non-const to get non-const "this" pointer - //we could instead put this into the constructor, but temporaries created by STL would lead to some overhead + //we could instead put this into the constructor, but temporaries created by STL could lead to some overhead - static T* retrieve(ObjectID id) //returns NULL if object is not found + static T* retrieve(ObjectID id) //returns NULL if object is not valid anymore { auto iter = activeObjects().find(const_cast(id)); return static_cast(iter == activeObjects().end() ? NULL : *iter); //static down-cast @@ -337,13 +348,14 @@ public: virtual CompareFilesResult getCategory() const = 0; virtual std::wstring getCatConflict() const = 0; //only filled if getCategory() == FILE_CONFLICT //sync operation + virtual SyncOperation testSyncOperation(SyncDirection testSyncDir) const; virtual SyncOperation getSyncOperation() const; std::wstring getSyncOpConflict() const; //return conflict when determining sync direction or during categorization - SyncOperation testSyncOperation(SyncDirection syncDir) const; //get syncOp with provided settings //sync settings void setSyncDir(SyncDirection newDir); void setSyncDirConflict(const std::wstring& description); //set syncDir = SYNC_DIR_NONE + fill conflict description + SyncDirection getSyncDir() const { return syncDir; } bool isActive() const; void setActive(bool active); @@ -383,11 +395,6 @@ private: virtual void removeObjectL() = 0; virtual void removeObjectR() = 0; - static SyncOperation getSyncOperation(CompareFilesResult cmpResult, - bool selectedForSynchronization, - SyncDirection syncDir, - const std::wstring& syncDirConflict); //evaluate comparison result and sync direction - bool selectedForSynchronization; SyncDirection syncDir; std::wstring syncDirConflict; //non-empty if we have a conflict setting sync-direction @@ -461,25 +468,33 @@ class FileMapping : public FileSystemObject public: virtual void accept(FSObjectVisitor& visitor) const; - FileMapping(const Zstring& shortNameLeft, //use empty string if "not existing" - const FileDescriptor& left, - CompareFilesResult defaultCmpResult, - const Zstring& shortNameRight, // - const FileDescriptor& right, + FileMapping(const Zstring& shortNameLeft, //use empty string if "not existing" + const FileDescriptor& left, + CompareFilesResult defaultCmpResult, + const Zstring& shortNameRight, // + const FileDescriptor& right, HierarchyObject& parentObj) : FileSystemObject(shortNameLeft, shortNameRight, parentObj), cmpResult(defaultCmpResult), dataLeft(left), - dataRight(right) {} + dataRight(right), + moveFileRef(NULL) {} template Int64 getLastWriteTime() const; - template UInt64 getFileSize() const; + template UInt64 getFileSize () const; + template FileId getFileId () const; template const Zstring getExtension() const; + void setMoveRef(ObjectID refId) { moveFileRef = refId; } //reference to corresponding renamed file + ObjectID getMoveRef() const { return moveFileRef; } //may be NULL + virtual CompareFilesResult getCategory() const; virtual std::wstring getCatConflict() const; - template void copyTo(const FileDescriptor* srcDescr); //copy + update file attributes + virtual SyncOperation testSyncOperation(SyncDirection testSyncDir) const; + virtual SyncOperation getSyncOperation() const; + + template void syncTo(const FileDescriptor& descrTarget, const FileDescriptor* descrSource = NULL); //copy + update file attributes (optional) private: template @@ -497,6 +512,8 @@ private: FileDescriptor dataLeft; FileDescriptor dataRight; + + ObjectID moveFileRef; }; //------------------------------------------------------------------ @@ -549,7 +566,15 @@ private: //------------------------------------------------------------------ +//generic type descriptions (usecase CSV legend, sync config) +std::wstring getCategoryDescription(CompareFilesResult cmpRes); +std::wstring getSyncOpDescription (SyncOperation op); +//item-specific type descriptions +std::wstring getCategoryDescription(const FileSystemObject& fsObj); +std::wstring getSyncOpDescription (const FileSystemObject& fsObj); + +//------------------------------------------------------------------ @@ -681,20 +706,6 @@ void FileSystemObject::setActive(bool active) } -inline -SyncOperation FileSystemObject::getSyncOperation() const -{ - return getSyncOperation(getCategory(), selectedForSynchronization, syncDir, syncDirConflict); -} - - -inline -SyncOperation FileSystemObject::testSyncOperation(SyncDirection proposedDir) const -{ - return getSyncOperation(getCategory(), true, proposedDir, std::wstring()); //should be safe by design -} - - template <> inline bool FileSystemObject::isEmpty() const { @@ -839,6 +850,22 @@ DirMapping& HierarchyObject::addSubDir(const Zstring& shortNameLeft, } +template <> inline +DirMapping& HierarchyObject::addSubDir(const Zstring& shortName) +{ + subDirs.emplace_back(shortName, Zstring(), *this); + return subDirs.back(); +} + + +template <> inline +DirMapping& HierarchyObject::addSubDir(const Zstring& shortName) +{ + subDirs.emplace_back(Zstring(), shortName, *this); + return subDirs.back(); +} + + inline FileMapping& HierarchyObject::addSubFile( const Zstring& shortNameLeft, @@ -852,19 +879,19 @@ FileMapping& HierarchyObject::addSubFile( } -inline -void HierarchyObject::addSubFile(const FileDescriptor& left, //file exists on left side only - const Zstring& shortNameLeft) +template <> inline +FileMapping& HierarchyObject::addSubFile(const Zstring& shortName, const FileDescriptor& descr) { - subFiles.emplace_back(shortNameLeft, left, FILE_LEFT_SIDE_ONLY, Zstring(), FileDescriptor(), *this); + subFiles.emplace_back(shortName, descr, FILE_LEFT_SIDE_ONLY, Zstring(), FileDescriptor(), *this); + return subFiles.back(); } -inline -void HierarchyObject::addSubFile(const Zstring& shortNameRight, //file exists on right side only - const FileDescriptor& right) +template <> inline +FileMapping& HierarchyObject::addSubFile(const Zstring& shortName, const FileDescriptor& descr) { - subFiles.emplace_back(Zstring(), FileDescriptor(), FILE_RIGHT_SIDE_ONLY, shortNameRight, right, *this); + subFiles.emplace_back(Zstring(), FileDescriptor(), FILE_RIGHT_SIDE_ONLY, shortName, descr, *this); + return subFiles.back(); } @@ -881,19 +908,19 @@ SymLinkMapping& HierarchyObject::addSubLink( } -inline -void HierarchyObject::addSubLink(const LinkDescriptor& left, //link exists on left side only - const Zstring& shortNameLeft) +template <> inline +SymLinkMapping& HierarchyObject::addSubLink(const Zstring& shortName, const LinkDescriptor& descr) { - subLinks.emplace_back(shortNameLeft, left, SYMLINK_LEFT_SIDE_ONLY, Zstring(), LinkDescriptor(), *this); + subLinks.emplace_back(shortName, descr, SYMLINK_LEFT_SIDE_ONLY, Zstring(), LinkDescriptor(), *this); + return subLinks.back(); } -inline -void HierarchyObject::addSubLink(const Zstring& shortNameRight, //link exists on right side only - const LinkDescriptor& right) +template <> inline +SymLinkMapping& HierarchyObject::addSubLink(const Zstring& shortName, const LinkDescriptor& descr) { - subLinks.emplace_back(Zstring(), LinkDescriptor(), SYMLINK_RIGHT_SIDE_ONLY, shortNameRight, right, *this); + subLinks.emplace_back(Zstring(), LinkDescriptor(), SYMLINK_RIGHT_SIDE_ONLY, shortName, descr, *this); + return subLinks.back(); } @@ -1062,6 +1089,20 @@ zen::UInt64 FileMapping::getFileSize() const } +template <> inline +FileId FileMapping::getFileId() const +{ + return dataLeft.id; +} + + +template <> inline +FileId FileMapping::getFileId() const +{ + return dataRight.id; +} + + template inline const Zstring FileMapping::getExtension() const { @@ -1076,24 +1117,26 @@ const Zstring FileMapping::getExtension() const template <> inline -void FileMapping::copyTo(const FileDescriptor* srcDescr) //copy + update file attributes +void FileMapping::syncTo(const FileDescriptor& descrTarget, const FileDescriptor* descrSource) //copy + update file attributes { - if (srcDescr) - dataRight = *srcDescr; - dataLeft = dataRight; + dataLeft = descrTarget; + if (descrSource) + dataRight = *descrSource; + moveFileRef = NULL; cmpResult = FILE_EQUAL; copyToL(); //copy FileSystemObject specific part } template <> inline -void FileMapping::copyTo(const FileDescriptor* srcDescr) //copy + update file attributes +void FileMapping::syncTo(const FileDescriptor& descrTarget, const FileDescriptor* descrSource) //copy + update file attributes { - if (srcDescr) - dataLeft = *srcDescr; - dataRight = dataLeft; + dataRight = descrTarget; + if (descrSource) + dataLeft = *descrSource; + moveFileRef = NULL; cmpResult = FILE_EQUAL; copyToR(); //copy FileSystemObject specific part } diff --git a/lib/FindFilePlus/FindFilePlus.vcxproj b/lib/FindFilePlus/FindFilePlus.vcxproj deleted file mode 100644 index 2c4256a6..00000000 --- a/lib/FindFilePlus/FindFilePlus.vcxproj +++ /dev/null @@ -1,245 +0,0 @@ - - - - - Debug - Win32 - - - Debug - x64 - - - Release - Win32 - - - Release - x64 - - - - {70394AEF-5897-4911-AFA1-82EAF0581EFA} - ShadowDll - Win32Proj - - - - DynamicLibrary - Unicode - true - Windows7.1SDK - - - DynamicLibrary - Unicode - Windows7.1SDK - - - DynamicLibrary - Unicode - true - Windows7.1SDK - - - DynamicLibrary - Unicode - Windows7.1SDK - - - - - - - - - - - - - - - - - - - <_ProjectFileVersion>10.0.30319.1 - OBJ\ - OBJ\$(ProjectName)_$(Configuration)_$(Platform)\ - false - OBJ\ - OBJ\$(ProjectName)_$(Configuration)_$(Platform)\ - false - .\ - OBJ\$(ProjectName)_$(Configuration)_$(Platform)\ - false - .\ - OBJ\$(ProjectName)_$(Configuration)_$(Platform)\ - false - FindFilePlus_$(Platform) - FindFilePlus_$(Platform) - FindFilePlus_$(Platform) - FindFilePlus_$(Platform) - D:\Data\WinDDK\inc\ddk;D:\Data\WinDDK\inc\api;D:\Data\WinDDK\inc\crt;$(WindowsSdkDir)\include;$(VCInstallDir)include - D:\Data\WinDDK\inc\ddk;D:\Data\WinDDK\inc\api;D:\Data\WinDDK\inc\crt;$(WindowsSdkDir)\include;$(VCInstallDir)include - D:\Data\WinDDK\inc\ddk;D:\Data\WinDDK\inc\api;D:\Data\WinDDK\inc\crt;$(WindowsSdkDir)\include;$(VCInstallDir)include - D:\Data\WinDDK\inc\ddk;D:\Data\WinDDK\inc\api;D:\Data\WinDDK\inc\crt;$(WindowsSdkDir)\include;$(VCInstallDir)include - - - - $(IntDir)Build.html - - - Disabled - _X86_;_DEBUG;_WINDOWS;_USRDLL;FIND_FILE_PLUS_DLL_EXPORTS;%(PreprocessorDefinitions) - true - EnableFastChecks - MultiThreadedDebugDLL - - - Level4 - true - EditAndContinue - 4100 - ../.. - - - $(OutDir)$(TargetName)$(TargetExt) - true - true - $(IntDir)$(TargetName).pdb - Windows - - - $(IntDir)$(TargetName).lib - MachineX86 - - - - - $(IntDir)Build.html - - - X64 - - - Disabled - _AMD64_;_DEBUG;_WINDOWS;_USRDLL;FIND_FILE_PLUS_DLL_EXPORTS;%(PreprocessorDefinitions) - true - EnableFastChecks - MultiThreadedDebugDLL - - - Level4 - true - ProgramDatabase - 4100 - ../.. - - - $(OutDir)$(TargetName)$(TargetExt) - true - true - $(IntDir)$(TargetName).pdb - Windows - - - $(IntDir)$(TargetName).lib - MachineX64 - - - - - $(IntDir)Build.html - - - MaxSpeed - true - _X86_;NDEBUG;_WINDOWS;_USRDLL;FIND_FILE_PLUS_DLL_EXPORTS;%(PreprocessorDefinitions) - MultiThreaded - true - - - Level4 - true - ProgramDatabase - 4100 - Speed - ../.. - - - $(OutDir)$(TargetName)$(TargetExt) - true - false - Windows - true - true - UseLinkTimeCodeGeneration - - - $(IntDir)$(TargetName).lib - MachineX86 - - - - - $(IntDir)Build.html - - - X64 - - - MaxSpeed - true - _AMD64_;NDEBUG;_WINDOWS;_USRDLL;FIND_FILE_PLUS_DLL_EXPORTS;%(PreprocessorDefinitions) - MultiThreaded - true - - - Level4 - true - ProgramDatabase - 4100 - Speed - ../.. - - - $(OutDir)$(TargetName)$(TargetExt) - true - false - Windows - true - true - UseLinkTimeCodeGeneration - - - $(IntDir)$(TargetName).lib - MachineX64 - - - - - - - false - - - false - - - false - - - false - - - - - - - - - - - - \ No newline at end of file diff --git a/lib/FindFilePlus/dll_main.cpp b/lib/FindFilePlus/dll_main.cpp deleted file mode 100644 index 5d64181b..00000000 --- a/lib/FindFilePlus/dll_main.cpp +++ /dev/null @@ -1,30 +0,0 @@ -// ************************************************************************** -// * This file is part of the FreeFileSync project. It is distributed under * -// * GNU General Public License: http://www.gnu.org/licenses/gpl.html * -// * Copyright (C) 2008-2011 ZenJu (zhnmju123 AT gmx.de) * -// ************************************************************************** - - -#define WIN32_LEAN_AND_MEAN -#include - -#include "init_dll_binding.h" - - -//optional: add init/teardown logic here -BOOL APIENTRY DllMain(HINSTANCE hinstDLL, - DWORD fdwReason, - LPVOID lpvReserved) -{ - switch (fdwReason) - { - case DLL_PROCESS_ATTACH: - if (!findplus::initDllBinding()) - return false; - case DLL_PROCESS_DETACH: - case DLL_THREAD_ATTACH: - case DLL_THREAD_DETACH: - break; - } - return true; -} diff --git a/lib/FindFilePlus/find_file_plus.cpp b/lib/FindFilePlus/find_file_plus.cpp deleted file mode 100644 index becfe553..00000000 --- a/lib/FindFilePlus/find_file_plus.cpp +++ /dev/null @@ -1,298 +0,0 @@ -// ************************************************************************** -// * This file is part of the FreeFileSync project. It is distributed under * -// * GNU General Public License: http://www.gnu.org/licenses/gpl.html * -// * Copyright (C) 2008-2011 ZenJu (zhnmju123 AT gmx.de) * -// ************************************************************************** - -#include "find_file_plus.h" -#include "init_dll_binding.h" -//#include //these two don't play nice with each other -#include "load_dll.h" -#include - -using namespace dll; -using namespace findplus; - - -namespace -{ -struct FileError -{ - FileError(ULONG errorCode) : win32Error(errorCode) {} - ULONG win32Error; -}; - - -//-------------------------------------------------------------------------------------------------------------- -typedef NTSTATUS (NTAPI* NtOpenFileFunc)(PHANDLE fileHandle, - ACCESS_MASK desiredAccess, - POBJECT_ATTRIBUTES objectAttributes, - PIO_STATUS_BLOCK ioStatusBlock, - ULONG shareAccess, - ULONG openOptions); - -typedef NTSTATUS (NTAPI* NtCloseFunc)(HANDLE handle); - -typedef NTSTATUS (NTAPI* NtQueryDirectoryFileFunc)(HANDLE fileHandle, - HANDLE event, - PIO_APC_ROUTINE apcRoutine, - PVOID apcContext, - PIO_STATUS_BLOCK ioStatusBlock, - PVOID fileInformation, - ULONG length, - FILE_INFORMATION_CLASS fileInformationClass, - BOOLEAN ReturnSingleEntry, - PUNICODE_STRING fileMask, - BOOLEAN restartScan); - -typedef ULONG (NTAPI* RtlNtStatusToDosErrorFunc)(NTSTATUS /*__in status*/); - -typedef struct _RTL_RELATIVE_NAME_U -{ - UNICODE_STRING RelativeName; - HANDLE ContainingDirectory; - PVOID /*PRTLP_CURDIR_REF*/ CurDirRef; -} RTL_RELATIVE_NAME_U, *PRTL_RELATIVE_NAME_U; - -typedef BOOLEAN (NTAPI* RtlDosPathNameToNtPathName_UFunc)(PCWSTR, //__in dosFileName, - PUNICODE_STRING, //__out ntFileName, - PCWSTR*, //__out_optFilePart, - PRTL_RELATIVE_NAME_U); //__out_opt relativeName - -typedef BOOLEAN (NTAPI* RtlDosPathNameToRelativeNtPathName_UFunc)(PCWSTR, //__in dosFileName, - PUNICODE_STRING, //__out ntFileName, - PCWSTR*, //__out_optFilePart, - PRTL_RELATIVE_NAME_U); //__out_opt relativeName - -typedef VOID (NTAPI* RtlFreeUnicodeStringFunc)(PUNICODE_STRING); //__inout unicodeString - -//-------------------------------------------------------------------------------------------------------------- - -//it seems we cannot use any of the ntoskrnl.lib files in WinDDK as they produce access violations -//fortunately dynamic binding works fine: -const SysDllFun ntOpenFile (L"ntdll.dll", "NtOpenFile"); -const SysDllFun ntClose (L"ntdll.dll", "NtClose"); -const SysDllFun ntQueryDirectoryFile (L"ntdll.dll", "NtQueryDirectoryFile"); -const SysDllFun rtlNtStatusToDosError (L"ntdll.dll", "RtlNtStatusToDosError"); -const SysDllFun rtlFreeUnicodeString (L"ntdll.dll", "RtlFreeUnicodeString"); -const SysDllFun rtlDosPathNameToNtPathName_U(SysDllFun(L"ntdll.dll", "RtlDosPathNameToRelativeNtPathName_U") ? - SysDllFun(L"ntdll.dll", "RtlDosPathNameToRelativeNtPathName_U") : //use the newer version if available - SysDllFun(L"ntdll.dll", "RtlDosPathNameToNtPathName_U")); //fallback for XP -//global constants only -> preserve thread safety! -} - - -bool findplus::initDllBinding() //evaluate in ::DllMain() when attaching process -{ - //NT/ZwXxx Routines - //http://msdn.microsoft.com/en-us/library/ff567122(v=VS.85).aspx - - //Run-Time Library (RTL) Routines - //http://msdn.microsoft.com/en-us/library/ff563638(v=VS.85).aspx - - //verify dynamic dll binding - return ntOpenFile && - ntClose && - ntQueryDirectoryFile && - rtlNtStatusToDosError && - rtlFreeUnicodeString && - rtlDosPathNameToNtPathName_U; - - //this may become handy some time: nt status code STATUS_ORDINAL_NOT_FOUND maps to win32 code ERROR_INVALID_ORDINAL -} - - -class findplus::FileSearcher -{ -public: - FileSearcher(const wchar_t* dirname); //throw FileError - ~FileSearcher(); - - void readdir(FileInformation& output); //throw FileError - -private: - UNICODE_STRING ntPathName; //it seems hDir implicitly keeps a reference to this, at least ::FindFirstFile() does no cleanup before ::FindClose()! - HANDLE hDir; - - ULONG nextEntryOffset; //!= 0 if entry is waiting in buffer - //::FindNextFileW() uses 0x1000 = 4096 = sizeof(FILE_BOTH_DIR_INFORMATION) + sizeof(TCHAR) * 2000 - //=> let's use the same, even if our header is 16 byte larger; maybe there is some packet size advantage for networks? Note that larger buffers seem to degrade performance. - static const ULONG BUFFER_SIZE = 4096; - LONGLONG buffer[BUFFER_SIZE / sizeof(LONGLONG)]; //buffer needs to be aligned at LONGLONG boundary - - static_assert(BUFFER_SIZE % sizeof(LONGLONG) == 0, "ups, our buffer is trimmed!"); -}; - - -FileSearcher::FileSearcher(const wchar_t* dirname) : - hDir(NULL), - nextEntryOffset(0) -{ - ntPathName.Buffer = NULL; - ntPathName.Length = 0; - ntPathName.MaximumLength = 0; - - zen::ScopeGuard guardConstructor = zen::makeGuard([&]() { this->~FileSearcher(); }); - //-------------------------------------------------------------------------------------------------------------- - - //convert dosFileName, e.g. C:\Users or \\?\C:\Users to ntFileName \??\C:\Users - //in contrast to ::FindFirstFile() we don't evaluate the relativeName, however tests indicate ntFileName is *always* filled with an absolute name, even if dosFileName is relative - - //NOTE: RtlDosPathNameToNtPathName_U may be used on all XP/Win7/Win8 for compatibility - // RtlDosPathNameToNtPathName_U: used by Windows XP available with OS version 3.51 (Windows NT) and higher - // RtlDosPathNameToRelativeNtPathName_U: used by Win7/Win8 available with OS version 5.2 (Windows Server 2003) and higher - if (!rtlDosPathNameToNtPathName_U(dirname, //__in dosFileName, - &ntPathName, //__out ntFileName, - NULL, //__out_optFilePart, - NULL)) //__out_opt relativeName - empty if dosFileName is absolute - throw FileError(rtlNtStatusToDosError(STATUS_OBJECT_PATH_NOT_FOUND)); //translates to ERROR_PATH_NOT_FOUND, same behavior like ::FindFirstFileEx() - - OBJECT_ATTRIBUTES objAttr = {}; - InitializeObjectAttributes(&objAttr, //[out] POBJECT_ATTRIBUTES initializedAttributes, - &ntPathName, //[in] PUNICODE_STRING objectName, - OBJ_CASE_INSENSITIVE, //[in] ULONG attributes, - NULL, //[in] HANDLE rootDirectory, - NULL); //[in, optional] PSECURITY_DESCRIPTOR securityDescriptor - - { - IO_STATUS_BLOCK status = {}; - NTSTATUS rv = ntOpenFile(&hDir, //__out PHANDLE FileHandle, - FILE_LIST_DIRECTORY | SYNCHRONIZE, //__in ACCESS_MASK desiredAccess, - 100001 used by ::FindFirstFile() on all XP/Win7/Win8 - &objAttr, //__in POBJECT_ATTRIBUTES objectAttributes, - &status, //__out PIO_STATUS_BLOCK ioStatusBlock, - FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, //__in ULONG shareAccess, - 7 on Win7/Win8, 3 on XP - FILE_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT | FILE_OPEN_FOR_BACKUP_INTENT); //__in ULONG openOptions - 4021 used on all XP/Win7/Win8 - if (!NT_SUCCESS(rv)) - throw FileError(rtlNtStatusToDosError(rv)); - } - - guardConstructor.dismiss(); -} - - -inline -FileSearcher::~FileSearcher() -{ - //cleanup in reverse order - if (hDir) - ntClose(hDir); - - if (ntPathName.Buffer) - rtlFreeUnicodeString(&ntPathName); //cleanup identical to ::FindFirstFile() - //note that most if this function seems inlined by the linker, so that its assembly looks equivalent to "RtlFreeHeap(GetProcessHeap(), 0, ntPathName.Buffer)" -} - - -void FileSearcher::readdir(FileInformation& output) -{ - //although FILE_ID_FULL_DIR_INFORMATION should suffice for our purposes, there are problems on Windows XP for certain directories, e.g. "\\Vboxsvr\build" - //making NtQueryDirectoryFile() return with STATUS_INVALID_PARAMETER while other directories, e.g. "C:\" work fine for some reason - //FILE_ID_BOTH_DIR_INFORMATION on the other hand works on XP/Win7/Win8 - //performance: there is no noticable difference between FILE_ID_BOTH_DIR_INFORMATION and FILE_ID_FULL_DIR_INFORMATION - - /* corresponding first access in ::FindFirstFileW() - - NTSTATUS rv = ntQueryDirectoryFile(hDir, //__in HANDLE fileHandle, - NULL, //__in_opt HANDLE event, - NULL, //__in_opt PIO_APC_ROUTINE apcRoutine, - NULL, //__in_opt PVOID apcContext, - &status, //__out PIO_STATUS_BLOCK ioStatusBlock, - &buffer, //__out_bcount(Length) PVOID fileInformation, - BUFFER_SIZE, //__in ULONG length, ::FindFirstFileW() on all XP/Win7/Win8 uses sizeof(FILE_BOTH_DIR_INFORMATION) + sizeof(TCHAR) * MAX_PATH == 0x268 - FileIdBothDirectoryInformation, //__in FILE_INFORMATION_CLASS fileInformationClass - all XP/Win7/Win8 use "FileBothDirectoryInformation" - true, //__in BOOLEAN returnSingleEntry, - NULL, //__in_opt PUNICODE_STRING mask, - false); //__in BOOLEAN restartScan - */ - - //analog to ::FindNextFileW() with performance optimized access (in contrast to first access in ::FindFirstFileW()) - if (nextEntryOffset == 0) - { - IO_STATUS_BLOCK status = {}; - NTSTATUS rv = ntQueryDirectoryFile(hDir, //__in HANDLE fileHandle, - NULL, //__in_opt HANDLE event, - NULL, //__in_opt PIO_APC_ROUTINE apcRoutine, - NULL, //__in_opt PVOID apcContext, - &status, //__out PIO_STATUS_BLOCK ioStatusBlock, - &buffer, //__out_bcount(Length) PVOID fileInformation, - BUFFER_SIZE, //__in ULONG length, ::FindNextFileW() on all XP/Win7/Win8 uses sizeof(FILE_BOTH_DIR_INFORMATION) + sizeof(TCHAR) * 2000 == 0x1000 - FileIdBothDirectoryInformation, //__in FILE_INFORMATION_CLASS fileInformationClass - all XP/Win7/Win8 use "FileBothDirectoryInformation" - false, //__in BOOLEAN returnSingleEntry, - NULL, //__in_opt PUNICODE_STRING mask, - false); //__in BOOLEAN restartScan - if (!NT_SUCCESS(rv)) - throw FileError(rtlNtStatusToDosError(rv)); //throws STATUS_NO_MORE_FILES when finished - - if (status.Information == 0) //except for the first call to call ::NtQueryDirectoryFile(): - throw FileError(rtlNtStatusToDosError(STATUS_BUFFER_OVERFLOW)); //if buffer size is too small, return value is STATUS_SUCCESS and Information == 0 -> we don't expect this! - } - - const FILE_ID_BOTH_DIR_INFORMATION& dirInfo = *reinterpret_cast(reinterpret_cast(buffer) + nextEntryOffset); - - if (dirInfo.NextEntryOffset == 0) - nextEntryOffset = 0; //our offset is relative to the beginning of the buffer - else - nextEntryOffset += dirInfo.NextEntryOffset; - - - auto toFileTime = [](const LARGE_INTEGER & rawTime) -> FILETIME - { - FILETIME tmp = { rawTime.LowPart, rawTime.HighPart }; - return tmp; - }; - - output.creationTime = toFileTime(dirInfo.CreationTime); - output.lastWriteTime = toFileTime(dirInfo.LastWriteTime); - output.fileSize.QuadPart = dirInfo.EndOfFile.QuadPart; - output.fileId.QuadPart = dirInfo.FileId.QuadPart; - output.fileAttributes = dirInfo.FileAttributes; - output.shortNameLength = dirInfo.FileNameLength / sizeof(TCHAR); //FileNameLength is in bytes! - - if (dirInfo.FileNameLength + sizeof(TCHAR) > sizeof(output.shortName)) //this may actually happen if ::NtQueryDirectoryFile() decides to return a - throw FileError(rtlNtStatusToDosError(STATUS_BUFFER_OVERFLOW)); //short name of length MAX_PATH + 1, 0-termination is not required! - - ::memcpy(output.shortName, dirInfo.FileName, dirInfo.FileNameLength); - output.shortName[output.shortNameLength] = 0; //NOTE: FILE_ID_BOTH_DIR_INFORMATION::FileName in general is NOT 0-terminated! It is on XP/Win7, but NOT on Win8! - - static_assert(sizeof(output.creationTime) == sizeof(dirInfo.CreationTime), "dang!"); - static_assert(sizeof(output.lastWriteTime) == sizeof(dirInfo.LastWriteTime), "dang!"); - static_assert(sizeof(output.fileSize) == sizeof(dirInfo.EndOfFile), "dang!"); - static_assert(sizeof(output.fileId) == sizeof(dirInfo.FileId), "dang!"); - static_assert(sizeof(output.fileAttributes) == sizeof(dirInfo.FileAttributes), "dang!"); -} - - -FindHandle findplus::openDir(const wchar_t* dirname) -{ - try - { - return new FileSearcher(dirname); //throw FileError - } - catch (const FileError& err) - { - setWin32Error(err.win32Error); - return NULL; - } -} - - -bool findplus::readDir(FindHandle hnd, FileInformation& output) -{ - try - { - hnd->readdir(output); //throw FileError - return true; - } - catch (const FileError& err) - { - setWin32Error(err.win32Error); - return false; - } -} - - -void findplus::closeDir(FindHandle hnd) -{ - if (hnd) //play a little "nice" - delete hnd; -} diff --git a/lib/FindFilePlus/find_file_plus.h b/lib/FindFilePlus/find_file_plus.h deleted file mode 100644 index aacdf0ea..00000000 --- a/lib/FindFilePlus/find_file_plus.h +++ /dev/null @@ -1,78 +0,0 @@ -// ************************************************************************** -// * This file is part of the FreeFileSync project. It is distributed under * -// * GNU General Public License: http://www.gnu.org/licenses/gpl.html * -// * Copyright (C) 2008-2011 ZenJu (zhnmju123 AT gmx.de) * -// ************************************************************************** - -#ifndef FIND_FIRST_FILE_PLUS_HEADER_087483434 -#define FIND_FIRST_FILE_PLUS_HEADER_087483434 - -#ifdef FIND_FILE_PLUS_DLL_EXPORTS -#define DLL_FUNCTION_DECLARATION extern "C" __declspec(dllexport) -#else -#define DLL_FUNCTION_DECLARATION extern "C" __declspec(dllimport) -#endif - - -#ifdef FIND_FILE_PLUS_DLL_EXPORTS -#include //driver level headers must be included *before* windows api headers! -#endif -#include // -#undef min -#undef max - -#include - -namespace findplus -{ -/*-------------- - |declarations| - --------------*/ - -struct FileInformation -{ - FILETIME creationTime; - FILETIME lastWriteTime; - ULARGE_INTEGER fileSize; - ULARGE_INTEGER fileId; - DWORD fileAttributes; - DWORD shortNameLength; - WCHAR shortName[MAX_PATH + 1]; //shortName is 0-terminated -}; //no need for #pragma pack -> all members already starting at 4 byte boundary! - -class FileSearcher; -typedef FileSearcher* FindHandle; - -DLL_FUNCTION_DECLARATION -FindHandle openDir(const wchar_t* dirname); //returns NULL on error, call ::GetLastError() -//note: do NOT place an asterisk at end, e.g. C:\SomeDir\*, as one would do for ::FindFirstFile() - -DLL_FUNCTION_DECLARATION -bool readDir(FindHandle hnd, FileInformation& output); //returns false on error or if there are no more files; ::GetLastError() returns ERROR_NO_MORE_FILES - -DLL_FUNCTION_DECLARATION -void closeDir(FindHandle hnd); - -/*---------- - |typedefs| - ----------*/ -typedef FindHandle (*OpenDirFunc )(const wchar_t* dirname); -typedef bool (*ReadDirFunc )(FindHandle hnd, FileInformation& dirInfo); -typedef void (*CloseDirFunc)(FindHandle hnd); - -/*-------------- - |symbol names| - --------------*/ -//const pointers ensure internal linkage -const char openDirFuncName [] = "openDir"; -const char readDirFuncName [] = "readDir"; -const char closeDirFuncName[] = "closeDir"; - -/*--------------- - |library names| - ---------------*/ -inline const wchar_t* getDllName() { return zen::is64BitBuild ? L"FindFilePlus_x64.dll" : L"FindFilePlus_Win32.dll"; } -} - - -#endif //FIND_FIRST_FILE_PLUS_HEADER_087483434 diff --git a/lib/FindFilePlus/init_dll_binding.h b/lib/FindFilePlus/init_dll_binding.h deleted file mode 100644 index 51b32c99..00000000 --- a/lib/FindFilePlus/init_dll_binding.h +++ /dev/null @@ -1,16 +0,0 @@ -// ************************************************************************** -// * This file is part of the FreeFileSync project. It is distributed under * -// * GNU General Public License: http://www.gnu.org/licenses/gpl.html * -// * Copyright (C) 2008-2011 ZenJu (zhnmju123 AT gmx.de) * -// ************************************************************************** - -#ifndef INIT_DLL_BINDING_HEADER_018356031467832145 -#define INIT_DLL_BINDING_HEADER_018356031467832145 - -namespace findplus -{ -//load and check dll binding at startup -bool initDllBinding(); //evaluate in ::DllMain() when attaching process -} - -#endif //INIT_DLL_BINDING_HEADER_018356031467832145 diff --git a/lib/FindFilePlus/load_dll.cpp b/lib/FindFilePlus/load_dll.cpp deleted file mode 100644 index 20d9a5fe..00000000 --- a/lib/FindFilePlus/load_dll.cpp +++ /dev/null @@ -1,23 +0,0 @@ -// ************************************************************************** -// * This file is part of the FreeFileSync project. It is distributed under * -// * GNU General Public License: http://www.gnu.org/licenses/gpl.html * -// * Copyright (C) 2008-2011 ZenJu (zhnmju123 AT gmx.de) * -// ************************************************************************** - -#include "load_dll.h" -#define WIN32_LEAN_AND_MEAN -#include - -void* /*FARPROC*/ dll::loadSymbol(const wchar_t* libraryName, const char* functionName) -{ - return ::GetProcAddress(::GetModuleHandle(libraryName), functionName); - //cleanup neither required nor allowed (::FreeLibrary()) - -} -//note: void* and FARPROC function pointer have same binary size on Windows - - -void dll::setWin32Error(unsigned long lastError) -{ - ::SetLastError(lastError); -} diff --git a/lib/FindFilePlus/load_dll.h b/lib/FindFilePlus/load_dll.h deleted file mode 100644 index 350de9f8..00000000 --- a/lib/FindFilePlus/load_dll.h +++ /dev/null @@ -1,46 +0,0 @@ -// ************************************************************************** -// * This file is part of the FreeFileSync project. It is distributed under * -// * GNU General Public License: http://www.gnu.org/licenses/gpl.html * -// * Copyright (C) 2008-2011 ZenJu (zhnmju123 AT gmx.de) * -// ************************************************************************** - -#ifndef LOAD_DLL_HEADER_0312463214872163832174 -#define LOAD_DLL_HEADER_0312463214872163832174 - -namespace dll -{ -void setWin32Error(unsigned long lastError); - -//NOTE: uses ::GetModuleHandle => call for system DLLs only! -template -class SysDllFun -{ -public: - SysDllFun(const wchar_t* systemLibrary, const char* functionName) : - fun(reinterpret_cast(loadSymbol(systemLibrary, functionName))) {} - - operator Func() const { return fun; } - -private: - Func fun; -}; - - - - - - - - - - - - - - - - -void* /*FARPROC*/ loadSymbol(const wchar_t* libraryName, const char* functionName); -} - -#endif //LOAD_DLL_HEADER_0312463214872163832174 diff --git a/lib/custom_grid.cpp b/lib/custom_grid.cpp index 97db1676..f2892624 100644 --- a/lib/custom_grid.cpp +++ b/lib/custom_grid.cpp @@ -557,23 +557,24 @@ private: case SO_CREATE_NEW_LEFT: case SO_OVERWRITE_LEFT: case SO_DELETE_LEFT: + case SO_MOVE_LEFT_SOURCE: + case SO_MOVE_LEFT_TARGET: + case SO_COPY_METADATA_TO_LEFT: result.first = *wxBLACK; result.second = COLOR_SYNC_BLUE; break; - case SO_COPY_METADATA_TO_LEFT: - result.first = *wxBLACK; - result.second = COLOR_SYNC_BLUE_LIGHT; + // result.second = COLOR_SYNC_BLUE_LIGHT; break; case SO_CREATE_NEW_RIGHT: case SO_OVERWRITE_RIGHT: case SO_DELETE_RIGHT: - result.first = *wxBLACK; - result.second = COLOR_SYNC_GREEN; - break; + case SO_MOVE_RIGHT_SOURCE: + case SO_MOVE_RIGHT_TARGET: case SO_COPY_METADATA_TO_RIGHT: result.first = *wxBLACK; - result.second = COLOR_SYNC_GREEN_LIGHT; + result.second = COLOR_SYNC_GREEN; break; + // result.second = COLOR_SYNC_GREEN_LIGHT; case SO_UNRESOLVED_CONFLICT: result.first = *wxBLACK; result.second = COLOR_YELLOW; @@ -2038,70 +2039,77 @@ void CustomGridMiddle::showToolTip(int rowNumber, wxPoint pos) if (getGridDataTableMiddle()->syncPreviewIsActive()) //synchronization preview { - const SyncOperation syncOp = fsObj->getSyncOperation(); - switch (syncOp) + const wchar_t* imageName = [&]() -> const wchar_t* { - case SO_CREATE_NEW_LEFT: - toolTip.show(getDescription(syncOp), pos, &GlobalResources::getImage(wxT("createLeft"))); - break; - case SO_CREATE_NEW_RIGHT: - toolTip.show(getDescription(syncOp), pos, &GlobalResources::getImage(wxT("createRight"))); - break; - case SO_DELETE_LEFT: - toolTip.show(getDescription(syncOp), pos, &GlobalResources::getImage(wxT("deleteLeft"))); - break; - case SO_DELETE_RIGHT: - toolTip.show(getDescription(syncOp), pos, &GlobalResources::getImage(wxT("deleteRight"))); - break; - case SO_OVERWRITE_LEFT: - case SO_COPY_METADATA_TO_LEFT: - toolTip.show(getDescription(syncOp), pos, &GlobalResources::getImage(wxT("updateLeft"))); - break; - case SO_OVERWRITE_RIGHT: - case SO_COPY_METADATA_TO_RIGHT: - toolTip.show(getDescription(syncOp), pos, &GlobalResources::getImage(wxT("updateRight"))); - break; - case SO_DO_NOTHING: - toolTip.show(getDescription(syncOp), pos, &GlobalResources::getImage(wxT("none"))); - break; - case SO_EQUAL: - toolTip.show(getDescription(syncOp), pos, &GlobalResources::getImage(wxT("equal"))); - break; - case SO_UNRESOLVED_CONFLICT: - toolTip.show(fsObj->getSyncOpConflict(), pos, &GlobalResources::getImage(wxT("conflict"))); - break; - }; + const SyncOperation syncOp = fsObj->getSyncOperation(); + switch (syncOp) + { + case SO_CREATE_NEW_LEFT: + return L"createLeft"; + case SO_CREATE_NEW_RIGHT: + return L"createRight"; + case SO_DELETE_LEFT: + return L"deleteLeft"; + case SO_DELETE_RIGHT: + return L"deleteRight"; + case SO_MOVE_LEFT_SOURCE: + return L"moveLeftSource"; + case SO_MOVE_LEFT_TARGET: + return L"moveLeftTarget"; + case SO_MOVE_RIGHT_SOURCE: + return L"moveRightSource"; + case SO_MOVE_RIGHT_TARGET: + return L"moveRightTarget"; + case SO_OVERWRITE_LEFT: + return L"updateLeft"; + case SO_COPY_METADATA_TO_LEFT: + return L"moveLeft"; + case SO_OVERWRITE_RIGHT: + return L"updateRight"; + case SO_COPY_METADATA_TO_RIGHT: + return L"moveRight"; + case SO_DO_NOTHING: + return L"none"; + case SO_EQUAL: + return L"equal"; + case SO_UNRESOLVED_CONFLICT: + return L"conflict"; + }; + assert(false); + return L""; + }(); + + toolTip.show(getSyncOpDescription(*fsObj), pos, &GlobalResources::getImage(imageName)); } else { - const CompareFilesResult cmpRes = fsObj->getCategory(); - switch (cmpRes) + const wchar_t* imageName = [&]() -> const wchar_t* { - case FILE_LEFT_SIDE_ONLY: - toolTip.show(getDescription(cmpRes), pos, &GlobalResources::getImage(wxT("leftOnly"))); - break; - case FILE_RIGHT_SIDE_ONLY: - toolTip.show(getDescription(cmpRes), pos, &GlobalResources::getImage(wxT("rightOnly"))); - break; - case FILE_LEFT_NEWER: - toolTip.show(getDescription(cmpRes), pos, &GlobalResources::getImage(wxT("leftNewer"))); - break; - case FILE_RIGHT_NEWER: - toolTip.show(getDescription(cmpRes), pos, &GlobalResources::getImage(wxT("rightNewer"))); - break; - case FILE_DIFFERENT: - toolTip.show(getDescription(cmpRes), pos, &GlobalResources::getImage(wxT("different"))); - break; - case FILE_EQUAL: - toolTip.show(getDescription(cmpRes), pos, &GlobalResources::getImage(wxT("equal"))); - break; - case FILE_DIFFERENT_METADATA: - toolTip.show(getDescription(cmpRes), pos, &GlobalResources::getImage(wxT("conflict"))); - break; - case FILE_CONFLICT: - toolTip.show(fsObj->getCatConflict(), pos, &GlobalResources::getImage(wxT("conflict"))); - break; - } + const CompareFilesResult cmpRes = fsObj->getCategory(); + switch (cmpRes) + { + case FILE_LEFT_SIDE_ONLY: + return L"leftOnly"; + case FILE_RIGHT_SIDE_ONLY: + return L"rightOnly"; + case FILE_LEFT_NEWER: + return L"leftNewer"; + case FILE_RIGHT_NEWER: + return L"rightNewer"; + case FILE_DIFFERENT: + return L"different"; + case FILE_EQUAL: + return L"equal"; + case FILE_DIFFERENT_METADATA: + return L"conflict"; + case FILE_CONFLICT: + return L"conflict"; + } + assert(false); + return L""; + }(); + + toolTip.show(getCategoryDescription(*fsObj), pos, &GlobalResources::getImage(imageName)); } } @@ -2284,6 +2292,7 @@ void GridCellRendererMiddle::Draw(wxGrid& grid, //HIGHLIGHTNING (sync direction): if (rowIsHighlighted && m_gridMiddle.highlightedPos != CustomGridMiddle::BLOCKPOS_CHECK_BOX) //don't allow changing direction for "=="-files + switch (m_gridMiddle.highlightedPos) { case CustomGridMiddle::BLOCKPOS_CHECK_BOX: @@ -2374,25 +2383,35 @@ const wxBitmap& zen::getSyncOpImage(SyncOperation syncOp) switch (syncOp) //evaluate comparison result and sync direction { case SO_CREATE_NEW_LEFT: - return GlobalResources::getImage(wxT("createLeftSmall")); + return GlobalResources::getImage(L"createLeftSmall"); case SO_CREATE_NEW_RIGHT: - return GlobalResources::getImage(wxT("createRightSmall")); + return GlobalResources::getImage(L"createRightSmall"); case SO_DELETE_LEFT: - return GlobalResources::getImage(wxT("deleteLeftSmall")); + return GlobalResources::getImage(L"deleteLeftSmall"); case SO_DELETE_RIGHT: - return GlobalResources::getImage(wxT("deleteRightSmall")); + return GlobalResources::getImage(L"deleteRightSmall"); + case SO_MOVE_LEFT_SOURCE: + return GlobalResources::getImage(L"moveLeftSourceSmall"); + case SO_MOVE_LEFT_TARGET: + return GlobalResources::getImage(L"moveLeftTargetSmall"); + case SO_MOVE_RIGHT_SOURCE: + return GlobalResources::getImage(L"moveRightSourceSmall"); + case SO_MOVE_RIGHT_TARGET: + return GlobalResources::getImage(L"moveRightTargetSmall"); case SO_OVERWRITE_RIGHT: + return GlobalResources::getImage(L"updateRightSmall"); case SO_COPY_METADATA_TO_RIGHT: - return GlobalResources::getImage(wxT("updateRightSmall")); + return GlobalResources::getImage(L"moveRightSmall"); case SO_OVERWRITE_LEFT: + return GlobalResources::getImage(L"updateLeftSmall"); case SO_COPY_METADATA_TO_LEFT: - return GlobalResources::getImage(wxT("updateLeftSmall")); + return GlobalResources::getImage(L"moveLeftSmall"); case SO_DO_NOTHING: - return GlobalResources::getImage(wxT("noneSmall")); + return GlobalResources::getImage(L"noneSmall"); case SO_EQUAL: - return GlobalResources::getImage(wxT("equalSmall")); + return GlobalResources::getImage(L"equalSmall"); case SO_UNRESOLVED_CONFLICT: - return GlobalResources::getImage(wxT("conflictSmall")); + return GlobalResources::getImage(L"conflictSmall"); } return wxNullBitmap; //dummy diff --git a/lib/db_file.cpp b/lib/db_file.cpp index faee4c8a..60a721b1 100644 --- a/lib/db_file.cpp +++ b/lib/db_file.cpp @@ -15,7 +15,7 @@ #include #include #include -#include +#include #ifdef FFS_WIN #include //includes "windows.h" @@ -29,15 +29,24 @@ namespace { //------------------------------------------------------------------------------------------------------------------------------- const char FILE_FORMAT_DESCR[] = "FreeFileSync"; -const int FILE_FORMAT_VER = 7; +const int FILE_FORMAT_VER = 8; //------------------------------------------------------------------------------------------------------------------------------- +typedef std::string UniqueId; +typedef Zbase MemoryStream; //ref-counted byte stream representing DirInformation +typedef std::map StreamMapping; //list of streams ordered by session UUID + + +//------------------------------------------------------------------------------------ +//| ensure 32/64 bit portability: used fixed size data types only e.g. std::uint32_t | +//------------------------------------------------------------------------------------ + template inline Zstring getDBFilename(const BaseDirMapping& baseMap, bool tempfile = false) { - //Linux and Windows builds are binary incompatible: char/wchar_t case, sensitive/insensitive - //32 and 64 bit db files ARE designed to be binary compatible! + //Linux and Windows builds are binary incompatible: different file id?, problem with case sensitivity? + //however 32 and 64 bit db files *are* designed to be binary compatible! //Give db files different names. //make sure they end with ".ffs_db". These files will not be included into comparison when located in base sync directories #ifdef FFS_WIN @@ -51,255 +60,209 @@ Zstring getDBFilename(const BaseDirMapping& baseMap, bool tempfile = false) } - -class FileInputStreamDB : public FileInputStream +StreamMapping loadStreams(const Zstring& filename) //throw FileError { -public: - FileInputStreamDB(const Zstring& filename) : //throw FileError - FileInputStream(filename) + if (!zen::fileExists(filename)) + throw FileErrorDatabaseNotExisting(_("Initial synchronization:") + L" \n\n" + + _("One of the FreeFileSync database files is not yet existing:") + L" \n" + + L"\"" + filename + L"\""); + try { + //read format description (uncompressed) + FileInputStream rawStream(filename); //throw FileError + //read FreeFileSync file identifier char formatDescr[sizeof(FILE_FORMAT_DESCR)] = {}; - Read(formatDescr, sizeof(formatDescr)); //throw FileError + rawStream.Read(formatDescr, sizeof(formatDescr)); //throw FileError if (!std::equal(FILE_FORMAT_DESCR, FILE_FORMAT_DESCR + sizeof(FILE_FORMAT_DESCR), formatDescr)) throw FileError(_("Incompatible synchronization database format:") + L" \n" + L"\"" + filename + L"\""); - } -private: -}; + wxZlibInputStream decompressed(rawStream, wxZLIB_ZLIB); + CheckedReader cr(decompressed, filename); -class FileOutputStreamDB : public FileOutputStream -{ -public: - FileOutputStreamDB(const Zstring& filename) : //throw FileError - FileOutputStream(filename) + std::int32_t version = cr.readNumberC(); + if (version != FILE_FORMAT_VER) //read file format version# + throw FileError(_("Incompatible synchronization database format:") + L" \n" + L"\"" + filename + L"\""); + + //read stream lists + StreamMapping output; + + std::uint32_t dbCount = cr.readNumberC(); //number of databases: one for each sync-pair + while (dbCount-- != 0) + { + //DB id of partner databases + const std::string sessionID = cr.readStringC(); + const MemoryStream stream = cr.readStringC(); //read db-entry stream (containing DirInformation) + + output.insert(std::make_pair(sessionID, stream)); + } + return output; + } + catch (const std::bad_alloc&) //this is most likely caused by a corrupted database file { - //write FreeFileSync file identifier - Write(FILE_FORMAT_DESCR, sizeof(FILE_FORMAT_DESCR)); //throw FileError + throw FileError(_("Error reading from synchronization database:") + L" (bad alloc)"); } - -private: -}; } -//####################################################################################################################################### -class ReadDirInfo : public zen::ReadInputStream +class StreamParser : private CheckedReader { public: - ReadDirInfo(wxInputStream& stream, const Zstring& errorObjName, DirInformation& dirInfo) : ReadInputStream(stream, errorObjName) + static DirInfoPtr execute(const MemoryStream& stream, const Zstring& fileName) //throw FileError -> return value always bound! { - //|------------------------------------------------------------------------------------- - //| ensure 32/64 bit portability: use fixed size data types only e.g. boost::uint32_t | - //|------------------------------------------------------------------------------------- - - //read filter settings -> currently not required, but persisting it doesn't hurt - dirInfo.filter = HardFilter::loadFilter(getStream()); - check(); - - //start recursion - execute(dirInfo.baseDirContainer); + try + { + //read streams into DirInfo + auto dirInfo = std::make_shared(); + wxMemoryInputStream buffer(&*stream.begin(), stream.size()); //convert char-array to inputstream: no copying, ownership not transferred + StreamParser(buffer, fileName, *dirInfo); //throw FileError + return dirInfo; + } + catch (const std::bad_alloc&) //this is most likely caused by a corrupted database file + { + throw FileError(_("Error reading from synchronization database:") + L" (bad alloc)"); + } } private: - void execute(DirContainer& dirCont) const + StreamParser(wxInputStream& stream, const Zstring& errorObjName, DirInformation& dirInfo) : CheckedReader(stream, errorObjName) { - while (readNumberC()) - readSubFile(dirCont); - - while (readNumberC()) - readSubLink(dirCont); - - while (readNumberC()) - readSubDirectory(dirCont); + recurse(dirInfo.baseDirContainer); } - void readSubFile(DirContainer& dirCont) const + Zstring readStringUtf8() const { - //attention: order of function argument evaluation is undefined! So do it one after the other... - const Zstring shortName = readStringC(); //file name - - const std::int64_t modTime = readNumberC(); - const std::uint64_t fileSize = readNumberC(); - - //const util::FileID fileIdentifier(stream_); - //check(); - - dirCont.addSubFile(shortName, - FileDescriptor(modTime, fileSize)); + return utf8CvrtTo(readStringC>()); } - - void readSubLink(DirContainer& dirCont) const + FileId readFileId() const { - //attention: order of function argument evaluation is undefined! So do it one after the other... - const Zstring shortName = readStringC(); //file name - const std::int64_t modTime = readNumberC(); - const Zstring targetPath = readStringC(); //file name - const LinkDescriptor::LinkType linkType = static_cast(readNumberC()); - - dirCont.addSubLink(shortName, - LinkDescriptor(modTime, targetPath, linkType)); - } + assert_static(sizeof(FileId().first ) <= sizeof(std::uint64_t)); + assert_static(sizeof(FileId().second) <= sizeof(std::uint64_t)); - - void readSubDirectory(DirContainer& dirCont) const - { - const Zstring shortName = readStringC(); //directory name - DirContainer& subDir = dirCont.addSubDir(shortName); - execute(subDir); //recurse + const auto devId = static_cast(readNumberC()); // + const auto fId = static_cast(readNumberC()); //silence "loss of precision" compiler warnings + return std::make_pair(devId, fId); } -}; -namespace -{ -typedef std::string UniqueId; -typedef std::shared_ptr > MemoryStreamPtr; //byte stream representing DirInformation -typedef std::map StreamMapping; //list of streams ordered by session UUID -} - -class ReadFileStream : public zen::ReadInputStream -{ -public: - ReadFileStream(wxInputStream& stream, const Zstring& filename, StreamMapping& streamList) : ReadInputStream(stream, filename) + void recurse(DirContainer& dirCont) const { - //|------------------------------------------------------------------------------------- - //| ensure 32/64 bit portability: used fixed size data types only e.g. boost::uint32_t | - //|------------------------------------------------------------------------------------- - - std::int32_t version = readNumberC(); + while (readNumberC()) //files + { + //attention: order of function argument evaluation is undefined! So do it one after the other... + const Zstring shortName = readStringUtf8(); //file name - if (version != FILE_FORMAT_VER) //read file format version - throw FileError(_("Incompatible synchronization database format:") + L" \n" + L"\"" + filename + L"\""); + const std::int64_t modTime = readNumberC(); + const std::uint64_t fileSize = readNumberC(); + const FileId fileID = readFileId(); - streamList.clear(); + dirCont.addSubFile(shortName, + FileDescriptor(modTime, fileSize, fileID)); + } - boost::uint32_t dbCount = readNumberC(); //number of databases: one for each sync-pair - while (dbCount-- != 0) + while (readNumberC()) //symlinks { - //DB id of partner databases - const CharArray tmp2 = readArrayC(); - const std::string sessionID(tmp2->begin(), tmp2->end()); - - CharArray buffer = readArrayC(); //read db-entry stream (containing DirInformation) + //attention: order of function argument evaluation is undefined! So do it one after the other... + const Zstring shortName = readStringUtf8(); //file name + const std::int64_t modTime = readNumberC(); + const Zstring targetPath = readStringUtf8(); //file name + const LinkDescriptor::LinkType linkType = static_cast(readNumberC()); + + dirCont.addSubLink(shortName, + LinkDescriptor(modTime, targetPath, linkType)); + } - streamList.insert(std::make_pair(sessionID, buffer)); + while (readNumberC()) //directories + { + const Zstring shortName = readStringUtf8(); //directory name + DirContainer& subDir = dirCont.addSubDir(shortName); + recurse(subDir); } } }; -namespace -{ -StreamMapping loadStreams(const Zstring& filename) //throw FileError -{ - if (!zen::fileExists(filename)) - throw FileErrorDatabaseNotExisting(_("Initial synchronization:") + L" \n\n" + - _("One of the FreeFileSync database files is not yet existing:") + L" \n" + - L"\"" + filename + L"\""); - - try - { - //read format description (uncompressed) - FileInputStreamDB uncompressed(filename); //throw FileError - - wxZlibInputStream input(uncompressed, wxZLIB_ZLIB); - StreamMapping streamList; - ReadFileStream(input, filename, streamList); - return streamList; - } - catch (const std::bad_alloc&) //this is most likely caused by a corrupted database file +//save/load DirContainer +void saveFile(const StreamMapping& streamList, const Zstring& filename) //throw FileError +{ { - throw FileError(_("Error reading from synchronization database:") + L" (bad_alloc)"); - } -} + FileOutputStream rawStream(filename); //throw FileError + //write FreeFileSync file identifier + rawStream.Write(FILE_FORMAT_DESCR, sizeof(FILE_FORMAT_DESCR)); //throw FileError -DirInfoPtr parseStream(const std::vector& stream, const Zstring& fileName) //throw FileError -> return value always bound! -{ - try - { - //read streams into DirInfo - auto dirInfo = std::make_shared(); - wxMemoryInputStream buffer(&stream[0], stream.size()); //convert char-array to inputstream: no copying, ownership not transferred - ReadDirInfo(buffer, fileName, *dirInfo); //throw FileError - return dirInfo; - } - catch (const std::bad_alloc&) //this is most likely caused by a corrupted database file - { - throw FileError(_("Error reading from synchronization database:") + L" (bad_alloc)"); - } -} -} + wxZlibOutputStream compressed(rawStream, 4, wxZLIB_ZLIB); + /* 4 - best compromise between speed and compression: (scanning 200.000 objects) + 0 (uncompressed) 8,95 MB - 422 ms + 2 2,07 MB - 470 ms + 4 1,87 MB - 500 ms + 6 1,77 MB - 613 ms + 9 (maximal compression) 1,74 MB - 3330 ms */ + CheckedWriter cw(compressed, filename); -std::pair zen::loadFromDisk(const BaseDirMapping& baseMapping) //throw FileError -{ - const Zstring fileNameLeft = getDBFilename(baseMapping); - const Zstring fileNameRight = getDBFilename(baseMapping); + //save file format version + cw.writeNumberC(FILE_FORMAT_VER); - //read file data: list of session ID + DirInfo-stream - const StreamMapping streamListLeft = ::loadStreams(fileNameLeft); //throw FileError - const StreamMapping streamListRight = ::loadStreams(fileNameRight); //throw FileError + //save stream list + cw.writeNumberC(static_cast(streamList.size())); //number of database records: one for each sync-pair - //find associated session: there can be at most one session within intersection of left and right ids - StreamMapping::const_iterator streamLeft = streamListLeft .end(); - StreamMapping::const_iterator streamRight = streamListRight.end(); - for (auto iterLeft = streamListLeft.begin(); iterLeft != streamListLeft.end(); ++iterLeft) - { - auto iterRight = streamListRight.find(iterLeft->first); - if (iterRight != streamListRight.end()) + for (auto iter = streamList.begin(); iter != streamList.end(); ++iter) { - streamLeft = iterLeft; - streamRight = iterRight; - break; + cw.writeStringC(iter->first ); //sync session id + cw.writeStringC(iter->second); //DirInformation stream } } - - if (streamLeft == streamListLeft .end() || - streamRight == streamListRight.end() || - !streamLeft ->second.get() || - !streamRight->second.get()) - throw FileErrorDatabaseNotExisting(_("Initial synchronization:") + L" \n\n" + - _("Database files do not share a common synchronization session:") + L" \n" + - L"\"" + fileNameLeft + L"\"\n" + - L"\"" + fileNameRight + L"\""); - //read streams into DirInfo - DirInfoPtr dirInfoLeft = parseStream(*streamLeft ->second, fileNameLeft); //throw FileError - DirInfoPtr dirInfoRight = parseStream(*streamRight->second, fileNameRight); //throw FileError - - return std::make_pair(dirInfoLeft, dirInfoRight); + //(try to) hide database file +#ifdef FFS_WIN + ::SetFileAttributes(zen::applyLongPathPrefix(filename).c_str(), FILE_ATTRIBUTE_HIDDEN); +#endif } -//------------------------------------------------------------------------------------------------------------------------- template -class SaveDirInfo : public WriteOutputStream +class StreamGenerator : private CheckedWriter { public: - SaveDirInfo(const BaseDirMapping& baseMapping, const DirContainer* oldDirInfo, const Zstring& errorObjName, wxOutputStream& stream) : WriteOutputStream(errorObjName, stream) + static MemoryStream execute(const BaseDirMapping& baseMapping, const DirContainer* oldDirInfo, const Zstring& errorObjName) { - //save filter settings - baseMapping.getFilter()->saveFilter(getStream()); - check(); + wxMemoryOutputStream buffer; + StreamGenerator(baseMapping, oldDirInfo, errorObjName, buffer); - //start recursion - execute(baseMapping, oldDirInfo); + MemoryStream output; + output.resize(buffer.GetSize()); + buffer.CopyTo(&*output.begin(), buffer.GetSize()); + return output; } private: - void execute(const HierarchyObject& hierObj, const DirContainer* oldDirInfo) + StreamGenerator(const BaseDirMapping& baseMapping, const DirContainer* oldDirInfo, const Zstring& errorObjName, wxOutputStream& stream) : CheckedWriter(stream, errorObjName) + { + recurse(baseMapping, oldDirInfo); + } + + void recurse(const HierarchyObject& hierObj, const DirContainer* oldDirInfo) { - std::for_each(hierObj.refSubFiles().begin(), hierObj.refSubFiles().end(), boost::bind(&SaveDirInfo::processFile, this, _1, oldDirInfo)); + // for (const auto& fileMap : hierObj.refSubFiles()) { processFile(fileMap, oldDirInfo); }); ! + + std::for_each(hierObj.refSubFiles().begin(), hierObj.refSubFiles().end(), [&](const FileMapping& fileMap) { this->processFile(fileMap, oldDirInfo); }); writeNumberC(false); //mark last entry - std::for_each(hierObj.refSubLinks().begin(), hierObj.refSubLinks().end(), boost::bind(&SaveDirInfo::processLink, this, _1, oldDirInfo)); + std::for_each(hierObj.refSubLinks().begin(), hierObj.refSubLinks().end(), [&](const SymLinkMapping& linkObj) { this->processLink(linkObj, oldDirInfo); }); writeNumberC(false); //mark last entry - std::for_each(hierObj.refSubDirs ().begin(), hierObj.refSubDirs ().end(), boost::bind(&SaveDirInfo::processDir, this, _1, oldDirInfo)); + std::for_each(hierObj.refSubDirs ().begin(), hierObj.refSubDirs ().end(), [&](const DirMapping& dirMap) { this->processDir(dirMap, oldDirInfo); }); writeNumberC(false); //mark last entry } + void writeStringUtf8(const Zstring& str) { writeStringC(utf8CvrtTo>(str)); } + + void writeFileId(const FileId& id) + { + writeNumberC(id.first ); //device id + writeNumberC(id.second); //file id + } + void processFile(const FileMapping& fileMap, const DirContainer* oldParentDir) { if (fileMap.getCategory() == FILE_EQUAL) //data in sync: write current state @@ -307,9 +270,10 @@ private: if (!fileMap.isEmpty()) { writeNumberC(true); //mark beginning of entry - writeStringC(fileMap.getShortName()); //save respecting case! (Windows) - writeNumberC(to(fileMap.getLastWriteTime())); //last modification time - writeNumberC(to(fileMap.getFileSize())); //filesize + writeStringUtf8(fileMap.getShortName()); //save respecting case! (Windows) + writeNumberC(to(fileMap.getLastWriteTime())); + writeNumberC(to(fileMap.getFileSize())); + writeFileId(fileMap.getFileId()); } } else //not in sync: reuse last synchronous state @@ -320,9 +284,10 @@ private: if (iter != oldParentDir->files.end()) { writeNumberC(true); //mark beginning of entry - writeStringC(iter->first); //save respecting case! (Windows) - writeNumberC(to(iter->second.lastWriteTimeRaw)); //last modification time - writeNumberC(to(iter->second.fileSize)); //filesize + writeStringUtf8(iter->first); //save respecting case! (Windows) + writeNumberC(to(iter->second.lastWriteTimeRaw)); + writeNumberC(to(iter->second.fileSize)); + writeFileId(iter->second.id); } } } @@ -335,9 +300,9 @@ private: if (!linkObj.isEmpty()) { writeNumberC(true); //mark beginning of entry - writeStringC(linkObj.getShortName()); //save respecting case! (Windows) - writeNumberC(to(linkObj.getLastWriteTime())); //last modification time - writeStringC(linkObj.getTargetPath()); + writeStringUtf8(linkObj.getShortName()); //save respecting case! (Windows) + writeNumberC(to(linkObj.getLastWriteTime())); + writeStringUtf8(linkObj.getTargetPath()); writeNumberC(linkObj.getLinkType()); } } @@ -349,9 +314,9 @@ private: if (iter != oldParentDir->links.end()) { writeNumberC(true); //mark beginning of entry - writeStringC(iter->first); //save respecting case! (Windows) - writeNumberC(to(iter->second.lastWriteTimeRaw)); //last modification time - writeStringC(iter->second.targetPath); + writeStringUtf8(iter->first); //save respecting case! (Windows) + writeNumberC(to(iter->second.lastWriteTimeRaw)); + writeStringUtf8(iter->second.targetPath); writeNumberC(iter->second.type); } } @@ -379,8 +344,8 @@ private: if (!dirMap.isEmpty()) { writeNumberC(true); //mark beginning of entry - writeStringC(dirMap.getShortName()); //save respecting case! (Windows) - execute(dirMap, oldDir); //recurse + writeStringUtf8(dirMap.getShortName()); //save respecting case! (Windows) + recurse(dirMap, oldDir); } } else //not in sync: reuse last synchronous state @@ -388,8 +353,8 @@ private: if (oldDir) { writeNumberC(true); //mark beginning of entry - writeStringC(*oldDirName); //save respecting case! (Windows) - execute(dirMap, oldDir); //recurse + writeStringUtf8(*oldDirName); //save respecting case! (Windows) + recurse(dirMap, oldDir); return; } //no data is also a "synchronous state"! @@ -408,69 +373,53 @@ private: break; case DIR_DIFFERENT_METADATA: writeNumberC(true); - writeStringC(dirMap.getShortName()); + writeStringUtf8(dirMap.getShortName()); //ATTENTION: strictly this is a violation of the principle of reporting last synchronous state! //however in this case this will result in "last sync unsuccessful" for this directory within algorithm, which is fine - execute(dirMap, oldDir); //recurse and save sub-items which are in sync + recurse(dirMap, oldDir); //recurse and save sub-items which are in sync break; } } } }; +} +//####################################################################################################################################### -class WriteFileStream : public WriteOutputStream +std::pair zen::loadFromDisk(const BaseDirMapping& baseMapping) //throw FileError { -public: - WriteFileStream(const StreamMapping& streamList, const Zstring& filename, wxOutputStream& stream) : WriteOutputStream(filename, stream) - { - //save file format version - writeNumberC(FILE_FORMAT_VER); + const Zstring fileNameLeft = getDBFilename(baseMapping); + const Zstring fileNameRight = getDBFilename(baseMapping); - writeNumberC(static_cast(streamList.size())); //number of database records: one for each sync-pair + //read file data: list of session ID + DirInfo-stream + const StreamMapping streamListLeft = ::loadStreams(fileNameLeft); //throw FileError + const StreamMapping streamListRight = ::loadStreams(fileNameRight); //throw FileError - for (StreamMapping::const_iterator i = streamList.begin(); i != streamList.end(); ++i) + //find associated session: there can be at most one session within intersection of left and right ids + StreamMapping::const_iterator streamLeft = streamListLeft .end(); + StreamMapping::const_iterator streamRight = streamListRight.end(); + for (auto iterLeft = streamListLeft.begin(); iterLeft != streamListLeft.end(); ++iterLeft) + { + auto iterRight = streamListRight.find(iterLeft->first); + if (iterRight != streamListRight.end()) { - //sync session id - writeArrayC(std::vector(i->first.begin(), i->first.end())); - - //write DirInformation stream - writeArrayC(*(i->second)); + streamLeft = iterLeft; + streamRight = iterRight; + break; } } -}; + if (streamLeft == streamListLeft .end() || + streamRight == streamListRight.end()) + throw FileErrorDatabaseNotExisting(_("Initial synchronization:") + L" \n\n" + + _("Database files do not share a common synchronization session:") + L" \n" + + L"\"" + fileNameLeft + L"\"\n" + + L"\"" + fileNameRight + L"\""); + //read streams into DirInfo + DirInfoPtr dirInfoLeft = StreamParser::execute(streamLeft ->second, fileNameLeft); //throw FileError + DirInfoPtr dirInfoRight = StreamParser::execute(streamRight->second, fileNameRight); //throw FileError -//save/load DirContainer -void saveFile(const StreamMapping& streamList, const Zstring& filename) //throw FileError -{ - { - //write format description (uncompressed) - FileOutputStreamDB uncompressed(filename); //throw FileError - - wxZlibOutputStream output(uncompressed, 4, wxZLIB_ZLIB); - /* 4 - best compromise between speed and compression: (scanning 200.000 objects) - 0 (uncompressed) 8,95 MB - 422 ms - 2 2,07 MB - 470 ms - 4 1,87 MB - 500 ms - 6 1,77 MB - 613 ms - 9 (maximal compression) 1,74 MB - 3330 ms */ - - WriteFileStream(streamList, filename, output); - } - //(try to) hide database file -#ifdef FFS_WIN - ::SetFileAttributes(zen::applyLongPathPrefix(filename).c_str(), FILE_ATTRIBUTE_HIDDEN); -#endif -} - - -bool equalEntry(const MemoryStreamPtr& lhs, const MemoryStreamPtr& rhs) -{ - if (!lhs.get() || !rhs.get()) - return lhs.get() == rhs.get(); - - return *lhs == *rhs; + return std::make_pair(dirInfoLeft, dirInfoRight); } @@ -522,12 +471,10 @@ void zen::saveToDisk(const BaseDirMapping& baseMapping) //throw FileError try { if (streamLeft != streamListLeft .end() && - streamRight != streamListRight.end() && - streamLeft ->second.get() && - streamRight->second.get()) + streamRight != streamListRight.end()) { - oldDirInfoLeft = parseStream(*streamLeft ->second, dbNameLeft); //throw FileError - oldDirInfoRight = parseStream(*streamRight->second, dbNameRight); //throw FileError + oldDirInfoLeft = StreamParser::execute(streamLeft ->second, dbNameLeft ); //throw FileError + oldDirInfoRight = StreamParser::execute(streamRight->second, dbNameRight); //throw FileError } } catch (FileError&) @@ -538,28 +485,13 @@ void zen::saveToDisk(const BaseDirMapping& baseMapping) //throw FileError } //create new database entries - MemoryStreamPtr newStreamLeft = std::make_shared>(); - { - wxMemoryOutputStream buffer; - const DirContainer* oldDir = oldDirInfoLeft.get() ? &oldDirInfoLeft->baseDirContainer : NULL; - SaveDirInfo(baseMapping, oldDir, dbNameLeft, buffer); - newStreamLeft->resize(buffer.GetSize()); //convert output stream to char-array - buffer.CopyTo(&(*newStreamLeft)[0], buffer.GetSize()); // - } - - MemoryStreamPtr newStreamRight = std::make_shared>(); - { - wxMemoryOutputStream buffer; - const DirContainer* oldDir = oldDirInfoRight.get() ? &oldDirInfoRight->baseDirContainer : NULL; - SaveDirInfo(baseMapping, oldDir, dbNameRight, buffer); - newStreamRight->resize(buffer.GetSize()); //convert output stream to char-array - buffer.CopyTo(&(*newStreamRight)[0], buffer.GetSize()); // - } + MemoryStream newStreamLeft = StreamGenerator::execute(baseMapping, oldDirInfoLeft .get() ? &oldDirInfoLeft ->baseDirContainer : NULL, dbNameLeft); + MemoryStream newStreamRight = StreamGenerator::execute(baseMapping, oldDirInfoRight.get() ? &oldDirInfoRight->baseDirContainer : NULL, dbNameRight); //check if there is some work to do at all { - const bool updateRequiredLeft = streamLeft == streamListLeft .end() || !equalEntry(newStreamLeft, streamLeft ->second); - const bool updateRequiredRight = streamRight == streamListRight.end() || !equalEntry(newStreamRight, streamRight->second); + const bool updateRequiredLeft = streamLeft == streamListLeft .end() || newStreamLeft != streamLeft ->second; + const bool updateRequiredRight = streamRight == streamListRight.end() || newStreamRight != streamRight->second; //some users monitor the *.ffs_db file with RTS => don't touch the file if it isnt't strictly needed if (!updateRequiredLeft && !updateRequiredRight) return; @@ -579,10 +511,10 @@ void zen::saveToDisk(const BaseDirMapping& baseMapping) //throw FileError streamListRight.insert(std::make_pair(sessionID, newStreamRight)); //write (temp-) files... - zen::ScopeGuard guardTempFileLeft = zen::makeGuard([&]() {zen::removeFile(dbNameLeftTmp); }); + zen::ScopeGuard guardTempFileLeft = zen::makeGuard([&] {zen::removeFile(dbNameLeftTmp); }); saveFile(streamListLeft, dbNameLeftTmp); //throw FileError - zen::ScopeGuard guardTempFileRight = zen::makeGuard([&]() {zen::removeFile(dbNameRightTmp); }); + zen::ScopeGuard guardTempFileRight = zen::makeGuard([&] {zen::removeFile(dbNameRightTmp); }); saveFile(streamListRight, dbNameRightTmp); //throw FileError //operation finished: rename temp files -> this should work transactionally: diff --git a/lib/db_file.h b/lib/db_file.h index d6d765cc..0413c404 100644 --- a/lib/db_file.h +++ b/lib/db_file.h @@ -14,11 +14,8 @@ namespace zen { const Zstring SYNC_DB_FILE_ENDING = Zstr(".ffs_db"); -void saveToDisk(const BaseDirMapping& baseMapping); //throw FileError - struct DirInformation { - HardFilter::FilterRef filter; //filter settings (used when retrieving directory data) DirContainer baseDirContainer; //hierarchical directory information }; typedef std::shared_ptr DirInfoPtr; @@ -26,6 +23,8 @@ typedef std::shared_ptr DirInfoPtr; DEFINE_NEW_FILE_ERROR(FileErrorDatabaseNotExisting); std::pair loadFromDisk(const BaseDirMapping& baseMapping); //throw FileError, FileErrorDatabaseNotExisting -> return value always bound! + +void saveToDisk(const BaseDirMapping& baseMapping); //throw FileError } #endif // DBFILE_H_INCLUDED diff --git a/lib/detect_renaming.cpp b/lib/detect_renaming.cpp deleted file mode 100644 index 39e7eb4b..00000000 --- a/lib/detect_renaming.cpp +++ /dev/null @@ -1,285 +0,0 @@ -// ************************************************************************** -// * This file is part of the FreeFileSync project. It is distributed under * -// * GNU General Public License: http://www.gnu.org/licenses/gpl.html * -// * Copyright (C) 2008-2011 ZenJu (zhnmju123 AT gmx.de) * -// ************************************************************************** - -#include "detect_renaming.h" -#include -#include -#include - -using namespace FreeFileSync; - -/*detect renamed files: -Example: - X -> |_| Create right -|_| -> Y Delete right - -is detected as: - -Rename Y to X on right - -Algorithm: ----------- -DB-file left ---filename, Metadata(=:MD)---> DB-file right - /|\ | - | fileID, MD - fileID, MD | - | \|/ - X Y - -*/ - - -class FindDBAssoc -{ - /* - load and associate db-files by filename and metadata(size, date) - fileID, MD |-> fileID - */ -public: - struct AssocKey - { - AssocKey(const Utility::FileID& fileId, - const wxLongLong& lastWriteTimeRaw, - const wxULongLong& fileSize); - - bool operator<(const AssocKey& other) const; - - Utility::FileID fileId_; - wxLongLong lastWriteTimeRaw_; - wxULongLong fileSize_; - }; - - FindDBAssoc(const FreeFileSync::BaseDirMapping& baseMapping, - std::map& assocDBLeftToRight); - -private: - void recurse(const DirContainer& leftSide, const DirContainer& rightSide); - - std::map& assocDBLeftToRight_; //--> -}; - - -inline -FindDBAssoc::AssocKey::AssocKey(const Utility::FileID& fileId, - const wxLongLong& lastWriteTimeRaw, - const wxULongLong& fileSize) : - fileId_(fileId), - lastWriteTimeRaw_(lastWriteTimeRaw), - fileSize_(fileSize) {} - - -inline -bool FindDBAssoc::AssocKey::operator<(const AssocKey& other) const -{ - if (fileId_ != other.fileId_) - return fileId_ < other.fileId_; - - if (lastWriteTimeRaw_ != other.lastWriteTimeRaw_) - return lastWriteTimeRaw_ < other.lastWriteTimeRaw_; - - return fileSize_ < other.fileSize_; -} - - -FindDBAssoc::FindDBAssoc(const FreeFileSync::BaseDirMapping& baseMapping, - std::map& assocDBLeftToRight) : assocDBLeftToRight_(assocDBLeftToRight) -{ - try - { - std::pair dbInfo = - FreeFileSync::loadFromDisk(baseMapping); //throw (FileError) - - recurse(dbInfo.first->baseDirContainer, - dbInfo.second->baseDirContainer); - } - catch (...) {} //swallow... -} - - -void FindDBAssoc::recurse(const DirContainer& leftSide, const DirContainer& rightSide) -{ - for (DirContainer::SubFileList::const_iterator i = leftSide.getSubFiles().begin(); i != leftSide.getSubFiles().end(); ++i) - { - const FileDescriptor& fileDescrI = i->second.getData(); - if (!fileDescrI.fileIdentifier.isNull()) //fileIdentifier may be NULL - { - const DirContainer::SubFileList::const_iterator j = rightSide.getSubFiles().find(i->first); - - //find files that exist on left and right - if (j != rightSide.getSubFiles().end()) - { - const FileDescriptor& fileDescrJ = j->second.getData(); - if (!fileDescrJ.fileIdentifier.isNull()) //fileIdentifier may be NULL - { - if ( fileDescrI.lastWriteTimeRaw == fileDescrJ.lastWriteTimeRaw && - fileDescrI.fileSize == fileDescrJ.fileSize) - { - assocDBLeftToRight_[AssocKey(fileDescrI.fileIdentifier, - fileDescrI.lastWriteTimeRaw, - fileDescrI.fileSize)] = fileDescrJ.fileIdentifier; - } - } - } - } - } - - //----------------------------------------------------------------------------------------------- - for (DirContainer::SubDirList::const_iterator i = leftSide.getSubDirs().begin(); i != leftSide.getSubDirs().end(); ++i) - { - const DirContainer::SubDirList::const_iterator j = rightSide.getSubDirs().find(i->first); - - //directories that exist on both sides - if (j != rightSide.getSubDirs().end()) - { - recurse(i->second, j->second); //recurse into subdirectories - } - } -} - - - -class FindRenameCandidates -{ -public: - FindRenameCandidates(FreeFileSync::BaseDirMapping& baseMapping) - { - FindDBAssoc(baseMapping, - assocDBLeftToRight); - - if (!assocDBLeftToRight.empty()) - recurse(baseMapping); - } - - void getRenameCandidates(std::vector >& renameOnLeft, - std::vector >& renameOnRight); - -private: - void recurse(HierarchyObject& hierObj) - { - //files - std::for_each(hierObj.subFiles.begin(), hierObj.subFiles.end(), - boost::bind(&FindRenameCandidates::processFile, this, _1)); - - //directories - std::for_each(hierObj.subDirs.begin(), hierObj.subDirs.end(), - boost::bind(&FindRenameCandidates::recurse, this, _1));//recursion - } - - void processFile(FileMapping& fileObj) - { - switch (fileObj.getSyncOperation()) //evaluate comparison result and sync direction - { - case SO_CREATE_NEW_LEFT: - if (!fileObj.getFileID().isNull()) //fileIdentifier may be NULL - createLeft[FindDBAssoc::AssocKey(fileObj.getFileID(), - fileObj.getLastWriteTime(), - fileObj.getFileSize())] = &fileObj; - break; - - case SO_CREATE_NEW_RIGHT: - if (!fileObj.getFileID().isNull()) //fileIdentifier may be NULL - createRight.push_back(&fileObj); - break; - - case SO_DELETE_LEFT: - if (!fileObj.getFileID().isNull()) //fileIdentifier may be NULL - deleteLeft.push_back(&fileObj); - break; - - case SO_DELETE_RIGHT: - if (!fileObj.getFileID().isNull()) //fileIdentifier may be NULL - deleteRight[FindDBAssoc::AssocKey(fileObj.getFileID(), - fileObj.getLastWriteTime(), - fileObj.getFileSize())] = &fileObj; - break; - - case SO_OVERWRITE_RIGHT: - case SO_OVERWRITE_LEFT: - case SO_DO_NOTHING: - case SO_UNRESOLVED_CONFLICT: - break; - } - - } - - - std::vector createRight; //pointer always bound! - std::vector deleteLeft; // - // | - // \|/ - std::map assocDBLeftToRight; - // | - // \|/ - std::map deleteRight; //pointer always bound! - std::map createLeft; // - -}; - - - -void FindRenameCandidates::getRenameCandidates( - std::vector >& renameOnLeft, - std::vector >& renameOnRight) -{ - for (std::vector::const_iterator crRightIter = createRight.begin(); - crRightIter != createRight.end(); - ++crRightIter) - { - const FindDBAssoc::AssocKey assocDbKey((*crRightIter)->getFileID(), - (*crRightIter)->getLastWriteTime(), - (*crRightIter)->getFileSize()); - - const std::map::const_iterator assocDBIter = - assocDBLeftToRight.find(assocDbKey); - - if (assocDBIter != assocDBLeftToRight.end()) - { - std::map::const_iterator delRightIter = - deleteRight.find(FindDBAssoc::AssocKey(assocDBIter->second, //FileID of right side - assocDbKey.lastWriteTimeRaw_, - assocDbKey.fileSize_)); - - if (delRightIter != deleteRight.end()) - { - renameOnRight.push_back(std::make_pair(*crRightIter, delRightIter->second)); - } - } - } - //------------------------------------------------------------------------------------------------ - for (std::vector::const_iterator delLeftIter = deleteLeft.begin(); - delLeftIter != deleteLeft.end(); - ++delLeftIter) - { - const FindDBAssoc::AssocKey assocDbKey((*delLeftIter)->getFileID(), - (*delLeftIter)->getLastWriteTime(), - (*delLeftIter)->getFileSize()); - - const std::map::const_iterator assocDBIter = - assocDBLeftToRight.find(assocDbKey); - - if (assocDBIter != assocDBLeftToRight.end()) - { - std::map::const_iterator createLeftIter = - createLeft.find(FindDBAssoc::AssocKey(assocDBIter->second, //FileID of right side - assocDbKey.lastWriteTimeRaw_, - assocDbKey.fileSize_)); - - if (createLeftIter != createLeft.end()) - { - renameOnLeft.push_back(std::make_pair(createLeftIter->second, *delLeftIter)); - } - } - } -} - - -void FreeFileSync::getRenameCandidates(FreeFileSync::BaseDirMapping& baseMapping, //in - std::vector >& renameOnLeft, //out - std::vector >& renameOnRight) //out throw()! -{ - FindRenameCandidates(baseMapping).getRenameCandidates(renameOnLeft, renameOnRight); -} - diff --git a/lib/detect_renaming.h b/lib/detect_renaming.h deleted file mode 100644 index e94927c0..00000000 --- a/lib/detect_renaming.h +++ /dev/null @@ -1,26 +0,0 @@ -// ************************************************************************** -// * This file is part of the FreeFileSync project. It is distributed under * -// * GNU General Public License: http://www.gnu.org/licenses/gpl.html * -// * Copyright (C) 2008-2011 ZenJu (zhnmju123 AT gmx.de) * -// ************************************************************************** - -#ifndef DETECTRENAMING_H_INCLUDED -#define DETECTRENAMING_H_INCLUDED - -#include "../file_hierarchy.h" - - -//identify a file "create and delete"-operation as a file renaming! - -namespace zen -{ -typedef FileMapping* CreateOnLeft; -typedef FileMapping* DeleteOnLeft; -typedef FileMapping* CreateOnRight; -typedef FileMapping* DeleteOnRight; -void getRenameCandidates(zen::BaseDirMapping& baseMapping, //in - std::vector >& renameOnLeft, //out - std::vector >& renameOnRight); //out throw()! -} - -#endif // DETECTRENAMING_H_INCLUDED diff --git a/lib/dir_exist_async.h b/lib/dir_exist_async.h index 72741ee2..f59e9490 100644 --- a/lib/dir_exist_async.h +++ b/lib/dir_exist_async.h @@ -20,9 +20,7 @@ bool dirExistsUpdating(const Zstring& dirname, bool allowUserInteraction, Proces { using namespace zen; - std::wstring statusText = _("Searching for directory %x..."); - replace(statusText, L"%x", std::wstring(L"\"") + dirname + L"\"", false); - procCallback.reportStatus(statusText); + procCallback.reportStatus(replaceCpy(_("Searching for directory %x..."), L"%x", std::wstring(L"\"") + dirname + L"\"", false)); auto ft = async([=]() -> bool { diff --git a/lib/dir_lock.cpp b/lib/dir_lock.cpp index 735fd7b6..ab3c84ea 100644 --- a/lib/dir_lock.cpp +++ b/lib/dir_lock.cpp @@ -74,10 +74,10 @@ public: //ATTENTION: setting file pointer IS required! => use CreateFile/FILE_GENERIC_WRITE + SetFilePointerEx! //although CreateFile/FILE_APPEND_DATA without SetFilePointerEx works locally, it MAY NOT work on some network shares creating a 4 gig file!!! - const HANDLE fileHandle = ::CreateFile(applyLongPathPrefix(lockfilename_.c_str()).c_str(), + const HANDLE fileHandle = ::CreateFile(applyLongPathPrefix(lockfilename_).c_str(), GENERIC_READ | GENERIC_WRITE, //use both when writing over network, see comment in file_io.cpp FILE_SHARE_READ, - 0, + NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); @@ -340,8 +340,8 @@ std::string retrieveLockId(const Zstring& lockfilename) //throw FileError, Error void waitOnDirLock(const Zstring& lockfilename, DirLockCallback* callback) //throw FileError { - std::wstring infoMsg = _("Waiting while directory is locked (%x)..."); - replace(infoMsg, L"%x", std::wstring(L"\"") + lockfilename + L"\""); + const std::wstring infoMsg = replaceCpy(_("Waiting while directory is locked (%x)..."), L"%x", std::wstring(L"\"") + lockfilename + L"\""); + if (callback) callback->reportInfo(infoMsg); //--------------------------------------------------------------- @@ -408,8 +408,8 @@ void waitOnDirLock(const Zstring& lockfilename, DirLockCallback* callback) //thr long remainingSeconds = ((DETECT_EXITUS_INTERVAL - (wxGetLocalTimeMillis() - lockSilentStart)) / 1000).ToLong(); remainingSeconds = std::max(0L, remainingSeconds); - std::wstring remSecMsg = _P("1 sec", "%x sec", remainingSeconds); - replace(remSecMsg, L"%x", toString(remainingSeconds)); + const std::wstring remSecMsg = replaceCpy(_P("1 sec", "%x sec", remainingSeconds), L"%x", toString(remainingSeconds)); + callback->reportInfo(infoMsg + L" " + remSecMsg); } else @@ -441,7 +441,7 @@ bool tryLock(const Zstring& lockfilename) //throw FileError const HANDLE fileHandle = ::CreateFile(applyLongPathPrefix(lockfilename).c_str(), GENERIC_READ | GENERIC_WRITE, //use both when writing over network, see comment in file_io.cpp FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, - 0, + NULL, CREATE_NEW, FILE_ATTRIBUTE_NORMAL, NULL); @@ -472,7 +472,7 @@ bool tryLock(const Zstring& lockfilename) //throw FileError ::close(fileHandle); #endif - zen::ScopeGuard guardLockFile = zen::makeGuard([&]() { zen::removeFile(lockfilename); }); + ScopeGuard guardLockFile = zen::makeGuard([&] { zen::removeFile(lockfilename); }); //write UUID at the beginning of the file: this ID is a universal identifier for this lock (no matter what the path is, considering symlinks, etc.) writeLockInfo(lockfilename); //throw FileError diff --git a/lib/dir_name.cpp b/lib/dir_name.cpp index 71a3e9ef..55a4185c 100644 --- a/lib/dir_name.cpp +++ b/lib/dir_name.cpp @@ -40,7 +40,7 @@ void setDirectoryNameImpl(const wxString& dirname, wxDirPickerCtrl* dirPicker, w if (dirPicker && !dirFormatted.empty()) { Zstring dir = toZ(dirFormatted); //convert to Zstring first: we don't want to pass wxString by value and risk MT issues! - auto ft = async([=]() { return zen::dirExists(dir); }); + auto ft = async([=] { return zen::dirExists(dir); }); if (ft.timed_wait(boost::posix_time::milliseconds(timeout)) && ft.get()) //potentially slow network access: wait 200ms at most dirPicker->SetPath(dirFormatted); diff --git a/lib/localization.cpp b/lib/localization.cpp index e8ff6040..574910ea 100644 --- a/lib/localization.cpp +++ b/lib/localization.cpp @@ -301,6 +301,7 @@ wxLanguage mapLanguageDialect(wxLanguage language) //case wxLANGUAGE_PORTUGUESE_BRAZILIAN: //case wxLANGUAGE_KOREAN: //case wxLANGUAGE_UKRAINIAN: + //case wxLANGUAGE_CROATIAN: //variants of wxLANGUAGE_ARABIC case wxLANGUAGE_ARABIC_ALGERIA: diff --git a/lib/parallel_scan.cpp b/lib/parallel_scan.cpp index 96b167b8..1052a408 100644 --- a/lib/parallel_scan.cpp +++ b/lib/parallel_scan.cpp @@ -141,7 +141,7 @@ Windows 7: Windows XP: 1 Thread: 41s | 13s 1 Thread: 45s | 13s 2 Threads: 42s | 11s 2 Threads: 38s | 8s -=> Traversing does not take any advantage of file locality so that even multiple threads operating on the same disk impose no performance overhead! +=> Traversing does not take any advantage of file locality so that even multiple threads operating on the same disk impose no performance overhead! (even faster on XP) */ @@ -196,7 +196,7 @@ public: errorMsg.clear(); errorResponse.reset(); - //dummy.unlock(); + dummy.unlock(); //optimization for condition_variable::notify_one() conditionCanReportError.notify_one(); return rv; @@ -204,13 +204,13 @@ public: void processErrors(FillBufferCallback& callback) //context of main thread, call repreatedly { - boost::lock_guard dummy(lockErrorMsg); + boost::unique_lock dummy(lockErrorMsg); if (!errorMsg.empty() && !errorResponse.get()) { FillBufferCallback::HandleError rv = callback.reportError(copyStringTo(errorMsg)); //throw! errorResponse.reset(new FillBufferCallback::HandleError(rv)); - //dummy.unlock(); + dummy.unlock(); //optimization for condition_variable::notify_one() conditionGotResponse.notify_one(); } } @@ -293,6 +293,7 @@ private: }; //------------------------------------------------------------------------------------------------- + struct TraverserShared { public: @@ -372,7 +373,7 @@ void DirCallback::onFile(const Zchar* shortName, const Zstring& fullName, const Linux: retrieveFileID takes about 50% longer in VM! (avoidable because of redundant stat() call!) */ - output_.addSubFile(fileNameShort, FileDescriptor(details.lastWriteTimeRaw, details.fileSize)); + output_.addSubFile(fileNameShort, FileDescriptor(details.lastWriteTimeRaw, details.fileSize, details.id)); cfg.acb_.incItemsScanned(); //add 1 element to the progress indicator } @@ -547,8 +548,8 @@ void zen::fillBuffer(const std::set& keysToRead, //in zen::ScopeGuard guardWorker = zen::makeGuard([&]() { - std::for_each(worker.begin(), worker.end(), std::mem_fun_ref(&boost::thread::interrupt)); //interrupt all at once, then join - std::for_each(worker.begin(), worker.end(), std::mem_fun_ref(&boost::thread::join)); + std::for_each(worker.begin(), worker.end(), [](boost::thread& wt) { wt.interrupt(); }); //interrupt all at once, then join + std::for_each(worker.begin(), worker.end(), [](boost::thread& wt) { wt.join(); }); }); std::shared_ptr acb = std::make_shared(); diff --git a/lib/status_handler.h b/lib/status_handler.h index 390b4f0a..686c1f0e 100644 --- a/lib/status_handler.h +++ b/lib/status_handler.h @@ -7,7 +7,6 @@ #ifndef STATUSHANDLER_H_INCLUDED #define STATUSHANDLER_H_INCLUDED -#include #include #include @@ -45,21 +44,18 @@ struct ProcessCallback //note: this one must NOT throw in order to properly allow undoing setting of statistics! //it is in general paired with a call to requestUiRefresh() to compensate! - virtual void updateProcessedData(int objectsProcessed, zen::Int64 dataProcessed) = 0; //throw() + virtual void updateProcessedData(int objectsProcessed, zen::Int64 dataProcessed) = 0; //throw()!! //opportunity to abort must be implemented in a frequently executed method like requestUiRefresh() virtual void requestUiRefresh() = 0; //throw ? - //this method is triggered repeatedly by requestUiRefresh() and can be used to refresh the ui by dispatching pending events - virtual void forceUiRefresh() = 0; - //called periodically after data was processed: expected(!) to request GUI update - virtual void reportStatus(const wxString& text) = 0; //status info only, should not be logged! + virtual void reportStatus(const std::wstring& text) = 0; //status info only, should not be logged! //called periodically after data was processed: expected(!) to request GUI update - virtual void reportInfo(const wxString& text) = 0; + virtual void reportInfo(const std::wstring& text) = 0; - virtual void reportWarning(const wxString& warningMessage, bool& warningActive) = 0; + virtual void reportWarning(const std::wstring& warningMessage, bool& warningActive) = 0; //error handling: enum Response @@ -67,8 +63,8 @@ struct ProcessCallback IGNORE_ERROR = 10, RETRY }; - virtual Response reportError (const wxString& errorMessage) = 0; //recoverable error situation - virtual void reportFatalError(const wxString& errorMessage) = 0; //non-recoverable error situation + virtual Response reportError (const std::wstring& errorMessage) = 0; //recoverable error situation + virtual void reportFatalError(const std::wstring& errorMessage) = 0; //non-recoverable error situation }; @@ -86,6 +82,8 @@ class StatusHandler : public ProcessCallback, public AbortCallback public: StatusHandler() : abortRequested(false) {} + virtual void forceUiRefresh() = 0; + virtual void requestUiRefresh() { if (updateUiIsAllowed()) //test if specific time span between ui updates is over diff --git a/structures.cpp b/structures.cpp index 1612445c..c3b20886 100644 --- a/structures.cpp +++ b/structures.cpp @@ -13,7 +13,7 @@ using namespace zen; -wxString zen::getVariantName(CompareVariant var) +std::wstring zen::getVariantName(CompareVariant var) { switch (var) { @@ -22,13 +22,12 @@ wxString zen::getVariantName(CompareVariant var) case CMP_BY_TIME_SIZE: return _("File time and size"); } - assert(false); - return wxEmptyString; + return _("Error"); } -wxString zen::getVariantName(DirectionConfig::Variant var) +std::wstring zen::getVariantName(DirectionConfig::Variant var) { switch (var) { @@ -41,6 +40,7 @@ wxString zen::getVariantName(DirectionConfig::Variant var) case DirectionConfig::CUSTOM: return _("Custom"); } + assert(false); return _("Error"); } @@ -92,7 +92,7 @@ DirectionSet zen::getTwoWaySet() } -wxString MainConfiguration::getCompVariantName() const +std::wstring MainConfiguration::getCompVariantName() const { const CompareVariant firstVariant = firstPair.altCmpConfig.get() ? firstPair.altCmpConfig->compareVar : @@ -113,7 +113,7 @@ wxString MainConfiguration::getCompVariantName() const } -wxString MainConfiguration::getSyncVariantName() const +std::wstring MainConfiguration::getSyncVariantName() const { const DirectionConfig::Variant firstVariant = firstPair.altSyncConfig.get() ? firstPair.altSyncConfig->directionCfg.var : @@ -134,120 +134,64 @@ wxString MainConfiguration::getSyncVariantName() const } -wxString zen::getDescription(CompareFilesResult cmpRes) +std::wstring zen::getSymbol(CompareFilesResult cmpRes) { switch (cmpRes) { case FILE_LEFT_SIDE_ONLY: - return _("File/folder exists on left side only"); + return L"only <-"; case FILE_RIGHT_SIDE_ONLY: - return _("File/folder exists on right side only"); + return L"only ->"; case FILE_LEFT_NEWER: - return _("Left file is newer"); + return L"newer <-"; case FILE_RIGHT_NEWER: - return _("Right file is newer"); + return L"newer ->"; case FILE_DIFFERENT: - return _("Files have different content"); + return L"!="; case FILE_EQUAL: - return _("Both sides are equal"); - case FILE_DIFFERENT_METADATA: - return _("Files/folders differ in attributes only"); - case FILE_CONFLICT: - return _("Conflict/file cannot be categorized"); - } - - assert(false); - return wxEmptyString; -} - - -wxString zen::getSymbol(CompareFilesResult cmpRes) -{ - switch (cmpRes) - { - case FILE_LEFT_SIDE_ONLY: - return wxT("<|"); - case FILE_RIGHT_SIDE_ONLY: - return wxT("|>"); - case FILE_LEFT_NEWER: - return wxT("<<"); - case FILE_RIGHT_NEWER: - return wxT(">>"); - case FILE_DIFFERENT: - return wxT("!="); - case FILE_EQUAL: - return wxT("'=="); //added quotation mark to avoid error in Excel cell when exporting to *.cvs + return L"'=="; //added quotation mark to avoid error in Excel cell when exporting to *.cvs case FILE_CONFLICT: case FILE_DIFFERENT_METADATA: - return wxT("\\/\\->"); + return L"conflict"; } - assert(false); - return wxEmptyString; + return std::wstring(); } -wxString zen::getDescription(SyncOperation op) +std::wstring zen::getSymbol(SyncOperation op) { switch (op) { case SO_CREATE_NEW_LEFT: - return _("Copy new file/folder to left"); + return L"create <-"; case SO_CREATE_NEW_RIGHT: - return _("Copy new file/folder to right"); + return L"create ->"; case SO_DELETE_LEFT: - return _("Delete left file/folder"); + return L"delete <-"; case SO_DELETE_RIGHT: - return _("Delete right file/folder"); - case SO_OVERWRITE_LEFT: - return _("Overwrite left file/folder with right one"); - case SO_OVERWRITE_RIGHT: - return _("Overwrite right file/folder with left one"); - case SO_DO_NOTHING: - return _("Do nothing"); - case SO_EQUAL: - return _("Both sides are equal"); - case SO_COPY_METADATA_TO_LEFT: - return _("Copy file attributes only to left"); - case SO_COPY_METADATA_TO_RIGHT: - return _("Copy file attributes only to right"); - case SO_UNRESOLVED_CONFLICT: //not used on GUI, but in .csv - return _("Conflict/file cannot be categorized"); - }; - - assert(false); - return wxEmptyString; -} - - -wxString zen::getSymbol(SyncOperation op) -{ - switch (op) - { - case SO_CREATE_NEW_LEFT: - return wxT("*-"); - case SO_CREATE_NEW_RIGHT: - return wxT("-*"); - case SO_DELETE_LEFT: - return wxT("D-"); - case SO_DELETE_RIGHT: - return wxT("-D"); + return L"delete ->"; + case SO_MOVE_LEFT_SOURCE: + case SO_MOVE_LEFT_TARGET: + return L"move <-"; + case SO_MOVE_RIGHT_SOURCE: + case SO_MOVE_RIGHT_TARGET: + return L"move ->"; case SO_OVERWRITE_LEFT: case SO_COPY_METADATA_TO_LEFT: - return wxT("<-"); + return L"update <-"; case SO_OVERWRITE_RIGHT: case SO_COPY_METADATA_TO_RIGHT: - return wxT("->"); + return L"update ->"; case SO_DO_NOTHING: - return wxT(" -"); + return L" -"; case SO_EQUAL: - return wxT("'=="); //added quotation mark to avoid error in Excel cell when exporting to *.cvs + return L"'=="; //added quotation mark to avoid error in Excel cell when exporting to *.cvs case SO_UNRESOLVED_CONFLICT: - return wxT("\\/\\->"); + return L"conflict"; }; - assert(false); - return wxEmptyString; + return std::wstring(); } @@ -329,7 +273,7 @@ zen::Int64 resolve(size_t value, UnitTime unit, zen::Int64 defaultVal) zen::UInt64 resolve(size_t value, UnitSize unit, zen::UInt64 defaultVal) { - double out = value; + double out = 0; switch (unit) { case USIZE_NONE: @@ -337,10 +281,10 @@ zen::UInt64 resolve(size_t value, UnitSize unit, zen::UInt64 defaultVal) case USIZE_BYTE: return value; case USIZE_KB: - out *= 1024; + out = 1024.0 * value; break; case USIZE_MB: - out *= 1024 * 1024; + out = 1024 * 1024.0 * value; break; } return out >= to(std::numeric_limits::max()) ? //prevent overflow!!! diff --git a/structures.h b/structures.h index 47d34d0c..046b719e 100644 --- a/structures.h +++ b/structures.h @@ -7,15 +7,13 @@ #ifndef FREEFILESYNC_H_INCLUDED #define FREEFILESYNC_H_INCLUDED -#include #include +#include #include #include -#include #include - namespace zen { enum CompareVariant @@ -24,7 +22,7 @@ enum CompareVariant CMP_BY_CONTENT }; -wxString getVariantName(CompareVariant var); +std::wstring getVariantName(CompareVariant var); enum SymLinkHandling { @@ -89,8 +87,7 @@ CompareFilesResult convertToFilesResult(CompareSymlinkResult value) } -wxString getDescription(CompareFilesResult cmpRes); -wxString getSymbol(CompareFilesResult cmpRes); +std::wstring getSymbol(CompareFilesResult cmpRes); enum SyncOperation @@ -99,17 +96,24 @@ enum SyncOperation SO_CREATE_NEW_RIGHT, SO_DELETE_LEFT, SO_DELETE_RIGHT, + + SO_MOVE_LEFT_SOURCE, //SO_DELETE_LEFT - optimization! + SO_MOVE_LEFT_TARGET, //SO_CREATE_NEW_LEFT + + SO_MOVE_RIGHT_SOURCE, //SO_DELETE_RIGHT - optimization! + SO_MOVE_RIGHT_TARGET, //SO_CREATE_NEW_RIGHT + SO_OVERWRITE_LEFT, SO_OVERWRITE_RIGHT, SO_COPY_METADATA_TO_LEFT, //objects are already equal: transfer metadata only SO_COPY_METADATA_TO_RIGHT, // + SO_DO_NOTHING, //= both sides differ, but nothing will be synced SO_EQUAL, //= both sides are equal, so nothing will be synced SO_UNRESOLVED_CONFLICT }; -wxString getDescription(SyncOperation op); -wxString getSymbol(SyncOperation op); +std::wstring getSymbol (SyncOperation op); //method used for exporting .csv file only! struct DirectionSet @@ -171,7 +175,7 @@ bool operator==(const DirectionConfig& lhs, const DirectionConfig& rhs) //get sync directions: DON'T call for variant AUTOMATIC! DirectionSet extractDirections(const DirectionConfig& cfg); -wxString getVariantName(DirectionConfig::Variant var); +std::wstring getVariantName(DirectionConfig::Variant var); @@ -209,8 +213,8 @@ enum DeletionPolicy struct SyncConfig { SyncConfig(const DirectionConfig& directCfg, - const DeletionPolicy handleDel, - const wxString& customDelDir) : + const DeletionPolicy handleDel, + const Zstring& customDelDir) : directionCfg(directCfg), handleDeletion(handleDel), customDeletionDirectory(customDelDir) {} @@ -223,7 +227,7 @@ struct SyncConfig //misc options DeletionPolicy handleDeletion; //use Recycle, delete permanently or move to user-defined location - wxString customDeletionDirectory; + Zstring customDeletionDirectory; }; inline @@ -231,7 +235,7 @@ bool operator==(const SyncConfig& lhs, const SyncConfig& rhs) { return lhs.directionCfg == rhs.directionCfg && lhs.handleDeletion == rhs.handleDeletion && - (lhs.handleDeletion != MOVE_TO_CUSTOM_DIRECTORY || //only cmp custom deletion directory if required! + (lhs.handleDeletion != MOVE_TO_CUSTOM_DIRECTORY || //only compare deletion directory if required! lhs.customDeletionDirectory == rhs.customDeletionDirectory); } @@ -365,16 +369,14 @@ struct MainConfiguration MainConfiguration() : #ifdef FFS_WIN globalFilter(Zstr("*"), - Zstr("\ -\\System Volume Information\\\n\ -\\RECYCLED\\\n\ -\\RECYCLER\\\n\ -\\$Recycle.Bin\\")) {} + Zstr("\\System Volume Information\\\n") + Zstr("\\RECYCLED\\\n") + Zstr("\\RECYCLER\\\n") + Zstr("\\$Recycle.Bin\\")) {} #elif defined FFS_LINUX globalFilter(Zstr("*"), - Zstr("\ -/.Trash-*/\n\ -/.recycle/")) {} + Zstr("/.Trash-*/\n") + Zstr("/.recycle/")) {} #endif CompConfig cmpConfig; //global compare settings: may be overwritten by folder pair settings @@ -384,18 +386,18 @@ struct MainConfiguration FolderPairEnh firstPair; //there needs to be at least one pair! std::vector additionalPairs; - wxString getCompVariantName() const; - wxString getSyncVariantName() const; + std::wstring getCompVariantName() const; + std::wstring getSyncVariantName() const; }; inline bool operator==(const MainConfiguration& lhs, const MainConfiguration& rhs) { - return lhs.cmpConfig == rhs.cmpConfig && - lhs.globalFilter == rhs.globalFilter && - lhs.syncCfg == rhs.syncCfg && - lhs.firstPair == rhs.firstPair && + return lhs.cmpConfig == rhs.cmpConfig && + lhs.globalFilter == rhs.globalFilter && + lhs.syncCfg == rhs.syncCfg && + lhs.firstPair == rhs.firstPair && lhs.additionalPairs == rhs.additionalPairs; } diff --git a/synchronization.cpp b/synchronization.cpp index 66c7d262..8a5027be 100644 --- a/synchronization.cpp +++ b/synchronization.cpp @@ -8,7 +8,7 @@ #include #include #include -#include +#include #include #include #include @@ -32,36 +32,55 @@ using namespace zen; +namespace +{ +inline +int getCUD(const SyncStatistics& stat) +{ + return stat.getCreate() + + stat.getUpdate() + + stat.getDelete(); +} +} + void SyncStatistics::init() { - createLeft = 0; - createRight = 0; - overwriteLeft = 0; - overwriteRight = 0; - deleteLeft = 0; - deleteRight = 0; - conflict = 0; - rowsTotal = 0; + createLeft = 0; + createRight = 0; + updateLeft = 0; + updateRight = 0; + deleteLeft = 0; + deleteRight = 0; + conflict = 0; + rowsTotal = 0; } SyncStatistics::SyncStatistics(const FolderComparison& folderCmp) { init(); - std::for_each(begin(folderCmp), end(folderCmp), [&](const BaseDirMapping& baseMap) { getNumbersRecursively(baseMap); }); + std::for_each(begin(folderCmp), end(folderCmp), [&](const BaseDirMapping& baseMap) { recurse(baseMap); }); } SyncStatistics::SyncStatistics(const HierarchyObject& hierObj) { init(); - getNumbersRecursively(hierObj); + recurse(hierObj); +} + + +SyncStatistics::SyncStatistics(const FileMapping& fileObj) +{ + init(); + getFileNumbers(fileObj); + rowsTotal += 1; } inline -void SyncStatistics::getNumbersRecursively(const HierarchyObject& hierObj) +void SyncStatistics::recurse(const HierarchyObject& hierObj) { std::for_each(hierObj.refSubDirs().begin(), hierObj.refSubDirs().end(), [&](const DirMapping& dirObj) { getDirNumbers(dirObj); }); @@ -101,13 +120,25 @@ void SyncStatistics::getFileNumbers(const FileMapping& fileObj) ++deleteRight; break; + case SO_MOVE_LEFT_TARGET: + ++updateLeft; + break; + + case SO_MOVE_RIGHT_TARGET: + ++updateRight; + break; + + case SO_MOVE_LEFT_SOURCE: //ignore + case SO_MOVE_RIGHT_SOURCE: // + break; + case SO_OVERWRITE_LEFT: - ++overwriteLeft; + ++updateLeft; dataToProcess += fileObj.getFileSize(); break; case SO_OVERWRITE_RIGHT: - ++overwriteRight; + ++updateRight; dataToProcess += fileObj.getFileSize(); break; @@ -118,11 +149,11 @@ void SyncStatistics::getFileNumbers(const FileMapping& fileObj) break; case SO_COPY_METADATA_TO_LEFT: - ++overwriteLeft; + ++updateLeft; break; case SO_COPY_METADATA_TO_RIGHT: - ++overwriteRight; + ++updateRight; break; case SO_DO_NOTHING: @@ -155,12 +186,12 @@ void SyncStatistics::getLinkNumbers(const SymLinkMapping& linkObj) case SO_OVERWRITE_LEFT: case SO_COPY_METADATA_TO_LEFT: - ++overwriteLeft; + ++updateLeft; break; case SO_OVERWRITE_RIGHT: case SO_COPY_METADATA_TO_RIGHT: - ++overwriteRight; + ++updateRight; break; case SO_UNRESOLVED_CONFLICT: @@ -169,6 +200,11 @@ void SyncStatistics::getLinkNumbers(const SymLinkMapping& linkObj) firstConflicts.push_back(std::make_pair(linkObj.getObjRelativeName(), linkObj.getSyncOpConflict())); break; + case SO_MOVE_LEFT_SOURCE: + case SO_MOVE_RIGHT_SOURCE: + case SO_MOVE_LEFT_TARGET: + case SO_MOVE_RIGHT_TARGET: + assert(false); case SO_DO_NOTHING: case SO_EQUAL: break; @@ -209,20 +245,24 @@ void SyncStatistics::getDirNumbers(const DirMapping& dirObj) break; case SO_COPY_METADATA_TO_LEFT: - ++overwriteLeft; + ++updateLeft; break; case SO_COPY_METADATA_TO_RIGHT: - ++overwriteRight; + ++updateRight; break; + case SO_MOVE_LEFT_SOURCE: + case SO_MOVE_RIGHT_SOURCE: + case SO_MOVE_LEFT_TARGET: + case SO_MOVE_RIGHT_TARGET: + assert(false); case SO_DO_NOTHING: case SO_EQUAL: break; } - //recurse into sub-dirs - getNumbersRecursively(dirObj); + recurse(dirObj); } @@ -245,7 +285,7 @@ std::vector zen::extractSyncCfg(const MainConfiguration& output.push_back( FolderPairSyncCfg(syncCfg.directionCfg.var == DirectionConfig::AUTOMATIC, syncCfg.handleDeletion, - toZ(syncCfg.customDeletionDirectory))); + syncCfg.customDeletionDirectory)); } return output; @@ -257,7 +297,7 @@ namespace bool synchronizationNeeded(const SyncStatistics& statisticsTotal) { return statisticsTotal.getCreate() + - statisticsTotal.getOverwrite() + + statisticsTotal.getUpdate() + statisticsTotal.getDelete() + //conflicts (unless excluded) justify a sync! Also note: if this method returns false, no warning about unresolved conflicts were shown! statisticsTotal.getConflict() != 0; @@ -269,18 +309,18 @@ bool synchronizationNeeded(const SyncStatistics& statisticsTotal) bool significantDifferenceDetected(const SyncStatistics& folderPairStat) { //initial file copying shall not be detected as major difference - if (folderPairStat.getCreate() == 0 && - folderPairStat.getOverwrite() == 0 && - folderPairStat.getDelete() == 0 && - folderPairStat.getConflict() == 0) return false; + if (folderPairStat.getCreate() == 0 && + folderPairStat.getUpdate () == 0 && + folderPairStat.getDelete () == 0 && + folderPairStat.getConflict() == 0) return false; if (folderPairStat.getCreate() == 0 && - folderPairStat.getOverwrite() == 0 && - folderPairStat.getDelete() == 0 && - folderPairStat.getConflict() == 0) return false; + folderPairStat.getUpdate () == 0 && + folderPairStat.getDelete () == 0 && + folderPairStat.getConflict() == 0) return false; - const int changedRows = folderPairStat.getCreate() + - folderPairStat.getOverwrite() + - folderPairStat.getDelete() + + const int changedRows = folderPairStat.getCreate () + + folderPairStat.getUpdate () + + folderPairStat.getDelete () + folderPairStat.getConflict(); return changedRows >= 10 && changedRows > 0.5 * folderPairStat.getRowCount(); @@ -361,10 +401,10 @@ SyncProcess::SyncProcess(xmlAccess::OptionalDialogs& warnings, transactionalFileCopy_(transactionalFileCopy), m_warnings(warnings), procCallback(handler) - { -if (runWithBackgroundPriority) -procBackground.reset(new ScheduleForBackgroundProcessing); - } +{ + if (runWithBackgroundPriority) + procBackground.reset(new ScheduleForBackgroundProcessing); +} //-------------------------------------------------------------------------------------------------------------- namespace @@ -377,7 +417,7 @@ class DeletionHandling //e.g. generate name of alternate deletion directory (uni public: DeletionHandling(DeletionPolicy handleDel, const Zstring& custDelFolder, - const Zstring& baseDir, //with separator postfix + const Zstring& baseDirPf, //with separator postfix ProcessCallback& procCallback); ~DeletionHandling(); //always (try to) clean up, even if synchronization is aborted! @@ -387,9 +427,9 @@ public: void removeFile (const Zstring& relativeName) const; //throw FileError void removeFolder(const Zstring& relativeName) const; //throw FileError - const wxString& getTxtRemovingFile () const { return txtRemovingFile; } // - const wxString& getTxtRemovingSymLink() const { return txtRemovingSymlink; } //status text templates - const wxString& getTxtRemovingDir () const { return txtRemovingDirectory; } // + const std::wstring& getTxtRemovingFile () const { return txtRemovingFile; } // + const std::wstring& getTxtRemovingSymLink() const { return txtRemovingSymlink; } //status text templates + const std::wstring& getTxtRemovingDir () const { return txtRemovingDirectory; } // //evaluate whether a deletion will actually free space within a volume bool deletionFreesSpace() const; @@ -401,12 +441,12 @@ private: Zstring sessionDelDir; //target deletion folder for current folder pair (with timestamp, ends with path separator) - Zstring baseDir_; //with separator postfix + Zstring baseDirPf_; //with separator postfix //preloaded status texts: - wxString txtRemovingFile; - wxString txtRemovingSymlink; - wxString txtRemovingDirectory; + std::wstring txtRemovingFile; + std::wstring txtRemovingSymlink; + std::wstring txtRemovingDirectory; bool cleanedUp; }; @@ -414,41 +454,41 @@ private: DeletionHandling::DeletionHandling(DeletionPolicy handleDel, const Zstring& custDelFolder, - const Zstring& baseDir, //with separator postfix + const Zstring& baseDirPf, //with separator postfix ProcessCallback& procCallback) : deletionType(handleDel), procCallback_(&procCallback), - baseDir_(baseDir), + baseDirPf_(baseDirPf), cleanedUp(false) { #ifdef FFS_WIN - if (baseDir.empty() || - (deletionType == MOVE_TO_RECYCLE_BIN && recycleBinStatus(baseDir) != STATUS_REC_EXISTS)) + if (baseDirPf.empty() || + (deletionType == MOVE_TO_RECYCLE_BIN && recycleBinStatus(baseDirPf) != STATUS_REC_EXISTS)) deletionType = DELETE_PERMANENTLY; //Windows' ::SHFileOperation() will do this anyway, but we have a better and faster deletion routine (e.g. on networks) #endif switch (deletionType) { case DELETE_PERMANENTLY: - txtRemovingFile = replaceCpy(_("Deleting file %x" ), L"%x", L"\n\"%x\"", false); - txtRemovingDirectory = replaceCpy(_("Deleting folder %x" ), L"%x", L"\n\"%x\"", false); - txtRemovingSymlink = replaceCpy(_("Deleting symbolic link %x"), L"%x", L"\n\"%x\"", false); + txtRemovingFile = replaceCpy(_("Deleting file %x" ), L"%x", L"\"%x\"", false); + txtRemovingDirectory = replaceCpy(_("Deleting folder %x" ), L"%x", L"\"%x\"", false); + txtRemovingSymlink = replaceCpy(_("Deleting symbolic link %x"), L"%x", L"\"%x\"", false); break; case MOVE_TO_RECYCLE_BIN: - sessionDelDir = getSessionDeletionDir(baseDir_, Zstr("FFS ")); + sessionDelDir = getSessionDeletionDir(baseDirPf_, Zstr("FFS ")); - txtRemovingFile = replaceCpy(_("Moving file %x to recycle bin" ), L"%x", L"\n\"%x\"", false); - txtRemovingDirectory = replaceCpy(_("Moving folder %x to recycle bin" ), L"%x", L"\n\"%x\"", false); - txtRemovingSymlink = replaceCpy(_("Moving symbolic link %x to recycle bin"), L"%x", L"\n\"%x\"", false); + txtRemovingFile = replaceCpy(_("Moving file %x to recycle bin" ), L"%x", L"\"%x\"", false); + txtRemovingDirectory = replaceCpy(_("Moving folder %x to recycle bin" ), L"%x", L"\"%x\"", false); + txtRemovingSymlink = replaceCpy(_("Moving symbolic link %x to recycle bin"), L"%x", L"\"%x\"", false); break; case MOVE_TO_CUSTOM_DIRECTORY: sessionDelDir = getSessionDeletionDir(custDelFolder); - txtRemovingFile = replaceCpy(replaceCpy(_("Moving file %x to %y" ), L"%x", L"\n\"%x\"", false), L"%y", L"\"" + utf8CvrtTo(custDelFolder) + L"\"", false); - txtRemovingDirectory = replaceCpy(replaceCpy(_("Moving folder %x to %y" ), L"%x", L"\n\"%x\"", false), L"%y", L"\"" + utf8CvrtTo(custDelFolder) + L"\"", false); - txtRemovingSymlink = replaceCpy(replaceCpy(_("Moving symbolic link %x to %y"), L"%x", L"\n\"%x\"", false), L"%y", L"\"" + utf8CvrtTo(custDelFolder) + L"\"", false); + txtRemovingFile = replaceCpy(replaceCpy(_("Moving file %x to %y" ), L"%x", L"\"%x\"", false), L"%y", L"\"" + utf8CvrtTo(custDelFolder) + L"\"", false); + txtRemovingDirectory = replaceCpy(replaceCpy(_("Moving folder %x to %y" ), L"%x", L"\"%x\"", false), L"%y", L"\"" + utf8CvrtTo(custDelFolder) + L"\"", false); + txtRemovingSymlink = replaceCpy(replaceCpy(_("Moving symbolic link %x to %y"), L"%x", L"\"%x\"", false), L"%y", L"\"" + utf8CvrtTo(custDelFolder) + L"\"", false); break; } } @@ -497,12 +537,12 @@ struct CallbackRemoveDirImpl : public CallbackRemoveDir virtual void notifyFileDeletion(const Zstring& filename) { - delHandling_.procCallback_->reportStatus(replaceCpy(delHandling_.getTxtRemovingFile(), L"%x", utf8CvrtTo(filename))); + delHandling_.procCallback_->reportStatus(replaceCpy(delHandling_.getTxtRemovingFile(), L"%x", utf8CvrtTo(filename))); } virtual void notifyDirDeletion(const Zstring& dirname) { - delHandling_.procCallback_->reportStatus(replaceCpy(delHandling_.getTxtRemovingDir(), L"%x", utf8CvrtTo(dirname))); + delHandling_.procCallback_->reportStatus(replaceCpy(delHandling_.getTxtRemovingDir(), L"%x", utf8CvrtTo(dirname))); } private: @@ -513,7 +553,7 @@ private: void DeletionHandling::removeFile(const Zstring& relativeName) const { - const Zstring fullName = baseDir_ + relativeName; + const Zstring fullName = baseDirPf_ + relativeName; switch (deletionType) { @@ -562,7 +602,7 @@ void DeletionHandling::removeFile(const Zstring& relativeName) const void DeletionHandling::removeFolder(const Zstring& relativeName) const { - const Zstring fullName = baseDir_ + relativeName; + const Zstring fullName = baseDirPf_ + relativeName; switch (deletionType) { @@ -621,7 +661,7 @@ bool DeletionHandling::deletionFreesSpace() const case MOVE_TO_RECYCLE_BIN: return false; //in general... (unless Recycle Bin is full) case MOVE_TO_CUSTOM_DIRECTORY: - switch (zen::onSameVolume(baseDir_, sessionDelDir)) + switch (zen::onSameVolume(baseDirPf_, sessionDelDir)) { case IS_SAME_YES: return false; @@ -642,20 +682,21 @@ namespace class DiskSpaceNeeded { public: - DiskSpaceNeeded(const BaseDirMapping& baseObj, bool freeSpaceDelLeft, bool freeSpaceDelRight) : - freeSpaceDelLeft_(freeSpaceDelLeft), - freeSpaceDelRight_(freeSpaceDelRight) + static std::pair calculate(const BaseDirMapping& baseObj, bool freeSpaceDelLeft, bool freeSpaceDelRight) { - processRecursively(baseObj); + DiskSpaceNeeded inst(baseObj, freeSpaceDelLeft, freeSpaceDelRight); + return std::make_pair(inst.spaceNeededLeft, inst.spaceNeededRight); } - std::pair getSpaceTotal() const +private: + DiskSpaceNeeded(const BaseDirMapping& baseObj, bool freeSpaceDelLeft, bool freeSpaceDelRight) : + freeSpaceDelLeft_(freeSpaceDelLeft), + freeSpaceDelRight_(freeSpaceDelRight) { - return std::make_pair(spaceNeededLeft, spaceNeededRight); + recurse(baseObj); } -private: - void processRecursively(const HierarchyObject& hierObj) + void recurse(const HierarchyObject& hierObj) { //don't process directories @@ -664,33 +705,33 @@ private: switch (i->getSyncOperation()) //evaluate comparison result and sync direction { case SO_CREATE_NEW_LEFT: - spaceNeededLeft += to(i->getFileSize()); + spaceNeededLeft += to(i->getFileSize()); break; case SO_CREATE_NEW_RIGHT: - spaceNeededRight += to(i->getFileSize()); + spaceNeededRight += to(i->getFileSize()); break; case SO_DELETE_LEFT: if (freeSpaceDelLeft_) - spaceNeededLeft -= to(i->getFileSize()); + spaceNeededLeft -= to(i->getFileSize()); break; case SO_DELETE_RIGHT: if (freeSpaceDelRight_) - spaceNeededRight -= to(i->getFileSize()); + spaceNeededRight -= to(i->getFileSize()); break; case SO_OVERWRITE_LEFT: if (freeSpaceDelLeft_) - spaceNeededLeft -= to(i->getFileSize()); - spaceNeededLeft += to(i->getFileSize()); + spaceNeededLeft -= to(i->getFileSize()); + spaceNeededLeft += to(i->getFileSize()); break; case SO_OVERWRITE_RIGHT: if (freeSpaceDelRight_) - spaceNeededRight -= to(i->getFileSize()); - spaceNeededRight += to(i->getFileSize()); + spaceNeededRight -= to(i->getFileSize()); + spaceNeededRight += to(i->getFileSize()); break; case SO_DO_NOTHING: @@ -698,6 +739,10 @@ private: case SO_UNRESOLVED_CONFLICT: case SO_COPY_METADATA_TO_LEFT: case SO_COPY_METADATA_TO_RIGHT: + case SO_MOVE_LEFT_SOURCE: + case SO_MOVE_RIGHT_SOURCE: + case SO_MOVE_LEFT_TARGET: + case SO_MOVE_RIGHT_TARGET: break; } @@ -705,78 +750,20 @@ private: //[...] //recurse into sub-dirs - std::for_each(hierObj.refSubDirs().begin(), hierObj.refSubDirs().end(), [&](const HierarchyObject& subDir) { this->processRecursively(subDir); }); + std::for_each(hierObj.refSubDirs().begin(), hierObj.refSubDirs().end(), [&](const HierarchyObject& subDir) { this->recurse(subDir); }); //for (auto& subDir : hierObj.refSubDirs()) - // processRecursively(subDir); + // recurse(subDir); } const bool freeSpaceDelLeft_; const bool freeSpaceDelRight_; - zen::Int64 spaceNeededLeft; - zen::Int64 spaceNeededRight; + Int64 spaceNeededLeft; + Int64 spaceNeededRight; }; } //---------------------------------------------------------------------------------------- -//test if current sync-line will result in deletion of files or -//big file is overwritten by smaller one -> used to avoid disc space bottlenecks (at least if permanent deletion is active) -inline -bool diskSpaceIsReduced(const FileMapping& fileObj) -{ - switch (fileObj.getSyncOperation()) //evaluate comparison result and sync direction - { - case SO_DELETE_LEFT: - case SO_DELETE_RIGHT: - return true; - - case SO_OVERWRITE_LEFT: - return fileObj.getFileSize() > fileObj.getFileSize(); - - case SO_OVERWRITE_RIGHT: - return fileObj.getFileSize() < fileObj.getFileSize(); - - case SO_CREATE_NEW_LEFT: - case SO_CREATE_NEW_RIGHT: - case SO_DO_NOTHING: - case SO_EQUAL: - case SO_UNRESOLVED_CONFLICT: - case SO_COPY_METADATA_TO_LEFT: - case SO_COPY_METADATA_TO_RIGHT: - return false; - } - assert(false); - return false; //dummy -} - - -inline -bool diskSpaceIsReduced(const DirMapping& dirObj) -{ - switch (dirObj.getSyncOperation()) //evaluate comparison result and sync direction - { - case SO_DELETE_LEFT: - case SO_DELETE_RIGHT: - return true; - - case SO_OVERWRITE_LEFT: - case SO_OVERWRITE_RIGHT: - assert(false); - case SO_CREATE_NEW_LEFT: - case SO_CREATE_NEW_RIGHT: - case SO_DO_NOTHING: - case SO_EQUAL: - case SO_UNRESOLVED_CONFLICT: - case SO_COPY_METADATA_TO_LEFT: - case SO_COPY_METADATA_TO_RIGHT: - return false; - } - assert(false); - return false; //dummy -} -//--------------------------------------------------------------------------------------------------------------- - - class zen::SynchronizeFolderPair { public: @@ -801,36 +788,58 @@ public: txtOverwritingFile (replaceCpy(_("Overwriting file %x" ), L"%x", L"\"%x\"", false)), txtOverwritingLink (replaceCpy(_("Overwriting symbolic link %x"), L"%x", L"\"%x\"", false)), txtVerifying (replaceCpy(_("Verifying file %x" ), L"%x", L"\"%x\"", false)), - txtWritingAttributes(replaceCpy(_("Updating attributes of %x" ), L"%x", L"\"%x\"", false)) {} + txtWritingAttributes(replaceCpy(_("Updating attributes of %x" ), L"%x", L"\"%x\"", false)), + txtMovingFile (replaceCpy(replaceCpy(_("Moving file %x to %y"), L"%x", L"\"%x\"", false), L"%y", L"\"%y\"", false)) {} void startSync(BaseDirMapping& baseMap) { - //loop through all files twice; reason: first delete files (or overwrite big ones with smaller ones), then copy rest - execute(baseMap); - execute(baseMap); + runZeroPass(baseMap); //first process file moves + runPass(baseMap); //delete files (or overwrite big ones with smaller ones) + runPass(baseMap); //copy rest } private: enum PassId { - FIRST_PASS, //delete files - SECOND_PASS //create, modify + PASS_ONE, //delete files + PASS_TWO, //create, modify + PASS_NEVER //skip }; + static PassId getPass(const FileMapping& fileObj); + static PassId getPass(const SymLinkMapping& linkObj); + static PassId getPass(const DirMapping& dirObj); + + template + void prepare2StepMove(FileMapping& sourceObj, FileMapping& targetObj); //throw FileError + bool createParentDir(FileSystemObject& fsObj); //throw FileError + template + void manageFileMove(FileMapping& sourceObj, FileMapping& targetObj); //throw FileError + + void runZeroPass(HierarchyObject& hierObj); template - void execute(HierarchyObject& hierObj); + void runPass(HierarchyObject& hierObj); + + void synchronizeFile(FileMapping& fileObj) const; + template void synchronizeFileInt(FileMapping& fileObj, SyncOperation syncOp) const; + + void synchronizeLink(SymLinkMapping& linkObj) const; + template void synchronizeLinkInt(SymLinkMapping& linkObj, SyncOperation syncOp) const; + + void synchronizeFolder(DirMapping& dirObj) const; + template void synchronizeFolderInt(DirMapping& dirObj, SyncOperation syncOp) const; - void synchronizeFile (FileMapping& fileObj) const; - void synchronizeLink (SymLinkMapping& linkObj) const; - void synchronizeFolder(DirMapping& dirObj) const; + void reportInfo (const std::wstring& rawText, const Zstring& objname) const { procCallback_.reportInfo (replaceCpy(rawText, L"%x", utf8CvrtTo(objname))); }; + void reportStatus(const std::wstring& rawText, const Zstring& objname) const { procCallback_.reportStatus(replaceCpy(rawText, L"%x", utf8CvrtTo(objname))); }; //more low level helper - template - void deleteSymlink(const SymLinkMapping& linkObj) const; template - void copyFileUpdatingTo(const FileMapping& fileObj, const DelTargetCommand& cmd, FileDescriptor& sourceAttr) const; + void copyFileUpdatingTo(const FileMapping& fileObj, const DelTargetCommand& cmd, FileAttrib& newAttr) const; void verifyFileCopy(const Zstring& source, const Zstring& target) const; + template + const DeletionHandling& getDelHandling() const; + ProcessCallback& procCallback_; #ifdef FFS_WIN shadow::ShadowCopy* shadowCopyHandler_; //optional! @@ -843,198 +852,556 @@ private: const bool transactionalFileCopy; //preload status texts - const wxString txtCreatingFile; - const wxString txtCreatingLink; - const wxString txtCreatingFolder; - const wxString txtOverwritingFile; - const wxString txtOverwritingLink; - const wxString txtVerifying; - const wxString txtWritingAttributes; + const std::wstring txtCreatingFile; + const std::wstring txtCreatingLink; + const std::wstring txtCreatingFolder; + const std::wstring txtOverwritingFile; + const std::wstring txtOverwritingLink; + const std::wstring txtVerifying; + const std::wstring txtWritingAttributes; + const std::wstring txtMovingFile; }; +//--------------------------------------------------------------------------------------------------------------- +namespace zen +{ +template <> inline +const DeletionHandling& SynchronizeFolderPair::getDelHandling() const { return delHandlingLeft_; } + +template <> inline +const DeletionHandling& SynchronizeFolderPair::getDelHandling() const { return delHandlingRight_; } +} + + +/* +__________________________ +|Move algorithm, 0th pass| +-------------------------- +1. loop over hierarchy and find "move source" + +2. check whether parent directory of "move source" is going to be deleted or location of "move source" may lead to name clash with other dir/symlink + -> no: delay move until 2nd pass + +3. create move target's parent directory recursively + execute move + do we have name clash? + -> prepare a 2-step move operation: 1. move source to root and update "move target" accordingly 2. delay move until 2nd pass + +4. If any of the operations above did not succeed (even after retry), update statistics and revert to "copy + delete" + Note: first pass may delete "move source"!!! + +__________________ +|killer-scenarios| +------------------ +propagate the following move sequences: +I) a -> a/a caveat sync'ing parent directory first leads to circular dependency! + +II) a/a -> a caveat: fixing name clash will remove source! + +III) c -> d caveat: move-sequence needs to be processed in correct order! + b -> c/b + a -> b/a +*/ + +namespace +{ +template inline +bool haveNameClash(const Zstring& shortname, Mapping& m) +{ + return std::find_if(m.begin(), m.end(), + [&](const typename Mapping::value_type& obj) { return EqualFilename()(obj.getObjShortName(), shortname); }) != m.end(); +} + + +Zstring findUniqueTempName(const Zstring& filename) +{ + Zstring output = filename + zen::TEMP_FILE_ENDING; + + //ensure uniqueness + for (int i = 1; somethingExists(output); ++i) + output = filename + Zchar('_') + toString(i) + zen::TEMP_FILE_ENDING; + + return output; +} +} + + +template +void SynchronizeFolderPair::prepare2StepMove(FileMapping& sourceObj, + FileMapping& targetObj) //throw FileError +{ + const Zstring& source = sourceObj.getFullName(); + const Zstring& tmpTarget = findUniqueTempName(sourceObj.getBaseDirPf() + sourceObj.getShortName()); + //this could still lead to a name-clash in obscure cases, if some file ex. on the other side with + //the very same (.ffs_tmp) name and is copied before the second step of the move is executed + //good news: even in this pathologic case, this may only prevent the copy of the other file, but not the move + + reportInfo(replaceCpy(txtMovingFile, L"%y", utf8CvrtTo(tmpTarget)), source); + + renameFile(source, tmpTarget); //throw FileError; + + //update file hierarchy + const FileDescriptor descrSource(sourceObj.getLastWriteTime(), + sourceObj.getFileSize (), + sourceObj.getFileId ()); + + sourceObj.removeObject(); + + FileMapping& tempFile = sourceObj.root().addSubFile(afterLast(tmpTarget, FILE_NAME_SEPARATOR), descrSource); + + //prepare move in second pass + tempFile.setSyncDir(side == LEFT_SIDE ? SYNC_DIR_LEFT : SYNC_DIR_RIGHT); + + targetObj.setMoveRef(tempFile .getId()); + tempFile .setMoveRef(targetObj.getId()); + + //NO statistics update! + procCallback_.requestUiRefresh(); //may throw +} + + +bool SynchronizeFolderPair::createParentDir(FileSystemObject& fsObj) //throw FileError, "false" on name clash +{ + if (DirMapping* parentDir = dynamic_cast(&fsObj.parent())) + { + if (!createParentDir(*parentDir)) + return false; + + //detect (and try to resolve) file type conflicts: 1. symlinks 2. files + const Zstring& shortname = parentDir->getObjShortName(); + if (haveNameClash(shortname, parentDir->parent().refSubLinks()) || + haveNameClash(shortname, parentDir->parent().refSubFiles())) + return false; + + //in this context "parentDir" cannot be scheduled for deletion since it contains a "move target"! + //note: if parentDir were deleted, we'd end up destroying "fsObj"! + assert(parentDir->getSyncOperation() != SO_DELETE_LEFT && + parentDir->getSyncOperation() != SO_DELETE_RIGHT); + + synchronizeFolder(*parentDir); //throw FileError + } + return true; +} + + +template +void SynchronizeFolderPair::manageFileMove(FileMapping& sourceObj, + FileMapping& targetObj) //throw FileError +{ + assert((sourceObj.getSyncOperation() == SO_MOVE_LEFT_SOURCE && targetObj.getSyncOperation() == SO_MOVE_LEFT_TARGET && side == LEFT_SIDE) || + (sourceObj.getSyncOperation() == SO_MOVE_RIGHT_SOURCE && targetObj.getSyncOperation() == SO_MOVE_RIGHT_TARGET && side == RIGHT_SIDE)); + + const bool sourceWillBeDeleted = [&]() -> bool + { + if (DirMapping* parentDir = dynamic_cast(&sourceObj.parent())) + { + switch (parentDir->getSyncOperation()) //evaluate comparison result and sync direction + { + case SO_DELETE_LEFT: + case SO_DELETE_RIGHT: + return true; //we need to do something about it + case SO_MOVE_LEFT_SOURCE: + case SO_MOVE_RIGHT_SOURCE: + case SO_MOVE_LEFT_TARGET: + case SO_MOVE_RIGHT_TARGET: + case SO_OVERWRITE_LEFT: + case SO_OVERWRITE_RIGHT: + case SO_CREATE_NEW_LEFT: + case SO_CREATE_NEW_RIGHT: + case SO_DO_NOTHING: + case SO_EQUAL: + case SO_UNRESOLVED_CONFLICT: + case SO_COPY_METADATA_TO_LEFT: + case SO_COPY_METADATA_TO_RIGHT: + break; + } + } + return false; + }(); + + auto haveNameClash = [](const FileMapping& fileObj) + { + return ::haveNameClash(fileObj.getObjShortName(), fileObj.parent().refSubLinks()) || + ::haveNameClash(fileObj.getObjShortName(), fileObj.parent().refSubDirs()); + }; + + if (sourceWillBeDeleted || haveNameClash(sourceObj)) + { + //prepare for move now: - revert to 2-step move on name clashes + if (haveNameClash(targetObj) || + !createParentDir(targetObj)) //throw FileError + return prepare2StepMove(sourceObj, targetObj); //throw FileError + + //finally start move! this should work now: + synchronizeFile(sourceObj); //throw FileError + } + //else: sourceObj will not be deleted, and is not standing in the way => delay to second pass + //note: this case may include "move sources" from two-step sub-routine! +} + + +void SynchronizeFolderPair::runZeroPass(HierarchyObject& hierObj) +{ + //search for file move-operations + + for (auto iter = hierObj.refSubFiles().begin(); iter != hierObj.refSubFiles().end(); ++iter) //VS 2010 crashes if we use for_each + lambda here... + { + FileMapping& fileObj = *iter; + + const SyncOperation syncOp = fileObj.getSyncOperation(); + switch (syncOp) //evaluate comparison result and sync direction + { + case SO_MOVE_LEFT_SOURCE: + case SO_MOVE_RIGHT_SOURCE: + { + FileMapping* sourceObj = &fileObj; + if (FileMapping* targetObj = dynamic_cast(FileSystemObject::retrieve(fileObj.getMoveRef()))) + { + if (!tryReportingError(procCallback_, [&] { return syncOp == SO_MOVE_LEFT_SOURCE ? this->manageFileMove(*sourceObj, *targetObj) : this->manageFileMove(*sourceObj, *targetObj); })) + { + //move operation has failed! We cannot allow to continue and have move source's parent directory deleted, messing up statistics! + // => revert to ordinary "copy + delete" + + auto getStat = [&]() -> std::pair + { + SyncStatistics statSrc(*sourceObj); + SyncStatistics statTrg(*targetObj); + + return std::make_pair(getCUD(statSrc) + getCUD(statTrg), + to(statSrc.getDataToProcess() + statTrg.getDataToProcess())); + }; + + const auto statBefore = getStat(); + sourceObj->setMoveRef(NULL); + targetObj->setMoveRef(NULL); + const auto statAfter = getStat(); + //fix statistics to match "copy + delete" + procCallback_.updateProcessedData(statBefore.first - statAfter.first, statBefore.second - statAfter.second); + } + } + } + break; + case SO_MOVE_LEFT_TARGET: //it's enough to try each move-pair *once* + case SO_MOVE_RIGHT_TARGET: // + case SO_DELETE_LEFT: + case SO_DELETE_RIGHT: + case SO_OVERWRITE_LEFT: + case SO_OVERWRITE_RIGHT: + case SO_CREATE_NEW_LEFT: + case SO_CREATE_NEW_RIGHT: + case SO_DO_NOTHING: + case SO_EQUAL: + case SO_UNRESOLVED_CONFLICT: + case SO_COPY_METADATA_TO_LEFT: + case SO_COPY_METADATA_TO_RIGHT: + break; + } + } + + std::for_each(hierObj.refSubDirs().begin(), hierObj.refSubDirs().end(), + [&](DirMapping& dirObj) { this->runZeroPass(dirObj); /*recurse */ }); +} +//--------------------------------------------------------------------------------------------------------------- + + +//1st, 2nd pass requirements: +// - avoid disk space shortage: 1. delete files, 2. overwrite big with small files first +// - support change in type: overwrite file by directory, symlink by file, ect. + +inline +SynchronizeFolderPair::PassId SynchronizeFolderPair::getPass(const FileMapping& fileObj) +{ + switch (fileObj.getSyncOperation()) //evaluate comparison result and sync direction + { + case SO_DELETE_LEFT: + case SO_DELETE_RIGHT: + return PASS_ONE; + + case SO_OVERWRITE_LEFT: + return fileObj.getFileSize() > fileObj.getFileSize() ? PASS_ONE : PASS_TWO; + + case SO_OVERWRITE_RIGHT: + return fileObj.getFileSize() < fileObj.getFileSize() ? PASS_ONE : PASS_TWO; + + case SO_MOVE_LEFT_SOURCE: // + case SO_MOVE_RIGHT_SOURCE: // [!] + return PASS_NEVER; + case SO_MOVE_LEFT_TARGET: // + case SO_MOVE_RIGHT_TARGET: //to be processed in second pass, after "move target" parent directory was created! + return PASS_TWO; + + case SO_CREATE_NEW_LEFT: + case SO_CREATE_NEW_RIGHT: + case SO_DO_NOTHING: + case SO_EQUAL: + case SO_UNRESOLVED_CONFLICT: + case SO_COPY_METADATA_TO_LEFT: + case SO_COPY_METADATA_TO_RIGHT: + return PASS_TWO; + } + assert(false); + return PASS_TWO; //dummy +} + + +inline +SynchronizeFolderPair::PassId SynchronizeFolderPair::getPass(const SymLinkMapping& linkObj) +{ + switch (linkObj.getSyncOperation()) //evaluate comparison result and sync direction + { + case SO_DELETE_LEFT: + case SO_DELETE_RIGHT: + return PASS_ONE; //make sure to delete symlinks in first pass, and equally named file or dir in second pass: usecase "overwrite symlink with regular file"! + + case SO_MOVE_LEFT_SOURCE: + case SO_MOVE_RIGHT_SOURCE: + case SO_MOVE_LEFT_TARGET: + case SO_MOVE_RIGHT_TARGET: + assert(false); + case SO_OVERWRITE_LEFT: + case SO_OVERWRITE_RIGHT: + case SO_CREATE_NEW_LEFT: + case SO_CREATE_NEW_RIGHT: + case SO_DO_NOTHING: + case SO_EQUAL: + case SO_UNRESOLVED_CONFLICT: + case SO_COPY_METADATA_TO_LEFT: + case SO_COPY_METADATA_TO_RIGHT: + return PASS_TWO; + } + assert(false); + return PASS_TWO; //dummy +} + + +inline +SynchronizeFolderPair::PassId SynchronizeFolderPair::getPass(const DirMapping& dirObj) +{ + switch (dirObj.getSyncOperation()) //evaluate comparison result and sync direction + { + case SO_DELETE_LEFT: + case SO_DELETE_RIGHT: + return PASS_ONE; + + case SO_OVERWRITE_LEFT: + case SO_OVERWRITE_RIGHT: + case SO_MOVE_LEFT_SOURCE: + case SO_MOVE_RIGHT_SOURCE: + case SO_MOVE_LEFT_TARGET: + case SO_MOVE_RIGHT_TARGET: + assert(false); + case SO_CREATE_NEW_LEFT: + case SO_CREATE_NEW_RIGHT: + case SO_DO_NOTHING: + case SO_EQUAL: + case SO_UNRESOLVED_CONFLICT: + case SO_COPY_METADATA_TO_LEFT: + case SO_COPY_METADATA_TO_RIGHT: + return PASS_TWO; + } + assert(false); + return PASS_TWO; //dummy +} template -void SynchronizeFolderPair::execute(HierarchyObject& hierObj) +void SynchronizeFolderPair::runPass(HierarchyObject& hierObj) { //synchronize files: std::for_each(hierObj.refSubFiles().begin(), hierObj.refSubFiles().end(), [&](FileMapping& fileObj) { - const bool letsDoThis = (pass == FIRST_PASS) == diskSpaceIsReduced(fileObj); //to be deleted files on first pass, rest on second! - if (letsDoThis) - tryReportingError(procCallback_, [&]() { synchronizeFile(fileObj); }); + if (pass == getPass(fileObj)) + tryReportingError(procCallback_, [&] { synchronizeFile(fileObj); }); }); - //synchronize symbolic links: (process in second step only) - if (pass == SECOND_PASS) - std::for_each(hierObj.refSubLinks().begin(), hierObj.refSubLinks().end(), - [&](SymLinkMapping& linkObj) { tryReportingError(procCallback_, [&]() { synchronizeLink(linkObj); }); }); + //synchronize symbolic links: + std::for_each(hierObj.refSubLinks().begin(), hierObj.refSubLinks().end(), + [&](SymLinkMapping& linkObj) + { + if (pass == getPass(linkObj)) + tryReportingError(procCallback_, [&] { synchronizeLink(linkObj); }); + }); //synchronize folders: std::for_each(hierObj.refSubDirs().begin(), hierObj.refSubDirs().end(), [&](DirMapping& dirObj) { - const bool letsDoThis = (pass == FIRST_PASS) == diskSpaceIsReduced(dirObj); //to be deleted dirs on first pass, rest on second! - if (letsDoThis) //if we created all folders on first pass it would look strange for initial mirror sync when all folders are created at once - tryReportingError(procCallback_, [&]() { synchronizeFolder(dirObj); }); + if (pass == getPass(dirObj)) + tryReportingError(procCallback_, [&] { synchronizeFolder(dirObj); }); - //recursion! - this->execute(dirObj); + this->runPass(dirObj); //recurse }); } +//--------------------------------------------------------------------------------------------------------------- -void SynchronizeFolderPair::synchronizeFile(FileMapping& fileObj) const +namespace { - wxString logText; - Zstring target; - - switch (fileObj.getSyncOperation()) //evaluate comparison result and sync direction +inline +bool getTargetDir(SyncOperation syncOp, SelectedSide* side) +{ + switch (syncOp) { case SO_CREATE_NEW_LEFT: - target = fileObj.getBaseDirPf() + fileObj.getRelativeName(); //can't use "getFullName" as target is not yet existing + case SO_DELETE_LEFT: + case SO_OVERWRITE_LEFT: + case SO_COPY_METADATA_TO_LEFT: + case SO_MOVE_LEFT_SOURCE: + case SO_MOVE_LEFT_TARGET: + *side = LEFT_SIDE; + return true; - logText = txtCreatingFile; - replace(logText, L"%x", utf8CvrtTo(target)); - procCallback_.reportInfo(logText); + case SO_CREATE_NEW_RIGHT: + case SO_DELETE_RIGHT: + case SO_OVERWRITE_RIGHT: + case SO_COPY_METADATA_TO_RIGHT: + case SO_MOVE_RIGHT_SOURCE: + case SO_MOVE_RIGHT_TARGET: + *side = RIGHT_SIDE; + return true; - try - { - FileDescriptor sourceAttr; - copyFileUpdatingTo(fileObj, - []() {}, //no target to delete - sourceAttr); + case SO_DO_NOTHING: + case SO_EQUAL: + case SO_UNRESOLVED_CONFLICT: + break; //nothing to do + } + return false; +} +} - fileObj.copyTo(&sourceAttr); //update FileMapping - } - catch (FileError&) - { - if (fileExists(fileObj.getFullName())) - throw; - //source deleted meanwhile... - procCallback_.updateProcessedData(0, to(fileObj.getFileSize())); - fileObj.removeObject(); - } - break; +inline +void SynchronizeFolderPair::synchronizeFile(FileMapping& fileObj) const +{ + const SyncOperation syncOp = fileObj.getSyncOperation(); + + SelectedSide sideTrg = LEFT_SIDE; + + if (getTargetDir(syncOp, &sideTrg)) + { + if (sideTrg == LEFT_SIDE) + synchronizeFileInt(fileObj, syncOp); + else + synchronizeFileInt(fileObj, syncOp); + } +} + + +template +void SynchronizeFolderPair::synchronizeFileInt(FileMapping& fileObj, SyncOperation syncOp) const +{ + static const SelectedSide sideSrc = OtherSide::result; + + switch (syncOp) + { + case SO_CREATE_NEW_LEFT: case SO_CREATE_NEW_RIGHT: - target = fileObj.getBaseDirPf() + fileObj.getRelativeName(); + { + const Zstring& target = fileObj.getBaseDirPf() + fileObj.getRelativeName(); //can't use "getFullName" as target is not yet existing - logText = txtCreatingFile; - replace(logText, L"%x", utf8CvrtTo(target)); - procCallback_.reportInfo(logText); + reportInfo(txtCreatingFile, target); try { - FileDescriptor sourceAttr; - copyFileUpdatingTo(fileObj, - []() {}, //no target to delete - sourceAttr); + FileAttrib newAttr; + copyFileUpdatingTo(fileObj, [] {}, /*no target to delete*/ newAttr); - fileObj.copyTo(&sourceAttr); //update FileMapping + const FileDescriptor descrSource(newAttr.modificationTime, newAttr.fileSize, newAttr.sourceFileId); + const FileDescriptor descrTarget(newAttr.modificationTime, newAttr.fileSize, newAttr.targetFileId); + fileObj.syncTo(descrTarget, &descrSource); //update FileMapping } catch (FileError&) { - if (fileExists(fileObj.getFullName())) + if (fileExists(fileObj.getFullName())) throw; //source deleted meanwhile... - procCallback_.updateProcessedData(0, to(fileObj.getFileSize())); - fileObj.removeObject(); + procCallback_.updateProcessedData(0, to(fileObj.getFileSize())); + fileObj.removeObject(); } - break; + } + break; case SO_DELETE_LEFT: - logText = replaceCpy(delHandlingLeft_.getTxtRemovingFile(), L"%x", utf8CvrtTo(fileObj.getFullName())); - procCallback_.reportInfo(logText); + case SO_DELETE_RIGHT: + reportInfo(getDelHandling().getTxtRemovingFile(), fileObj.getFullName()); - delHandlingLeft_.removeFile(fileObj.getObjRelativeName()); //throw FileError - fileObj.removeObject(); //update FileMapping + getDelHandling().removeFile(fileObj.getObjRelativeName()); //throw FileError + fileObj.removeObject(); //update FileMapping break; - case SO_DELETE_RIGHT: - logText = replaceCpy(delHandlingRight_.getTxtRemovingFile(), L"%x", utf8CvrtTo(fileObj.getFullName())); - procCallback_.reportInfo(logText); + case SO_MOVE_LEFT_SOURCE: + case SO_MOVE_LEFT_TARGET: + case SO_MOVE_RIGHT_SOURCE: + case SO_MOVE_RIGHT_TARGET: + if (FileMapping* targetObj = dynamic_cast(FileSystemObject::retrieve(fileObj.getMoveRef()))) + { + FileMapping* sourceObj = &fileObj; - delHandlingRight_.removeFile(fileObj.getObjRelativeName()); //throw FileError - fileObj.removeObject(); //update FileMapping - break; + if (syncOp != SO_MOVE_LEFT_SOURCE && syncOp != SO_MOVE_RIGHT_SOURCE) + std::swap(sourceObj, targetObj); - case SO_OVERWRITE_LEFT: - { - target = fileObj.getBaseDirPf() + fileObj.getRelativeName(); //respect differences in case of source object + assert((sourceObj->getSyncOperation() == SO_MOVE_LEFT_SOURCE && targetObj->getSyncOperation() == SO_MOVE_LEFT_TARGET && sideTrg == LEFT_SIDE) || + (sourceObj->getSyncOperation() == SO_MOVE_RIGHT_SOURCE && targetObj->getSyncOperation() == SO_MOVE_RIGHT_TARGET && sideTrg == RIGHT_SIDE)); - logText = txtOverwritingFile; - replace(logText, L"%x", utf8CvrtTo(target)); - procCallback_.reportInfo(logText); + const Zstring& source = sourceObj->getFullName(); + const Zstring& target = targetObj->getBaseDirPf() + targetObj->getRelativeName(); - FileDescriptor sourceAttr; - copyFileUpdatingTo(fileObj, - [&]() //delete target at appropriate time - { - procCallback_.reportStatus(replaceCpy(delHandlingLeft_.getTxtRemovingFile(), L"%x", utf8CvrtTo(fileObj.getFullName()))); + reportInfo(replaceCpy(txtMovingFile, L"%y", utf8CvrtTo(target)), source); - delHandlingLeft_.removeFile(fileObj.getObjRelativeName()); //throw FileError - fileObj.removeObject(); //remove file from FileMapping, to keep in sync (if subsequent copying fails!!) + renameFile(source, target); //throw FileError; - procCallback_.reportStatus(logText); //restore status text copy file - }, sourceAttr); + const FileDescriptor descrTarget(sourceObj->getLastWriteTime(), + sourceObj->getFileSize (), + sourceObj->getFileId ()); - fileObj.copyTo(&sourceAttr); //update FileMapping - } - break; + sourceObj->removeObject(); // + targetObj->syncTo(descrTarget); //update FileMapping + } + break; + case SO_OVERWRITE_LEFT: case SO_OVERWRITE_RIGHT: { - target = fileObj.getBaseDirPf() + fileObj.getRelativeName(); //respect differences in case of source object + const Zstring& target = fileObj.getBaseDirPf() + fileObj.getRelativeName(); //respect differences in case of source object - logText = txtOverwritingFile; - replace(logText, L"%x", utf8CvrtTo(target)); - procCallback_.reportInfo(logText); + reportInfo(txtOverwritingFile, target); - FileDescriptor sourceAttr; - copyFileUpdatingTo(fileObj, - [&]() //delete target at appropriate time + FileAttrib newAttr; + copyFileUpdatingTo(fileObj, + [&] //delete target at appropriate time { - procCallback_.reportStatus(replaceCpy(delHandlingRight_.getTxtRemovingFile(), L"%x", utf8CvrtTo(fileObj.getFullName()))); + reportStatus(this->getDelHandling().getTxtRemovingFile(), fileObj.getFullName()); - delHandlingRight_.removeFile(fileObj.getObjRelativeName()); //throw FileError - fileObj.removeObject(); //remove file from FileMapping, to keep in sync (if subsequent copying fails!!) + this->getDelHandling().removeFile(fileObj.getObjRelativeName()); //throw FileError + fileObj.removeObject(); //remove file from FileMapping, to keep in sync (if subsequent copying fails!!) - procCallback_.reportStatus(logText); //restore status text copy file - }, sourceAttr); + reportStatus(txtOverwritingFile, target); //restore status text copy file + }, newAttr); - fileObj.copyTo(&sourceAttr); //update FileMapping + const FileDescriptor descrSource(newAttr.modificationTime, newAttr.fileSize, newAttr.sourceFileId); + const FileDescriptor descrTarget(newAttr.modificationTime, newAttr.fileSize, newAttr.targetFileId); + fileObj.syncTo(descrTarget, &descrSource); //update FileMapping } break; case SO_COPY_METADATA_TO_LEFT: - logText = replaceCpy(txtWritingAttributes, L"%x", utf8CvrtTo(fileObj.getFullName())); - procCallback_.reportInfo(logText); - - if (fileObj.getShortName() != fileObj.getShortName()) //adapt difference in case (windows only) - renameFile(fileObj.getFullName(), - beforeLast(fileObj.getFullName(), FILE_NAME_SEPARATOR) + FILE_NAME_SEPARATOR + fileObj.getShortName()); //throw FileError; - - if (!sameFileTime(fileObj.getLastWriteTime(), fileObj.getLastWriteTime(), 2)) //respect 2 second FAT/FAT32 precision - setFileTime(fileObj.getFullName(), fileObj.getLastWriteTime(), SYMLINK_FOLLOW); //throw FileError - //do NOT read *current* source file time, but use buffered value which corresponds to time of comparison! - - fileObj.copyTo(NULL); //-> both sides *should* be completely equal now... - break; - case SO_COPY_METADATA_TO_RIGHT: - logText = replaceCpy(txtWritingAttributes, L"%x", utf8CvrtTo(fileObj.getFullName())); - procCallback_.reportInfo(logText); + { + reportInfo(txtWritingAttributes, fileObj.getFullName()); - if (fileObj.getShortName() != fileObj.getShortName()) //adapt difference in case (windows only) - renameFile(fileObj.getFullName(), - beforeLast(fileObj.getFullName(), FILE_NAME_SEPARATOR) + FILE_NAME_SEPARATOR + fileObj.getShortName()); //throw FileError; + if (fileObj.getShortName() != fileObj.getShortName()) //adapt difference in case (windows only) + renameFile(fileObj.getFullName(), + beforeLast(fileObj.getFullName(), FILE_NAME_SEPARATOR) + FILE_NAME_SEPARATOR + fileObj.getShortName()); //throw FileError; - if (!sameFileTime(fileObj.getLastWriteTime(), fileObj.getLastWriteTime(), 2)) //respect 2 second FAT/FAT32 precision - setFileTime(fileObj.getFullName(), fileObj.getLastWriteTime(), SYMLINK_FOLLOW); //throw FileError + if (!sameFileTime(fileObj.getLastWriteTime(), fileObj.getLastWriteTime(), 2)) //respect 2 second FAT/FAT32 precision + setFileTime(fileObj.getFullName(), fileObj.getLastWriteTime(), SYMLINK_FOLLOW); //throw FileError + //do NOT read *current* source file time, but use buffered value which corresponds to time of comparison! - fileObj.copyTo(NULL); //-> both sides *should* be completely equal now... - break; + const FileDescriptor descrTarget(fileObj.getLastWriteTime(), + fileObj.getFileSize (), + fileObj.getFileId ()); + fileObj.syncTo(descrTarget); //-> both sides *should* be completely equal now... + } + break; case SO_DO_NOTHING: case SO_EQUAL: @@ -1049,137 +1416,112 @@ void SynchronizeFolderPair::synchronizeFile(FileMapping& fileObj) const } +inline void SynchronizeFolderPair::synchronizeLink(SymLinkMapping& linkObj) const { - wxString logText; - Zstring target; + const SyncOperation syncOp = linkObj.getSyncOperation(); - switch (linkObj.getSyncOperation()) //evaluate comparison result and sync direction + SelectedSide sideTrg = LEFT_SIDE; + + if (getTargetDir(syncOp, &sideTrg)) { - case SO_CREATE_NEW_LEFT: - target = linkObj.getBaseDirPf() + linkObj.getRelativeName(); + if (sideTrg == LEFT_SIDE) + synchronizeLinkInt(linkObj, syncOp); + else + synchronizeLinkInt(linkObj, syncOp); + } +} - logText = txtCreatingLink; - replace(logText, L"%x", utf8CvrtTo(target)); - procCallback_.reportInfo(logText); - try - { - zen::copySymlink(linkObj.getFullName(), target, copyFilePermissions); //throw FileError +template +void SynchronizeFolderPair::synchronizeLinkInt(SymLinkMapping& linkObj, SyncOperation syncOp) const +{ + static const SelectedSide sideSrc = OtherSide::result; - linkObj.copyTo(); //update SymLinkMapping - } - catch (FileError&) - { - if (fileExists(linkObj.getFullName())) - throw; - //source deleted meanwhile... - linkObj.removeObject(); - } - break; + auto deleteSymlink = [&] + { + switch (linkObj.getLinkType()) + { + case LinkDescriptor::TYPE_DIR: + this->getDelHandling().removeFolder(linkObj.getObjRelativeName()); //throw FileError + break; + + case LinkDescriptor::TYPE_FILE: //Windows: true file symlink; Linux: file-link or broken link + this->getDelHandling().removeFile(linkObj.getObjRelativeName()); //throw FileError + break; + } + }; + switch (syncOp) + { + case SO_CREATE_NEW_LEFT: case SO_CREATE_NEW_RIGHT: - target = linkObj.getBaseDirPf() + linkObj.getRelativeName(); + { + const Zstring& target = linkObj.getBaseDirPf() + linkObj.getRelativeName(); - logText = txtCreatingLink; - replace(logText, L"%x", utf8CvrtTo(target)); - procCallback_.reportInfo(logText); + reportInfo(txtCreatingLink, target); try { - zen::copySymlink(linkObj.getFullName(), target, copyFilePermissions); //throw FileError + zen::copySymlink(linkObj.getFullName(), target, copyFilePermissions); //throw FileError - linkObj.copyTo(); //update SymLinkMapping + linkObj.copyTo(); //update SymLinkMapping } catch (FileError&) { - if (fileExists(linkObj.getFullName())) + if (fileExists(linkObj.getFullName())) throw; //source deleted meanwhile... - linkObj.removeObject(); + linkObj.removeObject(); } - break; + } + break; case SO_DELETE_LEFT: - logText = replaceCpy(delHandlingLeft_.getTxtRemovingSymLink(), L"%x", utf8CvrtTo(linkObj.getFullName())); - procCallback_.reportInfo(logText); - - deleteSymlink(linkObj); //throw FileError - - linkObj.removeObject(); //update SymLinkMapping - break; - case SO_DELETE_RIGHT: - logText = replaceCpy(delHandlingRight_.getTxtRemovingSymLink(), L"%x", utf8CvrtTo(linkObj.getFullName())); - procCallback_.reportInfo(logText); + reportInfo(getDelHandling().getTxtRemovingSymLink(), linkObj.getFullName()); - deleteSymlink(linkObj); //throw FileError + deleteSymlink(); //throw FileError - linkObj.removeObject(); //update SymLinkMapping + linkObj.removeObject(); //update SymLinkMapping break; case SO_OVERWRITE_LEFT: - target = linkObj.getBaseDirPf() + linkObj.getRelativeName(); //respect differences in case of source object - - logText = txtOverwritingLink; - replace(logText, L"%x", utf8CvrtTo(target)); - procCallback_.reportInfo(logText); - - procCallback_.reportStatus(replaceCpy(delHandlingLeft_.getTxtRemovingSymLink(), L"%x", utf8CvrtTo(linkObj.getFullName()))); - deleteSymlink(linkObj); //throw FileError - linkObj.removeObject(); //remove file from FileMapping, to keep in sync (if subsequent copying fails!!) - - procCallback_.reportStatus(logText); //restore status text - zen::copySymlink(linkObj.getFullName(), target, copyFilePermissions); //throw FileError - - linkObj.copyTo(); //update SymLinkMapping - break; - case SO_OVERWRITE_RIGHT: - target = linkObj.getBaseDirPf() + linkObj.getRelativeName(); //respect differences in case of source object - - logText = txtOverwritingLink; - replace(logText, L"%x", utf8CvrtTo(target)); - procCallback_.reportInfo(logText); + { + const Zstring& target = linkObj.getBaseDirPf() + linkObj.getRelativeName(); //respect differences in case of source object - procCallback_.reportStatus(replaceCpy(delHandlingRight_.getTxtRemovingSymLink(), L"%x", utf8CvrtTo(linkObj.getFullName()))); - deleteSymlink(linkObj); //throw FileError - linkObj.removeObject(); //remove file from FileMapping, to keep in sync (if subsequent copying fails!!) + reportInfo(txtOverwritingLink, target); - procCallback_.reportStatus(logText); //restore status text - zen::copySymlink(linkObj.getFullName(), target, copyFilePermissions); //throw FileError + reportStatus(getDelHandling().getTxtRemovingSymLink(), linkObj.getFullName()); + deleteSymlink(); //throw FileError + linkObj.removeObject(); //remove file from FileMapping, to keep in sync (if subsequent copying fails!!) - linkObj.copyTo(); //update SymLinkMapping - break; + reportStatus(txtOverwritingLink, target); //restore status text + zen::copySymlink(linkObj.getFullName(), target, copyFilePermissions); //throw FileError + linkObj.copyTo(); //update SymLinkMapping + } + break; case SO_COPY_METADATA_TO_LEFT: - logText = replaceCpy(txtWritingAttributes, L"%x", utf8CvrtTo(linkObj.getFullName())); - procCallback_.reportInfo(logText); - - if (linkObj.getShortName() != linkObj.getShortName()) //adapt difference in case (windows only) - renameFile(linkObj.getFullName(), - beforeLast(linkObj.getFullName(), FILE_NAME_SEPARATOR) + FILE_NAME_SEPARATOR + linkObj.getShortName()); //throw FileError; - - if (!sameFileTime(linkObj.getLastWriteTime(), linkObj.getLastWriteTime(), 2)) //respect 2 second FAT/FAT32 precision - setFileTime(linkObj.getFullName(), linkObj.getLastWriteTime(), SYMLINK_DIRECT); //throw FileError - - linkObj.copyTo(); //-> both sides *should* be completely equal now... - break; - case SO_COPY_METADATA_TO_RIGHT: - logText = replaceCpy(txtWritingAttributes, L"%x", utf8CvrtTo(linkObj.getFullName())); - procCallback_.reportInfo(logText); + reportInfo(txtWritingAttributes, linkObj.getFullName()); - if (linkObj.getShortName() != linkObj.getShortName()) //adapt difference in case (windows only) - renameFile(linkObj.getFullName(), - beforeLast(linkObj.getFullName(), FILE_NAME_SEPARATOR) + FILE_NAME_SEPARATOR + linkObj.getShortName()); //throw FileError; + if (linkObj.getShortName() != linkObj.getShortName()) //adapt difference in case (windows only) + renameFile(linkObj.getFullName(), + beforeLast(linkObj.getFullName(), FILE_NAME_SEPARATOR) + FILE_NAME_SEPARATOR + linkObj.getShortName()); //throw FileError; - if (!sameFileTime(linkObj.getLastWriteTime(), linkObj.getLastWriteTime(), 2)) //respect 2 second FAT/FAT32 precision - setFileTime(linkObj.getFullName(), linkObj.getLastWriteTime(), SYMLINK_DIRECT); //throw FileError + if (!sameFileTime(linkObj.getLastWriteTime(), linkObj.getLastWriteTime(), 2)) //respect 2 second FAT/FAT32 precision + setFileTime(linkObj.getFullName(), linkObj.getLastWriteTime(), SYMLINK_DIRECT); //throw FileError - linkObj.copyTo(); //-> both sides *should* be completely equal now... + linkObj.copyTo(); //-> both sides *should* be completely equal now... break; + case SO_MOVE_LEFT_SOURCE: + case SO_MOVE_RIGHT_SOURCE: + case SO_MOVE_LEFT_TARGET: + case SO_MOVE_RIGHT_TARGET: + assert(false); case SO_DO_NOTHING: case SO_EQUAL: case SO_UNRESOLVED_CONFLICT: @@ -1193,126 +1535,89 @@ void SynchronizeFolderPair::synchronizeLink(SymLinkMapping& linkObj) const } +inline void SynchronizeFolderPair::synchronizeFolder(DirMapping& dirObj) const { - wxString logText; - Zstring target; + const SyncOperation syncOp = dirObj.getSyncOperation(); - //synchronize folders: - switch (dirObj.getSyncOperation()) //evaluate comparison result and sync direction - { - case SO_CREATE_NEW_LEFT: - //some check to catch the error that directory on source has been deleted externally after "compare"... - if (!dirExists(dirObj.getFullName())) - { - // throw FileError(_ ("Source directory does not exist anymore:") + "\n\"" + dirObj.getFullName() + "\""); - const SyncStatistics subObjects(dirObj); //DON'T forget to notify about implicitly deleted objects! - procCallback_.updateProcessedData(subObjects.getCreate() + subObjects.getOverwrite() + subObjects.getDelete(), to(subObjects.getDataToProcess())); + SelectedSide sideTrg = LEFT_SIDE; - dirObj.refSubFiles().clear(); //...then remove sub-objects - dirObj.refSubLinks().clear(); // - dirObj.refSubDirs ().clear(); // - dirObj.removeObject(); - } - else - { - target = dirObj.getBaseDirPf() + dirObj.getRelativeName(); + if (getTargetDir(syncOp, &sideTrg)) + { + if (sideTrg == LEFT_SIDE) + synchronizeFolderInt(dirObj, syncOp); + else + synchronizeFolderInt(dirObj, syncOp); + } +} - logText = replaceCpy(txtCreatingFolder, L"%x", utf8CvrtTo(target)); - procCallback_.reportInfo(logText); - createDirectory(target, dirObj.getFullName(), copyFilePermissions); //no symlink copying! - dirObj.copyTo(); //update DirMapping - } - break; +template +void SynchronizeFolderPair::synchronizeFolderInt(DirMapping& dirObj, SyncOperation syncOp) const +{ + static const SelectedSide sideSrc = OtherSide::result; + switch (syncOp) + { + case SO_CREATE_NEW_LEFT: case SO_CREATE_NEW_RIGHT: - //some check to catch the error that directory on source has been deleted externally after "compare"... - if (!dirExists(dirObj.getFullName())) + if (dirExists(dirObj.getFullName())) { - //throw FileError(_ ("Source directory does not exist anymore:") + "\n\"" + dirObj.getFullName() + "\""); - const SyncStatistics subObjects(dirObj); //DON'T forget to notify about implicitly deleted objects! - procCallback_.updateProcessedData(subObjects.getCreate() + subObjects.getOverwrite() + subObjects.getDelete(), to(subObjects.getDataToProcess())); + const Zstring& target = dirObj.getBaseDirPf() + dirObj.getRelativeName(); - dirObj.refSubFiles().clear(); //...then remove sub-objects - dirObj.refSubLinks().clear(); // - dirObj.refSubDirs ().clear(); // - dirObj.removeObject(); + reportInfo(txtCreatingFolder, target); + createDirectory(target, dirObj.getFullName(), copyFilePermissions); //no symlink copying! + dirObj.copyTo(); //update DirMapping } - else + else //source directory has been deleted externally after "compare"... { - target = dirObj.getBaseDirPf() + dirObj.getRelativeName(); - - logText = replaceCpy(txtCreatingFolder, L"%x", utf8CvrtTo(target)); - procCallback_.reportInfo(logText); + // throw FileError(_ ("Source directory does not exist anymore:") + "\n\"" + dirObj.getFullName() + "\""); + const SyncStatistics subStats(dirObj); //DON'T forget to notify about implicitly deleted objects! + procCallback_.updateProcessedData(getCUD(subStats), to(subStats.getDataToProcess())); - createDirectory(target, dirObj.getFullName(), copyFilePermissions); //no symlink copying! - dirObj.copyTo(); //update DirMapping + dirObj.refSubFiles().clear(); //...then remove sub-objects + dirObj.refSubLinks().clear(); // + dirObj.refSubDirs ().clear(); // + dirObj.removeObject(); } break; case SO_COPY_METADATA_TO_LEFT: - logText = replaceCpy(txtWritingAttributes, L"%x", utf8CvrtTo(dirObj.getFullName())); - procCallback_.reportInfo(logText); - - if (dirObj.getShortName() != dirObj.getShortName()) //adapt difference in case (windows only) - renameFile(dirObj.getFullName(), - beforeLast(dirObj.getFullName(), FILE_NAME_SEPARATOR) + FILE_NAME_SEPARATOR + dirObj.getShortName()); //throw FileError; - //copyFileTimes(dirObj.getFullName(), dirObj.getFullName(), true); //throw FileError -> is executed after sub-objects have finished synchronization - - dirObj.copyTo(); //-> both sides *should* be completely equal now... - break; - case SO_COPY_METADATA_TO_RIGHT: - logText = replaceCpy(txtWritingAttributes, L"%x", utf8CvrtTo(dirObj.getFullName())); - procCallback_.reportInfo(logText); + reportInfo(txtWritingAttributes, dirObj.getFullName()); - if (dirObj.getShortName() != dirObj.getShortName()) //adapt difference in case (windows only) - renameFile(dirObj.getFullName(), - beforeLast(dirObj.getFullName(), FILE_NAME_SEPARATOR) + FILE_NAME_SEPARATOR + dirObj.getShortName()); //throw FileError; - //copyFileTimes(dirObj.getFullName(), dirObj.getFullName(), true); //throw FileError -> is executed after sub-objects have finished synchronization + if (dirObj.getShortName() != dirObj.getShortName()) //adapt difference in case (windows only) + renameFile(dirObj.getFullName(), + beforeLast(dirObj.getFullName(), FILE_NAME_SEPARATOR) + FILE_NAME_SEPARATOR + dirObj.getShortName()); //throw FileError; + //copyFileTimes -> useless at this time: modification time changes with each child-object creation/deletion - dirObj.copyTo(); //-> both sides *should* be completely equal now... + dirObj.copyTo(); //-> both sides *should* be completely equal now... break; case SO_DELETE_LEFT: - //status information - logText = replaceCpy(delHandlingLeft_.getTxtRemovingDir(), L"%x", utf8CvrtTo(dirObj.getFullName())); - procCallback_.reportInfo(logText); + case SO_DELETE_RIGHT: + { + reportInfo(getDelHandling().getTxtRemovingDir(), dirObj.getFullName()); - delHandlingLeft_.removeFolder(dirObj.getObjRelativeName()); //throw FileError - { - //progress indicator update: DON'T forget to notify about implicitly deleted objects! - const SyncStatistics subObjects(dirObj); - //...then remove everything - dirObj.refSubFiles().clear(); - dirObj.refSubLinks().clear(); - dirObj.refSubDirs ().clear(); - procCallback_.updateProcessedData(subObjects.getCreate() + subObjects.getOverwrite() + subObjects.getDelete(), to(subObjects.getDataToProcess())); - } - dirObj.removeObject(); //update DirMapping - break; + getDelHandling().removeFolder(dirObj.getObjRelativeName()); //throw FileError - case SO_DELETE_RIGHT: - //status information - logText = replaceCpy(delHandlingRight_.getTxtRemovingDir(), L"%x", utf8CvrtTo(dirObj.getFullName())); - procCallback_.reportInfo(logText); + //progress indicator update: DON'T forget to notify about implicitly deleted objects! + const SyncStatistics subStats(dirObj); + dirObj.refSubFiles().clear(); //...then remove everything + dirObj.refSubLinks().clear(); + dirObj.refSubDirs ().clear(); + procCallback_.updateProcessedData(getCUD(subStats), to(subStats.getDataToProcess())); - delHandlingRight_.removeFolder(dirObj.getObjRelativeName()); //throw FileError - { - //progress indicator update: DON'T forget to notify about implicitly deleted objects! - const SyncStatistics subObjects(dirObj); - //...then remove everything - dirObj.refSubFiles().clear(); - dirObj.refSubLinks().clear(); - dirObj.refSubDirs ().clear(); - procCallback_.updateProcessedData(subObjects.getCreate() + subObjects.getOverwrite() + subObjects.getDelete(), to(subObjects.getDataToProcess())); - } - dirObj.removeObject(); //update DirMapping - break; + dirObj.removeObject(); //update DirMapping + } + break; case SO_OVERWRITE_RIGHT: case SO_OVERWRITE_LEFT: + case SO_MOVE_LEFT_SOURCE: + case SO_MOVE_RIGHT_SOURCE: + case SO_MOVE_LEFT_TARGET: + case SO_MOVE_RIGHT_TARGET: assert(false); case SO_UNRESOLVED_CONFLICT: case SO_DO_NOTHING: @@ -1336,31 +1641,27 @@ void makeSameLength(std::wstring& first, std::wstring& second) second.resize(maxPref, L' '); } + +/* struct LessDependentDirectory : public std::binary_function { +-> a *very* bad idea: this is NOT a strict weak ordering! No transitivity of equivalence! + bool operator()(const Zstring& lhs, const Zstring& rhs) const { return LessFilename()(Zstring(lhs.c_str(), std::min(lhs.length(), rhs.length())), Zstring(rhs.c_str(), std::min(lhs.length(), rhs.length()))); } }; - -struct EqualDependentDirectory : public std::binary_function -{ - bool operator()(const Zstring& lhs, const Zstring& rhs) const - { - return EqualFilename()(Zstring(lhs.c_str(), std::min(lhs.length(), rhs.length())), - Zstring(rhs.c_str(), std::min(lhs.length(), rhs.length()))); - } -}; +*/ } void SyncProcess::startSynchronizationProcess(const std::vector& syncConfig, FolderComparison& folderCmp) { - //prevent shutdown while synchronization is in progress - DisableStandby dummy; - (void)dummy; + //prevent shutdown while synchronization is in progress + PreventStandby dummy; + (void)dummy; #ifdef NDEBUG wxLogNull noWxLogs; //prevent wxWidgets logging @@ -1371,12 +1672,11 @@ void SyncProcess::startSynchronizationProcess(const std::vector(statisticsTotal.getDataToProcess()), ProcessCallback::PROCESS_SYNCHRONIZING); @@ -1404,12 +1704,34 @@ void SyncProcess::startSynchronizationProcess(const std::vector DirReadSet; //count (at least one) read access - typedef std::map DirWriteMap; //count (read+)write accesses - DirReadSet dirReadCount; - DirWriteMap dirWriteCount; + std::map> dirReadWriteCount; //count read/write accesses + auto incReadCount = [&](const Zstring& baseDir) + { + dirReadWriteCount[baseDir]; //create entry + for (auto iter = dirReadWriteCount.begin(); iter != dirReadWriteCount.end(); ++iter) + { + auto& countRef = iter->second; + if (dependentDir(baseDir, iter->first)) + ++countRef.first; + } + }; + auto incWriteCount = [&](const Zstring& baseDir) + { + dirReadWriteCount[baseDir]; //create entry + for (auto iter = dirReadWriteCount.begin(); iter != dirReadWriteCount.end(); ++iter) + { + auto& countRef = iter->second; + if (dependentDir(baseDir, iter->first)) + ++countRef.second; + } + }; typedef std::vector > DirPairList; DirPairList significantDiff; @@ -1417,8 +1739,7 @@ void SyncProcess::startSynchronizationProcess(const std::vector > > DirSpaceRequAvailList; //dirname / space required / space available DirSpaceRequAvailList diskSpaceMissing; - typedef std::set DirRecyclerMissing; - DirRecyclerMissing recyclMissing; + std::set recyclMissing; //start checking folder pairs for (auto j = begin(folderCmp); j != end(folderCmp); ++j) @@ -1435,13 +1756,13 @@ void SyncProcess::startSynchronizationProcess(const std::vector() + - folderPairStat.getOverwrite() + - folderPairStat.getDelete () > 0; + const bool writeLeft = folderPairStat.getCreate() + + folderPairStat.getUpdate() + + folderPairStat.getDelete() > 0; - const bool writeRight = folderPairStat.getCreate () + - folderPairStat.getOverwrite() + - folderPairStat.getDelete () > 0; + const bool writeRight = folderPairStat.getCreate() + + folderPairStat.getUpdate() + + folderPairStat.getDelete() > 0; //skip folder pair if there is nothing to do (except for automatic mode, where data base needs to be written even in this case) if (!writeLeft && !writeRight && @@ -1453,7 +1774,7 @@ void SyncProcess::startSynchronizationProcess(const std::vectorgetBaseDirPf(). empty() && (writeLeft || folderPairCfg.inAutomaticMode)) || + if ((j->getBaseDirPf().empty() && (writeLeft || folderPairCfg.inAutomaticMode)) || (j->getBaseDirPf().empty() && (writeRight || folderPairCfg.inAutomaticMode))) { procCallback.reportFatalError(_("Target directory name must not be empty!")); @@ -1462,30 +1783,32 @@ void SyncProcess::startSynchronizationProcess(const std::vectorgetBaseDirPf(), j->getBaseDirPf())) //true in general + if (!dependentDir(j->getBaseDirPf(), j->getBaseDirPf())) //true in general { - if (writeLeft) + if (writeLeft && writeRight) + { + incWriteCount(j->getBaseDirPf()); + incWriteCount(j->getBaseDirPf()); + } + else if (writeLeft) { - ++dirWriteCount[j->getBaseDirPf()]; - if (writeRight) - ++dirWriteCount[j->getBaseDirPf()]; - else - dirReadCount.insert(j->getBaseDirPf()); + incWriteCount(j->getBaseDirPf()); + incReadCount (j->getBaseDirPf()); } else if (writeRight) { - dirReadCount.insert(j->getBaseDirPf()); - ++dirWriteCount[j->getBaseDirPf()]; + incReadCount (j->getBaseDirPf()); + incWriteCount(j->getBaseDirPf()); } } else //if folder pair contains two dependent folders, a warning was already issued after comparison; in this context treat as one write access at most { if (writeLeft || writeRight) - ++dirWriteCount[j->getBaseDirPf()]; + incWriteCount(j->getBaseDirPf()); } - if (folderPairStat.getOverwrite() + folderPairStat.getDelete() > 0) + if (folderPairStat.getUpdate() + folderPairStat.getDelete() > 0) { if (folderPairCfg.handleDeletion == zen::MOVE_TO_CUSTOM_DIRECTORY) { @@ -1500,7 +1823,9 @@ void SyncProcess::startSynchronizationProcess(const std::vector 0) //deletions only... (respect filtered items!) { Zstring missingSrcDir; @@ -1522,9 +1847,8 @@ void SyncProcess::startSynchronizationProcess(const std::vectorgetBaseDirPf(), j->getBaseDirPf())); //check for sufficient free diskspace in left directory - const std::pair spaceNeeded = DiskSpaceNeeded(*j, - delHandlerFp.first.deletionFreesSpace(), - delHandlerFp.second.deletionFreesSpace()).getSpaceTotal(); + const std::pair spaceNeeded = DiskSpaceNeeded::calculate(*j, delHandlerFp.first.deletionFreesSpace(), + delHandlerFp.second.deletionFreesSpace()); wxLongLong freeDiskSpaceLeft; if (wxGetDiskSpace(toWx(j->getBaseDirPf()), NULL, &freeDiskSpaceLeft)) { @@ -1546,14 +1870,14 @@ void SyncProcess::startSynchronizationProcess(const std::vector() + - folderPairStat.getDelete () > 0 && + if (folderPairStat.getUpdate() + + folderPairStat.getDelete() > 0 && recycleBinStatus(j->getBaseDirPf()) != STATUS_REC_EXISTS) recyclMissing.insert(j->getBaseDirPf()); - if (folderPairStat.getOverwrite() + - folderPairStat.getDelete () > 0 && + if (folderPairStat.getUpdate() + + folderPairStat.getDelete() > 0 && recycleBinStatus(j->getBaseDirPf()) != STATUS_REC_EXISTS) recyclMissing.insert(j->getBaseDirPf()); @@ -1565,20 +1889,20 @@ void SyncProcess::startSynchronizationProcess(const std::vector 0) { //show the first few conflicts in warning message also: - wxString warningMessage = wxString(_("Unresolved conflicts existing!")) + - wxT(" (") + toStringSep(statisticsTotal.getConflict()) + wxT(")\n\n"); + std::wstring warningMessage = _("Unresolved conflicts existing!") + + L" (" + toStringSep(statisticsTotal.getConflict()) + L")\n\n"; const SyncStatistics::ConflictTexts& firstConflicts = statisticsTotal.getFirstConflicts(); //get first few sync conflicts for (SyncStatistics::ConflictTexts::const_iterator i = firstConflicts.begin(); i != firstConflicts.end(); ++i) { - wxString conflictDescription = i->second; + std::wstring conflictDescription = i->second; //conflictDescription.Replace(wxT("\n"), wxT(" ")); //remove line-breaks warningMessage += std::wstring(L"\"") + i->first + L"\": " + conflictDescription + L"\n\n"; } if (statisticsTotal.getConflict() > static_cast(firstConflicts.size())) - warningMessage += wxT("[...]\n\n"); + warningMessage += L"[...]\n\n"; warningMessage += _("You can ignore conflicts and continue synchronization."); @@ -1589,13 +1913,14 @@ void SyncProcess::startSynchronizationProcess(const std::vectorfirst + L" <-> " + L"\n" + i->second; - warningMessage += wxString(L"\n\n") + _("More than 50% of the total number of files will be copied or deleted!"); + warningMessage += L"\n\n"; + warningMessage += _("More than 50% of the total number of files will be copied or deleted!"); procCallback.reportWarning(warningMessage, m_warnings.warningSignificantDifference); } @@ -1604,13 +1929,13 @@ void SyncProcess::startSynchronizationProcess(const std::vectorfirst + L"\"\n" + - _("Free disk space required:") + wxT(" ") + filesizeToShortString(to(i->second.first)) + L"\n" + - _("Free disk space available:") + wxT(" ") + filesizeToShortString(to(i->second.second)); + _("Free disk space required:") + L" " + filesizeToShortString(to(i->second.first)) + L"\n" + + _("Free disk space available:") + L" " + filesizeToShortString(to(i->second.second)); procCallback.reportWarning(warningMessage, m_warnings.warningNotEnoughDiskSpace); } @@ -1620,11 +1945,11 @@ void SyncProcess::startSynchronizationProcess(const std::vector(path); }); procCallback.reportWarning(warningMessage, m_warnings.warningRecyclerMissing); } @@ -1632,15 +1957,18 @@ void SyncProcess::startSynchronizationProcess(const std::vector conflictDirs; - for (DirWriteMap::const_iterator i = dirWriteCount.begin(); i != dirWriteCount.end(); ++i) - if (i->second >= 2 || //multiple write accesses - (i->second == 1 && dirReadCount.find(i->first) != dirReadCount.end())) //read/write access - conflictDirs.push_back(i->first); + for (auto iter = dirReadWriteCount.cbegin(); iter != dirReadWriteCount.cend(); ++iter) + { + const auto& countRef = iter->second; + if (countRef.second >= 2 || //multiple write accesses + (countRef.second == 1 && countRef.first >= 1)) //read/write access + conflictDirs.push_back(iter->first); + } if (!conflictDirs.empty()) { - wxString warningMessage = wxString(_("A directory will be modified which is part of multiple folder pairs! Please review synchronization settings!")) + wxT("\n"); - for (std::vector::const_iterator i = conflictDirs.begin(); i != conflictDirs.end(); ++i) + std::wstring warningMessage = _("A directory will be modified which is part of multiple folder pairs! Please review synchronization settings!") + L"\n"; + for (auto i = conflictDirs.begin(); i != conflictDirs.end(); ++i) warningMessage += std::wstring(L"\n") + L"\"" + *i + L"\""; procCallback.reportWarning(warningMessage, m_warnings.warningMultiFolderWriteAccess); @@ -1677,8 +2005,8 @@ void SyncProcess::startSynchronizationProcess(const std::vectorgetBaseDirPf() + L"\"" + L" \n" + - L"\t" + right + L"\"" + j->getBaseDirPf() + L"\""; + L" " + left + L"\"" + j->getBaseDirPf() + L"\"" + L" \n" + + L" " + right + L"\"" + j->getBaseDirPf() + L"\""; procCallback.reportInfo(statusTxt); //------------------------------------------------------------------------------------------ @@ -1725,7 +2053,6 @@ void SyncProcess::startSynchronizationProcess(const std::vector(e.what())); } } @@ -1768,7 +2095,7 @@ public: } private: - UInt64& bytesReported_; + UInt64& bytesReported_; ProcessCallback& statusHandler_; DelTargetCommand cmd_; }; @@ -1776,13 +2103,13 @@ private: //copy file while refreshing UI template -void SynchronizeFolderPair::copyFileUpdatingTo(const FileMapping& fileObj, const DelTargetCommand& cmd, FileDescriptor& sourceAttr) const +void SynchronizeFolderPair::copyFileUpdatingTo(const FileMapping& fileObj, const DelTargetCommand& cmd, FileAttrib& newAttr) const { const UInt64 totalBytesToCpy = fileObj.getFileSize::result>(); Zstring source = fileObj.getFullName::result>(); const Zstring& target = fileObj.getBaseDirPf() + fileObj.getRelativeName::result>(); - auto copyOperation = [&]() + auto copyOperation = [&] { //start of (possibly) long-running copy process: ensure status updates are performed regularly UInt64 bytesReported; @@ -1790,16 +2117,13 @@ void SynchronizeFolderPair::copyFileUpdatingTo(const FileMapping& fileObj, const zen::ScopeGuard guardStatistics = zen::makeGuard([&]() { procCallback_.updateProcessedData(0, -1 * to(bytesReported)); }); WhileCopying callback(bytesReported, procCallback_, cmd); - FileAttrib fileAttr; zen::copyFile(source, //type File implicitly means symlinks need to be dereferenced! - target, - copyFilePermissions, - transactionalFileCopy, - &callback, - &fileAttr); //throw FileError, ErrorFileLocked - - sourceAttr = FileDescriptor(fileAttr.modificationTime, fileAttr.fileSize); + target, + copyFilePermissions, + transactionalFileCopy, + &callback, + &newAttr); //throw FileError, ErrorFileLocked //inform about the (remaining) processed amount of data procCallback_.updateProcessedData(0, to(totalBytesToCpy) - to(bytesReported)); @@ -1851,24 +2175,6 @@ void SynchronizeFolderPair::copyFileUpdatingTo(const FileMapping& fileObj, const } -template -void SynchronizeFolderPair::deleteSymlink(const SymLinkMapping& linkObj) const -{ - const DeletionHandling& delHandling = side == LEFT_SIDE ? delHandlingLeft_ : delHandlingRight_; - - switch (linkObj.getLinkType()) - { - case LinkDescriptor::TYPE_DIR: - delHandling.removeFolder(linkObj.getObjRelativeName()); //throw FileError - break; - - case LinkDescriptor::TYPE_FILE: //Windows: true file symlink; Linux: file-link or broken link - delHandling.removeFile(linkObj.getObjRelativeName()); //throw FileError - break; - } -} - - //--------------------- data verification ------------------------- //callback functionality for status updates while verifying @@ -1936,8 +2242,7 @@ private: void SynchronizeFolderPair::verifyFileCopy(const Zstring& source, const Zstring& target) const { - wxString logText = replaceCpy(txtVerifying, L"%x", utf8CvrtTo(target)); - procCallback_.reportInfo(logText); + procCallback_.reportInfo(replaceCpy(txtVerifying, L"%x", utf8CvrtTo(target))); VerifyStatusUpdater callback(procCallback_); diff --git a/synchronization.h b/synchronization.h index 4e11d5a9..6cf32de5 100644 --- a/synchronization.h +++ b/synchronization.h @@ -21,19 +21,20 @@ class SyncStatistics public: SyncStatistics(const HierarchyObject& hierObj); SyncStatistics(const FolderComparison& folderCmp); + SyncStatistics(const FileMapping& fileObj); int getCreate() const; template int getCreate() const; - int getOverwrite() const; - template int getOverwrite() const; + int getUpdate() const; + template int getUpdate() const; int getDelete() const; template int getDelete() const; int getConflict() const { return conflict; } - typedef std::vector > ConflictTexts; // Pair(filename/conflict text) + typedef std::vector > ConflictTexts; // Pair(filename/conflict text) const ConflictTexts& getFirstConflicts() const { return firstConflicts; } zen::UInt64 getDataToProcess() const { return dataToProcess; } @@ -42,15 +43,15 @@ public: private: void init(); - void getNumbersRecursively(const HierarchyObject& hierObj); + void recurse(const HierarchyObject& hierObj); void getFileNumbers(const FileMapping& fileObj); void getLinkNumbers(const SymLinkMapping& linkObj); void getDirNumbers(const DirMapping& dirObj); - int createLeft, createRight; - int overwriteLeft, overwriteRight; - int deleteLeft, deleteRight; + int createLeft, createRight; + int updateLeft, updateRight; + int deleteLeft, deleteRight; int conflict; ConflictTexts firstConflicts; //save the first few conflict texts to display as a warning message zen::UInt64 dataToProcess; @@ -103,7 +104,7 @@ private: xmlAccess::OptionalDialogs& m_warnings; ProcessCallback& procCallback; -std::unique_ptr procBackground; + std::unique_ptr procBackground; }; @@ -131,16 +132,14 @@ std::unique_ptr procBackground; -// inline implementation -template <> -inline +// ----------- implementation ---------------- +template <> inline int SyncStatistics::getCreate() const { return createLeft; } -template <> -inline +template <> inline int SyncStatistics::getCreate() const { return createRight; @@ -152,36 +151,32 @@ int SyncStatistics::getCreate() const return getCreate() + getCreate(); } -template <> -inline -int SyncStatistics::getOverwrite() const +template <> inline +int SyncStatistics::getUpdate() const { - return overwriteLeft; + return updateLeft; } -template <> -inline -int SyncStatistics::getOverwrite() const +template <> inline +int SyncStatistics::getUpdate() const { - return overwriteRight; + return updateRight; } inline -int SyncStatistics::getOverwrite() const +int SyncStatistics::getUpdate() const { - return getOverwrite() + getOverwrite(); + return getUpdate() + getUpdate(); } -template <> -inline +template <> inline int SyncStatistics::getDelete() const { return deleteLeft; } -template <> -inline +template <> inline int SyncStatistics::getDelete() const { return deleteRight; diff --git a/ui/batch_status_handler.cpp b/ui/batch_status_handler.cpp index 93237c70..1a710eee 100644 --- a/ui/batch_status_handler.cpp +++ b/ui/batch_status_handler.cpp @@ -278,14 +278,14 @@ void BatchStatusHandler::updateProcessedData(int objectsProcessed, zen::Int64 da } -void BatchStatusHandler::reportStatus(const wxString& text) +void BatchStatusHandler::reportStatus(const std::wstring& text) { syncStatusFrame.setStatusText_NoUpdate(text); requestUiRefresh(); //throw AbortThisProcess } -void BatchStatusHandler::reportInfo(const wxString& text) +void BatchStatusHandler::reportInfo(const std::wstring& text) { errorLog.logMsg(text, TYPE_INFO); @@ -294,7 +294,7 @@ void BatchStatusHandler::reportInfo(const wxString& text) } -void BatchStatusHandler::reportWarning(const wxString& warningMessage, bool& warningActive) +void BatchStatusHandler::reportWarning(const std::wstring& warningMessage, bool& warningActive) { errorLog.logMsg(warningMessage, TYPE_WARNING); @@ -339,7 +339,7 @@ void BatchStatusHandler::reportWarning(const wxString& warningMessage, bool& war } -ProcessCallback::Response BatchStatusHandler::reportError(const wxString& errorMessage) +ProcessCallback::Response BatchStatusHandler::reportError(const std::wstring& errorMessage) { switch (handleError_) { @@ -384,7 +384,7 @@ ProcessCallback::Response BatchStatusHandler::reportError(const wxString& errorM } -void BatchStatusHandler::reportFatalError(const wxString& errorMessage) +void BatchStatusHandler::reportFatalError(const std::wstring& errorMessage) { if (handleError_ == xmlAccess::ON_ERROR_POPUP) exitWhenFinished = false; //log fatal error and show it on status dialog diff --git a/ui/batch_status_handler.h b/ui/batch_status_handler.h index 548447f6..998f2bc8 100644 --- a/ui/batch_status_handler.h +++ b/ui/batch_status_handler.h @@ -34,13 +34,13 @@ public: virtual void initNewProcess(int objectsTotal, zen::Int64 dataTotal, Process processID); virtual void updateProcessedData(int objectsProcessed, zen::Int64 dataProcessed); - virtual void reportStatus(const wxString& text); - virtual void reportInfo(const wxString& text); + virtual void reportStatus(const std::wstring& text); + virtual void reportInfo(const std::wstring& text); virtual void forceUiRefresh(); - virtual void reportWarning(const wxString& warningMessage, bool& warningActive); - virtual Response reportError(const wxString& errorMessage); - virtual void reportFatalError(const wxString& errorMessage); + virtual void reportWarning(const std::wstring& warningMessage, bool& warningActive); + virtual Response reportError(const std::wstring& errorMessage); + virtual void reportFatalError(const std::wstring& errorMessage); private: virtual void abortThisProcess(); diff --git a/ui/grid_view.cpp b/ui/grid_view.cpp index bd2bf4f4..0120764f 100644 --- a/ui/grid_view.cpp +++ b/ui/grid_view.cpp @@ -181,18 +181,22 @@ GridView::StatusSyncPreview GridView::updateSyncPreview(bool hideFiltered, //map switch (fsObj->getSyncOperation()) //evaluate comparison result and sync direction { case SO_CREATE_NEW_LEFT: + case SO_MOVE_LEFT_TARGET: output.existsSyncCreateLeft = true; if (!syncCreateLeftActive) continue; break; case SO_CREATE_NEW_RIGHT: + case SO_MOVE_RIGHT_TARGET: output.existsSyncCreateRight = true; if (!syncCreateRightActive) continue; break; case SO_DELETE_LEFT: + case SO_MOVE_LEFT_SOURCE: output.existsSyncDeleteLeft = true; if (!syncDeleteLeftActive) continue; break; case SO_DELETE_RIGHT: + case SO_MOVE_RIGHT_SOURCE: output.existsSyncDeleteRight = true; if (!syncDeleteRightActive) continue; break; diff --git a/ui/gui_generated.cpp b/ui/gui_generated.cpp index 3704d666..2b3761c5 100644 --- a/ui/gui_generated.cpp +++ b/ui/gui_generated.cpp @@ -942,6 +942,167 @@ FolderPairGenerated::~FolderPairGenerated() { } +CompareStatusGenerated::CompareStatusGenerated( wxWindow* parent, wxWindowID id, const wxPoint& pos, const wxSize& size, long style ) : wxPanel( parent, id, pos, size, style ) +{ + wxBoxSizer* bSizer40; + bSizer40 = new wxBoxSizer( wxVERTICAL ); + + + bSizer40->Add( 0, 0, 1, wxEXPAND, 5 ); + + wxBoxSizer* bSizer48; + bSizer48 = new wxBoxSizer( wxHORIZONTAL ); + + m_staticText30 = new wxStaticText( this, wxID_ANY, _("Operation:"), wxDefaultPosition, wxDefaultSize, 0 ); + m_staticText30->Wrap( -1 ); + m_staticText30->SetFont( wxFont( 10, 70, 90, 92, false, wxEmptyString ) ); + + bSizer48->Add( m_staticText30, 0, wxRIGHT|wxALIGN_CENTER_VERTICAL, 5 ); + + m_textCtrlStatus = new wxTextCtrl( this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, wxTE_READONLY ); + m_textCtrlStatus->SetBackgroundColour( wxColour( 208, 208, 208 ) ); + + bSizer48->Add( m_textCtrlStatus, 1, wxALIGN_CENTER_HORIZONTAL|wxALIGN_CENTER_VERTICAL, 5 ); + + bSizer40->Add( bSizer48, 0, wxALIGN_CENTER_HORIZONTAL|wxEXPAND|wxBOTTOM|wxRIGHT|wxLEFT, 5 ); + + m_gauge2 = new wxGauge( this, wxID_ANY, 100, wxDefaultPosition, wxSize( -1,14 ), wxGA_HORIZONTAL|wxGA_SMOOTH ); + bSizer40->Add( m_gauge2, 0, wxEXPAND|wxRIGHT|wxLEFT, 5 ); + + bSizer42 = new wxBoxSizer( wxHORIZONTAL ); + + wxBoxSizer* bSizer157; + bSizer157 = new wxBoxSizer( wxVERTICAL ); + + bSizerFilesFound = new wxBoxSizer( wxHORIZONTAL ); + + m_staticText321 = new wxStaticText( this, wxID_ANY, _("Items found:"), wxDefaultPosition, wxDefaultSize, 0 ); + m_staticText321->Wrap( -1 ); + m_staticText321->SetFont( wxFont( 10, 70, 90, 90, false, wxEmptyString ) ); + + bSizerFilesFound->Add( m_staticText321, 0, wxALIGN_BOTTOM, 5 ); + + m_staticTextScanned = new wxStaticText( this, wxID_ANY, _("dummy"), wxDefaultPosition, wxDefaultSize, 0 ); + m_staticTextScanned->Wrap( -1 ); + m_staticTextScanned->SetFont( wxFont( 9, 74, 90, 92, false, wxT("Arial") ) ); + + bSizerFilesFound->Add( m_staticTextScanned, 0, wxALIGN_BOTTOM|wxLEFT, 5 ); + + bSizer157->Add( bSizerFilesFound, 0, 0, 5 ); + + bSizerFilesRemaining = new wxBoxSizer( wxHORIZONTAL ); + + m_staticText46 = new wxStaticText( this, wxID_ANY, _("Items remaining:"), wxDefaultPosition, wxDefaultSize, 0 ); + m_staticText46->Wrap( -1 ); + m_staticText46->SetFont( wxFont( 10, 70, 90, 90, false, wxEmptyString ) ); + + bSizerFilesRemaining->Add( m_staticText46, 0, wxALIGN_BOTTOM, 5 ); + + wxBoxSizer* bSizer154; + bSizer154 = new wxBoxSizer( wxHORIZONTAL ); + + m_staticTextFilesRemaining = new wxStaticText( this, wxID_ANY, _("dummy"), wxDefaultPosition, wxDefaultSize, 0 ); + m_staticTextFilesRemaining->Wrap( -1 ); + m_staticTextFilesRemaining->SetFont( wxFont( 9, 74, 90, 92, false, wxT("Arial") ) ); + + bSizer154->Add( m_staticTextFilesRemaining, 0, wxALIGN_BOTTOM, 5 ); + + m_staticText117 = new wxStaticText( this, wxID_ANY, _("("), wxDefaultPosition, wxDefaultSize, 0 ); + m_staticText117->Wrap( -1 ); + m_staticText117->SetFont( wxFont( 9, 74, 90, 90, false, wxT("Arial") ) ); + + bSizer154->Add( m_staticText117, 0, wxLEFT|wxALIGN_BOTTOM, 5 ); + + m_staticTextDataRemaining = new wxStaticText( this, wxID_ANY, _("dummy"), wxDefaultPosition, wxDefaultSize, 0 ); + m_staticTextDataRemaining->Wrap( -1 ); + m_staticTextDataRemaining->SetFont( wxFont( 9, 74, 90, 90, false, wxT("Arial") ) ); + + bSizer154->Add( m_staticTextDataRemaining, 0, wxALIGN_BOTTOM, 5 ); + + m_staticText118 = new wxStaticText( this, wxID_ANY, _(")"), wxDefaultPosition, wxDefaultSize, 0 ); + m_staticText118->Wrap( -1 ); + m_staticText118->SetFont( wxFont( 9, 74, 90, 90, false, wxT("Arial") ) ); + + bSizer154->Add( m_staticText118, 0, wxALIGN_BOTTOM, 5 ); + + bSizerFilesRemaining->Add( bSizer154, 0, wxALIGN_BOTTOM|wxLEFT, 5 ); + + bSizer157->Add( bSizerFilesRemaining, 0, 0, 5 ); + + bSizer42->Add( bSizer157, 0, wxALIGN_CENTER_VERTICAL, 5 ); + + + bSizer42->Add( 0, 0, 1, wxEXPAND, 5 ); + + sSizerSpeed = new wxBoxSizer( wxHORIZONTAL ); + + m_staticText104 = new wxStaticText( this, wxID_ANY, _("Speed:"), wxDefaultPosition, wxDefaultSize, 0 ); + m_staticText104->Wrap( -1 ); + m_staticText104->SetFont( wxFont( 10, 70, 90, 90, false, wxEmptyString ) ); + + sSizerSpeed->Add( m_staticText104, 0, wxALIGN_BOTTOM, 5 ); + + m_staticTextSpeed = new wxStaticText( this, wxID_ANY, _("dummy"), wxDefaultPosition, wxDefaultSize, 0 ); + m_staticTextSpeed->Wrap( -1 ); + m_staticTextSpeed->SetFont( wxFont( 9, 74, 90, 92, false, wxT("Arial") ) ); + + sSizerSpeed->Add( m_staticTextSpeed, 0, wxLEFT|wxALIGN_BOTTOM, 5 ); + + bSizer42->Add( sSizerSpeed, 0, wxALIGN_CENTER_VERTICAL, 5 ); + + + bSizer42->Add( 10, 0, 0, wxALIGN_CENTER_VERTICAL, 5 ); + + sSizerTimeRemaining = new wxBoxSizer( wxHORIZONTAL ); + + m_staticTextTimeRemFixed = new wxStaticText( this, wxID_ANY, _("Time remaining:"), wxDefaultPosition, wxDefaultSize, 0 ); + m_staticTextTimeRemFixed->Wrap( -1 ); + m_staticTextTimeRemFixed->SetFont( wxFont( 10, 70, 90, 90, false, wxEmptyString ) ); + + sSizerTimeRemaining->Add( m_staticTextTimeRemFixed, 0, wxALIGN_BOTTOM, 5 ); + + m_staticTextRemTime = new wxStaticText( this, wxID_ANY, _("dummy"), wxDefaultPosition, wxDefaultSize, 0 ); + m_staticTextRemTime->Wrap( -1 ); + m_staticTextRemTime->SetFont( wxFont( 9, 74, 90, 92, false, wxT("Arial") ) ); + + sSizerTimeRemaining->Add( m_staticTextRemTime, 0, wxLEFT|wxALIGN_BOTTOM, 5 ); + + bSizer42->Add( sSizerTimeRemaining, 0, wxALIGN_CENTER_VERTICAL, 5 ); + + + bSizer42->Add( 0, 0, 1, wxEXPAND, 5 ); + + sSizerTimeElapsed = new wxBoxSizer( wxHORIZONTAL ); + + wxStaticText* m_staticText37; + m_staticText37 = new wxStaticText( this, wxID_ANY, _("Time elapsed:"), wxDefaultPosition, wxDefaultSize, 0 ); + m_staticText37->Wrap( -1 ); + m_staticText37->SetFont( wxFont( 10, 70, 90, 90, false, wxEmptyString ) ); + + sSizerTimeElapsed->Add( m_staticText37, 0, wxALIGN_BOTTOM, 5 ); + + m_staticTextTimeElapsed = new wxStaticText( this, wxID_ANY, _("dummy"), wxDefaultPosition, wxDefaultSize, 0 ); + m_staticTextTimeElapsed->Wrap( -1 ); + m_staticTextTimeElapsed->SetFont( wxFont( 9, 74, 90, 92, false, wxT("Arial") ) ); + + sSizerTimeElapsed->Add( m_staticTextTimeElapsed, 0, wxLEFT|wxALIGN_BOTTOM, 5 ); + + bSizer42->Add( sSizerTimeElapsed, 0, wxALIGN_CENTER_VERTICAL, 5 ); + + bSizer40->Add( bSizer42, 0, wxALIGN_CENTER_HORIZONTAL|wxEXPAND|wxTOP|wxRIGHT|wxLEFT, 5 ); + + + bSizer40->Add( 0, 0, 1, wxEXPAND, 5 ); + + this->SetSizer( bSizer40 ); + this->Layout(); + bSizer40->Fit( this ); +} + +CompareStatusGenerated::~CompareStatusGenerated() +{ +} + BatchDlgGenerated::BatchDlgGenerated( wxWindow* parent, wxWindowID id, const wxString& title, const wxPoint& pos, const wxSize& size, long style ) : wxDialog( parent, id, title, pos, size, style ) { this->SetSizeHints( wxSize( 560,320 ), wxDefaultSize ); @@ -1464,167 +1625,6 @@ BatchFolderPairGenerated::~BatchFolderPairGenerated() { } -CompareStatusGenerated::CompareStatusGenerated( wxWindow* parent, wxWindowID id, const wxPoint& pos, const wxSize& size, long style ) : wxPanel( parent, id, pos, size, style ) -{ - wxBoxSizer* bSizer40; - bSizer40 = new wxBoxSizer( wxVERTICAL ); - - - bSizer40->Add( 0, 0, 1, wxEXPAND, 5 ); - - wxBoxSizer* bSizer48; - bSizer48 = new wxBoxSizer( wxHORIZONTAL ); - - m_staticText30 = new wxStaticText( this, wxID_ANY, _("Operation:"), wxDefaultPosition, wxDefaultSize, 0 ); - m_staticText30->Wrap( -1 ); - m_staticText30->SetFont( wxFont( 10, 70, 90, 92, false, wxEmptyString ) ); - - bSizer48->Add( m_staticText30, 0, wxRIGHT|wxALIGN_CENTER_VERTICAL, 5 ); - - m_textCtrlStatus = new wxTextCtrl( this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, wxTE_READONLY ); - m_textCtrlStatus->SetBackgroundColour( wxColour( 208, 208, 208 ) ); - - bSizer48->Add( m_textCtrlStatus, 1, wxALIGN_CENTER_HORIZONTAL|wxALIGN_CENTER_VERTICAL, 5 ); - - bSizer40->Add( bSizer48, 0, wxALIGN_CENTER_HORIZONTAL|wxEXPAND|wxBOTTOM|wxRIGHT|wxLEFT, 5 ); - - m_gauge2 = new wxGauge( this, wxID_ANY, 100, wxDefaultPosition, wxSize( -1,14 ), wxGA_HORIZONTAL|wxGA_SMOOTH ); - bSizer40->Add( m_gauge2, 0, wxEXPAND|wxRIGHT|wxLEFT, 5 ); - - bSizer42 = new wxBoxSizer( wxHORIZONTAL ); - - wxBoxSizer* bSizer157; - bSizer157 = new wxBoxSizer( wxVERTICAL ); - - bSizerFilesFound = new wxBoxSizer( wxHORIZONTAL ); - - m_staticText321 = new wxStaticText( this, wxID_ANY, _("Items found:"), wxDefaultPosition, wxDefaultSize, 0 ); - m_staticText321->Wrap( -1 ); - m_staticText321->SetFont( wxFont( 10, 70, 90, 90, false, wxEmptyString ) ); - - bSizerFilesFound->Add( m_staticText321, 0, wxALIGN_BOTTOM, 5 ); - - m_staticTextScanned = new wxStaticText( this, wxID_ANY, _("dummy"), wxDefaultPosition, wxDefaultSize, 0 ); - m_staticTextScanned->Wrap( -1 ); - m_staticTextScanned->SetFont( wxFont( 9, 74, 90, 92, false, wxT("Arial") ) ); - - bSizerFilesFound->Add( m_staticTextScanned, 0, wxALIGN_BOTTOM|wxLEFT, 5 ); - - bSizer157->Add( bSizerFilesFound, 0, 0, 5 ); - - bSizerFilesRemaining = new wxBoxSizer( wxHORIZONTAL ); - - m_staticText46 = new wxStaticText( this, wxID_ANY, _("Items remaining:"), wxDefaultPosition, wxDefaultSize, 0 ); - m_staticText46->Wrap( -1 ); - m_staticText46->SetFont( wxFont( 10, 70, 90, 90, false, wxEmptyString ) ); - - bSizerFilesRemaining->Add( m_staticText46, 0, wxALIGN_BOTTOM, 5 ); - - wxBoxSizer* bSizer154; - bSizer154 = new wxBoxSizer( wxHORIZONTAL ); - - m_staticTextFilesRemaining = new wxStaticText( this, wxID_ANY, _("dummy"), wxDefaultPosition, wxDefaultSize, 0 ); - m_staticTextFilesRemaining->Wrap( -1 ); - m_staticTextFilesRemaining->SetFont( wxFont( 9, 74, 90, 92, false, wxT("Arial") ) ); - - bSizer154->Add( m_staticTextFilesRemaining, 0, wxALIGN_BOTTOM, 5 ); - - m_staticText117 = new wxStaticText( this, wxID_ANY, _("("), wxDefaultPosition, wxDefaultSize, 0 ); - m_staticText117->Wrap( -1 ); - m_staticText117->SetFont( wxFont( 9, 74, 90, 90, false, wxT("Arial") ) ); - - bSizer154->Add( m_staticText117, 0, wxLEFT|wxALIGN_BOTTOM, 5 ); - - m_staticTextDataRemaining = new wxStaticText( this, wxID_ANY, _("dummy"), wxDefaultPosition, wxDefaultSize, 0 ); - m_staticTextDataRemaining->Wrap( -1 ); - m_staticTextDataRemaining->SetFont( wxFont( 9, 74, 90, 90, false, wxT("Arial") ) ); - - bSizer154->Add( m_staticTextDataRemaining, 0, wxALIGN_BOTTOM, 5 ); - - m_staticText118 = new wxStaticText( this, wxID_ANY, _(")"), wxDefaultPosition, wxDefaultSize, 0 ); - m_staticText118->Wrap( -1 ); - m_staticText118->SetFont( wxFont( 9, 74, 90, 90, false, wxT("Arial") ) ); - - bSizer154->Add( m_staticText118, 0, wxALIGN_BOTTOM, 5 ); - - bSizerFilesRemaining->Add( bSizer154, 0, wxALIGN_BOTTOM|wxLEFT, 5 ); - - bSizer157->Add( bSizerFilesRemaining, 0, 0, 5 ); - - bSizer42->Add( bSizer157, 0, wxALIGN_CENTER_VERTICAL, 5 ); - - - bSizer42->Add( 0, 0, 1, wxEXPAND, 5 ); - - sSizerSpeed = new wxBoxSizer( wxHORIZONTAL ); - - m_staticText104 = new wxStaticText( this, wxID_ANY, _("Speed:"), wxDefaultPosition, wxDefaultSize, 0 ); - m_staticText104->Wrap( -1 ); - m_staticText104->SetFont( wxFont( 10, 70, 90, 90, false, wxEmptyString ) ); - - sSizerSpeed->Add( m_staticText104, 0, wxALIGN_BOTTOM, 5 ); - - m_staticTextSpeed = new wxStaticText( this, wxID_ANY, _("dummy"), wxDefaultPosition, wxDefaultSize, 0 ); - m_staticTextSpeed->Wrap( -1 ); - m_staticTextSpeed->SetFont( wxFont( 9, 74, 90, 92, false, wxT("Arial") ) ); - - sSizerSpeed->Add( m_staticTextSpeed, 0, wxLEFT|wxALIGN_BOTTOM, 5 ); - - bSizer42->Add( sSizerSpeed, 0, wxALIGN_CENTER_VERTICAL, 5 ); - - - bSizer42->Add( 10, 0, 0, wxALIGN_CENTER_VERTICAL, 5 ); - - sSizerTimeRemaining = new wxBoxSizer( wxHORIZONTAL ); - - m_staticTextTimeRemFixed = new wxStaticText( this, wxID_ANY, _("Time remaining:"), wxDefaultPosition, wxDefaultSize, 0 ); - m_staticTextTimeRemFixed->Wrap( -1 ); - m_staticTextTimeRemFixed->SetFont( wxFont( 10, 70, 90, 90, false, wxEmptyString ) ); - - sSizerTimeRemaining->Add( m_staticTextTimeRemFixed, 0, wxALIGN_BOTTOM, 5 ); - - m_staticTextRemTime = new wxStaticText( this, wxID_ANY, _("dummy"), wxDefaultPosition, wxDefaultSize, 0 ); - m_staticTextRemTime->Wrap( -1 ); - m_staticTextRemTime->SetFont( wxFont( 9, 74, 90, 92, false, wxT("Arial") ) ); - - sSizerTimeRemaining->Add( m_staticTextRemTime, 0, wxLEFT|wxALIGN_BOTTOM, 5 ); - - bSizer42->Add( sSizerTimeRemaining, 0, wxALIGN_CENTER_VERTICAL, 5 ); - - - bSizer42->Add( 0, 0, 1, wxEXPAND, 5 ); - - sSizerTimeElapsed = new wxBoxSizer( wxHORIZONTAL ); - - wxStaticText* m_staticText37; - m_staticText37 = new wxStaticText( this, wxID_ANY, _("Time elapsed:"), wxDefaultPosition, wxDefaultSize, 0 ); - m_staticText37->Wrap( -1 ); - m_staticText37->SetFont( wxFont( 10, 70, 90, 90, false, wxEmptyString ) ); - - sSizerTimeElapsed->Add( m_staticText37, 0, wxALIGN_BOTTOM, 5 ); - - m_staticTextTimeElapsed = new wxStaticText( this, wxID_ANY, _("dummy"), wxDefaultPosition, wxDefaultSize, 0 ); - m_staticTextTimeElapsed->Wrap( -1 ); - m_staticTextTimeElapsed->SetFont( wxFont( 9, 74, 90, 92, false, wxT("Arial") ) ); - - sSizerTimeElapsed->Add( m_staticTextTimeElapsed, 0, wxLEFT|wxALIGN_BOTTOM, 5 ); - - bSizer42->Add( sSizerTimeElapsed, 0, wxALIGN_CENTER_VERTICAL, 5 ); - - bSizer40->Add( bSizer42, 0, wxALIGN_CENTER_HORIZONTAL|wxEXPAND|wxTOP|wxRIGHT|wxLEFT, 5 ); - - - bSizer40->Add( 0, 0, 1, wxEXPAND, 5 ); - - this->SetSizer( bSizer40 ); - this->Layout(); - bSizer40->Fit( this ); -} - -CompareStatusGenerated::~CompareStatusGenerated() -{ -} - SyncCfgDlgGenerated::SyncCfgDlgGenerated( wxWindow* parent, wxWindowID id, const wxString& title, const wxPoint& pos, const wxSize& size, long style ) : wxDialog( parent, id, title, pos, size, style ) { this->SetSizeHints( wxDefaultSize, wxDefaultSize ); @@ -1663,7 +1663,7 @@ SyncCfgDlgGenerated::SyncCfgDlgGenerated( wxWindow* parent, wxWindowID id, const fgSizer1->Add( m_buttonAutomatic, 0, wxALIGN_CENTER_VERTICAL|wxEXPAND, 5 ); - m_staticText81 = new wxStaticText( this, wxID_ANY, _("Identify and propagate changes on both sides using a database. Deletions and conflicts are detected automatically."), wxDefaultPosition, wxDefaultSize, 0 ); + m_staticText81 = new wxStaticText( this, wxID_ANY, _("Identify and propagate changes on both sides using a database. Deletions, renaming and conflicts are detected automatically."), wxDefaultPosition, wxDefaultSize, 0 ); m_staticText81->Wrap( 400 ); fgSizer1->Add( m_staticText81, 0, wxALIGN_CENTER_VERTICAL|wxLEFT, 5 ); @@ -2282,12 +2282,12 @@ SyncStatusDlgGenerated::SyncStatusDlgGenerated( wxWindow* parent, wxWindowID id, bSizerFinalStat = new wxBoxSizer( wxVERTICAL ); m_listbookResult = new wxListbook( m_panelBackground, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxLB_TOP ); -#ifndef __WXGTK__ // Small icon style not supported in GTK - wxListView* m_listbookResultListView = m_listbookResult->GetListView(); - long m_listbookResultFlags = m_listbookResultListView->GetWindowStyleFlag(); - m_listbookResultFlags = ( m_listbookResultFlags & ~wxLC_ICON ) | wxLC_SMALL_ICON; - m_listbookResultListView->SetWindowStyleFlag( m_listbookResultFlags ); -#endif + wxSize m_listbookResultImageSize = wxSize( 180,1 ); + int m_listbookResultIndex = 0; + wxImageList* m_listbookResultImages = new wxImageList( m_listbookResultImageSize.GetWidth(), m_listbookResultImageSize.GetHeight() ); + m_listbookResult->AssignImageList( m_listbookResultImages ); + wxBitmap m_listbookResultBitmap; + wxImage m_listbookResultImage; bSizerFinalStat->Add( m_listbookResult, 1, wxEXPAND, 5 ); @@ -2351,14 +2351,6 @@ SyncStatusDlgGenerated::~SyncStatusDlgGenerated() } -MyPanel5::MyPanel5( wxWindow* parent, wxWindowID id, const wxPoint& pos, const wxSize& size, long style ) : wxPanel( parent, id, pos, size, style ) -{ -} - -MyPanel5::~MyPanel5() -{ -} - LogControlGenerated::LogControlGenerated( wxWindow* parent, wxWindowID id, const wxPoint& pos, const wxSize& size, long style ) : wxPanel( parent, id, pos, size, style ) { wxBoxSizer* bSizer153; @@ -3420,30 +3412,29 @@ GlobalSettingsDlgGenerated::GlobalSettingsDlgGenerated( wxWindow* parent, wxWind m_checkBoxTransCopy = new wxCheckBox( this, wxID_ANY, _("Transactional file copy"), wxDefaultPosition, wxDefaultSize, 0 ); sbSizer23->Add( m_checkBoxTransCopy, 0, wxEXPAND|wxALL, 5 ); - m_textCtrl22 = new wxTextCtrl( this, wxID_ANY, _("Write to a temporary file (*.ffs_tmp) first then rename it. This guarantees a consistent state even in case of fatal error."), wxDefaultPosition, wxDefaultSize, wxTE_MULTILINE|wxTE_NO_VSCROLL|wxTE_READONLY|wxNO_BORDER ); - m_textCtrl22->SetForegroundColour( wxSystemSettings::GetColour( wxSYS_COLOUR_GRAYTEXT ) ); - m_textCtrl22->SetBackgroundColour( wxSystemSettings::GetColour( wxSYS_COLOUR_BTNFACE ) ); - m_textCtrl22->SetMinSize( wxSize( 400,-1 ) ); + m_staticText82 = new wxStaticText( this, wxID_ANY, _("Write to a temporary file (*.ffs_tmp) first then rename it. This guarantees a consistent state even in case of fatal error."), wxDefaultPosition, wxDefaultSize, 0 ); + m_staticText82->Wrap( 400 ); + m_staticText82->SetForegroundColour( wxSystemSettings::GetColour( wxSYS_COLOUR_GRAYTEXT ) ); - sbSizer23->Add( m_textCtrl22, 0, wxLEFT|wxEXPAND, 20 ); + sbSizer23->Add( m_staticText82, 0, wxLEFT, 20 ); m_checkBoxCopyLocked = new wxCheckBox( this, wxID_ANY, _("Copy locked files"), wxDefaultPosition, wxDefaultSize, 0 ); sbSizer23->Add( m_checkBoxCopyLocked, 0, wxALL|wxEXPAND, 5 ); - m_textCtrlCopyLocked = new wxTextCtrl( this, wxID_ANY, _("Copy shared or locked files using Volume Shadow Copy Service (Requires Administrator rights)"), wxDefaultPosition, wxDefaultSize, wxTE_MULTILINE|wxTE_NO_VSCROLL|wxTE_READONLY|wxNO_BORDER ); - m_textCtrlCopyLocked->SetForegroundColour( wxSystemSettings::GetColour( wxSYS_COLOUR_GRAYTEXT ) ); - m_textCtrlCopyLocked->SetBackgroundColour( wxSystemSettings::GetColour( wxSYS_COLOUR_BTNFACE ) ); + m_staticTextCopyLocked = new wxStaticText( this, wxID_ANY, _("Copy shared or locked files using Volume Shadow Copy Service (Requires Administrator rights)"), wxDefaultPosition, wxDefaultSize, 0 ); + m_staticTextCopyLocked->Wrap( 400 ); + m_staticTextCopyLocked->SetForegroundColour( wxSystemSettings::GetColour( wxSYS_COLOUR_GRAYTEXT ) ); - sbSizer23->Add( m_textCtrlCopyLocked, 0, wxLEFT|wxEXPAND, 20 ); + sbSizer23->Add( m_staticTextCopyLocked, 0, wxLEFT|wxEXPAND, 20 ); m_checkBoxCopyPermissions = new wxCheckBox( this, wxID_ANY, _("Copy file access permissions"), wxDefaultPosition, wxDefaultSize, 0 ); sbSizer23->Add( m_checkBoxCopyPermissions, 0, wxALL|wxEXPAND, 5 ); - m_textCtrl2211 = new wxTextCtrl( this, wxID_ANY, _("Transfer file and directory permissions (Requires Administrator rights)"), wxDefaultPosition, wxDefaultSize, wxTE_MULTILINE|wxTE_NO_VSCROLL|wxTE_READONLY|wxNO_BORDER ); - m_textCtrl2211->SetForegroundColour( wxSystemSettings::GetColour( wxSYS_COLOUR_GRAYTEXT ) ); - m_textCtrl2211->SetBackgroundColour( wxSystemSettings::GetColour( wxSYS_COLOUR_BTNFACE ) ); + m_staticText8211 = new wxStaticText( this, wxID_ANY, _("Transfer file and directory permissions (Requires Administrator rights)"), wxDefaultPosition, wxDefaultSize, 0 ); + m_staticText8211->Wrap( 400 ); + m_staticText8211->SetForegroundColour( wxSystemSettings::GetColour( wxSYS_COLOUR_GRAYTEXT ) ); - sbSizer23->Add( m_textCtrl2211, 0, wxLEFT|wxEXPAND, 20 ); + sbSizer23->Add( m_staticText8211, 0, wxLEFT|wxEXPAND, 20 ); bSizer95->Add( sbSizer23, 0, wxALIGN_CENTER_HORIZONTAL|wxRIGHT|wxLEFT|wxEXPAND, 5 ); diff --git a/ui/gui_generated.h b/ui/gui_generated.h index de1dc89b..8fc345a2 100644 --- a/ui/gui_generated.h +++ b/ui/gui_generated.h @@ -46,14 +46,15 @@ namespace zen { class Graph2D; } #include #include #include +#include #include #include #include #include #include -#include #include #include +#include #include #include #include @@ -262,6 +263,43 @@ public: }; +/////////////////////////////////////////////////////////////////////////////// +/// Class CompareStatusGenerated +/////////////////////////////////////////////////////////////////////////////// +class CompareStatusGenerated : public wxPanel +{ +private: + +protected: + wxStaticText* m_staticText30; + wxTextCtrl* m_textCtrlStatus; + wxGauge* m_gauge2; + wxBoxSizer* bSizer42; + wxBoxSizer* bSizerFilesFound; + wxStaticText* m_staticText321; + wxStaticText* m_staticTextScanned; + wxBoxSizer* bSizerFilesRemaining; + wxStaticText* m_staticText46; + wxStaticText* m_staticTextFilesRemaining; + wxStaticText* m_staticText117; + wxStaticText* m_staticTextDataRemaining; + wxStaticText* m_staticText118; + wxBoxSizer* sSizerSpeed; + wxStaticText* m_staticText104; + wxStaticText* m_staticTextSpeed; + wxBoxSizer* sSizerTimeRemaining; + wxStaticText* m_staticTextTimeRemFixed; + wxStaticText* m_staticTextRemTime; + wxBoxSizer* sSizerTimeElapsed; + wxStaticText* m_staticTextTimeElapsed; + +public: + + CompareStatusGenerated( wxWindow* parent, wxWindowID id = wxID_ANY, const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxSize( -1,-1 ), long style = wxRAISED_BORDER|wxTAB_TRAVERSAL ); + ~CompareStatusGenerated(); + +}; + /////////////////////////////////////////////////////////////////////////////// /// Class BatchDlgGenerated /////////////////////////////////////////////////////////////////////////////// @@ -364,43 +402,6 @@ public: }; -/////////////////////////////////////////////////////////////////////////////// -/// Class CompareStatusGenerated -/////////////////////////////////////////////////////////////////////////////// -class CompareStatusGenerated : public wxPanel -{ -private: - -protected: - wxStaticText* m_staticText30; - wxTextCtrl* m_textCtrlStatus; - wxGauge* m_gauge2; - wxBoxSizer* bSizer42; - wxBoxSizer* bSizerFilesFound; - wxStaticText* m_staticText321; - wxStaticText* m_staticTextScanned; - wxBoxSizer* bSizerFilesRemaining; - wxStaticText* m_staticText46; - wxStaticText* m_staticTextFilesRemaining; - wxStaticText* m_staticText117; - wxStaticText* m_staticTextDataRemaining; - wxStaticText* m_staticText118; - wxBoxSizer* sSizerSpeed; - wxStaticText* m_staticText104; - wxStaticText* m_staticTextSpeed; - wxBoxSizer* sSizerTimeRemaining; - wxStaticText* m_staticTextTimeRemFixed; - wxStaticText* m_staticTextRemTime; - wxBoxSizer* sSizerTimeElapsed; - wxStaticText* m_staticTextTimeElapsed; - -public: - - CompareStatusGenerated( wxWindow* parent, wxWindowID id = wxID_ANY, const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxSize( -1,-1 ), long style = wxRAISED_BORDER|wxTAB_TRAVERSAL ); - ~CompareStatusGenerated(); - -}; - /////////////////////////////////////////////////////////////////////////////// /// Class SyncCfgDlgGenerated /////////////////////////////////////////////////////////////////////////////// @@ -585,22 +586,6 @@ public: }; -/////////////////////////////////////////////////////////////////////////////// -/// Class MyPanel5 -/////////////////////////////////////////////////////////////////////////////// -class MyPanel5 : public wxPanel -{ -private: - -protected: - -public: - - MyPanel5( wxWindow* parent, wxWindowID id = wxID_ANY, const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxSize( 500,300 ), long style = wxTAB_TRAVERSAL ); - ~MyPanel5(); - -}; - /////////////////////////////////////////////////////////////////////////////// /// Class LogControlGenerated /////////////////////////////////////////////////////////////////////////////// @@ -904,11 +889,11 @@ protected: wxPanel* m_panel8; wxStaticText* m_staticText56; wxCheckBox* m_checkBoxTransCopy; - wxTextCtrl* m_textCtrl22; + wxStaticText* m_staticText82; wxCheckBox* m_checkBoxCopyLocked; - wxTextCtrl* m_textCtrlCopyLocked; + wxStaticText* m_staticTextCopyLocked; wxCheckBox* m_checkBoxCopyPermissions; - wxTextCtrl* m_textCtrl2211; + wxStaticText* m_staticText8211; wxStaticText* m_staticText100; zen::BitmapButton* m_buttonResetDialogs; wxGrid* m_gridCustomCommand; diff --git a/ui/gui_status_handler.cpp b/ui/gui_status_handler.cpp index b353e918..6809b362 100644 --- a/ui/gui_status_handler.cpp +++ b/ui/gui_status_handler.cpp @@ -114,21 +114,21 @@ void CompareStatusHandler::updateProcessedData(int objectsProcessed, zen::Int64 } -void CompareStatusHandler::reportStatus(const wxString& text) +void CompareStatusHandler::reportStatus(const std::wstring& text) { mainDlg.compareStatus->setStatusText_NoUpdate(text); requestUiRefresh(); //throw AbortThisProcess } -void CompareStatusHandler::reportInfo(const wxString& text) +void CompareStatusHandler::reportInfo(const std::wstring& text) { mainDlg.compareStatus->setStatusText_NoUpdate(text); requestUiRefresh(); //throw AbortThisProcess } -ProcessCallback::Response CompareStatusHandler::reportError(const wxString& message) +ProcessCallback::Response CompareStatusHandler::reportError(const std::wstring& message) { if (ignoreErrors) return ProcessCallback::IGNORE_ERROR; @@ -155,7 +155,7 @@ ProcessCallback::Response CompareStatusHandler::reportError(const wxString& mess } -void CompareStatusHandler::reportFatalError(const wxString& errorMessage) +void CompareStatusHandler::reportFatalError(const std::wstring& errorMessage) { forceUiRefresh(); @@ -165,7 +165,7 @@ void CompareStatusHandler::reportFatalError(const wxString& errorMessage) } -void CompareStatusHandler::reportWarning(const wxString& warningMessage, bool& warningActive) +void CompareStatusHandler::reportWarning(const std::wstring& warningMessage, bool& warningActive) { if (!warningActive || ignoreErrors) //if errors are ignored, then warnings should also return; @@ -266,14 +266,14 @@ void SyncStatusHandler::updateProcessedData(int objectsProcessed, zen::Int64 dat } -void SyncStatusHandler::reportStatus(const wxString& text) +void SyncStatusHandler::reportStatus(const std::wstring& text) { syncStatusFrame.setStatusText_NoUpdate(text); //throw () requestUiRefresh(); //throw AbortThisProccess } -void SyncStatusHandler::reportInfo(const wxString& text) +void SyncStatusHandler::reportInfo(const std::wstring& text) { errorLog.logMsg(text, TYPE_INFO); @@ -282,7 +282,7 @@ void SyncStatusHandler::reportInfo(const wxString& text) } -ProcessCallback::Response SyncStatusHandler::reportError(const wxString& errorMessage) +ProcessCallback::Response SyncStatusHandler::reportError(const std::wstring& errorMessage) { switch (handleError_) { @@ -320,13 +320,13 @@ ProcessCallback::Response SyncStatusHandler::reportError(const wxString& errorMe } -void SyncStatusHandler::reportFatalError(const wxString& errorMessage) +void SyncStatusHandler::reportFatalError(const std::wstring& errorMessage) { errorLog.logMsg(errorMessage, TYPE_FATAL_ERROR); } -void SyncStatusHandler::reportWarning(const wxString& warningMessage, bool& warningActive) +void SyncStatusHandler::reportWarning(const std::wstring& warningMessage, bool& warningActive) { errorLog.logMsg(warningMessage, TYPE_WARNING); diff --git a/ui/gui_status_handler.h b/ui/gui_status_handler.h index 28429d68..997e511f 100644 --- a/ui/gui_status_handler.h +++ b/ui/gui_status_handler.h @@ -29,13 +29,13 @@ public: virtual void initNewProcess(int objectsTotal, zen::Int64 dataTotal, Process processID); virtual void updateProcessedData(int objectsProcessed, zen::Int64 dataProcessed); - virtual void reportStatus(const wxString& text); - virtual void reportInfo(const wxString& text); + virtual void reportStatus(const std::wstring& text); + virtual void reportInfo(const std::wstring& text); virtual void forceUiRefresh(); - virtual Response reportError(const wxString& text); - virtual void reportFatalError(const wxString& errorMessage); - virtual void reportWarning(const wxString& warningMessage, bool& warningActive); + virtual Response reportError(const std::wstring& text); + virtual void reportFatalError(const std::wstring& errorMessage); + virtual void reportWarning(const std::wstring& warningMessage, bool& warningActive); private: void OnKeyPressed(wxKeyEvent& event); @@ -56,13 +56,13 @@ public: virtual void initNewProcess(int objectsTotal, zen::Int64 dataTotal, Process processID); virtual void updateProcessedData(int objectsProcessed, zen::Int64 dataProcessed); - virtual void reportStatus(const wxString& text); - virtual void reportInfo(const wxString& text); + virtual void reportStatus(const std::wstring& text); + virtual void reportInfo(const std::wstring& text); virtual void forceUiRefresh(); - virtual Response reportError(const wxString& text); - virtual void reportFatalError(const wxString& errorMessage); - virtual void reportWarning(const wxString& warningMessage, bool& warningActive); + virtual Response reportError(const std::wstring& text); + virtual void reportFatalError(const std::wstring& errorMessage); + virtual void reportWarning(const std::wstring& warningMessage, bool& warningActive); private: virtual void abortThisProcess(); diff --git a/ui/main_dlg.cpp b/ui/main_dlg.cpp index e1227509..97c3625c 100644 --- a/ui/main_dlg.cpp +++ b/ui/main_dlg.cpp @@ -662,8 +662,8 @@ void MainDialog::init(const xmlAccess::XmlGuiConfig guiCfg, if (dirFmtLeft.empty() && dirFmtRight.empty()) //only skip check if both sides are empty! return; - dirEx.push_back(zen::async2([=]() { return !dirFmtLeft .empty() && zen::dirExists(dirFmtLeft); })); - dirEx.push_back(zen::async2([=]() { return !dirFmtRight.empty() && zen::dirExists(dirFmtRight); })); + dirEx.push_back(zen::async2([=] { return !dirFmtLeft .empty() && zen::dirExists(dirFmtLeft); })); + dirEx.push_back(zen::async2([=] { return !dirFmtRight.empty() && zen::dirExists(dirFmtRight); })); }; addDirCheck(currMainCfg.firstPair); std::for_each(currMainCfg.additionalPairs.begin(), currMainCfg.additionalPairs.end(), addDirCheck); @@ -972,7 +972,7 @@ public: mainDlg->enableAllElements(); } - virtual Response reportError(const wxString& errorMessage) + virtual Response reportError(const std::wstring& errorMessage) { if (abortRequested) throw AbortDeleteProcess(); @@ -1122,17 +1122,6 @@ wxString extractLastValidDir(const FileSystemObject& fsObj) return toWx(fullname); } -bool tryReplace(const wxString& phrase, const wxString& replacement, wxString& command) //return false on error -{ - if (command.find(phrase) != wxString::npos) - { - if (replacement.empty()) - return false; - replace(command, phrase, replacement); - } - return true; -} - void MainDialog::openExternalApplication(size_t rowNumber, bool leftSide, const wxString& commandline) { @@ -1163,10 +1152,22 @@ void MainDialog::openExternalApplication(size_t rowNumber, bool leftSide, const } wxString command = commandline; - if (tryReplace(L"%nameCo", nameCo, command) && //attention: replace %nameCo, %dirCo BEFORE %name, %dir to handle dependency - tryReplace(L"%dirCo", dirCo, command) && - tryReplace(L"%name", name, command) && - tryReplace(L"%dir", dir, command)) + + auto tryReplace = [&](const wxString& phrase, const wxString& replacement) -> bool + { + if (command.find(phrase) != wxString::npos) + { + if (replacement.empty()) + return false; + replace(command, phrase, replacement); + } + return true; + }; + + if (tryReplace(L"%nameCo", nameCo) && //attention: replace %nameCo, %dirCo BEFORE %name, %dir to handle dependency + tryReplace(L"%dirCo", dirCo ) && + tryReplace(L"%name", name ) && + tryReplace(L"%dir", dir )) zen::shellExecute(command); else //fallback { @@ -1246,9 +1247,6 @@ void MainDialog::disableAllElements(bool enableAbort) if (m_buttonAbort->IsShownOnScreen()) m_buttonAbort->SetFocus(); m_buttonCompare->Disable(); m_buttonCompare->Hide(); - m_bpButtonCmpConfig ->Disable(); - m_bpButtonSyncConfig->Disable(); - m_buttonStartSync ->Disable(); m_panelTopButtons->Layout(); } else @@ -1261,7 +1259,7 @@ void MainDialog::enableAllElements() EnableCloseButton(true); m_panelViewFilter ->Enable(); - m_bpButtonCmpConfig ->Enable(); + m_bpButtonCmpConfig ->Enable(); //wxGTK bug: this line seems to move main dialog to top!!!!!!! m_panelFilter ->Enable(); m_panelConfig ->Enable(); m_bpButtonSyncConfig ->Enable(); @@ -1277,9 +1275,6 @@ void MainDialog::enableAllElements() m_buttonAbort->Hide(); m_buttonCompare->Enable(); m_buttonCompare->Show(); - m_bpButtonCmpConfig ->Enable(); - m_bpButtonSyncConfig->Enable(); - m_buttonStartSync ->Enable(); m_panelTopButtons->Layout(); m_panelTopButtons->Enable(); @@ -3428,7 +3423,7 @@ void MainDialog::updateStatistics() //update preview of bytes to be transferred: const SyncStatistics st(gridDataView->getDataTentative()); const wxString toCreate = zen::toStringSep(st.getCreate()); - const wxString toUpdate = zen::toStringSep(st.getOverwrite()); + const wxString toUpdate = zen::toStringSep(st.getUpdate()); const wxString toDelete = zen::toStringSep(st.getDelete()); const wxString data = zen::filesizeToShortString(st.getDataToProcess()); @@ -3977,7 +3972,7 @@ void MainDialog::applySyncConfig() warningSyncDatabase_(warningSyncDatabase), parent_(parent) {} - virtual void reportWarning(const wxString& text) + virtual void reportWarning(const std::wstring& text) { if (warningSyncDatabase_) { @@ -4268,25 +4263,25 @@ void MainDialog::OnMenuExportFileList(wxCommandEvent& event) exportString += copyStringTo(_("Legend")) + wxT('\n'); if (syncPreview->previewIsEnabled()) { - exportString += wxT("\"") + copyStringTo(getDescription(SO_CREATE_NEW_LEFT)) + wxT("\";") + copyStringTo(getSymbol(SO_CREATE_NEW_LEFT)) + wxT('\n'); - exportString += wxT("\"") + copyStringTo(getDescription(SO_CREATE_NEW_RIGHT)) + wxT("\";") + copyStringTo(getSymbol(SO_CREATE_NEW_RIGHT)) + wxT('\n'); - exportString += wxT("\"") + copyStringTo(getDescription(SO_DELETE_LEFT)) + wxT("\";") + copyStringTo(getSymbol(SO_DELETE_LEFT)) + wxT('\n'); - exportString += wxT("\"") + copyStringTo(getDescription(SO_DELETE_RIGHT)) + wxT("\";") + copyStringTo(getSymbol(SO_DELETE_RIGHT)) + wxT('\n'); - exportString += wxT("\"") + copyStringTo(getDescription(SO_OVERWRITE_LEFT)) + wxT("\";") + copyStringTo(getSymbol(SO_OVERWRITE_LEFT)) + wxT('\n'); - exportString += wxT("\"") + copyStringTo(getDescription(SO_OVERWRITE_RIGHT)) + wxT("\";") + copyStringTo(getSymbol(SO_OVERWRITE_RIGHT)) + wxT('\n'); - exportString += wxT("\"") + copyStringTo(getDescription(SO_DO_NOTHING)) + wxT("\";") + copyStringTo(getSymbol(SO_DO_NOTHING)) + wxT('\n'); - exportString += wxT("\"") + copyStringTo(getDescription(SO_EQUAL)) + wxT("\";") + copyStringTo(getSymbol(SO_EQUAL)) + wxT('\n'); - exportString += wxT("\"") + copyStringTo(getDescription(SO_UNRESOLVED_CONFLICT)) + wxT("\";") + copyStringTo(getSymbol(SO_UNRESOLVED_CONFLICT)) + wxT('\n'); + exportString += wxT("\"") + copyStringTo(getSyncOpDescription(SO_EQUAL)) + wxT("\";") + copyStringTo(getSymbol(SO_EQUAL)) + wxT('\n'); + exportString += wxT("\"") + copyStringTo(getSyncOpDescription(SO_CREATE_NEW_LEFT)) + wxT("\";") + copyStringTo(getSymbol(SO_CREATE_NEW_LEFT)) + wxT('\n'); + exportString += wxT("\"") + copyStringTo(getSyncOpDescription(SO_CREATE_NEW_RIGHT)) + wxT("\";") + copyStringTo(getSymbol(SO_CREATE_NEW_RIGHT)) + wxT('\n'); + exportString += wxT("\"") + copyStringTo(getSyncOpDescription(SO_OVERWRITE_LEFT)) + wxT("\";") + copyStringTo(getSymbol(SO_OVERWRITE_LEFT)) + wxT('\n'); + exportString += wxT("\"") + copyStringTo(getSyncOpDescription(SO_OVERWRITE_RIGHT)) + wxT("\";") + copyStringTo(getSymbol(SO_OVERWRITE_RIGHT)) + wxT('\n'); + exportString += wxT("\"") + copyStringTo(getSyncOpDescription(SO_DELETE_LEFT)) + wxT("\";") + copyStringTo(getSymbol(SO_DELETE_LEFT)) + wxT('\n'); + exportString += wxT("\"") + copyStringTo(getSyncOpDescription(SO_DELETE_RIGHT)) + wxT("\";") + copyStringTo(getSymbol(SO_DELETE_RIGHT)) + wxT('\n'); + exportString += wxT("\"") + copyStringTo(getSyncOpDescription(SO_DO_NOTHING)) + wxT("\";") + copyStringTo(getSymbol(SO_DO_NOTHING)) + wxT('\n'); + exportString += wxT("\"") + copyStringTo(getSyncOpDescription(SO_UNRESOLVED_CONFLICT)) + wxT("\";") + copyStringTo(getSymbol(SO_UNRESOLVED_CONFLICT)) + wxT('\n'); } else { - exportString += wxT("\"") + copyStringTo(getDescription(FILE_LEFT_SIDE_ONLY)) + wxT("\";") + copyStringTo(getSymbol(FILE_LEFT_SIDE_ONLY)) + wxT('\n'); - exportString += wxT("\"") + copyStringTo(getDescription(FILE_RIGHT_SIDE_ONLY)) + wxT("\";") + copyStringTo(getSymbol(FILE_RIGHT_SIDE_ONLY)) + wxT('\n'); - exportString += wxT("\"") + copyStringTo(getDescription(FILE_LEFT_NEWER)) + wxT("\";") + copyStringTo(getSymbol(FILE_LEFT_NEWER)) + wxT('\n'); - exportString += wxT("\"") + copyStringTo(getDescription(FILE_RIGHT_NEWER)) + wxT("\";") + copyStringTo(getSymbol(FILE_RIGHT_NEWER)) + wxT('\n'); - exportString += wxT("\"") + copyStringTo(getDescription(FILE_DIFFERENT)) + wxT("\";") + copyStringTo(getSymbol(FILE_DIFFERENT)) + wxT('\n'); - exportString += wxT("\"") + copyStringTo(getDescription(FILE_EQUAL)) + wxT("\";") + copyStringTo(getSymbol(FILE_EQUAL)) + wxT('\n'); - exportString += wxT("\"") + copyStringTo(getDescription(FILE_CONFLICT)) + wxT("\";") + copyStringTo(getSymbol(FILE_CONFLICT)) + wxT('\n'); + exportString += wxT("\"") + copyStringTo(getCategoryDescription(FILE_EQUAL)) + wxT("\";") + copyStringTo(getSymbol(FILE_EQUAL)) + wxT('\n'); + exportString += wxT("\"") + copyStringTo(getCategoryDescription(FILE_DIFFERENT)) + wxT("\";") + copyStringTo(getSymbol(FILE_DIFFERENT)) + wxT('\n'); + exportString += wxT("\"") + copyStringTo(getCategoryDescription(FILE_LEFT_SIDE_ONLY)) + wxT("\";") + copyStringTo(getSymbol(FILE_LEFT_SIDE_ONLY)) + wxT('\n'); + exportString += wxT("\"") + copyStringTo(getCategoryDescription(FILE_RIGHT_SIDE_ONLY)) + wxT("\";") + copyStringTo(getSymbol(FILE_RIGHT_SIDE_ONLY)) + wxT('\n'); + exportString += wxT("\"") + copyStringTo(getCategoryDescription(FILE_LEFT_NEWER)) + wxT("\";") + copyStringTo(getSymbol(FILE_LEFT_NEWER)) + wxT('\n'); + exportString += wxT("\"") + copyStringTo(getCategoryDescription(FILE_RIGHT_NEWER)) + wxT("\";") + copyStringTo(getSymbol(FILE_RIGHT_NEWER)) + wxT('\n'); + exportString += wxT("\"") + copyStringTo(getCategoryDescription(FILE_CONFLICT)) + wxT("\";") + copyStringTo(getSymbol(FILE_CONFLICT)) + wxT('\n'); } exportString += wxT('\n'); diff --git a/ui/progress_indicator.cpp b/ui/progress_indicator.cpp index 25b9d6e8..092cb182 100644 --- a/ui/progress_indicator.cpp +++ b/ui/progress_indicator.cpp @@ -6,24 +6,23 @@ #include "progress_indicator.h" #include -#include "gui_generated.h" +#include +#include #include -#include "../lib/resources.h" -#include -#include -#include "../lib/statistics.h" #include -#include -#include "tray_icon.h" -#include #include -#include "../lib/error_log.h" #include -#include "taskbar.h" +#include +#include #include #include #include -#include +#include "gui_generated.h" +#include "../lib/resources.h" +#include "../lib/error_log.h" +#include "../lib/statistics.h" +#include "tray_icon.h" +#include "taskbar.h" using namespace zen; @@ -289,7 +288,7 @@ void CompareStatus::CompareStatusImpl::updateStatusPanelNow() showProgressExternally(toStringSep(scannedObjects) + wxT(" - ") + _("Scanning...")); break; case COMPARING_CONTENT: - showProgressExternally(percentageToShortString(fraction) + wxT(" - ") + _("Comparing content..."), fraction); + showProgressExternally(fractionToShortString(fraction) + wxT(" - ") + _("Comparing content..."), fraction); break; } @@ -393,13 +392,15 @@ public: m_bpButtonErrors ->setActive(true); m_bpButtonWarnings->setActive(true); - m_bpButtonInfo ->setActive(false); + m_bpButtonInfo ->setActive(errorCount + warningCount == 0); m_bpButtonErrors ->Show(errorCount != 0); m_bpButtonWarnings->Show(warningCount != 0); m_bpButtonInfo ->Show(infoCount != 0); updateLogText(); + + m_textCtrlInfo->Connect(wxEVT_KEY_DOWN, wxKeyEventHandler(LogControl::onKeyEvent), NULL, this); } virtual void OnErrors(wxCommandEvent& event) @@ -421,6 +422,20 @@ public: } private: + void onKeyEvent(wxKeyEvent& event) + { + const int keyCode = event.GetKeyCode(); + + if (event.ControlDown()) + switch (keyCode) + { + case 'A': //CTRL + A + m_textCtrlInfo->SetSelection(-1, -1); //select all + return; + } + event.Skip(); + } + void updateLogText() { int includedTypes = 0; @@ -509,9 +524,12 @@ struct LabelFormatterBytes : public LabelFormatter { virtual double getOptimalBlockSize(double bytesProposed) const { + bytesProposed *= 2; //make blocks twice the default size + + if (bytesProposed <= 1024 * 1024) //set 1 MB min size: reduce initial rapid changes in y-label + return 1024 * 1024; + //round to next number which is a convenient to read block size - if (bytesProposed <= 0) - return 0; const double k = std::floor(std::log(bytesProposed) / std::log(2.0)); const double e = std::pow(2.0, k); @@ -530,8 +548,11 @@ struct LabelFormatterTimeElapsed : public LabelFormatter { virtual double getOptimalBlockSize(double secProposed) const { - if (secProposed <= 5) - return 5; //minimum block size + if (secProposed <= 10) + return 10; //minimum block size + + if (secProposed <= 20) //avoid flicker between 10<->15<->20 sec blocks + return bestFit(secProposed, 10, 20); //for seconds and minutes: nice numbers are 1, 5, 10, 15, 20, 30 auto calcBlock = [](double val) -> double @@ -803,10 +824,7 @@ SyncStatus::SyncStatusImpl::~SyncStatusImpl() if (mainDialog) { mainDialog->enableAllElements(); - - //restore title text - mainDialog->SetTitle(titelTextBackup); - + mainDialog->SetTitle(titelTextBackup); //restore title text mainDialog->Raise(); mainDialog->SetFocus(); } @@ -977,13 +995,13 @@ void SyncStatus::SyncStatusImpl::updateStatusDialogNow(bool allowYield) showProgressExternally(wxString() + toStringSep(scannedObjects) + wxT(" - ") + _("Scanning...") + postFix); break; case SyncStatus::COMPARING_CONTENT: - showProgressExternally(wxString() + percentageToShortString(fraction) + wxT(" - ") + _("Comparing content...") + postFix, fraction); + showProgressExternally(wxString() + fractionToShortString(fraction) + wxT(" - ") + _("Comparing content...") + postFix, fraction); break; case SyncStatus::SYNCHRONIZING: - showProgressExternally(wxString() + percentageToShortString(fraction) + wxT(" - ") + _("Synchronizing...") + postFix, fraction); + showProgressExternally(wxString() + fractionToShortString(fraction) + wxT(" - ") + _("Synchronizing...") + postFix, fraction); break; case SyncStatus::PAUSE: - showProgressExternally(wxString() + percentageToShortString(fraction) + wxT(" - ") + _("Paused") + postFix, fraction); + showProgressExternally(wxString() + fractionToShortString(fraction) + wxT(" - ") + _("Paused") + postFix, fraction); break; case SyncStatus::ABORTED: showProgressExternally(_("Aborted") + postFix, fraction); @@ -1219,10 +1237,17 @@ void SyncStatus::SyncStatusImpl::processHasFinished(SyncStatus::SyncStatusID id, m_staticTextSpeed->SetLabel(timeElapMs <= 0 ? L"-" : zen::filesizeToShortString(zen::to(currentData * 1000 / timeElapMs)) + _("/sec")); //fill result listbox: + + //workaround wxListBox bug on Windows XP: labels are drawn on top of each other + assert(m_listbookResult->GetImageList()); //make sure listbook keeps *any* image list + //due to some crazy reasons that aren't worth debugging, this needs to be done directly in wxFormBuilder, + //the following call is *not* sufficient: m_listbookResult->AssignImageList(new wxImageList(0, 0)); + //note: alternative solutions involving wxLC_LIST, wxLC_REPORT and SetWindowStyleFlag() do not work portably! wxListBook using wxLC_ICON is obviously a class invariant! + //1. re-arrange graph into results listbook bSizerTop->Detach(m_panelProgress); m_panelProgress->Reparent(m_listbookResult); - m_listbookResult->AddPage(m_panelProgress, _("Statistics"), true); + m_listbookResult->AddPage(m_panelProgress, _("Statistics"), true); //AddPage() takes ownership! //2. log file LogControl* logControl = new LogControl(m_listbookResult, log); diff --git a/ui/small_dlgs.cpp b/ui/small_dlgs.cpp index 779bc427..cf323279 100644 --- a/ui/small_dlgs.cpp +++ b/ui/small_dlgs.cpp @@ -607,13 +607,13 @@ SyncPreviewDlg::SyncPreviewDlg(wxWindow* parent, m_staticTextVariant->SetLabel(variantName); m_textCtrlData->SetValue(zen::filesizeToShortString(statistics.getDataToProcess())); - m_textCtrlCreateL->SetValue(toStringSep(statistics.getCreate ())); - m_textCtrlUpdateL->SetValue(toStringSep(statistics.getOverwrite())); - m_textCtrlDeleteL->SetValue(toStringSep(statistics.getDelete ())); + m_textCtrlCreateL->SetValue(toStringSep(statistics.getCreate())); + m_textCtrlUpdateL->SetValue(toStringSep(statistics.getUpdate())); + m_textCtrlDeleteL->SetValue(toStringSep(statistics.getDelete())); - m_textCtrlCreateR->SetValue(toStringSep(statistics.getCreate ())); - m_textCtrlUpdateR->SetValue(toStringSep(statistics.getOverwrite())); - m_textCtrlDeleteR->SetValue(toStringSep(statistics.getDelete ())); + m_textCtrlCreateR->SetValue(toStringSep(statistics.getCreate())); + m_textCtrlUpdateR->SetValue(toStringSep(statistics.getUpdate())); + m_textCtrlDeleteR->SetValue(toStringSep(statistics.getDelete())); m_checkBoxDontShowAgain->SetValue(dontShowAgain); @@ -694,7 +694,7 @@ CompareCfgDialog::CompareCfgDialog(wxWindow* parent, #endif enumDescrHandleSyml. - add(SYMLINK_IGNORE, _("Ignore")). + add(SYMLINK_IGNORE, _("Exclude")). add(SYMLINK_USE_DIRECTLY, _("Direct")). add(SYMLINK_FOLLOW_LINK, _("Follow")); @@ -818,7 +818,7 @@ GlobalSettingsDlg::GlobalSettingsDlg(wxWindow* parent, xmlAccess::XmlGlobalSetti m_checkBoxCopyPermissions->SetLabel(_("Copy NTFS permissions")); #else m_checkBoxCopyLocked->Hide(); - m_textCtrlCopyLocked->Hide(); + m_staticTextCopyLocked->Hide(); #endif set(globalSettings.gui.externelApplications); diff --git a/ui/sync_cfg.cpp b/ui/sync_cfg.cpp index d19520be..26ea5b2e 100644 --- a/ui/sync_cfg.cpp +++ b/ui/sync_cfg.cpp @@ -5,6 +5,7 @@ // ************************************************************************** #include "sync_cfg.h" +#include #include "../lib/resources.h" #include "../lib/dir_name.h" #include @@ -12,10 +13,10 @@ #include #include #include "gui_generated.h" -#include #include #include "../lib/dir_name.h" #include +#include "../file_hierarchy.h" using namespace zen; using namespace xmlAccess; @@ -97,15 +98,15 @@ void updateConfigIcons(const DirectionConfig& directionCfg, { case SYNC_DIR_RIGHT: buttonLeftOnly->SetBitmapLabel(GlobalResources::getImage(wxT("createRight"))); - buttonLeftOnly->SetToolTip(getDescription(SO_CREATE_NEW_RIGHT)); + buttonLeftOnly->SetToolTip(getSyncOpDescription(SO_CREATE_NEW_RIGHT)); break; case SYNC_DIR_LEFT: buttonLeftOnly->SetBitmapLabel(GlobalResources::getImage(wxT("deleteLeft"))); - buttonLeftOnly->SetToolTip(getDescription(SO_DELETE_LEFT)); + buttonLeftOnly->SetToolTip(getSyncOpDescription(SO_DELETE_LEFT)); break; case SYNC_DIR_NONE: buttonLeftOnly->SetBitmapLabel(GlobalResources::getImage(wxT("none"))); - buttonLeftOnly->SetToolTip(getDescription(SO_DO_NOTHING)); + buttonLeftOnly->SetToolTip(getSyncOpDescription(SO_DO_NOTHING)); break; } @@ -113,15 +114,15 @@ void updateConfigIcons(const DirectionConfig& directionCfg, { case SYNC_DIR_RIGHT: buttonRightOnly->SetBitmapLabel(GlobalResources::getImage(wxT("deleteRight"))); - buttonRightOnly->SetToolTip(getDescription(SO_DELETE_RIGHT)); + buttonRightOnly->SetToolTip(getSyncOpDescription(SO_DELETE_RIGHT)); break; case SYNC_DIR_LEFT: buttonRightOnly->SetBitmapLabel(GlobalResources::getImage(wxT("createLeft"))); - buttonRightOnly->SetToolTip(getDescription(SO_CREATE_NEW_LEFT)); + buttonRightOnly->SetToolTip(getSyncOpDescription(SO_CREATE_NEW_LEFT)); break; case SYNC_DIR_NONE: buttonRightOnly->SetBitmapLabel(GlobalResources::getImage(wxT("none"))); - buttonRightOnly->SetToolTip(getDescription(SO_DO_NOTHING)); + buttonRightOnly->SetToolTip(getSyncOpDescription(SO_DO_NOTHING)); break; } @@ -129,15 +130,15 @@ void updateConfigIcons(const DirectionConfig& directionCfg, { case SYNC_DIR_RIGHT: buttonLeftNewer->SetBitmapLabel(GlobalResources::getImage(wxT("updateRight"))); - buttonLeftNewer->SetToolTip(getDescription(SO_OVERWRITE_RIGHT)); + buttonLeftNewer->SetToolTip(getSyncOpDescription(SO_OVERWRITE_RIGHT)); break; case SYNC_DIR_LEFT: buttonLeftNewer->SetBitmapLabel(GlobalResources::getImage(wxT("updateLeft"))); - buttonLeftNewer->SetToolTip(getDescription(SO_OVERWRITE_LEFT)); + buttonLeftNewer->SetToolTip(getSyncOpDescription(SO_OVERWRITE_LEFT)); break; case SYNC_DIR_NONE: buttonLeftNewer->SetBitmapLabel(GlobalResources::getImage(wxT("none"))); - buttonLeftNewer->SetToolTip(getDescription(SO_DO_NOTHING)); + buttonLeftNewer->SetToolTip(getSyncOpDescription(SO_DO_NOTHING)); break; } @@ -145,15 +146,15 @@ void updateConfigIcons(const DirectionConfig& directionCfg, { case SYNC_DIR_RIGHT: buttonRightNewer->SetBitmapLabel(GlobalResources::getImage(wxT("updateRight"))); - buttonRightNewer->SetToolTip(getDescription(SO_OVERWRITE_RIGHT)); + buttonRightNewer->SetToolTip(getSyncOpDescription(SO_OVERWRITE_RIGHT)); break; case SYNC_DIR_LEFT: buttonRightNewer->SetBitmapLabel(GlobalResources::getImage(wxT("updateLeft"))); - buttonRightNewer->SetToolTip(getDescription(SO_OVERWRITE_LEFT)); + buttonRightNewer->SetToolTip(getSyncOpDescription(SO_OVERWRITE_LEFT)); break; case SYNC_DIR_NONE: buttonRightNewer->SetBitmapLabel(GlobalResources::getImage(wxT("none"))); - buttonRightNewer->SetToolTip(getDescription(SO_DO_NOTHING)); + buttonRightNewer->SetToolTip(getSyncOpDescription(SO_DO_NOTHING)); break; } @@ -161,15 +162,15 @@ void updateConfigIcons(const DirectionConfig& directionCfg, { case SYNC_DIR_RIGHT: buttonDifferent->SetBitmapLabel(GlobalResources::getImage(wxT("updateRight"))); - buttonDifferent->SetToolTip(getDescription(SO_OVERWRITE_RIGHT)); + buttonDifferent->SetToolTip(getSyncOpDescription(SO_OVERWRITE_RIGHT)); break; case SYNC_DIR_LEFT: buttonDifferent->SetBitmapLabel(GlobalResources::getImage(wxT("updateLeft"))); - buttonDifferent->SetToolTip(getDescription(SO_OVERWRITE_LEFT)); + buttonDifferent->SetToolTip(getSyncOpDescription(SO_OVERWRITE_LEFT)); break; case SYNC_DIR_NONE: buttonDifferent->SetBitmapLabel(GlobalResources::getImage(wxT("none"))); - buttonDifferent->SetToolTip(getDescription(SO_DO_NOTHING)); + buttonDifferent->SetToolTip(getSyncOpDescription(SO_DO_NOTHING)); break; } @@ -177,11 +178,11 @@ void updateConfigIcons(const DirectionConfig& directionCfg, { case SYNC_DIR_RIGHT: buttonConflict->SetBitmapLabel(GlobalResources::getImage(wxT("updateRight"))); - buttonConflict->SetToolTip(getDescription(SO_OVERWRITE_RIGHT)); + buttonConflict->SetToolTip(getSyncOpDescription(SO_OVERWRITE_RIGHT)); break; case SYNC_DIR_LEFT: buttonConflict->SetBitmapLabel(GlobalResources::getImage(wxT("updateLeft"))); - buttonConflict->SetToolTip(getDescription(SO_OVERWRITE_LEFT)); + buttonConflict->SetToolTip(getSyncOpDescription(SO_OVERWRITE_LEFT)); break; case SYNC_DIR_NONE: buttonConflict->SetBitmapLabel(GlobalResources::getImage(wxT("conflict"))); @@ -219,7 +220,7 @@ SyncCfgDialog::SyncCfgDialog(wxWindow* window, //a proper set-method may be in order some time... setEnumVal(enumDelhandDescr, *m_choiceHandleDeletion, syncCfg.handleDeletion); - customDelFolder.setName(syncCfg.customDeletionDirectory); + customDelFolder.setName(toWx(syncCfg.customDeletionDirectory)); updateGui(); //error handling @@ -330,7 +331,7 @@ void SyncCfgDialog::OnApply(wxCommandEvent& event) //write configuration to main dialog syncCfgOut.directionCfg = currentDirectionCfg; syncCfgOut.handleDeletion = getEnumVal(enumDelhandDescr, *m_choiceHandleDeletion); - syncCfgOut.customDeletionDirectory = customDelFolder.getName(); + syncCfgOut.customDeletionDirectory = toZ(customDelFolder.getName()); if (refHandleError) *refHandleError = getEnumVal(enumErrhandDescr, *m_choiceHandleError); diff --git a/ui/wx_form_build_hide_warnings.h b/ui/wx_form_build_hide_warnings.h index 277fa0e7..5988aa12 100644 --- a/ui/wx_form_build_hide_warnings.h +++ b/ui/wx_form_build_hide_warnings.h @@ -7,10 +7,14 @@ #ifndef WX_FORM_BUILD_230948324234234 #define WX_FORM_BUILD_230948324234234 -//hide compiler warnings in generated code +//pamper over wxFormBuilder "sub-optimal" code #ifdef __GNUC__ #pragma GCC diagnostic ignored "-Wunused-but-set-variable" +#pragma GCC diagnostic ignored "-Wunused-variable" + +#elif defined _MSC_VER +#pragma warning(disable: 4189) #endif #endif //WX_FORM_BUILD_230948324234234 diff --git a/version/version.h b/version/version.h index e1117ea0..f029c89d 100644 --- a/version/version.h +++ b/version/version.h @@ -3,7 +3,7 @@ namespace zen { -const wchar_t currentVersion[] = L"4.2"; //internal linkage! +const wchar_t currentVersion[] = L"4.3"; //internal linkage! } #endif diff --git a/version/version.rc b/version/version.rc index b902445b..60e22b93 100644 --- a/version/version.rc +++ b/version/version.rc @@ -1,2 +1,2 @@ -#define VER_FREEFILESYNC 4,2,0,0 -#define VER_FREEFILESYNC_STR "4.2\0" +#define VER_FREEFILESYNC 4,3,0,0 +#define VER_FREEFILESYNC_STR "4.3\0" diff --git a/wx+/format_unit.cpp b/wx+/format_unit.cpp index 994a2b29..361dbc62 100644 --- a/wx+/format_unit.cpp +++ b/wx+/format_unit.cpp @@ -135,7 +135,7 @@ std::wstring zen::remainingTimeToShortString(double timeInSec) } -std::wstring zen::percentageToShortString(double fraction) +std::wstring zen::fractionToShortString(double fraction) { return replaceCpy(_("%x%"), L"%x", printNumber(L"%3.2f", fraction * 100.0), false); } diff --git a/wx+/format_unit.h b/wx+/format_unit.h index 4adf74f8..953910b6 100644 --- a/wx+/format_unit.h +++ b/wx+/format_unit.h @@ -15,7 +15,7 @@ namespace zen { std::wstring filesizeToShortString(UInt64 filesize); std::wstring remainingTimeToShortString(double timeInSec); -std::wstring percentageToShortString(double fraction); //within [0, 1] +std::wstring fractionToShortString(double fraction); //within [0, 1] template std::wstring toStringSep(NumberType number); //convert number to std::wstring including thousands separator diff --git a/wx+/serialize.h b/wx+/serialize.h index cec70278..020b8709 100644 --- a/wx+/serialize.h +++ b/wx+/serialize.h @@ -7,11 +7,8 @@ #ifndef SERIALIZE_H_INCLUDED #define SERIALIZE_H_INCLUDED -#include #include -#include #include -#include #include @@ -26,18 +23,13 @@ template void writeString(wxOutputStream& stream, const S& str); //############# wxWidgets stream adapter ############# -// can be used as base classes (have virtual destructors) class FileInputStream : public wxInputStream { public: - FileInputStream(const Zstring& filename) : //throw FileError - fileObj(filename) {} + FileInputStream(const Zstring& filename) : fileObj(filename) {} //throw FileError private: - virtual size_t OnSysRead(void* buffer, size_t bufsize) - { - return fileObj.read(buffer, bufsize); //throw FileError - } + virtual size_t OnSysRead(void* buffer, size_t bufsize) { return fileObj.read(buffer, bufsize); } //throw FileError zen::FileInput fileObj; }; @@ -46,8 +38,7 @@ private: class FileOutputStream : public wxOutputStream { public: - FileOutputStream(const Zstring& filename) : //throw FileError - fileObj(filename, zen::FileOutput::ACC_OVERWRITE) {} + FileOutputStream(const Zstring& filename) : fileObj(filename, zen::FileOutput::ACC_OVERWRITE) {} //throw FileError private: virtual size_t OnSysWrite(const void* buffer, size_t bufsize) @@ -60,11 +51,11 @@ private: }; - -class ReadInputStream //throw FileError +//wxInputStream proxy throwing FileError on error +class CheckedReader { -protected: - ReadInputStream(wxInputStream& stream, const Zstring& errorObjName) : stream_(stream), errorObjName_(errorObjName) {} +public: + CheckedReader(wxInputStream& stream, const Zstring& errorObjName) : stream_(stream), errorObjName_(errorObjName) {} template T readNumberC() const; //throw FileError, checked read operation @@ -72,23 +63,19 @@ protected: template S readStringC() const; //throw FileError, checked read operation - typedef std::shared_ptr > CharArray; //there's no guarantee std::string has a ref-counted implementation... so use this "thing" - CharArray readArrayC() const; //throw FileError - +private: void check() const; - wxInputStream& getStream() { return stream_; } - -private: wxInputStream& stream_; const Zstring& errorObjName_; //used for error text only }; -class WriteOutputStream //throw FileError +//wxOutputStream proxy throwing FileError on error +class CheckedWriter { -protected: - WriteOutputStream(const Zstring& errorObjName, wxOutputStream& stream) : stream_(stream), errorObjName_(errorObjName) {} +public: + CheckedWriter(wxOutputStream& stream, const Zstring& errorObjName) : stream_(stream), errorObjName_(errorObjName) {} template void writeNumberC(T number) const; //throw FileError, checked write operation @@ -96,13 +83,9 @@ protected: template void writeStringC(const S& str) const; //throw FileError, checked write operation - void writeArrayC(const std::vector& buffer) const; //throw FileError - +private: void check() const; - wxOutputStream& getStream() { return stream_; } - -private: wxOutputStream& stream_; const Zstring& errorObjName_; //used for error text only! }; @@ -124,11 +107,6 @@ private: - - - - - @@ -155,21 +133,15 @@ void writePOD(wxOutputStream& stream, const T& pod) template inline S readString(wxInputStream& stream) { + //don't even consider UTF8 conversions here! "string" is expected to handle arbitrary binary data! + typedef typename S::value_type CharType; const auto strLength = readPOD(stream); - if (strLength <= 1000) - { - CharType buffer[1000]; - stream.Read(buffer, sizeof(CharType) * strLength); - return S(buffer, strLength); - } - else - { - std::vector buffer(strLength); //throw std::bad_alloc - stream.Read(&buffer[0], sizeof(CharType) * strLength); - return S(&buffer[0], strLength); - } + S output; + output.resize(strLength); //throw std::bad_alloc + stream.Read(&*output.begin(), sizeof(CharType) * strLength); + return output; } @@ -182,7 +154,7 @@ void writeString(wxOutputStream& stream, const S& str) inline -void ReadInputStream::check() const +void CheckedReader::check() const { if (stream_.GetLastError() != wxSTREAM_NO_ERROR) throw zen::FileError(_("Error reading from synchronization database:") + L" \n" + L"\"" + errorObjName_ + L"\""); @@ -191,7 +163,7 @@ void ReadInputStream::check() const template inline -T ReadInputStream::readNumberC() const //checked read operation +T CheckedReader::readNumberC() const //checked read operation { T output = readPOD(stream_); check(); @@ -200,13 +172,15 @@ T ReadInputStream::readNumberC() const //checked read operation template inline -S ReadInputStream::readStringC() const //checked read operation +S CheckedReader::readStringC() const //checked read operation { S output; try { - output = readString(stream_); //throw (std::bad_alloc) + output = readString(stream_); //throw std::bad_alloc check(); + if (stream_.LastRead() != output.length() * sizeof(typename S::value_type)) //some additional check + throw FileError(_("Error reading from synchronization database:") + L" \n" + L"\"" + errorObjName_ + L"\""); } catch (std::exception&) { @@ -216,24 +190,8 @@ S ReadInputStream::readStringC() const //checked read operation } -inline -ReadInputStream::CharArray ReadInputStream::readArrayC() const -{ - const std::uint32_t byteCount = readNumberC(); - CharArray buffer(new std::vector(byteCount)); - if (byteCount > 0) - { - stream_.Read(&(*buffer)[0], byteCount); - check(); - if (stream_.LastRead() != byteCount) //some additional check - throw FileError(_("Error reading from synchronization database:") + L" \n" + L"\"" + errorObjName_ + L"\""); - } - return buffer; -} - - template inline -void WriteOutputStream::writeNumberC(T number) const //checked write operation +void CheckedWriter::writeNumberC(T number) const //checked write operation { writePOD(stream_, number); check(); @@ -241,29 +199,17 @@ void WriteOutputStream::writeNumberC(T number) const //checked write operation template inline -void WriteOutputStream::writeStringC(const S& str) const //checked write operation +void CheckedWriter::writeStringC(const S& str) const //checked write operation { writeString(stream_, str); check(); + if (stream_.LastWrite() != str.length() * sizeof(typename S::value_type)) //some additional check + throw FileError(_("Error writing to synchronization database:") + L" \n" + L"\"" + errorObjName_ + L"\""); } inline -void WriteOutputStream::writeArrayC(const std::vector& buffer) const -{ - writeNumberC(static_cast(buffer.size())); - if (buffer.size() > 0) - { - stream_.Write(&buffer[0], buffer.size()); - check(); - if (stream_.LastWrite() != buffer.size()) //some additional check - throw FileError(_("Error writing to synchronization database:") + L" \n" + L"\"" + errorObjName_ + L"\""); - } -} - - -inline -void WriteOutputStream::check() const +void CheckedWriter::check() const { if (stream_.GetLastError() != wxSTREAM_NO_ERROR) throw FileError(_("Error writing to synchronization database:") + L" \n" + L"\"" + errorObjName_ + L"\""); diff --git a/zen/FindFilePlus/FindFilePlus.vcxproj b/zen/FindFilePlus/FindFilePlus.vcxproj new file mode 100644 index 00000000..2c4256a6 --- /dev/null +++ b/zen/FindFilePlus/FindFilePlus.vcxproj @@ -0,0 +1,245 @@ + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + {70394AEF-5897-4911-AFA1-82EAF0581EFA} + ShadowDll + Win32Proj + + + + DynamicLibrary + Unicode + true + Windows7.1SDK + + + DynamicLibrary + Unicode + Windows7.1SDK + + + DynamicLibrary + Unicode + true + Windows7.1SDK + + + DynamicLibrary + Unicode + Windows7.1SDK + + + + + + + + + + + + + + + + + + + <_ProjectFileVersion>10.0.30319.1 + OBJ\ + OBJ\$(ProjectName)_$(Configuration)_$(Platform)\ + false + OBJ\ + OBJ\$(ProjectName)_$(Configuration)_$(Platform)\ + false + .\ + OBJ\$(ProjectName)_$(Configuration)_$(Platform)\ + false + .\ + OBJ\$(ProjectName)_$(Configuration)_$(Platform)\ + false + FindFilePlus_$(Platform) + FindFilePlus_$(Platform) + FindFilePlus_$(Platform) + FindFilePlus_$(Platform) + D:\Data\WinDDK\inc\ddk;D:\Data\WinDDK\inc\api;D:\Data\WinDDK\inc\crt;$(WindowsSdkDir)\include;$(VCInstallDir)include + D:\Data\WinDDK\inc\ddk;D:\Data\WinDDK\inc\api;D:\Data\WinDDK\inc\crt;$(WindowsSdkDir)\include;$(VCInstallDir)include + D:\Data\WinDDK\inc\ddk;D:\Data\WinDDK\inc\api;D:\Data\WinDDK\inc\crt;$(WindowsSdkDir)\include;$(VCInstallDir)include + D:\Data\WinDDK\inc\ddk;D:\Data\WinDDK\inc\api;D:\Data\WinDDK\inc\crt;$(WindowsSdkDir)\include;$(VCInstallDir)include + + + + $(IntDir)Build.html + + + Disabled + _X86_;_DEBUG;_WINDOWS;_USRDLL;FIND_FILE_PLUS_DLL_EXPORTS;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebugDLL + + + Level4 + true + EditAndContinue + 4100 + ../.. + + + $(OutDir)$(TargetName)$(TargetExt) + true + true + $(IntDir)$(TargetName).pdb + Windows + + + $(IntDir)$(TargetName).lib + MachineX86 + + + + + $(IntDir)Build.html + + + X64 + + + Disabled + _AMD64_;_DEBUG;_WINDOWS;_USRDLL;FIND_FILE_PLUS_DLL_EXPORTS;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebugDLL + + + Level4 + true + ProgramDatabase + 4100 + ../.. + + + $(OutDir)$(TargetName)$(TargetExt) + true + true + $(IntDir)$(TargetName).pdb + Windows + + + $(IntDir)$(TargetName).lib + MachineX64 + + + + + $(IntDir)Build.html + + + MaxSpeed + true + _X86_;NDEBUG;_WINDOWS;_USRDLL;FIND_FILE_PLUS_DLL_EXPORTS;%(PreprocessorDefinitions) + MultiThreaded + true + + + Level4 + true + ProgramDatabase + 4100 + Speed + ../.. + + + $(OutDir)$(TargetName)$(TargetExt) + true + false + Windows + true + true + UseLinkTimeCodeGeneration + + + $(IntDir)$(TargetName).lib + MachineX86 + + + + + $(IntDir)Build.html + + + X64 + + + MaxSpeed + true + _AMD64_;NDEBUG;_WINDOWS;_USRDLL;FIND_FILE_PLUS_DLL_EXPORTS;%(PreprocessorDefinitions) + MultiThreaded + true + + + Level4 + true + ProgramDatabase + 4100 + Speed + ../.. + + + $(OutDir)$(TargetName)$(TargetExt) + true + false + Windows + true + true + UseLinkTimeCodeGeneration + + + $(IntDir)$(TargetName).lib + MachineX64 + + + + + + + false + + + false + + + false + + + false + + + + + + + + + + + + \ No newline at end of file diff --git a/zen/FindFilePlus/dll_main.cpp b/zen/FindFilePlus/dll_main.cpp new file mode 100644 index 00000000..5d64181b --- /dev/null +++ b/zen/FindFilePlus/dll_main.cpp @@ -0,0 +1,30 @@ +// ************************************************************************** +// * This file is part of the FreeFileSync project. It is distributed under * +// * GNU General Public License: http://www.gnu.org/licenses/gpl.html * +// * Copyright (C) 2008-2011 ZenJu (zhnmju123 AT gmx.de) * +// ************************************************************************** + + +#define WIN32_LEAN_AND_MEAN +#include + +#include "init_dll_binding.h" + + +//optional: add init/teardown logic here +BOOL APIENTRY DllMain(HINSTANCE hinstDLL, + DWORD fdwReason, + LPVOID lpvReserved) +{ + switch (fdwReason) + { + case DLL_PROCESS_ATTACH: + if (!findplus::initDllBinding()) + return false; + case DLL_PROCESS_DETACH: + case DLL_THREAD_ATTACH: + case DLL_THREAD_DETACH: + break; + } + return true; +} diff --git a/zen/FindFilePlus/find_file_plus.cpp b/zen/FindFilePlus/find_file_plus.cpp new file mode 100644 index 00000000..becfe553 --- /dev/null +++ b/zen/FindFilePlus/find_file_plus.cpp @@ -0,0 +1,298 @@ +// ************************************************************************** +// * This file is part of the FreeFileSync project. It is distributed under * +// * GNU General Public License: http://www.gnu.org/licenses/gpl.html * +// * Copyright (C) 2008-2011 ZenJu (zhnmju123 AT gmx.de) * +// ************************************************************************** + +#include "find_file_plus.h" +#include "init_dll_binding.h" +//#include //these two don't play nice with each other +#include "load_dll.h" +#include + +using namespace dll; +using namespace findplus; + + +namespace +{ +struct FileError +{ + FileError(ULONG errorCode) : win32Error(errorCode) {} + ULONG win32Error; +}; + + +//-------------------------------------------------------------------------------------------------------------- +typedef NTSTATUS (NTAPI* NtOpenFileFunc)(PHANDLE fileHandle, + ACCESS_MASK desiredAccess, + POBJECT_ATTRIBUTES objectAttributes, + PIO_STATUS_BLOCK ioStatusBlock, + ULONG shareAccess, + ULONG openOptions); + +typedef NTSTATUS (NTAPI* NtCloseFunc)(HANDLE handle); + +typedef NTSTATUS (NTAPI* NtQueryDirectoryFileFunc)(HANDLE fileHandle, + HANDLE event, + PIO_APC_ROUTINE apcRoutine, + PVOID apcContext, + PIO_STATUS_BLOCK ioStatusBlock, + PVOID fileInformation, + ULONG length, + FILE_INFORMATION_CLASS fileInformationClass, + BOOLEAN ReturnSingleEntry, + PUNICODE_STRING fileMask, + BOOLEAN restartScan); + +typedef ULONG (NTAPI* RtlNtStatusToDosErrorFunc)(NTSTATUS /*__in status*/); + +typedef struct _RTL_RELATIVE_NAME_U +{ + UNICODE_STRING RelativeName; + HANDLE ContainingDirectory; + PVOID /*PRTLP_CURDIR_REF*/ CurDirRef; +} RTL_RELATIVE_NAME_U, *PRTL_RELATIVE_NAME_U; + +typedef BOOLEAN (NTAPI* RtlDosPathNameToNtPathName_UFunc)(PCWSTR, //__in dosFileName, + PUNICODE_STRING, //__out ntFileName, + PCWSTR*, //__out_optFilePart, + PRTL_RELATIVE_NAME_U); //__out_opt relativeName + +typedef BOOLEAN (NTAPI* RtlDosPathNameToRelativeNtPathName_UFunc)(PCWSTR, //__in dosFileName, + PUNICODE_STRING, //__out ntFileName, + PCWSTR*, //__out_optFilePart, + PRTL_RELATIVE_NAME_U); //__out_opt relativeName + +typedef VOID (NTAPI* RtlFreeUnicodeStringFunc)(PUNICODE_STRING); //__inout unicodeString + +//-------------------------------------------------------------------------------------------------------------- + +//it seems we cannot use any of the ntoskrnl.lib files in WinDDK as they produce access violations +//fortunately dynamic binding works fine: +const SysDllFun ntOpenFile (L"ntdll.dll", "NtOpenFile"); +const SysDllFun ntClose (L"ntdll.dll", "NtClose"); +const SysDllFun ntQueryDirectoryFile (L"ntdll.dll", "NtQueryDirectoryFile"); +const SysDllFun rtlNtStatusToDosError (L"ntdll.dll", "RtlNtStatusToDosError"); +const SysDllFun rtlFreeUnicodeString (L"ntdll.dll", "RtlFreeUnicodeString"); +const SysDllFun rtlDosPathNameToNtPathName_U(SysDllFun(L"ntdll.dll", "RtlDosPathNameToRelativeNtPathName_U") ? + SysDllFun(L"ntdll.dll", "RtlDosPathNameToRelativeNtPathName_U") : //use the newer version if available + SysDllFun(L"ntdll.dll", "RtlDosPathNameToNtPathName_U")); //fallback for XP +//global constants only -> preserve thread safety! +} + + +bool findplus::initDllBinding() //evaluate in ::DllMain() when attaching process +{ + //NT/ZwXxx Routines + //http://msdn.microsoft.com/en-us/library/ff567122(v=VS.85).aspx + + //Run-Time Library (RTL) Routines + //http://msdn.microsoft.com/en-us/library/ff563638(v=VS.85).aspx + + //verify dynamic dll binding + return ntOpenFile && + ntClose && + ntQueryDirectoryFile && + rtlNtStatusToDosError && + rtlFreeUnicodeString && + rtlDosPathNameToNtPathName_U; + + //this may become handy some time: nt status code STATUS_ORDINAL_NOT_FOUND maps to win32 code ERROR_INVALID_ORDINAL +} + + +class findplus::FileSearcher +{ +public: + FileSearcher(const wchar_t* dirname); //throw FileError + ~FileSearcher(); + + void readdir(FileInformation& output); //throw FileError + +private: + UNICODE_STRING ntPathName; //it seems hDir implicitly keeps a reference to this, at least ::FindFirstFile() does no cleanup before ::FindClose()! + HANDLE hDir; + + ULONG nextEntryOffset; //!= 0 if entry is waiting in buffer + //::FindNextFileW() uses 0x1000 = 4096 = sizeof(FILE_BOTH_DIR_INFORMATION) + sizeof(TCHAR) * 2000 + //=> let's use the same, even if our header is 16 byte larger; maybe there is some packet size advantage for networks? Note that larger buffers seem to degrade performance. + static const ULONG BUFFER_SIZE = 4096; + LONGLONG buffer[BUFFER_SIZE / sizeof(LONGLONG)]; //buffer needs to be aligned at LONGLONG boundary + + static_assert(BUFFER_SIZE % sizeof(LONGLONG) == 0, "ups, our buffer is trimmed!"); +}; + + +FileSearcher::FileSearcher(const wchar_t* dirname) : + hDir(NULL), + nextEntryOffset(0) +{ + ntPathName.Buffer = NULL; + ntPathName.Length = 0; + ntPathName.MaximumLength = 0; + + zen::ScopeGuard guardConstructor = zen::makeGuard([&]() { this->~FileSearcher(); }); + //-------------------------------------------------------------------------------------------------------------- + + //convert dosFileName, e.g. C:\Users or \\?\C:\Users to ntFileName \??\C:\Users + //in contrast to ::FindFirstFile() we don't evaluate the relativeName, however tests indicate ntFileName is *always* filled with an absolute name, even if dosFileName is relative + + //NOTE: RtlDosPathNameToNtPathName_U may be used on all XP/Win7/Win8 for compatibility + // RtlDosPathNameToNtPathName_U: used by Windows XP available with OS version 3.51 (Windows NT) and higher + // RtlDosPathNameToRelativeNtPathName_U: used by Win7/Win8 available with OS version 5.2 (Windows Server 2003) and higher + if (!rtlDosPathNameToNtPathName_U(dirname, //__in dosFileName, + &ntPathName, //__out ntFileName, + NULL, //__out_optFilePart, + NULL)) //__out_opt relativeName - empty if dosFileName is absolute + throw FileError(rtlNtStatusToDosError(STATUS_OBJECT_PATH_NOT_FOUND)); //translates to ERROR_PATH_NOT_FOUND, same behavior like ::FindFirstFileEx() + + OBJECT_ATTRIBUTES objAttr = {}; + InitializeObjectAttributes(&objAttr, //[out] POBJECT_ATTRIBUTES initializedAttributes, + &ntPathName, //[in] PUNICODE_STRING objectName, + OBJ_CASE_INSENSITIVE, //[in] ULONG attributes, + NULL, //[in] HANDLE rootDirectory, + NULL); //[in, optional] PSECURITY_DESCRIPTOR securityDescriptor + + { + IO_STATUS_BLOCK status = {}; + NTSTATUS rv = ntOpenFile(&hDir, //__out PHANDLE FileHandle, + FILE_LIST_DIRECTORY | SYNCHRONIZE, //__in ACCESS_MASK desiredAccess, - 100001 used by ::FindFirstFile() on all XP/Win7/Win8 + &objAttr, //__in POBJECT_ATTRIBUTES objectAttributes, + &status, //__out PIO_STATUS_BLOCK ioStatusBlock, + FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, //__in ULONG shareAccess, - 7 on Win7/Win8, 3 on XP + FILE_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT | FILE_OPEN_FOR_BACKUP_INTENT); //__in ULONG openOptions - 4021 used on all XP/Win7/Win8 + if (!NT_SUCCESS(rv)) + throw FileError(rtlNtStatusToDosError(rv)); + } + + guardConstructor.dismiss(); +} + + +inline +FileSearcher::~FileSearcher() +{ + //cleanup in reverse order + if (hDir) + ntClose(hDir); + + if (ntPathName.Buffer) + rtlFreeUnicodeString(&ntPathName); //cleanup identical to ::FindFirstFile() + //note that most if this function seems inlined by the linker, so that its assembly looks equivalent to "RtlFreeHeap(GetProcessHeap(), 0, ntPathName.Buffer)" +} + + +void FileSearcher::readdir(FileInformation& output) +{ + //although FILE_ID_FULL_DIR_INFORMATION should suffice for our purposes, there are problems on Windows XP for certain directories, e.g. "\\Vboxsvr\build" + //making NtQueryDirectoryFile() return with STATUS_INVALID_PARAMETER while other directories, e.g. "C:\" work fine for some reason + //FILE_ID_BOTH_DIR_INFORMATION on the other hand works on XP/Win7/Win8 + //performance: there is no noticable difference between FILE_ID_BOTH_DIR_INFORMATION and FILE_ID_FULL_DIR_INFORMATION + + /* corresponding first access in ::FindFirstFileW() + + NTSTATUS rv = ntQueryDirectoryFile(hDir, //__in HANDLE fileHandle, + NULL, //__in_opt HANDLE event, + NULL, //__in_opt PIO_APC_ROUTINE apcRoutine, + NULL, //__in_opt PVOID apcContext, + &status, //__out PIO_STATUS_BLOCK ioStatusBlock, + &buffer, //__out_bcount(Length) PVOID fileInformation, + BUFFER_SIZE, //__in ULONG length, ::FindFirstFileW() on all XP/Win7/Win8 uses sizeof(FILE_BOTH_DIR_INFORMATION) + sizeof(TCHAR) * MAX_PATH == 0x268 + FileIdBothDirectoryInformation, //__in FILE_INFORMATION_CLASS fileInformationClass - all XP/Win7/Win8 use "FileBothDirectoryInformation" + true, //__in BOOLEAN returnSingleEntry, + NULL, //__in_opt PUNICODE_STRING mask, + false); //__in BOOLEAN restartScan + */ + + //analog to ::FindNextFileW() with performance optimized access (in contrast to first access in ::FindFirstFileW()) + if (nextEntryOffset == 0) + { + IO_STATUS_BLOCK status = {}; + NTSTATUS rv = ntQueryDirectoryFile(hDir, //__in HANDLE fileHandle, + NULL, //__in_opt HANDLE event, + NULL, //__in_opt PIO_APC_ROUTINE apcRoutine, + NULL, //__in_opt PVOID apcContext, + &status, //__out PIO_STATUS_BLOCK ioStatusBlock, + &buffer, //__out_bcount(Length) PVOID fileInformation, + BUFFER_SIZE, //__in ULONG length, ::FindNextFileW() on all XP/Win7/Win8 uses sizeof(FILE_BOTH_DIR_INFORMATION) + sizeof(TCHAR) * 2000 == 0x1000 + FileIdBothDirectoryInformation, //__in FILE_INFORMATION_CLASS fileInformationClass - all XP/Win7/Win8 use "FileBothDirectoryInformation" + false, //__in BOOLEAN returnSingleEntry, + NULL, //__in_opt PUNICODE_STRING mask, + false); //__in BOOLEAN restartScan + if (!NT_SUCCESS(rv)) + throw FileError(rtlNtStatusToDosError(rv)); //throws STATUS_NO_MORE_FILES when finished + + if (status.Information == 0) //except for the first call to call ::NtQueryDirectoryFile(): + throw FileError(rtlNtStatusToDosError(STATUS_BUFFER_OVERFLOW)); //if buffer size is too small, return value is STATUS_SUCCESS and Information == 0 -> we don't expect this! + } + + const FILE_ID_BOTH_DIR_INFORMATION& dirInfo = *reinterpret_cast(reinterpret_cast(buffer) + nextEntryOffset); + + if (dirInfo.NextEntryOffset == 0) + nextEntryOffset = 0; //our offset is relative to the beginning of the buffer + else + nextEntryOffset += dirInfo.NextEntryOffset; + + + auto toFileTime = [](const LARGE_INTEGER & rawTime) -> FILETIME + { + FILETIME tmp = { rawTime.LowPart, rawTime.HighPart }; + return tmp; + }; + + output.creationTime = toFileTime(dirInfo.CreationTime); + output.lastWriteTime = toFileTime(dirInfo.LastWriteTime); + output.fileSize.QuadPart = dirInfo.EndOfFile.QuadPart; + output.fileId.QuadPart = dirInfo.FileId.QuadPart; + output.fileAttributes = dirInfo.FileAttributes; + output.shortNameLength = dirInfo.FileNameLength / sizeof(TCHAR); //FileNameLength is in bytes! + + if (dirInfo.FileNameLength + sizeof(TCHAR) > sizeof(output.shortName)) //this may actually happen if ::NtQueryDirectoryFile() decides to return a + throw FileError(rtlNtStatusToDosError(STATUS_BUFFER_OVERFLOW)); //short name of length MAX_PATH + 1, 0-termination is not required! + + ::memcpy(output.shortName, dirInfo.FileName, dirInfo.FileNameLength); + output.shortName[output.shortNameLength] = 0; //NOTE: FILE_ID_BOTH_DIR_INFORMATION::FileName in general is NOT 0-terminated! It is on XP/Win7, but NOT on Win8! + + static_assert(sizeof(output.creationTime) == sizeof(dirInfo.CreationTime), "dang!"); + static_assert(sizeof(output.lastWriteTime) == sizeof(dirInfo.LastWriteTime), "dang!"); + static_assert(sizeof(output.fileSize) == sizeof(dirInfo.EndOfFile), "dang!"); + static_assert(sizeof(output.fileId) == sizeof(dirInfo.FileId), "dang!"); + static_assert(sizeof(output.fileAttributes) == sizeof(dirInfo.FileAttributes), "dang!"); +} + + +FindHandle findplus::openDir(const wchar_t* dirname) +{ + try + { + return new FileSearcher(dirname); //throw FileError + } + catch (const FileError& err) + { + setWin32Error(err.win32Error); + return NULL; + } +} + + +bool findplus::readDir(FindHandle hnd, FileInformation& output) +{ + try + { + hnd->readdir(output); //throw FileError + return true; + } + catch (const FileError& err) + { + setWin32Error(err.win32Error); + return false; + } +} + + +void findplus::closeDir(FindHandle hnd) +{ + if (hnd) //play a little "nice" + delete hnd; +} diff --git a/zen/FindFilePlus/find_file_plus.h b/zen/FindFilePlus/find_file_plus.h new file mode 100644 index 00000000..72b76dbb --- /dev/null +++ b/zen/FindFilePlus/find_file_plus.h @@ -0,0 +1,78 @@ +// ************************************************************************** +// * This file is part of the FreeFileSync project. It is distributed under * +// * GNU General Public License: http://www.gnu.org/licenses/gpl.html * +// * Copyright (C) 2008-2011 ZenJu (zhnmju123 AT gmx.de) * +// ************************************************************************** + +#ifndef FIND_FIRST_FILE_PLUS_HEADER_087483434 +#define FIND_FIRST_FILE_PLUS_HEADER_087483434 + +#ifdef FIND_FILE_PLUS_DLL_EXPORTS +#define DLL_FUNCTION_DECLARATION extern "C" __declspec(dllexport) +#else +#define DLL_FUNCTION_DECLARATION extern "C" __declspec(dllimport) +#endif + + +#ifdef FIND_FILE_PLUS_DLL_EXPORTS +#include //driver level headers must be included *before* windows api headers! +#endif +#include // +#undef min +#undef max + +#include + +namespace findplus +{ +/*-------------- + |declarations| + --------------*/ + +struct FileInformation +{ + FILETIME creationTime; + FILETIME lastWriteTime; + ULARGE_INTEGER fileSize; + ULARGE_INTEGER fileId; + DWORD fileAttributes; + DWORD shortNameLength; + WCHAR shortName[MAX_PATH + 1]; //shortName is 0-terminated +}; //no need for #pragma pack -> all members already starting at 4 byte boundary! + +class FileSearcher; +typedef FileSearcher* FindHandle; + +DLL_FUNCTION_DECLARATION +FindHandle openDir(const wchar_t* dirname); //returns NULL on error, call ::GetLastError() +//note: do NOT place an asterisk at end, e.g. C:\SomeDir\*, as one would do for ::FindFirstFile() + +DLL_FUNCTION_DECLARATION +bool readDir(FindHandle hnd, FileInformation& output); //returns false on error or if there are no more files; ::GetLastError() returns ERROR_NO_MORE_FILES in this case + +DLL_FUNCTION_DECLARATION +void closeDir(FindHandle hnd); + +/*---------- + |typedefs| + ----------*/ +typedef FindHandle (*OpenDirFunc )(const wchar_t* dirname); +typedef bool (*ReadDirFunc )(FindHandle hnd, FileInformation& dirInfo); +typedef void (*CloseDirFunc)(FindHandle hnd); + +/*-------------- + |symbol names| + --------------*/ +//const pointers ensure internal linkage +const char openDirFuncName [] = "openDir"; +const char readDirFuncName [] = "readDir"; +const char closeDirFuncName[] = "closeDir"; + +/*--------------- + |library names| + ---------------*/ +inline const wchar_t* getDllName() { return zen::is64BitBuild ? L"FindFilePlus_x64.dll" : L"FindFilePlus_Win32.dll"; } +} + + +#endif //FIND_FIRST_FILE_PLUS_HEADER_087483434 diff --git a/zen/FindFilePlus/init_dll_binding.h b/zen/FindFilePlus/init_dll_binding.h new file mode 100644 index 00000000..51b32c99 --- /dev/null +++ b/zen/FindFilePlus/init_dll_binding.h @@ -0,0 +1,16 @@ +// ************************************************************************** +// * This file is part of the FreeFileSync project. It is distributed under * +// * GNU General Public License: http://www.gnu.org/licenses/gpl.html * +// * Copyright (C) 2008-2011 ZenJu (zhnmju123 AT gmx.de) * +// ************************************************************************** + +#ifndef INIT_DLL_BINDING_HEADER_018356031467832145 +#define INIT_DLL_BINDING_HEADER_018356031467832145 + +namespace findplus +{ +//load and check dll binding at startup +bool initDllBinding(); //evaluate in ::DllMain() when attaching process +} + +#endif //INIT_DLL_BINDING_HEADER_018356031467832145 diff --git a/zen/FindFilePlus/load_dll.cpp b/zen/FindFilePlus/load_dll.cpp new file mode 100644 index 00000000..20d9a5fe --- /dev/null +++ b/zen/FindFilePlus/load_dll.cpp @@ -0,0 +1,23 @@ +// ************************************************************************** +// * This file is part of the FreeFileSync project. It is distributed under * +// * GNU General Public License: http://www.gnu.org/licenses/gpl.html * +// * Copyright (C) 2008-2011 ZenJu (zhnmju123 AT gmx.de) * +// ************************************************************************** + +#include "load_dll.h" +#define WIN32_LEAN_AND_MEAN +#include + +void* /*FARPROC*/ dll::loadSymbol(const wchar_t* libraryName, const char* functionName) +{ + return ::GetProcAddress(::GetModuleHandle(libraryName), functionName); + //cleanup neither required nor allowed (::FreeLibrary()) + +} +//note: void* and FARPROC function pointer have same binary size on Windows + + +void dll::setWin32Error(unsigned long lastError) +{ + ::SetLastError(lastError); +} diff --git a/zen/FindFilePlus/load_dll.h b/zen/FindFilePlus/load_dll.h new file mode 100644 index 00000000..350de9f8 --- /dev/null +++ b/zen/FindFilePlus/load_dll.h @@ -0,0 +1,46 @@ +// ************************************************************************** +// * This file is part of the FreeFileSync project. It is distributed under * +// * GNU General Public License: http://www.gnu.org/licenses/gpl.html * +// * Copyright (C) 2008-2011 ZenJu (zhnmju123 AT gmx.de) * +// ************************************************************************** + +#ifndef LOAD_DLL_HEADER_0312463214872163832174 +#define LOAD_DLL_HEADER_0312463214872163832174 + +namespace dll +{ +void setWin32Error(unsigned long lastError); + +//NOTE: uses ::GetModuleHandle => call for system DLLs only! +template +class SysDllFun +{ +public: + SysDllFun(const wchar_t* systemLibrary, const char* functionName) : + fun(reinterpret_cast(loadSymbol(systemLibrary, functionName))) {} + + operator Func() const { return fun; } + +private: + Func fun; +}; + + + + + + + + + + + + + + + + +void* /*FARPROC*/ loadSymbol(const wchar_t* libraryName, const char* functionName); +} + +#endif //LOAD_DLL_HEADER_0312463214872163832174 diff --git a/zen/dir_watcher.cpp b/zen/dir_watcher.cpp index 81e49f89..c980c715 100644 --- a/zen/dir_watcher.cpp +++ b/zen/dir_watcher.cpp @@ -134,7 +134,8 @@ public: ReadChangesAsync(const Zstring& directory, //make sure to not leak in thread-unsafe types! const std::shared_ptr& shared) : shared_(shared), - dirname(directory) + dirname(directory), + hDir(INVALID_HANDLE_VALUE) { if (!endsWith(dirname, FILE_NAME_SEPARATOR)) dirname += FILE_NAME_SEPARATOR; @@ -143,8 +144,8 @@ public: //http://msdn.microsoft.com/en-us/library/aa363858(v=vs.85).aspx try { - Privileges::getInstance().ensureActive(SE_BACKUP_NAME); //throw FileError - Privileges::getInstance().ensureActive(SE_RESTORE_NAME); // + activatePrivilege(SE_BACKUP_NAME); //throw FileError + activatePrivilege(SE_RESTORE_NAME); // } catch (const FileError&) {} @@ -155,7 +156,7 @@ public: OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OVERLAPPED, NULL); - if (hDir == INVALID_HANDLE_VALUE ) + if (hDir == INVALID_HANDLE_VALUE) { const std::wstring errorMsg = _("Could not initialize directory monitoring:") + L"\n\"" + dirname + L"\"" + L"\n\n" + zen::getLastErrorFormatted(); if (errorCodeForNotExisting(::GetLastError())) @@ -253,7 +254,7 @@ public: std::swap(hDir, other.hDir); } - HANDLE getDirHandle() const { return hDir; } //for reading purposes only, don't abuse (e.g. close handle)! + HANDLE getDirHandle() const { return hDir; } //for reading/monitoring purposes only, don't abuse (e.g. close handle)! private: //shared between main and worker: @@ -268,13 +269,9 @@ class HandleVolumeRemoval : public NotifyRequestDeviceRemoval { public: HandleVolumeRemoval(HANDLE hDir, - boost::thread& worker, - const std::shared_ptr& shared, - const Zstring& dirname) : + boost::thread& worker) : NotifyRequestDeviceRemoval(hDir), //throw FileError worker_(worker), - shared_(shared), - dirname_(dirname), removalRequested(false), operationComplete(false) {} @@ -291,16 +288,12 @@ private: worker_.join(); //now hDir should have been released - //report removal as change to main directory - shared_->addChange(dirname_); - removalRequested = true; } //don't throw! + virtual void onRemovalFinished(HANDLE hnd, bool successful) { operationComplete = true; } //throw()! boost::thread& worker_; - std::shared_ptr shared_; - Zstring dirname_; bool removalRequested; bool operationComplete; }; @@ -312,6 +305,7 @@ struct DirWatcher::Pimpl boost::thread worker; std::shared_ptr shared; + Zstring dirname; std::unique_ptr volRemoval; }; @@ -320,9 +314,10 @@ DirWatcher::DirWatcher(const Zstring& directory) : //throw FileError pimpl_(new Pimpl) { pimpl_->shared = std::make_shared(); + pimpl_->dirname = directory; ReadChangesAsync reader(directory, pimpl_->shared); //throw FileError - pimpl_->volRemoval.reset(new HandleVolumeRemoval(reader.getDirHandle(), pimpl_->worker, pimpl_->shared, directory)); //throw FileError + pimpl_->volRemoval.reset(new HandleVolumeRemoval(reader.getDirHandle(), pimpl_->worker)); //throw FileError pimpl_->worker = boost::thread(std::move(reader)); } @@ -332,22 +327,29 @@ DirWatcher::~DirWatcher() pimpl_->worker.interrupt(); //pimpl_->worker.join(); -> we don't have time to wait... will take ~50ms anyway //caveat: exitting the app may simply kill this thread! +} + + +std::vector DirWatcher::getChanges(const std::function& processGuiMessages) //throw FileError +{ + std::vector output; - //wait until device removal is confirmed, to (hopefully!) prevent locking hDir again by new watch! + //wait until device removal is confirmed, to prevent locking hDir again by some new watch! if (pimpl_->volRemoval->requestReceived()) { - const boost::system_time maxwait = boost::get_system_time() + boost::posix_time::seconds(3); //HandleVolumeRemoval::finished() not guaranteed! + const boost::system_time maxwait = boost::get_system_time() + boost::posix_time::seconds(15); + //HandleVolumeRemoval::finished() not guaranteed! note: Windows gives unresponsive applications ca. 10 seconds until unmounting the usb stick in worst case while (!pimpl_->volRemoval->finished() && boost::get_system_time() < maxwait) + { + processGuiMessages(); //DBT_DEVICEREMOVECOMPLETE message is sent here! boost::thread::sleep(boost::get_system_time() + boost::posix_time::milliseconds(50)); - } -} - + } -std::vector DirWatcher::getChanges() //throw FileError -{ - std::vector output; - pimpl_->shared->getChanges(output); //throw FileError + output.push_back(pimpl_->dirname); //report removal as change to main directory + } + else //the normal case... + pimpl_->shared->getChanges(output); //throw FileError return output; } @@ -454,7 +456,7 @@ DirWatcher::~DirWatcher() } -std::vector DirWatcher::getChanges() //throw FileError +std::vector DirWatcher::getChanges(const std::function&) //throw FileError { std::vector buffer(1024 * (sizeof(struct inotify_event) + 16)); diff --git a/zen/dir_watcher.h b/zen/dir_watcher.h index df3c444c..a9898abb 100644 --- a/zen/dir_watcher.h +++ b/zen/dir_watcher.h @@ -9,6 +9,7 @@ #include #include +#include #include "file_error.h" namespace zen @@ -35,7 +36,7 @@ public: ~DirWatcher(); //extract accumulated changes since last call - std::vector getChanges(); //throw FileError + std::vector getChanges(const std::function& processGuiMessages); //throw FileError private: DirWatcher(const DirWatcher&); diff --git a/zen/file_handling.cpp b/zen/file_handling.cpp index 5d57938a..8523c633 100644 --- a/zen/file_handling.cpp +++ b/zen/file_handling.cpp @@ -15,7 +15,7 @@ #include "assert_static.h" #include #include -#include "file_id_internal.h" +#include "file_id_def.h" #ifdef FFS_WIN #include "privilege.h" @@ -194,12 +194,15 @@ namespace #ifdef FFS_WIN DWORD retrieveVolumeSerial(const Zstring& pathName) //return 0 on error! { - std::vector buffer(10000); + //note: this even works for network shares: \\share\dirname + + const DWORD BUFFER_SIZE = 10000; + std::vector buffer(BUFFER_SIZE); //full pathName need not yet exist! if (!::GetVolumePathName(pathName.c_str(), //__in LPCTSTR lpszFileName, &buffer[0], //__out LPTSTR lpszVolumePathName, - static_cast(buffer.size()))) //__in DWORD cchBufferLength + BUFFER_SIZE)) //__in DWORD cchBufferLength return 0; Zstring volumePath = &buffer[0]; @@ -608,7 +611,7 @@ struct RemoveCallbackImpl : public CallbackRemoveDir moveCallback_(moveCallback) {} virtual void notifyFileDeletion(const Zstring& filename) { moveCallback_.requestUiRefresh(sourceDir_); } - virtual void notifyDirDeletion(const Zstring& dirname) { moveCallback_.requestUiRefresh(sourceDir_); } + virtual void notifyDirDeletion (const Zstring& dirname ) { moveCallback_.requestUiRefresh(sourceDir_); } private: RemoveCallbackImpl(const RemoveCallbackImpl&); @@ -620,7 +623,7 @@ private: } -void moveDirectoryImpl(const Zstring& sourceDir, const Zstring& targetDir, bool ignoreExisting, CallbackMoveFile* callback) //throw FileError; +void moveDirectoryImpl(const Zstring& sourceDir, const Zstring& targetDir, bool ignoreExisting, CallbackMoveFile* callback) //throw FileError { //call back once per folder if (callback) @@ -683,7 +686,7 @@ void moveDirectoryImpl(const Zstring& sourceDir, const Zstring& targetDir, bool } -void zen::moveDirectory(const Zstring& sourceDir, const Zstring& targetDir, bool ignoreExisting, CallbackMoveFile* callback) //throw FileError; +void zen::moveDirectory(const Zstring& sourceDir, const Zstring& targetDir, bool ignoreExisting, CallbackMoveFile* callback) //throw FileError { #ifdef FFS_WIN const Zstring& sourceDirFormatted = sourceDir; @@ -999,13 +1002,13 @@ void copyObjectPermissions(const Zstring& source, const Zstring& target, ProcSym try { //enable privilege: required to read/write SACL information - Privileges::getInstance().ensureActive(SE_SECURITY_NAME); //polling allowed... + activatePrivilege(SE_SECURITY_NAME); //polling allowed... //enable privilege: required to copy owner information - Privileges::getInstance().ensureActive(SE_RESTORE_NAME); + activatePrivilege(SE_RESTORE_NAME); //the following privilege may be required according to http://msdn.microsoft.com/en-us/library/aa364399(VS.85).aspx (although not needed nor active in my tests) - Privileges::getInstance().ensureActive(SE_BACKUP_NAME); + activatePrivilege(SE_BACKUP_NAME); } catch (const FileError& e) { @@ -1416,14 +1419,19 @@ public: throw FileError(errorMsg); } - void setSrcAttr(const FileAttrib& attr) { sourceAttr = attr; } - FileAttrib getSrcAttr() const { assert(sourceAttr.modificationTime != 0); return sourceAttr; } + void setNewAttr(const FileAttrib& attr) { newAttrib = attr; } + + FileAttrib getSrcAttr() const + { + assert(newAttrib.modificationTime != 0); + return newAttrib; + } private: CallbackData(const CallbackData&); CallbackData& operator=(const CallbackData&); - FileAttrib sourceAttr; + FileAttrib newAttrib; std::wstring errorMsg; // bool exceptionInUserCallback; //these two are exclusive! UInt64 bytesTransferredOnException; @@ -1456,19 +1464,27 @@ DWORD CALLBACK copyCallbackInternal( //#################### return source file attributes ################################ if (dwCallbackReason == CALLBACK_STREAM_SWITCH) //called up front for every file (even if 0-sized) { - BY_HANDLE_FILE_INFORMATION fileInfo = {}; - if (!::GetFileInformationByHandle(hSourceFile, &fileInfo)) + BY_HANDLE_FILE_INFORMATION fileInfoSrc = {}; + if (!::GetFileInformationByHandle(hSourceFile, &fileInfoSrc)) { cbd.reportError(_("Error reading file attributes:") + L"\n\"" + cbd.sourceFile_ + L"\"" + L"\n\n" + getLastErrorFormatted()); return PROGRESS_CANCEL; } - const FileAttrib attr = { UInt64(fileInfo.nFileSizeLow, fileInfo.nFileSizeHigh), - toTimeT(fileInfo.ftLastWriteTime) - }; - //extractFileID(fileInfo)); + BY_HANDLE_FILE_INFORMATION fileInfoTrg = {}; + if (!::GetFileInformationByHandle(hDestinationFile, &fileInfoTrg)) + { + cbd.reportError(_("Error reading file attributes:") + L"\n\"" + cbd.targetFile_ + L"\"" + L"\n\n" + getLastErrorFormatted()); + return PROGRESS_CANCEL; + } + + FileAttrib attr; + attr.fileSize = UInt64(fileInfoSrc.nFileSizeLow, fileInfoSrc.nFileSizeHigh); + attr.modificationTime = toTimeT(fileInfoSrc.ftLastWriteTime); + attr.sourceFileId = extractFileID(fileInfoSrc); + attr.targetFileId = extractFileID(fileInfoTrg); - cbd.setSrcAttr(attr); + cbd.setNewAttr(attr); //#################### copy file creation time ################################ FILETIME creationTime = {}; @@ -1527,7 +1543,7 @@ DWORD CALLBACK copyCallbackInternal( void rawCopyWinApi_sub(const Zstring& sourceFile, const Zstring& targetFile, CallbackCopyFile* callback, - FileAttrib* sourceAttr) //throw FileError, ErrorTargetPathMissing, ErrorTargetExisting, ErrorFileLocked + FileAttrib* newAttrib) //throw FileError, ErrorTargetPathMissing, ErrorTargetExisting, ErrorFileLocked { zen::ScopeGuard guardTarget = zen::makeGuard([&]() { removeFile(targetFile); }); //transactional behavior: guard just before starting copy, we don't trust ::CopyFileEx(), do we ;) @@ -1601,8 +1617,8 @@ void rawCopyWinApi_sub(const Zstring& sourceFile, throw FileError(errorMessage); } - if (sourceAttr) - *sourceAttr = cbd.getSrcAttr(); + if (newAttrib) + *newAttrib = cbd.getSrcAttr(); { const Int64 modTime = getFileTime(sourceFile, SYMLINK_FOLLOW); //throw FileError @@ -1972,7 +1988,7 @@ void rawCopyWinApi(const Zstring& sourceFile, void rawCopyStream(const Zstring& sourceFile, const Zstring& targetFile, CallbackCopyFile* callback, - FileAttrib* sourceAttr) //throw FileError, ErrorTargetPathMissing, ErrorTargetExisting + FileAttrib* newAttrib) //throw FileError, ErrorTargetPathMissing, ErrorTargetExisting { zen::ScopeGuard guardTarget = zen::makeGuard([&]() { removeFile(targetFile); }); //transactional behavior: place guard before lifetime of FileOutput try @@ -2012,23 +2028,29 @@ void rawCopyStream(const Zstring& sourceFile, //adapt file modification time: { - struct stat srcInfo = {}; + struct ::stat srcInfo = {}; if (::stat(sourceFile.c_str(), &srcInfo) != 0) //read file attributes from source directory throw FileError(_("Error reading file attributes:") + L"\n\"" + sourceFile + L"\"" + L"\n\n" + getLastErrorFormatted()); - if (sourceAttr) - { - sourceAttr->fileSize = UInt64(srcInfo.st_size); - sourceAttr->modificationTime = srcInfo.st_mtime; - } - - struct utimbuf newTimes = {}; + struct ::utimbuf newTimes = {}; newTimes.actime = srcInfo.st_atime; newTimes.modtime = srcInfo.st_mtime; //set new "last write time" if (::utime(targetFile.c_str(), &newTimes) != 0) throw FileError(_("Error changing modification time:") + L"\n\"" + targetFile + L"\"" + L"\n\n" + getLastErrorFormatted()); + + if (newAttrib) + { + struct ::stat trgInfo = {}; + if (::stat(targetFile.c_str(), &trgInfo) != 0) //read file attributes from source directory + throw FileError(_("Error reading file attributes:") + L"\n\"" + targetFile + L"\"" + L"\n\n" + getLastErrorFormatted()); + + newAttrib->fileSize = UInt64(srcInfo.st_size); + newAttrib->modificationTime = srcInfo.st_mtime; + newAttrib->sourceFileId = extractFileID(srcInfo); + newAttrib->targetFileId = extractFileID(trgInfo); + } } guardTarget.dismiss(); //target has been created successfully! diff --git a/zen/file_handling.h b/zen/file_handling.h index 02f3e532..8ffe38d0 100644 --- a/zen/file_handling.h +++ b/zen/file_handling.h @@ -10,6 +10,7 @@ #include "zstring.h" #include "file_error.h" #include "int64.h" +#include "file_id_def.h" namespace zen { @@ -68,7 +69,9 @@ void createDirectory(const Zstring& directory); //throw FileError; -> function o struct FileAttrib { UInt64 fileSize; - Int64 modificationTime; //size_t UTC compatible + Int64 modificationTime; //time_t UTC compatible + FileId sourceFileId; + FileId targetFileId; }; void copyFile(const Zstring& sourceFile, //throw FileError, ErrorTargetPathMissing, ErrorFileLocked (Windows-only) @@ -76,7 +79,7 @@ void copyFile(const Zstring& sourceFile, //throw FileError, ErrorTargetPathMissi bool copyFilePermissions, bool transactionalCopy, CallbackCopyFile* callback, //may be NULL - FileAttrib* sourceAttr = NULL); //return current attributes at the time of copy + FileAttrib* newAttrib = NULL); //return current attributes at the time of copy //Note: it MAY happen that copyFile() leaves temp files behind, e.g. temporary network drop. // => clean them up at an appropriate time (automatically set sync directions to delete them). They have the following ending: const Zstring TEMP_FILE_ENDING = Zstr(".ffs_tmp"); diff --git a/zen/file_id.cpp b/zen/file_id.cpp index acbdcd7b..7527062b 100644 --- a/zen/file_id.cpp +++ b/zen/file_id.cpp @@ -5,7 +5,6 @@ // ************************************************************************** #include "file_id.h" -#include "file_id_internal.h" #ifdef FFS_WIN #include "win.h" //includes "windows.h" @@ -17,7 +16,7 @@ #endif -std::string zen::getFileID(const Zstring& filename) +zen::FileId zen::getFileID(const Zstring& filename) { #ifdef FFS_WIN //WARNING: CreateFile() is SLOW, while GetFileInformationByHandle() is cheap! @@ -43,11 +42,11 @@ std::string zen::getFileID(const Zstring& filename) #elif defined FFS_LINUX struct ::stat fileInfo = {}; - if (::lstat(filename.c_str(), &fileInfo) == 0) //lstat() does not follow symlinks + if (::stat(filename.c_str(), &fileInfo) == 0) //stat() follows symlinks return extractFileID(fileInfo); #endif - return std::string(); + return zen::FileId(); } @@ -56,10 +55,10 @@ bool zen::samePhysicalFile(const Zstring& file1, const Zstring& file2) if (EqualFilename()(file1, file2)) //quick check return true; - const std::string id1 = getFileID(file1); - const std::string id2 = getFileID(file2); + const auto id1 = getFileID(file1); + const auto id2 = getFileID(file2); - if (id1.empty() || id2.empty()) + if (id1 == zen::FileId() || id2 == zen::FileId()) return false; return id1 == id2; diff --git a/zen/file_id.h b/zen/file_id.h index f015569d..3fd4c6bb 100644 --- a/zen/file_id.h +++ b/zen/file_id.h @@ -7,6 +7,7 @@ #ifndef FILEID_H_INCLUDED #define FILEID_H_INCLUDED +#include "file_id_def.h" #include "zstring.h" #include @@ -15,8 +16,8 @@ namespace zen { //get unique file id (symbolic link handling: opens the link!!!) -//returns empty string on error! -std::string getFileID(const Zstring& filename); +//returns initial FileId() on error! +FileId getFileID(const Zstring& filename); //test whether two distinct paths point to the same file or directory: // true: paths point to same files/dirs diff --git a/zen/file_id_def.h b/zen/file_id_def.h new file mode 100644 index 00000000..b2029879 --- /dev/null +++ b/zen/file_id_def.h @@ -0,0 +1,65 @@ +// ************************************************************************** +// * This file is part of the FreeFileSync project. It is distributed under * +// * GNU General Public License: http://www.gnu.org/licenses/gpl.html * +// * Copyright (C) 2008-2011 ZenJu (zhnmju123 AT gmx.de) * +// ************************************************************************** + +#ifndef FILE_ID_INTERNAL_HEADER_013287632486321493 +#define FILE_ID_INTERNAL_HEADER_013287632486321493 + +#include +#include "assert_static.h" + +#ifdef FFS_WIN +#include "win.h" //includes "windows.h" + +#elif defined FFS_LINUX +#include +#endif + + +namespace zen +{ +#ifdef FFS_WIN +typedef std::pair FileId; //(volume serial number, file ID) + +inline +FileId extractFileID(const BY_HANDLE_FILE_INFORMATION& fileInfo) +{ + ULARGE_INTEGER uint = {}; + uint.HighPart = fileInfo.nFileIndexHigh; + uint.LowPart = fileInfo.nFileIndexLow; + return std::make_pair(fileInfo.dwVolumeSerialNumber, uint.QuadPart); +} + +inline +FileId extractFileID(DWORD dwVolumeSerialNumber, ULARGE_INTEGER fileId) +{ + return std::make_pair(dwVolumeSerialNumber, fileId.QuadPart); +} + +namespace impl +{ +inline +void validate(const FileId& id, const BY_HANDLE_FILE_INFORMATION& fileInfo) +{ + assert_static(sizeof(id.second) == sizeof(fileInfo.nFileIndexHigh) + sizeof(fileInfo.nFileIndexLow)); + assert_static(sizeof(id.first ) == sizeof(DWORD)); + assert_static(sizeof(id.second) == sizeof(ULARGE_INTEGER)); +} +} + +#elif defined FFS_LINUX +namespace impl { typedef struct ::stat StatDummy; } //sigh... + +typedef std::pair FileId; //(device id, inode) + +inline +FileId extractFileID(const struct stat& fileInfo) +{ + return std::make_pair(fileInfo.st_dev, fileInfo.st_ino); +} +#endif +} + +#endif //FILE_ID_INTERNAL_HEADER_013287632486321493 diff --git a/zen/file_id_internal.h b/zen/file_id_internal.h deleted file mode 100644 index 492d8432..00000000 --- a/zen/file_id_internal.h +++ /dev/null @@ -1,48 +0,0 @@ -// ************************************************************************** -// * This file is part of the FreeFileSync project. It is distributed under * -// * GNU General Public License: http://www.gnu.org/licenses/gpl.html * -// * Copyright (C) 2008-2011 ZenJu (zhnmju123 AT gmx.de) * -// ************************************************************************** - -#ifndef FILE_ID_INTERNAL_HEADER_013287632486321493 -#define FILE_ID_INTERNAL_HEADER_013287632486321493 - -#include - -#ifdef FFS_WIN -#include "win.h" //includes "windows.h" - -#elif defined FFS_LINUX -#include -#endif - -namespace -{ -template inline -std::string numberToBytes(T number) -{ - const char* rawBegin = reinterpret_cast(&number); - return std::string(rawBegin, rawBegin + sizeof(number)); -} - -#ifdef FFS_WIN -inline -std::string extractFileID(const BY_HANDLE_FILE_INFORMATION& fileInfo) -{ - return numberToBytes(fileInfo.dwVolumeSerialNumber) + - numberToBytes(fileInfo.nFileIndexHigh) + - numberToBytes(fileInfo.nFileIndexLow); -} -#elif defined FFS_LINUX -inline -std::string extractFileID(const struct stat& fileInfo) -{ - return numberToBytes(fileInfo.st_dev) + - numberToBytes(fileInfo.st_ino); -} -#endif - -} - - -#endif //FILE_ID_INTERNAL_HEADER_013287632486321493 diff --git a/zen/file_traverser.cpp b/zen/file_traverser.cpp index 7a2df695..81e70383 100644 --- a/zen/file_traverser.cpp +++ b/zen/file_traverser.cpp @@ -14,8 +14,8 @@ #include "long_path_prefix.h" #include "dst_hack.h" #include "file_update_handle.h" -//#include "dll_loader.h" -//#include "FindFilePlus/find_file_plus.h" +#include "dll.h" +#include "FindFilePlus/find_file_plus.h" #elif defined FFS_LINUX #include @@ -30,33 +30,34 @@ namespace { //implement "retry" in a generic way: -//returns "true" if "cmd" was invoked successfully, "false" if error occured and was ignored -template inline //function object with bool operator()(std::wstring& errorMsg), returns "true" on success, "false" on error and writes "errorMsg" in this case -bool tryReportingError(Command cmd, zen::TraverseCallback& callback) +template inline //function object expecting to throw FileError if operation fails +void tryReportingError(Command cmd, zen::TraverseCallback& callback) { for (;;) - { - std::wstring errorMsg; - if (cmd(errorMsg)) - return true; - - switch (callback.onError(errorMsg)) + try { - case TraverseCallback::TRAV_ERROR_RETRY: - break; - case TraverseCallback::TRAV_ERROR_IGNORE: - return false; - default: - assert(false); - break; + cmd(); + return; + } + catch (const FileError& e) + { + switch (callback.onError(e.toString())) + { + case TraverseCallback::TRAV_ERROR_RETRY: + break; + case TraverseCallback::TRAV_ERROR_IGNORE: + return; + default: + assert(false); + break; + } } - } } #ifdef FFS_WIN inline -bool setWin32FileInformationFromSymlink(const Zstring& linkName, zen::TraverseCallback::FileInfo& output) +bool extractFileInfoFromSymlink(const Zstring& linkName, zen::TraverseCallback::FileInfo& output) { //open handle to target of symbolic link HANDLE hFile = ::CreateFile(zen::applyLongPathPrefix(linkName).c_str(), @@ -75,288 +76,308 @@ bool setWin32FileInformationFromSymlink(const Zstring& linkName, zen::TraverseCa return false; //write output - output.lastWriteTimeRaw = toTimeT(fileInfoByHandle.ftLastWriteTime); output.fileSize = zen::UInt64(fileInfoByHandle.nFileSizeLow, fileInfoByHandle.nFileSizeHigh); + output.lastWriteTimeRaw = toTimeT(fileInfoByHandle.ftLastWriteTime); + //output.id = extractFileID(fileInfoByHandle); -> id from dereferenced symlink is problematic, since renaming will consider the link, not the target! return true; } + +DWORD retrieveVolumeSerial(const Zstring& pathName) //return 0 on error! +{ + //note: this even works for network shares: \\share\dirname + + const DWORD BUFFER_SIZE = 10000; + std::vector buffer(BUFFER_SIZE); + + //full pathName need not yet exist! + if (!::GetVolumePathName(pathName.c_str(), //__in LPCTSTR lpszFileName, + &buffer[0], //__out LPTSTR lpszVolumePathName, + BUFFER_SIZE)) //__in DWORD cchBufferLength + return 0; + + Zstring volumePath = &buffer[0]; + if (!endsWith(volumePath, FILE_NAME_SEPARATOR)) + volumePath += FILE_NAME_SEPARATOR; + + DWORD volumeSerial = 0; + if (!::GetVolumeInformation(volumePath.c_str(), //__in_opt LPCTSTR lpRootPathName, + NULL, //__out LPTSTR lpVolumeNameBuffer, + 0, //__in DWORD nVolumeNameSize, + &volumeSerial, //__out_opt LPDWORD lpVolumeSerialNumber, + NULL, //__out_opt LPDWORD lpMaximumComponentLength, + NULL, //__out_opt LPDWORD lpFileSystemFlags, + NULL, //__out LPTSTR lpFileSystemNameBuffer, + 0)) //__in DWORD nFileSystemNameSize + return 0; + + return volumeSerial; +} + + +const DllFun openDir (findplus::getDllName(), findplus::openDirFuncName ); // +const DllFun readDir (findplus::getDllName(), findplus::readDirFuncName ); //load at startup: avoid pre C++11 static initialization MT issues +const DllFun closeDir(findplus::getDllName(), findplus::closeDirFuncName); // + + /* -warn_static("finish") - DllFun openDir (findplus::getDllName(), findplus::openDirFuncName); - DllFun readDir (findplus::getDllName(), findplus::readDirFuncName); - DllFun closeDir(findplus::getDllName(), findplus::closeDirFuncName); - -> thread safety! -*/ -#endif +Common C-style interface for Win32 FindFirstFile(), FindNextFile() and FileFilePlus openDir(), closeDir(): +struct X //see "policy based design" +{ +typedef ... Handle; +typedef ... FindData; +static Handle create(const Zstring& directoryPf, FindData& fileInfo); //throw FileError +static void destroy(Handle hnd); //throw() +static bool next(Handle hnd, const Zstring& directory, WIN32_FIND_DATA& fileInfo) //throw FileError + +//helper routines +static void extractFileInfo (const FindData& fileInfo, const DWORD* volumeSerial, TraverseCallback::FileInfo& output); +static Int64 getModTime (const FindData& fileInfo); +static const FILETIME& getModTimeRaw (const FindData& fileInfo); //yet another concession to DST hack +static const FILETIME& getCreateTimeRaw(const FindData& fileInfo); // +static const wchar_t* getShortName (const FindData& fileInfo); +static bool isDirectory (const FindData& fileInfo); +static bool isSymlink (const FindData& fileInfo); } +Note: Win32 FindFirstFile(), FindNextFile() is a weaker abstraction than FileFilePlus openDir(), readDir(), closeDir() and Unix opendir(), closedir(), stat(), + so unfortunately we have to use former as a greatest common divisor +*/ -class DirTraverser + +struct Win32Traverser { -public: - DirTraverser(const Zstring& baseDirectory, bool followSymlinks, zen::TraverseCallback& sink, zen::DstHackCallback* dstCallback) : -#ifdef FFS_WIN - isFatFileSystem(dst::isFatDrive(baseDirectory)), -#endif - followSymlinks_(followSymlinks) + typedef HANDLE Handle; + typedef WIN32_FIND_DATA FindData; + + static Handle create(const Zstring& directory, FindData& fileInfo) //throw FileError { -#ifdef FFS_WIN - //format base directory name - const Zstring& directoryFormatted = baseDirectory; + const Zstring& directoryPf = endsWith(directory, FILE_NAME_SEPARATOR) ? + directory : + directory + FILE_NAME_SEPARATOR; -#elif defined FFS_LINUX - const Zstring directoryFormatted = //remove trailing slash - baseDirectory.size() > 1 && endsWith(baseDirectory, FILE_NAME_SEPARATOR) ? //exception: allow '/' - beforeLast(baseDirectory, FILE_NAME_SEPARATOR) : - baseDirectory; -#endif + HANDLE output = ::FindFirstFile(applyLongPathPrefix(directoryPf + L'*').c_str(), &fileInfo); + //no noticable performance difference compared to FindFirstFileEx with FindExInfoBasic, FIND_FIRST_EX_CASE_SENSITIVE and/or FIND_FIRST_EX_LARGE_FETCH + if (output == INVALID_HANDLE_VALUE) + throw FileError(_("Error traversing directory:") + L"\n\"" + directory + L"\"" + L"\n\n" + zen::getLastErrorFormatted()); + //::GetLastError() == ERROR_FILE_NOT_FOUND -> actually NOT okay, even for an empty directory this should not occur (., ..) + return output; + } - //traverse directories - traverse(directoryFormatted, sink, 0); + static void destroy(Handle hnd) { ::FindClose(hnd); } //throw() - //apply daylight saving time hack AFTER file traversing, to give separate feedback to user -#ifdef FFS_WIN - if (isFatFileSystem && dstCallback) - applyDstHack(*dstCallback); -#endif + static bool next(Handle hnd, const Zstring& directory, FindData& fileInfo) //throw FileError + { + if (!::FindNextFile(hnd, &fileInfo)) + { + if (::GetLastError() == ERROR_NO_MORE_FILES) //not an error situation + return false; + //else we have a problem... report it: + throw FileError(_("Error traversing directory:") + L"\n\"" + directory + L"\"" + L"\n\n" + zen::getLastErrorFormatted()); + } + return true; } -private: - DirTraverser(const DirTraverser&); - DirTraverser& operator=(const DirTraverser&); + //helper routines + template + static void extractFileInfo(const FindData& fileInfo, const DWORD* volumeSerial, TraverseCallback::FileInfo& output) + { + output.lastWriteTimeRaw = getModTime(fileInfo); + output.fileSize = UInt64(fileInfo.nFileSizeLow, fileInfo.nFileSizeHigh); + } - void traverse(const Zstring& directory, zen::TraverseCallback& sink, int level) + template + static Int64 getModTime(const FindData& fileInfo) { return toTimeT(fileInfo.ftLastWriteTime); } + + template + static const FILETIME& getModTimeRaw(const FindData& fileInfo) { return fileInfo.ftLastWriteTime; } + + template + static const FILETIME& getCreateTimeRaw(const FindData& fileInfo) { return fileInfo.ftCreationTime; } + + template + static const wchar_t* getShortName(const FindData& fileInfo) { return fileInfo.cFileName; } + + template + static bool isDirectory(const FindData& fileInfo) { return (fileInfo.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0; } + + template + static bool isSymlink(const FindData& fileInfo) { return (fileInfo.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) != 0; } +}; + + +struct FilePlusTraverser +{ + typedef findplus::FindHandle Handle; + typedef findplus::FileInformation FindData; + + static Handle create(const Zstring& directory, FindData& fileInfo) //throw FileError { - tryReportingError([&](std::wstring& errorMsg) -> bool + Handle output = ::openDir(applyLongPathPrefix(directory).c_str()); + if (output == NULL) + throw FileError(_("Error traversing directory:") + L"\n\"" + directory + L"\"" + L"\n\n" + zen::getLastErrorFormatted()); + + bool rv = next(output, directory, fileInfo); //throw FileError + if (!rv) //we expect at least two successful reads, even for an empty directory: ., .. + throw FileError(_("Error traversing directory:") + L"\n\"" + directory + L"\"" + L"\n\n" + zen::getLastErrorFormatted(ERROR_NO_MORE_FILES)); + + return output; + } + + static void destroy(Handle hnd) { ::closeDir(hnd); } //throw() + + static bool next(Handle hnd, const Zstring& directory, FindData& fileInfo) //throw FileError + { + if (!::readDir(hnd, fileInfo)) { - if (level == 100) //notify endless recursion - { - errorMsg = _("Endless loop when traversing directory:") + L"\n\"" + directory + L"\""; + if (::GetLastError() == ERROR_NO_MORE_FILES) //not an error situation return false; - } - return true; - }, sink); + //else we have a problem... report it: + throw FileError(_("Error traversing directory:") + L"\n\"" + directory + L"\"" + L"\n\n" + zen::getLastErrorFormatted()); + } + return true; + } -#ifdef FFS_WIN - /* - //ensure directoryPf ends with backslash - const Zstring& directoryPf = directory.EndsWith(FILE_NAME_SEPARATOR) ? - directory : - directory + FILE_NAME_SEPARATOR; - - FindHandle searchHandle = NULL; - tryReportingError([&](std::wstring& errorMsg) -> bool - { - searchHandle = this->openDir(applyLongPathPrefix(directoryPf).c_str()); - //no noticable performance difference compared to FindFirstFileEx with FindExInfoBasic, FIND_FIRST_EX_CASE_SENSITIVE and/or FIND_FIRST_EX_LARGE_FETCH + //helper routines + template + static void extractFileInfo(const FindData& fileInfo, const DWORD* volumeSerial, TraverseCallback::FileInfo& output) + { + output.fileSize = UInt64(fileInfo.fileSize.QuadPart); + output.lastWriteTimeRaw = getModTime(fileInfo); + if (volumeSerial) + output.id = extractFileID(*volumeSerial, fileInfo.fileId); + } - if (searchHandle == NULL) - { - //const DWORD lastError = ::GetLastError(); - //if (lastError == ERROR_FILE_NOT_FOUND) -> actually NOT okay, even for an empty directory this should not occur (., ..) - //return true; //fine: empty directory + template + static Int64 getModTime(const FindData& fileInfo) { return toTimeT(fileInfo.lastWriteTime); } - //else: we have a problem... report it: - errorMsg = _("Error traversing directory:") + "\n\"" + directory + "\"" + "\n\n" + zen::getLastErrorFormatted(); - return false; - } - return true; - }, sink); + template + static const FILETIME& getModTimeRaw(const FindData& fileInfo) { return fileInfo.lastWriteTime; } - if (searchHandle == NULL) - return; //empty dir or ignore error - ZEN_ON_BLOCK_EXIT(this->closeDir(searchHandle)); + template + static const FILETIME& getCreateTimeRaw(const FindData& fileInfo) { return fileInfo.creationTime; } - FileInformation fileInfo = {}; - for (;;) - { - bool moreData = false; - tryReportingError([&](std::wstring& errorMsg) -> bool - { - if (!this->readDir(searchHandle, fileInfo)) - { - if (::GetLastError() == ERROR_NO_MORE_FILES) //this is fine - return true; - - //else we have a problem... report it: - errorMsg = _("Error traversing directory:") + "\n\"" + directory + "\"" + "\n\n" + zen::getLastErrorFormatted(); - return false; - } - - moreData = true; - return true; - }, sink); - if (!moreData) //no more items or ignore error - return; - - - //don't return "." and ".." - const Zchar* const shortName = fileInfo.shortName; - if (shortName[0] == L'.' && - (shortName[1] == L'\0' || (shortName[1] == L'.' && shortName[2] == L'\0'))) - continue; + template + static const wchar_t* getShortName(const FindData& fileInfo) { return fileInfo.shortName; } - const Zstring& fullName = directoryPf + shortName; + template + static bool isDirectory(const FindData& fileInfo) { return (fileInfo.fileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0; } - const bool isSymbolicLink = (fileInfo.fileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) != 0; + template + static bool isSymlink(const FindData& fileInfo) { return (fileInfo.fileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) != 0; } +}; - if (isSymbolicLink && !followSymlinks_) //evaluate symlink directly - { - TraverseCallback::SymlinkInfo details; - try - { - details.targetPath = getSymlinkRawTargetString(fullName); //throw FileError - } - catch (FileError& e) - { - (void)e; - #ifndef NDEBUG //show broken symlink / access errors in debug build! - sink.onError(e.msg()); - #endif - } - - details.lastWriteTimeRaw = toTimeT(fileInfo.lastWriteTime); - details.dirLink = (fileInfo.fileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0; //directory symlinks have this flag on Windows - sink.onSymlink(shortName, fullName, details); - } - else if (fileInfo.fileAttributes & FILE_ATTRIBUTE_DIRECTORY) //a directory... or symlink that needs to be followed (for directory symlinks this flag is set too!) - { - const std::shared_ptr rv = sink.onDir(shortName, fullName); - if (rv) - traverse(fullName, *rv, level + 1); - } - else //a file or symlink that is followed... - { - TraverseCallback::FileInfo details; - - if (isSymbolicLink) //dereference symlinks! - { - if (!setWin32FileInformationFromSymlink(fullName, details)) - { - //broken symlink... - details.lastWriteTimeRaw = 0; //we are not interested in the modification time of the link - details.fileSize = 0U; - } - } - else - { - //####################################### DST hack ########################################### - if (isFatFileSystem) - { - const dst::RawTime rawTime(fileInfo.creationTime, fileInfo.lastWriteTime); - - if (dst::fatHasUtcEncoded(rawTime)) //throw (std::runtime_error) - fileInfo.lastWriteTime = dst::fatDecodeUtcTime(rawTime); //return real UTC time; throw (std::runtime_error) - else - markForDstHack.push_back(std::make_pair(fullName, fileInfo.lastWriteTime)); - } - //####################################### DST hack ########################################### - - details.lastWriteTimeRaw = toTimeT(fileInfo.lastWriteTime); - details.fileSize = fileInfo.fileSize.QuadPart; - } - - sink.onFile(shortName, fullName, details); - } - } - */ +class DirTraverser +{ +public: + DirTraverser(const Zstring& baseDirectory, bool followSymlinks, zen::TraverseCallback& sink, zen::DstHackCallback* dstCallback) : + isFatFileSystem(dst::isFatDrive(baseDirectory)), + followSymlinks_(followSymlinks), + volumeSerial(retrieveVolumeSerial(baseDirectory)) //return 0 on error + { + try //traversing certain folders with restricted permissions requires this privilege! (but copying these files may still fail) + { + activatePrivilege(SE_BACKUP_NAME); //throw FileError + } + catch (...) {} //don't cause issues in user mode + if (::openDir && ::readDir && ::closeDir) + traverse(baseDirectory, sink, 0); + else //fallback + traverse(baseDirectory, sink, 0); - //ensure directoryPf ends with backslash - const Zstring& directoryPf = endsWith(directory, FILE_NAME_SEPARATOR) ? - directory : - directory + FILE_NAME_SEPARATOR; - WIN32_FIND_DATA fileInfo = {}; + //apply daylight saving time hack AFTER file traversing, to give separate feedback to user + if (dstCallback && isFatFileSystem) + applyDstHack(*dstCallback); + } - HANDLE searchHandle = INVALID_HANDLE_VALUE; - tryReportingError([&](std::wstring& errorMsg) -> bool +private: + DirTraverser(const DirTraverser&); + DirTraverser& operator=(const DirTraverser&); + + template + void traverse(const Zstring& directory, zen::TraverseCallback& sink, int level) + { + tryReportingError([&] { - searchHandle = ::FindFirstFile(applyLongPathPrefix(directoryPf + L'*').c_str(), &fileInfo); - //no noticable performance difference compared to FindFirstFileEx with FindExInfoBasic, FIND_FIRST_EX_CASE_SENSITIVE and/or FIND_FIRST_EX_LARGE_FETCH + if (level == 100) //notify endless recursion + throw FileError(_("Endless loop when traversing directory:") + L"\n\"" + directory + L"\""); + }, sink); - if (searchHandle == INVALID_HANDLE_VALUE) - { - //const DWORD lastError = ::GetLastError(); - //if (lastError == ERROR_FILE_NOT_FOUND) -> actually NOT okay, even for an empty directory this should not occur (., ..) - //return true; //fine: empty directory + typename Trav::FindData fileInfo = {}; - //else: we have a problem... report it: - errorMsg = _("Error traversing directory:") + L"\n\"" + directory + L"\"" + L"\n\n" + zen::getLastErrorFormatted(); - return false; - } - return true; + typename Trav::Handle searchHandle = 0; + + tryReportingError([&] + { + typedef Trav Trav; //f u VS! + searchHandle = Trav::create(directory, fileInfo); //throw FileError }, sink); - if (searchHandle == INVALID_HANDLE_VALUE) - return; //empty dir or ignore error - ZEN_ON_BLOCK_EXIT(::FindClose(searchHandle)); + if (searchHandle == 0) + return; //ignored error + ZEN_ON_BLOCK_EXIT(typedef Trav Trav; Trav::destroy(searchHandle)); do { //don't return "." and ".." - const Zchar* const shortName = fileInfo.cFileName; + const Zchar* const shortName = Trav::getShortName(fileInfo); if (shortName[0] == L'.' && (shortName[1] == L'\0' || (shortName[1] == L'.' && shortName[2] == L'\0'))) continue; - const Zstring& fullName = directoryPf + shortName; - - const bool isSymbolicLink = (fileInfo.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) != 0; + const Zstring& fullName = endsWith(directory, FILE_NAME_SEPARATOR) ? + directory + shortName : + directory + FILE_NAME_SEPARATOR + shortName; - if (isSymbolicLink && !followSymlinks_) //evaluate symlink directly + if (Trav::isSymlink(fileInfo) && !followSymlinks_) //evaluate symlink directly { TraverseCallback::SymlinkInfo details; try { details.targetPath = getSymlinkRawTargetString(fullName); //throw FileError } - catch (FileError& e) - { - (void)e; -#ifndef NDEBUG //show broken symlink / access errors in debug build! - sink.onError(e.toString()); +#ifdef NDEBUG //Release + catch (FileError&) {} +#else + catch (FileError& e) { sink.onError(e.toString()); } //show broken symlink / access errors in debug build! #endif - } - details.lastWriteTimeRaw = toTimeT(fileInfo.ftLastWriteTime); - details.dirLink = (fileInfo.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0; //directory symlinks have this flag on Windows + details.lastWriteTimeRaw = Trav::getModTime (fileInfo); + details.dirLink = Trav::isDirectory(fileInfo); //directory symlinks have this flag on Windows sink.onSymlink(shortName, fullName, details); } - else if (fileInfo.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) //a directory... or symlink that needs to be followed (for directory symlinks this flag is set too!) + else if (Trav::isDirectory(fileInfo)) //a directory... or symlink that needs to be followed (for directory symlinks this flag is set too!) { const std::shared_ptr rv = sink.onDir(shortName, fullName); if (rv) - traverse(fullName, *rv, level + 1); + traverse(fullName, *rv, level + 1); } else //a file or symlink that is followed... { TraverseCallback::FileInfo details; - if (isSymbolicLink) //dereference symlinks! + if (Trav::isSymlink(fileInfo)) //dereference symlinks! { - if (!setWin32FileInformationFromSymlink(fullName, details)) - { - //broken symlink... - details.lastWriteTimeRaw = 0; //we are not interested in the modification time of the link - details.fileSize = 0U; - } + extractFileInfoFromSymlink(fullName, details); //try to... + //keep details initial if symlink is broken } else { + Trav::extractFileInfo(fileInfo, volumeSerial != 0 ? &volumeSerial : nullptr, details); //make optional character of volumeSerial explicit in the interface + //####################################### DST hack ########################################### if (isFatFileSystem) { - const dst::RawTime rawTime(fileInfo.ftCreationTime, fileInfo.ftLastWriteTime); + const dst::RawTime rawTime(Trav::getCreateTimeRaw(fileInfo), Trav::getModTimeRaw(fileInfo)); if (dst::fatHasUtcEncoded(rawTime)) //throw (std::runtime_error) - fileInfo.ftLastWriteTime = dst::fatDecodeUtcTime(rawTime); //return real UTC time; throw (std::runtime_error) + details.lastWriteTimeRaw = toTimeT(dst::fatDecodeUtcTime(rawTime)); //return real UTC time; throw (std::runtime_error) else - markForDstHack.push_back(std::make_pair(fullName, fileInfo.ftLastWriteTime)); + markForDstHack.push_back(std::make_pair(fullName, Trav::getModTimeRaw(fileInfo))); } //####################################### DST hack ########################################### - details.lastWriteTimeRaw = toTimeT(fileInfo.ftLastWriteTime); - details.fileSize = zen::UInt64(fileInfo.nFileSizeLow, fileInfo.nFileSizeHigh); } sink.onFile(shortName, fullName, details); @@ -366,141 +387,18 @@ private: { bool moreData = false; - tryReportingError([&](std::wstring& errorMsg) -> bool + typedef Trav Trav1; //f u VS! + tryReportingError([&] { - if (!::FindNextFile(searchHandle, // handle to search - &fileInfo)) // pointer to structure for data on found file - { - if (::GetLastError() == ERROR_NO_MORE_FILES) //this is fine - return true; - - //else we have a problem... report it: - errorMsg = _("Error traversing directory:") + L"\n\"" + directory + L"\"" + L"\n\n" + zen::getLastErrorFormatted(); - return false; - } - - moreData = true; - return true; + typedef Trav1 Trav; //f u VS! + moreData = Trav::next(searchHandle, directory, fileInfo); //throw FileError }, sink); return moreData; }()); - -#elif defined FFS_LINUX - DIR* dirObj = NULL; - if (!tryReportingError([&](std::wstring& errorMsg) -> bool - { - dirObj = ::opendir(directory.c_str()); //directory must NOT end with path separator, except "/" - if (dirObj == NULL) - { - errorMsg = _("Error traversing directory:") + L"\n\"" + directory + L"\"" + L"\n\n" + zen::getLastErrorFormatted(); - return false; - } - return true; - }, sink)) - return; - ZEN_ON_BLOCK_EXIT(::closedir(dirObj)); //never close NULL handles! -> crash - - while (true) - { - struct dirent* dirEntry = NULL; - tryReportingError([&](std::wstring& errorMsg) -> bool - { - errno = 0; //set errno to 0 as unfortunately this isn't done when readdir() returns NULL because it can't find any files - dirEntry = ::readdir(dirObj); - if (dirEntry == NULL) - { - if (errno == 0) - return true; //everything okay, not more items - - //else: we have a problem... report it: - errorMsg = _("Error traversing directory:") + L"\n\"" + directory + L"\"" + L"\n\n" + zen::getLastErrorFormatted(); - return false; - } - return true; - }, sink); - if (dirEntry == NULL) //no more items or ignore error - return; - - - //don't return "." and ".." - const char* const shortName = dirEntry->d_name; - if (shortName[0] == '.' && - (shortName[1] == '\0' || (shortName[1] == '.' && shortName[2] == '\0'))) - continue; - - const Zstring& fullName = endsWith(directory, FILE_NAME_SEPARATOR) ? //e.g. "/" - directory + shortName : - directory + FILE_NAME_SEPARATOR + shortName; - - struct stat fileInfo = {}; - - if (!tryReportingError([&](std::wstring& errorMsg) -> bool - { - if (::lstat(fullName.c_str(), &fileInfo) != 0) //lstat() does not resolve symlinks - { - errorMsg = _("Error reading file attributes:") + L"\n\"" + fullName + L"\"" + L"\n\n" + zen::getLastErrorFormatted(); - return false; - } - return true; - }, sink)) - continue; //ignore error: skip file - - const bool isSymbolicLink = S_ISLNK(fileInfo.st_mode); - - if (isSymbolicLink) - { - if (followSymlinks_) //on Linux Symlinks need to be followed to evaluate whether they point to a file or directory - { - if (::stat(fullName.c_str(), &fileInfo) != 0) //stat() resolves symlinks - { - sink.onFile(shortName, fullName, TraverseCallback::FileInfo()); //report broken symlink as file! - continue; - } - } - else //evaluate symlink directly - { - TraverseCallback::SymlinkInfo details; - try - { - details.targetPath = getSymlinkRawTargetString(fullName); //throw FileError - } - catch (FileError& e) - { -#ifndef NDEBUG //show broken symlink / access errors in debug build! - sink.onError(e.toString()); -#endif - } - - details.lastWriteTimeRaw = fileInfo.st_mtime; //UTC time(ANSI C format); unit: 1 second - details.dirLink = ::stat(fullName.c_str(), &fileInfo) == 0 && S_ISDIR(fileInfo.st_mode); //S_ISDIR and S_ISLNK are mutually exclusive on Linux => need to follow link - sink.onSymlink(shortName, fullName, details); - continue; - } - } - - //fileInfo contains dereferenced data in any case from here on - - if (S_ISDIR(fileInfo.st_mode)) //a directory... cannot be a symlink on Linux in this case - { - const std::shared_ptr rv = sink.onDir(shortName, fullName); - if (rv) - traverse(fullName, *rv, level + 1); - } - else //a file... (or symlink; pathological!) - { - TraverseCallback::FileInfo details; - details.lastWriteTimeRaw = fileInfo.st_mtime; //UTC time(ANSI C format); unit: 1 second - details.fileSize = zen::UInt64(fileInfo.st_size); - - sink.onFile(shortName, fullName, details); - } - } -#endif } -#ifdef FFS_WIN //####################################### DST hack ########################################### void applyDstHack(zen::DstHackCallback& dstCallback) { @@ -517,7 +415,7 @@ private: const dst::RawTime encodedTime = dst::fatEncodeUtcTime(i->second); //throw (std::runtime_error) { //may need to remove the readonly-attribute (e.g. FAT usb drives) - FileUpdateHandle updateHandle(i->first, [ = ]() + FileUpdateHandle updateHandle(i->first, [=]() { return ::CreateFile(zen::applyLongPathPrefix(i->first).c_str(), GENERIC_READ | GENERIC_WRITE, //use both when writing over network, see comment in file_io.cpp @@ -571,20 +469,167 @@ private: typedef std::vector > FilenameTimeList; FilenameTimeList markForDstHack; //####################################### DST hack ########################################### -#endif + const bool followSymlinks_; + const DWORD volumeSerial; //may be 0! }; -void zen::traverseFolder(const Zstring& directory, bool followSymlinks, TraverseCallback& sink, DstHackCallback* dstCallback) +#elif defined FFS_LINUX +class DirTraverser { -#ifdef FFS_WIN - try //traversing certain folders with restricted permissions requires this privilege! (but copying these files may still fail) +public: + DirTraverser(const Zstring& baseDirectory, bool followSymlinks, zen::TraverseCallback& sink, zen::DstHackCallback* dstCallback) : + followSymlinks_(followSymlinks) { - zen::Privileges::getInstance().ensureActive(SE_BACKUP_NAME); //throw FileError + const Zstring directoryFormatted = //remove trailing slash + baseDirectory.size() > 1 && endsWith(baseDirectory, FILE_NAME_SEPARATOR) ? //exception: allow '/' + beforeLast(baseDirectory, FILE_NAME_SEPARATOR) : + baseDirectory; + + /* quote: "Since POSIX.1 does not specify the size of the d_name field, and other nonstandard fields may precede + that field within the dirent structure, portable applications that use readdir_r() should allocate + the buffer whose address is passed in entry as follows: + len = offsetof(struct dirent, d_name) + pathconf(dirpath, _PC_NAME_MAX) + 1 + entryp = malloc(len); */ + const long maxPath = std::max(::pathconf(directoryFormatted.c_str(), _PC_NAME_MAX), 10000); //::pathconf may return -1 + buffer.resize(offsetof(struct ::dirent, d_name) + maxPath + 1); + + traverse(directoryFormatted, sink, 0); } - catch (...) {} //don't cause issues in user mode + +private: + DirTraverser(const DirTraverser&); + DirTraverser& operator=(const DirTraverser&); + + void traverse(const Zstring& directory, zen::TraverseCallback& sink, int level) + { + tryReportingError([&] + { + if (level == 100) //notify endless recursion + throw FileError(_("Endless loop when traversing directory:") + L"\n\"" + directory + L"\""); + }, sink); + + + DIR* dirObj = NULL; + tryReportingError([&] + { + dirObj = ::opendir(directory.c_str()); //directory must NOT end with path separator, except "/" + if (dirObj == NULL) + throw FileError(_("Error traversing directory:") + L"\n\"" + directory + L"\"" + L"\n\n" + zen::getLastErrorFormatted()); + }, sink); + + if (dirObj == NULL) + return; //ignored error + ZEN_ON_BLOCK_EXIT(::closedir(dirObj)); //never close NULL handles! -> crash + + while (true) + { + struct ::dirent* dirEntry = NULL; + tryReportingError([&] + { + if (::readdir_r(dirObj, reinterpret_cast< ::dirent*>(&buffer[0]), &dirEntry) != 0) + throw FileError(_("Error traversing directory:") + L"\n\"" + directory + L"\"" + L"\n\n" + zen::getLastErrorFormatted()); + }, sink); + if (dirEntry == NULL) //no more items or ignore error + return; + + + //don't return "." and ".." + const char* const shortName = dirEntry->d_name; //evaluate dirEntry *before* going into recursion => we use a single "buffer"! + if (shortName[0] == '.' && + (shortName[1] == '\0' || (shortName[1] == '.' && shortName[2] == '\0'))) + continue; + + const Zstring& fullName = endsWith(directory, FILE_NAME_SEPARATOR) ? //e.g. "/" + directory + shortName : + directory + FILE_NAME_SEPARATOR + shortName; + + struct ::stat fileInfo = {}; + bool haveData = false; + tryReportingError([&] + { + if (::lstat(fullName.c_str(), &fileInfo) != 0) //lstat() does not resolve symlinks + throw FileError(_("Error reading file attributes:") + L"\n\"" + fullName + L"\"" + L"\n\n" + zen::getLastErrorFormatted()); + haveData = true; + }, sink); + if (!haveData) + continue; //ignore error: skip file + + if (S_ISLNK(fileInfo.st_mode)) + { + if (followSymlinks_) //on Linux Symlinks need to be followed to evaluate whether they point to a file or directory + { + if (::stat(fullName.c_str(), &fileInfo) != 0) //stat() resolves symlinks + { + sink.onFile(shortName, fullName, TraverseCallback::FileInfo()); //report broken symlink as file! + continue; + } + + fileInfo.st_dev = 0; //id from dereferenced symlink is problematic, since renaming will consider the link, not the target! + fileInfo.st_ino = 0; // + } + else //evaluate symlink directly + { + TraverseCallback::SymlinkInfo details; + try + { + details.targetPath = getSymlinkRawTargetString(fullName); //throw FileError + } + catch (FileError& e) + { +#ifndef NDEBUG //show broken symlink / access errors in debug build! + sink.onError(e.toString()); #endif + } + + details.lastWriteTimeRaw = fileInfo.st_mtime; //UTC time(ANSI C format); unit: 1 second + details.dirLink = ::stat(fullName.c_str(), &fileInfo) == 0 && S_ISDIR(fileInfo.st_mode); + //S_ISDIR and S_ISLNK are mutually exclusive on Linux => explicitly need to follow link + sink.onSymlink(shortName, fullName, details); + continue; + } + } + + //fileInfo contains dereferenced data in any case from here on + + if (S_ISDIR(fileInfo.st_mode)) //a directory... cannot be a symlink on Linux in this case + { + const std::shared_ptr rv = sink.onDir(shortName, fullName); + if (rv) + traverse(fullName, *rv, level + 1); + } + else //a file... (or symlink; pathological!) + { + TraverseCallback::FileInfo details; + details.fileSize = zen::UInt64(fileInfo.st_size); + details.lastWriteTimeRaw = fileInfo.st_mtime; //UTC time (time_t format); unit: 1 second + details.id = extractFileID(fileInfo); + + sink.onFile(shortName, fullName, details); + } + } + } + std::vector buffer; + const bool followSymlinks_; +}; +#endif +} + + +void zen::traverseFolder(const Zstring& directory, bool followSymlinks, TraverseCallback& sink, DstHackCallback* dstCallback) +{ DirTraverser(directory, followSymlinks, sink, dstCallback); } + + +bool zen::supportForFileId() //Linux: always; Windows: if FindFilePlus_Win32.dll was loaded correctly +{ +#ifdef FFS_WIN + return ::openDir && ::readDir && ::closeDir; + +#elif defined FFS_LINUX + return true; +#endif +} diff --git a/zen/file_traverser.h b/zen/file_traverser.h index 3f4f47d5..075c32e5 100644 --- a/zen/file_traverser.h +++ b/zen/file_traverser.h @@ -10,6 +10,8 @@ #include #include "zstring.h" #include "int64.h" +#include "file_id_def.h" + //advanced file traverser returning metadata and hierarchical information on files and directories @@ -24,6 +26,7 @@ public: { UInt64 fileSize; //unit: bytes! Int64 lastWriteTimeRaw; //number of seconds since Jan. 1st 1970 UTC + FileId id; //optional: may be initial! }; struct SymlinkInfo @@ -67,6 +70,10 @@ void traverseFolder(const Zstring& directory, //throw(); //followSymlinks: //"true": Symlinks dereferenced and reported via onFile() and onDir() => onSymlink not used! //"false": Symlinks directly reported via onSymlink(), directory symlinks are not followed + + +//determine whether FileId can be expected to be retrieved +bool supportForFileId(); //Linux: always; Windows: if FindFilePlus_Win32.dll was loaded correctly } #endif // FILETRAVERSER_H_INCLUDED diff --git a/zen/guid.h b/zen/guid.h index 218c80a5..f9f497b2 100644 --- a/zen/guid.h +++ b/zen/guid.h @@ -10,7 +10,7 @@ #include #include -#ifdef __MINGW32__ //boost should start and clean up! +#ifdef __MINGW32__ //boost should start cleaning this mess up #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wshadow" #pragma GCC diagnostic ignored "-Wuninitialized" diff --git a/zen/int64.h b/zen/int64.h index e8a9cbe0..91e24437 100644 --- a/zen/int64.h +++ b/zen/int64.h @@ -56,7 +56,7 @@ public: value(rhs) {} //-> std::int64_t equals long int on x64 Linux! Still we want implicit behavior for all other systems! //unsafe explicit but checked conversion from arbitrary integer type - template explicit Int64(T rhs) : value(rhs) { checkRange(rhs); } + template explicit Int64(T rhs) : value(static_cast(rhs)) { checkRange(rhs); } Int64& operator=(const Int64& rhs) { value = rhs.value; return *this; } @@ -135,7 +135,7 @@ public: value(rhs) {} //-> std::uint64_t equals unsigned long int on x64 Linux! Still we want implicit behavior for all other systems! //unsafe explicit but checked conversion from arbitrary integer type - template explicit UInt64(T rhs) : value(rhs) { checkRange(rhs); } + template explicit UInt64(T rhs) : value(static_cast(rhs)) { checkRange(rhs); } UInt64& operator=(const UInt64& rhs) { value = rhs.value; return *this; } diff --git a/zen/long_path_prefix.h b/zen/long_path_prefix.h index 1d9213d1..d03409e1 100644 --- a/zen/long_path_prefix.h +++ b/zen/long_path_prefix.h @@ -7,6 +7,7 @@ #ifndef LONGPATHPREFIX_H_INCLUDED #define LONGPATHPREFIX_H_INCLUDED +#include "win.h" #include "zstring.h" namespace zen diff --git a/zen/notify_removal.cpp b/zen/notify_removal.cpp index 8d8eeb90..2b6b9003 100644 --- a/zen/notify_removal.cpp +++ b/zen/notify_removal.cpp @@ -74,11 +74,10 @@ private: const wchar_t MessageProvider::WINDOW_NAME[] = L"E6AD5EB1-527B-4EEF-AC75-27883B233380"; //random name -LRESULT CALLBACK topWndProc( - HWND hwnd, //handle to window - UINT uMsg, //message identifier - WPARAM wParam, //first message parameter - LPARAM lParam) //second message parameter +LRESULT CALLBACK topWndProc(HWND hwnd, //handle to window + UINT uMsg, //message identifier + WPARAM wParam, //first message parameter + LPARAM lParam) //second message parameter { if (messageProviderConstructed) //attention: this callback is triggered in the middle of singleton construction! It is a bad idea to to call back at this time! try @@ -110,18 +109,17 @@ MessageProvider::MessageProvider() : zen::ScopeGuard guardClass = zen::makeGuard([&]() { ::UnregisterClass(WINDOW_NAME, process); }); //create dummy-window - windowHandle = ::CreateWindow( - WINDOW_NAME, //LPCTSTR lpClassName OR ATOM in low-order word! - NULL, //LPCTSTR lpWindowName, - 0, //DWORD dwStyle, - 0, //int x, - 0, //int y, - 0, //int nWidth, - 0, //int nHeight, - 0, //note: we need a toplevel window to receive device arrival events, not a message-window (HWND_MESSAGE)! - NULL, //HMENU hMenu, - process, //HINSTANCE hInstance, - NULL); //LPVOID lpParam + windowHandle = ::CreateWindow(WINDOW_NAME, //LPCTSTR lpClassName OR ATOM in low-order word! + NULL, //LPCTSTR lpWindowName, + 0, //DWORD dwStyle, + 0, //int x, + 0, //int y, + 0, //int nWidth, + 0, //int nHeight, + 0, //note: we need a toplevel window to receive device arrival events, not a message-window (HWND_MESSAGE)! + NULL, //HMENU hMenu, + process, //HINSTANCE hInstance, + NULL); //LPVOID lpParam if (windowHandle == NULL) throw zen::FileError(std::wstring(L"Could not start monitoring window notifications:") + L"\n\n" + getLastErrorFormatted() + L" (CreateWindow)"); @@ -160,17 +158,16 @@ public: filter.dbch_devicetype = DBT_DEVTYP_HANDLE; filter.dbch_handle = hDir; - hNotification = ::RegisterDeviceNotification( - MessageProvider::instance().getWnd(), //__in HANDLE hRecipient, - &filter, //__in LPVOID NotificationFilter, - DEVICE_NOTIFY_WINDOW_HANDLE); //__in DWORD Flags + hNotification = ::RegisterDeviceNotification(MessageProvider::instance().getWnd(), //__in HANDLE hRecipient, + &filter, //__in LPVOID NotificationFilter, + DEVICE_NOTIFY_WINDOW_HANDLE); //__in DWORD Flags if (hNotification == NULL) { const DWORD lastError = ::GetLastError(); if (lastError != ERROR_CALL_NOT_IMPLEMENTED && //fail on SAMBA share: this shouldn't be a showstopper! lastError != ERROR_SERVICE_SPECIFIC_ERROR && //neither should be fail for "Pogoplug" mapped network drives lastError != ERROR_INVALID_DATA) //this seems to happen for a NetDrive-mapped FTP server - throw zen::FileError(std::wstring(L"Could not register device removal notifications:") + L"\n\n" + getLastErrorFormatted(lastError)); + throw zen::FileError(L"Could not register device removal notifications:" L"\n\n" + getLastErrorFormatted(lastError)); } } diff --git a/zen/privilege.cpp b/zen/privilege.cpp index 809202b7..6dd0b2d7 100644 --- a/zen/privilege.cpp +++ b/zen/privilege.cpp @@ -1,17 +1,15 @@ #include "privilege.h" +#include +#include "thread.h" //includes +#include "zstring.h" #include "scope_guard.h" using namespace zen; -Privileges& Privileges::getInstance() +namespace { - static Privileges instance; - return instance; -} - - -bool Privileges::privilegeIsActive(LPCTSTR privilege) //throw FileError +bool privilegeIsActive(LPCTSTR privilege) //throw FileError { HANDLE hToken = NULL; if (!::OpenProcessToken(::GetCurrentProcess(), //__in HANDLE ProcessHandle, @@ -42,7 +40,7 @@ bool Privileges::privilegeIsActive(LPCTSTR privilege) //throw FileError } -void Privileges::setPrivilege(LPCTSTR privilege, bool enable) //throw FileError +void setPrivilege(LPCTSTR privilege, bool enable) //throw FileError { HANDLE hToken = NULL; if (!::OpenProcessToken(::GetCurrentProcess(), //__in HANDLE ProcessHandle, @@ -62,15 +60,67 @@ void Privileges::setPrivilege(LPCTSTR privilege, bool enable) //throw FileError tp.Privileges[0].Luid = luid; tp.Privileges[0].Attributes = enable ? SE_PRIVILEGE_ENABLED : 0; - if (!::AdjustTokenPrivileges( - hToken, //__in HANDLE TokenHandle, - false, //__in BOOL DisableAllPrivileges, - &tp, //__in_opt PTOKEN_PRIVILEGES NewState, - 0, //__in DWORD BufferLength, - NULL, //__out_opt PTOKEN_PRIVILEGES PreviousState, - NULL)) //__out_opt PDWORD ReturnLength + if (!::AdjustTokenPrivileges(hToken, //__in HANDLE TokenHandle, + false, //__in BOOL DisableAllPrivileges, + &tp, //__in_opt PTOKEN_PRIVILEGES NewState, + 0, //__in DWORD BufferLength, + NULL, //__out_opt PTOKEN_PRIVILEGES PreviousState, + NULL)) //__out_opt PDWORD ReturnLength throw FileError(_("Error setting privilege:") + L" \"" + privilege + L"\"" + L"\n\n" + getLastErrorFormatted()); if (::GetLastError() == ERROR_NOT_ALL_ASSIGNED) //check although previous function returned with success! throw FileError(_("Error setting privilege:") + L" \"" + privilege + L"\"" + L"\n\n" + getLastErrorFormatted()); } + + +class Privileges +{ +public: + static Privileges& getInstance() + { + static Privileges inst; + return inst; + } + + void ensureActive(LPCTSTR privilege) //throw FileError + { + if (activePrivileges.find(privilege) != activePrivileges.end()) + return; //privilege already active + + if (privilegeIsActive(privilege)) //privilege was already active before starting this tool + activePrivileges.insert(std::make_pair(privilege, false)); + else + { + setPrivilege(privilege, true); + activePrivileges.insert(std::make_pair(privilege, true)); + } + } + +private: + Privileges() {} + Privileges(Privileges&); + void operator=(Privileges&); + + ~Privileges() //clean up: deactivate all privileges that have been activated by this application + { + for (auto iter = activePrivileges.begin(); iter != activePrivileges.end(); ++iter) + if (iter->second) + try + { + setPrivilege(iter->first.c_str(), false); + } + catch (...) {} + } + + std::map activePrivileges; //bool: enabled by this application +}; + +boost::mutex lockPrivileges; +} + + +void zen::activatePrivilege(LPCTSTR privilege) //throw FileError +{ + boost::lock_guard dummy(lockPrivileges); + Privileges::getInstance().ensureActive(privilege); +} diff --git a/zen/privilege.h b/zen/privilege.h index 4545aac7..88fc8992 100644 --- a/zen/privilege.h +++ b/zen/privilege.h @@ -7,57 +7,12 @@ #ifndef PRIVILEGE_H_INCLUDED #define PRIVILEGE_H_INCLUDED -#include -#include "zstring.h" #include "file_error.h" #include "win.h" //includes "windows.h" namespace zen { -#ifdef FFS_WIN -class Privileges -{ -public: - static Privileges& getInstance(); - - void ensureActive(LPCTSTR privilege) //throw FileError - { - if (activePrivileges.find(privilege) != activePrivileges.end()) - return; //privilege already active - - if (privilegeIsActive(privilege)) //privilege was already active before starting this tool - activePrivileges.insert(std::make_pair(privilege, false)); - else - { - setPrivilege(privilege, true); - activePrivileges.insert(std::make_pair(privilege, true)); - } - } - -private: - Privileges() {} - Privileges(Privileges&); - void operator=(Privileges&); - - ~Privileges() //clean up: deactivate all privileges that have been activated by this application - { - for (PrivBuffType::const_iterator i = activePrivileges.begin(); i != activePrivileges.end(); ++i) - try - { - if (i->second) - Privileges::setPrivilege(i->first.c_str(), false); - } - catch (...) {} - } - - static bool privilegeIsActive(LPCTSTR privilege); //throw FileError - static void setPrivilege(LPCTSTR privilege, bool enable); //throw FileError - - typedef std::map PrivBuffType; //bool: enabled by this application - - PrivBuffType activePrivileges; -}; -#endif +void activatePrivilege(LPCTSTR privilege); //throw FileError; thread-safe!!! } diff --git a/zen/process_status.h b/zen/process_status.h index cc5825aa..15266b28 100644 --- a/zen/process_status.h +++ b/zen/process_status.h @@ -3,29 +3,55 @@ #ifdef FFS_WIN #include "win.h" //includes "windows.h" + +#elif defined FFS_LINUX #endif namespace zen { -struct DisableStandby //signal a "busy" state to the operating system +struct PreventStandby //signal a "busy" state to the operating system { #ifdef FFS_WIN - DisableStandby() { ::SetThreadExecutionState(ES_CONTINUOUS | ES_SYSTEM_REQUIRED /* | ES_AWAYMODE_REQUIRED*/ ); } - ~DisableStandby() { ::SetThreadExecutionState(ES_CONTINUOUS); } + PreventStandby() { ::SetThreadExecutionState(ES_CONTINUOUS | ES_SYSTEM_REQUIRED /* | ES_AWAYMODE_REQUIRED*/ ); } + ~PreventStandby() { ::SetThreadExecutionState(ES_CONTINUOUS); } #endif }; +struct ScheduleForBackgroundProcessing //lower CPU and file I/O priorities +{ +#ifdef FFS_WIN #ifndef PROCESS_MODE_BACKGROUND_BEGIN #define PROCESS_MODE_BACKGROUND_BEGIN 0x00100000 // Windows Server 2003 and Windows XP/2000: This value is not supported! #define PROCESS_MODE_BACKGROUND_END 0x00200000 // #endif -struct ScheduleForBackgroundProcessing //lower CPU and file I/O priorities -{ -#ifdef FFS_WIN - ScheduleForBackgroundProcessing() { ::SetPriorityClass(::GetCurrentProcess(), PROCESS_MODE_BACKGROUND_BEGIN); } + ScheduleForBackgroundProcessing() { ::SetPriorityClass(::GetCurrentProcess(), PROCESS_MODE_BACKGROUND_BEGIN); } //this call lowers CPU priority, too!! ~ScheduleForBackgroundProcessing() { ::SetPriorityClass(::GetCurrentProcess(), PROCESS_MODE_BACKGROUND_END); } + +#elif defined FFS_LINUX + /* + CPU prio: + int getpriority(PRIO_PROCESS, 0); - errno caveat! + int ::setpriority(PRIO_PROCESS, 0, int prio); //a zero value for "who" denotes the calling process + + priority can be decreased, but NOT increased :( + + file I/O prio: + ScheduleForBackgroundProcessing() : oldIoPrio(::ioprio_get(IOPRIO_WHO_PROCESS, ::getpid())) + { + if (oldIoPrio != -1) + ::ioprio_set(IOPRIO_WHO_PROCESS, ::getpid(), IOPRIO_PRIO_VALUE(IOPRIO_CLASS_IDLE, 0)); + } + ~ScheduleForBackgroundProcessing() + { + if (oldIoPrio != -1) + ::ioprio_set(IOPRIO_WHO_PROCESS, ::getpid(), oldIoPrio); + } + + private: + const int oldIoPrio; + */ #endif }; } diff --git a/zen/stl_tools.h b/zen/stl_tools.h index 1707a1eb..96101821 100644 --- a/zen/stl_tools.h +++ b/zen/stl_tools.h @@ -28,11 +28,11 @@ void map_remove_if(M& map, Predicate p); template ForwardIterator binary_search(ForwardIterator first, ForwardIterator last, const T& value, Compare comp); -template +template BidirectionalIterator find_last(BidirectionalIterator first, BidirectionalIterator last, const T& value); //replacement for std::find_end taking advantage of bidirectional iterators (and giving the algorithm a reasonable name) -template +template BidirectionalIterator1 search_last(BidirectionalIterator1 first1, BidirectionalIterator1 last1, BidirectionalIterator2 first2, BidirectionalIterator2 last2); @@ -96,45 +96,47 @@ ForwardIterator binary_search(ForwardIterator first, ForwardIterator last, const } -template inline +template inline BidirectionalIterator find_last(const BidirectionalIterator first, BidirectionalIterator last, const T& value) { + //reverse iteration: 1. check 2. decrement 3. evaluate const BidirectionalIterator iterNotFound = last; - do + for (;;) //VS 2010 doesn't like "while (true)" { if (last == first) return iterNotFound; --last; + + if (*last == value) + return last; } - while (!(*last == value)); //loop over "last": 1. check 2. decrement 3. evaluate - return last; } -template inline +template inline BidirectionalIterator1 search_last(const BidirectionalIterator1 first1, BidirectionalIterator1 last1, const BidirectionalIterator2 first2, BidirectionalIterator2 last2) { - if (first1 == last1 || - first2 == last2) - return last1; - - int diff = static_cast(std::distance(first1, last1)) - - static_cast(std::distance(first2, last2)); - const BidirectionalIterator1 iterNotFound = last1; - --last2; - while (diff-- >= 0) //loop over "last1": 1. check 2. decrement 3. evaluate + //reverse iteration: 1. check 2. decrement 3. evaluate + for (;;) { - --last1; + BidirectionalIterator1 it1 = last1; + BidirectionalIterator2 it2 = last2; - BidirectionalIterator1 iter1 = last1; - for (BidirectionalIterator2 iter2 = last2; *iter1 == *iter2; --iter1, --iter2) - if (iter2 == first2) - return iter1; + for (;;) + { + if (it2 == first2) return it1; + if (it1 == first1) return iterNotFound; + + --it1; + --it2; + + if (*it1 != *it2) break; + } + --last1; } - return iterNotFound; } } diff --git a/zen/symlink_target.h b/zen/symlink_target.h index 370a0c56..dfbbba6d 100644 --- a/zen/symlink_target.h +++ b/zen/symlink_target.h @@ -66,7 +66,7 @@ Zstring getSymlinkRawTargetString(const Zstring& linkPath) //throw FileError try //reading certain symlinks/junctions requires admin rights! This shall not cause an error in user mode! { - Privileges::getInstance().ensureActive(SE_BACKUP_NAME); //throw FileError + activatePrivilege(SE_BACKUP_NAME); //throw FileError } catch (...) {} diff --git a/zen/time.h b/zen/time.h index f08f6ef8..6124d4d1 100644 --- a/zen/time.h +++ b/zen/time.h @@ -175,7 +175,10 @@ String formatTime(const String2& format, const TimeComp& comp, UserDefinedFormat { typedef typename GetCharType::Result CharType; - const struct std::tm& ctc = toClibTimeComponents(comp); + struct std::tm ctc = toClibTimeComponents(comp); + std::mktime (&ctc); // unfortunately std::strftime() needs all elements of "struct tm" filled, e.g. tm_wday, tm_yday + //note: although std::mktime() explicitly expects "local time", calculating weekday and day of year *should* be time-zone and DST independent + CharType buffer[256]; const size_t charsWritten = strftimeWrap(buffer, 256, strBegin(format), &ctc); return String(buffer, charsWritten); -- cgit