X-Git-Url: https://git.sur5r.net/?a=blobdiff_plain;f=bacula%2Fsrc%2Fdird%2Fcatreq.c;h=0cf0b6d92fb07e852dc4625046e30ad5461b5697;hb=9890727d214be9b91ad676e518bdbdfa7f4f4f22;hp=605094195966c2c67ce2e4afd8cb9c89c4182c9b;hpb=bc1130e954967ca82703b0cd4d09aad3858df7c7;p=bacula%2Fbacula diff --git a/bacula/src/dird/catreq.c b/bacula/src/dird/catreq.c index 6050941959..0cf0b6d92f 100644 --- a/bacula/src/dird/catreq.c +++ b/bacula/src/dird/catreq.c @@ -1,3 +1,30 @@ +/* + Bacula® - The Network Backup Solution + + Copyright (C) 2001-2012 Free Software Foundation Europe e.V. + + The main author of Bacula is Kern Sibbald, with contributions from + many others, a complete list can be found in the file AUTHORS. + This program is Free Software; you can redistribute it and/or + modify it under the terms of version three of the GNU Affero General Public + License as published by the Free Software Foundation and included + in the file LICENSE. + + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + 02110-1301, USA. + + Bacula® is a registered trademark of Kern Sibbald. + The licensor of Bacula is the Free Software Foundation Europe + (FSFE), Fiduciary Program, Sumatrastrasse 25, 8006 Zürich, + Switzerland, email:ftf@fsfeurope.org. +*/ /* * * Bacula Director -- catreq.c -- handles the message channel @@ -10,25 +37,11 @@ * Basic tasks done here: * Handle Catalog services. * - * Version $Id$ - */ -/* - Copyright (C) 2001-2005 Kern Sibbald - - This program is free software; you can redistribute it and/or - modify it under the terms of the GNU General Public License - version 2 as amended with additional clauses defined in the - file LICENSE in the main source directory. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - the file LICENSE for additional details. - */ #include "bacula.h" #include "dird.h" +#include "findlib/find.h" /* * Handle catalog request @@ -40,14 +53,14 @@ static char Find_media[] = "CatReq Job=%127s FindMedia=%d pool_name=%127s media_ static char Get_Vol_Info[] = "CatReq Job=%127s GetVolInfo VolName=%127s write=%d\n"; static char Update_media[] = "CatReq Job=%127s UpdateMedia VolName=%s" - " VolJobs=%u VolFiles=%u VolBlocks=%u VolBytes=%" lld " VolMounts=%u" - " VolErrors=%u VolWrites=%u MaxVolBytes=%" lld " EndTime=%d VolStatus=%10s" - " Slot=%d relabel=%d InChanger=%d VolReadTime=%" lld " VolWriteTime=%" lld - " VolParts=%u\n"; + " VolJobs=%u VolFiles=%u VolBlocks=%u VolBytes=%lld VolMounts=%u" + " VolErrors=%u VolWrites=%u MaxVolBytes=%lld EndTime=%lld VolStatus=%10s" + " Slot=%d relabel=%d InChanger=%d VolReadTime=%lld VolWriteTime=%lld" + " VolFirstWritten=%lld VolParts=%u\n"; static char Create_job_media[] = "CatReq Job=%127s CreateJobMedia " " FirstIndex=%u LastIndex=%u StartFile=%u EndFile=%u " - " StartBlock=%u EndBlock=%u Copy=%d Strip=%d\n"; + " StartBlock=%u EndBlock=%u Copy=%d Strip=%d MediaId=%" lld "\n"; /* Responses sent to Storage daemon */ @@ -55,7 +68,8 @@ static char OK_media[] = "1000 OK VolName=%s VolJobs=%u VolFiles=%u" " VolBlocks=%u VolBytes=%s VolMounts=%u VolErrors=%u VolWrites=%u" " MaxVolBytes=%s VolCapacityBytes=%s VolStatus=%s Slot=%d" " MaxVolJobs=%u MaxVolFiles=%u InChanger=%d VolReadTime=%s" - " VolWriteTime=%s EndFile=%u EndBlock=%u VolParts=%u LabelType=%d\n"; + " VolWriteTime=%s EndFile=%u EndBlock=%u VolParts=%u LabelType=%d" + " MediaId=%s\n"; static char OK_create[] = "1000 OK CreateJobMedia\n"; @@ -63,23 +77,24 @@ static char OK_create[] = "1000 OK CreateJobMedia\n"; static int send_volume_info_to_storage_daemon(JCR *jcr, BSOCK *sd, MEDIA_DBR *mr) { int stat; - char ed1[50], ed2[50], ed3[50], ed4[50], ed5[50]; + char ed1[50], ed2[50], ed3[50], ed4[50], ed5[50], ed6[50]; jcr->MediaId = mr->MediaId; pm_strcpy(jcr->VolumeName, mr->VolumeName); bash_spaces(mr->VolumeName); - stat = bnet_fsend(sd, OK_media, mr->VolumeName, mr->VolJobs, + stat = sd->fsend(OK_media, mr->VolumeName, mr->VolJobs, mr->VolFiles, mr->VolBlocks, edit_uint64(mr->VolBytes, ed1), mr->VolMounts, mr->VolErrors, mr->VolWrites, edit_uint64(mr->MaxVolBytes, ed2), edit_uint64(mr->VolCapacityBytes, ed3), mr->VolStatus, mr->Slot, mr->MaxVolJobs, mr->MaxVolFiles, mr->InChanger, - edit_uint64(mr->VolReadTime, ed4), - edit_uint64(mr->VolWriteTime, ed5), + edit_int64(mr->VolReadTime, ed4), + edit_int64(mr->VolWriteTime, ed5), mr->EndFile, mr->EndBlock, mr->VolParts, - mr->LabelType); + mr->LabelType, + edit_uint64(mr->MediaId, ed6)); unbash_spaces(mr->VolumeName); Dmsg2(100, "Vol Info for %s: %s", jcr->Job, sd->msg); return stat; @@ -94,10 +109,14 @@ void catalog_request(JCR *jcr, BSOCK *bs) int index, ok, label, writing; POOLMEM *omsg; POOL_DBR pr; + uint32_t Stripe, Copy; + uint64_t MediaId; + utime_t VolFirstWritten; + utime_t VolLastWritten; - memset(&mr, 0, sizeof(mr)); memset(&sdmr, 0, sizeof(sdmr)); memset(&jm, 0, sizeof(jm)); + Dsm_check(100); /* * Request to find next appendable Volume for this Job @@ -106,7 +125,7 @@ void catalog_request(JCR *jcr, BSOCK *bs) if (!jcr->db) { omsg = get_memory(bs->msglen+1); pm_strcpy(omsg, bs->msg); - bnet_fsend(bs, _("1990 Invalid Catalog Request: %s"), omsg); + bs->fsend(_("1990 Invalid Catalog Request: %s"), omsg); Jmsg1(jcr, M_FATAL, 0, _("Invalid Catalog request; DB not open: %s"), omsg); free_memory(omsg); return; @@ -117,10 +136,14 @@ void catalog_request(JCR *jcr, BSOCK *bs) if (sscanf(bs->msg, Find_media, &Job, &index, &pool_name, &mr.MediaType) == 4) { memset(&pr, 0, sizeof(pr)); bstrncpy(pr.Name, pool_name, sizeof(pr.Name)); + unbash_spaces(pr.Name); ok = db_get_pool_record(jcr, jcr->db, &pr); if (ok) { mr.PoolId = pr.PoolId; - ok = find_next_volume_for_append(jcr, &mr, true /*permit create new vol*/); + set_storageid_in_mr(jcr->wstore, &mr); + mr.ScratchPoolId = pr.ScratchPoolId; + ok = find_next_volume_for_append(jcr, &mr, index, fnv_create_vol, fnv_prune); + Dmsg3(050, "find_media ok=%d idx=%d vol=%s\n", ok, index, mr.VolumeName); } /* * Send Find Media response to Storage daemon @@ -128,7 +151,7 @@ void catalog_request(JCR *jcr, BSOCK *bs) if (ok) { send_volume_info_to_storage_daemon(jcr, bs, &mr); } else { - bnet_fsend(bs, _("1901 No Media.\n")); + bs->fsend(_("1901 No Media.\n")); Dmsg0(500, "1901 No Media.\n"); } @@ -155,21 +178,11 @@ void catalog_request(JCR *jcr, BSOCK *bs) * Pool matches, and it is either Append or Recycle * and Media Type matches and Pool allows any volume. */ - if (mr.PoolId != jcr->PoolId) { + if (mr.PoolId != jcr->jr.PoolId) { reason = _("not in Pool"); - } else if (strcmp(mr.MediaType, jcr->store->media_type) != 0) { + } else if (strcmp(mr.MediaType, jcr->wstore->media_type) != 0) { reason = _("not correct MediaType"); } else { - /* - * ****FIXME*** - * This test (accept_any_volume) is turned off - * because it doesn't properly check if the volume - * really is out of sequence! - * - * } else if (!jcr->pool->accept_any_volume) { - * reason = "Volume not in sequence"; - */ - /* * Now try recycling if necessary * reason set non-NULL if we cannot use it @@ -177,6 +190,9 @@ void catalog_request(JCR *jcr, BSOCK *bs) check_if_volume_valid_or_recyclable(jcr, &mr, &reason); } } + if (!reason && mr.Enabled != 1) { + reason = _("is not Enabled"); + } if (reason == NULL) { /* * Send Find Media response to Storage daemon @@ -184,12 +200,12 @@ void catalog_request(JCR *jcr, BSOCK *bs) send_volume_info_to_storage_daemon(jcr, bs, &mr); } else { /* Not suitable volume */ - bnet_fsend(bs, _("1998 Volume \"%s\" status is %s, %s.\n"), mr.VolumeName, + bs->fsend(_("1998 Volume \"%s\" catalog status is %s, %s.\n"), mr.VolumeName, mr.VolStatus, reason); } } else { - bnet_fsend(bs, _("1997 Volume \"%s\" not in catalog.\n"), mr.VolumeName); + bs->fsend(_("1997 Volume \"%s\" not in catalog.\n"), mr.VolumeName); Dmsg1(100, "1997 Volume \"%s\" not in catalog.\n", mr.VolumeName); } @@ -201,8 +217,9 @@ void catalog_request(JCR *jcr, BSOCK *bs) } else if (sscanf(bs->msg, Update_media, &Job, &sdmr.VolumeName, &sdmr.VolJobs, &sdmr.VolFiles, &sdmr.VolBlocks, &sdmr.VolBytes, &sdmr.VolMounts, &sdmr.VolErrors, &sdmr.VolWrites, &sdmr.MaxVolBytes, - &sdmr.LastWritten, &sdmr.VolStatus, &sdmr.Slot, &label, &sdmr.InChanger, - &sdmr.VolReadTime, &sdmr.VolWriteTime, &sdmr.VolParts) == 18) { + &VolLastWritten, &sdmr.VolStatus, &sdmr.Slot, &label, &sdmr.InChanger, + &sdmr.VolReadTime, &sdmr.VolWriteTime, &VolFirstWritten, + &sdmr.VolParts) == 19) { db_lock(jcr->db); Dmsg3(400, "Update media %s oldStat=%s newStat=%s\n", sdmr.VolumeName, @@ -212,20 +229,27 @@ void catalog_request(JCR *jcr, BSOCK *bs) if (!db_get_media_record(jcr, jcr->db, &mr)) { Jmsg(jcr, M_ERROR, 0, _("Unable to get Media record for Volume %s: ERR=%s\n"), mr.VolumeName, db_strerror(jcr->db)); - bnet_fsend(bs, _("1991 Catalog Request for vol=%s failed: %s"), + bs->fsend(_("1991 Catalog Request for vol=%s failed: %s"), mr.VolumeName, db_strerror(jcr->db)); db_unlock(jcr->db); return; } /* Set first written time if this is first job */ if (mr.FirstWritten == 0) { - mr.FirstWritten = jcr->start_time; /* use Job start time as first write */ + if (VolFirstWritten == 0) { + mr.FirstWritten = jcr->start_time; /* use Job start time as first write */ + } else { + mr.FirstWritten = VolFirstWritten; + } mr.set_first_written = true; } /* If we just labeled the tape set time */ if (label || mr.LabelDate == 0) { mr.LabelDate = jcr->start_time; mr.set_label_date = true; + if (mr.InitialWrite == 0) { + mr.InitialWrite = jcr->start_time; + } Dmsg2(400, "label=%d labeldate=%d\n", label, mr.LabelDate); } else { /* @@ -235,12 +259,37 @@ void catalog_request(JCR *jcr, BSOCK *bs) Jmsg(jcr, M_FATAL, 0, _("Volume Files at %u being set to %u" " for Volume \"%s\". This is incorrect.\n"), mr.VolFiles, sdmr.VolFiles, mr.VolumeName); - bnet_fsend(bs, _("1992 Update Media error\n")); + bs->fsend(_("1992 Update Media error. VolFiles=%u, CatFiles=%u\n"), + sdmr.VolFiles, mr.VolFiles); db_unlock(jcr->db); return; } } Dmsg2(400, "Update media: BefVolJobs=%u After=%u\n", mr.VolJobs, sdmr.VolJobs); + + /* + * Check if the volume has been written by the job, + * and update the LastWritten field if needed. + */ + if (mr.VolBlocks != sdmr.VolBlocks && VolLastWritten != 0) { + mr.LastWritten = VolLastWritten; + } + + /* + * Update to point to the last device used to write the Volume. + * However, do so only if we are writing the tape, i.e. + * the number of VolWrites has increased. + */ + if (jcr->wstore && sdmr.VolWrites > mr.VolWrites) { + Dmsg2(050, "Update StorageId old=%d new=%d\n", + mr.StorageId, jcr->wstore->StorageId); + /* Update StorageId after write */ + set_storageid_in_mr(jcr->wstore, &mr); + } else { + /* Nothing written, reset same StorageId */ + set_storageid_in_mr(NULL, &mr); + } + /* Copy updated values to original media record */ mr.VolJobs = sdmr.VolJobs; mr.VolFiles = sdmr.VolFiles; @@ -249,26 +298,30 @@ void catalog_request(JCR *jcr, BSOCK *bs) mr.VolMounts = sdmr.VolMounts; mr.VolErrors = sdmr.VolErrors; mr.VolWrites = sdmr.VolWrites; - mr.LastWritten = sdmr.LastWritten; mr.Slot = sdmr.Slot; mr.InChanger = sdmr.InChanger; - mr.VolReadTime = sdmr.VolReadTime; - mr.VolWriteTime = sdmr.VolWriteTime; mr.VolParts = sdmr.VolParts; bstrncpy(mr.VolStatus, sdmr.VolStatus, sizeof(mr.VolStatus)); + if (sdmr.VolReadTime >= 0) { + mr.VolReadTime = sdmr.VolReadTime; + } + if (sdmr.VolWriteTime >= 0) { + mr.VolWriteTime = sdmr.VolWriteTime; + } Dmsg2(400, "db_update_media_record. Stat=%s Vol=%s\n", mr.VolStatus, mr.VolumeName); /* - * Check if it has expired, and if not update the DB. Note, if - * Volume has expired, has_volume_expired() will update the DB. + * Update the database, then before sending the response to the + * SD, check if the Volume has expired. */ - if (has_volume_expired(jcr, &mr) || db_update_media_record(jcr, jcr->db, &mr)) { - send_volume_info_to_storage_daemon(jcr, bs, &mr); - } else { + if (!db_update_media_record(jcr, jcr->db, &mr)) { Jmsg(jcr, M_FATAL, 0, _("Catalog error updating Media record. %s"), db_strerror(jcr->db)); - bnet_fsend(bs, _("1992 Update Media error\n")); + bs->fsend(_("1993 Update Media error\n")); Dmsg0(400, "send error\n"); + } else { + (void)has_volume_expired(jcr, &mr); + send_volume_info_to_storage_daemon(jcr, bs, &mr); } db_unlock(jcr->db); @@ -277,162 +330,375 @@ void catalog_request(JCR *jcr, BSOCK *bs) */ } else if (sscanf(bs->msg, Create_job_media, &Job, &jm.FirstIndex, &jm.LastIndex, &jm.StartFile, &jm.EndFile, - &jm.StartBlock, &jm.EndBlock, &jm.Copy, &jm.Stripe) == 9) { + &jm.StartBlock, &jm.EndBlock, &Copy, &Stripe, &MediaId) == 10) { - jm.JobId = jcr->JobId; - jm.MediaId = jcr->MediaId; + if (jcr->mig_jcr) { + jm.JobId = jcr->mig_jcr->JobId; + } else { + jm.JobId = jcr->JobId; + } + jm.MediaId = MediaId; Dmsg6(400, "create_jobmedia JobId=%d MediaId=%d SF=%d EF=%d FI=%d LI=%d\n", jm.JobId, jm.MediaId, jm.StartFile, jm.EndFile, jm.FirstIndex, jm.LastIndex); if (!db_create_jobmedia_record(jcr, jcr->db, &jm)) { Jmsg(jcr, M_FATAL, 0, _("Catalog error creating JobMedia record. %s"), db_strerror(jcr->db)); - bnet_fsend(bs, _("1991 Update JobMedia error\n")); + bs->fsend(_("1992 Create JobMedia error\n")); } else { Dmsg0(400, "JobMedia record created\n"); - bnet_fsend(bs, OK_create); + bs->fsend(OK_create); } } else { omsg = get_memory(bs->msglen+1); pm_strcpy(omsg, bs->msg); - bnet_fsend(bs, _("1990 Invalid Catalog Request: %s"), omsg); + bs->fsend(_("1990 Invalid Catalog Request: %s"), omsg); Jmsg1(jcr, M_FATAL, 0, _("Invalid Catalog request: %s"), omsg); free_memory(omsg); } + Dmsg1(400, ">CatReq response: %s", bs->msg); Dmsg1(400, "Leave catreq jcr 0x%x\n", jcr); return; } /* - * Update File Attributes in the catalog with data - * sent by the Storage daemon. Note, we receive the whole - * attribute record, but we select out only the stat packet, - * VolSessionId, VolSessionTime, FileIndex, and file name - * to store in the catalog. + * Note, we receive the whole attribute record, but we select out only the stat + * packet, VolSessionId, VolSessionTime, FileIndex, file type, and file name to + * store in the catalog. */ -void catalog_update(JCR *jcr, BSOCK *bs) +static void update_attribute(JCR *jcr, char *msg, int32_t msglen) { unser_declare; uint32_t VolSessionId, VolSessionTime; int32_t Stream; uint32_t FileIndex; - uint32_t data_len; char *p; int len; char *fname, *attr; ATTR_DBR *ar = NULL; - POOLMEM *omsg; - - if (!jcr->pool->catalog_files) { - return; /* user disabled cataloging */ - } - if (!jcr->db) { - omsg = get_memory(bs->msglen+1); - pm_strcpy(omsg, bs->msg); - bnet_fsend(bs, _("1991 Invalid Catalog Update: %s"), omsg); - Jmsg1(jcr, M_FATAL, 0, _("Invalid Catalog Update; DB not open: %s"), omsg); - free_memory(omsg); - return; - } + uint32_t reclen; /* Start transaction allocates jcr->attr and jcr->ar if needed */ db_start_transaction(jcr, jcr->db); /* start transaction if not already open */ ar = jcr->ar; - /* Start by scanning directly in the message buffer to get Stream + /* + * Start by scanning directly in the message buffer to get Stream * there may be a cached attr so we cannot yet write into * jcr->attr or jcr->ar */ - p = bs->msg; + p = msg; skip_nonspaces(&p); /* UpdCat */ skip_spaces(&p); skip_nonspaces(&p); /* Job=nnn */ skip_spaces(&p); - skip_nonspaces(&p); /* FileAttributes */ + skip_nonspaces(&p); /* "FileAttributes" */ p += 1; + /* The following "SD header" fields are serialized */ unser_begin(p, 0); - unser_uint32(VolSessionId); - unser_uint32(VolSessionTime); - unser_int32(FileIndex); - unser_int32(Stream); - unser_uint32(data_len); - p += unser_length(p); + unser_uint32(VolSessionId); /* VolSessionId */ + unser_uint32(VolSessionTime); /* VolSessionTime */ + unser_int32(FileIndex); /* FileIndex */ + unser_int32(Stream); /* Stream */ + unser_uint32(reclen); /* Record length */ + p += unser_length(p); /* Raw record follows */ + + /** + * At this point p points to the raw record, which varies according + * to what kind of a record (Stream) was sent. Note, the integer + * fields at the beginning of these "raw" records are in ASCII with + * spaces between them so one can use scanf or manual scanning to + * extract the fields. + * + * File Attributes + * File_index + * File type + * Filename (full path) + * Encoded attributes + * Link name (if type==FT_LNK or FT_LNKSAVED) + * Encoded extended-attributes (for Win32) + * Delta sequence number (32 bit int) + * + * Restore Object + * File_index + * File_type + * Object_index + * Object_len (possibly compressed) + * Object_full_len (not compressed) + * Object_compression + * Plugin_name + * Object_name + * Binary Object data + */ - Dmsg1(400, "UpdCat msg=%s\n", bs->msg); - Dmsg5(400, "UpdCat VolSessId=%d VolSessT=%d FI=%d Strm=%d data_len=%d\n", - VolSessionId, VolSessionTime, FileIndex, Stream, data_len); + Dmsg1(400, "UpdCat msg=%s\n", msg); + Dmsg5(400, "UpdCat VolSessId=%d VolSessT=%d FI=%d Strm=%d reclen=%d\n", + VolSessionId, VolSessionTime, FileIndex, Stream, reclen); if (Stream == STREAM_UNIX_ATTRIBUTES || Stream == STREAM_UNIX_ATTRIBUTES_EX) { if (jcr->cached_attribute) { Dmsg2(400, "Cached attr. Stream=%d fname=%s\n", ar->Stream, ar->fname); - if (!db_create_file_attributes_record(jcr, jcr->db, ar)) { - Jmsg1(jcr, M_FATAL, 0, _("Attribute create error. %s"), db_strerror(jcr->db)); + if (!db_create_attributes_record(jcr, jcr->db, ar)) { + Jmsg1(jcr, M_FATAL, 0, _("Attribute create error: ERR=%s"), db_strerror(jcr->db)); } + jcr->cached_attribute = false; } /* Any cached attr is flushed so we can reuse jcr->attr and jcr->ar */ - jcr->attr = check_pool_memory_size(jcr->attr, bs->msglen); - memcpy(jcr->attr, bs->msg, bs->msglen); - p = jcr->attr - bs->msg + p; /* point p into jcr->attr */ - skip_nonspaces(&p); /* skip FileIndex */ + jcr->attr = check_pool_memory_size(jcr->attr, msglen); + memcpy(jcr->attr, msg, msglen); + p = jcr->attr - msg + p; /* point p into jcr->attr */ + skip_nonspaces(&p); /* skip FileIndex */ skip_spaces(&p); - skip_nonspaces(&p); /* skip FileType */ + ar->FileType = str_to_int32(p); + skip_nonspaces(&p); /* skip FileType */ skip_spaces(&p); fname = p; len = strlen(fname); /* length before attributes */ attr = &fname[len+1]; + ar->DeltaSeq = 0; + if (ar->FileType == FT_REG) { + p = attr + strlen(attr) + 1; /* point to link */ + p = p + strlen(p) + 1; /* point to extended attributes */ + p = p + strlen(p) + 1; /* point to delta sequence */ + /* + * Older FDs don't have a delta sequence, so check if it is there + */ + if (p - jcr->attr < msglen) { + ar->DeltaSeq = str_to_int32(p); /* delta_seq */ + } + } Dmsg2(400, "dirdattr = attr; ar->fname = fname; - ar->FileIndex = FileIndex; + if (ar->FileType == FT_DELETED) { + ar->FileIndex = 0; /* special value */ + } else { + ar->FileIndex = FileIndex; + } ar->Stream = Stream; ar->link = NULL; - ar->JobId = jcr->JobId; - ar->Sig = NULL; - ar->SigType = 0; + if (jcr->mig_jcr) { + ar->JobId = jcr->mig_jcr->JobId; + } else { + ar->JobId = jcr->JobId; + } + ar->Digest = NULL; + ar->DigestType = CRYPTO_DIGEST_NONE; jcr->cached_attribute = true; Dmsg2(400, "dirddb, ar)) { - Jmsg1(jcr, M_FATAL, 0, _("Attribute create error. %s"), db_strerror(jcr->db)); + } else if (Stream == STREAM_RESTORE_OBJECT) { + ROBJECT_DBR ro; + + memset(&ro, 0, sizeof(ro)); + ro.Stream = Stream; + ro.FileIndex = FileIndex; + if (jcr->mig_jcr) { + ro.JobId = jcr->mig_jcr->JobId; + } else { + ro.JobId = jcr->JobId; } -#endif - } else if (Stream == STREAM_MD5_SIGNATURE || Stream == STREAM_SHA1_SIGNATURE) { + + Dmsg1(100, "Robj=%s\n", p); + + skip_nonspaces(&p); /* skip FileIndex */ + skip_spaces(&p); + ro.FileType = str_to_int32(p); /* FileType */ + skip_nonspaces(&p); + skip_spaces(&p); + ro.object_index = str_to_int32(p); /* Object Index */ + skip_nonspaces(&p); + skip_spaces(&p); + ro.object_len = str_to_int32(p); /* object length possibly compressed */ + skip_nonspaces(&p); + skip_spaces(&p); + ro.object_full_len = str_to_int32(p); /* uncompressed object length */ + skip_nonspaces(&p); + skip_spaces(&p); + ro.object_compression = str_to_int32(p); /* compression */ + skip_nonspaces(&p); + skip_spaces(&p); + + ro.plugin_name = p; /* point to plugin name */ + len = strlen(ro.plugin_name); + ro.object_name = &ro.plugin_name[len+1]; /* point to object name */ + len = strlen(ro.object_name); + ro.object = &ro.object_name[len+1]; /* point to object */ + ro.object[ro.object_len] = 0; /* add zero for those who attempt printing */ + Dmsg7(100, "oname=%s stream=%d FT=%d FI=%d JobId=%d, obj_len=%d\nobj=\"%s\"\n", + ro.object_name, ro.Stream, ro.FileType, ro.FileIndex, ro.JobId, + ro.object_len, ro.object); + /* Send it */ + if (!db_create_restore_object_record(jcr, jcr->db, &ro)) { + Jmsg1(jcr, M_FATAL, 0, _("Restore object create error. %s"), db_strerror(jcr->db)); + } + + } else if (crypto_digest_stream_type(Stream) != CRYPTO_DIGEST_NONE) { fname = p; if (ar->FileIndex != FileIndex) { - Jmsg(jcr, M_WARNING, 0, _("Got MD5/SHA1 but not same File as attributes\n")); + Jmsg3(jcr, M_WARNING, 0, _("%s not same File=%d as attributes=%d\n"), + stream_to_ascii(Stream), FileIndex, ar->FileIndex); } else { - /* Update signature in catalog */ - char SIGbuf[50]; /* 24 bytes should be enough */ - int len, type; - if (Stream == STREAM_MD5_SIGNATURE) { - len = 16; - type = MD5_SIG; - } else { - len = 20; - type = SHA1_SIG; + /* Update digest in catalog */ + char digestbuf[BASE64_SIZE(CRYPTO_DIGEST_MAX_SIZE)]; + int len = 0; + int type = CRYPTO_DIGEST_NONE; + + switch(Stream) { + case STREAM_MD5_DIGEST: + len = CRYPTO_DIGEST_MD5_SIZE; + type = CRYPTO_DIGEST_MD5; + break; + case STREAM_SHA1_DIGEST: + len = CRYPTO_DIGEST_SHA1_SIZE; + type = CRYPTO_DIGEST_SHA1; + break; + case STREAM_SHA256_DIGEST: + len = CRYPTO_DIGEST_SHA256_SIZE; + type = CRYPTO_DIGEST_SHA256; + break; + case STREAM_SHA512_DIGEST: + len = CRYPTO_DIGEST_SHA512_SIZE; + type = CRYPTO_DIGEST_SHA512; + break; + default: + /* Never reached ... */ + Jmsg(jcr, M_ERROR, 0, _("Catalog error updating file digest. Unsupported digest stream type: %d"), + Stream); } - bin_to_base64(SIGbuf, fname, len); - Dmsg3(400, "SIGlen=%d SIG=%s type=%d\n", strlen(SIGbuf), SIGbuf, Stream); + + bin_to_base64(digestbuf, sizeof(digestbuf), fname, len, true); + Dmsg3(400, "DigestLen=%d Digest=%s type=%d\n", strlen(digestbuf), + digestbuf, Stream); if (jcr->cached_attribute) { - ar->Sig = SIGbuf; - ar->SigType = type; - Dmsg2(400, "Cached attr with SIG. Stream=%d fname=%s\n", ar->Stream, ar->fname); - if (!db_create_file_attributes_record(jcr, jcr->db, ar)) { - Jmsg1(jcr, M_FATAL, 0, _("Attribute create error. %s"), db_strerror(jcr->db)); + ar->Digest = digestbuf; + ar->DigestType = type; + Dmsg2(400, "Cached attr with digest. Stream=%d fname=%s\n", + ar->Stream, ar->fname); + + /* Update BaseFile table */ + if (!db_create_attributes_record(jcr, jcr->db, ar)) { + Jmsg1(jcr, M_FATAL, 0, _("attribute create error. %s"), + db_strerror(jcr->db)); } jcr->cached_attribute = false; } else { - if (!db_add_SIG_to_file_record(jcr, jcr->db, ar->FileId, SIGbuf, type)) { - Jmsg(jcr, M_ERROR, 0, _("Catalog error updating MD5/SHA1. %s"), + if (!db_add_digest_to_file_record(jcr, jcr->db, ar->FileId, digestbuf, type)) { + Jmsg(jcr, M_ERROR, 0, _("Catalog error updating file digest. %s"), db_strerror(jcr->db)); } } } } } + +/* + * Update File Attributes in the catalog with data + * sent by the Storage daemon. + */ +void catalog_update(JCR *jcr, BSOCK *bs) +{ + if (!jcr->pool->catalog_files) { + return; /* user disabled cataloging */ + } + if (jcr->is_job_canceled()) { + goto bail_out; + } + if (!jcr->db) { + POOLMEM *omsg = get_memory(bs->msglen+1); + pm_strcpy(omsg, bs->msg); + bs->fsend(_("1994 Invalid Catalog Update: %s"), omsg); + Jmsg1(jcr, M_FATAL, 0, _("Invalid Catalog Update; DB not open: %s"), omsg); + free_memory(omsg); + goto bail_out; + } + update_attribute(jcr, bs->msg, bs->msglen); + +bail_out: + if (jcr->is_job_canceled()) { + cancel_storage_daemon_job(jcr); + } +} + +/* + * Update File Attributes in the catalog with data read from + * the storage daemon spool file. We receive the filename and + * we try to read it. + */ +bool despool_attributes_from_file(JCR *jcr, const char *file) +{ + bool ret=false; + int32_t pktsiz; + size_t nbytes; + ssize_t size = 0; + int32_t msglen; /* message length */ + POOLMEM *msg = get_pool_memory(PM_MESSAGE); + FILE *spool_fd=NULL; + + Dmsg0(100, "Begin despool_attributes_from_file\n"); + + if (jcr->is_job_canceled() || !jcr->pool->catalog_files || !jcr->db) { + goto bail_out; /* user disabled cataloging */ + } + + spool_fd = fopen(file, "rb"); + if (!spool_fd) { + Dmsg0(100, "cancel despool_attributes_from_file\n"); + /* send an error message */ + goto bail_out; + } +#if defined(HAVE_POSIX_FADVISE) && defined(POSIX_FADV_WILLNEED) + posix_fadvise(fileno(spool_fd), 0, 0, POSIX_FADV_WILLNEED); +#endif + + while (fread((char *)&pktsiz, 1, sizeof(int32_t), spool_fd) == + sizeof(int32_t)) { + size += sizeof(int32_t); + msglen = ntohl(pktsiz); + if (msglen > 0) { + if (msglen > (int32_t) sizeof_pool_memory(msg)) { + msg = realloc_pool_memory(msg, msglen + 1); + } + nbytes = fread(msg, 1, msglen, spool_fd); + if (nbytes != (size_t) msglen) { + berrno be; + Dmsg2(400, "nbytes=%d msglen=%d\n", nbytes, msglen); + Qmsg1(jcr, M_FATAL, 0, _("fread attr spool error. ERR=%s\n"), + be.bstrerror()); + goto bail_out; + } + size += nbytes; + } + if (!jcr->is_job_canceled()) { + update_attribute(jcr, msg, msglen); + if (jcr->is_job_canceled()) { + goto bail_out; + } + } + } + if (ferror(spool_fd)) { + berrno be; + Qmsg1(jcr, M_FATAL, 0, _("fread attr spool error. ERR=%s\n"), + be.bstrerror()); + goto bail_out; + } + ret = true; + +bail_out: + if (spool_fd) { + fclose(spool_fd); + } + + if (jcr->is_job_canceled()) { + cancel_storage_daemon_job(jcr); + } + + free_pool_memory(msg); + Dmsg1(100, "End despool_attributes_from_file ret=%i\n", ret); + return ret; +}