PetaVision  Alpha
FileStream.cpp
1 /*
2  * FileStream.cpp
3  *
4  * Created on: Jun 9, 2016
5  * Author: pschultz
6  */
7 
8 extern "C" {
9 #include <unistd.h>
10 }
11 #include <cinttypes>
12 #include <cstdarg>
13 #include <cstdio>
14 #include <cstring>
15 #include <string>
16 #include <vector>
17 
18 #include "FileStream.hpp"
19 #include "io/io.hpp"
20 #include "utils/PVAssert.hpp"
21 #include "utils/PVLog.hpp"
22 
23 using std::string;
24 
25 namespace PV {
26 
27 FileStream::FileStream(char const *path, std::ios_base::openmode mode, bool verifyWrites) {
28  setOutStream(mFStream);
29  openFile(path, mode, verifyWrites);
30 }
31 
32 FileStream::~FileStream() {}
33 
34 void FileStream::openFile(char const *path, std::ios_base::openmode mode, bool verifyWrites) {
35  string fullPath = expandLeadingTilde(path);
36  mFileName = fullPath;
37  mMode = mode;
38  mVerifyWrites = verifyWrites;
39  int attempts = 0;
40  while (!mFStream.is_open()) {
41  mFStream.open(fullPath, mode);
42  if (!mFStream.fail()) {
43  break;
44  }
45  attempts++;
46  WarnLog() << "Failed to open \"" << fullPath << "\" on attempt " << attempts << "\n";
47  if (attempts < mMaxAttempts) {
48  sleep(1);
49  }
50  else {
51  break;
52  }
53  }
54  if (!mFStream.is_open()) {
55  Fatal() << "FileStream::openFile failure (" << strerror(errno) << ") for \"" << fullPath
56  << "\": MAX_FILESYSTEMCALL_TRIES = " << mMaxAttempts << " exceeded.\n";
57  }
58  else if (attempts > 0) {
59  WarnLog() << "FileStream::openFile succeeded for \"" << fullPath << "\" on attempt "
60  << attempts + 1 << "\n";
61  }
62  verifyFlags("openFile");
63 }
64 
65 void FileStream::verifyFlags(const char *caller) {
66  FatalIf(mFStream.fail(), "%s %s: Logical error.\n", mFileName.c_str(), caller);
67  FatalIf(mFStream.bad(), "%s %s: Read / Write error.\n", mFileName.c_str(), caller);
68  FatalIf(writeable() && getOutPos() == -1, "%s %s: out pos == -1\n", mFileName.c_str(), caller);
69  FatalIf(readable() && getInPos() == -1, "%s %s: in pos == -1\n", mFileName.c_str(), caller);
70 }
71 
72 void FileStream::write(void const *data, long length) {
73  long startPos = getOutPos();
74  mFStream.write((char *)data, length);
75  mFStream.flush();
76 
77  std::string errmsg;
78  errmsg.append("writing ").append(std::to_string(length)).append(" bytes");
79  verifyFlags(errmsg.c_str());
80  if (mVerifyWrites) {
81  std::ios_base::openmode mode = std::ios_base::in;
82  if (binary()) {
83  mode |= std::ios_base::binary;
84  }
85  FileStream writeVerifier(mFileName.c_str(), mode, false);
86  // Set the input position to the location we wrote to
87  writeVerifier.setInPos(startPos, true);
88  std::vector<uint8_t> check(length);
89 
90  // Read from the location we wrote to and compare
91  writeVerifier.read(check.data(), length);
92  if (memcmp(check.data(), data, length) != 0) {
93  Fatal() << "Verify write failed when writing " << length << " bytes to position "
94  << startPos << "\n"
95  << mFileName << "\n";
96  }
97  }
98 }
99 
100 void FileStream::read(void *data, long length) {
101  FatalIf(mFStream.eof(), "Attempting to read after EOF.\n");
102  long startPos = getInPos();
103  mFStream.read((char *)data, length);
104  long numRead = mFStream.gcount();
105  FatalIf(
106  numRead != length,
107  "Expected to read %d bytes from %s at position %d; read %d instead. "
108  "New read position: %d\n",
109  length,
110  mFileName.c_str(),
111  startPos,
112  numRead,
113  getInPos());
114  verifyFlags("read");
115 }
116 
117 void FileStream::setOutPos(long pos, std::ios_base::seekdir seekAnchor) {
118  mFStream.seekp(pos, seekAnchor);
119  verifyFlags("setOutPos");
120 }
121 
122 void FileStream::setOutPos(long pos, bool fromBeginning) {
123  if (!fromBeginning) {
124  mFStream.seekp(pos, std::ios_base::cur);
125  }
126  else {
127  mFStream.seekp(pos);
128  }
129  verifyFlags("setOutPos");
130 }
131 
132 void FileStream::setInPos(long pos, std::ios_base::seekdir seekAnchor) {
133  mFStream.seekg(pos, seekAnchor);
134  verifyFlags("setInPos");
135 }
136 
137 void FileStream::setInPos(long pos, bool fromBeginning) {
138  if (!fromBeginning) {
139  mFStream.seekg(pos, std::ios_base::cur);
140  }
141  else {
142  mFStream.seekg(pos);
143  }
144  verifyFlags("setInPos");
145 }
146 
147 long FileStream::getOutPos() { return mFStream.tellp(); }
148 
149 long FileStream::getInPos() { return mFStream.tellg(); }
150 
151 } /* namespace PV */