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