2 Bacula(R) - The Network Backup Solution
4 Copyright (C) 2000-2015 Kern Sibbald
6 The original author of Bacula is Kern Sibbald, with contributions
7 from many others, a complete list can be found in the file AUTHORS.
9 You may use this file and others of this release according to the
10 license defined in the LICENSE file, which includes the Affero General
11 Public License, v3.0 ("AGPLv3") and some additional permissions and
12 terms pursuant to its AGPLv3 Section 7.
14 This notice must be preserved when any source code is
15 conveyed and/or propagated.
17 Bacula(R) is a registered trademark of Kern Sibbald.
21 * Bacula Director -- catreq.c -- handles the message channel
22 * catalog request from the Storage daemon.
24 * Kern Sibbald, March MMI
26 * This routine runs as a thread and must be thread reentrant.
28 * Basic tasks done here:
29 * Handle Catalog services.
35 #include "findlib/find.h"
38 * Handle catalog request
39 * For now, we simply return next Volume to be used
42 /* Requests from the Storage daemon */
43 static char Find_media[] = "CatReq Job=%127s FindMedia=%d pool_name=%127s media_type=%127s vol_type=%d\n";
44 static char Get_Vol_Info[] = "CatReq Job=%127s GetVolInfo VolName=%127s write=%d\n";
46 static char Update_media[] = "CatReq Job=%127s UpdateMedia VolName=%s"
47 " VolJobs=%u VolFiles=%u VolBlocks=%u VolBytes=%lld VolABytes=%lld"
48 " VolHoleBytes=%lld VolHoles=%u VolMounts=%u"
49 " VolErrors=%u VolWrites=%lld MaxVolBytes=%lld EndTime=%lld VolStatus=%10s"
50 " Slot=%d relabel=%d InChanger=%d VolReadTime=%lld VolWriteTime=%lld"
51 " VolFirstWritten=%lld VolType=%u\n";
53 static char Create_jobmedia[] = "CatReq Job=%127s CreateJobMedia\n";
55 /* Responses sent to Storage daemon */
56 static char OK_media[] = "1000 OK VolName=%s VolJobs=%u VolFiles=%u"
57 " VolBlocks=%u VolBytes=%s VolABytes=%s VolHoleBytes=%s VolHoles=%u"
58 " VolMounts=%u VolErrors=%u VolWrites=%s"
59 " MaxVolBytes=%s VolCapacityBytes=%s VolStatus=%s Slot=%d"
60 " MaxVolJobs=%u MaxVolFiles=%u InChanger=%d VolReadTime=%s"
61 " VolWriteTime=%s EndFile=%u EndBlock=%u VolType=%u LabelType=%d"
62 " MediaId=%s ScratchPoolId=%s\n";
64 static char OK_create[] = "1000 OK CreateJobMedia\n";
67 static int send_volume_info_to_storage_daemon(JCR *jcr, BSOCK *sd, MEDIA_DBR *mr)
70 char ed1[50], ed2[50], ed3[50], ed4[50], ed5[50], ed6[50], ed7[50], ed8[50],
73 jcr->MediaId = mr->MediaId;
74 pm_strcpy(jcr->VolumeName, mr->VolumeName);
75 bash_spaces(mr->VolumeName);
76 stat = sd->fsend(OK_media, mr->VolumeName, mr->VolJobs,
77 mr->VolFiles, mr->VolBlocks, edit_uint64(mr->VolBytes, ed1),
78 edit_uint64(mr->VolABytes, ed2),
79 edit_uint64(mr->VolHoleBytes, ed3),
80 mr->VolHoles, mr->VolMounts, mr->VolErrors,
81 edit_uint64(mr->VolWrites, ed4),
82 edit_uint64(mr->MaxVolBytes, ed5),
83 edit_uint64(mr->VolCapacityBytes, ed6),
84 mr->VolStatus, mr->Slot, mr->MaxVolJobs, mr->MaxVolFiles,
86 edit_int64(mr->VolReadTime, ed7),
87 edit_int64(mr->VolWriteTime, ed8),
88 mr->EndFile, mr->EndBlock,
91 edit_uint64(mr->MediaId, ed9),
92 edit_uint64(mr->ScratchPoolId, ed10));
93 unbash_spaces(mr->VolumeName);
94 Dmsg2(100, "Vol Info for %s: %s", jcr->Job, sd->msg);
98 /* TODO: See if we want to let the FD do all kind
99 * of catalog request/update
101 void catalog_request(JCR *jcr, BSOCK *bs)
105 char Job[MAX_NAME_LENGTH];
106 char pool_name[MAX_NAME_LENGTH];
107 int index, ok, label, writing;
111 utime_t VolFirstWritten;
112 utime_t VolLastWritten;
115 memset(&sdmr, 0, sizeof(sdmr));
116 memset(&jm, 0, sizeof(jm));
120 * Request to find next appendable Volume for this Job
122 Dmsg1(200, "catreq %s", bs->msg);
124 omsg = get_memory(bs->msglen+1);
125 pm_strcpy(omsg, bs->msg);
126 bs->fsend(_("1990 Invalid Catalog Request: %s"), omsg);
127 Jmsg1(jcr, M_FATAL, 0, _("Invalid Catalog request; DB not open: %s"), omsg);
132 * Find next appendable medium for SD
134 n = sscanf(bs->msg, Find_media, &Job, &index, &pool_name, &mr.MediaType, &mr.VolType);
136 memset(&pr, 0, sizeof(pr));
137 bstrncpy(pr.Name, pool_name, sizeof(pr.Name));
138 unbash_spaces(pr.Name);
139 ok = db_get_pool_record(jcr, jcr->db, &pr);
141 mr.PoolId = pr.PoolId;
142 set_storageid_in_mr(jcr->wstore, &mr);
143 mr.ScratchPoolId = pr.ScratchPoolId;
144 ok = find_next_volume_for_append(jcr, &mr, index, fnv_create_vol, fnv_prune);
145 Dmsg3(050, "find_media ok=%d idx=%d vol=%s\n", ok, index, mr.VolumeName);
147 /* Report problem finding pool */
148 Jmsg1(jcr, M_WARNING, 0, _("Pool \"%s\" not found for SD find media request.\n"),
152 * Send Find Media response to Storage daemon
155 send_volume_info_to_storage_daemon(jcr, bs, &mr);
157 bs->fsend(_("1901 No Media.\n"));
158 Dmsg0(500, "1901 No Media.\n");
162 Dmsg1(1000, "Tried find_media. fields wanted=4, got=%d\n", n);
165 * Request to find specific Volume information
167 n = sscanf(bs->msg, Get_Vol_Info, &Job, &mr.VolumeName, &writing);
169 Dmsg1(100, "CatReq GetVolInfo Vol=%s\n", mr.VolumeName);
173 unbash_spaces(mr.VolumeName);
174 if (db_get_media_record(jcr, jcr->db, &mr)) {
175 const char *reason = NULL; /* detailed reason for rejection */
177 * If we are reading, accept any volume (reason == NULL)
178 * If we are writing, check if the Volume is valid
179 * for this job, and do a recycle if necessary
183 * SD wants to write this Volume, so make
184 * sure it is suitable for this job, i.e.
185 * Pool matches, and it is either Append or Recycle
186 * and Media Type matches and Pool allows any volume.
188 if (mr.PoolId != jcr->jr.PoolId) {
189 reason = _("not in Pool");
190 } else if (strcmp(mr.MediaType, jcr->wstore->media_type) != 0) {
191 reason = _("not correct MediaType");
194 * Now try recycling if necessary
195 * reason set non-NULL if we cannot use it
197 check_if_volume_valid_or_recyclable(jcr, &mr, &reason);
200 if (!reason && mr.Enabled != 1) {
201 reason = _("is not Enabled");
203 if (reason == NULL) {
205 * Send Find Media response to Storage daemon
207 send_volume_info_to_storage_daemon(jcr, bs, &mr);
209 /* Not suitable volume */
210 bs->fsend(_("1998 Volume \"%s\" catalog status is %s, %s.\n"), mr.VolumeName,
211 mr.VolStatus, reason);
215 bs->fsend(_("1997 Volume \"%s\" not in catalog.\n"), mr.VolumeName);
216 Dmsg1(100, "1997 Volume \"%s\" not in catalog.\n", mr.VolumeName);
220 Dmsg1(1000, "Tried get_vol_info. fields wanted=3, got=%d\n", n);
224 * Request to update Media record. Comes typically at the end
225 * of a Storage daemon Job Session, when labeling/relabeling a
226 * Volume, or when an EOF mark is written.
228 n = sscanf(bs->msg, Update_media, &Job, &sdmr.VolumeName,
229 &sdmr.VolJobs, &sdmr.VolFiles, &sdmr.VolBlocks, &sdmr.VolBytes,
230 &sdmr.VolABytes, &sdmr.VolHoleBytes, &sdmr.VolHoles,
231 &sdmr.VolMounts, &sdmr.VolErrors, &sdmr.VolWrites, &sdmr.MaxVolBytes,
232 &VolLastWritten, &sdmr.VolStatus, &sdmr.Slot, &label, &sdmr.InChanger,
233 &sdmr.VolReadTime, &sdmr.VolWriteTime, &VolFirstWritten,
237 Dmsg3(400, "Update media %s oldStat=%s newStat=%s\n", sdmr.VolumeName,
238 mr.VolStatus, sdmr.VolStatus);
239 bstrncpy(mr.VolumeName, sdmr.VolumeName, sizeof(mr.VolumeName)); /* copy Volume name */
240 unbash_spaces(mr.VolumeName);
241 if (!db_get_media_record(jcr, jcr->db, &mr)) {
242 Jmsg(jcr, M_ERROR, 0, _("Unable to get Media record for Volume %s: ERR=%s\n"),
243 mr.VolumeName, db_strerror(jcr->db));
244 bs->fsend(_("1991 Catalog Request for vol=%s failed: %s"),
245 mr.VolumeName, db_strerror(jcr->db));
249 /* Set first written time if this is first job */
250 if (mr.FirstWritten == 0) {
251 if (VolFirstWritten == 0) {
252 mr.FirstWritten = jcr->start_time; /* use Job start time as first write */
254 mr.FirstWritten = VolFirstWritten;
256 mr.set_first_written = true;
258 /* If we just labeled the tape set time */
259 if (label || mr.LabelDate == 0) {
260 mr.LabelDate = jcr->start_time;
261 mr.set_label_date = true;
262 if (mr.InitialWrite == 0) {
263 mr.InitialWrite = jcr->start_time;
265 Dmsg2(400, "label=%d labeldate=%d\n", label, mr.LabelDate);
268 * Insanity check for VolFiles get set to a smaller value
270 if (sdmr.VolFiles < mr.VolFiles) {
271 Jmsg(jcr, M_INFO, 0, _("Attempt to set Volume Files from %u to %u"
272 " for Volume \"%s\". Ignored.\n"),
273 mr.VolFiles, sdmr.VolFiles, mr.VolumeName);
274 sdmr.VolFiles = mr.VolFiles; /* keep orginal value */
277 Dmsg2(400, "Update media: BefVolJobs=%u After=%u\n", mr.VolJobs, sdmr.VolJobs);
280 * Check if the volume has been written by the job,
281 * and update the LastWritten field if needed.
283 if (mr.VolBlocks != sdmr.VolBlocks && VolLastWritten != 0) {
284 mr.LastWritten = VolLastWritten;
288 * Update to point to the last device used to write the Volume.
289 * However, do so only if we are writing the tape, i.e.
290 * the number of VolWrites has increased.
292 if (jcr->wstore && sdmr.VolWrites > mr.VolWrites) {
293 Dmsg2(050, "Update StorageId old=%d new=%d\n",
294 mr.StorageId, jcr->wstore->StorageId);
295 /* Update StorageId after write */
296 set_storageid_in_mr(jcr->wstore, &mr);
298 /* Nothing written, reset same StorageId */
299 set_storageid_in_mr(NULL, &mr);
302 /* Copy updated values to original media record */
303 mr.VolJobs = sdmr.VolJobs;
304 mr.VolFiles = sdmr.VolFiles;
305 mr.VolBlocks = sdmr.VolBlocks;
306 mr.VolBytes = sdmr.VolBytes;
307 mr.VolABytes = sdmr.VolABytes;
308 mr.VolHoleBytes = sdmr.VolHoleBytes;
309 mr.VolHoles = sdmr.VolHoles;
310 mr.VolMounts = sdmr.VolMounts;
311 mr.VolErrors = sdmr.VolErrors;
312 mr.VolWrites = sdmr.VolWrites;
314 mr.InChanger = sdmr.InChanger;
315 mr.VolType = sdmr.VolType;
316 bstrncpy(mr.VolStatus, sdmr.VolStatus, sizeof(mr.VolStatus));
317 if (sdmr.VolReadTime >= 0) {
318 mr.VolReadTime = sdmr.VolReadTime;
320 if (sdmr.VolWriteTime >= 0) {
321 mr.VolWriteTime = sdmr.VolWriteTime;
324 Dmsg2(400, "db_update_media_record. Stat=%s Vol=%s\n", mr.VolStatus, mr.VolumeName);
326 * Update the database, then before sending the response to the
327 * SD, check if the Volume has expired.
329 if (!db_update_media_record(jcr, jcr->db, &mr)) {
330 Jmsg(jcr, M_FATAL, 0, _("Catalog error updating Media record. %s"),
331 db_strerror(jcr->db));
332 bs->fsend(_("1993 Update Media error\n"));
333 Pmsg0(000, "1993 Update Media error\n");
335 (void)has_volume_expired(jcr, &mr);
336 send_volume_info_to_storage_daemon(jcr, bs, &mr);
341 Dmsg1(1000, "Tried update_media. fields wanted=20, got=%d\n", n);
344 * Request to create a JobMedia record
346 if (sscanf(bs->msg, Create_jobmedia, &Job) == 1) {
348 jm.JobId = jcr->wjcr->JobId;
350 jm.JobId = jcr->JobId;
354 db_start_transaction(jcr, jcr->db);
355 while (bs->recv() >= 0) {
356 if (ok && sscanf(bs->msg, "%u %u %u %u %u %u %lld\n",
357 &jm.FirstIndex, &jm.LastIndex, &jm.StartFile, &jm.EndFile,
358 &jm.StartBlock, &jm.EndBlock, &MediaId) != 7) {
363 jm.MediaId = MediaId;
364 Dmsg6(400, "create_jobmedia JobId=%d MediaId=%d SF=%d EF=%d FI=%d LI=%d\n",
365 jm.JobId, jm.MediaId, jm.StartFile, jm.EndFile, jm.FirstIndex, jm.LastIndex);
366 ok = db_create_jobmedia_record(jcr, jcr->db, &jm);
369 db_end_transaction(jcr, jcr->db);
371 Jmsg(jcr, M_FATAL, 0, _("Catalog error creating JobMedia record. %s"),
372 db_strerror(jcr->db));
374 bs->fsend(_("1992 Create JobMedia error\n"));
378 Dmsg0(400, "JobMedia record created\n");
379 bs->fsend(OK_create);
383 /* Handle snapshot catalog request */
384 if (snapshot_catreq(jcr, bs)) {
388 Dmsg1(1000, "Tried create_jobmedia. fields wanted=10, got=%d\n", n);
390 /* Everything failed. Send error message. */
391 omsg = get_memory(bs->msglen+1);
392 pm_strcpy(omsg, bs->msg);
393 bs->fsend(_("1990 Invalid Catalog Request: %s"), omsg);
394 Jmsg1(jcr, M_FATAL, 0, _("Invalid Catalog request: %s"), omsg);
398 Dmsg1(400, ">CatReq response: %s", bs->msg);
399 Dmsg1(400, "Leave catreq jcr 0x%x\n", jcr);
404 * Note, we receive the whole attribute record, but we select out only the stat
405 * packet, VolSessionId, VolSessionTime, FileIndex, file type, and file name to
406 * store in the catalog.
408 static void update_attribute(JCR *jcr, char *msg, int32_t msglen)
411 uint32_t VolSessionId, VolSessionTime;
420 /* Start transaction allocates jcr->attr and jcr->ar if needed */
421 db_start_transaction(jcr, jcr->db); /* start transaction if not already open */
425 * Start by scanning directly in the message buffer to get Stream
426 * there may be a cached attr so we cannot yet write into
427 * jcr->attr or jcr->ar
430 skip_nonspaces(&p); /* UpdCat */
432 skip_nonspaces(&p); /* Job=nnn */
434 skip_nonspaces(&p); /* "FileAttributes" */
436 /* The following "SD header" fields are serialized */
438 unser_uint32(VolSessionId); /* VolSessionId */
439 unser_uint32(VolSessionTime); /* VolSessionTime */
440 unser_int32(FileIndex); /* FileIndex */
441 unser_int32(Stream); /* Stream */
442 unser_uint32(reclen); /* Record length */
443 p += unser_length(p); /* Raw record follows */
446 * At this point p points to the raw record, which varies according
447 * to what kind of a record (Stream) was sent. Note, the integer
448 * fields at the beginning of these "raw" records are in ASCII with
449 * spaces between them so one can use scanf or manual scanning to
450 * extract the fields.
455 * Filename (full path)
457 * Link name (if type==FT_LNK or FT_LNKSAVED)
458 * Encoded extended-attributes (for Win32)
459 * Delta sequence number (32 bit int)
465 * Object_len (possibly compressed)
466 * Object_full_len (not compressed)
473 Dmsg1(400, "UpdCat msg=%s\n", msg);
474 Dmsg5(400, "UpdCat VolSessId=%d VolSessT=%d FI=%d Strm=%d reclen=%d\n",
475 VolSessionId, VolSessionTime, FileIndex, Stream, reclen);
477 if (Stream == STREAM_UNIX_ATTRIBUTES || Stream == STREAM_UNIX_ATTRIBUTES_EX) {
478 if (jcr->cached_attribute) {
479 Dmsg2(400, "Cached attr. Stream=%d fname=%s\n", ar->Stream, ar->fname);
480 if (!db_create_attributes_record(jcr, jcr->db, ar)) {
481 Jmsg1(jcr, M_FATAL, 0, _("Attribute create error: ERR=%s"), db_strerror(jcr->db));
483 jcr->cached_attribute = false;
485 /* Any cached attr is flushed so we can reuse jcr->attr and jcr->ar */
486 jcr->attr = check_pool_memory_size(jcr->attr, msglen);
487 memcpy(jcr->attr, msg, msglen);
488 p = jcr->attr - msg + p; /* point p into jcr->attr */
489 skip_nonspaces(&p); /* skip FileIndex */
491 ar->FileType = str_to_int32(p);
492 skip_nonspaces(&p); /* skip FileType */
495 len = strlen(fname); /* length before attributes */
496 attr = &fname[len+1];
498 if (ar->FileType == FT_REG) {
499 p = attr + strlen(attr) + 1; /* point to link */
500 p = p + strlen(p) + 1; /* point to extended attributes */
501 p = p + strlen(p) + 1; /* point to delta sequence */
503 * Older FDs don't have a delta sequence, so check if it is there
505 if (p - jcr->attr < msglen) {
506 ar->DeltaSeq = str_to_int32(p); /* delta_seq */
510 Dmsg2(400, "dird<stored: stream=%d %s\n", Stream, fname);
511 Dmsg1(400, "dird<stored: attr=%s\n", attr);
514 if (ar->FileType == FT_DELETED) {
515 ar->FileIndex = 0; /* special value */
517 ar->FileIndex = FileIndex;
522 ar->JobId = jcr->wjcr->JobId;
523 Dmsg1(100, "=== set JobId=%d\n", ar->JobId);
525 ar->JobId = jcr->JobId;
528 ar->DigestType = CRYPTO_DIGEST_NONE;
529 jcr->cached_attribute = true;
531 Dmsg2(400, "dird<filed: stream=%d %s\n", Stream, fname);
532 Dmsg1(400, "dird<filed: attr=%s\n", attr);
534 } else if (Stream == STREAM_RESTORE_OBJECT) {
537 memset(&ro, 0, sizeof(ro));
539 ro.FileIndex = FileIndex;
541 ro.JobId = jcr->wjcr->JobId;
542 Dmsg1(100, "=== set JobId=%d\n", ar->JobId);
544 ro.JobId = jcr->JobId;
547 Dmsg1(100, "Robj=%s\n", p);
549 skip_nonspaces(&p); /* skip FileIndex */
551 ro.FileType = str_to_int32(p); /* FileType */
554 ro.object_index = str_to_int32(p); /* Object Index */
557 ro.object_len = str_to_int32(p); /* object length possibly compressed */
560 ro.object_full_len = str_to_int32(p); /* uncompressed object length */
563 ro.object_compression = str_to_int32(p); /* compression */
567 ro.plugin_name = p; /* point to plugin name */
568 len = strlen(ro.plugin_name);
569 ro.object_name = &ro.plugin_name[len+1]; /* point to object name */
570 len = strlen(ro.object_name);
571 ro.object = &ro.object_name[len+1]; /* point to object */
572 ro.object[ro.object_len] = 0; /* add zero for those who attempt printing */
573 Dmsg7(100, "oname=%s stream=%d FT=%d FI=%d JobId=%d, obj_len=%d\nobj=\"%s\"\n",
574 ro.object_name, ro.Stream, ro.FileType, ro.FileIndex, ro.JobId,
575 ro.object_len, ro.object);
577 if (!db_create_restore_object_record(jcr, jcr->db, &ro)) {
578 Jmsg1(jcr, M_FATAL, 0, _("Restore object create error. %s"), db_strerror(jcr->db));
581 } else if (crypto_digest_stream_type(Stream) != CRYPTO_DIGEST_NONE) {
583 if (ar->FileIndex != FileIndex) {
584 Jmsg3(jcr, M_WARNING, 0, _("%s not same File=%d as attributes=%d\n"),
585 stream_to_ascii(Stream), FileIndex, ar->FileIndex);
587 /* Update digest in catalog */
588 char digestbuf[BASE64_SIZE(CRYPTO_DIGEST_MAX_SIZE)];
590 int type = CRYPTO_DIGEST_NONE;
593 case STREAM_MD5_DIGEST:
594 len = CRYPTO_DIGEST_MD5_SIZE;
595 type = CRYPTO_DIGEST_MD5;
597 case STREAM_SHA1_DIGEST:
598 len = CRYPTO_DIGEST_SHA1_SIZE;
599 type = CRYPTO_DIGEST_SHA1;
601 case STREAM_SHA256_DIGEST:
602 len = CRYPTO_DIGEST_SHA256_SIZE;
603 type = CRYPTO_DIGEST_SHA256;
605 case STREAM_SHA512_DIGEST:
606 len = CRYPTO_DIGEST_SHA512_SIZE;
607 type = CRYPTO_DIGEST_SHA512;
610 /* Never reached ... */
611 Jmsg(jcr, M_ERROR, 0, _("Catalog error updating file digest. Unsupported digest stream type: %d"),
615 bin_to_base64(digestbuf, sizeof(digestbuf), fname, len, true);
616 Dmsg3(400, "DigestLen=%d Digest=%s type=%d\n", strlen(digestbuf),
618 if (jcr->cached_attribute) {
619 ar->Digest = digestbuf;
620 ar->DigestType = type;
621 Dmsg2(400, "Cached attr with digest. Stream=%d fname=%s\n",
622 ar->Stream, ar->fname);
624 /* Update BaseFile table */
625 if (!db_create_attributes_record(jcr, jcr->db, ar)) {
626 Jmsg1(jcr, M_FATAL, 0, _("attribute create error. ERR=%s"),
627 db_strerror(jcr->db));
629 jcr->cached_attribute = false;
631 if (!db_add_digest_to_file_record(jcr, jcr->db, ar->FileId, digestbuf, type)) {
632 Jmsg(jcr, M_ERROR, 0, _("Catalog error updating file digest. %s"),
633 db_strerror(jcr->db));
641 * Update File Attributes in the catalog with data
642 * sent by the Storage daemon.
644 void catalog_update(JCR *jcr, BSOCK *bs)
646 if (!jcr->pool->catalog_files) {
647 return; /* user disabled cataloging */
649 if (jcr->is_job_canceled()) {
653 POOLMEM *omsg = get_memory(bs->msglen+1);
654 pm_strcpy(omsg, bs->msg);
655 bs->fsend(_("1994 Invalid Catalog Update: %s"), omsg);
656 Jmsg1(jcr, M_FATAL, 0, _("Invalid Catalog Update; DB not open: %s"), omsg);
660 update_attribute(jcr, bs->msg, bs->msglen);
663 if (jcr->is_job_canceled()) {
664 jcr->cached_attribute = false;
665 cancel_storage_daemon_job(jcr);
670 * Update File Attributes in the catalog with data read from
671 * the storage daemon spool file. We receive the filename and
674 bool despool_attributes_from_file(JCR *jcr, const char *file)
680 int32_t msglen; /* message length */
681 POOLMEM *msg = get_pool_memory(PM_MESSAGE);
684 Dmsg1(100, "Begin despool_attributes_from_file\n", file);
686 if (jcr->is_job_canceled() || !jcr->pool->catalog_files || !jcr->db) {
687 goto bail_out; /* user disabled cataloging */
690 spool_fd = fopen(file, "rb");
692 Dmsg0(100, "cancel despool_attributes_from_file\n");
693 /* send an error message */
696 #if defined(HAVE_POSIX_FADVISE) && defined(POSIX_FADV_WILLNEED)
697 posix_fadvise(fileno(spool_fd), 0, 0, POSIX_FADV_WILLNEED);
700 while (fread((char *)&pktsiz, 1, sizeof(int32_t), spool_fd) ==
702 size += sizeof(int32_t);
703 msglen = ntohl(pktsiz);
705 if (msglen > (int32_t) sizeof_pool_memory(msg)) {
706 msg = realloc_pool_memory(msg, msglen + 1);
708 nbytes = fread(msg, 1, msglen, spool_fd);
709 if (nbytes != (size_t) msglen) {
711 Dmsg2(400, "nbytes=%d msglen=%d\n", nbytes, msglen);
712 Qmsg1(jcr, M_FATAL, 0, _("fread attr spool error. ERR=%s\n"),
718 if (!jcr->is_job_canceled()) {
719 update_attribute(jcr, msg, msglen);
720 if (jcr->is_job_canceled() || (jcr->wjcr && jcr->wjcr->is_job_canceled())) {
725 if (ferror(spool_fd)) {
727 Qmsg1(jcr, M_FATAL, 0, _("fread attr spool error. ERR=%s\n"),
729 Dmsg1(050, "fread attr spool error. ERR=%s\n", be.bstrerror());
739 if (jcr->is_job_canceled()) {
740 jcr->cached_attribute = false;
741 cancel_storage_daemon_job(jcr);
744 free_pool_memory(msg);
745 Dmsg1(100, "End despool_attributes_from_file ret=%i\n", ret);