Exemple #1
0
/*
 * The following entry points are accessed through the function pointers we supplied to Bareos.
 * Each plugin type (dir, fd, sd) has its own set of entry points that the plugin must define.
 *
 * Create a new instance of the plugin i.e. allocate our private storage
 */
static bRC newPlugin(bpContext *ctx)
{
   plugin_ctx *p_ctx;

   p_ctx = (plugin_ctx *)malloc(sizeof(plugin_ctx));
   if (!p_ctx) {
      return bRC_Error;
   }
   memset(p_ctx, 0, sizeof(plugin_ctx));
   ctx->pContext = (void *)p_ctx;        /* set our context pointer */

   /*
    * Allocate some internal memory for:
    * - The current working dir.
    * - The file we are processing
    * - The link target of a symbolic link.
    * - The list of xattrs.
    */
   p_ctx->cwd = get_pool_memory(PM_FNAME);
   p_ctx->next_filename = get_pool_memory(PM_FNAME);
   p_ctx->link_target = get_pool_memory(PM_FNAME);
   p_ctx->xattr_list = get_pool_memory(PM_MESSAGE);

   /*
    * Resize all buffers for PATH like names to CEPHFS_PATH_MAX.
    */
   p_ctx->cwd = check_pool_memory_size(p_ctx->cwd, CEPHFS_PATH_MAX);
   p_ctx->next_filename = check_pool_memory_size(p_ctx->next_filename, CEPHFS_PATH_MAX);
   p_ctx->link_target = check_pool_memory_size(p_ctx->link_target, CEPHFS_PATH_MAX);

   /*
    * This is a alist that holds the stack of directories we have open.
    * We push the current directory onto this stack the moment we start
    * processing a sub directory and pop it from this list when we are
    * done processing that sub directory.
    */
   p_ctx->dir_stack = new alist(10, owned_by_alist);

   /*
    * Only register the events we are really interested in.
    */
   bfuncs->registerBareosEvents(ctx,
                                7,
                                bEventLevel,
                                bEventSince,
                                bEventRestoreCommand,
                                bEventBackupCommand,
                                bEventPluginCommand,
                                bEventEndRestoreJob,
                                bEventNewPluginOptions);

   return bRC_OK;
}
Exemple #2
0
/*
 * Given a full filename, split it into its path
 *  and filename parts. They are returned in pool memory
 *  in the mdb structure.
 */
void split_path_and_file(JCR *jcr, B_DB *mdb, const char *fname)
{
   const char *p, *f;

   /* Find path without the filename.
    * I.e. everything after the last / is a "filename".
    * OK, maybe it is a directory name, but we treat it like
    * a filename. If we don't find a / then the whole name
    * must be a path name (e.g. c:).
    */
   for (p=f=fname; *p; p++) {
      if (IsPathSeparator(*p)) {
         f = p;                       /* set pos of last slash */
      }
   }
   if (IsPathSeparator(*f)) {         /* did we find a slash? */
      f++;                            /* yes, point to filename */
   } else {
      f = p;                          /* no, whole thing must be path name */
   }

   /* If filename doesn't exist (i.e. root directory), we
    * simply create a blank name consisting of a single
    * space. This makes handling zero length filenames
    * easier.
    */
   mdb->fnl = p - f;
   if (mdb->fnl > 0) {
      mdb->fname = check_pool_memory_size(mdb->fname, mdb->fnl+1);
      memcpy(mdb->fname, f, mdb->fnl);    /* copy filename */
      mdb->fname[mdb->fnl] = 0;
   } else {
      mdb->fname[0] = 0;
      mdb->fnl = 0;
   }

   mdb->pnl = f - fname;
   if (mdb->pnl > 0) {
      mdb->path = check_pool_memory_size(mdb->path, mdb->pnl+1);
      memcpy(mdb->path, fname, mdb->pnl);
      mdb->path[mdb->pnl] = 0;
   } else {
      Mmsg1(&mdb->errmsg, _("Path length is zero. File=%s\n"), fname);
      Jmsg(jcr, M_ERROR, 0, "%s", mdb->errmsg);
      mdb->path[0] = 0;
      mdb->pnl = 0;
   }

   Dmsg2(500, "split path=%s file=%s\n", mdb->path, mdb->fname);
}
Exemple #3
0
void do_messages(UAContext *ua, const char *cmd)
{
   char msg[2000];
   int mlen;
   bool do_truncate = false;

   Pw(con_lock);
   pthread_cleanup_push(con_lock_release, (void *)NULL);
   rewind(con_fd);
   while (fgets(msg, sizeof(msg), con_fd)) {
      mlen = strlen(msg);
      ua->UA_sock->msg = check_pool_memory_size(ua->UA_sock->msg, mlen+1);
      strcpy(ua->UA_sock->msg, msg);
      ua->UA_sock->msglen = mlen;
      ua->UA_sock->send();
      do_truncate = true;
   }
   if (do_truncate) {
      (void)ftruncate(fileno(con_fd), 0L);
   }
   console_msg_pending = FALSE;
   ua->user_notified_msg_pending = FALSE;
   pthread_cleanup_pop(0);
   Vw(con_lock);
}
Exemple #4
0
/* Match a regexp and add the result to the items list
 * This function is recursive
 */
static void match_kw(regex_t *preg, const char *what, int len, POOLMEM **buf)
{
   int rc, size;
   int nmatch=20;
   regmatch_t pmatch[20];

   if (len <= 0) {
      return;
   }
   rc = regexec(preg, what, nmatch, pmatch, 0);
   if (rc == 0) {
#if 0
      Pmsg1(0, "\n\n%s\n0123456789012345678901234567890123456789\n        10         20         30\n", what);
      Pmsg2(0, "%i-%i\n", pmatch[0].rm_so, pmatch[0].rm_eo);
      Pmsg2(0, "%i-%i\n", pmatch[1].rm_so, pmatch[1].rm_eo);
      Pmsg2(0, "%i-%i\n", pmatch[2].rm_so, pmatch[2].rm_eo);
      Pmsg2(0, "%i-%i\n", pmatch[3].rm_so, pmatch[3].rm_eo);
#endif
      size = pmatch[1].rm_eo - pmatch[1].rm_so;
      *buf = check_pool_memory_size(*buf, size + 1);
      memcpy(*buf, what+pmatch[1].rm_so, size);
      (*buf)[size] = 0;

      items->list.append(bstrdup(*buf));
      /* We search for the next keyword in the line */
      match_kw(preg, what + pmatch[1].rm_eo, len - pmatch[1].rm_eo, buf);
   }
}
Exemple #5
0
/**
 * Update File Attribute data
 * We do the following:
 *  1. expand the bsock buffer to be large enough
 *  2. Write a "header" into the buffer with serialized data
 *    VolSessionId
 *    VolSeesionTime
 *    FileIndex
 *    Stream
 *    data length that follows
 *    start of raw byte data from the Device record.
 * Note, this is primarily for Attribute data, but can
 *   also handle any device record. The Director must know
 *   the raw byte data format that is defined for each Stream.
 * Now Restore Objects pass through here STREAM_RESTORE_OBJECT
 */
