]> git.ipfire.org Git - thirdparty/bacula.git/commitdiff
Add Content preview to FileSet catalog record.
authorEric Bollengier <eric@baculasystems.com>
Mon, 12 Dec 2022 20:15:00 +0000 (21:15 +0100)
committerEric Bollengier <eric@baculasystems.com>
Thu, 14 Sep 2023 11:57:00 +0000 (13:57 +0200)
The FileSet catalog record is now created during the Director startup,
it was done during the Job creation.

The Content field will represent the FileSet overview.
If the FileSet has files and directories, it will contain "files"
If the FileSet has plugin entries, each plugin will be added to
the Content field.

Ex:
Content="files,mysql,postgresql"

13 files changed:
bacula/src/cats/cats.h
bacula/src/cats/make_mysql_tables.in
bacula/src/cats/make_postgresql_tables.in
bacula/src/cats/make_sqlite3_tables.in
bacula/src/cats/sql_create.c
bacula/src/cats/sql_get.c
bacula/src/cats/update_mysql_tables.in
bacula/src/cats/update_postgresql_tables.in
bacula/src/dird/dird.c
bacula/src/dird/job.c
bacula/src/dird/protos.h
bacula/updatedb/update_mysql_tables_1025_to_1026.in
bacula/updatedb/update_postgresql_tables_1025_to_1026.in

index 84c1650bea1782544630080973400f6a9eac9529..832c13b2799fe0473bc2a0966bb431d1b81f9d39 100644 (file)
@@ -536,6 +536,7 @@ struct FILESET_DBR {
    char FileSet[MAX_NAME_LENGTH];     /* FileSet name */
    char MD5[50];                      /* MD5 signature of include/exclude */
    time_t CreateTime;                 /* date created */
+   char Content[MAX_PLUGIN_LENGTH];   /* List of plugins in a fileset record */
    /*
     * This is where we return CreateTime
     */
index 5b29d08c5fa5d66e833cf5db60d4bdd56a11b6f2..31e19a06513cb9e1586b1bc02f56f1ac64b2355b 100644 (file)
@@ -396,6 +396,7 @@ CREATE TABLE FileSet (
    FileSet TINYBLOB NOT NULL,
    MD5 TINYBLOB,
    CreateTime DATETIME,
+   Content BLOB DEFAULT '',
    PRIMARY KEY(FileSetId)
    );
 
index 21d18550201b27d90657ae6cdf3c920ed5021842..ba1db462213140a7a8f0254522a0bdfa684f1bad 100644 (file)
@@ -329,6 +329,7 @@ CREATE TABLE fileset
     fileset          text        not null,
     md5              text        not null,
     createtime       timestamp without time zone not null,
+    content           text        default '',
     primary key (filesetid)
 );
 
index da019118f0b76fb4951133de6e6dc29412e149af..cf09c020338c74c06164d57794474e71ecd32d2d 100644 (file)
@@ -342,6 +342,7 @@ CREATE TABLE FileSet (
    FileSet VARCHAR(128) NOT NULL,
    MD5 VARCHAR(25) NOT NULL,
    CreateTime DATETIME DEFAULT 0,
+   Content TEXT DEFAULT '',
    PRIMARY KEY(FileSetId)
    );
 
index 4b7b8e0eac40cdaaa0c04f9729377d54313b3141..15cefb5d7e8896c5f3a983cebf6cd9912a0ac885 100644 (file)
@@ -733,13 +733,15 @@ bool BDB::bdb_create_fileset_record(JCR *jcr, FILESET_DBR *fsr)
    struct tm tm;
    char esc_fs[MAX_ESCAPE_NAME_LENGTH];
    char esc_md5[MAX_ESCAPE_NAME_LENGTH];
+   char esc_content[MAX_ESCAPE_PLUGIN_LENGTH];
 
    /* TODO: Escape FileSet and MD5 */
    bdb_lock();
    fsr->created = false;
    bdb_escape_string(jcr, esc_fs, fsr->FileSet, strlen(fsr->FileSet));
    bdb_escape_string(jcr, esc_md5, fsr->MD5, strlen(fsr->MD5));
-   Mmsg(cmd, "SELECT FileSetId,CreateTime FROM FileSet WHERE "
+   bdb_escape_string(jcr, esc_content, fsr->Content, strlen(fsr->Content));
+   Mmsg(cmd, "SELECT FileSetId,CreateTime,Content FROM FileSet WHERE "
                   "FileSet='%s' AND MD5='%s'", esc_fs, esc_md5);
 
    fsr->FileSetId = 0;
@@ -762,6 +764,17 @@ bool BDB::bdb_create_fileset_record(JCR *jcr, FILESET_DBR *fsr)
          } else {
             bstrncpy(fsr->cCreateTime, row[1], sizeof(fsr->cCreateTime));
          }
