Do both a long and short form.
- Later:
-- Add a regression test for dbcheck.
-- Add disk seeking on restore.
-- Allow for optional cancelling of SD and FD in case DIR
+- Add John's appended files:
+ Appended = { /files/server/logs/http/*log }
+ and such files would be treated as follows.On a FULL backup, they would
+ be backed up like any other file.On an INCREMENTAL backup, where a
+ previous INCREMENTAL or FULL was already in thecatalogue and the length
+ of the file wasgreater than the length of the last backup, only thedata
+ added since the last backup will be dumped.On an INCREMENTAL backup, if
+ the length of the file is less than thelength of the file with the same
+ name last backed up, the completefile is dumped.On Windows systems, with
+ creation date of files, we can be evensmarter about this and not count
+ entirely upon the length.On a restore, the full and all incrementals
+ since it will beapplied in sequence to restore the file. - Add a
+ regression test for dbcheck. - Add disk seeking on restore. - Allow
+ for optional cancelling of SD and FD in case DIR
gets a fatal error. Requested by Jesse Guardiani <jesse@wingnet.net>
- Bizarre message: Error: Could not open WriteBootstrap file:
- Build console in client only build.
db_open_database(JCR *jcr, B_DB *mdb)
{
int errstat;
+ char port[10];
P(mutex);
if (mdb->connected) {
return 0;
}
+ bsnprintf(port, sizeof(port), "%d", mdb->db_port);
/* connect to the database */
mdb->db = PQsetdbLogin(
mdb->db_address, /* default = localhost */
- (char *) mdb->db_port, /* default port */
- NULL, /* pg options */
- NULL, /* tty, ignored */
+ port, /* default port */
+ NULL, /* pg options */
+ NULL, /* tty, ignored */
mdb->db_name, /* database name */
mdb->db_user, /* login name */
mdb->db_password); /* password */
if (PQstatus(mdb->db) != CONNECTION_OK) {
mdb->db = PQsetdbLogin(
mdb->db_address, /* default = localhost */
- (char *) mdb->db_port, /* default port */
- NULL, /* pg options */
- NULL, /* tty, ignored */
+ port, /* default port */
+ NULL, /* pg options */
+ NULL, /* tty, ignored */
mdb->db_name, /* database name */
mdb->db_user, /* login name */
mdb->db_password); /* password */
POSTGRESQL_ROW my_postgresql_fetch_row(B_DB *mdb)
{
- int j;
- POSTGRESQL_ROW row = NULL; // by default, return NULL
+ int j;
+ POSTGRESQL_ROW row = NULL; // by default, return NULL
- Dmsg0(50, "my_postgresql_fetch_row start\n");
+ Dmsg0(50, "my_postgresql_fetch_row start\n");
- if (mdb->row_number == -1 || mdb->row == NULL) {
+ if (mdb->row_number == -1 || mdb->row == NULL) {
+ Dmsg1(50, "we have need space of %d bytes\n", sizeof(char *) * mdb->num_fields);
- Dmsg1(50, "we have need space of %d bytes\n", sizeof(char *) * mdb->num_fields);
-
- if (mdb->row != NULL) {
- Dmsg0(50, "my_postgresql_fetch_row freeing space\n");
- free(mdb->row);
- mdb->row = NULL;
- }
+ if (mdb->row != NULL) {
+ Dmsg0(50, "my_postgresql_fetch_row freeing space\n");
+ free(mdb->row);
+ mdb->row = NULL;
+ }
- mdb->row = (POSTGRESQL_ROW) malloc(sizeof(char *) * mdb->num_fields);
+ mdb->row = (POSTGRESQL_ROW) malloc(sizeof(char *) * mdb->num_fields);
- // now reset the row_number now that we have the space allocated
- mdb->row_number = 0;
- }
+ // now reset the row_number now that we have the space allocated
+ mdb->row_number = 0;
+ }
- // if still within the result set
- if (mdb->row_number < mdb->num_rows) {
- Dmsg2(50, "my_postgresql_fetch_row row number '%d' is acceptable (0..%d)\n", mdb->row_number, mdb->num_rows);
- // get each value from this row
- for (j = 0; j < mdb->num_fields; j++) {
- mdb->row[j] = PQgetvalue(mdb->result, mdb->row_number, j);
- Dmsg2(50, "my_postgresql_fetch_row field '%d' has value '%s'\n", j, mdb->row[j]);
- }
- // increment the row number for the next call
- mdb->row_number++;
+ // if still within the result set
+ if (mdb->row_number < mdb->num_rows) {
+ Dmsg2(50, "my_postgresql_fetch_row row number '%d' is acceptable (0..%d)\n", mdb->row_number, mdb->num_rows);
+ // get each value from this row
+ for (j = 0; j < mdb->num_fields; j++) {
+ mdb->row[j] = PQgetvalue(mdb->result, mdb->row_number, j);
+ Dmsg2(50, "my_postgresql_fetch_row field '%d' has value '%s'\n", j, mdb->row[j]);
+ }
+ // increment the row number for the next call
+ mdb->row_number++;
- row = mdb->row;
- } else {
- Dmsg2(50, "my_postgresql_fetch_row row number '%d' is NOT acceptable (0..%d)\n", mdb->row_number, mdb->num_rows);
- }
+ row = mdb->row;
+ } else {
+ Dmsg2(50, "my_postgresql_fetch_row row number '%d' is NOT acceptable (0..%d)\n", mdb->row_number, mdb->num_rows);
+ }
- Dmsg1(50, "my_postgresql_fetch_row finishes returning %x\n", row);
+ Dmsg1(50, "my_postgresql_fetch_row finishes returning %x\n", row);
- return row;
+ return row;
}
int my_postgresql_max_length(B_DB *mdb, int field_num) {
- //
- // for a given column, find the max length
- //
- int max_length;
- int i;
- int this_length;
-
- max_length = 0;
- for (i = 0; i < mdb->num_rows; i++) {
- if (PQgetisnull(mdb->result, i, field_num)) {
- this_length = 4; // "NULL"
- } else {
- this_length = strlen(PQgetvalue(mdb->result, i, field_num));
- }
-
- if (max_length < this_length) {
- max_length = this_length;
- }
- }
-
- return max_length;
+ //
+ // for a given column, find the max length
+ //
+ int max_length;
+ int i;
+ int this_length;
+
+ max_length = 0;
+ for (i = 0; i < mdb->num_rows; i++) {
+ if (PQgetisnull(mdb->result, i, field_num)) {
+ this_length = 4; // "NULL"
+ } else {
+ this_length = strlen(PQgetvalue(mdb->result, i, field_num));
+ }
+
+ if (max_length < this_length) {
+ max_length = this_length;
+ }
+ }
+
+ return max_length;
}
POSTGRESQL_FIELD * my_postgresql_fetch_field(B_DB *mdb)
{
- int i;
-
- Dmsg0(50, "my_postgresql_fetch_field starts\n");
- if (mdb->fields == NULL) {
- Dmsg1(50, "allocating space for %d fields\n", mdb->num_fields);
- mdb->fields = (POSTGRESQL_FIELD *)
- malloc(sizeof(POSTGRESQL_FIELD) * mdb->num_fields);
-
- for (i = 0; i < mdb->num_fields; i++) {
- Dmsg1(50, "filling field %d\n", i);
- mdb->fields[i].name = PQfname(mdb->result, i);
- mdb->fields[i].max_length = my_postgresql_max_length(mdb, i);
- mdb->fields[i].type = PQftype(mdb->result, i);
- mdb->fields[i].flags = 0;
-
- Dmsg4(50, "my_postgresql_fetch_field finds field '%s' has length='%d' type='%d' and IsNull=%d\n",
- mdb->fields[i].name, mdb->fields[i].max_length, mdb->fields[i].type,
- mdb->fields[i].flags);
- } // end for
- } // end if
-
- // increment field number for the next time around
-
- Dmsg0(50, "my_postgresql_fetch_field finishes\n");
- return &mdb->fields[mdb->field_number++];
+ int i;
+
+ Dmsg0(50, "my_postgresql_fetch_field starts\n");
+ if (mdb->fields == NULL) {
+ Dmsg1(50, "allocating space for %d fields\n", mdb->num_fields);
+ mdb->fields = (POSTGRESQL_FIELD *)malloc(sizeof(POSTGRESQL_FIELD) * mdb->num_fields);
+
+ for (i = 0; i < mdb->num_fields; i++) {
+ Dmsg1(50, "filling field %d\n", i);
+ mdb->fields[i].name = PQfname(mdb->result, i);
+ mdb->fields[i].max_length = my_postgresql_max_length(mdb, i);
+ mdb->fields[i].type = PQftype(mdb->result, i);
+ mdb->fields[i].flags = 0;
+
+ Dmsg4(50, "my_postgresql_fetch_field finds field '%s' has length='%d' type='%d' and IsNull=%d\n",
+ mdb->fields[i].name, mdb->fields[i].max_length, mdb->fields[i].type,
+ mdb->fields[i].flags);
+ } // end for
+ } // end if
+
+ // increment field number for the next time around
+
+ Dmsg0(50, "my_postgresql_fetch_field finishes\n");
+ return &mdb->fields[mdb->field_number++];
}
void my_postgresql_data_seek(B_DB *mdb, int row)
{
- // set the row number to be returned on the next call
- // to my_postgresql_fetch_row
- mdb->row_number = row;
+ // set the row number to be returned on the next call
+ // to my_postgresql_fetch_row
+ mdb->row_number = row;
}
void my_postgresql_field_seek(B_DB *mdb, int field)
{
- mdb->field_number = field;
+ mdb->field_number = field;
}
int my_postgresql_query(B_DB *mdb, char *query) {
- Dmsg0(50, "my_postgresql_query started\n");
- // We are starting a new query. reset everything.
- mdb->num_rows = -1;
- mdb->row_number = -1;
- mdb->field_number = -1;
-
-
- Dmsg1(50, "my_postgresql_query starts with '%s'\n", query);
- mdb->result = PQexec(mdb->db, query);
- mdb->status = PQresultStatus(mdb->result);
- if (mdb->status == PGRES_TUPLES_OK || mdb->status == PGRES_COMMAND_OK) {
- Dmsg1(50, "we have a result\n", query);
-
- // how many fields in the set?
- mdb->num_fields = (int) PQnfields(mdb->result);
- Dmsg1(50, "we have %d fields\n", mdb->num_fields);
-
- mdb->num_rows = PQntuples(mdb->result);
- Dmsg1(50, "we have %d rows\n", mdb->num_rows);
-
- mdb->status = 0;
- } else {
- Dmsg1(50, "we failed\n", query);
- mdb->status = 1;
- }
+ Dmsg0(50, "my_postgresql_query started\n");
+ // We are starting a new query. reset everything.
+ mdb->num_rows = -1;
+ mdb->row_number = -1;
+ mdb->field_number = -1;
+
+
+ Dmsg1(50, "my_postgresql_query starts with '%s'\n", query);
+ mdb->result = PQexec(mdb->db, query);
+ mdb->status = PQresultStatus(mdb->result);
+ if (mdb->status == PGRES_TUPLES_OK || mdb->status == PGRES_COMMAND_OK) {
+ Dmsg1(50, "we have a result\n", query);
+
+ // how many fields in the set?
+ mdb->num_fields = (int) PQnfields(mdb->result);
+ Dmsg1(50, "we have %d fields\n", mdb->num_fields);
+
+ mdb->num_rows = PQntuples(mdb->result);
+ Dmsg1(50, "we have %d rows\n", mdb->num_rows);
+
+ mdb->status = 0;
+ } else {
+ Dmsg1(50, "we failed\n", query);
+ mdb->status = 1;
+ }
- Dmsg0(50, "my_postgresql_query finishing\n");
+ Dmsg0(50, "my_postgresql_query finishing\n");
- return mdb->status;
+ return mdb->status;
}
void my_postgresql_free_result (B_DB *mdb)
{
- if (mdb->result) {
- PQclear(mdb->result);
- }
-
- if (mdb->row) {
- free(mdb->row);
- mdb->row = NULL;
- }
-
- if (mdb->fields) {
- free(mdb->fields);
- mdb->fields = NULL;
- }
+ if (mdb->result) {
+ PQclear(mdb->result);
+ }
+
+ if (mdb->row) {
+ free(mdb->row);
+ mdb->row = NULL;
+ }
+
+ if (mdb->fields) {
+ free(mdb->fields);
+ mdb->fields = NULL;
+ }
}
int my_postgresql_currval(B_DB *mdb, char *table_name)
{
- // Obtain the current value of the sequence that
- // provides the serial value for primary key of the table.
-
- // currval is local to our session. It is not affected by
- // other transactions.
-
- // Determine the name of the sequence.
- // PostgreSQL automatically creates a sequence using
- // <table>_<column>_seq.
- // At the time of writing, all tables used this format for
- // for their primary key: <table>id
- // Except for basefiles which has a primary key on baseid.
- // Therefore, we need to special case that one table.
-
- // everything else can use the PostgreSQL formula.
-
- char sequence[NAMEDATALEN-1];
- char query [NAMEDATALEN+50];
- PGresult *result;
- int id = 0;
-
- if (strcasecmp(table_name, "basefiles") == 0) {
- bstrncpy(sequence, "basefiles_baseid", sizeof(sequence));
- } else {
- bstrncpy(sequence, table_name, sizeof(sequence));
- bstrncat(sequence, "_", sizeof(sequence));
- bstrncat(sequence, table_name, sizeof(sequence));
- bstrncat(sequence, "id", sizeof(sequence));
- }
-
- bstrncat(sequence, "_seq", sizeof(sequence));
- bsnprintf(query, sizeof(query), "SELECT currval('%s')", sequence);
-
-// Mmsg(&query, "SELECT currval('%s')", sequence);
- Dmsg1(50, "my_postgresql_currval invoked with '%s'\n", query);
- result = PQexec(mdb->db, query);
-
- Dmsg0(50, "exec done");
-
- if (PQresultStatus(result) == PGRES_TUPLES_OK) {
- Dmsg0(50, "getting value");
- id = atoi(PQgetvalue(result, 0, 0));
- Dmsg2(50, "got value '%s' which became %d\n", PQgetvalue(result, 0, 0), id);
- } else {
- Mmsg1(&mdb->errmsg, _("error fetching currval: %s\n"), PQerrorMessage(mdb->db));
- }
-
- PQclear(result);
-
- return id;
+ // Obtain the current value of the sequence that
+ // provides the serial value for primary key of the table.
+
+ // currval is local to our session. It is not affected by
+ // other transactions.
+
+ // Determine the name of the sequence.
+ // PostgreSQL automatically creates a sequence using
+ // <table>_<column>_seq.
+ // At the time of writing, all tables used this format for
+ // for their primary key: <table>id
+ // Except for basefiles which has a primary key on baseid.
+ // Therefore, we need to special case that one table.
+
+ // everything else can use the PostgreSQL formula.
+
+ char sequence[NAMEDATALEN-1];
+ char query [NAMEDATALEN+50];
+ PGresult *result;
+ int id = 0;
+
+ if (strcasecmp(table_name, "basefiles") == 0) {
+ bstrncpy(sequence, "basefiles_baseid", sizeof(sequence));
+ } else {
+ bstrncpy(sequence, table_name, sizeof(sequence));
+ bstrncat(sequence, "_", sizeof(sequence));
+ bstrncat(sequence, table_name, sizeof(sequence));
+ bstrncat(sequence, "id", sizeof(sequence));
+ }
+
+ bstrncat(sequence, "_seq", sizeof(sequence));
+ bsnprintf(query, sizeof(query), "SELECT currval('%s')", sequence);
+
+// Mmsg(&query, "SELECT currval('%s')", sequence);
+ Dmsg1(50, "my_postgresql_currval invoked with '%s'\n", query);
+ result = PQexec(mdb->db, query);
+
+ Dmsg0(50, "exec done");
+
+ if (PQresultStatus(result) == PGRES_TUPLES_OK) {
+ Dmsg0(50, "getting value");
+ id = atoi(PQgetvalue(result, 0, 0));
+ Dmsg2(50, "got value '%s' which became %d\n", PQgetvalue(result, 0, 0), id);
+ } else {
+ Mmsg1(&mdb->errmsg, _("error fetching currval: %s\n"), PQerrorMessage(mdb->db));
+ }
+
+ PQclear(result);
+
+ return id;
}
jr->JobStatus = (int)*row[9];
jr->Type = (int)*row[10];
jr->Level = (int)*row[11];
- jr->ClientId = str_to_uint64(row[12]);
+ jr->ClientId = str_to_uint64(row[12]!=NULL?row[12]:(char *)"");
sql_free_result(mdb);
db_unlock(mdb);
} else {
tree->avail_node = NULL; /* added node to tree */
}
- new_node->FileIndex = atoi(row[2]);
- new_node->JobId = (JobId_t)str_to_int64(row[3]);
- new_node->type = type;
- new_node->extract = true; /* extract all by default */
- new_node->hard_link = hard_link;
- new_node->soft_link = S_ISLNK(statp.st_mode) != 0;
- if (type == TN_DIR || type == TN_DIR_NLS) {
- new_node->extract_dir = true; /* if dir, extract it */
+ /*
+ * If the user has backed up a hard linked file twice, the
+ * second copy will be a pointer (i.e. hard link will be set),
+ * so we do not overwrite the original file with a pointer file.
+ */
+ if (!new_node->hard_link || hard_link) {
+ new_node->hard_link = hard_link;
+ new_node->FileIndex = atoi(row[2]);
+ new_node->JobId = (JobId_t)str_to_int64(row[3]);
+ new_node->type = type;
+ new_node->extract = true; /* extract all by default */
+ new_node->soft_link = S_ISLNK(statp.st_mode) != 0;
+ if (type == TN_DIR || type == TN_DIR_NLS) {
+ new_node->extract_dir = true; /* if dir, extract it */
+ }
}
tree->cnt++;
return 0;
#include "bacula.h"
#include "find.h"
-extern int32_t name_max; /* filename max length */
-extern int32_t path_max; /* path name max length */
+extern int32_t name_max; /* filename max length */
+extern int32_t path_max; /* path name max length */
/*
* Structure for keeping track of hard linked files, we
*/
struct f_link {
struct f_link *next;
- dev_t dev; /* device */
- ino_t ino; /* inode with device is unique */
+ dev_t dev; /* device */
+ ino_t ino; /* inode with device is unique */
short linkcount;
- uint32_t FileIndex; /* Bacula FileIndex of this file */
- char name[1]; /* The name */
+ uint32_t FileIndex; /* Bacula FileIndex of this file */
+ char name[1]; /* The name */
};
static void free_dir_ff_pkt(FF_PKT *dir_ff_pkt)
}
/*
- * Find a single file.
+ * Find a single file.
* handle_file is the callback for handling the file.
* p is the filename
* parent_device is the device we are currently on
*/
int
find_one_file(JCR *jcr, FF_PKT *ff_pkt, int handle_file(FF_PKT *ff, void *hpkt),
- void *pkt, char *fname, dev_t parent_device, int top_level)
+ void *pkt, char *fname, dev_t parent_device, int top_level)
{
struct utimbuf restore_times;
int rtn_stat;
Dmsg1(300, "Non-directory incremental: %s\n", ff_pkt->fname);
/* Not a directory */
if (ff_pkt->statp.st_mtime < ff_pkt->save_time
- && ((ff_pkt->flags & FO_MTIMEONLY) ||
- ff_pkt->statp.st_ctime < ff_pkt->save_time)) {
- /* Incremental option, file not changed */
- ff_pkt->type = FT_NOCHG;
- return handle_file(ff_pkt, pkt);
+ && ((ff_pkt->flags & FO_MTIMEONLY) ||
+ ff_pkt->statp.st_ctime < ff_pkt->save_time)) {
+ /* Incremental option, file not changed */
+ ff_pkt->type = FT_NOCHG;
+ return handle_file(ff_pkt, pkt);
}
}
*/
if (ff_pkt->statp.st_nlink > 1
&& (S_ISREG(ff_pkt->statp.st_mode)
- || S_ISCHR(ff_pkt->statp.st_mode)
- || S_ISBLK(ff_pkt->statp.st_mode)
- || S_ISFIFO(ff_pkt->statp.st_mode)
- || S_ISSOCK(ff_pkt->statp.st_mode))) {
+ || S_ISCHR(ff_pkt->statp.st_mode)
+ || S_ISBLK(ff_pkt->statp.st_mode)
+ || S_ISFIFO(ff_pkt->statp.st_mode)
+ || S_ISSOCK(ff_pkt->statp.st_mode))) {
struct f_link *lp;
/* Search link list of hard linked files */
for (lp = ff_pkt->linklist; lp; lp = lp->next)
- if (lp->ino == ff_pkt->statp.st_ino && lp->dev == ff_pkt->statp.st_dev) {
- ff_pkt->link = lp->name;
- ff_pkt->type = FT_LNKSAVED; /* Handle link, file already saved */
- ff_pkt->LinkFI = lp->FileIndex;
- return handle_file(ff_pkt, pkt);
- }
+ if (lp->ino == ff_pkt->statp.st_ino && lp->dev == ff_pkt->statp.st_dev) {
+ /* If we have already backed up the hard linked file don't do it again */
+ if (strcmp(lp->name, fname) == 0) {
+ Jmsg0(jcr, M_WARNING, 0, _("Attempt to backup hard linked file %s twice ignored.\n"));
+ return 1; /* ignore */
+ }
+ ff_pkt->link = lp->name;
+ ff_pkt->type = FT_LNKSAVED; /* Handle link, file already saved */
+ ff_pkt->LinkFI = lp->FileIndex;
+ return handle_file(ff_pkt, pkt);
+ }
/* File not previously dumped. Chain it into our list. */
lp = (struct f_link *)bmalloc(sizeof(struct f_link) + strlen(fname) +1);
strcpy(lp->name, fname);
lp->next = ff_pkt->linklist;
ff_pkt->linklist = lp;
- ff_pkt->linked = lp; /* mark saved link */
+ ff_pkt->linked = lp; /* mark saved link */
} else {
ff_pkt->linked = NULL;
}
sizeleft = ff_pkt->statp.st_size;
/* Don't bother opening empty, world readable files. Also do not open
- files when archive is meant for /dev/null. */
+ files when archive is meant for /dev/null. */
if (ff_pkt->null_output_device || (sizeleft == 0
- && MODE_RALL == (MODE_RALL & ff_pkt->statp.st_mode))) {
- ff_pkt->type = FT_REGE;
+ && MODE_RALL == (MODE_RALL & ff_pkt->statp.st_mode))) {
+ ff_pkt->type = FT_REGE;
} else {
- ff_pkt->type = FT_REG;
+ ff_pkt->type = FT_REG;
}
rtn_stat = handle_file(ff_pkt, pkt);
if (ff_pkt->linked) {
- ff_pkt->linked->FileIndex = ff_pkt->FileIndex;
+ ff_pkt->linked->FileIndex = ff_pkt->FileIndex;
}
return rtn_stat;
size = readlink(fname, buffer, path_max + name_max + 101);
if (size < 0) {
- /* Could not follow link */
- ff_pkt->type = FT_NOFOLLOW;
- ff_pkt->ff_errno = errno;
- rtn_stat = handle_file(ff_pkt, pkt);
- if (ff_pkt->linked) {
- ff_pkt->linked->FileIndex = ff_pkt->FileIndex;
- }
- return rtn_stat;
+ /* Could not follow link */
+ ff_pkt->type = FT_NOFOLLOW;
+ ff_pkt->ff_errno = errno;
+ rtn_stat = handle_file(ff_pkt, pkt);
+ if (ff_pkt->linked) {
+ ff_pkt->linked->FileIndex = ff_pkt->FileIndex;
+ }
+ return rtn_stat;
}
buffer[size] = 0;
- ff_pkt->link = buffer; /* point to link */
- ff_pkt->type = FT_LNK; /* got a real link */
+ ff_pkt->link = buffer; /* point to link */
+ ff_pkt->type = FT_LNK; /* got a real link */
rtn_stat = handle_file(ff_pkt, pkt);
if (ff_pkt->linked) {
- ff_pkt->linked->FileIndex = ff_pkt->FileIndex;
+ ff_pkt->linked->FileIndex = ff_pkt->FileIndex;
}
return rtn_stat;
struct dirent *entry, *result;
char *link;
int link_len;
- int len;
+ int len;
int status;
dev_t our_device = ff_pkt->statp.st_dev;
* in principle, we should be able to access everything.
*/
if (!have_win32_api() || (ff_pkt->flags & FO_PORTABLE)) {
- if (access(fname, R_OK) == -1 && geteuid() != 0) {
- /* Could not access() directory */
- ff_pkt->type = FT_NOACCESS;
- ff_pkt->ff_errno = errno;
- rtn_stat = handle_file(ff_pkt, pkt);
- if (ff_pkt->linked) {
- ff_pkt->linked->FileIndex = ff_pkt->FileIndex;
- }
- return rtn_stat;
- }
+ if (access(fname, R_OK) == -1 && geteuid() != 0) {
+ /* Could not access() directory */
+ ff_pkt->type = FT_NOACCESS;
+ ff_pkt->ff_errno = errno;
+ rtn_stat = handle_file(ff_pkt, pkt);
+ if (ff_pkt->linked) {
+ ff_pkt->linked->FileIndex = ff_pkt->FileIndex;
+ }
+ return rtn_stat;
+ }
}
/* Build a canonical directory name with a trailing slash in link var */
bstrncpy(link, fname, link_len);
/* Strip all trailing slashes */
while (len >= 1 && link[len - 1] == '/')
- len--;
+ len--;
link[len++] = '/'; /* add back one */
link[len] = 0;
ff_pkt->link = link;
if (ff_pkt->incremental &&
- (ff_pkt->statp.st_mtime < ff_pkt->save_time &&
- ff_pkt->statp.st_ctime < ff_pkt->save_time)) {
- /* Incremental option, directory entry not changed */
- ff_pkt->type = FT_DIRNOCHG;
+ (ff_pkt->statp.st_mtime < ff_pkt->save_time &&
+ ff_pkt->statp.st_ctime < ff_pkt->save_time)) {
+ /* Incremental option, directory entry not changed */
+ ff_pkt->type = FT_DIRNOCHG;
} else {
- ff_pkt->type = FT_DIR;
+ ff_pkt->type = FT_DIR;
}
/*
dir_ff_pkt->excluded_files_list = NULL;
dir_ff_pkt->excluded_paths_list = NULL;
dir_ff_pkt->linklist = NULL;
-
+
ff_pkt->link = ff_pkt->fname; /* reset "link" */
/*
* user has turned it off for this directory.
*/
if (ff_pkt->flags & FO_NO_RECURSION) {
- /* No recursion into this directory */
- ff_pkt->type = FT_NORECURSE;
- rtn_stat = handle_file(ff_pkt, pkt);
- if (ff_pkt->linked) {
- ff_pkt->linked->FileIndex = ff_pkt->FileIndex;
- }
- free(link);
- free_dir_ff_pkt(dir_ff_pkt);
- return rtn_stat;
+ /* No recursion into this directory */
+ ff_pkt->type = FT_NORECURSE;
+ rtn_stat = handle_file(ff_pkt, pkt);
+ if (ff_pkt->linked) {
+ ff_pkt->linked->FileIndex = ff_pkt->FileIndex;
+ }
+ free(link);
+ free_dir_ff_pkt(dir_ff_pkt);
+ return rtn_stat;
}
/*
* avoid doing so if the user only wants to dump one file system.
*/
if (!top_level && !(ff_pkt->flags & FO_MULTIFS) &&
- parent_device != ff_pkt->statp.st_dev) {
- /* returning here means we do not handle this directory */
- ff_pkt->type = FT_NOFSCHG;
- rtn_stat = handle_file(ff_pkt, pkt);
- if (ff_pkt->linked) {
- ff_pkt->linked->FileIndex = ff_pkt->FileIndex;
- }
- free(link);
- free_dir_ff_pkt(dir_ff_pkt);
- return rtn_stat;
+ parent_device != ff_pkt->statp.st_dev) {
+ /* returning here means we do not handle this directory */
+ ff_pkt->type = FT_NOFSCHG;
+ rtn_stat = handle_file(ff_pkt, pkt);
+ if (ff_pkt->linked) {
+ ff_pkt->linked->FileIndex = ff_pkt->FileIndex;
+ }
+ free(link);
+ free_dir_ff_pkt(dir_ff_pkt);
+ return rtn_stat;
}
/*
* Decend into or "recurse" into the directory to read
*/
errno = 0;
if ((directory = opendir(fname)) == NULL) {
- ff_pkt->type = FT_NOOPEN;
- ff_pkt->ff_errno = errno;
- rtn_stat = handle_file(ff_pkt, pkt);
- if (ff_pkt->linked) {
- ff_pkt->linked->FileIndex = ff_pkt->FileIndex;
- }
- free(link);
- free_dir_ff_pkt(dir_ff_pkt);
- return rtn_stat;
+ ff_pkt->type = FT_NOOPEN;
+ ff_pkt->ff_errno = errno;
+ rtn_stat = handle_file(ff_pkt, pkt);
+ if (ff_pkt->linked) {
+ ff_pkt->linked->FileIndex = ff_pkt->FileIndex;
+ }
+ free(link);
+ free_dir_ff_pkt(dir_ff_pkt);
+ return rtn_stat;
}
/*
rtn_stat = 1;
entry = (struct dirent *)malloc(sizeof(struct dirent) + name_max + 100);
for ( ; !job_canceled(jcr); ) {
- char *p, *q;
- int i;
+ char *p, *q;
+ int i;
- status = readdir_r(directory, entry, &result);
- if (status != 0 || result == NULL) {
+ status = readdir_r(directory, entry, &result);
+ if (status != 0 || result == NULL) {
// Dmsg2(99, "readdir returned stat=%d result=0x%x\n",
-// status, (long)result);
- break;
- }
- ASSERT(name_max+1 > (int)sizeof(struct dirent) + (int)NAMELEN(entry));
- p = entry->d_name;
+// status, (long)result);
+ break;
+ }
+ ASSERT(name_max+1 > (int)sizeof(struct dirent) + (int)NAMELEN(entry));
+ p = entry->d_name;
/* Skip `.', `..', and excluded file names. */
if (p[0] == '\0' || (p[0] == '.' && (p[1] == '\0' ||
(p[1] == '.' && p[2] == '\0')))) {
- continue;
- }
-
- if ((int)NAMELEN(entry) + len >= link_len) {
- link_len = len + NAMELEN(entry) + 1;
- link = (char *)brealloc(link, link_len + 1);
- }
- q = link + len;
- for (i=0; i < (int)NAMELEN(entry); i++) {
- *q++ = *p++;
- }
- *q = 0;
- if (!file_is_excluded(ff_pkt, link)) {
- rtn_stat = find_one_file(jcr, ff_pkt, handle_file, pkt, link, our_device, 0);
- if (ff_pkt->linked) {
- ff_pkt->linked->FileIndex = ff_pkt->FileIndex;
- }
- }
+ continue;
+ }
+
+ if ((int)NAMELEN(entry) + len >= link_len) {
+ link_len = len + NAMELEN(entry) + 1;
+ link = (char *)brealloc(link, link_len + 1);
+ }
+ q = link + len;
+ for (i=0; i < (int)NAMELEN(entry); i++) {
+ *q++ = *p++;
+ }
+ *q = 0;
+ if (!file_is_excluded(ff_pkt, link)) {
+ rtn_stat = find_one_file(jcr, ff_pkt, handle_file, pkt, link, our_device, 0);
+ if (ff_pkt->linked) {
+ ff_pkt->linked->FileIndex = ff_pkt->FileIndex;
+ }
+ }
}
closedir(directory);
free(link);
* the directory modes and dates. Temp directory values
* were used without this record.
*/
- handle_file(dir_ff_pkt, pkt); /* handle directory entry */
+ handle_file(dir_ff_pkt, pkt); /* handle directory entry */
if (ff_pkt->linked) {
- ff_pkt->linked->FileIndex = dir_ff_pkt->FileIndex;
+ ff_pkt->linked->FileIndex = dir_ff_pkt->FileIndex;
}
free_dir_ff_pkt(dir_ff_pkt);
if (ff_pkt->flags & FO_KEEPATIME) {
- utime(fname, &restore_times);
+ utime(fname, &restore_times);
}
return rtn_stat;
} /* end check for directory */
#ifdef HAVE_FREEBSD_OS
/*
* On FreeBSD, all block devices are character devices, so
- * to be able to read a raw disk, we need the check for
- * a character device.
+ * to be able to read a raw disk, we need the check for
+ * a character device.
   * crw-r----- 1 root operator - 116, 0x00040002 Jun 9 19:32 /dev/ad0s3
   * crw-r----- 1 root operator - 116, 0x00040002 Jun 9 19:32 /dev/rad0s3
*/
#else
if (top_level && S_ISBLK(ff_pkt->statp.st_mode)) {
#endif
- ff_pkt->type = FT_RAW; /* raw partition */
+ ff_pkt->type = FT_RAW; /* raw partition */
} else if (top_level && S_ISFIFO(ff_pkt->statp.st_mode) &&
- ff_pkt->flags & FO_READFIFO) {
+ ff_pkt->flags & FO_READFIFO) {
ff_pkt->type = FT_FIFO;
} else {
/* The only remaining types are special (character, ...) files */
lc = lp;
lp = lp->next;
if (lc) {
- free(lc);
- count++;
+ free(lc);
+ count++;
}
}
return count;
JCR *prev_dev; /* previous JCR attached to device */
pthread_cond_t job_start_wait; /* Wait for FD to start Job */
int type;
- DEVRES *device; /* device to use */
+ DCR *dcr; /* device context record */
+ DEVRES *device; /* device resource to use */
VOLUME_CAT_INFO VolCatInfo; /* Catalog info for desired volume */
POOLMEM *job_name; /* base Job name (not unique) */
POOLMEM *fileset_name; /* FileSet */
VOL_LIST *VolList; /* list to read */
int32_t NumVolumes; /* number of volumes used */
int32_t CurVolume; /* current volume number */
- int spool_attributes; /* set if spooling attributes */
- int no_attributes; /* set if no attributes wanted */
int label_status; /* device volume label status */
int label_errors; /* count of label errors */
- int session_opened;
- DEV_RECORD rec; /* Read/Write record */
+ bool session_opened;
long Ticket; /* ticket for this job */
- uint32_t VolFirstIndex; /* First file index this Volume */
- uint32_t VolLastIndex; /* Last file index this Volume */
- uint32_t FileIndex; /* Current File Index */
- uint32_t EndFile; /* End file written */
- uint32_t StartFile; /* Start write file */
- uint32_t StartBlock; /* Start write block */
- uint32_t EndBlock; /* Ending block written */
- bool NewVol; /* set when new Volume mounted */
- bool WroteVol; /* set when Volume written */
- bool NewFile; /* set when EOF written */
bool ignore_label_errors; /* ignore Volume label errors */
+ bool spool_attributes; /* set if spooling attributes */
+ bool no_attributes; /* set if no attributes wanted */
int CurVol; /* Current Volume count */
uint32_t FileId; /* Last file id inserted */
unlink(mp_chr(fname)); /* remove stale pid file */
}
/* Create new pid file */
- if ((pidfd = open(mp_chr(fname), O_CREAT|O_TRUNC|O_WRONLY|O_BINARY, 0644)) >= 0) {
+ if ((pidfd = open(mp_chr(fname), O_CREAT|O_TRUNC|O_WRONLY|O_BINARY, 0640)) >= 0) {
len = sprintf(pidbuf, "%d\n", (int)getpid());
write(pidfd, pidbuf, len);
close(pidfd);
register char *p = str;
register uint64_t value = 0;
+ if (!p) {
+ return 0;
+ }
while (B_ISSPACE(*p)) {
p++;
}
{
register char *p = str;
register int64_t value;
- int negative = FALSE;
+ bool negative = false;
+ if (!p) {
+ return 0;
+ }
while (B_ISSPACE(*p)) {
p++;
}
if (*p == '+') {
p++;
} else if (*p == '-') {
- negative = TRUE;
+ negative = true;
p++;
}
value = str_to_uint64(p);
{
if (jcr) {
Mmsg(name, "%s/%s.mail.%s.%d", working_directory, my_name,
- jcr->Job, (int)d);
+ jcr->Job, (int)(long)d);
} else {
Mmsg(name, "%s/%s.mail.%s.%d", working_directory, my_name,
- my_name, (int)d);
+ my_name, (int)(long)d);
}
Dmsg1(200, "mailname=%s\n", *name);
}
static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
+DCR *new_dcr(JCR *jcr, DEVICE *dev)
+{
+ DCR *dcr = (DCR *)malloc(sizeof(DCR));
+ memset(dcr, 0, sizeof(DCR));
+ jcr->dcr = dcr;
+ dcr->jcr = jcr;
+ dcr->dev = dev;
+ dcr->block = new_block(dev);
+ dcr->record = new_record();
+ dcr->spool_fd = -1;
+ return dcr;
+}
+
+void free_dcr(DCR *dcr)
+{
+ if (dcr->block) {
+ free_block(dcr->block);
+ }
+ if (dcr->record) {
+ free_record(dcr->record);
+ }
+ dcr->jcr->dcr = NULL;
+ free(dcr);
+}
+
+
/*********************************************************************
* Acquire device for reading. We permit (for the moment)
* only one reader. We read the Volume label from the block and
* Returns: 0 if failed for any reason
* 1 if successful
*/
-int acquire_device_for_read(JCR *jcr, DEVICE *dev, DEV_BLOCK *block)
+DCR *acquire_device_for_read(JCR *jcr)
{
bool vol_ok = false;
bool tape_previously_mounted;
VOL_LIST *vol;
int autochanger = 0;
int i;
-
+ DCR *dcr = jcr->dcr;
+ DEVICE *dev;
+
+ /* Called for each volume */
+ if (!dcr) {
+ dcr = new_dcr(jcr, jcr->device->dev);
+ }
+ dev = dcr->dev;
if (device_is_unmounted(dev)) {
Jmsg(jcr, M_WARNING, 0, _("device %s is BLOCKED due to user unmount.\n"),
dev_name(dev));
vol = vol->next;
}
pm_strcpy(&jcr->VolumeName, vol->VolumeName);
+ bstrncpy(dcr->VolumeName, vol->VolumeName, sizeof(dcr->VolumeName));
for (i=0; i<5; i++) {
if (job_canceled(jcr)) {
*/
for ( ; !(dev->state & ST_OPENED); ) {
Dmsg1(120, "bstored: open vol=%s\n", jcr->VolumeName);
- if (open_dev(dev, jcr->VolumeName, READ_ONLY) < 0) {
+ if (open_dev(dev, dcr->VolumeName, READ_ONLY) < 0) {
Jmsg(jcr, M_FATAL, 0, _("Open device %s volume %s failed, ERR=%s\n"),
- dev_name(dev), jcr->VolumeName, strerror_dev(dev));
+ dev_name(dev), dcr->VolumeName, strerror_dev(dev));
goto get_out;
}
Dmsg1(129, "open_dev %s OK\n", dev_name(dev));
* correctly possitioned. Possibly have way user can turn
* this optimization (to be implemented) off.
*/
- dev->state &= ~ST_LABEL; /* force reread of label */
+ dcr->dev->state &= ~ST_LABEL; /* force reread of label */
Dmsg0(200, "calling read-vol-label\n");
- switch (read_dev_volume_label(jcr, dev, block)) {
+ switch (read_dev_volume_label(jcr, dev, dcr->block)) {
case VOL_OK:
vol_ok = true;
break; /* got it */
P(dev->mutex);
unblock_device(dev);
V(dev->mutex);
- return vol_ok;
+ if (!vol_ok) {
+ free_dcr(dcr);
+ dcr = NULL;
+ }
+ return dcr;
}
/*
* multiple devices (for files), thus we have our own mutex
* on top of the device mutex.
*/
-DEVICE *acquire_device_for_append(JCR *jcr, DEVICE *dev, DEV_BLOCK *block)
+DCR *acquire_device_for_append(JCR *jcr)
{
int release = 0;
bool recycle = false;
bool do_mount = false;
- DEVICE *rtn_dev = NULL;
+ DCR *dcr;
+ DEVICE *dev = jcr->device->dev;
+ dcr = new_dcr(jcr, dev);
if (device_is_unmounted(dev)) {
Jmsg(jcr, M_WARNING, 0, _("device %s is BLOCKED due to user unmount.\n"),
dev_name(dev));
* dir_find_next_appendable_volume
*/
pm_strcpy(&jcr->VolumeName, dev->VolHdr.VolName);
+ bstrncpy(dcr->VolumeName, dev->VolHdr.VolName, sizeof(dcr->VolumeName));
if (!dir_get_volume_info(jcr, GET_VOL_INFO_FOR_WRITE) &&
!(dir_find_next_appendable_volume(jcr) &&
strcmp(dev->VolHdr.VolName, jcr->VolumeName) == 0)) { /* wrong tape mounted */
}
if (do_mount || recycle) {
- if (!mount_next_write_volume(jcr, dev, block, release)) {
+ if (!mount_next_write_volume(jcr, dev, dcr->block, release)) {
if (!job_canceled(jcr)) {
/* Reduce "noise" -- don't print if job canceled */
Jmsg(jcr, M_FATAL, 0, _("Could not ready device \"%s\" for append.\n"),
jcr->NumVolumes = 1;
}
attach_jcr_to_device(dev, jcr); /* attach jcr to device */
- rtn_dev = dev; /* return device */
+ goto ok_out;
/*
* If we jump here, it is an error return because
* rtn_dev will still be NULL
*/
get_out:
+ free_dcr(dcr);
+ dcr = NULL;
+ok_out:
P(dev->mutex);
unblock_device(dev);
V(dev->mutex);
V(mutex); /* unlock other threads */
- return rtn_dev;
+ return dcr;
}
/*
* the device remains open.
*
*/
-int release_device(JCR *jcr, DEVICE *dev)
+int release_device(JCR *jcr)
{
+ DEVICE *dev = jcr->dcr->dev;
lock_device(dev);
Dmsg1(100, "release_device device is %s\n", dev_is_tape(dev)?"tape":"disk");
if (dev_state(dev, ST_READ)) {
} else {
unlock_device(dev);
}
+ free_dcr(jcr->dcr);
+ jcr->dcr = NULL;
return 1;
}
static int begin_attribute_spool(JCR *jcr);
static int discard_attribute_spool(JCR *jcr);
static int commit_attribute_spool(JCR *jcr);
+static int open_data_spool_file(JCR *jcr);
+static int close_data_spool_file(JCR *jcr);
+static int begin_data_spool(JCR *jcr);
+static int discard_data_spool(JCR *jcr);
+static int commit_data_spool(JCR *jcr);
+
/*
* Append Data sent from File daemon
BSOCK *ds;
BSOCK *fd_sock = jcr->file_bsock;
bool ok = true;
- DEVICE *dev = jcr->device->dev;
+ DEVICE *dev;
DEV_RECORD rec;
DEV_BLOCK *block;
+ DCR *dcr;
Dmsg0(10, "Start append data.\n");
- /* Tell File daemon to send data */
- bnet_fsend(fd_sock, OK_data);
-
- begin_attribute_spool(jcr);
-
ds = fd_sock;
- if (!bnet_set_buffer_size(ds, dev->device->max_network_buffer_size, BNET_SETBUF_WRITE)) {
+ if (!bnet_set_buffer_size(ds, jcr->device->max_network_buffer_size, BNET_SETBUF_WRITE)) {
set_jcr_job_status(jcr, JS_ErrorTerminated);
Jmsg(jcr, M_FATAL, 0, _("Unable to set network buffer size.\n"));
- discard_attribute_spool(jcr);
return 0;
}
- Dmsg1(20, "Begin append device=%s\n", dev_name(dev));
-
- block = new_block(dev);
- memset(&rec, 0, sizeof(rec));
-
/*
* Acquire output device for writing. Note, after acquiring a
* device, we MUST release it, which is done at the end of this
* subroutine.
*/
Dmsg0(100, "just before acquire_device\n");
- if (!(dev=acquire_device_for_append(jcr, dev, block))) {
+ if (!(dcr=acquire_device_for_append(jcr))) {
set_jcr_job_status(jcr, JS_ErrorTerminated);
- free_block(block);
- discard_attribute_spool(jcr);
return 0;
}
+ dev = dcr->dev;
+ block = dcr->block;
+
+ Dmsg1(20, "Begin append device=%s\n", dev_name(dev));
+
+ begin_data_spool(jcr);
+ begin_attribute_spool(jcr);
+
Dmsg0(100, "Just after acquire_device_for_append\n");
/*
* Write Begin Session Record
ok = false;
}
+ /* Tell File daemon to send data */
+ bnet_fsend(fd_sock, OK_data);
/*
* Get Data from File daemon, write to device. To clarify what is
* file. 1. for the Attributes, 2. for the file data if any,
* and 3. for the MD5 if any.
*/
- jcr->VolFirstIndex = jcr->VolLastIndex = 0;
+ dcr->VolFirstIndex = dcr->VolLastIndex = 0;
jcr->run_time = time(NULL); /* start counting time for rates */
for (last_file_index = 0; ok && !job_canceled(jcr); ) {
* The data stream is just raw bytes
*/
while ((n=bget_msg(ds)) > 0 && !job_canceled(jcr)) {
-
rec.VolSessionId = jcr->VolSessionId;
rec.VolSessionTime = jcr->VolSessionTime;
rec.FileIndex = file_index;
}
}
+ if (!ok) {
+ discard_data_spool(jcr);
+ } else {
+ commit_data_spool(jcr);
+ }
+
Dmsg1(200, "calling release device JobStatus=%d\n", jcr->JobStatus);
/* Release the device */
- if (!release_device(jcr, dev)) {
+ if (!release_device(jcr)) {
Pmsg0(000, _("Error in release_device\n"));
set_jcr_job_status(jcr, JS_ErrorTerminated);
ok = false;
}
- free_block(block);
-
- commit_attribute_spool(jcr);
+ if (!ok) {
+ discard_attribute_spool(jcr);
+ } else {
+ commit_attribute_spool(jcr);
+ }
dir_send_job_status(jcr); /* update director */
return ok ? 1 : 0;
}
+
+static int begin_data_spool(JCR *jcr)
+{
+ if (jcr->dcr->spool_data) {
+ return open_data_spool_file(jcr);
+ }
+ return 1;
+}
+
+static int discard_data_spool(JCR *jcr)
+{
+ if (jcr->dcr->spool_data && jcr->dcr->spool_fd >= 0) {
+ return close_data_spool_file(jcr);
+ }
+ return 1;
+}
+
+static int commit_data_spool(JCR *jcr)
+{
+ if (jcr->dcr->spool_data && jcr->dcr->spool_fd >= 0) {
+// despool_data(jcr);
+ return close_data_spool_file(jcr);
+ }
+ return 1;
+}
+
+static void make_unique_data_spool_filename(JCR *jcr, POOLMEM **name)
+{
+ Mmsg(name, "%s/%s.data.spool.%s.%s", working_directory, my_name,
+ jcr->Job, jcr->device->hdr.name);
+}
+
+
+static int open_data_spool_file(JCR *jcr)
+{
+ POOLMEM *name = get_pool_memory(PM_MESSAGE);
+ int spool_fd;
+
+ make_unique_data_spool_filename(jcr, &name);
+ if ((spool_fd = open(name, O_CREAT|O_TRUNC|O_RDWR|O_BINARY, 0640)) >= 0) {
+ jcr->dcr->spool_fd = spool_fd;
+ jcr->spool_attributes = true;
+ } else {
+ Jmsg(jcr, M_ERROR, 0, "open data spool file %s failed: ERR=%s\n", name, strerror(errno));
+ free_pool_memory(name);
+ return 0;
+ }
+ free_pool_memory(name);
+ return 1;
+}
+
+static int close_data_spool_file(JCR *jcr)
+{
+ POOLMEM *name = get_pool_memory(PM_MESSAGE);
+
+ make_unique_data_spool_filename(jcr, &name);
+ close(jcr->dcr->spool_fd);
+ jcr->dcr->spool_fd = -1;
+ unlink(name);
+ free_pool_memory(name);
+ return 1;
+}
+
+
static bool are_attributes_spooled(JCR *jcr)
{
return jcr->spool_attributes && jcr->dir_bsock->spool_fd;
static int do_get_volume_info(JCR *jcr)
{
BSOCK *dir = jcr->dir_bsock;
+ DCR *dcr = jcr->dcr;
VOLUME_CAT_INFO vol;
int n;
jcr->VolumeName[0] = 0; /* No volume */
+ dcr->VolumeName[0] = 0; /* No volume */
if (bnet_recv(dir) <= 0) {
Dmsg0(200, "getvolname error bnet_recv\n");
Mmsg(&jcr->errmsg, _("Network error on bnet_recv in req_vol_info.\n"));
}
unbash_spaces(vol.VolCatName);
pm_strcpy(&jcr->VolumeName, vol.VolCatName); /* set desired VolumeName */
+ bstrncpy(dcr->VolumeName, vol.VolCatName, sizeof(dcr->VolumeName));
memcpy(&jcr->VolCatInfo, &vol, sizeof(jcr->VolCatInfo));
+ memcpy(&dcr->VolCatInfo, &vol, sizeof(dcr->VolCatInfo));
Dmsg2(200, "do_reqest_vol_info got slot=%d Volume=%s\n",
vol.Slot, vol.VolCatName);
int dir_create_jobmedia_record(JCR *jcr)
{
BSOCK *dir = jcr->dir_bsock;
+ DCR *dcr = jcr->dcr;
- if (!jcr->WroteVol) {
+ if (!dcr->WroteVol) {
return 1; /* nothing written to tape */
}
- jcr->WroteVol = false;
+ dcr->WroteVol = false;
bnet_fsend(dir, Create_job_media, jcr->Job,
- jcr->VolFirstIndex, jcr->VolLastIndex,
- jcr->StartFile, jcr->EndFile,
- jcr->StartBlock, jcr->EndBlock);
+ dcr->VolFirstIndex, dcr->VolLastIndex,
+ dcr->StartFile, dcr->EndFile,
+ dcr->StartBlock, dcr->EndBlock);
Dmsg1(100, "create_jobmedia(): %s", dir->msg);
if (bnet_recv(dir) <= 0) {
Dmsg0(190, "create_jobmedia error bnet_recv\n");
exit(1);
}
/* For we must now acquire the device for writing */
- out_block = new_block(out_dev);
lock_device(out_dev);
if (open_dev(out_dev, out_jcr->VolumeName, READ_WRITE) < 0) {
Emsg1(M_FATAL, 0, _("dev open failed: %s\n"), out_dev->errmsg);
unlock_device(out_dev);
- free_block(out_block);
exit(1);
}
unlock_device(out_dev);
- if (!(out_dev=acquire_device_for_append(out_jcr, out_dev, out_block))) {
- free_block(out_block);
+ if (!acquire_device_for_append(out_jcr)) {
free_jcr(in_jcr);
exit(1);
}
+ out_block = out_jcr->dcr->block;
read_records(in_jcr, in_dev, record_cb, mount_next_read_volume);
if (!write_block_to_device(out_jcr, out_dev, out_block)) {
Pmsg2(000, _("%u Jobs copied. %u records copied.\n"), jobs, records);
- free_block(out_block);
term_dev(in_dev);
term_dev(out_dev);
free_jcr(in_jcr);
if (is_bopen(&bfd)) {
set_attributes(jcr, attr, &bfd);
}
- release_device(jcr, dev);
+ release_device(jcr);
free_attr(attr);
term_dev(dev);
int write_block_to_device(JCR *jcr, DEVICE *dev, DEV_BLOCK *block)
{
int stat = 1;
+ DCR *dcr = jcr->dcr;
+
lock_device(dev);
/*
* and set new parameters to write this volume
* The same applies for if we are in a new file.
*/
- if (jcr->NewVol || jcr->NewFile) {
+ if (dcr->NewVol || dcr->NewFile) {
/* Create a jobmedia record for this job */
if (!dir_create_jobmedia_record(jcr)) {
Jmsg(jcr, M_ERROR, 0, _("Could not create JobMedia record for Volume=\"%s\" Job=%s\n"),
unlock_device(dev);
return 0;
}
- if (jcr->NewVol) {
+ if (dcr->NewVol) {
/* Note, setting a new volume also handles any pending new file */
set_new_volume_parameters(jcr, dev);
- jcr->NewFile = false; /* this handled for new file too */
+ dcr->NewFile = false; /* this handled for new file too */
} else {
set_new_file_parameters(jcr, dev);
}
uint32_t wlen; /* length to write */
int hit_max1, hit_max2;
bool ok;
+ DCR *dcr = jcr->dcr;
#ifdef NO_TAPE_WRITE_TEST
empty_block(block);
dir_update_volume_info(jcr, dev, 0);
if (!dir_create_jobmedia_record(jcr)) {
Jmsg(jcr, M_ERROR, 0, _("Could not create JobMedia record for Volume=\"%s\" Job=%s\n"),
- jcr->VolCatInfo.VolCatName, jcr->Job);
+ dcr->VolCatInfo.VolCatName, jcr->Job);
return 0;
}
dev->file_size = 0; /* reset file size */
if (mjcr->JobId == 0) {
continue; /* ignore console */
}
- mjcr->NewFile = true; /* set reminder to do set_new_file_params */
+ mjcr->dcr->NewFile = true; /* set reminder to do set_new_file_params */
}
set_new_file_parameters(jcr, dev);
}
/* Update jcr values */
if (dev_state(dev, ST_TAPE)) {
- jcr->EndBlock = dev->EndBlock;
- jcr->EndFile = dev->EndFile;
+ dcr->EndBlock = dev->EndBlock;
+ dcr->EndFile = dev->EndFile;
} else {
/* Save address of start of block just written */
- jcr->EndBlock = (uint32_t)dev->file_addr;
- jcr->EndFile = (uint32_t)(dev->file_addr >> 32);
+ dcr->EndBlock = (uint32_t)dev->file_addr;
+ dcr->EndFile = (uint32_t)(dev->file_addr >> 32);
}
- if (jcr->VolFirstIndex == 0 && block->FirstIndex > 0) {
- jcr->VolFirstIndex = block->FirstIndex;
+ if (dcr->VolFirstIndex == 0 && block->FirstIndex > 0) {
+ dcr->VolFirstIndex = block->FirstIndex;
}
if (block->LastIndex > 0) {
- jcr->VolLastIndex = block->LastIndex;
+ dcr->VolLastIndex = block->LastIndex;
}
- jcr->WroteVol = true;
+ dcr->WroteVol = true;
dev->file_addr += wlen; /* update file address */
dev->file_size += wlen;
int looping;
uint32_t BlockNumber;
int retry;
+ DCR *dcr = jcr->dcr;
if (dev_state(dev, ST_EOT)) {
return 0;
/* Update jcr values */
if (dev->state & ST_TAPE) {
- jcr->EndBlock = dev->EndBlock;
- jcr->EndFile = dev->EndFile;
+ dcr->EndBlock = dev->EndBlock;
+ dcr->EndFile = dev->EndFile;
} else {
- jcr->EndBlock = (uint32_t)dev->file_addr;
- jcr->EndFile = (uint32_t)(dev->file_addr >> 32);
- dev->block_num = jcr->EndBlock;
- dev->file = jcr->EndFile;
+ dcr->EndBlock = (uint32_t)dev->file_addr;
+ dcr->EndFile = (uint32_t)(dev->file_addr >> 32);
+ dev->block_num = dcr->EndBlock;
+ dev->file = dcr->EndFile;
}
dev->file_addr += block->block_len;
dev->file_size += block->block_len;
static void do_close(JCR *jcr)
{
- release_device(jcr, dev);
+ release_device(jcr);
free_attr(attr);
term_dev(dev);
free_record(rec);
{
Dmsg1(100, "Walk attached jcrs. Volume=%s\n", dev->VolCatInfo.VolCatName);
for (JCR *mjcr=NULL; (mjcr=next_attached_jcr(dev, mjcr)); ) {
+ DCR *dcr = mjcr->dcr;
if (verbose) {
Pmsg1(000, _("Create JobMedia for Job %s\n"), mjcr->Job);
}
if (dev->state & ST_TAPE) {
- mjcr->EndBlock = dev->EndBlock;
- mjcr->EndFile = dev->EndFile;
+ dcr->EndBlock = dev->EndBlock;
+ dcr->EndFile = dev->EndFile;
} else {
- mjcr->EndBlock = (uint32_t)dev->file_addr;
- mjcr->StartBlock = (uint32_t)(dev->file_addr >> 32);
+ dcr->EndBlock = (uint32_t)dev->file_addr;
+ dcr->StartBlock = (uint32_t)(dev->file_addr >> 32);
}
if (!create_jobmedia_record(db, mjcr)) {
Pmsg2(000, _("Could not create JobMedia record for Volume=%s Job=%s\n"),
detach_jcr_from_device(dev, bjcr);
read_records(bjcr, dev, record_cb, bscan_mount_next_read_volume);
- release_device(bjcr, dev);
+ release_device(bjcr);
free_attr(attr);
term_dev(dev);
static int record_cb(JCR *bjcr, DEVICE *dev, DEV_BLOCK *block, DEV_RECORD *rec)
{
JCR *mjcr;
+ DCR *dcr;
char ec1[30];
if (rec->data_len > 0) {
}
/* Reset some JCR variables */
for (mjcr=NULL; (mjcr=next_attached_jcr(dev, mjcr)); ) {
- mjcr->VolFirstIndex = mjcr->FileIndex = 0;
- mjcr->StartBlock = mjcr->EndBlock = 0;
- mjcr->StartFile = mjcr->EndFile = 0;
+ dcr = mjcr->dcr;
+ dcr->VolFirstIndex = dcr->FileIndex = 0;
+ dcr->StartBlock = dcr->EndBlock = 0;
+ dcr->StartFile = dcr->EndFile = 0;
}
Pmsg1(000, _("VOL_LABEL: OK for Volume: %s\n"), mr.VolumeName);
/* process label, if Job record exists don't update db */
mjcr = create_job_record(db, &jr, &label, rec);
+ dcr = mjcr->dcr;
update_db = save_update_db;
jr.PoolId = pr.PoolId;
/* Set start positions into JCR */
if (dev->state & ST_TAPE) {
- mjcr->StartBlock = dev->block_num;
- mjcr->StartFile = dev->file;
+ dcr->StartBlock = dev->block_num;
+ dcr->StartFile = dev->file;
} else {
- mjcr->StartBlock = (uint32_t)dev->file_addr;
- mjcr->StartFile = (uint32_t)(dev->file_addr >> 32);
+ dcr->StartBlock = (uint32_t)dev->file_addr;
+ dcr->StartFile = (uint32_t)(dev->file_addr >> 32);
}
mjcr->start_time = jr.StartTime;
mjcr->JobLevel = jr.Level;
* them.
*/
if (update_db) {
- for (mjcr=NULL; (mjcr=next_attached_jcr(dev, mjcr)); ) {
+ mjcr=next_attached_jcr(dev, NULL);
+ for ( ; mjcr; ) {
+ JCR *njcr;
jr.JobId = mjcr->JobId;
jr.JobStatus = JS_ErrorTerminated;
jr.JobFiles = mjcr->JobFiles;
jr.VolSessionTime = mjcr->VolSessionTime;
jr.JobTDate = (utime_t)mjcr->start_time;
jr.ClientId = mjcr->ClientId;
- free_jcr(mjcr);
if (!db_update_job_end_record(bjcr, db, &jr)) {
Pmsg1(0, _("Could not update job record. ERR=%s\n"), db_strerror(db));
}
+ njcr = mjcr->next_dev;
+ free_jcr(mjcr);
+ mjcr = njcr;
}
}
mr.VolFiles = rec->File;
}
return 1;
}
- if (mjcr->VolFirstIndex == 0) {
- mjcr->VolFirstIndex = block->FirstIndex;
+ dcr = mjcr->dcr;
+ if (dcr->VolFirstIndex == 0) {
+ dcr->VolFirstIndex = block->FirstIndex;
}
/* File Attributes stream */
* Called from main free_jcr() routine in src/lib/jcr.c so
* that we can do our Director specific cleanup of the jcr.
*/
-static void dird_free_jcr(JCR *jcr)
+static void bscan_free_jcr(JCR *jcr)
{
Dmsg0(200, "Start dird free_jcr\n");
if (jcr->RestoreBootstrap) {
free(jcr->RestoreBootstrap);
}
+ if (jcr->dcr) {
+ free_dcr(jcr->dcr);
+ jcr->dcr = NULL;
+ }
Dmsg0(200, "End dird free_jcr\n");
}
char *fname, char *lname, int type,
char *ap, DEV_RECORD *rec)
{
-
+ DCR *dcr = mjcr->dcr;
ar.fname = fname;
ar.link = lname;
ar.ClientId = mjcr->ClientId;
ar.Stream = rec->Stream;
ar.FileIndex = rec->FileIndex;
ar.attr = ap;
- if (mjcr->VolFirstIndex == 0) {
- mjcr->VolFirstIndex = rec->FileIndex;
+ if (dcr->VolFirstIndex == 0) {
+ dcr->VolFirstIndex = rec->FileIndex;
}
- mjcr->FileIndex = rec->FileIndex;
+ dcr->FileIndex = rec->FileIndex;
mjcr->JobFiles++;
if (!update_db) {
static int create_jobmedia_record(B_DB *db, JCR *mjcr)
{
JOBMEDIA_DBR jmr;
+ DCR *dcr = mjcr->dcr;
if (dev->state & ST_TAPE) {
- mjcr->EndBlock = dev->EndBlock;
- mjcr->EndFile = dev->EndFile;
+ dcr->EndBlock = dev->EndBlock;
+ dcr->EndFile = dev->EndFile;
} else {
- mjcr->EndBlock = (uint32_t)dev->file_addr;
- mjcr->EndFile = (uint32_t)(dev->file_addr >> 32);
+ dcr->EndBlock = (uint32_t)dev->file_addr;
+ dcr->EndFile = (uint32_t)(dev->file_addr >> 32);
}
memset(&jmr, 0, sizeof(jmr));
jmr.JobId = mjcr->JobId;
jmr.MediaId = mr.MediaId;
- jmr.FirstIndex = mjcr->VolFirstIndex;
- jmr.LastIndex = mjcr->FileIndex;
- jmr.StartFile = mjcr->StartFile;
- jmr.EndFile = mjcr->EndFile;
- jmr.StartBlock = mjcr->StartBlock;
- jmr.EndBlock = mjcr->EndBlock;
+ jmr.FirstIndex = dcr->VolFirstIndex;
+ jmr.LastIndex = dcr->FileIndex;
+ jmr.StartFile = dcr->StartFile;
+ jmr.EndFile = dcr->EndFile;
+ jmr.StartBlock = dcr->StartBlock;
+ jmr.EndBlock = dcr->EndBlock;
if (!update_db) {
* Transfer as much as possible to the Job JCR. Most important is
* the JobId and the ClientId.
*/
- jobjcr = new_jcr(sizeof(JCR), dird_free_jcr);
+ jobjcr = new_jcr(sizeof(JCR), bscan_free_jcr);
jobjcr->JobType = jr->Type;
jobjcr->JobLevel = jr->Level;
jobjcr->JobStatus = jr->JobStatus;
jobjcr->VolSessionTime = rec->VolSessionTime;
jobjcr->ClientId = jr->ClientId;
attach_jcr_to_device(dev, jobjcr);
+ new_dcr(jobjcr, dev);
return jobjcr;
}
int dir_ask_sysop_to_mount_volume(JCR *jcr, DEVICE *dev)
{
- fprintf(stderr, _("Mount Volume %s on device %s and press return when ready: "),
+ fprintf(stderr, _("Mount Volume \"%s\" on device \"%s\" and press return when ready: "),
jcr->VolumeName, dev_name(dev));
getchar();
return 1;
/* Use fixed block size to simplify read back */
min_block_size = dev->min_block_size;
dev->min_block_size = dev->max_block_size;
- block = new_block(dev);
/*
* Acquire output device for writing. Note, after acquiring a
* subroutine.
*/
Dmsg0(100, "just before acquire_device\n");
- if (!(dev=acquire_device_for_append(jcr, dev, block))) {
+ if (!acquire_device_for_append(jcr)) {
set_jcr_job_status(jcr, JS_ErrorTerminated);
- free_block(block);
return;
}
+ block = jcr->dcr->block;
Dmsg0(100, "Just after acquire_device_for_append\n");
/*
/*
* Generate data as if from File daemon, write to device
*/
- jcr->VolFirstIndex = 0;
+ jcr->dcr->VolFirstIndex = 0;
time(&jcr->run_time); /* start counting time for rates */
if (simple) {
Pmsg0(-1, "Begin writing Bacula records to tape ...\n");
}
/* Release the device */
- if (!release_device(jcr, dev)) {
+ if (!release_device(jcr)) {
Pmsg0(-1, _("Error in release_device\n"));
ok = FALSE;
}
do_unfill();
dev->min_block_size = min_block_size;
- free_block(block);
free_memory(rec.data);
}
create_vol_list(jcr);
close_dev(dev);
dev->state &= ~ST_READ;
- if (!acquire_device_for_read(jcr, dev, block)) {
+ if (!acquire_device_for_read(jcr)) {
Pmsg1(-1, "%s", dev->errmsg);
goto bail_out;
}
}
dev->state &= ~ST_READ;
- if (!acquire_device_for_read(jcr, dev, block)) {
+ if (!acquire_device_for_read(jcr)) {
Pmsg1(-1, "%s", dev->errmsg);
goto bail_out;
}
int dir_create_jobmedia_record(JCR *jcr)
{
- jcr->WroteVol = false;
+ jcr->dcr->WroteVol = false;
return 1;
}
create_vol_list(jcr);
close_dev(dev);
dev->state &= ~ST_READ;
- if (!acquire_device_for_read(jcr, dev, block)) {
+ if (!acquire_device_for_read(jcr)) {
Pmsg2(0, "Cannot open Dev=%s, Vol=%s\n", dev_name(dev), jcr->VolumeName);
return 0;
}
static void set_volume_name(char *VolName, int volnum)
{
+ DCR *dcr = jcr->dcr;
VolumeName = VolName;
vol_num = volnum;
pm_strcpy(&jcr->VolumeName, VolName);
bstrncpy(dev->VolCatInfo.VolCatName, VolName, sizeof(dev->VolCatInfo.VolCatName));
bstrncpy(jcr->VolCatInfo.VolCatName, VolName, sizeof(jcr->VolCatInfo.VolCatName));
+ bstrncpy(dcr->VolCatInfo.VolCatName, VolName, sizeof(dcr->VolCatInfo.VolCatName));
+ bstrncpy(dcr->VolumeName, VolName, sizeof(dcr->VolumeName));
jcr->VolCatInfo.Slot = volnum;
+ dcr->VolCatInfo.Slot = volnum;
}
/*
DEVICE *setup_to_access_device(JCR *jcr, int read_access)
{
DEVICE *dev;
- DEV_BLOCK *block;
char *p;
DEVRES *device;
}
Dmsg0(90, "Device opened for read.\n");
- block = new_block(dev);
-
create_vol_list(jcr);
if (read_access) {
- if (!acquire_device_for_read(jcr, dev, block)) {
- free_block(block);
+ if (!acquire_device_for_read(jcr)) {
return NULL;
}
}
- free_block(block);
return dev;
}
if (jcr->VolList) {
free_vol_list(jcr);
}
+ if (jcr->dcr) {
+ free_dcr(jcr->dcr);
+ jcr->dcr = NULL;
+ }
return;
}
struct stat statp;
int tape, fifo;
int errstat;
+ DCR *dcr = NULL;
/* Check that device is available */
if (stat(device->device_name, &statp) < 0) {
Emsg0(M_FATAL, 0, dev->errmsg);
}
dev->fd = -1;
+ dev->attached_dcrs = new dlist(dcr, &dcr->dev_link);
Dmsg2(29, "init_dev: tape=%d dev_name=%s\n", dev_is_tape(dev), dev->dev_name);
+
return dev;
}
pthread_mutex_destroy(&dev->mutex);
pthread_cond_destroy(&dev->wait);
pthread_cond_destroy(&dev->wait_next_vol);
+ if (dev->attached_dcrs) {
+ delete dev->attached_dcrs;
+ dev->attached_dcrs = NULL;
+ }
if (dev->state & ST_MALLOC) {
free_pool_memory((POOLMEM *)dev);
}
/* #define NEW_LOCK 1 */
-#define new_lock_device(dev) _new_lock_device(__FILE__, __LINE__, (dev))
+#define new_lock_device(dev) _new_lock_device(__FILE__, __LINE__, (dev))
#define new_lock_device_state(dev,state) _new_lock_device(__FILE__, __LINE__, (dev), (state))
-#define new_unlock_device(dev) _new_unlock_device(__FILE__, __LINE__, (dev))
+#define new_unlock_device(dev) _new_unlock_device(__FILE__, __LINE__, (dev))
#define lock_device(d) _lock_device(__FILE__, __LINE__, (d))
#define unlock_device(d) _unlock_device(__FILE__, __LINE__, (d))
#define give_back_device_lock(d, p) _give_back_device_lock(__FILE__, __LINE__, (d), (p))
/* Arguments to open_dev() */
-#define READ_WRITE 0
-#define READ_ONLY 1
+#define READ_WRITE 0
+#define READ_ONLY 1
#define OPEN_READ_WRITE 0
-#define OPEN_READ_ONLY 1
+#define OPEN_READ_ONLY 1
#define OPEN_WRITE_ONLY 2
/* Generic status bits returned from status_dev() */
-#define BMT_TAPE (1<<0) /* is tape device */
-#define BMT_EOF (1<<1) /* just read EOF */
-#define BMT_BOT (1<<2) /* at beginning of tape */
-#define BMT_EOT (1<<3) /* end of tape reached */
-#define BMT_SM (1<<4) /* DDS setmark */
-#define BMT_EOD (1<<5) /* DDS at end of data */
-#define BMT_WR_PROT (1<<6) /* tape write protected */
-#define BMT_ONLINE (1<<7) /* tape online */
-#define BMT_DR_OPEN (1<<8) /* tape door open */
-#define BMT_IM_REP_EN (1<<9) /* immediate report enabled */
+#define BMT_TAPE (1<<0) /* is tape device */
+#define BMT_EOF (1<<1) /* just read EOF */
+#define BMT_BOT (1<<2) /* at beginning of tape */
+#define BMT_EOT (1<<3) /* end of tape reached */
+#define BMT_SM (1<<4) /* DDS setmark */
+#define BMT_EOD (1<<5) /* DDS at end of data */
+#define BMT_WR_PROT (1<<6) /* tape write protected */
+#define BMT_ONLINE (1<<7) /* tape online */
+#define BMT_DR_OPEN (1<<8) /* tape door open */
+#define BMT_IM_REP_EN (1<<9) /* immediate report enabled */
/* Test capabilities */
#define dev_cap(dev, cap) ((dev)->capabilities & (cap))
/* Bits for device capabilities */
-#define CAP_EOF (1<<0) /* has MTWEOF */
-#define CAP_BSR (1<<1) /* has MTBSR */
-#define CAP_BSF (1<<2) /* has MTBSF */
-#define CAP_FSR (1<<3) /* has MTFSR */
-#define CAP_FSF (1<<4) /* has MTFSF */
-#define CAP_EOM (1<<5) /* has MTEOM */
-#define CAP_REM (1<<6) /* is removable media */
-#define CAP_RACCESS (1<<7) /* is random access device */
-#define CAP_AUTOMOUNT (1<<8) /* Read device at start to see what is there */
-#define CAP_LABEL (1<<9) /* Label blank tapes */
-#define CAP_ANONVOLS (1<<10) /* Mount without knowing volume name */
-#define CAP_ALWAYSOPEN (1<<11) /* always keep device open */
+#define CAP_EOF (1<<0) /* has MTWEOF */
+#define CAP_BSR (1<<1) /* has MTBSR */
+#define CAP_BSF (1<<2) /* has MTBSF */
+#define CAP_FSR (1<<3) /* has MTFSR */
+#define CAP_FSF (1<<4) /* has MTFSF */
+#define CAP_EOM (1<<5) /* has MTEOM */
+#define CAP_REM (1<<6) /* is removable media */
+#define CAP_RACCESS (1<<7) /* is random access device */
+#define CAP_AUTOMOUNT (1<<8) /* Read device at start to see what is there */
+#define CAP_LABEL (1<<9) /* Label blank tapes */
+#define CAP_ANONVOLS (1<<10) /* Mount without knowing volume name */
+#define CAP_ALWAYSOPEN (1<<11) /* always keep device open */
#define CAP_AUTOCHANGER (1<<12) /* AutoChanger */
#define CAP_OFFLINEUNMOUNT (1<<13) /* Offline before unmount */
-#define CAP_STREAM (1<<14) /* Stream device */
-#define CAP_BSFATEOM (1<<15) /* Backspace file at EOM */
-#define CAP_FASTFSF (1<<16) /* Fast forward space file */
-#define CAP_TWOEOF (1<<17) /* Write two eofs for EOM */
+#define CAP_STREAM (1<<14) /* Stream device */
+#define CAP_BSFATEOM (1<<15) /* Backspace file at EOM */
+#define CAP_FASTFSF (1<<16) /* Fast forward space file */
+#define CAP_TWOEOF (1<<17) /* Write two eofs for EOM */
#define CAP_CLOSEONPOLL (1<<18) /* Close device on polling */
/* Test state */
#define dev_state(dev, st_state) ((dev)->state & (st_state))
/* Device state bits */
-#define ST_OPENED (1<<0) /* set when device opened */
-#define ST_TAPE (1<<1) /* is a tape device */
-#define ST_FILE (1<<2) /* is a file device */
-#define ST_FIFO (1<<3) /* is a fifo device */
-#define ST_PROG (1<<4) /* is a program device */
-#define ST_LABEL (1<<5) /* label found */
+#define ST_OPENED (1<<0) /* set when device opened */
+#define ST_TAPE (1<<1) /* is a tape device */
+#define ST_FILE (1<<2) /* is a file device */
+#define ST_FIFO (1<<3) /* is a fifo device */
+#define ST_PROG (1<<4) /* is a program device */
+#define ST_LABEL (1<<5) /* label found */
#define ST_MALLOC (1<<6) /* dev packet malloc'ed in init_dev() */
-#define ST_APPEND (1<<7) /* ready for Bacula append */
-#define ST_READ (1<<8) /* ready for Bacula read */
-#define ST_EOT (1<<9) /* at end of tape */
-#define ST_WEOT (1<<10) /* Got EOT on write */
-#define ST_EOF (1<<11) /* Read EOF i.e. zero bytes */
-#define ST_NEXTVOL (1<<12) /* Start writing on next volume */
-#define ST_SHORT (1<<13) /* Short block read */
+#define ST_APPEND (1<<7) /* ready for Bacula append */
+#define ST_READ (1<<8) /* ready for Bacula read */
+#define ST_EOT (1<<9) /* at end of tape */
+#define ST_WEOT (1<<10) /* Got EOT on write */
+#define ST_EOF (1<<11) /* Read EOF i.e. zero bytes */
+#define ST_NEXTVOL (1<<12) /* Start writing on next volume */
+#define ST_SHORT (1<<13) /* Short block read */
/* dev_blocked states (mutually exclusive) */
#define BST_NOT_BLOCKED 0 /* not blocked */
-#define BST_UNMOUNTED 1 /* User unmounted device */
+#define BST_UNMOUNTED 1 /* User unmounted device */
#define BST_WAITING_FOR_SYSOP 2 /* Waiting for operator to mount tape */
#define BST_DOING_ACQUIRE 3 /* Opening/validating/moving tape */
#define BST_WRITING_LABEL 4 /* Labeling a tape */
#define BST_UNMOUNTED_WAITING_FOR_SYSOP 5 /* Closed by user during mount request */
-#define BST_MOUNT 6 /* Mount request */
+#define BST_MOUNT 6 /* Mount request */
/* Volume Catalog Information structure definition */
struct VOLUME_CAT_INFO {
/* Media info for the current Volume */
- uint32_t VolCatJobs; /* number of jobs on this Volume */
- uint32_t VolCatFiles; /* Number of files */
- uint32_t VolCatBlocks; /* Number of blocks */
- uint64_t VolCatBytes; /* Number of bytes written */
- uint32_t VolCatMounts; /* Number of mounts this volume */
- uint32_t VolCatErrors; /* Number of errors this volume */
- uint32_t VolCatWrites; /* Number of writes this volume */
- uint32_t VolCatReads; /* Number of reads this volume */
- uint64_t VolCatRBytes; /* Number of bytes read */
- uint32_t VolCatRecycles; /* Number of recycles this volume */
- int32_t Slot; /* Slot in changer */
- bool InChanger; /* Set if vol in current magazine */
- uint32_t VolCatMaxJobs; /* Maximum Jobs to write to volume */
- uint32_t VolCatMaxFiles; /* Maximum files to write to volume */
- uint64_t VolCatMaxBytes; /* Max bytes to write to volume */
+ uint32_t VolCatJobs; /* number of jobs on this Volume */
+ uint32_t VolCatFiles; /* Number of files */
+ uint32_t VolCatBlocks; /* Number of blocks */
+ uint64_t VolCatBytes; /* Number of bytes written */
+ uint32_t VolCatMounts; /* Number of mounts this volume */
+ uint32_t VolCatErrors; /* Number of errors this volume */
+ uint32_t VolCatWrites; /* Number of writes this volume */
+ uint32_t VolCatReads; /* Number of reads this volume */
+ uint64_t VolCatRBytes; /* Number of bytes read */
+ uint32_t VolCatRecycles; /* Number of recycles this volume */
+ int32_t Slot; /* Slot in changer */
+ bool InChanger; /* Set if vol in current magazine */
+ uint32_t VolCatMaxJobs; /* Maximum Jobs to write to volume */
+ uint32_t VolCatMaxFiles; /* Maximum files to write to volume */
+ uint64_t VolCatMaxBytes; /* Max bytes to write to volume */
uint64_t VolCatCapacityBytes; /* capacity estimate */
- uint64_t VolReadTime; /* time spent reading */
- uint64_t VolWriteTime; /* time spent writing this Volume */
- char VolCatStatus[20]; /* Volume status */
+ uint64_t VolReadTime; /* time spent reading */
+ uint64_t VolWriteTime; /* time spent writing this Volume */
+ char VolCatStatus[20]; /* Volume status */
char VolCatName[MAX_NAME_LENGTH]; /* Desired volume to mount */
-};
+};
typedef struct s_steal_lock {
- pthread_t no_wait_id; /* id of no wait thread */
- int dev_blocked; /* state */
- int dev_prev_blocked; /* previous blocked state */
+ pthread_t no_wait_id; /* id of no wait thread */
+ int dev_blocked; /* state */
+ int dev_prev_blocked; /* previous blocked state */
} bsteal_lock_t;
-struct DEVRES; /* Device resource defined in stored_conf.h */
+struct DEVRES; /* Device resource defined in stored_conf.h */
-/* Device structure definition */
+/*
+ * Device structure definition. There is one of these for
+ * each physical device. Everything here is "global" to
+ * that device and effects all jobs using the device.
+ */
struct DEVICE {
public:
- DEVICE *next; /* pointer to next open device */
- DEVICE *prev; /* pointer to prev open device */
- JCR *attached_jcrs; /* attached JCR list */
- pthread_mutex_t mutex; /* access control */
- pthread_cond_t wait; /* thread wait variable */
+ DEVICE *next; /* pointer to next open device */
+ DEVICE *prev; /* pointer to prev open device */
+ JCR *attached_jcrs; /* attached JCR list */
+ dlist *attached_dcrs; /* attached DCR list */
+ pthread_mutex_t mutex; /* access control */
+ pthread_cond_t wait; /* thread wait variable */
pthread_cond_t wait_next_vol; /* wait for tape to be mounted */
- pthread_t no_wait_id; /* this thread must not wait */
- int dev_blocked; /* set if we must wait (i.e. change tape) */
- int dev_prev_blocked; /* previous blocked state */
- int num_waiting; /* number of threads waiting */
- int num_writers; /* number of writing threads */
- int use_count; /* usage count on this device */
- int fd; /* file descriptor */
- int capabilities; /* capabilities mask */
- int state; /* state mask */
- int dev_errno; /* Our own errno */
- int mode; /* read/write modes */
- char *dev_name; /* device name */
- char *errmsg; /* nicely edited error message */
- uint32_t block_num; /* current block number base 0 */
- uint32_t file; /* current file number base 0 */
- uint64_t file_addr; /* Current file read/write address */
- uint64_t file_size; /* Current file size */
- uint32_t EndBlock; /* last block written */
- uint32_t EndFile; /* last file written */
- uint32_t min_block_size; /* min block size */
- uint32_t max_block_size; /* max block size */
- uint64_t max_volume_size; /* max bytes to put on one volume */
- uint64_t max_file_size; /* max file size to put in one file on volume */
- uint64_t volume_capacity; /* advisory capacity */
- uint32_t max_rewind_wait; /* max secs to allow for rewind */
- uint32_t max_open_wait; /* max secs to allow for open */
- uint32_t max_open_vols; /* max simultaneous open volumes */
- utime_t vol_poll_interval; /* interval between polling Vol mount */
- DEVRES *device; /* pointer to Device Resource */
- btimer_t *tid; /* timer id */
-
- VOLUME_CAT_INFO VolCatInfo; /* Volume Catalog Information */
- VOLUME_LABEL VolHdr; /* Actual volume label */
+ pthread_t no_wait_id; /* this thread must not wait */
+ int dev_blocked; /* set if we must wait (i.e. change tape) */
+ int dev_prev_blocked; /* previous blocked state */
+ int num_waiting; /* number of threads waiting */
+ int num_writers; /* number of writing threads */
+ int use_count; /* usage count on this device */
+ int fd; /* file descriptor */
+ int capabilities; /* capabilities mask */
+ int state; /* state mask */
+ int dev_errno; /* Our own errno */
+ int mode; /* read/write modes */
+ char *dev_name; /* device name */
+ char *errmsg; /* nicely edited error message */
+ uint32_t block_num; /* current block number base 0 */
+ uint32_t file; /* current file number base 0 */
+ uint64_t file_addr; /* Current file read/write address */
+ uint64_t file_size; /* Current file size */
+ uint32_t EndBlock; /* last block written */
+ uint32_t EndFile; /* last file written */
+ uint32_t min_block_size; /* min block size */
+ uint32_t max_block_size; /* max block size */
+ uint64_t max_volume_size; /* max bytes to put on one volume */
+ uint64_t max_file_size; /* max file size to put in one file on volume */
+ uint64_t volume_capacity; /* advisory capacity */
+ uint32_t max_rewind_wait; /* max secs to allow for rewind */
+ uint32_t max_open_wait; /* max secs to allow for open */
+ uint32_t max_open_vols; /* max simultaneous open volumes */
+ utime_t vol_poll_interval; /* interval between polling Vol mount */
+ DEVRES *device; /* pointer to Device Resource */
+ btimer_t *tid; /* timer id */
+
+ VOLUME_CAT_INFO VolCatInfo; /* Volume Catalog Information */
+ VOLUME_LABEL VolHdr; /* Actual volume label */
/* Device wait times ***FIXME*** look at durations */
char BadVolName[MAX_NAME_LENGTH]; /* Last wrong Volume mounted */
- bool poll; /* set to poll Volume */
+ bool poll; /* set to poll Volume */
int min_wait;
int max_wait;
int max_num_wait;
int num_wait;
};
+/*
+ * Device Context (or Control) Record.
+ * There is one of these records for each Job that is using
+ * the device. Items in this record are "local" to the Job and
+ * do not affect other Jobs.
+ */
+struct DCR {
+ dlink dev_link; /* link to attach to dev */
+ JCR *jcr; /* pointer to JCR */
+ DEVICE *dev; /* pointer to device */
+ DEV_BLOCK *block; /* pointer to block */
+ DEV_RECORD *record; /* pointer to record */
+ bool spool_data; /* set to spool data */
+ int spool_fd; /* fd if spooling */
+ bool NewVol; /* set if new Volume mounted */
+ bool WroteVol; /* set if Volume written */
+ bool NewFile; /* set when EOF written */
+ uint32_t VolFirstIndex; /* First file index this Volume */
+ uint32_t VolLastIndex; /* Last file index this Volume */
+ uint32_t FileIndex; /* Current File Index */
+ uint32_t EndFile; /* End file written */
+ uint32_t StartFile; /* Start write file */
+ uint32_t StartBlock; /* Start write block */
+ uint32_t EndBlock; /* Ending block written */
+ char VolumeName[MAX_NAME_LENGTH]; /* Volume name */
+ VOLUME_CAT_INFO VolCatInfo; /* Catalog info for desired volume */
+};
+
/* Get some definition of function to position
* to the end of the medium in MTEOM. System
* dependent. Arrgggg!
*/
#ifndef MTEOM
-#ifdef MTSEOD
+#ifdef MTSEOD
#define MTEOM MTSEOD
#endif
#ifdef MTEOD
if (mjcr->JobId == 0) {
continue; /* ignore console */
}
- mjcr->NewVol = true;
+ mjcr->dcr->NewVol = true;
if (jcr != mjcr) {
pm_strcpy(&mjcr->VolumeName, jcr->VolumeName); /* get a copy of the new volume */
+ bstrncpy(mjcr->dcr->VolumeName, jcr->VolumeName, sizeof(mjcr->dcr->VolumeName));
}
}
/* Clear NewVol now because dir_get_volume_info() already done */
- jcr->NewVol = false;
+ jcr->dcr->NewVol = false;
set_new_volume_parameters(jcr, dev);
jcr->run_time += time(NULL) - wait_time; /* correct run time for mount wait */
*/
void set_new_volume_parameters(JCR *jcr, DEVICE *dev)
{
- if (jcr->NewVol && !dir_get_volume_info(jcr, GET_VOL_INFO_FOR_WRITE)) {
+ DCR *dcr = jcr->dcr;
+ if (dcr->NewVol && !dir_get_volume_info(jcr, GET_VOL_INFO_FOR_WRITE)) {
Jmsg1(jcr, M_ERROR, 0, "%s", jcr->errmsg);
}
/* Set new start/end positions */
if (dev_state(dev, ST_TAPE)) {
- jcr->StartBlock = dev->block_num;
- jcr->StartFile = dev->file;
+ dcr->StartBlock = dev->block_num;
+ dcr->StartFile = dev->file;
} else {
- jcr->StartBlock = (uint32_t)dev->file_addr;
- jcr->StartFile = (uint32_t)(dev->file_addr >> 32);
+ dcr->StartBlock = (uint32_t)dev->file_addr;
+ dcr->StartFile = (uint32_t)(dev->file_addr >> 32);
}
/* Reset indicies */
- jcr->VolFirstIndex = 0;
- jcr->VolLastIndex = 0;
+ dcr->VolFirstIndex = 0;
+ dcr->VolLastIndex = 0;
jcr->NumVolumes++;
- jcr->NewVol = false;
- jcr->WroteVol = false;
+ dcr->NewVol = false;
+ dcr->WroteVol = false;
}
/*
*/
void set_new_file_parameters(JCR *jcr, DEVICE *dev)
{
+ DCR *dcr = jcr->dcr;
+
/* Set new start/end positions */
if (dev_state(dev, ST_TAPE)) {
- jcr->StartBlock = dev->block_num;
- jcr->StartFile = dev->file;
+ dcr->StartBlock = dev->block_num;
+ dcr->StartFile = dev->file;
} else {
- jcr->StartBlock = (uint32_t)dev->file_addr;
- jcr->StartFile = (uint32_t)(dev->file_addr >> 32);
+ dcr->StartBlock = (uint32_t)dev->file_addr;
+ dcr->StartFile = (uint32_t)(dev->file_addr >> 32);
}
/* Reset indicies */
- jcr->VolFirstIndex = 0;
- jcr->VolLastIndex = 0;
- jcr->NewFile = false;
- jcr->WroteVol = false;
+ dcr->VolFirstIndex = 0;
+ dcr->VolLastIndex = 0;
+ dcr->NewFile = false;
+ dcr->WroteVol = false;
}
break;
}
}
+ if (found) {
+ jcr->dcr = new_dcr(jcr, device->dev);
+ }
UnlockRes();
return found;
}
*/
ojcr = get_jcr_by_full_name(job);
if (ojcr && !ojcr->authenticated) {
- Dmsg2(100, "Found ojcr=0x%x Job %s\n", (unsigned)ojcr, job);
+ Dmsg2(100, "Found ojcr=0x%x Job %s\n", (unsigned)(long)ojcr, job);
free_jcr(ojcr);
}
jcr->JobId = JobId;
Emsg0(M_FATAL, 0, _("In free_jcr(), but still attached to device!!!!\n"));
}
pthread_cond_destroy(&jcr->job_start_wait);
+ if (jcr->dcr) {
+ free_dcr(jcr->dcr);
+ jcr->dcr = NULL;
+ }
return;
}
*/
void create_session_label(JCR *jcr, DEV_RECORD *rec, int label)
{
+ DCR *dcr = jcr->dcr;
ser_declare;
rec->VolSessionId = jcr->VolSessionId;
if (label == EOS_LABEL) {
ser_uint32(jcr->JobFiles);
ser_uint64(jcr->JobBytes);
- ser_uint32(jcr->StartBlock);
- ser_uint32(jcr->EndBlock);
- ser_uint32(jcr->StartFile);
- ser_uint32(jcr->EndFile);
+ ser_uint32(dcr->StartBlock);
+ ser_uint32(dcr->EndBlock);
+ ser_uint32(dcr->StartFile);
+ ser_uint32(dcr->EndFile);
ser_uint32(jcr->JobErrors);
/* Added in VerNum 11 */
int write_session_label(JCR *jcr, DEV_BLOCK *block, int label)
{
DEVICE *dev = jcr->device->dev;
+ DCR *dcr = jcr->dcr;
DEV_RECORD *rec;
rec = new_record();
switch (label) {
case SOS_LABEL:
if (dev->state & ST_TAPE) {
- jcr->StartBlock = dev->block_num;
- jcr->StartFile = dev->file;
+ dcr->StartBlock = dev->block_num;
+ dcr->StartFile = dev->file;
} else {
- jcr->StartBlock = (uint32_t)dev->file_addr;
- jcr->StartFile = (uint32_t)(dev->file_addr >> 32);
+ dcr->StartBlock = (uint32_t)dev->file_addr;
+ dcr->StartFile = (uint32_t)(dev->file_addr >> 32);
}
break;
case EOS_LABEL:
if (dev->state & ST_TAPE) {
- jcr->EndBlock = dev->EndBlock;
- jcr->EndFile = dev->EndFile;
+ dcr->EndBlock = dev->EndBlock;
+ dcr->EndFile = dev->EndFile;
} else {
- jcr->EndBlock = (uint32_t)dev->file_addr;
- jcr->EndFile = (uint32_t)(dev->file_addr >> 32);
+ dcr->EndBlock = (uint32_t)dev->file_addr;
+ dcr->EndFile = (uint32_t)(dev->file_addr >> 32);
}
break;
default:
if (jcr->NumVolumes > 1 && jcr->CurVolume < jcr->NumVolumes) {
close_dev(dev);
dev->state &= ~ST_READ;
- if (!acquire_device_for_read(jcr, dev, block)) {
+ if (!acquire_device_for_read(jcr)) {
Jmsg2(jcr, M_FATAL, 0, "Cannot open Dev=%s, Vol=%s\n", dev_name(dev),
jcr->VolumeName);
return 0;
*/
void release_volume(JCR *jcr, DEVICE *dev)
{
- if (jcr->WroteVol) {
+ if (jcr->dcr->WroteVol) {
Jmsg0(jcr, M_ERROR, 0, "Hey!!!!! WroteVol non-zero !!!!!\n");
}
/*
uint32_t new_VolSessionId();
/* From acquire.c */
-DEVICE *acquire_device_for_append(JCR *jcr, DEVICE *dev, DEV_BLOCK *block);
-int acquire_device_for_read(JCR *jcr, DEVICE *dev, DEV_BLOCK *block);
-int release_device(JCR *jcr, DEVICE *dev);
+DCR *acquire_device_for_append(JCR *jcr);
+DCR *acquire_device_for_read(JCR *jcr);
+int release_device(JCR *jcr);
+DCR *new_dcr(JCR *jcr, DEVICE *dev);
+void free_dcr(DCR *dcr);
/* From askdir.c */
enum get_vol_info_rw {
GET_VOL_INFO_FOR_WRITE,
GET_VOL_INFO_FOR_READ
};
-int dir_get_volume_info(JCR *jcr, enum get_vol_info_rw);
-int dir_find_next_appendable_volume(JCR *jcr);
-int dir_update_volume_info(JCR *jcr, DEVICE *dev, int label);
-int dir_ask_sysop_to_create_appendable_volume(JCR *jcr, DEVICE *dev);
-int dir_ask_sysop_to_mount_volume(JCR *jcr, DEVICE *dev);
-int dir_update_file_attributes(JCR *jcr, DEV_RECORD *rec);
-int dir_send_job_status(JCR *jcr);
-int dir_create_jobmedia_record(JCR *jcr);
+int dir_get_volume_info(JCR *jcr, enum get_vol_info_rw);
+int dir_find_next_appendable_volume(JCR *jcr);
+int dir_update_volume_info(JCR *jcr, DEVICE *dev, int label);
+int dir_ask_sysop_to_create_appendable_volume(JCR *jcr, DEVICE *dev);
+int dir_ask_sysop_to_mount_volume(JCR *jcr, DEVICE *dev);
+int dir_update_file_attributes(JCR *jcr, DEV_RECORD *rec);
+int dir_send_job_status(JCR *jcr);
+int dir_create_jobmedia_record(JCR *jcr);
/* authenticate.c */
-int authenticate_director(JCR *jcr);
-int authenticate_filed(JCR *jcr);
+int authenticate_director(JCR *jcr);
+int authenticate_filed(JCR *jcr);
/* From block.c */
-void dump_block(DEV_BLOCK *b, char *msg);
+void dump_block(DEV_BLOCK *b, char *msg);
DEV_BLOCK *new_block(DEVICE *dev);
DEV_BLOCK *dup_block(DEV_BLOCK *eblock);
-void init_block_write(DEV_BLOCK *block);
-void empty_block(DEV_BLOCK *block);
-void free_block(DEV_BLOCK *block);
-int write_block_to_device(JCR *jcr, DEVICE *dev, DEV_BLOCK *block);
-int write_block_to_dev(JCR *jcr, DEVICE *dev, DEV_BLOCK *block);
-void print_block_read_errors(JCR *jcr, DEV_BLOCK *block);
+void init_block_write(DEV_BLOCK *block);
+void empty_block(DEV_BLOCK *block);
+void free_block(DEV_BLOCK *block);
+int write_block_to_device(JCR *jcr, DEVICE *dev, DEV_BLOCK *block);
+int write_block_to_dev(JCR *jcr, DEVICE *dev, DEV_BLOCK *block);
+void print_block_read_errors(JCR *jcr, DEV_BLOCK *block);
#define CHECK_BLOCK_NUMBERS true
#define NO_BLOCK_NUMBER_CHECK false
-int read_block_from_device(JCR *jcr, DEVICE *dev, DEV_BLOCK *block, bool check_block_numbers);
-int read_block_from_dev(JCR *jcr, DEVICE *dev, DEV_BLOCK *block, bool check_block_numbers);
+int read_block_from_device(JCR *jcr, DEVICE *dev, DEV_BLOCK *block, bool check_block_numbers);
+int read_block_from_dev(JCR *jcr, DEVICE *dev, DEV_BLOCK *block, bool check_block_numbers);
/* From butil.c -- utilities for SD tool programs */
-void print_ls_output(char *fname, char *link, int type, struct stat *statp);
+void print_ls_output(char *fname, char *link, int type, struct stat *statp);
JCR *setup_jcr(char *name, char *device, BSR *bsr, char *VolumeName);
DEVICE *setup_to_access_device(JCR *jcr, int read_access);
-void display_tape_error_status(JCR *jcr, DEVICE *dev);
+void display_tape_error_status(JCR *jcr, DEVICE *dev);
DEVRES *find_device_res(char *device_name, int read_access);
/* From dev.c */
-DEVICE *init_dev(DEVICE *dev, DEVRES *device);
-int open_dev(DEVICE *dev, char *VolName, int mode);
-void close_dev(DEVICE *dev);
-void force_close_dev(DEVICE *dev);
-int truncate_dev(DEVICE *dev);
-void term_dev(DEVICE *dev);
-char * strerror_dev(DEVICE *dev);
-void clrerror_dev(DEVICE *dev, int func);
-int update_pos_dev(DEVICE *dev);
-int rewind_dev(DEVICE *dev);
-int load_dev(DEVICE *dev);
-int offline_dev(DEVICE *dev);
-int flush_dev(DEVICE *dev);
-int weof_dev(DEVICE *dev, int num);
-int write_block(DEVICE *dev);
-int write_dev(DEVICE *dev, char *buf, size_t len);
-int read_dev(DEVICE *dev, char *buf, size_t len);
+DEVICE *init_dev(DEVICE *dev, DEVRES *device);
+int open_dev(DEVICE *dev, char *VolName, int mode);
+void close_dev(DEVICE *dev);
+void force_close_dev(DEVICE *dev);
+int truncate_dev(DEVICE *dev);
+void term_dev(DEVICE *dev);
+char * strerror_dev(DEVICE *dev);
+void clrerror_dev(DEVICE *dev, int func);
+int update_pos_dev(DEVICE *dev);
+int rewind_dev(DEVICE *dev);
+int load_dev(DEVICE *dev);
+int offline_dev(DEVICE *dev);
+int flush_dev(DEVICE *dev);
+int weof_dev(DEVICE *dev, int num);
+int write_block(DEVICE *dev);
+int write_dev(DEVICE *dev, char *buf, size_t len);
+int read_dev(DEVICE *dev, char *buf, size_t len);
uint32_t status_dev(DEVICE *dev);
-int eod_dev(DEVICE *dev);
-int fsf_dev(DEVICE *dev, int num);
-int fsr_dev(DEVICE *dev, int num);
-int bsf_dev(DEVICE *dev, int num);
-int bsr_dev(DEVICE *dev, int num);
-void attach_jcr_to_device(DEVICE *dev, JCR *jcr);
-void detach_jcr_from_device(DEVICE *dev, JCR *jcr);
-JCR *next_attached_jcr(DEVICE *dev, JCR *jcr);
-int dev_can_write(DEVICE *dev);
-int offline_or_rewind_dev(DEVICE *dev);
-int reposition_dev(DEVICE *dev, uint32_t file, uint32_t block);
-void init_dev_wait_timers(DEVICE *dev);
-bool double_dev_wait_time(DEVICE *dev);
+int eod_dev(DEVICE *dev);
+int fsf_dev(DEVICE *dev, int num);
+int fsr_dev(DEVICE *dev, int num);
+int bsf_dev(DEVICE *dev, int num);
+int bsr_dev(DEVICE *dev, int num);
+void attach_jcr_to_device(DEVICE *dev, JCR *jcr);
+void detach_jcr_from_device(DEVICE *dev, JCR *jcr);
+JCR *next_attached_jcr(DEVICE *dev, JCR *jcr);
+int dev_can_write(DEVICE *dev);
+int offline_or_rewind_dev(DEVICE *dev);
+int reposition_dev(DEVICE *dev, uint32_t file, uint32_t block);
+void init_dev_wait_timers(DEVICE *dev);
+bool double_dev_wait_time(DEVICE *dev);
/* Get info about device */
-char * dev_name(DEVICE *dev);
-char * dev_vol_name(DEVICE *dev);
+char * dev_name(DEVICE *dev);
+char * dev_vol_name(DEVICE *dev);
uint32_t dev_block(DEVICE *dev);
uint32_t dev_file(DEVICE *dev);
-int dev_is_tape(DEVICE *dev);
+int dev_is_tape(DEVICE *dev);
/* From device.c */
-int open_device(JCR *jcr, DEVICE *dev);
-int first_open_device(DEVICE *dev);
-int fixup_device_block_write_error(JCR *jcr, DEVICE *dev, DEV_BLOCK *block);
-void _lock_device(char *file, int line, DEVICE *dev);
-void _unlock_device(char *file, int line, DEVICE *dev);
-void _block_device(char *file, int line, DEVICE *dev, int state);
-void _unblock_device(char *file, int line, DEVICE *dev);
-void _steal_device_lock(char *file, int line, DEVICE *dev, bsteal_lock_t *hold, int state);
-void _give_back_device_lock(char *file, int line, DEVICE *dev, bsteal_lock_t *hold);
-void set_new_volume_parameters(JCR *jcr, DEVICE *dev);
-void set_new_file_parameters(JCR *jcr, DEVICE *dev);
-int device_is_unmounted(DEVICE *dev);
+int open_device(JCR *jcr, DEVICE *dev);
+int first_open_device(DEVICE *dev);
+int fixup_device_block_write_error(JCR *jcr, DEVICE *dev, DEV_BLOCK *block);
+void _lock_device(char *file, int line, DEVICE *dev);
+void _unlock_device(char *file, int line, DEVICE *dev);
+void _block_device(char *file, int line, DEVICE *dev, int state);
+void _unblock_device(char *file, int line, DEVICE *dev);
+void _steal_device_lock(char *file, int line, DEVICE *dev, bsteal_lock_t *hold, int state);
+void _give_back_device_lock(char *file, int line, DEVICE *dev, bsteal_lock_t *hold);
+void set_new_volume_parameters(JCR *jcr, DEVICE *dev);
+void set_new_file_parameters(JCR *jcr, DEVICE *dev);
+int device_is_unmounted(DEVICE *dev);
/* From dircmd.c */
-void *connection_request(void *arg);
+void *connection_request(void *arg);
/* From fd_cmds.c */
-void run_job(JCR *jcr);
+void run_job(JCR *jcr);
/* From job.c */
-void stored_free_jcr(JCR *jcr);
-void connection_from_filed(void *arg);
-void handle_filed_connection(BSOCK *fd, char *job_name);
+void stored_free_jcr(JCR *jcr);
+void connection_from_filed(void *arg);
+void handle_filed_connection(BSOCK *fd, char *job_name);
/* From label.c */
-int read_dev_volume_label(JCR *jcr, DEVICE *dev, DEV_BLOCK *block);
-void create_session_label(JCR *jcr, DEV_RECORD *rec, int label);
-void create_volume_label(DEVICE *dev, char *VolName, char *PoolName);
-int write_volume_label_to_dev(JCR *jcr, DEVRES *device, char *VolName, char *PoolName);
-int write_session_label(JCR *jcr, DEV_BLOCK *block, int label);
-int write_volume_label_to_block(JCR *jcr, DEVICE *dev, DEV_BLOCK *block);
-void dump_volume_label(DEVICE *dev);
-void dump_label_record(DEVICE *dev, DEV_RECORD *rec, int verbose);
-int unser_volume_label(DEVICE *dev, DEV_RECORD *rec);
-int unser_session_label(SESSION_LABEL *label, DEV_RECORD *rec);
+int read_dev_volume_label(JCR *jcr, DEVICE *dev, DEV_BLOCK *block);
+void create_session_label(JCR *jcr, DEV_RECORD *rec, int label);
+void create_volume_label(DEVICE *dev, char *VolName, char *PoolName);
+int write_volume_label_to_dev(JCR *jcr, DEVRES *device, char *VolName, char *PoolName);
+int write_session_label(JCR *jcr, DEV_BLOCK *block, int label);
+int write_volume_label_to_block(JCR *jcr, DEVICE *dev, DEV_BLOCK *block);
+void dump_volume_label(DEVICE *dev);
+void dump_label_record(DEVICE *dev, DEV_RECORD *rec, int verbose);
+int unser_volume_label(DEVICE *dev, DEV_RECORD *rec);
+int unser_session_label(SESSION_LABEL *label, DEV_RECORD *rec);
/* From match_bsr.c */
-int match_bsr(BSR *bsr, DEV_RECORD *rec, VOLUME_LABEL *volrec,
- SESSION_LABEL *sesrec);
-int match_bsr_block(BSR *bsr, DEV_BLOCK *block);
-void position_bsr_block(BSR *bsr, DEV_BLOCK *block);
-BSR *find_next_bsr(BSR *root_bsr, DEVICE *dev);
-bool match_set_eof(BSR *bsr, DEV_RECORD *rec);
+int match_bsr(BSR *bsr, DEV_RECORD *rec, VOLUME_LABEL *volrec,
+ SESSION_LABEL *sesrec);
+int match_bsr_block(BSR *bsr, DEV_BLOCK *block);
+void position_bsr_block(BSR *bsr, DEV_BLOCK *block);
+BSR *find_next_bsr(BSR *root_bsr, DEVICE *dev);
+bool match_set_eof(BSR *bsr, DEV_RECORD *rec);
/* From mount.c */
-int mount_next_write_volume(JCR *jcr, DEVICE *dev, DEV_BLOCK *block, int release);
-int mount_next_read_volume(JCR *jcr, DEVICE *dev, DEV_BLOCK *block);
-void release_volume(JCR *jcr, DEVICE *dev);
-void mark_volume_in_error(JCR *jcr, DEVICE *dev);
+int mount_next_write_volume(JCR *jcr, DEVICE *dev, DEV_BLOCK *block, int release);
+int mount_next_read_volume(JCR *jcr, DEVICE *dev, DEV_BLOCK *block);
+void release_volume(JCR *jcr, DEVICE *dev);
+void mark_volume_in_error(JCR *jcr, DEVICE *dev);
/* From autochanger.c */
-int autoload_device(JCR *jcr, DEVICE *dev, int writing, BSOCK *dir);
-int autochanger_list(JCR *jcr, DEVICE *dev, BSOCK *dir);
-void invalidate_slot_in_catalog(JCR *jcr, DEVICE *dev);
+int autoload_device(JCR *jcr, DEVICE *dev, int writing, BSOCK *dir);
+int autochanger_list(JCR *jcr, DEVICE *dev, BSOCK *dir);
+void invalidate_slot_in_catalog(JCR *jcr, DEVICE *dev);
/* From parse_bsr.c */
-BSR *parse_bsr(JCR *jcr, char *lf);
-void dump_bsr(BSR *bsr, bool recurse);
-void free_bsr(BSR *bsr);
+BSR *parse_bsr(JCR *jcr, char *lf);
+void dump_bsr(BSR *bsr, bool recurse);
+void free_bsr(BSR *bsr);
VOL_LIST *new_vol();
-int add_vol(JCR *jcr, VOL_LIST *vol);
-void free_vol_list(JCR *jcr);
-void create_vol_list(JCR *jcr);
+int add_vol(JCR *jcr, VOL_LIST *vol);
+void free_vol_list(JCR *jcr);
+void create_vol_list(JCR *jcr);
/* From record.c */
-char *FI_to_ascii(int fi);
-char *stream_to_ascii(int stream, int fi);
-int write_record_to_block(DEV_BLOCK *block, DEV_RECORD *rec);
-int can_write_record_to_block(DEV_BLOCK *block, DEV_RECORD *rec);
-int read_record_from_block(DEV_BLOCK *block, DEV_RECORD *rec);
+char *FI_to_ascii(int fi);
+char *stream_to_ascii(int stream, int fi);
+int write_record_to_block(DEV_BLOCK *block, DEV_RECORD *rec);
+int can_write_record_to_block(DEV_BLOCK *block, DEV_RECORD *rec);
+int read_record_from_block(DEV_BLOCK *block, DEV_RECORD *rec);
DEV_RECORD *new_record();
-void free_record(DEV_RECORD *rec);
+void free_record(DEV_RECORD *rec);
/* From read_record.c */
int read_records(JCR *jcr, DEVICE *dev,
/* Responses sent to the File daemon */
static char OK_data[] = "3000 OK data\n";
+static char FD_error[] = "3000 error\n";
static char rec_header[] = "rechdr %ld %ld %ld %ld %ld";
/*
int ok = TRUE;
DEVICE *dev;
DEV_BLOCK *block;
+ DCR *dcr;
Dmsg0(20, "Start read data.\n");
dev = jcr->device->dev;
- /* Tell File daemon we will send data */
- bnet_fsend(fd, OK_data);
Dmsg1(10, "bstored>filed: %s\n", fd->msg);
- if (!bnet_set_buffer_size(fd, dev->device->max_network_buffer_size, BNET_SETBUF_WRITE)) {
+ if (!bnet_set_buffer_size(fd, jcr->device->max_network_buffer_size, BNET_SETBUF_WRITE)) {
return 0;
}
Dmsg1(20, "Begin read device=%s\n", dev_name(dev));
- block = new_block(dev);
-
create_vol_list(jcr);
if (jcr->NumVolumes == 0) {
Jmsg(jcr, M_FATAL, 0, _("No Volume names found for restore.\n"));
- free_block(block);
free_vol_list(jcr);
+ bnet_fsend(fd, FD_error);
return 0;
}
/*
* Ready device for reading, and read records
*/
- if (!acquire_device_for_read(jcr, dev, block)) {
- free_block(block);
+ if (!acquire_device_for_read(jcr)) {
free_vol_list(jcr);
return 0;
}
+ block = dcr->block;
+
+ /* Tell File daemon we will send data */
+ bnet_fsend(fd, OK_data);
ok = read_records(jcr, dev, record_cb, mount_next_read_volume);
/* Send end of data to FD */
bnet_sig(fd, BNET_EOD);
- if (!release_device(jcr, dev)) {
+ if (!release_device(jcr)) {
ok = FALSE;
}
- free_block(block);
free_vol_list(jcr);
Dmsg0(30, "Done reading.\n");
return ok ? 1 : 0;
Emsg1(M_ERROR, 0, _("Could not initialize %s\n"), device->device_name);
continue;
}
+
if (device->cap_bits & CAP_ALWAYSOPEN) {
Dmsg1(20, "calling first_open_device %s\n", device->device_name);
if (!first_open_device(device->dev)) {
}
if (device->cap_bits & CAP_AUTOMOUNT && device->dev &&
device->dev->state & ST_OPENED) {
- DEV_BLOCK *block;
JCR *jcr;
- block = new_block(device->dev);
+ DCR *dcr;
jcr = new_jcr(sizeof(JCR), stored_free_jcr);
- switch (read_dev_volume_label(jcr, device->dev, block)) {
+ jcr->device = device;
+ dcr = new_dcr(jcr, device->dev);
+ switch (read_dev_volume_label(jcr, device->dev, dcr->block)) {
case VOL_OK:
break;
default:
break;
}
free_jcr(jcr);
- free_block(block);
}
}
UnlockRes();
#undef VERSION
#define VERSION "1.33.4"
#define VSTRING "1"
-#define BDATE "02 Mar 2004"
-#define LSMDATE "02Mar04"
+#define BDATE "06 Mar 2004"
+#define LSMDATE "06Mar04"
/* Debug flags */
#undef DEBUG