fstreamPointers.C
Go to the documentation of this file.
1 /*---------------------------------------------------------------------------*\
2  ========= |
3  \\ / F ield | OpenFOAM: The Open Source CFD Toolbox
4  \\ / O peration |
5  \\ / A nd | www.openfoam.com
6  \\/ M anipulation |
7 -------------------------------------------------------------------------------
8  Copyright (C) 2011 OpenFOAM Foundation
9  Copyright (C) 2018-2022 OpenCFD Ltd.
10 -------------------------------------------------------------------------------
11 License
12  This file is part of OpenFOAM.
13 
14  OpenFOAM is free software: you can redistribute it and/or modify it
15  under the terms of the GNU General Public License as published by
16  the Free Software Foundation, either version 3 of the License, or
17  (at your option) any later version.
18 
19  OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
20  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
21  FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
22  for more details.
23 
24  You should have received a copy of the GNU General Public License
25  along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
26 
27 \*---------------------------------------------------------------------------*/
28 
29 #include "fstreamPointer.H"
30 #include "OCountStream.H"
31 #include "OSspecific.H"
32 #include <cstdio>
33 
34 // HAVE_LIBZ defined externally
35 // #define HAVE_LIBZ
36 
37 #ifdef HAVE_LIBZ
38 #include "gzstream.h"
39 #endif /* HAVE_LIBZ */
40 
41 // * * * * * * * * * * * * * Static Member Functions * * * * * * * * * * * * //
42 
44 {
45  #ifdef HAVE_LIBZ
46  return true;
47  #else
48  return false;
49  #endif
50 }
51 
52 
54 {
55  #ifdef HAVE_LIBZ
56  return true;
57  #else
58  return false;
59  #endif
60 }
61 
62 
63 // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
64 
66 (
67  const fileName& pathname
68 )
69 :
70  ptr_(nullptr)
71 {
72  const std::ios_base::openmode mode
73  (
74  std::ios_base::in | std::ios_base::binary
75  );
76 
77  ptr_.reset(new std::ifstream(pathname, mode));
78 
79  if (!ptr_->good())
80  {
81  // Try compressed version instead
82 
83  const fileName pathname_gz(pathname + ".gz");
84 
85  if (Foam::isFile(pathname_gz, false))
86  {
87  #ifdef HAVE_LIBZ
88 
89  ptr_.reset(new igzstream(pathname_gz, mode));
90 
91  #else /* HAVE_LIBZ */
92 
94  << "No read support for gz compressed files (libz)"
95  << " : could use 'gunzip' from the command-line" << nl
96  << "file: " << pathname_gz << endl
97  << exit(FatalError);
98 
99  #endif /* HAVE_LIBZ */
100  }
101  else
102  {
103  // TBD:
104  // Can also fallback and open .orig files too
105  //
106  // auto* file = dynamic_cast<std::ifstream*>(ptr_.get());
107  // file->open(pathname + ".orig", mode);
108  }
109  }
110 }
111 
112 
114 :
115  ptr_(),
116  atomic_(false)
117 {}
118 
119 
121 :
122  ptr_(new Foam::ocountstream),
123  atomic_(false)
124 {}
125 
126 
128 (
129  const fileName& pathname,
131  const bool append,
132  const bool atomic
133 )
134 :
135  ptr_(nullptr),
136  atomic_(atomic)
137 {
138  std::ios_base::openmode mode
139  (
140  std::ios_base::out | std::ios_base::binary
141  );
142 
143  if (append)
144  {
145  mode |= std::ios_base::app;
146 
147  // Cannot append to gzstream
149 
150  // Cannot use append + atomic operation, without lots of extra work
151  atomic_ = false;
152  }
153 
154 
155  // When opening new files, remove file variants out of the way.
156  // Eg, opening "file1"
157  // - remove old "file1.gz" (compressed)
158  // - also remove old "file1" if it is a symlink and we are not appending
159  //
160  // Not writing into symlinked files avoids problems with symlinked
161  // initial fields (eg, 0/U -> ../0.orig/U)
162 
163  const fileName pathname_gz(pathname + ".gz");
164  const fileName pathname_tmp(pathname + "~tmp~");
165 
166  fileName::Type fType = fileName::Type::UNDEFINED;
167 
168  if (IOstreamOption::COMPRESSED == comp)
169  {
170  // Output compression requested.
171 
172  #ifdef HAVE_LIBZ
173  // TBD:
174  // atomic_ = true; // Always treat COMPRESSED like an atomic
175 
176  const fileName& target = (atomic_ ? pathname_tmp : pathname_gz);
177 
178  // Remove old uncompressed version (if any)
179  fType = Foam::type(pathname, false);
180  if (fType == fileName::SYMLINK || fType == fileName::FILE)
181  {
182  Foam::rm(pathname);
183  }
184 
185  // Avoid writing into symlinked files (non-append mode)
186  if (!append || atomic_)
187  {
188  fType = Foam::type(target, false);
189  if (fType == fileName::SYMLINK)
190  {
191  Foam::rm(target);
192  }
193  }
194 
195  ptr_.reset(new ogzstream(target, mode));
196 
197  #else /* HAVE_LIBZ */
198 
200 
201  Warning
202  << nl
203  << "No write support for gz compressed files (libz)"
204  << " : downgraded to UNCOMPRESSED" << nl
205  << "file: " << pathname_gz << endl;
206 
207  #endif /* HAVE_LIBZ */
208  }
209 
210  if (IOstreamOption::COMPRESSED != comp)
211  {
212  const fileName& target = (atomic_ ? pathname_tmp : pathname);
213 
214  // Remove old compressed version (if any)
215  fType = Foam::type(pathname_gz, false);
216  if (fType == fileName::SYMLINK || fType == fileName::FILE)
217  {
218  Foam::rm(pathname_gz);
219  }
220 
221  // Avoid writing into symlinked files (non-append mode)
222  if (!append || atomic_)
223  {
224  fType = Foam::type(target, false);
225  if (fType == fileName::SYMLINK)
226  {
227  Foam::rm(target);
228  }
229  }
230 
231  ptr_.reset(new std::ofstream(target, mode));
232  }
233 }
234 
235 
236 // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
237 
238 void Foam::ifstreamPointer::reopen_gz(const std::string& pathname)
239 {
240  #ifdef HAVE_LIBZ
241  auto* gz = dynamic_cast<igzstream*>(ptr_.get());
242 
243  if (gz)
244  {
245  // Special treatment for gzstream
246  gz->close();
247  gz->clear();
248 
249  gz->open
250  (
251  pathname + ".gz",
252  (std::ios_base::in | std::ios_base::binary)
253  );
254  return;
255  }
256  #endif /* HAVE_LIBZ */
257 }
258 
259 
260 void Foam::ofstreamPointer::reopen(const std::string& pathname)
261 {
262  #ifdef HAVE_LIBZ
263  auto* gz = dynamic_cast<ogzstream*>(ptr_.get());
264 
265  if (gz)
266  {
267  // Special treatment for gzstream
268  gz->close();
269  gz->clear();
270 
271  if (atomic_)
272  {
273  gz->open
274  (
275  pathname + "~tmp~",
276  (std::ios_base::out | std::ios_base::binary)
277  );
278  }
279  else
280  {
281  gz->open
282  (
283  pathname + ".gz",
284  (std::ios_base::out | std::ios_base::binary)
285  );
286  }
287  return;
288  }
289  #endif /* HAVE_LIBZ */
290 
291  auto* file = dynamic_cast<std::ofstream*>(ptr_.get());
292 
293  if (file)
294  {
295  if (file->is_open())
296  {
297  file->close();
298  }
299  file->clear();
300 
301  // Don't need original request to append since rewind implies
302  // trashing that anyhow.
303 
304  if (atomic_)
305  {
306  file->open
307  (
308  pathname + "~tmp~",
309  (std::ios_base::out | std::ios_base::binary)
310  );
311  }
312  else
313  {
314  file->open
315  (
316  pathname,
317  (std::ios_base::out | std::ios_base::binary)
318  );
319  }
320  return;
321  }
322 }
323 
324 
325 void Foam::ofstreamPointer::close(const std::string& pathname)
326 {
327  if (!atomic_ || pathname.empty()) return;
328 
329  #ifdef HAVE_LIBZ
330  auto* gz = dynamic_cast<ogzstream*>(ptr_.get());
331 
332  if (gz)
333  {
334  // Special treatment for gzstream
335  gz->close();
336  gz->clear();
337 
338  std::rename
339  (
340  (pathname + "~tmp~").c_str(),
341  (pathname + ".gz").c_str()
342  );
343  return;
344  }
345  #endif /* HAVE_LIBZ */
346 
347  auto* file = dynamic_cast<std::ofstream*>(ptr_.get());
348 
349  if (file)
350  {
351  if (file->is_open())
352  {
353  file->close();
354  }
355  file->clear();
356 
357  std::rename
358  (
359  (pathname + "~tmp~").c_str(),
360  pathname.c_str()
361  );
362  return;
363  }
364 }
365 
366 
369 {
370  #ifdef HAVE_LIBZ
371  if (dynamic_cast<const igzstream*>(ptr_.get()))
372  {
373  return IOstreamOption::compressionType::COMPRESSED;
374  }
375  #endif /* HAVE_LIBZ */
376 
377  return IOstreamOption::compressionType::UNCOMPRESSED;
378 }
379 
380 
383 {
384  #ifdef HAVE_LIBZ
385  if (dynamic_cast<const ogzstream*>(ptr_.get()))
386  {
387  return IOstreamOption::compressionType::COMPRESSED;
388  }
389  #endif /* HAVE_LIBZ */
390 
391  return IOstreamOption::compressionType::UNCOMPRESSED;
392 }
393 
394 
395 // ************************************************************************* //
A symbolic link.
Definition: fileName.H:85
A class for handling file names.
Definition: fileName.H:71
errorManipArg< error, int > exit(error &err, const int errNo=1)
Definition: errorManip.H:125
compressionType
Compression treatment (UNCOMPRESSED | COMPRESSED)
error FatalError
Error stream (stdout output on all processes), with additional &#39;FOAM FATAL ERROR&#39; header text and sta...
IOstreamOption::compressionType whichCompression() const
Which compression type?
Trivial output stream for calculating byte counts.
Definition: OCountStream.H:164
static bool supports_gz()
True if compiled with libz support.
constexpr char nl
The newline &#39;\n&#39; character (0x0a)
Definition: Ostream.H:49
ofstreamPointer() noexcept
Default construct (empty)
Ostream & endl(Ostream &os)
Add newline and flush stream.
Definition: Ostream.H:487
static bool supports_gz()
True if compiled with libz support.
void reopen_gz(const std::string &pathname)
Special &#39;rewind&#39; method for compressed stream.
Functions used by OpenFOAM that are specific to POSIX compliant operating systems and need to be repl...
fileName::Type type(const fileName &name, const bool followLink=true)
Return the file type: DIRECTORY or FILE, normally following symbolic links.
Definition: POSIX.C:752
A regular file.
Definition: fileName.H:83
void reopen(const std::string &pathname)
Reopen for compressed/non-compressed.
const direction noexcept
Definition: Scalar.H:258
ifstreamPointer() noexcept=default
Default construct (empty)
void close(const std::string &pathname)
Close stream and rename file.
messageStream Warning
Warning stream (stdout output on master, null elsewhere), with additional &#39;FOAM Warning&#39; header text...
bool isFile(const fileName &name, const bool checkGzip=true, const bool followLink=true)
Does the name exist as a FILE in the file system?
Definition: POSIX.C:830
rAUs append(new volScalarField(IOobject::groupName("rAU", phase1.name()), 1.0/(U1Eqn.A()+byDt(max(phase1.residualAlpha() - alpha1, scalar(0)) *rho1))))
IOstreamOption::compressionType whichCompression() const
Which compression type?
mode_t mode(const fileName &name, const bool followLink=true)
Return the file mode, normally following symbolic links.
Definition: POSIX.C:726
Type
Enumerations to handle directory entry types.
Definition: fileName.H:80
Namespace for OpenFOAM.
bool rm(const fileName &file)
Remove a file (or its gz equivalent), returning true if successful.
Definition: POSIX.C:1357