├── .gitattributes ├── .gitignore ├── Doc ├── CoreClassDiagram.drawio └── CoreClassDiagram.drawio.svg ├── LICENSE ├── README.md ├── SimpleFileBackup.Core ├── BackupWriterFactory.cs ├── Data │ ├── BackupArguments.cs │ └── BackupMetadataInfo.cs ├── IBackupWriter.cs ├── Progress │ ├── BackupProgress.cs │ ├── BackupProgressInfo.cs │ └── IBackupProgress.cs ├── SimpleFileBackup.Core.csproj ├── Util │ ├── BackupProgressHelper.cs │ ├── DirectoryHelper.cs │ └── ZipArchiveExtensions.cs └── Writers │ ├── BaseBackupWriter.cs │ ├── CopyFileBackupWriter.cs │ ├── NamedBackupWriter.cs │ ├── SubfolderCopyBackupWriter.cs │ └── ZipBackupWriter.cs ├── SimpleFileBackup.Windows ├── App.config ├── BackupMode.cs ├── FormAbout.Designer.cs ├── FormAbout.cs ├── FormAbout.resx ├── FormMain.Designer.cs ├── FormMain.cs ├── FormMain.resx ├── Program.cs ├── Properties │ ├── AssemblyInfo.cs │ ├── Resources.Designer.cs │ ├── Resources.resx │ ├── Settings.Designer.cs │ ├── Settings.settings │ └── app.manifest ├── Resources │ └── about.html ├── SFB.ico ├── SimpleFileBackup.Windows.csproj └── packages.config └── SimpleFileBackup.sln /.gitattributes: -------------------------------------------------------------------------------- 1 | ############################################################################### 2 | # Set default behavior to automatically normalize line endings. 3 | ############################################################################### 4 | * text=auto 5 | 6 | ############################################################################### 7 | # Set default behavior for command prompt diff. 8 | # 9 | # This is need for earlier builds of msysgit that does not have it on by 10 | # default for csharp files. 11 | # Note: This is only used by command line 12 | ############################################################################### 13 | #*.cs diff=csharp 14 | 15 | ############################################################################### 16 | # Set the merge driver for project and solution files 17 | # 18 | # Merging from the command prompt will add diff markers to the files if there 19 | # are conflicts (Merging from VS is not affected by the settings below, in VS 20 | # the diff markers are never inserted). Diff markers may cause the following 21 | # file extensions to fail to load in VS. An alternative would be to treat 22 | # these files as binary and thus will always conflict and require user 23 | # intervention with every merge. To do so, just uncomment the entries below 24 | ############################################################################### 25 | #*.sln merge=binary 26 | #*.csproj merge=binary 27 | #*.vbproj merge=binary 28 | #*.vcxproj merge=binary 29 | #*.vcproj merge=binary 30 | #*.dbproj merge=binary 31 | #*.fsproj merge=binary 32 | #*.lsproj merge=binary 33 | #*.wixproj merge=binary 34 | #*.modelproj merge=binary 35 | #*.sqlproj merge=binary 36 | #*.wwaproj merge=binary 37 | 38 | ############################################################################### 39 | # behavior for image files 40 | # 41 | # image files are treated as binary by default. 42 | ############################################################################### 43 | #*.jpg binary 44 | #*.png binary 45 | #*.gif binary 46 | 47 | ############################################################################### 48 | # diff behavior for common document formats 49 | # 50 | # Convert binary document formats to text before diffing them. This feature 51 | # is only available from the command line. Turn it on by uncommenting the 52 | # entries below. 53 | ############################################################################### 54 | #*.doc diff=astextplain 55 | #*.DOC diff=astextplain 56 | #*.docx diff=astextplain 57 | #*.DOCX diff=astextplain 58 | #*.dot diff=astextplain 59 | #*.DOT diff=astextplain 60 | #*.pdf diff=astextplain 61 | #*.PDF diff=astextplain 62 | #*.rtf diff=astextplain 63 | #*.RTF diff=astextplain 64 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ## Ignore Visual Studio temporary files, build results, and 2 | ## files generated by popular Visual Studio add-ons. 3 | 4 | # User-specific files 5 | *.suo 6 | *.user 7 | *.userosscache 8 | *.sln.docstates 9 | 10 | # User-specific files (MonoDevelop/Xamarin Studio) 11 | *.userprefs 12 | 13 | # Build results 14 | [Dd]ebug/ 15 | [Dd]ebugPublic/ 16 | [Rr]elease/ 17 | [Rr]eleases/ 18 | x64/ 19 | x86/ 20 | bld/ 21 | [Bb]in/ 22 | [Oo]bj/ 23 | [Ll]og/ 24 | 25 | # Visual Studio 2015 cache/options directory 26 | .vs/ 27 | # Uncomment if you have tasks that create the project's static files in wwwroot 28 | #wwwroot/ 29 | 30 | # MSTest test Results 31 | [Tt]est[Rr]esult*/ 32 | [Bb]uild[Ll]og.* 33 | 34 | # NUNIT 35 | *.VisualState.xml 36 | TestResult.xml 37 | 38 | # Build Results of an ATL Project 39 | [Dd]ebugPS/ 40 | [Rr]eleasePS/ 41 | dlldata.c 42 | 43 | # DNX 44 | project.lock.json 45 | project.fragment.lock.json 46 | artifacts/ 47 | 48 | *_i.c 49 | *_p.c 50 | *_i.h 51 | *.ilk 52 | *.meta 53 | *.obj 54 | *.pch 55 | *.pdb 56 | *.pgc 57 | *.pgd 58 | *.rsp 59 | *.sbr 60 | *.tlb 61 | *.tli 62 | *.tlh 63 | *.tmp 64 | *.tmp_proj 65 | *.log 66 | *.vspscc 67 | *.vssscc 68 | .builds 69 | *.pidb 70 | *.svclog 71 | *.scc 72 | 73 | # Chutzpah Test files 74 | _Chutzpah* 75 | 76 | # Visual C++ cache files 77 | ipch/ 78 | *.aps 79 | *.ncb 80 | *.opendb 81 | *.opensdf 82 | *.sdf 83 | *.cachefile 84 | *.VC.db 85 | *.VC.VC.opendb 86 | 87 | # Visual Studio profiler 88 | *.psess 89 | *.vsp 90 | *.vspx 91 | *.sap 92 | 93 | # TFS 2012 Local Workspace 94 | $tf/ 95 | 96 | # Guidance Automation Toolkit 97 | *.gpState 98 | 99 | # ReSharper is a .NET coding add-in 100 | _ReSharper*/ 101 | *.[Rr]e[Ss]harper 102 | *.DotSettings.user 103 | 104 | # JustCode is a .NET coding add-in 105 | .JustCode 106 | 107 | # TeamCity is a build add-in 108 | _TeamCity* 109 | 110 | # DotCover is a Code Coverage Tool 111 | *.dotCover 112 | 113 | # NCrunch 114 | _NCrunch_* 115 | .*crunch*.local.xml 116 | nCrunchTemp_* 117 | 118 | # MightyMoose 119 | *.mm.* 120 | AutoTest.Net/ 121 | 122 | # Web workbench (sass) 123 | .sass-cache/ 124 | 125 | # Installshield output folder 126 | [Ee]xpress/ 127 | 128 | # DocProject is a documentation generator add-in 129 | DocProject/buildhelp/ 130 | DocProject/Help/*.HxT 131 | DocProject/Help/*.HxC 132 | DocProject/Help/*.hhc 133 | DocProject/Help/*.hhk 134 | DocProject/Help/*.hhp 135 | DocProject/Help/Html2 136 | DocProject/Help/html 137 | 138 | # Click-Once directory 139 | publish/ 140 | 141 | # Publish Web Output 142 | *.[Pp]ublish.xml 143 | *.azurePubxml 144 | # TODO: Comment the next line if you want to checkin your web deploy settings 145 | # but database connection strings (with potential passwords) will be unencrypted 146 | #*.pubxml 147 | *.publishproj 148 | 149 | # Microsoft Azure Web App publish settings. Comment the next line if you want to 150 | # checkin your Azure Web App publish settings, but sensitive information contained 151 | # in these scripts will be unencrypted 152 | PublishScripts/ 153 | 154 | # NuGet Packages 155 | *.nupkg 156 | # The packages folder can be ignored because of Package Restore 157 | **/packages/* 158 | # except build/, which is used as an MSBuild target. 159 | !**/packages/build/ 160 | # Uncomment if necessary however generally it will be regenerated when needed 161 | #!**/packages/repositories.config 162 | # NuGet v3's project.json files produces more ignoreable files 163 | *.nuget.props 164 | *.nuget.targets 165 | 166 | # Microsoft Azure Build Output 167 | csx/ 168 | *.build.csdef 169 | 170 | # Microsoft Azure Emulator 171 | ecf/ 172 | rcf/ 173 | 174 | # Windows Store app package directories and files 175 | AppPackages/ 176 | BundleArtifacts/ 177 | Package.StoreAssociation.xml 178 | _pkginfo.txt 179 | 180 | # Visual Studio cache files 181 | # files ending in .cache can be ignored 182 | *.[Cc]ache 183 | # but keep track of directories ending in .cache 184 | !*.[Cc]ache/ 185 | 186 | # Others 187 | ClientBin/ 188 | ~$* 189 | *~ 190 | *.dbmdl 191 | *.dbproj.schemaview 192 | *.jfm 193 | *.pfx 194 | *.publishsettings 195 | node_modules/ 196 | orleans.codegen.cs 197 | 198 | # Since there are multiple workflows, uncomment next line to ignore bower_components 199 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) 200 | #bower_components/ 201 | 202 | # RIA/Silverlight projects 203 | Generated_Code/ 204 | 205 | # Backup & report files from converting an old project file 206 | # to a newer Visual Studio version. Backup files are not needed, 207 | # because we have git ;-) 208 | _UpgradeReport_Files/ 209 | Backup*/ 210 | UpgradeLog*.XML 211 | UpgradeLog*.htm 212 | 213 | # SQL Server files 214 | *.mdf 215 | *.ldf 216 | 217 | # Business Intelligence projects 218 | *.rdl.data 219 | *.bim.layout 220 | *.bim_*.settings 221 | 222 | # Microsoft Fakes 223 | FakesAssemblies/ 224 | 225 | # GhostDoc plugin setting file 226 | *.GhostDoc.xml 227 | 228 | # Node.js Tools for Visual Studio 229 | .ntvs_analysis.dat 230 | 231 | # Visual Studio 6 build log 232 | *.plg 233 | 234 | # Visual Studio 6 workspace options file 235 | *.opt 236 | 237 | # Visual Studio LightSwitch build output 238 | **/*.HTMLClient/GeneratedArtifacts 239 | **/*.DesktopClient/GeneratedArtifacts 240 | **/*.DesktopClient/ModelManifest.xml 241 | **/*.Server/GeneratedArtifacts 242 | **/*.Server/ModelManifest.xml 243 | _Pvt_Extensions 244 | 245 | # Paket dependency manager 246 | .paket/paket.exe 247 | paket-files/ 248 | 249 | # FAKE - F# Make 250 | .fake/ 251 | 252 | # JetBrains Rider 253 | .idea/ 254 | *.sln.iml 255 | 256 | # CodeRush 257 | .cr/ 258 | 259 | # Python Tools for Visual Studio (PTVS) 260 | __pycache__/ 261 | *.pyc 262 | 263 | # drawio temporary files 264 | *.bkp -------------------------------------------------------------------------------- /Doc/CoreClassDiagram.drawio: -------------------------------------------------------------------------------- 1 | 7Vxbd5u4Fv41Xqvz4Cxuvj36krSZpmfSNj2ZPJ2lgGxzCsgDIrH760dC4iIksF2DnenwklgbIZC+vT/tvSXRM+f+9n0INutPyIFez9Ccbc9c9AxDH45M8o9Kdlyi6WMmWYWuw2W54Kv7A6YVuTR2HRgJFTFCHnY3otBGQQBtLMhAGKJXsdoSeeJTN2AFJcFXG3iy9NF18JpJx8Yol3+A7mqdPlkfTtgVH6SVeU+iNXDQa0FkXvfMeYgQZr/87Rx6dPTScXm83T16d9+H73//HP0Fvs0+Pvznv33W2M0xt2RdCGGAf7rp+8mL/7jTnOn2i3396ffN0n/8oz/gbUd4lw4YdMj48SIK8RqtUAC861w6C1EcOJA2q5FSXucOoQ0R6kT4f4jxjisDiDEiojX2PX6VdCPc/cnvTwpPtHA1SIuLbfHiYpeVnClVCVK0PRBFrs2EN66XN53q4JCUDhy4dBBQHNqwZrS4ImAQriCuqacbrCIdyoIWclzeQ+RD0i1SIYQewO6LqKqAa/wqq8dvJX0Hu0KFDXIDHBVavqcCUoFbr6ENWYvcdo1BSUP21eemwOuTH+wN0lKhK7ko0bpjNNBiz3wBXszHIY6IcpHbAqVu3oFnwlGCPgHPXQVUKQjMMCSCFxhil3DAlF/wXcdhqgsj9wd4TtqjGsWHkDQ+mPUGC6XK1BoOfRLc9hRMxp8ikIUAPr9LuzInnHKOUwcJv74+EPDTTbEFtFxGRG9FSJsBcdDRSPM0MnojLGKIrKDvYxGxvj62zsAiQ4lF7BACDKO3zCGD5jhkOBS5u280RCmlZlOKaZ9TNAnRGbC/x5tpuIp9yFVWQDZ6dX0PBBSjJQpwyj4UXXvtes4d2KGYAhJh0lJamq1R6P4g9UGqCuRyiLn5G9T+l4QY5shDRC0WAUoekN/0lTbGVSFRDXifAq+XRJ/AVqh4ByLMBTbyPLCJ3OfslX1CD24wQxgjn1c6jocktapUH1MTLXbEW3jNHWbd4nXWRWdZs6oVStCHY8HXJfB7Bum+dhtsYkx4WmHXpK84AS9E32EJLQWAqb17cIkV1o7pHDSLNsB2g9VdUmdh5ZIvfBCoCJF7l14ynawJR8AgmdswwJUcMSNjOafzFGELY07Kel5OCGRDZsM5CkhfgJtADYmmvEKqLYeSi3awEmTe3mGgp/Uax9yowPyPGBPQF27YYd405gPjwpibVZiTPryGLobXWzfCZPA76BuGfjQ+H/RP8eebj/0H/09nivzr2csTXLv9C2ce8ijhSQgS1CFDwxGAdWAEkAJy4RDAHIleoCnkBaTqI1OvqX5yAKDUJnnyeFP+f50FnO7+97Uryxy3EgCkNJH5/6UW2vP/5bwQ8/8/QQwcwra3wRIdEwLsBZjNAadFCr9UWGBY1pUpatVgIs0axlAVGZjjljyGgaQWzGOgQQFFonMS93gK1sFqUB0YKDFvzUmc1EA+Jx4B7iBvGHJFXHBeyHU5+yOa+dfY71BvGHVFSHBe1OUkroSx5ybYMYzTBV39pwDOHDqO6EMSQ/R1CXVTRt1UIOxRp/IeRS52EW0/ZHUV/uElwM1ydfvQbWviHlVZdIj8Umb3Xan8W2fqTWuDfnGGl1O8DPVHmvYJb4CNEX9M5+C35eAPJ2UHP1sLKCqGflYPP1VNiSn2rf90pKC2sJM8fRX27ZGCKrrrPICG4FV59Sp4WzNslX9HDXuepOoY8V9dvbu66ib8xsEfHsjr7dl2lQPYod8++uOLM3tVEqdDv330ld7+WeE3VBP70EsmRwHs4V8x3U/NveCeOdU226zYT7CbWomIakWfYz3NfP68BfJrxf8nz3ELAuBTHfDk0i1tZglsmInFW4QWyUi45ac8h5IkFdwW45tCG8/lO4hsU5atQzpM6e76tI96dXf3DCu5SkdW/MsGVtUmtdTrLbRjDFkv3v1W97bHYMrMdHrMs+cgsInSAepmvZX3oOZuaBzj+xCtSKgXXfLlDnuVEtWqybLEqAVaXCZbZlkozpSTUA0r3wDf9SgBfYDeC6St9oQF17aC2kFpsdowFImviSqiTRmxcfaz5Gy2CI6EQ7eV8WfRL+UzhqYEvqkE32wN/Kq9jAcsZ3eej9qOTsloKOFvzfGx5GRWP8M+Nf93nc/bOPKKZMeZkZc3sBTtPsNepoFOGxrXBsXS5pm1oSr3tVcbmGM5tZmTyXw48SZWi3l0ne40rjuqldPWlCc2Yvthc3vTX063H9zdduH/L9sAc+atslsXs52yxoAXnwqX8o2ytJAfreP7a7PNtuxI3mjfmbzj/MHiBlvliPFc494Ntmle4sIbbHWtfASHH+eq2mIr3WBqo5KanbbJVjmqil05/KzuEtH8xCYLZ8h4UVtV6u3ZN9/W2VQj53e1IVejU0/bmeIB3mzFpNHdtl8efsQPk5u73efBav1eH33cfltfiGJ+7iBuyVjbpQ3laFVoxInw6/pQNGrDKgWl7MX4bbkSHE03+kCMkvVx/ZnefTecTDfKUVbQDaOVC27qP5gvRK2strm6Tf2E1sXt93ojNGOYQqOTFjimzrp++TWAU5O9TfVQufyQpRyTNYDbPANZHAJlfKHuvWr14qARaXpF4/h8uSrWqlrFaT2Bf9iDf710/WQsznlpYFUMtnRLDrZGbQVb48t4Qid/yuTZQzR5X/CfNMF/SpB2QLRO3vN4SPcfajRk76luHmgu5joJ73Q5/TLRdfq7APf+4LqkJC0G17U7ef4p0bU1mggUU4qVpfoDY1xXv6XYWl4oeFMnWGttp5EjrIZplg+bNuPuWqIPbbTg71ZHiTWrvt0JVnE1WKFFh3FWpVbpWvopm3JEXfzswUiRyx01sAlWHdQqgiDqjN7DkOK6oFn4f3cKf48aHJOQqfm0jQr0JhL4yteTuZ1HIDvC75QUoPNt08HeMOyqr9s0BDsp5h9+ZfNF/v1c8/pv -------------------------------------------------------------------------------- /Doc/CoreClassDiagram.drawio.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 |
used in
used in
creates
creates
BackupArguments+ InputFiles+ OutputDirs+ OverwriteExisting
creates
creates
BackupMetadataInfo+ FileSizes+ FileCount+ FileSizeSum+ FromBackupArguments(BackupArguments)BackupWriterFactory+ BackupArguments+ CreateWriter..(..)+ CreateWriter..(..)+ CreateWriter..(..)

