Skip to content

Commit

Permalink
Merge pull request #1506
Browse files Browse the repository at this point in the history
filed: fix possible data-loss when excluding hardlinks
  • Loading branch information
BareosBot committed Sep 22, 2023
2 parents 4661789 + 1751da1 commit 2d909a0
Show file tree
Hide file tree
Showing 14 changed files with 225 additions and 207 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Expand Up @@ -130,6 +130,7 @@ and since Bareos version 20 this project adheres to [Semantic Versioning](https:
- stored: fix incoherent meta data when concurrently writing to the same volume [PR #1495]
- dird: fix expected file count error during bsr build [PR #1511]
- VMware Plugin: Fix transformer issues [PR #1532]
- filed: fix possible data-loss when excluding hardlinks [PR #1506]

### Documentation
- add explanation about binary version numbers [PR #1354]
Expand Down Expand Up @@ -235,6 +236,7 @@ and since Bareos version 20 this project adheres to [Semantic Versioning](https:
[PR #1502]: https://github.com/bareos/bareos/pull/1502
[PR #1503]: https://github.com/bareos/bareos/pull/1503
[PR #1505]: https://github.com/bareos/bareos/pull/1505
[PR #1506]: https://github.com/bareos/bareos/pull/1506
[PR #1507]: https://github.com/bareos/bareos/pull/1507
[PR #1508]: https://github.com/bareos/bareos/pull/1508
[PR #1511]: https://github.com/bareos/bareos/pull/1511
Expand Down
2 changes: 1 addition & 1 deletion core/src/filed/backup.cc
Expand Up @@ -422,7 +422,7 @@ static inline bool TerminateDigest(b_save_ctx& bsctx)

// Keep the checksum if this file is a hardlink
if (bsctx.ff_pkt->linked) {
FfPktSetLinkDigest(bsctx.ff_pkt, bsctx.digest_stream, sd->msg, size);
bsctx.ff_pkt->linked->set_digest(bsctx.digest_stream, sd->msg, size);
}

sd->message_length = size;
Expand Down
66 changes: 29 additions & 37 deletions core/src/filed/fd_plugins.cc
Expand Up @@ -782,10 +782,10 @@ int PluginSave(JobControlRecord* jcr, FindFilesPacket* ff_pkt, bool)
* Maintain a list of hard linked files already backed up. This allows
* us to ensure that the data of each file gets backed up only once. */
ff_pkt->LinkFI = 0;
ff_pkt->FileIndex = 0;
ff_pkt->linked = nullptr;
if (!BitIsSet(FO_NO_HARDLINK, ff_pkt->flags)
&& ff_pkt->statp.st_nlink > 1) {
CurLink* hl;

switch (ff_pkt->statp.st_mode & S_IFMT) {
case S_IFREG:
case S_IFCHR:
Expand All @@ -794,50 +794,42 @@ int PluginSave(JobControlRecord* jcr, FindFilesPacket* ff_pkt, bool)
#ifdef S_IFSOCK
case S_IFSOCK:
#endif
hl = lookup_hardlink(jcr, ff_pkt, ff_pkt->statp.st_ino,
ff_pkt->statp.st_dev);
if (hl) {
/* If we have already backed up the hard linked file don't do it
* again */
if (bstrcmp(hl->name, sp.fname)) {
Dmsg2(400, "== Name identical skip FI=%d file=%s\n",
hl->FileIndex, fname.c_str());
ff_pkt->no_read = true;
} else {
ff_pkt->link = hl->name;
ff_pkt->type
= FT_LNKSAVED; /* Handle link, file already saved */
ff_pkt->LinkFI = hl->FileIndex;
ff_pkt->linked = NULL;
ff_pkt->digest = hl->digest;
ff_pkt->digest_stream = hl->digest_stream;
ff_pkt->digest_len = hl->digest_len;

Dmsg3(400, "FT_LNKSAVED FI=%d LinkFI=%d file=%s\n",
ff_pkt->FileIndex, hl->FileIndex, hl->name);

ff_pkt->no_read = true;
}
} else {
// File not previously dumped. Chain it into our list.
hl = new_hardlink(jcr, ff_pkt, sp.fname, ff_pkt->statp.st_ino,
ff_pkt->statp.st_dev);
ff_pkt->linked = hl; /* Mark saved link */

if (!ff_pkt->linkhash) { ff_pkt->linkhash = new LinkHash(10000); }

auto [iter, _] = ff_pkt->linkhash->try_emplace(
Hardlink{ff_pkt->statp.st_dev, ff_pkt->statp.st_ino}, sp.fname);
auto& hl = iter->second;
if (hl.FileIndex == 0) {
ff_pkt->linked = &hl;
Dmsg2(400, "Added to hash FI=%d file=%s\n", ff_pkt->FileIndex,
hl->name);
hl.name.c_str());
} else if (bstrcmp(hl.name.c_str(), sp.fname)) {
Dmsg2(400, "== Name identical skip FI=%d file=%s\n", hl.FileIndex,
fname.c_str());
ff_pkt->no_read = true;
} else {
ff_pkt->link = hl.name.data();
ff_pkt->type = FT_LNKSAVED; /* Handle link, file already saved */
ff_pkt->LinkFI = hl.FileIndex;
ff_pkt->digest = hl.digest.data();
ff_pkt->digest_stream = hl.digest_stream;
ff_pkt->digest_len = hl.digest.size();

Dmsg3(400, "FT_LNKSAVED FI=%d LinkFI=%d file=%s\n",
ff_pkt->FileIndex, hl.FileIndex, hl.name.c_str());

ff_pkt->no_read = true;
}
break;
default:
ff_pkt->linked = NULL;
break;
}
} else {
ff_pkt->linked = NULL;
}

// Call Bareos core code to backup the plugin's file
SaveFile(jcr, ff_pkt, true);

if (ff_pkt->linked) { ff_pkt->linked->FileIndex = ff_pkt->FileIndex; }

// Restore original flags.
CopyBits(FO_MAX, flags, ff_pkt->flags);

Expand Down
3 changes: 1 addition & 2 deletions core/src/findlib/CMakeLists.txt
@@ -1,6 +1,6 @@
# BAREOS® - Backup Archiving REcovery Open Sourced
#
# Copyright (C) 2017-2022 Bareos GmbH & Co. KG
# Copyright (C) 2017-2023 Bareos GmbH & Co. KG
#
# This program is Free Software; you can redistribute it and/or
# modify it under the terms of version three of the GNU Affero General Public
Expand Down Expand Up @@ -28,7 +28,6 @@ set(BAREOSFIND_SRCS
find_one.cc
find.cc
fstype.cc
hardlink.cc
match.cc
mkpath.cc
shadowing.cc
Expand Down
24 changes: 1 addition & 23 deletions core/src/findlib/find.h
Expand Up @@ -34,6 +34,7 @@
#include "lib/htable.h"
#include "lib/dlist.h"
#include "lib/alist.h"
#include "findlib/hardlink.h"

#include <dirent.h>
#define NAMELEN(dirent) (strlen((dirent)->d_name))
Expand Down Expand Up @@ -168,28 +169,6 @@ struct HfsPlusInfo {
off_t rsrclength{0}; /**< Size of resource fork */
};

/**
* Structure for keeping track of hard linked files, we
* keep an entry for each hardlinked file that we save,
* which is the first one found. For all the other files that
* are linked to this one, we save only the directory
* entry so we can link it.
*/
struct CurLink {
struct hlink link;
dev_t dev; /**< Device */
ino_t ino; /**< Inode with device is unique */
uint32_t FileIndex; /**< Bareos FileIndex of this file */
int32_t digest_stream; /**< Digest type if needed */
uint32_t digest_len; /**< Digest len if needed */
char* digest; /**< Checksum of the file if needed */
char name[1]; /**< The name */
};

using LinkHash
= htable<htable_binary_key, CurLink, MonotonicBuffer::Size::Medium>;


/**
* Definition of the FindFiles packet passed as the
* first argument to the FindFiles callback subroutine.
Expand Down Expand Up @@ -285,7 +264,6 @@ findIncludeExcludeItem* new_preinclude(findFILESET* fileset);
findFOPTS* start_options(FindFilesPacket* ff);
void NewOptions(FindFilesPacket* ff, findIncludeExcludeItem* incexe);


#include "acl.h"
#include "xattr.h"

Expand Down
59 changes: 33 additions & 26 deletions core/src/findlib/find_one.cc
Expand Up @@ -429,37 +429,36 @@ static inline int process_hardlink(JobControlRecord* jcr,
bool* done)
{
int rtn_stat = 0;
CurLink* hl;

hl = lookup_hardlink(jcr, ff_pkt, ff_pkt->statp.st_ino, ff_pkt->statp.st_dev);
if (hl) {
// If we have already backed up the hard linked file don't do it again
if (bstrcmp(hl->name, fname)) {
Dmsg2(400, "== Name identical skip FI=%d file=%s\n", hl->FileIndex,
fname);
*done = true;
return 1; /* ignore */
}
if (!ff_pkt->linkhash) { ff_pkt->linkhash = new LinkHash(10000); }

auto [iter, inserted] = ff_pkt->linkhash->try_emplace(
Hardlink{ff_pkt->statp.st_dev, ff_pkt->statp.st_ino}, fname);
CurLink& hl = iter->second;

ff_pkt->link = hl->name;
if (hl.FileIndex == 0) {
// no file backed up yet
ff_pkt->linked = &hl;
*done = false;
} else if (bstrcmp(hl.name.c_str(), fname)) {
// If we have already backed up the hard linked file don't do it again
Dmsg2(400, "== Name identical skip FI=%d file=%s\n", hl.FileIndex, fname);
*done = true;
rtn_stat = 1; /* ignore */
} else {
// some other file was already backed up!
ff_pkt->link = hl.name.data();
ff_pkt->type = FT_LNKSAVED; /* Handle link, file already saved */
ff_pkt->LinkFI = hl->FileIndex;
ff_pkt->LinkFI = hl.FileIndex;
ff_pkt->linked = NULL;
ff_pkt->digest = hl->digest;
ff_pkt->digest_stream = hl->digest_stream;
ff_pkt->digest_len = hl->digest_len;
ff_pkt->digest = hl.digest.data();
ff_pkt->digest_stream = hl.digest_stream;
ff_pkt->digest_len = hl.digest.size();

rtn_stat = HandleFile(jcr, ff_pkt, top_level);
Dmsg3(400, "FT_LNKSAVED FI=%d LinkFI=%d file=%s\n", ff_pkt->FileIndex,
hl->FileIndex, hl->name);
hl.FileIndex, hl.name.c_str());
*done = true;
} else {
// File not previously dumped. Chain it into our list.
hl = new_hardlink(jcr, ff_pkt, fname, ff_pkt->statp.st_ino,
ff_pkt->statp.st_dev);
ff_pkt->linked = hl; /* Mark saved link */
Dmsg2(400, "Added to hash FI=%d file=%s\n", ff_pkt->FileIndex, hl->name);
*done = false;
}

return rtn_stat;
Expand Down Expand Up @@ -715,7 +714,6 @@ static inline int process_directory(JobControlRecord* jcr,

if (!FileIsExcluded(ff_pkt, link)) {
rtn_stat = FindOneFile(jcr, ff_pkt, HandleFile, link, our_device, false);
if (ff_pkt->linked) { ff_pkt->linked->FileIndex = ff_pkt->FileIndex; }
}
}

Expand Down Expand Up @@ -772,7 +770,9 @@ static inline int process_directory(JobControlRecord* jcr,
* the directory modes and dates. Temp directory values
* were used without this record. */
HandleFile(jcr, dir_ff_pkt, top_level); /* handle directory entry */
if (ff_pkt->linked) { ff_pkt->linked->FileIndex = dir_ff_pkt->FileIndex; }
if (dir_ff_pkt->linked) {
dir_ff_pkt->linked->FileIndex = dir_ff_pkt->FileIndex;
}
FreeDirFfPkt(dir_ff_pkt);

if (BitIsSet(FO_KEEPATIME, ff_pkt->flags)) {
Expand Down Expand Up @@ -897,7 +897,7 @@ int FindOneFile(JobControlRecord* jcr,
int rtn_stat;
bool done = false;

ff_pkt->fname = ff_pkt->link = fname;
ff_pkt->link = ff_pkt->fname = fname;
ff_pkt->type = FT_UNSET;
if (lstat(fname, &ff_pkt->statp) != 0) {
// Cannot stat file
Expand Down Expand Up @@ -950,6 +950,13 @@ int FindOneFile(JobControlRecord* jcr,
#endif

ff_pkt->LinkFI = 0;
// some codes accesses FileIndex even if the file was never send
// If we did not reset it here, they would read the file index of the
// last send file. This is obviously not great and as such we
// reset it to zero here before it can do any damage (0 is an invalid
// FileIndex).
ff_pkt->FileIndex = 0;
ff_pkt->linked = nullptr;
/* Handle hard linked files
*
* Maintain a list of hard linked files already backed up. This
Expand Down
104 changes: 0 additions & 104 deletions core/src/findlib/hardlink.cc

This file was deleted.

0 comments on commit 2d909a0

Please sign in to comment.