w11 - cpp 0.794
Backend server for Rlink and w11
Loading...
Searching...
No Matches
Rw11VirtTapeTap.cpp
Go to the documentation of this file.
1// $Id: Rw11VirtTapeTap.cpp 1186 2019-07-12 17:49:59Z mueller $
2// SPDX-License-Identifier: GPL-3.0-or-later
3// Copyright 2015-2019 by Walter F.J. Mueller <W.F.J.Mueller@gsi.de>
4//
5// Revision History:
6// Date Rev Version Comment
7// 2019-07-08 1180 1.1 use RfileFd; remove dtor
8// 2018-12-19 1090 1.0.4 use RosPrintf(bool)
9// 2018-09-22 1048 1.0.3 BUGFIX: coverity (resource leak; bad expression)
10// 2017-04-15 875 1.0.2 Open(): set default scheme
11// 2017-04-07 868 1.0.1 Dump(): add detail arg
12// 2015-06-04 686 1.0 Initial version
13// 2015-05-17 683 0.1 First draft
14// ---------------------------------------------------------------------------
15
20#include "librtools/RosFill.hpp"
22#include "librtools/Rtools.hpp"
23
24#include "Rw11VirtTapeTap.hpp"
25
26using namespace std;
27
33// all method definitions in namespace Retro
34namespace Retro {
35
36//------------------------------------------+-----------------------------------
37// constants definitions
38
39const uint32_t Rw11VirtTapeTap::kMetaEof;
40const uint32_t Rw11VirtTapeTap::kMetaEom;
42const uint32_t Rw11VirtTapeTap::kMeta_M_Mbz;
44
45//------------------------------------------+-----------------------------------
47
49 : Rw11VirtTape(punit),
50 fFd("Rw11VirtTapeTap::fFd."),
51 fSize(0),
52 fPos(0),
53 fBad(true),
54 fPadOdd(false),
55 fTruncPend(false)
56{}
57
58//------------------------------------------+-----------------------------------
60
61bool Rw11VirtTapeTap::Open(const std::string& url, RerrMsg& emsg)
62{
63 if (!fUrl.Set(url, "|wpro|e11|cap=|", "tap", emsg)) return false;
64
65 fWProt = fUrl.FindOpt("wpro");
66 fPadOdd = fUrl.FindOpt("e11");
67
68 string str_cap;
69 unsigned long capacity=0;
70 if (fUrl.FindOpt("cap",str_cap)) {
71 if (str_cap.length() > 0) {
72 unsigned long scale = 1;
73 string str_conv = str_cap;
74 char clast = str_cap[str_cap.length()-1];
75 bool ok = true;
76
77 if (! (clast >= '0' && clast <= '9') ) {
78 str_conv = str_cap.substr(0,str_cap.length()-1);
79 switch(str_cap[str_cap.length()-1]) {
80 case 'k':
81 case 'K':
82 scale = 1024;
83 break;
84 case 'm':
85 case 'M':
86 scale = 1024*1024;
87 break;
88 default:
89 ok = false;
90 break;
91 }
92 }
93 if (ok) {
94 RerrMsg emsg_conv;
95 ok = Rtools::String2Long(str_conv, capacity, emsg_conv);
96 }
97 if (!ok) {
98 emsg.Init("Rw11VirtTapeTap::Open()",
99 string("bad capacity option '")+str_cap+"'");
100 return false;
101 }
102 capacity *= scale;
103 }
104 }
105
106 if (!fFd.Open(fUrl.Path().c_str(), fWProt ? O_RDONLY : O_CREAT|O_RDWR,
107 S_IRUSR|S_IWUSR|S_IRGRP, emsg)) return false;
108
109 struct stat sbuf;
110 if (!fFd.Stat(&sbuf, emsg)) {
111 fFd.Close();
112 return false;
113 }
114
115 if ((sbuf.st_mode & S_IWUSR) == 0) fWProt = true;
116
117 fSize = sbuf.st_size;
118 fPos = 0;
119 fBad = false;
120 fTruncPend = true;
121
122 fCapacity = capacity;
123 fBot = true;
124 fEot = false;
125 fEom = false;
126 fPosFile = 0;
127 fPosRecord = 0;
128 return true;
129}
130
131//------------------------------------------+-----------------------------------
133
134bool Rw11VirtTapeTap::ReadRecord(size_t nbyt, uint8_t* data, size_t& ndone,
135 int& opcode, RerrMsg& emsg)
136{
138
139 opcode = kOpCodeBadFormat;
140 ndone = 0;
141 if (fBad) return BadTapeMsg("ReadRecord()", emsg);
142
143 if (fPos == fSize) {
144 fEom = true;
145 opcode = kOpCodeEom;
146 return true;
147 }
148
149 uint32_t metabeg;
150 uint32_t metaend;
151
152 if (!CheckSizeForw(sizeof(metabeg), "missed metabeg", emsg)) return SetBad();
153 if (!Read(sizeof(metabeg), reinterpret_cast<uint8_t*>(&metabeg),
154 emsg)) return SetBad();
155
156 if (metabeg == kMetaEof) {
158 opcode = kOpCodeEof;
159 fPosFile += 1;
160 fPosRecord = 0;
161 return true;
162 }
163
164 if (metabeg == kMetaEom) {
165 if (!Seek(sizeof(metabeg), -1, emsg)) return SetBad();
167 fEom = true;
168 opcode = kOpCodeEom;
169 return true;
170 }
171
172 size_t rlen;
173 bool perr;
174 if (!ParseMeta(metabeg, rlen, perr, emsg)) return SetBad();
175 size_t rlenpad = BytePadding(rlen);
176
177 if (!CheckSizeForw(rlenpad, "missed data", emsg)) return SetBad();
178
179 ndone = (rlen <= nbyt) ? rlen : nbyt;
180 if (!Read(ndone, data, emsg)) return SetBad();
181 if (ndone < rlenpad) {
182 if (!Seek(rlenpad, +1, emsg)) return SetBad();
183 }
184
185 if (!CheckSizeForw(sizeof(metaend), "missed metaend", emsg)) return SetBad();
186 if (!Read(sizeof(metaend), reinterpret_cast<uint8_t*>(&metaend),
187 emsg)) return SetBad();
188
189 if (metabeg != metaend) {
190 emsg.Init("Rw11VirtTapeTap::ReadRecord", "metabeg metaend mismatch");
191 ndone = 0;
192 return SetBad();
193 }
194
195 IncPosRecord(+1);
196 opcode = kOpCodeOK;
197 if (perr) {
199 opcode = kOpCodeBadParity;
200 }
201 if (ndone < rlen) {
203 opcode = kOpCodeRecLenErr;
204 }
205
206 fStats.Inc(kStatNVTReadByt, ndone);
207
208 return true;
209}
210
211//------------------------------------------+-----------------------------------
213
214bool Rw11VirtTapeTap::WriteRecord(size_t nbyt, const uint8_t* data,
215 int& opcode, RerrMsg& emsg)
216{
219
220 opcode = kOpCodeBadFormat;
221 if (fBad) return BadTapeMsg("WriteRecord()", emsg);
222
223 fEom = false;
224
225 uint32_t meta = nbyt;
226 uint8_t zero = 0x00;
227
228 if (!Write(sizeof(meta), reinterpret_cast<uint8_t*>(&meta),
229 false, emsg)) return SetBad();
230
231 if (!Write(nbyt, data,
232 false, emsg)) return SetBad();
233 if (fPadOdd && (nbyt&0x01)) {
234 if (!Write(sizeof(zero), &zero, false, emsg)) return SetBad();
235 }
236
237 if (!Write(sizeof(meta), reinterpret_cast<uint8_t*>(&meta),
238 false, emsg)) return SetBad();
239 if (!Write(sizeof(kMetaEom), reinterpret_cast<const uint8_t*>(&kMetaEom),
240 true, emsg)) return SetBad();
241
242 IncPosRecord(+1);
243 opcode = kOpCodeOK;
244
245 return true;
246}
247
248//------------------------------------------+-----------------------------------
250
252{
254
255 if (fBad) return BadTapeMsg("WriteEof()", emsg);
256
257 fEom = false;
258
259 if (!Write(sizeof(kMetaEof), reinterpret_cast<const uint8_t*>(&kMetaEof),
260 false, emsg)) return SetBad();
261 if (!Write(sizeof(kMetaEom), reinterpret_cast<const uint8_t*>(&kMetaEom),
262 true, emsg)) return SetBad();
263
264 fPosFile += 1;
265 fPosRecord = 0;
266
267 return true;
268}
269
270//------------------------------------------+-----------------------------------
272
273bool Rw11VirtTapeTap::SpaceForw(size_t nrec, size_t& ndone,
274 int& opcode, RerrMsg& emsg)
275{
277
278 opcode = kOpCodeBadFormat;
279 ndone = 0;
280 if (fBad) return BadTapeMsg("SpaceForw()", emsg);
281
282 while (nrec > 0) {
283
284 if (fPos == fSize) {
285 fEom = true;
286 opcode = kOpCodeEom;
287 return true;
288 }
289
290 uint32_t metabeg;
291
292 if (!CheckSizeForw(sizeof(metabeg), "missed metabeg", emsg)) return SetBad();
293 if (!Read(sizeof(metabeg), reinterpret_cast<uint8_t*>(&metabeg),
294 emsg)) return SetBad();
295
296 if (metabeg == kMetaEof) {
297 opcode = kOpCodeEof;
298 fPosFile += 1;
299 fPosRecord = 0;
300 return true;
301 }
302
303 if (metabeg == kMetaEom) {
304 if (!Seek(sizeof(metabeg), -1, emsg)) return SetBad();
305 fEom = true;
306 opcode = kOpCodeEom;
307 return true;
308 }
309
310 size_t rlen;
311 bool perr;
312 if (!ParseMeta(metabeg, rlen, perr, emsg)) return SetBad();
313 size_t rlenpad = BytePadding(rlen);
314
315 if (!CheckSizeForw(sizeof(metabeg)+rlenpad, "missed data or metaend", emsg))
316 return SetBad();
317 if (!Seek(sizeof(metabeg)+rlenpad, +1, emsg)) return SetBad();
318
319 IncPosRecord(+1);
320 nrec -= 1;
321 ndone += 1;
322 }
323
324 opcode = kOpCodeOK;
325
326 return true;
327}
328
329//------------------------------------------+-----------------------------------
331
332bool Rw11VirtTapeTap::SpaceBack(size_t nrec, size_t& ndone,
333 int& opcode, RerrMsg& emsg)
334{
336
337 opcode = kOpCodeBadFormat;
338 ndone = 0;
339 if (fBad) return BadTapeMsg("SpaceBack()", emsg);
340
341 fEom = false;
342 fTruncPend = true;
343
344 while (nrec > 0) {
345
346 if (fPos == 0) {
347 opcode = kOpCodeBot;
348 fPosFile = 0;
349 fPosRecord = 0;
350 return true;
351 }
352
353 uint32_t metaend;
354
355 if (!CheckSizeBack(sizeof(metaend), "missed metaend", emsg)) return SetBad();
356 if (!Seek(sizeof(metaend), -1, emsg)) return SetBad();
357 if (!Read(sizeof(metaend), reinterpret_cast<uint8_t*>(&metaend),
358 emsg)) return SetBad();
359
360 if (metaend == kMetaEof) {
361 if (!Seek(sizeof(metaend), -1, emsg)) return SetBad();
362 opcode = kOpCodeEof;
363 fPosFile -= 1;
364 fPosRecord = -1;
365 return true;
366 }
367
368 if (metaend == kMetaEom) {
369 emsg.Init("Rw11VirtTapeTap::SpaceBack()","unexpected EOM marker");
370 return SetBad();
371 }
372
373 size_t rlen;
374 bool perr;
375 if (!ParseMeta(metaend, rlen, perr, emsg)) return SetBad();
376 size_t rlenpad = BytePadding(rlen);
377
378 if (!CheckSizeBack(2*sizeof(metaend)+rlenpad,
379 "missed data or metabeg", emsg)) return SetBad();
380 if (!Seek(2*sizeof(metaend)+rlenpad, -1, emsg)) return SetBad();
381
382 IncPosRecord(-1);
383 nrec -= 1;
384 ndone += 1;
385 }
386
387 opcode = kOpCodeOK;
388
389 return true;
390}
391
392//------------------------------------------+-----------------------------------
394
395bool Rw11VirtTapeTap::Rewind(int& opcode, RerrMsg& emsg)
396{
398
399 opcode = kOpCodeBadFormat;
400 if (!Seek(0, 0, emsg)) return SetBad();
401
402 fBot = true;
403 fEot = false;
404 fEom = false;
405 fPosFile = 0;
406 fPosRecord = 0;
407 fBad = false;
408 fTruncPend = true;
409
410 opcode = kOpCodeOK;
411 return true;
412}
413
414//------------------------------------------+-----------------------------------
416
417void Rw11VirtTapeTap::Dump(std::ostream& os, int ind, const char* text,
418 int detail) const
419{
420 RosFill bl(ind);
421 os << bl << (text?text:"--") << "Rw11VirtTapeTap @ " << this << endl;
422
423 os << bl << " fFd: " << fFd.Fd() << endl;
424 os << bl << " fSize: " << fSize << endl;
425 os << bl << " fPos: " << fPos << endl;
426 os << bl << " fBad: " << RosPrintf(fBad) << endl;
427 os << bl << " fPadOdd: " << RosPrintf(fPadOdd) << endl;
428 os << bl << " fTruncPend: " << RosPrintf(fTruncPend) << endl;
429 Rw11VirtTape::Dump(os, ind, " ^", detail);
430 return;
431}
432
433//------------------------------------------+-----------------------------------
435
436bool Rw11VirtTapeTap::Seek(size_t seekpos, int dir, RerrMsg& emsg)
437{
438 off_t offset = seekpos;
439 int whence = SEEK_SET;
440 if (dir > 0) {
441 whence = SEEK_CUR;
442 } else if (dir < 0) {
443 whence = SEEK_CUR;
444 offset = -offset;
445 }
446 if (!fFd.Seek(offset, whence, emsg)) return false;
447
448 UpdatePos(seekpos, dir);
449
450 return true;
451}
452
453//------------------------------------------+-----------------------------------
455
456bool Rw11VirtTapeTap::Read(size_t nbyt, uint8_t* data, RerrMsg& emsg)
457{
458 ssize_t irc = fFd.Read(data, nbyt, emsg);
459 if (irc < 0) return false;
460 UpdatePos(nbyt, +1);
461 return true;
462}
463
464//------------------------------------------+-----------------------------------
466
467bool Rw11VirtTapeTap::Write(size_t nbyt, const uint8_t* data, bool back,
468 RerrMsg& emsg)
469{
470 if (fTruncPend) {
471 if (!fFd.Truncate(fPos, emsg)) return false;
472 fTruncPend = false;
473 fSize = fPos;
474 }
475
476 if (!fFd.WriteAll(data, nbyt, emsg)) return false;
477 UpdatePos(nbyt, +1);
478 if (fPos > fSize) fSize = fPos;
479
480 if (back) {
481 if (!Seek(nbyt, -1, emsg)) return false;
482 }
483
484 return true;
485}
486
487//------------------------------------------+-----------------------------------
489
490bool Rw11VirtTapeTap::CheckSizeForw(size_t nbyt, const char* text,
491 RerrMsg& emsg)
492{
493 if (fPos+nbyt <= fSize) return true;
494 emsg.Init("Rw11VirtTapeTap::CheckSizeForw()", text);
495 return false;
496}
497
498//------------------------------------------+-----------------------------------
500
501bool Rw11VirtTapeTap::CheckSizeBack(size_t nbyt, const char* text,
502 RerrMsg& emsg)
503{
504 if (nbyt <= fPos) return true;
505 emsg.Init("Rw11VirtTapeTap::CheckSizeBack()", text);
506 return false;
507}
508
509//------------------------------------------+-----------------------------------
511
512void Rw11VirtTapeTap::UpdatePos(size_t nbyt, int dir)
513{
514 if (dir == 0) {
515 fPos = nbyt;
516 } else if (dir > 0) {
517 fPos += nbyt;
518 } else {
519 fPos -= nbyt;
520 }
521
522 fBot = (fPos == 0);
523 fEot = (fCapacity == 0) ? false : (fPos > fCapacity);
524
525 return;
526}
527
528//------------------------------------------+-----------------------------------
530
531bool Rw11VirtTapeTap::ParseMeta(uint32_t meta, size_t& rlen, bool& perr,
532 RerrMsg& emsg)
533{
534 rlen = meta & kMeta_B_Rlen;
535 perr = meta & kMeta_M_Perr;
536 if (meta & kMeta_M_Mbz) {
537 emsg.Init("Rw11VirtTapeTap::ParseMeta", "bad meta tag");
538 return false;
539 }
540 return true;
541}
542
543//------------------------------------------+-----------------------------------
545
546bool Rw11VirtTapeTap::BadTapeMsg(const char* meth, RerrMsg& emsg)
547{
548 emsg.Init(string("Rw11VirtTapeTap::")+meth, "bad tape format");
549 return false;
550}
551
552} // end namespace Retro
FIXME_docs.
Definition: RerrMsg.hpp:25
void Init(const std::string &meth, const std::string &text)
FIXME_docs.
Definition: RerrMsg.cpp:74
int Fd() const
FIXME_docs.
Definition: Rfd.ipp:20
void Close()
FIXME_docs.
Definition: Rfd.cpp:82
bool WriteAll(const void *buf, size_t count, RerrMsg &emsg)
FIXME_docs.
Definition: RfileFd.cpp:119
ssize_t Read(void *buf, size_t count, RerrMsg &emsg)
FIXME_docs.
Definition: RfileFd.cpp:107
bool Stat(struct stat *sbuf, RerrMsg &emsg)
FIXME_docs.
Definition: RfileFd.cpp:71
off_t Seek(off_t offset, int whence, RerrMsg &emsg)
FIXME_docs.
Definition: RfileFd.cpp:83
bool Open(const char *fname, int flags, RerrMsg &emsg)
FIXME_docs.
Definition: RfileFd.cpp:45
bool Truncate(off_t length, RerrMsg &emsg)
FIXME_docs.
Definition: RfileFd.cpp:95
I/O appicator to generate fill characters.
Definition: RosFill.hpp:24
bool FindOpt(const std::string &name) const
FIXME_docs.
Definition: RparseUrl.cpp:196
bool Set(const std::string &url, const std::string &optlist, RerrMsg &emsg)
FIXME_docs.
Definition: RparseUrl.cpp:55
const std::string & Path() const
FIXME_docs.
Definition: RparseUrl.ipp:45
void Inc(size_t ind, double val=1.)
FIXME_docs.
Definition: Rstats.ipp:29
FIXME_docs.
Definition: Rw11Unit.hpp:39
virtual bool Open(const std::string &url, RerrMsg &emsg)
FIXME_docs.
static const uint32_t kMeta_M_Perr
virtual bool SpaceForw(size_t nrec, size_t &ndone, int &opcode, RerrMsg &emsg)
FIXME_docs.
static const uint32_t kMetaEom
EOM marker.
size_t fPos
file position
bool Write(size_t nbyt, const uint8_t *data, bool back, RerrMsg &emsg)
FIXME_docs.
static const uint32_t kMeta_B_Rlen
bool CheckSizeForw(size_t nbyt, const char *text, RerrMsg &emsg)
FIXME_docs.
static const uint32_t kMetaEof
EOF marker.
virtual bool WriteRecord(size_t nbyt, const uint8_t *data, int &opcode, RerrMsg &emsg)
FIXME_docs.
virtual bool Rewind(int &opcode, RerrMsg &emsg)
FIXME_docs.
bool CheckSizeBack(size_t nbyt, const char *text, RerrMsg &emsg)
FIXME_docs.
bool BadTapeMsg(const char *meth, RerrMsg &emsg)
FIXME_docs.
bool Seek(size_t seekpos, int dir, RerrMsg &emsg)
FIXME_docs.
virtual bool WriteEof(RerrMsg &emsg)
FIXME_docs.
Rw11VirtTapeTap(Rw11Unit *punit)
Default constructor.
bool Read(size_t nbyt, uint8_t *data, RerrMsg &emsg)
FIXME_docs.
bool ParseMeta(uint32_t meta, size_t &rlen, bool &perr, RerrMsg &emsg)
FIXME_docs.
bool fBad
BAD file format flag.
bool SetBad()
FIXME_docs.
static const uint32_t kMeta_M_Mbz
virtual bool ReadRecord(size_t nbyt, uint8_t *data, size_t &ndone, int &opcode, RerrMsg &emsg)
FIXME_docs.
bool fPadOdd
do odd byte padding
bool fTruncPend
truncate on next write
void IncPosRecord(int delta)
FIXME_docs.
virtual bool SpaceBack(size_t nrec, size_t &ndone, int &opcode, RerrMsg &emsg)
FIXME_docs.
void UpdatePos(size_t nbyt, int dir)
FIXME_docs.
RfileFd fFd
file number
virtual void Dump(std::ostream &os, int ind=0, const char *text=0, int detail=0) const
FIXME_docs.
size_t BytePadding(size_t rlen)
FIXME_docs.
virtual void Dump(std::ostream &os, int ind=0, const char *text=0, int detail=0) const
FIXME_docs.
@ kOpCodeRecLenErr
record length error
@ kOpCodeBot
ended at BOT
@ kOpCodeBadFormat
file format error
@ kOpCodeOK
operation OK
@ kOpCodeEof
ended at EOF
@ kOpCodeEom
ended at EOM
@ kOpCodeBadParity
record with parity error
int fPosRecord
tape pos: #record (-1=unknown)
size_t fCapacity
capacity in byte (0=unlimited)
bool fBot
tape at bot
bool fEom
tape beyond medium
int fPosFile
tape pos: #files (-1=unknown)
bool fEot
tape beyond eot
RparseUrl fUrl
Definition: Rw11Virt.hpp:66
Rstats fStats
statistics
Definition: Rw11Virt.hpp:68
bool fWProt
write protected
Definition: Rw11Virt.hpp:67
RosPrintfS< bool > RosPrintf(bool value, const char *form=0, int width=0, int prec=0)
Creates a print object for the formatted output of a bool value.
Definition: RosPrintf.ipp:38
bool String2Long(const std::string &str, long &res, RerrMsg &emsg, int base)
FIXME_docs.
Definition: Rtools.cpp:67
Declaration of class ReventLoop.
Definition: ReventLoop.cpp:47