2 * Bacula File Daemon verify-vol.c Verify files on a Volume
3 * versus attributes in Catalog
5 * Kern Sibbald, July MMII
11 Bacula® - The Network Backup Solution
13 Copyright (C) 2002-2006 Free Software Foundation Europe e.V.
15 The main author of Bacula is Kern Sibbald, with contributions from
16 many others, a complete list can be found in the file AUTHORS.
17 This program is Free Software; you can redistribute it and/or
18 modify it under the terms of version two of the GNU General Public
19 License as published by the Free Software Foundation and included
22 This program is distributed in the hope that it will be useful, but
23 WITHOUT ANY WARRANTY; without even the implied warranty of
24 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
25 General Public License for more details.
27 You should have received a copy of the GNU General Public License
28 along with this program; if not, write to the Free Software
29 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
32 Bacula® is a registered trademark of Kern Sibbald.
33 The licensor of Bacula is the Free Software Foundation Europe
34 (FSFE), Fiduciary Program, Sumatrastrasse 25, 8006 Zürich,
35 Switzerland, email:ftf@fsfeurope.org.
41 /* Data received from Storage Daemon */
42 static char rec_header[] = "rechdr %ld %ld %ld %ld %ld";
44 /* Forward referenced functions */
48 * Verify attributes of the requested files on the Volume
51 void do_verify_volume(JCR *jcr)
54 POOLMEM *fname; /* original file name */
55 POOLMEM *lname; /* link name */
58 uint32_t VolSessionId, VolSessionTime, file_index;
59 uint32_t record_file_index;
60 char digest[BASE64_SIZE(CRYPTO_DIGEST_MAX_SIZE)];
63 sd = jcr->store_bsock;
65 Jmsg(jcr, M_FATAL, 0, _("Storage command not issued before Verify.\n"));
66 set_jcr_job_status(jcr, JS_FatalError);
70 set_jcr_job_status(jcr, JS_Running);
73 CLIENT *client = (CLIENT *)GetNextRes(R_CLIENT, NULL);
77 buf_size = client->max_network_buffer_size;
79 buf_size = 0; /* use default */
81 if (!bnet_set_buffer_size(sd, buf_size, BNET_SETBUF_WRITE)) {
82 set_jcr_job_status(jcr, JS_FatalError);
85 jcr->buf_size = sd->msglen;
87 fname = get_pool_memory(PM_FNAME);
88 lname = get_pool_memory(PM_FNAME);
91 * Get a record from the Storage daemon
93 while (bget_msg(sd) >= 0 && !job_canceled(jcr)) {
95 * First we expect a Stream Record Header
97 if (sscanf(sd->msg, rec_header, &VolSessionId, &VolSessionTime, &file_index,
98 &stream, &size) != 5) {
99 Jmsg1(jcr, M_FATAL, 0, _("Record header scan error: %s\n"), sd->msg);
102 Dmsg2(30, "Got hdr: FilInx=%d Stream=%d.\n", file_index, stream);
105 * Now we expect the Stream Data
107 if (bget_msg(sd) < 0) {
108 Jmsg1(jcr, M_FATAL, 0, _("Data record error. ERR=%s\n"), bnet_strerror(sd));
111 if (size != ((uint32_t)sd->msglen)) {
112 Jmsg2(jcr, M_FATAL, 0, _("Actual data size %d not same as header %d\n"), sd->msglen, size);
115 Dmsg1(30, "Got stream data, len=%d\n", sd->msglen);
117 /* File Attributes stream */
119 case STREAM_UNIX_ATTRIBUTES:
120 case STREAM_UNIX_ATTRIBUTES_EX:
123 Dmsg0(400, "Stream=Unix Attributes.\n");
125 if ((int)sizeof_pool_memory(fname) < sd->msglen) {
126 fname = realloc_pool_memory(fname, sd->msglen + 1);
129 if ((int)sizeof_pool_memory(lname) < sd->msglen) {
130 lname = realloc_pool_memory(lname, sd->msglen + 1);
136 * An Attributes record consists of:
141 * Link name (if file linked i.e. FT_LNK)
142 * Extended Attributes (if Win32)
144 if (sscanf(sd->msg, "%d %d", &record_file_index, &type) != 2) {
145 Jmsg(jcr, M_FATAL, 0, _("Error scanning record header: %s\n"), sd->msg);
146 Dmsg0(0, "\nError scanning header\n");
149 Dmsg2(30, "Got Attr: FilInx=%d type=%d\n", record_file_index, type);
151 while (*ap++ != ' ') /* skip record file index */
153 while (*ap++ != ' ') /* skip type */
155 /* Save filename and position to attributes */
158 *fp++ = *ap++; /* copy filename to fname */
160 *fp = *ap++; /* terminate filename & point to attribs */
162 Dmsg1(200, "Attr=%s\n", ap);
163 /* Skip to Link name */
164 if (type == FT_LNK || type == FT_LNKSAVED) {
169 pm_strcat(lname, lp); /* "save" link name */
175 jcr->num_files_examined++;
176 pm_strcpy(jcr->last_fname, fname); /* last file examined */
180 * Send file attributes to Director
184 * Filename (full path)
186 * Link name (if type==FT_LNK)
187 * For a directory, link is the same as fname, but with trailing
188 * slash. For a linked file, link is the link.
190 /* Send file attributes to Director */
191 Dmsg2(200, "send ATTR inx=%d fname=%s\n", jcr->JobFiles, fname);
192 if (type == FT_LNK || type == FT_LNKSAVED) {
193 stat = bnet_fsend(dir, "%d %d %s %s%c%s%c%s%c", jcr->JobFiles,
194 STREAM_UNIX_ATTRIBUTES, "pinsug5", fname,
196 /* for a deleted record, we set fileindex=0 */
197 } else if (type == FT_DELETED) {
198 stat = bnet_fsend(dir,"%d %d %s %s%c%s%c%c", 0,
199 STREAM_UNIX_ATTRIBUTES, "pinsug5", fname,
202 stat = bnet_fsend(dir,"%d %d %s %s%c%s%c%c", jcr->JobFiles,
203 STREAM_UNIX_ATTRIBUTES, "pinsug5", fname,
206 Dmsg2(200, "bfiled>bdird: attribs len=%d: msg=%s\n", dir->msglen, dir->msg);
208 Jmsg(jcr, M_FATAL, 0, _("Network error in send to Director: ERR=%s\n"), bnet_strerror(dir));
213 case STREAM_MD5_DIGEST:
214 bin_to_base64(digest, sizeof(digest), (char *)sd->msg, CRYPTO_DIGEST_MD5_SIZE, true);
215 Dmsg2(400, "send inx=%d MD5=%s\n", jcr->JobFiles, digest);
216 bnet_fsend(dir, "%d %d %s *MD5-%d*", jcr->JobFiles, STREAM_MD5_DIGEST, digest,
218 Dmsg2(20, "bfiled>bdird: MD5 len=%d: msg=%s\n", dir->msglen, dir->msg);
221 case STREAM_SHA1_DIGEST:
222 bin_to_base64(digest, sizeof(digest), (char *)sd->msg, CRYPTO_DIGEST_SHA1_SIZE, true);
223 Dmsg2(400, "send inx=%d SHA1=%s\n", jcr->JobFiles, digest);
224 bnet_fsend(dir, "%d %d %s *SHA1-%d*", jcr->JobFiles, STREAM_SHA1_DIGEST,
225 digest, jcr->JobFiles);
226 Dmsg2(20, "bfiled>bdird: SHA1 len=%d: msg=%s\n", dir->msglen, dir->msg);
229 case STREAM_SHA256_DIGEST:
230 bin_to_base64(digest, sizeof(digest), (char *)sd->msg, CRYPTO_DIGEST_SHA256_SIZE, true);
231 Dmsg2(400, "send inx=%d SHA256=%s\n", jcr->JobFiles, digest);
232 bnet_fsend(dir, "%d %d %s *SHA256-%d*", jcr->JobFiles, STREAM_SHA256_DIGEST,
233 digest, jcr->JobFiles);
234 Dmsg2(20, "bfiled>bdird: SHA256 len=%d: msg=%s\n", dir->msglen, dir->msg);
237 case STREAM_SHA512_DIGEST:
238 bin_to_base64(digest, sizeof(digest), (char *)sd->msg, CRYPTO_DIGEST_SHA512_SIZE, true);
239 Dmsg2(400, "send inx=%d SHA512=%s\n", jcr->JobFiles, digest);
240 bnet_fsend(dir, "%d %d %s *SHA512-%d*", jcr->JobFiles, STREAM_SHA512_DIGEST,
241 digest, jcr->JobFiles);
242 Dmsg2(20, "bfiled>bdird: SHA512 len=%d: msg=%s\n", dir->msglen, dir->msg);
245 /* Ignore everything else */
250 } /* end while bnet_get */
251 set_jcr_job_status(jcr, JS_Terminated);
255 set_jcr_job_status(jcr, JS_ErrorTerminated);
258 if (jcr->compress_buf) {
259 free(jcr->compress_buf);
260 jcr->compress_buf = NULL;
262 free_pool_memory(fname);
263 free_pool_memory(lname);
264 Dmsg2(050, "End Verify-Vol. Files=%d Bytes=%" lld "\n", jcr->JobFiles,