/*
Bacula® - The Network Backup Solution
- Copyright (C) 2009-2009 Free Software Foundation Europe e.V.
+ Copyright (C) 2009-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 two of the GNU General Public
+ modify it under the terms of version three of the GNU Affero General Public
License as published by the Free Software Foundation, which is
listed in the file LICENSE.
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 General Public License
+ 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.
pattern = get_pool_memory(PM_NAME);
*jobids = *prev_dir = *pattern = 0;
dir_filenameid = pwd_id = offset = 0;
- see_copies = see_all_version = false;
+ see_copies = see_all_versions = false;
limit = 1000;
attr = new_attr(jcr);
list_entries = result_handler;
hlink *nodes;
int nb_node;
int max_node;
+
+ alist *table_node;
+
htable *cache_ppathid;
public:
max_node = NITEMS;
nodes = (hlink *) malloc(max_node * sizeof (hlink));
nb_node = 0;
+ table_node = New(alist(5, owned_by_alist));
+ table_node->append(nodes);
}
hlink *get_hlink() {
- if (nb_node >= max_node) {
- max_node *= 2;
- nodes = (hlink *)brealloc(nodes, sizeof(hlink) * max_node);
+ if (++nb_node >= max_node) {
+ nb_node = 0;
+ nodes = (hlink *)malloc(max_node * sizeof(hlink));
+ table_node->append(nodes);
}
- return nodes + nb_node++;
+ return nodes + nb_node;
}
bool lookup(char *pathid) {
~pathid_cache() {
cache_ppathid->destroy();
free(cache_ppathid);
- free(nodes);
+ delete table_node;
}
private:
pathid_cache(const pathid_cache &); /* prohibit pass by value */
/* Inserting path records for JobId */
Mmsg(mdb->cmd, "INSERT INTO PathVisibility (PathId, JobId) "
- "SELECT DISTINCT PathId, JobId FROM File WHERE JobId = %s",
- jobid);
+ "SELECT DISTINCT PathId, JobId "
+ "FROM (SELECT PathId, JobId FROM File WHERE JobId = %s "
+ "UNION "
+ "SELECT PathId, BaseFiles.JobId FROM BaseFiles JOIN File AS F USING (FileId) "
+ "WHERE BaseFiles.JobId = %s) AS B",
+ jobid, jobid);
QUERY_DB(jcr, mdb, mdb->cmd);
-
/* Now we have to do the directory recursion stuff to determine missing
* visibility We try to avoid recursion, to be as fast as possible We also
* only work on not allready hierarchised directories...
}
free(result);
}
-
+
Mmsg(mdb->cmd,
"INSERT INTO PathVisibility (PathId, JobId) "
"SELECT a.PathId,%s "
Mmsg(mdb->cmd,
"SELECT JobId from Job "
- "WHERE HashCache = 0 "
+ "WHERE HasCache = 0 "
"AND Type IN ('B') AND JobStatus IN ('T', 'f', 'A') "
"ORDER BY JobId");
Dmsg1(dbglevel, "Affected row(s) = %d\n", nb);
db_end_transaction(jcr, mdb);
+ db_unlock(mdb);
}
/*
/*
* Get all file versions for a specified client
+ * TODO: Handle basejobs using different client
*/
void Bvfs::get_all_file_versions(DBId_t pathid, DBId_t fnid, const char *client)
{
POOL_MEM query;
- Mmsg(query,// 1 2 3 4
-"SELECT 'V', File.FileId, File.Md5, File.JobId, File.LStat, "
-// 5 6
+ Mmsg(query,// 1 2 3
+"SELECT 'V', File.PathId, File.FilenameId, File.Md5, "
+// 4 5 6
+ "File.JobId, File.LStat, File.FileId, "
+// 7 8
"Media.VolumeName, Media.InChanger "
"FROM File, Job, Client, JobMedia, Media "
"WHERE File.FilenameId = %s "
"AND File.PathId=%s "
"AND File.JobId = Job.JobId "
- "AND Job.ClientId = Client.ClientId "
"AND Job.JobId = JobMedia.JobId "
"AND File.FileIndex >= JobMedia.FirstIndex "
"AND File.FileIndex <= JobMedia.LastIndex "
"AND JobMedia.MediaId = Media.MediaId "
+ "AND Job.ClientId = Client.ClientId "
"AND Client.Name = '%s' "
"%s ORDER BY FileId LIMIT %d OFFSET %d"
,edit_uint64(fnid, ed1), edit_uint64(pathid, ed2), client, q.c_str(),
if (*pattern) {
Mmsg(filter, " AND Filename.Name %s '%s' ", SQL_MATCH, pattern);
}
-
+ /* TODO: Use JobTDate instead of FileId to determine the latest version */
POOL_MEM query;
Mmsg(query, // 1 2 3 4
"SELECT 'F', File.PathId, File.FilenameId, listfiles.Name, File.JobId, "
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)) {
+ Dmsg0(dbglevel, "Can't search for path\n");
+ /* print error */
+ return false;
+ }
+ if (!strcmp(tmp2.c_str(), "")) { /* path not found */
+ Dmsg3(dbglevel, "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) {
+ Dmsg0(dbglevel, "hardlink should be two by two\n");
+ 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(dbglevel_sql, "q=%s\n", query.c_str());
+
+ if (!db_sql_query(db, query.c_str(), NULL, NULL)) {
+ Dmsg0(dbglevel, "Can't execute q\n");
+ goto bail_out;
+ }
+
+ /* TODO: handle basejob and SQLite3 */
+ Mmsg(query, sql_bvfs_select[db_type], output_table, output_table);
+
+ Dmsg1(dbglevel_sql, "q=%s\n", query.c_str());
+ if (!db_sql_query(db, query.c_str(), NULL, NULL)) {
+ Dmsg0(dbglevel, "Can't execute q\n");
+ 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;
+}