<<Interface>>
IBackupWriter


+ ExecuteBackup()

+ ExecuteBackup(Cancellation)

+ ExecuteBackup(Cancellation, IBackupProgress)

+ ExecuteBackup(IBackupProgress)

<<Interface>>...
BackupProgress+ BackupMetadataInfo- BackupProgress()+ BackupProgress(BackupMetadataInfo)+ BackupProgress(BackupMetadataInfo, Action<BackupProgressInfo>)
used for progress report
used for progress report
reports
reports

<<Interface>>

IBackupProgress: IProgress<BackupProgressInfo>


+ BackupMetadataInfo


<<Interface>>...
creates
creates
BackupProgressInfo+ PercentDone+ BytesBackedUp
Text is not SVG - cannot display
-------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022 Marcel Salvenmoser 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # SimpleFileBackup 2 | Simple C# program for copying multiple files to multiple locations at once 3 | 4 | ![SimpleFileBackup Windows UI](https://user-images.githubusercontent.com/18032233/181794403-6569fb36-1690-4342-8b1c-10d5d1243175.PNG) 5 | 6 | ## Download 7 | https://github.com/malthee/SimpleFileBackup/releases 8 | 9 | # SimpleFileBackup.Windows 10 | ## General 11 | Select files or folders by pressing the Select buttons on the right. You can select multiple files or folders at once. After pressing OK the file locations will be saved in the drop down list. You can also add files by typing the path in the textbox and pressing enter. If you made a wrong selection, you can delete single items by selecting them in the drop down list and pressing "Delete Item". You can clear the list by pressing "Clear List". 12 | 13 | Backup Destinations can be selected through the same process. Every file or folder in "Files to Backup" will be backed up to every "Backup Destination". 14 | 15 | ## Settings 16 | 17 | ### Override idenetical files in directory 18 | If you want to replace your old files with the new files enable the "Override identical files in directory" option. This way, if a file called 123.jpg is already in the directory, it will be replaced. Same goes for ZIP files. 19 | 20 | ### Put files in given directory 21 | Copies the files into the selected directories. 22 | 23 | ### Create a subfolder in directory 24 | Creates a subfolder in every given directory. 25 | 26 | ### Create a .zip file in directory 27 | Create a .zip from the given files and copy it to every listed directory. 28 | 29 | ### Name Folder/.zip 30 | Only works when "Create a subfolder in directory" or "Create a .zip file in directory" is selected. 31 | You can name your folder or .zip file with a maximum of 20 characters. The characters have to be compatible with the windows filesystem. 32 | 33 | ### Add date to Folder/.zip name 34 | Adds your local date to the folder/.zip name in the format name_10-10-2010. 35 | 36 | ### Save Defaults 37 | Saves your file/backup locations and settings to keep them for the next program start. 38 | 39 | ### Save Custom File Paths & Save Custom Backup Paths 40 | Saves your file/backup locations in a text file you can choose the location of. 41 | 42 | ### Open File Paths & Open Backup Paths 43 | You can open a text file that contains paths to files or directories. These paths will be inserted into the drop down list. 44 | 45 | ## Common problems 46 | 1. If you have windows security folder protection enabled, you might get errors like "File cannot be found" or "Permissions error". You can fix this by navigating to the protection history and pressing allow on the blocked entries. 47 | 48 | | Navigate to protection history | Press actions -> allow | 49 | |--|--| 50 | | ![Windows protection history](https://github.com/malthee/SimpleFileBackup/assets/18032233/1a83fb66-a7c0-4ac5-9aa7-9dd2f01d6d54) | ![Allowing write access in protection history](https://github.com/malthee/SimpleFileBackup/assets/18032233/9925116f-9230-44b0-bece-d86f9fb39fd0) | 51 | 52 | # SimpleFileBackup.Core 53 | Core is a `.NET Framework 2.0` library for persisting one or more files or folders in one or more other locations in any recoverable format. As an example it can be used to copy files and folders from different drive locations to multiple backup drives at once. 54 | 55 | An overview of the components can be seen in the following diagram: 56 | ![Class Diagram of SFB Core](Doc/CoreClassDiagram.drawio.svg) 57 | 58 | ## Public interface 59 | * `BackupWriterFactory`: provides implementations of `IBackupWriter` 60 | * `IBackupWriter`: contract every backup writer has to implement. Used to start a backup with or without cancellation and progress reporting. 61 | * `BackupArguments`: used to create a `BackupWriterFactory`. Contains input and output information. 62 | * `BackupMetadataInfo`: can be created with `BackupArguments`. Contains information about file size and count which is handled. 63 | * `IBackupProgress` and `BackupProgress`: extended Interface with `BackupMetadataInfo` for progress calculation and adapter implementation of `Progress`. 64 | * `BackupProgressInfo`: provides the user with information how far the backup is in percent and how many bytes have been written to output locations. 65 | 66 | ## Contribute 67 | Feature requests and bugs must have a ticket and description before any pull request is accepted. There is also a Project board on GitHub in which some current feature requests are prioritized and documented. 68 | Otherwise any contributers are welcome! 69 | -------------------------------------------------------------------------------- /SimpleFileBackup.Core/BackupWriterFactory.cs: -------------------------------------------------------------------------------- 1 | using SimpleFileBackup.Core.Data; 2 | using SimpleFileBackup.Core.Writers; 3 | using System; 4 | using System.Collections.Generic; 5 | using System.Linq; 6 | 7 | namespace SimpleFileBackup.Core 8 | { 9 | /// 10 | /// Factory for implementations. 11 | /// 12 | public class BackupWriterFactory 13 | { 14 | public const string DefaultDateFormat = "dd-MM-yyyy"; 15 | 16 | /// 17 | /// Arguments used to create s with. 18 | /// 19 | public BackupArguments BackupArguments { get; set; } 20 | 21 | public BackupWriterFactory(BackupArguments args) 22 | { 23 | BackupArguments = args; 24 | } 25 | 26 | public IBackupWriter CreateCopyFileBackupWriter() 27 | { 28 | return new CopyFileBackupWriter(BackupArguments); 29 | } 30 | 31 | public IBackupWriter CreateSubfolderCopyBackupWriter(string subfolderName) 32 | { 33 | return new SubfolderCopyBackupWriter(BackupArguments, subfolderName); 34 | } 35 | 36 | public IBackupWriter CreateSubfolderCopyBackupWriter(string subfolderName, DateTime dateSuffix, string dateFormat = DefaultDateFormat) 37 | { 38 | return new SubfolderCopyBackupWriter(BackupArguments, subfolderName, dateSuffix, dateFormat); 39 | } 40 | 41 | public IBackupWriter CreateZipBackupWriter(string zipName) 42 | { 43 | return new ZipBackupWriter(BackupArguments, zipName); 44 | } 45 | 46 | public IBackupWriter CreateZipBackupWriter(string zipName, DateTime dateSuffix, string dateFormat = DefaultDateFormat) 47 | { 48 | return new ZipBackupWriter(BackupArguments, zipName, dateSuffix, dateFormat); 49 | } 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /SimpleFileBackup.Core/Data/BackupArguments.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | 6 | namespace SimpleFileBackup.Core.Data 7 | { 8 | /// 9 | /// Data class with arguments needed to perform a backup. 10 | /// 11 | public class BackupArguments 12 | { 13 | /// 14 | /// Paths to files or folders. 15 | /// 16 | public IReadOnlyList InputFiles { get; } 17 | 18 | /// 19 | /// Folder paths of output directories. 20 | /// 21 | public IReadOnlyList OutputDirs { get; } 22 | 23 | /// 24 | /// Defines if existing files should be overwritten. 25 | /// 26 | public bool OverwriteExisting { get; } 27 | 28 | /// 29 | /// Creates a new instance with copies of and . 30 | /// 31 | /// 32 | /// 33 | /// 34 | public BackupArguments(IEnumerable inputFiles, IEnumerable outputDirs, bool overwriteExisting) 35 | { 36 | InputFiles = inputFiles.ToList(); 37 | OutputDirs = outputDirs.ToList(); 38 | OverwriteExisting = overwriteExisting; 39 | } 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /SimpleFileBackup.Core/Data/BackupMetadataInfo.cs: -------------------------------------------------------------------------------- 1 | using SimpleFileBackup.Core.Util; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.IO; 5 | using System.Text; 6 | using System.Threading; 7 | using System.Threading.Tasks; 8 | 9 | namespace SimpleFileBackup.Core.Data 10 | { 11 | /// 12 | /// Contains metadata about the input files of a backup. 13 | /// 14 | public class BackupMetadataInfo 15 | { 16 | /// 17 | /// Dictionary of file path and file size in byte. Invalid files will have size -1. 18 | /// 19 | public IReadOnlyDictionary FileSizes { get; } 20 | 21 | /// 22 | /// Count of all files including those nested in directories. 23 | /// 24 | public long FileCount { get; } 25 | 26 | /// 27 | /// Sum of all file sizes in bytes. 28 | /// 29 | public long FileSizeSum { get; } 30 | 31 | /// 32 | /// if the provided files are valid and accessable, otherwise . 33 | /// 34 | public bool FilesValid { get; } = true; 35 | 36 | private BackupMetadataInfo(long fileSizeSum, long fileCount, IReadOnlyDictionary fileSizes, bool filesValid) 37 | { 38 | FileSizeSum = fileSizeSum; 39 | FileCount = fileCount; 40 | FileSizes = fileSizes; 41 | FilesValid = filesValid; 42 | } 43 | 44 | /// 45 | /// Creates a new from . Gets file and directory size info. 46 | /// Includes file duplicates in size and count. 47 | /// 48 | /// 49 | /// 50 | /// 51 | public static Task FromBackupArgumentsAsync(BackupArguments args, CancellationToken cancellationToken = default) 52 | { 53 | return Task.Run(() => 54 | { 55 | var fileSizes = new Dictionary(); 56 | long fileSizeSum = 0, fileCount = 0; 57 | bool filesValid = true; 58 | 59 | foreach (string inputFile in args.InputFiles) 60 | { 61 | cancellationToken.ThrowIfCancellationRequested(); 62 | (long currentFileSize, long currentCount) = GetFileOrFolderSize(inputFile); 63 | 64 | if (currentFileSize >= 0) 65 | { 66 | fileSizeSum += currentFileSize; 67 | } 68 | else 69 | { 70 | filesValid = false; 71 | } 72 | 73 | fileCount += currentCount; 74 | fileSizes.Add(inputFile, currentFileSize); 75 | } 76 | 77 | return new BackupMetadataInfo(fileSizeSum, fileCount, fileSizes, filesValid); 78 | }); 79 | } 80 | 81 | /// 82 | /// Gets the file size and count of a single file or whole directory. 83 | /// 84 | /// 85 | /// Size in bytes or -1 if read not possible and count of file(s). 86 | private static (long Size, long Count) GetFileOrFolderSize(string inputFile) 87 | { 88 | long size = -1, count = 1; 89 | 90 | if (Directory.Exists(inputFile)) 91 | { 92 | var di = new DirectoryInfo(inputFile); 93 | (size, count) = DirectoryHelper.GetRecursiveDirectorySize(di); 94 | } 95 | else if (File.Exists(inputFile)) 96 | { 97 | var fi = new FileInfo(inputFile); 98 | size = fi.Length; 99 | } 100 | 101 | return (size, count); 102 | } 103 | } 104 | } 105 | -------------------------------------------------------------------------------- /SimpleFileBackup.Core/IBackupWriter.cs: -------------------------------------------------------------------------------- 1 | using SimpleFileBackup.Core.Progress; 2 | using System.Threading; 3 | using System.Threading.Tasks; 4 | 5 | namespace SimpleFileBackup.Core 6 | { 7 | public interface IBackupWriter 8 | { 9 | /// 10 | /// Backs up all input files and folders to their output directories. 11 | /// Reports progress through . Cancellable through . 12 | /// Does not revert changes on cancellation. 13 | /// 14 | /// 15 | /// 16 | /// 17 | Task ExecuteAsync(CancellationToken cancellationToken, IBackupProgress progress); 18 | 19 | /// 20 | /// Backs up all input files and folders to their output directories. 21 | /// Is cancellable through . 22 | /// Does not revert changes on cancellation. 23 | /// 24 | /// 25 | /// 26 | Task ExecuteAsync(CancellationToken cancellationToken); 27 | 28 | /// 29 | /// Backs up all input files and folders to their output directories. 30 | /// Reports progress through . 31 | /// 32 | /// 33 | /// 34 | Task ExecuteAsync(IBackupProgress progress); 35 | 36 | /// 37 | /// Backs up all input files and folders to their output directories. 38 | /// 39 | /// 40 | Task ExecuteAsync(); 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /SimpleFileBackup.Core/Progress/BackupProgress.cs: -------------------------------------------------------------------------------- 1 | using SimpleFileBackup.Core.Data; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Text; 5 | 6 | namespace SimpleFileBackup.Core.Progress 7 | { 8 | /// 9 | /// implementation with requiring a 10 | /// for progress calculation. 11 | ///
12 | ///
13 | public class BackupProgress : Progress, IBackupProgress 14 | { 15 | public BackupMetadataInfo BackupMetadataInfo { get; } 16 | 17 | // Hide default constructor because of required Metadata argument 18 | private BackupProgress() 19 | { } 20 | 21 | /// 22 | /// Initializes a instance. 23 | /// 24 | /// 25 | public BackupProgress(BackupMetadataInfo backupMetadataInfo): base() 26 | { 27 | BackupMetadataInfo = backupMetadataInfo; 28 | } 29 | 30 | /// 31 | /// Initializes a with a handler. 32 | /// 33 | /// 34 | /// 35 | public BackupProgress(Action handler, BackupMetadataInfo backupMetadataInfo) : base(handler) 36 | { 37 | BackupMetadataInfo = backupMetadataInfo; 38 | } 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /SimpleFileBackup.Core/Progress/BackupProgressInfo.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Text; 4 | 5 | namespace SimpleFileBackup.Core.Progress 6 | { 7 | /// 8 | /// Provides information about a running backup. 9 | /// 10 | public class BackupProgressInfo 11 | { 12 | /// 13 | /// How much progress the backup has made. Does not have to be related to bytes backed up. 14 | /// 15 | public double PercentDone { get; } 16 | 17 | /// 18 | /// How many bytes were backed up to output locations. 19 | /// 20 | public long BytesBackedUp { get; } 21 | 22 | public BackupProgressInfo(double percentDone, long bytesBackedUp) 23 | { 24 | PercentDone = percentDone; 25 | BytesBackedUp = bytesBackedUp; 26 | } 27 | 28 | public BackupProgressInfo WithPercentDone(double percentDone) 29 | { 30 | return new BackupProgressInfo(percentDone, BytesBackedUp); 31 | } 32 | 33 | public BackupProgressInfo WithBytesBackedUp(long bytesBackedUp) 34 | { 35 | return new BackupProgressInfo(PercentDone, bytesBackedUp); 36 | } 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /SimpleFileBackup.Core/Progress/IBackupProgress.cs: -------------------------------------------------------------------------------- 1 | using SimpleFileBackup.Core.Data; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Text; 5 | 6 | namespace SimpleFileBackup.Core.Progress 7 | { 8 | /// 9 | /// Extends with a for progress calculation. 10 | ///
11 | ///
12 | public interface IBackupProgress : IProgress 13 | { 14 | BackupMetadataInfo BackupMetadataInfo { get; } 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /SimpleFileBackup.Core/SimpleFileBackup.Core.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | netstandard2.0 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /SimpleFileBackup.Core/Util/BackupProgressHelper.cs: -------------------------------------------------------------------------------- 1 | using SimpleFileBackup.Core.Data; 2 | using SimpleFileBackup.Core.Progress; 3 | using System; 4 | using System.Collections.Generic; 5 | using System.Text; 6 | 7 | namespace SimpleFileBackup.Core.Util 8 | { 9 | internal class BackupProgressHelper 10 | { 11 | private readonly BackupArguments backupArguments; 12 | private readonly BackupMetadataInfo metadataInfo; 13 | 14 | public BackupProgressHelper(BackupArguments backupArguments, BackupMetadataInfo metadataInfo) 15 | { 16 | this.backupArguments = backupArguments ?? throw new ArgumentNullException(nameof(backupArguments)); 17 | this.metadataInfo = metadataInfo ?? throw new ArgumentNullException(nameof(metadataInfo)); 18 | } 19 | 20 | public BackupProgressInfo CurrentProgress { get; private set; } = new BackupProgressInfo(0, 0); 21 | 22 | /// 23 | /// Gets a new increased by the progress depending on the file size of the and the 24 | /// count of output directories in . 25 | /// 26 | /// 27 | /// 28 | public BackupProgressInfo AddProgressByFile(string inputFile) 29 | { 30 | metadataInfo.FileSizes.TryGetValue(inputFile, out long fileSize); 31 | 32 | // (1 for each file + size) / ((sizesum + filecount) * output location count) 33 | double percentIncrease = (1 + fileSize) / (double)((metadataInfo.FileSizeSum + backupArguments.InputFiles.Count) * backupArguments.OutputDirs.Count); 34 | 35 | var newProgress = new BackupProgressInfo( 36 | percentDone: Math.Min(1, CurrentProgress.PercentDone + percentIncrease), // prevent going over 1 37 | bytesBackedUp: CurrentProgress.BytesBackedUp + fileSize); 38 | 39 | return CurrentProgress = newProgress; 40 | } 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /SimpleFileBackup.Core/Util/DirectoryHelper.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.IO; 4 | using System.Text; 5 | using System.Xml.Linq; 6 | 7 | namespace SimpleFileBackup.Core.Util 8 | { 9 | internal static class DirectoryHelper 10 | { 11 | /// 12 | /// Get the full size and count of files of a directory and all of its subfolders recursively. 13 | /// 14 | /// 15 | /// 16 | public static (long Size, long Count) GetRecursiveDirectorySize(DirectoryInfo d) 17 | { 18 | long size = 0, count = 0; 19 | // Add directory file sizes. 20 | foreach (FileInfo fi in d.GetFiles()) 21 | { 22 | size += fi.Length; 23 | count++; 24 | } 25 | 26 | // Add subdirectory sizes. 27 | foreach (DirectoryInfo di in d.GetDirectories()) 28 | { 29 | var (s, c) = GetRecursiveDirectorySize(di); 30 | count += c; 31 | size += s; 32 | } 33 | 34 | return (size, count); 35 | } 36 | 37 | /// 38 | /// Copies all files and subfolders of source into target, keeping the file structure. 39 | /// 40 | /// 41 | /// 42 | /// 43 | public static void CopyFilesRecursively(DirectoryInfo source, DirectoryInfo target, bool overwriteExisting) 44 | { 45 | foreach (DirectoryInfo dir in source.GetDirectories()) 46 | { 47 | CopyFilesRecursively(dir, target.CreateSubdirectory(dir.Name), overwriteExisting); 48 | } 49 | 50 | // Keep input folder structure 51 | var outputDir = Path.Combine(target.FullName, source.Name); 52 | Directory.CreateDirectory(outputDir); 53 | 54 | foreach (FileInfo file in source.GetFiles()) 55 | { 56 | file.CopyTo(Path.Combine(outputDir, file.Name), overwriteExisting); 57 | } 58 | } 59 | 60 | /// 61 | /// Copies a file or a whole directory recursively into . 62 | /// May throw exceptions from IO access. 63 | /// 64 | /// 65 | /// 66 | /// 67 | public static void CopyFileOrDirectory(string inputFile, string outputDir, bool overwriteExisting) 68 | { 69 | if (Directory.Exists(inputFile)) 70 | { 71 | CopyFilesRecursively(new DirectoryInfo(inputFile), new DirectoryInfo(outputDir), overwriteExisting); 72 | } 73 | else // Should be file, throws exception when does not exist. 74 | { 75 | string fileName = Path.GetFileName(inputFile); 76 | File.Copy(inputFile, Path.Combine(outputDir, fileName), overwriteExisting); 77 | } 78 | } 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /SimpleFileBackup.Core/Util/ZipArchiveExtensions.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.IO.Compression; 4 | using System.IO; 5 | using System.Text; 6 | using System.Linq; 7 | 8 | namespace SimpleFileBackup.Core.Util 9 | { 10 | // https://stackoverflow.com/a/51514527 11 | public static class ZipArchiveExtensions 12 | { 13 | /// 14 | /// Creates a new entry in the zip either from a file or directory. 15 | /// 16 | /// 17 | /// 18 | /// 19 | public static void CreateEntryFromAny(this ZipArchive archive, string sourceName, string pathPrefix = "") 20 | { 21 | var fileName = Path.GetFileName(sourceName); 22 | if (File.GetAttributes(sourceName).HasFlag(FileAttributes.Directory)) 23 | { 24 | archive.CreateEntryFromDirectory(sourceName, Path.Combine(pathPrefix, fileName)); 25 | } 26 | else 27 | { 28 | archive.CreateEntryFromFile(sourceName, Path.Combine(pathPrefix, fileName), CompressionLevel.Fastest); 29 | } 30 | } 31 | 32 | /// 33 | /// Creates a new entry in the zip keeping the structure of the input directory. 34 | /// 35 | /// 36 | /// 37 | /// 38 | public static void CreateEntryFromDirectory(this ZipArchive archive, string sourceDirName, string pathPrefix = "") 39 | { 40 | string[] files = Directory.GetFiles(sourceDirName).Concat(Directory.GetDirectories(sourceDirName)).ToArray(); 41 | 42 | foreach (var file in files) 43 | { 44 | archive.CreateEntryFromAny(file, pathPrefix); 45 | } 46 | } 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /SimpleFileBackup.Core/Writers/BaseBackupWriter.cs: -------------------------------------------------------------------------------- 1 | using SimpleFileBackup.Core.Data; 2 | using SimpleFileBackup.Core.Progress; 3 | using SimpleFileBackup.Core.Util; 4 | using System; 5 | using System.Collections.Generic; 6 | using System.Diagnostics; 7 | using System.IO; 8 | using System.Linq; 9 | using System.Text; 10 | using System.Threading; 11 | using System.Threading.Tasks; 12 | 13 | namespace SimpleFileBackup.Core.Writers 14 | { 15 | /// 16 | /// Sets up the base arguments for a BackupWriter and routes ExecuteAsync overloads with default parameters. 17 | /// 18 | internal abstract class BaseBackupWriter : IBackupWriter 19 | { 20 | protected readonly BackupArguments backupArgs; 21 | 22 | internal BaseBackupWriter(BackupArguments backupArguments) 23 | { 24 | this.backupArgs = backupArguments; 25 | } 26 | 27 | /// 28 | /// Performs the backup with provided arguments. 29 | /// 30 | /// 31 | /// 32 | public abstract Task PerformBackup(CancellationToken cancellationToken = default, IBackupProgress progress = null); 33 | 34 | #region ExecuteAsync overloads, argument check 35 | 36 | public async Task ExecuteAsync(CancellationToken cancellationToken, IBackupProgress progress) 37 | { 38 | if (progress is null) 39 | { 40 | throw new ArgumentNullException(nameof(progress)); 41 | } 42 | 43 | if (progress is null) 44 | { 45 | throw new ArgumentNullException(nameof(progress)); 46 | } 47 | 48 | await PerformBackup(cancellationToken, progress); 49 | } 50 | 51 | public async Task ExecuteAsync(CancellationToken cancellationToken) 52 | { 53 | await PerformBackup(cancellationToken); 54 | } 55 | 56 | public async Task ExecuteAsync(IBackupProgress progress) 57 | { 58 | if (progress is null) 59 | { 60 | throw new ArgumentNullException(nameof(progress)); 61 | } 62 | 63 | await PerformBackup(progress: progress); 64 | } 65 | 66 | public async Task ExecuteAsync() 67 | { 68 | await PerformBackup(); 69 | } 70 | 71 | #endregion 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /SimpleFileBackup.Core/Writers/CopyFileBackupWriter.cs: -------------------------------------------------------------------------------- 1 | using SimpleFileBackup.Core.Data; 2 | using SimpleFileBackup.Core.Progress; 3 | using SimpleFileBackup.Core.Util; 4 | using System; 5 | using System.Collections.Generic; 6 | using System.Diagnostics; 7 | using System.IO; 8 | using System.Linq; 9 | using System.Text; 10 | using System.Threading; 11 | using System.Threading.Tasks; 12 | 13 | namespace SimpleFileBackup.Core.Writers 14 | { 15 | /// 16 | /// Writer that copies files from locations into other locations. 17 | /// 18 | internal class CopyFileBackupWriter : BaseBackupWriter 19 | { 20 | public CopyFileBackupWriter(BackupArguments backupArguments) : base(backupArguments) 21 | { 22 | } 23 | 24 | public override Task PerformBackup(CancellationToken cancellationToken = default, IBackupProgress progress = null) 25 | { 26 | BackupProgressHelper progressHelper = progress == null ? null : new BackupProgressHelper(backupArgs, progress.BackupMetadataInfo); 27 | 28 | return Task.Run(() => 29 | { 30 | // Copy each file into each dir 31 | foreach (var outputDir in backupArgs.OutputDirs) 32 | { 33 | foreach (var inputFile in backupArgs.InputFiles) 34 | { 35 | cancellationToken.ThrowIfCancellationRequested(); 36 | Directory.CreateDirectory(outputDir); 37 | DirectoryHelper.CopyFileOrDirectory(inputFile, outputDir, backupArgs.OverwriteExisting); 38 | progress?.Report(progressHelper.AddProgressByFile(inputFile)); 39 | } 40 | } 41 | }, cancellationToken); 42 | } 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /SimpleFileBackup.Core/Writers/NamedBackupWriter.cs: -------------------------------------------------------------------------------- 1 | using SimpleFileBackup.Core.Data; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Text; 5 | 6 | namespace SimpleFileBackup.Core.Writers 7 | { 8 | /// 9 | /// Base class for backup writers that allow setting a name with optional date suffix. 10 | /// 11 | internal abstract class NamedBackupWriter : BaseBackupWriter 12 | { 13 | protected readonly string backupName; 14 | 15 | public NamedBackupWriter(BackupArguments backupArguments, string backupName, DateTime dateSuffix, string dateFormat) : this(backupArguments, backupName) 16 | { 17 | this.backupName = dateSuffix != null ? $"{backupName}_{dateSuffix.ToString(dateFormat)}" : backupName; 18 | } 19 | 20 | public NamedBackupWriter(BackupArguments backupArguments, string backupName) : base(backupArguments) 21 | { 22 | if (string.IsNullOrWhiteSpace(backupName)) 23 | { 24 | throw new ArgumentException($"'{nameof(backupName)}' cannot be null or whitespace.", nameof(backupName)); 25 | } 26 | 27 | this.backupName = backupName; 28 | } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /SimpleFileBackup.Core/Writers/SubfolderCopyBackupWriter.cs: -------------------------------------------------------------------------------- 1 | using SimpleFileBackup.Core.Data; 2 | using SimpleFileBackup.Core.Progress; 3 | using SimpleFileBackup.Core.Util; 4 | using System; 5 | using System.Collections.Generic; 6 | using System.IO; 7 | using System.Text; 8 | using System.Threading; 9 | using System.Threading.Tasks; 10 | 11 | namespace SimpleFileBackup.Core.Writers 12 | { 13 | internal class SubfolderCopyBackupWriter : NamedBackupWriter 14 | { 15 | public SubfolderCopyBackupWriter(BackupArguments backupArguments, string subfolderName, DateTime dateSuffix, string dateFormat) 16 | : base(backupArguments, subfolderName, dateSuffix, dateFormat) 17 | { 18 | } 19 | 20 | public SubfolderCopyBackupWriter(BackupArguments backupArguments, string subfolderName) 21 | : base(backupArguments, subfolderName) 22 | { 23 | } 24 | 25 | public override Task PerformBackup(CancellationToken cancellationToken = default, IBackupProgress progress = null) 26 | { 27 | BackupProgressHelper progressHelper = progress == null ? null : new BackupProgressHelper(backupArgs, progress.BackupMetadataInfo); 28 | 29 | return Task.Run(() => 30 | { 31 | // Copy each file into each dir, create new subdir 32 | foreach (var outputDir in backupArgs.OutputDirs) 33 | { 34 | var outputSubDir = Directory.CreateDirectory(Path.Combine(outputDir, backupName)); 35 | 36 | foreach (var inputFile in backupArgs.InputFiles) 37 | { 38 | cancellationToken.ThrowIfCancellationRequested(); 39 | DirectoryHelper.CopyFileOrDirectory(inputFile, outputSubDir.FullName, backupArgs.OverwriteExisting); 40 | progress?.Report(progressHelper.AddProgressByFile(inputFile)); 41 | } 42 | } 43 | }, cancellationToken); 44 | } 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /SimpleFileBackup.Core/Writers/ZipBackupWriter.cs: -------------------------------------------------------------------------------- 1 | using SimpleFileBackup.Core.Data; 2 | using SimpleFileBackup.Core.Progress; 3 | using SimpleFileBackup.Core.Util; 4 | using System; 5 | using System.Collections.Generic; 6 | using System.IO; 7 | using System.IO.Compression; 8 | using System.Runtime.InteropServices.ComTypes; 9 | using System.Text; 10 | using System.Threading; 11 | using System.Threading.Tasks; 12 | 13 | namespace SimpleFileBackup.Core.Writers 14 | { 15 | internal class ZipBackupWriter : NamedBackupWriter 16 | { 17 | public ZipBackupWriter(BackupArguments backupArguments, string fileName, DateTime dateSuffix, string dateFormat) 18 | : base(backupArguments, fileName, dateSuffix, dateFormat) 19 | { 20 | } 21 | 22 | public ZipBackupWriter(BackupArguments backupArguments, string fileName) 23 | : base(backupArguments, fileName) 24 | { 25 | } 26 | 27 | public override Task PerformBackup(CancellationToken cancellationToken = default, IBackupProgress progress = null) 28 | { 29 | return Task.Run(() => 30 | { 31 | var outputDirs = backupArgs.OutputDirs.GetEnumerator(); 32 | if (!outputDirs.MoveNext()) return; 33 | 34 | Directory.CreateDirectory(outputDirs.Current); 35 | string originZip = CreateZipFromArguments(outputDirs.Current, cancellationToken, progress); 36 | long dirCount = 1; 37 | long zipSize = new FileInfo(originZip).Length; 38 | progress?.Report(new BackupProgressInfo(dirCount / (double)backupArgs.OutputDirs.Count, zipSize)); 39 | 40 | // Copy the zip into other outputs 41 | while (outputDirs.MoveNext()) 42 | { 43 | cancellationToken.ThrowIfCancellationRequested(); 44 | Directory.CreateDirectory(outputDirs.Current); 45 | File.Copy(originZip, Path.Combine(outputDirs.Current, backupName + ".zip"), backupArgs.OverwriteExisting); 46 | 47 | dirCount++; 48 | progress?.Report(new BackupProgressInfo(dirCount / (double)backupArgs.OutputDirs.Count, zipSize * dirCount)); 49 | } 50 | }, cancellationToken); 51 | } 52 | 53 | /// 54 | /// Creates a new zip archive with all input files from . Deletes existing file first if overwrite existing is enabled. 55 | /// 56 | /// 57 | /// 58 | /// Path to the new zip file. 59 | private string CreateZipFromArguments(string location, CancellationToken cancellationToken, IBackupProgress progress = null) 60 | { 61 | BackupProgressHelper progressHelper = progress == null ? null : new BackupProgressHelper(backupArgs, progress.BackupMetadataInfo); 62 | cancellationToken.ThrowIfCancellationRequested(); 63 | 64 | // Create zip in first backup dir, delete first if exists 65 | var fileLocation = Path.Combine(location, backupName + ".zip"); 66 | if (backupArgs.OverwriteExisting) 67 | { 68 | File.Delete(fileLocation); 69 | } 70 | 71 | // Add all input files and directories to zip 72 | using (var zipFile = ZipFile.Open(fileLocation, ZipArchiveMode.Create)) 73 | { 74 | foreach (var inputFile in backupArgs.InputFiles) 75 | { 76 | zipFile.CreateEntryFromAny(inputFile); 77 | if (progressHelper != null) 78 | { 79 | // While creating zip bytesBackedUp will stay 0 80 | progress?.Report(progressHelper.AddProgressByFile(inputFile).WithBytesBackedUp(0)); 81 | } 82 | progress?.Report(progressHelper.CurrentProgress); 83 | cancellationToken.ThrowIfCancellationRequested(); 84 | } 85 | } 86 | 87 | return fileLocation; 88 | } 89 | } 90 | } 91 | -------------------------------------------------------------------------------- /SimpleFileBackup.Windows/App.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 |
6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 0 15 | 16 | 17 | 18 | 19 | 20 | False 21 | 22 | 23 | False 24 | 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /SimpleFileBackup.Windows/BackupMode.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace SimpleFileBackup.Windows 8 | { 9 | internal enum BackupMode 10 | { 11 | Copy, 12 | Subfolder, 13 | Zip 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /SimpleFileBackup.Windows/FormAbout.Designer.cs: -------------------------------------------------------------------------------- 1 | namespace SimpleFileBackup.Windows 2 | { 3 | partial class FormAbout 4 | { 5 | /// 6 | /// Required designer variable. 7 | /// 8 | private System.ComponentModel.IContainer components = null; 9 | 10 | /// 11 | /// Clean up any resources being used. 12 | /// 13 | /// true if managed resources should be disposed; otherwise, false. 14 | protected override void Dispose(bool disposing) 15 | { 16 | if (disposing && (components != null)) 17 | { 18 | components.Dispose(); 19 | } 20 | base.Dispose(disposing); 21 | } 22 | 23 | #region Windows Form Designer generated code 24 | 25 | /// 26 | /// Required method for Designer support - do not modify 27 | /// the contents of this method with the code editor. 28 | /// 29 | private void InitializeComponent() 30 | { 31 | this.webBrowser = new System.Windows.Forms.WebBrowser(); 32 | this.SuspendLayout(); 33 | // 34 | // webBrowser 35 | // 36 | this.webBrowser.AllowNavigation = false; 37 | this.webBrowser.Dock = System.Windows.Forms.DockStyle.Fill; 38 | this.webBrowser.Location = new System.Drawing.Point(0, 0); 39 | this.webBrowser.MinimumSize = new System.Drawing.Size(20, 20); 40 | this.webBrowser.Name = "webBrowser"; 41 | this.webBrowser.Size = new System.Drawing.Size(333, 455); 42 | this.webBrowser.TabIndex = 0; 43 | // 44 | // FormAbout 45 | // 46 | this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); 47 | this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; 48 | this.ClientSize = new System.Drawing.Size(333, 455); 49 | this.Controls.Add(this.webBrowser); 50 | this.MaximizeBox = false; 51 | this.MinimizeBox = false; 52 | this.Name = "FormAbout"; 53 | this.ShowIcon = false; 54 | this.Text = "About"; 55 | this.Load += new System.EventHandler(this.FormAbout_Load); 56 | this.ResumeLayout(false); 57 | 58 | } 59 | 60 | #endregion 61 | private System.Windows.Forms.WebBrowser webBrowser; 62 | } 63 | } -------------------------------------------------------------------------------- /SimpleFileBackup.Windows/FormAbout.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.ComponentModel; 4 | using System.Data; 5 | using System.Drawing; 6 | using System.Linq; 7 | using System.Text; 8 | using System.Threading.Tasks; 9 | using System.Windows.Forms; 10 | 11 | namespace SimpleFileBackup.Windows 12 | { 13 | public partial class FormAbout : Form 14 | { 15 | public FormAbout() 16 | { 17 | InitializeComponent(); 18 | } 19 | 20 | private void FormAbout_Load(object sender, EventArgs e) 21 | { 22 | string html = Properties.Resources.about; 23 | webBrowser.DocumentText = html; 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /SimpleFileBackup.Windows/FormAbout.resx: -------------------------------------------------------------------------------- 1 |  2 | 3 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | text/microsoft-resx 110 | 111 | 112 | 2.0 113 | 114 | 115 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 116 | 117 | 118 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 119 | 120 | -------------------------------------------------------------------------------- /SimpleFileBackup.Windows/FormMain.Designer.cs: -------------------------------------------------------------------------------- 1 | namespace SimpleFileBackup.Windows 2 | { 3 | partial class FormMain 4 | { 5 | /// 6 | /// Required designer variable. 7 | /// 8 | private System.ComponentModel.IContainer components = null; 9 | 10 | /// 11 | /// Clean up any resources being used. 12 | /// 13 | /// true if managed resources should be disposed; otherwise, false. 14 | protected override void Dispose(bool disposing) 15 | { 16 | if (disposing && (components != null)) 17 | { 18 | components.Dispose(); 19 | } 20 | base.Dispose(disposing); 21 | } 22 | 23 | #region Windows Form Designer generated code 24 | 25 | /// 26 | /// Required method for Designer support - do not modify 27 | /// the contents of this method with the code editor. 28 | /// 29 | private void InitializeComponent() 30 | { 31 | System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(FormMain)); 32 | this.buttonFilestobackup = new System.Windows.Forms.Button(); 33 | this.labelFilesBackup = new System.Windows.Forms.Label(); 34 | this.labelBackup = new System.Windows.Forms.Label(); 35 | this.buttonBackupLocationsBrowse = new System.Windows.Forms.Button(); 36 | this.buttonOK = new System.Windows.Forms.Button(); 37 | this.labelInfotext = new System.Windows.Forms.Label(); 38 | this.comboBoxFilestobackup = new System.Windows.Forms.ComboBox(); 39 | this.buttonFilestobackupClear = new System.Windows.Forms.Button(); 40 | this.buttonFilestobackupDeleteitem = new System.Windows.Forms.Button(); 41 | this.comboBoxBackupLocations = new System.Windows.Forms.ComboBox(); 42 | this.buttonBackupLocationsDeleteItem = new System.Windows.Forms.Button(); 43 | this.buttonBackupLocationsClear = new System.Windows.Forms.Button(); 44 | this.menuStrip = new System.Windows.Forms.MenuStrip(); 45 | this.fileToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); 46 | this.saveDefaultsToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); 47 | this.saveCustomFilePathsToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); 48 | this.saveCustomBackupPathsToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); 49 | this.openFilePathsToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); 50 | this.openBackupPathsToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); 51 | this.aboutToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); 52 | this.groupBoxSettings = new System.Windows.Forms.GroupBox(); 53 | this.radioButtonNormal = new System.Windows.Forms.RadioButton(); 54 | this.radioButtonZIP = new System.Windows.Forms.RadioButton(); 55 | this.radioButtonFolder = new System.Windows.Forms.RadioButton(); 56 | this.textBoxName = new System.Windows.Forms.TextBox(); 57 | this.checkBoxDate = new System.Windows.Forms.CheckBox(); 58 | this.progressBarMain = new System.Windows.Forms.ProgressBar(); 59 | this.checkBoxOverride = new System.Windows.Forms.CheckBox(); 60 | this.buttonFolderstobackup = new System.Windows.Forms.Button(); 61 | this.buttonCancel = new System.Windows.Forms.Button(); 62 | this.labelProgress = new System.Windows.Forms.Label(); 63 | this.menuStrip.SuspendLayout(); 64 | this.groupBoxSettings.SuspendLayout(); 65 | this.SuspendLayout(); 66 | // 67 | // buttonFilestobackup 68 | // 69 | this.buttonFilestobackup.Location = new System.Drawing.Point(376, 60); 70 | this.buttonFilestobackup.Name = "buttonFilestobackup"; 71 | this.buttonFilestobackup.Size = new System.Drawing.Size(90, 20); 72 | this.buttonFilestobackup.TabIndex = 2; 73 | this.buttonFilestobackup.Text = "Select Files"; 74 | this.buttonFilestobackup.UseVisualStyleBackColor = true; 75 | this.buttonFilestobackup.Click += new System.EventHandler(this.ButtonFilestobackup_Click); 76 | // 77 | // labelFilesBackup 78 | // 79 | this.labelFilesBackup.AutoSize = true; 80 | this.labelFilesBackup.Location = new System.Drawing.Point(12, 44); 81 | this.labelFilesBackup.Name = "labelFilesBackup"; 82 | this.labelFilesBackup.Size = new System.Drawing.Size(80, 13); 83 | this.labelFilesBackup.TabIndex = 0; 84 | this.labelFilesBackup.Text = "Files to Backup"; 85 | // 86 | // labelBackup 87 | // 88 | this.labelBackup.AutoSize = true; 89 | this.labelBackup.Location = new System.Drawing.Point(12, 135); 90 | this.labelBackup.Name = "labelBackup"; 91 | this.labelBackup.Size = new System.Drawing.Size(105, 13); 92 | this.labelBackup.TabIndex = 6; 93 | this.labelBackup.Text = "Backup Destinations"; 94 | // 95 | // buttonBackupLocationsBrowse 96 | // 97 | this.buttonBackupLocationsBrowse.Location = new System.Drawing.Point(376, 151); 98 | this.buttonBackupLocationsBrowse.Name = "buttonBackupLocationsBrowse"; 99 | this.buttonBackupLocationsBrowse.Size = new System.Drawing.Size(90, 20); 100 | this.buttonBackupLocationsBrowse.TabIndex = 8; 101 | this.buttonBackupLocationsBrowse.Text = "Select Folders"; 102 | this.buttonBackupLocationsBrowse.UseVisualStyleBackColor = true; 103 | this.buttonBackupLocationsBrowse.Click += new System.EventHandler(this.ButtonBackupBrowse_Click); 104 | // 105 | // buttonOK 106 | // 107 | this.buttonOK.Location = new System.Drawing.Point(15, 360); 108 | this.buttonOK.Name = "buttonOK"; 109 | this.buttonOK.Size = new System.Drawing.Size(448, 44); 110 | this.buttonOK.TabIndex = 19; 111 | this.buttonOK.Text = "Backup"; 112 | this.buttonOK.UseVisualStyleBackColor = true; 113 | this.buttonOK.Click += new System.EventHandler(this.ButtonOK_Click); 114 | // 115 | // labelInfotext 116 | // 117 | this.labelInfotext.AutoEllipsis = true; 118 | this.labelInfotext.Font = new System.Drawing.Font("Microsoft Sans Serif", 8.25F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0))); 119 | this.labelInfotext.Location = new System.Drawing.Point(239, 221); 120 | this.labelInfotext.Name = "labelInfotext"; 121 | this.labelInfotext.Size = new System.Drawing.Size(224, 65); 122 | this.labelInfotext.TabIndex = 19; 123 | this.labelInfotext.TextAlign = System.Drawing.ContentAlignment.MiddleCenter; 124 | this.labelInfotext.Visible = false; 125 | // 126 | // comboBoxFilestobackup 127 | // 128 | this.comboBoxFilestobackup.FormattingEnabled = true; 129 | this.comboBoxFilestobackup.Location = new System.Drawing.Point(15, 61); 130 | this.comboBoxFilestobackup.Name = "comboBoxFilestobackup"; 131 | this.comboBoxFilestobackup.Size = new System.Drawing.Size(355, 21); 132 | this.comboBoxFilestobackup.TabIndex = 1; 133 | this.comboBoxFilestobackup.KeyDown += new System.Windows.Forms.KeyEventHandler(this.ComboBoxFilestobackup_KeyDown); 134 | // 135 | // buttonFilestobackupClear 136 | // 137 | this.buttonFilestobackupClear.Location = new System.Drawing.Point(376, 98); 138 | this.buttonFilestobackupClear.Name = "buttonFilestobackupClear"; 139 | this.buttonFilestobackupClear.Size = new System.Drawing.Size(90, 20); 140 | this.buttonFilestobackupClear.TabIndex = 4; 141 | this.buttonFilestobackupClear.Text = "Clear List"; 142 | this.buttonFilestobackupClear.UseVisualStyleBackColor = true; 143 | this.buttonFilestobackupClear.Click += new System.EventHandler(this.ButtonFilestobackupClear_Click); 144 | // 145 | // buttonFilestobackupDeleteitem 146 | // 147 | this.buttonFilestobackupDeleteitem.Location = new System.Drawing.Point(376, 117); 148 | this.buttonFilestobackupDeleteitem.Name = "buttonFilestobackupDeleteitem"; 149 | this.buttonFilestobackupDeleteitem.Size = new System.Drawing.Size(90, 20); 150 | this.buttonFilestobackupDeleteitem.TabIndex = 5; 151 | this.buttonFilestobackupDeleteitem.Text = "Delete Item"; 152 | this.buttonFilestobackupDeleteitem.UseVisualStyleBackColor = true; 153 | this.buttonFilestobackupDeleteitem.Click += new System.EventHandler(this.ButtonFilestobackupDeleteitem_Click); 154 | // 155 | // comboBoxBackupLocations 156 | // 157 | this.comboBoxBackupLocations.FormattingEnabled = true; 158 | this.comboBoxBackupLocations.Location = new System.Drawing.Point(15, 152); 159 | this.comboBoxBackupLocations.Name = "comboBoxBackupLocations"; 160 | this.comboBoxBackupLocations.Size = new System.Drawing.Size(355, 21); 161 | this.comboBoxBackupLocations.TabIndex = 7; 162 | this.comboBoxBackupLocations.KeyDown += new System.Windows.Forms.KeyEventHandler(this.ComboBoxBackupLocations_KeyDown); 163 | // 164 | // buttonBackupLocationsDeleteItem 165 | // 166 | this.buttonBackupLocationsDeleteItem.Location = new System.Drawing.Point(376, 189); 167 | this.buttonBackupLocationsDeleteItem.Name = "buttonBackupLocationsDeleteItem"; 168 | this.buttonBackupLocationsDeleteItem.Size = new System.Drawing.Size(90, 20); 169 | this.buttonBackupLocationsDeleteItem.TabIndex = 10; 170 | this.buttonBackupLocationsDeleteItem.Text = "Delete Item"; 171 | this.buttonBackupLocationsDeleteItem.UseVisualStyleBackColor = true; 172 | this.buttonBackupLocationsDeleteItem.Click += new System.EventHandler(this.ButtonBackupLocationsDeleteItem_Click); 173 | // 174 | // buttonBackupLocationsClear 175 | // 176 | this.buttonBackupLocationsClear.Location = new System.Drawing.Point(376, 170); 177 | this.buttonBackupLocationsClear.Name = "buttonBackupLocationsClear"; 178 | this.buttonBackupLocationsClear.Size = new System.Drawing.Size(90, 20); 179 | this.buttonBackupLocationsClear.TabIndex = 9; 180 | this.buttonBackupLocationsClear.Text = "Clear List"; 181 | this.buttonBackupLocationsClear.UseVisualStyleBackColor = true; 182 | this.buttonBackupLocationsClear.Click += new System.EventHandler(this.ButtonBackupLocationsClear_Click); 183 | // 184 | // menuStrip 185 | // 186 | this.menuStrip.BackColor = System.Drawing.SystemColors.ControlLight; 187 | this.menuStrip.Items.AddRange(new System.Windows.Forms.ToolStripItem[] { 188 | this.fileToolStripMenuItem, 189 | this.aboutToolStripMenuItem}); 190 | this.menuStrip.Location = new System.Drawing.Point(0, 0); 191 | this.menuStrip.Name = "menuStrip"; 192 | this.menuStrip.Size = new System.Drawing.Size(479, 24); 193 | this.menuStrip.TabIndex = 23; 194 | this.menuStrip.Text = "menuStrip1"; 195 | // 196 | // fileToolStripMenuItem 197 | // 198 | this.fileToolStripMenuItem.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] { 199 | this.saveDefaultsToolStripMenuItem, 200 | this.saveCustomFilePathsToolStripMenuItem, 201 | this.saveCustomBackupPathsToolStripMenuItem, 202 | this.openFilePathsToolStripMenuItem, 203 | this.openBackupPathsToolStripMenuItem}); 204 | this.fileToolStripMenuItem.Name = "fileToolStripMenuItem"; 205 | this.fileToolStripMenuItem.Size = new System.Drawing.Size(37, 20); 206 | this.fileToolStripMenuItem.Text = "File"; 207 | // 208 | // saveDefaultsToolStripMenuItem 209 | // 210 | this.saveDefaultsToolStripMenuItem.Name = "saveDefaultsToolStripMenuItem"; 211 | this.saveDefaultsToolStripMenuItem.ShortcutKeys = ((System.Windows.Forms.Keys)((System.Windows.Forms.Keys.Control | System.Windows.Forms.Keys.S))); 212 | this.saveDefaultsToolStripMenuItem.Size = new System.Drawing.Size(258, 22); 213 | this.saveDefaultsToolStripMenuItem.Text = "Save Defaults"; 214 | this.saveDefaultsToolStripMenuItem.Click += new System.EventHandler(this.SaveDefaultsToolStripMenuItem_Click); 215 | // 216 | // saveCustomFilePathsToolStripMenuItem 217 | // 218 | this.saveCustomFilePathsToolStripMenuItem.Name = "saveCustomFilePathsToolStripMenuItem"; 219 | this.saveCustomFilePathsToolStripMenuItem.ShortcutKeys = ((System.Windows.Forms.Keys)((System.Windows.Forms.Keys.Control | System.Windows.Forms.Keys.F))); 220 | this.saveCustomFilePathsToolStripMenuItem.Size = new System.Drawing.Size(258, 22); 221 | this.saveCustomFilePathsToolStripMenuItem.Text = "Save Custom File Paths"; 222 | this.saveCustomFilePathsToolStripMenuItem.Click += new System.EventHandler(this.SaveCustomFilePathsToolStripMenuItem_Click); 223 | // 224 | // saveCustomBackupPathsToolStripMenuItem 225 | // 226 | this.saveCustomBackupPathsToolStripMenuItem.Name = "saveCustomBackupPathsToolStripMenuItem"; 227 | this.saveCustomBackupPathsToolStripMenuItem.ShortcutKeys = ((System.Windows.Forms.Keys)((System.Windows.Forms.Keys.Control | System.Windows.Forms.Keys.B))); 228 | this.saveCustomBackupPathsToolStripMenuItem.Size = new System.Drawing.Size(258, 22); 229 | this.saveCustomBackupPathsToolStripMenuItem.Text = "Save Custom Backup Paths"; 230 | this.saveCustomBackupPathsToolStripMenuItem.Click += new System.EventHandler(this.SaveCustomBackupPathsToolStripMenuItem_Click); 231 | // 232 | // openFilePathsToolStripMenuItem 233 | // 234 | this.openFilePathsToolStripMenuItem.Name = "openFilePathsToolStripMenuItem"; 235 | this.openFilePathsToolStripMenuItem.ShortcutKeys = ((System.Windows.Forms.Keys)((System.Windows.Forms.Keys.Control | System.Windows.Forms.Keys.O))); 236 | this.openFilePathsToolStripMenuItem.Size = new System.Drawing.Size(258, 22); 237 | this.openFilePathsToolStripMenuItem.Text = "Open File Paths"; 238 | this.openFilePathsToolStripMenuItem.Click += new System.EventHandler(this.OpenPaths_Click); 239 | // 240 | // openBackupPathsToolStripMenuItem 241 | // 242 | this.openBackupPathsToolStripMenuItem.Name = "openBackupPathsToolStripMenuItem"; 243 | this.openBackupPathsToolStripMenuItem.ShortcutKeys = ((System.Windows.Forms.Keys)(((System.Windows.Forms.Keys.Control | System.Windows.Forms.Keys.Shift) 244 | | System.Windows.Forms.Keys.O))); 245 | this.openBackupPathsToolStripMenuItem.Size = new System.Drawing.Size(258, 22); 246 | this.openBackupPathsToolStripMenuItem.Text = "Open Backup Paths"; 247 | this.openBackupPathsToolStripMenuItem.Click += new System.EventHandler(this.OpenPaths_Click); 248 | // 249 | // aboutToolStripMenuItem 250 | // 251 | this.aboutToolStripMenuItem.Name = "aboutToolStripMenuItem"; 252 | this.aboutToolStripMenuItem.Size = new System.Drawing.Size(52, 20); 253 | this.aboutToolStripMenuItem.Text = "About"; 254 | this.aboutToolStripMenuItem.Click += new System.EventHandler(this.AboutToolStripMenuItem_Click); 255 | // 256 | // groupBoxSettings 257 | // 258 | this.groupBoxSettings.Controls.Add(this.radioButtonNormal); 259 | this.groupBoxSettings.Controls.Add(this.radioButtonZIP); 260 | this.groupBoxSettings.Controls.Add(this.radioButtonFolder); 261 | this.groupBoxSettings.Controls.Add(this.textBoxName); 262 | this.groupBoxSettings.Controls.Add(this.checkBoxDate); 263 | this.groupBoxSettings.Location = new System.Drawing.Point(18, 221); 264 | this.groupBoxSettings.Name = "groupBoxSettings"; 265 | this.groupBoxSettings.Size = new System.Drawing.Size(215, 133); 266 | this.groupBoxSettings.TabIndex = 12; 267 | this.groupBoxSettings.TabStop = false; 268 | this.groupBoxSettings.Text = "Settings"; 269 | // 270 | // radioButtonNormal 271 | // 272 | this.radioButtonNormal.AutoSize = true; 273 | this.radioButtonNormal.Checked = true; 274 | this.radioButtonNormal.Location = new System.Drawing.Point(6, 19); 275 | this.radioButtonNormal.Name = "radioButtonNormal"; 276 | this.radioButtonNormal.Size = new System.Drawing.Size(145, 17); 277 | this.radioButtonNormal.TabIndex = 13; 278 | this.radioButtonNormal.TabStop = true; 279 | this.radioButtonNormal.Text = "Put files in given directory"; 280 | this.radioButtonNormal.UseVisualStyleBackColor = true; 281 | this.radioButtonNormal.CheckedChanged += new System.EventHandler(this.RadioButtons_CheckedChanged); 282 | // 283 | // radioButtonZIP 284 | // 285 | this.radioButtonZIP.AutoSize = true; 286 | this.radioButtonZIP.Location = new System.Drawing.Point(6, 65); 287 | this.radioButtonZIP.Name = "radioButtonZIP"; 288 | this.radioButtonZIP.Size = new System.Drawing.Size(154, 17); 289 | this.radioButtonZIP.TabIndex = 15; 290 | this.radioButtonZIP.Text = "Create a .zip file in directory"; 291 | this.radioButtonZIP.UseVisualStyleBackColor = true; 292 | this.radioButtonZIP.CheckedChanged += new System.EventHandler(this.RadioButtons_CheckedChanged); 293 | // 294 | // radioButtonFolder 295 | // 296 | this.radioButtonFolder.AutoSize = true; 297 | this.radioButtonFolder.Location = new System.Drawing.Point(6, 42); 298 | this.radioButtonFolder.Name = "radioButtonFolder"; 299 | this.radioButtonFolder.Size = new System.Drawing.Size(165, 17); 300 | this.radioButtonFolder.TabIndex = 14; 301 | this.radioButtonFolder.Text = "Create a subfolder in directory"; 302 | this.radioButtonFolder.UseVisualStyleBackColor = true; 303 | this.radioButtonFolder.CheckedChanged += new System.EventHandler(this.RadioButtons_CheckedChanged); 304 | // 305 | // textBoxName 306 | // 307 | this.textBoxName.Enabled = false; 308 | this.textBoxName.Location = new System.Drawing.Point(6, 87); 309 | this.textBoxName.MaxLength = 20; 310 | this.textBoxName.Name = "textBoxName"; 311 | this.textBoxName.Size = new System.Drawing.Size(171, 20); 312 | this.textBoxName.TabIndex = 16; 313 | this.textBoxName.Text = "Name Folder/.zip"; 314 | this.textBoxName.Click += new System.EventHandler(this.TextBoxName_Click); 315 | this.textBoxName.PreviewKeyDown += new System.Windows.Forms.PreviewKeyDownEventHandler(this.TextBoxName_PreviewKeyDown); 316 | // 317 | // checkBoxDate 318 | // 319 | this.checkBoxDate.AutoSize = true; 320 | this.checkBoxDate.Enabled = false; 321 | this.checkBoxDate.Location = new System.Drawing.Point(6, 113); 322 | this.checkBoxDate.Name = "checkBoxDate"; 323 | this.checkBoxDate.Size = new System.Drawing.Size(163, 17); 324 | this.checkBoxDate.TabIndex = 17; 325 | this.checkBoxDate.Text = "Add date to Folder/.zip name"; 326 | this.checkBoxDate.UseVisualStyleBackColor = true; 327 | // 328 | // progressBarMain 329 | // 330 | this.progressBarMain.Location = new System.Drawing.Point(239, 330); 331 | this.progressBarMain.Name = "progressBarMain"; 332 | this.progressBarMain.Size = new System.Drawing.Size(224, 24); 333 | this.progressBarMain.Style = System.Windows.Forms.ProgressBarStyle.Continuous; 334 | this.progressBarMain.TabIndex = 18; 335 | // 336 | // checkBoxOverride 337 | // 338 | this.checkBoxOverride.AutoSize = true; 339 | this.checkBoxOverride.Location = new System.Drawing.Point(15, 179); 340 | this.checkBoxOverride.Name = "checkBoxOverride"; 341 | this.checkBoxOverride.Size = new System.Drawing.Size(183, 17); 342 | this.checkBoxOverride.TabIndex = 11; 343 | this.checkBoxOverride.Text = "Override identical files in directory"; 344 | this.checkBoxOverride.UseVisualStyleBackColor = true; 345 | // 346 | // buttonFolderstobackup 347 | // 348 | this.buttonFolderstobackup.Location = new System.Drawing.Point(376, 79); 349 | this.buttonFolderstobackup.Name = "buttonFolderstobackup"; 350 | this.buttonFolderstobackup.Size = new System.Drawing.Size(90, 20); 351 | this.buttonFolderstobackup.TabIndex = 3; 352 | this.buttonFolderstobackup.Text = "Select Folders"; 353 | this.buttonFolderstobackup.UseVisualStyleBackColor = true; 354 | this.buttonFolderstobackup.Click += new System.EventHandler(this.ButtonFolderstobackup_Click); 355 | // 356 | // buttonCancel 357 | // 358 | this.buttonCancel.Location = new System.Drawing.Point(15, 360); 359 | this.buttonCancel.Name = "buttonCancel"; 360 | this.buttonCancel.Size = new System.Drawing.Size(448, 44); 361 | this.buttonCancel.TabIndex = 20; 362 | this.buttonCancel.Text = "Cancel"; 363 | this.buttonCancel.UseVisualStyleBackColor = true; 364 | this.buttonCancel.Visible = false; 365 | this.buttonCancel.Click += new System.EventHandler(this.ButtonCancel_Click); 366 | // 367 | // labelProgress 368 | // 369 | this.labelProgress.AutoEllipsis = true; 370 | this.labelProgress.Location = new System.Drawing.Point(239, 286); 371 | this.labelProgress.Name = "labelProgress"; 372 | this.labelProgress.Size = new System.Drawing.Size(224, 37); 373 | this.labelProgress.TabIndex = 22; 374 | this.labelProgress.TextAlign = System.Drawing.ContentAlignment.MiddleCenter; 375 | // 376 | // FormMain 377 | // 378 | this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); 379 | this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; 380 | this.BackColor = System.Drawing.SystemColors.Control; 381 | this.ClientSize = new System.Drawing.Size(479, 416); 382 | this.Controls.Add(this.labelProgress); 383 | this.Controls.Add(this.buttonCancel); 384 | this.Controls.Add(this.buttonFolderstobackup); 385 | this.Controls.Add(this.checkBoxOverride); 386 | this.Controls.Add(this.progressBarMain); 387 | this.Controls.Add(this.groupBoxSettings); 388 | this.Controls.Add(this.buttonBackupLocationsDeleteItem); 389 | this.Controls.Add(this.buttonBackupLocationsClear); 390 | this.Controls.Add(this.comboBoxBackupLocations); 391 | this.Controls.Add(this.buttonFilestobackupDeleteitem); 392 | this.Controls.Add(this.buttonFilestobackupClear); 393 | this.Controls.Add(this.comboBoxFilestobackup); 394 | this.Controls.Add(this.labelInfotext); 395 | this.Controls.Add(this.buttonOK); 396 | this.Controls.Add(this.labelBackup); 397 | this.Controls.Add(this.buttonBackupLocationsBrowse); 398 | this.Controls.Add(this.labelFilesBackup); 399 | this.Controls.Add(this.buttonFilestobackup); 400 | this.Controls.Add(this.menuStrip); 401 | this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedSingle; 402 | this.Icon = ((System.Drawing.Icon)(resources.GetObject("$this.Icon"))); 403 | this.MainMenuStrip = this.menuStrip; 404 | this.MaximizeBox = false; 405 | this.Name = "FormMain"; 406 | this.ShowIcon = false; 407 | this.SizeGripStyle = System.Windows.Forms.SizeGripStyle.Hide; 408 | this.Text = "SimpleFileBackup"; 409 | this.Load += new System.EventHandler(this.FormMain_Load); 410 | this.menuStrip.ResumeLayout(false); 411 | this.menuStrip.PerformLayout(); 412 | this.groupBoxSettings.ResumeLayout(false); 413 | this.groupBoxSettings.PerformLayout(); 414 | this.ResumeLayout(false); 415 | this.PerformLayout(); 416 | 417 | } 418 | 419 | #endregion 420 | private System.Windows.Forms.Button buttonFilestobackup; 421 | private System.Windows.Forms.Label labelFilesBackup; 422 | private System.Windows.Forms.Label labelBackup; 423 | private System.Windows.Forms.Button buttonBackupLocationsBrowse; 424 | private System.Windows.Forms.Button buttonOK; 425 | private System.Windows.Forms.Label labelInfotext; 426 | private System.Windows.Forms.ComboBox comboBoxFilestobackup; 427 | private System.Windows.Forms.Button buttonFilestobackupClear; 428 | private System.Windows.Forms.Button buttonFilestobackupDeleteitem; 429 | private System.Windows.Forms.ComboBox comboBoxBackupLocations; 430 | private System.Windows.Forms.Button buttonBackupLocationsDeleteItem; 431 | private System.Windows.Forms.Button buttonBackupLocationsClear; 432 | private System.Windows.Forms.MenuStrip menuStrip; 433 | private System.Windows.Forms.ToolStripMenuItem aboutToolStripMenuItem; 434 | private System.Windows.Forms.GroupBox groupBoxSettings; 435 | private System.Windows.Forms.CheckBox checkBoxDate; 436 | private System.Windows.Forms.TextBox textBoxName; 437 | private System.Windows.Forms.ProgressBar progressBarMain; 438 | private System.Windows.Forms.RadioButton radioButtonZIP; 439 | private System.Windows.Forms.RadioButton radioButtonFolder; 440 | private System.Windows.Forms.RadioButton radioButtonNormal; 441 | private System.Windows.Forms.ToolStripMenuItem fileToolStripMenuItem; 442 | private System.Windows.Forms.CheckBox checkBoxOverride; 443 | private System.Windows.Forms.ToolStripMenuItem saveCustomFilePathsToolStripMenuItem; 444 | private System.Windows.Forms.ToolStripMenuItem saveCustomBackupPathsToolStripMenuItem; 445 | private System.Windows.Forms.ToolStripMenuItem openFilePathsToolStripMenuItem; 446 | private System.Windows.Forms.ToolStripMenuItem openBackupPathsToolStripMenuItem; 447 | private System.Windows.Forms.Button buttonFolderstobackup; 448 | private System.Windows.Forms.Button buttonCancel; 449 | private System.Windows.Forms.Label labelProgress; 450 | private System.Windows.Forms.ToolStripMenuItem saveDefaultsToolStripMenuItem; 451 | } 452 | } -------------------------------------------------------------------------------- /SimpleFileBackup.Windows/FormMain.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.ComponentModel; 4 | using System.Drawing; 5 | using System.Threading.Tasks; 6 | using System.Windows.Forms; 7 | using System.IO; 8 | using System.IO.Compression; 9 | using Microsoft.WindowsAPICodePack.Dialogs; 10 | using SimpleFileBackup.Core.Data; 11 | using SimpleFileBackup.Core; 12 | using SimpleFileBackup.Core.Progress; 13 | using System.Threading; 14 | using System.Security.Cryptography; 15 | using System.Linq; 16 | using System.Collections.Specialized; 17 | 18 | namespace SimpleFileBackup.Windows 19 | { 20 | /// 21 | /// Logic behind the SimpleFileBackup Windows Forms User Controls. 22 | /// 23 | public partial class FormMain : Form 24 | { 25 | public FormMain() 26 | { 27 | InitializeComponent(); 28 | } 29 | 30 | #region DisplayText 31 | 32 | private CancellationTokenSource displayCancellation = new CancellationTokenSource(); 33 | 34 | private async void DisplayText(string text, int ms, Color color) 35 | { 36 | if (text == labelInfotext.Text) 37 | { 38 | return; // If it's the same message don't display twice 39 | } 40 | 41 | displayCancellation?.Cancel(); // Cancel old message 42 | using (var currentTokenSource = new CancellationTokenSource()) 43 | { 44 | displayCancellation = currentTokenSource; 45 | labelInfotext.ForeColor = color; 46 | labelInfotext.Text = text; 47 | labelInfotext.Visible = true; 48 | try 49 | { 50 | await Task.Delay(ms, currentTokenSource.Token); 51 | labelInfotext.Visible = false; // Only hide when no other display task has started 52 | labelInfotext.Text = ""; 53 | } 54 | catch (OperationCanceledException) { } // ignored 55 | finally { displayCancellation = null; } 56 | } 57 | } 58 | 59 | #endregion 60 | 61 | /* --- Form Events --- */ 62 | 63 | #region Form Load, Init Paths and Settings 64 | 65 | private void FormMain_Load(object sender, EventArgs e) 66 | { 67 | var settings = Properties.Settings.Default; 68 | var inputFiles = settings.InputFiles?.Cast().ToArray(); 69 | if (inputFiles != null && inputFiles.Length > 0) 70 | { 71 | comboBoxFilestobackup.Items.AddRange(inputFiles); 72 | comboBoxFilestobackup.SelectedItem = comboBoxFilestobackup.Items[0]; 73 | } 74 | 75 | var outputDirs = settings.OutputDirectories?.Cast().ToArray(); 76 | if (outputDirs != null && outputDirs.Length > 0) 77 | { 78 | comboBoxBackupLocations.Items.AddRange(outputDirs); 79 | comboBoxBackupLocations.SelectedItem = comboBoxBackupLocations.Items[0]; 80 | } 81 | 82 | if (Enum.TryParse(settings.BackupMode.ToString(), out var mode)) 83 | { 84 | radioButtonNormal.Checked = mode == BackupMode.Copy; 85 | radioButtonFolder.Checked = mode == BackupMode.Subfolder; 86 | radioButtonZIP.Checked = mode == BackupMode.Zip; 87 | } 88 | 89 | checkBoxDate.Checked = settings.AddDate; 90 | checkBoxOverride.Checked = settings.Overwrite; 91 | textBoxName.Text = settings.BackupName; 92 | } 93 | 94 | #endregion 95 | 96 | #region Select Backup Files or Folders 97 | 98 | private void ButtonFilestobackup_Click(object sender, EventArgs e) 99 | { 100 | using (OpenFileDialog ofd = new OpenFileDialog { Multiselect = true }) 101 | { 102 | ofd.ShowDialog(); 103 | 104 | if (ofd.FileName == "") //no item selected cancel 105 | return; 106 | 107 | foreach (string s in ofd.FileNames) 108 | { 109 | if (!comboBoxFilestobackup.Items.Contains(s)) //only add if does not exist yet 110 | comboBoxFilestobackup.Items.Add(s); 111 | } 112 | 113 | comboBoxFilestobackup.SelectedItem = comboBoxFilestobackup.Items[comboBoxFilestobackup.Items.Count - 1]; //display last item 114 | } 115 | } 116 | 117 | private void ButtonFolderstobackup_Click(object sender, EventArgs e) 118 | { 119 | using (CommonOpenFileDialog cof = new CommonOpenFileDialog { IsFolderPicker = true, Multiselect = true }) 120 | { 121 | if (cof.ShowDialog() != CommonFileDialogResult.Ok) 122 | return; //if the user cancels the dialog 123 | 124 | foreach (string s in cof.FileNames) 125 | { 126 | if (!comboBoxFilestobackup.Items.Contains(s)) //only add if does not exist yet 127 | comboBoxFilestobackup.Items.Add(s); 128 | } 129 | 130 | comboBoxFilestobackup.SelectedItem = comboBoxFilestobackup.Items[comboBoxFilestobackup.Items.Count - 1]; //display last item 131 | } 132 | } 133 | 134 | private void ButtonFilestobackupClear_Click(object sender, EventArgs e) 135 | { 136 | comboBoxFilestobackup.Items.Clear(); 137 | comboBoxFilestobackup.Text = ""; 138 | DisplayText("Successfully cleared list.", 1500, Color.Green); 139 | } 140 | 141 | private void ComboBoxFilestobackup_KeyDown(object sender, KeyEventArgs e) //add or edit items 142 | { 143 | if (e.KeyCode == Keys.Enter) 144 | { 145 | if (!File.Exists(comboBoxFilestobackup.Text) && !Directory.Exists(comboBoxFilestobackup.Text)) 146 | { 147 | DisplayText("File or directory does not exist!", 1500, Color.Red); 148 | return; 149 | } 150 | 151 | if (comboBoxFilestobackup.SelectedItem != null) //delete old item and add new 152 | comboBoxFilestobackup.Items.Remove(comboBoxFilestobackup.SelectedItem); 153 | 154 | if (comboBoxFilestobackup.Items.Contains(comboBoxFilestobackup.Text)) //only add if does not exist yet 155 | { 156 | DisplayText("File or directory already exists!", 1500, Color.Red); 157 | return; 158 | } 159 | 160 | comboBoxFilestobackup.Items.Add(comboBoxFilestobackup.Text); 161 | DisplayText("Successfully added item.", 1500, Color.Green); 162 | } 163 | } 164 | 165 | private void ButtonFilestobackupDeleteitem_Click(object sender, EventArgs e) 166 | { 167 | if (comboBoxFilestobackup.SelectedItem != null) 168 | { 169 | comboBoxFilestobackup.Items.Remove(comboBoxFilestobackup.SelectedItem); 170 | comboBoxFilestobackup.Text = ""; 171 | DisplayText("Successfully deleted item.", 1500, Color.Green); 172 | } 173 | else 174 | DisplayText("No item to delete!", 1500, Color.Red); 175 | 176 | } 177 | 178 | #endregion 179 | 180 | #region Select Backup Locations 181 | 182 | private void ComboBoxBackupLocations_KeyDown(object sender, KeyEventArgs e) 183 | { 184 | if (e.KeyCode == Keys.Enter) 185 | { 186 | DirectoryInfo dir; 187 | try 188 | { 189 | // Create dir if not exists already 190 | dir = Directory.CreateDirectory(comboBoxBackupLocations.Text); 191 | } 192 | catch (Exception ex) 193 | { 194 | DisplayText(ex.Message, 1500, Color.Red); 195 | return; 196 | } 197 | 198 | if (comboBoxBackupLocations.SelectedItem != null) //delete old item and add new 199 | comboBoxBackupLocations.Items.Remove(comboBoxBackupLocations.SelectedItem); 200 | 201 | if (comboBoxBackupLocations.Items.Contains(dir.FullName)) 202 | { 203 | DisplayText("Directory already exists!", 1500, Color.Red); 204 | return; 205 | } 206 | 207 | comboBoxBackupLocations.Items.Add(dir.FullName); 208 | DisplayText("Successfully added path.", 1500, Color.Green); 209 | } 210 | } 211 | 212 | private void ButtonBackupBrowse_Click(object sender, EventArgs e) 213 | { 214 | using (CommonOpenFileDialog cof = new CommonOpenFileDialog { IsFolderPicker = true, Multiselect = true }) 215 | { 216 | if (cof.ShowDialog() != CommonFileDialogResult.Ok) 217 | return; //if the user cancels the dialog 218 | 219 | foreach (string s in cof.FileNames) 220 | { 221 | if (!comboBoxBackupLocations.Items.Contains(s)) //only add if not yet added 222 | comboBoxBackupLocations.Items.Add(s); 223 | } 224 | 225 | comboBoxBackupLocations.SelectedItem = comboBoxBackupLocations.Items[comboBoxBackupLocations.Items.Count - 1]; //select last added item 226 | } 227 | } 228 | 229 | private void ButtonBackupLocationsClear_Click(object sender, EventArgs e) 230 | { 231 | comboBoxBackupLocations.Items.Clear(); 232 | comboBoxBackupLocations.Text = ""; 233 | DisplayText("Successfully cleared list.", 1500, Color.Green); 234 | } 235 | 236 | private void ButtonBackupLocationsDeleteItem_Click(object sender, EventArgs e) 237 | { 238 | if (comboBoxBackupLocations.SelectedItem != null) 239 | { 240 | comboBoxBackupLocations.Items.Remove(comboBoxBackupLocations.SelectedItem); 241 | comboBoxBackupLocations.Text = ""; 242 | DisplayText("Successfully deleted item.", 1500, Color.Green); 243 | } 244 | else 245 | DisplayText("No item to delete!", 1500, Color.Red); 246 | 247 | } 248 | 249 | #endregion 250 | 251 | #region Show About 252 | 253 | private void AboutToolStripMenuItem_Click(object sender, EventArgs e) 254 | { 255 | using (FormAbout fa = new FormAbout()) 256 | { 257 | fa.ShowDialog(); 258 | } 259 | } 260 | 261 | #endregion 262 | 263 | #region Set Backup Name 264 | 265 | private const string BackupNamePlaceholder = "Name Folder/.zip"; 266 | 267 | private void TextBoxName_Click(object sender, EventArgs e) 268 | { 269 | if (textBoxName.Text.Equals(BackupNamePlaceholder)) 270 | textBoxName.Text = ""; 271 | } 272 | //^v when entering the textboxname delete the standard text 273 | private void TextBoxName_PreviewKeyDown(object sender, PreviewKeyDownEventArgs e) 274 | { 275 | if (textBoxName.Text.Equals(BackupNamePlaceholder)) 276 | textBoxName.Text = ""; 277 | } 278 | 279 | #endregion 280 | 281 | #region Radio Buttons 282 | 283 | private void RadioButtons_CheckedChanged(object sender, EventArgs e) 284 | { 285 | RadioButton rb = (RadioButton)sender; 286 | if (rb == radioButtonNormal) 287 | { 288 | // Toggle controls, which can only be used when rbfolder or rbzip is checked 289 | textBoxName.Enabled = false; 290 | textBoxName.Text = BackupNamePlaceholder; 291 | checkBoxDate.Enabled = false; 292 | checkBoxDate.Checked = false; 293 | } 294 | else 295 | { 296 | textBoxName.Enabled = true; 297 | checkBoxDate.Enabled = true; 298 | } 299 | } 300 | 301 | #endregion 302 | 303 | /* --- Saved Settings and Locations --- */ 304 | 305 | #region Settings Save 306 | 307 | private void SaveDefaultsToolStripMenuItem_Click(object sender, EventArgs e) 308 | { 309 | var settings = Properties.Settings.Default; 310 | settings.AddDate = checkBoxDate.Checked; 311 | settings.Overwrite = checkBoxOverride.Checked; 312 | settings.BackupName = textBoxName.Text; 313 | var inputFiles = new StringCollection(); 314 | inputFiles.AddRange(comboBoxFilestobackup.Items.Cast().ToArray()); 315 | var outputDirs = new StringCollection(); 316 | outputDirs.AddRange(comboBoxBackupLocations.Items.Cast().ToArray()); 317 | settings.InputFiles = inputFiles; 318 | settings.OutputDirectories = outputDirs; 319 | settings.BackupMode = 320 | radioButtonZIP.Checked ? (uint)BackupMode.Zip : 321 | radioButtonFolder.Checked ? (uint)BackupMode.Subfolder : 322 | (uint)BackupMode.Copy; 323 | 324 | settings.Save(); 325 | DisplayText("Successfully saved default values.", 1500, Color.Green); 326 | } 327 | 328 | #endregion 329 | 330 | #region Save and Open persisted Backup Path files 331 | 332 | private void OpenPaths_Click(object sender, EventArgs e) 333 | { 334 | ToolStripMenuItem menuItem = sender as ToolStripMenuItem; 335 | ComboBox boxToFill; 336 | 337 | if (menuItem == openFilePathsToolStripMenuItem) 338 | boxToFill = comboBoxFilestobackup; 339 | else if (menuItem == openBackupPathsToolStripMenuItem) 340 | boxToFill = comboBoxBackupLocations; 341 | else 342 | throw new NotSupportedException("Invalid menu item."); 343 | 344 | using (OpenFileDialog ofd = new OpenFileDialog { Filter = "Text files|*.txt" }) 345 | { 346 | ofd.ShowDialog(); 347 | if (ofd.FileName != "") 348 | { 349 | boxToFill.Items.Clear(); 350 | 351 | using (StreamReader sr = new StreamReader(ofd.FileName)) 352 | { 353 | int linesRead = 0; 354 | while (!sr.EndOfStream) 355 | { 356 | string readData = sr.ReadLine(); 357 | // v1.1 Removed restrictions 358 | //if (linesRead > 50 || readData.Length > 200) 359 | // break; //maximum of lines read should be around 50 and max lenght of path should be 200 to prevent memory problems 360 | boxToFill.Items.Add(readData); 361 | linesRead++; 362 | } 363 | } 364 | 365 | if (boxToFill.Items.Count != 0) //select first item, so the user know something is there 366 | boxToFill.SelectedItem = boxToFill.Items[0]; 367 | 368 | DisplayText("Successfully opened '" + ofd.FileName + "'", 1500, Color.Green); 369 | } 370 | } 371 | } 372 | 373 | private void SaveCustomFilePathsToolStripMenuItem_Click(object sender, EventArgs e) 374 | { 375 | using (SaveFileDialog sfd = new SaveFileDialog { AddExtension = true, Filter = "Text files|*.txt" }) 376 | { 377 | if (sfd.ShowDialog() == DialogResult.OK) 378 | { 379 | using (StreamWriter sw = new StreamWriter(sfd.FileName)) 380 | { 381 | foreach (string s in comboBoxFilestobackup.Items) 382 | { 383 | sw.WriteLine(s); 384 | } 385 | 386 | DisplayText("Successfully saved custom file paths.", 1500, Color.Green); 387 | } 388 | } 389 | } 390 | } 391 | 392 | private void SaveCustomBackupPathsToolStripMenuItem_Click(object sender, EventArgs e) 393 | { 394 | using (SaveFileDialog sfd = new SaveFileDialog { AddExtension = true, Filter = "Text files|*.txt" }) 395 | { 396 | if (sfd.ShowDialog() == DialogResult.OK) 397 | { 398 | using (StreamWriter sw = new StreamWriter(sfd.FileName)) 399 | { 400 | foreach (string s in comboBoxBackupLocations.Items) 401 | { 402 | sw.WriteLine(s); 403 | } 404 | 405 | DisplayText("Successfully saved custom backup paths.", 1500, Color.Green); 406 | } 407 | } 408 | 409 | } 410 | } 411 | 412 | #endregion 413 | 414 | /* ---- Backup Logic --- */ 415 | 416 | #region Backup 417 | 418 | private CancellationTokenSource backupCancellation = new CancellationTokenSource(); 419 | 420 | private bool ValidateArguments(BackupArguments backupArgs) 421 | { 422 | if (comboBoxFilestobackup.Items.Count == 0) // If no files to backup are given 423 | { 424 | DisplayText("No file selected!", 1500, Color.Red); 425 | return false; 426 | } 427 | 428 | if (comboBoxBackupLocations.Items.Count == 0) // If no backup locations are given 429 | { 430 | DisplayText("No backup path set!", 1500, Color.Red); 431 | return false; 432 | } 433 | 434 | // Check if files still exist 435 | foreach (string s in backupArgs.InputFiles) 436 | { 437 | if (!File.Exists(s) && !Directory.Exists(s)) 438 | { 439 | DisplayText("'" + s + "' does not exist!", 1500, Color.Red); 440 | return false; 441 | } 442 | } 443 | 444 | // Check if the folder/zip is named 445 | if ((radioButtonFolder.Checked || radioButtonZIP.Checked) && (textBoxName.Text.Equals("Name Folder/.zip") || (textBoxName.Text.Trim().Equals("")))) 446 | { 447 | DisplayText("Please enter a name for your Folder/.zip!", 1500, Color.Red); 448 | return false; 449 | } 450 | 451 | return true; 452 | } 453 | 454 | private async void ButtonOK_Click(object sender, EventArgs e) 455 | { 456 | DateTime dt = DateTime.Now; // For adding date to file names 457 | BackupArguments backupArgs = new BackupArguments(comboBoxFilestobackup.Items.Cast(), comboBoxBackupLocations.Items.Cast(), checkBoxOverride.Checked); 458 | 459 | // First validate input 460 | if (!ValidateArguments(backupArgs)) return; 461 | 462 | ResetBackupUi(); 463 | 464 | backupCancellation?.Cancel(); // Cancel currently running backup if not cancelled already 465 | var currentTokenSource = new CancellationTokenSource(); 466 | backupCancellation = currentTokenSource; 467 | BackupWriterFactory factory = new BackupWriterFactory(backupArgs); 468 | BackupMetadataInfo meta = await BackupMetadataInfo.FromBackupArgumentsAsync(backupArgs); 469 | BackupProgress progress = new BackupProgress(ReportBackupProgress, meta); 470 | IBackupWriter writer; 471 | 472 | if (radioButtonNormal.Checked) { writer = factory.CreateCopyFileBackupWriter(); } 473 | else if (radioButtonFolder.Checked) { writer = checkBoxDate.Checked ? factory.CreateSubfolderCopyBackupWriter(textBoxName.Text, dt) : factory.CreateSubfolderCopyBackupWriter(textBoxName.Text); } 474 | else if (radioButtonZIP.Checked) { writer = checkBoxDate.Checked ? factory.CreateZipBackupWriter(textBoxName.Text, dt) : factory.CreateZipBackupWriter(textBoxName.Text); } 475 | else { throw new NotSupportedException("Unsupported BackupWriter."); } 476 | 477 | labelProgress.Text = string.Format("{0} files and {1:n0} KB input", meta.FileCount, meta.FileSizeSum / 1000); 478 | 479 | try 480 | { 481 | await writer.ExecuteAsync(currentTokenSource.Token, progress); 482 | progressBarMain.Value = 100; 483 | DisplayText("File backup successful.", 3000, Color.Green); 484 | } 485 | catch (Exception ex) 486 | { 487 | progressBarMain.Value = 0; 488 | if (ex is OperationCanceledException) 489 | DisplayText("Successfully cancelled Backup.", 3000, Color.Green); 490 | else 491 | DisplayText(ex.Message, 3000, Color.Red); 492 | } 493 | finally 494 | { 495 | buttonOK.Visible = true; // Enable controls again 496 | buttonCancel.Visible = false; 497 | groupBoxSettings.Enabled = true; 498 | backupCancellation = null; 499 | currentTokenSource.Dispose(); 500 | } 501 | } 502 | 503 | private void ButtonCancel_Click(object sender, EventArgs e) 504 | { 505 | backupCancellation.Cancel(); 506 | DisplayText("Cancellation requested.", 3000, Color.Black); 507 | buttonCancel.Enabled = false; 508 | } 509 | 510 | private void ReportBackupProgress(BackupProgressInfo info) 511 | { 512 | progressBarMain.Value = (int)(info.PercentDone * 100); 513 | labelProgress.Text = labelProgress.Text.Split('\n')[0] 514 | + string.Format("\n{0:n0} KB written to output", info.BytesBackedUp / 1000); 515 | } 516 | 517 | private void ResetBackupUi() 518 | { 519 | buttonOK.Visible = false; // Disable and switch controls in the meantime 520 | buttonCancel.Visible = true; 521 | buttonCancel.Enabled = true; 522 | groupBoxSettings.Enabled = false; 523 | progressBarMain.Value = 0; 524 | labelProgress.Text = ""; 525 | } 526 | 527 | #endregion 528 | } 529 | } 530 | -------------------------------------------------------------------------------- /SimpleFileBackup.Windows/FormMain.resx: -------------------------------------------------------------------------------- 1 |  2 | 3 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | text/microsoft-resx 110 | 111 | 112 | 2.0 113 | 114 | 115 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 116 | 117 | 118 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 119 | 120 | 121 | 17, 17 122 | 123 | 124 | 125 | 126 | AAABAAEAICAAAAEACACoCAAAFgAAACgAAAAgAAAAQAAAAAEACAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA 127 | AAAAAAAAAQEBAAkJCQAPDw8AEhISABQUFAA4ODgASEhIALa2tgC7u7sA8/PzAPT09AD///8AAAAAAAAA 128 | AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA 129 | AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA 130 | AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA 131 | AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA 132 | AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA 133 | AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA 134 | AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA 135 | AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA 136 | AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA 137 | AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA 138 | AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA 139 | AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA 140 | AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA 141 | AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA 142 | AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA 143 | AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA 144 | AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA 145 | AAAAAAAAAAAAAAAAAAAAAAwMDAwMDAwMDAwMDAwMDAwMDAwMAAAAAAAAAAAAAAAMCQgICAgICAgICAgI 146 | CAgICAgICAkMAAAAAAAAAAAAAAwDAAAAAAAAAAAAAAAAAAAAAAAAAwwAAAAAAAAAAAAADAUAAAAAAAAA 147 | AAAAAAAAAAAAAAAFDAAAAAAAAAAAAAAMBQAAAAAAAAwAAAAADAAAAAAAAAUMAAAAAAAAAAAAAAwFAAAA 148 | AAAADAwMDAwMAAAAAAAABQwAAAAAAAAAAAAADAUAAAAAAAAADAwMDAAAAAAAAAAFDAAAAAAAAAAAAAAM 149 | BQAAAAAAAAAAAAAAAAAAAAAAAAUMAAAAAAAAAAAAAAwCAAAAAAAAAAAAAAAAAAAAAAAAAgwAAAAAAAAA 150 | AAAADAsKCgoKCgoKCgoKCgoKCgoKCgoLDAAAAAAAAAAAAAAMBwYGBgYGBgYGBgYGBgYGBgYGBgcMAAAA 151 | AAAAAAAAAAwFAAAAAAAAAAAAAAAAAAAAAAAABQwAAAAAAAAAAAAADAUAAAAAAAAAAAAAAAAAAAAAAAAF 152 | DAAAAAAAAAAAAAAMBQAAAAAAAAwAAAAADAAAAAAAAAUMAAAAAAAAAAAAAAwFAAAAAAAADAwMDAwMAAAA 153 | AAAABQwAAAAAAAAAAAAADAUAAAAAAAAADAwMDAAAAAAAAAAFDAAAAAAAAAAAAAAMBQAAAAAAAAAAAAAA 154 | AAAAAAAAAAUMAAAAAAAAAAAAAAwHBgYGBgYGBgYGBgYGBgYGBgYGBwwAAAAAAAAAAAAADAsKCgoKCgoK 155 | CgoKCgoKCgoKCgoLDAAAAAAAAAAAAAAMAgAAAAAAAAAAAAAAAAAAAAAAAAIMAAAAAAAAAAAAAAwFAAAA 156 | AAAAAAAAAAAAAAAAAAAABQwAAAAAAAAAAAAADAUAAAAAAAAMAQAAAQwAAAAAAAAFDAAAAAAAAAAAAAAM 157 | BQAAAAAAAAwMDAwMDAAAAAAAAAUMAAAAAAAAAAAAAAwFAAAAAAAABAwMDAwEAAAAAAAABQwAAAAAAAAA 158 | AAAADAUAAAAAAAAAAAAAAAAAAAAAAAAFDAAAAAAAAAAAAAAMAwAAAAAAAAAAAAAAAAAAAAAAAAMMAAAA 159 | AAAAAAAAAAwJCAgICAgICAgICAgICAgICAgICQwAAAAAAAAAAAAAAAwMDAwMDAwMDAwMDAwMDAwMDAwM 160 | AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA 161 | AAAAAAAAAAAAAP///////////AAAP/gAAB/4AAAf+AAAH/gAAB/4AAAf+AAAH/gAAB/4AAAf+AAAH/gA 162 | AB/4AAAf+AAAH/gAAB/4AAAf+AAAH/gAAB/4AAAf+AAAH/gAAB/4AAAf+AAAH/gAAB/4AAAf+AAAH/gA 163 | AB/4AAAf/AAAP/////////// 164 | 165 | 166 | -------------------------------------------------------------------------------- /SimpleFileBackup.Windows/Program.cs: -------------------------------------------------------------------------------- 1 | using SimpleFileBackup.Core; 2 | using SimpleFileBackup.Core.Data; 3 | using SimpleFileBackup.Core.Progress; 4 | using System; 5 | using System.Collections.Generic; 6 | using System.Linq; 7 | using System.Threading.Tasks; 8 | using System.Windows.Forms; 9 | 10 | namespace SimpleFileBackup.Windows 11 | { 12 | static class Program 13 | { 14 | /// 15 | /// The main entry point for the application. 16 | /// 17 | [STAThread] 18 | static void Main() 19 | { 20 | Application.EnableVisualStyles(); 21 | Application.SetCompatibleTextRenderingDefault(false); 22 | Application.Run(new FormMain()); 23 | } 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /SimpleFileBackup.Windows/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // General Information about an assembly is controlled through the following 6 | // set of attributes. Change these attribute values to modify the information 7 | // associated with an assembly. 8 | [assembly: AssemblyTitle("SimpleFileBackup Windows GUI")] 9 | [assembly: AssemblyDescription("")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("")] 12 | [assembly: AssemblyProduct("SimpleFileBackup")] 13 | [assembly: AssemblyCopyright("")] 14 | [assembly: AssemblyTrademark("")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | // Setting ComVisible to false makes the types in this assembly not visible 18 | // to COM components. If you need to access a type in this assembly from 19 | // COM, set the ComVisible attribute to true on that type. 20 | [assembly: ComVisible(false)] 21 | 22 | // The following GUID is for the ID of the typelib if this project is exposed to COM 23 | [assembly: Guid("2753db89-6f2b-495a-80fc-7f9155dbd2a0")] 24 | 25 | // Version information for an assembly consists of the following four values: 26 | // 27 | // Major Version 28 | // Minor Version 29 | // Build Number 30 | // Revision 31 | // 32 | // You can specify all the values or you can default the Build and Revision Numbers 33 | // by using the '*' as shown below: 34 | // [assembly: AssemblyVersion("1.0.*")] 35 | [assembly: AssemblyVersion("1.1.0.0")] 36 | [assembly: AssemblyFileVersion("1.1.0.0")] 37 | -------------------------------------------------------------------------------- /SimpleFileBackup.Windows/Properties/Resources.Designer.cs: -------------------------------------------------------------------------------- 1 | //------------------------------------------------------------------------------ 2 | // 3 | // This code was generated by a tool. 4 | // Runtime Version:4.0.30319.42000 5 | // 6 | // Changes to this file may cause incorrect behavior and will be lost if 7 | // the code is regenerated. 8 | // 9 | //------------------------------------------------------------------------------ 10 | 11 | namespace SimpleFileBackup.Windows.Properties { 12 | using System; 13 | 14 | 15 | /// 16 | /// A strongly-typed resource class, for looking up localized strings, etc. 17 | /// 18 | // This class was auto-generated by the StronglyTypedResourceBuilder 19 | // class via a tool like ResGen or Visual Studio. 20 | // To add or remove a member, edit your .ResX file then rerun ResGen 21 | // with the /str option, or rebuild your VS project. 22 | [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "17.0.0.0")] 23 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] 24 | [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] 25 | internal class Resources { 26 | 27 | private static global::System.Resources.ResourceManager resourceMan; 28 | 29 | private static global::System.Globalization.CultureInfo resourceCulture; 30 | 31 | [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] 32 | internal Resources() { 33 | } 34 | 35 | /// 36 | /// Returns the cached ResourceManager instance used by this class. 37 | /// 38 | [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] 39 | internal static global::System.Resources.ResourceManager ResourceManager { 40 | get { 41 | if (object.ReferenceEquals(resourceMan, null)) { 42 | global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("SimpleFileBackup.Windows.Properties.Resources", typeof(Resources).Assembly); 43 | resourceMan = temp; 44 | } 45 | return resourceMan; 46 | } 47 | } 48 | 49 | /// 50 | /// Overrides the current thread's CurrentUICulture property for all 51 | /// resource lookups using this strongly typed resource class. 52 | /// 53 | [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] 54 | internal static global::System.Globalization.CultureInfo Culture { 55 | get { 56 | return resourceCulture; 57 | } 58 | set { 59 | resourceCulture = value; 60 | } 61 | } 62 | 63 | /// 64 | /// Looks up a localized string similar to <!DOCTYPE html> 65 | ///<html> 66 | ///<head> 67 | /// <meta charset="utf-8" /> 68 | /// <title></title> 69 | ///</head> 70 | ///<body style="font-family:arial;"> 71 | /// <center> 72 | /// <h1>Simple File Backup Windows</h1> 73 | /// Program by Marcel Salvenmoser 74 | /// <br> 75 | /// <br> 76 | /// <h3>General</h3> 77 | /// Select files or folders by pressing the Select buttons on the right. You can select multiple files or folders at once. 78 | /// After pressing OK the file locations will be saved in the drop down list. You can also add files [rest of string was truncated]";. 79 | /// 80 | internal static string about { 81 | get { 82 | return ResourceManager.GetString("about", resourceCulture); 83 | } 84 | } 85 | } 86 | } 87 | -------------------------------------------------------------------------------- /SimpleFileBackup.Windows/Properties/Resources.resx: -------------------------------------------------------------------------------- 1 |  2 | 3 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | text/microsoft-resx 110 | 111 | 112 | 2.0 113 | 114 | 115 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 116 | 117 | 118 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 119 | 120 | 121 | 122 | ..\Resources\about.html;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;Windows-1252 123 | 124 | -------------------------------------------------------------------------------- /SimpleFileBackup.Windows/Properties/Settings.Designer.cs: -------------------------------------------------------------------------------- 1 | //------------------------------------------------------------------------------ 2 | // 3 | // This code was generated by a tool. 4 | // Runtime Version:4.0.30319.42000 5 | // 6 | // Changes to this file may cause incorrect behavior and will be lost if 7 | // the code is regenerated. 8 | // 9 | //------------------------------------------------------------------------------ 10 | 11 | namespace SimpleFileBackup.Windows.Properties { 12 | 13 | 14 | [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] 15 | [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "17.3.0.0")] 16 | internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase { 17 | 18 | private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings()))); 19 | 20 | public static Settings Default { 21 | get { 22 | return defaultInstance; 23 | } 24 | } 25 | 26 | [global::System.Configuration.UserScopedSettingAttribute()] 27 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] 28 | public global::System.Collections.Specialized.StringCollection InputFiles { 29 | get { 30 | return ((global::System.Collections.Specialized.StringCollection)(this["InputFiles"])); 31 | } 32 | set { 33 | this["InputFiles"] = value; 34 | } 35 | } 36 | 37 | [global::System.Configuration.UserScopedSettingAttribute()] 38 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] 39 | public global::System.Collections.Specialized.StringCollection OutputDirectories { 40 | get { 41 | return ((global::System.Collections.Specialized.StringCollection)(this["OutputDirectories"])); 42 | } 43 | set { 44 | this["OutputDirectories"] = value; 45 | } 46 | } 47 | 48 | [global::System.Configuration.UserScopedSettingAttribute()] 49 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] 50 | [global::System.Configuration.DefaultSettingValueAttribute("0")] 51 | public uint BackupMode { 52 | get { 53 | return ((uint)(this["BackupMode"])); 54 | } 55 | set { 56 | this["BackupMode"] = value; 57 | } 58 | } 59 | 60 | [global::System.Configuration.UserScopedSettingAttribute()] 61 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] 62 | [global::System.Configuration.DefaultSettingValueAttribute("")] 63 | public string BackupName { 64 | get { 65 | return ((string)(this["BackupName"])); 66 | } 67 | set { 68 | this["BackupName"] = value; 69 | } 70 | } 71 | 72 | [global::System.Configuration.UserScopedSettingAttribute()] 73 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] 74 | [global::System.Configuration.DefaultSettingValueAttribute("False")] 75 | public bool AddDate { 76 | get { 77 | return ((bool)(this["AddDate"])); 78 | } 79 | set { 80 | this["AddDate"] = value; 81 | } 82 | } 83 | 84 | [global::System.Configuration.UserScopedSettingAttribute()] 85 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] 86 | [global::System.Configuration.DefaultSettingValueAttribute("False")] 87 | public bool Overwrite { 88 | get { 89 | return ((bool)(this["Overwrite"])); 90 | } 91 | set { 92 | this["Overwrite"] = value; 93 | } 94 | } 95 | } 96 | } 97 | -------------------------------------------------------------------------------- /SimpleFileBackup.Windows/Properties/Settings.settings: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 0 13 | 14 | 15 | 16 | 17 | 18 | False 19 | 20 | 21 | False 22 | 23 | 24 | -------------------------------------------------------------------------------- /SimpleFileBackup.Windows/Properties/app.manifest: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 48 | 55 | 56 | 70 | -------------------------------------------------------------------------------- /SimpleFileBackup.Windows/Resources/about.html: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 |
9 |

Simple File Backup Windows

10 | Program by Marcel Salvenmoser 11 |
12 |
13 |

General

14 | Select files or folders by pressing the Select buttons on the right. You can select multiple files or folders at once. 15 | After pressing OK the file locations will be saved in the drop down list. You can also add files by typing the path in the textbox and pressing enter. If you made a wrong selection, you can delete single items by selecting them in the drop down list and pressing "Delete Item". 16 | You can clear the list by pressing "Clear List". 17 |
18 |
19 | Backup Destinations can be selected through the same process. Every file or folder in "Files to Backup" will be backed up to every "Backup Destination". 20 |
21 |
22 |

Settings

23 | Override idenetical files in directory 24 |
25 |
26 | If you want to replace your old files with the new files enable the "Override identical files in directory" option. 27 | This way, if a file called 123.jpg is already in the directory, it will be replaced. Same goes for ZIP files. 28 |
29 |
30 | Put files in given directory 31 |
32 |
33 | Copies the files and folders into the selected directories. 34 |
35 |
36 | Create a subfolder in directory 37 |
38 |
39 | Creates a subfolder in every given directory with the provided name. 40 |
41 |
42 | Create a .zip file in directory 43 |
44 |
45 | Create a .zip with the provided name from the given files and folders and copy it to every listed directory. 46 |
47 |
48 | Name Folder/.zip 49 |
50 |
51 | Only works when "Create a subfolder in directory" or "Create a .zip file in directory" is selected. 52 |
53 | You can name your folder or .zip file with a maximum of 20 characters. The characters have to be compatible with the windows filesystem. 54 |
55 |
56 | Add date to Folder/.zip name 57 |
58 |
59 | Adds your local date to the folder/.zip name in the format name_10-10-2010. 60 |
61 |
62 | Save Defaults 63 |
64 |
65 | Saves your file/backup locations and settings to keep them for the next program start. 66 |
67 |
68 | Save Custom File Paths & Save Custom Backup Paths 69 |
70 |
71 | Saves your file/backup locations in a text file you can choose the location of. 72 |
73 |
74 | Open File Paths & Open Backup Paths 75 |
76 |
77 | You can open a text file that contains paths to files or directories. These paths will be inserted into the drop down list. 78 |
79 |
80 |

Contact

81 | Bugs, Questions, anything: Submit a ticket on GitHub 82 |
83 |
84 |
    85 | Known Issues 86 |
  • Nothing at the moment
  • 87 |
88 |
89 |
90 |
91 | This is my first publicly released program. I made it because I needed a tool to backup files to more locations at once and I wanted to code something in my summer holidays. I do not expect much from this program but any feedback or criticism is appreciated. 92 |
93 |
94 | 95 | -------------------------------------------------------------------------------- /SimpleFileBackup.Windows/SFB.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/malthee/SimpleFileBackup/58c44cf6889dde4fb031a955c855e3d0590e4972/SimpleFileBackup.Windows/SFB.ico -------------------------------------------------------------------------------- /SimpleFileBackup.Windows/SimpleFileBackup.Windows.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | AnyCPU 7 | {2753DB89-6F2B-495A-80FC-7F9155DBD2A0} 8 | WinExe 9 | SimpleFileBackup.Windows 10 | SimpleFileBackupGUI 11 | v4.8 12 | 512 13 | true 14 | false 15 | publish\ 16 | true 17 | Disk 18 | false 19 | Foreground 20 | 7 21 | Days 22 | false 23 | false 24 | true 25 | https://github.com/malthee/SimpleFileBackup 26 | https://github.com/malthee/SimpleFileBackup 27 | en 28 | SimpleFileBackup 29 | Marcel Salvenmoser 30 | publish.htm 31 | true 32 | 9 33 | 1.1.0.%2a 34 | false 35 | true 36 | true 37 | 38 | 39 | AnyCPU 40 | true 41 | full 42 | false 43 | bin\Debug\ 44 | DEBUG;TRACE 45 | prompt 46 | 4 47 | false 48 | true 49 | false 50 | 51 | 52 | AnyCPU 53 | none 54 | true 55 | bin\Release\ 56 | TRACE 57 | prompt 58 | 4 59 | false 60 | 61 | 62 | SFB.ico 63 | 64 | 65 | false 66 | 67 | 68 | 69 | 70 | 71 | 72 | false 73 | 74 | 75 | 01A275E7015AABD2B7C9E1B6B4D53D722A9250CA 76 | 77 | 78 | 79 | 80 | 81 | 82 | true 83 | 84 | 85 | LocalIntranet 86 | 87 | 88 | Properties\app.manifest 89 | 90 | 91 | SimpleFileBackup.Windows.Program 92 | 93 | 94 | 95 | ..\packages\WindowsAPICodePack.1.1.3\lib\Microsoft.WindowsAPICodePack.dll 96 | 97 | 98 | ..\packages\WindowsAPICodePack.1.1.3\lib\Microsoft.WindowsAPICodePack.ExtendedLinguisticServices.dll 99 | 100 | 101 | ..\packages\WindowsAPICodePack.1.1.3\lib\Microsoft.WindowsAPICodePack.Sensors.dll 102 | 103 | 104 | ..\packages\WindowsAPICodePack.1.1.3\lib\Microsoft.WindowsAPICodePack.Shell.dll 105 | 106 | 107 | ..\packages\WindowsAPICodePack.1.1.3\lib\Microsoft.WindowsAPICodePack.ShellExtensions.dll 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | Form 126 | 127 | 128 | FormAbout.cs 129 | 130 | 131 | Form 132 | 133 | 134 | FormMain.cs 135 | 136 | 137 | 138 | 139 | FormAbout.cs 140 | 141 | 142 | FormMain.cs 143 | Designer 144 | 145 | 146 | ResXFileCodeGenerator 147 | Resources.Designer.cs 148 | Designer 149 | 150 | 151 | True 152 | Resources.resx 153 | True 154 | 155 | 156 | 157 | 158 | SettingsSingleFileGenerator 159 | Settings.Designer.cs 160 | 161 | 162 | True 163 | Settings.settings 164 | True 165 | 166 | 167 | 168 | 169 | Designer 170 | 171 | 172 | 173 | 174 | 175 | 176 | 177 | 178 | {e6a2a5d0-0421-4b5f-8c3e-ed6b7411c7e1} 179 | SimpleFileBackup.Core 180 | 181 | 182 | 183 | 184 | False 185 | Microsoft .NET Framework 4.8 %28x86 and x64%29 186 | true 187 | 188 | 189 | False 190 | .NET Framework 3.5 SP1 191 | false 192 | 193 | 194 | 195 | 196 | False 197 | 198 | 199 | 200 | 201 | Exclude 202 | True 203 | Assembly 204 | 205 | 206 | False 207 | 208 | 209 | 210 | 211 | Exclude 212 | True 213 | Assembly 214 | 215 | 216 | False 217 | 218 | 219 | 220 | 221 | Exclude 222 | True 223 | Assembly 224 | 225 | 226 | 227 | -------------------------------------------------------------------------------- /SimpleFileBackup.Windows/packages.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | -------------------------------------------------------------------------------- /SimpleFileBackup.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 17 4 | VisualStudioVersion = 17.3.32611.2 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SimpleFileBackup.Windows", "SimpleFileBackup.Windows\SimpleFileBackup.Windows.csproj", "{2753DB89-6F2B-495A-80FC-7F9155DBD2A0}" 7 | EndProject 8 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SimpleFileBackup.Core", "SimpleFileBackup.Core\SimpleFileBackup.Core.csproj", "{E6A2A5D0-0421-4B5F-8C3E-ED6B7411C7E1}" 9 | EndProject 10 | Global 11 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 12 | Debug|Any CPU = Debug|Any CPU 13 | Release|Any CPU = Release|Any CPU 14 | EndGlobalSection 15 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 16 | {2753DB89-6F2B-495A-80FC-7F9155DBD2A0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 17 | {2753DB89-6F2B-495A-80FC-7F9155DBD2A0}.Debug|Any CPU.Build.0 = Debug|Any CPU 18 | {2753DB89-6F2B-495A-80FC-7F9155DBD2A0}.Release|Any CPU.ActiveCfg = Release|Any CPU 19 | {2753DB89-6F2B-495A-80FC-7F9155DBD2A0}.Release|Any CPU.Build.0 = Release|Any CPU 20 | {E6A2A5D0-0421-4B5F-8C3E-ED6B7411C7E1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 21 | {E6A2A5D0-0421-4B5F-8C3E-ED6B7411C7E1}.Debug|Any CPU.Build.0 = Debug|Any CPU 22 | {E6A2A5D0-0421-4B5F-8C3E-ED6B7411C7E1}.Release|Any CPU.ActiveCfg = Release|Any CPU 23 | {E6A2A5D0-0421-4B5F-8C3E-ED6B7411C7E1}.Release|Any CPU.Build.0 = Release|Any CPU 24 | EndGlobalSection 25 | GlobalSection(SolutionProperties) = preSolution 26 | HideSolutionNode = FALSE 27 | EndGlobalSection 28 | GlobalSection(ExtensibilityGlobals) = postSolution 29 | SolutionGuid = {66C3E390-AA68-4719-90FB-0886E15E2A4D} 30 | EndGlobalSection 31 | EndGlobal 32 | --------------------------------------------------------------------------------