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
gpg --verify xxxx.tar.gz.sig
-
* 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 */
for (k=0; k<fo->base.size(); k++) {
sendit(sock, " B %s\n", fo->base.get(k));
}
+ for (k=0; k<fo->fstype.size(); k++) {
+ sendit(sock, " X %s\n", fo->fstype.get(k));
+ }
if (fo->reader) {
sendit(sock, " D %s\n", fo->reader);
}
fopt->regex.destroy();
fopt->wild.destroy();
fopt->base.destroy();
+ fopt->fstype.destroy();
if (fopt->reader) {
free(fopt->reader);
}
};
#undef MAX_FOPTS
-#define MAX_FOPTS 32
+#define MAX_FOPTS 34
/* File options structure */
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 */
};
for (k=0; k<fo->base.size(); k++) {
bnet_fsend(fd, "B %s\n", fo->base.get(k));
}
+ for (k=0; k<fo->fstype.size(); k++) {
+ bnet_fsend(fd, "X %s\n", fo->fstype.get(k));
+ }
if (fo->reader) {
bnet_fsend(fd, "D %s\n", fo->reader);
}
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);
{"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}
};
INC_KW_KEEPATIME,
INC_KW_EXCLUDE,
INC_KW_ACL,
- INC_KW_IGNORECASE
+ INC_KW_IGNORECASE,
+ INC_KW_HFSPLUS
};
/*
{"exclude", INC_KW_EXCLUDE},
{"aclsupport", INC_KW_ACL},
{"ignorecase", INC_KW_IGNORECASE},
+ {"hfsplussupport", INC_KW_HFSPLUS},
{NULL, 0}
};
{"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}
};
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
scan_to_eol(lc);
}
+
/*
* Come here when Options seen in Include/Exclude
*/
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 *));
# 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
#include <acl/libacl.h>
#endif
+#ifdef HAVE_DARWIN_OS
+#include <sys/paths.h>
+#endif
+
static int save_file(FF_PKT *ff_pkt, void *pkt);
/*
char attribs[MAXSTRING];
char attribsEx[MAXSTRING];
int stat, attr_stream, data_stream;
+ bool hfsplus = false;
struct MD5Context md5c;
struct SHA1Context sha1c;
int gotMD5 = 0;
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:
}
}
+ 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 */
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;
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
*
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.
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;
}
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;
}
}
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
+ * <file-index> <stream> <info>
+ */
+ 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 */
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"),
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:
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 */
fo->regex.destroy();
fo->wild.destroy();
fo->base.destroy();
+ fo->fstype.destroy();
if (fo->reader) {
free(fo->reader);
}
fo->regex.destroy();
fo->wild.destroy();
fo->base.destroy();
+ fo->fstype.destroy();
}
incexe->opts_list.destroy();
incexe->name_list.destroy();
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);
}
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));
for (k=0; k<fo->base.size(); k++) {
Dmsg1(400, "B %s\n", (char *)fo->base.get(k));
}
+ for (k=0; k<fo->fstype.size(); k++) {
+ Dmsg1(400, "X %s\n", (char *)fo->fstype.get(k));
+ }
if (fo->reader) {
Dmsg1(400, "D %s\n", fo->reader);
}
for (k=0; k<fo->base.size(); k++) {
Dmsg1(400, "B %s\n", (char *)fo->base.get(k));
}
+ for (k=0; k<fo->fstype.size(); k++) {
+ Dmsg1(400, "X %s\n", (char *)fo->fstype.get(k));
+ }
}
for (j=0; j<incexe->name_list.size(); j++) {
Dmsg1(400, "F %s\n", (char *)incexe->name_list.get(j));
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;
#include <acl/libacl.h>
#endif
+#ifdef HAVE_DARWIN_OS
+#include <sys/attr.h>
+#include <sys/paths.h>
+#endif
+
/* Data received from Storage Daemon */
static char rec_header[] = "rechdr %ld %ld %ld %ld %ld";
#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.
*
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;
* 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)) {
* 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;
}
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);
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);
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;
edit_uint64(fileAddr, ec1), attr->ofname, be.strerror());
extract = false;
bclose(&bfd);
+ if (is_bopen(&rsrc_bfd)) {
+ bclose(&rsrc_bfd);
+ }
continue;
}
}
be.strerror());
extract = false;
bclose(&bfd);
+ if (is_bopen(&rsrc_bfd)) {
+ bclose(&rsrc_bfd);
+ }
continue;
}
total += wsize;
edit_uint64(fileAddr, ec1), attr->ofname, be.strerror());
extract = false;
bclose(&bfd);
+ if (is_bopen(&rsrc_bfd)) {
+ bclose(&rsrc_bfd);
+ }
continue;
}
}
attr->ofname, zlib_strerror(stat));
extract = false;
bclose(&bfd);
+ if (is_bopen(&rsrc_bfd)) {
+ bclose(&rsrc_bfd);
+ }
continue;
}
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;
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 */
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,
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);
}
#include "bacula.h"
#include "filed.h"
+#ifdef HAVE_DARWIN_OS
+#include <sys/paths.h>
+#endif
+
static int verify_file(FF_PKT *ff_pkt, void *my_pkt);
/*
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 */
}
}
- 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;
-}
#
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:
#
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:
*/
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;
}
#include "bacula.h"
#include "find.h"
+#ifdef HAVE_DARWIN_OS
+#include <sys/paths.h>
+#endif
+
/* ===============================================================
*
* U N I X AND W I N D O W S
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;
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;
}
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;
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;
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);
* routines for the new syntax Options resource.
*
* Kern E. Sibbald, MM
+ *
+ * Version $Id$
*/
/*
Copyright (C) 2000-2004 Kern Sibbald and John Walker
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; k<fo->wild.size(); k++) {
if (fnmatch((char *)fo->wild.get(k), ff->fname, fnmode|ic) == 0) {
case FT_ISARCH:
case FT_NORECURSE:
case FT_NOFSCHG:
+ case FT_INVALIDFS:
case FT_NOOPEN:
// return ff->callback(ff, hpkt);
#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;
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 */
};
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
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
};
Thanks to the TAR programmers.
+ Version $Id$
+
*/
#include "bacula.h"
#include "find.h"
+#ifdef HAVE_DARWIN_OS
+#include <sys/attr.h>
+#endif
extern int32_t name_max; /* filename max length */
extern int32_t path_max; /* path name max length */
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 <ff->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.
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
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
/*
* 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);
}
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;
}
--- /dev/null
+/*
+ * 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 <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#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 <sys/param.h>
+#include <sys/mount.h>
+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 <sys/types.h>
+#include <sys/statvfs.h>
+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 <sys/vfs.h>
+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 <sys/types.h>
+#include <sys/stat.h>
+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
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 */
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"));
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;
}
"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;
}
}
#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) {
}
}
- 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);
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 */
}
/* 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 {
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;
}
* 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);
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 {
#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))
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:
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;
{"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},
.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 " "
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)
--- /dev/null
+/*
+ * 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);
+}
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:
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;
/* */
#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