]> git.sur5r.net Git - bacula/bacula/commitdiff
Add .bvfs_restore command
authorEric Bollengier <eric@eb.homelinux.org>
Sun, 3 Oct 2010 20:48:03 +0000 (22:48 +0200)
committerEric Bollengier <eric@eb.homelinux.org>
Wed, 6 Oct 2010 09:11:08 +0000 (11:11 +0200)
bacula/src/cats/bvfs.c
bacula/src/cats/bvfs.h
bacula/src/dird/ua_dotcmds.c

index cc00ca2bf3406eb601b51fe953fa324c974ab049..272c5dbcafac1b7416b5272361c687e36976f8fd 100644 (file)
@@ -327,7 +327,8 @@ static void update_path_hierarchy_cache(JCR *jcr,
       }
       free(result);
    }
-   
+
+   /* TODO: Add Path for BaseJobs */
    Mmsg(mdb->cmd, 
   "INSERT INTO PathVisibility (PathId, JobId)  "
    "SELECT a.PathId,%s "
@@ -706,3 +707,199 @@ bool Bvfs::ls_files()
 
    return nb_record == limit;
 }
+
+
+/* 
+ * Return next Id from comma separated list   
+ *
+ * Returns:
+ *   1 if next Id returned
+ *   0 if no more Ids are in list
+ *  -1 there is an error
+ * TODO: merge with get_next_jobid_from_list() and get_next_dbid_from_list()
+ */
+static int get_next_id_from_list(char **p, int64_t *Id)
+{
+   const int maxlen = 30;
+   char id[maxlen+1];
+   char *q = *p;
+
+   id[0] = 0;
+   for (int i=0; i<maxlen; i++) {
+      if (*q == 0) {
+         break;
+      } else if (*q == ',') {
+         q++;
+         break;
+      }
+      id[i] = *q++;
+      id[i+1] = 0;
+   }
+   if (id[0] == 0) {
+      return 0;
+   } else if (!is_a_number(id)) {
+      return -1;                      /* error */
+   }
+   *p = q;
+   *Id = str_to_int64(id);
+   return 1;
+}
+
+static int get_path_handler(void *ctx, int fields, char **row)
+{
+   POOL_MEM *buf = (POOL_MEM *) ctx;
+   pm_strcpy(*buf, row[0]);
+   return 0;
+}
+
+static bool check_temp(char *output_table)
+{
+   if (output_table[0] == 'b' &&
+       output_table[1] == '2' &&
+       is_an_integer(output_table + 2))
+   {
+      return true;
+   }
+   return false;
+}
+
+bool Bvfs::drop_restore_list(char *output_table)
+{
+   POOL_MEM query;
+   if (check_temp(output_table)) {
+      Mmsg(query, "DROP TABLE %s", output_table);
+      db_sql_query(db, query.c_str(), NULL, NULL);
+      return true;
+   }
+   return false;
+}
+
+bool Bvfs::compute_restore_list(char *fileid, char *dirid, char *hardlink, 
+                                char *output_table)
+{
+   POOL_MEM query;
+   POOL_MEM tmp, tmp2;
+   int64_t id, jobid;
+   bool init=false;
+   bool ret=false;
+   /* check args */
+   if ((*fileid   && !is_a_number_list(fileid))  ||
+       (*dirid    && !is_a_number_list(dirid))   ||
+       (*hardlink && !is_a_number_list(hardlink))||
+       (!*hardlink && !*fileid && !*dirid && !*hardlink))
+   {
+      return false;
+   }
+   if (!check_temp(output_table)) {
+      return false;
+   }
+
+   Mmsg(query, "CREATE TEMPORARY TABLE btemp%s AS ", output_table);
+
+   if (*fileid) {
+      init=true;
+      Mmsg(tmp, "(SELECT JobId, FileIndex, FilenameId, PathId, FileId "
+                   "FROM File WHERE FileId IN (%s))", fileid);
+      pm_strcat(query, tmp.c_str());
+   }
+
+   while (get_next_id_from_list(&dirid, &id) == 1) {
+      Mmsg(tmp, "SELECT Path FROM Path WHERE PathId=%lld", id);
+      
+      if (!db_sql_query(db, tmp.c_str(), get_path_handler, (void *)&tmp2)) {
+         /* print error */
+         return false;
+      }
+      if (!strcmp(tmp2.c_str(), "")) { /* path not found */
+         Dmsg3(0, "Path not found %lld q=%s s=%s\n",
+               id, tmp.c_str(), tmp2.c_str());
+         break;
+      }
+      /* escape % and _ for LIKE search */
+      tmp.check_size((strlen(tmp2.c_str())+1) * 2);
+      char *p = tmp.c_str();
+      for (char *s = tmp2.c_str(); *s ; s++) {
+         if (*s == '%' || *s == '_' || *s == '\\') {
+            *p = '\\'; 
+            p++;
+         }
+         *p = *s; 
+         p++;
+      }
+      *p = '\0';
+      tmp.strcat("%");
+
+      size_t len = strlen(tmp.c_str());
+      tmp2.check_size((len+1) * 2);
+      db_escape_string(jcr, db, tmp2.c_str(), tmp.c_str(), len);
+
+      if (init) {
+         query.strcat(" UNION ");
+      }
+      Mmsg(tmp, "(SELECT File.JobId, File.FileIndex, File.FilenameId, "
+                        "File.PathId, FileId "
+                   "FROM Path JOIN File USING (PathId) "
+                  "WHERE Path.Path LIKE '%s' AND File.JobId IN (%s)) ", 
+           tmp2.c_str(), jobids); 
+      query.strcat(tmp.c_str());
+      init = true;
+   }
+
+   /* expect jobid,fileindex */
+   int64_t prev_jobid=0;
+   while (get_next_id_from_list(&hardlink, &jobid) == 1) {
+      if (get_next_id_from_list(&hardlink, &id) != 1) {
+         return false;
+      }
+      if (jobid != prev_jobid) { /* new job */
+         if (prev_jobid == 0) {  /* first jobid */
+            if (init) {
+               query.strcat(" UNION ");
+            }
+         } else {               /* end last job, start new one */
+            tmp.strcat(")) UNION ");
+            query.strcat(tmp.c_str());
+         }
+         Mmsg(tmp, "(SELECT JobId, FileIndex, FilenameId, PathId, FileId "
+                       "FROM File WHERE JobId = %lld " 
+                        "AND FileIndex IN (%lld", jobid, id);
+         prev_jobid = jobid;
+
+      } else {                  /* same job, add new findex */
+         Mmsg(tmp2, ", %lld", id);
+         tmp.strcat(tmp2.c_str());
+      }
+   }
+
+   if (prev_jobid != 0) {       /* end last job */
+      tmp.strcat(")) ");
+      query.strcat(tmp.c_str());
+      init = true;
+   }
+
+   Dmsg1(0, "q=%s\n", query.c_str());
+
+   if (!db_sql_query(db, query.c_str(), NULL, NULL)) {
+      goto bail_out;
+   }
+
+   Mmsg(query, "CREATE TABLE %s AS ( "
+        "SELECT JobId, FileIndex, FileId "
+          "FROM ( "
+     "SELECT DISTINCT ON (PathId, FilenameId) JobId, FileIndex, FileId "
+       "FROM btemp%s "
+      "ORDER BY PathId, FilenameId, JobId DESC "
+          ") AS T "
+          "WHERE FileIndex > 0)", output_table, output_table);
+
+   Dmsg1(0, "q=%s\n", query.c_str());
+   if (!db_sql_query(db, query.c_str(), NULL, NULL)) {
+      goto bail_out;
+   }
+   ret = true;
+
+bail_out:
+   Mmsg(query, "DROP TABLE btemp%s", output_table);
+   db_sql_query(db, query.c_str(), NULL, NULL);
+   return ret;
+}
index fa4f6c2f53204c73515a048b8a4fc52781a85e97..5ed5ea58c5f74cf6ac4b80e8f6a9e70855862c4f 100644 (file)
@@ -150,6 +150,13 @@ public:
       offset+=limit;
    }
 
