OpenCores
URL https://opencores.org/ocsvn/w11/w11/trunk

Subversion Repositories w11

[/] [w11/] [tags/] [w11a_V0.7/] [tools/] [src/] [librw11/] [Rw11VirtTapeTap.cpp] - Blame information for rev 33

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 31 wfjm
// $Id: Rw11VirtTapeTap.cpp 686 2015-06-04 21:08:08Z mueller $
2
//
3
// Copyright 2015- by Walter F.J. Mueller <W.F.J.Mueller@gsi.de>
4
//
5
// This program is free software; you may redistribute and/or modify it under
6
// the terms of the GNU General Public License as published by the Free
7
// Software Foundation, either version 2, or at your option any later version.
8
//
9
// This program is distributed in the hope that it will be useful, but
10
// WITHOUT ANY WARRANTY, without even the implied warranty of MERCHANTABILITY
11
// or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
12
// for complete details.
13
// 
14
// Revision History: 
15
// Date         Rev Version  Comment
16
// 2015-06-04   686   1.0    Initial version
17
// 2015-05-17   683   0.1    First draft
18
// ---------------------------------------------------------------------------
19
 
20
/*!
21
  \file
22
  \version $Id: Rw11VirtTapeTap.cpp 686 2015-06-04 21:08:08Z mueller $
23
  \brief   Implemenation of Rw11VirtTapeTap.
24
*/
25
 
26
#include <sys/types.h>
27
#include <sys/stat.h>
28
#include <fcntl.h>
29
#include <unistd.h>
30
 
31
#include "librtools/RosFill.hpp"
32
#include "librtools/Rtools.hpp"
33
 
34
#include "Rw11VirtTapeTap.hpp"
35
 
36
using namespace std;
37
 
38
/*!
39
  \class Retro::Rw11VirtTapeTap
40
  \brief FIXME_docs
41
*/
42
 