+         if ((row[2] == NULL || strcmp(row[2], "") == 0) && esc_content[0]) {
+            Mmsg(cmd, "UPDATE FileSet SET Content='%s' WHERE FileSetId=%ld",
+                 esc_content, fsr->FileSetId);
+            if (!UpdateDB(jcr, cmd, false /* should match*/)) {
+               /* If we cannot update, this is not the end of the world, but we
+                * can display a message
+                */
+               Dmsg2(50, "Unable to update FileSet content field for %ld ERR=%s\n",
+                     fsr->FileSetId, sql_strerror());
+            }
+         }
          sql_free_result();
          bdb_unlock();
          return true;
@@ -776,8 +789,8 @@ bool BDB::bdb_create_fileset_record(JCR *jcr, FILESET_DBR *fsr)
    strftime(fsr->cCreateTime, sizeof(fsr->cCreateTime), "%Y-%m-%d %H:%M:%S", &tm);
 
    /* Must create it */
-      Mmsg(cmd, "INSERT INTO FileSet (FileSet,MD5,CreateTime) "
-"VALUES ('%s','%s','%s')", esc_fs, esc_md5, fsr->cCreateTime);
+      Mmsg(cmd, "INSERT INTO FileSet (FileSet,MD5,CreateTime,Content) "
+           "VALUES ('%s','%s','%s','%s')", esc_fs, esc_md5, fsr->cCreateTime, esc_content);
 
    if ((fsr->FileSetId = sql_insert_autokey_record(cmd, NT_("FileSet"))) == 0) {
       Mmsg2(&errmsg, _("Create DB FileSet record %s failed. ERR=%s\n"),
index c7632431f48e2fa108a7d7811deaa7de2c1660c8..d2c4caaa9d592f76cc1fc4588980ed79b2bfa166 100644 (file)
@@ -1087,13 +1087,13 @@ int BDB::bdb_get_fileset_record(JCR *jcr, FILESET_DBR *fsr)
    bdb_lock();
    if (fsr->FileSetId != 0) {               /* find by id */
       Mmsg(cmd,
-           "SELECT FileSetId,FileSet,MD5,CreateTime FROM FileSet "
+           "SELECT FileSetId,FileSet,MD5,CreateTime,Content FROM FileSet "
            "WHERE FileSetId=%s",
            edit_int64(fsr->FileSetId, ed1));
    } else {                           /* find by name */
       bdb_escape_string(jcr, esc, fsr->FileSet, strlen(fsr->FileSet));
       Mmsg(cmd,
-           "SELECT FileSetId,FileSet,MD5,CreateTime FROM FileSet "
+           "SELECT FileSetId,FileSet,MD5,CreateTime,Content FROM FileSet "
            "WHERE FileSet='%s' ORDER BY CreateTime DESC LIMIT 1", esc);
    }
 
@@ -1111,6 +1111,7 @@ int BDB::bdb_get_fileset_record(JCR *jcr, FILESET_DBR *fsr)
          bstrncpy(fsr->FileSet, row[1]!=NULL?row[1]:"", sizeof(fsr->FileSet));
          bstrncpy(fsr->MD5, row[2]!=NULL?row[2]:"", sizeof(fsr->MD5));
          bstrncpy(fsr->cCreateTime, row[3]!=NULL?row[3]:"", sizeof(fsr->cCreateTime));
+         bstrncpy(fsr->Content, row[4]!=NULL?row[4]:"", sizeof(fsr->Content));
          stat = fsr->FileSetId;
       }
       sql_free_result();
index 0ab9f7d4c7a21ef963060eb101b2d567e8e6bd87..9c085b31f5b2ffd7f50fbfbc279ea1cd4e520aa8 100644 (file)
@@ -718,6 +718,9 @@ ALTER TABLE Object
     MODIFY COLUMN ObjectCategory BLOB;
     MODIFY COLUMN ObjectUUID BLOB;
 
+ALTER TABLE FileSet
+    ADD COLUMN Content BLOB DEFAULT '';
+
 ALTER TABLE Job
     ADD COLUMN RealStartTime DATETIME,
     ADD COLUMN isVirtualFull     TINYINT    default 0,
index 320fbf5ecee6b5317404037de66e8c7c7ab8e69d..10b880a7ac188d9ecf71590c1da2de7dda46e4d8 100644 (file)
@@ -762,6 +762,8 @@ ALTER TABLE Media ADD COLUMN Protected       smallint    default 0;
 ALTER TABLE Media ADD COLUMN UseProtect      smallint    default 0;
 ALTER TABLE Media ADD COLUMN VolEncrypted    smallint    default 0;
 
+ALTER TABLE FileSet ADD COLUMN Content    text    default '';
+
 INSERT INTO Events (EventsCode, EventsType, EventsTime, EventsDaemon, EventsSource, EventsRef, EventsText) VALUES
   ('DU0001', 'catalog_update', NOW(), '*SHELL*', 'update_bacula_tables', 'pid$$', 'Catalog schema was updated to 1026');
 UPDATE Version SET VersionId=1026;
index 6cd5318d21e7c79ec4ae6ed16a654813825e6cfa..79543fe6824bca8a8f970df95f12e4857631c272 100644 (file)
@@ -1757,6 +1757,37 @@ static bool check_catalog(cat_op mode)
             counter->CurrentValue = counter->MinValue;  /* default value */
          }
       }