bool dir_update_file_attributes(DCR *dcr, DEV_RECORD *rec)
{
   JCR *jcr = dcr->jcr;
   BSOCK *dir = jcr->dir_bsock;
   ser_declare;

#ifdef NO_ATTRIBUTES_TEST
   return true;
#endif

   dir->msg = check_pool_memory_size(dir->msg, sizeof(FileAttributes) +
                MAX_NAME_LENGTH + sizeof(DEV_RECORD) + rec->data_len + 1);
   dir->msglen = bsnprintf(dir->msg, sizeof(FileAttributes) +
                MAX_NAME_LENGTH + 1, FileAttributes, jcr->Job);
   ser_begin(dir->msg + dir->msglen, 0);
   ser_uint32(rec->VolSessionId);
   ser_uint32(rec->VolSessionTime);
   ser_int32(rec->FileIndex);
   ser_int32(rec->Stream);
   ser_uint32(rec->data_len);
   ser_bytes(rec->data, rec->data_len);
   dir->msglen = ser_length(dir->msg);
   Dmsg1(1800, ">dird %s\n", dir->msg);    /* Attributes */
   return dir->send();
}
Exemple #6
0
int pm_strcpy(POOLMEM *&pm, POOL_MEM &str)
{
   int len = strlen(str.c_str()) + 1;

   pm = check_pool_memory_size(pm, len);
   memcpy(pm, str.c_str(), len);
   return len - 1;
}
Exemple #7
0
static void split_path_and_filename(UAContext *ua, RESTORE_CTX *rx, char *name)
{
   char *p, *f;

   /* Find path without the filename.
    * I.e. everything after the last / is a "filename".
    * OK, maybe it is a directory name, but we treat it like
    * a filename. If we don't find a / then the whole name
    * must be a path name (e.g. c:).
    */
   for (p=f=name; *p; p++) {
      if (IsPathSeparator(*p)) {
         f = p;                       /* set pos of last slash */
      }
   }
   if (IsPathSeparator(*f)) {         /* did we find a slash? */
      f++;                            /* yes, point to filename */
   } else {                           /* no, whole thing must be path name */
      f = p;
   }

   /* If filename doesn't exist (i.e. root directory), we
    * simply create a blank name consisting of a single
    * space. This makes handling zero length filenames
    * easier.
    */
   rx->fnl = p - f;
   if (rx->fnl > 0) {
      rx->fname = check_pool_memory_size(rx->fname, 2*(rx->fnl)+1);
      db_escape_string(ua->jcr, ua->db, rx->fname, f, rx->fnl);
   } else {
      rx->fname[0] = 0;
      rx->fnl = 0;
   }

   rx->pnl = f - name;
   if (rx->pnl > 0) {
      rx->path = check_pool_memory_size(rx->path, 2*(rx->pnl)+1);
      db_escape_string(ua->jcr, ua->db, rx->path, name, rx->pnl);
   } else {
      rx->path[0] = 0;
      rx->pnl = 0;
   }

   Dmsg2(100, "split path=%s file=%s\n", rx->path, rx->fname);
}
Exemple #8
0
int pm_strcat(POOLMEM *&pm, POOL_MEM &str)
{
   int pmlen = strlen(pm);
   int len = strlen(str.c_str()) + 1;

   pm = check_pool_memory_size(pm, pmlen + len);
   memcpy(pm+pmlen, str.c_str(), len);
   return pmlen + len - 1;
}
Exemple #9
0
/*
 *  create_volume_label_record
 *   Serialize label (from dev->VolHdr structure) into device record.
 *   Assumes that the dev->VolHdr structure is properly
 *   initialized.
*/
static void create_volume_label_record(DCR *dcr, DEVICE *dev, DEV_RECORD *rec)
{
   ser_declare;
   struct date_time dt;
   JCR *jcr = dcr->jcr;
   char buf[100];

   /* Serialize the label into the device record. */

   rec->data = check_pool_memory_size(rec->data, SER_LENGTH_Volume_Label);
   ser_begin(rec->data, SER_LENGTH_Volume_Label);
   ser_string(dev->VolHdr.Id);

   ser_uint32(dev->VolHdr.VerNum);

   if (dev->VolHdr.VerNum >= 11) {
      ser_btime(dev->VolHdr.label_btime);
      dev->VolHdr.write_btime = get_current_btime();
      ser_btime(dev->VolHdr.write_btime);
      dev->VolHdr.write_date = 0;
      dev->VolHdr.write_time = 0;
   } else {
      /* OLD WAY DEPRECATED */
      ser_float64(dev->VolHdr.label_date);
      ser_float64(dev->VolHdr.label_time);
      get_current_time(&dt);
      dev->VolHdr.write_date = dt.julian_day_number;
      dev->VolHdr.write_time = dt.julian_day_fraction;
   }
   ser_float64(dev->VolHdr.write_date);   /* 0 if VerNum >= 11 */
   ser_float64(dev->VolHdr.write_time);   /* 0  if VerNum >= 11 */

   ser_string(dev->VolHdr.VolumeName);
   ser_string(dev->VolHdr.PrevVolumeName);
   ser_string(dev->VolHdr.PoolName);
   ser_string(dev->VolHdr.PoolType);
   ser_string(dev->VolHdr.MediaType);

   ser_string(dev->VolHdr.HostName);
   ser_string(dev->VolHdr.LabelProg);
   ser_string(dev->VolHdr.ProgVersion);
   ser_string(dev->VolHdr.ProgDate);

   ser_end(rec->data, SER_LENGTH_Volume_Label);
   bstrncpy(dcr->VolumeName, dev->VolHdr.VolumeName, sizeof(dcr->VolumeName));
   rec->data_len = ser_length(rec->data);
   rec->FileIndex = dev->VolHdr.LabelType;
   rec->VolSessionId = jcr->VolSessionId;
   rec->VolSessionTime = jcr->VolSessionTime;
   rec->Stream = jcr->NumWriteVolumes;
   rec->maskedStream = jcr->NumWriteVolumes;
   Dmsg2(150, "Created Vol label rec: FI=%s len=%d\n",
         FI_to_ascii(buf, rec->FileIndex), rec->data_len);
}
Exemple #10
0
int pm_strcpy(POOLMEM *&pm, const char *str)
{
   int len;

   if (!str) str = "";

   len = strlen(str) + 1;
   pm = check_pool_memory_size(pm, len);
   memcpy(pm, str, len);
   return len - 1;
}
Exemple #11
0
/*
 * Create session label
 *  The pool memory must be released by the calling program
 */
void create_session_label(DCR *dcr, DEV_RECORD *rec, int label)
{
   JCR *jcr = dcr->jcr;
   ser_declare;

   rec->VolSessionId   = jcr->VolSessionId;
   rec->VolSessionTime = jcr->VolSessionTime;
   rec->Stream         = jcr->JobId;
   rec->maskedStream   = jcr->JobId;

   rec->data = check_pool_memory_size(rec->data, SER_LENGTH_Session_Label);
   ser_begin(rec->data, SER_LENGTH_Session_Label);
   if (me->compatible) {
      ser_string(OldBaculaId);
      ser_uint32(OldCompatibleBareosTapeVersion1);
   } else {
      ser_string(BareosId);
      ser_uint32(BareosTapeVersion);
   }

   ser_uint32(jcr->JobId);

   /* Changed in VerNum 11 */
   ser_btime(get_current_btime());
   ser_float64(0);

   ser_string(dcr->pool_name);
   ser_string(dcr->pool_type);
   ser_string(jcr->job_name);         /* base Job name */
   ser_string(jcr->client_name);

   /* Added in VerNum 10 */
   ser_string(jcr->Job);              /* Unique name of this Job */
   ser_string(jcr->fileset_name);
   ser_uint32(jcr->getJobType());
   ser_uint32(jcr->getJobLevel());
   /* Added in VerNum 11 */
   ser_string(jcr->fileset_md5);

   if (label == EOS_LABEL) {
      ser_uint32(jcr->JobFiles);
      ser_uint64(jcr->JobBytes);
      ser_uint32(dcr->StartBlock);
      ser_uint32(dcr->EndBlock);
      ser_uint32(dcr->StartFile);
      ser_uint32(dcr->EndFile);
      ser_uint32(jcr->JobErrors);

      /* Added in VerNum 11 */
      ser_uint32(jcr->JobStatus);
   }
   ser_end(rec->data, SER_LENGTH_Session_Label);
   rec->data_len = ser_length(rec->data);
}
Exemple #12
0
int pm_strcat(POOLMEM *&pm, const char *str)
{
   int pmlen = strlen(pm);
   int len;

   if (!str) str = "";

   len = strlen(str) + 1;
   pm = check_pool_memory_size(pm, pmlen + len);
   memcpy(pm+pmlen, str, len);
   return pmlen + len - 1;
}
Exemple #13
0
/*  unser_volume_label
 *
 * Unserialize the Bareos Volume label into the device Volume_Label
 * structure.
 *
 * Assumes that the record is already read.
 *
 * Returns: false on error
 *          true  on success
*/
bool unser_volume_label(DEVICE *dev, DEV_RECORD *rec)
{
   ser_declare;
   char buf1[100], buf2[100];

   if (rec->FileIndex != VOL_LABEL && rec->FileIndex != PRE_LABEL) {
      Mmsg3(dev->errmsg, _("Expecting Volume Label, got FI=%s Stream=%s len=%d\n"),
              FI_to_ascii(buf1, rec->FileIndex),
              stream_to_ascii(buf2, rec->Stream, rec->FileIndex),
              rec->data_len);
      if (!forge_on) {
         return false;
      }
   }

   dev->VolHdr.LabelType = rec->FileIndex;
   dev->VolHdr.LabelSize = rec->data_len;


   /* Unserialize the record into the Volume Header */
   rec->data = check_pool_memory_size(rec->data, SER_LENGTH_Volume_Label);
   ser_begin(rec->data, SER_LENGTH_Volume_Label);
   unser_string(dev->VolHdr.Id);
   unser_uint32(dev->VolHdr.VerNum);

   if (dev->VolHdr.VerNum >= 11) {
      unser_btime(dev->VolHdr.label_btime);
      unser_btime(dev->VolHdr.write_btime);
   } else { /* old way */
      unser_float64(dev->VolHdr.label_date);
      unser_float64(dev->VolHdr.label_time);
   }
   unser_float64(dev->VolHdr.write_date);    /* Unused with VerNum >= 11 */
   unser_float64(dev->VolHdr.write_time);    /* Unused with VerNum >= 11 */

   unser_string(dev->VolHdr.VolumeName);
   unser_string(dev->VolHdr.PrevVolumeName);
   unser_string(dev->VolHdr.PoolName);
   unser_string(dev->VolHdr.PoolType);
   unser_string(dev->VolHdr.MediaType);

   unser_string(dev->VolHdr.HostName);
   unser_string(dev->VolHdr.LabelProg);
   unser_string(dev->VolHdr.ProgVersion);
   unser_string(dev->VolHdr.ProgDate);

   ser_end(rec->data, SER_LENGTH_Volume_Label);
   Dmsg0(190, "unser_vol_label\n");
   if (debug_level >= 190) {
      dump_volume_label(dev);
   }
   return true;
}
Exemple #14
0
accurate_payload *B_ACCURATE_LMDB::lookup_payload(JCR *jcr, char *fname)
{
   int result;
   int lstat_length;
   MDB_val key, data;
   accurate_payload *payload = NULL;

   key.mv_data = fname;
   key.mv_size = strlen(fname) + 1;

   result = mdb_get(m_db_ro_txn, m_db_dbi, &key, &data);
   switch (result) {
   case 0:
      /*
       * Success.
       *
       * We need to make a private copy of the LDMB data as we are not
       * allowed to change its content and we need to update the lstat
       * and chksum pointer to point to the actual lstat and chksum that
       * is stored behind the accurate_payload structure in the LMDB.
       */
      m_pay_load = check_pool_memory_size(m_pay_load, data.mv_size);

      payload = (accurate_payload *)m_pay_load;
      memcpy(payload, data.mv_data, data.mv_size);
      payload->lstat = (char *)payload + sizeof(accurate_payload);
      lstat_length = strlen(payload->lstat);
      payload->chksum = (char *)payload->lstat + lstat_length + 1;

      /*
       * We keep the transaction as short a possible so after a lookup
       * and copying the actual data out we reset the read transaction
       * and do a renew of the read transaction for a new run.
       */
      mdb_txn_reset(m_db_ro_txn);
      result = mdb_txn_renew(m_db_ro_txn);
      if (result != 0) {
         Jmsg1(jcr, M_FATAL, 0, _("Unable to renew read transaction: %s\n"), mdb_strerror(result));
         return NULL;
      }
      break;
   case MDB_NOTFOUND:
      /*
       * Failed to find the given key.
       */
      break;
   default:
      break;
   }

   return payload;
}
Exemple #15
0
/*
 * Add a character to the current string
 */
