Improve safeBackup function and documentation (#2966)

* Update safeBackup to use a new filename format for easier identification

<filename>-<hostname>-safeBackup-<number>.file_extention

* Update client-architecture.md to articulate backup file formatting and how to disable preserving local files to prevent local data loss
This commit is contained in:
abraunegg 2024-11-14 06:14:31 +11:00 committed by GitHub
commit 8f9927f45b
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 60 additions and 25 deletions

View file

@ -97,9 +97,41 @@ This exclusion process can be illustrated by the following activity diagram. A '
When using the default operational modes (`--sync` or `--monitor`) the client application is conforming to how the Microsoft Windows OneDrive client operates in terms of resolving conflicts for files.
Additionally, when using `--resync` this conflict resolution can differ slightly, as, when using `--resync` you are *deleting* the known application state, thus, the application has zero reference as to what was previously in sync with the local file system.
When using `--resync` this conflict resolution can differ slightly, as, when using `--resync` you are *deleting* the known application state, thus, the application has zero reference as to what was previously in sync with the local file system.
Due to this factor, when using `--resync` the online source is always going to be considered accurate and the source-of-truth, regardless of the local file state, file timestamp or file hash.
Due to this factor, when using `--resync` the online source is always going to be considered accurate and the source-of-truth, regardless of the local file state, local file timestamp or local file hash. When a difference in local file hash is detected, the file will be renamed to prevent local data loss.
> [!IMPORTANT]
> In v2.5.3 and above, when a local file is renamed due to conflict handling, this will be in the following format pattern to allow easier identification:
>
> **filename-hostname-safeBackup-number.file_extension**
>
> For example:
> ```
> -rw-------. 1 alex alex 53402 Sep 21 08:25 file5.data
> -rw-------. 1 alex alex 53423 Nov 13 18:18 file5-onedrive-client-dev-safeBackup-0001.data
> -rw-------. 1 alex alex 53422 Nov 13 18:19 file5-onedrive-client-dev-safeBackup-0002.data
> ```
>
> In client versions v2.5.2 and below, the renamed file have the following naming convention:
>
> **filename-hostname-number.file_extension**
>
> resulting in backup filenames of the following format:
> ```
> -rw-------. 1 alex alex 53402 Sep 21 08:25 file5.data
> -rw-------. 1 alex alex 53432 Nov 14 05:22 file5-onedrive-client-dev-2.data
> -rw-------. 1 alex alex 53435 Nov 14 05:24 file5-onedrive-client-dev-3.data
> -rw-------. 1 alex alex 53419 Nov 14 05:22 file5-onedrive-client-dev.data
> ```
>
> [!CAUTION]
> The creation of backup files when there is a conflict to avoid local data loss can be disabled.
>
> To do this, utilise the configuration option **bypass_data_preservation**
>
> If this is enabled, you will experience data loss on your local data as the local file will be over-written with data from OneDrive online. Use with care and caution.
### Default Operational Modes - Conflict Handling

View file

@ -56,30 +56,31 @@ shared static this() {
// Creates a safe backup of the given item, and only performs the function if not in a --dry-run scenario
void safeBackup(const(char)[] path, bool dryRun, out string renamedPath) {
auto ext = extension(path);
auto newPath = path.chomp(ext) ~ "-" ~ deviceName;
int n = 2;
auto ext = extension(path);
auto newPath = path.chomp(ext) ~ "-" ~ deviceName ~ "-safeBackup-";
int n = 1;
// Limit to 1000 iterations .. 1000 file backups
while (exists(newPath ~ ext) && n < 1000) {
newPath = newPath.chomp("-" ~ (n - 1).to!string) ~ "-" ~ n.to!string;
n++;
}
while (exists(newPath ~ format("%04d", n) ~ ext) && n < 1000) {
n++;
}
// Check if unique file name was found
if (exists(newPath ~ ext)) {
if (exists(newPath ~ format("%04d", n) ~ ext)) {
// On the 1000th backup of this file, this should be triggered
addLogEntry("Failed to backup " ~ to!string(path) ~ ": Unique file name could not be found after 1000 attempts", ["error"]);
return; // Exit function as a unique file name could not be found
}
// Configure the new name
newPath ~= ext;
// Log that we are perform the backup by renaming the file
if (verboseLogging) {addLogEntry("The local item is out-of-sync with OneDrive, renaming to preserve existing file and prevent local data loss: " ~ to!string(path) ~ " -> " ~ to!string(newPath) , ["verbose"]);}
// Configure the new name with zero-padded counter
newPath ~= format("%04d", n) ~ ext;
if (!dryRun) {
// Log that we are performing the backup by renaming the file
if (verboseLogging) {
addLogEntry("The local item is out-of-sync with OneDrive, renaming to preserve existing file and prevent local data loss: " ~ to!string(path) ~ " -> " ~ to!string(newPath), ["verbose"]);
}
if (!dryRun) {
// Not a --dry-run scenario - do the file rename
//
// There are 2 options to rename a file
@ -96,13 +97,15 @@ void safeBackup(const(char)[] path, bool dryRun, out string renamedPath) {
try {
rename(path, newPath);
renamedPath = to!string(newPath);
} catch (Exception e) {
// Handle exceptions, e.g., log error
addLogEntry("Renaming of local file failed for " ~ to!string(path) ~ ": " ~ e.msg, ["error"]);
}
} else {
if (debugLogging) {addLogEntry("DRY-RUN: Skipping renaming local file to preserve existing file and prevent data loss: " ~ to!string(path) ~ " -> " ~ to!string(newPath), ["debug"]);}
}
} catch (Exception e) {
// Handle exceptions, e.g., log error
addLogEntry("Renaming of local file failed for " ~ to!string(path) ~ ": " ~ e.msg, ["error"]);
}
} else {
if (debugLogging) {
addLogEntry("DRY-RUN: Skipping renaming local file to preserve existing file and prevent data loss: " ~ to!string(path) ~ " -> " ~ to!string(newPath), ["debug"]);
}
}
}
// Rename the given item, and only performs the function if not in a --dry-run scenario