+      /* Loop over all fileset, defining/updating them in each database */
+      FILESET *fs;
+      foreach_res(fs, R_FILESET) {
+         FILESET_DBR fsr;
+
+         bmemset(&fsr, 0, sizeof(FILESET_DBR));
+         bstrncpy(fsr.FileSet, fs->hdr.name, sizeof(fsr.FileSet));
+         if (fs->have_MD5) {
+            struct MD5Context md5c;
+            unsigned char digest[MD5HashSize];
+            memcpy(&md5c, &fs->md5c, sizeof(md5c));
+            MD5Final(digest, &md5c);
+            /*
+             * Keep the flag (last arg) set to false otherwise old FileSets will
+             * get new MD5 sums and the user will get Full backups on everything
+             */
+            bin_to_base64(fsr.MD5, sizeof(fsr.MD5), (char *)digest, MD5HashSize, false);
+            bstrncpy(fs->MD5, fsr.MD5, sizeof(fs->MD5));
+         }
+         /* Previously, the content of the fileset was not generated, so, if
+          * we have a fileset like that, we can update the record
+          */
+         if (!db_get_fileset_record(NULL, db, &fsr) || fsr.Content[0] == 0) {
+            fileset_get_content(&fsr, fs);
+            if (!db_create_fileset_record(NULL, db, &fsr)) {
+               Jmsg(NULL, M_FATAL, 0,
+                    _("Could not create FileSet \"%s\" record. ERR=%s\n"),
+                    fs->hdr.name, configfile);
+            }
+         }
+      }
       /* cleanup old job records */
       if (mode == UPDATE_AND_FIX) {
          alist events(100, not_owned_by_alist);
index a880717fa8a5726c2d10558163d426851264b822..d0b408054abc0be1678f6fde073b5133b662dbc8 100644 (file)
@@ -1389,13 +1389,96 @@ bool get_or_create_client_record(JCR *jcr)
    return true;
 }
 
