1 /*
2    BAREOS® - Backup Archiving REcovery Open Sourced
3 
4    Copyright (C) 2001-2012 Free Software Foundation Europe e.V.
5    Copyright (C) 2011-2012 Planets Communications B.V.
6    Copyright (C) 2013-2021 Bareos GmbH & Co. KG
7 
8    This program is Free Software; you can redistribute it and/or
9    modify it under the terms of version three of the GNU Affero General Public
10    License as published by the Free Software Foundation and included
11    in the file LICENSE.
12 
13    This program is distributed in the hope that it will be useful, but
14    WITHOUT ANY WARRANTY; without even the implied warranty of
15    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16    Affero General Public License for more details.
17 
18    You should have received a copy of the GNU Affero General Public License
19    along with this program; if not, write to the Free Software
20    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
21    02110-1301, USA.
22 */
23 /*
24  * Kern Sibbald, March MMI
25  * added BB02 format October MMII
26  */
27 /**
28  @file
29  * tape block handling functions
30  */
31 
32 #include "include/bareos.h"
33 #include "stored/stored.h"
34 #include "stored/crc32/crc32.h"
35 #include "stored/dev.h"
36 #include "stored/device.h"
37 #include "stored/device_control_record.h"
38 #include "stored/label.h"
39 #include "stored/socket_server.h"
40 #include "stored/spool.h"
41 #include "lib/berrno.h"
42 #include "lib/edit.h"
43 #include "include/jcr.h"
44 
45 namespace storagedaemon {
46 
47 static bool TerminateWritingVolume(DeviceControlRecord* dcr);
48 static bool DoNewFileBookkeeping(DeviceControlRecord* dcr);
49 static void RereadLastBlock(DeviceControlRecord* dcr);
50 
51 bool forge_on = false; /* proceed inspite of I/O errors */
52 
53 /**
54  * Dump the block header, then walk through
55  * the block printing out the record headers.
56  */
DumpBlock(DeviceBlock * b,const char * msg)57 void DumpBlock(DeviceBlock* b, const char* msg)
58 {
59   ser_declare;
60   char* p;
61   char Id[BLKHDR_ID_LENGTH + 1];
62   uint32_t CheckSum, BlockCheckSum;
63   uint32_t block_len;
64   uint32_t BlockNumber;
65   uint32_t VolSessionId, VolSessionTime, data_len;
66   int32_t FileIndex;
67   int32_t Stream;
68   int bhl, rhl;
69   char buf1[100], buf2[100];
70 
71   UnserBegin(b->buf, BLKHDR1_LENGTH);
72   unser_uint32(CheckSum);
73   unser_uint32(block_len);
74   unser_uint32(BlockNumber);
75   UnserBytes(Id, BLKHDR_ID_LENGTH);
76   ASSERT(UnserLength(b->buf) == BLKHDR1_LENGTH);
77   Id[BLKHDR_ID_LENGTH] = 0;
78   if (Id[3] == '2') {
79     unser_uint32(VolSessionId);
80     unser_uint32(VolSessionTime);
81     bhl = BLKHDR2_LENGTH;
82     rhl = RECHDR2_LENGTH;
83   } else {
84     VolSessionId = VolSessionTime = 0;
85     bhl = BLKHDR1_LENGTH;
86     rhl = RECHDR1_LENGTH;
87   }
88 
89   if (block_len > 4000000) {
90     Dmsg3(20, "Dump block %s 0x%x blocksize too big %u\n", msg, b, block_len);
91     return;
92   }
93 
94   BlockCheckSum = crc32_fast((uint8_t*)b->buf + BLKHDR_CS_LENGTH,
95                              block_len - BLKHDR_CS_LENGTH);
96   Pmsg6(000,
97         _("Dump block %s %x: size=%d BlkNum=%d\n"
98           "               Hdrcksum=%x cksum=%x\n"),
99         msg, b, block_len, BlockNumber, CheckSum, BlockCheckSum);
100   p = b->buf + bhl;
101   while (p < (b->buf + block_len + WRITE_RECHDR_LENGTH)) {
102     UnserBegin(p, WRITE_RECHDR_LENGTH);
103     if (rhl == RECHDR1_LENGTH) {
104       unser_uint32(VolSessionId);
105       unser_uint32(VolSessionTime);
106     }
107     unser_int32(FileIndex);
108     unser_int32(Stream);
109     unser_uint32(data_len);
110     Pmsg6(000, _("   Rec: VId=%u VT=%u FI=%s Strm=%s len=%d p=%x\n"),
111           VolSessionId, VolSessionTime, FI_to_ascii(buf1, FileIndex),
112           stream_to_ascii(buf2, Stream, FileIndex), data_len, p);
113     p += data_len + rhl;
114   }
115 }
116 
117 /**
118  * Create a new block structure.
119  * We pass device so that the block can inherit the
120  * min and max block sizes.
121  */
new_block(Device * dev)122 DeviceBlock* new_block(Device* dev)
123 {
124   DeviceBlock* block = (DeviceBlock*)GetMemory(sizeof(DeviceBlock));
125 
126   memset(block, 0, sizeof(DeviceBlock));
127 
128   if (dev->max_block_size == 0) {
129     block->buf_len = dev->device_resource->label_block_size;
130     Dmsg1(100,
131           "created new block of blocksize %d (dev->device->label_block_size) "
132           "as dev->max_block_size is zero\n",
133           block->buf_len);
134   } else {
135     block->buf_len = dev->max_block_size;
136     Dmsg1(100, "created new block of blocksize %d (dev->max_block_size)\n",
137           block->buf_len);
138   }
139   block->dev = dev;
140   block->block_len = block->buf_len; /* default block size */
141   block->buf = GetMemory(block->buf_len);
142   EmptyBlock(block);
143   block->BlockVer = BLOCK_VER; /* default write version */
144   Dmsg1(650, "Returning new block=%x\n", block);
145   return block;
146 }
147 
148 /**
149  * Duplicate an existing block (eblock)
150  */
dup_block(DeviceBlock * eblock)151 DeviceBlock* dup_block(DeviceBlock* eblock)
152 {
153   DeviceBlock* block = (DeviceBlock*)GetMemory(sizeof(DeviceBlock));
154   int buf_len = SizeofPoolMemory(eblock->buf);
155 
156   memcpy(block, eblock, sizeof(DeviceBlock));
157   block->buf = GetMemory(buf_len);
158   memcpy(block->buf, eblock->buf, buf_len);
159   return block;
160 }
161 
162 /**
163  * Only the first block checksum error was reported.
164  *   If there are more, report it now.
165  */
PrintBlockReadErrors(JobControlRecord * jcr,DeviceBlock * block)166 void PrintBlockReadErrors(JobControlRecord* jcr, DeviceBlock* block)
167 {
168   if (block->read_errors > 1) {
169     Jmsg(jcr, M_ERROR, 0, _("%d block read errors not printed.\n"),
170          block->read_errors);
171   }
172 }
173 
174 /**
175  * Free block
176  */
FreeBlock(DeviceBlock * block)177 void FreeBlock(DeviceBlock* block)
178 {
179   if (block) {
180     Dmsg1(999, "FreeBlock buffer %x\n", block->buf);
181     FreeMemory(block->buf);
182     Dmsg1(999, "FreeBlock block %x\n", block);
183     FreeMemory((POOLMEM*)block);
184   }
185 }
186 
187 /**
188  * Empty the block -- for writing
189  */
EmptyBlock(DeviceBlock * block)190 void EmptyBlock(DeviceBlock* block)
191 {
192   block->binbuf = WRITE_BLKHDR_LENGTH;
193   block->bufp = block->buf + block->binbuf;
194   block->read_len = 0;
195   block->write_failed = false;
196   block->block_read = false;
197   block->FirstIndex = block->LastIndex = 0;
198 }
199 
200 /**
201  * Create block header just before write. The space
202  * in the buffer should have already been reserved by
203  * init_block.
204  */
SerBlockHeader(DeviceBlock * block,bool DoChecksum)205 static uint32_t SerBlockHeader(DeviceBlock* block, bool DoChecksum)
206 {
207   ser_declare;
208   uint32_t CheckSum = 0;
209   uint32_t block_len = block->binbuf;
210 
211   Dmsg1(1390, "SerBlockHeader: block_len=%d\n", block_len);
212   SerBegin(block->buf, BLKHDR2_LENGTH);
213   ser_uint32(CheckSum);
214   ser_uint32(block_len);
215   ser_uint32(block->BlockNumber);
216   SerBytes(WRITE_BLKHDR_ID, BLKHDR_ID_LENGTH);
217   if (BLOCK_VER >= 2) {
218     ser_uint32(block->VolSessionId);
219     ser_uint32(block->VolSessionTime);
220   }
221 
222   /*
223    * Checksum whole block except for the checksum
224    */
225   if (DoChecksum) {
226     CheckSum = crc32_fast((uint8_t*)block->buf + BLKHDR_CS_LENGTH,
227                           block_len - BLKHDR_CS_LENGTH);
228   }
229   Dmsg1(1390, "ser_bloc_header: checksum=%x\n", CheckSum);
230   SerBegin(block->buf, BLKHDR2_LENGTH);
231   ser_uint32(CheckSum); /* now add checksum to block header */
232   return CheckSum;
233 }
234 
235 /**
236  * UnSerialize the block header for reading block.
237  * This includes setting all the buffer pointers correctly.
238  *
239  * Returns: false on failure (not a block)
240  *          true  on success
241  */
unSerBlockHeader(JobControlRecord * jcr,Device * dev,DeviceBlock * block)242 static inline bool unSerBlockHeader(JobControlRecord* jcr,
243                                     Device* dev,
244                                     DeviceBlock* block)
245 {
246   ser_declare;
247   char Id[BLKHDR_ID_LENGTH + 1];
248   uint32_t CheckSum, BlockCheckSum;
249   uint32_t block_len;
250   uint32_t block_end;
251   uint32_t BlockNumber;
252   int bhl;
253 
254   UnserBegin(block->buf, BLKHDR_LENGTH);
255   unser_uint32(CheckSum);
256   unser_uint32(block_len);
257   unser_uint32(BlockNumber);
258   UnserBytes(Id, BLKHDR_ID_LENGTH);
259   ASSERT(UnserLength(block->buf) == BLKHDR1_LENGTH);
260 
261   Id[BLKHDR_ID_LENGTH] = 0;
262   if (Id[3] == '1') {
263     bhl = BLKHDR1_LENGTH;
264     block->BlockVer = 1;
265     block->bufp = block->buf + bhl;
266     if (!bstrncmp(Id, BLKHDR1_ID, BLKHDR_ID_LENGTH)) {
267       dev->dev_errno = EIO;
268       Mmsg4(dev->errmsg,
269             _("Volume data error at %u:%u! Wanted ID: \"%s\", got \"%s\". "
270               "Buffer discarded.\n"),
271             dev->file, dev->block_num, BLKHDR1_ID, Id);
272       if (block->read_errors == 0 || verbose >= 2) {
273         Jmsg(jcr, M_ERROR, 0, "%s", dev->errmsg);
274       }
275       block->read_errors++;
276       return false;
277     }
278   } else if (Id[3] == '2') {
279     unser_uint32(block->VolSessionId);
280     unser_uint32(block->VolSessionTime);
281     bhl = BLKHDR2_LENGTH;
282     block->BlockVer = 2;
283     block->bufp = block->buf + bhl;
284     if (!bstrncmp(Id, BLKHDR2_ID, BLKHDR_ID_LENGTH)) {
285       dev->dev_errno = EIO;
286       Mmsg4(dev->errmsg,
287             _("Volume data error at %u:%u! Wanted ID: \"%s\", got \"%s\". "
288               "Buffer discarded.\n"),
289             dev->file, dev->block_num, BLKHDR2_ID, Id);
290       if (block->read_errors == 0 || verbose >= 2) {
291         Jmsg(jcr, M_ERROR, 0, "%s", dev->errmsg);
292       }
293       block->read_errors++;
294       return false;
295     }
296   } else {
297     dev->dev_errno = EIO;
298     Mmsg4(dev->errmsg,
299           _("Volume data error at %u:%u! Wanted ID: \"%s\", got \"%s\". Buffer "
300             "discarded.\n"),
301           dev->file, dev->block_num, BLKHDR2_ID, Id);
302     Dmsg1(50, "%s", dev->errmsg);
303     if (block->read_errors == 0 || verbose >= 2) {
304       Jmsg(jcr, M_ERROR, 0, "%s", dev->errmsg);
305     }
306     block->read_errors++;
307     unser_uint32(block->VolSessionId);
308     unser_uint32(block->VolSessionTime);
309     return false;
310   }
311 
312   /*
313    * Sanity check
314    */
315   if (block_len > MAX_BLOCK_LENGTH) {
316     dev->dev_errno = EIO;
317     Mmsg3(dev->errmsg,
318           _("Volume data error at %u:%u! Block length %u is insane (too "
319             "large), probably due to a bad archive.\n"),
320           dev->file, dev->block_num, block_len);
321     if (block->read_errors == 0 || verbose >= 2) {
322       Jmsg(jcr, M_ERROR, 0, "%s", dev->errmsg);
323     }
324     block->read_errors++;
325     return false;
326   }
327 
328   Dmsg1(390, "unSerBlockHeader block_len=%d\n", block_len);
329   /*
330    * Find end of block or end of buffer whichever is smaller
331    */
332   if (block_len > block->read_len) {
333     block_end = block->read_len;
334   } else {
335     block_end = block_len;
336   }
337   block->binbuf = block_end - bhl;
338   block->block_len = block_len;
339   block->BlockNumber = BlockNumber;
340   Dmsg3(390, "Read binbuf = %d %d block_len=%d\n", block->binbuf, bhl,
341         block_len);
342   if (block_len <= block->read_len && dev->DoChecksum()) {
343     BlockCheckSum = crc32_fast((uint8_t*)block->buf + BLKHDR_CS_LENGTH,
344                                block_len - BLKHDR_CS_LENGTH);
345     if (BlockCheckSum != CheckSum) {
346       dev->dev_errno = EIO;
347       Mmsg6(dev->errmsg,
348             _("Volume data error at %u:%u!\n"
349               "Block checksum mismatch in block=%u len=%d: calc=%x blk=%x\n"),
350             dev->file, dev->block_num, (unsigned)BlockNumber, block_len,
351             BlockCheckSum, CheckSum);
352       if (block->read_errors == 0 || verbose >= 2) {
353         Jmsg(jcr, M_ERROR, 0, "%s", dev->errmsg);
354         DumpBlock(block, "with checksum error");
355       }
356       block->read_errors++;
357       if (!forge_on) { return false; }
358     }
359   }
360   return true;
361 }
362 
RereadLastBlock(DeviceControlRecord * dcr)363 static void RereadLastBlock(DeviceControlRecord* dcr)
364 {
365 #define CHECK_LAST_BLOCK
366 #ifdef CHECK_LAST_BLOCK
367   bool ok = true;
368   Device* dev = dcr->dev;
369   JobControlRecord* jcr = dcr->jcr;
370   DeviceBlock* block = dcr->block;
371   /*
372    * If the device is a tape and it supports backspace record,
373    *   we backspace over one or two eof marks depending on
374    *   how many we just wrote, then over the last record,
375    *   then re-read it and verify that the block number is
376    *   correct.
377    */
378   if (dev->IsTape() && dev->HasCap(CAP_BSR)) {
379     /*
380      * Now back up over what we wrote and read the last block
381      */
382     if (!dev->bsf(1)) {
383       BErrNo be;
384       ok = false;
385       Jmsg(jcr, M_ERROR, 0, _("Backspace file at EOT failed. ERR=%s\n"),
386            be.bstrerror(dev->dev_errno));
387     }
388     if (ok && dev->HasCap(CAP_TWOEOF) && !dev->bsf(1)) {
389       BErrNo be;
390       ok = false;
391       Jmsg(jcr, M_ERROR, 0, _("Backspace file at EOT failed. ERR=%s\n"),
392            be.bstrerror(dev->dev_errno));
393     }
394     /*
395      * Backspace over record
396      */
397     if (ok && !dev->bsr(1)) {
398       BErrNo be;
399       ok = false;
400       Jmsg(jcr, M_ERROR, 0, _("Backspace record at EOT failed. ERR=%s\n"),
401            be.bstrerror(dev->dev_errno));
402       /*
403        *  On FreeBSD systems, if the user got here, it is likely that his/her
404        *    tape drive is "frozen".  The correct thing to do is a
405        *    rewind(), but if we do that, higher levels in cleaning up, will
406        *    most likely write the EOS record over the beginning of the
407        *    tape.  The rewind *is* done later in mount.c when another
408        *    tape is requested. Note, the clrerror() call in bsr()
409        *    calls ioctl(MTCERRSTAT), which *should* fix the problem.
410        */
411     }
412     if (ok) {
413       DeviceBlock* lblock = new_block(dev);
414       /*
415        * Note, this can destroy dev->errmsg
416        */
417       dcr->block = lblock;
418       if (DeviceControlRecord::ReadStatus::Ok
419           != dcr->ReadBlockFromDev(NO_BLOCK_NUMBER_CHECK)) {
420         Jmsg(jcr, M_ERROR, 0, _("Re-read last block at EOT failed. ERR=%s"),
421              dev->errmsg);
422       } else {
423         /*
424          * If we wrote block and the block numbers don't agree
425          *  we have a possible problem.
426          */
427         if (lblock->BlockNumber != dev->LastBlock) {
428           if (dev->LastBlock > (lblock->BlockNumber + 1)) {
429             Jmsg(jcr, M_FATAL, 0,
430                  _("Re-read of last block: block numbers differ by more than "
431                    "one.\n"
432                    "Probable tape misconfiguration and data loss. Read "
433                    "block=%u Want block=%u.\n"),
434                  lblock->BlockNumber, dev->LastBlock);
435           } else {
436             Jmsg(jcr, M_ERROR, 0,
437                  _("Re-read of last block OK, but block numbers differ. Read "
438                    "block=%u Want block=%u.\n"),
439                  lblock->BlockNumber, dev->LastBlock);
440           }
441         } else {
442           Jmsg(jcr, M_INFO, 0, _("Re-read of last block succeeded.\n"));
443         }
444       }
445       FreeBlock(lblock);
446       dcr->block = block;
447     }
448   }
449 #endif
450 }
451 
452 /**
453  * If this routine is called, we do our bookkeeping and
454  * then assure that the volume will not be written any more.
455  */
TerminateWritingVolume(DeviceControlRecord * dcr)456 static bool TerminateWritingVolume(DeviceControlRecord* dcr)
457 {
458   Device* dev = dcr->dev;
459   bool ok = true;
460 
461   /* Create a JobMedia record to indicated end of tape */
462   dev->VolCatInfo.VolCatFiles = dev->file;
463   if (!dcr->DirCreateJobmediaRecord(false)) {
464     Dmsg0(50, "Error from create JobMedia\n");
465     dev->dev_errno = EIO;
466     Mmsg2(dev->errmsg,
467           _("Could not create JobMedia record for Volume=\"%s\" Job=%s\n"),
468           dcr->getVolCatName(), dcr->jcr->Job);
469     Jmsg(dcr->jcr, M_FATAL, 0, "%s", dev->errmsg);
470     ok = false;
471   }
472   dcr->block->write_failed = true;
473   if (!dev->weof(1)) { /* end the tape */
474     dev->VolCatInfo.VolCatErrors++;
475     Jmsg(dcr->jcr, M_ERROR, 0,
476          _("Error writing final EOF to tape. This Volume may not be readable.\n"
477            "%s"),
478          dev->errmsg);
479     ok = false;
480     Dmsg0(50, "Error writing final EOF to volume.\n");
481   }
482   if (ok) {
483     ok = WriteAnsiIbmLabels(dcr, ANSI_EOV_LABEL, dev->VolHdr.VolumeName);
484   }
485   bstrncpy(dev->VolCatInfo.VolCatStatus, "Full",
486            sizeof(dev->VolCatInfo.VolCatStatus));
487   dev->VolCatInfo.VolCatFiles = dev->file; /* set number of files */
488 
489   if (!dcr->DirUpdateVolumeInfo(false, true)) {
490     Mmsg(dev->errmsg, _("Error sending Volume info to Director.\n"));
491     ok = false;
492     Dmsg0(50, "Error updating volume info.\n");
493   }
494   Dmsg1(50, "DirUpdateVolumeInfo Terminate writing -- %s\n",
495         ok ? "OK" : "ERROR");
496 
497   /*
498    * Walk through all attached dcrs setting flag to call
499    * SetNewFileParameters() when that dcr is next used.
500    */
501   for (auto mdcr : dev->attached_dcrs) {
502     if (mdcr->jcr->JobId == 0) { continue; }
503     mdcr->NewFile = true; /* set reminder to do set_new_file_params */
504   }
505   /*
506    * Set new file/block parameters for current dcr
507    */
508   SetNewFileParameters(dcr);
509 
510   if (ok && dev->HasCap(CAP_TWOEOF) && !dev->weof(1)) { /* end the tape */
511     dev->VolCatInfo.VolCatErrors++;
512     /*
513      * This may not be fatal since we already wrote an EOF
514      */
515     Jmsg(dcr->jcr, M_ERROR, 0, "%s", dev->errmsg);
516     Dmsg0(50, "Writing second EOF failed.\n");
517   }
518 
519   dev->SetAteot(); /* no more writing this tape */
520   Dmsg1(50, "*** Leave TerminateWritingVolume -- %s\n", ok ? "OK" : "ERROR");
521   return ok;
522 }
523 
524 /**
525  * Do bookkeeping when a new file is created on a Volume. This is
526  *  also done for disk files to generate the jobmedia records for
527  *  quick seeking.
528  */
DoNewFileBookkeeping(DeviceControlRecord * dcr)529 static bool DoNewFileBookkeeping(DeviceControlRecord* dcr)
530 {
531   Device* dev = dcr->dev;
532   JobControlRecord* jcr = dcr->jcr;
533 
534   /*
535    * Create a JobMedia record so restore can seek
536    */
537   if (!dcr->DirCreateJobmediaRecord(false)) {
538     Dmsg0(50, "Error from create_job_media.\n");
539     dev->dev_errno = EIO;
540     Jmsg2(jcr, M_FATAL, 0,
541           _("Could not create JobMedia record for Volume=\"%s\" Job=%s\n"),
542           dcr->getVolCatName(), jcr->Job);
543     TerminateWritingVolume(dcr);
544     dev->dev_errno = EIO;
545     return false;
546   }
547   dev->VolCatInfo.VolCatFiles = dev->file;
548   if (!dcr->DirUpdateVolumeInfo(false, false)) {
549     Dmsg0(50, "Error from update_vol_info.\n");
550     TerminateWritingVolume(dcr);
551     dev->dev_errno = EIO;
552     return false;
553   }
554   Dmsg0(100, "DirUpdateVolumeInfo max file size -- OK\n");
555 
556   /*
557    * Walk through all attached dcrs setting flag to call
558    * SetNewFileParameters() when that dcr is next used.
559    */
560   for (auto mdcr : dev->attached_dcrs) {
561     if (mdcr->jcr->JobId == 0) { continue; }
562     mdcr->NewFile = true; /* set reminder to do set_new_file_params */
563   }
564   /*
565    * Set new file/block parameters for current dcr
566    */
567   SetNewFileParameters(dcr);
568   return true;
569 }
570 
571 #ifdef DEBUG_BLOCK_CHECKSUM
572 static const bool debug_block_checksum = true;
573 #else
574 static const bool debug_block_checksum = false;
575 #endif
576 
577 #ifdef NO_TAPE_WRITE_TEST
578 static const bool no_tape_write_test = true;
579 #else
580 static const bool no_tape_write_test = false;
581 #endif
582 
583 /**
584  * Write a block to the device
585  *
586  * Returns: true  on success or EOT
587  *          false on hard error
588  */
WriteBlockToDev()589 bool DeviceControlRecord::WriteBlockToDev()
590 {
591   ssize_t status = 0;
592   uint32_t wlen; /* length to write */
593   int hit_max1, hit_max2;
594   bool ok = true;
595   DeviceControlRecord* dcr = this;
596   uint32_t checksum;
597 
598   if (no_tape_write_test) {
599     EmptyBlock(block);
600     return true;
601   }
602   if (JobCanceled(jcr)) {
603     Dmsg0(100, "return WriteBlockToDev, job is canceled\n");
604     return false;
605   }
606 
607   ASSERT(block->binbuf == ((uint32_t)(block->bufp - block->buf)));
608 
609   wlen = block->binbuf;
610   if (wlen <= WRITE_BLKHDR_LENGTH) { /* Does block have data in it? */
611     Dmsg0(100, "return WriteBlockToDev no data to write\n");
612     return true;
613   }
614 
615   /* DumpBlock(block, "before write"); */
616   if (dev->AtWeot()) {
617     Dmsg0(100, "return WriteBlockToDev with ST_WEOT\n");
618     dev->dev_errno = ENOSPC;
619     Jmsg1(jcr, M_FATAL, 0, _("Cannot write block. Device at EOM. dev=%s\n"),
620           dev->print_name());
621     Dmsg1(100, "Attempt to write on read-only Volume. dev=%s\n",
622           dev->print_name());
623     return false;
624   }
625   if (!dev->CanAppend()) {
626     dev->dev_errno = EIO;
627     Jmsg1(jcr, M_FATAL, 0, _("Attempt to write on read-only Volume. dev=%s\n"),
628           dev->print_name());
629     Dmsg1(100, "Attempt to write on read-only Volume. dev=%s\n",
630           dev->print_name());
631     return false;
632   }
633 
634   if (!dev->IsOpen()) {
635     Jmsg1(jcr, M_FATAL, 0, _("Attempt to write on closed device=%s\n"),
636           dev->print_name());
637     Dmsg1(100, "Attempt to write on closed device=%s\n", dev->print_name());
638     return false;
639   }
640 
641   /*
642    * Clear to the end of the buffer if it is not full,
643    * and on devices with CAP_ADJWRITESIZE set, apply min and fixed blocking.
644    */
645   if (wlen != block->buf_len) {
646     uint32_t blen = wlen; /* current buffer length */
647 
648     Dmsg2(250, "binbuf=%d buf_len=%d\n", block->binbuf, block->buf_len);
649 
650     if (!dev->HasCap(CAP_ADJWRITESIZE)) {
651       Dmsg1(400, "%s: block write size is not adjustable", dev->print_name());
652     } else {
653       /* (dev->HasCap(CAP_ADJWRITESIZE)) */
654       if (dev->min_block_size == dev->max_block_size) {
655         /*
656          * Fixed block size
657          */
658         wlen = block->buf_len; /* fixed block size already rounded */
659       } else if (wlen < dev->min_block_size) {
660         /*
661          * Min block size
662          */
663         wlen = ((dev->min_block_size + TAPE_BSIZE - 1) / TAPE_BSIZE)
664                * TAPE_BSIZE;
665       } else {
666         /*
667          * Ensure size is rounded
668          */
669         wlen = ((wlen + TAPE_BSIZE - 1) / TAPE_BSIZE) * TAPE_BSIZE;
670       }
671 
672       if (wlen - blen > 0) {
673         memset(block->bufp, 0, wlen - blen); /* clear garbage */
674       }
675     }
676   }
677 
678   Dmsg5(400,
679         "dev=%s: writing %d bytes as block of %d bytes. Block sizes: min=%d, "
680         "max=%d\n",
681         dev->print_name(), block->binbuf, wlen, dev->min_block_size,
682         dev->max_block_size);
683 
684   checksum = SerBlockHeader(block, dev->DoChecksum());
685 
686   /*
687    * Limit maximum Volume size to value specified by user
688    */
689   hit_max1 = (dev->max_volume_size > 0)
690              && ((dev->VolCatInfo.VolCatBytes + block->binbuf))
691                     >= dev->max_volume_size;
692   hit_max2 = (dev->VolCatInfo.VolCatMaxBytes > 0)
693              && ((dev->VolCatInfo.VolCatBytes + block->binbuf))
694                     >= dev->VolCatInfo.VolCatMaxBytes;
695 
696   if (hit_max1 || hit_max2) {
697     char ed1[50];
698     uint64_t max_cap;
699 
700     Dmsg0(100, "==== Output bytes Triggered medium max capacity.\n");
701     if (hit_max1) {
702       max_cap = dev->max_volume_size;
703     } else {
704       max_cap = dev->VolCatInfo.VolCatMaxBytes;
705     }
706     Jmsg(jcr, M_INFO, 0,
707          _("User defined maximum volume capacity %s exceeded on device %s.\n"),
708          edit_uint64_with_commas(max_cap, ed1), dev->print_name());
709     TerminateWritingVolume(dcr);
710     RereadLastBlock(dcr); /* DEBUG */
711     dev->dev_errno = ENOSPC;
712 
713     return false;
714   }
715 
716   /*
717    * Limit maximum File size on volume to user specified value
718    */
719   if ((dev->max_file_size > 0)
720       && (dev->file_size + block->binbuf) >= dev->max_file_size) {
721     dev->file_size = 0; /* reset file size */
722 
723     if (!dev->weof(1)) { /* write eof */
724       Dmsg0(50, "WEOF error in max file size.\n");
725       Jmsg(jcr, M_FATAL, 0, _("Unable to write EOF. ERR=%s\n"),
726            dev->bstrerror());
727       TerminateWritingVolume(dcr);
728       dev->dev_errno = ENOSPC;
729       return false;
730     }
731     if (!WriteAnsiIbmLabels(dcr, ANSI_EOF_LABEL, dev->VolHdr.VolumeName)) {
732       return false;
733     }
734 
735     if (!DoNewFileBookkeeping(dcr)) {
736       /*
737        * Error message already sent
738        */
739       return false;
740     }
741   }
742 
743   dev->VolCatInfo.VolCatWrites++;
744   Dmsg1(1300, "Write block of %u bytes\n", wlen);
745 #ifdef DEBUG_BLOCK_ZEROING
746   uint32_t* bp = (uint32_t*)block->buf;
747   if (bp[0] == 0 && bp[1] == 0 && bp[2] == 0 && block->buf[12] == 0) {
748     Jmsg0(jcr, M_ABORT, 0, _("Write block header zeroed.\n"));
749   }
750 #endif
751 
752   /*
753    * Do write here,
754    * make a somewhat feeble attempt to recover
755    * from the OS telling us it is busy.
756    */
757   int retry = 0;
758   errno = 0;
759   status = 0;
760   do {
761     if (retry > 0 && status == -1 && errno == EBUSY) {
762       BErrNo be;
763       Dmsg4(100, "===== write retry=%d status=%d errno=%d: ERR=%s\n", retry,
764             status, errno, be.bstrerror());
765       Bmicrosleep(5, 0); /* pause a bit if busy or lots of errors */
766       dev->clrerror(-1);
767     }
768     status = dev->write(block->buf, (size_t)wlen);
769   } while (status == -1 && (errno == EBUSY) && retry++ < 3);
770 
771   if (debug_block_checksum) {
772     uint32_t achecksum = SerBlockHeader(block, dev->DoChecksum());
773     if (checksum != achecksum) {
774       Jmsg2(jcr, M_ERROR, 0,
775             _("Block checksum changed during write: before=%ud after=%ud\n"),
776             checksum, achecksum);
777       DumpBlock(block, "with checksum error");
778     }
779   }
780 
781 #ifdef DEBUG_BLOCK_ZEROING
782   if (bp[0] == 0 && bp[1] == 0 && bp[2] == 0 && block->buf[12] == 0) {
783     Jmsg0(jcr, M_ABORT, 0, _("Write block header zeroed.\n"));
784   }
785 #endif
786 
787   if (status != (ssize_t)wlen) {
788     /*
789      * Some devices simply report EIO when the volume is full.
790      * With a little more thought we may be able to check
791      * capacity and distinguish real errors and EOT
792      * conditions.  In any case, we probably want to
793      * simulate an End of Medium.
794      */
795     if (status == -1) {
796       BErrNo be;
797       dev->clrerror(-1);
798       if (dev->dev_errno == 0) { dev->dev_errno = ENOSPC; /* out of space */ }
799       if (dev->dev_errno != ENOSPC) {
800         dev->VolCatInfo.VolCatErrors++;
801         Jmsg4(jcr, M_ERROR, 0,
802               _("Write error at %u:%u on device %s. ERR=%s.\n"), dev->file,
803               dev->block_num, dev->print_name(), be.bstrerror());
804       }
805     } else {
806       dev->dev_errno = ENOSPC; /* out of space */
807     }
808 
809     if (dev->dev_errno == ENOSPC) {
810       Jmsg(jcr, M_INFO, 0,
811            _("End of Volume \"%s\" at %u:%u on device %s. Write of %u bytes "
812              "got %d.\n"),
813            dev->getVolCatName(), dev->file, dev->block_num, dev->print_name(),
814            wlen, status);
815     } else {
816       BErrNo be;
817 
818       be.SetErrno(dev->dev_errno);
819       Mmsg5(dev->errmsg,
820             _("Write error on fd=%d at file:blk %u:%u on device %s. ERR=%s.\n"),
821             dev->fd, dev->file, dev->block_num, dev->print_name(),
822             be.bstrerror());
823     }
824 
825     GeneratePluginEvent(jcr, bSdEventWriteError, dcr);
826 
827     if (dev->dev_errno != ENOSPC) { Jmsg(jcr, M_ERROR, 0, "%s", dev->errmsg); }
828 
829     if (debug_level >= 100) {
830       BErrNo be;
831 
832       be.SetErrno(dev->dev_errno);
833       Dmsg7(100,
834             "=== Write error. fd=%d size=%u rtn=%d dev_blk=%d blk_blk=%d "
835             "errno=%d: ERR=%s\n",
836             dev->fd, wlen, status, dev->block_num, block->BlockNumber,
837             dev->dev_errno, be.bstrerror(dev->dev_errno));
838     }
839 
840     ok = TerminateWritingVolume(dcr);
841     if (!ok && !forge_on) { return false; }
842     if (ok) { RereadLastBlock(dcr); }
843     return false;
844   }
845 
846   /*
847    * We successfully wrote the block, now do housekeeping
848    */
849   Dmsg2(1300, "VolCatBytes=%d newVolCatBytes=%d\n",
850         (int)dev->VolCatInfo.VolCatBytes,
851         (int)(dev->VolCatInfo.VolCatBytes + wlen));
852   dev->VolCatInfo.VolCatBytes += wlen;
853   dev->VolCatInfo.VolCatBlocks++;
854   dev->EndBlock = dev->block_num;
855   dev->EndFile = dev->file;
856   dev->LastBlock = block->BlockNumber;
857   block->BlockNumber++;
858 
859   /*
860    * Update dcr values
861    */
862   if (dev->IsTape()) {
863     dcr->EndBlock = dev->EndBlock;
864     dcr->EndFile = dev->EndFile;
865     dev->block_num++;
866   } else {
867     /*
868      * Save address of block just written
869      */
870     uint64_t addr = dev->file_addr + wlen - 1;
871     dcr->EndBlock = (uint32_t)addr;
872     dcr->EndFile = (uint32_t)(addr >> 32);
873     dev->block_num = dcr->EndBlock;
874     dev->file = dcr->EndFile;
875   }
876   dcr->VolMediaId = dev->VolCatInfo.VolMediaId;
877   if (dcr->VolFirstIndex == 0 && block->FirstIndex > 0) {
878     dcr->VolFirstIndex = block->FirstIndex;
879   }
880   if (block->LastIndex > 0) { dcr->VolLastIndex = block->LastIndex; }
881   dcr->WroteVol = true;
882   dev->file_addr += wlen; /* update file address */
883   dev->file_size += wlen;
884 
885   Dmsg2(1300, "WriteBlock: wrote block %d bytes=%d\n", dev->block_num, wlen);
886   EmptyBlock(block);
887   return true;
888 }
889 
890 
891 /**
892  * Write a block to the device, with locking and unlocking
893  *
894  * Returns: true  on success
895  *        : false on failure
896  *
897  */
WriteBlockToDevice()898 bool DeviceControlRecord::WriteBlockToDevice()
899 {
900   bool status = true;
901   DeviceControlRecord* dcr = this;
902 
903   if (dcr->spooling) {
904     status = WriteBlockToSpoolFile(dcr);
905     return status;
906   }
907 
908   if (!dcr->IsDevLocked()) { /* device already locked? */
909     /*
910      * Note, do not change this to dcr->r_dlock
911      */
912     dev->rLock(); /* no, lock it */
913   }
914 
915   /*
916    * If a new volume has been mounted since our last write
917    * Create a JobMedia record for the previous volume written,
918    * and set new parameters to write this volume
919    *
920    * The same applies for if we are in a new file.
921    */
922   if (dcr->NewVol || dcr->NewFile) {
923     if (JobCanceled(jcr)) {
924       status = false;
925       Dmsg0(100, "Canceled\n");
926       goto bail_out;
927     }
928     /* Create a jobmedia record for this job */
929     if (!dcr->DirCreateJobmediaRecord(false)) {
930       dev->dev_errno = EIO;
931       Jmsg2(jcr, M_FATAL, 0,
932             _("Could not create JobMedia record for Volume=\"%s\" Job=%s\n"),
933             dcr->getVolCatName(), jcr->Job);
934       SetNewVolumeParameters(dcr);
935       status = false;
936       Dmsg0(100, "cannot create media record\n");
937       goto bail_out;
938     }
939     if (dcr->NewVol) {
940       /*
941        * Note, setting a new volume also handles any pending new file
942        */
943       SetNewVolumeParameters(dcr);
944     } else {
945       SetNewFileParameters(dcr);
946     }
947   }
948 
949   if (!dcr->WriteBlockToDev()) {
950     if (JobCanceled(jcr) || jcr->is_JobType(JT_SYSTEM)) {
951       status = false;
952     } else {
953       status = FixupDeviceBlockWriteError(dcr);
954     }
955   }
956 
957 bail_out:
958   if (!dcr->IsDevLocked()) { /* did we lock dev above? */
959     /*
960      * Note, do not change this to dcr->dunlock
961      */
962     dev->Unlock(); /* unlock it now */
963   }
964   return status;
965 }
966 
967 /**
968  * Read block with locking
969  */
ReadBlockFromDevice(bool check_block_numbers)970 DeviceControlRecord::ReadStatus DeviceControlRecord::ReadBlockFromDevice(
971     bool check_block_numbers)
972 {
973   ReadStatus status;
974 
975   Dmsg0(250, "Enter ReadBlockFromDevice\n");
976   dev->rLock();
977   status = ReadBlockFromDev(check_block_numbers);
978   dev->Unlock();
979   Dmsg0(250, "Leave ReadBlockFromDevice\n");
980   return status;
981 }
982 
983 /**
984  * Read the next block into the block structure and unserialize
985  *  the block header.  For a file, the block may be partially
986  *  or completely in the current buffer.
987  */
ReadBlockFromDev(bool check_block_numbers)988 DeviceControlRecord::ReadStatus DeviceControlRecord::ReadBlockFromDev(
989     bool check_block_numbers)
990 {
991   ssize_t status;
992   int looping;
993   int retry;
994   DeviceControlRecord* dcr = this;
995 
996   if (JobCanceled(jcr)) {
997     Mmsg(dev->errmsg, _("Job failed or canceled.\n"));
998     block->read_len = 0;
999     return ReadStatus::Error;
1000   }
1001 
1002   if (dev->AtEot()) {
1003     Mmsg(dev->errmsg, _("Attempt to read past end of tape or file.\n"));
1004     block->read_len = 0;
1005     return ReadStatus::EndOfTape;
1006   }
1007   looping = 0;
1008   Dmsg1(250, "Full read in ReadBlockFromDevice() len=%d\n", block->buf_len);
1009 
1010   if (!dev->IsOpen()) {
1011     Mmsg4(dev->errmsg,
1012           _("Attempt to read closed device: fd=%d at file:blk %u:%u on device "
1013             "%s\n"),
1014           dev->fd, dev->file, dev->block_num, dev->print_name());
1015     Jmsg(dcr->jcr, M_WARNING, 0, "%s", dev->errmsg);
1016     block->read_len = 0;
1017     return ReadStatus::Error;
1018   }
1019 
1020 reread:
1021   if (looping > 1) {
1022     dev->dev_errno = EIO;
1023     Mmsg1(dev->errmsg, _("Block buffer size looping problem on device %s\n"),
1024           dev->print_name());
1025     Jmsg(jcr, M_ERROR, 0, "%s", dev->errmsg);
1026     block->read_len = 0;
1027     return ReadStatus::Error;
1028   }
1029 
1030   retry = 0;
1031   errno = 0;
1032   status = 0;
1033 
1034   do {
1035     if (retry) {
1036       BErrNo be;
1037       Dmsg4(100, "===== read retry=%d status=%d errno=%d: ERR=%s\n", retry,
1038             status, errno, be.bstrerror());
1039       Bmicrosleep(10, 0); /* pause a bit if busy or lots of errors */
1040       dev->clrerror(-1);
1041     }
1042     status = dev->read(block->buf, (size_t)block->buf_len);
1043 
1044   } while (status == -1 && (errno == EBUSY || errno == EINTR || errno == EIO)
1045            && retry++ < 3);
1046 
1047   if (status < 0) {
1048     BErrNo be;
1049 
1050     dev->clrerror(-1);
1051     Dmsg1(250, "Read device got: ERR=%s\n", be.bstrerror());
1052     block->read_len = 0;
1053     Mmsg5(dev->errmsg,
1054           _("Read error on fd=%d at file:blk %u:%u on device %s. ERR=%s.\n"),
1055           dev->fd, dev->file, dev->block_num, dev->print_name(),
1056           be.bstrerror());
1057 
1058     GeneratePluginEvent(jcr, bSdEventReadError, dcr);
1059 
1060     Jmsg(jcr, M_ERROR, 0, "%s", dev->errmsg);
1061     if (device_resource->eof_on_error_is_eot && dev->AtEof()) {
1062       dev->SetEot();
1063       return ReadStatus::EndOfTape;
1064     }
1065     return ReadStatus::Error;
1066   }
1067 
1068   Dmsg3(250, "Read device got %d bytes at %u:%u\n", status, dev->file,
1069         dev->block_num);
1070 
1071   if (status == 0) { /* EOF (Berkley I/O Conventions) */
1072     dev->block_num = 0;
1073     block->read_len = 0;
1074     Mmsg3(dev->errmsg, _("Read zero bytes at %u:%u on device %s.\n"), dev->file,
1075           dev->block_num, dev->print_name());
1076     if (dev->AtEof()) { /* EOF already set before means end of tape */
1077       dev->SetEot();
1078       return ReadStatus::EndOfTape;
1079     }
1080     dev->SetAteof();
1081     return ReadStatus::EndOfFile;
1082   }
1083 
1084   /*
1085    * successful read (status > 0)
1086    */
1087 
1088   block->read_len = status; /* save length read */
1089   if (block->read_len == 80
1090       && (dcr->VolCatInfo.LabelType != B_BAREOS_LABEL
1091           || dcr->device_resource->label_type != B_BAREOS_LABEL)) {
1092     /* ***FIXME*** should check label */
1093     Dmsg2(100, "Ignore 80 byte ANSI label at %u:%u\n", dev->file,
1094           dev->block_num);
1095     dev->ClearEof();
1096     goto reread; /* skip ANSI/IBM label */
1097   }
1098 
1099   if (block->read_len < BLKHDR2_LENGTH) {
1100     dev->dev_errno = EIO;
1101     Mmsg4(dev->errmsg,
1102           _("Volume data error at %u:%u! Very short block of %d bytes on "
1103             "device %s discarded.\n"),
1104           dev->file, dev->block_num, block->read_len, dev->print_name());
1105     Jmsg(jcr, M_ERROR, 0, "%s", dev->errmsg);
1106     dev->SetShortBlock();
1107     block->read_len = block->binbuf = 0;
1108     Dmsg2(200, "set block=%p binbuf=%d\n", block, block->binbuf);
1109     return ReadStatus::Error;
1110   }
1111 
1112   // BlockNumber = block->BlockNumber + 1;
1113   if (!unSerBlockHeader(jcr, dev, block)) {
1114     if (forge_on) {
1115       dev->file_addr += block->read_len;
1116       dev->file_size += block->read_len;
1117       goto reread;
1118     }
1119     return ReadStatus::Error;
1120   }
1121 
1122   /*
1123    * If the block is bigger than the buffer, we Reposition for
1124    *  re-reading the block, allocate a buffer of the correct size,
1125    *  and go re-read.
1126    */
1127   if (block->block_len > block->buf_len) {
1128     dev->dev_errno = EIO;
1129     Mmsg2(
1130         dev->errmsg,
1131         _("Block length %u is greater than buffer %u. Attempting recovery.\n"),
1132         block->block_len, block->buf_len);
1133     Jmsg(jcr, M_ERROR, 0, "%s", dev->errmsg);
1134     Pmsg1(000, "%s", dev->errmsg);
1135     /*
1136      * Attempt to Reposition to re-read the block
1137      */
1138     if (dev->IsTape()) {
1139       Dmsg0(250, "BootStrapRecord for reread; block too big for buffer.\n");
1140       if (!dev->bsr(1)) {
1141         Mmsg(dev->errmsg, "%s", dev->bstrerror());
1142         Jmsg(jcr, M_ERROR, 0, "%s", dev->errmsg);
1143         block->read_len = 0;
1144         return ReadStatus::Error;
1145       }
1146     } else {
1147       Dmsg0(250, "Seek to beginning of block for reread.\n");
1148       boffset_t pos
1149           = dev->d_lseek(dcr, (boffset_t)0, SEEK_CUR); /* get curr pos */
1150       pos -= block->read_len;
1151       dev->d_lseek(dcr, pos, SEEK_SET);
1152       dev->file_addr = pos;
1153     }
1154     Mmsg1(dev->errmsg, _("Setting block buffer size to %u bytes.\n"),
1155           block->block_len);
1156     Jmsg(jcr, M_INFO, 0, "%s", dev->errmsg);
1157     Pmsg1(000, "%s", dev->errmsg);
1158     /*
1159      * Set new block length
1160      */
1161     dev->max_block_size = block->block_len;
1162     block->buf_len = block->block_len;
1163     FreeMemory(block->buf);
1164     block->buf = GetMemory(block->buf_len);
1165     EmptyBlock(block);
1166     looping++;
1167     goto reread; /* re-read block with correct block size */
1168   }
1169 
1170   if (block->block_len > block->read_len) {
1171     dev->dev_errno = EIO;
1172     Mmsg4(dev->errmsg,
1173           _("Volume data error at %u:%u! Short block of %d bytes on device %s "
1174             "discarded.\n"),
1175           dev->file, dev->block_num, block->read_len, dev->print_name());
1176     Jmsg(jcr, M_ERROR, 0, "%s", dev->errmsg);
1177     dev->SetShortBlock();
1178     block->read_len = block->binbuf = 0;
1179     return ReadStatus::Error;
1180   }
1181 
1182   dev->ClearShortBlock();
1183   dev->ClearEof();
1184   dev->VolCatInfo.VolCatReads++;
1185   dev->VolCatInfo.VolCatRBytes += block->read_len;
1186 
1187   dev->EndBlock = dev->block_num;
1188   dev->EndFile = dev->file;
1189   dev->block_num++;
1190 
1191   /*
1192    * Update dcr values
1193    */
1194   if (dev->IsTape()) {
1195     dcr->EndBlock = dev->EndBlock;
1196     dcr->EndFile = dev->EndFile;
1197   } else {
1198     /*
1199      * We need to take care about a short block in EndBlock/File computation
1200      */
1201     uint32_t len = MIN(block->read_len, block->block_len);
1202     uint64_t addr = dev->file_addr + len - 1;
1203     dcr->EndBlock = (uint32_t)addr;
1204     dcr->EndFile = (uint32_t)(addr >> 32);
1205     dev->block_num = dev->EndBlock = dcr->EndBlock;
1206     dev->file = dev->EndFile = dcr->EndFile;
1207   }
1208   dcr->VolMediaId = dev->VolCatInfo.VolMediaId;
1209   dev->file_addr += block->read_len;
1210   dev->file_size += block->read_len;
1211 
1212   /*
1213    * If we read a short block on disk,
1214    * seek to beginning of next block. This saves us
1215    * from shuffling blocks around in the buffer. Take a
1216    * look at this from an efficiency stand point later, but
1217    * it should only happen once at the end of each job.
1218    *
1219    * I've been lseek()ing negative relative to SEEK_CUR for 30
1220    *   years now. However, it seems that with the new off_t definition,
1221    *   it is not possible to seek negative amounts, so we use two
1222    *   lseek(). One to get the position, then the second to do an
1223    *   absolute positioning -- so much for efficiency.  KES Sep 02.
1224    */
1225   Dmsg0(250, "At end of read block\n");
1226   if (block->read_len > block->block_len && !dev->IsTape()) {
1227     char ed1[50];
1228     boffset_t pos
1229         = dev->d_lseek(dcr, (boffset_t)0, SEEK_CUR); /* get curr pos */
1230     Dmsg1(250, "Current lseek pos=%s\n", edit_int64(pos, ed1));
1231     pos -= (block->read_len - block->block_len);
1232     dev->d_lseek(dcr, pos, SEEK_SET);
1233     Dmsg3(250, "Did lseek pos=%s blk_size=%d rdlen=%d\n", edit_int64(pos, ed1),
1234           block->block_len, block->read_len);
1235     dev->file_addr = pos;
1236     dev->file_size = pos;
1237   }
1238   Dmsg2(250, "Exit read_block read_len=%d block_len=%d\n", block->read_len,
1239         block->block_len);
1240   block->block_read = true;
1241   return ReadStatus::Ok;
1242 }
1243 
1244 } /* namespace storagedaemon */
1245