+
+/*
+ * Clean up the device for reuse without freeing the memory
+ */
+bool clean_device(DCR *dcr)
+{
+ bool ok;
+ dcr->keep_dcr = true; /* do not free the dcr */
+ ok = release_device(dcr);
+ dcr->keep_dcr = false;
+ return ok;
+}
+
+/*
+ * Create a new Device Control Record and attach
+ * it to the device (if this is a real job).
+ * Note, this has been updated so that it can be called first
+ * without a DEVICE, then a second or third time with a DEVICE,
+ * and each time, it should cleanup and point to the new device.
+ * This should facilitate switching devices.
+ * Note, each dcr must point to the controlling job (jcr). However,
+ * a job can have multiple dcrs, so we must not store in the jcr's
+ * structure as previously. The higher level routine must store
+ * this dcr in the right place
+ *
+ */
+DCR *new_dcr(JCR *jcr, DCR *dcr, DEVICE *dev)
+{
+ if (!dcr) {
+ dcr = (DCR *)malloc(sizeof(DCR));
+ memset(dcr, 0, sizeof(DCR));
+ dcr->tid = pthread_self();
+ dcr->spool_fd = -1;
+ }
+ dcr->jcr = jcr; /* point back to jcr */
+ /* Set device information, possibly change device */
+ if (dev) {
+ if (dcr->block) {
+ free_block(dcr->block);
+ }
+ dcr->block = new_block(dev);
+ if (dcr->rec) {
+ free_record(dcr->rec);
+ }
+ dcr->rec = new_record();
+ if (dcr->attached_to_dev) {
+ detach_dcr_from_dev(dcr);
+ }
+ /* Use job spoolsize prior to device spoolsize */
+ if (jcr->spool_size) {
+ dcr->max_job_spool_size = jcr->spool_size;
+ } else {
+ dcr->max_job_spool_size = dev->device->max_job_spool_size;
+ }
+ dcr->device = dev->device;
+ dcr->dev = dev;
+ attach_dcr_to_dev(dcr);
+ }
+ return dcr;
+}
+
+/*
+ * Search the dcrs list for the given dcr. If it is found,
+ * as it should be, then remove it. Also zap the jcr pointer
+ * to the dcr if it is the same one.
+ *
+ * Note, this code will be turned on when we can write to multiple
+ * dcrs at the same time.
+ */
+#ifdef needed
+static void remove_dcr_from_dcrs(DCR *dcr)
+{
+ JCR *jcr = dcr->jcr;
+ if (jcr->dcrs) {
+ int i = 0;
+ DCR *ldcr;
+ int num = jcr->dcrs->size();
+ for (i=0; i < num; i++) {
+ ldcr = (DCR *)jcr->dcrs->get(i);
+ if (ldcr == dcr) {
+ jcr->dcrs->remove(i);
+ if (jcr->dcr == dcr) {
+ jcr->dcr = NULL;
+ }
+ }
+ }
+ }
+}
+#endif
+
+static void attach_dcr_to_dev(DCR *dcr)
+{
+ DEVICE *dev = dcr->dev;
+ JCR *jcr = dcr->jcr;
+
+ if (jcr) Dmsg1(500, "JobId=%u enter attach_dcr_to_dev\n", (uint32_t)jcr->JobId);
+ if (!dcr->attached_to_dev && dev->initiated && jcr && jcr->get_JobType() != JT_SYSTEM) {
+ dev->attached_dcrs->append(dcr); /* attach dcr to device */
+ dcr->attached_to_dev = true;
+ Dmsg1(500, "JobId=%u attach_dcr_to_dev\n", (uint32_t)jcr->JobId);
+ }
+}
+
+void detach_dcr_from_dev(DCR *dcr)
+{
+ DEVICE *dev = dcr->dev;
+ Dmsg0(500, "Enter detach_dcr_from_dev\n"); /* jcr is NULL in some cases */
+
+ /* Detach this dcr only if attached */
+ if (dcr->attached_to_dev && dev) {
+ dev->dlock();
+ dcr->unreserve_device();
+ dcr->dev->attached_dcrs->remove(dcr); /* detach dcr from device */
+ dcr->attached_to_dev = false;
+// remove_dcr_from_dcrs(dcr); /* remove dcr from jcr list */
+ dev->dunlock();
+ }
+}
+
+/*
+ * Free up all aspects of the given dcr -- i.e. dechain it,
+ * release allocated memory, zap pointers, ...
+ */
+void free_dcr(DCR *dcr)
+{
+ JCR *jcr = dcr->jcr;
+
+ detach_dcr_from_dev(dcr);
+
+ if (dcr->block) {
+ free_block(dcr->block);
+ }
+ if (dcr->rec) {
+ free_record(dcr->rec);
+ }
+ if (jcr && jcr->dcr == dcr) {
+ jcr->dcr = NULL;
+ }
+ free(dcr);
+}
+
+static void set_dcr_from_vol(DCR *dcr, VOL_LIST *vol)
+{
+ /*
+ * Note, if we want to be able to work from a .bsr file only
+ * for disaster recovery, we must "simulate" reading the catalog
+ */
+ bstrncpy(dcr->VolumeName, vol->VolumeName, sizeof(dcr->VolumeName));
+ bstrncpy(dcr->VolCatInfo.VolCatName, vol->VolumeName, sizeof(dcr->VolCatInfo.VolCatName));
+ bstrncpy(dcr->media_type, vol->MediaType, sizeof(dcr->media_type));
+ dcr->VolCatInfo.Slot = vol->Slot;
+ dcr->VolCatInfo.InChanger = vol->Slot > 0;
+}