]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/filed/backup.c
Integrated Preben 'Peppe' Guldberg <peppe@wielders.org>
[bacula/bacula] / bacula / src / filed / backup.c
1 /*
2  *  Bacula File Daemon  backup.c  send file attributes and data
3  *   to the Storage daemon.
4  *
5  *    Kern Sibbald, March MM
6  *
7  *   Version $Id$
8  *
9  */
10 /*
11    Copyright (C) 2000-2004 Kern Sibbald
12
13    This program is free software; you can redistribute it and/or
14    modify it under the terms of the GNU General Public License as
15    published by the Free Software Foundation; either version 2 of
16    the License, or (at your option) any later version.
17
18    This program is distributed in the hope that it will be useful,
19    but WITHOUT ANY WARRANTY; without even the implied warranty of
20    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
21    General Public License for more details.
22
23    You should have received a copy of the GNU General Public
24    License along with this program; if not, write to the Free
25    Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
26    MA 02111-1307, USA.
27
28  */
29
30 #include "bacula.h"
31 #include "filed.h"
32
33 #ifdef HAVE_ACL
34 #include <sys/acl.h>
35 #include <acl/libacl.h>
36 #endif
37
38 static int save_file(FF_PKT *ff_pkt, void *pkt);
39 static int send_data(int stream, FF_PKT *ff_pkt, BSOCK *sd, JCR *jcr, struct CHKSUM *chksum);
40
41 /* 
42  * Find all the requested files and send them
43  * to the Storage daemon. 
44  *
45  * Note, we normally carry on a one-way
46  * conversation from this point on with the SD, simply blasting
47  * data to him.  To properly know what is going on, we
48  * also run a "heartbeat" monitor which reads the socket and
49  * reacts accordingly (at the moment it has nothing to do
50  * except echo the heartbeat to the Director).
51  * 
52  */
53 bool blast_data_to_storage_daemon(JCR *jcr, char *addr) 
54 {
55    BSOCK *sd;
56    bool ok = true;
57
58    sd = jcr->store_bsock;
59
60    set_jcr_job_status(jcr, JS_Running);
61
62    Dmsg1(300, "bfiled: opened data connection %d to stored\n", sd->fd);
63
64    LockRes();
65    CLIENT *client = (CLIENT *)GetNextRes(R_CLIENT, NULL);
66    UnlockRes();
67    uint32_t buf_size;
68    if (client) {
69       buf_size = client->max_network_buffer_size;
70    } else {
71       buf_size = 0;                   /* use default */
72    }
73    if (!bnet_set_buffer_size(sd, buf_size, BNET_SETBUF_WRITE)) {
74       set_jcr_job_status(jcr, JS_ErrorTerminated);
75       Jmsg(jcr, M_FATAL, 0, _("Cannot set buffer size FD->SD.\n"));
76       return false;
77    }
78
79    jcr->buf_size = sd->msglen;             
80    /* Adjust for compression so that output buffer is
81     * 12 bytes + 0.1% larger than input buffer plus 18 bytes.
82     * This gives a bit extra plus room for the sparse addr if any.
83     * Note, we adjust the read size to be smaller so that the
84     * same output buffer can be used without growing it.
85     */
86    jcr->compress_buf_size = jcr->buf_size + ((jcr->buf_size+999) / 1000) + 30;
87    jcr->compress_buf = get_memory(jcr->compress_buf_size);
88
89    Dmsg1(300, "set_find_options ff=%p\n", jcr->ff);
90    set_find_options((FF_PKT *)jcr->ff, jcr->incremental, jcr->mtime);
91    Dmsg0(300, "start find files\n");
92
93    start_heartbeat_monitor(jcr);
94
95    /* Subroutine save_file() is called for each file */
96    if (!find_files(jcr, (FF_PKT *)jcr->ff, save_file, (void *)jcr)) {
97       ok = false;                     /* error */
98       set_jcr_job_status(jcr, JS_ErrorTerminated);
99 //    Jmsg(jcr, M_FATAL, 0, _("Find files error.\n"));
100    }
101
102    stop_heartbeat_monitor(jcr);
103
104    bnet_sig(sd, BNET_EOD);            /* end data connection */
105
106    if (jcr->big_buf) {
107       free(jcr->big_buf);
108       jcr->big_buf = NULL;
109    }
110    if (jcr->compress_buf) {
111       free_pool_memory(jcr->compress_buf);
112       jcr->compress_buf = NULL;
113    }
114    Dmsg1(300, "end blast_data stat=%d\n", ok);
115    return ok;
116 }          
117
118 /* 
119  * Called here by find() for each file included.
120  *
121  *  *****FIXME*****   add FSMs File System Modules
122  *
123  *  Send the file and its data to the Storage daemon.
124  *
125  *  Returns: 1 if OK
126  *           0 if error
127  *          -1 to ignore file/directory (not used here)
128  */
129 static int save_file(FF_PKT *ff_pkt, void *vjcr)
130 {
131    char attribs[MAXSTRING];
132    char attribsEx[MAXSTRING];
133    int stat, attr_stream, data_stream;
134    struct CHKSUM chksum;
135    BSOCK *sd;
136    JCR *jcr = (JCR *)vjcr;
137
138    if (job_canceled(jcr)) {
139       return 0;
140    }
141
142    sd = jcr->store_bsock;
143    jcr->num_files_examined++;         /* bump total file count */
144
145    switch (ff_pkt->type) {
146    case FT_LNKSAVED:                  /* Hard linked, file already saved */
147       Dmsg2(130, "FT_LNKSAVED hard link: %s => %s\n", ff_pkt->fname, ff_pkt->link);
148       break;
149    case FT_REGE:
150       Dmsg1(130, "FT_REGE saving: %s\n", ff_pkt->fname);
151       break;
152    case FT_REG:
153       Dmsg1(130, "FT_REG saving: %s\n", ff_pkt->fname);
154       break;
155    case FT_LNK:
156       Dmsg2(130, "FT_LNK saving: %s -> %s\n", ff_pkt->fname, ff_pkt->link);
157       break;
158    case FT_DIRBEGIN:
159       return 1;                       /* not used */
160    case FT_NORECURSE:
161    case FT_NOFSCHG:
162    case FT_INVALIDFS:
163    case FT_DIREND:
164       if (ff_pkt->type == FT_NORECURSE) {
165          Jmsg(jcr, M_INFO, 1, _("     Recursion turned off. Will not descend into %s\n"), 
166             ff_pkt->fname);
167       } else if (ff_pkt->type == FT_NOFSCHG) {
168          Jmsg(jcr, M_INFO, 1, _("     File system change prohibited. Will not descend into %s\n"), 
169             ff_pkt->fname);
170       } else if (ff_pkt->type == FT_INVALIDFS) {
171          Jmsg(jcr, M_INFO, 1, _("     Disallowed filesystem. Will not descend into %s\n"), 
172             ff_pkt->fname);
173       }
174       ff_pkt->type = FT_DIREND;       /* value is used below */
175       Dmsg1(130, "FT_DIR saving: %s\n", ff_pkt->link);
176       break;
177    case FT_SPEC:
178       Dmsg1(130, "FT_SPEC saving: %s\n", ff_pkt->fname);
179       break;
180    case FT_RAW:
181       Dmsg1(130, "FT_RAW saving: %s\n", ff_pkt->fname);
182       break;
183    case FT_FIFO:
184       Dmsg1(130, "FT_FIFO saving: %s\n", ff_pkt->fname);
185       break;
186    case FT_NOACCESS: {
187       berrno be;
188       be.set_errno(ff_pkt->ff_errno);
189       Jmsg(jcr, M_NOTSAVED, 0, _("     Could not access %s: ERR=%s\n"), ff_pkt->fname, 
190          be.strerror());
191       jcr->Errors++;
192       return 1;
193    }
194    case FT_NOFOLLOW: {
195       berrno be;
196       be.set_errno(ff_pkt->ff_errno);
197       Jmsg(jcr, M_NOTSAVED, 0, _("     Could not follow link %s: ERR=%s\n"), ff_pkt->fname, 
198          be.strerror());
199       jcr->Errors++;
200       return 1;
201    }
202    case FT_NOSTAT: {
203       berrno be;
204       be.set_errno(ff_pkt->ff_errno);
205       Jmsg(jcr, M_NOTSAVED, 0, _("     Could not stat %s: ERR=%s\n"), ff_pkt->fname, 
206          be.strerror());
207       jcr->Errors++;
208       return 1;
209    }
210    case FT_DIRNOCHG:
211    case FT_NOCHG:
212       Jmsg(jcr, M_SKIPPED, 1, _("     Unchanged file skipped: %s\n"), ff_pkt->fname);
213       return 1;
214    case FT_ISARCH:
215       Jmsg(jcr, M_NOTSAVED, 0, _("     Archive file not saved: %s\n"), ff_pkt->fname);
216       return 1;
217    case FT_NOOPEN: {
218       berrno be;
219       be.set_errno(ff_pkt->ff_errno);
220       Jmsg(jcr, M_NOTSAVED, 0, _("     Could not open directory %s: ERR=%s\n"), ff_pkt->fname, 
221          be.strerror());
222       jcr->Errors++;
223       return 1;
224    }
225    default:
226       Jmsg(jcr, M_NOTSAVED, 0,  _("     Unknown file type %d; not saved: %s\n"), ff_pkt->type, ff_pkt->fname);
227       jcr->Errors++;
228       return 1;
229    }
230
231    Dmsg1(130, "bfiled: sending %s to stored\n", ff_pkt->fname);
232
233    /* Find what data stream we will use, then encode the attributes */
234    data_stream = select_data_stream(ff_pkt);
235    encode_stat(attribs, ff_pkt, data_stream);
236
237    /* Now possibly extend the attributes */
238    attr_stream = encode_attribsEx(jcr, attribsEx, ff_pkt);
239
240    Dmsg3(300, "File %s\nattribs=%s\nattribsEx=%s\n", ff_pkt->fname, attribs, attribsEx);
241      
242    P(jcr->mutex);
243    jcr->JobFiles++;                    /* increment number of files sent */
244    ff_pkt->FileIndex = jcr->JobFiles;  /* return FileIndex */
245    pm_strcpy(jcr->last_fname, ff_pkt->fname);
246    V(jcr->mutex);
247     
248    /*
249     * Send Attributes header to Storage daemon
250     *    <file-index> <stream> <info>
251     */
252    if (!bnet_fsend(sd, "%ld %d 0", jcr->JobFiles, attr_stream)) {
253       berrno be;
254       Jmsg1(jcr, M_FATAL, 0, _("Network send error to SD. ERR=%s\n"),
255             bnet_strerror(sd));
256       return 0;
257    }
258    Dmsg1(300, ">stored: attrhdr %s\n", sd->msg);
259
260    /*
261     * Send file attributes to Storage daemon
262     *   File_index
263     *   File type
264     *   Filename (full path)
265     *   Encoded attributes
266     *   Link name (if type==FT_LNK or FT_LNKSAVED)
267     *   Encoded extended-attributes (for Win32)
268     *
269     * For a directory, link is the same as fname, but with trailing
270     * slash. For a linked file, link is the link.
271     */
272    if (ff_pkt->type == FT_LNK || ff_pkt->type == FT_LNKSAVED) {
273       Dmsg2(300, "Link %s to %s\n", ff_pkt->fname, ff_pkt->link);
274       stat = bnet_fsend(sd, "%ld %d %s%c%s%c%s%c%s%c", jcr->JobFiles, 
275                ff_pkt->type, ff_pkt->fname, 0, attribs, 0, ff_pkt->link, 0,
276                attribsEx, 0);
277    } else if (ff_pkt->type == FT_DIREND) {
278       /* Here link is the canonical filename (i.e. with trailing slash) */
279       stat = bnet_fsend(sd, "%ld %d %s%c%s%c%c%s%c", jcr->JobFiles, 
280                ff_pkt->type, ff_pkt->link, 0, attribs, 0, 0, attribsEx, 0);
281    } else {
282       stat = bnet_fsend(sd, "%ld %d %s%c%s%c%c%s%c", jcr->JobFiles, 
283                ff_pkt->type, ff_pkt->fname, 0, attribs, 0, 0, attribsEx, 0);
284    }
285
286    Dmsg2(300, ">stored: attr len=%d: %s\n", sd->msglen, sd->msg);
287    if (!stat) {
288       berrno be;
289       Jmsg1(jcr, M_FATAL, 0, _("Network send error to SD. ERR=%s\n"),
290             bnet_strerror(sd));
291       return 0;
292    }
293    bnet_sig(sd, BNET_EOD);            /* indicate end of attributes data */
294
295    /*
296     * Setup for signature handling.
297     * Then initialise the file descriptor we use for data and other streams.
298     */
299    chksum_init(&chksum, ff_pkt->flags);
300
301    binit(&ff_pkt->bfd);
302    if (ff_pkt->flags & FO_PORTABLE) {
303       set_portable_backup(&ff_pkt->bfd); /* disable Win32 BackupRead() */
304    }
305    if (ff_pkt->reader) {
306       set_prog(&ff_pkt->bfd, ff_pkt->reader, jcr);
307    }
308
309    /* 
310     * Open any file with data that we intend to save, then save it.
311     *
312     * Note, if is_win32_backup, we must open the Directory so that
313     * the BackupRead will save its permissions and ownership streams.
314     */
315    if (ff_pkt->type != FT_LNKSAVED && (S_ISREG(ff_pkt->statp.st_mode) && 
316          ff_pkt->statp.st_size > 0) || 
317          ff_pkt->type == FT_RAW || ff_pkt->type == FT_FIFO ||
318          (!is_portable_backup(&ff_pkt->bfd) && ff_pkt->type == FT_DIREND)) {
319       btimer_t *tid;    
320       if (ff_pkt->type == FT_FIFO) {
321          tid = start_thread_timer(pthread_self(), 60);
322       } else {
323          tid = NULL;
324       }
325       if (bopen(&ff_pkt->bfd, ff_pkt->fname, O_RDONLY | O_BINARY, 0) < 0) {
326          ff_pkt->ff_errno = errno;
327          berrno be;
328          Jmsg(jcr, M_NOTSAVED, 0, _("     Cannot open %s: ERR=%s.\n"), ff_pkt->fname, 
329               be.strerror());
330          jcr->Errors++;
331          if (tid) {
332             stop_thread_timer(tid);
333             tid = NULL;
334          }
335          return 1;
336       }
337       if (tid) {
338          stop_thread_timer(tid);
339          tid = NULL;
340       }
341       stat = send_data(data_stream, ff_pkt, sd, jcr, &chksum);
342       bclose(&ff_pkt->bfd);
343       if (!stat) {
344          return 0;
345       }
346    }
347
348 #ifdef HAVE_DARWIN_OS
349    /* Open resource fork if necessary and save content */
350    if (ff_pkt->type != FT_LNKSAVED && (S_ISREG(ff_pkt->statp.st_mode) &&
351             ff_pkt->flags & FO_HFSPLUS)) {
352       if (ff_pkt->hfsinfo.rsrclength > 0) {
353          int flags;
354          if (!bopen_rsrc(&ff_pkt->bfd, ff_pkt->fname, O_RDONLY | O_BINARY, 0) < 0) {
355             ff_pkt->ff_errno = errno;
356             berrno be;
357             Jmsg(jcr, M_NOTSAVED, -1, _("     Cannot open resource fork for %s: ERR=%s.\n"), ff_pkt->fname, 
358                   be.strerror());
359             jcr->Errors++;
360             if (is_bopen(&ff_pkt->bfd)) {
361                bclose(&ff_pkt->bfd);
362             }
363             return 1;
364          }
365          flags = ff_pkt->flags;
366          ff_pkt->flags &= ~(FO_GZIP|FO_SPARSE);
367          stat = send_data(STREAM_MACOS_FORK_DATA, ff_pkt, sd, jcr, &chksum);
368          ff_pkt->flags = flags;
369          bclose(&ff_pkt->bfd);
370          if (!stat) {
371             return 0;
372          }
373       }
374
375       Dmsg1(300, "Saving Finder Info for \"%s\"", ff_pkt->fname);
376       bnet_fsend(sd, "%ld %d 0", jcr->JobFiles, STREAM_HFSPLUS_ATTRIBUTES);
377       Dmsg1(300, "bfiled>stored:header %s\n", sd->msg);
378       memcpy(sd->msg, ff_pkt->hfsinfo.fndrinfo, 32);
379       sd->msglen = 32;
380       chksum_update(&chksum, (unsigned char *)sd->msg, sd->msglen);
381       bnet_send(sd);
382       bnet_sig(sd, BNET_EOD);
383    }
384 #endif
385
386 #ifdef HAVE_ACL
387    /* ACL stream */
388    if (ff_pkt->flags & FO_ACL) {
389       POOLMEM *msgsave;
390       char *acl_text;
391       /* Read ACLs for files, dirs and links */
392       if (ff_pkt->type == FT_DIREND) {
393          /* Directory: Try for default ACL*/
394          acl_t myAcl = acl_get_file(ff_pkt->fname, ACL_TYPE_DEFAULT);
395          if (!myAcl) {
396             Dmsg1(200, "No default ACL defined for directory: %s!\n", ff_pkt->fname);
397             /* If there is no default ACL get standard ACL */
398             myAcl = acl_get_file(ff_pkt->fname, ACL_TYPE_ACCESS);
399             if (!myAcl) {
400                Jmsg1(jcr, M_WARNING, 0, "Error while trying to get ACL of directory: %s!\n", ff_pkt->fname);
401             }
402          }
403          acl_text = acl_to_any_text(myAcl, NULL, ',', TEXT_ABBREVIATE);
404          /* Free memory */
405          acl_free(myAcl);
406       } else {
407          /* Files or links */
408          acl_t myAcl = acl_get_file(ff_pkt->fname, ACL_TYPE_ACCESS);
409          if (!myAcl) {
410             Jmsg1(jcr, M_WARNING, 0, "Error while trying to get ACL of file: %s!\n", ff_pkt->fname);
411             acl_free(myAcl);
412          }
413          acl_text = acl_to_any_text(myAcl, NULL, ',', TEXT_ABBREVIATE);
414          acl_free(myAcl);
415       }
416
417       /* If there is an ACL, send it to the Storage daemon */
418       if (acl_text) {
419          sd = jcr->store_bsock;
420          pm_strcpy(&jcr->last_fname, ff_pkt->fname);
421
422          /*
423           * Send ACL header
424           *
425           */
426          if (!bnet_fsend(sd, "%ld %d 0", jcr->JobFiles, STREAM_UNIX_ATTRIBUTES_ACL)) {
427             berrno be;
428             Jmsg1(jcr, M_FATAL, 0, _("Network send error to SD. ERR=%s\n"),
429                   bnet_strerror(sd));
430             return 0;
431          }
432
433          /* Send the buffer to the storage deamon */
434          msgsave = sd->msg;
435          sd->msg = acl_text;
436          sd->msglen = strlen(acl_text) + 1;
437          if (!bnet_send(sd)) {
438             berrno be;
439             sd->msg = msgsave;
440             sd->msglen = 0;
441             Jmsg1(jcr, M_FATAL, 0, _("Network send error to SD. ERR=%s\n"),
442                   bnet_strerror(sd));
443          } else {
444             jcr->JobBytes += sd->msglen;
445             sd->msg = msgsave;
446             if (!bnet_sig(sd, BNET_EOD)) {
447                berrno be;
448                Jmsg1(jcr, M_FATAL, 0, _("Network send error to SD. ERR=%s\n"),
449                      bnet_strerror(sd));
450             } else {
451                Dmsg1(200, "ACL of file: %s successfully backed up!\n", ff_pkt->fname);
452             }
453          }  
454       }
455    }
456 #endif
457
458    /* Terminate any signature and send it to Storage daemon and the Director */
459    if (chksum.updated) {
460       int stream = 0;
461       chksum_final(&chksum);
462       if (chksum.type == CHKSUM_MD5) {
463          stream = STREAM_MD5_SIGNATURE;
464       } else if (chksum.type == CHKSUM_SHA1) {
465          stream = STREAM_SHA1_SIGNATURE;
466       } else {
467          Jmsg1(jcr, M_WARNING, 0, _("Unknown signature type %i."), chksum.type);
468       }
469       if (stream != 0) {
470          bnet_fsend(sd, "%ld %d 0", jcr->JobFiles, stream);
471          Dmsg1(300, "bfiled>stored:header %s\n", sd->msg);
472          memcpy(sd->msg, chksum.signature, chksum.length);
473          sd->msglen = chksum.length;
474          bnet_send(sd);
475          bnet_sig(sd, BNET_EOD);              /* end of checksum */
476       }
477    }
478
479    return 1;
480 }
481
482 /*
483  * Send data read from an already open file descriptor.
484  *
485  * We return 1 on sucess and 0 on errors.
486  *
487  * ***FIXME***
488  * We use ff_pkt->statp.st_size when FO_SPARSE.
489  * Currently this is not a problem as the only other stream, resource forks,
490  * are not handled as sparse files.
491  */
492 int send_data(int stream, FF_PKT *ff_pkt, BSOCK *sd, JCR *jcr, struct CHKSUM *chksum)
493 {
494    uint64_t fileAddr = 0;             /* file address */
495    char *rbuf, *wbuf;
496    int rsize = jcr->buf_size;      /* read buffer size */
497    POOLMEM *msgsave;
498
499    msgsave = sd->msg;
500    rbuf = sd->msg;                    /* read buffer */             
501    wbuf = sd->msg;                    /* write buffer */
502
503
504    Dmsg1(300, "Saving data, type=%d\n", ff_pkt->type);
505
506
507 #ifdef HAVE_LIBZ
508    uLong compress_len, max_compress_len = 0;
509    const Bytef *cbuf = NULL;
510
511    if (ff_pkt->flags & FO_GZIP) {
512       if (ff_pkt->flags & FO_SPARSE) {
513          cbuf = (Bytef *)jcr->compress_buf + SPARSE_FADDR_SIZE;
514          max_compress_len = jcr->compress_buf_size - SPARSE_FADDR_SIZE;
515       } else {
516          cbuf = (Bytef *)jcr->compress_buf;
517          max_compress_len = jcr->compress_buf_size; /* set max length */
518       }
519       wbuf = jcr->compress_buf;    /* compressed output here */
520    }
521 #endif
522
523    /*
524     * Send Data header to Storage daemon
525     *    <file-index> <stream> <info>
526     */
527    if (!bnet_fsend(sd, "%ld %d 0", jcr->JobFiles, stream)) {
528       berrno be;
529       Jmsg1(jcr, M_FATAL, 0, _("Network send error to SD. ERR=%s\n"),
530             bnet_strerror(sd));
531       return 0;
532    }
533    Dmsg1(300, ">stored: datahdr %s\n", sd->msg);
534
535    /*
536     * Make space at beginning of buffer for fileAddr because this
537     *   same buffer will be used for writing if compression if off. 
538     */
539    if (ff_pkt->flags & FO_SPARSE) {
540       rbuf += SPARSE_FADDR_SIZE;
541       rsize -= SPARSE_FADDR_SIZE;
542 #ifdef HAVE_FREEBSD_OS
543       /* 
544        * To read FreeBSD partitions, the read size must be
545        *  a multiple of 512.
546        */
547       rsize = (rsize/512) * 512;
548 #endif
549    }
550
551    /* 
552     * Read the file data
553     */
554    while ((sd->msglen=(uint32_t)bread(&ff_pkt->bfd, rbuf, rsize)) > 0) {
555       int sparseBlock = 0;
556
557       /* Check for sparse blocks */
558       if (ff_pkt->flags & FO_SPARSE) {
559          ser_declare;
560          if (sd->msglen == rsize && 
561              (fileAddr+sd->msglen < (uint64_t)ff_pkt->statp.st_size)) {
562             sparseBlock = is_buf_zero(rbuf, rsize);
563          }
564             
565          ser_begin(wbuf, SPARSE_FADDR_SIZE);
566          ser_uint64(fileAddr);     /* store fileAddr in begin of buffer */
567       } 
568
569       jcr->ReadBytes += sd->msglen;         /* count bytes read */
570       fileAddr += sd->msglen;
571
572       /* Update checksum if requested */
573       chksum_update(chksum, (unsigned char *)rbuf, sd->msglen);
574
575 #ifdef HAVE_LIBZ
576       /* Do compression if turned on */
577       if (!sparseBlock && ff_pkt->flags & FO_GZIP) {
578          int zstat;
579          compress_len = max_compress_len;
580          Dmsg4(400, "cbuf=0x%x len=%u rbuf=0x%x len=%u\n", cbuf, compress_len,
581             rbuf, sd->msglen);
582          /* NOTE! This call modifies compress_len !!! */
583          if ((zstat=compress2((Bytef *)cbuf, &compress_len, 
584                (const Bytef *)rbuf, (uLong)sd->msglen,
585                ff_pkt->GZIP_level)) != Z_OK) {
586             Jmsg(jcr, M_FATAL, 0, _("Compression error: %d\n"), zstat);
587             sd->msg = msgsave;
588             sd->msglen = 0;
589             set_jcr_job_status(jcr, JS_ErrorTerminated);
590             return 0;
591          }
592          Dmsg2(400, "compressed len=%d uncompressed len=%d\n", 
593             compress_len, sd->msglen);
594
595          sd->msglen = compress_len;      /* set compressed length */
596       }
597 #endif
598
599       /* Send the buffer to the Storage daemon */
600       if (!sparseBlock) {
601          if (ff_pkt->flags & FO_SPARSE) {
602             sd->msglen += SPARSE_FADDR_SIZE; /* include fileAddr in size */
603          }
604          sd->msg = wbuf;              /* set correct write buffer */
605          if (!bnet_send(sd)) {
606             berrno be;
607             Jmsg2(jcr, M_FATAL, 0, _("Network send error %d to SD. ERR=%s\n"),
608                   sd->msglen, bnet_strerror(sd));
609             sd->msg = msgsave;     /* restore bnet buffer */
610             sd->msglen = 0;
611             return 0;
612          }
613       }
614       Dmsg1(130, "Send data to SD len=%d\n", sd->msglen);
615       /*          #endif */
616       jcr->JobBytes += sd->msglen;      /* count bytes saved possibly compressed */
617       sd->msg = msgsave;                /* restore read buffer */
618
619    } /* end while read file data */
620
621
622    if (sd->msglen < 0) {
623       berrno be;
624       be.set_errno(ff_pkt->bfd.berrno);
625       Jmsg(jcr, M_ERROR, 0, _("Read error on file %s. ERR=%s\n"),
626          ff_pkt->fname, be.strerror());
627    }
628
629    if (!bnet_sig(sd, BNET_EOD)) {        /* indicate end of file data */
630       berrno be;
631       Jmsg1(jcr, M_FATAL, 0, _("Network send error to SD. ERR=%s\n"),
632             bnet_strerror(sd));
633       return 0;
634    }
635
636    return 1;
637 }