static void add_str(LEX *lf, int ch)
{
   /*
    * The default config string is sized to 256 bytes.
    * If we need longer config strings its increased with 256 bytes each time.
    */
   if ((lf->str_len + 3) >= lf->str_max_len) {
      lf->str = check_pool_memory_size(lf->str, lf->str_max_len + 256);
      lf->str_max_len = sizeof_pool_memory(lf->str);
   }

   lf->str[lf->str_len++] = ch;
   lf->str[lf->str_len] = 0;
}
Exemple #16
0
/* Update the attributes record by adding the file digest */
bool db_add_digest_to_file_record(JCR *jcr, B_DB *mdb,
                                  FileId_t FileId,
                                  char *digest, int type)
{
    bool retval;
    char ed1[50];
    int len = strlen(digest);

    db_lock(mdb);
    mdb->esc_name = check_pool_memory_size(mdb->esc_name, len*2+1);
    mdb->db_escape_string(jcr, mdb->esc_name, digest, len);
    Mmsg(mdb->cmd, "UPDATE File SET MD5='%s' WHERE FileId=%s", mdb->esc_name,
         edit_int64(FileId, ed1));
    retval = UPDATE_DB(jcr, mdb, mdb->cmd);
    db_unlock(mdb);
    return retval;
}
Exemple #17
0
bool unser_session_label(SESSION_LABEL *label, DEV_RECORD *rec)
{
   ser_declare;

   rec->data = check_pool_memory_size(rec->data, SER_LENGTH_Session_Label);
   unser_begin(rec->data, SER_LENGTH_Session_Label);
   unser_string(label->Id);
   unser_uint32(label->VerNum);
   unser_uint32(label->JobId);
   if (label->VerNum >= 11) {
      unser_btime(label->write_btime);
   } else {
      unser_float64(label->write_date);
   }
   unser_float64(label->write_time);
   unser_string(label->PoolName);
   unser_string(label->PoolType);
   unser_string(label->JobName);
   unser_string(label->ClientName);
   if (label->VerNum >= 10) {
      unser_string(label->Job);          /* Unique name of this Job */
      unser_string(label->FileSetName);
      unser_uint32(label->JobType);
      unser_uint32(label->JobLevel);
   }
   if (label->VerNum >= 11) {
      unser_string(label->FileSetMD5);
   } else {
      label->FileSetMD5[0] = 0;
   }
   if (rec->FileIndex == EOS_LABEL) {
      unser_uint32(label->JobFiles);
      unser_uint64(label->JobBytes);
      unser_uint32(label->StartBlock);
      unser_uint32(label->EndBlock);
      unser_uint32(label->StartFile);
      unser_uint32(label->EndFile);
      unser_uint32(label->JobErrors);
      if (label->VerNum >= 11) {
         unser_uint32(label->JobStatus);
      } else {
         label->JobStatus = JS_Terminated; /* kludge */
      }
   }
   return true;
}
Exemple #18
0
/*
 * BAREOS's implementation of fgets(). The difference is that it handles
 *   being interrupted by a signal (e.g. a SIGCHLD) and it has a
 *   different calling sequence which implements input lines of
 *   up to a million characters.
 */
char *bfgets(POOLMEM *&s, FILE *fd)
{
   int ch;
   int soft_max;
   int i = 0;

   s[0] = 0;
   soft_max = sizeof_pool_memory(s) - 10;
   for ( ;; ) {
      do {
         errno = 0;
         ch = fgetc(fd);
      } while (ch == EOF && ferror(fd) && (errno == EINTR || errno == EAGAIN));
      if (ch == EOF) {
         if (i == 0) {
            return NULL;
         } else {
            return s;
         }
      }
      if (i > soft_max) {
         /* Insanity check */
         if (soft_max > 1000000) {
            return s;
         }
         s = check_pool_memory_size(s, soft_max+10000);
         soft_max = sizeof_pool_memory(s) - 10;
      }
      s[i++] = ch;
      s[i] = 0;
      if (ch == '\r') { /* Support for Mac/Windows file format */
         ch = fgetc(fd);
         if (ch != '\n') { /* Mac (\r only) */
            (void)ungetc(ch, fd); /* Push next character back to fd */
         }
         s[i-1] = '\n';
         break;
      }
      if (ch == '\n') {
         break;
      }
   }
   return s;
}
Exemple #19
0
/**
 * Update NDMP level mapping
 *
 * Returns: false on failure
 *          true on success
 */
bool db_update_ndmp_level_mapping(JCR *jcr, B_DB *mdb, JOB_DBR *jr, char *filesystem, int level)
{
    bool retval;
    char ed1[50], ed2[50], ed3[50];

    db_lock(mdb);

    mdb->esc_name = check_pool_memory_size(mdb->esc_name, strlen(filesystem) * 2 + 1);
    db_escape_string(jcr, mdb, mdb->esc_name, filesystem, strlen(filesystem));

    Mmsg(mdb->cmd,
         "UPDATE NDMPLevelMap SET DumpLevel='%s' WHERE "
         "ClientId='%s' AND FileSetId='%s' AND FileSystem='%s'",
         edit_uint64(level, ed1), edit_uint64(jr->ClientId, ed2),
         edit_uint64(jr->FileSetId, ed3), mdb->esc_name);

    retval = UPDATE_DB(jcr, mdb, mdb->cmd);

    db_unlock(mdb);
    return retval;
}
Exemple #20
0
/*
 * Open the bootstrap file and find the first Storage=
 * Returns ok if able to open
 *
 * It fills the storage name (should be the first line)
 * and the file descriptor to the bootstrap file,
 * it should be used for next operations, and need to be
 * closed at the end.
 */
bool open_bootstrap_file(JCR *jcr, bootstrap_info &info)
{
   FILE *bs;
   UAContext *ua;
   info.bs = NULL;
   info.ua = NULL;

   if (!jcr->RestoreBootstrap) {
      return false;
   }
   bstrncpy(info.storage, jcr->res.rstore->name(), MAX_NAME_LENGTH);

   bs = fopen(jcr->RestoreBootstrap, "rb");
   if (!bs) {
      berrno be;
      Jmsg(jcr, M_FATAL, 0, _("Could not open bootstrap file %s: ERR=%s\n"),
         jcr->RestoreBootstrap, be.bstrerror());
      jcr->setJobStatus(JS_ErrorTerminated);
      return false;
   }

   ua = new_ua_context(jcr);
   ua->cmd = check_pool_memory_size(ua->cmd, UA_CMD_SIZE + 1);
   while (!fgets(ua->cmd, UA_CMD_SIZE, bs)) {
      parse_ua_args(ua);
      if (ua->argc != 1) {
         continue;
      }
      if (bstrcasecmp(ua->argk[0], "Storage")) {
         bstrncpy(info.storage, ua->argv[0], MAX_NAME_LENGTH);
         break;
      }
   }
   info.bs = bs;
   info.ua = ua;
   fseek(bs, 0, SEEK_SET);      /* return to the top of the file */
   return true;
}
Exemple #21
0
static bool decompress_with_zlib(JCR *jcr,
                                 const char *last_fname,
                                 char **data,
                                 uint32_t *length,
                                 bool sparse,
                                 bool with_header,
                                 bool want_data_stream)
{
   char ec1[50]; /* Buffer printing huge values */
   uLong compress_len;
   const unsigned char *cbuf;
   char *wbuf;
   int status, real_compress_len;

   /*
    * NOTE! We only use uLong and Byte because they are
    * needed by the zlib routines, they should not otherwise
    * be used in Bareos.
    */
   if (sparse && want_data_stream) {
      wbuf = jcr->compress.inflate_buffer + OFFSET_FADDR_SIZE;
      compress_len = jcr->compress.inflate_buffer_size - OFFSET_FADDR_SIZE;
   } else {
      wbuf = jcr->compress.inflate_buffer;
      compress_len = jcr->compress.inflate_buffer_size;
   }

   /*
    * See if this is a compressed stream with the new compression header or an old one.
    */
   if (with_header) {
      cbuf = (const unsigned char*)*data + sizeof(comp_stream_header);
      real_compress_len = *length - sizeof(comp_stream_header);
   } else {
      cbuf = (const unsigned char*)*data;
      real_compress_len = *length;
   }

   Dmsg2(400, "Comp_len=%d msglen=%d\n", compress_len, *length);

   while ((status = uncompress((Byte *)wbuf, &compress_len, (const Byte *)cbuf, (uLong)real_compress_len)) == Z_BUF_ERROR) {
      /*
       * The buffer size is too small, try with a bigger one
       */
      jcr->compress.inflate_buffer_size = jcr->compress.inflate_buffer_size + (jcr->compress.inflate_buffer_size >> 1);
      jcr->compress.inflate_buffer = check_pool_memory_size(jcr->compress.inflate_buffer, jcr->compress.inflate_buffer_size);

      if (sparse && want_data_stream) {
         wbuf = jcr->compress.inflate_buffer + OFFSET_FADDR_SIZE;
         compress_len = jcr->compress.inflate_buffer_size - OFFSET_FADDR_SIZE;
      } else {
         wbuf = jcr->compress.inflate_buffer;
         compress_len = jcr->compress.inflate_buffer_size;
      }
      Dmsg2(400, "Comp_len=%d msglen=%d\n", compress_len, *length);
   }

   if (status != Z_OK) {
      Qmsg(jcr, M_ERROR, 0, _("Uncompression error on file %s. ERR=%s\n"), last_fname, zlib_strerror(status));
      return false;
   }

   /*
    * We return a decompressed data stream with the fileoffset encoded when this was a sparse stream.
    */
   if (sparse && want_data_stream) {
      memcpy(jcr->compress.inflate_buffer, *data, OFFSET_FADDR_SIZE);
   }

   *data = jcr->compress.inflate_buffer;
   *length = compress_len;

   Dmsg2(400, "Write uncompressed %d bytes, total before write=%s\n", compress_len, edit_uint64(jcr->JobBytes, ec1));

   return true;
}
Exemple #22
0
/*
 * 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.
 */
