DBId_t StorageId;
char Name[MAX_NAME_LENGTH]; /* Device name */
int AutoChanger; /* Set if autochanger */
+ int UseProtect; /* Set if the Storage Daemon can handle Protect */
/* Not in database */
bool created; /* set if created by db_create ... */
uint32_t MaxVolJobs; /* Max Jobs on Volume */
uint32_t MaxVolFiles; /* Max files on Volume */
int32_t Recycle; /* recycle yes/no */
+ int32_t Protect; /* Protect yes/no */
+ int32_t UseProtect; /* Use Protect feature yes/no */
int32_t Slot; /* slot in changer */
int32_t Enabled; /* 0=disabled, 1=enabled, 2=archived */
int32_t InChanger; /* Volume currently in changer */
ScratchPoolId INTEGER UNSIGNED DEFAULT 0,
RecyclePoolId INTEGER UNSIGNED DEFAULT 0,
Comment BLOB,
- Worm TINYINT DEFAULT 0,
- UseWorm TINYINT DEFAULT 0,
+ Protect TINYINT DEFAULT 0,
+ UseProtect TINYINT DEFAULT 0,
PRIMARY KEY(MediaId),
UNIQUE (VolumeName(128)),
INDEX (PoolId),
scratchpoolid integer default 0,
recyclepoolid integer default 0,
comment text,
+ protect smallint default 0,
+ useprotect smallint default 0,
primary key (mediaid)
);
ScratchPoolId INTEGER UNSIGNED REFERENCES Pool DEFAULT 0,
RecyclePoolId INTEGER UNSIGNED REFERENCES Pool DEFAULT 0,
Comment TEXT,
- Worm TINYINT DEFAULT 0,
- UseWorm TINYINT DEFAULT 0,
+ Protect TINYINT DEFAULT 0,
+ UseProtect TINYINT DEFAULT 0,
PRIMARY KEY(MediaId)
);
return true;
}
if (mr->MediaId != 0) { /* find by id */
- Mmsg(filter, "WHERE MediaId=%s", edit_int64(mr->MediaId, ed1));
+ Mmsg(cmd, "SELECT MediaId,VolumeName,VolJobs,VolFiles,"
+ "VolBlocks,VolBytes,VolABytes,VolHoleBytes,VolHoles,VolMounts,"
+ "VolErrors,VolWrites,MaxVolBytes,VolCapacityBytes,"
+ "MediaType,VolStatus,PoolId,VolRetention,VolUseDuration,MaxVolJobs,"
+ "MaxVolFiles,Recycle,Slot,FirstWritten,LastWritten,InChanger,"
+ "EndFile,EndBlock,VolType,VolParts,VolCloudParts,LastPartBytes,"
+ "LabelType,LabelDate,StorageId,"
+ "Enabled,LocationId,RecycleCount,InitialWrite,"
+ "ScratchPoolId,RecyclePoolId,VolReadTime,VolWriteTime,ActionOnPurge,CacheRetention,Pool.Name,Protect,UseProtect "
+ "FROM Media JOIN Pool USING (PoolId) WHERE MediaId=%s",
+ edit_int64(mr->MediaId, ed1));
} else { /* find by name */
bdb_escape_string(jcr, esc, mr->VolumeName, strlen(mr->VolumeName));
- Mmsg(filter, "WHERE VolumeName='%s'", esc);
+ Mmsg(cmd, "SELECT MediaId,VolumeName,VolJobs,VolFiles,"
+ "VolBlocks,VolBytes,VolABytes,VolHoleBytes,VolHoles,VolMounts,"
+ "VolErrors,VolWrites,MaxVolBytes,VolCapacityBytes,"
+ "MediaType,VolStatus,PoolId,VolRetention,VolUseDuration,MaxVolJobs,"
+ "MaxVolFiles,Recycle,Slot,FirstWritten,LastWritten,InChanger,"
+ "EndFile,EndBlock,VolType,VolParts,VolCloudParts,LastPartBytes,"
+ "LabelType,LabelDate,StorageId,"
+ "Enabled,LocationId,RecycleCount,InitialWrite,"
+ "ScratchPoolId,RecyclePoolId,VolReadTime,VolWriteTime,ActionOnPurge,CacheRetention,Pool.Name,Protect,UseProtect "
+ "FROM Media JOIN Pool USING (PoolId) WHERE VolumeName='%s'", esc);
}
- Mmsg(cmd, "SELECT MediaId,VolumeName,VolJobs,VolFiles,"
- "VolBlocks,VolBytes,VolABytes,VolHoleBytes,VolHoles,VolMounts,"
- "VolErrors,VolWrites,Media.MaxVolBytes,Media.VolCapacityBytes,"
- "MediaType,VolStatus,Media.PoolId,Media.VolRetention,Media.VolUseDuration,Media.MaxVolJobs,"
- "Media.MaxVolFiles,Media.Recycle,Slot,FirstWritten,LastWritten,InChanger,"
- "EndFile,EndBlock,VolType,VolParts,VolCloudParts,LastPartBytes,"
- "Media.LabelType,LabelDate,StorageId,"
- "Media.Enabled,LocationId,RecycleCount,InitialWrite,"
- "Media.ScratchPoolId,Media.RecyclePoolId,VolReadTime,VolWriteTime,Media.ActionOnPurge,"
- "Media.CacheRetention,Pool.Name "
- "FROM Media JOIN Pool USING (PoolId) %s", filter.c_str());
-
if (QueryDB(jcr, cmd)) {
char ed1[50];
if (sql_num_rows() > 1) {
mr->ActionOnPurge = str_to_int32(row[43]);
mr->CacheRetention = str_to_int64(row[44]);
bstrncpy(mr->Pool, row[45], sizeof(mr->Pool));
-
+ mr->Protect = str_to_int64(row[46]);
+ mr->UseProtect = str_to_int64(row[47]);
ok = true;
}
} else {
"EndFile,EndBlock,VolType,Media.LabelType,StorageId,DeviceId,"
"MediaAddressing,VolReadTime,VolWriteTime,"
"LocationId,RecycleCount,InitialWrite,Media.ScratchPoolId,Media.RecyclePoolId, "
- "Media.ActionOnPurge,%s AS ExpiresIn, Comment"
+ "Media.ActionOnPurge,%s AS ExpiresIn, Comment, Protect, UseProtect"
" FROM Media %s WHERE Media.VolumeName='%s' %s",
expiresin,
join,
"EndFile,EndBlock,VolType,Media.LabelType,StorageId,DeviceId,"
"MediaAddressing,VolReadTime,VolWriteTime,"
"LocationId,RecycleCount,InitialWrite,Media.ScratchPoolId,Media.RecyclePoolId, "
- "Media.ActionOnPurge,%s AS ExpiresIn, Comment"
+ "Media.ActionOnPurge,%s AS ExpiresIn, Comment, Protect, UseProtect"
" FROM Media %s WHERE Media.PoolId=%s %s ORDER BY MediaId",
expiresin,
join,
strftime(dt, sizeof(dt), "%Y-%m-%d %H:%M:%S", &tm);
JobTDate = (btime_t)stime;
+ if (!is_name_valid(jr->WriteDevice, NULL)) {
+ *jr->WriteDevice = 0; // Not valid, not used
+ }
+ if (!is_name_valid(jr->LastReadDevice, NULL)) {
+ *jr->LastReadDevice = 0; // Not valid, not used
+ }
+
bdb_lock();
Mmsg(cmd, "UPDATE Job SET JobStatus='%c',Level='%c',StartTime='%s',"
-"ClientId=%s,JobTDate=%s,PoolId=%s,FileSetId=%s,RealStartTime='%s' WHERE JobId=%s",
+ "ClientId=%s,JobTDate=%s,PoolId=%s,FileSetId=%s,RealStartTime='%s',"
+ "isVirtualFull=%d,LastReadStorageId=%d,LastReadDevice='%s',"
+ "WriteStorageId=%d,WriteDevice='%s',StatusInfo='%s',Encrypted=%d WHERE JobId=%s",
(char)(jcr->JobStatus),
(char)(jr->JobLevel), dt,
edit_int64(jr->ClientId, ed1),
edit_int64(jr->PoolId, ed3),
edit_int64(jr->FileSetId, ed4),
dt,
+ jr->isVirtualFull,
+ jr->LastReadStorageId,
+ jr->LastReadDevice,
+ jr->WriteStorageId,
+ jr->WriteDevice,
+ jr->StatusInfo,
+ jr->Encrypted,
edit_int64(jr->JobId, ed5));
stat = UpdateDB(jcr, cmd, false);
"LabelType=%d,StorageId=%s,PoolId=%s,VolRetention=%s,VolUseDuration=%s,"
"MaxVolJobs=%d,MaxVolFiles=%d,Enabled=%d,LocationId=%s,"
"ScratchPoolId=%s,RecyclePoolId=%s,RecycleCount=%d,Recycle=%d,"
- "ActionOnPurge=%d,CacheRetention=%s,EndBlock=%u"
+ "ActionOnPurge=%d,CacheRetention=%s,EndBlock=%u,Protect=%d,UseProtect=%d"
" WHERE VolumeName='%s'",
mr->VolJobs, mr->VolFiles, mr->VolBlocks,
edit_uint64(mr->VolBytes, ed1),
edit_uint64(mr->RecyclePoolId, ed15),
mr->RecycleCount,mr->Recycle, mr->ActionOnPurge,
edit_uint64(mr->CacheRetention, ed16),
- mr->EndBlock,
+ mr->EndBlock,mr->Protect,mr->UseProtect,
esc_name);
Dmsg1(dbglevel1, "%s\n", cmd);
CREATE INDEX meta_attachmentemailid ON MetaAttachment (AttachmentEmailId(255));
ALTER TABLE Media
- MODIFY COLUMN Worm TINYINT DEFAULT 0,
- MODIFY COLUMN UseWorm TINYINT DEFAULT 0;
+ MODIFY COLUMN Protect TINYINT DEFAULT 0,
+ MODIFY COLUMN UseProtect TINYINT DEFAULT 0;
ALTER TABLE Object
ADD COLUMN FileIndex integer not null default 0,
ADD COLUMN Encrypted int default 0;
ALTER TABLE Media
- ADD COLUMN Worm smallint default 0,
- ADD COLUMN UseWorm smallint default 0;
+ ADD COLUMN Protect smallint default 0,
+ ADD COLUMN UseProtect smallint default 0;
INSERT INTO Events (EventsCode, EventsType, EventsTime, EventsDaemon, EventsSource, EventsRef, EventsText) VALUES
('DU0001', 'catalog_update', NOW(), '*SHELL*', 'update_bacula_tables', 'pid$$', 'Catalog schema was updated to 1026');
ALTER TABLE Job ADD COLUMN StatusInfo text default '';
ATLER TABLE Job ADD COLUMN Encrypted int default 0;
-ALTER TABLE Media ADD COLUMN Worm smallint default 0;
-ALTER TABLE Media ADD COLUMN IsWorm smallint default 0;
+ALTER TABLE Media ADD COLUMN Protect smallint default 0;
+ALTER TABLE Media ADD COLUMN IsProtect smallint default 0;
INSERT INTO Events (EventsCode, EventsType, EventsTime, EventsDaemon, EventsSource, EventsRef, EventsText) VALUES
('DU0001', 'catalog_update', NOW(), '*SHELL*', 'update_bacula_tables', 'pid$$', 'Catalog schema was updated to 1026');
*/
jcr->start_time = time(NULL);
jcr->jr.StartTime = jcr->start_time;
+ bstrncpy(jcr->jr.WriteDevice, jcr->write_dev, sizeof(jcr->jr.WriteDevice));
+
if (!db_update_job_start_record(jcr, jcr->db, &jcr->jr)) {
Jmsg(jcr, M_FATAL, 0, "[DE0008] %s", db_strerror(jcr->db));
}
*/
/* Requests from the Storage daemon */
-static char Find_media[] = "CatReq JobId=%ld FindMedia=%d pool_name=%127s media_type=%127s vol_type=%d create=%d\n";
+static char Find_media[] = "CatReq JobId=%ld FindMedia=%d pool_name=%127s media_type=%127s vol_type=%d create=%d use_protect=%d\n";
static char Get_Vol_Info[] = "CatReq JobId=%ld GetVolInfo VolName=%127s write=%d\n";
static char Update_media[] = "CatReq JobId=%ld UpdateMedia VolName=%s"
" VolErrors=%u VolWrites=%lld MaxVolBytes=%lld EndTime=%lld VolStatus=%10s"
" Slot=%d relabel=%d InChanger=%d VolReadTime=%llu VolWriteTime=%llu"
" VolFirstWritten=%lld VolType=%u VolParts=%d VolCloudParts=%d"
- " LastPartBytes=%lld Enabled=%d Recycle=%d\n";
+ " LastPartBytes=%lld Enabled=%d Recycle=%d Protect=%d UseProtect=%d\n";
static char FileEvent_add[] = "%c %d %127s %127s 0";
/* Full format when coming from the Verify Job */
" MaxVolJobs=%u MaxVolFiles=%u InChanger=%d VolReadTime=%s"
" VolWriteTime=%s EndFile=%u EndBlock=%u VolType=%u LabelType=%d"
" MediaId=%s ScratchPoolId=%s VolParts=%d VolCloudParts=%d"
- " LastPartBytes=%lld Enabled=%d MaxPoolBytes=%s PoolBytes=%s Recycle=%d\n";
+ " LastPartBytes=%lld Enabled=%d MaxPoolBytes=%s PoolBytes=%s Recycle=%d Protect=%d UseProtect=%d\n";
static char OK_create[] = "1000 OK CreateJobMedia\n";
mr->Enabled,
edit_uint64(pr.MaxPoolBytes, ed11),
edit_uint64(pr.PoolBytes, ed12),
- mr->Recycle);
+ mr->Recycle, mr->Protect, mr->UseProtect);
unbash_spaces(mr->VolumeName);
Dmsg2(100, "Vol Info for %s: %s", jcr->Job, sd->msg);
return stat;
utime_t VolFirstWritten;
utime_t VolLastWritten;
int n;
- int can_create=0;
- int Enabled, Recycle;
+ int can_create=0, use_protect=0;
+ int Enabled, Recycle, Protect, UseProtect;
JobId_t JobId = 0;
STORE *wstore = jcr->store_mngr->get_wstore();
/*
* Find next appendable medium for SD
*/
- n = sscanf(bs->msg, Find_media, &JobId, &index, &pool_name, &mr.MediaType, &mr.VolType, &can_create);
- if (n == 6) {
+ n = sscanf(bs->msg, Find_media, &JobId, &index, &pool_name, &mr.MediaType, &mr.VolType, &can_create, &use_protect);
+ if (n == 7) {
POOL_MEM errmsg;
POOL_DBR pr;
bstrncpy(pr.Name, pool_name, sizeof(pr.Name));
mr.ScratchPoolId = pr.ScratchPoolId;
ok = find_next_volume_for_append(jcr, &mr, index,
can_create?fnv_create_vol : fnv_no_create_vol,
- fnv_prune, errmsg);
+ fnv_prune, use_protect, errmsg);
Dmsg3(050, "find_media ok=%d idx=%d vol=%s\n", ok, index, mr.VolumeName);
} else {
/* Report problem finding pool */
&VolLastWritten, &sdmr.VolStatus, &sdmr.Slot, &label, &sdmr.InChanger,
&sdmr.VolReadTime, &sdmr.VolWriteTime, &VolFirstWritten,
&sdmr.VolType, &sdmr.VolParts, &sdmr.VolCloudParts,
- &sdmr.LastPartBytes, &Enabled, &Recycle);
- if (n == 27) {
+ &sdmr.LastPartBytes, &Enabled, &Recycle, &Protect, &UseProtect);
+ if (n == 29) {
db_lock(jcr->db);
Dmsg3(400, "Update media %s oldStat=%s newStat=%s\n", sdmr.VolumeName,
mr.VolStatus, sdmr.VolStatus);
mr.LastPartBytes = sdmr.LastPartBytes;
mr.Enabled = Enabled; /* byte assignment */
mr.Recycle = Recycle; /* byte assignment */
+ mr.Protect = Protect; /* byte assignment */
+ mr.UseProtect = UseProtect; /* byte assignment */
bstrncpy(mr.VolStatus, sdmr.VolStatus, sizeof(mr.VolStatus));
mr.VolReadTime = sdmr.VolReadTime;
mr.VolWriteTime = sdmr.VolWriteTime;
/* Response from Storage daemon */
static char OKjob[] = "3000 OK Job SDid=%d SDtime=%d Authorization=%100s\n";
-static char OK_device[] = "3000 OK use device device=%s\n";
+static char OK_device[] = "3000 OK use device device=%127s protect=%d encrypt=%d\n";
/* Storage Daemon requests */
static char Job_start[] = "3010 Job %127s start\n";
*/
/* Do read side of storage daemon */
if (ok && rstore) {
+ int protect=0, encrypt=0;
/* For the moment, only migrate, copy and vbackup have rpool */
if (jcr->is_JobType(JT_MIGRATE) || jcr->is_JobType(JT_COPY) ||
(jcr->is_JobType(JT_BACKUP) && jcr->is_JobLevel(L_VIRTUAL_FULL))) {
sd->signal(BNET_EOD); /* end of Storages */
if (bget_dirmsg(jcr, sd, BSOCK_TYPE_SD) > 0) {
Dmsg1(100, "<stored: %s", sd->msg);
- ok = sscanf(sd->msg, OK_device, device_name.c_str()) == 1;
+ ok = sscanf(sd->msg, OK_device, device_name.c_str(), &protect, &encrypt) == 3;
} else {
ok = false;
}
if (ok) {
Jmsg(jcr, M_INFO, 0, _("Using Device \"%s\" to read.\n"), device_name.c_str());
pm_strcpy(jcr->read_dev, device_name.c_str());
+ jcr->SD_set_worm = protect;
+ jcr->jr.Encrypted = encrypt;
}
}
/* Do write side of storage daemon */
if (ok && wstore) {
+ int protect=0, encrypt=0;
pm_strcpy(pool_type, jcr->pool->pool_type);
pm_strcpy(pool_name, jcr->pool->name());
bash_spaces(pool_type);
sd->signal(BNET_EOD); /* end of Storages */
if (bget_dirmsg(jcr, sd, BSOCK_TYPE_SD) > 0) {
Dmsg1(100, "<stored: %s", sd->msg);
- ok = sscanf(sd->msg, OK_device, device_name.c_str()) == 1;
+ ok = sscanf(sd->msg, OK_device, device_name.c_str(), &protect, &encrypt) == 3;
} else {
ok = false;
}
if (ok) {
Jmsg(jcr, M_INFO, 0, _("Using Device \"%s\" to write.\n"), device_name.c_str());
pm_strcpy(jcr->write_dev, device_name.c_str());
+ jcr->SD_set_worm = protect;
+ jcr->jr.Encrypted = encrypt;
}
}
if (!ok) {
* jcr->pool
* MEDIA_DBR mr with PoolId set
* create -- whether or not to create a new volume
+ * use_protect -- whether or not the device will mark the volume as protected (0 no, -1 don't know, 1 yes)
*/
int find_next_volume_for_append(JCR *jcr, MEDIA_DBR *mr, int index,
- bool create, bool prune, POOL_MEM &errmsg)
+ bool create, bool prune, int use_protect, POOL_MEM &errmsg)
{
int retry = 0;
bool ok;
STORE *store = jcr->store_mngr->get_wstore();
bstrncpy(mr->MediaType, store->media_type, sizeof(mr->MediaType));
- Dmsg6(dbglvl, "find_next_vol_for_append: JobId=%u PoolId=%d, MediaType=%s index=%d create=%d prune=%d\n",
+ Dmsg7(dbglvl, "find_next_vol_for_append: JobId=%u PoolId=%d, MediaType=%s index=%d create=%d prune=%d protect=%d\n",
(uint32_t)jcr->JobId, (int)mr->PoolId, mr->MediaType, index,
- create, prune);
+ create, prune, use_protect);
/*
* If we are using an Autochanger, restrict Volume
* search to the Autochanger on the first pass
}
Dmsg2(dbglvl, "VolJobs=%d FirstWritten=%d\n", mr->VolJobs, mr->FirstWritten);
if (ok) {
+ /* If the current device uses the Protect feature, we need to keep track of it */
+ if (use_protect == 1) {
+ mr->UseProtect = 1;
+ }
/* If we can use the volume, check if it is expired */
if (has_volume_expired(jcr, mr)) {
if (retry++ < 200) { /* sanity check */
expired = true;
}
}
- /* Here, if the volume is WORM, we cannot change the status if a storage
+ /* Here, if the volume is Protect, we cannot change the status if a storage
* is not connected
*/
if (expired) {
}
}
Dmsg2(dbglvl, "Vol=%s expired=%d\n", mr->VolumeName, expired);
+ /* Special case, we have marked the volume as Expired, and the Storage
+ * Daemon wants to mark it as Protect
+ */
+ if (expired && mr->UseProtect) {
+ return false;
+ }
return expired;
}
bool has_quota_reached(JCR *jcr);
void set_storageid_in_mr(STORE *store, MEDIA_DBR *mr);
int find_next_volume_for_append(JCR *jcr, MEDIA_DBR *mr, int index,
- bool create, bool purge, POOL_MEM &errmsg);
+ bool create, bool purge, int use_worm, POOL_MEM &errmsg);
bool has_volume_expired(JCR *jcr, MEDIA_DBR *mr);
void check_if_volume_valid_or_recyclable(JCR *jcr, MEDIA_DBR *mr, const char **reason);
bool get_scratch_volume(JCR *jcr, bool InChanger, MEDIA_DBR *mr,
get_job_storage(&store, job, run);
set_storageid_in_mr(store.store, &mr);
/* no need to set ScratchPoolId, since we use fnv_no_create_vol */
- if (!find_next_volume_for_append(jcr, &mr, 1, fnv_no_create_vol, fnv_prune, errmsg)) {
+ if (!find_next_volume_for_append(jcr, &mr, 1, fnv_no_create_vol, fnv_prune, -1 /* no worm */, errmsg)) {
ua->error_msg(_("Could not find next Volume for Job %s (Pool=%s, Level=%s).%s\n"),
job->name(), pr.Name, level_to_str(edl, sizeof(edl), run->level), errmsg.c_str());
} else {
set_storageid_in_mr(jcr->store_mngr->get_wstore(), &mr);
Dmsg0(250, "call find_next_volume_for_append\n");
/* no need to set ScratchPoolId, since we use fnv_no_create_vol */
- ok = find_next_volume_for_append(jcr, &mr, 1, fnv_no_create_vol, fnv_no_prune, errmsg);
+ ok = find_next_volume_for_append(jcr, &mr, 1, fnv_no_create_vol, fnv_no_prune, -1, errmsg);
}
if (!ok) {
bstrncpy(mr.VolumeName, "*unknown*", sizeof(mr.VolumeName));
Dmsg2(dbglevel, "Read pool=%s (From %s)\n", jcr->rpool->name(), jcr->rpool_source);
jcr->start_time = time(NULL);
+ jcr->jr.isVirtualFull = 1;
jcr->jr.StartTime = jcr->start_time;
jcr->jr.JobLevel = L_FULL; /* we want this to appear as a Full backup */
if (!db_update_job_start_record(jcr, jcr->db, &jcr->jr)) {
#ifdef DIRECTOR_DAEMON
/* Director Daemon specific data part of JCR */
+ bool SD_set_worm; /* Initiate the procedure to set the WORM attribute */
bool SD_msg_chan_started; /* True if the msg thread is started */
pthread_t SD_msg_chan; /* Message channel thread id */
pthread_cond_t term_wait; /* Wait for job termination */
}
}
+/* Set atime/mtime for a given file
+ * Must be called on open file
+ */
+int set_own_time(int fd, const char *path, btime_t atime, btime_t mtime)
+{
+#ifdef HAVE_FUTIMES
+ struct timeval times[2];
+ times[0].tv_sec = atime;
+ times[0].tv_usec = 0;
+ times[1].tv_sec = mtime;
+ times[1].tv_usec = 0;
+
+ if (fd > 0) {
+ if (futimes(fd, times) == 0) {
+ return 0;
+ }
+ }
+#endif
+ struct utimbuf ut;
+ ut.actime = atime;
+ ut.modtime = mtime;
+
+ if (utime(path, &ut) == 0) {
+ return 0;
+ }
+ return -1;
+}
+
+
/* Get path/fname from argument, use realpath to get the full name if
* available
*/
free(cpath);
free(cargv0);
}
-
-/* Set atime/mtime for a given file
- * Must be called on open file
- */
-int set_own_time(int fd, const char *path, btime_t atime, btime_t mtime)
-{
-#ifdef HAVE_FUTIMES
- struct timeval times[2];
- times[0].tv_sec = atime;
- times[0].tv_usec = 0;
- times[1].tv_sec = mtime;
- times[1].tv_usec = 0;
-
- if (fd > 0) {
- if (futimes(fd, times) == 0) {
- return 0;
- }
- }
-#endif
- struct utimbuf ut;
- ut.actime = atime;
- ut.modtime = mtime;
-
- if (utime(path, &ut) == 0) {
- return 0;
- }
- return -1;
}
#ifdef TEST_PROGRAM
static const int dbglvl = 200;
/* Requests sent to the Director */
-static char Find_media[] = "CatReq JobId=%ld FindMedia=%d pool_name=%s media_type=%s vol_type=%d create=%d\n";
+static char Find_media[] = "CatReq JobId=%ld FindMedia=%d pool_name=%s media_type=%s vol_type=%d create=%d use_protect=%d\n";
static char Get_Vol_Info[] = "CatReq JobId=%ld GetVolInfo VolName=%s write=%d\n";
static char Update_media[] = "CatReq JobId=%ld UpdateMedia VolName=%s"
" VolJobs=%u VolFiles=%u VolBlocks=%u VolBytes=%s VolABytes=%s"
" VolErrors=%u VolWrites=%u MaxVolBytes=%s EndTime=%s VolStatus=%s"
" Slot=%d relabel=%d InChanger=%d VolReadTime=%s VolWriteTime=%s"
" VolFirstWritten=%s VolType=%u VolParts=%d VolCloudParts=%d"
- " LastPartBytes=%lld Enabled=%d Recycle=%d\n";
+ " LastPartBytes=%lld Enabled=%d Recycle=%d Protect=%d UseProtect=%d\n";
static char Create_jobmedia[] = "CatReq JobId=%ld CreateJobMedia\n";
static char FileAttributes[] = "UpdCat JobId=%ld FileAttributes ";
" Slot=%ld MaxVolJobs=%lu MaxVolFiles=%lu InChanger=%ld"
" VolReadTime=%lld VolWriteTime=%lld EndFile=%lu EndBlock=%lu"
" VolType=%lu LabelType=%ld MediaId=%lld ScratchPoolId=%lld"
- " VolParts=%d VolCloudParts=%d LastPartBytes=%lld Enabled=%d MaxPoolBytes=%lld PoolBytes=%lld Recycle=%d\n";
+ " VolParts=%d VolCloudParts=%d LastPartBytes=%lld Enabled=%d MaxPoolBytes=%lld PoolBytes=%lld Recycle=%d"
+ " Protect=%d UseProtect=%d\n";
static char OK_create[] = "1000 OK CreateJobMedia\n";
BSOCK *dir = jcr->dir_bsock;
VOLUME_CAT_INFO vol;
int n;
- int32_t Enabled, Recycle;
+ int32_t Enabled, Recycle, Protect, UseProtect;
int32_t InChanger;
dcr->setVolCatInfo(false);
&vol.EndFile, &vol.EndBlock, &vol.VolCatType,
&vol.LabelType, &vol.VolMediaId, &vol.VolScratchPoolId,
&vol.VolCatParts, &vol.VolCatCloudParts,
- &vol.VolLastPartBytes, &Enabled, &vol.MaxPoolBytes, &vol.PoolBytes, &Recycle);
+ &vol.VolLastPartBytes, &Enabled, &vol.MaxPoolBytes, &vol.PoolBytes, &Recycle, &Protect, &UseProtect);
Dmsg2(dbglvl, "<dird n=%d %s", n, dir->msg);
- if (n != 33) {
+ if (n != 35) {
Dmsg1(dbglvl, "get_volume_info failed: ERR=%s", dir->msg);
/*
* Note, we can get an error here either because there is
vol.InChanger = InChanger; /* bool in structure */
vol.VolEnabled = Enabled; /* bool in structure */
vol.VolRecycle = Recycle; /* bool in structure */
+ vol.Protect = Protect; /* bool in structure */
+ vol.UseProtect = UseProtect; /* bool in structure */
vol.is_valid = true;
vol.VolCatBytes = vol.VolCatAmetaBytes + vol.VolCatAdataBytes;
unbash_spaces(vol.VolCatName);
bash_spaces(dcr->media_type);
bash_spaces(dcr->pool_name);
dir->fsend(Find_media, jcr->JobId, vol_index, dcr->pool_name, dcr->media_type,
- dcr->dev->dev_type, can_create);
+ dcr->dev->dev_type, can_create, dcr->dev->use_protect());
unbash_spaces(dcr->media_type);
unbash_spaces(dcr->pool_name);
Dmsg1(dbglvl, ">dird %s", dir->msg);
Dmsg1(dbglvl, "Got same vol = %s\n", lastVolume);
break;
}
+ /* Here, the Director *asks* us to mark the volume in ReadOnly */
+ if (dcr->dev->use_protect() &&
+ (strcmp(dcr->VolCatInfo.VolCatStatus, "Used") == 0 || strcmp(dcr->VolCatInfo.VolCatStatus, "Full") == 0))
+ {
+ Dmsg1(dbglvl, "Need to mark %s in read-only/immutable\n", dcr->VolumeName);
+ break;
+ }
/* If VolCatAdataBytes, we have ALIGNED_DEV */
if (dcr->VolCatInfo.VolCatType == 0 && dcr->VolCatInfo.VolCatAdataBytes != 0) {
dcr->VolCatInfo.VolCatType = B_ALIGNED_DEV;
if (dev->is_worm() && vol.VolRecycle) {
Jmsg(jcr, M_INFO, 0, _("WORM cassette detected: setting Recycle=No on Volume=\"%s\"\n"), vol.VolCatName);
vol.VolRecycle = false;
+ vol.Protect = true;
}
pm_strcpy(VolumeName, vol.VolCatName);
bash_spaces(VolumeName);
vol.VolCatCloudParts,
vol.VolLastPartBytes,
Enabled,
- Recycle);
+ Recycle,
+ vol.Protect,
+ dev->use_protect()
+ );
Dmsg1(100, ">dird %s", dir->msg);
/*
* We sent info directly from dev to the Director.
utime_t VolFirstWritten; /* Time of first write */
utime_t VolLastWritten; /* Time of last write */
bool InChanger; /* Set if vol in current magazine */
+ bool Protect; /* Set if the vol is Readonly, worm or immutable */
+ bool UseProtect; /* Set if the device can set the volume Readonly, worm or immutable */
bool is_valid; /* set if this data is valid */
bool VolEnabled; /* set if volume enabled */
bool VolRecycle; /* set if volume can be recycled */
virtual int set_writable() { pm_strcpy(errmsg, _("Not implemented")); return -1;};
virtual int set_readonly() { pm_strcpy(errmsg, _("Not implemented")); return -1;};
virtual int set_atime(btime_t val) { pm_strcpy(errmsg, _("Not implemented")); return -1;};
+ virtual int use_protect() { return 0; };
virtual const char *print_type() = 0; /* in dev.c */
virtual const char *print_driver_type() { return "";};
virtual const char *print_full_type() { return print_type();};
/* Imported functions */
const char *mode_to_str(int mode);
+int file_dev::use_protect()
+{
+ if (device->set_vol_immutable || device->set_vol_read_only) {
+ return 1;
+ }
+ return 0;
+}
/* default primitives are designed for file */
int DEVICE::d_open(const char *pathname, int flags)
int set_writable();
int set_readonly();
int set_atime(btime_t val);
+ int use_protect();
};
#endif /* __FILE_DEV_ */
static char use_device[] = "use device=%127s\n";
/* Responses sent to Director daemon */
-static char OK_device[] = "3000 OK use device device=%s\n";
+static char OK_device[] = "3000 OK use device device=%s protect=%d encrypt=%d\n";
static char NO_device[] = "3924 Device \"%s\" not in SD Device"
" resources or no matching Media Type or is disabled.\n";
static char BAD_use[] = "3913 Bad use command: %s\n";
if (rctx.notify_dir) {
POOL_MEM dev_name;
BSOCK *dir = rctx.jcr->dir_bsock;
+ int protect = 0;
+ if (rctx.device->set_vol_immutable || rctx.device->set_vol_read_only) {
+ protect = 1;
+ }
pm_strcpy(dev_name, rctx.device->hdr.name);
bash_spaces(dev_name);
- ok = dir->fsend(OK_device, dev_name.c_str()); /* Return real device name */
+ ok = dir->fsend(OK_device, dev_name.c_str(), protect, 0); /* Return real device name */
Dmsg1(dbglvl, ">dird: %s", dir->msg);
if (!ok) {
dcr->unreserve_device(false);
alert_list_which which, alert_cb alert_callback);
int delete_alerts();
bool check_lintape_eod();
+ int use_worm() { return device->worm_command && device->control_name; };
alist *alert_list;
};
CREATE INDEX meta_attachmentemailid ON MetaAttachment (AttachmentEmailId(255));
ALTER TABLE Media
- MODIFY COLUMN Worm TINYINT DEFAULT 0,
- MODIFY COLUMN UseWorm TINYINT DEFAULT 0;
+ MODIFY COLUMN Protect TINYINT DEFAULT 0,
+ MODIFY COLUMN UseProtect TINYINT DEFAULT 0;
ALTER TABLE Object
ADD COLUMN FileIndex integer not null default 0,
ADD COLUMN Encrypted int default 0;
ALTER TABLE Media
- ADD COLUMN Worm smallint default 0,
- ADD COLUMN UseWorm smallint default 0;
+ ADD COLUMN Protect smallint default 0,
+ ADD COLUMN UseProtect smallint default 0;
INSERT INTO Events (EventsCode, EventsType, EventsTime, EventsDaemon, EventsSource, EventsRef, EventsText) VALUES
('DU0001', 'catalog_update', NOW(), '*SHELL*', 'update_bacula_tables', 'pid$$', 'Catalog schema was updated to 1026');
ALTER TABLE Job ADD COLUMN StatusInfo text default '';
ATLER TABLE Job ADD COLUMN Encrypted int default 0;
-ALTER TABLE Media ADD COLUMN Worm smallint default 0;
-ALTER TABLE Media ADD COLUMN IsWorm smallint default 0;
+ALTER TABLE Media ADD COLUMN Protect smallint default 0;
+ALTER TABLE Media ADD COLUMN IsProtect smallint default 0;
INSERT INTO Events (EventsCode, EventsType, EventsTime, EventsDaemon, EventsSource, EventsRef, EventsText) VALUES
('DU0001', 'catalog_update', NOW(), '*SHELL*', 'update_bacula_tables', 'pid$$', 'Catalog schema was updated to 1026');