+struct name_item
+{
+   rblink link;
+   char val[1];
+};
+
+static int my_strcmp(void *a, void *b)
+{
+   struct name_item *a1 = (struct name_item*)a;
+   struct name_item *b1 = (struct name_item*)b;
+   return strcmp(a1->val, b1->val);
+}
+
+/* Get the content overview of a FileSet */
+void fileset_get_content(FILESET_DBR *fdbr, FILESET *fileset)
+{
+   POOL_MEM tmp;
+   struct name_item *el = NULL;
+   bool files = false, first=true;
+   rblist c(el, &el->link);
+   regex_t r1;
+   regmatch_t pmatch[6];
+   /* We are looking for the plugin name, so basically Plugin = "mysql: options"
+    * Some plugins like Exchange have the interesting part inside the second part
+    */
+   regcomp(&r1, "^ *([a-zA-Z0-9-]+) *(: */@([A-Za-z]+))?", REG_EXTENDED);
+   for (int i=0; i<fileset->num_includes; i++) {
+      INCEXE *ie = fileset->include_items[i];
+
+      if (ie->name_list.size() > 0) {
+         files = true;
+      }
+      for (int j=0; j < ie->plugin_list.size(); j++) {
+         char *item = (char *)ie->plugin_list.get(j);
+         if (regexec(&r1, item, 5, pmatch, 0) == 0 &&
+             pmatch[1].rm_so >= 0 &&
+             pmatch[1].rm_eo > 0)
+         {
+            int l = pmatch[1].rm_eo - pmatch[1].rm_so + 1;
+            tmp.check_size(l+1);
+            bstrncpy(tmp.c_str(),
+                     item + pmatch[1].rm_so,
+                     l);
+
+            /* Special case for VSS plugins, the exact module is found in the
+             * second part
+             */
+            if (strcasecmp(tmp.c_str(), "vss") == 0 &&
+                pmatch[3].rm_so >= 0 &&
+                pmatch[3].rm_eo > 0)
+            {
+               //  vss -   SYSTEMSTATE                         \0
+               l = l + 1 + pmatch[3].rm_eo - pmatch[3].rm_so;
+               tmp.check_size(l+1);
+               bstrncat(tmp.c_str(), "-", l);
+               bstrncat(tmp.c_str(), item + pmatch[3].rm_so, l);
+            }
+
+            struct name_item *el2;
+            el = (struct name_item *) malloc(sizeof(struct name_item) + l + 1);
+            bstrncpy(el->val, tmp.c_str(), l);
+            el2 = (struct name_item *)c.insert(el, my_strcmp);
+            if (el2 != el) {
+               free(el);     // not inserted
+            }
+         }
+      }
+   }
+   pm_strcpy(tmp, "");
+   if (files) {
+      pm_strcpy(tmp, "files");
+      first=false;
+   }
+   foreach_rblist(el, &c) {
+      if (!first) {
+         pm_strcat(tmp, ",");
+      }
+      pm_strcat(tmp, el->val);
+      first = false;
+   }
+   bstrncpy(fdbr->Content, tmp.c_str(), sizeof(fdbr->Content));
+   regfree(&r1);
+}
+
 /*
  * Get or Create FileSet record
  */
 bool get_or_create_fileset_record(JCR *jcr)
 {
    FILESET_DBR fsr;
-
    bmemset(&fsr, 0, sizeof(FILESET_DBR));
    bstrncpy(fsr.FileSet, jcr->fileset->hdr.name, sizeof(fsr.FileSet));
    if (jcr->fileset->have_MD5) {
@@ -1414,7 +1497,10 @@ bool get_or_create_fileset_record(JCR *jcr)
       Jmsg(jcr, M_WARNING, 0, _("FileSet MD5 digest not found.\n"));
    }
    if (!jcr->fileset->ignore_fs_changes ||
-       !db_get_fileset_record(jcr, jcr->db, &fsr)) {
+       !db_get_fileset_record(jcr, jcr->db, &fsr))
+   {
+      /* Now we create the fileset at reload/startup, it should not happen */
+      fileset_get_content(&fsr, jcr->fileset);
       if (!db_create_fileset_record(jcr, jcr->db, &fsr)) {
          Jmsg(jcr, M_ERROR, 0, _("Could not create FileSet \"%s\" record. ERR=%s\n"),
             fsr.FileSet, db_strerror(jcr->db));
index 046686fec61c7e4563004aef8a34ff4ed479c506..4342653fef408b0be1ddc4d2269a300bb4f05871 100644 (file)
@@ -128,6 +128,7 @@ extern void set_jcr_defaults(JCR *jcr, JOB *job);
 extern void create_unique_job_name(JCR *jcr, const char *base_name);
 extern void update_job_end_record(JCR *jcr);
 extern bool get_or_create_client_record(JCR *jcr);
+extern void fileset_get_content(FILESET_DBR *fdbr, FILESET *fileset);
 extern bool get_or_create_fileset_record(JCR *jcr);
 extern DBId_t get_or_create_pool_record(JCR *jcr, char *pool_name);
 extern void apply_pool_overrides(JCR *jcr);
index cba15eddc8ab48452b09660735edfed109e31772..99574136825c305f68fcff31d56be10a9d86b8ca 100644 (file)
@@ -90,6 +90,9 @@ ALTER TABLE Object
     MODIFY COLUMN ObjectCategory BLOB;
     MODIFY COLUMN ObjectUUID BLOB;
 
+ALTER TABLE FileSet
+    ADD COLUMN Content BLOB DEFAULT '';
+
 ALTER TABLE Job
     ADD COLUMN RealStartTime DATETIME,
     ADD COLUMN isVirtualFull     TINYINT    default 0,
index 4fb563b8f7ede55ff2b648bd49c3959acaad97c0..5f9e27cb97bd6875d9d86af4d8b71c777613af7e 100644 (file)
@@ -69,6 +69,8 @@ ALTER TABLE Media ADD COLUMN Protected            smallint    default 0;
 ALTER TABLE Media ADD COLUMN UseProtect           smallint    default 0;
 ALTER TABLE Media ADD COLUMN VolEncrypted         smallint    default 0;
 
+ALTER TABLE FileSet ADD COLUMN Content    text    default '';
+
 INSERT INTO Events (EventsCode, EventsType, EventsTime, EventsDaemon, EventsSource, EventsRef, EventsText) VALUES
   ('DU0001', 'catalog_update', NOW(), '*SHELL*', 'update_bacula_tables', 'pid$$', 'Catalog schema was updated to 1026');
 UPDATE Version SET VersionId=1026;