From 989727a9b308d44693e2c220ba075cd574229d92 Mon Sep 17 00:00:00 2001 From: Kern Sibbald Date: Thu, 9 Dec 2004 21:47:28 +0000 Subject: [PATCH] - Integrated Preben 'Peppe' Guldberg patch to avoid doing MTIOCGET on OSes that do not support it such as OpenBSD. - Integrated Preben 'Peppe' Guldberg patch to add filesystem type matching to FileSets in the Options resource. - Integrated Preben 'Peppe' Guldberg patch to add Mac OSX resource fork support (save/restore) to Bacula -- HFS Plus support. git-svn-id: https://bacula.svn.sourceforge.net/svnroot/bacula/trunk@1757 91ce42f0-d328-0410-95d8-f526ca767f89 --- bacula/VERIFYING | 3 +- bacula/src/baconfig.h | 1 + bacula/src/dird/dird_conf.c | 4 + bacula/src/dird/dird_conf.h | 3 +- bacula/src/dird/fd_cmds.c | 3 + bacula/src/dird/inc_conf.c | 33 +++- bacula/src/dird/query.sql | 7 +- bacula/src/filed/backup.c | 165 ++++++++++++++++++-- bacula/src/filed/estimate.c | 20 ++- bacula/src/filed/job.c | 16 ++ bacula/src/filed/restore.c | 163 +++++++++++++++++-- bacula/src/filed/verify.c | 251 ++++++++++++++++++++---------- bacula/src/findlib/Makefile.in | 4 +- bacula/src/findlib/Makefile.mingw | 4 +- bacula/src/findlib/attribs.c | 9 ++ bacula/src/findlib/bfile.c | 34 ++++ bacula/src/findlib/bfile.h | 3 + bacula/src/findlib/find.c | 4 + bacula/src/findlib/find.h | 18 ++- bacula/src/findlib/find_one.c | 96 +++++++++++- bacula/src/findlib/fstype.c | 232 +++++++++++++++++++++++++++ bacula/src/findlib/protos.h | 3 + bacula/src/stored/btape.c | 12 +- bacula/src/stored/dev.c | 36 ++--- bacula/src/stored/dev.h | 1 + bacula/src/stored/record.c | 8 + bacula/src/stored/stored_conf.c | 1 + bacula/src/tools/Makefile.in | 5 +- bacula/src/tools/fstype.c | 91 +++++++++++ bacula/src/tools/testfind.c | 24 +-- bacula/src/version.h | 4 +- 31 files changed, 1092 insertions(+), 166 deletions(-) create mode 100644 bacula/src/findlib/fstype.c create mode 100644 bacula/src/tools/fstype.c diff --git a/bacula/VERIFYING b/bacula/VERIFYING index 8f549c4d30..2c7babd9ab 100644 --- a/bacula/VERIFYING +++ b/bacula/VERIFYING @@ -12,7 +12,7 @@ Putting the Bacula Key in your Keyring: Once you download the Bacula public key, you must insert it in your keyring. The procedure will differ depending on whether you are using PGP or GPG. For GPG, assuming you have put the key -in bacula.k, the procedure is: +in bacula.key, the procedure is: gpg --import bacula.key @@ -36,4 +36,3 @@ for GPG, you use the following command to do the verification: gpg --verify xxxx.tar.gz.sig - diff --git a/bacula/src/baconfig.h b/bacula/src/baconfig.h index db85a20c19..90033c84c6 100644 --- a/bacula/src/baconfig.h +++ b/bacula/src/baconfig.h @@ -168,6 +168,7 @@ * that it can filter packets, but otherwise, it is not used * or saved */ #define FT_DIRBEGIN 18 /* Directory at beginning (not saved) */ +#define FT_INVALIDFS 19 /* File system not allowed for */ /* Definitions for upper part of type word (see above). */ #define AR_DATA_STREAM (1<<16) /* Data stream id present */ diff --git a/bacula/src/dird/dird_conf.c b/bacula/src/dird/dird_conf.c index ef72bee1ad..433945d9bd 100644 --- a/bacula/src/dird/dird_conf.c +++ b/bacula/src/dird/dird_conf.c @@ -587,6 +587,9 @@ void dump_resource(int type, RES *reshdr, void sendit(void *sock, const char *fm for (k=0; kbase.size(); k++) { sendit(sock, " B %s\n", fo->base.get(k)); } + for (k=0; kfstype.size(); k++) { + sendit(sock, " X %s\n", fo->fstype.get(k)); + } if (fo->reader) { sendit(sock, " D %s\n", fo->reader); } @@ -748,6 +751,7 @@ static void free_incexe(INCEXE *incexe) fopt->regex.destroy(); fopt->wild.destroy(); fopt->base.destroy(); + fopt->fstype.destroy(); if (fopt->reader) { free(fopt->reader); } diff --git a/bacula/src/dird/dird_conf.h b/bacula/src/dird/dird_conf.h index c33913d24d..d008a969f7 100644 --- a/bacula/src/dird/dird_conf.h +++ b/bacula/src/dird/dird_conf.h @@ -244,7 +244,7 @@ struct JOB { }; #undef MAX_FOPTS -#define MAX_FOPTS 32 +#define MAX_FOPTS 34 /* File options structure */ struct FOPTS { @@ -252,6 +252,7 @@ struct FOPTS { alist regex; /* regex string(s) */ alist wild; /* wild card strings */ alist base; /* list of base names */ + alist fstype; /* file system type limitation */ char *reader; /* reader program */ char *writer; /* writer program */ }; diff --git a/bacula/src/dird/fd_cmds.c b/bacula/src/dird/fd_cmds.c index 46131fc04b..77ae25fdbf 100644 --- a/bacula/src/dird/fd_cmds.c +++ b/bacula/src/dird/fd_cmds.c @@ -406,6 +406,9 @@ static int send_fileset(JCR *jcr) for (k=0; kbase.size(); k++) { bnet_fsend(fd, "B %s\n", fo->base.get(k)); } + for (k=0; kfstype.size(); k++) { + bnet_fsend(fd, "X %s\n", fo->fstype.get(k)); + } if (fo->reader) { bnet_fsend(fd, "D %s\n", fo->reader); } diff --git a/bacula/src/dird/inc_conf.c b/bacula/src/dird/inc_conf.c index 23c514e32c..079904c94c 100644 --- a/bacula/src/dird/inc_conf.c +++ b/bacula/src/dird/inc_conf.c @@ -39,6 +39,7 @@ void store_inc(LEX *lc, RES_ITEM *item, int index, int pass); static void store_newinc(LEX *lc, RES_ITEM *item, int index, int pass); static void store_regex(LEX *lc, RES_ITEM *item, int index, int pass); static void store_wild(LEX *lc, RES_ITEM *item, int index, int pass); +static void store_fstype(LEX *lc, RES_ITEM *item, int index, int pass); static void store_opts(LEX *lc, RES_ITEM *item, int index, int pass); static void store_fname(LEX *lc, RES_ITEM *item, int index, int pass); static void options_res(LEX *lc, RES_ITEM *item, int index, int pass); @@ -93,6 +94,8 @@ static RES_ITEM options_items[] = { {"reader", store_reader, NULL, 0, 0, 0}, {"writer", store_writer, NULL, 0, 0, 0}, {"ignorecase", store_opts, NULL, 0, 0, 0}, + {"fstype", store_fstype, NULL, 0, 0, 0}, + {"hfsplussupport", store_opts, NULL, 0, 0, 0}, {NULL, NULL, NULL, 0, 0, 0} }; @@ -116,7 +119,8 @@ enum { INC_KW_KEEPATIME, INC_KW_EXCLUDE, INC_KW_ACL, - INC_KW_IGNORECASE + INC_KW_IGNORECASE, + INC_KW_HFSPLUS }; /* @@ -140,6 +144,7 @@ static struct s_kw FS_option_kw[] = { {"exclude", INC_KW_EXCLUDE}, {"aclsupport", INC_KW_ACL}, {"ignorecase", INC_KW_IGNORECASE}, + {"hfsplussupport", INC_KW_HFSPLUS}, {NULL, 0} }; @@ -197,6 +202,8 @@ static struct s_fs_opt FS_options[] = { {"no", INC_KW_ACL, "0"}, {"yes", INC_KW_IGNORECASE, "i"}, {"no", INC_KW_IGNORECASE, "0"}, + {"yes", INC_KW_HFSPLUS, "R"}, /* "R" for resource fork */ + {"no", INC_KW_HFSPLUS, "0"}, {NULL, 0, 0} }; @@ -563,6 +570,28 @@ static void store_wild(LEX *lc, RES_ITEM *item, int index, int pass) scan_to_eol(lc); } +/* Store fstype info */ +static void store_fstype(LEX *lc, RES_ITEM *item, int index, int pass) +{ + int token; + + token = lex_get_token(lc, T_SKIP_EOL); + if (pass == 1) { + /* Pickup fstype string */ + switch (token) { + case T_IDENTIFIER: + case T_UNQUOTED_STRING: + case T_QUOTED_STRING: + res_incexe.current_opts->fstype.append(bstrdup(lc->str)); + Dmsg3(900, "set fstype %p size=%d %s\n", + res_incexe.current_opts, res_incexe.current_opts->fstype.size(), lc->str); + break; + default: + scan_err1(lc, _("Expected an fstype string, got: %s\n"), lc->str); + } + } + scan_to_eol(lc); +} /* * Store Filename info. Note, for minor efficiency reasons, we @@ -599,6 +628,7 @@ static void store_fname(LEX *lc, RES_ITEM *item, int index, int pass) scan_to_eol(lc); } + /* * Come here when Options seen in Include/Exclude */ @@ -684,6 +714,7 @@ static void setup_current_opts(void) fo->regex.init(1, true); fo->wild.init(1, true); fo->base.init(1, true); + fo->fstype.init(1, true); res_incexe.current_opts = fo; if (res_incexe.num_opts == 0) { res_incexe.opts_list = (FOPTS **)malloc(sizeof(FOPTS *)); diff --git a/bacula/src/dird/query.sql b/bacula/src/dird/query.sql index 443cf8f867..55101486c9 100644 --- a/bacula/src/dird/query.sql +++ b/bacula/src/dird/query.sql @@ -58,12 +58,13 @@ SELECT DISTINCT Job.JobId,Client.Name as Client,Level,StartTime,JobFiles,JobByte # 6 :List all backups for a Client *Enter Client Name: -SELECT DISTINCT Job.JobId as JobId,Client.Name as Client,Level,StartTime, +SELECT DISTINCT Job.JobId as JobId,Client.Name as Client, + FileSet.FileSet AS FileSet,Level,StartTime, JobFiles,JobBytes,VolumeName - FROM Client,Job,JobMedia,Media + FROM Client,Job,JobMedia,Media,FileSet WHERE Client.Name='%1' AND Client.ClientId=Job.ClientId - AND JobStatus='T' + AND JobStatus='T' AND Job.FileSetId=FileSet.FileSetId AND JobMedia.JobId=Job.JobId AND JobMedia.MediaId=Media.MediaId ORDER BY Job.StartTime; # 7 diff --git a/bacula/src/filed/backup.c b/bacula/src/filed/backup.c index 81021f6946..9fbe3f7c9b 100644 --- a/bacula/src/filed/backup.c +++ b/bacula/src/filed/backup.c @@ -35,6 +35,10 @@ #include #endif +#ifdef HAVE_DARWIN_OS +#include +#endif + static int save_file(FF_PKT *ff_pkt, void *pkt); /* @@ -130,6 +134,7 @@ static int save_file(FF_PKT *ff_pkt, void *vjcr) char attribs[MAXSTRING]; char attribsEx[MAXSTRING]; int stat, attr_stream, data_stream; + bool hfsplus = false; struct MD5Context md5c; struct SHA1Context sha1c; int gotMD5 = 0; @@ -163,15 +168,19 @@ static int save_file(FF_PKT *ff_pkt, void *vjcr) return 1; /* not used */ case FT_NORECURSE: case FT_NOFSCHG: + case FT_INVALIDFS: case FT_DIREND: if (ff_pkt->type == FT_NORECURSE) { - Jmsg(jcr, M_INFO, 1, _(" Recursion turned off. Will not descend into %s\n"), + Jmsg(jcr, M_INFO, 1, _(" Recursion turned off. Will not descend into %s\n"), ff_pkt->fname); } else if (ff_pkt->type == FT_NOFSCHG) { - Jmsg(jcr, M_INFO, 1, _(" File system change prohibited. Will not descend into %s\n"), + Jmsg(jcr, M_INFO, 1, _(" File system change prohibited. Will not descend into %s\n"), + ff_pkt->fname); + } else if (ff_pkt->type == FT_INVALIDFS) { + Jmsg(jcr, M_INFO, 1, _(" Disallowed filesystem. Will not descend into %s\n"), ff_pkt->fname); } - ff_pkt->type = FT_DIREND; /* value is used below */ + ff_pkt->type = FT_DIREND; /* value is used below */ Dmsg1(130, "FT_DIR saving: %s\n", ff_pkt->link); break; case FT_SPEC: @@ -269,6 +278,29 @@ static int save_file(FF_PKT *ff_pkt, void *vjcr) } } + binit(&ff_pkt->rsrc_bfd); +#ifdef HAVE_DARWIN_OS + /* Open resource fork if necessary */ + if (ff_pkt->type != FT_LNKSAVED && (S_ISREG(ff_pkt->statp.st_mode) && + ff_pkt->flags & FO_HFSPLUS)) { + /* Remember Finder Info, whether we have data or fork, or not */ + hfsplus = true; + if (ff_pkt->hfsinfo.rsrclength > 0) { + if (!bopen_rsrc(&ff_pkt->rsrc_bfd, ff_pkt->fname, O_RDONLY | O_BINARY, 0) < 0) { + ff_pkt->ff_errno = errno; + berrno be; + Jmsg(jcr, M_NOTSAVED, -1, _(" Cannot open resource fork for %s: ERR=%s.\n"), ff_pkt->fname, + be.strerror()); + jcr->Errors++; + if (is_bopen(&ff_pkt->bfd)) { + bclose(&ff_pkt->bfd); + } + return 1; + } + } + } +#endif + Dmsg1(130, "bfiled: sending %s to stored\n", ff_pkt->fname); /* Find what data stream we will use, then encode the attributes */ @@ -295,6 +327,9 @@ static int save_file(FF_PKT *ff_pkt, void *vjcr) if (is_bopen(&ff_pkt->bfd)) { bclose(&ff_pkt->bfd); } + if (is_bopen(&ff_pkt->rsrc_bfd)) { + bclose(&ff_pkt->rsrc_bfd); + } Jmsg1(jcr, M_FATAL, 0, _("Network send error to SD. ERR=%s\n"), bnet_strerror(sd)); return 0; @@ -333,12 +368,23 @@ static int save_file(FF_PKT *ff_pkt, void *vjcr) if (is_bopen(&ff_pkt->bfd)) { bclose(&ff_pkt->bfd); } + if (is_bopen(&ff_pkt->rsrc_bfd)) { + bclose(&ff_pkt->rsrc_bfd); + } Jmsg1(jcr, M_FATAL, 0, _("Network send error to SD. ERR=%s\n"), bnet_strerror(sd)); return 0; } bnet_sig(sd, BNET_EOD); /* indicate end of attributes data */ + if (is_bopen(&ff_pkt->bfd) || hfsplus) { + if (ff_pkt->flags & FO_MD5) { + MD5Init(&md5c); + } else if (ff_pkt->flags & FO_SHA1) { + SHA1Init(&sha1c); + } + } + /* * If the file has data, read it and send to the Storage daemon * @@ -379,18 +425,15 @@ static int save_file(FF_PKT *ff_pkt, void *vjcr) if (!bnet_fsend(sd, "%ld %d 0", jcr->JobFiles, data_stream)) { berrno be; bclose(&ff_pkt->bfd); + if (is_bopen(&ff_pkt->rsrc_bfd)) { + bclose(&ff_pkt->rsrc_bfd); + } Jmsg1(jcr, M_FATAL, 0, _("Network send error to SD. ERR=%s\n"), bnet_strerror(sd)); return 0; } Dmsg1(300, ">stored: datahdr %s\n", sd->msg); - if (ff_pkt->flags & FO_MD5) { - MD5Init(&md5c); - } else if (ff_pkt->flags & FO_SHA1) { - SHA1Init(&sha1c); - } - /* * Make space at beginning of buffer for fileAddr because this * same buffer will be used for writing if compression if off. @@ -452,6 +495,9 @@ static int save_file(FF_PKT *ff_pkt, void *vjcr) sd->msg = msgsave; sd->msglen = 0; bclose(&ff_pkt->bfd); + if (is_bopen(&ff_pkt->rsrc_bfd)) { + bclose(&ff_pkt->rsrc_bfd); + } set_jcr_job_status(jcr, JS_ErrorTerminated); return 0; } @@ -475,6 +521,9 @@ static int save_file(FF_PKT *ff_pkt, void *vjcr) sd->msg = msgsave; /* restore bnet buffer */ sd->msglen = 0; bclose(&ff_pkt->bfd); + if (is_bopen(&ff_pkt->rsrc_bfd)) { + bclose(&ff_pkt->rsrc_bfd); + } return 0; } } @@ -495,12 +544,108 @@ static int save_file(FF_PKT *ff_pkt, void *vjcr) bclose(&ff_pkt->bfd); /* close file */ if (!bnet_sig(sd, BNET_EOD)) { /* indicate end of file data */ + berrno be; + Jmsg1(jcr, M_FATAL, 0, _("Network send error to SD. ERR=%s\n"), + bnet_strerror(sd)); + if (is_bopen(&ff_pkt->rsrc_bfd)) { + bclose(&ff_pkt->rsrc_bfd); + } + return 0; + } + } + +#ifdef HAVE_DARWIN_OS + /* + * If resource fork has data, read it and send to the Storage daemon + * + */ + if (is_bopen(&ff_pkt->rsrc_bfd)) { + uint64_t fileAddr = 0; /* file address */ + int rsize = jcr->buf_size; /* read buffer size */ + + Dmsg1(300, "Saving resource fork for \"%s\"", ff_pkt->fname); + + /* + * Send Data header to Storage daemon + * + */ + if (!bnet_fsend(sd, "%ld %d 0", jcr->JobFiles, STREAM_MACOS_FORK_DATA)) { + berrno be; + bclose(&ff_pkt->rsrc_bfd); + Jmsg1(jcr, M_FATAL, 0, _("Network send error to SD. ERR=%s\n"), + bnet_strerror(sd)); + return 0; + } + Dmsg1(300, ">stored: datahdr %s\n", sd->msg); + + /* + * Read the resource fork + */ + while ((sd->msglen=(uint32_t)bread(&ff_pkt->rsrc_bfd, sd->msg, rsize)) > 0) { + jcr->ReadBytes += sd->msglen; /* count bytes read */ + fileAddr += sd->msglen; + + /* Update MD5 if requested */ + if (ff_pkt->flags & FO_MD5) { + MD5Update(&md5c, (unsigned char *)sd->msg, sd->msglen); + gotMD5 = 1; + } else if (ff_pkt->flags & FO_SHA1) { + SHA1Update(&sha1c, (unsigned char *)sd->msg, sd->msglen); + gotSHA1 = 1; + } + + /* Send the buffer to the Storage daemon */ + if (!bnet_send(sd)) { + berrno be; + Jmsg2(jcr, M_FATAL, 0, _("Network send error %d to SD. ERR=%s\n"), + sd->msglen, bnet_strerror(sd)); + sd->msglen = 0; + bclose(&ff_pkt->rsrc_bfd); + return 0; + } + Dmsg1(130, "Send data to SD len=%d\n", sd->msglen); + /* #endif */ + jcr->JobBytes += sd->msglen; /* count bytes saved possibly compressed */ + } /* end while read file data */ + + if (sd->msglen < 0) { + berrno be; + be.set_errno(ff_pkt->rsrc_bfd.berrno); + Jmsg(jcr, M_ERROR, 0, _("Read error on resource fork of %s. ERR=%s\n"), + ff_pkt->fname, be.strerror()); + } + + bclose(&ff_pkt->rsrc_bfd); /* close resource fork */ + if (!bnet_sig(sd, BNET_EOD)) { /* indicate end of resource fork */ berrno be; Jmsg1(jcr, M_FATAL, 0, _("Network send error to SD. ERR=%s\n"), bnet_strerror(sd)); return 0; } } +#endif + +#ifdef HAVE_DARWIN_OS + /* Handle Finder Info */ + if (S_ISREG(ff_pkt->statp.st_mode) && ff_pkt->flags & FO_HFSPLUS) { + Dmsg1(300, "Saving Finder Info for \"%s\"", ff_pkt->fname); + bnet_fsend(sd, "%ld %d 0", jcr->JobFiles, STREAM_HFSPLUS_ATTRIBUTES); + Dmsg1(300, "bfiled>stored:header %s\n", sd->msg); + memcpy(sd->msg, ff_pkt->hfsinfo.fndrinfo, 32); + sd->msglen = 32; + /* Update MD5 if requested */ + if (ff_pkt->flags & FO_MD5) { + MD5Update(&md5c, (unsigned char *)sd->msg, sd->msglen); + gotMD5 = 1; + } else if (ff_pkt->flags & FO_SHA1) { + SHA1Update(&sha1c, (unsigned char *)sd->msg, sd->msglen); + gotSHA1 = 1; + } + bnet_send(sd); + bnet_sig(sd, BNET_EOD); + } +#endif + #ifdef HAVE_ACL /* ACL stream */ @@ -556,13 +701,11 @@ static int save_file(FF_PKT *ff_pkt, void *vjcr) berrno be; sd->msg = msgsave; sd->msglen = 0; - bclose(&ff_pkt->bfd); Jmsg1(jcr, M_FATAL, 0, _("Network send error to SD. ERR=%s\n"), bnet_strerror(sd)); } else { jcr->JobBytes += sd->msglen; sd->msg = msgsave; - bclose(&ff_pkt->bfd); if (!bnet_sig(sd, BNET_EOD)) { berrno be; Jmsg1(jcr, M_FATAL, 0, _("Network send error to SD. ERR=%s\n"), diff --git a/bacula/src/filed/estimate.c b/bacula/src/filed/estimate.c index bee59417ea..eaa181a6b2 100644 --- a/bacula/src/filed/estimate.c +++ b/bacula/src/filed/estimate.c @@ -64,6 +64,9 @@ static int tally_file(FF_PKT *ff_pkt, void *ijcr) case FT_REGE: case FT_REG: case FT_LNK: + case FT_NORECURSE: + case FT_NOFSCHG: + case FT_INVALIDFS: case FT_DIREND: case FT_SPEC: case FT_RAW: @@ -76,16 +79,23 @@ static int tally_file(FF_PKT *ff_pkt, void *ijcr) case FT_DIRNOCHG: case FT_NOCHG: case FT_ISARCH: - case FT_NORECURSE: - case FT_NOFSCHG: case FT_NOOPEN: default: return 1; } - if (ff_pkt->type != FT_LNKSAVED && S_ISREG(ff_pkt->statp.st_mode) && - ff_pkt->statp.st_size > 0) { - jcr->JobBytes += ff_pkt->statp.st_size; + if (ff_pkt->type != FT_LNKSAVED && S_ISREG(ff_pkt->statp.st_mode)) { + if (ff_pkt->statp.st_size > 0) { + jcr->JobBytes += ff_pkt->statp.st_size; + } +#ifdef HAVE_DARWIN_OS + if (ff_pkt->flags & FO_HFSPLUS) { + if (ff_pkt->hfsinfo.rsrclength > 0) { + jcr->JobBytes += ff_pkt->hfsinfo.rsrclength; + } + jcr->JobBytes += 32; /* Finder info */ + } +#endif } jcr->num_files_examined++; jcr->JobFiles++; /* increment number of files seen */ diff --git a/bacula/src/filed/job.c b/bacula/src/filed/job.c index 623f665bf5..1cbb589aa0 100644 --- a/bacula/src/filed/job.c +++ b/bacula/src/filed/job.c @@ -250,6 +250,7 @@ void *handle_client_request(void *dirp) fo->regex.destroy(); fo->wild.destroy(); fo->base.destroy(); + fo->fstype.destroy(); if (fo->reader) { free(fo->reader); } @@ -270,6 +271,7 @@ void *handle_client_request(void *dirp) fo->regex.destroy(); fo->wild.destroy(); fo->base.destroy(); + fo->fstype.destroy(); } incexe->opts_list.destroy(); incexe->name_list.destroy(); @@ -627,6 +629,7 @@ static findFOPTS *start_options(FF_PKT *ff) fo->regex.init(1, true); fo->wild.init(1, true); fo->base.init(1, true); + fo->fstype.init(1, true); incexe->current_opts = fo; incexe->opts_list.append(fo); } @@ -759,6 +762,11 @@ static void add_fileset(JCR *jcr, const char *item) current_opts->base.append(bstrdup(item)); state = state_options; break; + case 'X': + current_opts = start_options(ff); + current_opts->fstype.append(bstrdup(item)); + state = state_options; + break; case 'W': current_opts = start_options(ff); current_opts->wild.append(bstrdup(item)); @@ -807,6 +815,9 @@ static bool term_fileset(JCR *jcr) for (k=0; kbase.size(); k++) { Dmsg1(400, "B %s\n", (char *)fo->base.get(k)); } + for (k=0; kfstype.size(); k++) { + Dmsg1(400, "X %s\n", (char *)fo->fstype.get(k)); + } if (fo->reader) { Dmsg1(400, "D %s\n", fo->reader); } @@ -832,6 +843,9 @@ static bool term_fileset(JCR *jcr) for (k=0; kbase.size(); k++) { Dmsg1(400, "B %s\n", (char *)fo->base.get(k)); } + for (k=0; kfstype.size(); k++) { + Dmsg1(400, "X %s\n", (char *)fo->fstype.get(k)); + } } for (j=0; jname_list.size(); j++) { Dmsg1(400, "F %s\n", (char *)incexe->name_list.get(j)); @@ -880,6 +894,8 @@ static void set_options(findFOPTS *fo, const char *opts) case 'p': /* use portable data format */ fo->flags |= FO_PORTABLE; break; + case 'R': /* Resource forks and Finder Info */ + fo->flags |= FO_HFSPLUS; case 'r': /* read fifo */ fo->flags |= FO_READFIFO; break; diff --git a/bacula/src/filed/restore.c b/bacula/src/filed/restore.c index 3ad0006cf8..7c4d7173ae 100644 --- a/bacula/src/filed/restore.c +++ b/bacula/src/filed/restore.c @@ -34,6 +34,11 @@ #include #endif +#ifdef HAVE_DARWIN_OS +#include +#include +#endif + /* Data received from Storage Daemon */ static char rec_header[] = "rechdr %ld %ld %ld %ld %ld"; @@ -44,6 +49,25 @@ static const char *zlib_strerror(int stat); #define RETRY 10 /* retry wait time */ +#ifdef HAVE_DARWIN_OS +/* helper routine for closing resource forks */ +int bclose_chksize(JCR *jcr, BFILE *bfd, off_t osize) +{ + char ec1[50], ec2[50]; + off_t fsize; + + fsize = blseek(bfd, 0, SEEK_CUR); + bclose(bfd); /* first close file */ + if (fsize > 0 && fsize != osize) { + Jmsg3(jcr, M_ERROR, 0, _("File size of resource fork for restored file %s not correct. Original %s, restored %s.\n"), + jcr->last_fname, edit_uint64(osize, ec1), + edit_uint64(fsize, ec2)); + return -1; + } + return 0; +} +#endif + /* * Restore the requested files. * @@ -64,12 +88,26 @@ void do_restore(JCR *jcr) uint64_t fileAddr = 0; /* file write address */ int non_support_data = 0; int non_support_attr = 0; + int non_support_rsrc = 0; + int non_support_finfo = 0; int non_support_acl = 0; int prog_name_msg = 0; ATTR *attr; #ifdef HAVE_ACL acl_t acl; #endif + BFILE rsrc_bfd; /* we often check if it is open */ +#ifdef HAVE_DARWIN_OS + off_t rsrcAddr = 0; + off_t rsrc_len; /* original length of resource fork */ + + /* TODO: initialise attrList once elsewhere? */ + struct attrlist attrList; + memset(&attrList, 0, sizeof(attrList)); + attrList.bitmapcount = ATTR_BIT_MAP_COUNT; + attrList.commonattr = ATTR_CMN_FNDRINFO; +#endif + binit(&rsrc_bfd); binit(&bfd); sd = jcr->store_bsock; @@ -104,7 +142,10 @@ void do_restore(JCR *jcr) * 2. Stream data * a. Attributes (Unix or Win32) * or b. File data for the file - * or c. Possibly MD5 or SHA1 record + * or c. Resource fork + * or d. Finder info + * or e. ACLs + * or f. Possibly MD5 or SHA1 record * 3. Repeat step 1 */ while (bget_msg(sd) >= 0 && !job_canceled(jcr)) { @@ -140,14 +181,26 @@ void do_restore(JCR *jcr) * close the output file. */ if (extract) { - if (!is_bopen(&bfd)) { + if (!is_bopen(&bfd) +#ifdef HAVE_DARWIN_OS + && !is_bopen(&rsrc_bfd) +#endif + ) { Jmsg0(jcr, M_ERROR, 0, _("Logic error output file should be open\n")); } - set_attributes(jcr, attr, &bfd); +#ifdef HAVE_DARWIN_OS + if (is_bopen(&rsrc_bfd)) { + bclose_chksize(jcr, &rsrc_bfd, rsrc_len); + } +#endif + if (is_bopen(&bfd)) { + set_attributes(jcr, attr, &bfd); + } extract = false; Dmsg0(30, "Stop extracting.\n"); } + if (!unpack_attributes_record(jcr, stream, sd->msg, attr)) { goto bail_out; } @@ -173,6 +226,10 @@ void do_restore(JCR *jcr) build_attr_output_fnames(jcr, attr); +#ifdef HAVE_DARWIN_OS + from_base64(&rsrc_len, attr->attrEx); +#endif + jcr->num_files_examined++; Dmsg1(30, "Outfile=%s\n", attr->ofname); @@ -184,14 +241,7 @@ void do_restore(JCR *jcr) break; case CF_EXTRACT: extract = true; - P(jcr->mutex); - pm_strcpy(jcr->last_fname, attr->ofname); - V(jcr->mutex); - jcr->JobFiles++; - fileAddr = 0; - print_ls_output(jcr, attr); - /* Set attributes after file extracted */ - break; + /* FALLTHROUGH */ case CF_CREATED: P(jcr->mutex); pm_strcpy(jcr->last_fname, attr->ofname); @@ -199,8 +249,21 @@ void do_restore(JCR *jcr) jcr->JobFiles++; fileAddr = 0; print_ls_output(jcr, attr); - /* set attributes now because file will not be extracted */ - set_attributes(jcr, attr, &bfd); + if (!extract) { + /* set attributes now because file will not be extracted */ + set_attributes(jcr, attr, &bfd); + } +#ifdef HAVE_DARWIN_OS + if (rsrc_len > 0) { + rsrcAddr = 0; + if (bopen_rsrc(&rsrc_bfd, jcr->last_fname, O_WRONLY | O_TRUNC | O_BINARY, 0) < 0) { + Jmsg(jcr, M_ERROR, 0, _(" Cannot open resource fork for %s"), jcr->last_fname); + } else { + Dmsg0(30, "Restoring resource fork"); + extract = true; + } + } +#endif break; } break; @@ -228,6 +291,9 @@ void do_restore(JCR *jcr) edit_uint64(fileAddr, ec1), attr->ofname, be.strerror()); extract = false; bclose(&bfd); + if (is_bopen(&rsrc_bfd)) { + bclose(&rsrc_bfd); + } continue; } } @@ -244,6 +310,9 @@ void do_restore(JCR *jcr) be.strerror()); extract = false; bclose(&bfd); + if (is_bopen(&rsrc_bfd)) { + bclose(&rsrc_bfd); + } continue; } total += wsize; @@ -279,6 +348,9 @@ void do_restore(JCR *jcr) edit_uint64(fileAddr, ec1), attr->ofname, be.strerror()); extract = false; bclose(&bfd); + if (is_bopen(&rsrc_bfd)) { + bclose(&rsrc_bfd); + } continue; } } @@ -294,6 +366,9 @@ void do_restore(JCR *jcr) attr->ofname, zlib_strerror(stat)); extract = false; bclose(&bfd); + if (is_bopen(&rsrc_bfd)) { + bclose(&rsrc_bfd); + } continue; } @@ -305,6 +380,9 @@ void do_restore(JCR *jcr) Jmsg2(jcr, M_ERROR, 0, _("Write error on %s: %s\n"), attr->ofname, be.strerror()); extract = false; bclose(&bfd); + if (is_bopen(&rsrc_bfd)) { + bclose(&rsrc_bfd); + } continue; } total += compress_len; @@ -317,11 +395,59 @@ void do_restore(JCR *jcr) Jmsg(jcr, M_ERROR, 0, _("GZIP data stream found, but GZIP not configured!\n")); extract = false; bclose(&bfd); + if (is_bopen(&rsrc_bfd)) { + bclose(&rsrc_bfd); + } continue; } #endif break; + /* Resource fork stream - only recorded after a file to be restored */ + /* Silently ignore if we cannot write - we already reported that */ + case STREAM_MACOS_FORK_DATA: +#ifdef HAVE_DARWIN_OS + if (is_bopen(&rsrc_bfd) && sd->msglen) { + Dmsg2(30, "Write %u bytes, total before write=%u\n", sd->msglen, total); + if (bwrite(&rsrc_bfd, sd->msg, sd->msglen) != sd->msglen) { + Dmsg0(0, "===Write error===\n"); + berrno be; + be.set_errno(rsrc_bfd.berrno); + Jmsg2(jcr, M_ERROR, 0, _("Write error on resource fork of %s: ERR=%s\n"), jcr->last_fname, + be.strerror()); + extract = false; + if (is_bopen(&bfd)) { + bclose(&bfd); + } + bclose(&rsrc_bfd); + continue; + } + total += sd->msglen; + jcr->JobBytes += sd->msglen; + jcr->ReadBytes += sd->msglen; + rsrcAddr += sd->msglen; + } + break; +#else + non_support_rsrc++; +#endif + + case STREAM_HFSPLUS_ATTRIBUTES: +#ifdef HAVE_DARWIN_OS + Dmsg0(30, "Restoring Finder Info"); + if (sd->msglen != 32) { + Jmsg(jcr, M_ERROR, 0, _(" Invalid length of Finder Info (got %d, not 32)"), sd->msglen); + continue; + } + if (setattrlist(jcr->last_fname, &attrList, sd->msg, sd->msglen, 0) != 0) { + Jmsg(jcr, M_ERROR, 0, _(" Could not set Finder Info on %s"), jcr->last_fname); + continue; + } + break; +#else + non_support_finfo++; +#endif + case STREAM_UNIX_ATTRIBUTES_ACL: #ifdef HAVE_ACL /* Recover ACL from stream and check it */ @@ -395,6 +521,11 @@ ok_out: free(jcr->compress_buf); jcr->compress_buf = NULL; } +#ifdef HAVE_DARWIN_OS + if (is_bopen(&rsrc_bfd)) { + bclose_chksize(jcr, &rsrc_bfd, rsrc_len); + } +#endif bclose(&bfd); free_attr(attr); Dmsg2(10, "End Do Restore. Files=%d Bytes=%" lld "\n", jcr->JobFiles, @@ -403,6 +534,12 @@ ok_out: Jmsg(jcr, M_ERROR, 0, _("%d non-supported data streams and %d non-supported attrib streams ignored.\n"), non_support_data, non_support_attr); } + if (non_support_rsrc) { + Jmsg(jcr, M_INFO, 0, _("%d non-supported resource fork streams ignored.\n"), non_support_rsrc); + } + if (non_support_finfo) { + Jmsg(jcr, M_INFO, 0, _("%d non-supported Finder Info streams ignored.\n"), non_support_rsrc); + } if (non_support_acl) { Jmsg(jcr, M_INFO, 0, _("%d non-supported acl streams ignored.\n"), non_support_acl); } diff --git a/bacula/src/filed/verify.c b/bacula/src/filed/verify.c index ced8398772..7deceb5f49 100644 --- a/bacula/src/filed/verify.c +++ b/bacula/src/filed/verify.c @@ -29,6 +29,10 @@ #include "bacula.h" #include "filed.h" +#ifdef HAVE_DARWIN_OS +#include +#endif + static int verify_file(FF_PKT *ff_pkt, void *my_pkt); /* @@ -65,9 +69,12 @@ void do_verify(JCR *jcr) static int verify_file(FF_PKT *ff_pkt, void *pkt) { char attribs[MAXSTRING]; + char attribsEx[MAXSTRING]; int64_t n; int stat; BFILE bfd; + BFILE rsrc_bfd; + bool hfsplus = false; struct MD5Context md5c; struct SHA1Context sha1c; unsigned char signature[25]; /* large enough for either */ @@ -171,97 +178,171 @@ static int verify_file(FF_PKT *ff_pkt, void *pkt) } } - encode_stat(attribs, ff_pkt, 0); - - P(jcr->mutex); - jcr->JobFiles++; /* increment number of files sent */ - pm_strcpy(jcr->last_fname, ff_pkt->fname); - V(jcr->mutex); - - /* - * Send file attributes to Director - * File_index - * Stream - * Verify Options - * Filename (full path) - * Encoded attributes - * Link name (if type==FT_LNK) - * For a directory, link is the same as fname, but with trailing - * slash. For a linked file, link is the link. - */ - /* Send file attributes to Director (note different format than for Storage) */ - Dmsg2(400, "send ATTR inx=%d fname=%s\n", jcr->JobFiles, ff_pkt->fname); - if (ff_pkt->type == FT_LNK || ff_pkt->type == FT_LNKSAVED) { - stat = bnet_fsend(dir, "%d %d %s %s%c%s%c%s%c", jcr->JobFiles, - STREAM_UNIX_ATTRIBUTES, ff_pkt->VerifyOpts, ff_pkt->fname, - 0, attribs, 0, ff_pkt->link, 0); - } else if (ff_pkt->type == FT_DIREND) { - /* Here link is the canonical filename (i.e. with trailing slash) */ - stat = bnet_fsend(dir,"%d %d %s %s%c%s%c%c", jcr->JobFiles, - STREAM_UNIX_ATTRIBUTES, ff_pkt->VerifyOpts, ff_pkt->link, - 0, attribs, 0, 0); - } else { - stat = bnet_fsend(dir,"%d %d %s %s%c%s%c%c", jcr->JobFiles, - STREAM_UNIX_ATTRIBUTES, ff_pkt->VerifyOpts, ff_pkt->fname, - 0, attribs, 0, 0); - } - Dmsg2(20, "bfiled>bdird: attribs len=%d: msg=%s\n", dir->msglen, dir->msg); - if (!stat) { - Jmsg(jcr, M_FATAL, 0, _("Network error in send to Director: ERR=%s\n"), bnet_strerror(dir)); - if (is_bopen(&bfd)) { - bclose(&bfd); + binit(&rsrc_bfd); /* we check if this is open below */ +#ifdef HAVE_DARWIN_OS + /* Open resource fork if necessary */ + if (ff_pkt->type != FT_LNKSAVED && (S_ISREG(ff_pkt->statp.st_mode) && + ff_pkt->flags & FO_HFSPLUS)) { + /* Remember Finder Info, whether we have data or fork, or not */ + hfsplus = true; + if (ff_pkt->hfsinfo.rsrclength > 0) { + if (bopen_rsrc(&rsrc_bfd, ff_pkt->fname, O_RDONLY | O_BINARY, 0) < 0) { + ff_pkt->ff_errno = errno; + berrno be; + Jmsg(jcr, M_NOTSAVED, -1, _(" Cannot open resource fork for %s: ERR=%s\n"), + ff_pkt->fname, be.strerror()); + jcr->Errors++; + if (is_bopen(&ff_pkt->bfd)) { + bclose(&ff_pkt->bfd); + } + return 1; + } } - return 0; } +#endif + + encode_stat(attribs, ff_pkt, 0); - /* If file opened, compute MD5 or SHA1 hash */ - if (is_bopen(&bfd) && ff_pkt->flags & FO_MD5) { - char MD5buf[40]; /* 24 should do */ - MD5Init(&md5c); - while ((n=bread(&bfd, jcr->big_buf, jcr->buf_size)) > 0) { - MD5Update(&md5c, ((unsigned char *)jcr->big_buf), (int)n); - jcr->JobBytes += n; - jcr->ReadBytes += n; + /* Now possibly extend the attributes */ + encode_attribsEx(jcr, attribsEx, ff_pkt); + + P(jcr->mutex); + jcr->JobFiles++; /* increment number of files sent */ + pm_strcpy(jcr->last_fname, ff_pkt->fname); + V(jcr->mutex); + + /* + * Send file attributes to Director + * File_index + * Stream + * Verify Options + * Filename (full path) + * Encoded attributes + * Link name (if type==FT_LNK) + * For a directory, link is the same as fname, but with trailing + * slash. For a linked file, link is the link. + */ + /* Send file attributes to Director (note different format than for Storage) */ + Dmsg2(400, "send ATTR inx=%d fname=%s\n", jcr->JobFiles, ff_pkt->fname); + if (ff_pkt->type == FT_LNK || ff_pkt->type == FT_LNKSAVED) { + stat = bnet_fsend(dir, "%d %d %s %s%c%s%c%s%c", jcr->JobFiles, + STREAM_UNIX_ATTRIBUTES, ff_pkt->VerifyOpts, ff_pkt->fname, + 0, attribs, 0, ff_pkt->link, 0); + } else if (ff_pkt->type == FT_DIREND) { + /* Here link is the canonical filename (i.e. with trailing slash) */ + stat = bnet_fsend(dir,"%d %d %s %s%c%s%c%c", jcr->JobFiles, + STREAM_UNIX_ATTRIBUTES, ff_pkt->VerifyOpts, ff_pkt->link, + 0, attribs, 0, 0); + } else { + stat = bnet_fsend(dir,"%d %d %s %s%c%s%c%c", jcr->JobFiles, + STREAM_UNIX_ATTRIBUTES, ff_pkt->VerifyOpts, ff_pkt->fname, + 0, attribs, 0, 0); } - if (n < 0) { - berrno be; - be.set_errno(bfd.berrno); - Jmsg(jcr, M_ERROR, 1, _("Error reading file %s: ERR=%s\n"), - ff_pkt->fname, be.strerror()); - jcr->Errors++; + Dmsg2(20, "bfiled>bdird: attribs len=%d: msg=%s\n", dir->msglen, dir->msg); + if (!stat) { + Jmsg(jcr, M_FATAL, 0, _("Network error in send to Director: ERR=%s\n"), bnet_strerror(dir)); + if (is_bopen(&bfd)) { + bclose(&bfd); + } + if (is_bopen(&rsrc_bfd)) { + bclose(&rsrc_bfd); + } + return 0; } - MD5Final(signature, &md5c); - bin_to_base64(MD5buf, (char *)signature, 16); /* encode 16 bytes */ - Dmsg2(400, "send inx=%d MD5=%s\n", jcr->JobFiles, MD5buf); - bnet_fsend(dir, "%d %d %s *MD5-%d*", jcr->JobFiles, STREAM_MD5_SIGNATURE, MD5buf, - jcr->JobFiles); - Dmsg2(20, "bfiled>bdird: MD5 len=%d: msg=%s\n", dir->msglen, dir->msg); - } else if (is_bopen(&bfd) && ff_pkt->flags & FO_SHA1) { - char SHA1buf[40]; /* 24 should do */ - SHA1Init(&sha1c); - while ((n=bread(&bfd, jcr->big_buf, jcr->buf_size)) > 0) { - SHA1Update(&sha1c, ((unsigned char *)jcr->big_buf), (int)n); - jcr->JobBytes += n; - jcr->ReadBytes += n; + /* compute MD5 or SHA1 hash */ + if ((is_bopen(&bfd) || hfsplus) && ff_pkt->flags & FO_MD5) { + char MD5buf[40]; /* 24 should do */ + MD5Init(&md5c); + if (is_bopen(&bfd)) { + while ((n=bread(&bfd, jcr->big_buf, jcr->buf_size)) > 0) { + MD5Update(&md5c, ((unsigned char *)jcr->big_buf), (int)n); + jcr->JobBytes += n; + jcr->ReadBytes += n; + } + if (n < 0) { + berrno be; + be.set_errno(bfd.berrno); + Jmsg(jcr, M_ERROR, 1, _("Error reading file %s: ERR=%s\n"), + ff_pkt->fname, be.strerror()); + jcr->Errors++; + } + } +#ifdef HAVE_DARWIN_OS + if (is_bopen(&rsrc_bfd)) { + while ((n=bread(&rsrc_bfd, jcr->big_buf, jcr->buf_size)) > 0) { + MD5Update(&md5c, ((unsigned char *)jcr->big_buf), (int)n); + jcr->JobBytes += n; + jcr->ReadBytes += n; + } + if (n < 0) { + berrno be; + be.set_errno(rsrc_bfd.berrno); + Jmsg(jcr, M_ERROR, 1, _("Error reading file %s: ERR=%s\n"), + ff_pkt->fname, be.strerror()); + jcr->Errors++; + } + } + if (ff_pkt->flags & FO_HFSPLUS) { + MD5Update(&md5c, ((unsigned char *)ff_pkt->hfsinfo.fndrinfo), 32); + } +#endif + MD5Final(signature, &md5c); + + bin_to_base64(MD5buf, (char *)signature, 16); /* encode 16 bytes */ + Dmsg2(400, "send inx=%d MD5=%s\n", jcr->JobFiles, MD5buf); + bnet_fsend(dir, "%d %d %s *MD5-%d*", jcr->JobFiles, STREAM_MD5_SIGNATURE, MD5buf, + jcr->JobFiles); + Dmsg2(20, "bfiled>bdird: MD5 len=%d: msg=%s\n", dir->msglen, dir->msg); + } else if ((is_bopen(&bfd) || hfsplus) && ff_pkt->flags & FO_SHA1) { + char SHA1buf[40]; /* 24 should do */ + SHA1Init(&sha1c); + if (is_bopen(&bfd)) { + while ((n=bread(&bfd, jcr->big_buf, jcr->buf_size)) > 0) { + SHA1Update(&sha1c, ((unsigned char *)jcr->big_buf), (int)n); + jcr->JobBytes += n; + jcr->ReadBytes += n; + } + if (n < 0) { + berrno be; + be.set_errno(bfd.berrno); + Jmsg(jcr, M_ERROR, 1, _("Error reading file %s: ERR=%s\n"), + ff_pkt->fname, be.strerror()); + jcr->Errors++; + } + } +#ifdef HAVE_DARWIN_OS + if (is_bopen(&rsrc_bfd)) { + while ((n=bread(&rsrc_bfd, jcr->big_buf, jcr->buf_size)) > 0) { + SHA1Update(&sha1c, ((unsigned char *)jcr->big_buf), (int)n); + jcr->JobBytes += n; + jcr->ReadBytes += n; + } + if (n < 0) { + berrno be; + be.set_errno(rsrc_bfd.berrno); + Jmsg(jcr, M_ERROR, 1, _("Error reading file %s: ERR=%s\n"), + ff_pkt->fname, be.strerror()); + jcr->Errors++; + } + } + if (ff_pkt->flags & FO_HFSPLUS) { + SHA1Update(&sha1c, ((unsigned char *)ff_pkt->hfsinfo.fndrinfo), 32); + } +#endif + SHA1Final(&sha1c, signature); + + bin_to_base64(SHA1buf, (char *)signature, 20); /* encode 20 bytes */ + Dmsg2(400, "send inx=%d SHA1=%s\n", jcr->JobFiles, SHA1buf); + bnet_fsend(dir, "%d %d %s *SHA1-%d*", jcr->JobFiles, STREAM_SHA1_SIGNATURE, + SHA1buf, jcr->JobFiles); + Dmsg2(20, "bfiled>bdird: SHA1 len=%d: msg=%s\n", dir->msglen, dir->msg); } - if (n < 0) { - berrno be; - be.set_errno(bfd.berrno); - Jmsg(jcr, M_ERROR, 1, _("Error reading file %s: ERR=%s\n"), - ff_pkt->fname, be.strerror()); - jcr->Errors++; + if (is_bopen(&bfd)) { + bclose(&bfd); } - SHA1Final(&sha1c, signature); - - bin_to_base64(SHA1buf, (char *)signature, 20); /* encode 20 bytes */ - Dmsg2(400, "send inx=%d SHA1=%s\n", jcr->JobFiles, SHA1buf); - bnet_fsend(dir, "%d %d %s *SHA1-%d*", jcr->JobFiles, STREAM_SHA1_SIGNATURE, - SHA1buf, jcr->JobFiles); - Dmsg2(20, "bfiled>bdird: SHA1 len=%d: msg=%s\n", dir->msglen, dir->msg); - } - if (is_bopen(&bfd)) { - bclose(&bfd); + if (is_bopen(&rsrc_bfd)) { + bclose(&rsrc_bfd); + } + return 1; } - return 1; -} diff --git a/bacula/src/findlib/Makefile.in b/bacula/src/findlib/Makefile.in index 7d2c71b5d1..2bbdacc573 100644 --- a/bacula/src/findlib/Makefile.in +++ b/bacula/src/findlib/Makefile.in @@ -21,9 +21,9 @@ dummy: # LIBSRCS = find.c match.c find_one.c attibs.c create_file.c \ - bfile.c enable_priv.c makepath.c save-cwd.c winapi.c + bfile.c enable_priv.c fstype.c makepath.c save-cwd.c winapi.c LIBOBJS = find.o match.o find_one.o attribs.o create_file.o \ - bfile.o enable_priv.o makepath.o save-cwd.o winapi.o + bfile.o enable_priv.o fstype.o makepath.o save-cwd.o winapi.o .SUFFIXES: .c .o .PHONY: diff --git a/bacula/src/findlib/Makefile.mingw b/bacula/src/findlib/Makefile.mingw index 5cc0fdd2c0..46fdb6d3c9 100644 --- a/bacula/src/findlib/Makefile.mingw +++ b/bacula/src/findlib/Makefile.mingw @@ -94,9 +94,9 @@ dummy: # LIBSRCS = find.c match.c find_one.c attibs.c create_file.c \ - bfile.c enable_priv.c makepath.c save-cwd.c winapi.c + bfile.c enable_priv.c fstype.c makepath.c save-cwd.c winapi.c LIBOBJS = find.o match.o find_one.o attribs.o create_file.o \ - bfile.o enable_priv.o makepath.o save-cwd.o winapi.o + bfile.o enable_priv.o fstype.o makepath.o save-cwd.o winapi.o .SUFFIXES: .c .o .PHONY: diff --git a/bacula/src/findlib/attribs.c b/bacula/src/findlib/attribs.c index 32a839bf3e..ec9ecd6c91 100755 --- a/bacula/src/findlib/attribs.c +++ b/bacula/src/findlib/attribs.c @@ -420,7 +420,16 @@ bool set_attributes(JCR *jcr, ATTR *attr, BFILE *ofd) */ int encode_attribsEx(JCR *jcr, char *attribsEx, FF_PKT *ff_pkt) { +#ifdef HAVE_DARWIN_OS + char *p; + p = attribsEx; + if (ff_pkt->flags & FO_HFSPLUS) { + p += to_base64((uint64_t)(ff_pkt->hfsinfo.rsrclength), p); + } + *p = 0; +#else *attribsEx = 0; /* no extended attributes */ +#endif return STREAM_UNIX_ATTRIBUTES; } diff --git a/bacula/src/findlib/bfile.c b/bacula/src/findlib/bfile.c index bd5fefbb1c..dc72bbc7bc 100644 --- a/bacula/src/findlib/bfile.c +++ b/bacula/src/findlib/bfile.c @@ -31,6 +31,10 @@ #include "bacula.h" #include "find.h" +#ifdef HAVE_DARWIN_OS +#include +#endif + /* =============================================================== * * U N I X AND W I N D O W S @@ -77,6 +81,10 @@ const char *stream_to_ascii(int stream) return "Program data"; case STREAM_SHA1_SIGNATURE: return "SHA1 signature"; + case STREAM_MACOS_FORK_DATA: + return "HFS+ resource fork"; + case STREAM_HFSPLUS_ATTRIBUTES: + return "HFS+ Finder Info"; default: sprintf(buf, "%d", stream); return (const char *)buf; @@ -178,6 +186,10 @@ int is_stream_supported(int stream) case STREAM_PROGRAM_NAMES: case STREAM_PROGRAM_DATA: case STREAM_SHA1_SIGNATURE: +#ifdef HAVE_DARWIN_OS + case STREAM_MACOS_FORK_DATA: + case STREAM_HFSPLUS_ATTRIBUTES: +#endif case 0: /* compatibility with old tapes */ return 1; } @@ -469,6 +481,10 @@ int is_stream_supported(int stream) case STREAM_PROGRAM_NAMES: case STREAM_PROGRAM_DATA: case STREAM_SHA1_SIGNATURE: +#ifdef HAVE_DARWIN_OS + case STREAM_MACOS_FORK_DATA: + case STREAM_HFSPLUS_ATTRIBUTES: +#endif case 0: /* compatibility with old tapes */ return 1; @@ -513,6 +529,24 @@ int bopen(BFILE *bfd, const char *fname, int flags, mode_t mode) return bfd->fid; } +#ifdef HAVE_DARWIN_OS +/* Open the resource fork of a file. */ +int bopen_rsrc(BFILE *bfd, const char *fname, int flags, mode_t mode) +{ + POOLMEM *rsrc_fname; + size_t fname_len; + + fname_len = strlen(fname); + rsrc_fname = get_pool_memory(PM_FNAME); + bstrncpy(rsrc_fname, fname, fname_len + 1); + bstrncpy(rsrc_fname + fname_len, _PATH_RSRCFORKSPEC, + strlen(_PATH_RSRCFORKSPEC) + 1); + bopen(bfd, rsrc_fname, flags, mode); + free_pool_memory(rsrc_fname); + return bfd->fid; +} +#endif + int bclose(BFILE *bfd) { int stat; diff --git a/bacula/src/findlib/bfile.h b/bacula/src/findlib/bfile.h index 91beed66a7..21a25c0cab 100644 --- a/bacula/src/findlib/bfile.h +++ b/bacula/src/findlib/bfile.h @@ -96,6 +96,9 @@ int is_stream_supported(int stream); int is_win32_stream(int stream); char *xberror(BFILE *bfd); /* DO NOT USE -- use berrno class */ int bopen(BFILE *bfd, const char *fname, int flags, mode_t mode); +#ifdef HAVE_DARWIN_OS +int bopen_rsrc(BFILE *bfd, const char *fname, int flags, mode_t mode); +#endif int bclose(BFILE *bfd); ssize_t bread(BFILE *bfd, void *buf, size_t count); ssize_t bwrite(BFILE *bfd, void *buf, size_t count); diff --git a/bacula/src/findlib/find.c b/bacula/src/findlib/find.c index 2a1d7029a5..03cd5c5078 100644 --- a/bacula/src/findlib/find.c +++ b/bacula/src/findlib/find.c @@ -6,6 +6,8 @@ * routines for the new syntax Options resource. * * Kern E. Sibbald, MM + * + * Version $Id$ */ /* Copyright (C) 2000-2004 Kern Sibbald and John Walker @@ -175,6 +177,7 @@ static bool accept_file(FF_PKT *ff) ff->GZIP_level = fo->GZIP_level; ff->reader = fo->reader; ff->writer = fo->writer; + ff->fstypes = &(fo->fstype); ic = (ff->flags & FO_IGNORECASE) ? FNM_CASEFOLD : 0; for (k=0; kwild.size(); k++) { if (fnmatch((char *)fo->wild.get(k), ff->fname, fnmode|ic) == 0) { @@ -239,6 +242,7 @@ static int our_callback(FF_PKT *ff, void *hpkt) case FT_ISARCH: case FT_NORECURSE: case FT_NOFSCHG: + case FT_INVALIDFS: case FT_NOOPEN: // return ff->callback(ff, hpkt); diff --git a/bacula/src/findlib/find.h b/bacula/src/findlib/find.h index 4a3cf4fd75..ba29809654 100755 --- a/bacula/src/findlib/find.h +++ b/bacula/src/findlib/find.h @@ -93,7 +93,7 @@ enum { #define FO_ACL (1<<14) /* Backup ACLs */ #define FO_NO_HARDLINK (1<<15) /* don't handle hard links */ #define FO_IGNORECASE (1<<16) /* Ignore file name case */ - +#define FO_HFSPLUS (1<<17) /* Resource forks and Finder Info */ struct s_included_file { struct s_included_file *next; @@ -134,6 +134,7 @@ struct findFOPTS { alist regex; /* regex string(s) */ alist wild; /* wild card strings */ alist base; /* list of base names */ + alist fstype; /* file system type limitation */ char *reader; /* reader program */ char *writer; /* writer program */ }; @@ -157,6 +158,13 @@ struct findFILESET { alist exclude_list; }; +#ifdef HAVE_DARWIN_OS +struct HFSPLUS_INFO { + unsigned long length; /* Mandatory field */ + char fndrinfo[32]; /* Finder Info */ + off_t rsrclength; /* Size of resource fork */ +}; +#endif /* * Definition of the find_files packet passed as the @@ -189,9 +197,17 @@ struct FF_PKT { int GZIP_level; /* compression level */ char *reader; /* reader program */ char *writer; /* writer program */ + alist *fstypes; /* allowed file system types */ /* List of all hard linked files found */ struct f_link *linklist; /* hard linked files */ + + /* Darwin specific things. So as not to clutter every bclose() + * with an #ifdef, we always include rsrc_bfd */ + BFILE rsrc_bfd; /* fd for resource forks */ +#ifdef HAVE_DARWIN_OS + struct HFSPLUS_INFO hfsinfo; /* Finder Info and resource fork size */ +#endif }; diff --git a/bacula/src/findlib/find_one.c b/bacula/src/findlib/find_one.c index d9f6d4d44f..e4b1bcfead 100755 --- a/bacula/src/findlib/find_one.c +++ b/bacula/src/findlib/find_one.c @@ -23,10 +23,15 @@ Thanks to the TAR programmers. + Version $Id$ + */ #include "bacula.h" #include "find.h" +#ifdef HAVE_DARWIN_OS +#include +#endif extern int32_t name_max; /* filename max length */ extern int32_t path_max; /* path name max length */ @@ -55,6 +60,36 @@ static void free_dir_ff_pkt(FF_PKT *dir_ff_pkt) free(dir_ff_pkt); } +/* + * Check to see if we allow the file system type of a file or directory. + * If we do not have a list of file system types, we accept anything. + */ +static int accept_fstype(FF_PKT *ff, void *dummy) { + int i; + char *fs; + bool accept = true; + + if (ff->fstypes->size()) { + accept = false; + fs = fstype(ff->fname); + if (fs == NULL) { + Dmsg1(50, "Cannot determine file system type for \"%s\"\n", ff->fname); + } else { + for (i = 0; i fstypes->size(); ++i) { + if (strcmp(fs, (char *)ff->fstypes->get(i)) == 0) { + Dmsg2(100, "Accepting fstype %s for \"%s\"\n", fs, ff->fname); + accept = true; + break; + } + Dmsg3(200, "fstype %s for \"%s\" does not match %s\n", fs, + ff->fname, ff->fstypes->get(i)); + } + free(fs); + } + } + return accept; +} + /* * Find a single file. * handle_file is the callback for handling the file. @@ -79,6 +114,23 @@ find_one_file(JCR *jcr, FF_PKT *ff_pkt, int handle_file(FF_PKT *ff, void *hpkt), return handle_file(ff_pkt, pkt); } +#ifdef HAVE_DARWIN_OS + if (S_ISREG(ff_pkt->statp.st_mode) && ff_pkt->flags & FO_HFSPLUS) { + /* TODO: initialise attrList once elsewhere? */ + struct attrlist attrList; + memset(&attrList, 0, sizeof(attrList)); + attrList.bitmapcount = ATTR_BIT_MAP_COUNT; + attrList.commonattr = ATTR_CMN_FNDRINFO; + attrList.fileattr = ATTR_FILE_RSRCLENGTH; + if (getattrlist(fname, &attrList, &ff_pkt->hfsinfo, + sizeof(ff_pkt->hfsinfo), 0) != 0) { + ff_pkt->type = FT_NOSTAT; + ff_pkt->ff_errno = errno; + return handle_file(ff_pkt, pkt); + } + } +#endif + Dmsg1(300, "File ----: %s\n", fname); /* Save current times of this directory in case we need to @@ -87,6 +139,27 @@ find_one_file(JCR *jcr, FF_PKT *ff_pkt, int handle_file(FF_PKT *ff, void *hpkt), restore_times.actime = ff_pkt->statp.st_atime; restore_times.modtime = ff_pkt->statp.st_mtime; + if (top_level) { + /* + * Check if we start with an allowed file system. + * + * handle_file() calls accept_file() which fills in ff_pkt->fstypes + * Temporarily use our own handler with a fake, but probable, type. + */ + int (*callback)(FF_PKT *, void *) = ff_pkt->callback; + ff_pkt->callback = accept_fstype; + ff_pkt->type = FT_DIRBEGIN; + rtn_stat = handle_file(ff_pkt, pkt); + ff_pkt->callback = callback; + if (!rtn_stat) { + ff_pkt->type = FT_INVALIDFS; + if (ff_pkt->flags & FO_KEEPATIME) { + utime(fname, &restore_times); + } + Jmsg1(jcr, M_ERROR, 0, _("Top level entry \"%s\" has an unlisted fstype\n"), fname); + return rtn_stat; + } + } /* * If this is an Incremental backup, see if file was modified @@ -292,16 +365,22 @@ find_one_file(JCR *jcr, FF_PKT *ff_pkt, int handle_file(FF_PKT *ff, void *hpkt), /* * Do not descend into subdirectories (recurse) if the * user has turned it off for this directory. - * Or if we are crossing file systems, - * avoid doing so if the user only wants to dump one file system. + * + * If we are crossing file systems, we are either not allowed + * to cross, or we may be restricted by a list of permitted + * file systems. */ if (ff_pkt->flags & FO_NO_RECURSION) { ff_pkt->type = FT_NORECURSE; recurse = false; - } else if (!top_level && !(ff_pkt->flags & FO_MULTIFS) && - parent_device != ff_pkt->statp.st_dev) { - ff_pkt->type = FT_NOFSCHG; - recurse = false; + } else if (!top_level && parent_device != ff_pkt->statp.st_dev) { + if(!(ff_pkt->flags & FO_MULTIFS)) { + ff_pkt->type = FT_NOFSCHG; + recurse = false; + } else if (!accept_fstype(ff_pkt, NULL)) { + ff_pkt->type = FT_INVALIDFS; + recurse = false; + } } if (!recurse) { rtn_stat = handle_file(ff_pkt, pkt); @@ -310,7 +389,10 @@ find_one_file(JCR *jcr, FF_PKT *ff_pkt, int handle_file(FF_PKT *ff, void *hpkt), } free(link); free_dir_ff_pkt(dir_ff_pkt); - ff_pkt->link = ff_pkt->fname; /* reset "link" */ + ff_pkt->link = ff_pkt->fname; /* reset "link" */ + if (ff_pkt->flags & FO_KEEPATIME) { + utime(fname, &restore_times); + } return rtn_stat; } diff --git a/bacula/src/findlib/fstype.c b/bacula/src/findlib/fstype.c new file mode 100644 index 0000000000..1de11ef27c --- /dev/null +++ b/bacula/src/findlib/fstype.c @@ -0,0 +1,232 @@ +/* + * Implement routines to determine file system types. + * + * Written by Preben 'Peppe' Guldberg, December MMIV + * + * Version $Id$ + */ + +/* + Copyright (C) Kern Sibbald + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2 of + the License, or (at your option) any later version. + + 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., 59 Temple Place - Suite 330, Boston, + MA 02111-1307, USA. + + */ + +#ifndef TEST_PROGRAM +#include "bacula.h" +#include "find.h" +#else /* Set up for testing a stand alone program */ +#include +#include +#include +#define SUPPORTEDOSES "HAVE_DARWIN_OS\n" \ + "HAVE_FREEBSD_OS\n" \ + "HAVE_HPUX_OS\n" \ + "HAVE_IRIX_OS\n" \ + "HAVE_LINUX_OS\n" \ + "HAVE_NETBSD_OS\n" \ + "HAVE_OPENBSD_OS\n" \ + "HAVE_SUN_OS\n" +#define POOLMEM char +#define bstrdup strdup +#define Dmsg0(n,s) fprintf(stderr, s "\n"); +#define Dmsg1(n,s,a1) fprintf(stderr, s "\n", a1); +#define Dmsg2(n,s,a1,a2) fprintf(stderr, s "\n", a1, a2); +#endif + +/* + * These functions should be implemented for each OS + * + * POOLMEM *fstype(const char *fname); + */ +#if defined(HAVE_DARWIN_OS) \ + || defined(HAVE_FREEBSD_OS ) \ + || defined(HAVE_NETBSD_OS) \ + || defined(HAVE_OPENBSD_OS) +#include +#include +POOLMEM *fstype(const char *fname) +{ + struct statfs st; + if (statfs(fname, &st) == 0) { + return bstrdup(st.f_fstypename); + } + Dmsg1(50, "statfs() failed for \"%s\"", fname); + return NULL; +} + +#elif defined(HAVE_HPUX_OS) \ + || defined(HAVE_IRIX_OS) +#include +#include +POOLMEM *fstype(const char *fname) +{ + struct statvfs st; + if (statvfs(fname, &st) == 0) { + return bstrdup(st.f_basetype); + } + Dmsg1(50, "statfs() failed for \"%s\"", fname); + return NULL; +} + +#elif defined(HAVE_LINUX_OS) +#include +POOLMEM *fstype(const char *fname) +{ + struct statfs st; + if (statfs(fname, &st) == 0) { + /* + * Values nicked from statfs(2), testing and + * + * $ grep -r SUPER_MAGIC /usr/include/linux + * + * Entries are sorted on ("fsname") + */ + switch (st.f_type) { + +#if 0 /* These need confirmation */ + case 0xadf5: return bstrdup("adfs"); /* ADFS_SUPER_MAGIC */ + case 0xadff: return bstrdup("affs"); /* AFFS_SUPER_MAGIC */ + case 0x6B414653: return bstrdup("afs"); /* AFS_FS_MAGIC */ + case 0x0187: return bstrdup("autofs"); /* AUTOFS_SUPER_MAGIC */ + case 0x62646576: return bstrdup("bdev"); /* ??? */ + case 0x42465331: return bstrdup("befs"); /* BEFS_SUPER_MAGIC */ + case 0x1BADFACE: return bstrdup("bfs"); /* BFS_MAGIC */ + case 0x42494e4d: return bstrdup("binfmt_misc"); /* ??? */ + case (('C'<<8)|'N'): return bstrdup("capifs"); /* CAPIFS_SUPER_MAGIC */ + case 0xFF534D42: return bstrdup("cifs"); /* CIFS_MAGIC_NUMBER */ + case 0x73757245: return bstrdup("coda"); /* CODA_SUPER_MAGIC */ + case 0x012ff7b7: return bstrdup("coherent"); /* COH_SUPER_MAGIC */ + case 0x28cd3d45: return bstrdup("cramfs"); /* CRAMFS_MAGIC */ + case 0x1373: return bstrdup("devfs"); /* DEVFS_SUPER_MAGIC */ + case 0x1cd1: return bstrdup("devpts"); /* ??? */ + case 0x414A53: return bstrdup("efs"); /* EFS_SUPER_MAGIC */ + case 0x03111965: return bstrdup("eventpollfs"); /* EVENTPOLLFS_MAGIC */ + case 0x137d: return bstrdup("ext"); /* EXT_SUPER_MAGIC */ + case 0xef51: return bstrdup("ext2"); /* EXT2_OLD_SUPER_MAGIC */ + case 0xBAD1DEA: return bstrdup("futexfs"); /* ??? */ + case 0xaee71ee7: return bstrdup("gadgetfs"); /* GADGETFS_MAGIC */ + case 0x00c0ffee: return bstrdup("hostfs"); /* HOSTFS_SUPER_MAGIC */ + case 0xf995e849: return bstrdup("hpfs"); /* HPFS_SUPER_MAGIC */ + case 0xb00000ee: return bstrdup("hppfs"); /* HPPFS_SUPER_MAGIC */ + case 0x958458f6: return bstrdup("hugetlbfs"); /* HUGETLBFS_MAGIC */ + case 0x12061983: return bstrdup("hwgfs"); /* HWGFS_MAGIC */ + case 0x66726f67: return bstrdup("ibmasmfs"); /* IBMASMFS_MAGIC */ + case 0x9660: return bstrdup("iso9660"); /* ISOFS_SUPER_MAGIC */ + case 0x9660: return bstrdup("isofs"); /* ISOFS_SUPER_MAGIC */ + case 0x07c0: return bstrdup("jffs"); /* JFFS_MAGIC_SB_BITMASK */ + case 0x72b6: return bstrdup("jffs2"); /* JFFS2_SUPER_MAGIC */ + case 0x3153464a: return bstrdup("jfs"); /* JFS_SUPER_MAGIC */ + case 0x2468: return bstrdup("minix"); /* MINIX2_SUPER_MAGIC */ + case 0x2478: return bstrdup("minix"); /* MINIX2_SUPER_MAGIC2 */ + case 0x137f: return bstrdup("minix"); /* MINIX_SUPER_MAGIC */ + case 0x138f: return bstrdup("minix"); /* MINIX_SUPER_MAGIC2 */ + case 0x19800202: return bstrdup("mqueue"); /* MQUEUE_MAGIC */ + case 0x4d44: return bstrdup("msdos"); /* MSDOS_SUPER_MAGIC */ + case 0x564c: return bstrdup("ncpfs"); /* NCP_SUPER_MAGIC */ + case 0x6969: return bstrdup("nfs"); /* NFS_SUPER_MAGIC */ + case 0x5346544e: return bstrdup("ntfs"); /* NTFS_SB_MAGIC */ + case 0x9fa1: return bstrdup("openpromfs"); /* OPENPROM_SUPER_MAGIC */ + case 0x6f70726f: return bstrdup("oprofilefs"); /* OPROFILEFS_MAGIC */ + case 0xa0b4d889: return bstrdup("pfmfs"); /* PFMFS_MAGIC */ + case 0x50495045: return bstrdup("pipfs"); /* PIPEFS_MAGIC */ + case 0x9fa0: return bstrdup("proc"); /* PROC_SUPER_MAGIC */ + case 0x002f: return bstrdup("qnx4"); /* QNX4_SUPER_MAGIC */ + case 0x858458f6: return bstrdup("ramfs"); /* RAMFS_MAGIC */ + case 0x52654973: return bstrdup("reiserfs"); /* REISERFS_SUPER_MAGIC */ + case 0x7275: return bstrdup("romfs"); /* ROMFS_MAGIC */ + case 0x858458f6: return bstrdup("rootfs"); /* RAMFS_MAGIC */ + case 0x67596969: return bstrdup("rpc_pipefs"); /* RPCAUTH_GSSMAGIC */ + case 0x517B: return bstrdup("smbfs"); /* SMB_SUPER_MAGIC */ + case 0x534F434B: return bstrdup("sockfs"); /* SOCKFS_MAGIC */ + case 0x62656572: return bstrdup("sysfs"); /* SYSFS_MAGIC */ + case 0x012ff7b6: return bstrdup("sysv2"); /* SYSV2_SUPER_MAGIC */ + case 0x012ff7b5: return bstrdup("sysv4"); /* SYSV4_SUPER_MAGIC */ + case 0x858458f6: return bstrdup("tmpfs"); /* RAMFS_MAGIC */ + case 0x01021994: return bstrdup("tmpfs"); /* TMPFS_MAGIC */ + case 0x15013346: return bstrdup("udf"); /* UDF_SUPER_MAGIC */ + case 0x00011954: return bstrdup("ufs"); /* UFS_MAGIC */ + case 0x9fa2: return bstrdup("usbdevfs"); /* USBDEVICE_SUPER_MAGIC */ + case 0xa501FCF5: return bstrdup("vxfs"); /* VXFS_SUPER_MAGIC */ + case 0x012ff7b4: return bstrdup("xenix"); /* XENIX_SUPER_MAGIC */ + case 0x58465342: return bstrdup("xfs"); /* XFS_SB_MAGIC */ + case 0x012fd16d: return bstrdup("xiafs"); /* _XIAFS_SUPER_MAGIC */ + + case 0xef53: return bstrdup("ext2"); /* EXT2_SUPER_MAGIC */ + /* case 0xef53: ext2 and ext3 are the same */ /* EXT3_SUPER_MAGIC */ +#else /* Known good values */ +#endif + + default: + Dmsg2(10, "Unknown file system type \"0x%x\" for \"%s\".", st.f_type, + fname); + return NULL; + } + } + Dmsg1(50, "statfs() failed for \"%s\"", fname); + return NULL; +} + +#elif defined(HAVE_SUN_OS) +#include +#include +POOLMEM *fstype(const char *fname) +{ + struct stat st; + if (lstat(fname, &st) == 0) { + return bstrdup(st.st_fstype); + } + Dmsg1(50, "lstat() failed for \"%s\"", fname); + return NULL; +} + +#else /* No recognised OS */ +POOLMEM *fstype(const char *fname) +{ + Dmsg0(10, "!!! fstype() not implemented for this OS. !!!"); +#ifdef TEST_PROGRAM + Dmsg1(10, "Please define one of the following when compiling:\n\n%s\n", + SUPPORTEDOSES); + exit(EXIT_FAILURE); +#endif + return NULL; +} +#endif + +#ifdef TEST_PROGRAM +int main(int argc, char **argv) +{ + char *p; + int status = 0; + + if (argc < 2) { + p = (argc < 1) ? "fstype" : argv[0]; + printf("usage:\t%s path ...\n" + "\t%s prints the file system type and pathname of the paths.\n", + p, p); + return EXIT_FAILURE; + } + while (*++argv) { + if ((p = fstype(*argv)) == NULL) { + status = EXIT_FAILURE; + } else { + printf("%s\t%s\n", p, *argv); + } + } + return status; +} +#endif diff --git a/bacula/src/findlib/protos.h b/bacula/src/findlib/protos.h index 58566d9cfd..97dbbc8033 100644 --- a/bacula/src/findlib/protos.h +++ b/bacula/src/findlib/protos.h @@ -64,4 +64,7 @@ int make_path(JCR *jcr, const char *argpath, int mode, int parent_mode, uid_t owner, gid_t group, int preserve_existing, char *verbose_fmt_string); +/* from fstype.c */ +POOLMEM *fstype(const char *fname); + /* from bfile.c -- see bfile.h */ diff --git a/bacula/src/stored/btape.c b/bacula/src/stored/btape.c index 281aba0018..9179482924 100644 --- a/bacula/src/stored/btape.c +++ b/bacula/src/stored/btape.c @@ -552,6 +552,7 @@ static void capcmd() printf("%sLABEL ", dev->capabilities & CAP_LABEL ? "" : "!"); printf("%sANONVOLS ", dev->capabilities & CAP_ANONVOLS ? "" : "!"); printf("%sALWAYSOPEN ", dev->capabilities & CAP_ALWAYSOPEN ? "" : "!"); + printf("%sMTIOCGET ", dev->capabilities & CAP_MTIOCGET ? "" : "!"); printf("\n"); printf(_("Device status:\n")); @@ -1327,7 +1328,10 @@ bail_out: set_off = true; goto test_again; } - Pmsg0(-1, "You must correct this error or Bacula will not work.\n"); + Pmsg0(-1, "You must correct this error or Bacula will not work.\n" + "Some systems, e.g. OpenBSD, require you to set\n" + " File Block Bookkeeping = no\n" + "in your device resource. Use with caution.\n"); return -2; } @@ -1404,7 +1408,11 @@ failed: "nnn must match your tape driver's block size, which\n" "can be determined by reading your tape manufacturers\n" "information, and the information on your kernel dirver.\n" - "Fixed block sizes, however, are not normally an ideal solution.\n"); + "Fixed block sizes, however, are not normally an ideal solution.\n" + "\n" + "Some systems, e.g. OpenBSD, require you to set\n" + " File Block Bookkeeping = no\n" + "in your device resource. Use with caution.\n"); return; } diff --git a/bacula/src/stored/dev.c b/bacula/src/stored/dev.c index ac75f9732c..baf1e2085b 100644 --- a/bacula/src/stored/dev.c +++ b/bacula/src/stored/dev.c @@ -460,7 +460,7 @@ eod_dev(DEVICE *dev) } #ifdef MTEOM - if (dev_cap(dev, CAP_FASTFSF) && !dev_cap(dev, CAP_EOM)) { + if (dev_cap(dev, CAP_MTIOCGET) && dev_cap(dev, CAP_FASTFSF) && !dev_cap(dev, CAP_EOM)) { struct mtget mt_stat; Dmsg0(100,"Using FAST FSF for EOM\n"); if (ioctl(dev->fd, MTIOCGET, (char *)&mt_stat) == 0 && mt_stat.mt_fileno <= 0) { @@ -479,12 +479,13 @@ eod_dev(DEVICE *dev) } } - if (dev_cap(dev, CAP_EOM)) { - Dmsg0(100,"Using EOM for EOM\n"); - mt_com.mt_op = MTEOM; - mt_com.mt_count = 1; - } - if (dev_cap(dev, CAP_FASTFSF) || dev_cap(dev, CAP_EOM)) { + if (dev_cap(dev, CAP_MTIOCGET) && (dev_cap(dev, CAP_FASTFSF) || dev_cap(dev, CAP_EOM))) { + if (dev_cap(dev, CAP_EOM)) { + Dmsg0(100,"Using EOM for EOM\n"); + mt_com.mt_op = MTEOM; + mt_com.mt_count = 1; + } + if ((stat=ioctl(dev->fd, MTIOCTOP, (char *)&mt_com)) < 0) { berrno be; clrerror_dev(dev, mt_com.mt_op); @@ -532,13 +533,11 @@ eod_dev(DEVICE *dev) if (file_num == (int)dev->file) { struct mtget mt_stat; Dmsg1(100, "fsf_dev did not advance from file %d\n", file_num); -#ifndef HAVE_OPENBSD_OS - if (ioctl(dev->fd, MTIOCGET, (char *)&mt_stat) == 0 && + if (dev_cap(dev, CAP_MTIOCGET) && ioctl(dev->fd, MTIOCGET, (char *)&mt_stat) == 0 && mt_stat.mt_fileno >= 0) { Dmsg2(100, "Adjust file from %d to %d\n", dev->file , mt_stat.mt_fileno); dev->file = mt_stat.mt_fileno; } -#endif stat = 0; break; /* we are not progressing, bail out */ } @@ -554,7 +553,7 @@ eod_dev(DEVICE *dev) /* Backup over EOF */ stat = bsf_dev(dev, 1); /* If BSF worked and fileno is known (not -1), set file */ - if (ioctl(dev->fd, MTIOCGET, (char *)&mt_stat) == 0 && mt_stat.mt_fileno >= 0) { + if (dev_cap(dev, CAP_MTIOCGET) && ioctl(dev->fd, MTIOCGET, (char *)&mt_stat) == 0 && mt_stat.mt_fileno >= 0) { Dmsg2(100, "BSFATEOF adjust file from %d to %d\n", dev->file , mt_stat.mt_fileno); dev->file = mt_stat.mt_fileno; } else { @@ -679,7 +678,11 @@ uint32_t status_dev(DEVICE *dev) Dmsg0(-20, " IM_REP_EN"); } #endif /* !SunOS && !OSF */ - Dmsg2(-20, " file=%d block=%d\n", mt_stat.mt_fileno, mt_stat.mt_blkno); + if (dev_cap(dev, CAP_MTIOCGET)) { + Dmsg2(-20, " file=%d block=%d\n", mt_stat.mt_fileno, mt_stat.mt_blkno); + } else { + Dmsg2(-20, " file=%d block=%d\n", -1, -1); + } } else { stat |= BMT_ONLINE | BMT_BOT; } @@ -833,7 +836,7 @@ fsf_dev(DEVICE *dev, int num) * the SCSI driver will ensure that we do not * forward space past the end of the medium. */ - if (dev_cap(dev, CAP_FSF) && dev_cap(dev, CAP_FASTFSF)) { + if (dev_cap(dev, CAP_FSF) && dev_cap(dev, CAP_MTIOCGET) && dev_cap(dev, CAP_FASTFSF)) { mt_com.mt_op = MTFSF; mt_com.mt_count = num; stat = ioctl(dev->fd, MTIOCTOP, (char *)&mt_com); @@ -1035,15 +1038,12 @@ fsr_dev(DEVICE *dev, int num) struct mtget mt_stat; clrerror_dev(dev, MTFSR); Dmsg1(100, "FSF fail: ERR=%s\n", be.strerror()); -#ifndef HAVE_OPENBSD_OS - if (ioctl(dev->fd, MTIOCGET, (char *)&mt_stat) == 0 && mt_stat.mt_fileno >= 0) { + if (dev_cap(dev, CAP_MTIOCGET) && ioctl(dev->fd, MTIOCGET, (char *)&mt_stat) == 0 && mt_stat.mt_fileno >= 0) { Dmsg4(100, "Adjust from %d:%d to %d:%d\n", dev->file, dev->block_num, mt_stat.mt_fileno, mt_stat.mt_blkno); dev->file = mt_stat.mt_fileno; dev->block_num = mt_stat.mt_blkno; - } else -#endif - { + } else { if (dev->state & ST_EOF) { dev->state |= ST_EOT; } else { diff --git a/bacula/src/stored/dev.h b/bacula/src/stored/dev.h index adb7674af9..c6871518dc 100644 --- a/bacula/src/stored/dev.h +++ b/bacula/src/stored/dev.h @@ -90,6 +90,7 @@ enum { #define CAP_TWOEOF (1<<17) /* Write two eofs for EOM */ #define CAP_CLOSEONPOLL (1<<18) /* Close device on polling */ #define CAP_POSITIONBLOCKS (1<<19) /* Use block positioning */ +#define CAP_MTIOCGET (1<<20) /* Basic support for fileno and blkno */ /* Test state */ #define dev_state(dev, st_state) ((dev)->state & (st_state)) diff --git a/bacula/src/stored/record.c b/bacula/src/stored/record.c index 616b068abd..3275c91452 100644 --- a/bacula/src/stored/record.c +++ b/bacula/src/stored/record.c @@ -112,6 +112,10 @@ const char *stream_to_ascii(int stream, int fi) return "PROG-NAMES"; case STREAM_PROGRAM_DATA: return "PROG-DATA"; + case STREAM_MACOS_FORK_DATA: + return "MACOS-RSRC"; + case STREAM_HFSPLUS_ATTRIBUTES: + return "HFSPLUS-ATTR"; case -STREAM_UNIX_ATTRIBUTES: return "contUATTR"; case -STREAM_FILE_DATA: @@ -136,6 +140,10 @@ const char *stream_to_ascii(int stream, int fi) return "contPROG-NAMES"; case -STREAM_PROGRAM_DATA: return "contPROG-DATA"; + case -STREAM_MACOS_FORK_DATA: + return "contMACOS-RSRC"; + case -STREAM_HFSPLUS_ATTRIBUTES: + return "contHFSPLUS-ATTR"; default: sprintf(buf, "%d", stream); return buf; diff --git a/bacula/src/stored/stored_conf.c b/bacula/src/stored/stored_conf.c index 8a8de08288..22f071c22c 100644 --- a/bacula/src/stored/stored_conf.c +++ b/bacula/src/stored/stored_conf.c @@ -102,6 +102,7 @@ static RES_ITEM dev_items[] = { {"autochanger", store_yesno, ITEM(res_dev.cap_bits), CAP_AUTOCHANGER, ITEM_DEFAULT, 0}, {"closeonpoll", store_yesno, ITEM(res_dev.cap_bits), CAP_CLOSEONPOLL, ITEM_DEFAULT, 0}, {"blockpositioning", store_yesno, ITEM(res_dev.cap_bits), CAP_POSITIONBLOCKS, ITEM_DEFAULT, 1}, + {"usemtiocget", store_yesno, ITEM(res_dev.cap_bits), CAP_MTIOCGET, ITEM_DEFAULT, 1}, {"changerdevice", store_strname,ITEM(res_dev.changer_name), 0, 0, 0}, {"changercommand", store_strname,ITEM(res_dev.changer_command), 0, 0, 0}, {"alertcommand", store_strname,ITEM(res_dev.alert_command), 0, 0, 0}, diff --git a/bacula/src/tools/Makefile.in b/bacula/src/tools/Makefile.in index 64dffb6b6c..7b53649f00 100644 --- a/bacula/src/tools/Makefile.in +++ b/bacula/src/tools/Makefile.in @@ -38,7 +38,7 @@ DIRCONFOBJS = ../dird/dird_conf.o ../dird/run_conf.o ../dird/inc_conf.o .c.o: $(CXX) $(DEFS) $(DEBUG) -c $(CPPFLAGS) -I$(srcdir) -I$(basedir) $(DINCLUDE) $(CFLAGS) $< #------------------------------------------------------------------------- -all: Makefile bsmtp dbcheck testfind testls +all: Makefile bsmtp dbcheck fstype testfind testls @echo "==== Make of tools is good ====" @echo " " @@ -48,6 +48,9 @@ bsmtp: bsmtp.o ../lib/libbac.a dbcheck: dbcheck.o ../lib/libbac.a ../cats/libsql.a $(DIRCONFOBJS) $(CXX) $(LDFLAGS) -L../lib -L../cats -o $@ dbcheck.o $(DIRCONFOBJS) -lsql -lbac -lm $(DB_LIBS) $(LIBS) +fstype: fstype.o ../lib/libbac.a ../findlib/libfind.a + $(CXX) $(LDFLAGS) -L../lib -L../findlib -o $@ fstype.o -lfind -lbac -lm $(DLIB) $(LIBS) + testfind: ../findlib/libfind.a ../lib/libbac.a $(FINDOBJS) $(CXX) -g $(LDFLAGS) -L. -L../lib -L../findlib -o $@ $(FINDOBJS) \ $(DLIB) -lfind -lbac -lm $(LIBS) diff --git a/bacula/src/tools/fstype.c b/bacula/src/tools/fstype.c new file mode 100644 index 0000000000..c34fe51963 --- /dev/null +++ b/bacula/src/tools/fstype.c @@ -0,0 +1,91 @@ +/* + * Program for determining file system type + * + * Written by Preben 'Peppe' Guldberg, December MMIV + * + * Version $Id$ + * + */ + +/* + Copyright (C) 2004 Kern Sibbald + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2 of + the License, or (at your option) any later version. + + 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., 59 Temple Place - Suite 330, Boston, + MA 02111-1307, USA. + + */ + +#include "bacula.h" +#include "findlib/find.h" + +static void usage() +{ + fprintf(stderr, _( +"\n" +"Usage: fstype [-d debug_level] path ...\n" +"\n" +" Print the file system type a given file/directory is on.\n" +" The following options are supported:\n" +"\n" +" -v print both path and file system type.\n" +" -? print this message.\n" +"\n")); + + exit(1); +} + + +int +main (int argc, char *const *argv) +{ + POOLMEM *fs; + int verbose = 0; + int status = 0; + int ch, i; + + while ((ch = getopt(argc, argv, "v?")) != -1) { + switch (ch) { + case 'v': + verbose = 1; + break; + case '?': + default: + usage(); + + } + } + argc -= optind; + argv += optind; + + if (argc < 1) { + usage(); + } + + for (i = 0; i < argc; --argc, ++argv) { + if ((fs = fstype(*argv)) != NULL) { + if (verbose) { + printf("%s: %s\n", *argv, fs); + } else { + puts(fs); + } + free(fs); + } else { + fprintf(stderr, "%s: unknown\n", *argv); + status = 1; + } + } + + exit(status); +} diff --git a/bacula/src/tools/testfind.c b/bacula/src/tools/testfind.c index 61e64a2717..3630884ead 100644 --- a/bacula/src/tools/testfind.c +++ b/bacula/src/tools/testfind.c @@ -208,12 +208,22 @@ static int print_file(FF_PKT *ff, void *pkt) break; case FT_DIRBEGIN: return 1; + case FT_NORECURSE: + case FT_NOFSCHG: + case FT_INVALIDFS: case FT_DIREND: - if (debug_level == 1) { - printf("%s\n", ff->fname); - } else if (debug_level > 1) { - printf("Dir: %s\n", ff->fname); + if (debug_level) { + char errmsg[100] = ""; + if (ff->type == FT_NORECURSE) { + bstrncpy(errmsg, "\t[will not descend: recursion turned off]", sizeof(errmsg)); + } else if (ff->type == FT_NOFSCHG) { + bstrncpy(errmsg, "\t[will not descend: file system change not allowed]", sizeof(errmsg)); + } else if (ff->type == FT_INVALIDFS) { + bstrncpy(errmsg, "\t[will not descend: disallowed file system]", sizeof(errmsg)); + } + printf("%s%s%s\n", (debug_level > 1 ? "Dir: " : ""), ff->fname, errmsg); } + ff->type = FT_DIREND; count_files(ff); break; case FT_SPEC: @@ -239,12 +249,6 @@ static int print_file(FF_PKT *ff, void *pkt) case FT_ISARCH: printf(_("Err: Attempt to backup archive. Not saved. %s\n"), ff->fname); break; - case FT_NORECURSE: - printf(_("Recursion turned off. Directory not entered. %s\n"), ff->fname); - break; - case FT_NOFSCHG: - printf(_("Skip: File system change prohibited. Directory not entered. %s\n"), ff->fname); - break; case FT_NOOPEN: printf(_("Err: Could not open directory %s: %s\n"), ff->fname, strerror(errno)); break; diff --git a/bacula/src/version.h b/bacula/src/version.h index 63200ca108..859b77eab4 100644 --- a/bacula/src/version.h +++ b/bacula/src/version.h @@ -1,8 +1,8 @@ /* */ #undef VERSION #define VERSION "1.37.1" -#define BDATE "06 December 2004" -#define LSMDATE "06Dec04" +#define BDATE "09 December 2004" +#define LSMDATE "09Dec04" /* Debug flags */ #undef DEBUG -- 2.39.5