static void update_attribute(JCR *jcr, char *msg, int32_t msglen)
{
   unser_declare;
   uint32_t VolSessionId, VolSessionTime;
   int32_t Stream;
   uint32_t FileIndex;
   char *p;
   int len;
   char *fname, *attr;
   ATTR_DBR *ar = NULL;
   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
    * there may be a cached attr so we cannot yet write into
    * jcr->attr or jcr->ar
    */
   p = msg;
   skip_nonspaces(&p);                /* UpdCat */
   skip_spaces(&p);
   skip_nonspaces(&p);                /* Job=nnn */
   skip_spaces(&p);
   skip_nonspaces(&p);                /* "FileAttributes" */
   p += 1;

   /*
    * The following "SD header" fields are serialized
    */
   unser_begin(p, 0);
   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", msg);
   Dmsg5(400, "UpdCat VolSessId=%d VolSessT=%d FI=%d Strm=%d reclen=%d\n",
         VolSessionId, VolSessionTime, FileIndex, Stream, reclen);

   jcr->SDJobBytes += reclen; /* update number of bytes transferred for quotas */

   /*
    * Depending on the stream we are handling dispatch.
    */
   switch (Stream) {
   case STREAM_UNIX_ATTRIBUTES:
   case STREAM_UNIX_ATTRIBUTES_EX:
      if (jcr->cached_attribute) {
         Dmsg2(400, "Cached attr. Stream=%d fname=%s\n", ar->Stream, ar->fname);
         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, msglen);
      memcpy(jcr->attr, msg, msglen);
      p = jcr->attr - msg + p;         /* point p into jcr->attr */
      skip_nonspaces(&p);              /* skip FileIndex */
      skip_spaces(&p);
      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, "dird<stored: stream=%d %s\n", Stream, fname);
      Dmsg1(400, "dird<stored: attr=%s\n", attr);

      ar->attr = attr;
      ar->fname = fname;
      if (ar->FileType == FT_DELETED) {
         ar->FileIndex = 0;     /* special value */
      } else {
         ar->FileIndex = FileIndex;
      }
      ar->Stream = Stream;
      ar->link = NULL;
      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, "dird<filed: stream=%d %s\n", Stream, fname);
      Dmsg1(400, "dird<filed: attr=%s\n", attr);
      break;
   case 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;
      }

      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);

      /*
       * Store 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));
      }
      break;
   }
   default:
      if (crypto_digest_stream_type(Stream) != CRYPTO_DIGEST_NONE) {
         fname = p;
         if (ar->FileIndex != FileIndex) {
            Jmsg3(jcr, M_WARNING, 0, _("%s not same File=%d as attributes=%d\n"),
               stream_to_ascii(Stream), FileIndex, ar->FileIndex);
         } else {
            /*
             * 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(digestbuf, sizeof(digestbuf), fname, len, true);

            Dmsg3(400, "DigestLen=%d Digest=%s type=%d\n", strlen(digestbuf),
                  digestbuf, Stream);

            if (jcr->cached_attribute) {
               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_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));
               }
            }
         }
      }
      break;
   }
}
Exemple #23
0
bool B_ACCURATE_LMDB::update_payload(JCR *jcr, char *fname, accurate_payload *payload)
{
   int result,
       total_length,
       lstat_length,
       chksum_length;
   MDB_val key, data;
   bool retval = false;
   accurate_payload *new_payload;

   lstat_length = strlen(payload->lstat);
   chksum_length = strlen(payload->chksum);
   total_length = sizeof(accurate_payload) + lstat_length + chksum_length + 2;

   /*
    * Make sure m_pay_load is large enough.
    */
   m_pay_load = check_pool_memory_size(m_pay_load, total_length);

   /*
    * We store the total pay load as:
    *
    * accurate_payload structure\0lstat\0chksum\0
    */
   new_payload = (accurate_payload *)m_pay_load;

   new_payload->lstat = (char *)payload + sizeof(accurate_payload);
   memcpy(new_payload->lstat, payload->lstat, lstat_length);
   new_payload->lstat[lstat_length] = '\0';

   new_payload->chksum = (char *)new_payload->lstat + lstat_length + 1;
   if (chksum_length) {
      memcpy(new_payload->chksum, payload->chksum, chksum_length);
   }
   new_payload->chksum[chksum_length] = '\0';

   new_payload->delta_seq = payload->delta_seq;
   new_payload->filenr = payload->filenr;

   key.mv_data = fname;
   key.mv_size = strlen(fname) + 1;

   data.mv_data = new_payload;
   data.mv_size = total_length;

retry:
   result = mdb_put(m_db_rw_txn, m_db_dbi, &key, &data, 0);
   switch (result) {
   case 0:
      result = mdb_txn_commit(m_db_rw_txn);
      if (result == 0) {
         result = mdb_txn_begin(m_db_env, NULL, 0, &m_db_rw_txn);
         if (result != 0) {
            Jmsg1(jcr, M_FATAL, 0, _("Unable to create write transaction: %s\n"), mdb_strerror(result));
         } else {
            retval = true;
         }
      } else {
         Jmsg1(jcr, M_FATAL, 0, _("Unable close write transaction: %s\n"), mdb_strerror(result));
      }
      break;
   case MDB_TXN_FULL:
      /*
       * Seems we filled the transaction.
       * Flush the current transaction start a new one and retry the put.
       */
      result = mdb_txn_commit(m_db_rw_txn);
      if (result == 0) {
         result = mdb_txn_begin(m_db_env, NULL, 0, &m_db_rw_txn);
         if (result == 0) {
            goto retry;
         }
      }
      /*
       * Fallthrough wanted.
       */
   default:
      Jmsg1(jcr, M_FATAL, 0, _("Unable insert new data: %s\n"), mdb_strerror(result));
      break;
   }

   return retval;
}
Exemple #24
0
/*
 * See who is connecting and lookup the authentication information.
 * First make him prove his identity and then prove our identity to the Remote daemon.
 */
