X-Git-Url: https://git.sur5r.net/?a=blobdiff_plain;f=bacula%2Fsrc%2Ffindlib%2Ffind_one.c;h=8e4beb931275ea4b3bfc8b007a49b95b60705f01;hb=10cfd798ced2d27f61ead2de6fe9b1bcc8e3468d;hp=38fbfa47b350c6de370d197d03870675cbfaf5dd;hpb=51f54360499bd4bcb9ac9fb63adda2f4fd02d40d;p=bacula%2Fbacula diff --git a/bacula/src/findlib/find_one.c b/bacula/src/findlib/find_one.c index 38fbfa47b3..8e4beb9312 100644 --- a/bacula/src/findlib/find_one.c +++ b/bacula/src/findlib/find_one.c @@ -1,29 +1,20 @@ /* - Bacula® - The Network Backup Solution - - Copyright (C) 2000-2009 Free Software Foundation Europe e.V. - - The main author of Bacula is Kern Sibbald, with contributions from - many others, a complete list can be found in the file AUTHORS. - This program is Free Software; you can redistribute it and/or - modify it under the terms of version two of the GNU General Public - License as published by the Free Software Foundation and included - in the file LICENSE. - - This program is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - 02110-1301, USA. - - Bacula® is a registered trademark of Kern Sibbald. - The licensor of Bacula is the Free Software Foundation Europe - (FSFE), Fiduciary Program, Sumatrastrasse 25, 8006 Zürich, - Switzerland, email:ftf@fsfeurope.org. + Bacula(R) - The Network Backup Solution + + Copyright (C) 2000-2018 Kern Sibbald + + The original author of Bacula is Kern Sibbald, with contributions + from many others, a complete list can be found in the file AUTHORS. + + You may use this file and others of this release according to the + license defined in the LICENSE file, which includes the Affero General + Public License, v3.0 ("AGPLv3") and some additional permissions and + terms pursuant to its AGPLv3 Section 7. + + This notice must be preserved when any source code is + conveyed and/or propagated. + + Bacula(R) is a registered trademark of Kern Sibbald. */ /* @@ -34,8 +25,6 @@ Thanks to the TAR programmers. - Version $Id$ - */ #include "bacula.h" @@ -61,6 +50,9 @@ struct f_link { dev_t dev; /* device */ ino_t ino; /* inode with device is unique */ uint32_t FileIndex; /* Bacula 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 */ }; @@ -86,7 +78,7 @@ static inline int LINKHASH(const struct stat &info) /* * Create a new directory Find File packet, but copy * some of the essential info from the current packet. - * However, be careful to zero out the rest of the + * However, be careful to zero out the rest of the * packet. */ static FF_PKT *new_dir_ff_pkt(FF_PKT *ff_pkt) @@ -96,12 +88,23 @@ static FF_PKT *new_dir_ff_pkt(FF_PKT *ff_pkt) dir_ff_pkt->fname = bstrdup(ff_pkt->fname); dir_ff_pkt->link = bstrdup(ff_pkt->link); dir_ff_pkt->sys_fname = get_pool_memory(PM_FNAME); + + if (ff_pkt->strip_snap_path) { + dir_ff_pkt->fname_save = get_pool_memory(PM_FNAME); + dir_ff_pkt->link_save = get_pool_memory(PM_FNAME); + pm_strcpy(dir_ff_pkt->fname_save, ff_pkt->fname_save); + pm_strcpy(dir_ff_pkt->link_save, ff_pkt->link_save); + + } else { + dir_ff_pkt->fname_save = NULL; + dir_ff_pkt->link_save = NULL; + } + dir_ff_pkt->included_files_list = NULL; dir_ff_pkt->excluded_files_list = NULL; dir_ff_pkt->excluded_paths_list = NULL; dir_ff_pkt->linkhash = NULL; - dir_ff_pkt->fname_save = NULL; - dir_ff_pkt->link_save = NULL; + dir_ff_pkt->ignoredir_fname = NULL; return dir_ff_pkt; } @@ -133,7 +136,7 @@ static int accept_fstype(FF_PKT *ff, void *dummy) { if (ff->fstypes.size()) { accept = false; - if (!fstype(ff->fname, fs, sizeof(fs))) { + if (!fstype(ff, fs, sizeof(fs))) { Dmsg1(50, "Cannot determine file system type for \"%s\"\n", ff->fname); } else { for (i = 0; i < ff->fstypes.size(); ++i) { @@ -239,33 +242,30 @@ bool has_file_changed(JCR *jcr, FF_PKT *ff_pkt) if (lstat(ff_pkt->fname, &statp) != 0) { berrno be; - Jmsg(jcr, M_WARNING, 0, + Jmsg(jcr, M_WARNING, 0, _("Cannot stat file %s: ERR=%s\n"),ff_pkt->fname,be.bstrerror()); return true; } if (statp.st_mtime != ff_pkt->statp.st_mtime) { - /* TODO: add time of changes */ Jmsg(jcr, M_ERROR, 0, _("%s mtime changed during backup.\n"), ff_pkt->fname); + Dmsg3(50, "%s mtime (%lld) changed during backup (%lld).\n", ff_pkt->fname, + (int64_t)ff_pkt->statp.st_mtime, (int64_t)statp.st_mtime); return true; } if (statp.st_ctime != ff_pkt->statp.st_ctime) { - /* TODO: add time of changes */ Jmsg(jcr, M_ERROR, 0, _("%s ctime changed during backup.\n"), ff_pkt->fname); - return true; - } - - if (statp.st_size != ff_pkt->statp.st_size) { - /* TODO: add size change */ - Jmsg(jcr, M_ERROR, 0, _("%s size changed during backup.\n"),ff_pkt->fname); + Dmsg3(50, "%s ctime (%lld) changed during backup (%lld).\n", ff_pkt->fname, + (int64_t)ff_pkt->statp.st_ctime, (int64_t)statp.st_ctime); return true; } - if ((statp.st_blksize != ff_pkt->statp.st_blksize) || - (statp.st_blocks != ff_pkt->statp.st_blocks)) { - /* TODO: add size change */ - Jmsg(jcr, M_ERROR, 0, _("%s size changed during backup.\n"),ff_pkt->fname); + if ((int64_t)statp.st_size != (int64_t)ff_pkt->statp.st_size) { + Jmsg(jcr, M_ERROR, 0, _("%s size of %lld changed during backup to %lld.n"),ff_pkt->fname, + (int64_t)ff_pkt->statp.st_size, (int64_t)statp.st_size); + Dmsg3(50, "%s size (%lld) changed during backup (%lld).\n", ff_pkt->fname, + (int64_t)ff_pkt->statp.st_size, (int64_t)statp.st_size); return true; } @@ -276,9 +276,9 @@ bool has_file_changed(JCR *jcr, FF_PKT *ff_pkt) * For incremental/diffential or accurate backups, we * determine if the current file has changed. */ -static bool check_changes(JCR *jcr, FF_PKT *ff_pkt) +bool check_changes(JCR *jcr, FF_PKT *ff_pkt) { - /* in special mode (like accurate backup), the programmer can + /* in special mode (like accurate backup), the programmer can * choose his comparison function. */ if (ff_pkt->check_fct) { @@ -291,14 +291,55 @@ static bool check_changes(JCR *jcr, FF_PKT *ff_pkt) if (ff_pkt->incremental && (ff_pkt->statp.st_mtime < ff_pkt->save_time && ((ff_pkt->flags & FO_MTIMEONLY) || - ff_pkt->statp.st_ctime < ff_pkt->save_time))) + ff_pkt->statp.st_ctime < ff_pkt->save_time))) { return false; - } + } return true; } +static bool have_ignoredir(FF_PKT *ff_pkt) +{ + struct stat sb; + char *ignoredir; + + /* Ensure that pointers are defined */ + if (!ff_pkt->fileset || !ff_pkt->fileset->incexe) { + return false; + } + ignoredir = ff_pkt->fileset->incexe->ignoredir; + + if (ignoredir) { + if (!ff_pkt->ignoredir_fname) { + ff_pkt->ignoredir_fname = get_pool_memory(PM_FNAME); + } + Mmsg(ff_pkt->ignoredir_fname, "%s/%s", ff_pkt->fname, ignoredir); + if (stat(ff_pkt->ignoredir_fname, &sb) == 0) { + Dmsg2(100, "Directory '%s' ignored (found %s)\n", + ff_pkt->fname, ignoredir); + return true; /* Just ignore this directory */ + } + } + return false; +} + +/* + * When the current file is a hardlink, the backup code can compute + * the checksum and store it into the link_t structure. + */ +void +ff_pkt_set_link_digest(FF_PKT *ff_pkt, + int32_t digest_stream, const char *digest, uint32_t len) +{ + if (ff_pkt->linked && !ff_pkt->linked->digest) { /* is a hardlink */ + ff_pkt->linked->digest = (char *) bmalloc(len); + memcpy(ff_pkt->linked->digest, digest, len); + ff_pkt->linked->digest_len = len; + ff_pkt->linked->digest_stream = digest_stream; + } +} + /* * Find a single file. * handle_file is the callback for handling the file. @@ -308,7 +349,7 @@ static bool check_changes(JCR *jcr, FF_PKT *ff_pkt) * descending into a directory. */ int -find_one_file(JCR *jcr, FF_PKT *ff_pkt, +find_one_file(JCR *jcr, FF_PKT *ff_pkt, int handle_file(JCR *jcr, FF_PKT *ff, bool top_level), char *fname, dev_t parent_device, bool top_level) { @@ -345,7 +386,7 @@ find_one_file(JCR *jcr, FF_PKT *ff_pkt, char fs[100]; - if (!fstype(ff_pkt->fname, fs, sizeof(fs))) { + if (!fstype(ff_pkt, fs, sizeof(fs))) { bstrncpy(fs, "unknown", sizeof(fs)); } @@ -384,8 +425,8 @@ find_one_file(JCR *jcr, FF_PKT *ff_pkt, * since our last "save_time", presumably the last Full save * or Incremental. */ - if ( !S_ISDIR(ff_pkt->statp.st_mode) - && !check_changes(jcr, ff_pkt)) + if ( !S_ISDIR(ff_pkt->statp.st_mode) + && !check_changes(jcr, ff_pkt)) { Dmsg1(500, "Non-directory incremental: %s\n", ff_pkt->fname); ff_pkt->type = FT_NOCHG; @@ -407,6 +448,7 @@ find_one_file(JCR *jcr, FF_PKT *ff_pkt, ff_pkt->ff_errno = errno; return handle_file(jcr, ff_pkt, top_level); } + return -1; /* ignore */ } #endif @@ -446,8 +488,11 @@ find_one_file(JCR *jcr, FF_PKT *ff_pkt, ff_pkt->type = FT_LNKSAVED; /* Handle link, file already saved */ ff_pkt->LinkFI = lp->FileIndex; ff_pkt->linked = 0; + ff_pkt->digest = lp->digest; + ff_pkt->digest_stream = lp->digest_stream; + ff_pkt->digest_len = lp->digest_len; rtn_stat = handle_file(jcr, ff_pkt, top_level); - Dmsg3(400, "FT_LNKSAVED FI=%d LinkFI=%d file=%s\n", + Dmsg3(400, "FT_LNKSAVED FI=%d LinkFI=%d file=%s\n", ff_pkt->FileIndex, lp->FileIndex, lp->name); return rtn_stat; } @@ -455,6 +500,9 @@ find_one_file(JCR *jcr, FF_PKT *ff_pkt, /* File not previously dumped. Chain it into our list. */ len = strlen(fname) + 1; lp = (struct f_link *)bmalloc(sizeof(struct f_link) + len); + lp->digest = NULL; /* set later */ + lp->digest_stream = 0; /* set later */ + lp->digest_len = 0; /* set later */ lp->ino = ff_pkt->statp.st_ino; lp->dev = ff_pkt->statp.st_dev; lp->FileIndex = 0; /* set later */ @@ -485,11 +533,11 @@ find_one_file(JCR *jcr, FF_PKT *ff_pkt, if (ff_pkt->linked) { ff_pkt->linked->FileIndex = ff_pkt->FileIndex; } - Dmsg3(400, "FT_REG FI=%d linked=%d file=%s\n", ff_pkt->FileIndex, + Dmsg3(400, "FT_REG FI=%d linked=%d file=%s\n", ff_pkt->FileIndex, ff_pkt->linked ? 1 : 0, fname); if (ff_pkt->flags & FO_KEEPATIME) { utime(fname, &restore_times); - } + } return rtn_stat; @@ -528,44 +576,12 @@ find_one_file(JCR *jcr, FF_PKT *ff_pkt, bool recurse = true; bool volhas_attrlist = ff_pkt->volhas_attrlist; /* Remember this if we recurse */ - /* - * If we are using Win32 (non-portable) backup API, don't check - * access as everything is more complicated, and - * in principle, we should be able to access everything. - */ - if (!have_win32_api() || (ff_pkt->flags & FO_PORTABLE)) { - if (access(fname, R_OK) == -1 && geteuid() != 0) { - /* Could not access() directory */ - ff_pkt->type = FT_NOACCESS; - ff_pkt->ff_errno = errno; - rtn_stat = handle_file(jcr, ff_pkt, top_level); - if (ff_pkt->linked) { - ff_pkt->linked->FileIndex = ff_pkt->FileIndex; - } - return rtn_stat; - } - } - /* * Ignore this directory and everything below if the file .nobackup * (or what is defined for IgnoreDir in this fileset) exists */ - if (ff_pkt->ignoredir != NULL) { - struct stat sb; - char fname[MAXPATHLEN]; - - if (strlen(ff_pkt->fname) + strlen("/") + - strlen(ff_pkt->ignoredir) + 1 > MAXPATHLEN) - return 1; /* Is this wisdom? */ - - strcpy(fname, ff_pkt->fname); - strcat(fname, "/"); - strcat(fname, ff_pkt->ignoredir); - if (stat(fname, &sb) == 0) { - Dmsg2(100, "Directory '%s' ignored (found %s)\n", - ff_pkt->fname, ff_pkt->ignoredir); - return 1; /* Just ignore this directory */ - } + if (have_ignoredir(ff_pkt)) { + return 1; /* Just ignore this directory */ } /* Build a canonical directory name with a trailing slash in link var */ @@ -588,13 +604,32 @@ find_one_file(JCR *jcr, FF_PKT *ff_pkt, } /* * We have set st_rdev to 1 if it is a reparse point, otherwise 0, - * if st_rdev is 2, it is a mount point + * if st_rdev is 2, it is a mount point */ #if defined(HAVE_WIN32) + /* + * A reparse point (WIN32_REPARSE_POINT) + * is something special like one of the following: + * IO_REPARSE_TAG_DFS 0x8000000A + * IO_REPARSE_TAG_DFSR 0x80000012 + * IO_REPARSE_TAG_HSM 0xC0000004 + * IO_REPARSE_TAG_HSM2 0x80000006 + * IO_REPARSE_TAG_SIS 0x80000007 + * IO_REPARSE_TAG_SYMLINK 0xA000000C + * + * A junction point is a: + * IO_REPARSE_TAG_MOUNT_POINT 0xA0000003 + * which can be either a link to a Volume (WIN32_MOUNT_POINT) + * or a link to a directory (WIN32_JUNCTION_POINT) + * + * Ignore WIN32_REPARSE_POINT and WIN32_JUNCTION_POINT + */ if (ff_pkt->statp.st_rdev == WIN32_REPARSE_POINT) { ff_pkt->type = FT_REPARSE; + } else if (ff_pkt->statp.st_rdev == WIN32_JUNCTION_POINT) { + ff_pkt->type = FT_JUNCTION; } -#endif +#endif /* * Note, we return the directory to the calling program (handle_file) * when we first see the directory (FT_DIRBEGIN. @@ -604,7 +639,8 @@ find_one_file(JCR *jcr, FF_PKT *ff_pkt, * in the directory is seen (i.e. the FT_DIREND). */ rtn_stat = handle_file(jcr, ff_pkt, top_level); - if (rtn_stat < 1 || ff_pkt->type == FT_REPARSE) { /* ignore or error status */ + if (rtn_stat < 1 || ff_pkt->type == FT_REPARSE || + ff_pkt->type == FT_JUNCTION) { /* ignore or error status */ free(link); return rtn_stat; } @@ -788,21 +824,24 @@ int term_find_one(FF_PKT *ff) int count = 0; int i; - + if (ff->linkhash == NULL) return 0; for (i =0 ; i < LINK_HASHTABLE_SIZE; i ++) { /* Free up list of hard linked files */ - lp = ff->linkhash[i]; - while (lp) { - lc = lp; - lp = lp->next; - if (lc) { - free(lc); - count++; + lp = ff->linkhash[i]; + while (lp) { + lc = lp; + lp = lp->next; + if (lc) { + if (lc->digest) { + free(lc->digest); + } + free(lc); + count++; + } } - } - ff->linkhash[i] = NULL; + ff->linkhash[i] = NULL; } free(ff->linkhash); ff->linkhash = NULL;