/*
- Bacula® - The Network Backup Solution
-
- Copyright (C) 2002-2010 Free Software Foundation Europe e.V.
-
- The main author of Bacula is Kern Sibbald, with contributions from
- many others, a complete list can be found in the file AUTHORS.
- This program is Free Software; you can redistribute it and/or
- modify it under the terms of version three of the GNU Affero General Public
- License as published by the Free Software Foundation and included
- in the file LICENSE.
-
- This program is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- General Public License for more details.
-
- You should have received a copy of the GNU Affero General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
- 02110-1301, USA.
-
- Bacula® is a registered trademark of Kern Sibbald.
- The licensor of Bacula is the Free Software Foundation Europe
- (FSFE), Fiduciary Program, Sumatrastrasse 25, 8006 Zürich,
- Switzerland, email:ftf@fsfeurope.org.
+ Bacula(R) - The Network Backup Solution
+
+ Copyright (C) 2000-2017 Kern Sibbald
+
+ The original author of Bacula is Kern Sibbald, with contributions
+ from many others, a complete list can be found in the file AUTHORS.
+
+ You may use this file and others of this release according to the
+ license defined in the LICENSE file, which includes the Affero General
+ Public License, v3.0 ("AGPLv3") and some additional permissions and
+ terms pursuant to its AGPLv3 Section 7.
+
+ This notice must be preserved when any source code is
+ conveyed and/or propagated.
+
+ Bacula(R) is a registered trademark of Kern Sibbald.
*/
/*
- *
* Bacula Director -- User Agent Database restore Command
* Creates a bootstrap file for restoring files and
* starts the restore job.
extern void print_bsr(UAContext *ua, RBSR *bsr);
-
/* Forward referenced functions */
static int last_full_handler(void *ctx, int num_fields, char **row);
static int jobid_handler(void *ctx, int num_fields, char **row);
static void free_name_list(NAME_LIST *name_list);
static bool select_backups_before_date(UAContext *ua, RESTORE_CTX *rx, char *date);
static bool build_directory_tree(UAContext *ua, RESTORE_CTX *rx);
-static void free_rx(RESTORE_CTX *rx);
static void split_path_and_filename(UAContext *ua, RESTORE_CTX *rx, char *fname);
static int jobid_fileindex_handler(void *ctx, int num_fields, char **row);
static bool insert_file_into_findex_list(UAContext *ua, RESTORE_CTX *rx, char *file,
static int get_restore_client_name(UAContext *ua, RESTORE_CTX &rx);
static bool get_date(UAContext *ua, char *date, int date_len);
static int restore_count_handler(void *ctx, int num_fields, char **row);
-static bool insert_table_into_findex_list(UAContext *ua, RESTORE_CTX *rx, char *table);
static void get_and_display_basejobs(UAContext *ua, RESTORE_CTX *rx);
+void new_rx(RESTORE_CTX *rx)
+{
+ RBSR *bsr = NULL;
+ memset(rx, 0, sizeof(*rx));
+ rx->path = get_pool_memory(PM_FNAME);
+ rx->path[0] = 0;
+
+ rx->fname = get_pool_memory(PM_FNAME);
+ rx->fname[0] = 0;
+
+ rx->JobIds = get_pool_memory(PM_FNAME);
+ rx->JobIds[0] = 0;
+
+ rx->component_fname = get_pool_memory(PM_FNAME);
+ rx->component_fname[0] = 0;
+
+ rx->BaseJobIds = get_pool_memory(PM_FNAME);
+ rx->BaseJobIds[0] = 0;
+
+ rx->query = get_pool_memory(PM_FNAME);
+ rx->query[0] = 0;
+
+ rx->bsr_list = New(rblist(bsr, &bsr->link));
+ rx->hardlinks_in_mem = true;
+}
+
+
/*
* Restore files
*
char *strip_prefix, *add_prefix, *add_suffix, *regexp;
strip_prefix = add_prefix = add_suffix = regexp = NULL;
- memset(&rx, 0, sizeof(rx));
- rx.path = get_pool_memory(PM_FNAME);
- rx.fname = get_pool_memory(PM_FNAME);
- rx.JobIds = get_pool_memory(PM_FNAME);
- rx.JobIds[0] = 0;
- rx.BaseJobIds = get_pool_memory(PM_FNAME);
- rx.query = get_pool_memory(PM_FNAME);
- rx.bsr = new_bsr();
+ new_rx(&rx); /* Initialize RESTORE_CTX */
+
+ if (!open_new_client_db(ua)) {
+ goto bail_out;
+ }
- i = find_arg_with_value(ua, "comment");
- if (i >= 0) {
- rx.comment = ua->argv[i];
- if (!is_comment_legal(ua, rx.comment)) {
- goto bail_out;
+ for (i = 0; i < ua->argc ; i++) {
+ if (strcasecmp(ua->argk[i], "fdcalled") == 0) {
+ rx.fdcalled = true;
+
+ } else if (strcasecmp(ua->argk[i], "noautoparent") == 0) {
+ rx.no_auto_parent = true;
}
- }
+ if (!ua->argv[i]) {
+ continue; /* skip if no value given */
+ }
+ if (strcasecmp(ua->argk[i], "comment") == 0) {
+ rx.comment = ua->argv[i];
+ if (!is_comment_legal(ua, rx.comment)) {
+ goto bail_out;
+ }
- i = find_arg_with_value(ua, "where");
- if (i >= 0) {
- rx.where = ua->argv[i];
- }
+ } else if (strcasecmp(ua->argk[i], "where") == 0) {
+ rx.where = ua->argv[i];
- i = find_arg_with_value(ua, "strip_prefix");
- if (i >= 0) {
- strip_prefix = ua->argv[i];
- }
+ } else if (strcasecmp(ua->argk[i], "when") == 0) {
+ rx.when = ua->argv[i];
- i = find_arg_with_value(ua, "add_prefix");
- if (i >= 0) {
- add_prefix = ua->argv[i];
- }
+ } else if (strcasecmp(ua->argk[i], "replace") == 0) {
+ rx.replace = ua->argv[i];
- i = find_arg_with_value(ua, "add_suffix");
- if (i >= 0) {
- add_suffix = ua->argv[i];
- }
+ } else if (strcasecmp(ua->argk[i], "strip_prefix") == 0) {
+ strip_prefix = ua->argv[i];
- i = find_arg_with_value(ua, "regexwhere");
- if (i >= 0) {
- rx.RegexWhere = ua->argv[i];
+ } else if (strcasecmp(ua->argk[i], "add_prefix") == 0) {
+ add_prefix = ua->argv[i];
+
+ } else if (strcasecmp(ua->argk[i], "add_suffix") == 0) {
+ add_suffix = ua->argv[i];
+
+ } else if (strcasecmp(ua->argk[i], "regexwhere") == 0) {
+ rx.RegexWhere = ua->argv[i];
+
+ } else if (strcasecmp(ua->argk[i], "optimizespeed") == 0) {
+ if (strcasecmp(ua->argv[i], "0") || strcasecmp(ua->argv[i], "no") ||
+ strcasecmp(ua->argv[i], "false")) {
+ rx.hardlinks_in_mem = false;
+ }
+ }
}
if (strip_prefix || add_suffix || add_prefix) {
}
}
- if (!open_client_db(ua)) {
- goto bail_out;
- }
-
/* Ensure there is at least one Restore Job */
LockRes();
foreach_res(job, R_JOB) {
break;
}
- if (rx.bsr->JobId) {
+ if (rx.bsr_list->size() > 0) {
char ed1[50];
- if (!complete_bsr(ua, rx.bsr)) { /* find Vol, SessId, SessTime from JobIds */
+ if (!complete_bsr(ua, rx.bsr_list)) { /* find Vol, SessId, SessTime from JobIds */
ua->error_msg(_("Unable to construct a valid BSR. Cannot continue.\n"));
goto bail_out;
}
ua->warning_msg(_("No files selected to be restored.\n"));
goto bail_out;
}
+
+ ua->send_msg(_("Bootstrap records written to %s\n"), ua->jcr->RestoreBootstrap);
display_bsr_info(ua, rx); /* display vols needed, etc */
if (rx.selected_files==1) {
ua->info_msg(_("\n1 file selected to be restored.\n\n"));
} else {
- ua->info_msg(_("\n%s files selected to be restored.\n\n"),
+ ua->info_msg(_("\n%s files selected to be restored.\n\n"),
edit_uint64_with_commas(rx.selected_files, ed1));
}
} else {
if (rx.restore_jobs == 1) {
job = rx.restore_job;
} else {
- job = select_restore_job_resource(ua);
+ job = get_restore_job(ua);
}
if (!job) {
goto bail_out;
}
get_client_name(ua, &rx);
- if (!rx.ClientName) {
+ if (!rx.ClientName[0]) {
ua->error_msg(_("No Client resource found!\n"));
goto bail_out;
}
/* Build run command */
pm_strcpy(buf, "");
+ if (rx.RestoreMediaType[0]) {
+ Mmsg(buf, " mediatype=\"%s\"", rx.RestoreMediaType);
+ pm_strcat(ua->cmd, buf);
+ pm_strcpy(buf, "");
+ }
if (rx.RegexWhere) {
escaped_where_name = escape_filename(rx.RegexWhere);
- Mmsg(buf, " regexwhere=\"%s\"",
+ Mmsg(buf, " regexwhere=\"%s\"",
escaped_where_name ? escaped_where_name : rx.RegexWhere);
} else if (rx.where) {
escaped_where_name = escape_filename(rx.where);
- Mmsg(buf," where=\"%s\"",
+ Mmsg(buf," where=\"%s\"",
escaped_where_name ? escaped_where_name : rx.where);
}
pm_strcat(ua->cmd, buf);
+ if (rx.replace) {
+ Mmsg(buf, " replace=%s", rx.replace);
+ pm_strcat(ua->cmd, buf);
+ }
+
+ if (rx.fdcalled) {
+ pm_strcat(ua->cmd, " fdcalled=yes");
+ }
+
+ if (rx.when) {
+ Mmsg(buf, " when=\"%s\"", rx.when);
+ pm_strcat(ua->cmd, buf);
+ }
+
if (rx.comment) {
Mmsg(buf, " comment=\"%s\"", rx.comment);
pm_strcat(ua->cmd, buf);
if (escaped_where_name != NULL) {
bfree(escaped_where_name);
}
-
+
if (regexp) {
bfree(regexp);
}
pm_strcat(ua->cmd, " yes"); /* pass it on to the run command */
}
Dmsg1(200, "Submitting: %s\n", ua->cmd);
- /* Transfer jobids to jcr to for picking up restore objects */
+ /*
+ * Transfer jobids, component stuff to jcr to
+ * pass to run_cmd(). Note, these are fields and
+ * other things that are not passed on the command
+ * line.
+ */
+ /* ***FIXME*** pass jobids on command line */
+ if (jcr->JobIds) {
+ free_pool_memory(jcr->JobIds);
+ }
jcr->JobIds = rx.JobIds;
rx.JobIds = NULL;
+ jcr->component_fname = rx.component_fname;
+ rx.component_fname = NULL;
+ jcr->component_fd = rx.component_fd;
+ rx.component_fd = NULL;
parse_ua_args(ua);
run_cmd(ua, ua->cmd);
free_rx(&rx);
+ garbage_collect_memory(); /* release unused memory */
return 1;
bail_out:
bfree(regexp);
}
+ /* Free the plugin config if needed, we don't want to re-use
+ * this part of the next try
+ */
+ free_plugin_config_items(jcr->plugin_config);
+ jcr->plugin_config = NULL;
+
free_rx(&rx);
+ garbage_collect_memory(); /* release unused memory */
return 0;
}
-/*
+/*
* Fill the rx->BaseJobIds and display the list
*/
static void get_and_display_basejobs(UAContext *ua, RESTORE_CTX *rx)
if (!db_get_used_base_jobids(ua->jcr, ua->db, rx->JobIds, &jobids)) {
ua->warning_msg("%s", db_strerror(ua->db));
}
-
+
if (jobids.count) {
POOL_MEM q;
Mmsg(q, uar_print_jobs, jobids.list);
pm_strcpy(rx->BaseJobIds, jobids.list);
}
-static void free_rx(RESTORE_CTX *rx)
+void free_rx(RESTORE_CTX *rx)
{
- free_bsr(rx->bsr);
- rx->bsr = NULL;
+ free_bsr(rx->bsr_list);
+ rx->bsr_list = NULL;
free_and_null_pool_memory(rx->JobIds);
free_and_null_pool_memory(rx->BaseJobIds);
free_and_null_pool_memory(rx->fname);
free_and_null_pool_memory(rx->path);
free_and_null_pool_memory(rx->query);
+ if (rx->fileregex) {
+ free(rx->fileregex);
+ rx->fileregex = NULL;
+ }
+ if (rx->component_fd) {
+ fclose(rx->component_fd);
+ rx->component_fd = NULL;
+ }
+ if (rx->component_fname) {
+ unlink(rx->component_fname);
+ }
+ free_and_null_pool_memory(rx->component_fname);
free_name_list(&rx->name_list);
}
i = find_arg_with_value(ua, NT_("backupclient"));
}
if (i >= 0) {
- if (!has_value(ua, i)) {
+ if (!is_name_valid(ua->argv[i], &ua->errmsg)) {
+ ua->error_msg("%s argument: %s", ua->argk[i], ua->errmsg);
return 0;
}
bstrncpy(rx->ClientName, ua->argv[i], sizeof(rx->ClientName));
return 1;
}
memset(&cr, 0, sizeof(cr));
- if (!get_client_dbr(ua, &cr)) {
+ /* We want the name of the client where the backup was made */
+ if (!get_client_dbr(ua, &cr, JT_BACKUP_RESTORE)) {
return 0;
}
bstrncpy(rx->ClientName, cr.Name, sizeof(rx->ClientName));
static int get_restore_client_name(UAContext *ua, RESTORE_CTX &rx)
{
/* Start with same name as backup client */
- bstrncpy(rx.RestoreClientName, rx.ClientName, sizeof(rx.RestoreClientName));
+ bstrncpy(rx.RestoreClientName, rx.ClientName, sizeof(rx.RestoreClientName));
/* try command line argument */
int i = find_arg_with_value(ua, NT_("restoreclient"));
if (i >= 0) {
- if (!has_value(ua, i)) {
+ if (!is_name_valid(ua->argv[i], &ua->errmsg)) {
+ ua->error_msg("%s argument: %s", ua->argk[i], ua->errmsg);
return 0;
}
bstrncpy(rx.RestoreClientName, ua->argv[i], sizeof(rx.RestoreClientName));
"restoreclient", /* 19 */
"copies", /* 20 */
"comment", /* 21 */
+ "restorejob", /* 22 */
+ "replace", /* 23 */
+ "xxxxxxxxx", /* 24 */
+ "fdcalled", /* 25 */
+ "when", /* 26 */
+ "noautoparent", /* 27 */
NULL
};
break;
}
}
+
if (!found_kw) {
ua->error_msg(_("Unknown keyword: %s\n"), ua->argk[i]);
return 0;
len = strlen(ua->cmd);
fname = (char *)malloc(len * 2 + 1);
db_escape_string(ua->jcr, ua->db, fname, ua->cmd, len);
- Mmsg(rx->query, uar_file[db_type], rx->ClientName, fname);
+ Mmsg(rx->query, uar_file[db_get_type_index(ua->db)], rx->ClientName, fname);
free(fname);
gui_save = ua->jcr->gui;
ua->jcr->gui = true;
case 11: /* Choose a jobid and select jobs */
if (!get_cmd(ua, _("Enter JobId to get the state to restore: ")) ||
- !is_an_integer(ua->cmd))
+ !is_an_integer(ua->cmd))
{
return 0;
}
ua->send_msg(_("Selecting jobs to build the Full state at %s\n"),
jr.cStartTime);
jr.JobLevel = L_INCREMENTAL; /* Take Full+Diff+Incr */
- if (!db_accurate_get_jobids(ua->jcr, ua->db, &jr, &jobids)) {
+ if (!db_get_accurate_jobids(ua->jcr, ua->db, &jr, &jobids)) {
return 0;
}
pm_strcpy(rx->JobIds, jobids.list);
POOLMEM *JobIds = get_pool_memory(PM_FNAME);
*JobIds = 0;
rx->TotalFiles = 0;
- /*
+ /*
* Find total number of files to be restored, and filter the JobId
* list to contain only ones permitted by the ACL conditions.
*/
pm_strcat(JobIds, edit_int64(JobId, ed1));
rx->TotalFiles += jr.JobFiles;
}
- free_pool_memory(rx->JobIds);
- rx->JobIds = JobIds; /* Set ACL filtered list */
+ pm_strcpy(rx->JobIds, JobIds); /* Set ACL filtered list */
+ free_pool_memory(JobIds);
if (*rx->JobIds == 0) {
ua->warning_msg(_("No Jobs selected.\n"));
return 0;
switch (*p) {
case '<':
p++;
- if ((ffd = fopen(p, "rb")) == NULL) {
+ if ((ffd = bfopen(p, "rb")) == NULL) {
berrno be;
ua->error_msg(_("Cannot open file %s: ERR=%s\n"),
p, be.bstrerror());
strip_trailing_newline(file);
split_path_and_filename(ua, rx, file);
if (*rx->JobIds == 0) {
- Mmsg(rx->query, uar_jobid_fileindex, date, rx->path, rx->fname,
+ Mmsg(rx->query, uar_jobid_fileindex, date, rx->path, rx->fname,
rx->ClientName);
} else {
Mmsg(rx->query, uar_jobids_fileindex, rx->JobIds, date,
rx->path, rx->fname, rx->ClientName);
+ /*
+ * Note: we have just edited the JobIds into the query, so
+ * we need to clear JobIds, or they will be added
+ * back into JobIds with the query below, and then
+ * restored twice. Fixes bug #2212.
+ */
+ rx->JobIds[0] = 0;
}
rx->found = false;
/* Find and insert jobid and File Index */
*/
static bool insert_dir_into_findex_list(UAContext *ua, RESTORE_CTX *rx, char *dir,
char *date)
-{
+{
strip_trailing_junk(dir);
if (*rx->JobIds == 0) {
ua->error_msg(_("No JobId specified cannot continue.\n"));
return false;
} else {
- Mmsg(rx->query, uar_jobid_fileindex_from_dir[db_type], rx->JobIds, dir, rx->ClientName);
+ Mmsg(rx->query, uar_jobid_fileindex_from_dir[db_get_type_index(ua->db)], rx->JobIds, dir, rx->ClientName);
}
rx->found = false;
/* Find and insert jobid and File Index */
/*
* Get the JobId and FileIndexes of all files in the specified table
*/
-static bool insert_table_into_findex_list(UAContext *ua, RESTORE_CTX *rx, char *table)
+bool insert_table_into_findex_list(UAContext *ua, RESTORE_CTX *rx, char *table)
{
strip_trailing_junk(table);
Mmsg(rx->query, uar_jobid_fileindex_from_table, table);
Dmsg2(100, "split path=%s file=%s\n", rx->path, rx->fname);
}
+static bool can_restore_all_files(UAContext *ua)
+{
+ alist *lst;
+ if (ua->cons) {
+ lst = ua->cons->ACL_lists[Directory_ACL];
+ /* ACL not defined, or the first entry is not *all* */
+ /* TODO: See if we search for *all* in all the list */
+ if (!lst || strcasecmp((char*)lst->get(0), "*all*") != 0) {
+ return false;
+ }
+ if (!lst || strcasecmp((char *)lst->get(0), "*all*") != 0) {
+ return false;
+ }
+ }
+ return true;
+}
+
static bool ask_for_fileregex(UAContext *ua, RESTORE_CTX *rx)
{
- if (find_arg(ua, NT_("all")) >= 0) { /* if user enters all on command line */
+ bool can_restore=can_restore_all_files(ua);
+
+ if (can_restore && find_arg(ua, NT_("all")) >= 0) { /* if user enters all on command line */
return true; /* select everything */
}
+
ua->send_msg(_("\n\nFor one or more of the JobIds selected, no files were found,\n"
"so file selection is not possible.\n"
"Most likely your retention policy pruned the files.\n"));
+
+ if (!can_restore) {
+ ua->error_msg(_("\nThe current Console has UserId or Directory restrictions. "
+ "The full restore is not allowed.\n"));
+ return false;
+ }
+
if (get_yesno(ua, _("\nDo you want to restore all the files? (yes|no): "))) {
if (ua->pint32_val == 1)
return true;
if (*errmsg) {
ua->send_msg(_("Regex compile error: %s\n"), errmsg);
} else {
- rx->bsr->fileregex = bstrdup(ua->cmd);
+ rx->fileregex = bstrdup(ua->cmd);
return true;
}
}
if (lst->next) {
add_delta_list_findex(rx, lst->next);
}
- add_findex(rx->bsr, lst->JobId, lst->FileIndex);
+ add_findex(rx->bsr_list, lst->JobId, lst->FileIndex);
+}
+
+/*
+ * This is a list of all the files (components) that the
+ * user has requested for restore. It is requested by
+ * the plugin (for now hard coded only for VSS).
+ * In the future, this will be requested by a RestoreObject
+ * and the plugin name will be sent to the FD.
+ */
+static bool write_component_file(UAContext *ua, RESTORE_CTX *rx, char *fname)
+{
+ int fd;
+ if (!rx->component_fd) {
+ Mmsg(rx->component_fname, "%s/%s.restore.sel.XXXXXX", working_directory, my_name);
+ fd = mkstemp(rx->component_fname);
+ if (fd < 0) {
+ berrno be;
+ ua->error_msg(_("Unable to create component file %s. ERR=%s\n"),
+ rx->component_fname, be.bstrerror());
+ return false;
+ }
+ rx->component_fd = fdopen(fd, "w+");
+ if (!rx->component_fd) {
+ berrno be;
+ ua->error_msg(_("Unable to fdopen component file %s. ERR=%s\n"),
+ rx->component_fname, be.bstrerror());
+ return false;
+ }
+ }
+ fprintf(rx->component_fd, "%s\n", fname);
+ if (ferror(rx->component_fd)) {
+ ua->error_msg(_("Error writing component file.\n"));
+ fclose(rx->component_fd);
+ unlink(rx->component_fname);
+ rx->component_fd = NULL;
+ return false;
+ }
+ return true;
}
static bool build_directory_tree(UAContext *ua, RESTORE_CTX *rx)
tree.root = new_tree(rx->TotalFiles);
tree.ua = ua;
tree.all = rx->all;
+ tree.hardlinks_in_mem = rx->hardlinks_in_mem;
+ tree.no_auto_parent = rx->no_auto_parent;
last_JobId = 0;
+ tree.last_dir_acl = NULL;
/*
* For display purposes, the same JobId, with different volumes may
* appear more than once, however, we only insert it once.
#define new_get_file_list
#ifdef new_get_file_list
- if (!db_get_file_list(ua->jcr, ua->db,
- rx->JobIds, false /* do not use md5 */,
+ if (!db_get_file_list(ua->jcr, ua->db,
+ rx->JobIds, false /* do not use md5 */,
true /* get delta */,
insert_tree_handler, (void *)&tree))
{
}
}
#endif
+ /*
+ * At this point, the tree is built, so we can garbage collect
+ * any memory released by the SQL engine that RedHat has
+ * not returned to the OS :-(
+ */
+ garbage_collect_memory();
+
/*
* Look at the first JobId on the list (presumably the oldest) and
* if it is marked purged, don't do the manual selection because
if (JobId == last_JobId) {
continue; /* eliminate duplicate JobIds */
}
- add_findex_all(rx->bsr, JobId);
+ add_findex_all(rx->bsr_list, JobId, rx->fileregex);
}
}
} else {
* extracted making a bootstrap file.
*/
if (OK) {
+ char cwd[2000];
for (TREE_NODE *node=first_tree_node(tree.root); node; node=next_tree_node(node)) {
Dmsg2(400, "FI=%d node=0x%x\n", node->FileIndex, node);
if (node->extract || node->extract_dir) {
Dmsg3(400, "JobId=%lld type=%d FI=%d\n", (uint64_t)node->JobId, node->type, node->FileIndex);
/* TODO: optimize bsr insertion when jobid are non sorted */
add_delta_list_findex(rx, node->delta_list);
- add_findex(rx->bsr, node->JobId, node->FileIndex);
+ add_findex(rx->bsr_list, node->JobId, node->FileIndex);
+ /*
+ * Special VSS plugin code to return selected
+ * components. For the moment, it is hard coded
+ * for the VSS plugin.
+ */
+ if (fnmatch(":component_info_*", node->fname, 0) == 0) {
+ tree_getpath(node, cwd, sizeof(cwd));
+ if (!write_component_file(ua, rx, cwd)) {
+ OK = false;
+ break;
+ }
+ }
if (node->extract && node->type != TN_NEWDIR) {
rx->selected_files++; /* count only saved files */
}
}
}
}
-
+ if (tree.uid_acl) {
+ delete tree.uid_acl;
+ delete tree.gid_acl;
+ delete tree.dir_acl;
+ }
free_tree(tree.root); /* free the directory tree */
return OK;
}
int i;
/* Create temp tables */
- db_sql_query(ua->db, uar_del_temp, NULL, NULL);
- db_sql_query(ua->db, uar_del_temp1, NULL, NULL);
- if (!db_sql_query(ua->db, uar_create_temp[db_type], NULL, NULL)) {
+ db_sql_query(ua->db, uar_del_temp, NULL, NULL);
+ db_sql_query(ua->db, uar_del_temp1, NULL, NULL);
+ if (!db_sql_query(ua->db, uar_create_temp[db_get_type_index(ua->db)], NULL, NULL)) {
ua->error_msg("%s\n", db_strerror(ua->db));
}
- if (!db_sql_query(ua->db, uar_create_temp1[db_type], NULL, NULL)) {
+ if (!db_sql_query(ua->db, uar_create_temp1[db_get_type_index(ua->db)], NULL, NULL)) {
ua->error_msg("%s\n", db_strerror(ua->db));
}
/*
* Select Client from the Catalog
*/
memset(&cr, 0, sizeof(cr));
- if (!get_client_dbr(ua, &cr)) {
+ if (!get_client_dbr(ua, &cr, JT_BACKUP_RESTORE)) {
goto bail_out;
}
bstrncpy(rx->ClientName, cr.Name, sizeof(rx->ClientName));
*/
memset(&fsr, 0, sizeof(fsr));
i = find_arg_with_value(ua, "FileSet");
- if (i >= 0) {
+
+ if (i >= 0 && is_name_valid(ua->argv[i], &ua->errmsg)) {
bstrncpy(fsr.FileSet, ua->argv[i], sizeof(fsr.FileSet));
if (!db_get_fileset_record(ua->jcr, ua->db, &fsr)) {
ua->error_msg(_("Error getting FileSet \"%s\": ERR=%s\n"), fsr.FileSet,
db_strerror(ua->db));
i = -1;
}
+ } else if (i >= 0) { /* name is invalid */
+ ua->error_msg(_("FileSet argument: %s\n"), ua->errmsg);
}
+
if (i < 0) { /* fileset not found */
edit_int64(cr.ClientId, ed1);
Mmsg(rx->query, uar_sel_fileset, ed1, ed1);
memset(&pr, 0, sizeof(pr));
bstrncpy(pr.Name, rx->pool->name(), sizeof(pr.Name));
if (db_get_pool_record(ua->jcr, ua->db, &pr)) {
- bsnprintf(pool_select, sizeof(pool_select), "AND Media.PoolId=%s ",
+ bsnprintf(pool_select, sizeof(pool_select), "AND Media.PoolId=%s ",
edit_int64(pr.PoolId, ed1));
} else {
ua->warning_msg(_("Pool \"%s\" not found, using any pool.\n"), pr.Name);
if (rx->JobIds[0] != 0) {
if (find_arg(ua, NT_("copies")) > 0) {
/* Display a list of all copies */
- db_list_copies_records(ua->jcr, ua->db, 0, rx->JobIds,
+ db_list_copies_records(ua->jcr, ua->db, 0, rx->JobIds,
prtit, ua, HORZ_LIST);
}
/* Display a list of Jobs selected for this restore */
}
bail_out:
- db_sql_query(ua->db, uar_del_temp, NULL, NULL);
- db_sql_query(ua->db, uar_del_temp1, NULL, NULL);
+ db_sql_query(ua->db, uar_del_temp, NULL, NULL);
+ db_sql_query(ua->db, uar_del_temp1, NULL, NULL);
return ok;
}
static int jobid_fileindex_handler(void *ctx, int num_fields, char **row)
{
RESTORE_CTX *rx = (RESTORE_CTX *)ctx;
+ JobId_t JobId = str_to_int64(row[0]);
- Dmsg2(200, "JobId=%s FileIndex=%s\n", row[0], row[1]);
- rx->JobId = str_to_int64(row[0]);
- add_findex(rx->bsr, rx->JobId, str_to_int64(row[1]));
+ Dmsg3(200, "JobId=%s JobIds=%s FileIndex=%s\n", row[0], rx->JobIds, row[1]);
+
+ /* New JobId, add it to JobIds
+ * The list is sorted by JobId, so we need a cache for the previous value
+ *
+ * It will permit to find restore objects to send during the restore
+ */
+ if (rx->JobId != JobId) {
+ if (*rx->JobIds) {
+ pm_strcat(rx->JobIds, ",");
+ }
+ pm_strcat(rx->JobIds, row[0]);
+ rx->JobId = JobId;
+ }
+
+ add_findex(rx->bsr_list, rx->JobId, str_to_int64(row[1]));
rx->found = true;
rx->selected_files++;
return 0;
name_list->num_ids = 0;
}
-void find_storage_resource(UAContext *ua, RESTORE_CTX &rx, char *Storage, char *MediaType)
+void find_storage_resource(UAContext *ua, RESTORE_CTX &rx, char *Storage, char *MediaType)
{
STORE *store;
}
}
if (store && (store != rx.store)) {
- ua->info_msg(_("Warning default storage overridden by \"%s\" on command line.\n"),
+ ua->info_msg(_("\nWarning Storage is overridden by \"%s\" on the command line.\n"),
store->name());
rx.store = store;
- Dmsg1(200, "Set store=%s\n", rx.store->name());
+ bstrncpy(rx.RestoreMediaType, MediaType, sizeof(rx.RestoreMediaType));
+ if (strcmp(MediaType, store->media_type) != 0) {
+ ua->info_msg(_("This may not work because of two different MediaTypes:\n"
+ " Storage MediaType=\"%s\"\n"
+ " Volume MediaType=\"%s\".\n\n"),
+ store->media_type, MediaType);
+ }
+ Dmsg2(200, "Set store=%s MediaType=%s\n", rx.store->name(), rx.RestoreMediaType);
}
return;
}
if (acl_access_ok(ua, Storage_ACL, store->name())) {
rx.store = store;
Dmsg1(200, "Set store=%s\n", rx.store->name());
- ua->warning_msg(_("Storage \"%s\" not found, using Storage \"%s\" from MediaType \"%s\".\n"),
- Storage, store->name(), MediaType);
+ if (Storage == NULL || Storage[0] == 0) {
+ ua->warning_msg(_("Using Storage \"%s\" from MediaType \"%s\".\n"),
+ store->name(), MediaType);
+ } else {
+ ua->warning_msg(_("Storage \"%s\" not found, using Storage \"%s\" from MediaType \"%s\".\n"),
+ Storage, store->name(), MediaType);
+ }
}
UnlockRes();
return;