static inline bool two_way_authenticate(int rcode, BSOCK *bs, JCR* jcr)
{
   POOLMEM *dirname = get_pool_memory(PM_MESSAGE);
   DIRRES *director = NULL;
   int tls_local_need = BNET_TLS_NONE;
   int tls_remote_need = BNET_TLS_NONE;
   bool compatible = true;                /* Want md5 compatible DIR */
   bool auth_success = false;
   alist *verify_list = NULL;
   btimer_t *tid = NULL;

   if (rcode != R_DIRECTOR) {
      Dmsg1(dbglvl, "I only authenticate directors, not %d\n", rcode);
      Jmsg1(jcr, M_FATAL, 0, _("I only authenticate directors, not %d\n"), rcode);
      goto auth_fatal;
   }

   if (bs->msglen < 25 || bs->msglen > 500) {
      Dmsg2(dbglvl, "Bad Hello command from Director at %s. Len=%d.\n",
            bs->who(), bs->msglen);
      char addr[64];
      char *who = bnet_get_peer(bs, addr, sizeof(addr)) ? bs->who() : addr;
      Jmsg2(jcr, M_FATAL, 0, _("Bad Hello command from Director at %s. Len=%d.\n"),
             who, bs->msglen);
      goto auth_fatal;
   }
   dirname = check_pool_memory_size(dirname, bs->msglen);

   if (sscanf(bs->msg, "Hello Director %s calling", dirname) != 1) {
      char addr[64];
      char *who = bnet_get_peer(bs, addr, sizeof(addr)) ? bs->who() : addr;
      bs->msg[100] = 0;
      Dmsg2(dbglvl, "Bad Hello command from Director at %s: %s\n",
            bs->who(), bs->msg);
      Jmsg2(jcr, M_FATAL, 0, _("Bad Hello command from Director at %s: %s\n"),
            who, bs->msg);
      goto auth_fatal;
   }
   unbash_spaces(dirname);
   foreach_res(director, R_DIRECTOR) {
      if (bstrcmp(director->hdr.name, dirname))
         break;
   }
   if (!director) {
      char addr[64];
      char *who = bnet_get_peer(bs, addr, sizeof(addr)) ? bs->who() : addr;
      Jmsg2(jcr, M_FATAL, 0, _("Connection from unknown Director %s at %s rejected.\n"),
            dirname, who);
      goto auth_fatal;
   }

   if (have_tls) {
      /*
       * TLS Requirement
       */
      if (director->tls_enable) {
         if (director->tls_require) {
            tls_local_need = BNET_TLS_REQUIRED;
         } else {
            tls_local_need = BNET_TLS_OK;
         }
      }

      if (director->tls_authenticate) {
         tls_local_need = BNET_TLS_REQUIRED;
      }

      if (director->tls_verify_peer) {
         verify_list = director->tls_allowed_cns;
      }
   }

   /*
    * Timeout Hello after 10 min
    */
   tid = start_bsock_timer(bs, AUTH_TIMEOUT);

   /*
    * Sanity check.
    */
   ASSERT(director->password.encoding == p_encoding_md5);

   /*
    * Challenge the director
    */
   auth_success = cram_md5_challenge(bs, director->password.value, tls_local_need, compatible);
   if (job_canceled(jcr)) {
      auth_success = false;
      goto auth_fatal;                   /* quick exit */
   }

   if (auth_success) {
      auth_success = cram_md5_respond(bs, director->password.value, &tls_remote_need, &compatible);
      if (!auth_success) {
          char addr[64];
          char *who = bnet_get_peer(bs, addr, sizeof(addr)) ? bs->who() : addr;
          Dmsg1(dbglvl, "cram_get_auth failed for %s\n", who);
      }
   } else {
       char addr[64];
       char *who = bnet_get_peer(bs, addr, sizeof(addr)) ? bs->who() : addr;
       Dmsg1(dbglvl, "cram_auth failed for %s\n", who);
   }

   if (!auth_success) {
       Emsg1(M_FATAL, 0, _("Incorrect password given by Director at %s.\n"),
             bs->who());
       goto auth_fatal;
   }

   /*
    * Verify that the remote host is willing to meet our TLS requirements
    */
   if (tls_remote_need < tls_local_need && tls_local_need != BNET_TLS_OK && tls_remote_need != BNET_TLS_OK) {
      Jmsg0(jcr, M_FATAL, 0, _("Authorization problem: Remote server did not"
           " advertize required TLS support.\n"));
      Dmsg2(dbglvl, "remote_need=%d local_need=%d\n", tls_remote_need, tls_local_need);
      auth_success = false;
      goto auth_fatal;
   }

   /*
    * Verify that we are willing to meet the remote host's requirements
    */
   if (tls_remote_need > tls_local_need && tls_local_need != BNET_TLS_OK && tls_remote_need != BNET_TLS_OK) {
      Jmsg0(jcr, M_FATAL, 0, _("Authorization problem: Remote server requires TLS.\n"));
      Dmsg2(dbglvl, "remote_need=%d local_need=%d\n", tls_remote_need, tls_local_need);
      auth_success = false;
      goto auth_fatal;
   }

   if (tls_local_need >= BNET_TLS_OK && tls_remote_need >= BNET_TLS_OK) {
      /*
       * Engage TLS! Full Speed Ahead!
       */
      if (!bnet_tls_server(director->tls_ctx, bs, verify_list)) {
         Jmsg0(jcr, M_FATAL, 0, _("TLS negotiation failed.\n"));
         auth_success = false;
         goto auth_fatal;
      }
      if (director->tls_authenticate) {         /* authentication only? */
         bs->free_tls();                        /* shutodown tls */
      }
   }

auth_fatal:
   if (tid) {
      stop_bsock_timer(tid);
      tid = NULL;
   }
   free_pool_memory(dirname);
   jcr->director = director;

   /*
    * Single thread all failures to avoid DOS
    */
   if (!auth_success) {
      P(mutex);
      bmicrosleep(6, 0);
      V(mutex);
   }

   return auth_success;
}
Exemple #25
0
bool B_ACCURATE_LMDB::add_file(JCR *jcr,
                               char *fname,
                               int fname_length,
                               char *lstat,
                               int lstat_length,
                               char *chksum,
                               int chksum_length,
                               int32_t delta_seq)
{
   accurate_payload *payload;
   int result;
   int total_length;
   MDB_val key, data;
   bool retval = false;

   total_length = sizeof(accurate_payload) + lstat_length + chksum_length + 2;

   /*
    * Make sure m_pay_load is large enough.
    */
   m_pay_load = check_pool_memory_size(m_pay_load, total_length);

   /*
    * We store the total pay load as:
    *
    * accurate_payload structure\0lstat\0chksum\0
    */
   payload = (accurate_payload *)m_pay_load;

   payload->lstat = (char *)payload + sizeof(accurate_payload);
   memcpy(payload->lstat, lstat, lstat_length);
   payload->lstat[lstat_length] = '\0';

   payload->chksum = (char *)payload->lstat + lstat_length + 1;
   if (chksum_length) {
      memcpy(payload->chksum, chksum, chksum_length);
   }
   payload->chksum[chksum_length] = '\0';

   payload->delta_seq = delta_seq;
   payload->filenr = m_filenr++;

   key.mv_data = fname;
   key.mv_size = strlen(fname) + 1;

   data.mv_data = payload;
   data.mv_size = total_length;

retry:
   result = mdb_put(m_db_rw_txn, m_db_dbi, &key, &data, MDB_NOOVERWRITE);
   switch (result) {
   case 0:
      if (chksum) {
         Dmsg4(dbglvl, "add fname=<%s> lstat=%s delta_seq=%i chksum=%s\n", fname, lstat, delta_seq, chksum);
      } else {
         Dmsg2(dbglvl, "add fname=<%s> lstat=%s\n", fname, lstat);
      }
      retval = true;
      break;
   case MDB_TXN_FULL:
      /*
       * Seems we filled the transaction.
       * Flush the current transaction start a new one and retry the put.
       */
      result = mdb_txn_commit(m_db_rw_txn);
      if (result == 0) {
         result = mdb_txn_begin(m_db_env, NULL, 0, &m_db_rw_txn);
         if (result == 0) {
            goto retry;
         }
      }
      /*
       * Fallthrough wanted.
       */
   default:
      Jmsg1(jcr, M_FATAL, 0, _("Unable insert new data: %s\n"), mdb_strerror(result));
      break;
   }

   return retval;
}
Exemple #26
0
/**
 * Called here by find() for each file included.
 *   This is a callback. The original is find_files() above.
 *
 *  Send the file and its data to the Storage daemon.
 *
 *  Returns: 1 if OK
 *           0 if error
 *          -1 to ignore file/directory (not used here)
 */