+   /* Compute restore list */
+   bool compute_restore_list(char *fileid, char *dirid, char *hardlink, 
+                             char *output_table);
+   
+   /* Drop previous restore list */
+   bool drop_restore_list(char *output_table);
+
    /* for internal use */
    int _handle_path(void *, int, char **);
    
index dc119285c0f42b68661bdd8d12aa3b6318b15786..e479d97b72e7271ecde58c802528ef420c4fa15f 100644 (file)
@@ -75,7 +75,8 @@ static bool dot_bvfs_lsfiles(UAContext *ua, const char *cmd);
 static bool dot_bvfs_update(UAContext *ua, const char *cmd);
 static bool dot_bvfs_get_jobids(UAContext *ua, const char *cmd);
 static bool dot_bvfs_versions(UAContext *ua, const char *cmd);
-static bool dot_bvfs_get_path(UAContext *ua, const char *cmd);
+static bool dot_bvfs_restore(UAContext *ua, const char *cmd);
+static bool dot_bvfs_cleanup(UAContext *ua, const char *cmd);
 
 static bool api_cmd(UAContext *ua, const char *cmd);
 static bool sql_cmd(UAContext *ua, const char *cmd);
@@ -113,7 +114,8 @@ static struct cmdstruct commands[] = { /* help */  /* can be used in runscript *
  { NT_(".bvfs_update"), dot_bvfs_update,         NULL,       true},
  { NT_(".bvfs_get_jobids"), dot_bvfs_get_jobids, NULL,       true},
  { NT_(".bvfs_versions"), dot_bvfs_versions,     NULL,       true},
- { NT_(".bvfs_get_path"), dot_bvfs_get_path,     NULL,       true},
+ { NT_(".bvfs_restore"), dot_bvfs_restore,       NULL,       true},
+ { NT_(".bvfs_cleanup"), dot_bvfs_cleanup,       NULL,       true},
  { NT_(".types"),      typescmd,                 NULL,       false}
              };
 #define comsize ((int)(sizeof(commands)/sizeof(struct cmdstruct)))
@@ -318,29 +320,54 @@ static bool bvfs_parse_arg(UAContext *ua,
    return true;
 }
 
-/* .bvfs_get_path pathid=10
- *   -> /etc/
+/* .bvfs_cleanup path=b2XXXXX
  */
-static bool dot_bvfs_get_path(UAContext *ua, const char *cmd)
+static bool dot_bvfs_cleanup(UAContext *ua, const char *cmd)
 {
-   char buf[128];
-   int i = find_arg_with_value(ua, NT_("pathid"));
-   if (!open_client_db(ua)) {
-      return false;
+   int i;
+   if ((i = find_arg_with_value(ua, "path")) >= 0) {
+      open_client_db(ua);
+      Bvfs fs(ua->jcr, ua->db);
+      fs.drop_restore_list(ua->argv[i]);
    }
-   if (i >= 0) {
-      if (is_a_number(ua->argv[i])) {
-         bsnprintf(buf, sizeof(buf), "SELECT Path FROM Path WHERE PathId=%lld", 
-                   str_to_int64(ua->argv[i]));
+   return true;
+}
 
-         if (!db_sql_query(ua->db, buf, one_handler, (void *)ua))
-         {
-            ua->error_msg("Can't find pathid\n");
-            /* print error */
-         }
-      }
+/* .bvfs_restore path=b2XXXXX jobid=1,2 fileid=1,2 dirid=1,2 hardlink=1,2,3,4
+ */
+static bool dot_bvfs_restore(UAContext *ua, const char *cmd)
+{
+   DBId_t pathid=0;
+   int limit=2000, offset=0, i;
+   char *path=NULL, *jobid=NULL;
+   char *empty = (char *)"";
+   char *fileid, *dirid, *hardlink, *id;
+   id = fileid = dirid = hardlink = empty;
+
+   if (!bvfs_parse_arg(ua, &pathid, &path, &jobid,
+                       &limit, &offset))
+   {
+      ua->error_msg("Can't find jobid, pathid or path argument\n");
+      return true;              /* not enough param */
+   }
+
+   Bvfs fs(ua->jcr, ua->db);
+   fs.set_jobids(jobid);
+
+   if ((i = find_arg_with_value(ua, "fileid")) >= 0) {
+      fileid = ua->argv[i];
+   }
+   if ((i = find_arg_with_value(ua, "dirid")) >= 0) {
+      dirid = ua->argv[i];
+   }
+   if ((i = find_arg_with_value(ua, "hardlink")) >= 0) {
+      hardlink = ua->argv[i];
+   }
+
+   if (fs.compute_restore_list(fileid, dirid, hardlink, path)) {
+      ua->send_msg("OK\n");
    } else {
-      ua->error_msg("Can't find pathid=\n");
+      ua->error_msg("Can't create restore list\n");
    }
    return true;
 }