]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/filed/verify_vol.c
Backport from Bacula Enterprise
[bacula/bacula] / bacula / src / filed / verify_vol.c
1 /*
2    Bacula(R) - The Network Backup Solution
3
4    Copyright (C) 2000-2015 Kern Sibbald
5    Copyright (C) 2002-2014 Free Software Foundation Europe e.V.
6
7    The original author of Bacula is Kern Sibbald, with contributions
8    from many others, a complete list can be found in the file AUTHORS.
9
10    You may use this file and others of this release according to the
11    license defined in the LICENSE file, which includes the Affero General
12    Public License, v3.0 ("AGPLv3") and some additional permissions and
13    terms pursuant to its AGPLv3 Section 7.
14
15    This notice must be preserved when any source code is 
16    conveyed and/or propagated.
17
18    Bacula(R) is a registered trademark of Kern Sibbald.
19 */
20 /*
21  *  Bacula File Daemon  verify-vol.c Verify files on a Volume
22  *    versus attributes in Catalog
23  *
24  *    Kern Sibbald, July MMII
25  *
26  */
27
28 #include "bacula.h"
29 #include "filed.h"
30
31 /* Data received from Storage Daemon */
32 static char rec_header[] = "rechdr %ld %ld %ld %ld %ld";
33
34 /* Forward referenced functions */
35
36
37 /*
38  * Verify attributes of the requested files on the Volume
39  *
40  */
41 void do_verify_volume(JCR *jcr)
42 {
43    BSOCK *sd, *dir;
44    POOLMEM *fname;                    /* original file name */
45    POOLMEM *lname;                    /* link name */
46    int32_t stream, full_stream;
47    uint32_t size;
48    uint32_t VolSessionId, VolSessionTime, file_index;
49    uint32_t record_file_index;
50    char digest[BASE64_SIZE(CRYPTO_DIGEST_MAX_SIZE)];
51    int type, stat;
52
53    sd = jcr->store_bsock;
54    if (!sd) {
55       Jmsg(jcr, M_FATAL, 0, _("Storage command not issued before Verify.\n"));
56       jcr->setJobStatus(JS_FatalError);
57       return;
58    }
59    dir = jcr->dir_bsock;
60    jcr->setJobStatus(JS_Running);
61
62    LockRes();
63    CLIENT *client = (CLIENT *)GetNextRes(R_CLIENT, NULL);
64    UnlockRes();
65    uint32_t buf_size;
66    if (client) {
67       buf_size = client->max_network_buffer_size;
68    } else {
69       buf_size = 0;                   /* use default */
70    }
71    if (!sd->set_buffer_size(buf_size, BNET_SETBUF_WRITE)) {
72       jcr->setJobStatus(JS_FatalError);
73       return;
74    }
75    jcr->buf_size = sd->msglen;
76
77    fname = get_pool_memory(PM_FNAME);
78    lname = get_pool_memory(PM_FNAME);
79
80    GetMsg *fdmsg = New(GetMsg(jcr, sd, rec_header, GETMSG_MAX_MSG_SIZE));
81    fdmsg->start_read_sock();
82    bmessage *bmsg = New(bmessage(GETMSG_MAX_MSG_SIZE));
83
84    /*
85     * Get a record from the Storage daemon
86     */
87    while (fdmsg->bget_msg(&bmsg) >= 0 && !job_canceled(jcr)) {
88       /*
89        * First we expect a Stream Record Header
90        */
91       if (sscanf(bmsg->rbuf, rec_header, &VolSessionId, &VolSessionTime, &file_index,
92           &full_stream, &size) != 5) {
93          Jmsg1(jcr, M_FATAL, 0, _("Record header scan error: %s\n"), bmsg->rbuf);
94          goto bail_out;
95       }
96       stream = full_stream & STREAMMASK_TYPE;
97       Dmsg4(30, "Got hdr: FilInx=%d FullStream=%d Stream=%d size=%d.\n", file_index, full_stream, stream, size);
98
99       /*
100        * Now we expect the Stream Data
101        */
102       if (fdmsg->bget_msg(&bmsg) < 0) {
103          Jmsg1(jcr, M_FATAL, 0, _("Data record error. ERR=%s\n"), sd->bstrerror());
104          goto bail_out;
105       }
106       if (size != ((uint32_t)bmsg->origlen)) {
107          Jmsg2(jcr, M_FATAL, 0, _("Actual data size %d not same as header %d\n"), bmsg->origlen, size);
108          goto bail_out;
109       }
110       Dmsg2(30, "Got stream data %s, len=%d\n", stream_to_ascii(stream), bmsg->rbuflen);
111
112       /* File Attributes stream */
113       switch (stream) {
114       case STREAM_UNIX_ATTRIBUTES:
115       case STREAM_UNIX_ATTRIBUTES_EX:
116          char *ap, *lp, *fp;
117
118          Dmsg0(400, "Stream=Unix Attributes.\n");
119
120          if ((int)sizeof_pool_memory(fname) < bmsg->rbuflen) {
121             fname = realloc_pool_memory(fname, bmsg->rbuflen + 1);
122          }
123
124          if ((int)sizeof_pool_memory(lname) < bmsg->rbuflen) {
125             lname = realloc_pool_memory(lname, bmsg->rbuflen + 1);
126          }
127          *fname = 0;
128          *lname = 0;
129
130          /*
131           * An Attributes record consists of:
132           *    File_index
133           *    Type   (FT_types)
134           *    Filename
135           *    Attributes
136           *    Link name (if file linked i.e. FT_LNK)
137           *    Extended Attributes (if Win32)
138           */
139          if (sscanf(bmsg->rbuf, "%d %d", &record_file_index, &type) != 2) {
140             Jmsg(jcr, M_FATAL, 0, _("Error scanning record header: %s\n"), bmsg->rbuf);
141             Dmsg0(0, "\nError scanning header\n");
142             goto bail_out;
143          }
144          Dmsg2(30, "Got Attr: FilInx=%d type=%d\n", record_file_index, type);
145          ap = bmsg->rbuf;
146          while (*ap++ != ' ')         /* skip record file index */
147             ;
148          while (*ap++ != ' ')         /* skip type */
149             ;
150          /* Save filename and position to attributes */
151          fp = fname;
152          while (*ap != 0) {
153             *fp++  = *ap++;           /* copy filename to fname */
154          }
155          *fp = *ap++;                 /* terminate filename & point to attribs */
156
157          Dmsg2(100, "File=%s Attr=%s\n", fname, ap);
158          /* Skip to Link name */
159          if (type == FT_LNK || type == FT_LNKSAVED) {
160             lp = ap;
161             while (*lp++ != 0) {
162                ;
163             }
164             pm_strcat(lname, lp);        /* "save" link name */
165          } else {
166             *lname = 0;
167          }
168          jcr->lock();
169          jcr->JobFiles++;
170          jcr->num_files_examined++;
171          pm_strcpy(jcr->last_fname, fname); /* last file examined */
172          jcr->unlock();
173
174          /*
175           * Send file attributes to Director
176           *   File_index
177           *   Stream
178           *   Verify Options
179           *   Filename (full path)
180           *   Encoded attributes
181           *   Link name (if type==FT_LNK)
182           * For a directory, link is the same as fname, but with trailing
183           * slash. For a linked file, link is the link.
184           */
185          /* Send file attributes to Director */
186          Dmsg2(200, "send ATTR inx=%d fname=%s\n", jcr->JobFiles, fname);
187          if (type == FT_LNK || type == FT_LNKSAVED) {
188             stat = dir->fsend("%d %d %s %s%c%s%c%s%c", jcr->JobFiles,
189                           STREAM_UNIX_ATTRIBUTES, "pinsug5", fname,
190                           0, ap, 0, lname, 0);
191          /* for a deleted record, we set fileindex=0 */
192          } else if (type == FT_DELETED)  {
193             stat = dir->fsend("%d %d %s %s%c%s%c%c", 0,
194                           STREAM_UNIX_ATTRIBUTES, "pinsug5", fname,
195                           0, ap, 0, 0);
196          } else {
197             stat = dir->fsend("%d %d %s %s%c%s%c%c", jcr->JobFiles,
198                           STREAM_UNIX_ATTRIBUTES, "pinsug5", fname,
199                           0, ap, 0, 0);
200          }
201          Dmsg2(200, "bfiled>bdird: attribs len=%d: msg=%s\n", dir->msglen, dir->msg);
202          if (!stat) {
203             Jmsg(jcr, M_FATAL, 0, _("Network error in send to Director: ERR=%s\n"), dir->bstrerror());
204             goto bail_out;
205          }
206          break;
207
208       case STREAM_MD5_DIGEST:
209          bin_to_base64(digest, sizeof(digest), (char *)bmsg->rbuf, CRYPTO_DIGEST_MD5_SIZE, true);
210          Dmsg2(400, "send inx=%d MD5=%s\n", jcr->JobFiles, digest);
211          dir->fsend("%d %d %s *MD5-%d*", jcr->JobFiles, STREAM_MD5_DIGEST, digest,
212                     jcr->JobFiles);
213          Dmsg2(20, "bfiled>bdird: MD5 len=%d: msg=%s\n", dir->msglen, dir->msg);
214          break;
215
216       case STREAM_SHA1_DIGEST:
217          bin_to_base64(digest, sizeof(digest), (char *)bmsg->rbuf, CRYPTO_DIGEST_SHA1_SIZE, true);
218          Dmsg2(400, "send inx=%d SHA1=%s\n", jcr->JobFiles, digest);
219          dir->fsend("%d %d %s *SHA1-%d*", jcr->JobFiles, STREAM_SHA1_DIGEST,
220                     digest, jcr->JobFiles);
221          Dmsg2(20, "bfiled>bdird: SHA1 len=%d: msg=%s\n", dir->msglen, dir->msg);
222          break;
223
224       case STREAM_SHA256_DIGEST:
225          bin_to_base64(digest, sizeof(digest), (char *)bmsg->rbuf, CRYPTO_DIGEST_SHA256_SIZE, true);
226          Dmsg2(400, "send inx=%d SHA256=%s\n", jcr->JobFiles, digest);
227          dir->fsend("%d %d %s *SHA256-%d*", jcr->JobFiles, STREAM_SHA256_DIGEST,
228                     digest, jcr->JobFiles);
229          Dmsg2(20, "bfiled>bdird: SHA256 len=%d: msg=%s\n", dir->msglen, dir->msg);
230          break;
231
232       case STREAM_SHA512_DIGEST:
233          bin_to_base64(digest, sizeof(digest), (char *)bmsg->rbuf, CRYPTO_DIGEST_SHA512_SIZE, true);
234          Dmsg2(400, "send inx=%d SHA512=%s\n", jcr->JobFiles, digest);
235          dir->fsend("%d %d %s *SHA512-%d*", jcr->JobFiles, STREAM_SHA512_DIGEST,
236                     digest, jcr->JobFiles);
237          Dmsg2(20, "bfiled>bdird: SHA512 len=%d: msg=%s\n", dir->msglen, dir->msg);
238          break;
239
240       /*
241        * Restore stream object is counted, but not restored here
242        */
243       case STREAM_RESTORE_OBJECT:
244          jcr->lock();
245          jcr->JobFiles++;
246          jcr->num_files_examined++;
247          jcr->unlock();
248          break;
249
250       /* Ignore everything else */
251       default:
252          break;
253
254       } /* end switch */
255    } /* end while bnet_get */
256    jcr->setJobStatus(JS_Terminated);
257    goto ok_out;
258
259 bail_out:
260    jcr->setJobStatus(JS_ErrorTerminated);
261
262 ok_out:
263    Dmsg0(215, "wait BufferedMsg\n");
264    fdmsg->wait_read_sock();
265    delete bmsg;
266    free_GetMsg(fdmsg);
267
268    if (jcr->compress_buf) {
269       free(jcr->compress_buf);
270       jcr->compress_buf = NULL;
271    }
272    free_pool_memory(fname);
273    free_pool_memory(lname);
274    Dmsg2(050, "End Verify-Vol. Files=%d Bytes=%" lld "\n", jcr->JobFiles,
275       jcr->JobBytes);
276 }