int save_file(JCR *jcr, FF_PKT *ff_pkt, bool top_level)
{
   bool do_read = false;
   bool plugin_started = false;
   bool do_plugin_set = false;
   int status, data_stream;
   int rtnstat = 0;
   b_save_ctx bsctx;
   bool has_file_data = false;
   struct save_pkt sp;          /* use by option plugin */
   BSOCK *sd = jcr->store_bsock;

   if (jcr->is_canceled() || jcr->is_incomplete()) {
      return 0;
   }

   jcr->num_files_examined++;         /* bump total file count */

   switch (ff_pkt->type) {
   case FT_LNKSAVED:                  /* Hard linked, file already saved */
      Dmsg2(130, "FT_LNKSAVED hard link: %s => %s\n", ff_pkt->fname, ff_pkt->link);
      break;
   case FT_REGE:
      Dmsg1(130, "FT_REGE saving: %s\n", ff_pkt->fname);
      has_file_data = true;
      break;
   case FT_REG:
      Dmsg1(130, "FT_REG saving: %s\n", ff_pkt->fname);
      has_file_data = true;
      break;
   case FT_LNK:
      Dmsg2(130, "FT_LNK saving: %s -> %s\n", ff_pkt->fname, ff_pkt->link);
      break;
   case FT_RESTORE_FIRST:
      Dmsg1(100, "FT_RESTORE_FIRST saving: %s\n", ff_pkt->fname);
      break;
   case FT_PLUGIN_CONFIG:
      Dmsg1(100, "FT_PLUGIN_CONFIG saving: %s\n", ff_pkt->fname);
      break;
   case FT_DIRBEGIN:
      jcr->num_files_examined--;      /* correct file count */
      return 1;                       /* not used */
   case FT_NORECURSE:
      Jmsg(jcr, M_INFO, 1, _("     Recursion turned off. Will not descend from %s into %s\n"),
           ff_pkt->top_fname, ff_pkt->fname);
      ff_pkt->type = FT_DIREND;       /* Backup only the directory entry */
      break;
   case FT_NOFSCHG:
      /* Suppress message for /dev filesystems */
      if (!is_in_fileset(ff_pkt)) {
         Jmsg(jcr, M_INFO, 1, _("     %s is a different filesystem. Will not descend from %s into it.\n"),
              ff_pkt->fname, ff_pkt->top_fname);
      }
      ff_pkt->type = FT_DIREND;       /* Backup only the directory entry */
      break;
   case FT_INVALIDFS:
      Jmsg(jcr, M_INFO, 1, _("     Disallowed filesystem. Will not descend from %s into %s\n"),
           ff_pkt->top_fname, ff_pkt->fname);
      ff_pkt->type = FT_DIREND;       /* Backup only the directory entry */
      break;
   case FT_INVALIDDT:
      Jmsg(jcr, M_INFO, 1, _("     Disallowed drive type. Will not descend into %s\n"),
           ff_pkt->fname);
      break;
   case FT_REPARSE:
   case FT_JUNCTION:
   case FT_DIREND:
      Dmsg1(130, "FT_DIREND: %s\n", ff_pkt->link);
      break;
   case FT_SPEC:
      Dmsg1(130, "FT_SPEC saving: %s\n", ff_pkt->fname);
      if (S_ISSOCK(ff_pkt->statp.st_mode)) {
        Jmsg(jcr, M_SKIPPED, 1, _("     Socket file skipped: %s\n"), ff_pkt->fname);
        return 1;
      }
      break;
   case FT_RAW:
      Dmsg1(130, "FT_RAW saving: %s\n", ff_pkt->fname);
      has_file_data = true;
      break;
   case FT_FIFO:
      Dmsg1(130, "FT_FIFO saving: %s\n", ff_pkt->fname);
      break;
   case FT_NOACCESS: {
      berrno be;
      Jmsg(jcr, M_NOTSAVED, 0, _("     Could not access \"%s\": ERR=%s\n"),
           ff_pkt->fname, be.bstrerror(ff_pkt->ff_errno));
      jcr->JobErrors++;
      return 1;
   }
   case FT_NOFOLLOW: {
      berrno be;
      Jmsg(jcr, M_NOTSAVED, 0, _("     Could not follow link \"%s\": ERR=%s\n"),
           ff_pkt->fname, be.bstrerror(ff_pkt->ff_errno));
      jcr->JobErrors++;
      return 1;
   }
   case FT_NOSTAT: {
      berrno be;
      Jmsg(jcr, M_NOTSAVED, 0, _("     Could not stat \"%s\": ERR=%s\n"),
           ff_pkt->fname, be.bstrerror(ff_pkt->ff_errno));
      jcr->JobErrors++;
      return 1;
   }
   case FT_DIRNOCHG:
   case FT_NOCHG:
      Jmsg(jcr, M_SKIPPED, 1, _("     Unchanged file skipped: %s\n"), ff_pkt->fname);
      return 1;
   case FT_ISARCH:
      Jmsg(jcr, M_NOTSAVED, 0, _("     Archive file not saved: %s\n"), ff_pkt->fname);
      return 1;
   case FT_NOOPEN: {
      berrno be;
      Jmsg(jcr, M_NOTSAVED, 0, _("     Could not open directory \"%s\": ERR=%s\n"),
           ff_pkt->fname, be.bstrerror(ff_pkt->ff_errno));
      jcr->JobErrors++;
      return 1;
   }
   case FT_DELETED:
      Dmsg1(130, "FT_DELETED: %s\n", ff_pkt->fname);
      break;
   default:
      Jmsg(jcr, M_NOTSAVED, 0,  _("     Unknown file type %d; not saved: %s\n"),
           ff_pkt->type, ff_pkt->fname);
      jcr->JobErrors++;
      return 1;
   }

   Dmsg1(130, "filed: sending %s to stored\n", ff_pkt->fname);

   /*
    * Setup backup signing context.
    */
   memset(&bsctx, 0, sizeof(b_save_ctx));
   bsctx.digest_stream = STREAM_NONE;
   bsctx.jcr = jcr;
   bsctx.ff_pkt = ff_pkt;

   /*
    * Digests and encryption are only useful if there's file data
    */
   if (has_file_data) {
      if (!setup_encryption_digests(bsctx)) {
         goto good_rtn;
      }
   }

   /*
    * Initialize the file descriptor we use for data and other streams.
    */
   binit(&ff_pkt->bfd);
   if (bit_is_set(FO_PORTABLE, ff_pkt->flags)) {
      set_portable_backup(&ff_pkt->bfd); /* disable Win32 BackupRead() */
   }

   /*
    * Option and cmd plugin are not compatible together
    */
   if (ff_pkt->cmd_plugin) {
      do_plugin_set = true;
   } else if (ff_pkt->opt_plugin) {
      /*
       * Ask the option plugin what to do with this file
       */
      switch (plugin_option_handle_file(jcr, ff_pkt, &sp)) {
      case bRC_OK:
         Dmsg2(10, "Option plugin %s will be used to backup %s\n", ff_pkt->plugin, ff_pkt->fname);
         jcr->opt_plugin = true;
         jcr->plugin_sp = &sp;
         plugin_update_ff_pkt(ff_pkt, &sp);
         do_plugin_set = true;
         break;
      case bRC_Skip:
         Dmsg2(10, "Option plugin %s decided to skip %s\n", ff_pkt->plugin, ff_pkt->fname);
         goto good_rtn;
      case bRC_Core:
         Dmsg2(10, "Option plugin %s decided to let bareos handle %s\n", ff_pkt->plugin, ff_pkt->fname);
         break;
      default:
         goto bail_out;
      }
   }

   if (do_plugin_set) {
      /*
       * Tell bfile that it needs to call plugin
       */
      if (!set_cmd_plugin(&ff_pkt->bfd, jcr)) {
         goto bail_out;
      }
      send_plugin_name(jcr, sd, true);      /* signal start of plugin data */
      plugin_started = true;
   }

   /*
    * Send attributes -- must be done after binit()
    */
   if (!encode_and_send_attributes(jcr, ff_pkt, data_stream)) {
      goto bail_out;
   }

   /*
    * Meta data only for restore object
    */
   if (IS_FT_OBJECT(ff_pkt->type)) {
      goto good_rtn;
   }

   /*
    * Meta data only for deleted files
    */
   if (ff_pkt->type == FT_DELETED) {
      goto good_rtn;
   }

   /*
    * Set up the encryption context and send the session data to the SD
    */
   if (has_file_data && jcr->crypto.pki_encrypt) {
      if (!crypto_session_send(jcr, sd)) {
         goto bail_out;
      }
   }

   /*
    * For a command plugin use the setting from the plugins savepkt no_read field
    * which is saved in the ff_pkt->no_read variable. do_read is the inverted
    * value of this variable as no_read == TRUE means do_read == FALSE
    */
   if (ff_pkt->cmd_plugin) {
      do_read = !ff_pkt->no_read;
   } else {
      /*
       * Open any file with data that we intend to save, then save it.
       *
       * Note, if is_win32_backup, we must open the Directory so that
       * the BackupRead will save its permissions and ownership streams.
       */
      if (ff_pkt->type != FT_LNKSAVED && S_ISREG(ff_pkt->statp.st_mode)) {
#ifdef HAVE_WIN32
         do_read = !is_portable_backup(&ff_pkt->bfd) || ff_pkt->statp.st_size > 0;
#else
         do_read = ff_pkt->statp.st_size > 0;
#endif
      } else if (ff_pkt->type == FT_RAW ||
                 ff_pkt->type == FT_FIFO ||
                 ff_pkt->type == FT_REPARSE ||
                 ff_pkt->type == FT_JUNCTION ||
                (!is_portable_backup(&ff_pkt->bfd) &&
                 ff_pkt->type == FT_DIREND)) {
         do_read = true;
      }
   }

   Dmsg2(150, "type=%d do_read=%d\n", ff_pkt->type, do_read);
   if (do_read) {
      btimer_t *tid;
      int noatime;

      if (ff_pkt->type == FT_FIFO) {
         tid = start_thread_timer(jcr, pthread_self(), 60);
      } else {
         tid = NULL;
      }

      noatime = bit_is_set(FO_NOATIME, ff_pkt->flags) ? O_NOATIME : 0;
      ff_pkt->bfd.reparse_point = (ff_pkt->type == FT_REPARSE ||
                                   ff_pkt->type == FT_JUNCTION);

      if (bopen(&ff_pkt->bfd, ff_pkt->fname, O_RDONLY | O_BINARY | noatime, 0, ff_pkt->statp.st_rdev) < 0) {
         ff_pkt->ff_errno = errno;
         berrno be;
         Jmsg(jcr, M_NOTSAVED, 0,
              _("     Cannot open \"%s\": ERR=%s.\n"),
              ff_pkt->fname, be.bstrerror());
         jcr->JobErrors++;
         if (tid) {
            stop_thread_timer(tid);
            tid = NULL;
         }
         goto good_rtn;
      }

      if (tid) {
         stop_thread_timer(tid);
         tid = NULL;
      }

      status = send_data(jcr, data_stream, ff_pkt, bsctx.digest, bsctx.signing_digest);

      if (bit_is_set(FO_CHKCHANGES, ff_pkt->flags)) {
         has_file_changed(jcr, ff_pkt);
      }

      bclose(&ff_pkt->bfd);

      if (!status) {
         goto bail_out;
      }
   }

   if (have_darwin_os) {
      /*
       * Regular files can have resource forks and Finder Info
       */
      if (ff_pkt->type != FT_LNKSAVED &&
         (S_ISREG(ff_pkt->statp.st_mode) &&
          bit_is_set(FO_HFSPLUS, ff_pkt->flags))) {
         if (!save_rsrc_and_finder(bsctx)) {
            goto bail_out;
         }
      }
   }

   /*
    * Save ACLs when requested and available for anything not being a symlink.
    */
   if (have_acl) {
      if (bit_is_set(FO_ACL, ff_pkt->flags) && ff_pkt->type != FT_LNK) {
         if (!do_backup_acl(jcr, ff_pkt)) {
            goto bail_out;
         }
      }
   }

   /*
    * Save Extended Attributes when requested and available for all files.
    */
   if (have_xattr) {
      if (bit_is_set(FO_XATTR, ff_pkt->flags)) {
         if (!do_backup_xattr(jcr, ff_pkt)) {
            goto bail_out;
         }
      }
   }

   /*
    * Terminate the signing digest and send it to the Storage daemon
    */
   if (bsctx.signing_digest) {
      if (!terminate_signing_digest(bsctx)) {
         goto bail_out;
      }
   }

   /*
    * Terminate any digest and send it to Storage daemon
    */
   if (bsctx.digest) {
      if (!terminate_digest(bsctx)) {
         goto bail_out;
      }
   }

   /*
    * Check if original file has a digest, and send it
    */
   if (ff_pkt->type == FT_LNKSAVED && ff_pkt->digest) {
      Dmsg2(300, "Link %s digest %d\n", ff_pkt->fname, ff_pkt->digest_len);
      sd->fsend("%ld %d 0", jcr->JobFiles, ff_pkt->digest_stream);

      sd->msg = check_pool_memory_size(sd->msg, ff_pkt->digest_len);
      memcpy(sd->msg, ff_pkt->digest, ff_pkt->digest_len);
      sd->msglen = ff_pkt->digest_len;
      sd->send();

      sd->signal(BNET_EOD);              /* end of hardlink record */
   }

good_rtn:
   rtnstat = jcr->is_canceled() ? 0 : 1; /* good return if not canceled */

bail_out:
   if (jcr->is_incomplete() || jcr->is_canceled()) {
      rtnstat = 0;
   }
   if (plugin_started) {
      send_plugin_name(jcr, sd, false); /* signal end of plugin data */
   }
   if (ff_pkt->opt_plugin) {
      jcr->plugin_sp = NULL;            /* sp is local to this function */
      jcr->opt_plugin = false;
   }
   if (bsctx.digest) {
      crypto_digest_free(bsctx.digest);
   }
   if (bsctx.signing_digest) {
      crypto_digest_free(bsctx.signing_digest);
   }

   return rtnstat;
}
Exemple #27
0
bool encode_and_send_attributes(JCR *jcr, FF_PKT *ff_pkt, int &data_stream)
{
   BSOCK *sd = jcr->store_bsock;
   POOL_MEM attribs(PM_NAME),
            attribsExBuf(PM_NAME);
   char *attribsEx = NULL;
   int attr_stream;
   int comp_len;
   bool status;
   int hangup = get_hangup();
#ifdef FD_NO_SEND_TEST
   return true;
#endif

   Dmsg1(300, "encode_and_send_attrs fname=%s\n", ff_pkt->fname);
   /** Find what data stream we will use, then encode the attributes */
   if ((data_stream = select_data_stream(ff_pkt, me->compatible)) == STREAM_NONE) {
      /* This should not happen */
      Jmsg0(jcr, M_FATAL, 0, _("Invalid file flags, no supported data stream type.\n"));
      return false;
   }
   encode_stat(attribs.c_str(), &ff_pkt->statp, sizeof(ff_pkt->statp), ff_pkt->LinkFI, data_stream);

   /** Now possibly extend the attributes */
   if (IS_FT_OBJECT(ff_pkt->type)) {
      attr_stream = STREAM_RESTORE_OBJECT;
   } else {
      attribsEx = attribsExBuf.c_str();
      attr_stream = encode_attribsEx(jcr, attribsEx, ff_pkt);
   }

   Dmsg3(300, "File %s\nattribs=%s\nattribsEx=%s\n", ff_pkt->fname, attribs.c_str(), attribsEx);

   jcr->lock();
   jcr->JobFiles++;                    /* increment number of files sent */
   ff_pkt->FileIndex = jcr->JobFiles;  /* return FileIndex */
   pm_strcpy(jcr->last_fname, ff_pkt->fname);
   jcr->unlock();

   /*
    * Debug code: check if we must hangup
    */
   if (hangup && (jcr->JobFiles > (uint32_t)hangup)) {
      jcr->setJobStatus(JS_Incomplete);
      Jmsg1(jcr, M_FATAL, 0, "Debug hangup requested after %d files.\n", hangup);
      set_hangup(0);
      return false;
   }

   /**
    * Send Attributes header to Storage daemon
    *    <file-index> <stream> <info>
    */
   if (!sd->fsend("%ld %d 0", jcr->JobFiles, attr_stream)) {
      if (!jcr->is_canceled() && !jcr->is_incomplete()) {
         Jmsg1(jcr, M_FATAL, 0, _("Network send error to SD. ERR=%s\n"), sd->bstrerror());
      }
      return false;
   }
   Dmsg1(300, ">stored: attrhdr %s", sd->msg);

   /**
    * Send file attributes to Storage daemon
    *   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
    *
    * or send Restore Object to Storage daemon
    *   File_index
    *   File_type
    *   Object_index
    *   Object_len  (possibly compressed)
    *   Object_full_len (not compressed)
    *   Object_compression
    *   Plugin_name
    *   Object_name
    *   Binary Object data
    *
    * For a directory, link is the same as fname, but with trailing
    * slash. For a linked file, link is the link.
    */
   if (!IS_FT_OBJECT(ff_pkt->type) && ff_pkt->type != FT_DELETED) { /* already stripped */
      strip_path(ff_pkt);
   }
   switch (ff_pkt->type) {
   case FT_JUNCTION:
   case FT_LNK:
   case FT_LNKSAVED:
      Dmsg3(300, "Link %d %s to %s\n", jcr->JobFiles, ff_pkt->fname, ff_pkt->link);
      status = sd->fsend("%ld %d %s%c%s%c%s%c%s%c%u%c", jcr->JobFiles,
                         ff_pkt->type, ff_pkt->fname, 0, attribs.c_str(), 0,
                         ff_pkt->link, 0, attribsEx, 0, ff_pkt->delta_seq, 0);
      break;
   case FT_DIREND:
   case FT_REPARSE:
      /* Here link is the canonical filename (i.e. with trailing slash) */
      status = sd->fsend("%ld %d %s%c%s%c%c%s%c%u%c", jcr->JobFiles,
                         ff_pkt->type, ff_pkt->link, 0, attribs.c_str(), 0, 0,
                         attribsEx, 0, ff_pkt->delta_seq, 0);
      break;
   case FT_PLUGIN_CONFIG:
   case FT_RESTORE_FIRST:
      comp_len = ff_pkt->object_len;
      ff_pkt->object_compression = 0;

      if (ff_pkt->object_len > 1000) {
         /*
          * Big object, compress it
          */
         comp_len = compressBound(ff_pkt->object_len);
         POOLMEM *comp_obj = get_memory(comp_len);
         /*
          * FIXME: check Zdeflate error
          */
         Zdeflate(ff_pkt->object, ff_pkt->object_len, comp_obj, comp_len);
         if (comp_len < ff_pkt->object_len) {
            ff_pkt->object = comp_obj;
            ff_pkt->object_compression = 1;    /* zlib level 9 compression */
         } else {
            /*
             * Uncompressed object smaller, use it
             */
            comp_len = ff_pkt->object_len;
         }
         Dmsg2(100, "Object compressed from %d to %d bytes\n", ff_pkt->object_len, comp_len);
      }

      sd->msglen = Mmsg(sd->msg, "%d %d %d %d %d %d %s%c%s%c",
                        jcr->JobFiles, ff_pkt->type, ff_pkt->object_index,
                        comp_len, ff_pkt->object_len, ff_pkt->object_compression,
                        ff_pkt->fname, 0, ff_pkt->object_name, 0);
      sd->msg = check_pool_memory_size(sd->msg, sd->msglen + comp_len + 2);
      memcpy(sd->msg + sd->msglen, ff_pkt->object, comp_len);

      /*
       * Note we send one extra byte so Dir can store zero after object
       */
      sd->msglen += comp_len + 1;
      status = sd->send();
      if (ff_pkt->object_compression) {
         free_and_null_pool_memory(ff_pkt->object);
      }
      break;
   case FT_REG:
      status = sd->fsend("%ld %d %s%c%s%c%c%s%c%d%c", jcr->JobFiles,
                         ff_pkt->type, ff_pkt->fname, 0, attribs.c_str(), 0, 0,
                         attribsEx, 0, ff_pkt->delta_seq, 0);
      break;
   default:
      status = sd->fsend("%ld %d %s%c%s%c%c%s%c%u%c", jcr->JobFiles,
                         ff_pkt->type, ff_pkt->fname, 0, attribs.c_str(), 0, 0,
                         attribsEx, 0, ff_pkt->delta_seq, 0);
      break;
   }

   if (!IS_FT_OBJECT(ff_pkt->type) && ff_pkt->type != FT_DELETED) {
      unstrip_path(ff_pkt);
   }

   Dmsg2(300, ">stored: attr len=%d: %s\n", sd->msglen, sd->msg);
   if (!status && !jcr->is_job_canceled()) {
      Jmsg1(jcr, M_FATAL, 0, _("Network send error to SD. ERR=%s\n"), sd->bstrerror());
   }

   sd->signal(BNET_EOD);            /* indicate end of attributes data */

   return status;
}
Exemple #28
0
static bool decompress_with_fastlz(JCR *jcr,
                                   const char *last_fname,
                                   char **data,
                                   uint32_t *length,
                                   uint32_t comp_magic,
                                   bool sparse,
                                   bool want_data_stream)
{
   int zstat;
   zfast_stream stream;
   zfast_stream_compressor compressor = COMPRESSOR_FASTLZ;
   char ec1[50]; /* Buffer printing huge values */

   switch (comp_magic) {
   case COMPRESS_FZ4L:
   case COMPRESS_FZ4H:
      compressor = COMPRESSOR_LZ4;
      break;
   }

   /*
    * NOTE! We only use uInt and Bytef because they are
    * needed by the fastlz routines, they should not otherwise
    * be used in Bareos.
    */
   memset(&stream, 0, sizeof(stream));
   stream.next_in = (Bytef *)*data + sizeof(comp_stream_header);
   stream.avail_in = (uInt)*length - sizeof(comp_stream_header);
   if (sparse && want_data_stream) {
      stream.next_out = (Bytef *)jcr->compress.inflate_buffer + OFFSET_FADDR_SIZE;
      stream.avail_out = (uInt)jcr->compress.inflate_buffer_size - OFFSET_FADDR_SIZE;
   } else {
      stream.next_out = (Bytef *)jcr->compress.inflate_buffer;
      stream.avail_out = (uInt)jcr->compress.inflate_buffer_size;
   }

   Dmsg2(400, "Comp_len=%d msglen=%d\n", stream.avail_in, *length);

   if ((zstat = fastlzlibDecompressInit(&stream)) != Z_OK) {
      goto cleanup;
   }

   if ((zstat = fastlzlibSetCompressor(&stream, compressor)) != Z_OK) {
      goto cleanup;
   }

   while (1) {
      zstat = fastlzlibDecompress(&stream);
      switch (zstat) {
      case Z_BUF_ERROR:
         /*
          * The buffer size is too small, try with a bigger one
          */
         jcr->compress.inflate_buffer_size = jcr->compress.inflate_buffer_size + (jcr->compress.inflate_buffer_size >> 1);
         jcr->compress.inflate_buffer = check_pool_memory_size(jcr->compress.inflate_buffer, jcr->compress.inflate_buffer_size);
         if (sparse && want_data_stream) {
            stream.next_out = (Bytef *)jcr->compress.inflate_buffer + OFFSET_FADDR_SIZE;
            stream.avail_out = (uInt)jcr->compress.inflate_buffer_size - OFFSET_FADDR_SIZE;
         } else {
            stream.next_out = (Bytef *)jcr->compress.inflate_buffer;
            stream.avail_out = (uInt)jcr->compress.inflate_buffer_size;
         }
         continue;
      case Z_OK:
      case Z_STREAM_END:
         break;
      default:
         goto cleanup;
      }
      break;
   }

   /*
    * We return a decompressed data stream with the fileoffset encoded when this was a sparse stream.
    */
   if (sparse && want_data_stream) {
      memcpy(jcr->compress.inflate_buffer, *data, OFFSET_FADDR_SIZE);
   }

   *data = jcr->compress.inflate_buffer;
   *length = stream.total_out;
   Dmsg2(400, "Write uncompressed %d bytes, total before write=%s\n", *length, edit_uint64(jcr->JobBytes, ec1));
   fastlzlibDecompressEnd(&stream);

   return true;

cleanup:
   Qmsg(jcr, M_ERROR, 0, _("Uncompression error on file %s. ERR=%s\n"), last_fname, zlib_strerror(zstat));
   fastlzlibDecompressEnd(&stream);

   return false;
}
Exemple #29
0
static bool decompress_with_lzo(JCR *jcr,
                                const char *last_fname,
                                char **data,
                                uint32_t *length,
                                bool sparse,
                                bool want_data_stream)
{
   char ec1[50]; /* Buffer printing huge values */
   lzo_uint compress_len;
   const unsigned char *cbuf;
   unsigned char *wbuf;
   int status, real_compress_len;

   if (sparse && want_data_stream) {
      compress_len = jcr->compress.inflate_buffer_size - OFFSET_FADDR_SIZE;
      cbuf = (const unsigned char *)*data + OFFSET_FADDR_SIZE + sizeof(comp_stream_header);
      wbuf = (unsigned char *)jcr->compress.inflate_buffer + OFFSET_FADDR_SIZE;
   } else {
      compress_len = jcr->compress.inflate_buffer_size;
      cbuf = (const unsigned char *)*data + sizeof(comp_stream_header);
      wbuf = (unsigned char *)jcr->compress.inflate_buffer;
   }

   real_compress_len = *length - sizeof(comp_stream_header);
   Dmsg2(400, "Comp_len=%d msglen=%d\n", compress_len, *length);
   while ((status = lzo1x_decompress_safe(cbuf, real_compress_len, wbuf, &compress_len, NULL)) == LZO_E_OUTPUT_OVERRUN) {
      /*
       * The buffer size is too small, try with a bigger one
       */
      jcr->compress.inflate_buffer_size = jcr->compress.inflate_buffer_size + (jcr->compress.inflate_buffer_size >> 1);
      jcr->compress.inflate_buffer = check_pool_memory_size(jcr->compress.inflate_buffer, jcr->compress.inflate_buffer_size);

      if (sparse && want_data_stream) {
         compress_len = jcr->compress.inflate_buffer_size - OFFSET_FADDR_SIZE;
         wbuf = (unsigned char *)jcr->compress.inflate_buffer + OFFSET_FADDR_SIZE;
      } else {
         compress_len = jcr->compress.inflate_buffer_size;
         wbuf = (unsigned char *)jcr->compress.inflate_buffer;
      }
      Dmsg2(400, "Comp_len=%d msglen=%d\n", compress_len, *length);
   }

   if (status != LZO_E_OK) {
      Qmsg(jcr, M_ERROR, 0, _("LZO uncompression error on file %s. ERR=%d\n"), last_fname, status);
      return false;
   }

   /*
    * We return a decompressed data stream with the fileoffset encoded when this was a sparse stream.
    */
   if (sparse && want_data_stream) {
      memcpy(jcr->compress.inflate_buffer, *data, OFFSET_FADDR_SIZE);
   }

   *data = jcr->compress.inflate_buffer;
   *length = compress_len;

   Dmsg2(400, "Write uncompressed %d bytes, total before write=%s\n", compress_len, edit_uint64(jcr->JobBytes, ec1));

   return true;
}
Exemple #30
0
/*
 * Read the header record
 */
