]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/filed/backup.c
Update version
[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    bnet_sig(sd, BNET_EOD);            /* end of sending data */
100
101    stop_heartbeat_monitor(jcr);
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    if (!encode_and_send_attributes(jcr, ff_pkt, data_stream)) {
228       return 0;
229    }
230
231    /*
232     * Setup for signature handling.
233     * Then initialise the file descriptor we use for data and other streams.
234     */
235    chksum_init(&chksum, ff_pkt->flags);
236
237    binit(&ff_pkt->bfd);
238    if (ff_pkt->flags & FO_PORTABLE) {
239       set_portable_backup(&ff_pkt->bfd); /* disable Win32 BackupRead() */
240    }
241    if (ff_pkt->reader) {
242       if (!set_prog(&ff_pkt->bfd, ff_pkt->reader, jcr)) {
243          Jmsg(jcr, M_FATAL, 0, _("Python reader program \"%s\" not found.\n"), 
244             ff_pkt->reader);
245          return 0;
246       }
247    }
248
249    /*
250     * Open any file with data that we intend to save, then save it.
251     *
252     * Note, if is_win32_backup, we must open the Directory so that
253     * the BackupRead will save its permissions and ownership streams.
254     */
255    if (ff_pkt->type != FT_LNKSAVED && (S_ISREG(ff_pkt->statp.st_mode) &&
256          ff_pkt->statp.st_size > 0) ||
257          ff_pkt->type == FT_RAW || ff_pkt->type == FT_FIFO ||
258          (!is_portable_backup(&ff_pkt->bfd) && ff_pkt->type == FT_DIREND)) {
259       btimer_t *tid;
260       if (ff_pkt->type == FT_FIFO) {
261          tid = start_thread_timer(pthread_self(), 60);
262       } else {
263          tid = NULL;
264       }
265       if (bopen(&ff_pkt->bfd, ff_pkt->fname, O_RDONLY | O_BINARY, 0) < 0) {
266          ff_pkt->ff_errno = errno;
267          berrno be;
268          Jmsg(jcr, M_NOTSAVED, 0, _("     Cannot open %s: ERR=%s.\n"), ff_pkt->fname,
269               be.strerror());
270          jcr->Errors++;
271          if (tid) {
272             stop_thread_timer(tid);
273             tid = NULL;
274          }
275          return 1;
276       }
277       if (tid) {
278          stop_thread_timer(tid);
279          tid = NULL;
280       }
281       stat = send_data(jcr, data_stream, ff_pkt, &chksum);
282       bclose(&ff_pkt->bfd);
283       if (!stat) {
284          return 0;
285       }
286    }
287
288 #ifdef HAVE_DARWIN_OS
289    /* Regular files can have resource forks and Finder Info */
290    if (ff_pkt->type != FT_LNKSAVED && (S_ISREG(ff_pkt->statp.st_mode) &&
291             ff_pkt->flags & FO_HFSPLUS)) {
292       if (ff_pkt->hfsinfo.rsrclength > 0) {
293          int flags;
294          if (!bopen_rsrc(&ff_pkt->bfd, ff_pkt->fname, O_RDONLY | O_BINARY, 0) < 0) {
295             ff_pkt->ff_errno = errno;
296             berrno be;
297             Jmsg(jcr, M_NOTSAVED, -1, _("     Cannot open resource fork for %s: ERR=%s.\n"), ff_pkt->fname,
298                   be.strerror());
299             jcr->Errors++;
300             if (is_bopen(&ff_pkt->bfd)) {
301                bclose(&ff_pkt->bfd);
302             }
303             return 1;
304          }
305          flags = ff_pkt->flags;
306          ff_pkt->flags &= ~(FO_GZIP|FO_SPARSE);
307          stat = send_data(jcr, STREAM_MACOS_FORK_DATA, ff_pkt, &chksum);
308          ff_pkt->flags = flags;
309          bclose(&ff_pkt->bfd);
310          if (!stat) {
311             return 0;
312          }
313       }
314
315       Dmsg1(300, "Saving Finder Info for \"%s\"\n", ff_pkt->fname);
316       bnet_fsend(sd, "%ld %d 0", jcr->JobFiles, STREAM_HFSPLUS_ATTRIBUTES);
317       Dmsg1(300, "bfiled>stored:header %s\n", sd->msg);
318       memcpy(sd->msg, ff_pkt->hfsinfo.fndrinfo, 32);
319       sd->msglen = 32;
320       chksum_update(&chksum, (unsigned char *)sd->msg, sd->msglen);
321       bnet_send(sd);
322       bnet_sig(sd, BNET_EOD);
323    }
324 #endif
325
326    if (ff_pkt->flags & FO_ACL) {
327       /* Read access ACLs for files, dirs and links */
328       if (!read_and_send_acl(jcr, BACL_TYPE_ACCESS, STREAM_UNIX_ATTRIBUTES_ACCESS_ACL)) {
329          return 0;
330       }
331       /* Directories can have default ACLs too */
332       if (ff_pkt->type == FT_DIREND && (BACL_CAP & BACL_CAP_DEFAULTS_DIR)) {
333          if (!read_and_send_acl(jcr, BACL_TYPE_DEFAULT, STREAM_UNIX_ATTRIBUTES_DEFAULT_ACL)) {
334             return 0;
335          }
336       }
337    }
338
339    /* Terminate any signature and send it to Storage daemon and the Director */
340    if (chksum.updated) {
341       int stream = 0;
342       chksum_final(&chksum);
343       if (chksum.type == CHKSUM_MD5) {
344          stream = STREAM_MD5_SIGNATURE;
345       } else if (chksum.type == CHKSUM_SHA1) {
346          stream = STREAM_SHA1_SIGNATURE;
347       } else {
348          Jmsg1(jcr, M_WARNING, 0, _("Unknown signature type %i.\n"), chksum.type);
349       }
350       if (stream != 0) {
351          bnet_fsend(sd, "%ld %d 0", jcr->JobFiles, stream);
352          Dmsg1(300, "bfiled>stored:header %s\n", sd->msg);
353          memcpy(sd->msg, chksum.signature, chksum.length);
354          sd->msglen = chksum.length;
355          bnet_send(sd);
356          bnet_sig(sd, BNET_EOD);              /* end of checksum */
357       }
358    }
359
360    return 1;
361 }
362
363 /*
364  * Send data read from an already open file descriptor.
365  *
366  * We return 1 on sucess and 0 on errors.
367  *
368  * ***FIXME***
369  * We use ff_pkt->statp.st_size when FO_SPARSE.
370  * Currently this is not a problem as the only other stream, resource forks,
371  * are not handled as sparse files.
372  */
373 int send_data(JCR *jcr, int stream, FF_PKT *ff_pkt, struct CHKSUM *chksum)
374 {
375    BSOCK *sd = jcr->store_bsock;
376    uint64_t fileAddr = 0;             /* file address */
377    char *rbuf, *wbuf;
378    int rsize = jcr->buf_size;      /* read buffer size */
379    POOLMEM *msgsave;
380
381    msgsave = sd->msg;
382    rbuf = sd->msg;                    /* read buffer */
383    wbuf = sd->msg;                    /* write buffer */
384
385
386    Dmsg1(300, "Saving data, type=%d\n", ff_pkt->type);
387
388
389 #ifdef HAVE_LIBZ
390    uLong compress_len, max_compress_len = 0;
391    const Bytef *cbuf = NULL;
392
393    if (ff_pkt->flags & FO_GZIP) {
394       if (ff_pkt->flags & FO_SPARSE) {
395          cbuf = (Bytef *)jcr->compress_buf + SPARSE_FADDR_SIZE;
396          max_compress_len = jcr->compress_buf_size - SPARSE_FADDR_SIZE;
397       } else {
398          cbuf = (Bytef *)jcr->compress_buf;
399          max_compress_len = jcr->compress_buf_size; /* set max length */
400       }
401       wbuf = jcr->compress_buf;    /* compressed output here */
402    }
403 #endif
404
405    /*
406     * Send Data header to Storage daemon
407     *    <file-index> <stream> <info>
408     */
409    if (!bnet_fsend(sd, "%ld %d 0", jcr->JobFiles, stream)) {
410       Jmsg1(jcr, M_FATAL, 0, _("Network send error to SD. ERR=%s\n"),
411             bnet_strerror(sd));
412       return 0;
413    }
414    Dmsg1(300, ">stored: datahdr %s\n", sd->msg);
415
416    /*
417     * Make space at beginning of buffer for fileAddr because this
418     *   same buffer will be used for writing if compression if off.
419     */
420    if (ff_pkt->flags & FO_SPARSE) {
421       rbuf += SPARSE_FADDR_SIZE;
422       rsize -= SPARSE_FADDR_SIZE;
423 #ifdef HAVE_FREEBSD_OS
424       /*
425        * To read FreeBSD partitions, the read size must be
426        *  a multiple of 512.
427        */
428       rsize = (rsize/512) * 512;
429 #endif
430    }
431
432    /* a RAW device read on win32 only works if the buffer is a multiple of 512 */
433 #ifdef HAVE_WIN32
434    if (S_ISBLK(ff_pkt->statp.st_mode))
435       rsize = (rsize/512) * 512;      
436 #endif
437
438    /*
439     * Read the file data
440     */
441    while ((sd->msglen=(uint32_t)bread(&ff_pkt->bfd, rbuf, rsize)) > 0) {
442       int sparseBlock = 0;
443
444       /* Check for sparse blocks */
445       if (ff_pkt->flags & FO_SPARSE) {
446          ser_declare;
447          if (sd->msglen == rsize &&
448              (fileAddr+sd->msglen < (uint64_t)ff_pkt->statp.st_size)) {
449             sparseBlock = is_buf_zero(rbuf, rsize);
450          }
451
452          ser_begin(wbuf, SPARSE_FADDR_SIZE);
453          ser_uint64(fileAddr);     /* store fileAddr in begin of buffer */
454       }
455
456       jcr->ReadBytes += sd->msglen;         /* count bytes read */
457       fileAddr += sd->msglen;
458
459       /* Update checksum if requested */
460       chksum_update(chksum, (unsigned char *)rbuf, sd->msglen);
461
462 #ifdef HAVE_LIBZ
463       /* Do compression if turned on */
464       if (!sparseBlock && ff_pkt->flags & FO_GZIP) {
465          int zstat;
466          compress_len = max_compress_len;
467          Dmsg4(400, "cbuf=0x%x len=%u rbuf=0x%x len=%u\n", cbuf, compress_len,
468             rbuf, sd->msglen);
469          /* NOTE! This call modifies compress_len !!! */
470          if ((zstat=compress2((Bytef *)cbuf, &compress_len,
471                (const Bytef *)rbuf, (uLong)sd->msglen,
472                ff_pkt->GZIP_level)) != Z_OK) {
473             Jmsg(jcr, M_FATAL, 0, _("Compression error: %d\n"), zstat);
474             sd->msg = msgsave;
475             sd->msglen = 0;
476             set_jcr_job_status(jcr, JS_ErrorTerminated);
477             return 0;
478          }
479          Dmsg2(400, "compressed len=%d uncompressed len=%d\n",
480             compress_len, sd->msglen);
481
482          sd->msglen = compress_len;      /* set compressed length */
483       }
484 #endif
485
486       /* Send the buffer to the Storage daemon */
487       if (!sparseBlock) {
488          if (ff_pkt->flags & FO_SPARSE) {
489             sd->msglen += SPARSE_FADDR_SIZE; /* include fileAddr in size */
490          }
491          sd->msg = wbuf;              /* set correct write buffer */
492          if (!bnet_send(sd)) {
493             Jmsg1(jcr, M_FATAL, 0, _("Network send error to SD. ERR=%s\n"),
494                   bnet_strerror(sd));
495             sd->msg = msgsave;     /* restore bnet buffer */
496             sd->msglen = 0;
497             return 0;
498          }
499       }
500       Dmsg1(130, "Send data to SD len=%d\n", sd->msglen);
501       /*          #endif */
502       jcr->JobBytes += sd->msglen;      /* count bytes saved possibly compressed */
503       sd->msg = msgsave;                /* restore read buffer */
504
505    } /* end while read file data */
506
507
508    if (sd->msglen < 0) {
509       berrno be;
510       Jmsg(jcr, M_ERROR, 0, _("Read error on file %s. ERR=%s\n"),
511          ff_pkt->fname, be.strerror(ff_pkt->bfd.berrno));
512       if (jcr->Errors++ > 1000) {       /* insanity check */
513          Jmsg(jcr, M_FATAL, 0, _("Too many errors.\n"));
514       }
515
516    }
517
518    if (!bnet_sig(sd, BNET_EOD)) {        /* indicate end of file data */
519       Jmsg1(jcr, M_FATAL, 0, _("Network send error to SD. ERR=%s\n"),
520             bnet_strerror(sd));
521       return 0;
522    }
523
524    return 1;
525 }
526
527 /*
528  * Read and send an ACL for the last encountered file.
529  */
530 static bool read_and_send_acl(JCR *jcr, int acltype, int stream)
531 {
532 #ifdef HAVE_ACL
533    BSOCK *sd = jcr->store_bsock;
534    POOLMEM *msgsave;
535    int len;
536
537    len = bacl_get(jcr, acltype);
538    if (len < 0) {
539       Jmsg1(jcr, M_WARNING, 0, _("Error reading ACL of %s\n"), jcr->last_fname);
540       return true; 
541    }
542    if (len == 0) {
543       return true;                    /* no ACL */
544    }
545
546    /* Send header */
547    if (!bnet_fsend(sd, "%ld %d 0", jcr->JobFiles, stream)) {
548       Jmsg1(jcr, M_FATAL, 0, _("Network send error to SD. ERR=%s\n"),
549             bnet_strerror(sd));
550       return false;
551    }
552
553    /* Send the buffer to the storage deamon */
554    Dmsg2(400, "Backing up ACL type 0x%2x <%s>\n", acltype, jcr->acl_text);
555    msgsave = sd->msg;
556    sd->msg = jcr->acl_text;
557    sd->msglen = len + 1;
558    if (!bnet_send(sd)) {
559       sd->msg = msgsave;
560       sd->msglen = 0;
561       Jmsg1(jcr, M_FATAL, 0, _("Network send error to SD. ERR=%s\n"),
562             bnet_strerror(sd));
563       return false;
564    }
565
566    jcr->JobBytes += sd->msglen;
567    sd->msg = msgsave;
568    if (!bnet_sig(sd, BNET_EOD)) {
569       Jmsg1(jcr, M_FATAL, 0, _("Network send error to SD. ERR=%s\n"),
570             bnet_strerror(sd));
571       return false;
572    }
573
574    Dmsg1(200, "ACL of file: %s successfully backed up!\n", jcr->last_fname);
575 #endif
576    return true;
577 }
578
579 static bool encode_and_send_attributes(JCR *jcr, FF_PKT *ff_pkt, int &data_stream) 
580 {
581    BSOCK *sd = jcr->store_bsock;
582    char attribs[MAXSTRING];
583    char attribsEx[MAXSTRING];
584    int attr_stream;
585    int stat;
586 #ifdef FD_NO_SEND_TEST
587    return true;
588 #endif
589
590    /* Find what data stream we will use, then encode the attributes */
591    data_stream = select_data_stream(ff_pkt);
592    encode_stat(attribs, ff_pkt, data_stream);
593
594    /* Now possibly extend the attributes */
595    attr_stream = encode_attribsEx(jcr, attribsEx, ff_pkt);
596
597    Dmsg3(300, "File %s\nattribs=%s\nattribsEx=%s\n", ff_pkt->fname, attribs, attribsEx);
598
599    P(jcr->mutex);
600    jcr->JobFiles++;                    /* increment number of files sent */
601    ff_pkt->FileIndex = jcr->JobFiles;  /* return FileIndex */
602    pm_strcpy(jcr->last_fname, ff_pkt->fname);
603    V(jcr->mutex);
604
605    /*
606     * Send Attributes header to Storage daemon
607     *    <file-index> <stream> <info>
608     */
609    if (!bnet_fsend(sd, "%ld %d 0", jcr->JobFiles, attr_stream)) {
610       Jmsg1(jcr, M_FATAL, 0, _("Network send error to SD. ERR=%s\n"),
611             bnet_strerror(sd));
612       return false;
613    }
614    Dmsg1(300, ">stored: attrhdr %s\n", sd->msg);
615
616    /*
617     * Send file attributes to Storage daemon
618     *   File_index
619     *   File type
620     *   Filename (full path)
621     *   Encoded attributes
622     *   Link name (if type==FT_LNK or FT_LNKSAVED)
623     *   Encoded extended-attributes (for Win32)
624     *
625     * For a directory, link is the same as fname, but with trailing
626     * slash. For a linked file, link is the link.
627     */
628    if (ff_pkt->type == FT_LNK || ff_pkt->type == FT_LNKSAVED) {
629       Dmsg2(300, "Link %s to %s\n", ff_pkt->fname, ff_pkt->link);
630       stat = bnet_fsend(sd, "%ld %d %s%c%s%c%s%c%s%c", jcr->JobFiles,
631                ff_pkt->type, ff_pkt->fname, 0, attribs, 0, ff_pkt->link, 0,
632                attribsEx, 0);
633    } else if (ff_pkt->type == FT_DIREND) {
634       /* Here link is the canonical filename (i.e. with trailing slash) */
635       stat = bnet_fsend(sd, "%ld %d %s%c%s%c%c%s%c", jcr->JobFiles,
636                ff_pkt->type, ff_pkt->link, 0, attribs, 0, 0, attribsEx, 0);
637    } else {
638       stat = bnet_fsend(sd, "%ld %d %s%c%s%c%c%s%c", jcr->JobFiles,
639                ff_pkt->type, ff_pkt->fname, 0, attribs, 0, 0, attribsEx, 0);
640    }
641
642    Dmsg2(300, ">stored: attr len=%d: %s\n", sd->msglen, sd->msg);
643    if (!stat) {
644       Jmsg1(jcr, M_FATAL, 0, _("Network send error to SD. ERR=%s\n"),
645             bnet_strerror(sd));
646       return false;
647    }
648    bnet_sig(sd, BNET_EOD);            /* indicate end of attributes data */
649    return true;
650 }