43
// all method definitions in namespace Retro
44
namespace Retro {
45
 
46
//------------------------------------------+-----------------------------------
47
// constants definitions
48
 
49
const uint32_t Rw11VirtTapeTap::kMetaEof;
50
const uint32_t Rw11VirtTapeTap::kMetaEom;
51
const uint32_t Rw11VirtTapeTap::kMeta_M_Perr;
52
const uint32_t Rw11VirtTapeTap::kMeta_M_Mbz;
53
const uint32_t Rw11VirtTapeTap::kMeta_B_Rlen;
54
 
55
//------------------------------------------+-----------------------------------
56
//! Default constructor
57
 
58
Rw11VirtTapeTap::Rw11VirtTapeTap(Rw11Unit* punit)
59
  : Rw11VirtTape(punit),
60
    fFd(0),
61
    fSize(0),
62
    fPos(0),
63
    fBad(true),
64
    fPadOdd(false),
65
    fTruncPend(false)
66
{}
67
 
68
//------------------------------------------+-----------------------------------
69
//! Destructor
70
 
71
Rw11VirtTapeTap::~Rw11VirtTapeTap()
72
{
73
  if (fFd > 2) ::close(fFd);
74
}
75
 
76
//------------------------------------------+-----------------------------------
77
//! FIXME_docs
78
 
79
bool Rw11VirtTapeTap::Open(const std::string& url, RerrMsg& emsg)
80
{
81
  if (!fUrl.Set(url, "|wpro|e11|cap=|", emsg)) return false;
82
 
83
  fWProt  = fUrl.FindOpt("wpro");
84
  fPadOdd = fUrl.FindOpt("e11");
85
 
86
  string str_cap;
87
  unsigned long capacity=0;
88
  if (fUrl.FindOpt("cap",str_cap)) {
89
    if (str_cap.length() > 0) {
90
      unsigned long scale = 1;
91
      string str_conv = str_cap;
92
      char clast = str_cap[str_cap.length()-1];
93
      bool ok = true;
94
 
95
      if (! (clast >= '0' && clast <= '9') ) {
96
        str_conv = str_cap.substr(0,str_cap.length()-1);
97
        switch(str_cap[str_cap.length()-1]) {
98
        case 'k':
99
        case 'K':
100
          scale = 1024;
101
          break;
102
        case 'm':
103
        case 'M':
104
          scale = 1024*1024;
105
          break;
106
        default:
107
          ok = false;
108
          break;
109
        }
110
      }
111
      if (ok) {
112
        RerrMsg emsg_conv;
113
        ok = Rtools::String2Long(str_conv, capacity, emsg_conv);
114
      }
115
      if (!ok) {
116
        emsg.Init("Rw11VirtTapeTap::Open()",
117
                  string("bad capacity option '")+str_cap+"'");
118
        return false;
119
      }
120
      capacity *= scale;
121
    }
122
  }
123
 
124
  int fd = ::open(fUrl.Path().c_str(), fWProt ? O_RDONLY : O_CREAT|O_RDWR,
125
                  S_IRUSR|S_IWUSR|S_IRGRP);
126
  if (fd < 0) {
127
    emsg.InitErrno("Rw11VirtTapeTap::Open()",
128
                   string("open() for '") + fUrl.Path() + "' failed: ", errno);
129
    return false;
130
  }
131
 
132
  struct stat sbuf;
133
  if (::fstat(fd, &sbuf) < 0) {
134
    emsg.InitErrno("Rw11VirtTapeTap::Open()",
135
                   string("stat() for '") + fUrl.Path() + "' failed: ", errno);
136
    return false;
137
  }
138
 
139
  if ((sbuf.st_mode & S_IWUSR) == 0) fWProt = true;
140
 
141
  fFd   = fd;
142
  fSize = sbuf.st_size;
143
  fPos  = 0;
144
  fBad  = false;
145
  fTruncPend = true;
146
 
147
  fCapacity = capacity;
148
  fBot = true;
149
  fEot = false;
150
  fEom = false;
151
  fPosFile   = 0;
152
  fPosRecord = 0;
153
  return true;
154
}
155
 
156
//------------------------------------------+-----------------------------------
157
//! FIXME_docs
158
 
159
bool Rw11VirtTapeTap::ReadRecord(size_t nbyt, uint8_t* data, size_t& ndone,
160
                                  int& opcode, RerrMsg& emsg)
161
{
162
  fStats.Inc(kStatNVTReadRec);
163
 
164
  opcode = kOpCodeBadFormat;
165
  ndone  = 0;
166
  if (fBad) return BadTapeMsg("ReadRecord()", emsg);
167
 
168
  if (fPos == fSize) {
169
    fEom   = true;
170
    opcode = kOpCodeEom;
171
    return true;
172
  }
173
 
174
  uint32_t metabeg;
175
  uint32_t metaend;
176
 
177
  if (!CheckSizeForw(sizeof(metabeg), "missed metabeg", emsg)) return SetBad();
178
  if (!Read(sizeof(metabeg), reinterpret_cast<uint8_t*>(&metabeg),
179
            emsg)) return SetBad();
180
 
181
  if (metabeg == kMetaEof) {
182
    fStats.Inc(kStatNVTReadEof);
183
    opcode = kOpCodeEof;
184
    fPosFile   += 1;
185
    fPosRecord  = 0;
186
    return true;
187
  }
188
 
189
  if (metabeg == kMetaEom) {
190
    if (!Seek(sizeof(metabeg), -1, emsg)) return SetBad();
191
    fStats.Inc(kStatNVTReadEom);
192
    fEom   = true;
193
    opcode = kOpCodeEom;
194
    return true;
195
  }
196
 
197
  size_t rlen;
198
  bool   perr;
199
  if (!ParseMeta(metabeg, rlen, perr, emsg)) return SetBad();
200
  size_t rlenpad = BytePadding(rlen);
201
 
202
  if (!CheckSizeForw(rlenpad, "missed data", emsg)) return SetBad();
203
 
204
  ndone = (rlen <= nbyt) ? rlen : nbyt;
205
  if (!Read(ndone, data, emsg)) return SetBad();
206
  if (ndone < rlenpad) {
207
    if (!Seek(rlenpad, +1, emsg)) return SetBad();
208
  }
209
 
210
  if (!CheckSizeForw(sizeof(metaend), "missed metaend", emsg)) return SetBad();
211
  if (!Read(sizeof(metaend), reinterpret_cast<uint8_t*>(&metaend),
212
            emsg)) return SetBad();
213
 
214
  if (metabeg != metaend) {
215
    emsg.Init("Rw11VirtTapeTap::ReadRecord", "metabeg metaend mismatch");
216
    ndone = 0;
217
    return SetBad();
218
  }
219
 
220
  IncPosRecord(+1);
221
  opcode = kOpCodeOK;
222
  if (perr) {
223
    fStats.Inc(kStatNVTReadPErr);
224
    opcode = kOpCodeBadParity;
225
  }
226
  if (ndone < rlen) {
227
    fStats.Inc(kStatNVTReadLErr);
228
    opcode = kOpCodeRecLenErr;
229
  }
230
 
231
  fStats.Inc(kStatNVTReadByt, ndone);
232
 
233
  return true;
234
}
235
 
236
//------------------------------------------+-----------------------------------
237
//! FIXME_docs
238
 
239
bool Rw11VirtTapeTap::WriteRecord(size_t nbyt, const uint8_t* data,
240
                                int& opcode, RerrMsg& emsg)
241
{
242
  fStats.Inc(kStatNVTWriteRec);
243
  fStats.Inc(kStatNVTWriteByt, nbyt);
244
 
245
  opcode = kOpCodeBadFormat;
246
  if (fBad) return BadTapeMsg("WriteRecord()", emsg);
247
 
248
  fEom   = false;
249
 
250
  uint32_t meta = nbyt;
251
  uint8_t  zero = 0x00;
252
 
253
  if (!Write(sizeof(meta), reinterpret_cast<uint8_t*>(&meta),
254
             false, emsg)) return SetBad();
255
 
256
  if (!Write(nbyt, data,
257
             false, emsg)) return SetBad();
258
  if (fPadOdd && (nbyt&0x01)) {
259
    if (!Write(sizeof(zero), &zero, false, emsg)) return SetBad();
260
  }
261
 
262
  if (!Write(sizeof(meta), reinterpret_cast<uint8_t*>(&meta),
263
             false, emsg)) return SetBad();
264
  if (!Write(sizeof(kMetaEom), reinterpret_cast<const uint8_t*>(&kMetaEom),
265
             true, emsg)) return SetBad();
266
 
267
  IncPosRecord(+1);
268
  opcode = kOpCodeOK;
269
 
270
  return true;
271
}
272
 
273
//------------------------------------------+-----------------------------------
274
//! FIXME_docs
275
 
276
bool Rw11VirtTapeTap::WriteEof(RerrMsg& emsg)
277
{
278
  fStats.Inc(kStatNVTWriteEof);
279
 
280
  if (fBad) return BadTapeMsg("WriteEof()", emsg);
281
 
282
  fEom   = false;
283
 
284
  if (!Write(sizeof(kMetaEof), reinterpret_cast<const uint8_t*>(&kMetaEof),
285
             false, emsg)) return SetBad();
286
  if (!Write(sizeof(kMetaEom), reinterpret_cast<const uint8_t*>(&kMetaEom),
287
             true, emsg)) return SetBad();
288
 
289
  fPosFile   += 1;
290
  fPosRecord  = 0;
291
 
292
  return true;
293
}
294
 
295
//------------------------------------------+-----------------------------------
296
//! FIXME_docs
297
 
298
bool Rw11VirtTapeTap::SpaceForw(size_t nrec, size_t& ndone,
299
                              int& opcode, RerrMsg& emsg)
300
{
301
  fStats.Inc(kStatNVTSpaForw);
302
 
303
  opcode = kOpCodeBadFormat;
304
  ndone  = 0;
305
  if (fBad) return BadTapeMsg("SpaceForw()", emsg);
306
 
307
  while (nrec > 0) {
308
 
309
    if (fPos == fSize) {
310
      fEom   = true;
311
      opcode = kOpCodeEom;
312
      return true;
313
    }
314
 
315
    uint32_t metabeg;
316
 
317
    if (!CheckSizeForw(sizeof(metabeg), "missed metabeg", emsg)) return SetBad();
318
    if (!Read(sizeof(metabeg), reinterpret_cast<uint8_t*>(&metabeg),
319
              emsg)) return SetBad();
320
 
321
    if (metabeg == kMetaEof) {
322
      opcode = kOpCodeEof;
323
      fPosFile   += 1;
324
      fPosRecord  = 0;
325
      return true;
326
    }
327
 
328
    if (metabeg == kMetaEom) {
329
      if (!Seek(sizeof(metabeg), -1, emsg)) return SetBad();
330
      fEom   = true;
331
      opcode = kOpCodeEom;
332
      return true;
333
    }
334
 
335
    size_t rlen;
336
    bool   perr;
337
    if (!ParseMeta(metabeg, rlen, perr, emsg)) return SetBad();
338
    size_t rlenpad = BytePadding(rlen);
339
 
340
    if (!CheckSizeForw(sizeof(metabeg)+rlenpad, "missed data or metaend", emsg))
341
      return SetBad();
342
    if (!Seek(sizeof(metabeg)+rlenpad, +1, emsg)) return SetBad();
343
 
344
    IncPosRecord(+1);
345
    nrec  -= 1;
346
    ndone += 1;
347
  }
348
 
349
  opcode = kOpCodeOK;
350
 
351
  return true;
352
}
353
 
354
//------------------------------------------+-----------------------------------
355
//! FIXME_docs
356
 
357
bool Rw11VirtTapeTap::SpaceBack(size_t nrec, size_t& ndone,
358
                              int& opcode, RerrMsg& emsg)
359
{
360
  fStats.Inc(kStatNVTSpaBack);
361
 
362
  opcode = kOpCodeBadFormat;
363
  ndone  = 0;
364
  if (fBad) return BadTapeMsg("SpaceBack()", emsg);
365
 
366
  fEom = false;
367
  fTruncPend = true;
368
 
369
  while (nrec > 0) {
370
 
371
    if (fPos == 0) {
372
      opcode = kOpCodeBot;
373
      fPosFile    = 0;
374
      fPosRecord  = 0;
375
      return true;
376
    }
377
 
378
    uint32_t metaend;
379
 
380
    if (!CheckSizeBack(sizeof(metaend), "missed metaend", emsg)) return SetBad();
381
    if (!Seek(sizeof(metaend), -1, emsg)) return SetBad();
382
    if (!Read(sizeof(metaend), reinterpret_cast<uint8_t*>(&metaend),
383
              emsg)) return SetBad();
384
 
385
    if (metaend == kMetaEof) {
386
      if (!Seek(sizeof(metaend), -1, emsg)) return SetBad();
387
      opcode = kOpCodeEof;
388
      fPosFile   -= 1;
389
      fPosRecord  = -1;
390
      return true;
391
    }
392
 
393
    if (metaend == kMetaEom) {
394
      emsg.Init("Rw11VirtTapeTap::SpaceBack()","unexpected EOM marker");
395
      return SetBad();
396
    }
397
 
398
    size_t rlen;
399
    bool   perr;
400
    if (!ParseMeta(metaend, rlen, perr, emsg)) return SetBad();
401
    size_t rlenpad = BytePadding(rlen);
402
 
403
    if (!CheckSizeBack(2*sizeof(metaend)+rlenpad,
404
                       "missed data or metabeg", emsg)) return SetBad();
405
    if (!Seek(2*sizeof(metaend)+rlenpad, -1, emsg)) return SetBad();
406
 
407
    IncPosRecord(-1);
408
    nrec  -= 1;
409
    ndone += 1;
410
  }
411
 
412
  opcode = kOpCodeOK;
413
 
414
  return true;
415
}
416
 
417
//------------------------------------------+-----------------------------------
418
//! FIXME_docs
419
 
420
bool Rw11VirtTapeTap::Rewind(int& opcode, RerrMsg& emsg)
421
{
422
  fStats.Inc(kStatNVTRewind);
423
 
424
  opcode = kOpCodeBadFormat;
425
  if (Seek(0, 0, emsg) <0) return SetBad();
426
 
427
  fBot = true;
428
  fEot = false;
429
  fEom = false;
430
  fPosFile   = 0;
431
  fPosRecord = 0;
432
  fBad = false;
433
  fTruncPend = true;
434
 
435
  opcode = kOpCodeOK;
436
  return true;
437
}
438
 
439
//------------------------------------------+-----------------------------------
440
//! FIXME_docs
441
 
442
void Rw11VirtTapeTap::Dump(std::ostream& os, int ind, const char* text) const
443
{
444
  RosFill bl(ind);
445
  os << bl << (text?text:"--") << "Rw11VirtTapeTap @ " << this << endl;
446
 
447
  os << bl << "  fFd:             " << fFd << endl;
448
  os << bl << "  fSize:           " << fSize << endl;
449
  os << bl << "  fPos:            " << fPos << endl;
450
  os << bl << "  fBad:            " << fBad << endl;
451
  os << bl << "  fPadOdd:         " << fPadOdd << endl;
452
  Rw11VirtTape::Dump(os, ind, " ^");
453
  return;
454
}
455
 
456
//------------------------------------------+-----------------------------------
457
//! FIXME_docs
458
 
459
bool Rw11VirtTapeTap::Seek(size_t seekpos, int dir, RerrMsg& emsg)
460
{
461
  off_t offset = seekpos;
462
  int   whence = SEEK_SET;
463
  if (dir > 0) {
464
    whence = SEEK_CUR;
465
  } else if (dir < 0) {
466
    whence = SEEK_CUR;
467
    offset = -offset;
468
  }
469
  if (::lseek(fFd, offset, whence) < 0) {
470
    emsg.InitErrno("Rw11VirtTapeTap::Seek()", "seek() failed: ", errno);
471
    return false;
472
  }
473
 
474
  UpdatePos(seekpos, dir);
475
 
476
  return true;
477
}
478
 
479
//------------------------------------------+-----------------------------------
480
//! FIXME_docs
481
 
482
bool Rw11VirtTapeTap::Read(size_t nbyt, uint8_t* data, RerrMsg& emsg)
483
{
484
   ssize_t irc = ::read(fFd, data, nbyt);
485
  if (irc < 0) {
486
    emsg.InitErrno("Rw11VirtTapeTap::Read()", "read() failed: ", errno);
487
    return false;
488
  }
489
  UpdatePos(nbyt, +1);
490
  return true;
491
}
492
 
493
//------------------------------------------+-----------------------------------
494
//! FIXME_docs
495
 
496
bool Rw11VirtTapeTap::Write(size_t nbyt, const uint8_t* data, bool back,
497
                               RerrMsg& emsg)
498
{
499
  if (fTruncPend) {
500
    if (ftruncate(fFd, fPos) < 0) {
501
      emsg.InitErrno("Rw11VirtTapeTap::Write()", "ftruncate() failed: ", errno);
502
      return false;
503
    }
504
    fTruncPend = false;
505
    fSize = fPos;
506
  }
507
 
508
  ssize_t irc = ::write(fFd, data, nbyt);
509
  if (irc < 0) {
510
    emsg.InitErrno("Rw11VirtTapeTap::Write()", "write() failed: ", errno);
511
    return false;
512
  }
513
 
514
  UpdatePos(nbyt, +1);
515
  if (fPos > fSize) fSize = fPos;
516
 
517
  if (back) {
518
    if (!Seek(nbyt, -1, emsg)) return false;
519
  }
520
 
521
  return true;
522
}
523
 
524
//------------------------------------------+-----------------------------------
525
//! FIXME_docs
526
 
527
bool Rw11VirtTapeTap::CheckSizeForw(size_t nbyt, const char* text,
528
                                     RerrMsg& emsg)
529
{
530
  if (fPos+nbyt <= fSize) return true;
531
  emsg.Init("Rw11VirtTapeTap::CheckSizeForw()", text);
532
  return false;
533
}
534
 
535
//------------------------------------------+-----------------------------------
536
//! FIXME_docs
537
 
538
bool Rw11VirtTapeTap::CheckSizeBack(size_t nbyt, const char* text,
539
                                     RerrMsg& emsg)
540
{
541
  if (nbyt <= fPos) return true;
542
  emsg.Init("Rw11VirtTapeTap::CheckSizeBack()", text);
543
  return false;
544
}
545
 
546
//------------------------------------------+-----------------------------------
547
//! FIXME_docs
548
 
549
void Rw11VirtTapeTap::UpdatePos(size_t nbyt, int dir)
550
{
551
  if (dir == 0) {
552
    fPos  = nbyt;
553
  } else if (dir > 0) {
554
    fPos += nbyt;
555
  } else {
556
    fPos -= nbyt;
557
  }
558
 
559
  fBot = (fPos == 0);
560
  fEot = (fCapacity == 0) ? false : (fPos > fCapacity);
561
 
562
  return;
563
}
564
 
565
//------------------------------------------+-----------------------------------
566
//! FIXME_docs
567
 
568
bool Rw11VirtTapeTap::ParseMeta(uint32_t meta, size_t& rlen, bool& perr,
569
                                 RerrMsg& emsg)
570
{
571
  rlen = meta & kMeta_B_Rlen;
572
  perr = meta & kMeta_M_Perr;
573
  if (meta & kMeta_M_Mbz) {
574
    emsg.Init("Rw11VirtTapeTap::ParseMeta", "bad meta tag");
575
    return false;
576
  }
577
  return true;
578
}
579
 
580
//------------------------------------------+-----------------------------------
581
//! FIXME_docs
582
 
583
bool Rw11VirtTapeTap::BadTapeMsg(const char* meth, RerrMsg& emsg)
584
{
585
  emsg.Init(string("Rw11VirtTapeTap::")+meth, "bad tape format");
586
  return false;
587
}
588
 
589
} // end namespace Retro

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.