static bool read_header(DCR *dcr, DEV_BLOCK *block, DEV_RECORD *rec)
{
    ser_declare;
    uint32_t VolSessionId;
    uint32_t VolSessionTime;
    int32_t  FileIndex;
    int32_t  Stream;
    uint32_t rhl;
    char buf1[100], buf2[100];

    Dmsg0(dbgep, "=== rpath 1 read_header\n");
    /* Clear state flags */
    rec->state_bits = 0;
    if (block->dev->is_tape()) {
        rec->state_bits |= REC_ISTAPE;
    }
    rec->Block = ((DEVICE *)block->dev)->EndBlock;
    rec->File = ((DEVICE *)block->dev)->EndFile;

    /*
     * Get the header. There is always a full header,
     * otherwise we find it in the next block.
     */
    Dmsg3(read_dbglvl, "Block=%d Ver=%d block_len=%u\n",
          block->BlockNumber, block->BlockVer, block->block_len);
    if (block->BlockVer == 1) {
        rhl = RECHDR1_LENGTH;
    } else {
        rhl = RECHDR2_LENGTH;
    }
    if (rec->remlen >= rhl) {
        Dmsg0(dbgep, "=== rpath 2 begin unserial header\n");
        Dmsg4(read_dbglvl, "read_header: remlen=%d data_len=%d rem=%d blkver=%d\n",
              rec->remlen, rec->data_len, rec->remainder, block->BlockVer);

        unser_begin(block->bufp, WRITE_RECHDR_LENGTH);
        if (block->BlockVer == 1) {
            unser_uint32(VolSessionId);
            unser_uint32(VolSessionTime);
        } else {
            VolSessionId = block->VolSessionId;
            VolSessionTime = block->VolSessionTime;
        }
        unser_int32(FileIndex);
        unser_int32(Stream);
        unser_uint32(rec->data_bytes);

        block->bufp += rhl;
        block->binbuf -= rhl;
        rec->remlen -= rhl;

        /* If we are looking for more (remainder!=0), we reject anything
         *  where the VolSessionId and VolSessionTime don't agree
         */
        if (rec->remainder && (rec->VolSessionId != VolSessionId ||
                               rec->VolSessionTime != VolSessionTime)) {
            rec->state_bits |= REC_NO_MATCH;
            Dmsg0(read_dbglvl, "remainder and VolSession doesn't match\n");
            Dmsg0(dbgep, "=== rpath 4 VolSession no match\n");
            return false;             /* This is from some other Session */
        }

        /* if Stream is negative, it means that this is a continuation
         * of a previous partially written record.
         */
        if (Stream < 0) {               /* continuation record? */
            Dmsg0(dbgep, "=== rpath 5 negative stream\n");
            Dmsg1(read_dbglvl, "Got negative Stream => continuation. remainder=%d\n",
                  rec->remainder);
            rec->state_bits |= REC_CONTINUATION;
            if (!rec->remainder) {       /* if we didn't read previously */
                Dmsg0(dbgep, "=== rpath 6 no remainder\n");
                rec->data_len = 0;        /* return data as if no continuation */
            } else if (rec->Stream != -Stream) {
                Dmsg0(dbgep, "=== rpath 7 wrong cont stream\n");
                rec->state_bits |= REC_NO_MATCH;
                return false;             /* This is from some other Session */
            }
            rec->Stream = -Stream;       /* set correct Stream */
            rec->maskedStream = rec->Stream & STREAMMASK_TYPE;
        } else {                        /* Regular record */
            Dmsg0(dbgep, "=== rpath 8 normal stream\n");
            rec->Stream = Stream;
            rec->maskedStream = rec->Stream & STREAMMASK_TYPE;
            rec->data_len = 0;           /* transfer to beginning of data */
        }
        rec->VolSessionId = VolSessionId;
        rec->VolSessionTime = VolSessionTime;
        rec->FileIndex = FileIndex;
        if (FileIndex > 0) {
            Dmsg0(dbgep, "=== rpath 9 FileIndex>0\n");
            if (block->FirstIndex == 0) {
                Dmsg0(dbgep, "=== rpath 10 FirstIndex\n");
                block->FirstIndex = FileIndex;
            }
            block->LastIndex = rec->FileIndex;
        }

        Dmsg6(read_dbglvl, "read_header: FI=%s SessId=%d Strm=%s len=%u rec->remlen=%d data_len=%d\n",
              FI_to_ascii(buf1, rec->FileIndex), rec->VolSessionId,
              stream_to_ascii(buf2, rec->Stream, rec->FileIndex), rec->data_bytes, rec->remlen,
              rec->data_len);
    } else {
        Dmsg0(dbgep, "=== rpath 11a block out of records\n");
        /*
         * No more records in this block because the number
         * of remaining bytes are less than a record header
         * length, so return empty handed, but indicate that
         * he must read again. By returning, we allow the
         * higher level routine to fetch the next block and
         * then reread.
         */
        Dmsg0(read_dbglvl, "read_header: End of block\n");
        rec->state_bits |= (REC_NO_HEADER | REC_BLOCK_EMPTY);
        empty_block(block);                      /* mark block empty */
        return false;
    }

    /* Sanity check */
    if (rec->data_bytes >= MAX_BLOCK_LENGTH) {
        Dmsg0(dbgep, "=== rpath 11b maxlen too big\n");
        /*
         * Something is wrong, force read of next block, abort
         *   continuing with this block.
         */
        rec->state_bits |= (REC_NO_HEADER | REC_BLOCK_EMPTY);
        empty_block(block);
        Jmsg2(dcr->jcr, M_WARNING, 0, _("Sanity check failed. maxlen=%d datalen=%d. Block discarded.\n"),
              MAX_BLOCK_LENGTH, rec->data_bytes);
        return false;
    }

    rec->data = check_pool_memory_size(rec->data, rec->data_len+rec->data_bytes);
    rec->rstate = st_data;
    return true;
}