]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/filed/verify.c
This commit was manufactured by cvs2svn to create tag
[bacula/bacula] / bacula / src / filed / verify.c
1 /*
2  *  Bacula File Daemon  verify.c  Verify files.
3  *
4  *    Kern Sibbald, October MM
5  *
6  *   Version $Id$
7  *
8  */
9 /*
10    Copyright (C) 2000-2004 Kern Sibbald
11
12    This program is free software; you can redistribute it and/or
13    modify it under the terms of the GNU General Public License as
14    published by the Free Software Foundation; either version 2 of
15    the License, or (at your option) any later version.
16
17    This program is distributed in the hope that it will be useful,
18    but WITHOUT ANY WARRANTY; without even the implied warranty of
19    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20    General Public License for more details.
21
22    You should have received a copy of the GNU General Public
23    License along with this program; if not, write to the Free
24    Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
25    MA 02111-1307, USA.
26
27  */
28
29 #include "bacula.h"
30 #include "filed.h"
31
32 static int verify_file(FF_PKT *ff_pkt, void *my_pkt, bool);
33 static int read_chksum(BFILE *bfd, CHKSUM *chksum, JCR *jcr);
34
35 /*
36  * Find all the requested files and send attributes
37  * to the Director.
38  *
39  */
40 void do_verify(JCR *jcr)
41 {
42    set_jcr_job_status(jcr, JS_Running);
43    jcr->buf_size = DEFAULT_NETWORK_BUFFER_SIZE;
44    if ((jcr->big_buf = (char *) malloc(jcr->buf_size)) == NULL) {
45       Jmsg1(jcr, M_ABORT, 0, _("Cannot malloc %d network read buffer\n"),
46          DEFAULT_NETWORK_BUFFER_SIZE);
47    }
48    set_find_options((FF_PKT *)jcr->ff, jcr->incremental, jcr->mtime);
49    Dmsg0(10, "Start find files\n");
50    /* Subroutine verify_file() is called for each file */
51    find_files(jcr, (FF_PKT *)jcr->ff, verify_file, (void *)jcr);
52    Dmsg0(10, "End find files\n");
53
54    if (jcr->big_buf) {
55       free(jcr->big_buf);
56       jcr->big_buf = NULL;
57    }
58    set_jcr_job_status(jcr, JS_Terminated);
59 }
60
61 /*
62  * Called here by find() for each file.
63  *
64  *  Find the file, compute the MD5 or SHA1 and send it back to the Director
65  */
66 static int verify_file(FF_PKT *ff_pkt, void *pkt, bool top_level)
67 {
68    char attribs[MAXSTRING];
69    char attribsEx[MAXSTRING];
70    int stat;
71    BFILE bfd;
72    struct CHKSUM chksum;
73    BSOCK *dir;
74    JCR *jcr = (JCR *)pkt;
75
76    if (job_canceled(jcr)) {
77       return 0;
78    }
79
80    dir = jcr->dir_bsock;
81    jcr->num_files_examined++;         /* bump total file count */
82
83    switch (ff_pkt->type) {
84    case FT_LNKSAVED:                  /* Hard linked, file already saved */
85       Dmsg2(30, "FT_LNKSAVED saving: %s => %s\n", ff_pkt->fname, ff_pkt->link);
86       break;
87    case FT_REGE:
88       Dmsg1(30, "FT_REGE saving: %s\n", ff_pkt->fname);
89       break;
90    case FT_REG:
91       Dmsg1(30, "FT_REG saving: %s\n", ff_pkt->fname);
92       break;
93    case FT_LNK:
94       Dmsg2(30, "FT_LNK saving: %s -> %s\n", ff_pkt->fname, ff_pkt->link);
95       break;
96    case FT_DIRBEGIN:
97       return 1;                       /* ignored */
98    case FT_DIREND:
99       Dmsg1(30, "FT_DIR saving: %s\n", ff_pkt->fname);
100       break;
101    case FT_SPEC:
102       Dmsg1(30, "FT_SPEC saving: %s\n", ff_pkt->fname);
103       break;
104    case FT_RAW:
105       Dmsg1(30, "FT_RAW saving: %s\n", ff_pkt->fname);
106       break;
107    case FT_FIFO:
108       Dmsg1(30, "FT_FIFO saving: %s\n", ff_pkt->fname);
109       break;
110    case FT_NOACCESS: {
111       berrno be;
112       be.set_errno(ff_pkt->ff_errno);
113       Jmsg(jcr, M_NOTSAVED, 1, _("     Could not access %s: ERR=%s\n"), ff_pkt->fname, be.strerror());
114       jcr->Errors++;
115       return 1;
116    }
117    case FT_NOFOLLOW: {
118       berrno be;
119       be.set_errno(ff_pkt->ff_errno);
120       Jmsg(jcr, M_NOTSAVED, 1, _("     Could not follow link %s: ERR=%s\n"), ff_pkt->fname, be.strerror());
121       jcr->Errors++;
122       return 1;
123    }
124    case FT_NOSTAT: {
125       berrno be;
126       be.set_errno(ff_pkt->ff_errno);
127       Jmsg(jcr, M_NOTSAVED, 1, _("     Could not stat %s: ERR=%s\n"), ff_pkt->fname, be.strerror());
128       jcr->Errors++;
129       return 1;
130    }
131    case FT_DIRNOCHG:
132    case FT_NOCHG:
133       Jmsg(jcr, M_SKIPPED, 1, _("     Unchanged file skipped: %s\n"), ff_pkt->fname);
134       return 1;
135    case FT_ISARCH:
136       Jmsg(jcr, M_SKIPPED, 1, _("     Archive file skipped: %s\n"), ff_pkt->fname);
137       return 1;
138    case FT_NORECURSE:
139       Jmsg(jcr, M_SKIPPED, 1, _("     Recursion turned off. Directory skipped: %s\n"), ff_pkt->fname);
140       return 1;
141    case FT_NOFSCHG:
142       Jmsg(jcr, M_SKIPPED, 1, _("     File system change prohibited. Directory skipped: %s\n"), ff_pkt->fname);
143       return 1;
144    case FT_NOOPEN: {
145       berrno be;
146       be.set_errno(ff_pkt->ff_errno);
147       Jmsg(jcr, M_NOTSAVED, 1, _("     Could not open directory %s: ERR=%s\n"), ff_pkt->fname, be.strerror());
148       jcr->Errors++;
149       return 1;
150    }
151    default:
152       Jmsg(jcr, M_NOTSAVED, 0, _("     Unknown file type %d: %s\n"), ff_pkt->type, ff_pkt->fname);
153       jcr->Errors++;
154       return 1;
155    }
156
157    /* Encode attributes and possibly extend them */
158    encode_stat(attribs, ff_pkt, 0);
159    encode_attribsEx(jcr, attribsEx, ff_pkt);
160
161    jcr->lock();
162    jcr->JobFiles++;                  /* increment number of files sent */
163    pm_strcpy(jcr->last_fname, ff_pkt->fname);
164    jcr->unlock();
165
166    /*
167     * Send file attributes to Director
168     *   File_index
169     *   Stream
170     *   Verify Options
171     *   Filename (full path)
172     *   Encoded attributes
173     *   Link name (if type==FT_LNK)
174     * For a directory, link is the same as fname, but with trailing
175     * slash. For a linked file, link is the link.
176     */
177    /* Send file attributes to Director (note different format than for Storage) */
178    Dmsg2(400, "send ATTR inx=%d fname=%s\n", jcr->JobFiles, ff_pkt->fname);
179    if (ff_pkt->type == FT_LNK || ff_pkt->type == FT_LNKSAVED) {
180       stat = bnet_fsend(dir, "%d %d %s %s%c%s%c%s%c", jcr->JobFiles,
181             STREAM_UNIX_ATTRIBUTES, ff_pkt->VerifyOpts, ff_pkt->fname,
182             0, attribs, 0, ff_pkt->link, 0);
183    } else if (ff_pkt->type == FT_DIREND) {
184          /* Here link is the canonical filename (i.e. with trailing slash) */
185          stat = bnet_fsend(dir,"%d %d %s %s%c%s%c%c", jcr->JobFiles,
186                STREAM_UNIX_ATTRIBUTES, ff_pkt->VerifyOpts, ff_pkt->link,
187                0, attribs, 0, 0);
188    } else {
189       stat = bnet_fsend(dir,"%d %d %s %s%c%s%c%c", jcr->JobFiles,
190             STREAM_UNIX_ATTRIBUTES, ff_pkt->VerifyOpts, ff_pkt->fname,
191             0, attribs, 0, 0);
192    }
193    Dmsg2(20, "bfiled>bdird: attribs len=%d: msg=%s\n", dir->msglen, dir->msg);
194    if (!stat) {
195       Jmsg(jcr, M_FATAL, 0, _("Network error in send to Director: ERR=%s\n"), bnet_strerror(dir));
196       return 0;
197    }
198
199    /*
200     * The remainder of the function is all about getting the checksum.
201     * First we initialise, then we read files, other streams and Finder Info.
202     */
203    if (ff_pkt->type != FT_LNKSAVED && (S_ISREG(ff_pkt->statp.st_mode) &&
204             ff_pkt->flags & (FO_MD5|FO_SHA1))) {
205       chksum_init(&chksum, ff_pkt->flags);
206       binit(&bfd);
207
208       if (ff_pkt->statp.st_size > 0 || ff_pkt->type == FT_RAW
209             || ff_pkt->type == FT_FIFO) {
210          if ((bopen(&bfd, ff_pkt->fname, O_RDONLY | O_BINARY, 0)) < 0) {
211             ff_pkt->ff_errno = errno;
212             berrno be;
213             be.set_errno(bfd.berrno);
214             Jmsg(jcr, M_NOTSAVED, 1, _("     Cannot open %s: ERR=%s.\n"),
215                  ff_pkt->fname, be.strerror());
216             jcr->Errors++;
217             return 1;
218          }
219          read_chksum(&bfd, &chksum, jcr);
220          bclose(&bfd);
221       }
222
223 #ifdef HAVE_DARWIN_OS
224       /* Open resource fork if necessary */
225       if (ff_pkt->flags & FO_HFSPLUS && ff_pkt->hfsinfo.rsrclength > 0) {
226          if (bopen_rsrc(&bfd, ff_pkt->fname, O_RDONLY | O_BINARY, 0) < 0) {
227             ff_pkt->ff_errno = errno;
228             berrno be;
229             Jmsg(jcr, M_NOTSAVED, -1, _("     Cannot open resource fork for %s: ERR=%s.\n"),
230                   ff_pkt->fname, be.strerror());
231             jcr->Errors++;
232             if (is_bopen(&ff_pkt->bfd)) {
233                bclose(&ff_pkt->bfd);
234             }
235             return 1;
236          }
237          read_chksum(&bfd, &chksum, jcr);
238          bclose(&bfd);
239       }
240       if (ff_pkt->flags & FO_HFSPLUS) {
241          chksum_update(&chksum, ((unsigned char *)ff_pkt->hfsinfo.fndrinfo), 32);
242       }
243 #endif
244
245       /* compute MD5 or SHA1 hash */
246       if (chksum.updated) {
247          char chksumbuf[40];                  /* 24 should do */
248          int stream = 0;
249
250          chksum_final(&chksum);
251          if (chksum.type == CHKSUM_MD5) {
252             stream = STREAM_MD5_SIGNATURE;
253          } else if (chksum.type == CHKSUM_SHA1) {
254             stream = STREAM_SHA1_SIGNATURE;
255          }
256          bin_to_base64(chksumbuf, (char *)chksum.signature, chksum.length);
257          Dmsg3(400, "send inx=%d %s=%s\n", jcr->JobFiles, chksum.name, chksumbuf);
258          bnet_fsend(dir, "%d %d %s *%s-%d*", jcr->JobFiles, stream, chksumbuf,
259                chksum.name, jcr->JobFiles);
260          Dmsg3(20, "bfiled>bdird: %s len=%d: msg=%s\n", chksum.name,
261                dir->msglen, dir->msg);
262       }
263    }
264
265    return 1;
266 }
267
268 /*
269  * Read checksum of bfd, updating chksum
270  * In case of errors we need the job control record and file name.
271  */
272 int read_chksum(BFILE *bfd, CHKSUM *chksum, JCR *jcr)
273 {
274    int64_t n;
275
276    while ((n=bread(bfd, jcr->big_buf, jcr->buf_size)) > 0) {
277       chksum_update(chksum, ((unsigned char *)jcr->big_buf), (int)n);
278       jcr->JobBytes += n;
279       jcr->ReadBytes += n;
280    }
281    if (n < 0) {
282       berrno be;
283       be.set_errno(bfd->berrno);
284       Jmsg(jcr, M_ERROR, 1, _("Error reading file %s: ERR=%s\n"),
285             jcr->last_fname, be.strerror());
286       jcr->Errors++;
287       return -1;
288    }
289    return 0;
290 }