]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/stored/mac.c
kes Fix problem of Virtual backup not writing a sequential FileIndex.
[bacula/bacula] / bacula / src / stored / mac.c
1 /*
2    Bacula® - The Network Backup Solution
3
4    Copyright (C) 2006-2008 Free Software Foundation Europe e.V.
5
6    The main author of Bacula is Kern Sibbald, with contributions from
7    many others, a complete list can be found in the file AUTHORS.
8    This program is Free Software; you can redistribute it and/or
9    modify it under the terms of version two of the GNU General Public
10    License as published by the Free Software Foundation and included
11    in the file LICENSE.
12
13    This program is distributed in the hope that it will be useful, but
14    WITHOUT ANY WARRANTY; without even the implied warranty of
15    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16    General Public License for more details.
17
18    You should have received a copy of the GNU General Public License
19    along with this program; if not, write to the Free Software
20    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
21    02110-1301, USA.
22
23    Bacula® is a registered trademark of Kern Sibbald.
24    The licensor of Bacula is the Free Software Foundation Europe
25    (FSFE), Fiduciary Program, Sumatrastrasse 25, 8006 Zürich,
26    Switzerland, email:ftf@fsfeurope.org.
27 */
28 /*
29  * SD -- mac.c --  responsible for doing
30  *     migration, archive, copy, and virtual backup jobs.
31  *
32  *     Kern Sibbald, January MMVI
33  *
34  *   Version $Id$
35  */
36
37 #include "bacula.h"
38 #include "stored.h"
39
40 /* Import functions */
41 extern char Job_end[];   
42
43 /* Forward referenced subroutines */
44 static bool record_cb(DCR *dcr, DEV_RECORD *rec);
45
46
47 /*
48  *  Read Data and send to File Daemon
49  *   Returns: false on failure
50  *            true  on success
51  */
52 bool do_mac(JCR *jcr)
53 {
54    bool ok = true;
55    BSOCK *dir = jcr->dir_bsock;
56    const char *Type;
57    char ec1[50];
58    DEVICE *dev;
59
60    switch(jcr->get_JobType()) {
61    case JT_MIGRATE:
62       Type = "Migration";
63       break;
64    case JT_ARCHIVE:
65       Type = "Archive";
66       break;
67    case JT_COPY:
68       Type = "Copy";
69       break;
70    case JT_BACKUP:
71       Type = "Virtual Backup";
72       break;
73    default:
74       Type = "Unknown";
75       break;
76    }
77
78
79    Dmsg0(20, "Start read data.\n");
80
81    if (!jcr->read_dcr || !jcr->dcr) {
82       Jmsg(jcr, M_FATAL, 0, _("Read and write devices not properly initialized.\n"));
83       goto bail_out;
84    }
85    Dmsg2(100, "read_dcr=%p write_dcr=%p\n", jcr->read_dcr, jcr->dcr);
86
87
88    create_restore_volume_list(jcr);
89    if (jcr->NumReadVolumes == 0) {
90       Jmsg(jcr, M_FATAL, 0, _("No Volume names found for %s.\n"), Type);
91       goto bail_out;
92    }
93
94    Dmsg3(200, "Found %d volumes names for %s. First=%s\n", jcr->NumReadVolumes,
95       jcr->VolList->VolumeName, Type);
96
97    /* Ready devices for reading and writing */
98    if (!acquire_device_for_read(jcr->read_dcr) ||
99        !acquire_device_for_append(jcr->dcr)) {
100       set_jcr_job_status(jcr, JS_ErrorTerminated);
101       goto bail_out;
102    }
103
104    Dmsg2(200, "===== After acquire pos %u:%u\n", jcr->dcr->dev->file, jcr->dcr->dev->block_num);
105      
106    set_jcr_job_status(jcr, JS_Running);
107    dir_send_job_status(jcr);
108
109    begin_data_spool(jcr->dcr);
110    begin_attribute_spool(jcr);
111
112    jcr->dcr->VolFirstIndex = jcr->dcr->VolLastIndex = 0;
113    jcr->run_time = time(NULL);
114    set_start_vol_position(jcr->dcr);
115
116    ok = read_records(jcr->read_dcr, record_cb, mount_next_read_volume);
117    goto ok_out;
118
119 bail_out:
120    ok = false;
121
122 ok_out:
123    if (jcr->dcr) {
124       dev = jcr->dcr->dev;
125       Dmsg1(100, "ok=%d\n", ok);
126       if (ok || dev->can_write()) {
127          /* Flush out final partial block of this session */
128          if (!write_block_to_device(jcr->dcr)) {
129             Jmsg2(jcr, M_FATAL, 0, _("Fatal append error on device %s: ERR=%s\n"),
130                   dev->print_name(), dev->bstrerror());
131             Dmsg0(100, _("Set ok=FALSE after write_block_to_device.\n"));
132             ok = false;
133          }
134          Dmsg2(200, "Flush block to device pos %u:%u\n", dev->file, dev->block_num);
135       }  
136
137       if (!ok) {
138          discard_data_spool(jcr->dcr);
139       } else {
140          /* Note: if commit is OK, the device will remain locked */
141          commit_data_spool(jcr->dcr);
142       }
143
144       if (ok && dev->is_dvd()) {
145          ok = dvd_close_job(jcr->dcr);   /* do DVD cleanup if any */
146       }
147       /* Release the device -- and send final Vol info to DIR */
148       release_device(jcr->dcr);
149
150       if (!ok || job_canceled(jcr)) {
151          discard_attribute_spool(jcr);
152       } else {
153          commit_attribute_spool(jcr);
154       }
155    }
156
157    if (jcr->read_dcr) {
158       if (!release_device(jcr->read_dcr)) {
159          ok = false;
160       }
161    }
162
163    free_restore_volume_list(jcr);
164
165    dir_send_job_status(jcr);          /* update director */
166
167
168    Dmsg0(30, "Done reading.\n");
169    jcr->end_time = time(NULL);
170    dequeue_messages(jcr);             /* send any queued messages */
171    if (ok) {
172       set_jcr_job_status(jcr, JS_Terminated);
173    }
174    generate_daemon_event(jcr, "JobEnd");
175    dir->fsend(Job_end, jcr->Job, jcr->JobStatus, jcr->JobFiles,
176       edit_uint64(jcr->JobBytes, ec1));
177    Dmsg4(100, Job_end, jcr->Job, jcr->JobStatus, jcr->JobFiles, ec1); 
178        
179    dir->signal(BNET_EOD);             /* send EOD to Director daemon */
180
181    return ok;
182 }
183
184 /*
185  * Called here for each record from read_records()
186  *  Returns: true if OK
187  *           false if error
188  */
189 static bool record_cb(DCR *dcr, DEV_RECORD *rec)
190 {
191    JCR *jcr = dcr->jcr;
192    DEVICE *dev = jcr->dcr->dev;
193    char buf1[100], buf2[100];
194    int32_t stream;   
195    uint32_t last_VolSessionId = 0;
196    uint32_t last_VolSessionTime = 0;
197    int32_t  last_FileIndex = 0;
198    
199    /* If label and not for us, discard it */
200    if (rec->FileIndex < 0 && rec->match_stat <= 0) {
201       return true;
202    }
203    /* We want to write SOS_LABEL and EOS_LABEL discard all others */
204    switch (rec->FileIndex) {                        
205    case PRE_LABEL:
206    case VOL_LABEL:
207    case EOT_LABEL:
208    case EOM_LABEL:
209       return true;                    /* don't write vol labels */
210    }
211    /*
212     * For normal migration jobs, FileIndex values are sequential because
213     *  we are dealing with one job.  However, for Vbackup (consolidation),
214     *  we will be getting records from multiple jobs and writing them back
215     *  out, so we need to ensure that the output FileIndex is sequential.
216     *  We do so by detecting a FileIndex change and incrementing the
217     *  JobFiles, which we then use as the output FileIndex.
218     */
219    if (rec->VolSessionId != last_VolSessionId || 
220        rec->VolSessionTime != last_VolSessionTime ||
221        (rec->FileIndex > 0 && rec->FileIndex != last_FileIndex)) {
222       jcr->JobFiles++;
223       last_VolSessionId = rec->VolSessionId;
224       last_VolSessionTime = rec->VolSessionTime;
225       last_FileIndex = rec->FileIndex;
226       rec->FileIndex = jcr->JobFiles;     /* set sequential output FileIndex */
227    }
228    /*
229     * Modify record SessionId and SessionTime to correspond to
230     * output.
231     */
232    rec->VolSessionId = jcr->VolSessionId;
233    rec->VolSessionTime = jcr->VolSessionTime;
234    Dmsg5(200, "before write_rec JobId=%d FI=%s SessId=%d Strm=%s len=%d\n",
235       jcr->JobId,
236       FI_to_ascii(buf1, rec->FileIndex), rec->VolSessionId,
237       stream_to_ascii(buf1, rec->Stream,rec->FileIndex), rec->data_len);
238
239    while (!write_record_to_block(jcr->dcr->block, rec)) {
240       Dmsg4(200, "!write_record_to_block blkpos=%u:%u len=%d rem=%d\n", 
241             dev->file, dev->block_num, rec->data_len, rec->remainder);
242       if (!write_block_to_device(jcr->dcr)) {
243          Dmsg2(90, "Got write_block_to_dev error on device %s. %s\n",
244             dev->print_name(), dev->bstrerror());
245          Jmsg2(jcr, M_FATAL, 0, _("Fatal append error on device %s: ERR=%s\n"),
246                dev->print_name(), dev->bstrerror());
247          return false;
248       }
249       Dmsg2(200, "===== Wrote block new pos %u:%u\n", dev->file, dev->block_num);
250    }
251    jcr->JobBytes += rec->data_len;   /* increment bytes this job */
252    if (rec->FileIndex <= 0) {
253       return true;                    /* don't send LABELs to Dir */
254    }
255    Dmsg5(500, "wrote_record JobId=%d FI=%s SessId=%d Strm=%s len=%d\n",
256       jcr->JobId,
257       FI_to_ascii(buf1, rec->FileIndex), rec->VolSessionId,
258       stream_to_ascii(buf2, rec->Stream, rec->FileIndex), rec->data_len);
259
260    /* Send attributes and digest to Director for Catalog */
261    stream = rec->Stream;
262    if (stream == STREAM_UNIX_ATTRIBUTES || stream == STREAM_UNIX_ATTRIBUTES_EX ||
263        crypto_digest_stream_type(stream) != CRYPTO_DIGEST_NONE) {
264       if (!jcr->no_attributes) {
265          BSOCK *dir = jcr->dir_bsock;
266          if (are_attributes_spooled(jcr)) {
267             dir->set_spooling();
268          }
269          Dmsg0(850, "Send attributes to dir.\n");
270          if (!dir_update_file_attributes(jcr->dcr, rec)) {
271             dir->clear_spooling();
272             Jmsg(jcr, M_FATAL, 0, _("Error updating file attributes. ERR=%s\n"),
273                dir->bstrerror());
274             return false;
275          }
276          dir->clear_spooling();
277       }
278    }
279
280    return true;
281 }